diff --git a/.gitignore b/.gitignore
index b7e4a0186..88ccbb56f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -43,6 +43,7 @@ bld_dbg/*
bld_rel/*
bld_dbg_x64/*
bld_rel_x64/*
+.vscode
# Auto generated files.
config.log
config.status
@@ -75,3 +76,6 @@ src/api/ml/z3.mllib
*.bak
doc/api
doc/code
+.vs
+examples/**/obj
+CMakeSettings.json
diff --git a/CMakeLists.txt b/CMakeLists.txt
index bc5eecdef..188d8dfde 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -34,7 +34,7 @@ endif()
################################################################################
set(Z3_VERSION_MAJOR 4)
set(Z3_VERSION_MINOR 8)
-set(Z3_VERSION_PATCH 4)
+set(Z3_VERSION_PATCH 5)
set(Z3_VERSION_TWEAK 0)
set(Z3_VERSION "${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}.${Z3_VERSION_PATCH}.${Z3_VERSION_TWEAK}")
set(Z3_FULL_VERSION_STR "${Z3_VERSION}") # Note this might be modified
@@ -205,9 +205,6 @@ message(STATUS "PYTHON_EXECUTABLE: ${PYTHON_EXECUTABLE}")
include(${CMAKE_SOURCE_DIR}/cmake/target_arch_detect.cmake)
detect_target_architecture(TARGET_ARCHITECTURE)
message(STATUS "Detected target architecture: ${TARGET_ARCHITECTURE}")
-if ("${TARGET_ARCHITECTURE}" STREQUAL "x86_64")
- list(APPEND Z3_COMPONENT_CXX_DEFINES "-D_AMD64_")
-endif()
################################################################################
@@ -257,6 +254,15 @@ elseif (CYGWIN)
elseif (WIN32)
message(STATUS "Platform: Windows")
list(APPEND Z3_COMPONENT_CXX_DEFINES "-D_WINDOWS")
+elseif (EMSCRIPTEN)
+ message(STATUS "Platform: Emscripten")
+ list(APPEND Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS
+ "-Os"
+ "-s ALLOW_MEMORY_GROWTH=1"
+ "-s ASSERTIONS=0"
+ "-s DISABLE_EXCEPTION_CATCHING=0"
+ "-s ERROR_ON_UNDEFINED_SYMBOLS=1"
+ )
else()
message(FATAL_ERROR "Platform \"${CMAKE_SYSTEM_NAME}\" not recognised")
endif()
@@ -425,6 +431,15 @@ list(APPEND Z3_DEPENDENT_LIBS ${CMAKE_THREAD_LIBS_INIT})
################################################################################
include(${CMAKE_SOURCE_DIR}/cmake/compiler_warnings.cmake)
+################################################################################
+# Save Clang optimization records
+################################################################################
+option(SAVE_CLANG_OPTIMIZATION_RECORDS "Enable saving Clang optimization records." OFF)
+
+if (SAVE_CLANG_OPTIMIZATION_RECORDS)
+ z3_add_cxx_flag("-fsave-optimization-record" REQUIRED)
+endif()
+
################################################################################
# If using Ninja, force color output for Clang (and gcc, disabled to check build).
################################################################################
diff --git a/RELEASE_NOTES b/RELEASE_NOTES
index 06618a8f2..ba254db4e 100644
--- a/RELEASE_NOTES
+++ b/RELEASE_NOTES
@@ -1,5 +1,15 @@
RELEASE NOTES
+Version 4.8.4
+=============
+
+- Notes
+ - fixes bugs
+ - a substantial update to how the seq theory solver handles regular
+ expressions. Other performance improvements to the seq solver.
+ - Managed .NET DLLs include dotnet standard 1.4 on supported platforms.
+ - Windows Managed DLLs are strong signed in the released binaries.
+
Version 4.8.3
=============
- New features
diff --git a/cmake/modules/DotnetImports.props.in b/cmake/modules/DotnetImports.props.in
new file mode 100644
index 000000000..090d46502
--- /dev/null
+++ b/cmake/modules/DotnetImports.props.in
@@ -0,0 +1,8 @@
+
+
+ ${_DN_OUTPUT_PATH}/
+ ${_DN_XPLAT_LIB_DIR}/
+ ${_DN_VERSION}
+ ${_DN_CUSTOM_BUILDPROPS}
+
+
diff --git a/cmake/modules/FindDotnet.cmake b/cmake/modules/FindDotnet.cmake
new file mode 100644
index 000000000..98c5f2079
--- /dev/null
+++ b/cmake/modules/FindDotnet.cmake
@@ -0,0 +1,471 @@
+#.rst
+# FindDotnet
+# ----------
+#
+# Find DotNet executable, and initialize functions for adding dotnet projects.
+#
+# Results are reported in the following variables::
+#
+# DOTNET_FOUND - True if dotnet executable is found
+# DOTNET_EXE - Dotnet executable
+# DOTNET_VERSION - Dotnet version as reported by dotnet executable
+# NUGET_EXE - Nuget executable (WIN32 only)
+# NUGET_CACHE_PATH - Nuget package cache path
+#
+# The following functions are defined to add dotnet/msbuild projects:
+#
+# ADD_DOTNET -- add a project to be built by dotnet.
+#
+# ```
+# ADD_DOTNET( [RELEASE|DEBUG] [X86|X64|ANYCPU] [NETCOREAPP]
+# [CONFIG configuration]
+# [PLATFORM platform]
+# [PACKAGE output_nuget_packages... ]
+# [VERSION nuget_package_version]
+# [DEPENDS depend_nuget_packages... ]
+# [OUTPUT_PATH output_path relative to cmake binary output dir]
+# [CUSTOM_BUILDPROPS value....]
+# [SOURCES additional_file_dependencies... ]
+# [ARGUMENTS additional_build_args...]
+# [PACK_ARGUMENTS additional_pack_args...])
+# ```
+#
+# RUN_DOTNET -- Run a project with `dotnet run`. The `OUTPUT` argument represents artifacts
+# produced by running the .NET program, and can be consumed from other build steps.
+#
+# ```
+# RUN_DOTNET( [RELEASE|DEBUG] [X86|X64|ANYCPU] [NETCOREAPP]
+# [ARGUMENTS program_args...]
+# [OUTPUT outputs...]
+# [CONFIG configuration]
+# [PLATFORM platform]
+# [DEPENDS depend_nuget_packages... ]
+# [OUTPUT_PATH output_path relative to cmake binary output dir]
+# [CUSTOM_BUILDPROPS value....]
+# [SOURCES additional_file_dependencies... ])
+# ```
+#
+# ADD_MSBUILD -- add a project to be built by msbuild. Windows-only. When building in Unix systems, msbuild targets are skipped.
+#
+# ```
+# ADD_MSBUILD( [RELEASE|DEBUG] [X86|X64|ANYCPU] [NETCOREAPP]
+# [CONFIG configuration]
+# [PLATFORM platform]
+# [PACKAGE output_nuget_packages... ]
+# [DEPENDS depend_nuget_packages... ]
+# [CUSTOM_BUILDPROPS value....]
+# [SOURCES additional_file_dependencies... ]
+# [ARGUMENTS additional_build_args...]
+# [PACK_ARGUMENTS additional_pack_args...])
+# ```
+#
+# SMOKETEST_DOTNET -- add a dotnet smoke test project to the build. The project will be run during a build,
+# and if the program fails to build or run, the build fails. Currently only .NET Core App framework is supported.
+# Multiple smoke tests will be run one-by-one to avoid global resource conflicts.
+#
+# SMOKETEST_DOTNET( [RELEASE|DEBUG] [X86|X64|ANYCPU] [NETCOREAPP]
+# [ARGUMENTS program_args...]
+# [CONFIG configuration]
+# [PLATFORM platform]
+# [DEPENDS depend_nuget_packages... ]
+# [OUTPUT_PATH output_path relative to cmake binary output dir]
+# [CUSTOM_BUILDPROPS value....]
+# [SOURCES additional_file_dependencies... ])
+#
+# For all the above functions, `RELEASE|DEBUG` overrides `CONFIG`, `X86|X64|ANYCPU` overrides PLATFORM.
+# For Unix systems, the target framework defaults to `netstandard2.0`, unless `NETCOREAPP` is specified.
+# For Windows, the project is built as-is, allowing multi-targeting.
+#
+#
+# DOTNET_REGISTER_LOCAL_REPOSITORY -- register a local NuGet package repository.
+#
+# ```
+# DOTNET_REGISTER_LOCAL_REPOSITORY(repo_name repo_path)
+# ```
+#
+# TEST_DOTNET -- add a dotnet test project to ctest. The project will be run with `dotnet test`,
+# and trx test reports will be generated in the build directory. For Windows, all target frameworks
+# are tested against. For other platforms, only .NET Core App is tested against.
+# Test failures will not fail the build.
+# Tests are only run with `ctest -C `, not with `cmake --build ...`
+#
+# ```
+# TEST_DOTNET(
+# [ARGUMENTS additional_dotnet_test_args...]
+# [OUTPUT_PATH output_path relative to cmake binary output dir])
+# ```
+#
+# GEN_DOTNET_PROPS -- Generates a Directory.Build.props file. The created file is populated with MSBuild properties:
+# - DOTNET_PACKAGE_VERSION: a version string that can be referenced in the actual project file as $(DOTNET_PACKAGE_VERSION).
+# The version string value can be set with PACKAGE_VERSION argument, and defaults to '1.0.0'.
+# - XPLAT_LIB_DIR: points to the cmake build root directory.
+# - OutputPath: Points to the cmake binary directory (overridden by OUTPUT_PATH, relatively). Therefore, projects built without cmake will consistently output
+# to the cmake build directory.
+# - Custom properties can be injected with XML_INJECT argument, which injects an arbitrary string into the project XML file.
+#
+# ```
+# GEN_DOTNET_PROPS(
+# [PACKAGE_VERSION version]
+# [XML_INJECT xml_injection])
+# ```
+#
+# Require 3.5 for batch copy multiple files
+
+cmake_minimum_required(VERSION 3.5.0)
+
+IF(DOTNET_FOUND)
+ RETURN()
+ENDIF()
+
+SET(NUGET_CACHE_PATH "~/.nuget/packages")
+FIND_PROGRAM(DOTNET_EXE dotnet)
+SET(DOTNET_MODULE_DIR ${CMAKE_CURRENT_LIST_DIR})
+
+IF(NOT DOTNET_EXE)
+ SET(DOTNET_FOUND FALSE)
+ IF(Dotnet_FIND_REQUIRED)
+ MESSAGE(SEND_ERROR "Command 'dotnet' is not found.")
+ ENDIF()
+ RETURN()
+ENDIF()
+
+EXECUTE_PROCESS(
+ COMMAND ${DOTNET_EXE} --version
+ OUTPUT_VARIABLE DOTNET_VERSION
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+)
+
+IF(WIN32)
+ FIND_PROGRAM(NUGET_EXE nuget PATHS ${CMAKE_BINARY_DIR}/tools)
+ IF(NUGET_EXE)
+ MESSAGE("-- Found nuget: ${NUGET_EXE}")
+ ELSE()
+ SET(NUGET_EXE ${CMAKE_BINARY_DIR}/tools/nuget.exe)
+ MESSAGE("-- Downloading nuget...")
+ FILE(DOWNLOAD https://dist.nuget.org/win-x86-commandline/latest/nuget.exe ${NUGET_EXE})
+ MESSAGE("nuget.exe downloaded and saved to ${NUGET_EXE}")
+ ENDIF()
+ENDIF()
+
+FUNCTION(DOTNET_REGISTER_LOCAL_REPOSITORY repo_name repo_path)
+ MESSAGE("-- Registering NuGet local repository '${repo_name}' at '${repo_path}'.")
+ GET_FILENAME_COMPONENT(repo_path ${repo_path} ABSOLUTE)
+ IF(WIN32)
+ STRING(REPLACE "/" "\\" repo_path ${repo_path})
+ EXECUTE_PROCESS(COMMAND ${NUGET_EXE} sources list OUTPUT_QUIET)
+ EXECUTE_PROCESS(COMMAND ${NUGET_EXE} sources Remove -Name "${repo_name}" OUTPUT_QUIET ERROR_QUIET)
+ EXECUTE_PROCESS(COMMAND ${NUGET_EXE} sources Add -Name "${repo_name}" -Source "${repo_path}")
+ ELSE()
+ GET_FILENAME_COMPONENT(nuget_config ~/.nuget/NuGet/NuGet.Config ABSOLUTE)
+ EXECUTE_PROCESS(COMMAND ${DOTNET_EXE} nuget locals all --list OUTPUT_QUIET)
+ EXECUTE_PROCESS(COMMAND sed -i "/${repo_name}/d" "${nuget_config}")
+ EXECUTE_PROCESS(COMMAND sed -i "s## \\n #g" "${nuget_config}")
+ ENDIF()
+ENDFUNCTION()
+
+FUNCTION(DOTNET_GET_DEPS _DN_PROJECT arguments)
+ CMAKE_PARSE_ARGUMENTS(
+ # prefix
+ _DN
+ # options (flags)
+ "RELEASE;DEBUG;X86;X64;ANYCPU;NETCOREAPP"
+ # oneValueArgs
+ "CONFIG;PLATFORM;VERSION;OUTPUT_PATH"
+ # multiValueArgs
+ "PACKAGE;DEPENDS;ARGUMENTS;PACK_ARGUMENTS;OUTPUT;SOURCES;CUSTOM_BUILDPROPS"
+ # the input arguments
+ ${arguments})
+
+ GET_FILENAME_COMPONENT(_DN_abs_proj "${_DN_PROJECT}" ABSOLUTE)
+ GET_FILENAME_COMPONENT(_DN_proj_dir "${_DN_abs_proj}" DIRECTORY)
+ GET_FILENAME_COMPONENT(_DN_projname "${_DN_PROJECT}" NAME)
+ STRING(REGEX REPLACE "\\.[^.]*$" "" _DN_projname_noext ${_DN_projname})
+
+ FILE(GLOB_RECURSE DOTNET_deps
+ ${_DN_proj_dir}/*.cs
+ ${_DN_proj_dir}/*.fs
+ ${_DN_proj_dir}/*.vb
+ ${_DN_proj_dir}/*.xaml
+ ${_DN_proj_dir}/*.resx
+ ${_DN_proj_dir}/*.xml
+ ${_DN_proj_dir}/*.*proj
+ ${_DN_proj_dir}/*.cs
+ ${_DN_proj_dir}/*.config)
+ LIST(APPEND DOTNET_deps ${_DN_SOURCES})
+ SET(_DN_deps "")
+ FOREACH(dep ${DOTNET_deps})
+ IF(NOT dep MATCHES /obj/ AND NOT dep MATCHES /bin/)
+ LIST(APPEND _DN_deps ${dep})
+ ENDIF()
+ ENDFOREACH()
+
+
+ IF(_DN_RELEASE)
+ SET(_DN_CONFIG Release)
+ ELSEIF(_DN_DEBUG)
+ SET(_DN_CONFIG Debug)
+ ENDIF()
+
+ IF(NOT _DN_CONFIG)
+ SET(_DN_CONFIG "$<$:Debug>$<$>:Release>")
+ ENDIF()
+
+ # If platform is not specified, do not pass the Platform property.
+ # dotnet will pick the default Platform.
+
+ IF(_DN_X86)
+ SET(_DN_PLATFORM x86)
+ ELSEIF(_DN_X64)
+ SET(_DN_PLATFORM x64)
+ ELSEIF(_DN_ANYCPU)
+ SET(_DN_PLATFORM "AnyCPU")
+ ENDIF()
+
+ # If package version is not set, first fallback to DOTNET_PACKAGE_VERSION
+ # If again not set, defaults to 1.0.0
+ IF(NOT _DN_VERSION)
+ SET(_DN_VERSION ${DOTNET_PACKAGE_VERSION})
+ ENDIF()
+ IF(NOT _DN_VERSION)
+ SET(_DN_VERSION "1.0.0")
+ ENDIF()
+
+ # Set the output path to the binary directory.
+ # Build outputs in separated output directories prevent overwriting.
+ # Later we then copy the outputs to the destination.
+
+ IF(NOT _DN_OUTPUT_PATH)
+ SET(_DN_OUTPUT_PATH ${_DN_projname_noext})
+ ENDIF()
+
+ GET_FILENAME_COMPONENT(_DN_OUTPUT_PATH ${CMAKE_BINARY_DIR}/${_DN_OUTPUT_PATH} ABSOLUTE)
+
+ # In a cmake build, the XPLAT libraries are always copied over.
+ # Set the proper directory for .NET projects.
+ SET(_DN_XPLAT_LIB_DIR ${CMAKE_BINARY_DIR})
+
+ SET(DOTNET_PACKAGES ${_DN_PACKAGE} PARENT_SCOPE)
+ SET(DOTNET_CONFIG ${_DN_CONFIG} PARENT_SCOPE)
+ SET(DOTNET_PLATFORM ${_DN_PLATFORM} PARENT_SCOPE)
+ SET(DOTNET_DEPENDS ${_DN_DEPENDS} PARENT_SCOPE)
+ SET(DOTNET_PROJNAME ${_DN_projname_noext} PARENT_SCOPE)
+ SET(DOTNET_PROJPATH ${_DN_abs_proj} PARENT_SCOPE)
+ SET(DOTNET_PROJDIR ${_DN_proj_dir} PARENT_SCOPE)
+ SET(DOTNET_ARGUMENTS ${_DN_ARGUMENTS} PARENT_SCOPE)
+ SET(DOTNET_RUN_OUTPUT ${_DN_OUTPUT} PARENT_SCOPE)
+ SET(DOTNET_PACKAGE_VERSION ${_DN_VERSION} PARENT_SCOPE)
+ SET(DOTNET_OUTPUT_PATH ${_DN_OUTPUT_PATH} PARENT_SCOPE)
+ SET(DOTNET_deps ${_DN_deps} PARENT_SCOPE)
+
+ IF(_DN_PLATFORM)
+ SET(_DN_PLATFORM_PROP "/p:Platform=${_DN_PLATFORM}")
+ ENDIF()
+
+ IF(_DN_NETCOREAPP)
+ SET(_DN_BUILD_OPTIONS -f netcoreapp2.0)
+ SET(_DN_PACK_OPTIONS /p:TargetFrameworks=netcoreapp2.0)
+ ELSEIF(UNIX)
+ # Unix builds default to netstandard2.0
+ SET(_DN_BUILD_OPTIONS -f netstandard2.0)
+ SET(_DN_PACK_OPTIONS /p:TargetFrameworks=netstandard2.0)
+ ENDIF()
+
+ SET(_DN_IMPORT_PROP ${CMAKE_CURRENT_BINARY_DIR}/${_DN_projname}.imports.props)
+ CONFIGURE_FILE(${DOTNET_MODULE_DIR}/DotnetImports.props.in ${_DN_IMPORT_PROP})
+ SET(_DN_IMPORT_ARGS "/p:DirectoryBuildPropsPath=${_DN_IMPORT_PROP}")
+
+ SET(DOTNET_IMPORT_PROPERTIES ${_DN_IMPORT_ARGS} PARENT_SCOPE)
+ SET(DOTNET_BUILD_PROPERTIES ${_DN_PLATFORM_PROP} ${_DN_IMPORT_ARGS} PARENT_SCOPE)
+ SET(DOTNET_BUILD_OPTIONS ${_DN_BUILD_OPTIONS} PARENT_SCOPE)
+ SET(DOTNET_PACK_OPTIONS --include-symbols ${_DN_PACK_OPTIONS} ${_DN_PACK_ARGUMENTS} PARENT_SCOPE)
+
+ENDFUNCTION()
+
+MACRO(ADD_DOTNET_DEPENDENCY_TARGETS tgt)
+ FOREACH(pkg_dep ${DOTNET_DEPENDS})
+ ADD_DEPENDENCIES(${tgt}_${DOTNET_PROJNAME} PKG_${pkg_dep})
+ MESSAGE(" ${DOTNET_PROJNAME} <- ${pkg_dep}")
+ ENDFOREACH()
+
+ FOREACH(pkg ${DOTNET_PACKAGES})
+ STRING(TOLOWER ${pkg} pkg_lowercase)
+ GET_FILENAME_COMPONENT(cache_path ${NUGET_CACHE_PATH}/${pkg_lowercase} ABSOLUTE)
+ IF(WIN32)
+ SET(rm_command powershell -NoLogo -NoProfile -NonInteractive -Command "Remove-Item -Recurse -Force -ErrorAction Ignore '${cache_path}'\; exit 0")
+ ELSE()
+ SET(rm_command rm -rf ${cache_path})
+ ENDIF()
+ ADD_CUSTOM_TARGET(
+ DOTNET_PURGE_${pkg}
+ COMMAND ${CMAKE_COMMAND} -E echo "======= [x] Purging nuget package cache for ${pkg}"
+ COMMAND ${rm_command}
+ DEPENDS ${DOTNET_deps}
+ )
+ ADD_DEPENDENCIES(${tgt}_${DOTNET_PROJNAME} DOTNET_PURGE_${pkg})
+ # Add a target for the built package -- this can be referenced in
+ # another project.
+ ADD_CUSTOM_TARGET(PKG_${pkg})
+ ADD_DEPENDENCIES(PKG_${pkg} ${tgt}_${DOTNET_PROJNAME})
+ MESSAGE("==== ${DOTNET_PROJNAME} -> ${pkg}")
+ ENDFOREACH()
+ENDMACRO()
+
+MACRO(DOTNET_BUILD_COMMANDS)
+ IF(${DOTNET_IS_MSBUILD})
+ SET(build_dotnet_cmds
+ COMMAND ${CMAKE_COMMAND} -E echo "======= Building msbuild project ${DOTNET_PROJNAME} [${DOTNET_CONFIG} ${DOTNET_PLATFORM}]"
+ COMMAND ${NUGET_EXE} restore -Force ${DOTNET_PROJPATH}
+ COMMAND ${DOTNET_EXE} msbuild ${DOTNET_PROJPATH} /t:Clean ${DOTNET_BUILD_PROPERTIES} /p:Configuration="${DOTNET_CONFIG}"
+ COMMAND ${DOTNET_EXE} msbuild ${DOTNET_PROJPATH} /t:Build ${DOTNET_BUILD_PROPERTIES} /p:Configuration="${DOTNET_CONFIG}" ${DOTNET_ARGUMENTS})
+ SET(build_dotnet_type "msbuild")
+ ELSE()
+ SET(build_dotnet_cmds
+ COMMAND ${CMAKE_COMMAND} -E echo "======= Building .NET project ${DOTNET_PROJNAME} [${DOTNET_CONFIG} ${DOTNET_PLATFORM}]"
+ COMMAND ${DOTNET_EXE} restore ${DOTNET_PROJPATH} ${DOTNET_IMPORT_PROPERTIES}
+ COMMAND ${DOTNET_EXE} clean ${DOTNET_PROJPATH} ${DOTNET_BUILD_PROPERTIES}
+ COMMAND ${DOTNET_EXE} build --no-restore ${DOTNET_PROJPATH} -c ${DOTNET_CONFIG} ${DOTNET_BUILD_PROPERTIES} ${DOTNET_BUILD_OPTIONS} ${DOTNET_ARGUMENTS})
+ SET(build_dotnet_type "dotnet")
+ ENDIF()
+
+ # DOTNET_OUTPUTS refer to artifacts produced, that the BUILD_proj_name target depends on.
+ SET(DOTNET_OUTPUTS ${CMAKE_CURRENT_BINARY_DIR}/${DOTNET_PROJNAME}.buildtimestamp)
+ LIST(APPEND build_dotnet_cmds COMMAND ${CMAKE_COMMAND} -E touch ${DOTNET_OUTPUTS})
+ IF(NOT "${DOTNET_PACKAGES}" STREQUAL "")
+ MESSAGE("-- Adding ${build_dotnet_type} project ${DOTNET_PROJPATH} (version ${DOTNET_PACKAGE_VERSION})")
+ FOREACH(pkg ${DOTNET_PACKAGES})
+ LIST(APPEND DOTNET_OUTPUTS ${DOTNET_OUTPUT_PATH}/${pkg}.${DOTNET_PACKAGE_VERSION}.nupkg)
+ LIST(APPEND DOTNET_OUTPUTS ${DOTNET_OUTPUT_PATH}/${pkg}.${DOTNET_PACKAGE_VERSION}.symbols.nupkg)
+ LIST(APPEND build_dotnet_cmds COMMAND ${CMAKE_COMMAND} -E remove ${DOTNET_OUTPUT_PATH}/${pkg}.${DOTNET_PACKAGE_VERSION}.nupkg)
+ LIST(APPEND build_dotnet_cmds COMMAND ${CMAKE_COMMAND} -E remove ${DOTNET_OUTPUT_PATH}/${pkg}.${DOTNET_PACKAGE_VERSION}.symbols.nupkg)
+ ENDFOREACH()
+ LIST(APPEND build_dotnet_cmds COMMAND ${DOTNET_EXE} pack --no-build --no-restore ${DOTNET_PROJPATH} -c ${DOTNET_CONFIG} ${DOTNET_BUILD_PROPERTIES} ${DOTNET_PACK_OPTIONS})
+ ELSE()
+ MESSAGE("-- Adding ${build_dotnet_type} project ${DOTNET_PROJPATH} (no nupkg)")
+ ENDIF()
+
+ ADD_CUSTOM_COMMAND(
+ OUTPUT ${DOTNET_OUTPUTS}
+ DEPENDS ${DOTNET_deps}
+ ${build_dotnet_cmds}
+ )
+ ADD_CUSTOM_TARGET(
+ BUILD_${DOTNET_PROJNAME} ALL
+ DEPENDS ${DOTNET_OUTPUTS})
+
+ENDMACRO()
+
+FUNCTION(ADD_DOTNET DOTNET_PROJECT)
+ DOTNET_GET_DEPS(${DOTNET_PROJECT} "${ARGN}")
+ SET(DOTNET_IS_MSBUILD FALSE)
+ DOTNET_BUILD_COMMANDS()
+ ADD_DOTNET_DEPENDENCY_TARGETS(BUILD)
+ENDFUNCTION()
+
+FUNCTION(ADD_MSBUILD DOTNET_PROJECT)
+ IF(NOT WIN32)
+ MESSAGE("-- Building non-Win32, skipping ${DOTNET_PROJECT}")
+ RETURN()
+ ENDIF()
+
+ DOTNET_GET_DEPS(${DOTNET_PROJECT} "${ARGN}")
+ SET(DOTNET_IS_MSBUILD TRUE)
+ DOTNET_BUILD_COMMANDS()
+ ADD_DOTNET_DEPENDENCY_TARGETS(BUILD)
+ENDFUNCTION()
+
+FUNCTION(RUN_DOTNET DOTNET_PROJECT)
+ DOTNET_GET_DEPS(${DOTNET_PROJECT} "${ARGN};NETCOREAPP")
+ MESSAGE("-- Adding dotnet run project ${DOTNET_PROJECT}")
+ FILE(MAKE_DIRECTORY ${DOTNET_OUTPUT_PATH})
+ ADD_CUSTOM_COMMAND(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${DOTNET_PROJNAME}.runtimestamp ${DOTNET_RUN_OUTPUT}
+ DEPENDS ${DOTNET_deps}
+ COMMAND ${DOTNET_EXE} restore ${DOTNET_PROJPATH} ${DOTNET_IMPORT_PROPERTIES}
+ COMMAND ${DOTNET_EXE} clean ${DOTNET_PROJPATH} ${DOTNET_BUILD_PROPERTIES}
+ COMMAND ${DOTNET_EXE} build --no-restore ${DOTNET_PROJPATH} -c ${DOTNET_CONFIG} ${DOTNET_BUILD_PROPERTIES} ${DOTNET_BUILD_OPTIONS}
+ # XXX tfm
+ COMMAND ${DOTNET_EXE} ${DOTNET_OUTPUT_PATH}/netcoreapp2.0/${DOTNET_PROJNAME}.dll ${DOTNET_ARGUMENTS}
+ COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/${DOTNET_PROJNAME}.runtimestamp
+ WORKING_DIRECTORY ${DOTNET_OUTPUT_PATH})
+ ADD_CUSTOM_TARGET(
+ RUN_${DOTNET_PROJNAME}
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${DOTNET_PROJNAME}.runtimestamp ${DOTNET_RUN_OUTPUT})
+ ADD_DOTNET_DEPENDENCY_TARGETS(RUN)
+ENDFUNCTION()
+
+FUNCTION(TEST_DOTNET DOTNET_PROJECT)
+ DOTNET_GET_DEPS(${DOTNET_PROJECT} "${ARGN}")
+ MESSAGE("-- Adding dotnet test project ${DOTNET_PROJECT}")
+ IF(WIN32)
+ SET(test_framework_args "")
+ ELSE()
+ SET(test_framework_args -f netcoreapp2.0)
+ ENDIF()
+
+ ADD_TEST(NAME ${DOTNET_PROJNAME}
+ COMMAND ${DOTNET_EXE} test ${test_framework_args} --results-directory "${CMAKE_BINARY_DIR}" --logger trx ${DOTNET_ARGUMENTS}
+ WORKING_DIRECTORY ${DOTNET_OUTPUT_PATH})
+
+ENDFUNCTION()
+
+SET_PROPERTY(GLOBAL PROPERTY DOTNET_LAST_SMOKETEST "")
+
+FUNCTION(SMOKETEST_DOTNET DOTNET_PROJECT)
+ MESSAGE("-- Adding dotnet smoke test project ${DOTNET_PROJECT}")
+ IF(WIN32)
+ RUN_DOTNET(${DOTNET_PROJECT} "${ARGN}")
+ ELSE()
+ RUN_DOTNET(${DOTNET_PROJECT} "${ARGN}")
+ ENDIF()
+
+ DOTNET_GET_DEPS(${DOTNET_PROJECT} "${ARGN}")
+ ADD_CUSTOM_TARGET(
+ SMOKETEST_${DOTNET_PROJNAME}
+ ALL
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${DOTNET_PROJNAME}.runtimestamp)
+ ADD_DOTNET_DEPENDENCY_TARGETS(SMOKETEST)
+ GET_PROPERTY(_dn_last_smoketest GLOBAL PROPERTY DOTNET_LAST_SMOKETEST)
+ IF(_dn_last_smoketest)
+ MESSAGE("${_dn_last_smoketest} -> SMOKETEST_${DOTNET_PROJNAME}")
+ ADD_DEPENDENCIES(SMOKETEST_${DOTNET_PROJNAME} ${_dn_last_smoketest})
+ ENDIF()
+ # Chain the smoke tests together so they are executed sequentially
+ SET_PROPERTY(GLOBAL PROPERTY DOTNET_LAST_SMOKETEST SMOKETEST_${DOTNET_PROJNAME})
+
+ENDFUNCTION()
+
+SET(DOTNET_IMPORTS_TEMPLATE ${CMAKE_CURRENT_LIST_DIR}/DotnetImports.props.in)
+
+FUNCTION(GEN_DOTNET_PROPS target_props_file)
+ CMAKE_PARSE_ARGUMENTS(
+ # prefix
+ _DNP
+ # options (flags)
+ ""
+ # oneValueArgs
+ "PACKAGE_VERSION;XML_INJECT"
+ # multiValueArgs
+ ""
+ # the input arguments
+ ${ARGN})
+
+ IF(NOT _DNP_PACKAGE_VERSION)
+ SET(_DNP_PACKAGE_VERSION 1.0.0)
+ ENDIF()
+
+ IF(_DNP_XML_INJECT)
+ SET(_DN_CUSTOM_BUILDPROPS ${_DNP_XML_INJECT})
+ ENDIF()
+
+ SET(_DN_OUTPUT_PATH ${CMAKE_BINARY_DIR})
+ SET(_DN_XPLAT_LIB_DIR ${CMAKE_BINARY_DIR})
+ SET(_DN_VERSION ${_DNP_PACKAGE_VERSION})
+ CONFIGURE_FILE(${DOTNET_IMPORTS_TEMPLATE} ${target_props_file})
+ UNSET(_DN_OUTPUT_PATH)
+ UNSET(_DN_XPLAT_LIB_DIR)
+ UNSET(_DN_VERSION)
+ENDFUNCTION()
+
+
+MESSAGE("-- Found .NET toolchain: ${DOTNET_EXE} (version ${DOTNET_VERSION})")
+SET(DOTNET_FOUND TRUE)
diff --git a/contrib/ci/Dockerfiles/z3_base_ubuntu32_16.04.Dockerfile b/contrib/ci/Dockerfiles/z3_base_ubuntu32_16.04.Dockerfile
index 87e3c8d67..6012bb25f 100644
--- a/contrib/ci/Dockerfiles/z3_base_ubuntu32_16.04.Dockerfile
+++ b/contrib/ci/Dockerfiles/z3_base_ubuntu32_16.04.Dockerfile
@@ -32,7 +32,6 @@ RUN apt-get update && \
libomp-dev \
llvm-3.9 \
make \
- mono-devel \
ninja-build \
python3 \
python3-setuptools \
@@ -48,4 +47,6 @@ RUN useradd -m user && \
echo 'user ALL=(root) NOPASSWD: ALL' >> /etc/sudoers
USER user
WORKDIR /home/user
-ENV ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-3.9/bin/llvm-symbolizer
+# TODO .NET core does not support Linux x86 yet, disable it for now.
+# see: https://github.com/dotnet/coreclr/issues/9265
+ENV ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-3.9/bin/llvm-symbolizer DOTNET_BINDINGS=0
diff --git a/contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile b/contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile
index c963ce255..9c6bdc054 100644
--- a/contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile
+++ b/contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile
@@ -2,9 +2,10 @@ FROM ubuntu:14.04
RUN apt-get update && \
apt-get -y --no-install-recommends install \
+ apt-transport-https \
binutils \
clang-3.9 \
- cmake \
+ curl \
doxygen \
default-jdk \
gcc-multilib \
@@ -18,13 +19,20 @@ RUN apt-get update && \
lib32gomp1 \
llvm-3.9 \
make \
- mono-devel \
ninja-build \
python3 \
python3-setuptools \
python2.7 \
python-setuptools
+RUN curl -SL https://packages.microsoft.com/config/ubuntu/14.04/packages-microsoft-prod.deb --output packages-microsoft-prod.deb && \
+ dpkg -i packages-microsoft-prod.deb && \
+ apt-get update && \
+ apt-get -y --no-install-recommends install dotnet-sdk-2.1
+
+RUN curl -SL https://cmake.org/files/v3.12/cmake-3.12.0-Linux-x86_64.sh --output cmake-3.12.0-Linux-x86_64.sh && \
+ sh cmake-3.12.0-Linux-x86_64.sh --prefix=/usr/local --exclude-subdir
+
# Create `user` user for container with password `user`. and give it
# password-less sudo access
RUN useradd -m user && \
diff --git a/contrib/ci/Dockerfiles/z3_base_ubuntu_16.04.Dockerfile b/contrib/ci/Dockerfiles/z3_base_ubuntu_16.04.Dockerfile
index 08686e275..f4d9c873a 100644
--- a/contrib/ci/Dockerfiles/z3_base_ubuntu_16.04.Dockerfile
+++ b/contrib/ci/Dockerfiles/z3_base_ubuntu_16.04.Dockerfile
@@ -2,10 +2,12 @@ FROM ubuntu:16.04
RUN apt-get update && \
apt-get -y --no-install-recommends install \
+ apt-transport-https \
binutils \
clang \
clang-3.9 \
cmake \
+ curl \
doxygen \
default-jdk \
gcc-multilib \
@@ -20,7 +22,6 @@ RUN apt-get update && \
libomp-dev \
llvm-3.9 \
make \
- mono-devel \
ninja-build \
python3 \
python3-setuptools \
@@ -28,6 +29,11 @@ RUN apt-get update && \
python-setuptools \
sudo
+RUN curl -SL https://packages.microsoft.com/config/ubuntu/16.04/packages-microsoft-prod.deb --output packages-microsoft-prod.deb && \
+ dpkg -i packages-microsoft-prod.deb && \
+ apt-get update && \
+ apt-get -y --no-install-recommends install dotnet-sdk-2.1
+
# Create `user` user for container with password `user`. and give it
# password-less sudo access
RUN useradd -m user && \
diff --git a/contrib/ci/scripts/test_z3_examples_cmake.sh b/contrib/ci/scripts/test_z3_examples_cmake.sh
index 687efebb4..a149a1d83 100755
--- a/contrib/ci/scripts/test_z3_examples_cmake.sh
+++ b/contrib/ci/scripts/test_z3_examples_cmake.sh
@@ -88,11 +88,14 @@ if [ "X${PYTHON_BINDINGS}" = "X1" ]; then
fi
if [ "X${DOTNET_BINDINGS}" = "X1" ]; then
- # Build .NET example
- # FIXME: Move compliation step into CMake target
- mcs ${Z3_SRC_DIR}/examples/dotnet/Program.cs /target:exe /out:dotnet_test.exe /reference:Microsoft.Z3.dll /r:System.Numerics.dll
# Run .NET example
- run_quiet run_non_native_binding mono ./dotnet_test.exe
+ if [ "X${ASAN_BUILD}" = "X1" ]; then
+ # The dotnet test get stuck on ASAN
+ # so don't run it for now.
+ echo "Skipping .NET example under ASan build"
+ else
+ run_quiet run_non_native_binding dotnet ${Z3_BUILD_DIR}/dotnet/netcoreapp2.0/dotnet.dll
+ fi
fi
if [ "X${JAVA_BINDINGS}" = "X1" ]; then
diff --git a/contrib/qprofdiff/main.cpp b/contrib/qprofdiff/main.cpp
index 58d21b77d..9a78249c2 100644
--- a/contrib/qprofdiff/main.cpp
+++ b/contrib/qprofdiff/main.cpp
@@ -78,10 +78,13 @@ int parse(string const & filename, map & data) {
entry.num_instances = entry.max_generation = entry.max_cost = 0;
}
+ // Existing entries represent previous occurrences of quantifiers
+ // that, at some point, were removed (e.g. backtracked). We sum
+ // up instances from all occurrences of the same qid.
map_entry & entry = data[qid];
- entry.num_instances = atoi(tokens[1].c_str());
- entry.max_generation = (unsigned)atoi(tokens[2].c_str());
- entry.max_cost = (unsigned)atoi(tokens[3].c_str());
+ entry.num_instances += atoi(tokens[1].c_str());
+ entry.max_generation = max(entry.max_generation, (unsigned)atoi(tokens[2].c_str()));
+ entry.max_cost = max(entry.max_cost, (unsigned)atoi(tokens[3].c_str()));
}
}
@@ -205,7 +208,7 @@ void diff(map & left, map & right) {
}
stable_sort(flat_data.begin(), flat_data.end(),
- options.find("-si") != options.end() ? diff_item_lt_num_instances:
+ options.find("-si") != options.end() ? diff_item_lt_num_instances :
options.find("-sg") != options.end() ? diff_item_lt_max_generation :
options.find("-sc") != options.end() ? diff_item_lt_max_cost :
diff_item_lt_num_instances);
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 6c50320ed..5d06029f9 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -112,3 +112,10 @@ set_target_properties(z3_tptp5 PROPERTIES EXCLUDE_FROM_ALL TRUE)
if (BUILD_PYTHON_BINDINGS)
add_subdirectory(python)
endif()
+
+################################################################################
+# Build dotnet examples
+################################################################################
+if (BUILD_DOTNET_BINDINGS)
+ add_subdirectory(dotnet)
+endif()
\ No newline at end of file
diff --git a/examples/c++/example.cpp b/examples/c++/example.cpp
index ab9c73209..f93045c9d 100644
--- a/examples/c++/example.cpp
+++ b/examples/c++/example.cpp
@@ -1166,6 +1166,14 @@ static void parse_example() {
// expr b = c.parse_string("(benchmark tst :extrafuns ((x Int) (y Int)) :formula (> x y) :formula (> x 0))");
}
+static void parse_string() {
+ std::cout << "parse string\n";
+ z3::context c;
+ z3::solver s(c);
+ s.from_string("(declare-const x Int)(assert (> x 10))");
+ std::cout << s.check() << "\n";
+}
+
void mk_model_example() {
context c;
@@ -1252,6 +1260,7 @@ int main() {
sudoku_example(); std::cout << "\n";
consequence_example(); std::cout << "\n";
parse_example(); std::cout << "\n";
+ parse_string(); std::cout << "\n";
mk_model_example(); std::cout << "\n";
recfun_example(); std::cout << "\n";
std::cout << "done\n";
diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c
index 980592f25..f9c108b92 100644
--- a/examples/c/test_capi.c
+++ b/examples/c/test_capi.c
@@ -1697,7 +1697,7 @@ void parser_example3()
LOG_MSG("parser_example3");
cfg = Z3_mk_config();
- /* See quantifer_example1 */
+ /* See quantifier_example1 */
Z3_set_param_value(cfg, "model", "true");
ctx = mk_context_custom(cfg, error_handler);
Z3_del_config(cfg);
diff --git a/examples/dotnet/CMakeLists.txt b/examples/dotnet/CMakeLists.txt
new file mode 100644
index 000000000..108326f83
--- /dev/null
+++ b/examples/dotnet/CMakeLists.txt
@@ -0,0 +1,34 @@
+find_package(Dotnet REQUIRED)
+
+if("${TARGET_ARCHITECTURE}" STREQUAL "i686")
+ set(Z3_DOTNET_PLATFORM "x86")
+else()
+ set(Z3_DOTNET_PLATFORM "AnyCPU")
+endif()
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/dotnet.csproj dotnet.csproj COPYONLY)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Program.cs Program.cs COPYONLY)
+
+ADD_DOTNET(${CMAKE_CURRENT_BINARY_DIR}/dotnet.csproj
+ PLATFORM ${Z3_DOTNET_PLATFORM}
+ NETCOREAPP
+ CUSTOM_BUILDPROPS "${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}.${Z3_VERSION_PATCH}"
+ DEPENDS Microsoft.Z3)
+
+if(UNIX AND NOT APPLE)
+ set(z3_dotnet_native_lib ${CMAKE_BINARY_DIR}/libz3.so)
+ set(z3_dotnet_test_manual_copy_deps
+ ${CMAKE_BINARY_DIR}/Microsoft.Z3/netstandard2.0/Microsoft.Z3.dll
+ ${z3_dotnet_native_lib}
+ )
+
+ add_custom_target(
+ z3_dotnet_test_manual_copy_assembly_hack ALL
+ COMMAND ${CMAKE_COMMAND} -E copy ${z3_dotnet_test_manual_copy_deps} ${CMAKE_BINARY_DIR}/dotnet/netcoreapp2.0/
+ # hack the libz3 entry in deps so it's easy enough for dotnet to reach it...
+ COMMAND sed \"s/runtimes\\/.*libz3\\.so/libz3.so/\" -i ${CMAKE_BINARY_DIR}/dotnet/netcoreapp2.0/dotnet.deps.json
+ )
+
+ add_dependencies(z3_dotnet_test_manual_copy_assembly_hack BUILD_dotnet)
+endif()
+
diff --git a/examples/dotnet/README b/examples/dotnet/README
index 3f7e989df..b42156761 100644
--- a/examples/dotnet/README
+++ b/examples/dotnet/README
@@ -1,7 +1,6 @@
Small example using the .Net bindings.
-This example is only built if you have Visual Studio.
To build the example execute
make examples
in the build directory.
-It will create the executable dotnet_example.exe
+It will create a .net core 2.0 app.
diff --git a/examples/dotnet/dotnet.csproj b/examples/dotnet/dotnet.csproj
new file mode 100644
index 000000000..7776259ea
--- /dev/null
+++ b/examples/dotnet/dotnet.csproj
@@ -0,0 +1,12 @@
+
+
+
+ Exe
+ netcoreapp2.0
+
+
+
+
+
+
+
diff --git a/examples/msf/SolverFoundation.Plugin.Z3/Z3MILPSolver.cs b/examples/msf/SolverFoundation.Plugin.Z3/Z3MILPSolver.cs
index f3a8f9f2c..4f8cdc759 100644
--- a/examples/msf/SolverFoundation.Plugin.Z3/Z3MILPSolver.cs
+++ b/examples/msf/SolverFoundation.Plugin.Z3/Z3MILPSolver.cs
@@ -33,14 +33,14 @@ namespace Microsoft.SolverFoundation.Plugin.Z3
#region Solver construction and destruction
- /// Constructor that initializes the base clases
+ /// Constructor that initializes the base classes
public Z3MILPSolver() : base(null)
{
_result = LinearResult.Feasible;
_solver = new Z3BaseSolver(this);
}
- /// Constructor that initializes the base clases
+ /// Constructor that initializes the base classes
public Z3MILPSolver(ISolverEnvironment context) : this() { }
///
diff --git a/examples/msf/SolverFoundation.Plugin.Z3/Z3TermSolver.cs b/examples/msf/SolverFoundation.Plugin.Z3/Z3TermSolver.cs
index 530df3394..de91c7b6e 100644
--- a/examples/msf/SolverFoundation.Plugin.Z3/Z3TermSolver.cs
+++ b/examples/msf/SolverFoundation.Plugin.Z3/Z3TermSolver.cs
@@ -29,13 +29,13 @@ namespace Microsoft.SolverFoundation.Plugin.Z3
private NonlinearResult _result;
private Z3BaseSolver _solver;
- /// Constructor that initializes the base clases
+ /// Constructor that initializes the base classes
public Z3TermSolver() : base(null)
{
_solver = new Z3BaseSolver(this);
}
- /// Constructor that initializes the base clases
+ /// Constructor that initializes the base classes
public Z3TermSolver(ISolverEnvironment context) : this() { }
///
diff --git a/examples/python/data/horn3.smt2 b/examples/python/data/horn3.smt2
new file mode 100644
index 000000000..873784e43
--- /dev/null
+++ b/examples/python/data/horn3.smt2
@@ -0,0 +1,17 @@
+(declare-rel Invariant (Bool))
+(declare-rel Goal ())
+(declare-var l0 Bool)
+(declare-var l2 Bool)
+(declare-var l4 Bool)
+(declare-var l6 Bool)
+(declare-var l8 Bool)
+(declare-var l10 Bool)
+(rule (=> (not (or l4)) (Invariant l4)))
+(rule (=> (and (Invariant l4)
+ (= (and (not l4) (not l2)) l6)
+ (= (and l4 l2) l8)
+ (= (and (not l8) (not l6)) l10)
+ ) (Invariant l10)))
+(rule (=> (and (Invariant l4)
+ l4) Goal))
+(query Goal)
diff --git a/examples/python/data/horn4.smt2 b/examples/python/data/horn4.smt2
new file mode 100644
index 000000000..0a64b41db
--- /dev/null
+++ b/examples/python/data/horn4.smt2
@@ -0,0 +1,99 @@
+(declare-rel Invariant (Bool Bool Bool Bool Bool Bool))
+(declare-rel Goal ())
+(declare-var l0 Bool)
+(declare-var l2 Bool)
+(declare-var l4 Bool)
+(declare-var l6 Bool)
+(declare-var l8 Bool)
+(declare-var l10 Bool)
+(declare-var l12 Bool)
+(declare-var l14 Bool)
+(declare-var l16 Bool)
+(declare-var l18 Bool)
+(declare-var l20 Bool)
+(declare-var l22 Bool)
+(declare-var l24 Bool)
+(declare-var l26 Bool)
+(declare-var l28 Bool)
+(declare-var l30 Bool)
+(declare-var l32 Bool)
+(declare-var l34 Bool)
+(declare-var l36 Bool)
+(declare-var l38 Bool)
+(declare-var l40 Bool)
+(declare-var l42 Bool)
+(declare-var l44 Bool)
+(declare-var l46 Bool)
+(declare-var l48 Bool)
+(declare-var l50 Bool)
+(declare-var l52 Bool)
+(declare-var l54 Bool)
+(declare-var l56 Bool)
+(declare-var l58 Bool)
+(declare-var l60 Bool)
+(declare-var l62 Bool)
+(declare-var l64 Bool)
+(declare-var l66 Bool)
+(declare-var l68 Bool)
+(declare-var l70 Bool)
+(declare-var l72 Bool)
+(declare-var l74 Bool)
+(declare-var l76 Bool)
+(declare-var l78 Bool)
+(declare-var l80 Bool)
+(declare-var l82 Bool)
+(declare-var l84 Bool)
+(declare-var l86 Bool)
+(rule (=> (not (or l4 l6 l8 l10 l12 l14)) (Invariant l4 l6 l8 l10 l12 l14)))
+(rule (=> (and (Invariant l4 l6 l8 l10 l12 l14)
+ (= (and l6 (not l4)) l16)
+ (= (and l10 (not l8)) l18)
+ (= (and l18 l16) l20)
+ (= (and (not l14) (not l12)) l22)
+ (= (and l22 l20) l24)
+ (= (and (not l24) (not l4)) l26)
+ (= (and (not l6) l4) l28)
+ (= (and (not l28) (not l16)) l30)
+ (= (and (not l30) (not l24)) l32)
+ (= (and l6 l4) l34)
+ (= (and (not l34) l8) l36)
+ (= (and l34 (not l8)) l38)
+ (= (and (not l38) (not l36)) l40)
+ (= (and (not l40) (not l24)) l42)
+ (= (and l34 l8) l44)
+ (= (and (not l44) l10) l46)
+ (= (and l44 (not l10)) l48)
+ (= (and (not l48) (not l46)) l50)
+ (= (and (not l50) (not l24)) l52)
+ (= (and l10 l8) l54)
+ (= (and l54 l34) l56)
+ (= (and (not l56) l12) l58)
+ (= (and l56 (not l12)) l60)
+ (= (and (not l60) (not l58)) l62)
+ (= (and (not l62) (not l24)) l64)
+ (= (and l56 l12) l66)
+ (= (and (not l66) l14) l68)
+ (= (and l66 (not l14)) l70)
+ (= (and (not l70) (not l68)) l72)
+ (= (and (not l72) (not l24)) l74)
+ (= (and l6 l4) l76)
+ (= (and (not l76) l18) l78)
+ (= (and (not l78) l10) l80)
+ (= (and (not l80) l22) l82)
+ (= (and (not l82) (not l24)) l84)
+ (= (and l84 (not l0)) l86)
+ ) (Invariant l26 l32 l42 l52 l64 l74)))
+(rule (=> (and (Invariant l4 l6 l8 l10 l12 l14)
+ (= (and l84 (not l0)) l86)
+ (= (and (not l82) (not l24)) l84)
+ (= (and (not l80) l22) l82)
+ (= (and (not l78) l10) l80)
+ (= (and (not l76) l18) l78)
+ (= (and l6 l4) l76)
+ (= (and l10 (not l8)) l18)
+ (= (and (not l14) (not l12)) l22)
+ (= (and l22 l20) l24)
+ (= (and l18 l16) l20)
+ (= (and l6 (not l4)) l16)
+ l86) Goal))
+(query Goal)
diff --git a/examples/python/data/horn5.smt2 b/examples/python/data/horn5.smt2
new file mode 100644
index 000000000..37642d517
--- /dev/null
+++ b/examples/python/data/horn5.smt2
@@ -0,0 +1,21 @@
+(declare-rel Invariant (Bool Bool Bool Bool))
+(declare-rel Goal ())
+(declare-var l0 Bool)
+(declare-var l2 Bool)
+(declare-var l4 Bool)
+(declare-var l6 Bool)
+(declare-var l8 Bool)
+(declare-var l10 Bool)
+(declare-var l12 Bool)
+(declare-var l14 Bool)
+(declare-var l16 Bool)
+(rule (=> (not (or l4 l6 l8 l10)) (Invariant l4 l6 l8 l10)))
+(rule (=> (and (Invariant l4 l6 l8 l10)
+ (= (and l6 l4) l12)
+ (= (and l12 l8) l14)
+ (= (and l10 (not l0)) l16)
+ ) (Invariant l12 l8 l0 l14)))
+(rule (=> (and (Invariant l4 l6 l8 l10)
+ (= (and l10 (not l0)) l16)
+ l16) Goal))
+(query Goal)
diff --git a/examples/python/data/horn6.smt2 b/examples/python/data/horn6.smt2
new file mode 100644
index 000000000..d90187e4d
--- /dev/null
+++ b/examples/python/data/horn6.smt2
@@ -0,0 +1,292 @@
+(declare-rel Invariant (Bool Bool Bool Bool Bool Bool Bool Bool Bool Bool Bool Bool Bool Bool Bool Bool Bool Bool Bool Bool Bool Bool Bool Bool Bool Bool Bool Bool Bool Bool Bool Bool Bool Bool))
+(declare-rel Goal ())
+(declare-var l0 Bool)
+(declare-var l2 Bool)
+(declare-var l4 Bool)
+(declare-var l6 Bool)
+(declare-var l8 Bool)
+(declare-var l10 Bool)
+(declare-var l12 Bool)
+(declare-var l14 Bool)
+(declare-var l16 Bool)
+(declare-var l18 Bool)
+(declare-var l20 Bool)
+(declare-var l22 Bool)
+(declare-var l24 Bool)
+(declare-var l26 Bool)
+(declare-var l28 Bool)
+(declare-var l30 Bool)
+(declare-var l32 Bool)
+(declare-var l34 Bool)
+(declare-var l36 Bool)
+(declare-var l38 Bool)
+(declare-var l40 Bool)
+(declare-var l42 Bool)
+(declare-var l44 Bool)
+(declare-var l46 Bool)
+(declare-var l48 Bool)
+(declare-var l50 Bool)
+(declare-var l52 Bool)
+(declare-var l54 Bool)
+(declare-var l56 Bool)
+(declare-var l58 Bool)
+(declare-var l60 Bool)
+(declare-var l62 Bool)
+(declare-var l64 Bool)
+(declare-var l66 Bool)
+(declare-var l68 Bool)
+(declare-var l70 Bool)
+(declare-var l72 Bool)
+(declare-var l74 Bool)
+(declare-var l76 Bool)
+(declare-var l78 Bool)
+(declare-var l80 Bool)
+(declare-var l82 Bool)
+(declare-var l84 Bool)
+(declare-var l86 Bool)
+(declare-var l88 Bool)
+(declare-var l90 Bool)
+(declare-var l92 Bool)
+(declare-var l94 Bool)
+(declare-var l96 Bool)
+(declare-var l98 Bool)
+(declare-var l100 Bool)
+(declare-var l102 Bool)
+(declare-var l104 Bool)
+(declare-var l106 Bool)
+(declare-var l108 Bool)
+(declare-var l110 Bool)
+(declare-var l112 Bool)
+(declare-var l114 Bool)
+(declare-var l116 Bool)
+(declare-var l118 Bool)
+(declare-var l120 Bool)
+(declare-var l122 Bool)
+(declare-var l124 Bool)
+(declare-var l126 Bool)
+(declare-var l128 Bool)
+(declare-var l130 Bool)
+(declare-var l132 Bool)
+(declare-var l134 Bool)
+(declare-var l136 Bool)
+(declare-var l138 Bool)
+(declare-var l140 Bool)
+(declare-var l142 Bool)
+(declare-var l144 Bool)
+(declare-var l146 Bool)
+(declare-var l148 Bool)
+(declare-var l150 Bool)
+(declare-var l152 Bool)
+(declare-var l154 Bool)
+(declare-var l156 Bool)
+(declare-var l158 Bool)
+(declare-var l160 Bool)
+(declare-var l162 Bool)
+(declare-var l164 Bool)
+(declare-var l166 Bool)
+(declare-var l168 Bool)
+(declare-var l170 Bool)
+(declare-var l172 Bool)
+(declare-var l174 Bool)
+(declare-var l176 Bool)
+(declare-var l178 Bool)
+(declare-var l180 Bool)
+(declare-var l182 Bool)
+(declare-var l184 Bool)
+(declare-var l186 Bool)
+(declare-var l188 Bool)
+(declare-var l190 Bool)
+(declare-var l192 Bool)
+(declare-var l194 Bool)
+(declare-var l196 Bool)
+(declare-var l198 Bool)
+(declare-var l200 Bool)
+(declare-var l202 Bool)
+(declare-var l204 Bool)
+(declare-var l206 Bool)
+(declare-var l208 Bool)
+(declare-var l210 Bool)
+(declare-var l212 Bool)
+(declare-var l214 Bool)
+(declare-var l216 Bool)
+(declare-var l218 Bool)
+(declare-var l220 Bool)
+(declare-var l222 Bool)
+(declare-var l224 Bool)
+(declare-var l226 Bool)
+(declare-var l228 Bool)
+(declare-var l230 Bool)
+(declare-var l232 Bool)
+(declare-var l234 Bool)
+(declare-var l236 Bool)
+(declare-var l238 Bool)
+(declare-var l240 Bool)
+(declare-var l242 Bool)
+(declare-var l244 Bool)
+(declare-var l246 Bool)
+(declare-var l248 Bool)
+(declare-var l250 Bool)
+(declare-var l252 Bool)
+(declare-var l254 Bool)
+(declare-var l256 Bool)
+(declare-var l258 Bool)
+(declare-var l260 Bool)
+(declare-var l262 Bool)
+(declare-var l264 Bool)
+(declare-var l266 Bool)
+(declare-var l268 Bool)
+(declare-var l270 Bool)
+(declare-var l272 Bool)
+(declare-var l274 Bool)
+(declare-var l276 Bool)
+(declare-var l278 Bool)
+(declare-var l280 Bool)
+(declare-var l282 Bool)
+(declare-var l284 Bool)
+(declare-var l286 Bool)
+(declare-var l288 Bool)
+(declare-var l290 Bool)
+(declare-var l292 Bool)
+(declare-var l294 Bool)
+(declare-var l296 Bool)
+(declare-var l298 Bool)
+(declare-var l300 Bool)
+(declare-var l302 Bool)
+(declare-var l304 Bool)
+(declare-var l306 Bool)
+(declare-var l308 Bool)
+(declare-var l310 Bool)
+(declare-var l312 Bool)
+(declare-var l314 Bool)
+(declare-var l316 Bool)
+(rule (=> (not (or l8 l10 l12 l14 l16 l18 l20 l22 l24 l26 l28 l30 l32 l34 l36 l38 l40 l42 l44 l46 l48 l50 l52 l54 l56 l58 l60 l62 l64 l66 l68 l70 l72 l74)) (Invariant l8 l10 l12 l14 l16 l18 l20 l22 l24 l26 l28 l30 l32 l34 l36 l38 l40 l42 l44 l46 l48 l50 l52 l54 l56 l58 l60 l62 l64 l66 l68 l70 l72 l74)))
+(rule (=> (and (Invariant l8 l10 l12 l14 l16 l18 l20 l22 l24 l26 l28 l30 l32 l34 l36 l38 l40 l42 l44 l46 l48 l50 l52 l54 l56 l58 l60 l62 l64 l66 l68 l70 l72 l74)
+ (= (and (not l20) (not l14)) l76)
+ (= (and (not l76) l8) l78)
+ (= (and l20 l14) l80)
+ (= (and (not l80) (not l78)) l82)
+ (= (and (not l28) l8) l84)
+ (= (and (not l84) l10) l86)
+ (= (and l18 l12) l88)
+ (= (and l88 l38) l90)
+ (= (and (not l24) (not l8)) l92)
+ (= (and l92 (not l26)) l94)
+ (= (and l94 l28) l96)
+ (= (and l96 (not l90)) l98)
+ (= (and (not l98) (not l86)) l100)
+ (= (and l38 l18) l102)
+ (= (and l102 l12) l104)
+ (= (and (not l104) (not l26)) l106)
+ (= (and l24 (not l16)) l108)
+ (= (and l108 (not l32)) l110)
+ (= (and l110 l106) l112)
+ (= (and (not l32) l14) l114)
+ (= (and (not l114) (not l112)) l116)
+ (= (and (not l114) l16) l118)
+ (= (and l32 (not l14)) l120)
+ (= (and l120 l106) l122)
+ (= (and l122 l24) l124)
+ (= (and (not l124) (not l118)) l126)
+ (= (and l26 (not l22)) l128)
+ (= (and l128 (not l36)) l130)
+ (= (and (not l36) l20) l132)
+ (= (and l130 (not l90)) l134)
+ (= (and (not l134) (not l132)) l136)
+ (= (and (not l132) l22) l138)
+ (= (and l26 (not l20)) l140)
+ (= (and l140 l36) l142)
+ (= (and l142 (not l90)) l144)
+ (= (and (not l144) (not l138)) l146)
+ (= (and (not l106) l24) l148)
+ (= (and l106 (not l24)) l150)
+ (= (and (not l150) (not l148)) l152)
+ (= (and (not l90) l24) l154)
+ (= (and l90 l26) l156)
+ (= (and (not l156) (not l154)) l158)
+ (= (and (not l30) l2) l160)
+ (= (and l28 (not l2)) l162)
+ (= (and (not l162) (not l160)) l164)
+ (= (and l28 l2) l166)
+ (= (and (not l166) l30) l168)
+ (= (and (not l30) l28) l170)
+ (= (and l170 l8) l172)
+ (= (and (not l172) (not l168)) l174)
+ (= (and (not l34) l4) l176)
+ (= (and l32 (not l4)) l178)
+ (= (and (not l178) (not l176)) l180)
+ (= (and l32 l4) l182)
+ (= (and (not l182) l34) l184)
+ (= (and (not l34) l32) l186)
+ (= (and l186 l14) l188)
+ (= (and (not l188) (not l184)) l190)
+ (= (and (not l40) l6) l192)
+ (= (and l36 (not l6)) l194)
+ (= (and (not l194) (not l192)) l196)
+ (= (and (not l24) (not l10)) l198)
+ (= (and l198 (not l26)) l200)
+ (= (and l200 (not l28)) l202)
+ (= (and l202 (not l90)) l204)
+ (= (and (not l204) (not l84)) l206)
+ (= (and l36 l6) l208)
+ (= (and (not l208) l40) l210)
+ (= (and (not l40) l36) l212)
+ (= (and l212 l20) l214)
+ (= (and (not l214) (not l210)) l216)
+ (= (and l62 l44) l218)
+ (= (and l52 l46) l220)
+ (= (and l220 l72) l222)
+ (= (and (not l60) (not l58)) l224)
+ (= (and l224 l62) l226)
+ (= (and l226 (not l222)) l228)
+ (= (and (not l228) (not l218)) l230)
+ (= (and (not l222) (not l60)) l232)
+ (= (and (not l66) l58) l234)
+ (= (and (not l66) l48) l236)
+ (= (and l234 l232) l238)
+ (= (and (not l238) (not l236)) l240)
+ (= (and l66 l50) l242)
+ (= (and l66 (not l48)) l244)
+ (= (and l244 l232) l246)
+ (= (and l246 l58) l248)
+ (= (and (not l248) (not l242)) l250)
+ (= (and (not l70) l60) l252)
+ (= (and (not l70) l54) l254)
+ (= (and l252 (not l222)) l256)
+ (= (and (not l256) (not l254)) l258)
+ (= (and l70 l56) l260)
+ (= (and l70 l60) l262)
+ (= (and l262 (not l222)) l264)
+ (= (and (not l264) (not l260)) l266)
+ (= (and (not l232) l58) l268)
+ (= (and l232 (not l58)) l270)
+ (= (and (not l270) (not l268)) l272)
+ (= (and l222 l60) l274)
+ (= (and (not l222) l58) l276)
+ (= (and (not l276) (not l274)) l278)
+ (= (and l62 (not l2)) l280)
+ (= (and (not l64) l2) l282)
+ (= (and (not l282) (not l280)) l284)
+ (= (and l62 l42) l286)
+ (= (and l286 (not l284)) l288)
+ (= (and l66 (not l4)) l290)
+ (= (and (not l68) l4) l292)
+ (= (and (not l292) (not l290)) l294)
+ (= (and (not l244) l66) l296)
+ (= (and l296 (not l294)) l298)
+ (= (and l70 (not l6)) l300)
+ (= (and (not l74) l6) l302)
+ (= (and (not l302) (not l300)) l304)
+ (= (and l224 (not l62)) l306)
+ (= (and (not l62) l42) l308)
+ (= (and l306 (not l222)) l310)
+ (= (and (not l310) (not l308)) l312)
+ (= (and l70 l54) l314)
+ (= (and l314 (not l304)) l316)
+ ) (Invariant l86 l100 l116 l118 l126 l136 l138 l146 l152 l158 l164 l174 l180 l190 l196 l206 l216 l218 l230 l240 l242 l250 l258 l260 l266 l272 l278 l284 l288 l294 l298 l304 l312 l316)))
+(rule (=> (and (Invariant l8 l10 l12 l14 l16 l18 l20 l22 l24 l26 l28 l30 l32 l34 l36 l38 l40 l42 l44 l46 l48 l50 l52 l54 l56 l58 l60 l62 l64 l66 l68 l70 l72 l74)
+ (= (and (not l80) (not l78)) l82)
+ (= (and l20 l14) l80)
+ (= (and (not l76) l8) l78)
+ (= (and (not l20) (not l14)) l76)
+ (not l82)) Goal))
+(query Goal)
diff --git a/examples/python/example.py b/examples/python/example.py
index 761ae10be..b93ed6abf 100644
--- a/examples/python/example.py
+++ b/examples/python/example.py
@@ -2,7 +2,7 @@
# The Z3 Python API requires libz3.dll/.so/.dylib in the
# PATH/LD_LIBRARY_PATH/DYLD_LIBRARY_PATH
-# environment variable and the PYTHON_PATH environment variable
+# environment variable and the PYTHONPATH environment variable
# needs to point to the `python' directory that contains `z3/z3.py'
# (which is at bin/python in our binary releases).
diff --git a/examples/python/mini_ic3.py b/examples/python/mini_ic3.py
index 5a8ea566b..b7b732459 100644
--- a/examples/python/mini_ic3.py
+++ b/examples/python/mini_ic3.py
@@ -17,6 +17,7 @@ class Horn2Transitions:
def __init__(self):
self.trans = True
self.init = True
+ self.inputs = []
self.goal = True
self.index = 0
@@ -48,6 +49,9 @@ class Horn2Transitions:
if pred is None:
return False
self.goal = self.subst_vars("x", inv, pred)
+ self.goal = self.subst_vars("i", self.goal, self.goal)
+ self.inputs += self.vars
+ self.inputs = list(set(self.inputs))
return True
def is_body(self, body):
@@ -77,6 +81,9 @@ class Horn2Transitions:
self.xs = self.vars
pred = self.subst_vars("xn", inv1, pred)
self.xns = self.vars
+ pred = self.subst_vars("i", pred, pred)
+ self.inputs += self.vars
+ self.inputs = list(set(self.inputs))
self.trans = pred
return True
@@ -97,12 +104,24 @@ class Horn2Transitions:
def mk_subst(self, prefix, inv):
self.index = 0
- return [(f, self.mk_bool(prefix)) for f in inv.children()]
+ if self.is_inv(inv) is not None:
+ return [(f, self.mk_bool(prefix)) for f in inv.children()]
+ else:
+ vars = self.get_vars(inv)
+ return [(f, self.mk_bool(prefix)) for f in vars]
def mk_bool(self, prefix):
self.index += 1
return Bool("%s%d" % (prefix, self.index))
+ def get_vars(self, f, rs=[]):
+ if is_var(f):
+ return z3util.vset(rs + [f], str)
+ else:
+ for f_ in f.children():
+ rs = self.get_vars(f_, rs)
+ return z3util.vset(rs, str)
+
# Produce a finite domain solver.
# The theory QF_FD covers bit-vector formulas
# and pseudo-Boolean constraints.
@@ -169,8 +188,9 @@ def prune(R):
return R - removed
class MiniIC3:
- def __init__(self, init, trans, goal, x0, xn):
+ def __init__(self, init, trans, goal, x0, inputs, xn):
self.x0 = x0
+ self.inputs = inputs
self.xn = xn
self.init = init
self.bad = goal
@@ -229,6 +249,9 @@ class MiniIC3:
def project0(self, m):
return self.values2literals(m, self.x0)
+ def projectI(self, m):
+ return self.values2literals(m, self.inputs)
+
def projectN(self, m):
return self.values2literals(m, self.xn)
@@ -242,12 +265,14 @@ class MiniIC3:
is_sat = self.s_bad.check()
if is_sat == sat:
m = self.s_bad.model()
- props = self.project0(m)
+ cube = self.project0(m)
+ props = cube + self.projectI(m)
self.s_good.push()
self.s_good.add(R)
is_sat2 = self.s_good.check(props)
assert is_sat2 == unsat
core = self.s_good.unsat_core()
+ core = [c for c in core if c in set(cube)]
self.s_good.pop()
self.s_bad.pop()
return is_sat, core
@@ -263,8 +288,8 @@ class MiniIC3:
# minimize cube that is core of Dual solver.
# this assumes that props & cube => Trans
- def minimize_cube(self, cube, lits):
- is_sat = self.min_cube_solver.check(lits + [c for c in cube])
+ def minimize_cube(self, cube, inputs, lits):
+ is_sat = self.min_cube_solver.check(lits + [c for c in cube] + [i for i in inputs])
assert is_sat == unsat
core = self.min_cube_solver.unsat_core()
assert core
@@ -306,7 +331,9 @@ class MiniIC3:
def generalize(self, cube, f):
s = self.states[f - 1].solver
if unsat == s.check(cube):
- return s.unsat_core(), f
+ core = s.unsat_core()
+ if not check_disjoint(self.init, self.prev(And(core))):
+ return core, f
return cube, f
# Check if the negation of cube is inductive at level f
@@ -319,7 +346,7 @@ class MiniIC3:
m = s.model()
s.pop()
if is_sat == sat:
- cube = self.next(self.minimize_cube(self.project0(m), self.projectN(m)))
+ cube = self.next(self.minimize_cube(self.project0(m), self.projectI(m), self.projectN(m)))
elif is_sat == unsat:
cube, f = self.generalize(cube, f)
return cube, f, is_sat
@@ -348,7 +375,7 @@ class MiniIC3:
def test(file):
h2t = Horn2Transitions()
h2t.parse(file)
- mp = MiniIC3(h2t.init, h2t.trans, h2t.goal, h2t.xs, h2t.xns)
+ mp = MiniIC3(h2t.init, h2t.trans, h2t.goal, h2t.xs, h2t.inputs, h2t.xns)
result = mp.run()
if isinstance(result, Goal):
g = result
@@ -364,75 +391,7 @@ def test(file):
test("data/horn1.smt2")
test("data/horn2.smt2")
-
-
-
-"""
-# TBD: Quip variant of IC3
-
-must = True
-may = False
-
-class QGoal:
- def __init__(self, cube, parent, level, must):
- self.level = level
- self.cube = cube
- self.parent = parent
- self.must = must
-
-class Quip(MiniIC3):
-
- # prev & tras -> r', such that r' intersects with cube
- def add_reachable(self, prev, cube):
- s = fd_solver()
- s.add(self.trans)
- s.add(prev)
- s.add(Or(cube))
- is_sat = s.check()
- assert is_sat == sat
- m = s.model();
- result = self.values2literals(m, cube)
- assert result
- self.reachable.add(result)
-
- # A state s0 and level f0 such that
- # not(s0) is f0-1 inductive
- def quip_blocked(self, s0, f0):
- self.push_heap(QGoal(self.next(s0), None, f0, must))
- while self.goals:
- f, g = heapq.heappop(self.goals)
- sys.stdout.write("%d." % f)
- sys.stdout.flush()
- if f == 0:
- if g.must:
- print("")
- return g
- self.add_reachable(self.init, p.parent.cube)
- continue
-
- # TBD
- return None
-
-
- def run(self):
- if not check_disjoint(self.init, self.bad):
- return "goal is reached in initial state"
- level = 0
- while True:
- inv = self.is_valid()
- if inv is not None:
- return inv
- is_sat, cube = self.unfold()
- if is_sat == unsat:
- level += 1
- print("Unfold %d" % level)
- sys.stdout.flush()
- self.add_solver()
- elif is_sat == sat:
- cex = self.quipie_blocked(cube, level)
- if cex is not None:
- return cex
- else:
- return is_sat
-
-"""
\ No newline at end of file
+test("data/horn3.smt2")
+test("data/horn4.smt2")
+test("data/horn5.smt2")
+# test("data/horn6.smt2") # takes long time to finish
diff --git a/examples/python/mini_quip.py b/examples/python/mini_quip.py
new file mode 100644
index 000000000..a10d5a334
--- /dev/null
+++ b/examples/python/mini_quip.py
@@ -0,0 +1,786 @@
+from z3 import *
+import heapq
+import numpy
+import time
+import random
+
+verbose = True
+
+# Simplistic (and fragile) converter from
+# a class of Horn clauses corresponding to
+# a transition system into a transition system
+# representation as
+# It assumes it is given three Horn clauses
+# of the form:
+# init(x) => Invariant(x)
+# Invariant(x) and trans(x,x') => Invariant(x')
+# Invariant(x) and goal(x) => Goal(x)
+# where Invariant and Goal are uninterpreted predicates
+
+class Horn2Transitions:
+ def __init__(self):
+ self.trans = True
+ self.init = True
+ self.inputs = []
+ self.goal = True
+ self.index = 0
+
+ def parse(self, file):
+ fp = Fixedpoint()
+ goals = fp.parse_file(file)
+ for r in fp.get_rules():
+ if not is_quantifier(r):
+ continue
+ b = r.body()
+ if not is_implies(b):
+ continue
+ f = b.arg(0)
+ g = b.arg(1)
+ if self.is_goal(f, g):
+ continue
+ if self.is_transition(f, g):
+ continue
+ if self.is_init(f, g):
+ continue
+
+ def is_pred(self, p, name):
+ return is_app(p) and p.decl().name() == name
+
+ def is_goal(self, body, head):
+ if not self.is_pred(head, "Goal"):
+ return False
+ pred, inv = self.is_body(body)
+ if pred is None:
+ return False
+ self.goal = self.subst_vars("x", inv, pred)
+ self.goal = self.subst_vars("i", self.goal, self.goal)
+ self.inputs += self.vars
+ self.inputs = list(set(self.inputs))
+ return True
+
+ def is_body(self, body):
+ if not is_and(body):
+ return None, None
+ fmls = [f for f in body.children() if self.is_inv(f) is None]
+ inv = None
+ for f in body.children():
+ if self.is_inv(f) is not None:
+ inv = f;
+ break
+ return And(fmls), inv
+
+ def is_inv(self, f):
+ if self.is_pred(f, "Invariant"):
+ return f
+ return None
+
+ def is_transition(self, body, head):
+ pred, inv0 = self.is_body(body)
+ if pred is None:
+ return False
+ inv1 = self.is_inv(head)
+ if inv1 is None:
+ return False
+ pred = self.subst_vars("x", inv0, pred)
+ self.xs = self.vars
+ pred = self.subst_vars("xn", inv1, pred)
+ self.xns = self.vars
+ pred = self.subst_vars("i", pred, pred)
+ self.inputs += self.vars
+ self.inputs = list(set(self.inputs))
+ self.trans = pred
+ return True
+
+ def is_init(self, body, head):
+ for f in body.children():
+ if self.is_inv(f) is not None:
+ return False
+ inv = self.is_inv(head)
+ if inv is None:
+ return False
+ self.init = self.subst_vars("x", inv, body)
+ return True
+
+ def subst_vars(self, prefix, inv, fml):
+ subst = self.mk_subst(prefix, inv)
+ self.vars = [ v for (k,v) in subst ]
+ return substitute(fml, subst)
+
+ def mk_subst(self, prefix, inv):
+ self.index = 0
+ if self.is_inv(inv) is not None:
+ return [(f, self.mk_bool(prefix)) for f in inv.children()]
+ else:
+ vars = self.get_vars(inv)
+ return [(f, self.mk_bool(prefix)) for f in vars]
+
+ def mk_bool(self, prefix):
+ self.index += 1
+ return Bool("%s%d" % (prefix, self.index))
+
+ def get_vars(self, f, rs=[]):
+ if is_var(f):
+ return z3util.vset(rs + [f], str)
+ else:
+ for f_ in f.children():
+ rs = self.get_vars(f_, rs)
+ return z3util.vset(rs, str)
+
+# Produce a finite domain solver.
+# The theory QF_FD covers bit-vector formulas
+# and pseudo-Boolean constraints.
+# By default cardinality and pseudo-Boolean
+# constraints are converted to clauses. To override
+# this default for cardinality constraints
+# we set sat.cardinality.solver to True
+
+def fd_solver():
+ s = SolverFor("QF_FD")
+ s.set("sat.cardinality.solver", True)
+ return s
+
+
+# negate, avoid double negation
+def negate(f):
+ if is_not(f):
+ return f.arg(0)
+ else:
+ return Not(f)
+
+def cube2clause(cube):
+ return Or([negate(f) for f in cube])
+
+class State:
+ def __init__(self, s):
+ self.R = set([])
+ self.solver = s
+
+ def add(self, clause):
+ if clause not in self.R:
+ self.R |= { clause }
+ self.solver.add(clause)
+
+def is_seq(f):
+ return isinstance(f, list) or isinstance(f, tuple) or isinstance(f, AstVector)
+
+# Check if the initial state is bad
+def check_disjoint(a, b):
+ s = fd_solver()
+ s.add(a)
+ s.add(b)
+ return unsat == s.check()
+
+
+# Remove clauses that are subsumed
+def prune(R):
+ removed = set([])
+ s = fd_solver()
+ for f1 in R:
+ s.push()
+ for f2 in R:
+ if f2 not in removed:
+ s.add(Not(f2) if f1.eq(f2) else f2)
+ if s.check() == unsat:
+ removed |= { f1 }
+ s.pop()
+ return R - removed
+
+# Quip variant of IC3
+
+must = True
+may = False
+
+class QLemma:
+ def __init__(self, c):
+ self.cube = c
+ self.clause = cube2clause(c)
+ self.bad = False
+
+ def __hash__(self):
+ return hash(tuple(set(self.cube)))
+
+ def __eq__(self, qlemma2):
+ if set(self.cube) == set(qlemma2.cube) and self.bad == qlemma2.bad:
+ return True
+ else:
+ return False
+
+ def __ne__():
+ if not self.__eq__(self, qlemma2):
+ return True
+ else:
+ return False
+
+
+class QGoal:
+ def __init__(self, cube, parent, level, must, encounter):
+ self.level = level
+ self.cube = cube
+ self.parent = parent
+ self.must = must
+
+ def __lt__(self, other):
+ return self.level < other.level
+
+
+class QReach:
+
+ # it is assumed that there is a single initial state
+ # with all latches set to 0 in hardware design, so
+ # here init will always give a state where all variable are set to 0
+ def __init__(self, init, xs):
+ self.xs = xs
+ self.constant_xs = [Not(x) for x in self.xs]
+ s = fd_solver()
+ s.add(init)
+ is_sat = s.check()
+ assert is_sat == sat
+ m = s.model()
+ # xs is a list, "for" will keep the order when iterating
+ self.states = numpy.array([[False for x in self.xs]]) # all set to False
+ assert not numpy.max(self.states) # since all element is False, so maximum should be False
+
+ # check if new state exists
+ def is_exist(self, state):
+ if state in self.states:
+ return True
+ return False
+
+ def enumerate(self, i, state_b, state):
+ while i < len(state) and state[i] not in self.xs:
+ i += 1
+ if i >= len(state):
+ if state_b.tolist() not in self.states.tolist():
+ self.states = numpy.append(self.states, [state_b], axis = 0)
+ return state_b
+ else:
+ return None
+ state_b[i] = False
+ if self.enumerate(i+1, state_b, state) is not None:
+ return state_b
+ else:
+ state_b[i] = True
+ return self.enumerate(i+1, state_b, state)
+
+ def is_full_state(self, state):
+ for i in range(len(self.xs)):
+ if state[i] in self.xs:
+ return False
+ return True
+
+ def add(self, cube):
+ state = self.cube2partial_state(cube)
+ assert len(state) == len(self.xs)
+ if not self.is_exist(state):
+ return None
+ if self.is_full_state(state):
+ self.states = numpy.append(self.states, [state], axis = 0)
+ else:
+ # state[i] is instance, state_b[i] is boolean
+ state_b = numpy.array(state)
+ for i in range(len(state)): # state is of same length as self.xs
+ # i-th literal in state hasn't been assigned value
+ # init un-assigned literals in state_b as True
+ # make state_b only contain boolean value
+ if state[i] in self.xs:
+ state_b[i] = True
+ else:
+ state_b[i] = is_true(state[i])
+ if self.enumerate(0, state_b, state) is not None:
+ lits_to_remove = set([negate(f) for f in list(set(cube) - set(self.constant_xs))])
+ self.constant_xs = list(set(self.constant_xs) - lits_to_remove)
+ return state
+ return None
+
+
+ def cube2partial_state(self, cube):
+ s = fd_solver()
+ s.add(And(cube))
+ is_sat = s.check()
+ assert is_sat == sat
+ m = s.model()
+ state = numpy.array([m.eval(x) for x in self.xs])
+ return state
+
+
+ def state2cube(self, s):
+ result = copy.deepcopy(self.xs) # x1, x2, ...
+ for i in range(len(self.xs)):
+ if not s[i]:
+ result[i] = Not(result[i])
+ return result
+
+ def intersect(self, cube):
+ state = self.cube2partial_state(cube)
+ mask = True
+ for i in range(len(self.xs)):
+ if is_true(state[i]) or is_false(state[i]):
+ mask = (self.states[:, i] == state[i]) & mask
+ intersects = numpy.reshape(self.states[mask], (-1, len(self.xs)))
+ if intersects.size > 0:
+ return And(self.state2cube(intersects[0])) # only need to return one single intersect
+ return None
+
+
+class Quip:
+
+ def __init__(self, init, trans, goal, x0, inputs, xn):
+ self.x0 = x0
+ self.inputs = inputs
+ self.xn = xn
+ self.init = init
+ self.bad = goal
+ self.trans = trans
+ self.min_cube_solver = fd_solver()
+ self.min_cube_solver.add(Not(trans))
+ self.goals = []
+ s = State(fd_solver())
+ s.add(init)
+ s.solver.add(trans) # check if a bad state can be reached in one step from current level
+ self.states = [s]
+ self.s_bad = fd_solver()
+ self.s_good = fd_solver()
+ self.s_bad.add(self.bad)
+ self.s_good.add(Not(self.bad))
+ self.reachable = QReach(self.init, x0)
+ self.frames = [] # frames is a 2d list, each row (representing level) is a set containing several (clause, bad) pairs
+ self.count_may = 0
+
+ def next(self, f):
+ if is_seq(f):
+ return [self.next(f1) for f1 in f]
+ return substitute(f, zip(self.x0, self.xn))
+
+ def prev(self, f):
+ if is_seq(f):
+ return [self.prev(f1) for f1 in f]
+ return substitute(f, zip(self.xn, self.x0))
+
+ def add_solver(self):
+ s = fd_solver()
+ s.add(self.trans)
+ self.states += [State(s)]
+
+ def R(self, i):
+ return And(self.states[i].R)
+
+ def value2literal(self, m, x):
+ value = m.eval(x)
+ if is_true(value):
+ return x
+ if is_false(value):
+ return Not(x)
+ return None
+
+ def values2literals(self, m, xs):
+ p = [self.value2literal(m, x) for x in xs]
+ return [x for x in p if x is not None]
+
+ def project0(self, m):
+ return self.values2literals(m, self.x0)
+
+ def projectI(self, m):
+ return self.values2literals(m, self.inputs)
+
+ def projectN(self, m):
+ return self.values2literals(m, self.xn)
+
+
+ # Block a cube by asserting the clause corresponding to its negation
+ def block_cube(self, i, cube):
+ self.assert_clause(i, cube2clause(cube))
+
+ # Add a clause to levels 1 until i
+ def assert_clause(self, i, clause):
+ for j in range(1, i + 1):
+ self.states[j].add(clause)
+ assert str(self.states[j].solver) != str([False])
+
+
+ # minimize cube that is core of Dual solver.
+ # this assumes that props & cube => Trans
+ # which means props & cube can only give us a Tr in Trans,
+ # and it will never make !Trans sat
+ def minimize_cube(self, cube, inputs, lits):
+ # min_cube_solver has !Trans (min_cube.solver.add(!Trans))
+ is_sat = self.min_cube_solver.check(lits + [c for c in cube] + [i for i in inputs])
+ assert is_sat == unsat
+ # unsat_core gives us some lits which make Tr sat,
+ # so that we can ignore other lits and include more states
+ core = self.min_cube_solver.unsat_core()
+ assert core
+ return [c for c in core if c in set(cube)]
+
+ # push a goal on a heap
+ def push_heap(self, goal):
+ heapq.heappush(self.goals, (goal.level, goal))
+
+
+ # make sure cube to be blocked excludes all reachable states
+ def check_reachable(self, cube):
+ s = fd_solver()
+ for state in self.reachable.states:
+ s.push()
+ r = self.reachable.state2cube(state)
+ s.add(And(self.prev(r)))
+ s.add(self.prev(cube))
+ is_sat = s.check()
+ s.pop()
+ if is_sat == sat:
+ # if sat, it means the cube to be blocked contains reachable states
+ # so it is an invalid cube
+ return False
+ # if all fail, is_sat will be unsat
+ return True
+
+ # Rudimentary generalization:
+ # If the cube is already unsat with respect to transition relation
+ # extract a core (not necessarily minimal)
+ # otherwise, just return the cube.
+ def generalize(self, cube, f):
+ s = self.states[f - 1].solver
+ if unsat == s.check(cube):
+ core = s.unsat_core()
+ if self.check_reachable(core):
+ return core, f
+ return cube, f
+
+
+ def valid_reachable(self, level):
+ s = fd_solver()
+ s.add(self.init)
+ for i in range(level):
+ s.add(self.trans)
+ for state in self.reachable.states:
+ s.push()
+ s.add(And(self.next(self.reachable.state2cube(state))))
+ print self.reachable.state2cube(state)
+ print s.check()
+ s.pop()
+
+ def lemmas(self, level):
+ return [(l.clause, l.bad) for l in self.frames[level]]
+
+ # whenever a new reachable state is found, we use it to mark some existing lemmas as bad lemmas
+ def mark_bad_lemmas(self, new):
+ s = fd_solver()
+ reset = False
+ for frame in self.frames:
+ for lemma in frame:
+ s.push()
+ s.add(lemma.clause)
+ is_sat = s.check(new)
+ if is_sat == unsat:
+ reset = True
+ lemma.bad = True
+ s.pop()
+ if reset:
+ self.states = [self.states[0]]
+ for i in range(1, len(self.frames)):
+ self.add_solver()
+ for lemma in self.frames[i]:
+ if not lemma.bad:
+ self.states[i].add(lemma.clause)
+
+ # prev & tras -> r', such that r' intersects with cube
+ def add_reachable(self, prev, cube):
+ s = fd_solver()
+ s.add(self.trans)
+ s.add(prev)
+ s.add(self.next(And(cube)))
+ is_sat = s.check()
+ assert is_sat == sat
+ m = s.model()
+ new = self.projectN(m)
+ state = self.reachable.add(self.prev(new)) # always add as non-primed
+ if state is not None: # if self.states do not have new state yet
+ self.mark_bad_lemmas(self.prev(new))
+
+
+ # Check if the negation of cube is inductive at level f
+ def is_inductive(self, f, cube):
+ s = self.states[f - 1].solver
+ s.push()
+ s.add(self.prev(Not(And(cube))))
+ is_sat = s.check(cube)
+ if is_sat == sat:
+ m = s.model()
+ s.pop()
+ if is_sat == sat:
+ cube = self.next(self.minimize_cube(self.project0(m), self.projectI(m), self.projectN(m)))
+ elif is_sat == unsat:
+ cube, f = self.generalize(cube, f)
+ cube = self.next(cube)
+ return cube, f, is_sat
+
+
+ # Determine if there is a cube for the current state
+ # that is potentially reachable.
+ def unfold(self, level):
+ core = []
+ self.s_bad.push()
+ R = self.R(level)
+ self.s_bad.add(R) # check if current frame intersects with bad states, no trans
+ is_sat = self.s_bad.check()
+ if is_sat == sat:
+ m = self.s_bad.model()
+ cube = self.project0(m)
+ props = cube + self.projectI(m)
+ self.s_good.push()
+ self.s_good.add(R)
+ is_sat2 = self.s_good.check(props)
+ assert is_sat2 == unsat
+ core = self.s_good.unsat_core()
+ assert core
+ core = [c for c in core if c in set(cube)]
+ self.s_good.pop()
+ self.s_bad.pop()
+ return is_sat, core
+
+ # A state s0 and level f0 such that
+ # not(s0) is f0-1 inductive
+ def quip_blocked(self, s0, f0):
+ self.push_heap(QGoal(self.next(s0), None, f0, must, 0))
+ while self.goals:
+ f, g = heapq.heappop(self.goals)
+ sys.stdout.write("%d." % f)
+ if not g.must:
+ self.count_may -= 1
+ sys.stdout.flush()
+ if f == 0:
+ if g.must:
+ s = fd_solver()
+ s.add(self.init)
+ s.add(self.prev(g.cube))
+ # since init is a complete assignment, so g.cube must equal to init in sat solver
+ assert is_sat == s.check()
+ if verbose:
+ print("")
+ return g
+ self.add_reachable(self.init, g.parent.cube)
+ continue
+
+ r0 = self.reachable.intersect(self.prev(g.cube))
+ if r0 is not None:
+ if g.must:
+ if verbose:
+ print ""
+ s = fd_solver()
+ s.add(self.trans)
+ # make it as a concrete reachable state
+ # intersect returns an And(...), so use children to get cube list
+ g.cube = r0.children()
+ while True:
+ is_sat = s.check(self.next(g.cube))
+ assert is_sat == sat
+ r = self.next(self.project0(s.model()))
+ r = self.reachable.intersect(self.prev(r))
+ child = QGoal(self.next(r.children()), g, 0, g.must, 0)
+ g = child
+ if not check_disjoint(self.init, self.prev(g.cube)):
+ # g is init, break the loop
+ break
+ init = g
+ while g.parent is not None:
+ g.parent.level = g.level + 1
+ g = g.parent
+ return init
+ if g.parent is not None:
+ self.add_reachable(r0, g.parent.cube)
+ continue
+
+ cube = None
+ is_sat = sat
+ f_1 = len(self.frames) - 1
+ while f_1 >= f:
+ for l in self.frames[f_1]:
+ if not l.bad and len(l.cube) > 0 and set(l.cube).issubset(g.cube):
+ cube = l.cube
+ is_sat == unsat
+ break
+ f_1 -= 1
+ if cube is None:
+ cube, f_1, is_sat = self.is_inductive(f, g.cube)
+ if is_sat == unsat:
+ self.frames[f_1].add(QLemma(self.prev(cube)))
+ self.block_cube(f_1, self.prev(cube))
+ if f_1 < f0:
+ # learned clause might also be able to block same bad states in higher level
+ if set(list(cube)) != set(list(g.cube)):
+ self.push_heap(QGoal(cube, None, f_1 + 1, may, 0))
+ self.count_may += 1
+ else:
+ # re-queue g.cube in higher level, here g.parent is simply for tracking down the trace when output.
+ self.push_heap(QGoal(g.cube, g.parent, f_1 + 1, g.must, 0))
+ if not g.must:
+ self.count_may += 1
+ else:
+ # qcube is a predecessor of g
+ qcube = QGoal(cube, g, f_1 - 1, g.must, 0)
+ if not g.must:
+ self.count_may += 1
+ self.push_heap(qcube)
+
+ if verbose:
+ print("")
+ return None
+
+ # Check if there are two states next to each other that have the same clauses.
+ def is_valid(self):
+ i = 1
+ inv = None
+ while True:
+ # self.states[].R contains full lemmas
+ # self.frames[] contains delta-encoded lemmas
+ while len(self.states) <= i+1:
+ self.add_solver()
+ while len(self.frames) <= i+1:
+ self.frames.append(set())
+ duplicates = set([])
+ for l in self.frames[i+1]:
+ if l in self.frames[i]:
+ duplicates |= {l}
+ self.frames[i] = self.frames[i] - duplicates
+ pushed = set([])
+ for l in (self.frames[i] - self.frames[i+1]):
+ if not l.bad:
+ s = self.states[i].solver
+ s.push()
+ s.add(self.next(Not(l.clause)))
+ s.add(l.clause)
+ is_sat = s.check()
+ s.pop()
+ if is_sat == unsat:
+ self.frames[i+1].add(l)
+ self.states[i+1].add(l.clause)
+ pushed |= {l}
+ self.frames[i] = self.frames[i] - pushed
+ if (not (self.states[i].R - self.states[i+1].R)
+ and len(self.states[i].R) != 0):
+ inv = prune(self.states[i].R)
+ F_inf = self.frames[i]
+ j = i + 1
+ while j < len(self.states):
+ for l in F_inf:
+ self.states[j].add(l.clause)
+ j += 1
+ self.frames[len(self.states)-1] = F_inf
+ self.frames[i] = set([])
+ break
+ elif (len(self.states[i].R) == 0
+ and len(self.states[i+1].R) == 0):
+ break
+ i += 1
+
+ if inv is not None:
+ self.s_bad.push()
+ self.s_bad.add(And(inv))
+ is_sat = self.s_bad.check()
+ if is_sat == unsat:
+ self.s_bad.pop()
+ return And(inv)
+ self.s_bad.pop()
+ return None
+
+ def run(self):
+ if not check_disjoint(self.init, self.bad):
+ return "goal is reached in initial state"
+ level = 0
+ while True:
+ inv = self.is_valid() # self.add_solver() here
+ if inv is not None:
+ return inv
+ is_sat, cube = self.unfold(level)
+ if is_sat == unsat:
+ level += 1
+ if verbose:
+ print("Unfold %d" % level)
+ sys.stdout.flush()
+ elif is_sat == sat:
+ cex = self.quip_blocked(cube, level)
+ if cex is not None:
+ return cex
+ else:
+ return is_sat
+
+def test(file):
+ h2t = Horn2Transitions()
+ h2t.parse(file)
+ if verbose:
+ print("Test file: %s") % file
+ mp = Quip(h2t.init, h2t.trans, h2t.goal, h2t.xs, h2t.inputs, h2t.xns)
+ start_time = time.time()
+ result = mp.run()
+ end_time = time.time()
+ if isinstance(result, QGoal):
+ g = result
+ if verbose:
+ print("Trace")
+ while g:
+ if verbose:
+ print(g.level, g.cube)
+ g = g.parent
+ print("--- used %.3f seconds ---" % (end_time - start_time))
+ validate(mp, result, mp.trans)
+ return
+ if isinstance(result, ExprRef):
+ if verbose:
+ print("Invariant:\n%s " % result)
+ print("--- used %.3f seconds ---" % (end_time - start_time))
+ validate(mp, result, mp.trans)
+ return
+ print(result)
+
+def validate(var, result, trans):
+ if isinstance(result, QGoal):
+ g = result
+ s = fd_solver()
+ s.add(trans)
+ while g.parent is not None:
+ s.push()
+ s.add(var.prev(g.cube))
+ s.add(var.next(g.parent.cube))
+ assert sat == s.check()
+ s.pop()
+ g = g.parent
+ if verbose:
+ print "--- validation succeed ----"
+ return
+ if isinstance(result, ExprRef):
+ inv = result
+ s = fd_solver()
+ s.add(trans)
+ s.push()
+ s.add(var.prev(inv))
+ s.add(Not(var.next(inv)))
+ assert unsat == s.check()
+ s.pop()
+ cube = var.prev(var.init)
+ step = 0
+ while True:
+ step += 1
+ # too many steps to reach invariant
+ if step > 1000:
+ if verbose:
+ print "--- validation failed --"
+ return
+ if not check_disjoint(var.prev(cube), var.prev(inv)):
+ # reach invariant
+ break
+ s.push()
+ s.add(cube)
+ assert s.check() == sat
+ cube = var.projectN(s.model())
+ s.pop()
+ if verbose:
+ print "--- validation succeed ----"
+ return
+
+
+
+test("data/horn1.smt2")
+test("data/horn2.smt2")
+test("data/horn3.smt2")
+test("data/horn4.smt2")
+test("data/horn5.smt2")
+# test("data/horn6.smt2") # not able to finish
diff --git a/scripts/mk_genfile_common.py b/scripts/mk_genfile_common.py
index c42eaf86d..6354613fe 100644
--- a/scripts/mk_genfile_common.py
+++ b/scripts/mk_genfile_common.py
@@ -8,6 +8,7 @@
# You should **not** import ``mk_util`` here
# to avoid having this code depend on the
# of the Python build system.
+import io
import os
import pprint
import logging
@@ -622,7 +623,7 @@ def mk_gparams_register_modules_internal(h_files_full_path, path):
reg_mod_descr_pat = re.compile('[ \t]*REG_MODULE_DESCRIPTION\(\'([^\']*)\', *\'([^\']*)\'\)')
for h_file in sorted_headers_by_component(h_files_full_path):
added_include = False
- with open(h_file, 'r') as fin:
+ with io.open(h_file, encoding='utf-8', mode='r') as fin:
for line in fin:
m = reg_pat.match(line)
if m:
@@ -696,7 +697,7 @@ def mk_install_tactic_cpp_internal(h_files_full_path, path):
for h_file in sorted_headers_by_component(h_files_full_path):
added_include = False
try:
- with open(h_file, 'r') as fin:
+ with io.open(h_file, encoding='utf-8', mode='r') as fin:
for line in fin:
if tactic_pat.match(line):
if not added_include:
@@ -719,7 +720,7 @@ def mk_install_tactic_cpp_internal(h_files_full_path, path):
fullname, line))
raise e
except Exception as e:
- _loggeer.error("Failed to read file {}\n".format(h_file))
+ _logger.error("Failed to read file {}\n".format(h_file))
raise e
# First pass will just generate the tactic factories
fout.write('#define ADD_TACTIC_CMD(NAME, DESCR, CODE) ctx.insert(alloc(tactic_cmd, symbol(NAME), DESCR, [](ast_manager &m, const params_ref &p) { return CODE; }))\n')
@@ -764,7 +765,7 @@ def mk_mem_initializer_cpp_internal(h_files_full_path, path):
finalizer_pat = re.compile('[ \t]*ADD_FINALIZER\(\'([^\']*)\'\)')
for h_file in sorted_headers_by_component(h_files_full_path):
added_include = False
- with open(h_file, 'r') as fin:
+ with io.open(h_file, encoding='utf-8', mode='r') as fin:
for line in fin:
m = initializer_pat.match(line)
if m:
diff --git a/scripts/mk_nuget_release.py b/scripts/mk_nuget_release.py
index 7ce14bf5d..db7a1af64 100644
--- a/scripts/mk_nuget_release.py
+++ b/scripts/mk_nuget_release.py
@@ -38,7 +38,7 @@ def download_installs():
urllib.request.urlretrieve(url, "packages/%s" % name)
os_info = {"z64-ubuntu-14" : ('so', 'ubuntu.14.04-x64'),
- 'ubuntu-16' : ('so', 'ubuntu.16.04-x64'),
+ 'ubuntu-16' : ('so', 'ubuntu-x64'),
'x64-win' : ('dll', 'win-x64'),
'x86-win' : ('dll', 'win-x86'),
'osx' : ('dylib', 'macos'),
@@ -52,7 +52,7 @@ def classify_package(f):
return None
def unpack():
- shutil.rmtree("out")
+ shutil.rmtree("out", ignore_errors=True)
# unzip files in packages
# out
# +- runtimes
@@ -70,9 +70,9 @@ def unpack():
path = os.path.abspath(os.path.join("packages", f))
zip_ref = zipfile.ZipFile(path, 'r')
zip_ref.extract("%s/bin/libz3.%s" % (package_dir, ext), "tmp")
- mk_dir("out/runtimes/%s" % dst)
- shutil.move("tmp/%s/bin/libz3.%s" % (package_dir, ext), "out/runtimes/%s/." % dst, "/y")
- if "win" in f:
+ mk_dir("out/runtimes/%s/native" % dst)
+ shutil.move("tmp/%s/bin/libz3.%s" % (package_dir, ext), "out/runtimes/%s/native/." % dst, "/y")
+ if "x64-win" in f:
mk_dir("out/lib/netstandard1.4/")
for b in ["Microsoft.Z3.dll"]:
zip_ref.extract("%s/bin/%s" % (package_dir, b), "tmp")
@@ -85,17 +85,18 @@ def create_nuget_spec():
Microsoft.Z3
%s
Microsoft
- Z3 is a satisfiability modulo theories solver from Microsoft Research.
+
+Z3 is a satisfiability modulo theories solver from Microsoft Research.
+
+Linux Dependencies:
+ libgomp.so.1 installed
+
Copyright Microsoft Corporation. All rights reserved.
smt constraint solver theorem prover
https://raw.githubusercontent.com/Z3Prover/z3/master/package/icon.jpg
https://github.com/Z3Prover/z3
https://raw.githubusercontent.com/Z3Prover/z3/master/LICENSE.txt
-
+
true
en
diff --git a/scripts/mk_project.py b/scripts/mk_project.py
index 8cf60ab62..2748e30a1 100644
--- a/scripts/mk_project.py
+++ b/scripts/mk_project.py
@@ -8,7 +8,7 @@
from mk_util import *
def init_version():
- set_version(4, 8, 4, 0)
+ set_version(4, 8, 5, 0)
# Z3 Project definition
def init_project_def():
@@ -87,7 +87,7 @@ def init_project_def():
export_files=API_files,
staging_link='python')
add_dot_net_dll('dotnet', ['api_dll'], 'api/dotnet', dll_name='Microsoft.Z3', assembly_info_dir='Properties', default_key_file='src/api/dotnet/Microsoft.Z3.snk')
- add_dot_net_core_dll('dotnetcore', ['api_dll'], 'api/dotnet', dll_name='Microsoft.Z3', assembly_info_dir='Properties', default_key_file='src/api/dotnet/Microsoft.Z3.snk')
+ add_dot_net_core_dll('dotnetcore', ['api_dll'], 'api/dotnet', dll_name='Microsoft.Z3', default_key_file='src/api/dotnet/Microsoft.Z3.snk')
add_java_dll('java', ['api_dll'], 'api/java', dll_name='libz3java', package_name="com.microsoft.z3", manifest_file='manifest')
add_ml_lib('ml', ['api_dll'], 'api/ml', lib_name='libz3ml')
add_hlib('cpp', 'api/c++', includes2install=['z3++.h'])
diff --git a/scripts/mk_util.py b/scripts/mk_util.py
index 83ae3d455..2e827a7f3 100644
--- a/scripts/mk_util.py
+++ b/scripts/mk_util.py
@@ -6,6 +6,7 @@
#
# Author: Leonardo de Moura (leonardo)
############################################
+import io
import sys
import os
import re
@@ -90,6 +91,7 @@ TRACE = False
PYTHON_ENABLED=False
DOTNET_ENABLED=False
DOTNET_CORE_ENABLED=False
+ESRP_SIGN=False
DOTNET_KEY_FILE=getenv("Z3_DOTNET_KEY_FILE", None)
JAVA_ENABLED=False
ML_ENABLED=False
@@ -706,14 +708,14 @@ def display_help(exit_code):
# Parse configuration option for mk_make script
def parse_options():
global VERBOSE, DEBUG_MODE, IS_WINDOWS, VS_X64, ONLY_MAKEFILES, SHOW_CPPS, VS_PROJ, TRACE, VS_PAR, VS_PAR_NUM
- global DOTNET_ENABLED, DOTNET_CORE_ENABLED, DOTNET_KEY_FILE, JAVA_ENABLED, ML_ENABLED, JS_ENABLED, STATIC_LIB, STATIC_BIN, PREFIX, GMP, PYTHON_PACKAGE_DIR, GPROF, GIT_HASH, GIT_DESCRIBE, PYTHON_INSTALL_ENABLED, PYTHON_ENABLED
+ global DOTNET_ENABLED, DOTNET_CORE_ENABLED, DOTNET_KEY_FILE, JAVA_ENABLED, ML_ENABLED, JS_ENABLED, STATIC_LIB, STATIC_BIN, PREFIX, GMP, PYTHON_PACKAGE_DIR, GPROF, GIT_HASH, GIT_DESCRIBE, PYTHON_INSTALL_ENABLED, PYTHON_ENABLED, ESRP_SIGN
global LINUX_X64, SLOW_OPTIMIZE, USE_OMP, LOG_SYNC
global GUARD_CF, ALWAYS_DYNAMIC_BASE
try:
options, remainder = getopt.gnu_getopt(sys.argv[1:],
'b:df:sxhmcvtnp:gj',
['build=', 'debug', 'silent', 'x64', 'help', 'makefiles', 'showcpp', 'vsproj', 'guardcf',
- 'trace', 'dotnet', 'dotnetcore', 'dotnet-key=', 'staticlib', 'prefix=', 'gmp', 'java', 'parallel=', 'gprof', 'js',
+ 'trace', 'dotnet', 'dotnetcore', 'dotnet-key=', 'esrp', 'staticlib', 'prefix=', 'gmp', 'java', 'parallel=', 'gprof', 'js',
'githash=', 'git-describe', 'x86', 'ml', 'optimize', 'noomp', 'pypkgdir=', 'python', 'staticbin', 'log-sync'])
except:
print("ERROR: Invalid command line option")
@@ -751,6 +753,8 @@ def parse_options():
DOTNET_CORE_ENABLED = True
elif opt in ('--dotnet-key'):
DOTNET_KEY_FILE = arg
+ elif opt in ('--esrp'):
+ ESRP_SIGN = True
elif opt in ('--staticlib'):
STATIC_LIB = True
elif opt in ('--staticbin'):
@@ -803,7 +807,7 @@ def extract_c_includes(fname):
# We should generate and error for any occurrence of #include that does not match the previous pattern.
non_std_inc_pat = re.compile(".*#include.*")
- f = open(fname, 'r')
+ f = io.open(fname, encoding='utf-8', mode='r')
linenum = 1
for line in f:
m1 = std_inc_pat.match(line)
@@ -1770,6 +1774,22 @@ class DotNetDLLComponent(Component):
def has_assembly_info(self):
return True
+ def make_assembly_info(c, major, minor, build, revision):
+ assembly_info_template = os.path.join(c.src_dir, c.assembly_info_dir, 'AssemblyInfo.cs.in')
+ assembly_info_output = assembly_info_template[:-3]
+ assert assembly_info_output.endswith('.cs')
+ if os.path.exists(assembly_info_template):
+ configure_file(assembly_info_template, assembly_info_output,
+ { 'VER_MAJOR': str(major),
+ 'VER_MINOR': str(minor),
+ 'VER_BUILD': str(build),
+ 'VER_REVISION': str(revision),
+ }
+ )
+ else:
+ raise MKException("Failed to find assembly template info file '%s'" % assembly_info_template)
+
+
def mk_win_dist(self, build_path, dist_path):
if is_dotnet_enabled():
mk_dir(os.path.join(dist_path, INSTALL_BIN_DIR))
@@ -1867,6 +1887,7 @@ class DotNetCoreDLLComponent(Component):
key = ""
if not self.key_file is None:
key = "%s" % self.key_file
+ key += "\ntrue"
if VS_X64:
platform = 'x64'
@@ -1921,18 +1942,87 @@ class DotNetCoreDLLComponent(Component):
dotnetCmdLine.extend(['-o', path])
MakeRuleCmd.write_cmd(out, ' '.join(dotnetCmdLine))
-
- out.write('\n')
+ self.sign_esrp(out)
+ out.write('\n')
out.write('%s: %s\n\n' % (self.name, dllfile))
+ def sign_esrp(self, out):
+ global ESRP_SIGNx
+ print("esrp-sign", ESRP_SIGN)
+ if not ESRP_SIGN:
+ return
+
+ import uuid
+ guid = str(uuid.uuid4())
+ path = os.path.abspath(BUILD_DIR).replace("\\","\\\\")
+ assemblySignStr = """
+{
+ "Version": "1.0.0",
+ "SignBatches"
+ :
+ [
+ {
+ "SourceLocationType": "UNC",
+ "SourceRootDirectory": "%s",
+ "DestinationLocationType": "UNC",
+ "DestinationRootDirectory": "c:\\\\ESRP\\\\output",
+ "SignRequestFiles": [
+ {
+ "CustomerCorrelationId": "%s",
+ "SourceLocation": "libz3.dll",
+ "DestinationLocation": "libz3.dll"
+ },
+ {
+ "CustomerCorrelationId": "%s",
+ "SourceLocation": "Microsoft.Z3.dll",
+ "DestinationLocation": "Microsoft.Z3.dll"
+ }
+ ],
+ "SigningInfo": {
+ "Operations": [
+ {
+ "KeyCode" : "CP-230012",
+ "OperationCode" : "SigntoolSign",
+ "Parameters" : {
+ "OpusName": "Microsoft",
+ "OpusInfo": "http://www.microsoft.com",
+ "FileDigest": "/fd \\"SHA256\\"",
+ "PageHash": "/NPH",
+ "TimeStamp": "/tr \\"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\\" /td sha256"
+ },
+ "ToolName" : "sign",
+ "ToolVersion" : "1.0"
+ },
+ {
+ "KeyCode" : "CP-230012",
+ "OperationCode" : "SigntoolVerify",
+ "Parameters" : {},
+ "ToolName" : "sign",
+ "ToolVersion" : "1.0"
+ }
+ ]
+ }
+ }
+ ]
+} """ % (path, guid, guid)
+ assemblySign = os.path.join(os.path.abspath(BUILD_DIR), 'dotnet', 'assembly-sign-input.json')
+ with open(assemblySign, 'w') as ous:
+ ous.write(assemblySignStr)
+ outputFile = os.path.join(os.path.abspath(BUILD_DIR), 'dotnet', "esrp-out.json")
+ esrpCmdLine = ["esrpclient.exe", "sign", "-a", "C:\\esrp\\config\\authorization.json", "-p", "C:\\esrp\\config\\policy.json", "-i", assemblySign, "-o", outputFile]
+ MakeRuleCmd.write_cmd(out, ' '.join(esrpCmdLine))
+ MakeRuleCmd.write_cmd(out, "move /Y C:\\esrp\\output\\libz3.dll .")
+ MakeRuleCmd.write_cmd(out, "move /Y C:\\esrp\\output\\Microsoft.Z3.dll .")
+
def main_component(self):
return is_dotnet_core_enabled()
def has_assembly_info(self):
# TBD: is this required for dotnet core given that version numbers are in z3.csproj file?
- return True
+ return False
+
def mk_win_dist(self, build_path, dist_path):
if is_dotnet_core_enabled():
mk_dir(os.path.join(dist_path, INSTALL_BIN_DIR))
@@ -2635,7 +2725,7 @@ def mk_config():
'SLINK_FLAGS=/nologo /LDd\n' % static_opt)
if VS_X64:
config.write(
- 'CXXFLAGS=/c /Zi /nologo /W3 /WX- /Od /Oy- /D WIN32 /D _AMD64_ /D _DEBUG /D Z3DEBUG /D _CONSOLE /D _TRACE /D _WINDOWS /Gm- /EHsc /RTC1 /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /analyze- %s %s\n' % (extra_opt, static_opt))
+ 'CXXFLAGS=/c /Zi /nologo /W3 /WX- /Od /Oy- /D WIN32 /D _DEBUG /D Z3DEBUG /D _CONSOLE /D _TRACE /D _WINDOWS /Gm- /EHsc /RTC1 /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /analyze- %s %s\n' % (extra_opt, static_opt))
config.write(
'LINK_EXTRA_FLAGS=/link /DEBUG /MACHINE:X64 /SUBSYSTEM:CONSOLE /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE /NXCOMPAT %s\n'
'SLINK_EXTRA_FLAGS=/link /DEBUG /MACHINE:X64 /SUBSYSTEM:WINDOWS /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 %s %s\n' % (link_extra_opt, maybe_disable_dynamic_base, link_extra_opt))
@@ -2660,7 +2750,7 @@ def mk_config():
extra_opt = '%s /D _TRACE ' % extra_opt
if VS_X64:
config.write(
- 'CXXFLAGS=/c%s /Zi /nologo /W3 /WX- /O2 /D _EXTERNAL_RELEASE /D WIN32 /D NDEBUG /D _LIB /D _WINDOWS /D _AMD64_ /D _UNICODE /D UNICODE /Gm- /EHsc /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /TP %s %s\n' % (GL, extra_opt, static_opt))
+ 'CXXFLAGS=/c%s /Zi /nologo /W3 /WX- /O2 /D _EXTERNAL_RELEASE /D WIN32 /D NDEBUG /D _LIB /D _WINDOWS /D _UNICODE /D UNICODE /Gm- /EHsc /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /TP %s %s\n' % (GL, extra_opt, static_opt))
config.write(
'LINK_EXTRA_FLAGS=/link%s /MACHINE:X64 /SUBSYSTEM:CONSOLE /INCREMENTAL:NO /STACK:8388608 %s\n'
'SLINK_EXTRA_FLAGS=/link%s /MACHINE:X64 /SUBSYSTEM:WINDOWS /INCREMENTAL:NO /STACK:8388608 %s\n' % (LTCG, link_extra_opt, LTCG, link_extra_opt))
@@ -2782,7 +2872,6 @@ def mk_config():
if is64():
if not sysname.startswith('CYGWIN') and not sysname.startswith('MSYS') and not sysname.startswith('MINGW'):
CXXFLAGS = '%s -fPIC' % CXXFLAGS
- CPPFLAGS = '%s -D_AMD64_' % CPPFLAGS
if sysname == 'Linux':
CPPFLAGS = '%s -D_USE_THREAD_LOCAL' % CPPFLAGS
elif not LINUX_X64:
@@ -3020,19 +3109,7 @@ def mk_version_dot_h(major, minor, build, revision):
def mk_all_assembly_infos(major, minor, build, revision):
for c in get_components():
if c.has_assembly_info():
- assembly_info_template = os.path.join(c.src_dir, c.assembly_info_dir, 'AssemblyInfo.cs.in')
- assembly_info_output = assembly_info_template[:-3]
- assert assembly_info_output.endswith('.cs')
- if os.path.exists(assembly_info_template):
- configure_file(assembly_info_template, assembly_info_output,
- { 'VER_MAJOR': str(major),
- 'VER_MINOR': str(minor),
- 'VER_BUILD': str(build),
- 'VER_REVISION': str(revision),
- }
- )
- else:
- raise MKException("Failed to find assembly template info file '%s'" % assembly_info_template)
+ c.make_assembly_info(major, minor, build, revision)
def get_header_files_for_components(component_src_dirs):
assert isinstance(component_src_dirs, list)
diff --git a/scripts/mk_win_dist.py b/scripts/mk_win_dist.py
index bd3cad18a..2a88c625c 100644
--- a/scripts/mk_win_dist.py
+++ b/scripts/mk_win_dist.py
@@ -26,6 +26,7 @@ DIST_DIR='dist'
FORCE_MK=False
DOTNET_ENABLED=True
DOTNET_CORE_ENABLED=False
+ESRP_SIGN=False
DOTNET_KEY_FILE=None
JAVA_ENABLED=True
GIT_HASH=False
@@ -65,6 +66,7 @@ def display_help():
print(" --nodotnet do not include .NET bindings in the binary distribution files.")
print(" --dotnetcore build for dotnet core.")
print(" --dotnet-key= sign the .NET assembly with the private key in .")
+ print(" --esrp sign with esrp.")
print(" --nojava do not include Java bindings in the binary distribution files.")
print(" --nopython do not include Python bindings in the binary distribution files.")
print(" --githash include git hash in the Zip file.")
@@ -74,7 +76,7 @@ def display_help():
# Parse configuration option for mk_make script
def parse_options():
- global FORCE_MK, JAVA_ENABLED, GIT_HASH, DOTNET_ENABLED, DOTNET_CORE_ENABLED, DOTNET_KEY_FILE, PYTHON_ENABLED, X86ONLY, X64ONLY
+ global FORCE_MK, JAVA_ENABLED, GIT_HASH, DOTNET_ENABLED, DOTNET_CORE_ENABLED, DOTNET_KEY_FILE, PYTHON_ENABLED, X86ONLY, X64ONLY, ESRP_SIGN
path = BUILD_DIR
options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:hsf', ['build=',
'help',
@@ -84,6 +86,7 @@ def parse_options():
'nodotnet',
'dotnetcore',
'dotnet-key=',
+ 'esrp',
'githash',
'nopython',
'x86-only',
@@ -109,6 +112,8 @@ def parse_options():
PYTHON_ENABLED = False
elif opt == '--dotnet-key':
DOTNET_KEY_FILE = arg
+ elif opt == '--esrp':
+ ESRP_SIGN = True
elif opt == '--nojava':
JAVA_ENABLED = False
elif opt == '--githash':
@@ -142,6 +147,8 @@ def mk_build_dir(path, x64):
opts.append('--java')
if x64:
opts.append('-x')
+ if ESRP_SIGN:
+ opts.append('--esrp')
if GIT_HASH:
opts.append('--githash=%s' % mk_util.git_hash())
opts.append('--git-describe')
@@ -210,6 +217,7 @@ def get_z3_name(x64):
return 'z3-%s.%s.%s-%s-win' % (major, minor, build, platform)
def mk_dist_dir(x64):
+ global ESRP_SIGN
if x64:
platform = "x64"
build_path = BUILD_X64_DIR
@@ -218,6 +226,7 @@ def mk_dist_dir(x64):
build_path = BUILD_X86_DIR
dist_path = os.path.join(DIST_DIR, get_z3_name(x64))
mk_dir(dist_path)
+ mk_util.ESRP_SIGN = ESRP_SIGN
if DOTNET_CORE_ENABLED:
mk_util.DOTNET_CORE_ENABLED = True
else:
diff --git a/scripts/update_api.py b/scripts/update_api.py
index 901ea4fda..6b953eefe 100755
--- a/scripts/update_api.py
+++ b/scripts/update_api.py
@@ -338,26 +338,33 @@ def Z3_set_error_handler(ctx, hndlr, _elems=Elementaries(_lib.Z3_set_error_handl
""")
for sig in _API2PY:
- name = sig[0]
- result = sig[1]
- params = sig[2]
- num = len(params)
- core_py.write("def %s(" % name)
- display_args(num)
- comma = ", " if num != 0 else ""
- core_py.write("%s_elems=Elementaries(_lib.%s)):\n" % (comma, name))
- lval = "r = " if result != VOID else ""
- core_py.write(" %s_elems.f(" % lval)
- display_args_to_z3(params)
- core_py.write(")\n")
- if len(params) > 0 and param_type(params[0]) == CONTEXT and not name in Unwrapped:
- core_py.write(" _elems.Check(a0)\n")
- if result == STRING:
- core_py.write(" return _to_pystr(r)\n")
- elif result != VOID:
- core_py.write(" return r\n")
- core_py.write("\n")
- core_py
+ mk_py_wrapper_single(sig)
+ if sig[1] == STRING:
+ mk_py_wrapper_single(sig, decode_string=False)
+
+def mk_py_wrapper_single(sig, decode_string=True):
+ name = sig[0]
+ result = sig[1]
+ params = sig[2]
+ num = len(params)
+ def_name = name
+ if not decode_string:
+ def_name += '_bytes'
+ core_py.write("def %s(" % def_name)
+ display_args(num)
+ comma = ", " if num != 0 else ""
+ core_py.write("%s_elems=Elementaries(_lib.%s)):\n" % (comma, name))
+ lval = "r = " if result != VOID else ""
+ core_py.write(" %s_elems.f(" % lval)
+ display_args_to_z3(params)
+ core_py.write(")\n")
+ if len(params) > 0 and param_type(params[0]) == CONTEXT and not name in Unwrapped:
+ core_py.write(" _elems.Check(a0)\n")
+ if result == STRING and decode_string:
+ core_py.write(" return _to_pystr(r)\n")
+ elif result != VOID:
+ core_py.write(" return r\n")
+ core_py.write("\n")
## .NET API native interface
@@ -584,7 +591,7 @@ def mk_java(java_dir, package_name):
java_wrapper.write('extern "C" {\n')
java_wrapper.write('#endif\n\n')
java_wrapper.write('#ifdef __GNUC__\n#if __GNUC__ >= 4\n#define DLL_VIS __attribute__ ((visibility ("default")))\n#else\n#define DLL_VIS\n#endif\n#else\n#define DLL_VIS\n#endif\n\n')
- java_wrapper.write('#if defined(_M_X64) || defined(_AMD64_)\n\n')
+ java_wrapper.write('#if defined(__LP64__) || defined(_WIN64)\n\n')
java_wrapper.write('#define GETLONGAELEMS(T,OLD,NEW) \\\n')
java_wrapper.write(' T * NEW = (OLD == 0) ? 0 : (T*) jenv->GetLongArrayElements(OLD, NULL);\n')
java_wrapper.write('#define RELEASELONGAELEMS(OLD,NEW) \\\n')
@@ -1335,6 +1342,10 @@ z3_long_funs = frozenset([
'Z3_simplify_ex',
])
+z3_ml_overrides = frozenset([
+ 'Z3_mk_config'
+ ])
+
def mk_z3native_stubs_c(ml_src_dir, ml_output_dir): # C interface
ml_wrapperf = os.path.join(ml_output_dir, 'z3native_stubs.c')
ml_wrapper = open(ml_wrapperf, 'w')
@@ -1346,6 +1357,10 @@ def mk_z3native_stubs_c(ml_src_dir, ml_output_dir): # C interface
ml_pref.close()
for name, result, params in _dotnet_decls:
+
+ if name in z3_ml_overrides:
+ continue
+
ip = inparams(params)
op = outparams(params)
ap = arrayparams(params)
@@ -1528,6 +1543,11 @@ def mk_z3native_stubs_c(ml_src_dir, ml_output_dir): # C interface
i = i + 1
ml_wrapper.write(');\n')
+ if name in NULLWrapped:
+ ml_wrapper.write(' if (z3rv_m == NULL) {\n')
+ ml_wrapper.write(' caml_raise_with_string(*caml_named_value("Z3EXCEPTION"), "Object allocation failed");\n')
+ ml_wrapper.write(' }\n')
+
if release_caml_gc:
ml_wrapper.write('\n caml_acquire_runtime_system();\n')
diff --git a/src/ackermannization/ackr_bound_probe.cpp b/src/ackermannization/ackr_bound_probe.cpp
index c6cdaf268..4c18a3f7e 100644
--- a/src/ackermannization/ackr_bound_probe.cpp
+++ b/src/ackermannization/ackr_bound_probe.cpp
@@ -65,7 +65,7 @@ public:
for_each_expr_core(p, visited, g.form(i));
}
const double total = ackr_helper::calculate_lemma_bound(p.m_fun2terms);
- TRACE("ackr_bound_probe", tout << "total=" << total << std::endl;);
+ TRACE("ackermannize", tout << "total=" << total << std::endl;);
return result(total);
}
diff --git a/src/ackermannization/ackr_model_converter.cpp b/src/ackermannization/ackr_model_converter.cpp
index c5e04ab23..4815d5a2c 100644
--- a/src/ackermannization/ackr_model_converter.cpp
+++ b/src/ackermannization/ackr_model_converter.cpp
@@ -84,7 +84,7 @@ void ackr_model_converter::convert(model * source, model * destination) {
}
void ackr_model_converter::convert_constants(model * source, model * destination) {
- TRACE("ackr_model", tout << "converting constants\n";);
+ TRACE("ackermannize", tout << "converting constants\n";);
obj_map interpretations;
model_evaluator evaluator(*source);
evaluator.set_model_completion(true);
@@ -113,7 +113,7 @@ void ackr_model_converter::convert_constants(model * source, model * destination
void ackr_model_converter::add_entry(model_evaluator & evaluator,
app* term, expr* value,
obj_map& interpretations) {
- TRACE("ackr_model", tout << "add_entry"
+ TRACE("ackermannize", tout << "add_entry"
<< mk_ismt2_pp(term, m, 2)
<< "->"
<< mk_ismt2_pp(value, m, 2) << "\n";
@@ -137,7 +137,7 @@ void ackr_model_converter::add_entry(model_evaluator & evaluator,
args.push_back(std::move(arg_value));
}
if (fi->get_entry(args.c_ptr()) == nullptr) {
- TRACE("ackr_model",
+ TRACE("ackermannize",
tout << mk_ismt2_pp(declaration, m) << " args: " << std::endl;
for (unsigned i = 0; i < args.size(); i++)
tout << mk_ismt2_pp(args.get(i), m) << std::endl;
@@ -145,7 +145,7 @@ void ackr_model_converter::add_entry(model_evaluator & evaluator,
fi->insert_new_entry(args.c_ptr(), value);
}
else {
- TRACE("ackr_model", tout << "entry already present\n";);
+ TRACE("ackermannize", tout << "entry already present\n";);
}
}
diff --git a/src/ackermannization/lackr.cpp b/src/ackermannization/lackr.cpp
index 9130d628c..4fe7797d4 100644
--- a/src/ackermannization/lackr.cpp
+++ b/src/ackermannization/lackr.cpp
@@ -56,7 +56,7 @@ lbool lackr::operator() () {
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,
+ CTRACE("ackermannize", rv == l_true,
model_smt2_pp(tout << "abstr_model(\n", m_m, *(m_model.get()), 2); tout << ")\n"; );
return rv;
}
@@ -89,7 +89,7 @@ bool lackr::init() {
// Introduce ackermann lemma for the two given terms.
//
bool lackr::ackr(app * const t1, app * const t2) {
- TRACE("lackr", tout << "ackr "
+ TRACE("ackermannize", tout << "ackr "
<< mk_ismt2_pp(t1, m_m, 2) << " , " << mk_ismt2_pp(t2, m_m, 2) << "\n";);
const unsigned sz = t1->get_num_args();
SASSERT(t2->get_num_args() == sz);
@@ -99,7 +99,7 @@ bool lackr::ackr(app * const t1, app * const t2) {
expr * const arg2 = t2->get_arg(i);
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";);
+ TRACE("ackermannize", tout << "never eq\n";);
return false;
}
eqs.push_back(m_m.mk_eq(arg1, arg2));
@@ -107,22 +107,22 @@ bool lackr::ackr(app * const t1, app * const t2) {
app * const a1 = m_info->get_abstr(t1);
app * const a2 = m_info->get_abstr(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";);
+ TRACE("ackermannize", tout << "abstr1 " << mk_ismt2_pp(a1, m_m, 2) << "\n";);
+ TRACE("ackermannize", tout << "abstr2 " << mk_ismt2_pp(a2, m_m, 2) << "\n";);
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";);
+ TRACE("ackermannize", 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";);
+ TRACE("ackermannize", tout << "ackr constr rhs" << mk_ismt2_pp(rhs, m_m, 2) << "\n";);
expr_ref cg(m_m.mk_implies(lhs, rhs), m_m);
- TRACE("lackr", tout << "ackr constr" << mk_ismt2_pp(cg, m_m, 2) << "\n";);
+ TRACE("ackermannize", tout << "ackr constr" << mk_ismt2_pp(cg, m_m, 2) << "\n";);
expr_ref cga(m_m);
m_info->abstract(cg, cga); // constraint needs abstraction due to nested applications
m_simp(cga);
- TRACE("lackr", tout << "ackr constr abs:" << mk_ismt2_pp(cga, m_m, 2) << "\n";);
+ TRACE("ackermannize", tout << "ackr constr abs:" << mk_ismt2_pp(cga, m_m, 2) << "\n";);
if (m_m.is_true(cga)) return false;
m_st.m_ackrs_sz++;
- m_ackrs.push_back(cga);
+ m_ackrs.push_back(std::move(cga));
return true;
}
@@ -130,11 +130,10 @@ bool lackr::ackr(app * const t1, app * const t2) {
// Introduce the ackermann lemma for each pair of terms.
//
void lackr::eager_enc() {
- TRACE("lackr", tout << "#funs: " << m_fun2terms.size() << std::endl;);
- const fun2terms_map::iterator e = m_fun2terms.end();
- for (fun2terms_map::iterator i = m_fun2terms.begin(); i != e; ++i) {
+ TRACE("ackermannize", tout << "#funs: " << m_fun2terms.size() << std::endl;);
+ for (auto const& kv : m_fun2terms) {
checkpoint();
- app_set * const ts = i->get_value();
+ app_set * const ts = kv.get_value();
const app_set::iterator r = ts->end();
for (app_set::iterator j = ts->begin(); j != r; ++j) {
app_set::iterator k = j;
@@ -142,10 +141,11 @@ void lackr::eager_enc() {
for (; k != r; ++k) {
app * const t1 = *j;
app * const t2 = *k;
- SASSERT(t1->get_decl() == i->m_key);
- SASSERT(t2->get_decl() == i->m_key);
- if (t1 == t2) continue;
- ackr(t1,t2);
+ SASSERT(t1->get_decl() == kv.m_key);
+ SASSERT(t2->get_decl() == kv.m_key);
+ if (t1 != t2) {
+ ackr(t1,t2);
+ }
}
}
}
@@ -153,18 +153,15 @@ void lackr::eager_enc() {
void lackr::abstract() {
- const fun2terms_map::iterator e = m_fun2terms.end();
- for (fun2terms_map::iterator i = m_fun2terms.begin(); i != e; ++i) {
- func_decl* const fd = i->m_key;
- app_set * const ts = i->get_value();
+ for (auto const& kv : m_fun2terms) {
+ func_decl* const fd = kv.m_key;
+ app_set * const ts = kv.get_value();
sort* const s = fd->get_range();
- const app_set::iterator r = ts->end();
- for (app_set::iterator j = ts->begin(); j != r; ++j) {
+ for (app * t : (*ts)) {
app * const fc = m_m.mk_fresh_const(fd->get_name().str().c_str(), s);
- app * const t = *j;
SASSERT(t->get_decl() == fd);
m_info->set_abstr(t, fc);
- TRACE("lackr", tout << "abstr term "
+ TRACE("ackermannize", tout << "abstr term "
<< mk_ismt2_pp(t, m_m, 2)
<< " -> "
<< mk_ismt2_pp(fc, m_m, 2)
@@ -189,7 +186,7 @@ void lackr::add_term(app* a) {
ts = alloc(app_set);
m_fun2terms.insert(fd, ts);
}
- TRACE("lackr", tout << "term(" << mk_ismt2_pp(a, m_m, 2) << ")\n";);
+ TRACE("ackermannize", tout << "term(" << mk_ismt2_pp(a, m_m, 2) << ")\n";);
ts->insert(a);
}
@@ -203,7 +200,7 @@ void lackr::push_abstraction() {
lbool lackr::eager() {
SASSERT(m_is_init);
push_abstraction();
- TRACE("lackr", tout << "run sat 0\n"; );
+ TRACE("ackermannize", tout << "run sat 0\n"; );
const lbool rv0 = m_sat->check_sat(0, nullptr);
if (rv0 == l_false) return l_false;
eager_enc();
@@ -211,7 +208,7 @@ lbool lackr::eager() {
all = m_m.mk_and(m_ackrs.size(), m_ackrs.c_ptr());
m_simp(all);
m_sat->assert_expr(all);
- TRACE("lackr", tout << "run sat all\n"; );
+ TRACE("ackermannize", tout << "run sat all\n"; );
return m_sat->check_sat(0, nullptr);
}
@@ -223,7 +220,7 @@ lbool lackr::lazy() {
while (true) {
m_st.m_it++;
checkpoint();
- TRACE("lackr", tout << "lazy check: " << m_st.m_it << "\n";);
+ TRACE("ackermannize", tout << "lazy check: " << m_st.m_it << "\n";);
const lbool r = m_sat->check_sat(0, nullptr);
if (r == l_undef) return l_undef; // give up
if (r == l_false) return l_false; // abstraction unsat
@@ -264,16 +261,15 @@ bool lackr::collect_terms() {
visited.mark(curr, true);
stack.pop_back();
break;
- case AST_APP:
- {
+ case AST_APP: {
app * const a = to_app(curr);
if (for_each_expr_args(stack, visited, a->get_num_args(), a->get_args())) {
visited.mark(curr, true);
stack.pop_back();
add_term(a);
}
- }
break;
+ }
case AST_QUANTIFIER:
return false; // quantifiers not supported
default:
diff --git a/src/ackermannization/lackr.h b/src/ackermannization/lackr.h
index 98c1988f7..049fb8bb3 100644
--- a/src/ackermannization/lackr.h
+++ b/src/ackermannization/lackr.h
@@ -102,7 +102,7 @@ class lackr {
//
// Introduce congruence ackermann lemma for the two given terms.
//
- bool ackr(app * const t1, app * const t2);
+ bool ackr(app * t1, app * t2);
//
// Introduce the ackermann lemma for each pair of terms.
diff --git a/src/ackermannization/lackr_model_constructor.cpp b/src/ackermannization/lackr_model_constructor.cpp
index df0aac15e..f24a53cdb 100644
--- a/src/ackermannization/lackr_model_constructor.cpp
+++ b/src/ackermannization/lackr_model_constructor.cpp
@@ -237,7 +237,7 @@ struct lackr_model_constructor::imp {
// handle functions
if (m_ackr_helper.should_ackermannize(a)) { // handle uninterpreted
app_ref key(m_m.mk_app(a->get_decl(), values.c_ptr()), m_m);
- if (!make_value_uninterpreted_function(a, values, key.get(), result)) {
+ if (!make_value_uninterpreted_function(a, key.get(), result)) {
return false;
}
}
@@ -284,7 +284,6 @@ struct lackr_model_constructor::imp {
}
bool make_value_uninterpreted_function(app* a,
- expr_ref_vector& values,
app* key,
expr_ref& result) {
// get ackermann constant
@@ -370,15 +369,12 @@ lackr_model_constructor::lackr_model_constructor(ast_manager& m, ackr_info_ref i
{}
lackr_model_constructor::~lackr_model_constructor() {
- if (m_imp) dealloc(m_imp);
+ dealloc(m_imp);
}
bool lackr_model_constructor::check(model_ref& abstr_model) {
m_conflicts.reset();
- if (m_imp) {
- dealloc(m_imp);
- m_imp = nullptr;
- }
+ dealloc(m_imp);
m_imp = alloc(lackr_model_constructor::imp, m_m, m_info, abstr_model, m_conflicts);
const bool rv = m_imp->check();
m_state = rv ? CHECKED : CONFLICT;
diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp
index d10da60db..eeb85687d 100644
--- a/src/api/api_ast.cpp
+++ b/src/api/api_ast.cpp
@@ -34,6 +34,7 @@ Revision History:
#include "ast/rewriter/var_subst.h"
#include "ast/rewriter/expr_safe_replace.h"
#include "ast/rewriter/recfun_replace.h"
+#include "ast/rewriter/seq_rewriter.h"
#include "ast/pp.h"
#include "util/scoped_ctrl_c.h"
#include "util/cancel_eh.h"
@@ -733,6 +734,7 @@ extern "C" {
Z3_CATCH_RETURN(Z3_L_UNDEF);
}
+
static Z3_ast simplify(Z3_context c, Z3_ast _a, Z3_params _p) {
Z3_TRY;
RESET_ERROR_CODE();
@@ -742,6 +744,7 @@ extern "C" {
unsigned timeout = p.get_uint("timeout", mk_c(c)->get_timeout());
bool use_ctrl_c = p.get_bool("ctrl_c", false);
th_rewriter m_rw(m, p);
+ m_rw.set_solver(alloc(api::seq_expr_solver, m, p));
expr_ref result(m);
cancel_eh eh(m.limit());
api::context::set_interruptable si(*(mk_c(c)), eh);
diff --git a/src/api/api_config_params.cpp b/src/api/api_config_params.cpp
index 54b3c5795..60d5fa556 100644
--- a/src/api/api_config_params.cpp
+++ b/src/api/api_config_params.cpp
@@ -68,10 +68,17 @@ extern "C" {
}
Z3_config Z3_API Z3_mk_config(void) {
- memory::initialize(UINT_MAX);
- LOG_Z3_mk_config();
- Z3_config r = reinterpret_cast(alloc(context_params));
- RETURN_Z3(r);
+ try {
+ memory::initialize(UINT_MAX);
+ LOG_Z3_mk_config();
+ Z3_config r = reinterpret_cast(alloc(context_params));
+ RETURN_Z3(r);
+ } catch (z3_exception & ex) {
+ // The error handler is only available for contexts
+ // Just throw a warning.
+ warning_msg("%s", ex.msg());
+ return nullptr;
+ }
}
void Z3_API Z3_del_config(Z3_config c) {
diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp
index 0b1bf4490..a2492cb1a 100644
--- a/src/api/api_context.cpp
+++ b/src/api/api_context.cpp
@@ -109,13 +109,10 @@ namespace api {
context::~context() {
m_last_obj = nullptr;
- u_map::iterator it = m_allocated_objects.begin();
- while (it != m_allocated_objects.end()) {
- api::object* val = it->m_value;
- DEBUG_CODE(warning_msg("Uncollected memory: %d: %s", it->m_key, typeid(*val).name()););
- m_allocated_objects.remove(it->m_key);
+ for (auto& kv : m_allocated_objects) {
+ api::object* val = kv.m_value;
+ DEBUG_CODE(warning_msg("Uncollected memory: %d: %s", kv.m_key, typeid(*val).name()););
dealloc(val);
- it = m_allocated_objects.begin();
}
}
@@ -489,9 +486,3 @@ extern "C" {
}
};
-
-Z3_API ast_manager& Z3_get_manager(Z3_context c) {
- return mk_c(c)->m();
-}
-
-
diff --git a/src/api/api_context.h b/src/api/api_context.h
index a6b8600d6..aacd4edd3 100644
--- a/src/api/api_context.h
+++ b/src/api/api_context.h
@@ -38,6 +38,9 @@ Revision History:
#include "cmd_context/cmd_context.h"
#include "api/api_polynomial.h"
#include "util/hashtable.h"
+#include "ast/rewriter/seq_rewriter.h"
+#include "smt/smt_solver.h"
+#include "solver/solver.h"
namespace smtlib {
class parser;
@@ -49,6 +52,24 @@ namespace realclosure {
namespace api {
+ class seq_expr_solver : public expr_solver {
+ ast_manager& m;
+ params_ref const& p;
+ solver_ref s;
+ public:
+ seq_expr_solver(ast_manager& m, params_ref const& p): m(m), p(p) {}
+ lbool check_sat(expr* e) {
+ if (!s) {
+ s = mk_smt_solver(m, p, symbol("ALL"));
+ }
+ s->push();
+ s->assert_expr(e);
+ lbool r = s->check_sat();
+ s->pop(1);
+ return r;
+ }
+ };
+
class context : public tactic_manager {
struct add_plugins { add_plugins(ast_manager & m); };
diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp
index 9728cbc00..8301ea604 100644
--- a/src/api/api_fpa.cpp
+++ b/src/api/api_fpa.cpp
@@ -242,8 +242,8 @@ extern "C" {
RETURN_Z3(nullptr);
}
api::context * ctx = mk_c(c);
- expr * a = negative != 0 ? ctx->fpautil().mk_ninf(to_sort(s)) :
- ctx->fpautil().mk_pinf(to_sort(s));
+ expr * a = negative ? ctx->fpautil().mk_ninf(to_sort(s)) :
+ ctx->fpautil().mk_pinf(to_sort(s));
ctx->save_ast_trail(a);
RETURN_Z3(of_expr(a));
Z3_CATCH_RETURN(nullptr);
@@ -259,8 +259,8 @@ extern "C" {
RETURN_Z3(nullptr);
}
api::context * ctx = mk_c(c);
- expr * a = negative != 0 ? ctx->fpautil().mk_nzero(to_sort(s)) :
- ctx->fpautil().mk_pzero(to_sort(s));
+ expr * a = negative ? ctx->fpautil().mk_nzero(to_sort(s)) :
+ ctx->fpautil().mk_pzero(to_sort(s));
ctx->save_ast_trail(a);
RETURN_Z3(of_expr(a));
Z3_CATCH_RETURN(nullptr);
@@ -351,7 +351,7 @@ extern "C" {
ctx->fpautil().fm().set(tmp,
ctx->fpautil().get_ebits(to_sort(ty)),
ctx->fpautil().get_sbits(to_sort(ty)),
- sgn != 0, exp, sig);
+ sgn, exp, sig);
expr * a = ctx->fpautil().mk_value(tmp);
ctx->save_ast_trail(a);
RETURN_Z3(of_expr(a));
@@ -371,7 +371,7 @@ extern "C" {
ctx->fpautil().fm().set(tmp,
ctx->fpautil().get_ebits(to_sort(ty)),
ctx->fpautil().get_sbits(to_sort(ty)),
- sgn != 0, exp, sig);
+ sgn, exp, sig);
expr * a = ctx->fpautil().mk_value(tmp);
ctx->save_ast_trail(a);
RETURN_Z3(of_expr(a));
diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp
index c7347f299..0937e668e 100644
--- a/src/api/api_model.cpp
+++ b/src/api/api_model.cpp
@@ -79,11 +79,7 @@ extern "C" {
Z3_TRY;
LOG_Z3_model_has_interp(c, m, a);
CHECK_NON_NULL(m, 0);
- if (to_model_ref(m)->has_interpretation(to_func_decl(a))) {
- return true;
- } else {
- return false;
- }
+ return to_model_ref(m)->has_interpretation(to_func_decl(a));
Z3_CATCH_RETURN(false);
}
@@ -165,7 +161,10 @@ extern "C" {
CHECK_NON_NULL(m, false);
CHECK_IS_EXPR(t, false);
model * _m = to_model_ref(m);
- expr_ref result(mk_c(c)->m());
+ params_ref p;
+ ast_manager& mgr = mk_c(c)->m();
+ _m->set_solver(alloc(api::seq_expr_solver, mgr, p));
+ expr_ref result(mgr);
model::scoped_model_completion _scm(*_m, model_completion);
result = (*_m)(to_expr(t));
mk_c(c)->save_ast_trail(result.get());
@@ -472,7 +471,7 @@ extern "C" {
model_smt2_pp(buffer, mk_c(c)->m(), *(to_model_ref(m)), 0);
// Hack for removing the trailing '\n'
result = buffer.str();
- if (result.size() != 0)
+ if (!result.empty())
result.resize(result.size()-1);
}
else {
diff --git a/src/api/api_numeral.cpp b/src/api/api_numeral.cpp
index cfa64e2c3..90d5998f3 100644
--- a/src/api/api_numeral.cpp
+++ b/src/api/api_numeral.cpp
@@ -198,19 +198,19 @@ extern "C" {
mpf_rounding_mode rm;
if (mk_c(c)->fpautil().is_rm_numeral(to_expr(a), rm)) {
switch (rm) {
- case OP_FPA_RM_NEAREST_TIES_TO_EVEN:
+ case MPF_ROUND_NEAREST_TEVEN:
return mk_c(c)->mk_external_string("roundNearestTiesToEven");
break;
- case OP_FPA_RM_NEAREST_TIES_TO_AWAY:
+ case MPF_ROUND_NEAREST_TAWAY:
return mk_c(c)->mk_external_string("roundNearestTiesToAway");
break;
- case OP_FPA_RM_TOWARD_POSITIVE:
+ case MPF_ROUND_TOWARD_POSITIVE:
return mk_c(c)->mk_external_string("roundTowardPositive");
break;
- case OP_FPA_RM_TOWARD_NEGATIVE:
+ case MPF_ROUND_TOWARD_NEGATIVE:
return mk_c(c)->mk_external_string("roundTowardNegative");
break;
- case OP_FPA_RM_TOWARD_ZERO:
+ case MPF_ROUND_TOWARD_ZERO:
default:
return mk_c(c)->mk_external_string("roundTowardZero");
break;
diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp
index 0b56b788d..5d35b23b0 100644
--- a/src/api/api_opt.cpp
+++ b/src/api/api_opt.cpp
@@ -79,6 +79,16 @@ extern "C" {
Z3_CATCH;
}
+ void Z3_API Z3_optimize_assert_and_track(Z3_context c, Z3_optimize o, Z3_ast a, Z3_ast t) {
+ Z3_TRY;
+ LOG_Z3_optimize_assert_and_track(c, o, a, t);
+ RESET_ERROR_CODE();
+ CHECK_FORMULA(a,);
+ CHECK_FORMULA(t,);
+ to_optimize_ptr(o)->add_hard_constraint(to_expr(a), to_expr(t));
+ Z3_CATCH;
+ }
+
unsigned Z3_API Z3_optimize_assert_soft(Z3_context c, Z3_optimize o, Z3_ast a, Z3_string weight, Z3_symbol id) {
Z3_TRY;
LOG_Z3_optimize_assert_soft(c, o, a, weight, id);
diff --git a/src/api/api_params.cpp b/src/api/api_params.cpp
index 31a196f96..b2fa2e815 100644
--- a/src/api/api_params.cpp
+++ b/src/api/api_params.cpp
@@ -66,7 +66,7 @@ extern "C" {
Z3_TRY;
LOG_Z3_params_set_bool(c, p, k, v);
RESET_ERROR_CODE();
- to_params(p)->m_params.set_bool(norm_param_name(to_symbol(k)).c_str(), v != 0);
+ to_params(p)->m_params.set_bool(norm_param_name(to_symbol(k)).c_str(), v);
Z3_CATCH;
}
diff --git a/src/api/api_rcf.cpp b/src/api/api_rcf.cpp
index bcaf0869f..840f6d3a8 100644
--- a/src/api/api_rcf.cpp
+++ b/src/api/api_rcf.cpp
@@ -274,7 +274,7 @@ extern "C" {
RESET_ERROR_CODE();
reset_rcf_cancel(c);
std::ostringstream buffer;
- rcfm(c).display(buffer, to_rcnumeral(a), compact != 0, html != 0);
+ rcfm(c).display(buffer, to_rcnumeral(a), compact, html);
return mk_c(c)->mk_external_string(buffer.str());
Z3_CATCH_RETURN("");
}
diff --git a/src/api/api_seq.cpp b/src/api/api_seq.cpp
index 6b48360a3..19e298ee8 100644
--- a/src/api/api_seq.cpp
+++ b/src/api/api_seq.cpp
@@ -106,8 +106,8 @@ extern "C" {
SET_ERROR_CODE(Z3_INVALID_ARG, "expression is not a string literal");
return "";
}
- std::string result = str.encode();
- return mk_c(c)->mk_external_string(result);
+ std::string s = str.encode();
+ return mk_c(c)->mk_external_string(s);
Z3_CATCH_RETURN("");
}
diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp
index a5ad7b525..cafbfb9ff 100644
--- a/src/api/api_solver.cpp
+++ b/src/api/api_solver.cpp
@@ -163,12 +163,45 @@ extern "C" {
to_solver_ref(s)->set_model_converter(ctx->get_model_converter());
}
+ static void solver_from_dimacs_stream(Z3_context c, Z3_solver s, std::istream& is) {
+ init_solver(c, s);
+ ast_manager& m = to_solver_ref(s)->get_manager();
+ std::stringstream err;
+ sat::solver solver(to_solver_ref(s)->get_params(), m.limit());
+ if (!parse_dimacs(is, err, solver)) {
+ SET_ERROR_CODE(Z3_PARSER_ERROR, err.str().c_str());
+ return;
+ }
+ sat2goal s2g;
+ ref mc;
+ atom2bool_var a2b(m);
+ for (unsigned v = 0; v < solver.num_vars(); ++v) {
+ a2b.insert(m.mk_const(symbol(v), m.mk_bool_sort()), v);
+ }
+ goal g(m);
+ s2g(solver, a2b, to_solver_ref(s)->get_params(), g, mc);
+ for (unsigned i = 0; i < g.size(); ++i) {
+ to_solver_ref(s)->assert_expr(g.form(i));
+ }
+ }
+
+ // DIMACS files start with "p cnf" and number of variables/clauses.
+ // This is not legal SMT syntax, so use the DIMACS parser.
+ static bool is_dimacs_string(Z3_string c_str) {
+ return c_str[0] == 'p' && c_str[1] == ' ' && c_str[2] == 'c';
+ }
+
void Z3_API Z3_solver_from_string(Z3_context c, Z3_solver s, Z3_string c_str) {
Z3_TRY;
LOG_Z3_solver_from_string(c, s, c_str);
std::string str(c_str);
std::istringstream is(str);
- solver_from_stream(c, s, is);
+ if (is_dimacs_string(c_str)) {
+ solver_from_dimacs_stream(c, s, is);
+ }
+ else {
+ solver_from_stream(c, s, is);
+ }
Z3_CATCH;
}
@@ -181,25 +214,8 @@ extern "C" {
if (!is) {
SET_ERROR_CODE(Z3_FILE_ACCESS_ERROR, nullptr);
}
- else if (ext && std::string("dimacs") == ext) {
- ast_manager& m = to_solver_ref(s)->get_manager();
- std::stringstream err;
- sat::solver solver(to_solver_ref(s)->get_params(), m.limit());
- if (!parse_dimacs(is, err, solver)) {
- SET_ERROR_CODE(Z3_PARSER_ERROR, err.str().c_str());
- return;
- }
- sat2goal s2g;
- ref mc;
- atom2bool_var a2b(m);
- for (unsigned v = 0; v < solver.num_vars(); ++v) {
- a2b.insert(m.mk_const(symbol(v), m.mk_bool_sort()), v);
- }
- goal g(m);
- s2g(solver, a2b, to_solver_ref(s)->get_params(), g, mc);
- for (unsigned i = 0; i < g.size(); ++i) {
- to_solver_ref(s)->assert_expr(g.form(i));
- }
+ else if (ext && (std::string("dimacs") == ext || std::string("cnf") == ext)) {
+ solver_from_dimacs_stream(c, s, is);
}
else {
solver_from_stream(c, s, is);
@@ -369,7 +385,7 @@ extern "C" {
init_solver(c, s);
Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m());
mk_c(c)->save_object(v);
- expr_ref_vector fmls = to_solver_ref(s)->get_units(mk_c(c)->m());
+ expr_ref_vector fmls = to_solver_ref(s)->get_units();
for (expr* f : fmls) {
v->m_ast_vector.push_back(f);
}
@@ -384,7 +400,7 @@ extern "C" {
init_solver(c, s);
Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m());
mk_c(c)->save_object(v);
- expr_ref_vector fmls = to_solver_ref(s)->get_non_units(mk_c(c)->m());
+ expr_ref_vector fmls = to_solver_ref(s)->get_non_units();
for (expr* f : fmls) {
v->m_ast_vector.push_back(f);
}
@@ -392,6 +408,53 @@ extern "C" {
Z3_CATCH_RETURN(nullptr);
}
+ void Z3_API Z3_solver_get_levels(Z3_context c, Z3_solver s, Z3_ast_vector literals, unsigned sz, unsigned levels[]) {
+ Z3_TRY;
+ LOG_Z3_solver_get_levels(c, s, literals, sz, levels);
+ RESET_ERROR_CODE();
+ init_solver(c, s);
+ if (sz != Z3_ast_vector_size(c, literals)) {
+ SET_ERROR_CODE(Z3_IOB, nullptr);
+ return;
+ }
+ ptr_vector _vars;
+ for (unsigned i = 0; i < sz; ++i) {
+ expr* e = to_expr(Z3_ast_vector_get(c, literals, i));
+ mk_c(c)->m().is_not(e, e);
+ _vars.push_back(e);
+ }
+ unsigned_vector _levels(sz);
+ to_solver_ref(s)->get_levels(_vars, _levels);
+ for (unsigned i = 0; i < sz; ++i) {
+ levels[i] = _levels[i];
+ }
+ Z3_CATCH;
+ }
+
+ void Z3_API Z3_solver_set_activity(Z3_context c, Z3_solver s, Z3_ast a, double activity) {
+ Z3_TRY;
+ LOG_Z3_solver_set_activity(c, s, a, activity);
+ RESET_ERROR_CODE();
+ init_solver(c, s);
+ to_solver_ref(s)->set_activity(to_expr(a), activity);
+ Z3_CATCH;
+ }
+
+ Z3_ast_vector Z3_API Z3_solver_get_trail(Z3_context c, Z3_solver s) {
+ Z3_TRY;
+ LOG_Z3_solver_get_trail(c, s);
+ RESET_ERROR_CODE();
+ init_solver(c, s);
+ Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m());
+ mk_c(c)->save_object(v);
+ expr_ref_vector trail = to_solver_ref(s)->get_trail();
+ for (expr* f : trail) {
+ v->m_ast_vector.push_back(f);
+ }
+ RETURN_Z3(of_ast_vector(v));
+ Z3_CATCH_RETURN(nullptr);
+ }
+
static Z3_lbool _solver_check(Z3_context c, Z3_solver s, unsigned num_assumptions, Z3_ast const assumptions[]) {
for (unsigned i = 0; i < num_assumptions; i++) {
if (!is_expr(to_ast(assumptions[i]))) {
@@ -532,6 +595,17 @@ extern "C" {
Z3_CATCH_RETURN("");
}
+ Z3_string Z3_API Z3_solver_to_dimacs_string(Z3_context c, Z3_solver s) {
+ Z3_TRY;
+ LOG_Z3_solver_to_string(c, s);
+ RESET_ERROR_CODE();
+ init_solver(c, s);
+ std::ostringstream buffer;
+ to_solver_ref(s)->display_dimacs(buffer);
+ return mk_c(c)->mk_external_string(buffer.str());
+ Z3_CATCH_RETURN("");
+ }
+
Z3_lbool Z3_API Z3_get_implied_equalities(Z3_context c,
Z3_solver s,
diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h
index d5d3bc1ff..6113fdbe9 100644
--- a/src/api/c++/z3++.h
+++ b/src/api/c++/z3++.h
@@ -388,6 +388,7 @@ namespace z3 {
template
array(ast_vector_tpl const & v);
~array() { delete[] m_array; }
+ void resize(unsigned sz) { delete[] m_array; m_size = sz; m_array = new T[sz]; }
unsigned size() const { return m_size; }
T & operator[](int i) { assert(0 <= i); assert(static_cast(i) < m_size); return m_array[i]; }
T const & operator[](int i) const { assert(0 <= i); assert(static_cast(i) < m_size); return m_array[i]; }
@@ -505,7 +506,7 @@ namespace z3 {
out << Z3_ast_to_string(n.ctx(), n.m_ast); return out;
}
- inline bool eq(ast const & a, ast const & b) { return Z3_is_eq_ast(a.ctx(), a, b) != 0; }
+ inline bool eq(ast const & a, ast const & b) { return Z3_is_eq_ast(a.ctx(), a, b); }
/**
@@ -518,6 +519,12 @@ namespace z3 {
sort(context & c, Z3_ast a):ast(c, a) {}
sort(sort const & s):ast(s) {}
operator Z3_sort() const { return reinterpret_cast(m_ast); }
+
+ /**
+ \brief retrieve unique identifier for func_decl.
+ */
+ unsigned id() const { unsigned r = Z3_get_sort_id(ctx(), *this); check_error(); return r; }
+
/**
\brief Return true if this sort and \c s are equal.
*/
@@ -615,6 +622,11 @@ namespace z3 {
operator Z3_func_decl() const { return reinterpret_cast(m_ast); }
func_decl & operator=(func_decl const & s) { return static_cast(ast::operator=(s)); }
+ /**
+ \brief retrieve unique identifier for func_decl.
+ */
+ unsigned id() const { unsigned r = Z3_get_func_decl_id(ctx(), *this); check_error(); return r; }
+
unsigned arity() const { return Z3_get_arity(ctx(), *this); }
sort domain(unsigned i) const { assert(i < arity()); Z3_sort r = Z3_get_domain(ctx(), *this, i); check_error(); return sort(ctx(), r); }
sort range() const { Z3_sort r = Z3_get_range(ctx(), *this); check_error(); return sort(ctx(), r); }
@@ -713,10 +725,10 @@ namespace z3 {
small integers, 64 bit integers or rational or decimal strings.
*/
bool is_numeral() const { return kind() == Z3_NUMERAL_AST; }
- bool is_numeral_i64(int64_t& i) const { bool r = 0 != Z3_get_numeral_int64(ctx(), m_ast, &i); check_error(); return r;}
- bool is_numeral_u64(uint64_t& 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_i64(int64_t& i) const { bool r = Z3_get_numeral_int64(ctx(), m_ast, &i); check_error(); return r;}
+ bool is_numeral_u64(uint64_t& i) const { bool r = Z3_get_numeral_uint64(ctx(), m_ast, &i); check_error(); return r;}
+ bool is_numeral_i(int& i) const { bool r = Z3_get_numeral_int(ctx(), m_ast, &i); check_error(); return r;}
+ bool is_numeral_u(unsigned& i) const { bool r = 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; }
bool is_numeral(double& d) const { if (!is_numeral()) return false; d = Z3_get_numeral_double(ctx(), m_ast); check_error(); return true; }
@@ -736,15 +748,15 @@ namespace z3 {
/**
\brief Return true if this expression is a universal quantifier.
*/
- bool is_forall() const { return 0 != Z3_is_quantifier_forall(ctx(), m_ast); }
+ bool is_forall() const { return Z3_is_quantifier_forall(ctx(), m_ast); }
/**
\brief Return true if this expression is an existential quantifier.
*/
- bool is_exists() const { return 0 != Z3_is_quantifier_exists(ctx(), m_ast); }
+ bool is_exists() const { return Z3_is_quantifier_exists(ctx(), m_ast); }
/**
\brief Return true if this expression is a lambda expression.
*/
- bool is_lambda() const { return 0 != Z3_is_lambda(ctx(), m_ast); }
+ bool is_lambda() const { return Z3_is_lambda(ctx(), m_ast); }
/**
\brief Return true if this expression is a variable.
@@ -753,12 +765,12 @@ namespace z3 {
/**
\brief Return true if expression is an algebraic number.
*/
- bool is_algebraic() const { return 0 != Z3_is_algebraic_number(ctx(), m_ast); }
+ bool is_algebraic() const { return 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; }
+ bool is_well_sorted() const { bool r = Z3_is_well_sorted(ctx(), m_ast); check_error(); return r; }
/**
\brief Return string representation of numeral or algebraic number
@@ -771,6 +783,11 @@ namespace z3 {
return std::string(Z3_get_numeral_decimal_string(ctx(), m_ast, precision));
}
+ /**
+ \brief retrieve unique identifier for expression.
+ */
+ unsigned id() const { unsigned r = Z3_get_ast_id(ctx(), m_ast); check_error(); return r; }
+
/**
\brief Return int value of numeral, throw if result cannot fit in
machine int
@@ -1720,6 +1737,10 @@ namespace z3 {
m_vector = s.m_vector;
return *this;
}
+ ast_vector_tpl& set(unsigned idx, ast& a) {
+ Z3_ast_vector_set(ctx(), m_vector, idx, a);
+ return *this;
+ }
/*
Disabled pending C++98 build upgrade
bool contains(T const& x) const {
@@ -1746,6 +1767,9 @@ namespace z3 {
++m_index;
return *this;
}
+ void set(T& arg) {
+ Z3_ast_vector_set(m_vector->ctx(), *m_vector, m_index, arg);
+ }
iterator operator++(int) { iterator tmp = *this; ++m_index; return tmp; }
T * operator->() const { return &(operator*()); }
T operator*() const { return (*m_vector)[m_index]; }
@@ -2073,7 +2097,7 @@ namespace z3 {
// for function f.
bool has_interp(func_decl f) const {
check_context(*this, f);
- return 0 != Z3_model_has_interp(ctx(), m_model, f);
+ return Z3_model_has_interp(ctx(), m_model, f);
}
func_interp add_func_interp(func_decl& f, expr& else_val) {
@@ -2112,8 +2136,8 @@ namespace z3 {
}
unsigned size() const { return Z3_stats_size(ctx(), m_stats); }
std::string key(unsigned i) const { Z3_string s = Z3_stats_get_key(ctx(), m_stats, i); check_error(); return s; }
- bool is_uint(unsigned i) const { bool r = Z3_stats_is_uint(ctx(), m_stats, i); check_error(); return r != 0; }
- bool is_double(unsigned i) const { bool r = Z3_stats_is_double(ctx(), m_stats, i); check_error(); return r != 0; }
+ bool is_uint(unsigned i) const { bool r = Z3_stats_is_uint(ctx(), m_stats, i); check_error(); return r; }
+ bool is_double(unsigned i) const { bool r = Z3_stats_is_double(ctx(), m_stats, i); check_error(); return r; }
unsigned uint_value(unsigned i) const { unsigned r = Z3_stats_get_uint_value(ctx(), m_stats, i); check_error(); return r; }
double double_value(unsigned i) const { double r = Z3_stats_get_double_value(ctx(), m_stats, i); check_error(); return r; }
friend std::ostream & operator<<(std::ostream & out, stats const & s);
@@ -2210,6 +2234,18 @@ namespace z3 {
expr_vector assertions() const { Z3_ast_vector r = Z3_solver_get_assertions(ctx(), m_solver); check_error(); return expr_vector(ctx(), r); }
expr_vector non_units() const { Z3_ast_vector r = Z3_solver_get_non_units(ctx(), m_solver); check_error(); return expr_vector(ctx(), r); }
expr_vector units() const { Z3_ast_vector r = Z3_solver_get_units(ctx(), m_solver); check_error(); return expr_vector(ctx(), r); }
+ expr_vector trail() const { Z3_ast_vector r = Z3_solver_get_trail(ctx(), m_solver); check_error(); return expr_vector(ctx(), r); }
+ expr_vector trail(array& levels) const {
+ Z3_ast_vector r = Z3_solver_get_trail(ctx(), m_solver);
+ check_error();
+ expr_vector result(ctx(), r);
+ unsigned sz = result.size();
+ levels.resize(sz);
+ Z3_solver_get_levels(ctx(), m_solver, r, sz, levels.ptr());
+ check_error();
+ return result;
+ }
+ void set_activity(expr const& lit, double act) { Z3_solver_set_activity(ctx(), m_solver, lit, act); }
expr proof() const { Z3_ast r = Z3_solver_get_proof(ctx(), m_solver); check_error(); return expr(ctx(), r); }
friend std::ostream & operator<<(std::ostream & out, solver const & s);
@@ -2233,6 +2269,8 @@ namespace z3 {
fml));
}
+ std::string dimacs() const { return std::string(Z3_solver_to_dimacs_string(ctx(), m_solver)); }
+
param_descrs get_param_descrs() { return param_descrs(ctx(), Z3_solver_get_param_descrs(ctx(), m_solver)); }
@@ -2353,12 +2391,12 @@ namespace z3 {
unsigned size() const { return Z3_goal_size(ctx(), m_goal); }
expr operator[](int i) const { assert(0 <= i); Z3_ast r = Z3_goal_formula(ctx(), m_goal, i); check_error(); return expr(ctx(), r); }
Z3_goal_prec precision() const { return Z3_goal_precision(ctx(), m_goal); }
- bool inconsistent() const { return Z3_goal_inconsistent(ctx(), m_goal) != 0; }
+ bool inconsistent() const { return Z3_goal_inconsistent(ctx(), m_goal); }
unsigned depth() const { return Z3_goal_depth(ctx(), m_goal); }
void reset() { Z3_goal_reset(ctx(), m_goal); }
unsigned num_exprs() const { return Z3_goal_num_exprs(ctx(), m_goal); }
- bool is_decided_sat() const { return Z3_goal_is_decided_sat(ctx(), m_goal) != 0; }
- bool is_decided_unsat() const { return Z3_goal_is_decided_unsat(ctx(), m_goal) != 0; }
+ bool is_decided_sat() const { return Z3_goal_is_decided_sat(ctx(), m_goal); }
+ bool is_decided_unsat() const { return Z3_goal_is_decided_unsat(ctx(), m_goal); }
model convert_model(model const & m) const {
check_context(*this, m);
Z3_model new_m = Z3_goal_convert_model(ctx(), m_goal, m);
@@ -2609,6 +2647,11 @@ namespace z3 {
strm << weight;
return handle(Z3_optimize_assert_soft(ctx(), m_opt, e, strm.str().c_str(), 0));
}
+ void add(expr const& e, expr const& t) {
+ assert(e.is_bool());
+ Z3_optimize_assert_and_track(ctx(), m_opt, e, t);
+ }
+
handle add(expr const& e, char const* weight) {
assert(e.is_bool());
return handle(Z3_optimize_assert_soft(ctx(), m_opt, e, weight, 0));
diff --git a/src/api/dotnet/CMakeLists.txt b/src/api/dotnet/CMakeLists.txt
index 20621e4fc..3ff1a484a 100644
--- a/src/api/dotnet/CMakeLists.txt
+++ b/src/api/dotnet/CMakeLists.txt
@@ -1,12 +1,10 @@
-find_package(DotNetToolchain REQUIRED)
+find_package(Dotnet 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")
@@ -127,160 +125,64 @@ endforeach()
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}")
+
+# Generate items
+set(Z3_DOTNET_COMPILE_ITEMS "")
+foreach(csfile ${Z3_DOTNET_ASSEMBLY_SOURCES})
+ set(Z3_DOTNET_COMPILE_ITEMS "${Z3_DOTNET_COMPILE_ITEMS}\n ")
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"
- )
-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.snk"
- )
+
+# FindDotnet.cmake forwards CMake build type to MSBuild.
+# And thus we can put the conditional properties in the project file.
+# Note, nuget package file names do not have the ${VER_REV} part.
+
+set(Z3_DOTNET_NUPKG_VERSION "${VER_MAJOR}.${VER_MINOR}.${VER_BUILD}")
+if("${TARGET_ARCHITECTURE}" STREQUAL "i686")
+ set(Z3_DOTNET_PLATFORM "x86")
else()
- message(FATAL_ERROR "Unknown .NET toolchain")
+ set(Z3_DOTNET_PLATFORM "AnyCPU")
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"
-)
+# TODO conditional for signing. we can then enable the ``Release_delaysign`` configuration
-# 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
- "$<$:/debug+>"
- "$<$:/debug:full>"
- "$<$:/optimize->"
- # This has to be quoted otherwise the ``;`` is interpreted as a command separator
- "$<$:\"/define:DEBUG$TRACE\">"
- # Release flags, expands to nothing if we are doing a debug build
- "$<$>:/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: Ideally we should emit files into a configuration specific directory
-# when using multi-configuration generators so that the files generated by each
-# configuration don't clobber each other. Unfortunately the ``get_property()``
-# command only works correctly for single configuration generators so we can't
-# use it. We also can't use ``$`` because the ``OUTPUT``
-# argument to ``add_custom_commands()`` won't accept it.
-# See http://public.kitware.com/pipermail/cmake/2016-March/063101.html
-#
-# For now just output file to the root binary directory like the Python build
-# system does and emit a warning when appropriate.
-if (DEFINED CMAKE_CONFIGURATION_TYPES)
- # Multi-configuration build (e.g. Visual Studio and Xcode).
- message(WARNING "You are using a multi-configuration generator. The build rules for"
- " the \".NET\" bindings currently do not emit files per configuration so previously"
- " generated files for other configurations will be overwritten.")
-endif()
-
-set(Z3_DOTNET_ASSEMBLY_OUTPUT_DIR "${CMAKE_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}\""
-)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Microsoft.Z3.csproj.in ${CMAKE_CURRENT_BINARY_DIR}/build/Microsoft.Z3.csproj)
+ADD_DOTNET(${CMAKE_CURRENT_BINARY_DIR}/build/Microsoft.Z3.csproj
+ VERSION ${Z3_DOTNET_NUPKG_VERSION}
+ PLATFORM ${Z3_DOTNET_PLATFORM}
+ SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Microsoft.Z3.csproj.in
+ ${CMAKE_CURRENT_SOURCE_DIR}/Microsoft.Z3.props
+ ${CMAKE_CURRENT_SOURCE_DIR}/Microsoft.Z3.targets
+ ${Z3_DOTNET_ASSEMBLY_SOURCES}
+ PACKAGE Microsoft.Z3
+ PACK_ARGUMENTS "/p:_DN_CMAKE_CONFIG=$"
+ )
+add_dependencies(BUILD_Microsoft.Z3 libz3)
# Convenient top-level target
-add_custom_target(build_z3_dotnet_bindings
- ALL
- DEPENDS
- "${Z3_DOTNET_ASSEMBLY_DLL}"
-)
+add_custom_target(build_z3_dotnet_bindings ALL DEPENDS BUILD_Microsoft.Z3)
+
+# Register the local nupkg repo
+set(Z3_DOTNET_LOCALREPO_NAME "Microsoft Z3 Local Repository")
+DOTNET_REGISTER_LOCAL_REPOSITORY(${Z3_DOTNET_LOCALREPO_NAME} ${CMAKE_BINARY_DIR})
###############################################################################
-# Install
+# Install: register a local nuget repo and install our package.
+# the build step depends on the 'purge' target, making sure that
+# a user will always restore the freshly-built package.
###############################################################################
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.
- # Note: If multi-configuration generator support is ever fixed then these
- # scripts will be broken.
- 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)
- # Don't install Z3_DOTNET_ASSEMBLY_DLL into the gac. Instead just copy into
- # installation directory.
- install(FILES "${Z3_DOTNET_ASSEMBLY_DLL}" DESTINATION "${CMAKE_INSTALL_LIBDIR}")
- install(FILES "${Z3_DOTNET_ASSEMBLY_DLL_DOC}" DESTINATION "${CMAKE_INSTALL_LIBDIR}")
-else()
- message(FATAL_ERROR "Unknown .NET toolchain")
+if(INSTALL_DOTNET_BINDINGS)
+ install(FILES "${CMAKE_BINARY_DIR}/Microsoft.Z3/Microsoft.Z3.${Z3_DOTNET_NUPKG_VERSION}.nupkg" DESTINATION "${CMAKE_INSTALL_LIBDIR}/z3.nuget")
+ # move the local repo to the installation directory (cancel the build-time repo)
+ install(CODE "include(${CMAKE_CURRENT_LIST_DIR}/../../../cmake/modules/FindDotnet.cmake)\n DOTNET_REGISTER_LOCAL_REPOSITORY(\"${Z3_DOTNET_LOCALREPO_NAME}\" ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/z3.nuget)")
+ install(FILES "${CMAKE_BINARY_DIR}/Microsoft.Z3/Microsoft.Z3.xml" DESTINATION "${CMAKE_INSTALL_LIBDIR}/z3.nuget")
+# TODO GAC?
+# set(GAC_PKG_NAME "Microsoft.Z3.Sharp")
+# set(PREFIX "${CMAKE_INSTALL_PREFIX}")
+# set(VERSION "${Z3_VERSION}")
endif()
+
diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs
index a941f8e86..cdaae332b 100644
--- a/src/api/dotnet/Context.cs
+++ b/src/api/dotnet/Context.cs
@@ -475,7 +475,7 @@ namespace Microsoft.Z3
/// Update a datatype field at expression t with value v.
/// The function performs a record update at t. The field
/// that is passed in as argument is updated with value v,
- /// the remainig fields of t are unchanged.
+ /// the remaining fields of t are unchanged.
///
public Expr MkUpdateField(FuncDecl field, Expr t, Expr v)
{
diff --git a/src/api/dotnet/Goal.cs b/src/api/dotnet/Goal.cs
index 4dbc78b7e..883b91f35 100644
--- a/src/api/dotnet/Goal.cs
+++ b/src/api/dotnet/Goal.cs
@@ -144,7 +144,7 @@ namespace Microsoft.Z3
uint n = Size;
BoolExpr[] res = new BoolExpr[n];
for (uint i = 0; i < n; i++)
- res[i] = new BoolExpr(Context, Native.Z3_goal_formula(Context.nCtx, NativeObject, i));
+ res[i] = (BoolExpr)Expr.Create(Context, Native.Z3_goal_formula(Context.nCtx, NativeObject, i));
return res;
}
}
diff --git a/src/api/dotnet/Lambda.cs b/src/api/dotnet/Lambda.cs
index 35497f88f..1cd9db2dd 100644
--- a/src/api/dotnet/Lambda.cs
+++ b/src/api/dotnet/Lambda.cs
@@ -76,7 +76,7 @@ namespace Microsoft.Z3
get
{
- return new BoolExpr(Context, Native.Z3_get_quantifier_body(Context.nCtx, NativeObject));
+ return Expr.Create(Context, Native.Z3_get_quantifier_body(Context.nCtx, NativeObject));
}
}
diff --git a/src/api/dotnet/Microsoft.Z3.csproj b/src/api/dotnet/Microsoft.Z3.csproj
deleted file mode 100644
index 045c610dd..000000000
--- a/src/api/dotnet/Microsoft.Z3.csproj
+++ /dev/null
@@ -1,418 +0,0 @@
-
-
-
- Debug
- AnyCPU
- 8.0.30703
- 2.0
- {EC3DB697-B734-42F7-9468-5B62821EEB5A}
- Library
- Properties
- Microsoft.Z3
- Microsoft.Z3
- v4.0
- 512
- Client
- 0
-
-
- true
- full
- false
- ..\Debug\
- DEBUG;TRACE
- prompt
- 4
- true
- ..\Debug\Microsoft.Z3.XML
- False
- False
- True
- False
- False
- True
- False
- True
- True
- False
- False
- False
- True
- False
- False
- False
- True
- False
- False
- True
- True
- True
- False
- False
-
-
-
-
-
-
- True
- Full
- %28none%29
- 2
-
-
- pdbonly
- true
- ..\external\
-
-
- prompt
- 4
- true
- ..\external\Microsoft.Z3.xml
- AnyCPU
-
-
- ..\external\
- true
- ..\external\Microsoft.Z3.xml
- true
- pdbonly
- AnyCPU
- bin\Release\Microsoft.Z3.dll.CodeAnalysisLog.xml
- true
- GlobalSuppressions.cs
- prompt
- MinimumRecommendedRules.ruleset
- ;C:\Program Files\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets
- true
- ;C:\Program Files\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules
- true
- false
-
-
- true
- ..\x64\Debug\
- DEBUG;TRACE
- true
- full
- x64
- ..\Debug\Microsoft.Z3.dll.CodeAnalysisLog.xml
- true
- GlobalSuppressions.cs
- prompt
- MinimumRecommendedRules.ruleset
- ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets
- true
- ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules
- true
- True
- False
- True
- False
- False
- False
- False
- False
- False
- False
- False
- False
- False
- False
- False
- False
- True
- False
- False
- True
- False
- False
- False
-
-
-
-
-
-
- False
- Full
- %28none%29
- 0
- ..\x64\Debug\Microsoft.Z3.XML
-
-
- ..\x64\external_64\
- true
- ..\x64\external_64\Microsoft.Z3.xml
- true
- pdbonly
- x64
- ..\release\Microsoft.Z3.dll.CodeAnalysisLog.xml
- true
- GlobalSuppressions.cs
- prompt
- MinimumRecommendedRules.ruleset
- ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets
- true
- ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules
- True
- False
- True
- False
- False
- True
- True
- True
- False
- False
- False
- True
- True
- False
- False
- False
- True
- False
- False
- True
- True
- False
- False
-
-
-
-
- -repro
-
- True
- Full
- %28none%29
- 2
-
-
- ..\x64\external\
- true
- ..\x64\external\Microsoft.Z3.XML
- true
- pdbonly
- x64
- bin\Release\Microsoft.Z3.dll.CodeAnalysisLog.xml
- true
- GlobalSuppressions.cs
- prompt
- MinimumRecommendedRules.ruleset
- ;C:\Program Files\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets
- true
- ;C:\Program Files\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules
- true
-
-
- false
-
-
-
-
-
-
- false
-
-
- ..\Release_delaysign\
- true
- ..\Release_delaysign\Microsoft.Z3.XML
- true
- pdbonly
- AnyCPU
- ..\release\Microsoft.Z3.dll.CodeAnalysisLog.xml
- true
- GlobalSuppressions.cs
- prompt
- MinimumRecommendedRules.ruleset
- ;C:\Program Files\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets
- true
- ;C:\Program Files\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules
- true
- DELAYSIGN
-
-
- bin\x64\Release_delaysign\
- true
- bin\x64\Release_delaysign\Microsoft.Z3.XML
- true
- pdbonly
- x64
- ..\release\Microsoft.Z3.dll.CodeAnalysisLog.xml
- true
- GlobalSuppressions.cs
- prompt
- MinimumRecommendedRules.ruleset
- ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets
- true
- ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules;C:\Program Files\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules
- true
-
-
- true
- ..\x86\Debug\
- DEBUG;TRACE
- true
- full
- x86
- ..\Debug\Microsoft.Z3.dll.CodeAnalysisLog.xml
- true
- GlobalSuppressions.cs
- prompt
- MinimumRecommendedRules.ruleset
- ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets
- ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules
- ..\x86\Debug\Microsoft.Z3.XML
-
-
- bin\x86\Release\
- true
- bin\x86\Release\Microsoft.Z3.xml
- true
- pdbonly
- x86
- ..\external\Microsoft.Z3.dll.CodeAnalysisLog.xml
- true
- GlobalSuppressions.cs
- prompt
- MinimumRecommendedRules.ruleset
- ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets
- ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules
-
-
- bin\x86\external\
- true
- bin\x86\external\Microsoft.Z3.XML
- true
- pdbonly
- x86
- bin\Release\Microsoft.Z3.dll.CodeAnalysisLog.xml
- true
- GlobalSuppressions.cs
- prompt
- MinimumRecommendedRules.ruleset
- ;C:\Program Files\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets
- true
- ;C:\Program Files\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules
- true
-
-
- bin\x86\Release_delaysign\
- DELAYSIGN
- true
- bin\x86\Release_delaysign\Microsoft.Z3.XML
- true
- pdbonly
- x86
- ..\release\Microsoft.Z3.dll.CodeAnalysisLog.xml
- true
- GlobalSuppressions.cs
- prompt
- MinimumRecommendedRules.ruleset
- ;C:\Program Files\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets
- true
- ;C:\Program Files\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/api/dotnet/Microsoft.Z3.csproj.in b/src/api/dotnet/Microsoft.Z3.csproj.in
new file mode 100644
index 000000000..fc6d6a978
--- /dev/null
+++ b/src/api/dotnet/Microsoft.Z3.csproj.in
@@ -0,0 +1,95 @@
+
+
+
+
+
+ Microsoft.Z3
+ Microsoft.Z3
+ Microsoft.Z3
+
+ Z3 .NET Interface
+ Z3 .NET Interface
+
+ Z3
+
+ Z3 is a satisfiability modulo theories solver from Microsoft Research.
+ .NET Interface to the Z3 Theorem Prover
+
+ Copyright (C) 2006-2019 Microsoft Corporation
+ Copyright (C) 2006-2019 Microsoft Corporation
+
+ Microsoft Corporation
+ Microsoft Corporation
+
+ @VER_MAJOR@.@VER_MINOR@.@VER_BUILD@.@VER_REVISION@
+ @VER_MAJOR@.@VER_MINOR@.@VER_BUILD@.@VER_REVISION@
+
+ @VER_MAJOR@.@VER_MINOR@.@VER_BUILD@.@VER_REVISION@
+ @VER_MAJOR@.@VER_MINOR@.@VER_BUILD@.@VER_REVISION@
+
+ ${DOTNET_PACKAGE_VERSION}
+ smt constraint solver theorem prover
+
+ Microsoft
+ Microsoft
+
+
+
+
+ false
+ false
+
+
+
+ DELAYSIGN
+ true
+ true
+
+
+
+
+
+ netstandard2.0;net45
+ library
+ True
+ 1701,1702
+ 4
+ true
+ $(OutputPath)\Microsoft.Z3.xml
+
+
+
+
+${Z3_DOTNET_COMPILE_ITEMS}
+
+
+
+
+
+ build
+
+
+ build
+
+
+
+
+
+
+
+
+ runtimes\win-x64\native
+
+
+ runtimes\linux-x64\native
+
+
+
+
+
+
+ runtimes\win-x86\native
+
+
+
+
diff --git a/src/api/dotnet/Microsoft.Z3.props b/src/api/dotnet/Microsoft.Z3.props
new file mode 100644
index 000000000..a5db71359
--- /dev/null
+++ b/src/api/dotnet/Microsoft.Z3.props
@@ -0,0 +1,23 @@
+
+
+
+
+
+ true
+ true
+ true
+
+
+ $(MSBuildThisFileDirectory)..\
+ $(Z3_PACKAGE_PATH)runtimes\win-x64\native\libz3.dll
+ $(Z3_PACKAGE_PATH)runtimes\win-x86\native\libz3.dll
+ $(Z3_PACKAGE_PATH)runtimes\linux-x64\native\libz3.so
+
+
+
+
+
+ false
+
+
+
diff --git a/src/api/dotnet/Microsoft.Z3.targets b/src/api/dotnet/Microsoft.Z3.targets
new file mode 100644
index 000000000..38e56b350
--- /dev/null
+++ b/src/api/dotnet/Microsoft.Z3.targets
@@ -0,0 +1,11 @@
+
+
+
+
+
+ %(RecursiveDir)%(FileName)%(Extension)
+ PreserveNewest
+
+
+
+
diff --git a/src/api/dotnet/Optimize.cs b/src/api/dotnet/Optimize.cs
index 4713f414a..9a7bd3bd1 100644
--- a/src/api/dotnet/Optimize.cs
+++ b/src/api/dotnet/Optimize.cs
@@ -25,7 +25,7 @@ using System.Linq;
namespace Microsoft.Z3
{
///
- /// Object for managing optimizization context
+ /// Object for managing optimization context
///
public class Optimize : Z3Object
{
diff --git a/src/api/dotnet/Quantifier.cs b/src/api/dotnet/Quantifier.cs
index f4a889092..57d38e7c1 100644
--- a/src/api/dotnet/Quantifier.cs
+++ b/src/api/dotnet/Quantifier.cs
@@ -148,7 +148,7 @@ namespace Microsoft.Z3
get
{
- return new BoolExpr(Context, Native.Z3_get_quantifier_body(Context.nCtx, NativeObject));
+ return (BoolExpr)Expr.Create(Context, Native.Z3_get_quantifier_body(Context.nCtx, NativeObject));
}
}
diff --git a/src/api/dotnet/core/README.txt b/src/api/dotnet/core/README.txt
deleted file mode 100644
index fa274f72b..000000000
--- a/src/api/dotnet/core/README.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-Z3 API for .NET Core
-
-Z3's .NET API uses Code Contracts, which are not included in .NET Core. The
-enclosed file called DummyContracts.cs provides stubs for the Code Contracts
-functions, so that the API will compile, but not perform any contract
-checking. To build this using .NET core, run (in this directory):
-
-dotnet restore
-dotnet build core.csproj -c Release
-
-If you are building with the cmake system, you should first
-copy over files that are produced by the compiler into
-this directory. You need to copy over Native.cs and Enumeration.cs
-
--- good luck!
diff --git a/src/api/dotnet/core/core.csproj b/src/api/dotnet/core/core.csproj
deleted file mode 100644
index 5fa3275cf..000000000
--- a/src/api/dotnet/core/core.csproj
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
- netcoreapp1.0
- $(DefineConstants);DOTNET_CORE
- portable
- Microsoft.Z3
- Library
- core
- $(PackageTargetFallback);dnxcore50
- 1.0.4
-
-
-
-
-
-
-
diff --git a/src/api/dotnet/dotnet35/Example/App.config b/src/api/dotnet/dotnet35/Example/App.config
deleted file mode 100644
index 737ed23f2..000000000
--- a/src/api/dotnet/dotnet35/Example/App.config
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/src/api/dotnet/dotnet35/Example/Example.csproj b/src/api/dotnet/dotnet35/Example/Example.csproj
deleted file mode 100644
index 842fbac41..000000000
--- a/src/api/dotnet/dotnet35/Example/Example.csproj
+++ /dev/null
@@ -1,78 +0,0 @@
-
-
-
-
- Debug
- AnyCPU
- {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}
- Exe
- Properties
- Example
- Example
- v4.5.2
- 512
- true
-
-
- AnyCPU
- true
- full
- false
- bin\Debug\
- TRACE;DEBUG;FRAMEWORK_LT_4
- prompt
- 4
-
-
- AnyCPU
- pdbonly
- true
- bin\Release\
- TRACE;FRAMEWORK_LT_4
- prompt
- 4
-
-
- true
- bin\x64\Debug\
- TRACE;DEBUG;FRAMEWORK_LT_4
- full
- x64
- prompt
- MinimumRecommendedRules.ruleset
- true
-
-
- bin\x64\Release\
- TRACE;FRAMEWORK_LT_4
- true
- pdbonly
- x64
- prompt
- MinimumRecommendedRules.ruleset
- true
-
-
-
- Program.cs
-
-
-
-
-
-
-
-
- {ec3db697-b734-42f7-9468-5b62821eeb5a}
- Microsoft.Z3.NET35
-
-
-
-
-
diff --git a/src/api/dotnet/dotnet35/Example/Properties/AssemblyInfo.cs b/src/api/dotnet/dotnet35/Example/Properties/AssemblyInfo.cs
deleted file mode 100644
index ed0d8454f..000000000
--- a/src/api/dotnet/dotnet35/Example/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("Example")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("Example")]
-[assembly: AssemblyCopyright("Copyright © 2017")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("2a8e577b-7b6d-4ca9-832a-ca2eec314812")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.csproj b/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.csproj
deleted file mode 100644
index 15eaac445..000000000
--- a/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.csproj
+++ /dev/null
@@ -1,347 +0,0 @@
-
-
-
- Debug
- AnyCPU
- 8.0.30703
- 2.0
- {EC3DB697-B734-42F7-9468-5B62821EEB5A}
- Library
- Properties
- Microsoft.Z3
- Microsoft.Z3
- v3.5
- 512
-
-
- 0
-
-
- true
- full
- false
- Debug\
- TRACE;DEBUG;FRAMEWORK_LT_4
- prompt
- 4
- true
- Debug\Microsoft.Z3.XML
- False
- False
- True
- False
- False
- True
- False
- True
- True
- False
- False
- False
- True
- False
- False
- False
- True
- False
- False
- True
- True
- True
- False
- False
-
-
-
-
-
-
- True
- Full
- %28none%29
- 2
-
-
- pdbonly
- true
- Release\
- FRAMEWORK_LT_4
- prompt
- 4
- true
- Release\Microsoft.Z3.xml
- x86
-
-
- true
-
-
-
-
-
-
- false
-
-
- true
- bin\x64\Debug\
- TRACE;DEBUG;FRAMEWORK_LT_4
- true
- Debug\Microsoft.Z3.XML
- full
- x64
- prompt
- MinimumRecommendedRules.ruleset
-
-
- bin\x64\Release\
- FRAMEWORK_LT_4
- true
- Release\Microsoft.Z3.xml
- true
- pdbonly
- x64
- prompt
- MinimumRecommendedRules.ruleset
-
-
-
- packages\Code.Contract.1.0.0\lib\net35\Microsoft.Contracts.dll
- True
-
-
-
-
-
-
- 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
-
-
- Enumerations.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
-
-
- Native.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
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.sln b/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.sln
deleted file mode 100644
index 1e33f136e..000000000
--- a/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.sln
+++ /dev/null
@@ -1,48 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 14
-VisualStudioVersion = 14.0.25420.1
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Z3.NET35", "Microsoft.Z3.NET35.csproj", "{EC3DB697-B734-42F7-9468-5B62821EEB5A}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example", "Example\Example.csproj", "{2A8E577B-7B6D-4CA9-832A-CA2EEC314812}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Debug|x64 = Debug|x64
- Debug|x86 = Debug|x86
- Release|Any CPU = Release|Any CPU
- Release|x64 = Release|x64
- Release|x86 = Release|x86
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|x64.ActiveCfg = Debug|Any CPU
- {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|x64.Build.0 = Debug|Any CPU
- {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|x86.ActiveCfg = Debug|Any CPU
- {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|x86.Build.0 = Debug|Any CPU
- {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|Any CPU.Build.0 = Release|Any CPU
- {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x64.ActiveCfg = Release|x64
- {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x64.Build.0 = Release|x64
- {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x86.ActiveCfg = Release|Any CPU
- {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x86.Build.0 = Release|Any CPU
- {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|x64.ActiveCfg = Debug|Any CPU
- {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|x64.Build.0 = Debug|Any CPU
- {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|x86.ActiveCfg = Debug|Any CPU
- {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|x86.Build.0 = Debug|Any CPU
- {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|Any CPU.Build.0 = Release|Any CPU
- {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|x64.ActiveCfg = Release|x64
- {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|x64.Build.0 = Release|x64
- {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|x86.ActiveCfg = Release|Any CPU
- {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|x86.Build.0 = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
-EndGlobal
diff --git a/src/api/dotnet/dotnet35/Properties/AssemblyInfo.cs b/src/api/dotnet/dotnet35/Properties/AssemblyInfo.cs
deleted file mode 100644
index fb4319002..000000000
--- a/src/api/dotnet/dotnet35/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-using System;
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Security.Permissions;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("Z3 .NET Interface")]
-[assembly: AssemblyDescription(".NET Interface to the Z3 Theorem Prover")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("Microsoft Corporation")]
-[assembly: AssemblyProduct("Z3")]
-[assembly: AssemblyCopyright("Copyright (C) 2006-2015 Microsoft Corporation")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("4853ed71-2078-40f4-8117-bc46646bce0e")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("4.2.0.0")]
-[assembly: AssemblyVersion("4.5.1.6031")]
-[assembly: AssemblyFileVersion("4.5.1.6031")]
diff --git a/src/api/dotnet/dotnet35/Properties/AssemblyInfo.cs.in b/src/api/dotnet/dotnet35/Properties/AssemblyInfo.cs.in
deleted file mode 100644
index e5a85f16f..000000000
--- a/src/api/dotnet/dotnet35/Properties/AssemblyInfo.cs.in
+++ /dev/null
@@ -1,38 +0,0 @@
-using System;
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Security.Permissions;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("Z3 .NET Interface")]
-[assembly: AssemblyDescription(".NET Interface to the Z3 Theorem Prover")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("Microsoft Corporation")]
-[assembly: AssemblyProduct("Z3")]
-[assembly: AssemblyCopyright("Copyright (C) 2006-2015 Microsoft Corporation")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("4853ed71-2078-40f4-8117-bc46646bce0e")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("4.2.0.0")]
-[assembly: AssemblyVersion("@VER_MAJOR@.@VER_MINOR@.@VER_BUILD@.@VER_REVISION@")]
-[assembly: AssemblyFileVersion("@VER_MAJOR@.@VER_MINOR@.@VER_BUILD@.@VER_REVISION@")]
diff --git a/src/api/dotnet/dotnet35/Readme.NET35 b/src/api/dotnet/dotnet35/Readme.NET35
deleted file mode 100644
index f8c2958ee..000000000
--- a/src/api/dotnet/dotnet35/Readme.NET35
+++ /dev/null
@@ -1,10 +0,0 @@
-The default Z3 bindings for .NET are built for the .NET framework version 4.
-Should the need arise, it is also possible to build them for .NET 3.5; the
-instructions are as follows:
-
-In the project properties of Microsoft.Z3.csproj:
-- Under 'Application': Change Target framework to .NET Framework 3.5
-- Under 'Build': Add FRAMEWORK_LT_4 to the condidional compilation symbols
-- Remove the reference to System.Numerics
-- Install the NuGet Package "Microsoft Code Contracts for Net3.5":
- In the Package Manager Console enter Install-Package Code.Contract
diff --git a/src/api/dotnet/dotnet35/packages.config b/src/api/dotnet/dotnet35/packages.config
deleted file mode 100644
index bc9f365bc..000000000
--- a/src/api/dotnet/dotnet35/packages.config
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
diff --git a/src/api/java/CMakeLists.txt b/src/api/java/CMakeLists.txt
index 302b3d5bd..c2d73ffb1 100644
--- a/src/api/java/CMakeLists.txt
+++ b/src/api/java/CMakeLists.txt
@@ -39,8 +39,7 @@ add_library(z3java SHARED ${Z3_JAVA_NATIVE_CPP})
target_link_libraries(z3java PRIVATE libz3)
# FIXME:
# Not sure if using all the flags used by the Z3 components is really necessary
-# here. At the bare minimum setting _AMD64_ depending on the target is
-# necessary but seeing as the Python build system uses all the flags used for building
+# here. The Python build system uses all the flags used for building
# Z3's components to build ``Native.cpp`` lets do the same for now.
target_compile_options(z3java PRIVATE ${Z3_COMPONENT_CXX_FLAGS})
target_compile_definitions(z3java PRIVATE ${Z3_COMPONENT_CXX_DEFINES})
diff --git a/src/api/java/Context.java b/src/api/java/Context.java
index ede494598..20c1c3737 100644
--- a/src/api/java/Context.java
+++ b/src/api/java/Context.java
@@ -3356,7 +3356,7 @@ public class Context implements AutoCloseable {
}
/**
- * Create a numeral of FloatingPoint sort from a float.
+ * Create a numeral of FloatingPoint sort from a double.
* @param v numeral value.
* @param s FloatingPoint sort.
* @throws Z3Exception
@@ -3368,7 +3368,7 @@ public class Context implements AutoCloseable {
/**
* Create a numeral of FloatingPoint sort from an int.
- * * @param v numeral value.
+ * @param v numeral value.
* @param s FloatingPoint sort.
* @throws Z3Exception
**/
@@ -3380,8 +3380,8 @@ public class Context implements AutoCloseable {
/**
* Create a numeral of FloatingPoint sort from a sign bit and two integers.
* @param sgn the sign.
- * @param sig the significand.
* @param exp the exponent.
+ * @param sig the significand.
* @param s FloatingPoint sort.
* @throws Z3Exception
**/
@@ -3393,8 +3393,8 @@ public class Context implements AutoCloseable {
/**
* Create a numeral of FloatingPoint sort from a sign bit and two 64-bit integers.
* @param sgn the sign.
- * @param sig the significand.
* @param exp the exponent.
+ * @param sig the significand.
* @param s FloatingPoint sort.
* @throws Z3Exception
**/
@@ -3415,7 +3415,7 @@ public class Context implements AutoCloseable {
}
/**
- * Create a numeral of FloatingPoint sort from a float.
+ * Create a numeral of FloatingPoint sort from a double.
* @param v numeral value.
* @param s FloatingPoint sort.
* @throws Z3Exception
@@ -3447,7 +3447,7 @@ public class Context implements AutoCloseable {
**/
public FPNum mkFP(boolean sgn, int exp, int sig, FPSort s)
{
- return mkFPNumeral(sgn, sig, exp, s);
+ return mkFPNumeral(sgn, exp, sig, s);
}
/**
@@ -3460,7 +3460,7 @@ public class Context implements AutoCloseable {
**/
public FPNum mkFP(boolean sgn, long exp, long sig, FPSort s)
{
- return mkFPNumeral(sgn, sig, exp, s);
+ return mkFPNumeral(sgn, exp, sig, s);
}
diff --git a/src/api/java/Goal.java b/src/api/java/Goal.java
index 903325850..f5fa35fdb 100644
--- a/src/api/java/Goal.java
+++ b/src/api/java/Goal.java
@@ -130,8 +130,7 @@ public class Goal extends Z3Object {
int n = size();
BoolExpr[] res = new BoolExpr[n];
for (int i = 0; i < n; i++)
- res[i] = new BoolExpr(getContext(), Native.goalFormula(getContext()
- .nCtx(), getNativeObject(), i));
+ res[i] = (BoolExpr) Expr.create(getContext(), Native.goalFormula(getContext().nCtx(), getNativeObject(), i));
return res;
}
diff --git a/src/api/java/Lambda.java b/src/api/java/Lambda.java
index 45375fb29..cf9809a23 100644
--- a/src/api/java/Lambda.java
+++ b/src/api/java/Lambda.java
@@ -70,9 +70,9 @@ import com.microsoft.z3.enumerations.Z3_ast_kind;
*
* @throws Z3Exception
**/
- public BoolExpr getBody()
+ public Expr getBody()
{
- return new BoolExpr(getContext(), Native.getQuantifierBody(getContext()
+ return Expr.create(getContext(), Native.getQuantifierBody(getContext()
.nCtx(), getNativeObject()));
}
diff --git a/src/api/java/Quantifier.java b/src/api/java/Quantifier.java
index 29483d1aa..73b726e8d 100644
--- a/src/api/java/Quantifier.java
+++ b/src/api/java/Quantifier.java
@@ -141,7 +141,7 @@ public class Quantifier extends BoolExpr
**/
public BoolExpr getBody()
{
- return new BoolExpr(getContext(), Native.getQuantifierBody(getContext()
+ return (BoolExpr) Expr.create(getContext(), Native.getQuantifierBody(getContext()
.nCtx(), getNativeObject()));
}
diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml
index 9d8a9c923..5fb87bf64 100644
--- a/src/api/ml/z3.ml
+++ b/src/api/ml/z3.ml
@@ -2023,3 +2023,7 @@ let toggle_warning_messages = Z3native.toggle_warning_messages
let enable_trace = Z3native.enable_trace
let disable_trace = Z3native.enable_trace
+
+module Memory = struct
+ let reset = Z3native.reset_memory
+end
diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli
index ddc9f2a41..4b6d8bc25 100644
--- a/src/api/ml/z3.mli
+++ b/src/api/ml/z3.mli
@@ -3472,3 +3472,11 @@ val enable_trace : string -> unit
Remarks: It is a NOOP otherwise.
*)
val disable_trace : string -> unit
+
+
+(** Memory management **)
+module Memory :
+sig
+ (** Reset all allocated resources **)
+ val reset : unit -> unit
+end
diff --git a/src/api/ml/z3native_stubs.c.pre b/src/api/ml/z3native_stubs.c.pre
index 71ee18ce9..5c1a3bd06 100644
--- a/src/api/ml/z3native_stubs.c.pre
+++ b/src/api/ml/z3native_stubs.c.pre
@@ -448,3 +448,21 @@ CAMLprim value DLL_PUBLIC n_set_internal_error_handler(value ctx_v)
Z3_set_error_handler(ctx_p->ctx, MLErrorHandler);
CAMLreturn(Val_unit);
}
+
+CAMLprim DLL_PUBLIC value n_mk_config() {
+ CAMLparam0();
+ CAMLlocal1(result);
+ Z3_config z3rv;
+
+ /* invoke Z3 function */
+ z3rv = Z3_mk_config();
+
+ if (z3rv == NULL) {
+ caml_raise_with_string(*caml_named_value("Z3EXCEPTION"), "Object allocation failed");
+ }
+
+ /* construct simple return value */
+ result = caml_alloc_custom(&default_custom_ops, sizeof(Z3_config), 0, 1); *(Z3_config*)Data_custom_val(result) = z3rv;
+ /* cleanup and return */
+ CAMLreturn(result);
+}
diff --git a/src/api/python/README.txt b/src/api/python/README.txt
index 9312b1119..561b8dedc 100644
--- a/src/api/python/README.txt
+++ b/src/api/python/README.txt
@@ -1,8 +1,4 @@
-You can learn more about Z3Py at:
-http://rise4fun.com/Z3Py/tutorial/guide
-
-On Windows, you must build Z3 before using Z3Py.
-To build Z3, you should executed the following command
+On Windows, to build Z3, you should executed the following command
in the Z3 root directory at the Visual Studio Command Prompt
msbuild /p:configuration=external
@@ -12,8 +8,8 @@ If you are using a 64-bit Python interpreter, you should use
msbuild /p:configuration=external /p:platform=x64
-On Linux and macOS, you must install Z3Py, before trying example.py.
-To install Z3Py on Linux and macOS, you should execute the following
+On Linux and macOS, you must install python bindings, before trying example.py.
+To install python on Linux and macOS, you should execute the following
command in the Z3 root directory
sudo make install-z3py
diff --git a/src/api/python/setup.py b/src/api/python/setup.py
index 2a750fee6..2d5e5c75d 100644
--- a/src/api/python/setup.py
+++ b/src/api/python/setup.py
@@ -10,13 +10,14 @@ from distutils.util import get_platform
from distutils.errors import LibError
from distutils.command.build import build as _build
from distutils.command.sdist import sdist as _sdist
+from distutils.command.clean import clean as _clean
from setuptools.command.develop import develop as _develop
from setuptools.command.bdist_egg import bdist_egg as _bdist_egg
build_env = dict(os.environ)
build_env['PYTHON'] = sys.executable
-build_env['CXXFLAGS'] = "-std=c++11"
+build_env['CXXFLAGS'] = build_env.get('CXXFLAGS', '') + " -std=c++11"
ROOT_DIR = os.path.abspath(os.path.dirname(__file__))
SRC_DIR_LOCAL = os.path.join(ROOT_DIR, 'core')
@@ -37,13 +38,23 @@ else:
LIBRARY_FILE = "libz3.so"
EXECUTABLE_FILE = "z3"
+def rmtree(tree):
+ if os.path.exists(tree):
+ shutil.rmtree(tree, ignore_errors=False)
+
def _clean_bins():
"""
Clean up the binary files and headers that are installed along with the bindings
"""
- shutil.rmtree(LIBS_DIR, ignore_errors=True)
- shutil.rmtree(BINS_DIR, ignore_errors=True)
- shutil.rmtree(HEADERS_DIR, ignore_errors=True)
+ rmtree(LIBS_DIR)
+ rmtree(BINS_DIR)
+ rmtree(HEADERS_DIR)
+
+def _clean_native_build():
+ """
+ Clean the "build" directory in the z3 native root
+ """
+ rmtree(BUILD_DIR)
def _z3_version():
post = os.getenv('Z3_VERSION_SUFFIX', '')
@@ -146,10 +157,16 @@ class bdist_egg(_bdist_egg):
class sdist(_sdist):
def run(self):
- self.execute(_clean_bins, (), msg="Cleaning binary files")
+ self.execute(_clean_bins, (), msg="Cleaning binary files and headers")
self.execute(_copy_sources, (), msg="Copying source files")
_sdist.run(self)
+class clean(_clean):
+ def run(self):
+ self.execute(_clean_bins, (), msg="Cleaning binary files and headers")
+ self.execute(_clean_native_build, (), msg="Cleaning native build")
+ _clean.run(self)
+
# the build directory needs to exist
#try: os.makedirs(os.path.join(ROOT_DIR, 'build'))
#except OSError: pass
@@ -178,7 +195,7 @@ setup(
name='z3-solver',
version=_z3_version(),
description='an efficient SMT solver library',
- long_description='Z3 is a theorem prover from Microsoft Research with support for bitvectors, booleans, arrays, floating point numbers, strings, and other data types.\n\nFor documentation, please read http://z3prover.github.io/api/html/z3.html\n\nIn the event of technical difficulties related to configuration, compiliation, or installation, please submit issues to https://github.com/angr/angr-z3',
+ long_description='Z3 is a theorem prover from Microsoft Research with support for bitvectors, booleans, arrays, floating point numbers, strings, and other data types.\n\nFor documentation, please read http://z3prover.github.io/api/html/z3.html\n\nIn the event of technical difficulties related to configuration, compilation, or installation, please submit issues to https://github.com/angr/angr-z3',
author="The Z3 Theorem Prover Project",
maintainer="Audrey Dutcher",
maintainer_email="audrey@rhelmot.io",
@@ -191,5 +208,5 @@ setup(
'z3': [os.path.join('lib', '*'), os.path.join('include', '*.h'), os.path.join('include', 'c++', '*.h')]
},
data_files=[('bin',[os.path.join('bin',EXECUTABLE_FILE)])],
- cmdclass={'build': build, 'develop': develop, 'sdist': sdist, 'bdist_egg': bdist_egg},
+ cmdclass={'build': build, 'develop': develop, 'sdist': sdist, 'bdist_egg': bdist_egg, 'clean': clean},
)
diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py
index ffd9c27a1..f8651ab90 100644
--- a/src/api/python/z3/z3.py
+++ b/src/api/python/z3/z3.py
@@ -482,6 +482,7 @@ def _to_ast_ref(a, ctx):
else:
return _to_expr_ref(a, ctx)
+
#########################################
#
# Sorts
@@ -3836,7 +3837,7 @@ def Extract(high, low, a):
>>> Extract(6, 2, x).sort()
BitVec(5)
>>> simplify(Extract(StringVal("abcd"),2,1))
- "c"
+ c
"""
if isinstance(high, str):
high = StringVal(high)
@@ -4489,11 +4490,15 @@ def K(dom, v):
return ArrayRef(Z3_mk_const_array(ctx.ref(), dom.ast, v.as_ast()), ctx)
def Ext(a, b):
- """Return extensionality index for arrays.
+ """Return extensionality index for one-dimensional arrays.
+ >> a, b = Consts('a b', SetSort(IntSort()))
+ >> Ext(a, b)
+ Ext(a, b)
"""
+ ctx = a.ctx
if __debug__:
- _z3_assert(is_array(a) and is_array(b))
- return _to_expr_ref(Z3_mk_array_ext(ctx.ref(), a.as_ast(), b.as_ast()));
+ _z3_assert(is_array(a) and is_array(b), "arguments must be arrays")
+ return _to_expr_ref(Z3_mk_array_ext(ctx.ref(), a.as_ast(), b.as_ast()), ctx)
def is_select(a):
"""Return `True` if `a` is a Z3 array select application.
@@ -5339,7 +5344,7 @@ class Goal(Z3PPObject):
def __copy__(self):
return self.translate(self.ctx)
- def __deepcopy__(self):
+ def __deepcopy__(self, memo={}):
return self.translate(self.ctx)
def simplify(self, *arguments, **keywords):
@@ -5527,7 +5532,7 @@ class AstVector(Z3PPObject):
def __copy__(self):
return self.translate(self.ctx)
- def __deepcopy__(self):
+ def __deepcopy__(self, memo={}):
return self.translate(self.ctx)
def __repr__(self):
@@ -5871,7 +5876,7 @@ class FuncInterp(Z3PPObject):
def __copy__(self):
return self.translate(self.ctx)
- def __deepcopy__(self):
+ def __deepcopy__(self, memo={}):
return self.translate(self.ctx)
def as_list(self):
@@ -6167,7 +6172,7 @@ class ModelRef(Z3PPObject):
def __copy__(self):
return self.translate(self.ctx)
- def __deepcopy__(self):
+ def __deepcopy__(self, memo={}):
return self.translate(self.ctx)
def Model(ctx = None):
@@ -6664,17 +6669,11 @@ class Solver(Z3PPObject):
def from_file(self, filename):
"""Parse assertions from a file"""
- try:
- Z3_solver_from_file(self.ctx.ref(), self.solver, filename)
- except Z3Exception as e:
- _handle_parse_error(e, self.ctx)
+ Z3_solver_from_file(self.ctx.ref(), self.solver, filename)
def from_string(self, s):
"""Parse assertions from a string"""
- try:
- Z3_solver_from_string(self.ctx.ref(), self.solver, s)
- except Z3Exception as e:
- _handle_parse_error(e, self.ctx)
+ Z3_solver_from_string(self.ctx.ref(), self.solver, s)
def cube(self, vars = None):
"""Get set of cubes
@@ -6732,6 +6731,25 @@ class Solver(Z3PPObject):
"""
return AstVector(Z3_solver_get_non_units(self.ctx.ref(), self.solver), self.ctx)
+ def trail_levels(self):
+ """Return trail and decision levels of the solver state after a check() call.
+ """
+ trail = self.trail()
+ levels = (ctypes.c_uint * len(trail))()
+ Z3_solver_get_levels(self.ctx.ref(), self.solver, trail.vector, len(trail), levels)
+ return trail, levels
+
+ def trail(self):
+ """Return trail of the solver state after a check() call.
+ """
+ return AstVector(Z3_solver_get_trail(self.ctx.ref(), self.solver), self.ctx)
+
+ def set_activity(self, lit, act):
+ """Set activity of literal on solver object.
+ This influences the case split order of the variable.
+ """
+ Z3_solver_set_activity(self.ctx.ref(), self.solver, lit.ast, act)
+
def statistics(self):
"""Return statistics for the last `check()`.
@@ -6791,7 +6809,7 @@ class Solver(Z3PPObject):
def __copy__(self):
return self.translate(self.ctx)
- def __deepcopy__(self):
+ def __deepcopy__(self, memo={}):
return self.translate(self.ctx)
def sexpr(self):
@@ -6805,6 +6823,10 @@ class Solver(Z3PPObject):
"""
return Z3_solver_to_string(self.ctx.ref(), self.solver)
+ def dimacs(self):
+ """Return a textual representation of the solver in DIMACS format."""
+ return Z3_solver_to_dimacs_string(self.ctx.ref(), self.solver)
+
def to_smt2(self):
"""return SMTLIB2 formatted benchmark for solver's assertions"""
es = self.assertions()
@@ -7063,17 +7085,11 @@ class Fixedpoint(Z3PPObject):
def parse_string(self, s):
"""Parse rules and queries from a string"""
- try:
- return AstVector(Z3_fixedpoint_from_string(self.ctx.ref(), self.fixedpoint, s), self.ctx)
- except Z3Exception as e:
- _handle_parse_error(e, self.ctx)
+ return AstVector(Z3_fixedpoint_from_string(self.ctx.ref(), self.fixedpoint, s), self.ctx)
def parse_file(self, f):
"""Parse rules and queries from a file"""
- try:
- return AstVector(Z3_fixedpoint_from_file(self.ctx.ref(), self.fixedpoint, f), self.ctx)
- except Z3Exception as e:
- _handle_parse_error(e, self.ctx)
+ return AstVector(Z3_fixedpoint_from_file(self.ctx.ref(), self.fixedpoint, f), self.ctx)
def get_rules(self):
"""retrieve rules that have been added to fixedpoint context"""
@@ -7330,6 +7346,35 @@ class Optimize(Z3PPObject):
self.add(fml)
return self
+ def assert_and_track(self, a, p):
+ """Assert constraint `a` and track it in the unsat core using the Boolean constant `p`.
+
+ If `p` is a string, it will be automatically converted into a Boolean constant.
+
+ >>> x = Int('x')
+ >>> p3 = Bool('p3')
+ >>> s = Optimize()
+ >>> s.assert_and_track(x > 0, 'p1')
+ >>> s.assert_and_track(x != 1, 'p2')
+ >>> s.assert_and_track(x < 0, p3)
+ >>> print(s.check())
+ unsat
+ >>> c = s.unsat_core()
+ >>> len(c)
+ 2
+ >>> Bool('p1') in c
+ True
+ >>> Bool('p2') in c
+ False
+ >>> p3 in c
+ True
+ """
+ if isinstance(p, str):
+ p = Bool(p, self.ctx)
+ _z3_assert(isinstance(a, BoolRef), "Boolean expression expected")
+ _z3_assert(isinstance(p, BoolRef) and is_const(p), "Boolean expression expected")
+ Z3_optimize_assert_and_track(self.ctx.ref(), self.optimize, a.as_ast(), p.as_ast())
+
def add_soft(self, arg, weight = "1", id = None):
"""Add soft constraint with optional weight and optional identifier.
If no weight is supplied, then the penalty for violating the soft constraint
@@ -7410,17 +7455,11 @@ class Optimize(Z3PPObject):
def from_file(self, filename):
"""Parse assertions and objectives from a file"""
- try:
- Z3_optimize_from_file(self.ctx.ref(), self.optimize, filename)
- except Z3Exception as e:
- _handle_parse_error(e, self.ctx)
+ Z3_optimize_from_file(self.ctx.ref(), self.optimize, filename)
def from_string(self, s):
"""Parse assertions and objectives from a string"""
- try:
- Z3_optimize_from_string(self.ctx.ref(), self.optimize, s)
- except Z3Exception as e:
- _handle_parse_error(e, self.ctx)
+ Z3_optimize_from_string(self.ctx.ref(), self.optimize, s)
def assertions(self):
"""Return an AST vector containing all added constraints."""
@@ -9914,6 +9953,8 @@ class SeqRef(ExprRef):
def as_string(self):
"""Return a string representation of sequence expression."""
+ if self.is_string_value():
+ return Z3_get_string(self.ctx_ref(), self.as_ast())
return Z3_ast_to_string(self.ctx_ref(), self.as_ast())
@@ -9993,8 +10034,6 @@ def Strings(names, ctx=None):
def Empty(s):
"""Create the empty sequence of the given sort
>>> e = Empty(StringSort())
- >>> print(e)
- ""
>>> e2 = StringVal("")
>>> print(e.eq(e2))
True
@@ -10080,7 +10119,7 @@ def Replace(s, src, dst):
"""Replace the first occurrence of 'src' by 'dst' in 's'
>>> r = Replace("aaa", "a", "b")
>>> simplify(r)
- "baa"
+ baa
"""
ctx = _get_ctx2(dst, s)
if ctx is None and is_expr(src):
diff --git a/src/api/z3_api.h b/src/api/z3_api.h
index 6e3ce57a1..e1710b499 100644
--- a/src/api/z3_api.h
+++ b/src/api/z3_api.h
@@ -1515,19 +1515,19 @@ extern "C" {
although some parameters can be changed using #Z3_update_param_value.
All main interaction with Z3 happens in the context of a \c Z3_context.
- In contrast to #Z3_mk_context_rc, the life time of Z3_ast objects
+ In contrast to #Z3_mk_context_rc, the life time of \c Z3_ast objects
are determined by the scope level of #Z3_solver_push and #Z3_solver_pop.
- In other words, a Z3_ast object remains valid until there is a
- call to Z3_solver_pop that takes the current scope below the level where
+ In other words, a \c Z3_ast object remains valid until there is a
+ call to #Z3_solver_pop that takes the current scope below the level where
the object was created.
- Note that all other reference counted objects, including Z3_model,
- Z3_solver, Z3_func_interp have to be managed by the caller.
+ Note that all other reference counted objects, including \c Z3_model,
+ \c Z3_solver, \c Z3_func_interp have to be managed by the caller.
Their reference counts are not handled by the context.
Further remarks:
- - Z3_sort, Z3_func_decl, Z3_app, Z3_pattern are Z3_ast's.
- - Z3 uses hash-consing, i.e., when the same Z3_ast is created twice,
+ - \c Z3_sort, \c Z3_func_decl, \c Z3_app, \c Z3_pattern are \c Z3_ast's.
+ - Z3 uses hash-consing, i.e., when the same \c Z3_ast is created twice,
Z3 will return the same pointer twice.
\sa Z3_del_context
@@ -1540,20 +1540,20 @@ extern "C" {
\brief Create a context using the given configuration.
This function is similar to #Z3_mk_context. However,
in the context returned by this function, the user
- is responsible for managing Z3_ast reference counters.
+ is responsible for managing \c Z3_ast reference counters.
Managing reference counters is a burden and error-prone,
but allows the user to use the memory more efficiently.
- The user must invoke #Z3_inc_ref for any Z3_ast returned
- by Z3, and #Z3_dec_ref whenever the Z3_ast is not needed
+ The user must invoke #Z3_inc_ref for any \c Z3_ast returned
+ by Z3, and #Z3_dec_ref whenever the \c Z3_ast is not needed
anymore. This idiom is similar to the one used in
BDD (binary decision diagrams) packages such as CUDD.
Remarks:
- - Z3_sort, Z3_func_decl, Z3_app, Z3_pattern are Z3_ast's.
+ - \c Z3_sort, \c Z3_func_decl, \c Z3_app, \c Z3_pattern are \c Z3_ast's.
- After a context is created, the configuration cannot be changed.
- All main interaction with Z3 happens in the context of a \c Z3_context.
- - Z3 uses hash-consing, i.e., when the same Z3_ast is created twice,
+ - Z3 uses hash-consing, i.e., when the same \c Z3_ast is created twice,
Z3 will return the same pointer twice.
def_API('Z3_mk_context_rc', CONTEXT, (_in(CONFIG),))
@@ -1615,7 +1615,7 @@ extern "C" {
Starting at Z3 4.0, parameter sets are used to configure many components such as:
simplifiers, tactics, solvers, etc.
- \remark Reference counting must be used to manage parameter sets, even when the Z3_context was
+ \remark Reference counting must be used to manage parameter sets, even when the \c Z3_context was
created using #Z3_mk_context instead of #Z3_mk_context_rc.
def_API('Z3_mk_params', PARAMS, (_in(CONTEXT),))
@@ -4094,7 +4094,7 @@ extern "C" {
The remaining fields are left unchanged. It is the record
equivalent of an array store (see \sa Z3_mk_store).
If the datatype has more than one constructor, then the update function
- behaves as identity if there is a miss-match between the accessor and
+ behaves as identity if there is a mismatch between the accessor and
constructor. For example ((_ update-field car) nil 1) is nil,
while ((_ update-field car) (cons 2 nil) 1) is (cons 1 nil).
@@ -4416,7 +4416,7 @@ extern "C" {
bool Z3_API Z3_is_well_sorted(Z3_context c, Z3_ast t);
/**
- \brief Return Z3_L_TRUE if \c a is true, Z3_L_FALSE if it is false, and Z3_L_UNDEF otherwise.
+ \brief Return \c Z3_L_TRUE if \c a is true, \c Z3_L_FALSE if it is false, and \c Z3_L_UNDEF otherwise.
def_API('Z3_get_bool_value', INT, (_in(CONTEXT), _in(AST)))
*/
@@ -4998,7 +4998,7 @@ extern "C" {
Z3_ast_vector Z3_API Z3_model_get_sort_universe(Z3_context c, Z3_model m, Z3_sort s);
/**
- \brief translate model from context c to context \c dst.
+ \brief translate model from context \c c to context \c dst.
def_API('Z3_model_translate', MODEL, (_in(CONTEXT), _in(MODEL), _in(CONTEXT)))
*/
@@ -6213,6 +6213,13 @@ extern "C" {
*/
Z3_ast_vector Z3_API Z3_solver_get_units(Z3_context c, Z3_solver s);
+ /**
+ \brief Return the trail modulo model conversion, in order of decision level
+ The decision level can be retrieved using \c Z3_solver_get_level based on the trail.
+
+ def_API('Z3_solver_get_trail', AST_VECTOR, (_in(CONTEXT), _in(SOLVER)))
+ */
+ Z3_ast_vector Z3_API Z3_solver_get_trail(Z3_context c, Z3_solver s);
/**
\brief Return the set of non units in the solver state.
@@ -6221,13 +6228,28 @@ extern "C" {
*/
Z3_ast_vector Z3_API Z3_solver_get_non_units(Z3_context c, Z3_solver s);
+ /**
+ \brief retrieve the decision depth of Boolean literals (variables or their negations).
+ Assumes a check-sat call and no other calls (to extract models) have been invoked.
+
+ def_API('Z3_solver_get_levels', VOID, (_in(CONTEXT), _in(SOLVER), _in(AST_VECTOR), _in(UINT), _in_array(3, UINT)))
+ */
+ void Z3_API Z3_solver_get_levels(Z3_context c, Z3_solver s, Z3_ast_vector literals, unsigned sz, unsigned levels[]);
+
+ /**
+ \brief set activity score associated with literal.
+
+ def_API('Z3_solver_set_activity', VOID, (_in(CONTEXT), _in(SOLVER), _in(AST), _in(DOUBLE)))
+ */
+ void Z3_API Z3_solver_set_activity(Z3_context c, Z3_solver s, Z3_ast l, double activity);
+
/**
\brief Check whether the assertions in a given solver are consistent or not.
The function #Z3_solver_get_model retrieves a model if the
assertions is satisfiable (i.e., the result is \c
Z3_L_TRUE) and model construction is enabled.
- Note that if the call returns Z3_L_UNDEF, Z3 does not
+ Note that if the call returns \c Z3_L_UNDEF, Z3 does not
ensure that calls to #Z3_solver_get_model succeed and any models
produced in this case are not guaranteed to satisfy the assertions.
@@ -6269,7 +6291,7 @@ extern "C" {
the current context implies that they are equal.
A side-effect of the function is a satisfiability check on the assertions on the solver that is passed in.
- The function return Z3_L_FALSE if the current assertions are not satisfiable.
+ The function return \c Z3_L_FALSE if the current assertions are not satisfiable.
def_API('Z3_get_implied_equalities', INT, (_in(CONTEXT), _in(SOLVER), _in(UINT), _in_array(2, AST), _out_array(2, UINT)))
*/
@@ -6342,7 +6364,7 @@ extern "C" {
Z3_ast_vector Z3_API Z3_solver_get_unsat_core(Z3_context c, Z3_solver s);
/**
- \brief Return a brief justification for an "unknown" result (i.e., Z3_L_UNDEF) for
+ \brief Return a brief justification for an "unknown" result (i.e., \c Z3_L_UNDEF) for
the commands #Z3_solver_check and #Z3_solver_check_assumptions
def_API('Z3_solver_get_reason_unknown', STRING, (_in(CONTEXT), _in(SOLVER)))
@@ -6368,6 +6390,14 @@ extern "C" {
*/
Z3_string Z3_API Z3_solver_to_string(Z3_context c, Z3_solver s);
+ /**
+ \brief Convert a solver into a DIMACS formatted string.
+ \sa Z3_goal_to_diamcs_string for requirements.
+
+ def_API('Z3_solver_to_dimacs_string', STRING, (_in(CONTEXT), _in(SOLVER)))
+ */
+ Z3_string Z3_API Z3_solver_to_dimacs_string(Z3_context c, Z3_solver s);
+
/*@}*/
/** @name Statistics */
diff --git a/src/api/z3_fixedpoint.h b/src/api/z3_fixedpoint.h
index 393cba224..54a42e9bf 100644
--- a/src/api/z3_fixedpoint.h
+++ b/src/api/z3_fixedpoint.h
@@ -106,9 +106,9 @@ extern "C" {
\endcode
query returns
- - Z3_L_FALSE if the query is unsatisfiable.
- - Z3_L_TRUE if the query is satisfiable. Obtain the answer by calling #Z3_fixedpoint_get_answer.
- - Z3_L_UNDEF if the query was interrupted, timed out or otherwise failed.
+ - \c Z3_L_FALSE if the query is unsatisfiable.
+ - \c Z3_L_TRUE if the query is satisfiable. Obtain the answer by calling #Z3_fixedpoint_get_answer.
+ - \c Z3_L_UNDEF if the query was interrupted, timed out or otherwise failed.
def_API('Z3_fixedpoint_query', INT, (_in(CONTEXT), _in(FIXEDPOINT), _in(AST)))
*/
@@ -120,9 +120,9 @@ extern "C" {
The queries are encoded as relations (function declarations).
query returns
- - Z3_L_FALSE if the query is unsatisfiable.
- - Z3_L_TRUE if the query is satisfiable. Obtain the answer by calling #Z3_fixedpoint_get_answer.
- - Z3_L_UNDEF if the query was interrupted, timed out or otherwise failed.
+ - \c Z3_L_FALSE if the query is unsatisfiable.
+ - \c Z3_L_TRUE if the query is satisfiable. Obtain the answer by calling #Z3_fixedpoint_get_answer.
+ - \c Z3_L_UNDEF if the query was interrupted, timed out or otherwise failed.
def_API('Z3_fixedpoint_query_relations', INT, (_in(CONTEXT), _in(FIXEDPOINT), _in(UINT), _in_array(2, FUNC_DECL)))
*/
@@ -138,8 +138,8 @@ extern "C" {
Each conjunct encodes values of the bound variables of the query that are satisfied.
In PDR mode, the returned answer is a single conjunction.
- When used in Datalog mode the previous call to #Z3_fixedpoint_query must have returned Z3_L_TRUE.
- When used with the PDR engine, the previous call must have been either Z3_L_TRUE or Z3_L_FALSE.
+ When used in Datalog mode the previous call to #Z3_fixedpoint_query must have returned \c Z3_L_TRUE.
+ When used with the PDR engine, the previous call must have been either \c Z3_L_TRUE or \c Z3_L_FALSE.
def_API('Z3_fixedpoint_get_answer', AST, (_in(CONTEXT), _in(FIXEDPOINT)))
*/
@@ -148,7 +148,7 @@ extern "C" {
/**
\brief Retrieve a string that describes the last status returned by #Z3_fixedpoint_query.
- Use this method when #Z3_fixedpoint_query returns Z3_L_UNDEF.
+ Use this method when #Z3_fixedpoint_query returns \c Z3_L_UNDEF.
def_API('Z3_fixedpoint_get_reason_unknown', STRING, (_in(CONTEXT), _in(FIXEDPOINT) ))
*/
@@ -395,7 +395,7 @@ extern "C" {
Z3_fixedpoint_predecessor_eh predecessor_eh,
Z3_fixedpoint_unfold_eh unfold_eh);
- void Z3_fixedpoint_add_constraint (Z3_context c, Z3_fixedpoint d, Z3_ast e, unsigned lvl);
+ void Z3_API Z3_fixedpoint_add_constraint (Z3_context c, Z3_fixedpoint d, Z3_ast e, unsigned lvl);
/*@}*/
/*@}*/
diff --git a/src/api/z3_fpa.h b/src/api/z3_fpa.h
index cc2091caa..1eaa1f64e 100644
--- a/src/api/z3_fpa.h
+++ b/src/api/z3_fpa.h
@@ -134,7 +134,7 @@ extern "C" {
\param ebits number of exponent bits
\param sbits number of significand bits
- \remark ebits must be larger than 1 and sbits must be larger than 2.
+ \remark \c ebits must be larger than 1 and \c sbits must be larger than 2.
def_API('Z3_mk_fpa_sort', SORT, (_in(CONTEXT), _in(UINT), _in(UINT)))
*/
@@ -213,7 +213,7 @@ extern "C" {
Z3_sort Z3_API Z3_mk_fpa_sort_128(Z3_context c);
/**
- \brief Create a floating-point NaN of sort s.
+ \brief Create a floating-point NaN of sort \c s.
\param c logical context
\param s target sort
@@ -223,7 +223,7 @@ extern "C" {
Z3_ast Z3_API Z3_mk_fpa_nan(Z3_context c, Z3_sort s);
/**
- \brief Create a floating-point infinity of sort s.
+ \brief Create a floating-point infinity of sort \c s.
\param c logical context
\param s target sort
@@ -236,7 +236,7 @@ extern "C" {
Z3_ast Z3_API Z3_mk_fpa_inf(Z3_context c, Z3_sort s, bool negative);
/**
- \brief Create a floating-point zero of sort s.
+ \brief Create a floating-point zero of sort \c s.
\param c logical context
\param s target sort
@@ -252,7 +252,7 @@ extern "C" {
\brief Create an expression of FloatingPoint sort from three bit-vector expressions.
This is the operator named `fp' in the SMT FP theory definition.
- Note that \c sign is required to be a bit-vector of size 1. Significand and exponent
+ Note that \c sgn is required to be a bit-vector of size 1. Significand and exponent
are required to be longer than 1 and 2 respectively. The FloatingPoint sort
of the resulting expression is automatically determined from the bit-vector sizes
of the arguments. The exponent is assumed to be in IEEE-754 biased representation.
@@ -276,7 +276,7 @@ extern "C" {
\param v value
\param ty sort
- ty must be a FloatingPoint sort
+ \c ty must be a FloatingPoint sort
\sa Z3_mk_numeral
@@ -294,7 +294,7 @@ extern "C" {
\param v value
\param ty sort
- ty must be a FloatingPoint sort
+ \c ty must be a FloatingPoint sort
\sa Z3_mk_numeral
@@ -309,7 +309,7 @@ extern "C" {
\param v value
\param ty result sort
- ty must be a FloatingPoint sort
+ \c ty must be a FloatingPoint sort
\sa Z3_mk_numeral
@@ -326,7 +326,7 @@ extern "C" {
\param exp exponent
\param ty result sort
- ty must be a FloatingPoint sort
+ \c ty must be a FloatingPoint sort
\sa Z3_mk_numeral
@@ -343,7 +343,7 @@ extern "C" {
\param exp exponent
\param ty result sort
- ty must be a FloatingPoint sort
+ \c ty must be a FloatingPoint sort
\sa Z3_mk_numeral
@@ -379,7 +379,7 @@ extern "C" {
\param t1 term of FloatingPoint sort
\param t2 term of FloatingPoint sort
- rm must be of RoundingMode sort, t1 and t2 must have the same FloatingPoint sort.
+ \c rm must be of RoundingMode sort, \c t1 and \c t2 must have the same FloatingPoint sort.
def_API('Z3_mk_fpa_add', AST, (_in(CONTEXT),_in(AST),_in(AST),_in(AST)))
*/
@@ -393,7 +393,7 @@ extern "C" {
\param t1 term of FloatingPoint sort
\param t2 term of FloatingPoint sort
- rm must be of RoundingMode sort, t1 and t2 must have the same FloatingPoint sort.
+ \c rm must be of RoundingMode sort, \c t1 and \c t2 must have the same FloatingPoint sort.
def_API('Z3_mk_fpa_sub', AST, (_in(CONTEXT),_in(AST),_in(AST),_in(AST)))
*/
@@ -407,7 +407,7 @@ extern "C" {
\param t1 term of FloatingPoint sort
\param t2 term of FloatingPoint sort
- rm must be of RoundingMode sort, t1 and t2 must have the same FloatingPoint sort.
+ \c rm must be of RoundingMode sort, \c t1 and \c t2 must have the same FloatingPoint sort.
def_API('Z3_mk_fpa_mul', AST, (_in(CONTEXT),_in(AST),_in(AST),_in(AST)))
*/
@@ -421,7 +421,7 @@ extern "C" {
\param t1 term of FloatingPoint sort.
\param t2 term of FloatingPoint sort
- The nodes rm must be of RoundingMode sort t1 and t2 must have the same FloatingPoint sort.
+ The nodes \c rm must be of RoundingMode sort, \c t1 and \c t2 must have the same FloatingPoint sort.
def_API('Z3_mk_fpa_div', AST, (_in(CONTEXT),_in(AST),_in(AST),_in(AST)))
*/
@@ -436,9 +436,9 @@ extern "C" {
\param t2 term of FloatingPoint sort
\param t3 term of FloatingPoint sort
- The result is round((t1 * t2) + t3)
+ The result is \ccode{round((t1 * t2) + t3)}.
- rm must be of RoundingMode sort, t1, t2, and t3 must have the same FloatingPoint sort.
+ \c rm must be of RoundingMode sort, \c t1, \c t2, and \c t3 must have the same FloatingPoint sort.
def_API('Z3_mk_fpa_fma', AST, (_in(CONTEXT),_in(AST),_in(AST),_in(AST),_in(AST)))
*/
@@ -451,7 +451,7 @@ extern "C" {
\param rm term of RoundingMode sort
\param t term of FloatingPoint sort
- rm must be of RoundingMode sort, t must have FloatingPoint sort.
+ \c rm must be of RoundingMode sort, \c t must have FloatingPoint sort.
def_API('Z3_mk_fpa_sqrt', AST, (_in(CONTEXT),_in(AST),_in(AST)))
*/
@@ -464,7 +464,7 @@ extern "C" {
\param t1 term of FloatingPoint sort
\param t2 term of FloatingPoint sort
- t1 and t2 must have the same FloatingPoint sort.
+ \c t1 and \c t2 must have the same FloatingPoint sort.
def_API('Z3_mk_fpa_rem', AST, (_in(CONTEXT),_in(AST),_in(AST)))
*/
@@ -478,7 +478,7 @@ extern "C" {
\param rm term of RoundingMode sort
\param t term of FloatingPoint sort
- t must be of FloatingPoint sort.
+ \c t must be of FloatingPoint sort.
def_API('Z3_mk_fpa_round_to_integral', AST, (_in(CONTEXT),_in(AST),_in(AST)))
*/
@@ -491,7 +491,7 @@ extern "C" {
\param t1 term of FloatingPoint sort
\param t2 term of FloatingPoint sort
- t1, t2 must have the same FloatingPoint sort.
+ \c t1, \c t2 must have the same FloatingPoint sort.
def_API('Z3_mk_fpa_min', AST, (_in(CONTEXT),_in(AST),_in(AST)))
*/
@@ -504,7 +504,7 @@ extern "C" {
\param t1 term of FloatingPoint sort
\param t2 term of FloatingPoint sort
- t1, t2 must have the same FloatingPoint sort.
+ \c t1, \c t2 must have the same FloatingPoint sort.
def_API('Z3_mk_fpa_max', AST, (_in(CONTEXT),_in(AST),_in(AST)))
*/
@@ -517,7 +517,7 @@ extern "C" {
\param t1 term of FloatingPoint sort
\param t2 term of FloatingPoint sort
- t1 and t2 must have the same FloatingPoint sort.
+ \c t1 and \c t2 must have the same FloatingPoint sort.
def_API('Z3_mk_fpa_leq', AST, (_in(CONTEXT),_in(AST),_in(AST)))
*/
@@ -530,7 +530,7 @@ extern "C" {
\param t1 term of FloatingPoint sort
\param t2 term of FloatingPoint sort
- t1 and t2 must have the same FloatingPoint sort.
+ \c t1 and \c t2 must have the same FloatingPoint sort.
def_API('Z3_mk_fpa_lt', AST, (_in(CONTEXT),_in(AST),_in(AST)))
*/
@@ -543,7 +543,7 @@ extern "C" {
\param t1 term of FloatingPoint sort
\param t2 term of FloatingPoint sort
- t1 and t2 must have the same FloatingPoint sort.
+ \c t1 and \c t2 must have the same FloatingPoint sort.
def_API('Z3_mk_fpa_geq', AST, (_in(CONTEXT),_in(AST),_in(AST)))
*/
@@ -556,7 +556,7 @@ extern "C" {
\param t1 term of FloatingPoint sort
\param t2 term of FloatingPoint sort
- t1 and t2 must have the same FloatingPoint sort.
+ \c t1 and \c t2 must have the same FloatingPoint sort.
def_API('Z3_mk_fpa_gt', AST, (_in(CONTEXT),_in(AST),_in(AST)))
*/
@@ -569,93 +569,93 @@ extern "C" {
\param t1 term of FloatingPoint sort
\param t2 term of FloatingPoint sort
- Note that this is IEEE 754 equality (as opposed to SMT-LIB =).
+ Note that this is IEEE 754 equality (as opposed to SMT-LIB \ccode{=}).
- t1 and t2 must have the same FloatingPoint sort.
+ \c t1 and \c t2 must have the same FloatingPoint sort.
def_API('Z3_mk_fpa_eq', AST, (_in(CONTEXT),_in(AST),_in(AST)))
*/
Z3_ast Z3_API Z3_mk_fpa_eq(Z3_context c, Z3_ast t1, Z3_ast t2);
/**
- \brief Predicate indicating whether t is a normal floating-point number.
+ \brief Predicate indicating whether \c t is a normal floating-point number.
\param c logical context
\param t term of FloatingPoint sort
- t must have FloatingPoint sort.
+ \c t must have FloatingPoint sort.
def_API('Z3_mk_fpa_is_normal', AST, (_in(CONTEXT),_in(AST)))
*/
Z3_ast Z3_API Z3_mk_fpa_is_normal(Z3_context c, Z3_ast t);
/**
- \brief Predicate indicating whether t is a subnormal floating-point number.
+ \brief Predicate indicating whether \c t is a subnormal floating-point number.
\param c logical context
\param t term of FloatingPoint sort
- t must have FloatingPoint sort.
+ \c t must have FloatingPoint sort.
def_API('Z3_mk_fpa_is_subnormal', AST, (_in(CONTEXT),_in(AST)))
*/
Z3_ast Z3_API Z3_mk_fpa_is_subnormal(Z3_context c, Z3_ast t);
/**
- \brief Predicate indicating whether t is a floating-point number with zero value, i.e., +zero or -zero.
+ \brief Predicate indicating whether \c t is a floating-point number with zero value, i.e., +zero or -zero.
\param c logical context
\param t term of FloatingPoint sort
- t must have FloatingPoint sort.
+ \c t must have FloatingPoint sort.
def_API('Z3_mk_fpa_is_zero', AST, (_in(CONTEXT),_in(AST)))
*/
Z3_ast Z3_API Z3_mk_fpa_is_zero(Z3_context c, Z3_ast t);
/**
- \brief Predicate indicating whether t is a floating-point number representing +oo or -oo.
+ \brief Predicate indicating whether \c t is a floating-point number representing +oo or -oo.
\param c logical context
\param t term of FloatingPoint sort
- t must have FloatingPoint sort.
+ \c t must have FloatingPoint sort.
def_API('Z3_mk_fpa_is_infinite', AST, (_in(CONTEXT),_in(AST)))
*/
Z3_ast Z3_API Z3_mk_fpa_is_infinite(Z3_context c, Z3_ast t);
/**
- \brief Predicate indicating whether t is a NaN.
+ \brief Predicate indicating whether \c t is a NaN.
\param c logical context
\param t term of FloatingPoint sort
- t must have FloatingPoint sort.
+ \c t must have FloatingPoint sort.
def_API('Z3_mk_fpa_is_nan', AST, (_in(CONTEXT),_in(AST)))
*/
Z3_ast Z3_API Z3_mk_fpa_is_nan(Z3_context c, Z3_ast t);
/**
- \brief Predicate indicating whether t is a negative floating-point number.
+ \brief Predicate indicating whether \c t is a negative floating-point number.
\param c logical context
\param t term of FloatingPoint sort
- t must have FloatingPoint sort.
+ \c t must have FloatingPoint sort.
def_API('Z3_mk_fpa_is_negative', AST, (_in(CONTEXT),_in(AST)))
*/
Z3_ast Z3_API Z3_mk_fpa_is_negative(Z3_context c, Z3_ast t);
/**
- \brief Predicate indicating whether t is a positive floating-point number.
+ \brief Predicate indicating whether \c t is a positive floating-point number.
\param c logical context
\param t term of FloatingPoint sort
- t must have FloatingPoint sort.
+ \c t must have FloatingPoint sort.
def_API('Z3_mk_fpa_is_positive', AST, (_in(CONTEXT),_in(AST)))
*/
@@ -664,15 +664,15 @@ extern "C" {
/**
\brief Conversion of a single IEEE 754-2008 bit-vector into a floating-point number.
- Produces a term that represents the conversion of a bit-vector term bv to a
- floating-point term of sort s.
+ Produces a term that represents the conversion of a bit-vector term \c bv to a
+ floating-point term of sort \c s.
\param c logical context
\param bv a bit-vector term
\param s floating-point sort
- s must be a FloatingPoint sort, t must be of bit-vector sort, and the bit-vector
- size of bv must be equal to ebits+sbits of s. The format of the bit-vector is
+ \c s must be a FloatingPoint sort, \c t must be of bit-vector sort, and the bit-vector
+ size of \c bv must be equal to \ccode{ebits+sbits} of \c s. The format of the bit-vector is
as defined by the IEEE 754-2008 interchange format.
def_API('Z3_mk_fpa_to_fp_bv', AST, (_in(CONTEXT),_in(AST),_in(SORT)))
@@ -682,16 +682,16 @@ extern "C" {
/**
\brief Conversion of a FloatingPoint term into another term of different FloatingPoint sort.
- Produces a term that represents the conversion of a floating-point term t to a
- floating-point term of sort s. If necessary, the result will be rounded according
- to rounding mode rm.
+ Produces a term that represents the conversion of a floating-point term \c t to a
+ floating-point term of sort \c s. If necessary, the result will be rounded according
+ to rounding mode \c rm.
\param c logical context
\param rm term of RoundingMode sort
\param t term of FloatingPoint sort
\param s floating-point sort
- s must be a FloatingPoint sort, rm must be of RoundingMode sort, t must be of floating-point sort.
+ \c s must be a FloatingPoint sort, \c rm must be of RoundingMode sort, \c t must be of floating-point sort.
def_API('Z3_mk_fpa_to_fp_float', AST, (_in(CONTEXT),_in(AST),_in(AST),_in(SORT)))
*/
@@ -700,16 +700,16 @@ extern "C" {
/**
\brief Conversion of a term of real sort into a term of FloatingPoint sort.
- Produces a term that represents the conversion of term t of real sort into a
- floating-point term of sort s. If necessary, the result will be rounded according
- to rounding mode rm.
+ Produces a term that represents the conversion of term \c t of real sort into a
+ floating-point term of sort \c s. If necessary, the result will be rounded according
+ to rounding mode \c rm.
\param c logical context
\param rm term of RoundingMode sort
\param t term of Real sort
\param s floating-point sort
- s must be a FloatingPoint sort, rm must be of RoundingMode sort, t must be of real sort.
+ \c s must be a FloatingPoint sort, \c rm must be of RoundingMode sort, \c t must be of real sort.
def_API('Z3_mk_fpa_to_fp_real', AST, (_in(CONTEXT),_in(AST),_in(AST),_in(SORT)))
*/
@@ -718,17 +718,17 @@ extern "C" {
/**
\brief Conversion of a 2's complement signed bit-vector term into a term of FloatingPoint sort.
- Produces a term that represents the conversion of the bit-vector term t into a
- floating-point term of sort s. The bit-vector t is taken to be in signed
+ Produces a term that represents the conversion of the bit-vector term \c t into a
+ floating-point term of sort \c s. The bit-vector \c t is taken to be in signed
2's complement format. If necessary, the result will be rounded according
- to rounding mode rm.
+ to rounding mode \c rm.
\param c logical context
\param rm term of RoundingMode sort
\param t term of bit-vector sort
\param s floating-point sort
- s must be a FloatingPoint sort, rm must be of RoundingMode sort, t must be of bit-vector sort.
+ \c s must be a FloatingPoint sort, \c rm must be of RoundingMode sort, \c t must be of bit-vector sort.
def_API('Z3_mk_fpa_to_fp_signed', AST, (_in(CONTEXT),_in(AST),_in(AST),_in(SORT)))
*/
@@ -737,17 +737,17 @@ extern "C" {
/**
\brief Conversion of a 2's complement unsigned bit-vector term into a term of FloatingPoint sort.
- Produces a term that represents the conversion of the bit-vector term t into a
- floating-point term of sort s. The bit-vector t is taken to be in unsigned
+ Produces a term that represents the conversion of the bit-vector term \c t into a
+ floating-point term of sort \c s. The bit-vector \c t is taken to be in unsigned
2's complement format. If necessary, the result will be rounded according
- to rounding mode rm.
+ to rounding mode \c rm.
\param c logical context
\param rm term of RoundingMode sort
\param t term of bit-vector sort
\param s floating-point sort
- s must be a FloatingPoint sort, rm must be of RoundingMode sort, t must be of bit-vector sort.
+ \c s must be a FloatingPoint sort, \c rm must be of RoundingMode sort, \c t must be of bit-vector sort.
def_API('Z3_mk_fpa_to_fp_unsigned', AST, (_in(CONTEXT),_in(AST),_in(AST),_in(SORT)))
*/
@@ -756,9 +756,9 @@ extern "C" {
/**
\brief Conversion of a floating-point term into an unsigned bit-vector.
- Produces a term that represents the conversion of the floating-point term t into a
- bit-vector term of size sz in unsigned 2's complement format. If necessary, the result
- will be rounded according to rounding mode rm.
+ Produces a term that represents the conversion of the floating-point term \c t into a
+ bit-vector term of size \c sz in unsigned 2's complement format. If necessary, the result
+ will be rounded according to rounding mode \c rm.
\param c logical context
\param rm term of RoundingMode sort
@@ -772,9 +772,9 @@ extern "C" {
/**
\brief Conversion of a floating-point term into a signed bit-vector.
- Produces a term that represents the conversion of the floating-point term t into a
- bit-vector term of size sz in signed 2's complement format. If necessary, the result
- will be rounded according to rounding mode rm.
+ Produces a term that represents the conversion of the floating-point term \c t into a
+ bit-vector term of size \c sz in signed 2's complement format. If necessary, the result
+ will be rounded according to rounding mode \c rm.
\param c logical context
\param rm term of RoundingMode sort
@@ -788,7 +788,7 @@ extern "C" {
/**
\brief Conversion of a floating-point term into a real-numbered term.
- Produces a term that represents the conversion of the floating-point term t into a
+ Produces a term that represents the conversion of the floating-point term \c t into a
real number. Note that this type of conversion will often result in non-linear
constraints over real terms.
@@ -936,7 +936,7 @@ extern "C" {
\param c logical context
\param t a floating-point numeral
- Remarks: The significand s is always 0.0 <= s < 2.0; the resulting string is long
+ Remarks: The significand \c s is always \ccode{0.0 <= s < 2.0}; the resulting string is long
enough to represent the real significand precisely.
def_API('Z3_fpa_get_numeral_significand_string', STRING, (_in(CONTEXT), _in(AST)))
@@ -951,8 +951,8 @@ extern "C" {
\param n pointer to output uint64
Remarks: This function extracts the significand bits in `t`, without the
- hidden bit or normalization. Sets the Z3_INVALID_ARG error code if the
- significand does not fit into a uint64. NaN is an invalid argument.
+ hidden bit or normalization. Sets the \c Z3_INVALID_ARG error code if the
+ significand does not fit into a \c uint64. NaN is an invalid argument.
def_API('Z3_fpa_get_numeral_significand_uint64', BOOL, (_in(CONTEXT), _in(AST), _out(UINT64)))
*/
@@ -1007,7 +1007,7 @@ extern "C" {
\param c logical context
\param t term of FloatingPoint sort
- t must have FloatingPoint sort. The size of the resulting bit-vector is automatically
+ \c t must have FloatingPoint sort. The size of the resulting bit-vector is automatically
determined.
Note that IEEE 754-2008 allows multiple different representations of NaN. This conversion
@@ -1021,9 +1021,9 @@ extern "C" {
/**
\brief Conversion of a real-sorted significand and an integer-sorted exponent into a term of FloatingPoint sort.
- Produces a term that represents the conversion of sig * 2^exp into a
- floating-point term of sort s. If necessary, the result will be rounded
- according to rounding mode rm.
+ Produces a term that represents the conversion of \ccode{sig * 2^exp} into a
+ floating-point term of sort \c s. If necessary, the result will be rounded
+ according to rounding mode \c rm.
\param c logical context
\param rm term of RoundingMode sort
@@ -1031,7 +1031,7 @@ extern "C" {
\param sig significand term of Real sort
\param s FloatingPoint sort
- s must be a FloatingPoint sort, rm must be of RoundingMode sort, exp must be of int sort, sig must be of real sort.
+ \c s must be a FloatingPoint sort, \c rm must be of RoundingMode sort, \c exp must be of int sort, \c sig must be of real sort.
def_API('Z3_mk_fpa_to_fp_int_real', AST, (_in(CONTEXT),_in(AST),_in(AST),_in(AST),_in(SORT)))
*/
diff --git a/src/api/z3_macros.h b/src/api/z3_macros.h
index c74144e90..d1ac18804 100644
--- a/src/api/z3_macros.h
+++ b/src/api/z3_macros.h
@@ -19,7 +19,3 @@ Copyright (c) 2015 Microsoft Corporation
#ifndef DEFINE_TYPE
#define DEFINE_TYPE(T) typedef struct _ ## T *T
#endif
-
-#ifndef DEFINE_VOID
-#define DEFINE_VOID(T) typedef void* T
-#endif
diff --git a/src/api/z3_optimization.h b/src/api/z3_optimization.h
index 750f286a5..18cee9bec 100644
--- a/src/api/z3_optimization.h
+++ b/src/api/z3_optimization.h
@@ -56,11 +56,23 @@ extern "C" {
\brief Assert hard constraint to the optimization context.
\sa Z3_optimize_assert_soft
+ \sa Z3_optimize_assert_and_track
def_API('Z3_optimize_assert', VOID, (_in(CONTEXT), _in(OPTIMIZE), _in(AST)))
*/
void Z3_API Z3_optimize_assert(Z3_context c, Z3_optimize o, Z3_ast a);
+
+ /**
+ \brief Assert tracked hard constraint to the optimization context.
+
+ \sa Z3_optimize_assert
+ \sa Z3_optimize_assert_soft
+
+ def_API('Z3_optimize_assert_and_track', VOID, (_in(CONTEXT), _in(OPTIMIZE), _in(AST), _in(AST)))
+ */
+ void Z3_API Z3_optimize_assert_and_track(Z3_context c, Z3_optimize o, Z3_ast a, Z3_ast t);
+
/**
\brief Assert soft constraint to the optimization context.
\param c - context
@@ -142,7 +154,7 @@ extern "C" {
/**
\brief Retrieve a string that describes the last status returned by #Z3_optimize_check.
- Use this method when #Z3_optimize_check returns Z3_L_UNDEF.
+ Use this method when #Z3_optimize_check returns \c Z3_L_UNDEF.
def_API('Z3_optimize_get_reason_unknown', STRING, (_in(CONTEXT), _in(OPTIMIZE) ))
*/
@@ -228,8 +240,8 @@ extern "C" {
/**
\brief Retrieve lower bound value or approximation for the i'th optimization objective.
The returned vector is of length 3. It always contains numerals.
- The three numerals are coefficients a, b, c and encode the result of \c Z3_optimize_get_lower
- a * infinity + b + c * epsilon.
+ The three numerals are coefficients \c a, \c b, \c c and encode the result of
+ #Z3_optimize_get_lower \ccode{a * infinity + b + c * epsilon}.
\param c - context
\param o - optimization context
@@ -330,7 +342,7 @@ extern "C" {
/**
\brief Return objectives on the optimization context.
If the objective function is a max-sat objective it is returned
- as a Pseudo-Boolean (minimization) sum of the form (+ (if f1 w1 0) (if f2 w2 0) ...)
+ as a Pseudo-Boolean (minimization) sum of the form \ccode{(+ (if f1 w1 0) (if f2 w2 0) ...)}
If the objective function is entered as a maximization objective, then return
the corresponding minimization objective. In this way the resulting objective
function is always returned as a minimization objective.
diff --git a/src/api/z3_polynomial.h b/src/api/z3_polynomial.h
index 0561bfd9c..5f4815d02 100644
--- a/src/api/z3_polynomial.h
+++ b/src/api/z3_polynomial.h
@@ -36,9 +36,8 @@ extern "C" {
\pre \c p, \c q and \c x are Z3 expressions where \c p and \c q are arithmetic terms.
Note that, any subterm that cannot be viewed as a polynomial is assumed to be a variable.
- Example: f(a) is a considered to be a variable in the polynomial
-
- f(a)*f(a) + 2*f(a) + 1
+ Example: \ccode{f(a)} is a considered to be a variable in the polynomial \ccode{
+ f(a)*f(a) + 2*f(a) + 1}
def_API('Z3_polynomial_subresultants', AST_VECTOR, (_in(CONTEXT), _in(AST), _in(AST), _in(AST)))
*/
diff --git a/src/api/z3_rcf.h b/src/api/z3_rcf.h
index dc025bddd..4e4ecbd15 100644
--- a/src/api/z3_rcf.h
+++ b/src/api/z3_rcf.h
@@ -74,7 +74,7 @@ extern "C" {
Z3_rcf_num Z3_API Z3_rcf_mk_infinitesimal(Z3_context c);
/**
- \brief Store in roots the roots of the polynomial a[n-1]*x^{n-1} + ... + a[0].
+ \brief Store in roots the roots of the polynomial \ccode{a[n-1]*x^{n-1} + ... + a[0]}.
The output vector \c roots must have size \c n.
It returns the number of roots of the polynomial.
@@ -85,91 +85,91 @@ extern "C" {
unsigned Z3_API Z3_rcf_mk_roots(Z3_context c, unsigned n, Z3_rcf_num const a[], Z3_rcf_num roots[]);
/**
- \brief Return the value a + b.
+ \brief Return the value \ccode{a + b}.
def_API('Z3_rcf_add', RCF_NUM, (_in(CONTEXT), _in(RCF_NUM), _in(RCF_NUM)))
*/
Z3_rcf_num Z3_API Z3_rcf_add(Z3_context c, Z3_rcf_num a, Z3_rcf_num b);
/**
- \brief Return the value a - b.
+ \brief Return the value \ccode{a - b}.
def_API('Z3_rcf_sub', RCF_NUM, (_in(CONTEXT), _in(RCF_NUM), _in(RCF_NUM)))
*/
Z3_rcf_num Z3_API Z3_rcf_sub(Z3_context c, Z3_rcf_num a, Z3_rcf_num b);
/**
- \brief Return the value a * b.
+ \brief Return the value \ccode{a * b}.
def_API('Z3_rcf_mul', RCF_NUM, (_in(CONTEXT), _in(RCF_NUM), _in(RCF_NUM)))
*/
Z3_rcf_num Z3_API Z3_rcf_mul(Z3_context c, Z3_rcf_num a, Z3_rcf_num b);
/**
- \brief Return the value a / b.
+ \brief Return the value \ccode{a / b}.
def_API('Z3_rcf_div', RCF_NUM, (_in(CONTEXT), _in(RCF_NUM), _in(RCF_NUM)))
*/
Z3_rcf_num Z3_API Z3_rcf_div(Z3_context c, Z3_rcf_num a, Z3_rcf_num b);
/**
- \brief Return the value -a
+ \brief Return the value \ccode{-a}.
def_API('Z3_rcf_neg', RCF_NUM, (_in(CONTEXT), _in(RCF_NUM)))
*/
Z3_rcf_num Z3_API Z3_rcf_neg(Z3_context c, Z3_rcf_num a);
/**
- \brief Return the value 1/a
+ \brief Return the value \ccode{1/a}.
def_API('Z3_rcf_inv', RCF_NUM, (_in(CONTEXT), _in(RCF_NUM)))
*/
Z3_rcf_num Z3_API Z3_rcf_inv(Z3_context c, Z3_rcf_num a);
/**
- \brief Return the value a^k
+ \brief Return the value \ccode{a^k}.
def_API('Z3_rcf_power', RCF_NUM, (_in(CONTEXT), _in(RCF_NUM), _in(UINT)))
*/
Z3_rcf_num Z3_API Z3_rcf_power(Z3_context c, Z3_rcf_num a, unsigned k);
/**
- \brief Return \c true if a < b
+ \brief Return \c true if \ccode{a < b}.
def_API('Z3_rcf_lt', BOOL, (_in(CONTEXT), _in(RCF_NUM), _in(RCF_NUM)))
*/
bool Z3_API Z3_rcf_lt(Z3_context c, Z3_rcf_num a, Z3_rcf_num b);
/**
- \brief Return \c true if a > b
+ \brief Return \c true if \ccode{a > b}.
def_API('Z3_rcf_gt', BOOL, (_in(CONTEXT), _in(RCF_NUM), _in(RCF_NUM)))
*/
bool Z3_API Z3_rcf_gt(Z3_context c, Z3_rcf_num a, Z3_rcf_num b);
/**
- \brief Return \c true if a <= b
+ \brief Return \c true if \ccode{a <= b}.
def_API('Z3_rcf_le', BOOL, (_in(CONTEXT), _in(RCF_NUM), _in(RCF_NUM)))
*/
bool Z3_API Z3_rcf_le(Z3_context c, Z3_rcf_num a, Z3_rcf_num b);
/**
- \brief Return \c true if a >= b
+ \brief Return \c true if \ccode{a >= b}.
def_API('Z3_rcf_ge', BOOL, (_in(CONTEXT), _in(RCF_NUM), _in(RCF_NUM)))
*/
bool Z3_API Z3_rcf_ge(Z3_context c, Z3_rcf_num a, Z3_rcf_num b);
/**
- \brief Return \c true if a == b
+ \brief Return \c true if \ccode{a == b}.
def_API('Z3_rcf_eq', BOOL, (_in(CONTEXT), _in(RCF_NUM), _in(RCF_NUM)))
*/
bool Z3_API Z3_rcf_eq(Z3_context c, Z3_rcf_num a, Z3_rcf_num b);
/**
- \brief Return \c true if a != b
+ \brief Return \c true if \ccode{a != b}.
def_API('Z3_rcf_neq', BOOL, (_in(CONTEXT), _in(RCF_NUM), _in(RCF_NUM)))
*/
@@ -191,7 +191,7 @@ extern "C" {
/**
\brief Extract the "numerator" and "denominator" of the given RCF numeral.
- We have that a = n/d, moreover n and d are not represented using rational functions.
+ We have that \ccode{a = n/d}, moreover \c n and \c d are not represented using rational functions.
def_API('Z3_rcf_get_numerator_denominator', VOID, (_in(CONTEXT), _in(RCF_NUM), _out(RCF_NUM), _out(RCF_NUM)))
*/
diff --git a/src/api/z3_spacer.h b/src/api/z3_spacer.h
index 88129d095..09cbe6a51 100644
--- a/src/api/z3_spacer.h
+++ b/src/api/z3_spacer.h
@@ -37,9 +37,9 @@ extern "C" {
\endcode
query returns
- - Z3_L_FALSE if the query is unsatisfiable.
- - Z3_L_TRUE if the query is satisfiable. Obtain the answer by calling #Z3_fixedpoint_get_answer.
- - Z3_L_UNDEF if the query was interrupted, timed out or otherwise failed.
+ - \c Z3_L_FALSE if the query is unsatisfiable.
+ - \c Z3_L_TRUE if the query is satisfiable. Obtain the answer by calling #Z3_fixedpoint_get_answer.
+ - \c Z3_L_UNDEF if the query was interrupted, timed out or otherwise failed.
def_API('Z3_fixedpoint_query_from_lvl', INT, (_in(CONTEXT), _in(FIXEDPOINT), _in(AST), _in(UINT)))
*/
@@ -48,7 +48,7 @@ extern "C" {
/**
\brief Retrieve a bottom-up (from query) sequence of ground facts
- The previous call to Z3_fixedpoint_query must have returned Z3_L_TRUE.
+ The previous call to #Z3_fixedpoint_query must have returned \c Z3_L_TRUE.
def_API('Z3_fixedpoint_get_ground_sat_answer', AST, (_in(CONTEXT), _in(FIXEDPOINT)))
*/
diff --git a/src/ast/CMakeLists.txt b/src/ast/CMakeLists.txt
index ce2817b58..56ab78b8a 100644
--- a/src/ast/CMakeLists.txt
+++ b/src/ast/CMakeLists.txt
@@ -17,6 +17,7 @@ z3_add_component(ast
csp_decl_plugin.cpp
datatype_decl_plugin.cpp
decl_collector.cpp
+ display_dimacs.cpp
dl_decl_plugin.cpp
expr2polynomial.cpp
expr2var.cpp
diff --git a/src/ast/act_cache.cpp b/src/ast/act_cache.cpp
index 14f0985b4..db3f0f12b 100644
--- a/src/ast/act_cache.cpp
+++ b/src/ast/act_cache.cpp
@@ -73,11 +73,9 @@ void act_cache::init() {
}
void act_cache::dec_refs() {
- map::iterator it = m_table.begin();
- map::iterator end = m_table.end();
- for (; it != end; ++it) {
- m_manager.dec_ref((*it).m_key);
- m_manager.dec_ref(UNTAG(expr*, (*it).m_value));
+ for (auto & kv : m_table) {
+ m_manager.dec_ref(kv.m_key.first);
+ m_manager.dec_ref(UNTAG(expr*, kv.m_value));
}
}
@@ -105,18 +103,18 @@ act_cache::~act_cache() {
void act_cache::del_unused() {
unsigned sz = m_queue.size();
while (m_qhead < sz) {
- expr * k = m_queue[m_qhead];
+ entry_t const& e = m_queue[m_qhead];
m_qhead++;
- SASSERT(m_table.contains(k));
- map::key_value * entry = m_table.find_core(k);
+ SASSERT(m_table.contains(e));
+ map::key_value * entry = m_table.find_core(e);
SASSERT(entry);
if (GET_TAG(entry->m_value) == 0) {
// Key k was never accessed by client code.
// That is, find(k) was never executed by client code.
m_unused--;
expr * v = entry->m_value;
- m_table.erase(k);
- m_manager.dec_ref(k);
+ m_table.erase(e);
+ m_manager.dec_ref(e.first);
m_manager.dec_ref(v);
break;
}
@@ -135,12 +133,13 @@ void act_cache::del_unused() {
/**
\brief Insert a new entry k -> v into the cache.
*/
-void act_cache::insert(expr * k, expr * v) {
+void act_cache::insert(expr * k, unsigned offset, expr * v) {
SASSERT(k);
+ entry_t e(k, offset);
if (m_unused >= m_max_unused)
del_unused();
expr * dummy = reinterpret_cast(1);
- map::key_value & entry = m_table.insert_if_not_there(k, dummy);
+ map::key_value & entry = m_table.insert_if_not_there(e, dummy);
#if 0
unsigned static counter = 0;
counter++;
@@ -156,7 +155,7 @@ void act_cache::insert(expr * k, expr * v) {
m_manager.inc_ref(k);
m_manager.inc_ref(v);
entry.m_value = v;
- m_queue.push_back(k);
+ m_queue.push_back(e);
m_unused++;
DEBUG_CODE(expected_tag = 0;); // new entry
}
@@ -175,7 +174,7 @@ void act_cache::insert(expr * k, expr * v) {
}
DEBUG_CODE({
expr * v2;
- SASSERT(m_table.find(k, v2));
+ SASSERT(m_table.find(e, v2));
SASSERT(v == UNTAG(expr*, v2));
SASSERT(expected_tag == GET_TAG(v2));
});
@@ -185,8 +184,9 @@ void act_cache::insert(expr * k, expr * v) {
\brief Search for key k in the cache.
If entry k -> (v, tag) is found, we set tag to 1.
*/
-expr * act_cache::find(expr * k) {
- map::key_value * entry = m_table.find_core(k);
+expr * act_cache::find(expr * k, unsigned offset) {
+ entry_t e(k, offset);
+ map::key_value * entry = m_table.find_core(e);
if (entry == nullptr)
return nullptr;
if (GET_TAG(entry->m_value) == 0) {
@@ -196,7 +196,7 @@ expr * act_cache::find(expr * k) {
m_unused--;
DEBUG_CODE({
expr * v;
- SASSERT(m_table.find(k, v));
+ SASSERT(m_table.find(e, v));
SASSERT(GET_TAG(v) == 1);
});
}
diff --git a/src/ast/act_cache.h b/src/ast/act_cache.h
index 67c5cf050..49b49face 100644
--- a/src/ast/act_cache.h
+++ b/src/ast/act_cache.h
@@ -26,9 +26,15 @@ Notes:
class act_cache {
ast_manager & m_manager;
- typedef cmap, default_eq > map;
+ typedef std::pair entry_t;
+ struct entry_hash {
+ unsigned operator()(entry_t const& e) const {
+ return e.first->hash() + e.second;
+ }
+ };
+ typedef cmap > map;
map m_table;
- ptr_vector m_queue; // recently created queue
+ svector m_queue; // recently created queue
unsigned m_qhead;
unsigned m_unused;
unsigned m_max_unused;
@@ -42,8 +48,10 @@ public:
act_cache(ast_manager & m);
act_cache(ast_manager & m, unsigned max_unused);
~act_cache();
- void insert(expr * k, expr * v);
- expr * find(expr * k);
+ void insert(expr * k, expr * v) { insert(k, 0, v); }
+ expr * find(expr * k) { return find(k, 0); }
+ void insert(expr * k, unsigned offset, expr * v);
+ expr * find(expr * k, unsigned offset);
void reset();
void cleanup();
unsigned size() const { return m_table.size(); }
diff --git a/src/ast/array_decl_plugin.cpp b/src/ast/array_decl_plugin.cpp
index fa17b591d..44c423c09 100644
--- a/src/ast/array_decl_plugin.cpp
+++ b/src/ast/array_decl_plugin.cpp
@@ -571,6 +571,11 @@ func_decl * array_recognizers::get_as_array_func_decl(expr * n) const {
return to_func_decl(to_app(n)->get_decl()->get_parameter(0).get_ast());
}
+func_decl * array_recognizers::get_as_array_func_decl(func_decl * f) const {
+ SASSERT(is_as_array(f));
+ return to_func_decl(f->get_parameter(0).get_ast());
+}
+
array_util::array_util(ast_manager& m):
array_recognizers(m.mk_family_id("array")),
m_manager(m) {
diff --git a/src/ast/array_decl_plugin.h b/src/ast/array_decl_plugin.h
index beaccfbd3..c735fb811 100644
--- a/src/ast/array_decl_plugin.h
+++ b/src/ast/array_decl_plugin.h
@@ -149,7 +149,9 @@ public:
bool is_const(func_decl* f) const { return is_decl_of(f, m_fid, OP_CONST_ARRAY); }
bool is_map(func_decl* f) const { return is_decl_of(f, m_fid, OP_ARRAY_MAP); }
bool is_as_array(func_decl* f) const { return is_decl_of(f, m_fid, OP_AS_ARRAY); }
+ bool is_as_array(func_decl* f, func_decl*& g) const { return is_decl_of(f, m_fid, OP_AS_ARRAY) && (g = get_as_array_func_decl(f), true); }
func_decl * get_as_array_func_decl(expr * n) const;
+ func_decl * get_as_array_func_decl(func_decl* f) const;
};
class array_util : public array_recognizers {
diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp
index 0f6a81a59..b84dac136 100644
--- a/src/ast/ast.cpp
+++ b/src/ast/ast.cpp
@@ -1407,6 +1407,7 @@ ast_manager::ast_manager(ast_manager const & src, bool disable_proofs):
m_format_manager = alloc(ast_manager, PGM_DISABLED, m_trace_stream, true);
init();
copy_families_plugins(src);
+ update_fresh_id(src);
}
void ast_manager::update_fresh_id(ast_manager const& m) {
@@ -2156,7 +2157,6 @@ app * ast_manager::mk_app_core(func_decl * decl, unsigned num_args, expr * const
app * new_node = nullptr;
unsigned sz = app::get_obj_size(num_args);
void * mem = allocate_node(sz);
-
try {
if (m_int_real_coercions && coercion_needed(decl, num_args, args)) {
expr_ref_buffer new_args(*this);
diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp
index 5f2d36279..ceeab30ff 100644
--- a/src/ast/ast_smt2_pp.cpp
+++ b/src/ast/ast_smt2_pp.cpp
@@ -238,7 +238,7 @@ format * smt2_pp_environment::pp_float_literal(app * t, bool use_bv_lits, bool u
string_buffer<> buf;
VERIFY(get_futil().is_numeral(t, v));
if (fm.is_nan(v)) {
- buf << "(_ NaN " << v.get().get_ebits() << " " << v.get().get_sbits() << ")";
+ buf << "(_ NaN " << v.get().get_ebits() << " " << v.get().get_sbits() << ")";
return mk_string(m, buf.c_str());
}
else if (fm.is_pinf(v)) {
diff --git a/src/ast/ast_smt_pp.cpp b/src/ast/ast_smt_pp.cpp
index 0def08094..2490e0314 100644
--- a/src/ast/ast_smt_pp.cpp
+++ b/src/ast/ast_smt_pp.cpp
@@ -399,12 +399,12 @@ class smt_printer {
pp_marked_expr(n->get_arg(0));
m_out << ") (_ bv1 1))";
}
- else if (m_manager.is_label(n, pos, names) && names.size() >= 1) {
+ else if (m_manager.is_label(n, pos, names) && !names.empty()) {
m_out << "(! ";
pp_marked_expr(n->get_arg(0));
m_out << (pos?":lblpos":":lblneg") << " " << m_renaming.get_symbol(names[0], false) << ")";
}
- else if (m_manager.is_label_lit(n, names) && names.size() >= 1) {
+ else if (m_manager.is_label_lit(n, names) && !names.empty()) {
m_out << "(! true :lblpos " << m_renaming.get_symbol(names[0], false) << ")";
}
else if (num_args == 0) {
@@ -952,7 +952,7 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) {
if (m_logic != symbol::null && m_logic != symbol("")) {
strm << "(set-logic " << m_logic << ")\n";
}
- if (m_attributes.size() > 0) {
+ if (!m_attributes.empty()) {
strm << "; " << m_attributes.c_str();
}
diff --git a/src/ast/bv_decl_plugin.cpp b/src/ast/bv_decl_plugin.cpp
index c4bada552..50f1fbfed 100644
--- a/src/ast/bv_decl_plugin.cpp
+++ b/src/ast/bv_decl_plugin.cpp
@@ -558,11 +558,15 @@ func_decl * bv_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p
case OP_ROTATE_LEFT:
if (arity != 1)
m_manager->raise_exception("rotate left expects one argument");
+ if (num_parameters != 1 || !parameters[0].is_int())
+ m_manager->raise_exception("rotate left expects one integer parameter");
return m_manager->mk_func_decl(m_rotate_left_sym, arity, domain, domain[0],
func_decl_info(m_family_id, k, num_parameters, parameters));
case OP_ROTATE_RIGHT:
if (arity != 1)
m_manager->raise_exception("rotate right expects one argument");
+ if (num_parameters != 1 || !parameters[0].is_int())
+ m_manager->raise_exception("rotate right expects one integer parameter");
return m_manager->mk_func_decl(m_rotate_right_sym, arity, domain, domain[0],
func_decl_info(m_family_id, k, num_parameters, parameters));
case OP_REPEAT:
diff --git a/src/ast/csp_decl_plugin.h b/src/ast/csp_decl_plugin.h
index 7c10bbfe9..486aa7f03 100644
--- a/src/ast/csp_decl_plugin.h
+++ b/src/ast/csp_decl_plugin.h
@@ -148,7 +148,7 @@ public:
bool is_resource(expr* e, unsigned& r);
bool is_makespan(expr* e, unsigned& r);
bool is_add_resource_available(expr * e, expr *& res, unsigned& loadpct, unsigned& cap_time, uint64_t& start, uint64_t& end, svector& properites);
- bool is_add_job_resource(expr * e, expr *& job, expr*& res, unsigned& loadpct, uint64_t& capacity, uint64_t& end, svector& properites);
+ bool is_add_job_resource(expr * e, expr *& job, expr*& res, unsigned& loadpct, uint64_t& capacity, uint64_t& finite_capacity_end, svector& properites);
bool is_set_preemptable(expr* e, expr *& job);
bool is_model(expr* e) const { return is_app_of(e, m_fid, OP_JS_MODEL); }
bool is_js_properties(expr* e, svector& properties);
diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp
index db3c0e2a0..8b57a33ae 100644
--- a/src/ast/datatype_decl_plugin.cpp
+++ b/src/ast/datatype_decl_plugin.cpp
@@ -143,7 +143,77 @@ namespace datatype {
}
return r;
}
- size* size::mk_power(size* a1, size* a2) { return alloc(power, a1, a2); }
+
+ size* size::mk_power(size* a1, size* a2) {
+ return alloc(power, a1, a2);
+ }
+
+
+ sort_size plus::eval(obj_map const& S) {
+ rational r(0);
+ ptr_vector todo;
+ todo.push_back(m_arg1);
+ todo.push_back(m_arg2);
+ while (!todo.empty()) {
+ size* s = todo.back();
+ todo.pop_back();
+ plus* p = dynamic_cast(s);
+ if (p) {
+ todo.push_back(p->m_arg1);
+ todo.push_back(p->m_arg2);
+ }
+ else {
+ sort_size sz = s->eval(S);
+ if (sz.is_infinite()) return sz;
+ if (sz.is_very_big()) return sz;
+ r += rational(sz.size(), rational::ui64());
+ }
+ }
+ return sort_size(r);
+ }
+
+ size* plus::subst(obj_map& S) {
+ return mk_plus(m_arg1->subst(S), m_arg2->subst(S));
+ }
+
+ sort_size times::eval(obj_map const& S) {
+ sort_size s1 = m_arg1->eval(S);
+ sort_size s2 = m_arg2->eval(S);
+ if (s1.is_infinite()) return s1;
+ if (s2.is_infinite()) return s2;
+ if (s1.is_very_big()) return s1;
+ if (s2.is_very_big()) return s2;
+ rational r = rational(s1.size(), rational::ui64()) * rational(s2.size(), rational::ui64());
+ return sort_size(r);
+ }
+
+ size* times::subst(obj_map& S) {
+ return mk_times(m_arg1->subst(S), m_arg2->subst(S));
+ }
+
+ sort_size power::eval(obj_map const& S) {
+ sort_size s1 = m_arg1->eval(S);
+ sort_size s2 = m_arg2->eval(S);
+ // s1^s2
+ if (s1.is_infinite()) return s1;
+ if (s2.is_infinite()) return s2;
+ if (s1.is_very_big()) return s1;
+ if (s2.is_very_big()) return s2;
+ if (s1.size() == 1) return s1;
+ if (s2.size() == 1) return s1;
+ if (s1.size() > (2 << 20) || s2.size() > 10) return sort_size::mk_very_big();
+ rational r = ::power(rational(s1.size(), rational::ui64()), static_cast(s2.size()));
+ return sort_size(r);
+ }
+
+ size* power::subst(obj_map& S) {
+ return mk_power(m_arg1->subst(S), m_arg2->subst(S));
+ }
+
+ size* sparam::subst(obj_map& S) {
+ return S[m_param];
+ }
+
}
namespace decl {
@@ -625,13 +695,14 @@ namespace datatype {
param_size::size* sz;
obj_map S;
unsigned n = get_datatype_num_parameter_sorts(s);
+ def & d = get_def(s->get_name());
+ SASSERT(n == d.params().size());
for (unsigned i = 0; i < n; ++i) {
sort* ps = get_datatype_parameter_sort(s, i);
sz = get_sort_size(params, ps);
- sz->inc_ref();
- S.insert(ps, sz);
- }
- def & d = get_def(s->get_name());
+ sz->inc_ref();
+ S.insert(d.params().get(i), sz);
+ }
sz = d.sort_size()->subst(S);
for (auto & kv : S) {
kv.m_value->dec_ref();
@@ -708,7 +779,7 @@ namespace datatype {
continue;
}
- ptr_vector s_add;
+ ptr_vector s_add;
for (constructor const* c : d) {
ptr_vector s_mul;
for (accessor const* a : *c) {
@@ -723,7 +794,7 @@ namespace datatype {
/**
\brief Return true if the inductive datatype is well-founded.
- Pre-condition: The given argument constains the parameters of an inductive datatype.
+ Pre-condition: The given argument constrains the parameters of an inductive datatype.
*/
bool util::is_well_founded(unsigned num_types, sort* const* sorts) {
buffer well_founded(num_types, false);
diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h
index 736cc0875..cf0b47784 100644
--- a/src/ast/datatype_decl_plugin.h
+++ b/src/ast/datatype_decl_plugin.h
@@ -132,71 +132,28 @@ namespace datatype {
size* m_arg1, *m_arg2;
plus(size* a1, size* a2): m_arg1(a1), m_arg2(a2) { a1->inc_ref(); a2->inc_ref();}
~plus() override { m_arg1->dec_ref(); m_arg2->dec_ref(); }
- size* subst(obj_map& S) override { return mk_plus(m_arg1->subst(S), m_arg2->subst(S)); }
- sort_size eval(obj_map const& S) override {
- rational r(0);
- ptr_vector todo;
- todo.push_back(m_arg1);
- todo.push_back(m_arg2);
- while (!todo.empty()) {
- size* s = todo.back();
- todo.pop_back();
- plus* p = dynamic_cast(s);
- if (p) {
- todo.push_back(p->m_arg1);
- todo.push_back(p->m_arg2);
- }
- else {
- sort_size sz = s->eval(S);
- if (sz.is_infinite()) return sz;
- if (sz.is_very_big()) return sz;
- r += rational(sz.size(), rational::ui64());
- }
- }
- return sort_size(r);
- }
+ size* subst(obj_map& S) override;
+ sort_size eval(obj_map const& S) override;
};
struct times : public size {
size* m_arg1, *m_arg2;
times(size* a1, size* a2): m_arg1(a1), m_arg2(a2) { a1->inc_ref(); a2->inc_ref(); }
~times() override { m_arg1->dec_ref(); m_arg2->dec_ref(); }
- size* subst(obj_map& S) override { return mk_times(m_arg1->subst(S), m_arg2->subst(S)); }
- sort_size eval(obj_map const& S) override {
- sort_size s1 = m_arg1->eval(S);
- sort_size s2 = m_arg2->eval(S);
- if (s1.is_infinite()) return s1;
- if (s2.is_infinite()) return s2;
- if (s1.is_very_big()) return s1;
- if (s2.is_very_big()) return s2;
- rational r = rational(s1.size(), rational::ui64()) * rational(s2.size(), rational::ui64());
- return sort_size(r);
- }
+ size* subst(obj_map& S) override;
+ sort_size eval(obj_map const& S) override;
};
struct power : public size {
size* m_arg1, *m_arg2;
power(size* a1, size* a2): m_arg1(a1), m_arg2(a2) { a1->inc_ref(); a2->inc_ref(); }
~power() override { m_arg1->dec_ref(); m_arg2->dec_ref(); }
- size* subst(obj_map& S) override { return mk_power(m_arg1->subst(S), m_arg2->subst(S)); }
- sort_size eval(obj_map const& S) override {
- sort_size s1 = m_arg1->eval(S);
- sort_size s2 = m_arg2->eval(S);
- // s1^s2
- if (s1.is_infinite()) return s1;
- if (s2.is_infinite()) return s2;
- if (s1.is_very_big()) return s1;
- if (s2.is_very_big()) return s2;
- if (s1.size() == 1) return s1;
- if (s2.size() == 1) return s1;
- if (s1.size() > (2 << 20) || s2.size() > 10) return sort_size::mk_very_big();
- rational r = ::power(rational(s1.size(), rational::ui64()), static_cast(s2.size()));
- return sort_size(r);
- }
+ size* subst(obj_map& S) override;
+ sort_size eval(obj_map const& S) override;
};
struct sparam : public size {
sort_ref m_param;
sparam(sort_ref& p): m_param(p) {}
~sparam() override {}
- size* subst(obj_map& S) override { return S[m_param]; }
+ size* subst(obj_map& S) override;
sort_size eval(obj_map const& S) override { return S[m_param]; }
};
};
diff --git a/src/ast/display_dimacs.cpp b/src/ast/display_dimacs.cpp
new file mode 100644
index 000000000..da39538d9
--- /dev/null
+++ b/src/ast/display_dimacs.cpp
@@ -0,0 +1,81 @@
+/*++
+Copyright (c) 2019 Microsoft Corporation
+
+Module Name:
+
+ display_dimacs.h
+
+Abstract:
+
+ Display expressions in DIMACS format.
+
+Author:
+
+ Nikolaj Bjorner (nbjorner0 2019-01-24
+
+Revision History:
+
+--*/
+
+#include "ast.h"
+#include "display_dimacs.h"
+
+std::ostream& display_dimacs(std::ostream& out, expr_ref_vector const& fmls) {
+ ast_manager& m = fmls.m();
+ unsigned_vector expr2var;
+ ptr_vector exprs;
+ unsigned num_vars = 0;
+ unsigned num_cls = fmls.size();
+ for (expr * f : fmls) {
+ unsigned num_lits;
+ expr * const * lits;
+ if (m.is_or(f)) {
+ num_lits = to_app(f)->get_num_args();
+ lits = to_app(f)->get_args();
+ }
+ else {
+ num_lits = 1;
+ lits = &f;
+ }
+ for (unsigned j = 0; j < num_lits; j++) {
+ expr * l = lits[j];
+ if (m.is_not(l))
+ l = to_app(l)->get_arg(0);
+ if (expr2var.get(l->get_id(), UINT_MAX) == UINT_MAX) {
+ num_vars++;
+ expr2var.setx(l->get_id(), num_vars, UINT_MAX);
+ exprs.setx(l->get_id(), l, nullptr);
+ }
+ }
+ }
+ out << "p cnf " << num_vars << " " << num_cls << "\n";
+ for (expr* f : fmls) {
+ unsigned num_lits;
+ expr * const * lits;
+ if (m.is_or(f)) {
+ num_lits = to_app(f)->get_num_args();
+ lits = to_app(f)->get_args();
+ }
+ else {
+ num_lits = 1;
+ lits = &f;
+ }
+ for (unsigned j = 0; j < num_lits; j++) {
+ expr * l = lits[j];
+ if (m.is_not(l)) {
+ out << "-";
+ l = to_app(l)->get_arg(0);
+ }
+ SASSERT(exprs[l->get_id()]);
+ out << expr2var[l->get_id()] << " ";
+ }
+ out << "0\n";
+ }
+ for (expr* e : exprs) {
+ if (e && is_app(e)) {
+ symbol const& n = to_app(e)->get_decl()->get_name();
+ out << "c " << expr2var[e->get_id()] << " " << n << "\n";
+ }
+ }
+ return out;
+}
diff --git a/src/ast/display_dimacs.h b/src/ast/display_dimacs.h
new file mode 100644
index 000000000..91c2386be
--- /dev/null
+++ b/src/ast/display_dimacs.h
@@ -0,0 +1,26 @@
+/*++
+Copyright (c) 2019 Microsoft Corporation
+
+Module Name:
+
+ display_dimacs.h
+
+Abstract:
+
+ Display expressions in DIMACS format.
+
+Author:
+
+ Nikolaj Bjorner (nbjorner0 2019-01-24
+
+Revision History:
+
+--*/
+#ifndef DISPLAY_DIMACS_H_
+#define DISPLAY_DIMACS_H_
+
+#include "ast.h"
+
+std::ostream& display_dimacs(std::ostream& out, expr_ref_vector const& fmls);
+
+#endif /* DISPLAY_DIMACS_H__ */
diff --git a/src/ast/dl_decl_plugin.cpp b/src/ast/dl_decl_plugin.cpp
index f4a538abd..01b06518e 100644
--- a/src/ast/dl_decl_plugin.cpp
+++ b/src/ast/dl_decl_plugin.cpp
@@ -147,7 +147,7 @@ namespace datalog {
for (unsigned i = 0; i < n; ++i) {
parameter const& p = r->get_parameter(i);
if (!p.is_ast() || !is_sort(p.get_ast())) {
- m_manager->raise_exception("exptected sort parameter");
+ m_manager->raise_exception("expected sort parameter");
return false;
}
sorts.push_back(to_sort(p.get_ast()));
@@ -185,7 +185,7 @@ namespace datalog {
verbose_stream() << "Domain: " << mk_pp(domain[0], m) << "\n" <<
mk_pp(sorts[i], m) << "\n" <<
mk_pp(domain[i+1], m) << "\n";);
- m_manager->raise_exception("sort miss-match for relational access");
+ m_manager->raise_exception("sort mismatch for relational access");
return nullptr;
}
}
@@ -252,7 +252,7 @@ namespace datalog {
func_decl * dl_decl_plugin::mk_unionw(decl_kind k, sort* s1, sort* s2) {
ast_manager& m = *m_manager;
if (s1 != s2) {
- m_manager->raise_exception("sort miss-match for arguments to union");
+ m_manager->raise_exception("sort mismatch for arguments to union");
return nullptr;
}
if (!is_rel_sort(s1)) {
@@ -298,7 +298,7 @@ namespace datalog {
return nullptr;
}
if (sorts[idx] != m.get_sort(e)) {
- m_manager->raise_exception("sort miss-match in filter");
+ m_manager->raise_exception("sort mismatch in filter");
return nullptr;
}
break;
@@ -391,7 +391,7 @@ namespace datalog {
return nullptr;
}
if (sorts1[i1] != sorts2[i2]) {
- m_manager->raise_exception("sort miss-match in join");
+ m_manager->raise_exception("sort mismatch in join");
return nullptr;
}
}
@@ -435,7 +435,7 @@ namespace datalog {
return nullptr;
}
if (sorts1[i1] != sorts2[i2]) {
- m_manager->raise_exception("sort miss-match in join");
+ m_manager->raise_exception("sort mismatch in join");
return nullptr;
}
}
diff --git a/src/ast/expr2polynomial.cpp b/src/ast/expr2polynomial.cpp
index 280d7487a..82bace428 100644
--- a/src/ast/expr2polynomial.cpp
+++ b/src/ast/expr2polynomial.cpp
@@ -436,7 +436,7 @@ struct expr2polynomial::imp {
margs.push_back(t);
}
}
- if (margs.size() == 0) {
+ if (margs.empty()) {
args.push_back(m_autil.mk_numeral(rational(1), is_int));
}
else if (margs.size() == 1) {
@@ -447,7 +447,7 @@ struct expr2polynomial::imp {
}
}
- if (args.size() == 0) {
+ if (args.empty()) {
r = m_autil.mk_numeral(rational(0), is_int);
}
else if (args.size() == 1) {
diff --git a/src/ast/expr2var.cpp b/src/ast/expr2var.cpp
index b1fdba2b5..61adcfc3a 100644
--- a/src/ast/expr2var.cpp
+++ b/src/ast/expr2var.cpp
@@ -29,8 +29,17 @@ void expr2var::insert(expr * n, var v) {
TRACE("expr2var", tout << "interpreted:\n" << mk_ismt2_pp(n, m()) << "\n";);
m_interpreted_vars = true;
}
- m().inc_ref(n);
- m_mapping.insert(n, v);
+ unsigned idx = m_id2map.get(n->get_id(), UINT_MAX);
+ if (idx == UINT_MAX) {
+ m().inc_ref(n);
+ idx = m_mapping.size();
+ m_mapping.push_back(key_value(n, v));
+ m_id2map.setx(n->get_id(), idx, UINT_MAX);
+ }
+ else {
+ m_mapping[idx] = key_value(n, v);
+ }
+
m_recent_exprs.push_back(n);
}
@@ -40,20 +49,22 @@ expr2var::expr2var(ast_manager & m):
}
expr2var::~expr2var() {
- dec_ref_map_keys(m(), m_mapping);
+ for (auto & kv : m_mapping) {
+ m().dec_ref(kv.m_key);
+ }
}
expr2var::var expr2var::to_var(expr * n) const {
- var v = UINT_MAX;
- m_mapping.find(n, v);
+ var v = m_id2map.get(n->get_id(), UINT_MAX);
+ if (v != UINT_MAX) {
+ v = m_mapping[v].m_value;
+ }
return v;
}
void expr2var::display(std::ostream & out) const {
- obj_map::iterator it = m_mapping.begin();
- obj_map::iterator end = m_mapping.end();
- for (; it != end; ++it) {
- out << mk_ismt2_pp(it->m_key, m()) << " -> " << it->m_value << "\n";
+ for (auto const& kv : m_mapping) {
+ out << mk_ismt2_pp(kv.m_key, m()) << " -> " << kv.m_value << "\n";
}
}
@@ -68,8 +79,11 @@ void expr2var::mk_inv(expr_ref_vector & var2expr) const {
}
void expr2var::reset() {
- dec_ref_map_keys(m(), m_mapping);
- SASSERT(m_mapping.empty());
+ for (auto & kv : m_mapping) {
+ m().dec_ref(kv.m_key);
+ }
+ m_mapping.reset();
+ m_id2map.reset();
m_recent_exprs.reset();
m_recent_lim.reset();
m_interpreted_vars = false;
@@ -83,8 +97,15 @@ void expr2var::pop(unsigned num_scopes) {
if (num_scopes > 0) {
unsigned sz = m_recent_lim[m_recent_lim.size() - num_scopes];
for (unsigned i = sz; i < m_recent_exprs.size(); ++i) {
- m_mapping.erase(m_recent_exprs[i]);
- m().dec_ref(m_recent_exprs[i]);
+ expr* n = m_recent_exprs[i];
+ unsigned idx = m_id2map[n->get_id()];
+ if (idx + 1 != m_mapping.size()) {
+ m_id2map[m_mapping.back().m_key->get_id()] = idx;
+ m_mapping[idx] = m_mapping.back();
+ }
+ m_id2map[n->get_id()] = UINT_MAX;
+ m_mapping.pop_back();
+ m().dec_ref(n);
}
m_recent_exprs.shrink(sz);
m_recent_lim.shrink(m_recent_lim.size() - num_scopes);
diff --git a/src/ast/expr2var.h b/src/ast/expr2var.h
index 2b4d8c3fe..2bf2fe160 100644
--- a/src/ast/expr2var.h
+++ b/src/ast/expr2var.h
@@ -32,12 +32,14 @@ Notes:
class expr2var {
public:
typedef unsigned var;
- typedef obj_map expr2var_mapping;
- typedef expr2var_mapping::iterator iterator;
+ typedef obj_map::key_data key_value;
+ typedef key_value const* iterator;
typedef ptr_vector::const_iterator recent_iterator;
protected:
ast_manager & m_manager;
- expr2var_mapping m_mapping;
+
+ unsigned_vector m_id2map;
+ svector m_mapping;
ptr_vector m_recent_exprs;
unsigned_vector m_recent_lim;
bool m_interpreted_vars;
@@ -51,7 +53,7 @@ public:
var to_var(expr * n) const;
- bool is_var(expr * n) const { return m_mapping.contains(n); }
+ bool is_var(expr * n) const { return m_id2map.get(n->get_id(), UINT_MAX) != UINT_MAX; }
void display(std::ostream & out) const;
diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp
index 1dc13ff9e..eef2452db 100644
--- a/src/ast/fpa/fpa2bv_converter.cpp
+++ b/src/ast/fpa/fpa2bv_converter.cpp
@@ -3300,11 +3300,11 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args
ll = m_bv_util.mk_sign_extend(3, m_bv_util.mk_concat(bv1, m_bv_util.mk_numeral(0, bv_sz-1)));
ul = m_bv_util.mk_zero_extend(4, m_bv_util.mk_bv_neg(m_bv_util.mk_numeral(1, bv_sz-1)));
ovfl = m.mk_or(ovfl, m_bv_util.mk_sle(pre_rounded, m_bv_util.mk_bv_neg(m_bv_util.mk_numeral(1, bv_sz + 3))));
+ pre_rounded = m.mk_ite(x_is_neg, m_bv_util.mk_bv_neg(pre_rounded), pre_rounded);
in_range = m.mk_and(m.mk_not(ovfl),
m_bv_util.mk_sle(ll, pre_rounded),
m_bv_util.mk_sle(pre_rounded, ul));
dbg_decouple("fpa2bv_to_bv_in_range_ll", ll);
- pre_rounded = m.mk_ite(x_is_neg, m_bv_util.mk_bv_neg(pre_rounded), pre_rounded);
}
dbg_decouple("fpa2bv_to_bv_in_range_ovfl", ovfl);
dbg_decouple("fpa2bv_to_bv_in_range_ul", ul);
diff --git a/src/ast/pattern/pattern_inference.cpp b/src/ast/pattern/pattern_inference.cpp
index cf3c8bc31..93b269f87 100644
--- a/src/ast/pattern/pattern_inference.cpp
+++ b/src/ast/pattern/pattern_inference.cpp
@@ -594,7 +594,6 @@ bool pattern_inference_cfg::reduce_quantifier(
unsigned new_weight;
if (m_database.match_quantifier(q, new_patterns, new_weight)) {
DEBUG_CODE(for (unsigned i = 0; i < new_patterns.size(); i++) { SASSERT(is_well_sorted(m, new_patterns.get(i))); });
- quantifier_ref new_q(m);
if (q->get_num_patterns() > 0) {
// just update the weight...
TRACE("pattern_inference", tout << "updating weight to: " << new_weight << "\n" << mk_pp(q, m) << "\n";);
@@ -604,10 +603,10 @@ bool pattern_inference_cfg::reduce_quantifier(
quantifier_ref tmp(m);
tmp = m.update_quantifier(q, new_patterns.size(), (expr**) new_patterns.c_ptr(), q->get_expr());
result = m.update_quantifier_weight(tmp, new_weight);
- TRACE("pattern_inference", tout << "found patterns in database, weight: " << new_weight << "\n" << mk_pp(new_q, m) << "\n";);
+ TRACE("pattern_inference", tout << "found patterns in database, weight: " << new_weight << "\n" << mk_pp(result, m) << "\n";);
}
if (m.proofs_enabled())
- result_pr = m.mk_rewrite(q, new_q);
+ result_pr = m.mk_rewrite(q, result);
return true;
}
}
diff --git a/src/ast/proofs/proof_utils.cpp b/src/ast/proofs/proof_utils.cpp
index 5483a9ea0..5c37c3794 100644
--- a/src/ast/proofs/proof_utils.cpp
+++ b/src/ast/proofs/proof_utils.cpp
@@ -238,7 +238,7 @@ class reduce_hypotheses {
{ args.push_back(fact); }
- if (args.size() == 0) { return pf; }
+ if (args.empty()) { return pf; }
else if (args.size() == 1) {
lemma = args.get(0);
} else {
diff --git a/src/ast/recfun_decl_plugin.cpp b/src/ast/recfun_decl_plugin.cpp
index 1ac44067f..ebdf86ca5 100644
--- a/src/ast/recfun_decl_plugin.cpp
+++ b/src/ast/recfun_decl_plugin.cpp
@@ -68,7 +68,7 @@ namespace recfun {
struct ite_find_p : public i_expr_pred {
ast_manager & m;
ite_find_p(ast_manager & m) : m(m) {}
- virtual bool operator()(expr * e) { return m.is_ite(e); }
+ bool operator()(expr * e) override { return m.is_ite(e); }
};
// ignore ites under quantifiers.
// this is redundant as the code
@@ -331,7 +331,7 @@ namespace recfun {
struct is_imm_pred : is_immediate_pred {
util & u;
is_imm_pred(util & u) : u(u) {}
- bool operator()(expr * rhs) {
+ bool operator()(expr * rhs) override {
// find an `app` that is an application of a defined function
struct find : public i_expr_pred {
util & u;
diff --git a/src/ast/recfun_decl_plugin.h b/src/ast/recfun_decl_plugin.h
index 0247335e8..b294cdfce 100644
--- a/src/ast/recfun_decl_plugin.h
+++ b/src/ast/recfun_decl_plugin.h
@@ -56,7 +56,7 @@ namespace recfun {
friend class def;
func_decl_ref m_pred; //& args) {
diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h
index cf7e7c951..a3bb3b6e1 100644
--- a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h
+++ b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h
@@ -75,9 +75,23 @@ bool bit_blaster_tpl::is_minus_one(unsigned sz, expr * const * bits) const
static void _num2bits(ast_manager & m, rational const & v, unsigned sz, expr_ref_vector & out_bits) {
SASSERT(v.is_nonneg());
rational aux = v;
- rational two(2);
+ rational two(2), base32(1ull << 32ull, rational::ui64());
for (unsigned i = 0; i < sz; i++) {
- if ((aux % two).is_zero())
+ if (i + 32 < sz) {
+ unsigned u = (aux % base32).get_unsigned();
+ for (unsigned j = 0; j < 32; ++j) {
+ if (0 != (u & (1 << j))) {
+ out_bits.push_back(m.mk_true());
+ }
+ else {
+ out_bits.push_back(m.mk_false());
+ }
+ }
+ aux = div(aux, base32);
+ i += 31;
+ continue;
+ }
+ else if ((aux % two).is_zero())
out_bits.push_back(m.mk_false());
else
out_bits.push_back(m.mk_true());
diff --git a/src/ast/rewriter/bv_bounds.cpp b/src/ast/rewriter/bv_bounds.cpp
index f30df7890..1658833a8 100644
--- a/src/ast/rewriter/bv_bounds.cpp
+++ b/src/ast/rewriter/bv_bounds.cpp
@@ -628,7 +628,7 @@ bool bv_bounds::is_sat_core(app * v) {
numeral new_hi = lower - one;
numeral ptr = lower;
if (has_neg_intervals) {
- SASSERT(negative_intervals != NULL);
+ SASSERT(negative_intervals != nullptr);
std::sort(negative_intervals->begin(), negative_intervals->end(), interval_comp);
intervals::const_iterator e = negative_intervals->end();
for (intervals::const_iterator i = negative_intervals->begin(); i != e; ++i) {
diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp
index 81226b010..f6b760f9c 100644
--- a/src/ast/rewriter/bv_rewriter.cpp
+++ b/src/ast/rewriter/bv_rewriter.cpp
@@ -196,6 +196,9 @@ br_status bv_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons
return mk_bv_comp(args[0], args[1], result);
case OP_MKBV:
return mk_mkbv(num_args, args, result);
+ case OP_BIT2BOOL:
+ SASSERT(num_args == 1);
+ return mk_bit2bool(args[0], f->get_parameter(0).get_int(), result);
case OP_BSMUL_NO_OVFL:
return mk_bvsmul_no_overflow(num_args, args, result);
case OP_BUMUL_NO_OVFL:
@@ -779,10 +782,11 @@ br_status bv_rewriter::mk_extract(unsigned high, unsigned low, expr * arg, expr_
}
}
- if (m().is_ite(arg)) {
- result = m().mk_ite(to_app(arg)->get_arg(0),
- m_mk_extract(high, low, to_app(arg)->get_arg(1)),
- m_mk_extract(high, low, to_app(arg)->get_arg(2)));
+ expr* c = nullptr, *t = nullptr, *e = nullptr;
+ if (m().is_ite(arg, c, t, e) &&
+ (t->get_ref_count() == 1 || !m().is_ite(t)) &&
+ (e->get_ref_count() == 1 || !m().is_ite(e))) {
+ result = m().mk_ite(c, m_mk_extract(high, low, t), m_mk_extract(high, low, e));
return BR_REWRITE2;
}
@@ -2202,6 +2206,19 @@ br_status bv_rewriter::mk_bv_mul(unsigned num_args, expr * const * args, expr_re
return st;
}
+br_status bv_rewriter::mk_bit2bool(expr * n, int idx, expr_ref & result) {
+ rational v, bit;
+ unsigned sz = 0;
+ if (!is_numeral(n, v, sz))
+ return BR_FAILED;
+ if (idx < 0 || idx >= static_cast(sz))
+ return BR_FAILED;
+ div(v, rational::power_of_two(idx), bit);
+ mod(bit, rational(2), bit);
+ result = m().mk_bool_val(bit.is_one());
+ return BR_DONE;
+}
+
br_status bv_rewriter::mk_bit2bool(expr * lhs, expr * rhs, expr_ref & result) {
unsigned sz = get_bv_size(lhs);
if (sz != 1)
diff --git a/src/ast/rewriter/bv_rewriter.h b/src/ast/rewriter/bv_rewriter.h
index 205ebbf8e..8ad589a49 100644
--- a/src/ast/rewriter/bv_rewriter.h
+++ b/src/ast/rewriter/bv_rewriter.h
@@ -134,6 +134,7 @@ class bv_rewriter : public poly_rewriter {
br_status mk_bv_redand(expr * arg, expr_ref & result);
br_status mk_bv_comp(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_bit2bool(expr * lhs, expr * rhs, expr_ref & result);
+ br_status mk_bit2bool(expr * lhs, int idx, expr_ref & result);
br_status mk_blast_eq_value(expr * lhs, expr * rhs, expr_ref & result);
br_status mk_eq_concat(expr * lhs, expr * rhs, expr_ref & result);
br_status mk_mkbv(unsigned num, expr * const * args, expr_ref & result);
diff --git a/src/ast/rewriter/bv_trailing.cpp b/src/ast/rewriter/bv_trailing.cpp
index 433ef6f66..f7c9e121e 100644
--- a/src/ast/rewriter/bv_trailing.cpp
+++ b/src/ast/rewriter/bv_trailing.cpp
@@ -364,7 +364,7 @@ struct bv_trailing::imp {
}
void reset_cache(const unsigned condition) {
- SASSERT(m_count_cache[0] == NULL);
+ SASSERT(m_count_cache[0] == nullptr);
for (unsigned i = 1; i <= TRAILING_DEPTH; ++i) {
if (m_count_cache[i] == nullptr) continue;
TRACE("bv-trailing", tout << "may reset cache " << i << " " << condition << "\n";);
diff --git a/src/ast/rewriter/der.cpp b/src/ast/rewriter/der.cpp
index 027846c31..c95c07f63 100644
--- a/src/ast/rewriter/der.cpp
+++ b/src/ast/rewriter/der.cpp
@@ -374,13 +374,11 @@ void der::apply_substitution(quantifier * q, expr_ref & r) {
expr_ref_buffer new_patterns(m_manager);
expr_ref_buffer new_no_patterns(m_manager);
for (unsigned j = 0; j < q->get_num_patterns(); j++) {
- expr_ref new_pat = m_subst(q->get_pattern(j), m_subst_map.size(), m_subst_map.c_ptr());
- new_patterns.push_back(new_pat);
+ new_patterns.push_back(m_subst(q->get_pattern(j), m_subst_map.size(), m_subst_map.c_ptr()));
}
for (unsigned j = 0; j < q->get_num_no_patterns(); j++) {
- expr_ref new_nopat = m_subst(q->get_no_pattern(j), m_subst_map.size(), m_subst_map.c_ptr());
- new_no_patterns.push_back(new_nopat);
+ new_no_patterns.push_back(m_subst(q->get_no_pattern(j), m_subst_map.size(), m_subst_map.c_ptr()));
}
r = m_manager.update_quantifier(q, new_patterns.size(), new_patterns.c_ptr(),
diff --git a/src/ast/rewriter/distribute_forall.cpp b/src/ast/rewriter/distribute_forall.cpp
index 54d7e2eca..c621579cb 100644
--- a/src/ast/rewriter/distribute_forall.cpp
+++ b/src/ast/rewriter/distribute_forall.cpp
@@ -126,8 +126,7 @@ void distribute_forall::reduce1_quantifier(quantifier * q) {
br.mk_not(arg, not_arg);
quantifier_ref tmp_q(m_manager);
tmp_q = m_manager.update_quantifier(q, not_arg);
- expr_ref new_q = elim_unused_vars(m_manager, tmp_q, params_ref());
- new_args.push_back(new_q);
+ new_args.push_back(elim_unused_vars(m_manager, tmp_q, params_ref()));
}
expr_ref result(m_manager);
// m_bsimp.mk_and actually constructs a (not (or ...)) formula,
diff --git a/src/ast/rewriter/hoist_rewriter.cpp b/src/ast/rewriter/hoist_rewriter.cpp
new file mode 100644
index 000000000..31909f12b
--- /dev/null
+++ b/src/ast/rewriter/hoist_rewriter.cpp
@@ -0,0 +1,201 @@
+/*++
+Copyright (c) 2019 Microsoft Corporation
+
+Module Name:
+
+ hoist_rewriter.cpp
+
+Abstract:
+
+ Hoist predicates over disjunctions
+
+Author:
+
+ Nikolaj Bjorner (nbjorner) 2019-2-4
+
+Notes:
+
+--*/
+
+
+#include "ast/rewriter/hoist_rewriter.h"
+#include "ast/ast_util.h"
+#include "ast/rewriter/expr_safe_replace.h"
+#include "ast/ast_pp.h"
+
+
+hoist_rewriter::hoist_rewriter(ast_manager & m, params_ref const & p):
+ m_manager(m), m_args1(m), m_args2(m) {
+ updt_params(p);
+}
+
+br_status hoist_rewriter::mk_or(unsigned num_args, expr * const * es, expr_ref & result) {
+ if (num_args < 2) {
+ return BR_FAILED;
+ }
+ for (unsigned i = 0; i < num_args; ++i) {
+ if (!is_and(es[i], nullptr)) {
+ return BR_FAILED;
+ }
+ }
+
+ bool turn = false;
+ m_preds1.reset();
+ m_preds2.reset();
+ m_uf1.reset();
+ m_uf2.reset();
+ m_expr2var.reset();
+ m_var2expr.reset();
+ basic_union_find* uf[2] = { &m_uf1, &m_uf2 };
+ obj_hashtable* preds[2] = { &m_preds1, &m_preds2 };
+ expr_ref_vector* args[2] = { &m_args1, &m_args2 };
+ VERIFY(is_and(es[0], args[turn]));
+ expr* e1, *e2;
+ for (expr* e : *(args[turn])) {
+ if (m().is_eq(e, e1, e2)) {
+ (*uf)[turn].merge(mk_var(e1), mk_var(e2));
+ }
+ else {
+ (*preds)[turn].insert(e);
+ }
+ }
+ unsigned round = 0;
+ for (unsigned j = 1; j < num_args; ++j) {
+ ++round;
+ m_es.reset();
+ m_mark.reset();
+
+ bool last = turn;
+ turn = !turn;
+ (*preds)[turn].reset();
+ reset(m_uf0);
+ VERIFY(is_and(es[j], args[turn]));
+
+ for (expr* e : *args[turn]) {
+ if (m().is_eq(e, e1, e2)) {
+ m_es.push_back(e1);
+ m_uf0.merge(mk_var(e1), mk_var(e2));
+ }
+ else if ((*preds)[last].contains(e)) {
+ (*preds)[turn].insert(e);
+ }
+ }
+
+ if ((*preds)[turn].empty() && m_es.empty()) {
+ return BR_FAILED;
+ }
+
+ m_eqs.reset();
+ for (expr* e : m_es) {
+ if (m_mark.is_marked(e)) {
+ continue;
+ }
+ unsigned u = mk_var(e);
+ unsigned v = u;
+ m_roots.reset();
+ do {
+ m_mark.mark(e);
+ unsigned r = (*uf)[last].find(v);
+ if (m_roots.find(r, e2)) {
+ m_eqs.push_back(std::make_pair(e, e2));
+ }
+ else {
+ m_roots.insert(r, e);
+ }
+ v = m_uf0.next(v);
+ e = mk_expr(v);
+ }
+ while (u != v);
+ }
+ reset((*uf)[turn]);
+ for (auto const& p : m_eqs) {
+ (*uf)[turn].merge(mk_var(p.first), mk_var(p.second));
+ }
+ if ((*preds)[turn].empty() && m_eqs.empty()) {
+ return BR_FAILED;
+ }
+ }
+ // p & eqs & (or fmls)
+ expr_ref_vector fmls(m()), ors(m());
+ expr_safe_replace subst(m());
+ for (expr * p : (*preds)[turn]) {
+ expr* q = nullptr;
+ if (m().is_not(p, q)) {
+ subst.insert(q, m().mk_false());
+ }
+ else {
+ subst.insert(p, m().mk_true());
+ }
+ fmls.push_back(p);
+ }
+ for (auto const& p : m_eqs) {
+ subst.insert(p.first, p.second);
+ fmls.push_back(m().mk_eq(p.first, p.second));
+ }
+
+ for (unsigned i = 0; i < num_args; ++i) {
+ expr_ref tmp(m());
+ subst(es[i], tmp);
+ ors.push_back(tmp);
+ }
+ fmls.push_back(m().mk_or(ors.size(), ors.c_ptr()));
+ result = m().mk_and(fmls.size(), fmls.c_ptr());
+ TRACE("hoist",
+ for (unsigned i = 0; i < num_args; ++i) {
+ tout << mk_pp(es[i], m()) << "\n";
+ }
+ tout << "=>\n";
+ tout << result << "\n";);
+ return BR_DONE;
+}
+
+unsigned hoist_rewriter::mk_var(expr* e) {
+ unsigned v = 0;
+ if (m_expr2var.find(e, v)) {
+ return v;
+ }
+ v = m_uf1.mk_var();
+ v = m_uf2.mk_var();
+ SASSERT(v == m_var2expr.size());
+ m_expr2var.insert(e, v);
+ m_var2expr.push_back(e);
+ return v;
+}
+
+br_status hoist_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
+ switch (f->get_decl_kind()) {
+ case OP_OR:
+ return mk_or(num_args, args, result);
+ default:
+ return BR_FAILED;
+ }
+}
+
+bool hoist_rewriter::is_and(expr * e, expr_ref_vector* args) {
+ if (m().is_and(e)) {
+ if (args) {
+ args->reset();
+ args->append(to_app(e)->get_num_args(), to_app(e)->get_args());
+ }
+ return true;
+ }
+ if (m().is_not(e, e) && m().is_or(e)) {
+ if (args) {
+ args->reset();
+ for (expr* arg : *to_app(e)) {
+ args->push_back(::mk_not(m(), arg));
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+
+void hoist_rewriter::reset(basic_union_find& uf) {
+ uf.reset();
+ for (expr* e : m_var2expr) {
+ (void)e;
+ uf.mk_var();
+ }
+}
diff --git a/src/ast/rewriter/hoist_rewriter.h b/src/ast/rewriter/hoist_rewriter.h
new file mode 100644
index 000000000..0f45a073c
--- /dev/null
+++ b/src/ast/rewriter/hoist_rewriter.h
@@ -0,0 +1,80 @@
+/*++
+Copyright (c) 2019 Microsoft Corporation
+
+Module Name:
+
+ hoist_rewriter.h
+
+Abstract:
+
+ Hoist predicates over disjunctions
+
+Author:
+
+ Nikolaj Bjorner (nbjorner) 2019-2-4
+
+Notes:
+
+--*/
+#ifndef HOIST_REWRITER_H_
+#define HOIST_REWRITER_H_
+
+#include "ast/ast.h"
+#include "ast/rewriter/rewriter.h"
+#include "util/params.h"
+#include "util/union_find.h"
+#include "util/obj_hashtable.h"
+
+class hoist_rewriter {
+ ast_manager & m_manager;
+ expr_ref_vector m_args1, m_args2;
+ obj_hashtable m_preds1, m_preds2;
+ basic_union_find m_uf1, m_uf2, m_uf0;
+ ptr_vector m_es;
+ svector> m_eqs;
+ u_map m_roots;
+ obj_map m_expr2var;
+ ptr_vector m_var2expr;
+ expr_mark m_mark;
+
+ br_status mk_or(unsigned num_args, expr * const * args, expr_ref & result);
+
+ bool is_and(expr* e, expr_ref_vector* args);
+
+ bool is_var(expr* e) { return m_expr2var.contains(e); }
+ expr* mk_expr(unsigned v) { return m_var2expr[v]; }
+ unsigned mk_var(expr* e);
+
+ void reset(basic_union_find& uf);
+
+public:
+ hoist_rewriter(ast_manager & m, params_ref const & p = params_ref());
+ ast_manager& m() const { return m_manager; }
+ family_id get_fid() const { return m().get_basic_family_id(); }
+ bool is_eq(expr * t) const { return m().is_eq(t); }
+ void updt_params(params_ref const & p) {}
+ static void get_param_descrs(param_descrs & r) {}
+ br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
+};
+
+struct hoist_rewriter_cfg : public default_rewriter_cfg {
+ hoist_rewriter m_r;
+ bool rewrite_patterns() const { return false; }
+ br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
+ result_pr = nullptr;
+ if (f->get_family_id() != m_r.get_fid())
+ return BR_FAILED;
+ return m_r.mk_app_core(f, num, args, result);
+ }
+ hoist_rewriter_cfg(ast_manager & m, params_ref const & p):m_r(m, p) {}
+};
+
+class hoist_rewriter_star : public rewriter_tpl {
+ hoist_rewriter_cfg m_cfg;
+public:
+ hoist_rewriter_star(ast_manager & m, params_ref const & p = params_ref()):
+ rewriter_tpl(m, false, m_cfg),
+ m_cfg(m, p) {}
+};
+
+#endif
diff --git a/src/ast/rewriter/pb_rewriter.cpp b/src/ast/rewriter/pb_rewriter.cpp
index cb42052b9..2e2c28edc 100644
--- a/src/ast/rewriter/pb_rewriter.cpp
+++ b/src/ast/rewriter/pb_rewriter.cpp
@@ -323,7 +323,7 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons
break;
}
}
- TRACE("pb",
+ TRACE("pb_verbose",
expr_ref tmp(m);
tmp = m.mk_app(f, num_args, args);
tout << tmp << "\n";
diff --git a/src/ast/rewriter/rewriter.cpp b/src/ast/rewriter/rewriter.cpp
index 80b690428..7e646871c 100644
--- a/src/ast/rewriter/rewriter.cpp
+++ b/src/ast/rewriter/rewriter.cpp
@@ -42,7 +42,7 @@ void rewriter_core::del_cache_stack() {
}
}
-void rewriter_core::cache_result(expr * k, expr * v) {
+void rewriter_core::cache_shifted_result(expr * k, unsigned offset, expr * v) {
#if 0
// trace for tracking cache usage
verbose_stream() << "1 " << k->get_id() << std::endl;
@@ -53,7 +53,7 @@ void rewriter_core::cache_result(expr * k, expr * v) {
SASSERT(m().get_sort(k) == m().get_sort(v));
- m_cache->insert(k, v);
+ m_cache->insert(k, offset, v);
#if 0
static unsigned num_cached = 0;
num_cached ++;
diff --git a/src/ast/rewriter/rewriter.h b/src/ast/rewriter/rewriter.h
index 4195e7de6..d380fa707 100644
--- a/src/ast/rewriter/rewriter.h
+++ b/src/ast/rewriter/rewriter.h
@@ -90,8 +90,10 @@ protected:
void init_cache_stack();
void del_cache_stack();
void reset_cache();
- void cache_result(expr * k, expr * v);
+ void cache_result(expr * k, expr * v) { cache_shifted_result(k, 0, v); }
+ void cache_shifted_result(expr * k, unsigned offset, expr * v);
expr * get_cached(expr * k) const { return m_cache->find(k); }
+ expr * get_cached(expr* k, unsigned offset) const { return m_cache->find(k, offset); }
void cache_result(expr * k, expr * v, proof * pr);
proof * get_cached_pr(expr * k) const { return static_cast(m_cache_pr->find(k)); }
diff --git a/src/ast/rewriter/rewriter_def.h b/src/ast/rewriter/rewriter_def.h
index 3ee1e4caf..0eeb1f52f 100644
--- a/src/ast/rewriter/rewriter_def.h
+++ b/src/ast/rewriter/rewriter_def.h
@@ -38,9 +38,10 @@ void rewriter_tpl::process_var(var * v) {
if (!ProofGen) {
// bindings are only used when Proof Generation is not enabled.
unsigned idx = v->get_idx();
+
if (idx < m_bindings.size()) {
unsigned index = m_bindings.size() - idx - 1;
- var * r = (var*)(m_bindings[index]);
+ expr * r = m_bindings[index];
if (r != nullptr) {
CTRACE("rewriter", v->get_sort() != m().get_sort(r),
tout << expr_ref(v, m()) << ":" << sort_ref(v->get_sort(), m()) << " != " << expr_ref(r, m()) << ":" << sort_ref(m().get_sort(r), m());
@@ -50,11 +51,18 @@ void rewriter_tpl::process_var(var * v) {
if (!is_ground(r) && m_shifts[index] != m_bindings.size()) {
unsigned shift_amount = m_bindings.size() - m_shifts[index];
+ expr* c = get_cached(r, shift_amount);
+ if (c) {
+ result_stack().push_back(c);
+ set_new_child_flag(v);
+ return;
+ }
expr_ref tmp(m());
m_shifter(r, shift_amount, tmp);
result_stack().push_back(tmp);
TRACE("rewriter", tout << "shift: " << shift_amount << " idx: " << idx << " --> " << tmp << "\n";
display_bindings(tout););
+ cache_shifted_result(r, shift_amount, tmp);
}
else {
result_stack().push_back(r);
@@ -380,7 +388,6 @@ void rewriter_tpl::process_app(app * t, frame & fr) {
TRACE("get_macro", display_bindings(tout););
begin_scope();
m_num_qvars += num_args;
- //m_num_qvars = 0;
m_root = def;
push_frame(def, false, RW_UNBOUNDED_DEPTH);
return;
@@ -480,7 +487,7 @@ void rewriter_tpl::process_quantifier(quantifier * q, frame & fr) {
m_root = q->get_expr();
unsigned sz = m_bindings.size();
for (unsigned i = 0; i < num_decls; i++) {
- m_bindings.push_back(0);
+ m_bindings.push_back(nullptr);
m_shifts.push_back(sz);
}
}
@@ -514,7 +521,12 @@ void rewriter_tpl::process_quantifier(quantifier * q, frame & fr) {
}
if (ProofGen) {
quantifier_ref new_q(m().update_quantifier(q, num_pats, new_pats.c_ptr(), num_no_pats, new_no_pats.c_ptr(), new_body), m());
- m_pr = q == new_q ? nullptr : m().mk_quant_intro(q, new_q, result_pr_stack().get(fr.m_spos));
+ m_pr = nullptr;
+ if (q != new_q) {
+ m_pr = result_pr_stack().get(fr.m_spos);
+ m_pr = m().mk_bind_proof(q, m_pr);
+ m_pr = m().mk_quant_intro(q, new_q, m_pr);
+ }
m_r = new_q;
proof_ref pr2(m());
if (m_cfg.reduce_quantifier(new_q, new_body, new_pats.c_ptr(), new_no_pats.c_ptr(), m_r, pr2)) {
diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp
index b67163f7c..cb915d86b 100644
--- a/src/ast/rewriter/seq_rewriter.cpp
+++ b/src/ast/rewriter/seq_rewriter.cpp
@@ -33,30 +33,32 @@ Notes:
expr_ref sym_expr::accept(expr* e) {
ast_manager& m = m_t.get_manager();
expr_ref result(m);
+ var_subst subst(m);
+ seq_util u(m);
+ unsigned r1, r2, r3;
switch (m_ty) {
- case t_pred: {
- var_subst subst(m);
+ case t_pred:
result = subst(m_t, 1, &e);
+ break;
+ case t_not:
+ result = m_expr->accept(e);
+ result = m.mk_not(result);
break;
- }
case t_char:
SASSERT(m.get_sort(e) == m.get_sort(m_t));
SASSERT(m.get_sort(e) == m_sort);
result = m.mk_eq(e, m_t);
break;
- case t_range: {
- bv_util bv(m);
- rational r1, r2, r3;
- unsigned sz;
- if (bv.is_numeral(m_t, r1, sz) && bv.is_numeral(e, r2, sz) && bv.is_numeral(m_s, r3, sz)) {
+ case t_range:
+ if (u.is_const_char(m_t, r1) && u.is_const_char(e, r2) && u.is_const_char(m_s, r3)) {
result = m.mk_bool_val((r1 <= r2) && (r2 <= r3));
}
else {
- result = m.mk_and(bv.mk_ule(m_t, e), bv.mk_ule(e, m_s));
+ result = m.mk_and(u.mk_le(m_t, e), u.mk_le(e, m_s));
}
break;
}
- }
+
return result;
}
@@ -65,6 +67,7 @@ std::ostream& sym_expr::display(std::ostream& out) const {
case t_char: return out << m_t;
case t_range: return out << m_t << ":" << m_s;
case t_pred: return out << m_t;
+ case t_not: return m_expr->display(out << "not ");
}
return out << "expression type not recognized";
}
@@ -80,10 +83,11 @@ struct display_expr1 {
class sym_expr_boolean_algebra : public boolean_algebra {
ast_manager& m;
expr_solver& m_solver;
+ expr_ref m_var;
typedef sym_expr* T;
public:
sym_expr_boolean_algebra(ast_manager& m, expr_solver& s):
- m(m), m_solver(s) {}
+ m(m), m_solver(s), m_var(m) {}
T mk_false() override {
expr_ref fml(m.mk_false(), m);
@@ -94,6 +98,7 @@ public:
return sym_expr::mk_pred(fml, m.mk_bool_sort());
}
T mk_and(T x, T y) override {
+ seq_util u(m);
if (x->is_char() && y->is_char()) {
if (x->get_char() == y->get_char()) {
return x;
@@ -103,6 +108,21 @@ public:
return sym_expr::mk_pred(fml, x->get_sort());
}
}
+ unsigned lo1, hi1, lo2, hi2;
+ if (x->is_range() && y->is_range() &&
+ u.is_const_char(x->get_lo(), lo1) && u.is_const_char(x->get_hi(), hi1) &&
+ u.is_const_char(y->get_lo(), lo2) && u.is_const_char(y->get_hi(), hi2)) {
+ lo1 = std::max(lo1, lo2);
+ hi1 = std::min(hi1, hi2);
+ if (lo1 > hi1) {
+ expr_ref fml(m.mk_false(), m);
+ return sym_expr::mk_pred(fml, x->get_sort());
+ }
+ expr_ref _start(u.mk_char(lo1), m);
+ expr_ref _stop(u.mk_char(hi1), m);
+ return sym_expr::mk_range(_start, _stop);
+ }
+
sort* s = x->get_sort();
if (m.is_bool(s)) s = y->get_sort();
var_ref v(m.mk_var(0, s), m);
@@ -111,13 +131,29 @@ public:
if (m.is_true(fml1)) {
return y;
}
- if (m.is_true(fml2)) return x;
- if (fml1 == fml2) return x;
+ if (m.is_true(fml2)) {
+ return x;
+ }
+ if (fml1 == fml2) {
+ return x;
+ }
+ if (is_complement(fml1, fml2)) {
+ expr_ref ff(m.mk_false(), m);
+ return sym_expr::mk_pred(ff, x->get_sort());
+ }
bool_rewriter br(m);
expr_ref fml(m);
br.mk_and(fml1, fml2, fml);
return sym_expr::mk_pred(fml, x->get_sort());
}
+
+ bool is_complement(expr* f1, expr* f2) {
+ expr* f = nullptr;
+ return
+ (m.is_not(f1, f) && f == f2) ||
+ (m.is_not(f2, f) && f == f1);
+ }
+
T mk_or(T x, T y) override {
if (x->is_char() && y->is_char() &&
x->get_char() == y->get_char()) {
@@ -148,6 +184,7 @@ public:
}
}
}
+
T mk_or(unsigned sz, T const* ts) override {
switch (sz) {
case 0: return mk_false();
@@ -161,15 +198,24 @@ public:
}
}
}
+
lbool is_sat(T x) override {
+ unsigned lo, hi;
+ seq_util u(m);
+
if (x->is_char()) {
return l_true;
}
- if (x->is_range()) {
- // TBD check lower is below upper.
+ if (x->is_range() && u.is_const_char(x->get_lo(), lo) && u.is_const_char(x->get_hi(), hi)) {
+ return (lo <= hi) ? l_true : l_false;
}
- expr_ref v(m.mk_fresh_const("x", x->get_sort()), m);
- expr_ref fml = x->accept(v);
+ if (x->is_not() && x->get_arg()->is_range() && u.is_const_char(x->get_arg()->get_lo(), lo) && 0 < lo) {
+ return l_true;
+ }
+ if (!m_var || m.get_sort(m_var) != x->get_sort()) {
+ m_var = m.mk_fresh_const("x", x->get_sort());
+ }
+ expr_ref fml = x->accept(m_var);
if (m.is_true(fml)) {
return l_true;
}
@@ -178,19 +224,14 @@ public:
}
return m_solver.check_sat(fml);
}
+
T mk_not(T x) override {
- var_ref v(m.mk_var(0, x->get_sort()), m);
- expr_ref fml(m.mk_not(x->accept(v)), m);
- return sym_expr::mk_pred(fml, x->get_sort());
+ return sym_expr::mk_not(m, x);
}
- /*virtual vector, T>> generate_min_terms(vector constraints){
-
- return 0;
- }*/
};
-re2automaton::re2automaton(ast_manager& m): m(m), u(m), bv(m), m_ba(nullptr), m_sa(nullptr) {}
+re2automaton::re2automaton(ast_manager& m): m(m), u(m), m_ba(nullptr), m_sa(nullptr) {}
re2automaton::~re2automaton() {}
@@ -248,9 +289,8 @@ eautomaton* re2automaton::re2aut(expr* e) {
s1.length() == 1 && s2.length() == 1) {
unsigned start = s1[0];
unsigned stop = s2[0];
- unsigned nb = s1.num_bits();
- expr_ref _start(bv.mk_numeral(start, nb), m);
- expr_ref _stop(bv.mk_numeral(stop, nb), m);
+ expr_ref _start(u.mk_char(start), m);
+ expr_ref _stop(u.mk_char(stop), m);
TRACE("seq", tout << "Range: " << start << " " << stop << "\n";);
a = alloc(eautomaton, sm, sym_expr::mk_range(_start, _stop));
return a.detach();
@@ -309,6 +349,9 @@ eautomaton* re2automaton::re2aut(expr* e) {
else if (u.re.is_intersection(e, e1, e2) && m_sa && (a = re2aut(e1)) && (b = re2aut(e2))) {
return m_sa->mk_product(*a, *b);
}
+ else {
+ TRACE("seq", tout << "not handled " << mk_pp(e, m) << "\n";);
+ }
return nullptr;
}
@@ -343,9 +386,9 @@ eautomaton* re2automaton::seq2aut(expr* e) {
br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(f->get_family_id() == get_fid());
-
+ br_status st = BR_FAILED;
switch(f->get_decl_kind()) {
-
+
case OP_SEQ_UNIT:
SASSERT(num_args == 1);
return mk_seq_unit(args[0], result);
@@ -356,16 +399,19 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
return mk_re_plus(args[0], result);
case OP_RE_STAR:
SASSERT(num_args == 1);
- return mk_re_star(args[0], result);
+ st = mk_re_star(args[0], result);
+ break;
case OP_RE_OPTION:
SASSERT(num_args == 1);
return mk_re_opt(args[0], result);
case OP_RE_CONCAT:
if (num_args == 1) {
- result = args[0]; return BR_DONE;
+ result = args[0];
+ return BR_DONE;
}
SASSERT(num_args == 2);
- return mk_re_concat(args[0], args[1], result);
+ st = mk_re_concat(args[0], args[1], result);
+ break;
case OP_RE_UNION:
if (num_args == 1) {
result = args[0]; return BR_DONE;
@@ -405,13 +451,19 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
return mk_seq_length(args[0], result);
case OP_SEQ_EXTRACT:
SASSERT(num_args == 3);
- return mk_seq_extract(args[0], args[1], args[2], result);
+ st = mk_seq_extract(args[0], args[1], args[2], result);
+ break;
case OP_SEQ_CONTAINS:
SASSERT(num_args == 2);
return mk_seq_contains(args[0], args[1], result);
case OP_SEQ_AT:
SASSERT(num_args == 2);
return mk_seq_at(args[0], args[1], result);
+#if 0
+ case OP_SEQ_NTH:
+ SASSERT(num_args == 2);
+ return mk_seq_nth(args[0], args[1], result);
+#endif
case OP_SEQ_PREFIX:
SASSERT(num_args == 2);
return mk_seq_prefix(args[0], args[1], result);
@@ -456,21 +508,20 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
case _OP_STRING_STRIDOF:
UNREACHABLE();
}
- return BR_FAILED;
+ CTRACE("seq", st != BR_FAILED, tout << result << "\n";);
+ return st;
}
/*
* (seq.unit (_ BitVector 8)) ==> String constant
*/
br_status seq_rewriter::mk_seq_unit(expr* e, expr_ref& result) {
- bv_util bvu(m());
- rational n_val;
- unsigned int n_size;
+ unsigned ch;
// specifically we want (_ BitVector 8)
- if (bvu.is_bv(e) && bvu.is_numeral(e, n_val, n_size) && n_size == 8) {
+ if (m_util.is_const_char(e, ch)) {
// convert to string constant
- zstring str(n_val.get_unsigned());
- TRACE("seq_verbose", tout << "rewrite seq.unit of 8-bit value " << n_val.to_string() << " to string constant \"" << str<< "\"" << std::endl;);
+ zstring str(ch);
+ TRACE("seq_verbose", tout << "rewrite seq.unit of 8-bit value " << ch << " to string constant \"" << str<< "\"" << std::endl;);
result = m_util.str.mk_string(str);
return BR_DONE;
}
@@ -566,6 +617,7 @@ br_status seq_rewriter::mk_seq_extract(expr* a, expr* b, expr* c, expr_ref& resu
bool constantPos = m_autil.is_numeral(b, pos);
bool constantLen = m_autil.is_numeral(c, len);
+
// case 1: pos<0 or len<=0
// rewrite to ""
if ( (constantPos && pos.is_neg()) || (constantLen && !len.is_pos()) ) {
@@ -574,7 +626,7 @@ br_status seq_rewriter::mk_seq_extract(expr* a, expr* b, expr* c, expr_ref& resu
}
// case 1.1: pos >= length(base)
// rewrite to ""
- if (constantBase && constantPos && pos >= rational(s.length())) {
+ if (constantPos && constantBase && pos >= rational(s.length())) {
result = m_util.str.mk_empty(m().get_sort(a));
return BR_DONE;
}
@@ -582,52 +634,73 @@ br_status seq_rewriter::mk_seq_extract(expr* a, expr* b, expr* c, expr_ref& resu
constantPos &= pos.is_unsigned();
constantLen &= len.is_unsigned();
- if (constantBase && constantPos && constantLen) {
- if (pos.get_unsigned() + len.get_unsigned() >= s.length()) {
- // case 2: pos+len goes past the end of the string
- unsigned _len = s.length() - pos.get_unsigned() + 1;
- result = m_util.str.mk_string(s.extract(pos.get_unsigned(), _len));
- } else {
- // case 3: pos+len still within string
- result = m_util.str.mk_string(s.extract(pos.get_unsigned(), len.get_unsigned()));
- }
- return BR_DONE;
- }
-
- if (constantPos && constantLen) {
+ if (constantPos && constantLen && constantBase) {
unsigned _pos = pos.get_unsigned();
unsigned _len = len.get_unsigned();
- SASSERT(_len > 0);
- expr_ref_vector as(m()), bs(m());
- m_util.str.get_concat(a, as);
- if (as.empty()) {
- result = a;
- return BR_DONE;
- }
- for (unsigned i = 0; i < as.size() && _len > 0; ++i) {
- if (m_util.str.is_unit(as[i].get())) {
- if (_pos == 0) {
- bs.push_back(as[i].get());
- --_len;
- }
- else {
- --_pos;
- }
- }
- else {
- return BR_FAILED;
- }
- }
- if (bs.empty()) {
- result = m_util.str.mk_empty(m().get_sort(a));
- }
- else {
- result = m_util.str.mk_concat(bs);
+ if (_pos + _len >= s.length()) {
+ // case 2: pos+len goes past the end of the string
+ unsigned _len = s.length() - _pos + 1;
+ result = m_util.str.mk_string(s.extract(_pos, _len));
+ } else {
+ // case 3: pos+len still within string
+ result = m_util.str.mk_string(s.extract(_pos, _len));
}
return BR_DONE;
}
- return BR_FAILED;
+
+ expr_ref_vector as(m()), bs(m());
+ m_util.str.get_concat_units(a, as);
+ if (as.empty()) {
+ result = m_util.str.mk_empty(m().get_sort(a));
+ return BR_DONE;
+ }
+
+ if (!constantPos) {
+ return BR_FAILED;
+ }
+ unsigned _pos = pos.get_unsigned();
+
+ // (extract s 0 (len s)) = s
+ expr* a2 = nullptr;
+ if (_pos == 0 && m_util.str.is_length(c, a2) && a == a2) {
+ result = a;
+ return BR_DONE;
+ }
+
+ unsigned offset = 0;
+ for (; offset < as.size() && m_util.str.is_unit(as.get(offset)) && offset < _pos; ++offset) {};
+ if (offset == 0 && _pos > 0) {
+ return BR_FAILED;
+ }
+ if (_pos == 0 && !constantLen) {
+ return BR_FAILED;
+ }
+ // (extract (++ (unit x) (unit y)) 3 c) = empty
+ if (offset == as.size()) {
+ result = m_util.str.mk_empty(m().get_sort(a));
+ return BR_DONE;
+ }
+ SASSERT(offset != 0 || _pos == 0);
+
+ if (constantLen && _pos == offset) {
+ unsigned _len = len.get_unsigned();
+ // (extract (++ (unit a) (unit b) (unit c) x) 1 2) = (++ (unit b) (unit c))
+ unsigned i = offset;
+ for (; i < as.size() && m_util.str.is_unit(as.get(i)) && i - offset < _len; ++i);
+ if (i - offset == _len) {
+ result = m_util.str.mk_concat(_len, as.c_ptr() + offset);
+ return BR_DONE;
+ }
+ }
+ if (offset == 0) {
+ return BR_FAILED;
+ }
+ expr_ref pos1(m());
+ pos1 = m_autil.mk_sub(b, m_autil.mk_int(offset));
+ result = m_util.str.mk_concat(as.size() - offset, as.c_ptr() + offset);
+ result = m_util.str.mk_substr(result, pos1, c);
+ return BR_REWRITE3;
}
bool seq_rewriter::cannot_contain_suffix(expr* a, expr* b) {
@@ -809,6 +882,32 @@ br_status seq_rewriter::mk_seq_at(expr* a, expr* b, expr_ref& result) {
return BR_DONE;
}
+br_status seq_rewriter::mk_seq_nth(expr* a, expr* b, expr_ref& result) {
+ zstring c;
+ rational r;
+ if (!m_autil.is_numeral(b, r) || !r.is_unsigned()) {
+ return BR_FAILED;
+ }
+ unsigned len = r.get_unsigned();
+
+ expr_ref_vector as(m());
+ m_util.str.get_concat_units(a, as);
+
+ for (unsigned i = 0; i < as.size(); ++i) {
+ expr* a = as.get(i), *u = nullptr;
+ if (m_util.str.is_unit(a, u)) {
+ if (len == i) {
+ result = u;
+ return BR_DONE;
+ }
+ }
+ else {
+ return BR_FAILED;
+ }
+ }
+ return BR_FAILED;
+}
+
br_status seq_rewriter::mk_seq_index(expr* a, expr* b, expr* c, expr_ref& result) {
zstring s1, s2;
rational r;
@@ -1238,6 +1337,7 @@ br_status seq_rewriter::mk_str_in_regexp(expr* a, expr* b, expr_ref& result) {
scoped_ptr aut;
expr_ref_vector seq(m());
if (!(aut = m_re2aut(b))) {
+ TRACE("seq", tout << "not translated to automaton " << mk_pp(b, m()) << "\n";);
return BR_FAILED;
}
@@ -1254,6 +1354,7 @@ br_status seq_rewriter::mk_str_in_regexp(expr* a, expr* b, expr_ref& result) {
}
if (!is_sequence(a, seq)) {
+ TRACE("seq", tout << "not a sequence " << mk_pp(a, m()) << "\n";);
return BR_FAILED;
}
@@ -1305,17 +1406,16 @@ br_status seq_rewriter::mk_str_in_regexp(expr* a, expr* b, expr_ref& result) {
}
}
u_map const& frontier = maps[select_map];
- u_map::iterator it = frontier.begin(), end = frontier.end();
expr_ref_vector ors(m());
- for (; it != end; ++it) {
+ for (auto const& kv : frontier) {
unsigned_vector states;
bool has_final = false;
- aut->get_epsilon_closure(it->m_key, states);
+ aut->get_epsilon_closure(kv.m_key, states);
for (unsigned i = 0; i < states.size() && !has_final; ++i) {
has_final = aut->is_final_state(states[i]);
}
if (has_final) {
- ors.push_back(it->m_value);
+ ors.push_back(kv.m_value);
}
}
result = mk_or(ors);
@@ -1434,6 +1534,14 @@ br_status seq_rewriter::mk_re_inter(expr* a, expr* b, expr_ref& result) {
result = a;
return BR_DONE;
}
+ expr* ac = nullptr, *bc = nullptr;
+ if ((m_util.re.is_complement(a, ac) && ac == b) ||
+ (m_util.re.is_complement(b, bc) && bc == a)) {
+ sort* seq_sort = nullptr;
+ VERIFY(m_util.is_re(a, seq_sort));
+ result = m_util.re.mk_empty(seq_sort);
+ return BR_DONE;
+ }
return BR_FAILED;
}
@@ -1977,15 +2085,13 @@ bool seq_rewriter::min_length(unsigned n, expr* const* es, unsigned& len) {
bool seq_rewriter::is_string(unsigned n, expr* const* es, zstring& s) const {
zstring s1;
expr* e;
- bv_util bv(m());
- rational val;
- unsigned sz;
+ unsigned ch;
for (unsigned i = 0; i < n; ++i) {
if (m_util.str.is_string(es[i], s1)) {
s = s + s1;
}
- else if (m_util.str.is_unit(es[i], e) && bv.is_numeral(e, val, sz)) {
- s = s + zstring(val.get_unsigned());
+ else if (m_util.str.is_unit(es[i], e) && m_util.is_const_char(e, ch)) {
+ s = s + zstring(ch);
}
else {
return false;
diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h
index f5878b2c2..25b8979fc 100644
--- a/src/ast/rewriter/seq_rewriter.h
+++ b/src/ast/rewriter/seq_rewriter.h
@@ -31,31 +31,38 @@ class sym_expr {
enum ty {
t_char,
t_pred,
+ t_not,
t_range
};
- ty m_ty;
- sort* m_sort;
- expr_ref m_t;
- expr_ref m_s;
- unsigned m_ref;
- sym_expr(ty ty, expr_ref& t, expr_ref& s, sort* srt) : m_ty(ty), m_sort(srt), m_t(t), m_s(s), m_ref(0) {}
+ ty m_ty;
+ sort* m_sort;
+ sym_expr* m_expr;
+ expr_ref m_t;
+ expr_ref m_s;
+ unsigned m_ref;
+ sym_expr(ty ty, expr_ref& t, expr_ref& s, sort* srt, sym_expr* e) :
+ m_ty(ty), m_sort(srt), m_expr(e), m_t(t), m_s(s), m_ref(0) {}
public:
+ ~sym_expr() { if (m_expr) m_expr->dec_ref(); }
expr_ref accept(expr* e);
- static sym_expr* mk_char(expr_ref& t) { return alloc(sym_expr, t_char, t, t, t.get_manager().get_sort(t)); }
+ static sym_expr* mk_char(expr_ref& t) { return alloc(sym_expr, t_char, t, t, t.get_manager().get_sort(t), nullptr); }
static sym_expr* mk_char(ast_manager& m, expr* t) { expr_ref tr(t, m); return mk_char(tr); }
- static sym_expr* mk_pred(expr_ref& t, sort* s) { return alloc(sym_expr, t_pred, t, t, s); }
- static sym_expr* mk_range(expr_ref& lo, expr_ref& hi) { return alloc(sym_expr, t_range, lo, hi, lo.get_manager().get_sort(hi)); }
+ static sym_expr* mk_pred(expr_ref& t, sort* s) { return alloc(sym_expr, t_pred, t, t, s, nullptr); }
+ static sym_expr* mk_range(expr_ref& lo, expr_ref& hi) { return alloc(sym_expr, t_range, lo, hi, lo.get_manager().get_sort(hi), nullptr); }
+ static sym_expr* mk_not(ast_manager& m, sym_expr* e) { expr_ref f(m); e->inc_ref(); return alloc(sym_expr, t_not, f, f, e->get_sort(), e); }
void inc_ref() { ++m_ref; }
void dec_ref() { --m_ref; if (m_ref == 0) dealloc(this); }
std::ostream& display(std::ostream& out) const;
bool is_char() const { return m_ty == t_char; }
bool is_pred() const { return !is_char(); }
bool is_range() const { return m_ty == t_range; }
+ bool is_not() const { return m_ty == t_not; }
sort* get_sort() const { return m_sort; }
expr* get_char() const { SASSERT(is_char()); return m_t; }
expr* get_pred() const { SASSERT(is_pred()); return m_t; }
expr* get_lo() const { SASSERT(is_range()); return m_t; }
expr* get_hi() const { SASSERT(is_range()); return m_s; }
+ sym_expr* get_arg() const { SASSERT(is_not()); return m_expr; }
};
class sym_expr_manager {
@@ -77,7 +84,6 @@ class re2automaton {
ast_manager& m;
sym_expr_manager sm;
seq_util u;
- bv_util bv;
scoped_ptr m_solver;
scoped_ptr m_ba;
scoped_ptr m_sa;
@@ -108,6 +114,7 @@ class seq_rewriter {
br_status mk_seq_extract(expr* a, expr* b, expr* c, expr_ref& result);
br_status mk_seq_contains(expr* a, expr* b, expr_ref& result);
br_status mk_seq_at(expr* a, expr* b, expr_ref& result);
+ br_status mk_seq_nth(expr* a, expr* b, expr_ref& result);
br_status mk_seq_index(expr* a, expr* b, expr* c, expr_ref& result);
br_status mk_seq_replace(expr* a, expr* b, expr* c, expr_ref& result);
br_status mk_seq_prefix(expr* a, expr* b, expr_ref& result);
diff --git a/src/ast/rewriter/var_subst.cpp b/src/ast/rewriter/var_subst.cpp
index cbd79e08c..ff479b565 100644
--- a/src/ast/rewriter/var_subst.cpp
+++ b/src/ast/rewriter/var_subst.cpp
@@ -135,17 +135,14 @@ expr_ref unused_vars_eliminator::operator()(quantifier* q) {
return result;
}
- expr_ref tmp(m);
expr_ref_buffer new_patterns(m);
expr_ref_buffer new_no_patterns(m);
for (unsigned i = 0; i < num_patterns; i++) {
- tmp = m_subst(q->get_pattern(i), var_mapping.size(), var_mapping.c_ptr());
- new_patterns.push_back(tmp);
+ new_patterns.push_back(m_subst(q->get_pattern(i), var_mapping.size(), var_mapping.c_ptr()));
}
for (unsigned i = 0; i < num_no_patterns; i++) {
- tmp = m_subst(q->get_no_pattern(i), var_mapping.size(), var_mapping.c_ptr());
- new_no_patterns.push_back(tmp);
+ new_no_patterns.push_back(m_subst(q->get_no_pattern(i), var_mapping.size(), var_mapping.c_ptr()));
}
result = m.mk_quantifier(q->get_kind(),
diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp
index 8fc130ef1..20e1fb36c 100644
--- a/src/ast/seq_decl_plugin.cpp
+++ b/src/ast/seq_decl_plugin.cpp
@@ -20,6 +20,7 @@ Revision History:
#include "ast/arith_decl_plugin.h"
#include "ast/array_decl_plugin.h"
#include "ast/ast_pp.h"
+#include "ast/bv_decl_plugin.h"
#include
static bool is_hex_digit(char ch, unsigned& d) {
@@ -68,14 +69,14 @@ static bool is_escape_char(char const *& s, unsigned& result) {
}
/* 2 octal digits */
if (is_octal_digit(*(s + 1), d1) && is_octal_digit(*(s + 2), d2) &&
- !is_octal_digit(*(s + 3), d3)) {
+ !is_octal_digit(*(s + 3), d3)) {
result = d1 * 8 + d2;
s += 3;
return true;
}
/* 3 octal digits */
if (is_octal_digit(*(s + 1), d1) && is_octal_digit(*(s + 2), d2) &&
- is_octal_digit(*(s + 3), d3)) {
+ is_octal_digit(*(s + 3), d3)) {
result = d1*64 + d2*8 + d3;
s += 4;
return true;
@@ -295,13 +296,10 @@ bool zstring::operator==(const zstring& other) const {
return false;
}
for (unsigned i = 0; i < length(); ++i) {
- unsigned Xi = m_buffer[i];
- unsigned Yi = other[i];
- if (Xi != Yi) {
+ if (m_buffer[i] != other[i]) {
return false;
}
}
-
return true;
}
@@ -324,19 +322,14 @@ bool operator<(const zstring& lhs, const zstring& rhs) {
unsigned Ri = rhs[i];
if (Li < Ri) {
return true;
- } else if (Li > Ri) {
+ }
+ else if (Li > Ri) {
return false;
- } else {
- continue;
- }
+ }
}
// at this point, all compared characters are equal,
// so decide based on the relative lengths
- if (lhs.length() < rhs.length()) {
- return true;
- } else {
- return false;
- }
+ return lhs.length() < rhs.length();
}
@@ -377,8 +370,8 @@ bool seq_decl_plugin::match(ptr_vector& binding, sort* s, sort* sP) {
if (s->get_family_id() == sP->get_family_id() &&
s->get_decl_kind() == sP->get_decl_kind() &&
s->get_num_parameters() == sP->get_num_parameters()) {
- for (unsigned i = 0, sz = s->get_num_parameters(); i < sz; ++i) {
- parameter const& p = s->get_parameter(i);
+ for (unsigned i = 0, sz = s->get_num_parameters(); i < sz; ++i) {
+ parameter const& p = s->get_parameter(i);
if (p.is_ast() && is_sort(p.get_ast())) {
parameter const& p2 = sP->get_parameter(i);
if (!match(binding, to_sort(p.get_ast()), to_sort(p2.get_ast()))) return false;
@@ -435,7 +428,7 @@ void seq_decl_plugin::match_right_assoc(psig& sig, unsigned dsz, sort *const* do
}
void seq_decl_plugin::match(psig& sig, unsigned dsz, sort *const* dom, sort* range, sort_ref& range_out) {
- ptr_vector binding;
+ m_binding.reset();
ast_manager& m = *m_manager;
if (sig.m_dom.size() != dsz) {
std::ostringstream strm;
@@ -445,10 +438,10 @@ void seq_decl_plugin::match(psig& sig, unsigned dsz, sort *const* dom, sort* ran
}
bool is_match = true;
for (unsigned i = 0; is_match && i < dsz; ++i) {
- is_match = match(binding, dom[i], sig.m_dom[i].get());
+ is_match = match(m_binding, dom[i], sig.m_dom[i].get());
}
if (range && is_match) {
- is_match = match(binding, range, sig.m_range);
+ is_match = match(m_binding, range, sig.m_range);
}
if (!is_match) {
std::ostringstream strm;
@@ -474,7 +467,7 @@ void seq_decl_plugin::match(psig& sig, unsigned dsz, sort *const* dom, sort* ran
strm << "is ambiguous. Function takes no arguments and sort of range has not been constrained";
m.raise_exception(strm.str().c_str());
}
- range_out = apply_binding(binding, sig.m_range);
+ range_out = apply_binding(m_binding, sig.m_range);
SASSERT(range_out);
}
@@ -555,7 +548,7 @@ void seq_decl_plugin::init() {
m_sigs[OP_RE_OF_PRED] = alloc(psig, m, "re.of.pred", 1, 1, &predA, reA);
m_sigs[OP_SEQ_TO_RE] = alloc(psig, m, "seq.to.re", 1, 1, &seqA, reA);
m_sigs[OP_SEQ_IN_RE] = alloc(psig, m, "seq.in.re", 1, 2, seqAreA, boolT);
- m_sigs[OP_STRING_CONST] = 0;
+ m_sigs[OP_STRING_CONST] = nullptr;
m_sigs[_OP_STRING_STRIDOF] = alloc(psig, m, "str.indexof", 0, 3, str2TintT, intT);
m_sigs[_OP_STRING_STRREPL] = alloc(psig, m, "str.replace", 0, 3, str3T, strT);
m_sigs[OP_STRING_ITOS] = alloc(psig, m, "int.to.str", 0, 1, &intT, strT);
@@ -967,6 +960,24 @@ app* seq_util::str::mk_char(char ch) const {
return mk_char(s, 0);
}
+bool seq_util::is_const_char(expr* e, unsigned& c) const {
+ bv_util bv(m);
+ rational r;
+ unsigned sz;
+ return bv.is_numeral(e, r, sz) && sz == 8 && r.is_unsigned() && (c = r.get_unsigned(), true);
+}
+
+app* seq_util::mk_char(unsigned ch) const {
+ bv_util bv(m);
+ return bv.mk_numeral(rational(ch), 8);
+}
+
+app* seq_util::mk_le(expr* ch1, expr* ch2) const {
+ bv_util bv(m);
+ return bv.mk_ule(ch1, ch2);
+}
+
+
bool seq_util::str::is_string(expr const* n, zstring& s) const {
if (is_string(n)) {
s = zstring(to_app(n)->get_decl()->get_parameter(0).get_symbol().bare_str());
@@ -1044,7 +1055,6 @@ app* seq_util::re::mk_empty(sort* s) {
return m.mk_app(m_fid, OP_RE_EMPTY_SET, 0, nullptr, 0, nullptr, s);
}
-
bool seq_util::re::is_loop(expr const* n, expr*& body, unsigned& lo, unsigned& hi) {
if (is_loop(n)) {
app const* a = to_app(n);
diff --git a/src/ast/seq_decl_plugin.h b/src/ast/seq_decl_plugin.h
index f8107f1e0..1148c8411 100644
--- a/src/ast/seq_decl_plugin.h
+++ b/src/ast/seq_decl_plugin.h
@@ -22,7 +22,6 @@ Revision History:
#define SEQ_DECL_PLUGIN_H_
#include "ast/ast.h"
-#include "ast/bv_decl_plugin.h"
enum seq_sort_kind {
@@ -140,6 +139,7 @@ class seq_decl_plugin : public decl_plugin {
};
ptr_vector m_sigs;
+ ptr_vector m_binding;
bool m_init;
symbol m_stringc_sym;
symbol m_charc_sym;
@@ -220,6 +220,9 @@ public:
bool is_re(expr* e) const { return is_re(m.get_sort(e)); }
bool is_re(expr* e, sort*& seq) const { return is_re(m.get_sort(e), seq); }
bool is_char(expr* e) const { return is_char(m.get_sort(e)); }
+ bool is_const_char(expr* e, unsigned& c) const;
+ app* mk_char(unsigned ch) const;
+ app* mk_le(expr* ch1, expr* ch2) const;
app* mk_skolem(symbol const& name, unsigned n, expr* const* args, sort* range);
bool is_skolem(expr const* e) const { return is_app_of(e, m_fid, _OP_SEQ_SKOLEM); }
diff --git a/src/ast/shared_occs.cpp b/src/ast/shared_occs.cpp
index 89867e8c1..9528892e7 100644
--- a/src/ast/shared_occs.cpp
+++ b/src/ast/shared_occs.cpp
@@ -21,13 +21,11 @@ Revision History:
#include "util/ref_util.h"
inline void shared_occs::insert(expr * t) {
- obj_hashtable::entry * dummy;
- if (m_shared.insert_if_not_there_core(t, dummy))
- m.inc_ref(t);
+ m_shared.reserve(t->get_id() + 1);
+ m_shared[t->get_id()] = t;
}
void shared_occs::reset() {
- dec_ref_collection_values(m, m_shared);
m_shared.reset();
}
@@ -132,9 +130,15 @@ void shared_occs::operator()(expr * t) {
}
void shared_occs::display(std::ostream & out, ast_manager & m) const {
- iterator it = begin_shared();
- iterator end = end_shared();
- for (; it != end; ++it) {
- out << mk_ismt2_pp(*it, m) << "\n";
+ for (expr* s : m_shared) {
+ if (s) {
+ out << mk_ismt2_pp(s, m) << "\n";
+ }
}
}
+
+unsigned shared_occs::num_shared() const{
+ unsigned count = 0;
+ for (expr* s : m_shared) if (s) count++;
+ return count;
+}
diff --git a/src/ast/shared_occs.h b/src/ast/shared_occs.h
index 40921922a..300bb584f 100644
--- a/src/ast/shared_occs.h
+++ b/src/ast/shared_occs.h
@@ -53,7 +53,7 @@ class shared_occs {
bool m_track_atomic;
bool m_visit_quantifiers;
bool m_visit_patterns;
- obj_hashtable m_shared;
+ expr_ref_vector m_shared;
typedef std::pair frame;
svector m_stack;
bool process(expr * t, shared_occs_mark & visited);
@@ -64,15 +64,14 @@ public:
m(_m),
m_track_atomic(track_atomic),
m_visit_quantifiers(visit_quantifiers),
- m_visit_patterns(visit_patterns) {
+ m_visit_patterns(visit_patterns),
+ m_shared(m) {
}
~shared_occs();
void operator()(expr * t);
void operator()(expr * t, shared_occs_mark & visited);
- bool is_shared(expr * t) const { return m_shared.contains(t); }
- unsigned num_shared() const { return m_shared.size(); }
- iterator begin_shared() const { return m_shared.begin(); }
- iterator end_shared() const { return m_shared.end(); }
+ bool is_shared(expr * t) const { return m_shared.get(t->get_id(), nullptr) != nullptr; }
+ unsigned num_shared() const;
void reset();
void cleanup();
void display(std::ostream & out, ast_manager & mgr) const;
diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp
index ea5994ece..80cd6373e 100644
--- a/src/cmd_context/basic_cmds.cpp
+++ b/src/cmd_context/basic_cmds.cpp
@@ -137,7 +137,7 @@ ATOMIC_CMD(get_assignment_cmd, "get-assignment", "retrieve assignment", {
symbol const & name = kv.m_key;
macro_decls const & _m = kv.m_value;
for (auto md : _m) {
- if (md.m_domain.size() == 0 && ctx.m().is_bool(md.m_body)) {
+ if (md.m_domain.empty() && ctx.m().is_bool(md.m_body)) {
model::scoped_model_completion _scm(*m, true);
expr_ref val = (*m)(md.m_body);
if (ctx.m().is_true(val) || ctx.m().is_false(val)) {
@@ -309,7 +309,6 @@ protected:
symbol m_produce_unsat_assumptions;
symbol m_produce_models;
symbol m_produce_assignments;
- symbol m_produce_interpolants;
symbol m_produce_assertions;
symbol m_regular_output_channel;
symbol m_diagnostic_output_channel;
@@ -326,7 +325,7 @@ protected:
return
s == m_print_success || s == m_print_warning || s == m_expand_definitions ||
s == m_interactive_mode || s == m_produce_proofs || s == m_produce_unsat_cores || s == m_produce_unsat_assumptions ||
- s == m_produce_models || s == m_produce_assignments || s == m_produce_interpolants ||
+ s == m_produce_models || s == m_produce_assignments ||
s == m_regular_output_channel || s == m_diagnostic_output_channel ||
s == m_random_seed || s == m_verbosity || s == m_global_decls || s == m_global_declarations ||
s == m_produce_assertions || s == m_reproducible_resource_limit;
@@ -346,7 +345,6 @@ public:
m_produce_unsat_assumptions(":produce-unsat-assumptions"),
m_produce_models(":produce-models"),
m_produce_assignments(":produce-assignments"),
- m_produce_interpolants(":produce-interpolants"),
m_produce_assertions(":produce-assertions"),
m_regular_output_channel(":regular-output-channel"),
m_diagnostic_output_channel(":diagnostic-output-channel"),
@@ -418,10 +416,6 @@ class set_option_cmd : public set_get_option_cmd {
check_not_initialized(ctx, m_produce_proofs);
ctx.set_produce_proofs(to_bool(value));
}
- else if (m_option == m_produce_interpolants) {
- check_not_initialized(ctx, m_produce_interpolants);
- ctx.set_produce_interpolants(to_bool(value));
- }
else if (m_option == m_produce_unsat_cores) {
check_not_initialized(ctx, m_produce_unsat_cores);
ctx.set_produce_unsat_cores(to_bool(value));
@@ -577,9 +571,6 @@ public:
else if (opt == m_produce_proofs) {
print_bool(ctx, ctx.produce_proofs());
}
- else if (opt == m_produce_interpolants) {
- print_bool(ctx, ctx.produce_interpolants());
- }
else if (opt == m_produce_unsat_cores) {
print_bool(ctx, ctx.produce_unsat_cores());
}
diff --git a/src/cmd_context/check_logic.cpp b/src/cmd_context/check_logic.cpp
index 47c919d4a..35bbde2b2 100644
--- a/src/cmd_context/check_logic.cpp
+++ b/src/cmd_context/check_logic.cpp
@@ -237,10 +237,12 @@ struct check_logic::imp {
return;
}
else if (m_bv_arrays) {
- if (get_array_arity(s) != 1)
- fail("logic supports only unidimensional arrays");
- if (!m_bv_util.is_bv_sort(get_array_range(s)) || !m_bv_util.is_bv_sort(get_array_domain(s, 0)))
- fail("logic supports only arrays from bitvectors to bitvectors");
+ unsigned sz = get_array_arity(s);
+ for (unsigned i = 0; i < sz; ++i) {
+ if (!m_bv_util.is_bv_sort(get_array_domain(s, i)))
+ fail("logic supports only arrays from bitvectors to bitvectors");
+ }
+ check_sort(get_array_range(s));
}
else {
fail("logic does not support arrays");
diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp
index fb81c673e..c58453460 100644
--- a/src/cmd_context/cmd_context.cpp
+++ b/src/cmd_context/cmd_context.cpp
@@ -560,14 +560,6 @@ void cmd_context::set_produce_proofs(bool f) {
m_params.m_proof = f;
}
-void cmd_context::set_produce_interpolants(bool f) {
- // can only be set before initialization
- // FIXME currently synonym for produce_proofs
- // also sets the default solver to be simple smt
- SASSERT(!has_manager());
- m_params.m_proof = f;
- // set_solver_factory(mk_smt_solver_factory());
-}
bool cmd_context::produce_models() const {
return m_params.m_model;
@@ -577,11 +569,6 @@ bool cmd_context::produce_proofs() const {
return m_params.m_proof;
}
-bool cmd_context::produce_interpolants() const {
- // FIXME currently synonym for produce_proofs
- return m_params.m_proof;
-}
-
bool cmd_context::produce_unsat_cores() const {
return m_params.m_unsat_core;
}
@@ -1895,25 +1882,14 @@ void cmd_context::validate_model() {
}
}
-// FIXME: really interpolants_enabled ought to be a parameter to the solver factory,
-// but this is a global change, so for now, we use an alternate solver factory
-// for interpolation
void cmd_context::mk_solver() {
bool proofs_enabled, models_enabled, unsat_core_enabled;
params_ref p;
m_params.get_solver_params(m(), p, proofs_enabled, models_enabled, unsat_core_enabled);
- if (produce_interpolants() && m_interpolating_solver_factory) {
- m_solver = (*m_interpolating_solver_factory)(m(), p, true /* must have proofs */, models_enabled, unsat_core_enabled, m_logic);
- }
- else
- m_solver = (*m_solver_factory)(m(), p, proofs_enabled, models_enabled, unsat_core_enabled, m_logic);
+ m_solver = (*m_solver_factory)(m(), p, proofs_enabled, models_enabled, unsat_core_enabled, m_logic);
}
-void cmd_context::set_interpolating_solver_factory(solver_factory * f) {
- SASSERT(!has_manager());
- m_interpolating_solver_factory = f;
-}
void cmd_context::set_solver_factory(solver_factory * f) {
m_solver_factory = f;
@@ -2108,7 +2084,7 @@ void cmd_context::dt_eh::operator()(sort * dt, pdecl* pd) {
m_owner.insert(a);
}
}
- if (m_owner.m_scopes.size() > 0) {
+ if (!m_owner.m_scopes.empty()) {
m_owner.pm().inc_ref(pd);
m_owner.m_psort_inst_stack.push_back(pd);
}
diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h
index b2ed1e5cb..55ea65cb5 100644
--- a/src/cmd_context/cmd_context.h
+++ b/src/cmd_context/cmd_context.h
@@ -33,6 +33,7 @@ Notes:
#include "ast/ast_printer.h"
#include "ast/datatype_decl_plugin.h"
#include "ast/recfun_decl_plugin.h"
+#include "ast/rewriter/seq_rewriter.h"
#include "tactic/generic_model_converter.h"
#include "solver/solver.h"
#include "solver/progress_callback.h"
@@ -240,7 +241,6 @@ protected:
svector m_scopes;
scoped_ptr m_solver_factory;
- scoped_ptr m_interpolating_solver_factory;
ref m_solver;
ref m_check_sat_result;
ref m_opt;
@@ -315,7 +315,6 @@ public:
void set_cancel(bool f);
context_params & params() { return m_params; }
solver_factory &get_solver_factory() { return *m_solver_factory; }
- solver_factory &get_interpolating_solver_factory() { return *m_interpolating_solver_factory; }
opt_wrapper* get_opt();
void set_opt(opt_wrapper* o);
void global_params_updated(); // this method should be invoked when global (and module) params are updated.
@@ -341,14 +340,12 @@ public:
void set_random_seed(unsigned s) { m_random_seed = s; }
bool produce_models() const;
bool produce_proofs() const;
- bool produce_interpolants() const;
bool produce_unsat_cores() const;
bool well_sorted_check_enabled() const;
bool validate_model_enabled() const;
void set_produce_models(bool flag);
void set_produce_unsat_cores(bool flag);
void set_produce_proofs(bool flag);
- void set_produce_interpolants(bool flag);
void set_produce_unsat_assumptions(bool flag) { m_produce_unsat_assumptions = flag; }
bool produce_assignments() const { return m_produce_assignments; }
bool produce_unsat_assumptions() const { return m_produce_unsat_assumptions; }
@@ -364,7 +361,6 @@ public:
sexpr_manager & sm() const { if (!m_sexpr_manager) const_cast(this)->m_sexpr_manager = alloc(sexpr_manager); return *m_sexpr_manager; }
void set_solver_factory(solver_factory * s);
- void set_interpolating_solver_factory(solver_factory * s);
void set_check_sat_result(check_sat_result * r) { m_check_sat_result = r; }
check_sat_result * get_check_sat_result() const { return m_check_sat_result.get(); }
check_sat_state cs_state() const;
@@ -493,4 +489,24 @@ public:
std::ostream & operator<<(std::ostream & out, cmd_context::status st);
+
+class th_solver : public expr_solver {
+ cmd_context& m_ctx;
+ params_ref m_params;
+ ref m_solver;
+public:
+ th_solver(cmd_context& ctx): m_ctx(ctx) {}
+
+ lbool check_sat(expr* e) override {
+ if (!m_solver) {
+ m_solver = m_ctx.get_solver_factory()(m_ctx.m(), m_params, false, true, false, symbol::null);
+ }
+ m_solver->push();
+ m_solver->assert_expr(e);
+ lbool r = m_solver->check_sat(0,nullptr);
+ m_solver->pop(1);
+ return r;
+ }
+};
+
#endif
diff --git a/src/cmd_context/context_params.cpp b/src/cmd_context/context_params.cpp
index c0ab1e3e2..447718aa9 100644
--- a/src/cmd_context/context_params.cpp
+++ b/src/cmd_context/context_params.cpp
@@ -166,8 +166,8 @@ void context_params::updt_params(params_ref const & p) {
}
void context_params::collect_param_descrs(param_descrs & d) {
- d.insert("timeout", CPK_UINT, "default timeout (in milliseconds) used for solvers", "4294967295");
- d.insert("rlimit", CPK_UINT, "default resource limit used for solvers. Unrestricted when set to 0.", "0");
+ insert_rlimit(d);
+ insert_timeout(d);
d.insert("well_sorted_check", CPK_BOOL, "type checker", "false");
d.insert("type_check", CPK_BOOL, "type checker (alias for well_sorted_check)", "true");
d.insert("auto_config", CPK_BOOL, "use heuristics to automatically select solver and configure it", "true");
diff --git a/src/cmd_context/eval_cmd.cpp b/src/cmd_context/eval_cmd.cpp
index 3f564edff..a599cfa4a 100644
--- a/src/cmd_context/eval_cmd.cpp
+++ b/src/cmd_context/eval_cmd.cpp
@@ -72,6 +72,7 @@ public:
unsigned timeout = m_params.get_uint("timeout", UINT_MAX);
unsigned rlimit = m_params.get_uint("rlimit", 0);
model_evaluator ev(*(md.get()), m_params);
+ ev.set_solver(alloc(th_solver, ctx));
cancel_eh eh(ctx.m().limit());
{
scoped_ctrl_c ctrlc(eh);
diff --git a/src/cmd_context/extra_cmds/dbg_cmds.cpp b/src/cmd_context/extra_cmds/dbg_cmds.cpp
index bdd2c8b97..7c1383d62 100644
--- a/src/cmd_context/extra_cmds/dbg_cmds.cpp
+++ b/src/cmd_context/extra_cmds/dbg_cmds.cpp
@@ -77,30 +77,12 @@ BINARY_SYM_CMD(shift_vars_cmd,
store_expr_ref(ctx, m_sym, r.get());
});
-UNARY_CMD(pp_shared_cmd, "dbg-pp-shared", "", "display shared subterms of the given term", CPK_EXPR, expr *, {
- shared_occs s(ctx.m());
- s(arg);
- ctx.regular_stream() << "(shared";
- shared_occs::iterator it = s.begin_shared();
- shared_occs::iterator end = s.end_shared();
- for (; it != end; ++it) {
- expr * curr = *it;
- ctx.regular_stream() << std::endl << " ";
- ctx.display(ctx.regular_stream(), curr, 2);
- }
- ctx.regular_stream() << ")" << std::endl;
-});
UNARY_CMD(assert_not_cmd, "assert-not", "", "assert negation", CPK_EXPR, expr *, {
expr_ref ne(ctx.m().mk_not(arg), ctx.m());
ctx.assert_expr(ne);
});
-UNARY_CMD(num_shared_cmd, "dbg-num-shared", "", "return the number of shared subterms", CPK_EXPR, expr *, {
- shared_occs s(ctx.m());
- s(arg);
- ctx.regular_stream() << s.num_shared() << std::endl;
-});
UNARY_CMD(size_cmd, "dbg-size", "", "return the size of the given term", CPK_EXPR, expr *, {
ctx.regular_stream() << get_num_exprs(arg) << std::endl;
@@ -524,11 +506,21 @@ public:
for (func_decl* v : m_vars) vars.push_back(v);
for (expr* e : m_lits) lits.push_back(e);
flatten_and(lits);
- qe::term_graph tg(m);
- tg.set_vars(vars, false);
- tg.add_lits(lits);
- expr_ref_vector p = tg.project();
- ctx.regular_stream() << p << "\n";
+ solver_factory& sf = ctx.get_solver_factory();
+ params_ref pa;
+ solver_ref s = sf(m, pa, false, true, true, symbol::null);
+ solver_ref se = sf(m, pa, false, true, true, symbol::null);
+ s->assert_expr(lits);
+ lbool r = s->check_sat();
+ if (r != l_true) {
+ ctx.regular_stream() << "sat check " << r << "\n";
+ return;
+ }
+ model_ref mdl;
+ s->get_model(mdl);
+ qe::euf_arith_mbi_plugin plugin(s.get(), se.get());
+ plugin.project(mdl, lits);
+ ctx.regular_stream() << lits << "\n";
}
};
@@ -540,8 +532,6 @@ void install_dbg_cmds(cmd_context & ctx) {
ctx.insert(alloc(set_cmd));
ctx.insert(alloc(pp_var_cmd));
ctx.insert(alloc(shift_vars_cmd));
- ctx.insert(alloc(pp_shared_cmd));
- ctx.insert(alloc(num_shared_cmd));
ctx.insert(alloc(assert_not_cmd));
ctx.insert(alloc(size_cmd));
ctx.insert(alloc(subst_cmd));
diff --git a/src/cmd_context/simplify_cmd.cpp b/src/cmd_context/simplify_cmd.cpp
index de548562e..077a46659 100644
--- a/src/cmd_context/simplify_cmd.cpp
+++ b/src/cmd_context/simplify_cmd.cpp
@@ -24,29 +24,10 @@ Notes:
#include "util/scoped_timer.h"
#include "util/scoped_ctrl_c.h"
#include "util/cancel_eh.h"
-#include "ast/rewriter/seq_rewriter.h"
#include
class simplify_cmd : public parametric_cmd {
- class th_solver : public expr_solver {
- cmd_context& m_ctx;
- params_ref m_params;
- ref m_solver;
- public:
- th_solver(cmd_context& ctx): m_ctx(ctx) {}
-
- lbool check_sat(expr* e) override {
- if (!m_solver) {
- m_solver = m_ctx.get_solver_factory()(m_ctx.m(), m_params, false, true, false, symbol::null);
- }
- m_solver->push();
- m_solver->assert_expr(e);
- lbool r = m_solver->check_sat(0,nullptr);
- m_solver->pop(1);
- return r;
- }
- };
expr * m_target;
public:
diff --git a/src/cmd_context/tactic_cmds.cpp b/src/cmd_context/tactic_cmds.cpp
index a89e76edb..7fdca8cdd 100644
--- a/src/cmd_context/tactic_cmds.cpp
+++ b/src/cmd_context/tactic_cmds.cpp
@@ -224,7 +224,7 @@ public:
ctx.display_sat_result(r);
result->set_status(r);
if (r == l_undef) {
- if (reason_unknown != "") {
+ if (!reason_unknown.empty()) {
result->m_unknown = reason_unknown;
// ctx.diagnostic_stream() << "\"" << escaped(reason_unknown.c_str(), true) << "\"" << std::endl;
}
diff --git a/src/math/polynomial/algebraic_numbers.cpp b/src/math/polynomial/algebraic_numbers.cpp
index 17360f35b..25a1985a7 100644
--- a/src/math/polynomial/algebraic_numbers.cpp
+++ b/src/math/polynomial/algebraic_numbers.cpp
@@ -561,7 +561,9 @@ namespace algebraic_numbers {
};
void sort_roots(numeral_vector & r) {
- std::sort(r.begin(), r.end(), lt_proc(m_wrapper));
+ if (m_limit.inc()) {
+ std::sort(r.begin(), r.end(), lt_proc(m_wrapper));
+ }
}
void isolate_roots(scoped_upoly const & up, numeral_vector & roots) {
@@ -1750,8 +1752,7 @@ namespace algebraic_numbers {
// then they MUST BE DIFFERENT.
// Thus, if we keep refining the interval of a and b,
// eventually they will not overlap
- while (true) {
- checkpoint();
+ while (m_limit.inc()) {
refine(a);
refine(b);
m_compare_refine++;
@@ -1764,6 +1765,9 @@ namespace algebraic_numbers {
}
}
+ if (!m_limit.inc())
+ return 0;
+
// make sure that intervals of a and b have the same magnitude
int a_m = magnitude(a_lower, a_upper);
int b_m = magnitude(b_lower, b_upper);
@@ -1810,6 +1814,7 @@ namespace algebraic_numbers {
// V == 0 --> a = b
// if (V < 0) == (p_b(b_lower) < 0) then b > a else b < a
//
+
m_compare_sturm++;
upolynomial::scoped_upolynomial_sequence seq(upm());
upm().sturm_tarski_seq(cell_a->m_p_sz, cell_a->m_p, cell_b->m_p_sz, cell_b->m_p, seq);
diff --git a/src/math/polynomial/polynomial.cpp b/src/math/polynomial/polynomial.cpp
index aec901f61..8f7f08c7f 100644
--- a/src/math/polynomial/polynomial.cpp
+++ b/src/math/polynomial/polynomial.cpp
@@ -67,7 +67,7 @@ namespace polynomial {
bool first = true;
out << "[";
for (unsigned i = 0; i < m_var2degree.size(); ++ i) {
- if (m_var2degree.size() > 0) {
+ if (!m_var2degree.empty()) {
if (!first) {
out << ",";
}
diff --git a/src/math/polynomial/upolynomial.cpp b/src/math/polynomial/upolynomial.cpp
index 39bdb6812..65dbf91f4 100644
--- a/src/math/polynomial/upolynomial.cpp
+++ b/src/math/polynomial/upolynomial.cpp
@@ -96,7 +96,7 @@ namespace upolynomial {
void core_manager::factors::display(std::ostream & out) const {
out << nm().to_string(m_constant);
- if (m_factors.size() > 0) {
+ if (!m_factors.empty()) {
for (unsigned i = 0; i < m_factors.size(); ++ i) {
out << " * (";
m_upm.display(out, m_factors[i]);
@@ -524,11 +524,11 @@ namespace upolynomial {
set(sz1, p1, buffer);
if (sz1 <= 1)
return;
+
numeral const & b_n = p2[sz2-1];
SASSERT(!m().is_zero(b_n));
scoped_numeral a_m(m());
- while (true) {
- checkpoint();
+ while (m_limit.inc()) {
TRACE("rem_bug", tout << "rem loop, p2:\n"; display(tout, sz2, p2); tout << "\nbuffer:\n"; display(tout, buffer); tout << "\n";);
sz1 = buffer.size();
if (sz1 < sz2) {
@@ -1339,12 +1339,10 @@ namespace upolynomial {
// Return the number of sign changes in the coefficients of p
unsigned manager::sign_changes(unsigned sz, numeral const * p) {
unsigned r = 0;
- int sign, prev_sign;
- sign = 0;
- prev_sign = 0;
+ int prev_sign = 0;
unsigned i = 0;
for (; i < sz; i++) {
- sign = sign_of(p[i]);
+ int sign = sign_of(p[i]);
if (sign == 0)
continue;
if (sign != prev_sign && prev_sign != 0)
@@ -2519,7 +2517,7 @@ namespace upolynomial {
// Keep expanding the Sturm sequence starting at seq
void manager::sturm_seq_core(upolynomial_sequence & seq) {
scoped_numeral_vector r(m());
- while (true) {
+ while (m_limit.inc()) {
unsigned sz = seq.size();
srem(seq.size(sz-2), seq.coeffs(sz-2), seq.size(sz-1), seq.coeffs(sz-1), r);
if (is_zero(r))
diff --git a/src/math/polynomial/upolynomial_factorization.cpp b/src/math/polynomial/upolynomial_factorization.cpp
index 5d9d3f1f1..45cc3f86d 100644
--- a/src/math/polynomial/upolynomial_factorization.cpp
+++ b/src/math/polynomial/upolynomial_factorization.cpp
@@ -532,7 +532,7 @@ bool check_hansel_lift(z_manager & upm, numeral_vector const & C,
upm.mul(A_lifted.size(), A_lifted.c_ptr(), B_lifted.size(), B_lifted.c_ptr(), test1);
upm.sub(C.size(), C.c_ptr(), test1.size(), test1.c_ptr(), test1);
to_zp_manager(br_upm, test1);
- if (test1.size() != 0) {
+ if (!test1.empty()) {
TRACE("polynomial::factorization::bughunt",
tout << "sage: R. = ZZ['x']" << endl;
tout << "sage: A = "; upm.display(tout, A); tout << endl;
@@ -1072,7 +1072,8 @@ bool factor_square_free(z_manager & upm, numeral_vector const & f, factors & fs,
prime_iterator prime_it;
scoped_numeral gcd_tmp(nm);
unsigned trials = 0;
- while (trials < params.m_p_trials) {
+ TRACE("polynomial::factorization::bughunt", tout << "trials: " << params.m_p_trials << "\n";);
+ while (trials <= params.m_p_trials) {
upm.checkpoint();
// construct prime to check
uint64_t next_prime = prime_it.next();
diff --git a/src/math/polynomial/upolynomial_factorization_int.h b/src/math/polynomial/upolynomial_factorization_int.h
index 10bfb4d8b..816914545 100644
--- a/src/math/polynomial/upolynomial_factorization_int.h
+++ b/src/math/polynomial/upolynomial_factorization_int.h
@@ -401,7 +401,7 @@ namespace upolynomial {
} else {
if (selection_i >= m_current.size() || (int) current < m_current[selection_i]) {
SASSERT(m_factors.get_degree(current) == 1);
- if (out.size() == 0) {
+ if (out.empty()) {
upm.set(m_factors[current].size(), m_factors[current].c_ptr(), out);
} else {
upm.mul(out.size(), out.c_ptr(), m_factors[current].size(), m_factors[current].c_ptr(), out);
diff --git a/src/math/realclosure/realclosure.cpp b/src/math/realclosure/realclosure.cpp
index 77623a2df..3e05be734 100644
--- a/src/math/realclosure/realclosure.cpp
+++ b/src/math/realclosure/realclosure.cpp
@@ -154,7 +154,7 @@ namespace realclosure {
struct value {
unsigned m_ref_count; //!< Reference counter
- bool m_rational; //!< True if the value is represented as an abitrary precision rational value.
+ bool m_rational; //!< True if the value is represented as an arbitrary precision rational value.
mpbqi m_interval; //!< approximation as an interval with binary rational end-points
// When performing an operation OP, we may have to make the width (upper - lower) of m_interval very small.
// The precision (i.e., a small interval) needed for executing OP is usually unnecessary for subsequent operations,
@@ -283,7 +283,7 @@ namespace realclosure {
struct algebraic : public extension {
polynomial m_p;
mpbqi m_iso_interval;
- sign_det * m_sign_det; //!< != 0 if m_iso_interval constains more than one root of m_p.
+ sign_det * m_sign_det; //!< != 0 if m_iso_interval constrains more than one root of m_p.
unsigned m_sc_idx; //!< != UINT_MAX if m_sign_det != 0, in this case m_sc_idx < m_sign_det->m_sign_conditions.size()
bool m_depends_on_infinitesimals; //!< True if the polynomial p depends on infinitesimal extensions.
@@ -1741,7 +1741,7 @@ namespace realclosure {
\brief In the sign determination algorithm main loop, we keep processing polynomials q,
and checking whether they discriminate the roots of the target polynomial.
- The vectors sc_cardinalities contains the cardinalites of the new realizable sign conditions.
+ The vectors sc_cardinalities contains the cardinalities of the new realizable sign conditions.
That is, we started we a sequence of sign conditions
sc_1, ..., sc_n,
If q2_used is true, then we expanded this sequence as
@@ -1750,7 +1750,7 @@ namespace realclosure {
Thus, q is useful (i.e., it is a discriminator for the roots of p) IF
If !q2_used, then There is an i s.t. sc_cardinalities[2*i] > 0 && sc_cardinalities[2*i] > 0
- If q2_used, then There is an i s.t. AtLeatTwo(sc_cardinalities[3*i] > 0, sc_cardinalities[3*i+1] > 0, sc_cardinalities[3*i+2] > 0)
+ If q2_used, then There is an i s.t. AtLeastTwo(sc_cardinalities[3*i] > 0, sc_cardinalities[3*i+1] > 0, sc_cardinalities[3*i+2] > 0)
*/
bool keep_new_sc_assignment(unsigned sz, int const * sc_cardinalities, bool q2_used) {
SASSERT(q2_used || sz % 2 == 0);
@@ -2038,7 +2038,7 @@ namespace realclosure {
// We should keep q only if it discriminated something.
// That is,
// If !use_q2, then There is an i s.t. sc_cardinalities[2*i] > 0 && sc_cardinalities[2*i] > 0
- // If use_q2, then There is an i s.t. AtLeatTwo(sc_cardinalities[3*i] > 0, sc_cardinalities[3*i+1] > 0, sc_cardinalities[3*i+2] > 0)
+ // If use_q2, then There is an i s.t. AtLeastTwo(sc_cardinalities[3*i] > 0, sc_cardinalities[3*i+1] > 0, sc_cardinalities[3*i+2] > 0)
if (!keep_new_sc_assignment(sc_cardinalities.size(), sc_cardinalities.c_ptr(), use_q2)) {
// skip q since it did not reduced the cardinality of the existing sign conditions.
continue;
@@ -3466,11 +3466,11 @@ namespace realclosure {
// ---------------------------------
bool is_monic(value_ref_buffer const & p) {
- return p.size() > 0 && is_rational_one(p[p.size() - 1]);
+ return !p.empty() && is_rational_one(p[p.size() - 1]);
}
bool is_monic(polynomial const & p) {
- return p.size() > 0 && is_rational_one(p[p.size() - 1]);
+ return !p.empty() && is_rational_one(p[p.size() - 1]);
}
/**
diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp
index 8a771e07c..4053c41b7 100644
--- a/src/math/simplex/model_based_opt.cpp
+++ b/src/math/simplex/model_based_opt.cpp
@@ -606,7 +606,7 @@ namespace opt {
}
}
- void model_based_opt::mk_coeffs_without(vector& dst, vector const src, unsigned x) {
+ void model_based_opt::mk_coeffs_without(vector& dst, vector const& src, unsigned x) {
for (var const & v : src) {
if (v.m_id != x) dst.push_back(v);
}
diff --git a/src/math/simplex/model_based_opt.h b/src/math/simplex/model_based_opt.h
index e52d0cfe0..30442fc58 100644
--- a/src/math/simplex/model_based_opt.h
+++ b/src/math/simplex/model_based_opt.h
@@ -132,7 +132,7 @@ namespace opt {
void normalize(unsigned row_id);
- void mk_coeffs_without(vector& dst, vector const src, unsigned x);
+ void mk_coeffs_without(vector& dst, vector const& src, unsigned x);
unsigned new_row();
diff --git a/src/model/func_interp.cpp b/src/model/func_interp.cpp
index 38eb4b00b..f981270b6 100644
--- a/src/model/func_interp.cpp
+++ b/src/model/func_interp.cpp
@@ -25,11 +25,11 @@ Revision History:
func_entry::func_entry(ast_manager & m, unsigned arity, expr * const * args, expr * result):
m_args_are_values(true),
m_result(result) {
- SASSERT(is_ground(result));
+ //SASSERT(is_ground(result));
m.inc_ref(result);
for (unsigned i = 0; i < arity; i++) {
expr * arg = args[i];
- SASSERT(is_ground(arg));
+ //SASSERT(is_ground(arg));
if (!m.is_value(arg))
m_args_are_values = false;
m.inc_ref(arg);
diff --git a/src/model/model.cpp b/src/model/model.cpp
index 2efc39db8..e6a3ffedf 100644
--- a/src/model/model.cpp
+++ b/src/model/model.cpp
@@ -85,7 +85,7 @@ struct model::value_proc : public some_value_proc {
expr * operator()(sort * s) override {
ptr_vector * u = nullptr;
if (m_model.m_usort2universe.find(s, u)) {
- if (u->size() > 0)
+ if (!u->empty())
return u->get(0);
}
return nullptr;
@@ -277,6 +277,13 @@ model::func_decl_set* model::collect_deps(top_sort& ts, func_interp * fi) {
fi->compress();
expr* e = fi->get_else();
if (e) for_each_expr(collector, e);
+ unsigned num_args = fi->get_arity();
+ for (func_entry* fe : *fi) {
+ for (unsigned i = 0; i < num_args; ++i) {
+ for_each_expr(collector, fe->get_arg(i));
+ }
+ for_each_expr(collector, fe->get_result());
+ }
return s;
}
@@ -468,6 +475,10 @@ expr_ref model::operator()(expr* t) {
return m_mev(t);
}
+void model::set_solver(expr_solver* s) {
+ m_mev.set_solver(s);
+}
+
expr_ref_vector model::operator()(expr_ref_vector const& ts) {
expr_ref_vector rs(m);
for (expr* t : ts) rs.push_back((*this)(t));
diff --git a/src/model/model.h b/src/model/model.h
index 0b74de771..2599a3fcd 100644
--- a/src/model/model.h
+++ b/src/model/model.h
@@ -95,6 +95,7 @@ public:
bool is_false(expr* t);
bool is_true(expr_ref_vector const& ts);
void reset_eval_cache();
+ void set_solver(expr_solver* solver);
class scoped_model_completion {
bool m_old_completion;
diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp
index 0fe1fe7c6..968aca51f 100644
--- a/src/model/model_evaluator.cpp
+++ b/src/model/model_evaluator.cpp
@@ -40,6 +40,7 @@ Revision History:
struct evaluator_cfg : public default_rewriter_cfg {
ast_manager & m;
model_core & m_model;
+ params_ref m_params;
bool_rewriter m_b_rw;
arith_rewriter m_a_rw;
bv_rewriter m_bv_rw;
@@ -55,10 +56,13 @@ struct evaluator_cfg : public default_rewriter_cfg {
bool m_cache;
bool m_array_equalities;
bool m_array_as_stores;
+ obj_map m_def_cache;
+ expr_ref_vector m_pinned;
evaluator_cfg(ast_manager & m, model_core & md, params_ref const & p):
m(m),
m_model(md),
+ m_params(p),
m_b_rw(m),
// We must allow customers to set parameters for arithmetic rewriter/evaluator.
// In particular, the maximum degree of algebraic numbers that will be evaluated.
@@ -70,7 +74,8 @@ struct evaluator_cfg : public default_rewriter_cfg {
m_pb_rw(m),
m_f_rw(m),
m_seq_rw(m),
- m_ar(m) {
+ m_ar(m),
+ m_pinned(m) {
bool flat = true;
m_b_rw.set_flat(flat);
m_a_rw.set_flat(flat);
@@ -200,6 +205,39 @@ struct evaluator_cfg : public default_rewriter_cfg {
return BR_REWRITE1;
}
}
+#if 1
+ if (st == BR_FAILED && num == 0 && m_ar.is_as_array(f) && m_model_completion) {
+ func_decl* g = nullptr;
+ VERIFY(m_ar.is_as_array(f, g));
+ expr* def = nullptr;
+ quantifier* q = nullptr;
+ proof* def_pr = nullptr;
+ if (m_def_cache.find(g, def)) {
+ result = def;
+ return BR_DONE;
+ }
+ if (get_macro(g, def, q, def_pr)) {
+ sort_ref_vector sorts(m);
+ expr_ref_vector vars(m);
+ svector var_names;
+ unsigned sz = g->get_arity();
+ for (unsigned i = 0; i < sz; ++i) {
+ var_names.push_back(symbol(sz - i - 1));
+ vars.push_back(m.mk_var(sz - i - 1, g->get_domain(i)));
+ sorts.push_back(g->get_domain(i));
+ }
+ var_subst subst(m, false);
+ result = subst(def, sorts.size(), vars.c_ptr());
+ result = m.mk_lambda(sorts.size(), sorts.c_ptr(), var_names.c_ptr(), result);
+ model_evaluator ev(m_model, m_params);
+ result = ev(result);
+ m_pinned.push_back(result);
+ m_def_cache.insert(g, result);
+ return BR_DONE;
+ }
+ }
+#endif
+
CTRACE("model_evaluator", st != BR_FAILED, tout << result << "\n";);
return st;
}
@@ -222,7 +260,7 @@ struct evaluator_cfg : public default_rewriter_cfg {
}
}
- bool get_macro(func_decl * f, expr * & def, quantifier * & q, proof * & def_pr) {
+ bool get_macro(func_decl * f, expr * & def, quantifier * & , proof * &) {
#define TRACE_MACRO TRACE("model_evaluator", tout << "get_macro for " << f->get_name() << " (model completion: " << m_model_completion << ")\n";);
@@ -627,3 +665,7 @@ bool model_evaluator::eval(expr_ref_vector const& ts, expr_ref& r, bool model_co
tmp = mk_and(ts);
return eval(tmp, r, model_completion);
}
+
+void model_evaluator::set_solver(expr_solver* solver) {
+ m_imp->m_cfg.m_seq_rw.set_solver(solver);
+}
diff --git a/src/model/model_evaluator.h b/src/model/model_evaluator.h
index 8666e3519..1959af246 100644
--- a/src/model/model_evaluator.h
+++ b/src/model/model_evaluator.h
@@ -25,6 +25,7 @@ Revision History:
class model;
class model_core;
+class expr_solver;
typedef rewriter_exception model_evaluator_exception;
@@ -55,6 +56,8 @@ public:
bool is_false(expr * t);
bool is_true(expr_ref_vector const& ts);
+ void set_solver(expr_solver* solver);
+
/**
* best effort evaluator of extensional array equality.
*/
diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp
index 1c9abf78c..e8578f327 100644
--- a/src/muz/base/dl_context.cpp
+++ b/src/muz/base/dl_context.cpp
@@ -658,7 +658,7 @@ namespace datalog {
void context::add_table_fact(func_decl * pred, unsigned num_args, unsigned args[]) {
if (pred->get_arity() != num_args) {
std::ostringstream out;
- out << "miss-matched number of arguments passed to " << mk_ismt2_pp(pred, m) << " " << num_args << " passed";
+ out << "mismatched number of arguments passed to " << mk_ismt2_pp(pred, m) << " " << num_args << " passed";
throw default_exception(out.str());
}
table_fact fact;
@@ -1243,7 +1243,7 @@ namespace datalog {
void context::declare_vars(expr_ref_vector& rules, mk_fresh_name& fresh_names, std::ostream& out) {
//
// replace bound variables in rules by 'var declarations'
- // First remove quantifers, then replace bound variables
+ // First remove quantifiers, then replace bound variables
// by fresh constants.
//
smt2_pp_environment_dbg env(m);
diff --git a/src/muz/base/dl_rule_set.h b/src/muz/base/dl_rule_set.h
index e870e369c..633676ec7 100644
--- a/src/muz/base/dl_rule_set.h
+++ b/src/muz/base/dl_rule_set.h
@@ -230,7 +230,7 @@ namespace datalog {
bool is_closed() const { return m_stratifier != 0; }
unsigned get_num_rules() const { return m_rules.size(); }
- bool empty() const { return m_rules.size() == 0; }
+ bool empty() const { return m_rules.empty(); }
rule * get_rule(unsigned i) const { return m_rules[i]; }
rule * last() const { return m_rules[m_rules.size()-1]; }
diff --git a/src/muz/bmc/dl_bmc_engine.cpp b/src/muz/bmc/dl_bmc_engine.cpp
index f804a239a..b03a9aab1 100644
--- a/src/muz/bmc/dl_bmc_engine.cpp
+++ b/src/muz/bmc/dl_bmc_engine.cpp
@@ -986,7 +986,7 @@ namespace datalog {
m_sort2pred.insert(new_sorts[i].get(), it->m_key);
m_pinned.push_back(new_sorts[i].get());
}
- if (new_sorts.size() > 0) {
+ if (!new_sorts.empty()) {
TRACE("bmc", dtu.display_datatype(new_sorts[0].get(), tout););
}
del_datatype_decls(dts.size(), dts.c_ptr());
diff --git a/src/muz/fp/datalog_parser.cpp b/src/muz/fp/datalog_parser.cpp
index 1cc85e6cd..0724d471a 100644
--- a/src/muz/fp/datalog_parser.cpp
+++ b/src/muz/fp/datalog_parser.cpp
@@ -101,7 +101,7 @@ public:
resize_data(0);
#if _WINDOWS
errno_t err = fopen_s(&m_file, fname, "rb");
- m_ok = (m_file != NULL) && (err == 0);
+ m_ok = (m_file != nullptr) && (err == 0);
#else
m_file = fopen(fname, "rb");
m_ok = (m_file != nullptr);
@@ -1057,7 +1057,7 @@ protected:
line.push_back(ch);
ch = strm.get();
}
- return line.size() > 0;
+ return !line.empty();
}
void add_rule(app* head, unsigned sz, app* const* body, const bool * is_neg) {
diff --git a/src/muz/rel/dl_base.h b/src/muz/rel/dl_base.h
index decf499a2..d307912be 100644
--- a/src/muz/rel/dl_base.h
+++ b/src/muz/rel/dl_base.h
@@ -1120,10 +1120,7 @@ namespace datalog {
virtual bool operator==(const iterator_core & it) {
//we worry about the equality operator only because of checking
//the equality with the end() iterator
- if(is_finished() && it.is_finished()) {
- return true;
- }
- return false;
+ return is_finished() && it.is_finished();
}
private:
//private and undefined copy constructor and assignment operator
@@ -1153,10 +1150,7 @@ namespace datalog {
virtual bool operator==(const row_iterator_core & it) {
//we worry about the equality operator only because of checking
//the equality with the end() iterator
- if(is_finished() && it.is_finished()) {
- return true;
- }
- return false;
+ return is_finished() && it.is_finished();
}
private:
//private and undefined copy constructor and assignment operator
diff --git a/src/muz/rel/dl_compiler.h b/src/muz/rel/dl_compiler.h
index d7bdcad34..6bc2a819f 100644
--- a/src/muz/rel/dl_compiler.h
+++ b/src/muz/rel/dl_compiler.h
@@ -148,7 +148,7 @@ namespace datalog {
void make_join(reg_idx t1, reg_idx t2, const variable_intersection & vars, reg_idx & result,
bool reuse_t1, instruction_block & acc);
void make_min(reg_idx source, reg_idx & target, const unsigned_vector & group_by_cols,
- const unsigned min_col, instruction_block & acc);
+ unsigned min_col, instruction_block & acc);
void make_join_project(reg_idx t1, reg_idx t2, const variable_intersection & vars,
const unsigned_vector & removed_cols, reg_idx & result, bool reuse_t1, instruction_block & acc);
void make_filter_interpreted_and_project(reg_idx src, app_ref & cond,
diff --git a/src/muz/rel/dl_finite_product_relation.cpp b/src/muz/rel/dl_finite_product_relation.cpp
index 0b1fbc840..ccb4584f7 100644
--- a/src/muz/rel/dl_finite_product_relation.cpp
+++ b/src/muz/rel/dl_finite_product_relation.cpp
@@ -487,7 +487,7 @@ namespace datalog {
res->init(*res_table, joined_orelations, true);
- if(m_tr_table_joined_cols.size()) {
+ if(!m_tr_table_joined_cols.empty()) {
//There were some shared variables between the table and the relation part.
//We enforce those equalities here.
if(!m_filter_tr_identities) {
diff --git a/src/muz/rel/dl_instruction.cpp b/src/muz/rel/dl_instruction.cpp
index 2b76d99f7..79508a4f6 100644
--- a/src/muz/rel/dl_instruction.cpp
+++ b/src/muz/rel/dl_instruction.cpp
@@ -41,7 +41,6 @@ namespace datalog {
execution_context::~execution_context() {
reset();
- dealloc(m_stopwatch);
}
void execution_context::reset() {
@@ -104,15 +103,15 @@ namespace datalog {
m_timelimit_ms = time_in_ms;
if (!m_stopwatch) {
m_stopwatch = alloc(stopwatch);
+ } else {
+ m_stopwatch->stop();
+ m_stopwatch->reset();
}
- m_stopwatch->stop();
- m_stopwatch->reset();
m_stopwatch->start();
}
void execution_context::reset_timelimit() {
- if (m_stopwatch) {
- m_stopwatch->stop();
- }
+ dealloc(m_stopwatch);
+ m_stopwatch = nullptr;
m_timelimit_ms = 0;
}
diff --git a/src/muz/rel/dl_instruction.h b/src/muz/rel/dl_instruction.h
index 6e0b7bfe5..918763a95 100644
--- a/src/muz/rel/dl_instruction.h
+++ b/src/muz/rel/dl_instruction.h
@@ -285,7 +285,7 @@ namespace datalog {
const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt,
const unsigned * removed_cols, reg_idx result);
static instruction * mk_min(reg_idx source, reg_idx target, const unsigned_vector & group_by_cols,
- const unsigned min_col);
+ unsigned min_col);
static instruction * mk_rename(reg_idx src, unsigned cycle_len, const unsigned * permutation_cycle,
reg_idx tgt);
static instruction * mk_filter_by_negation(reg_idx tgt, reg_idx neg_rel, unsigned col_cnt,
diff --git a/src/muz/rel/dl_sieve_relation.h b/src/muz/rel/dl_sieve_relation.h
index 5f20cecb4..2d89faa5b 100644
--- a/src/muz/rel/dl_sieve_relation.h
+++ b/src/muz/rel/dl_sieve_relation.h
@@ -170,7 +170,7 @@ namespace datalog {
SASSERT(is_inner_col(idx));
return m_sig2inner[idx];
}
- bool no_sieved_columns() const { return m_ignored_cols.size()==0; }
+ bool no_sieved_columns() const { return m_ignored_cols.empty(); }
bool no_inner_columns() const { return m_ignored_cols.size()==get_signature().size(); }
relation_base & get_inner() { return *m_inner; }
diff --git a/src/muz/rel/dl_sparse_table.cpp b/src/muz/rel/dl_sparse_table.cpp
index a51fbf3b1..db62d14d5 100644
--- a/src/muz/rel/dl_sparse_table.cpp
+++ b/src/muz/rel/dl_sparse_table.cpp
@@ -1216,7 +1216,7 @@ namespace datalog {
verbose_action _va("filter_by_negation");
- if (m_cols1.size() == 0) {
+ if (m_cols1.empty()) {
if (!neg.empty()) {
tgt.reset();
}
diff --git a/src/muz/rel/dl_sparse_table.h b/src/muz/rel/dl_sparse_table.h
index 43a967729..46f6f3932 100644
--- a/src/muz/rel/dl_sparse_table.h
+++ b/src/muz/rel/dl_sparse_table.h
@@ -72,7 +72,7 @@ namespace datalog {
~sparse_table_plugin() override;
bool can_handle_signature(const table_signature & s) override
- { return s.size()>0; }
+ { return !s.empty(); }
table_base * mk_empty(const table_signature & s) override;
sparse_table * mk_clone(const sparse_table & t);
diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp
index bad25ef71..76e7e24c6 100644
--- a/src/muz/spacer/spacer_context.cpp
+++ b/src/muz/spacer/spacer_context.cpp
@@ -3058,7 +3058,7 @@ expr_ref context::get_ground_sat_answer() const {
ground_fact_conjs.push_back(m.mk_eq(sig_arg, sig_val));
ground_arg_vals.push_back(sig_val);
}
- if (ground_fact_conjs.size () > 0) {
+ if (!ground_fact_conjs.empty()) {
expr_ref ground_fact(m);
ground_fact = mk_and(ground_fact_conjs);
m_pm.formula_o2n(ground_fact, ground_fact, i);
diff --git a/src/muz/spacer/spacer_iuc_solver.cpp b/src/muz/spacer/spacer_iuc_solver.cpp
index 27b8ee357..f28864e27 100644
--- a/src/muz/spacer/spacer_iuc_solver.cpp
+++ b/src/muz/spacer/spacer_iuc_solver.cpp
@@ -27,443 +27,426 @@ Notes:
#include "muz/spacer/spacer_iuc_proof.h"
namespace spacer {
-void iuc_solver::push ()
-{
- m_defs.push_back (def_manager (*this));
- m_solver.push ();
-}
-
-void iuc_solver::pop (unsigned n)
-{
- m_solver.pop (n);
- unsigned lvl = m_defs.size ();
- SASSERT (n <= lvl);
- unsigned new_lvl = lvl-n;
- while (m_defs.size() > new_lvl) {
- m_num_proxies -= m_defs.back ().m_defs.size ();
- m_defs.pop_back ();
+ void iuc_solver::push () {
+ m_defs.push_back (def_manager (*this));
+ m_solver.push ();
}
-}
-
-app* iuc_solver::fresh_proxy ()
-{
- if (m_num_proxies == m_proxies.size()) {
- std::stringstream name;
- name << "spacer_proxy!" << m_proxies.size ();
- app_ref res(m);
- res = m.mk_const (symbol (name.str ().c_str ()),
- m.mk_bool_sort ());
- m_proxies.push_back (res);
-
- // -- add the new proxy to proxy eliminator
- proof_ref pr(m);
- pr = m.mk_asserted (m.mk_true ());
- m_elim_proxies_sub.insert (res, m.mk_true (), pr);
+ void iuc_solver::pop (unsigned n) {
+ m_solver.pop (n);
+ unsigned lvl = m_defs.size ();
+ SASSERT (n <= lvl);
+ unsigned new_lvl = lvl-n;
+ while (m_defs.size() > new_lvl) {
+ m_num_proxies -= m_defs.back ().m_defs.size ();
+ m_defs.pop_back ();
+ }
}
- return m_proxies.get (m_num_proxies++);
-}
-app* iuc_solver::mk_proxy (expr *v)
-{
- {
+ app* iuc_solver::fresh_proxy () {
+ if (m_num_proxies == m_proxies.size()) {
+ std::stringstream name;
+ name << "spacer_proxy!" << m_proxies.size ();
+ app_ref res(m);
+ res = m.mk_const (symbol (name.str ().c_str ()),
+ m.mk_bool_sort ());
+ m_proxies.push_back (res);
+
+ // -- add the new proxy to proxy eliminator
+ proof_ref pr(m);
+ pr = m.mk_asserted (m.mk_true ());
+ m_elim_proxies_sub.insert (res, m.mk_true (), pr);
+
+ }
+ return m_proxies.get (m_num_proxies++);
+ }
+
+ app* iuc_solver::mk_proxy (expr *v) {
expr *e = v;
m.is_not (v, e);
- if (is_uninterp_const(e)) { return to_app(v); }
+ if (is_uninterp_const(e)) {
+ return to_app(v);
+ }
+
+ def_manager &def = !m_defs.empty() ? m_defs.back () : m_base_defs;
+ return def.mk_proxy (v);
}
- def_manager &def = m_defs.size () > 0 ? m_defs.back () : m_base_defs;
- return def.mk_proxy (v);
-}
-
-bool iuc_solver::mk_proxies (expr_ref_vector &v, unsigned from)
-{
- bool dirty = false;
- for (unsigned i = from, sz = v.size(); i < sz; ++i) {
- app *p = mk_proxy (v.get (i));
- dirty |= (v.get (i) != p);
- v[i] = p;
+ bool iuc_solver::mk_proxies (expr_ref_vector &v, unsigned from) {
+ bool dirty = false;
+ for (unsigned i = from, sz = v.size(); i < sz; ++i) {
+ app *p = mk_proxy (v.get (i));
+ dirty |= (v.get (i) != p);
+ v[i] = p;
+ }
+ return dirty;
}
- return dirty;
-}
-void iuc_solver::push_bg (expr *e)
-{
- if (m_assumptions.size () > m_first_assumption)
- { m_assumptions.shrink(m_first_assumption); }
- m_assumptions.push_back (e);
- m_first_assumption = m_assumptions.size ();
-}
-
-void iuc_solver::pop_bg (unsigned n)
-{
- if (n == 0) { return; }
-
- if (m_assumptions.size () > m_first_assumption) {
+ void iuc_solver::push_bg (expr *e) {
+ if (m_assumptions.size () > m_first_assumption) {
+ m_assumptions.shrink(m_first_assumption);
+ }
+ m_assumptions.push_back (e);
+ m_first_assumption = m_assumptions.size ();
+ }
+
+ void iuc_solver::pop_bg (unsigned n) {
+ if (n == 0) return;
+
+ if (m_assumptions.size () > m_first_assumption) {
+ m_assumptions.shrink(m_first_assumption);
+ }
+ m_first_assumption = m_first_assumption > n ? m_first_assumption - n : 0;
+ m_assumptions.shrink (m_first_assumption);
+ }
+
+ unsigned iuc_solver::get_num_bg () {
+ return m_first_assumption;
+ }
+
+ lbool iuc_solver::check_sat_core (unsigned num_assumptions, expr * const *assumptions) {
+ // -- remove any old assumptions
m_assumptions.shrink(m_first_assumption);
+
+ // -- replace theory literals in background assumptions with proxies
+ mk_proxies (m_assumptions);
+ // -- in case mk_proxies added new literals, they are all background
+ m_first_assumption = m_assumptions.size ();
+
+ m_assumptions.append (num_assumptions, assumptions);
+ m_is_proxied = mk_proxies (m_assumptions, m_first_assumption);
+
+ return set_status (m_solver.check_sat (m_assumptions));
}
- m_first_assumption = m_first_assumption > n ? m_first_assumption - n : 0;
- m_assumptions.shrink (m_first_assumption);
-}
+
+ lbool iuc_solver::check_sat_cc(const expr_ref_vector &cube,
+ vector const & clauses) {
+ if (clauses.empty())
+ return check_sat(cube.size(), cube.c_ptr());
+
+ // -- remove any old assumptions
+ m_assumptions.shrink(m_first_assumption);
+
+ // -- replace theory literals in background assumptions with proxies
+ mk_proxies(m_assumptions);
+ // -- in case mk_proxies added new literals, they are all background
+ m_first_assumption = m_assumptions.size();
+
+ m_assumptions.append(cube);
+ m_is_proxied = mk_proxies(m_assumptions, m_first_assumption);
+
+ return set_status (m_solver.check_sat_cc(m_assumptions, clauses));
+ }
+
-unsigned iuc_solver::get_num_bg () {return m_first_assumption;}
-
-lbool iuc_solver::check_sat (unsigned num_assumptions, expr * const *assumptions)
-{
- // -- remove any old assumptions
- m_assumptions.shrink(m_first_assumption);
-
- // -- replace theory literals in background assumptions with proxies
- mk_proxies (m_assumptions);
- // -- in case mk_proxies added new literals, they are all background
- m_first_assumption = m_assumptions.size ();
-
- m_assumptions.append (num_assumptions, assumptions);
- m_is_proxied = mk_proxies (m_assumptions, m_first_assumption);
-
- return set_status (m_solver.check_sat (m_assumptions));
-}
-
-lbool iuc_solver::check_sat_cc(const expr_ref_vector &cube,
- vector const & clauses) {
- if (clauses.empty())
- return check_sat(cube.size(), cube.c_ptr());
-
- // -- remove any old assumptions
- m_assumptions.shrink(m_first_assumption);
-
- // -- replace theory literals in background assumptions with proxies
- mk_proxies(m_assumptions);
- // -- in case mk_proxies added new literals, they are all background
- m_first_assumption = m_assumptions.size();
-
- m_assumptions.append(cube);
- m_is_proxied = mk_proxies(m_assumptions, m_first_assumption);
-
- return set_status (m_solver.check_sat_cc(m_assumptions, clauses));
-}
-
-
-app* iuc_solver::def_manager::mk_proxy (expr *v)
-{
- app* r;
- if (m_expr2proxy.find(v, r))
- return r;
-
- ast_manager &m = m_parent.m;
- app* proxy = m_parent.fresh_proxy ();
- app* def = m.mk_or (m.mk_not (proxy), v);
- m_defs.push_back (def);
- m_expr2proxy.insert (v, proxy);
- m_proxy2def.insert (proxy, def);
-
- m_parent.assert_expr (def);
- return proxy;
-}
-
-bool iuc_solver::def_manager::is_proxy (app *k, app_ref &def)
-{
- app *r = nullptr;
- bool found = m_proxy2def.find (k, r);
- def = r;
- return found;
-}
-
-void iuc_solver::def_manager::reset ()
-{
- m_expr2proxy.reset ();
- m_proxy2def.reset ();
- m_defs.reset ();
-}
-
-bool iuc_solver::def_manager::is_proxy_def (expr *v)
-{
- // XXX This might not be the most robust way to check
- return m_defs.contains (v);
-}
-
-bool iuc_solver::is_proxy(expr *e, app_ref &def)
-{
- if (!is_uninterp_const(e))
- return false;
-
- app* a = to_app (e);
-
- for (int i = m_defs.size (); i-- > 0; )
- if (m_defs[i].is_proxy (a, def))
- return true;
-
- return m_base_defs.is_proxy (a, def);
-}
-
-void iuc_solver::collect_statistics (statistics &st) const
-{
- m_solver.collect_statistics (st);
- st.update ("time.iuc_solver.get_iuc", m_iuc_sw.get_seconds());
- st.update ("time.iuc_solver.get_iuc.hyp_reduce1", m_hyp_reduce1_sw.get_seconds());
- st.update ("time.iuc_solver.get_iuc.hyp_reduce2", m_hyp_reduce2_sw.get_seconds());
- st.update ("time.iuc_solver.get_iuc.learn_core", m_learn_core_sw.get_seconds());
-
- st.update("iuc_solver.num_proxies", m_proxies.size());
-}
-
-void iuc_solver::reset_statistics ()
-{
- m_iuc_sw.reset();
- m_hyp_reduce1_sw.reset();
- m_hyp_reduce2_sw.reset();
- m_learn_core_sw.reset();
-}
-
-void iuc_solver::get_unsat_core (expr_ref_vector &core) {
- m_solver.get_unsat_core (core);
- undo_proxies_in_core (core);
-}
-
-void iuc_solver::undo_proxies_in_core (expr_ref_vector &r)
-{
- app_ref e(m);
- expr_fast_mark1 bg;
- for (unsigned i = 0; i < m_first_assumption; ++i) {
- bg.mark(m_assumptions.get(i));
+ app* iuc_solver::def_manager::mk_proxy (expr *v) {
+ app* r;
+ if (m_expr2proxy.find(v, r))
+ return r;
+
+ ast_manager &m = m_parent.m;
+ app* proxy = m_parent.fresh_proxy ();
+ app* def = m.mk_or (m.mk_not (proxy), v);
+ m_defs.push_back (def);
+ m_expr2proxy.insert (v, proxy);
+ m_proxy2def.insert (proxy, def);
+
+ m_parent.assert_expr (def);
+ return proxy;
}
- // expand proxies
- unsigned j = 0;
- for (expr* rr : r) {
- // skip background assumptions
- if (bg.is_marked(rr))
- continue;
+ bool iuc_solver::def_manager::is_proxy (app *k, app_ref &def) {
+ app *r = nullptr;
+ bool found = m_proxy2def.find (k, r);
+ def = r;
+ return found;
+ }
+
+ void iuc_solver::def_manager::reset () {
+ m_expr2proxy.reset ();
+ m_proxy2def.reset ();
+ m_defs.reset ();
+ }
- // -- undo proxies, but only if they were introduced in check_sat
- if (m_is_proxied && is_proxy(rr, e)) {
- SASSERT (m.is_or (e));
- r[j++] = e->get_arg (1);
+ bool iuc_solver::def_manager::is_proxy_def (expr *v) {
+ // XXX This might not be the most robust way to check
+ return m_defs.contains (v);
+ }
+
+ bool iuc_solver::is_proxy(expr *e, app_ref &def) {
+ if (!is_uninterp_const(e))
+ return false;
+
+ app* a = to_app (e);
+
+ for (int i = m_defs.size (); i-- > 0; )
+ if (m_defs[i].is_proxy (a, def))
+ return true;
+
+ return m_base_defs.is_proxy (a, def);
+ }
+
+ void iuc_solver::collect_statistics (statistics &st) const {
+ m_solver.collect_statistics (st);
+ st.update ("time.iuc_solver.get_iuc", m_iuc_sw.get_seconds());
+ st.update ("time.iuc_solver.get_iuc.hyp_reduce1", m_hyp_reduce1_sw.get_seconds());
+ st.update ("time.iuc_solver.get_iuc.hyp_reduce2", m_hyp_reduce2_sw.get_seconds());
+ st.update ("time.iuc_solver.get_iuc.learn_core", m_learn_core_sw.get_seconds());
+
+ st.update("iuc_solver.num_proxies", m_proxies.size());
+ }
+
+ void iuc_solver::reset_statistics () {
+ m_iuc_sw.reset();
+ m_hyp_reduce1_sw.reset();
+ m_hyp_reduce2_sw.reset();
+ m_learn_core_sw.reset();
+ }
+
+ void iuc_solver::get_unsat_core (expr_ref_vector &core) {
+ m_solver.get_unsat_core (core);
+ undo_proxies_in_core (core);
+ }
+
+ void iuc_solver::undo_proxies_in_core (expr_ref_vector &r) {
+ app_ref e(m);
+ expr_fast_mark1 bg;
+ for (unsigned i = 0; i < m_first_assumption; ++i) {
+ bg.mark(m_assumptions.get(i));
+ }
+
+ // expand proxies
+ unsigned j = 0;
+ for (expr* rr : r) {
+ // skip background assumptions
+ if (bg.is_marked(rr))
+ continue;
+
+ // -- undo proxies, but only if they were introduced in check_sat
+ if (m_is_proxied && is_proxy(rr, e)) {
+ SASSERT (m.is_or (e));
+ r[j++] = e->get_arg (1);
+ }
+ else {
+ r[j++] = rr;
+ }
+ }
+ r.shrink (j);
+ }
+
+ void iuc_solver::undo_proxies (expr_ref_vector &r) {
+ app_ref e(m);
+ // expand proxies
+ for (unsigned i = 0, sz = r.size (); i < sz; ++i)
+ if (is_proxy(r.get(i), e)) {
+ SASSERT (m.is_or (e));
+ r[i] = e->get_arg (1);
+ }
+ }
+
+ void iuc_solver::elim_proxies (expr_ref_vector &v) {
+ expr_ref f = mk_and (v);
+ scoped_ptr rep = mk_expr_simp_replacer (m);
+ rep->set_substitution (&m_elim_proxies_sub);
+ (*rep)(f);
+ v.reset();
+ flatten_and(f, v);
+ }
+
+ void iuc_solver::get_iuc(expr_ref_vector &core) {
+ scoped_watch _t_ (m_iuc_sw);
+
+ typedef obj_hashtable expr_set;
+ expr_set core_lits;
+ for (unsigned i = m_first_assumption, sz = m_assumptions.size(); i < sz; ++i) {
+ expr *a = m_assumptions.get (i);
+ app_ref def(m);
+ if (is_proxy(a, def)) { core_lits.insert(def.get()); }
+ core_lits.insert (a);
+ }
+
+ if (m_iuc == 0) {
+ // ORIGINAL PDR CODE
+ // AG: deprecated
+ proof_ref pr(m);
+ pr = get_proof ();
+
+ farkas_learner learner_old;
+ learner_old.set_split_literals(m_split_literals);
+
+ learner_old.get_lemmas (pr, core_lits, core);
+ elim_proxies (core);
+ simplify_bounds (core); // XXX potentially redundant
}
else {
- r[j++] = rr;
- }
- }
- r.shrink (j);
-}
-
-void iuc_solver::undo_proxies (expr_ref_vector &r)
-{
- app_ref e(m);
- // expand proxies
- for (unsigned i = 0, sz = r.size (); i < sz; ++i)
- if (is_proxy(r.get(i), e)) {
- SASSERT (m.is_or (e));
- r[i] = e->get_arg (1);
- }
-}
-
-void iuc_solver::elim_proxies (expr_ref_vector &v)
-{
- expr_ref f = mk_and (v);
- scoped_ptr rep = mk_expr_simp_replacer (m);
- rep->set_substitution (&m_elim_proxies_sub);
- (*rep)(f);
- v.reset();
- flatten_and(f, v);
-}
-
-void iuc_solver::get_iuc(expr_ref_vector &core)
-{
- scoped_watch _t_ (m_iuc_sw);
-
- typedef obj_hashtable expr_set;
- expr_set core_lits;
- for (unsigned i = m_first_assumption, sz = m_assumptions.size(); i < sz; ++i) {
- expr *a = m_assumptions.get (i);
- app_ref def(m);
- if (is_proxy(a, def)) { core_lits.insert(def.get()); }
- core_lits.insert (a);
- }
-
- if (m_iuc == 0) {
- // ORIGINAL PDR CODE
- // AG: deprecated
- proof_ref pr(m);
- pr = get_proof ();
-
- farkas_learner learner_old;
- learner_old.set_split_literals(m_split_literals);
-
- learner_old.get_lemmas (pr, core_lits, core);
- elim_proxies (core);
- simplify_bounds (core); // XXX potentially redundant
- }
- else {
- // NEW IUC
- proof_ref res(get_proof(), m);
-
- // -- old hypothesis reducer while the new one is broken
- if (m_old_hyp_reducer) {
- scoped_watch _t_ (m_hyp_reduce1_sw);
- // AG: deprecated
- // pre-process proof in order to get a proof which is
- // better suited for unsat-core-extraction
- if (m_print_farkas_stats) {
- iuc_proof iuc_before(m, res.get(), core_lits);
- verbose_stream() << "\nOld reduce_hypotheses. Before:";
- iuc_before.dump_farkas_stats();
+ // NEW IUC
+ proof_ref res(get_proof(), m);
+
+ // -- old hypothesis reducer while the new one is broken
+ if (m_old_hyp_reducer) {
+ scoped_watch _t_ (m_hyp_reduce1_sw);
+ // AG: deprecated
+ // pre-process proof in order to get a proof which is
+ // better suited for unsat-core-extraction
+ if (m_print_farkas_stats) {
+ iuc_proof iuc_before(m, res.get(), core_lits);
+ verbose_stream() << "\nOld reduce_hypotheses. Before:";
+ iuc_before.dump_farkas_stats();
+ }
+
+ proof_utils::reduce_hypotheses(res);
+ proof_utils::permute_unit_resolution(res);
+
+ if (m_print_farkas_stats) {
+ iuc_proof iuc_after(m, res.get(), core_lits);
+ verbose_stream() << "Old reduce_hypothesis. After:";
+ iuc_after.dump_farkas_stats();
+ }
}
-
- proof_utils::reduce_hypotheses(res);
- proof_utils::permute_unit_resolution(res);
-
- if (m_print_farkas_stats) {
- iuc_proof iuc_after(m, res.get(), core_lits);
- verbose_stream() << "Old reduce_hypothesis. After:";
- iuc_after.dump_farkas_stats();
- }
- }
- // -- new hypothesis reducer
- else
- {
+ // -- new hypothesis reducer
+ else
+ {
#if 0
- static unsigned bcnt = 0;
+ static unsigned bcnt = 0;
+ {
+ bcnt++;
+ TRACE("spacer", tout << "Dumping pf bcnt: " << bcnt << "\n";);
+ if (bcnt == 123) {
+ std::ofstream ofs;
+ ofs.open("/tmp/bpf_" + std::to_string(bcnt) + ".dot");
+ iuc_proof iuc_pf_before(m, res.get(), core_lits);
+ iuc_pf_before.display_dot(ofs);
+ ofs.close();
+
+ proof_checker pc(m);
+ expr_ref_vector side(m);
+ ENSURE(pc.check(res, side));
+ }
+ }
+#endif
+ scoped_watch _t_ (m_hyp_reduce2_sw);
+
+ // pre-process proof for better iuc extraction
+ if (m_print_farkas_stats) {
+ iuc_proof iuc_before(m, res.get(), core_lits);
+ verbose_stream() << "\n New hypothesis_reducer. Before:";
+ iuc_before.dump_farkas_stats();
+ }
+
+ proof_ref pr1(m);
+ {
+ scoped_watch _t_ (m_hyp_reduce1_sw);
+ theory_axiom_reducer ta_reducer(m);
+ pr1 = ta_reducer.reduce (res.get());
+ }
+
+ proof_ref pr2(m);
+ {
+ scoped_watch _t_ (m_hyp_reduce2_sw);
+ hypothesis_reducer hyp_reducer(m);
+ pr2 = hyp_reducer.reduce(pr1);
+ }
+
+ res = pr2;
+
+ if (m_print_farkas_stats) {
+ iuc_proof iuc_after(m, res.get(), core_lits);
+ verbose_stream() << "New hypothesis_reducer. After:";
+ iuc_after.dump_farkas_stats();
+ }
+ }
+
+ iuc_proof iuc_pf(m, res, core_lits);
+
+#if 0
+ static unsigned cnt = 0;
{
- bcnt++;
- TRACE("spacer", tout << "Dumping pf bcnt: " << bcnt << "\n";);
- if (bcnt == 123) {
+ cnt++;
+ TRACE("spacer", tout << "Dumping pf cnt: " << cnt << "\n";);
+ if (cnt == 123) {
std::ofstream ofs;
- ofs.open("/tmp/bpf_" + std::to_string(bcnt) + ".dot");
- iuc_proof iuc_pf_before(m, res.get(), core_lits);
- iuc_pf_before.display_dot(ofs);
+ ofs.open("/tmp/pf_" + std::to_string(cnt) + ".dot");
+ iuc_pf.display_dot(ofs);
ofs.close();
-
proof_checker pc(m);
expr_ref_vector side(m);
ENSURE(pc.check(res, side));
}
}
#endif
- scoped_watch _t_ (m_hyp_reduce2_sw);
-
- // pre-process proof for better iuc extraction
- if (m_print_farkas_stats) {
- iuc_proof iuc_before(m, res.get(), core_lits);
- verbose_stream() << "\n New hypothesis_reducer. Before:";
- iuc_before.dump_farkas_stats();
+ unsat_core_learner learner(m, iuc_pf);
+
+ unsat_core_plugin* plugin;
+ // -- register iuc plugins
+ switch (m_iuc_arith) {
+ case 0:
+ case 1:
+ plugin =
+ alloc(unsat_core_plugin_farkas_lemma,
+ learner, m_split_literals,
+ (m_iuc_arith == 1) /* use constants from A */);
+ learner.register_plugin(plugin);
+ break;
+ case 2:
+ SASSERT(false && "Broken");
+ plugin = alloc(unsat_core_plugin_farkas_lemma_optimized, learner, m);
+ learner.register_plugin(plugin);
+ break;
+ case 3:
+ plugin = alloc(unsat_core_plugin_farkas_lemma_bounded, learner, m);
+ learner.register_plugin(plugin);
+ break;
+ default:
+ UNREACHABLE();
+ break;
}
-
- proof_ref pr1(m);
+
+ switch (m_iuc) {
+ case 1:
+ // -- iuc based on the lowest cut in the proof
+ plugin = alloc(unsat_core_plugin_lemma, learner);
+ learner.register_plugin(plugin);
+ break;
+ case 2:
+ // -- iuc based on the smallest cut in the proof
+ plugin = alloc(unsat_core_plugin_min_cut, learner, m);
+ learner.register_plugin(plugin);
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+
{
- scoped_watch _t_ (m_hyp_reduce1_sw);
- theory_axiom_reducer ta_reducer(m);
- pr1 = ta_reducer.reduce (res.get());
- }
-
- proof_ref pr2(m);
- {
- scoped_watch _t_ (m_hyp_reduce2_sw);
- hypothesis_reducer hyp_reducer(m);
- pr2 = hyp_reducer.reduce(pr1);
- }
-
- res = pr2;
-
- if (m_print_farkas_stats) {
- iuc_proof iuc_after(m, res.get(), core_lits);
- verbose_stream() << "New hypothesis_reducer. After:";
- iuc_after.dump_farkas_stats();
+ scoped_watch _t_ (m_learn_core_sw);
+ // compute interpolating unsat core
+ learner.compute_unsat_core(core);
}
+
+ elim_proxies (core);
+ // AG: this should be taken care of by minimizing the iuc cut
+ simplify_bounds (core);
}
-
- iuc_proof iuc_pf(m, res, core_lits);
-
-#if 0
- static unsigned cnt = 0;
- {
- cnt++;
- TRACE("spacer", tout << "Dumping pf cnt: " << cnt << "\n";);
- if (cnt == 123) {
- std::ofstream ofs;
- ofs.open("/tmp/pf_" + std::to_string(cnt) + ".dot");
- iuc_pf.display_dot(ofs);
- ofs.close();
- proof_checker pc(m);
- expr_ref_vector side(m);
- ENSURE(pc.check(res, side));
- }
- }
-#endif
- unsat_core_learner learner(m, iuc_pf);
-
- unsat_core_plugin* plugin;
- // -- register iuc plugins
- switch (m_iuc_arith) {
- case 0:
- case 1:
- plugin =
- alloc(unsat_core_plugin_farkas_lemma,
- learner, m_split_literals,
- (m_iuc_arith == 1) /* use constants from A */);
- learner.register_plugin(plugin);
- break;
- case 2:
- SASSERT(false && "Broken");
- plugin = alloc(unsat_core_plugin_farkas_lemma_optimized, learner, m);
- learner.register_plugin(plugin);
- break;
- case 3:
- plugin = alloc(unsat_core_plugin_farkas_lemma_bounded, learner, m);
- learner.register_plugin(plugin);
- break;
- default:
- UNREACHABLE();
- break;
- }
-
- switch (m_iuc) {
- case 1:
- // -- iuc based on the lowest cut in the proof
- plugin = alloc(unsat_core_plugin_lemma, learner);
- learner.register_plugin(plugin);
- break;
- case 2:
- // -- iuc based on the smallest cut in the proof
- plugin = alloc(unsat_core_plugin_min_cut, learner, m);
- learner.register_plugin(plugin);
- break;
- default:
- UNREACHABLE();
- break;
- }
-
- {
- scoped_watch _t_ (m_learn_core_sw);
- // compute interpolating unsat core
- learner.compute_unsat_core(core);
- }
-
- elim_proxies (core);
- // AG: this should be taken care of by minimizing the iuc cut
- simplify_bounds (core);
+
+ IF_VERBOSE(2,
+ verbose_stream () << "IUC Core:\n" << core << "\n";);
}
-
- IF_VERBOSE(2,
- verbose_stream () << "IUC Core:\n" << core << "\n";);
-}
-
-void iuc_solver::refresh ()
-{
- // only refresh in non-pushed state
- SASSERT (m_defs.empty());
- expr_ref_vector assertions (m);
- for (unsigned i = 0, e = m_solver.get_num_assertions(); i < e; ++i) {
- expr* a = m_solver.get_assertion (i);
- if (!m_base_defs.is_proxy_def(a)) { assertions.push_back(a); }
-
+
+ void iuc_solver::refresh () {
+ // only refresh in non-pushed state
+ SASSERT (m_defs.empty());
+ expr_ref_vector assertions (m);
+ for (unsigned i = 0, e = m_solver.get_num_assertions(); i < e; ++i) {
+ expr* a = m_solver.get_assertion (i);
+ if (!m_base_defs.is_proxy_def(a)) { assertions.push_back(a); }
+
+ }
+ m_base_defs.reset ();
+ NOT_IMPLEMENTED_YET ();
+ // solver interface does not have a reset method. need to introduce it somewhere.
+ // m_solver.reset ();
+ for (unsigned i = 0, e = assertions.size (); i < e; ++i)
+ { m_solver.assert_expr(assertions.get(i)); }
}
- m_base_defs.reset ();
- NOT_IMPLEMENTED_YET ();
- // solver interface does not have a reset method. need to introduce it somewhere.
- // m_solver.reset ();
- for (unsigned i = 0, e = assertions.size (); i < e; ++i)
- { m_solver.assert_expr(assertions.get(i)); }
-}
-
+
}
diff --git a/src/muz/spacer/spacer_iuc_solver.h b/src/muz/spacer/spacer_iuc_solver.h
index c0a0072ed..9b50b4c4e 100644
--- a/src/muz/spacer/spacer_iuc_solver.h
+++ b/src/muz/spacer/spacer_iuc_solver.h
@@ -122,12 +122,15 @@ public:
void assert_expr_core(expr *t) override { m_solver.assert_expr(t); }
void assert_expr_core2(expr *t, expr *a) override { NOT_IMPLEMENTED_YET(); }
expr_ref_vector cube(expr_ref_vector&, unsigned) override { return expr_ref_vector(m); }
+ void get_levels(ptr_vector const& vars, unsigned_vector& depth) override { m_solver.get_levels(vars, depth); }
+ expr_ref_vector get_trail() override { return m_solver.get_trail(); }
+ void set_activity(expr* lit, double act) override { m_solver.set_activity(lit, act); }
void push() override;
void pop(unsigned n) override;
unsigned get_scope_level() const override { return m_solver.get_scope_level(); }
- lbool check_sat(unsigned num_assumptions, expr * const *assumptions) override;
+ lbool check_sat_core(unsigned num_assumptions, expr * const *assumptions) override;
lbool check_sat_cc(const expr_ref_vector &cube, vector const & clauses) override;
void set_progress_callback(progress_callback *callback) override {
m_solver.set_progress_callback(callback);
diff --git a/src/muz/transforms/dl_mk_array_instantiation.cpp b/src/muz/transforms/dl_mk_array_instantiation.cpp
index 626109528..a94383453 100644
--- a/src/muz/transforms/dl_mk_array_instantiation.cpp
+++ b/src/muz/transforms/dl_mk_array_instantiation.cpp
@@ -253,7 +253,7 @@ namespace datalog {
all_selects.push_back(rewrite_select(array, select_ops[i]));
}
}
- if(all_selects.size()==0)
+ if(all_selects.empty())
{
expr_ref_vector dummy_args(m);
dummy_args.push_back(array);
diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp
index f430f3a0c..6ea764a0a 100644
--- a/src/nlsat/nlsat_solver.cpp
+++ b/src/nlsat/nlsat_solver.cpp
@@ -190,7 +190,7 @@ namespace nlsat {
}
~imp() {
- reset();
+ clear();
}
void mk_true_bvar() {
@@ -230,6 +230,14 @@ namespace nlsat {
m_assignment.reset();
}
+ void clear() {
+ m_explain.reset();
+ m_lemma.reset();
+ m_lazy_clause.reset();
+ undo_until_size(0);
+ del_clauses();
+ del_unref_atoms();
+ }
void checkpoint() {
if (!m_rlimit.inc()) throw solver_exception(m_rlimit.get_cancel_msg());
diff --git a/src/opt/CMakeLists.txt b/src/opt/CMakeLists.txt
index dcb13c062..fb61c0c33 100644
--- a/src/opt/CMakeLists.txt
+++ b/src/opt/CMakeLists.txt
@@ -1,5 +1,6 @@
z3_add_component(opt
SOURCES
+ maxlex.cpp
maxres.cpp
maxsmt.cpp
opt_cmds.cpp
diff --git a/src/opt/maxlex.cpp b/src/opt/maxlex.cpp
new file mode 100644
index 000000000..56dbfebf5
--- /dev/null
+++ b/src/opt/maxlex.cpp
@@ -0,0 +1,198 @@
+/*++
+Copyright (c) 2019 Microsoft Corporation
+
+Module Name:
+
+ maxlex.cpp
+
+Abstract:
+
+ MaxLex solves weighted max-sat problems where weights impose lexicographic order.
+ MaxSAT is particularly easy for this class:
+ In order of highest weight, check if soft constraint can be satisfied.
+ If so, assert it, otherwise assert the negation and record whether the soft
+ constraint is true or false in the solution.
+
+Author:
+
+ Nikolaj Bjorner (nbjorner) 2019-25-1
+
+--*/
+
+#include "opt/opt_context.h"
+#include "opt/maxsmt.h"
+#include "opt/maxlex.h"
+
+namespace opt {
+
+ bool is_maxlex(weights_t & _ws) {
+ vector ws(_ws);
+ std::sort(ws.begin(), ws.end());
+ ws.reverse();
+ rational sum(0);
+ for (rational const& w : ws) {
+ sum += w;
+ }
+ for (rational const& w : ws) {
+ if (sum > w + w) return false;
+ sum -= w;
+ }
+ return true;
+ }
+
+ class maxlex : public maxsmt_solver_base {
+
+ struct cmp_soft {
+ bool operator()(soft const& s1, soft const& s2) const {
+ return s1.weight > s2.weight;
+ }
+ };
+
+ ast_manager& m;
+ maxsat_context& m_c;
+
+ void update_assignment() {
+ model_ref mdl;
+ s().get_model(mdl);
+ if (mdl) {
+ m_model = mdl;
+ m_c.model_updated(mdl.get());
+ update_assignment(mdl);
+ }
+ }
+
+ void assert_value(soft& soft) {
+ switch (soft.value) {
+ case l_true:
+ s().assert_expr(soft.s);
+ break;
+ case l_false:
+ s().assert_expr(expr_ref(m.mk_not(soft.s), m));
+ break;
+ default:
+ break;
+ }
+ }
+
+ void update_assignment(model_ref & mdl) {
+ bool first_undef = true, second_undef = false;
+ for (auto & soft : m_soft) {
+ if (first_undef && soft.value != l_undef) {
+ continue;
+ }
+ first_undef = false;
+ if (soft.value != l_false) {
+ lbool v = mdl->is_true(soft.s) ? l_true : l_undef;;
+ if (v == l_undef) {
+ second_undef = true;
+ }
+ if (second_undef) {
+ soft.set_value(v);
+ }
+ else {
+ SASSERT(v == l_true);
+ soft.set_value(v);
+ assert_value(soft);
+ }
+ }
+ }
+ update_bounds();
+ }
+
+ void update_bounds() {
+ m_lower.reset();
+ m_upper.reset();
+ for (auto & soft : m_soft) {
+ switch (soft.value) {
+ case l_undef:
+ m_upper += soft.weight;
+ break;
+ case l_true:
+ break;
+ case l_false:
+ m_lower += soft.weight;
+ m_upper += soft.weight;
+ break;
+ }
+ }
+ trace_bounds("maxlex");
+ }
+
+ void init() {
+ for (auto & soft : m_soft) {
+ soft.set_value(l_undef);
+ }
+ model_ref mdl;
+ s().get_model(mdl);
+ if (mdl) update_assignment(mdl);
+ }
+
+ //
+ // include soft constraints that are known to be assignable to true after failed literal.
+ //
+ lbool maxlexN() {
+ unsigned sz = m_soft.size();
+ for (unsigned i = 0; i < sz; ++i) {
+ auto& soft = m_soft[i];
+ if (soft.value != l_undef) {
+ continue;
+ }
+ expr_ref_vector asms(m);
+ asms.push_back(soft.s);
+ lbool is_sat = s().check_sat(asms);
+ switch (is_sat) {
+ case l_true:
+ update_assignment();
+ SASSERT(soft.value == l_true);
+ break;
+ case l_false:
+ soft.set_value(l_false);
+ assert_value(soft);
+ for (unsigned j = i + 1; j < sz; ++j) {
+ auto& soft2 = m_soft[j];
+ if (soft2.value != l_true) {
+ break;
+ }
+ assert_value(soft2);
+ }
+ update_bounds();
+ break;
+ case l_undef:
+ return l_undef;
+ }
+ }
+ return l_true;
+ }
+
+ public:
+
+ maxlex(maxsat_context& c, unsigned id, weights_t & ws, expr_ref_vector const& s):
+ maxsmt_solver_base(c, ws, s),
+ m(c.get_manager()),
+ m_c(c) {
+ // ensure that soft constraints are sorted with largest soft constraints first.
+ cmp_soft cmp;
+ std::sort(m_soft.begin(), m_soft.end(), cmp);
+ }
+
+ lbool operator()() override {
+ init();
+ return maxlexN();
+ }
+
+
+ void commit_assignment() override {
+ for (auto & soft : m_soft) {
+ if (soft.value == l_undef) {
+ return;
+ }
+ assert_value(soft);
+ }
+ }
+ };
+
+ maxsmt_solver_base* mk_maxlex(maxsat_context& c, unsigned id, weights_t & ws, expr_ref_vector const& soft) {
+ return alloc(maxlex, c, id, ws, soft);
+ }
+
+}
diff --git a/src/opt/maxlex.h b/src/opt/maxlex.h
new file mode 100644
index 000000000..55aab76d3
--- /dev/null
+++ b/src/opt/maxlex.h
@@ -0,0 +1,32 @@
+/*++
+Copyright (c) 2014 Microsoft Corporation
+
+Module Name:
+
+ maxlex.h
+
+Abstract:
+
+ MaxLex solves weighted max-sat problems where weights impose lexicographic order.
+
+Author:
+
+ Nikolaj Bjorner (nbjorner) 2019-25-1
+
+Notes:
+
+--*/
+
+#ifndef MAXLEX_H_
+#define MAXLEX_H_
+
+namespace opt {
+
+ bool is_maxlex(weights_t & ws);
+
+ maxsmt_solver_base* mk_maxlex(maxsat_context& c, unsigned id, weights_t & ws, expr_ref_vector const& soft);
+
+
+};
+
+#endif
diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp
index 75a42886c..25b51372e 100644
--- a/src/opt/maxres.cpp
+++ b/src/opt/maxres.cpp
@@ -177,6 +177,7 @@ public:
else {
asum = mk_fresh_bool("soft");
fml = m.mk_iff(asum, e);
+ m_defs.push_back(fml);
add(fml);
}
new_assumption(asum, w);
@@ -328,8 +329,8 @@ public:
verify_assumptions();
m_lower.reset();
for (soft& s : m_soft) {
- s.is_true = m_model->is_true(s.s);
- if (!s.is_true) {
+ s.set_value(m_model->is_true(s.s));
+ if (!s.is_true()) {
m_lower += s.weight;
}
}
@@ -374,7 +375,7 @@ public:
get_mus_model(mdl);
is_sat = minimize_core(_core);
core.append(_core.size(), _core.c_ptr());
- verify_core(core);
+ DEBUG_CODE(verify_core(core););
++m_stats.m_num_cores;
if (is_sat != l_true) {
IF_VERBOSE(100, verbose_stream() << "(opt.maxres minimization failed)\n";);
@@ -382,6 +383,7 @@ public:
}
if (core.empty()) {
IF_VERBOSE(100, verbose_stream() << "(opt.maxres core is empty)\n";);
+ TRACE("opt", tout << "empty core\n";);
cores.reset();
m_lower = m_upper;
return l_true;
@@ -516,6 +518,10 @@ public:
max_resolve(core, w);
fml = mk_not(m, mk_and(m, core.size(), core.c_ptr()));
add(fml);
+ // save small cores such that lex-combinations of maxres can reuse these cores.
+ if (core.size() <= 2) {
+ m_defs.push_back(fml);
+ }
m_lower += w;
if (m_st == s_primal_dual) {
m_lower = std::min(m_lower, m_upper);
@@ -698,8 +704,7 @@ public:
fml = m.mk_implies(d, cls);
update_model(d, cls);
add(fml);
- m_defs.push_back(fml);
-
+ m_defs.push_back(fml);
}
else {
d = cls;
@@ -733,7 +738,7 @@ public:
m_correction_set_size = correction_set_size;
}
- TRACE("opt", tout << *mdl;);
+ TRACE("opt_verbose", tout << *mdl;);
rational upper(0);
@@ -756,10 +761,10 @@ public:
m_model = mdl;
m_c.model_updated(mdl.get());
- TRACE("opt", tout << "updated upper: " << upper << "\nmodel\n" << *m_model;);
+ TRACE("opt", tout << "updated upper: " << upper << "\n";);
for (soft& s : m_soft) {
- s.is_true = m_model->is_true(s.s);
+ s.set_value(m_model->is_true(s.s));
}
verify_assignment();
@@ -833,22 +838,29 @@ public:
void commit_assignment() override {
if (m_found_feasible_optimum) {
- TRACE("opt", tout << "Committing feasible solution\n" << m_defs << " " << m_asms;);
add(m_defs);
add(m_asms);
+ TRACE("opt", tout << "Committing feasible solution\ndefs:" << m_defs << "\nasms:" << m_asms << "\n";);
+
}
// else: there is only a single assignment to these soft constraints.
}
void verify_core(exprs const& core) {
return;
- IF_VERBOSE(3, verbose_stream() << "verify core " << s().check_sat(core.size(), core.c_ptr()) << "\n";);
+ IF_VERBOSE(1, verbose_stream() << "verify core " << s().check_sat(core.size(), core.c_ptr()) << "\n";);
ref _solver = mk_smt_solver(m, m_params, symbol());
_solver->assert_expr(s().get_assertions());
_solver->assert_expr(core);
lbool is_sat = _solver->check_sat(0, nullptr);
- IF_VERBOSE(0, verbose_stream() << "core status (l_false:) " << is_sat << "\n");
- VERIFY(is_sat == l_false);
+ IF_VERBOSE(0, verbose_stream() << "core status (l_false:) " << is_sat << " core size " << core.size() << "\n");
+ CTRACE("opt", is_sat != l_false,
+ for (expr* c : core) tout << "core: " << mk_pp(c, m) << "\n";
+ _solver->display(tout);
+ tout << "other solver\n";
+ s().display(tout);
+ );
+ VERIFY(is_sat == l_false || m.canceled());
}
void verify_assumptions() {
@@ -870,7 +882,7 @@ public:
expr_ref n(m);
for (soft& s : m_soft) {
n = s.s;
- if (!s.is_true) {
+ if (!s.is_true()) {
n = mk_not(m, n);
}
_solver->assert_expr(n);
diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp
index dc4451b6c..5441c4def 100644
--- a/src/opt/maxsmt.cpp
+++ b/src/opt/maxsmt.cpp
@@ -18,17 +18,18 @@ Notes:
--*/
#include
+#include "util/uint_set.h"
+#include "ast/ast_pp.h"
+#include "ast/ast_util.h"
+#include "ast/pb_decl_plugin.h"
#include "opt/maxsmt.h"
#include "opt/maxres.h"
+#include "opt/maxlex.h"
#include "opt/wmax.h"
#include "opt/opt_params.hpp"
-#include "ast/ast_pp.h"
-#include "util/uint_set.h"
#include "opt/opt_context.h"
#include "smt/theory_wmaxsat.h"
#include "smt/theory_pb.h"
-#include "ast/ast_util.h"
-#include "ast/pb_decl_plugin.h"
namespace opt {
@@ -61,7 +62,7 @@ namespace opt {
rational k(0), cost(0);
vector weights;
for (soft const& s : m_soft) {
- if (s.is_true) {
+ if (s.is_true()) {
k += s.weight;
}
else {
@@ -80,13 +81,13 @@ namespace opt {
m_lower.reset();
m_upper.reset();
for (soft& s : m_soft) {
- s.is_true = m.is_true(s.s);
- if (!s.is_true) m_upper += s.weight;
+ s.set_value(m.is_true(s.s));
+ if (!s.is_true()) m_upper += s.weight;
}
TRACE("opt",
tout << "upper: " << m_upper << " assignments: ";
- for (soft& s : m_soft) tout << (s.is_true?"T":"F");
+ for (soft& s : m_soft) tout << (s.is_true()?"T":"F");
tout << "\n";);
return true;
}
@@ -231,10 +232,14 @@ namespace opt {
lbool maxsmt::operator()() {
lbool is_sat = l_undef;
m_msolver = nullptr;
+ opt_params optp(m_params);
symbol const& maxsat_engine = m_c.maxsat_engine();
IF_VERBOSE(1, verbose_stream() << "(maxsmt)\n";);
TRACE("opt_verbose", s().display(tout << "maxsmt\n") << "\n";);
- if (m_soft_constraints.empty() || maxsat_engine == symbol("maxres") || maxsat_engine == symbol::null) {
+ if (optp.maxlex_enable() && is_maxlex(m_weights)) {
+ m_msolver = mk_maxlex(m_c, m_index, m_weights, m_soft_constraints);
+ }
+ else if (m_soft_constraints.empty() || maxsat_engine == symbol("maxres") || maxsat_engine == symbol::null) {
m_msolver = mk_maxres(m_c, m_index, m_weights, m_soft_constraints);
}
else if (maxsat_engine == symbol("pd-maxres")) {
diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h
index b61d876b3..796510ce2 100644
--- a/src/opt/maxsmt.h
+++ b/src/opt/maxsmt.h
@@ -59,10 +59,13 @@ namespace opt {
struct soft {
expr_ref s;
rational weight;
- bool is_true;
- soft(expr_ref const& s, rational const& w, bool t): s(s), weight(w), is_true(t) {}
- soft(soft const& other):s(other.s), weight(other.weight), is_true(other.is_true) {}
- soft& operator=(soft const& other) { s = other.s; weight = other.weight; is_true = other.is_true; return *this; }
+ lbool value;
+ void set_value(bool t) { value = t?l_true:l_undef; }
+ void set_value(lbool t) { value = t; }
+ bool is_true() const { return value == l_true; }
+ soft(expr_ref const& s, rational const& w, bool t): s(s), weight(w), value(t?l_true:l_undef) {}
+ soft(soft const& other):s(other.s), weight(other.weight), value(other.value) {}
+ soft& operator=(soft const& other) { s = other.s; weight = other.weight; value = other.value; return *this; }
};
ast_manager& m;
maxsat_context& m_c;
@@ -84,7 +87,7 @@ namespace opt {
~maxsmt_solver_base() override {}
rational get_lower() const override { return m_lower; }
rational get_upper() const override { return m_upper; }
- bool get_assignment(unsigned index) const override { return m_soft[index].is_true; }
+ bool get_assignment(unsigned index) const override { return m_soft[index].is_true(); }
void collect_statistics(statistics& st) const override { }
void get_model(model_ref& mdl, svector& labels) override { mdl = m_model.get(); labels = m_labels;}
virtual void commit_assignment();
diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp
index a6f3d8152..d57cee2a4 100644
--- a/src/opt/opt_context.cpp
+++ b/src/opt/opt_context.cpp
@@ -48,6 +48,7 @@ Notes:
namespace opt {
void context::scoped_state::push() {
+ m_asms_lim.push_back(m_asms.size());
m_hard_lim.push_back(m_hard.size());
m_objectives_lim.push_back(m_objectives.size());
m_objectives_term_trail_lim.push_back(m_objectives_term_trail.size());
@@ -55,6 +56,7 @@ namespace opt {
void context::scoped_state::pop() {
m_hard.resize(m_hard_lim.back());
+ m_asms.resize(m_asms_lim.back());
unsigned k = m_objectives_term_trail_lim.back();
while (m_objectives_term_trail.size() > k) {
unsigned idx = m_objectives_term_trail.back();
@@ -73,6 +75,7 @@ namespace opt {
}
m_objectives_lim.pop_back();
m_hard_lim.pop_back();
+ m_asms_lim.pop_back();
}
void context::scoped_state::add(expr* hard) {
@@ -125,7 +128,7 @@ namespace opt {
m_solver(nullptr),
m_pareto1(false),
m_box_index(UINT_MAX),
- m_optsmt(m),
+ m_optsmt(m, *this),
m_scoped_state(m),
m_fm(alloc(generic_model_converter, m, "opt")),
m_model_fixed(),
@@ -188,6 +191,12 @@ namespace opt {
clear_state();
}
+ void context::add_hard_constraint(expr* f, expr* t) {
+ m_scoped_state.m_asms.push_back(t);
+ m_scoped_state.add(m.mk_implies(t, f));
+ clear_state();
+ }
+
void context::get_hard_constraints(expr_ref_vector& hard) {
hard.append(m_scoped_state.m_hard);
}
@@ -253,7 +262,7 @@ namespace opt {
m_hard_constraints.append(s.m_hard);
}
- lbool context::optimize(expr_ref_vector const& asms) {
+ lbool context::optimize(expr_ref_vector const& _asms) {
if (m_pareto) {
return execute_pareto();
}
@@ -263,6 +272,8 @@ namespace opt {
clear_state();
init_solver();
import_scoped_state();
+ expr_ref_vector asms(_asms);
+ asms.append(m_scoped_state.m_asms);
normalize(asms);
if (m_hard_constraints.size() == 1 && m.is_false(m_hard_constraints.get(0))) {
return l_false;
@@ -300,6 +311,7 @@ namespace opt {
}
return is_sat;
}
+ s.assert_expr(asms);
IF_VERBOSE(1, verbose_stream() << "(optimize:sat)\n");
TRACE("opt", model_smt2_pp(tout, m, *m_model, 0););
m_optsmt.setup(*m_opt_solver.get());
@@ -356,11 +368,22 @@ namespace opt {
}
}
+ void context::set_model(model_ref& m) {
+ m_model = m;
+ opt_params optp(m_params);
+ if (optp.dump_models()) {
+ model_ref md = m->copy();
+ fix_model(md);
+ std::cout << *md << "\n";
+ }
+ }
+
+
void context::get_model_core(model_ref& mdl) {
mdl = m_model;
fix_model(mdl);
if (mdl) mdl->set_model_completion(true);
- TRACE("opt", tout << *mdl;);
+ CTRACE("opt", mdl, tout << *mdl;);
}
void context::get_box_model(model_ref& mdl, unsigned index) {
@@ -382,7 +405,7 @@ namespace opt {
lbool context::execute_min_max(unsigned index, bool committed, bool scoped, bool is_max) {
if (scoped) get_solver().push();
lbool result = m_optsmt.lex(index, is_max);
- if (result == l_true) m_optsmt.get_model(m_model, m_labels);
+ if (result == l_true) { m_optsmt.get_model(m_model, m_labels); SASSERT(m_model); }
if (scoped) get_solver().pop(1);
if (result == l_true && committed) m_optsmt.commit_assignment(index);
if (result == l_true && m_optsmt.is_unbounded(index, is_max) && contains_quantifiers()) {
@@ -436,7 +459,7 @@ namespace opt {
for (unsigned i = 0; r == l_true && i < sz; ++i) {
objective const& o = m_objectives[i];
bool is_last = i + 1 == sz;
- r = execute(o, i + 1 < sz, sc && !is_last && o.m_type != O_MAXSMT);
+ r = execute(o, i + 1 < sz, sc && !is_last);
if (r == l_true && o.m_type == O_MINIMIZE && !get_lower_as_num(i).is_finite()) {
return r;
}
@@ -481,7 +504,7 @@ namespace opt {
++j;
}
}
- if (r == l_true && m_box_models.size() > 0) {
+ if (r == l_true && !m_box_models.empty()) {
m_model = m_box_models[0];
}
return r;
@@ -853,7 +876,10 @@ namespace opt {
bool& neg, symbol& id, expr_ref& orig_term, unsigned& index) {
if (!is_app(fml)) return false;
neg = false;
+ orig_term = nullptr;
+ index = 0;
app* a = to_app(fml);
+
if (m_objective_fns.find(a->get_decl(), index) && m_objectives[index].m_type == O_MAXSMT) {
for (unsigned i = 0; i < a->get_num_args(); ++i) {
expr_ref arg(a->get_arg(i), m);
@@ -995,13 +1021,13 @@ namespace opt {
void context::from_fmls(expr_ref_vector const& fmls) {
TRACE("opt", tout << fmls << "\n";);
m_hard_constraints.reset();
- expr_ref orig_term(m);
for (expr * fml : fmls) {
app_ref tr(m);
+ expr_ref orig_term(m);
expr_ref_vector terms(m);
vector weights;
rational offset(0);
- unsigned index;
+ unsigned index = 0;
symbol id;
bool neg;
if (is_maxsat(fml, terms, weights, offset, neg, id, orig_term, index)) {
@@ -1058,6 +1084,9 @@ namespace opt {
void context::model_updated(model* md) {
+ model_ref mdl = md;
+ set_model(mdl);
+#if 0
opt_params optp(m_params);
symbol prefix = optp.solution_prefix();
if (prefix == symbol::null || prefix == symbol("")) return;
@@ -1070,6 +1099,7 @@ namespace opt {
out << *mdl;
out.close();
}
+#endif
}
@@ -1573,7 +1603,6 @@ namespace opt {
m_model_converter->display(verbose_stream() << "mc\n");
model_smt2_pp(verbose_stream(), m, *mdl, 0);
verbose_stream() << to_string_internal() << "\n");
- exit(0);
}
}
}
@@ -1596,7 +1625,7 @@ namespace opt {
value = obj.m_adjust_value(value);
rational value0 = ms.get_lower();
TRACE("opt", tout << "value " << value << " " << value0 << "\n";);
- SASSERT(value == value0);
+ // TBD is this correct? SASSERT(value == value0);
}
}
}
@@ -1604,6 +1633,7 @@ namespace opt {
void context::validate_lex() {
rational r1;
expr_ref val(m);
+ SASSERT(m_model);
for (unsigned i = 0; i < m_objectives.size(); ++i) {
objective const& obj = m_objectives[i];
switch(obj.m_type) {
@@ -1632,7 +1662,10 @@ namespace opt {
}
// TBD: check that optimal was not changed.
}
- TRACE("opt", tout << "value " << value << "\n";);
+ maxsmt& ms = *m_maxsmts.find(obj.m_id);
+ rational value0 = ms.get_lower();
+ TRACE("opt", tout << "value " << value << " other " << value0 << "\n";);
+ // TBD SASSERT(value0 == value);
break;
}
}
diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h
index fe0d4a13e..5959c4d19 100644
--- a/src/opt/opt_context.h
+++ b/src/opt/opt_context.h
@@ -115,20 +115,23 @@ namespace opt {
arith_util m_arith;
bv_util m_bv;
unsigned_vector m_hard_lim;
+ unsigned_vector m_asms_lim;
unsigned_vector m_objectives_lim;
unsigned_vector m_objectives_term_trail;
unsigned_vector m_objectives_term_trail_lim;
map_id m_indices;
public:
- expr_ref_vector m_hard;
+ expr_ref_vector m_hard;
+ expr_ref_vector m_asms;
vector m_objectives;
scoped_state(ast_manager& m):
m(m),
m_arith(m),
m_bv(m),
- m_hard(m)
+ m_hard(m),
+ m_asms(m)
{}
void push();
void pop();
@@ -180,6 +183,7 @@ namespace opt {
unsigned add_soft_constraint(expr* f, rational const& w, symbol const& id);
unsigned add_objective(app* t, bool is_max);
void add_hard_constraint(expr* f);
+ void add_hard_constraint(expr* f, expr* t);
void get_hard_constraints(expr_ref_vector& hard);
expr_ref get_objective(unsigned i);
@@ -189,7 +193,7 @@ namespace opt {
bool empty() override { return m_scoped_state.m_objectives.empty(); }
void set_hard_constraints(expr_ref_vector const& hard) override;
lbool optimize(expr_ref_vector const& asms) override;
- void set_model(model_ref& _m) override { m_model = _m; }
+ void set_model(model_ref& _m) override;
void get_model_core(model_ref& _m) override;
void get_box_model(model_ref& _m, unsigned index) override;
void fix_model(model_ref& _m) override;
diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg
index f72bafbd8..dd9e26aae 100644
--- a/src/opt/opt_params.pyg
+++ b/src/opt/opt_params.pyg
@@ -5,6 +5,7 @@ def_module_params('opt',
('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'core_maxsat', 'wmax', 'maxres', 'pd-maxres'"),
('priority', SYMBOL, 'lex', "select how to priortize objectives: 'lex' (lexicographic), 'pareto', 'box'"),
('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'),
+ ('dump_models', BOOL, False, 'display intermediary models to stdout'),
('solution_prefix', SYMBOL, '', "path prefix to dump intermediary, but non-optimal, solutions"),
('timeout', UINT, UINT_MAX, 'timeout (in milliseconds) (UINT_MAX and 0 mean no timeout)'),
('rlimit', UINT, 0, 'resource limit (0 means no limit)'),
@@ -13,6 +14,7 @@ def_module_params('opt',
('elim_01', BOOL, True, 'eliminate 01 variables'),
('pp.neat', BOOL, True, 'use neat (as opposed to less readable, but faster) pretty printer when displaying context'),
('pb.compile_equality', BOOL, False, 'compile arithmetical equalities into pseudo-Boolean equality (instead of two inequalites)'),
+ ('maxlex.enable', BOOL, True, 'enable maxlex heuristic for lexicographic MaxSAT problems'),
('maxres.hill_climb', BOOL, True, 'give preference for large weight cores'),
('maxres.add_upper_bound_block', BOOL, False, 'restict upper bound with constraint'),
('maxres.max_num_cores', UINT, UINT_MAX, 'maximal number of cores per round'),
diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp
index e61a02d80..80a81ba3a 100644
--- a/src/opt/opt_solver.cpp
+++ b/src/opt/opt_solver.cpp
@@ -158,7 +158,7 @@ namespace opt {
return m_dump_benchmarks;
}
- lbool opt_solver::check_sat_core(unsigned num_assumptions, expr * const * assumptions) {
+ lbool opt_solver::check_sat_core2(unsigned num_assumptions, expr * const * assumptions) {
TRACE("opt_verbose", {
tout << "context size: " << m_context.size() << "\n";
for (unsigned i = 0; i < m_context.size(); ++i) {
@@ -208,6 +208,9 @@ namespace opt {
return m_context.preferred_sat(asms, cores);
}
+ void opt_solver::get_levels(ptr_vector const& vars, unsigned_vector& depth) {
+ return m_context.get_levels(vars, depth);
+ }
/**
diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h
index 39562ec54..be71376ac 100644
--- a/src/opt/opt_solver.h
+++ b/src/opt/opt_solver.h
@@ -95,7 +95,7 @@ namespace opt {
void assert_expr_core(expr * t) override;
void push_core() override;
void pop_core(unsigned n) override;
- lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) override;
+ lbool check_sat_core2(unsigned num_assumptions, expr * const * assumptions) override;
void get_unsat_core(expr_ref_vector & r) override;
void get_model_core(model_ref & _m) override;
proof * get_proof() override;
@@ -108,6 +108,9 @@ namespace opt {
ast_manager& get_manager() const override { return m; }
lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) override;
lbool preferred_sat(expr_ref_vector const& asms, vector& cores) override;
+ void get_levels(ptr_vector const& vars, unsigned_vector& depth) override;
+ expr_ref_vector get_trail() override { return m_context.get_trail(); }
+ void set_activity(expr* lit, double act) override { m_context.set_activity(lit, act); }
expr_ref_vector cube(expr_ref_vector&, unsigned) override { return expr_ref_vector(m); }
void set_logic(symbol const& logic);
diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp
index a461d4a22..4a35acd02 100644
--- a/src/opt/optsmt.cpp
+++ b/src/opt/optsmt.cpp
@@ -31,6 +31,7 @@ Notes:
#include
#include "opt/optsmt.h"
#include "opt/opt_solver.h"
+#include "opt/opt_context.h"
#include "ast/arith_decl_plugin.h"
#include "smt/theory_arith.h"
#include "ast/ast_pp.h"
@@ -171,6 +172,7 @@ namespace opt {
}
lbool optsmt::geometric_lex(unsigned obj_index, bool is_maximize) {
+ TRACE("opt", tout << "index: " << obj_index << " is-max: " << is_maximize << "\n";);
arith_util arith(m);
bool is_int = arith.is_int(m_objs[obj_index].get());
lbool is_sat = l_true;
@@ -189,9 +191,11 @@ namespace opt {
SASSERT(delta_per_step.is_int());
SASSERT(delta_per_step.is_pos());
is_sat = m_s->check_sat(0, nullptr);
+ TRACE("opt", tout << "check " << is_sat << "\n";);
if (is_sat == l_true) {
m_s->maximize_objective(obj_index, bound);
m_s->get_model(m_model);
+ SASSERT(m_model);
m_s->get_labels(m_labels);
inf_eps obj = m_s->saved_objective_value(obj_index);
update_lower_lex(obj_index, obj, is_maximize);
@@ -220,13 +224,17 @@ namespace opt {
delta_per_step = rational::one();
SASSERT(num_scopes > 0);
--num_scopes;
- m_s->pop(1);
+ m_s->pop(1);
}
else {
break;
}
}
m_s->pop(num_scopes);
+
+ if (is_sat == l_false && !m_model) {
+ return l_false;
+ }
if (m.canceled() || is_sat == l_undef) {
return l_undef;
@@ -355,12 +363,14 @@ namespace opt {
verbose_stream() << "(optsmt lower bound: " << v << ")\n";
else
verbose_stream() << "(optsmt upper bound: " << (-v) << ")\n";
- );
+ );
expr_ref tmp(m);
for (unsigned i = idx+1; i < m_vars.size(); ++i) {
m_s->maximize_objective(i, tmp);
m_lower[i] = m_s->saved_objective_value(i);
}
+
+ m_context.set_model(m_model);
}
}
@@ -574,7 +584,7 @@ namespace opt {
return m_upper[i];
}
- void optsmt::get_model(model_ref& mdl, svector & labels) {
+ void optsmt::get_model(model_ref& mdl, svector & labels) {
mdl = m_model.get();
labels = m_labels;
}
diff --git a/src/opt/optsmt.h b/src/opt/optsmt.h
index 6db7eaadf..c9aa4f41d 100644
--- a/src/opt/optsmt.h
+++ b/src/opt/optsmt.h
@@ -27,8 +27,11 @@ namespace opt {
Returns an optimal assignment to objective functions.
*/
+ class context;
+
class optsmt {
ast_manager& m;
+ context& m_context;
opt_solver* m_s;
vector m_lower;
vector m_upper;
@@ -40,8 +43,8 @@ namespace opt {
svector m_labels;
sref_vector m_models;
public:
- optsmt(ast_manager& m):
- m(m), m_s(nullptr), m_objs(m), m_lower_fmls(m) {}
+ optsmt(ast_manager& m, context& ctx):
+ m(m), m_context(ctx), m_s(nullptr), m_objs(m), m_lower_fmls(m) {}
void setup(opt_solver& solver);
diff --git a/src/opt/pb_sls.cpp b/src/opt/pb_sls.cpp
index 9054e2b00..17c3f9128 100644
--- a/src/opt/pb_sls.cpp
+++ b/src/opt/pb_sls.cpp
@@ -403,10 +403,8 @@ namespace smt {
}
int new_break_count = flip(~lit);
if (-break_count != new_break_count) {
- verbose_stream() << lit << "\n";
- IF_VERBOSE(0, display(verbose_stream(), cls););
- display(verbose_stream());
- exit(0);
+ IF_VERBOSE(0, display(verbose_stream() << lit << "\n", cls);
+ display(verbose_stream()));
}
// VERIFY(-break_count == flip(~lit));
}
diff --git a/src/opt/sortmax.cpp b/src/opt/sortmax.cpp
index df361f24a..1a19032e2 100644
--- a/src/opt/sortmax.cpp
+++ b/src/opt/sortmax.cpp
@@ -114,7 +114,7 @@ namespace opt {
}
void update_assignment() {
- for (soft& s : m_soft) s.is_true = is_true(s.s);
+ for (soft& s : m_soft) s.set_value(is_true(s.s));
}
bool is_true(expr* e) {
diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp
index ee7f92a23..9fb683179 100644
--- a/src/opt/wmax.cpp
+++ b/src/opt/wmax.cpp
@@ -75,11 +75,9 @@ namespace opt {
trace_bounds("wmax");
TRACE("opt",
- s().display(tout); tout << "\n";
+ s().display(tout)<< "\n";
tout << "lower: " << m_lower << " upper: " << m_upper << "\n";);
while (!m.canceled() && m_lower < m_upper) {
- //mk_assumptions(asms);
- //is_sat = s().preferred_sat(asms, cores);
is_sat = s().check_sat(0, nullptr);
if (m.canceled()) {
is_sat = l_undef;
@@ -124,7 +122,7 @@ namespace opt {
}
void update_assignment() {
- for (soft& s : m_soft) s.is_true = is_true(s.s);
+ for (soft& s : m_soft) s.set_value(is_true(s.s));
}
struct compare_asm {
diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp
index 64f9c36fd..bf1e25e57 100644
--- a/src/parsers/smt2/smt2parser.cpp
+++ b/src/parsers/smt2/smt2parser.cpp
@@ -1371,11 +1371,11 @@ namespace smt2 {
else {
while (!curr_is_rparen()) {
m_env.begin_scope();
+ check_lparen_next("invalid pattern binding, '(' expected");
unsigned num_bindings = m_num_bindings;
parse_match_pattern(srt);
patterns.push_back(expr_stack().back());
expr_stack().pop_back();
- check_lparen_next("invalid pattern binding, '(' expected");
parse_expr();
cases.push_back(expr_stack().back());
expr_stack().pop_back();
@@ -1474,22 +1474,29 @@ namespace smt2 {
* _
* x
*/
-
- bool parse_constructor_pattern(sort * srt) {
- if (!curr_is_lparen()) {
- return false;
- }
- next();
+
+ void parse_match_pattern(sort * srt) {
+ symbol C;
svector vars;
expr_ref_vector args(m());
- symbol C(check_identifier_next("constructor symbol expected"));
- while (!curr_is_rparen()) {
- symbol v(check_identifier_next("variable symbol expected"));
- if (v != m_underscore && vars.contains(v)) {
- throw parser_exception("unexpected repeated variable in pattern expression");
- }
- vars.push_back(v);
- }
+
+ if (curr_is_identifier()) {
+ C = curr_id();
+ }
+ else if (curr_is_lparen()) {
+ next();
+ C = check_identifier_next("constructor symbol expected");
+ while (!curr_is_rparen()) {
+ symbol v(check_identifier_next("variable symbol expected"));
+ if (v != m_underscore && vars.contains(v)) {
+ throw parser_exception("unexpected repeated variable in pattern expression");
+ }
+ vars.push_back(v);
+ }
+ }
+ else {
+ throw parser_exception("expecting a constructor, _, variable or constructor application");
+ }
next();
// now have C, vars
@@ -1498,10 +1505,28 @@ namespace smt2 {
// store expression in expr_stack().
// ensure that bound variables are adjusted to vars
- func_decl* f = m_ctx.find_func_decl(C, 0, nullptr, vars.size(), nullptr, srt);
- if (!f) {
+ func_decl* f = nullptr;
+ try {
+ f = m_ctx.find_func_decl(C, 0, nullptr, vars.size(), nullptr, srt);
+ }
+ catch (cmd_exception &) {
+ if (!args.empty()) {
+ throw;
+ }
+ }
+
+ if (!f && !args.empty()) {
throw parser_exception("expecting a constructor that has been declared");
}
+ if (!f) {
+ m_num_bindings++;
+ var * v = m().mk_var(0, srt);
+ if (C != m_underscore) {
+ m_env.insert(C, local(v, m_num_bindings));
+ }
+ expr_stack().push_back(v);
+ return;
+ }
if (!dtutil().is_constructor(f)) {
throw parser_exception("expecting a constructor");
}
@@ -1517,40 +1542,6 @@ namespace smt2 {
}
}
expr_stack().push_back(m().mk_app(f, args.size(), args.c_ptr()));
- return true;
- }
-
- void parse_match_pattern(sort* srt) {
- if (parse_constructor_pattern(srt)) {
- // done
- }
- else if (curr_id() == m_underscore) {
- // we have a wild-card.
- // store dummy variable in expr_stack()
- next();
- var* v = m().mk_var(0, srt);
- expr_stack().push_back(v);
- }
- else {
- symbol xC(check_identifier_next("constructor symbol or variable expected"));
- // check if xC is a constructor, otherwise make it a variable
- // of sort srt.
- try {
- func_decl* f = m_ctx.find_func_decl(xC, 0, nullptr, 0, nullptr, srt);
- if (!dtutil().is_constructor(f)) {
- throw parser_exception("expecting a constructor, got a previously declared function");
- }
- if (f->get_arity() > 0) {
- throw parser_exception("constructor expects arguments, but no arguments were supplied in pattern");
- }
- expr_stack().push_back(m().mk_const(f));
- }
- catch (cmd_exception &) {
- var* v = m().mk_var(0, srt);
- expr_stack().push_back(v);
- m_env.insert(xC, local(v, m_num_bindings++));
- }
- }
}
symbol parse_indexed_identifier_core() {
diff --git a/src/qe/nlarith_util.cpp b/src/qe/nlarith_util.cpp
index 12977b449..c2d95a1ee 100644
--- a/src/qe/nlarith_util.cpp
+++ b/src/qe/nlarith_util.cpp
@@ -684,7 +684,7 @@ namespace nlarith {
void get_coefficients(poly const& p, app*& a, app*& b, app*& c) {
a = b = c = z();
- if (p.size() > 0) c = p[0];
+ if (!p.empty()) c = p[0];
if (p.size() > 1) b = p[1];
if (p.size() > 2) a = p[2];
SASSERT(p.size() <= 3);
@@ -1359,7 +1359,7 @@ namespace nlarith {
void quot_rem(poly const& u, poly const& v, poly& q, poly& r, app_ref& lc, unsigned& power) {
lc = v.empty()?num(0):v[v.size()-1];
power = 0;
- if (u.size() < v.size() || v.size() == 0) {
+ if (u.size() < v.size() || v.empty()) {
q.reset();
r.reset();
r.append(u);
diff --git a/src/qe/qe.h b/src/qe/qe.h
index 1027f0b61..1eb7b7e4a 100644
--- a/src/qe/qe.h
+++ b/src/qe/qe.h
@@ -253,7 +253,7 @@ namespace qe {
/**
\brief Guarded definitions.
- A realizer to a an existential quantified formula is a disjunction
+ A realizer to an existential quantified formula is a disjunction
together with a substitution from the existentially quantified variables
to terms such that:
1. The original formula (exists (vars) fml) is equivalent to the disjunction of guards.
diff --git a/src/qe/qe_arith.cpp b/src/qe/qe_arith.cpp
index cd81167e3..a0aea08da 100644
--- a/src/qe/qe_arith.cpp
+++ b/src/qe/qe_arith.cpp
@@ -387,7 +387,7 @@ namespace qe {
for (row const& r : rows) {
expr_ref_vector ts(m);
expr_ref t(m), s(m), val(m);
- if (r.m_vars.size() == 0) {
+ if (r.m_vars.empty()) {
continue;
}
if (r.m_vars.size() == 1 && r.m_vars[0].m_coeff.is_neg() && r.m_type != opt::t_mod) {
diff --git a/src/qe/qe_arrays.cpp b/src/qe/qe_arrays.cpp
index 4c81418b6..4bead6684 100644
--- a/src/qe/qe_arrays.cpp
+++ b/src/qe/qe_arrays.cpp
@@ -798,7 +798,7 @@ namespace qe {
*/
expr* reduce_core (app *a) {
if (!m_arr_u.is_store (a->get_arg (0))) return a;
- expr* array = a->get_arg(0);
+ expr* array = a->get_arg(0);
unsigned arity = get_array_arity(m.get_sort(array));
expr* const* js = a->get_args() + 1;
@@ -810,7 +810,7 @@ namespace qe {
if (is_equals (arity, idxs, js)) {
add_idx_cond (cond);
- return a->get_arg (2);
+ return a->get_arg (a->get_num_args() - 1);
}
else {
cond = m.mk_not (cond);
diff --git a/src/qe/qe_lite.cpp b/src/qe/qe_lite.cpp
index 3226f7554..4585c88c1 100644
--- a/src/qe/qe_lite.cpp
+++ b/src/qe/qe_lite.cpp
@@ -2370,6 +2370,7 @@ void qe_lite::operator()(uint_set const& index_set, bool index_of_bound, expr_re
(*m_impl)(index_set, index_of_bound, fmls);
}
+namespace {
class qe_lite_tactic : public tactic {
struct imp {
@@ -2494,7 +2495,6 @@ public:
(*m_imp)(in, result);
}
-
void collect_statistics(statistics & st) const override {
// m_imp->collect_statistics(st);
}
@@ -2503,14 +2503,14 @@ public:
// m_imp->reset_statistics();
}
-
void cleanup() override {
ast_manager & m = m_imp->m;
- dealloc(m_imp);
- m_imp = alloc(imp, m, m_params);
+ m_imp->~imp();
+ m_imp = new (m_imp) imp(m, m_params);
}
};
+}
tactic * mk_qe_lite_tactic(ast_manager & m, params_ref const & p) {
return alloc(qe_lite_tactic, m, p);
diff --git a/src/qe/qe_lite.h b/src/qe/qe_lite.h
index 63ad8bedd..3251fa3f8 100644
--- a/src/qe/qe_lite.h
+++ b/src/qe/qe_lite.h
@@ -18,8 +18,7 @@ Revision History:
--*/
-#ifndef QE_LITE_H_
-#define QE_LITE_H_
+#pragma once
#include "ast/ast.h"
#include "util/uint_set.h"
@@ -67,5 +66,3 @@ tactic * mk_qe_lite_tactic(ast_manager & m, params_ref const & p = params_ref())
/*
ADD_TACTIC("qe-light", "apply light-weight quantifier elimination.", "mk_qe_lite_tactic(m, p)")
*/
-
-#endif
diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp
index b7f0d0d49..77f910260 100644
--- a/src/qe/qe_mbi.cpp
+++ b/src/qe/qe_mbi.cpp
@@ -30,6 +30,7 @@ Notes:
#include "ast/ast_util.h"
#include "ast/for_each_expr.h"
+#include "ast/rewriter/expr_safe_replace.h"
#include "ast/rewriter/bool_rewriter.h"
#include "ast/arith_decl_plugin.h"
#include "model/model_evaluator.h"
@@ -95,101 +96,6 @@ namespace qe {
m_solver->assert_expr(mk_not(mk_and(lits)));
}
- // -------------------------------
- // euf_mbi
-
- struct euf_mbi_plugin::is_atom_proc {
- ast_manager& m;
- expr_ref_vector& m_atoms;
- is_atom_proc(expr_ref_vector& atoms): m(atoms.m()), m_atoms(atoms) {}
- void operator()(app* a) {
- if (m.is_eq(a)) {
- m_atoms.push_back(a);
- }
- else if (m.is_bool(a) && a->get_family_id() != m.get_basic_family_id()) {
- m_atoms.push_back(a);
- }
- }
- void operator()(expr*) {}
- };
-
- euf_mbi_plugin::euf_mbi_plugin(solver* s, solver* sNot):
- mbi_plugin(s->get_manager()),
- m_atoms(m),
- m_solver(s),
- m_dual_solver(sNot) {
- params_ref p;
- p.set_bool("core.minimize", true);
- m_solver->updt_params(p);
- m_dual_solver->updt_params(p);
- expr_ref_vector fmls(m);
- m_solver->get_assertions(fmls);
- expr_fast_mark1 marks;
- is_atom_proc proc(m_atoms);
- for (expr* e : fmls) {
- quick_for_each_expr(proc, marks, e);
- }
- }
-
- mbi_result euf_mbi_plugin::operator()(expr_ref_vector& lits, model_ref& mdl) {
- lbool r = m_solver->check_sat(lits);
- switch (r) {
- case l_false:
- lits.reset();
- m_solver->get_unsat_core(lits);
- // optionally minimize core using superposition.
- return mbi_unsat;
- case l_true: {
- m_solver->get_model(mdl);
- model_evaluator mev(*mdl.get());
- lits.reset();
- for (expr* e : m_atoms) {
- if (mev.is_true(e)) {
- lits.push_back(e);
- }
- else if (mev.is_false(e)) {
- lits.push_back(m.mk_not(e));
- }
- }
- TRACE("qe", tout << "atoms from model: " << lits << "\n";);
- r = m_dual_solver->check_sat(lits);
- expr_ref_vector core(m);
- term_graph tg(m);
- switch (r) {
- case l_false:
- // use the dual solver to find a 'small' implicant
- m_dual_solver->get_unsat_core(core);
- TRACE("qe", tout << "core: " << core << "\n";);
- // project the implicant onto vars
- tg.set_vars(m_shared, false);
- tg.add_lits(core);
- lits.reset();
- lits.append(tg.project(*mdl));
- TRACE("qe", tout << "project: " << lits << "\n";);
- return mbi_sat;
- case l_undef:
- return mbi_undef;
- case l_true:
- UNREACHABLE();
- return mbi_undef;
- }
- return mbi_sat;
- }
- default:
- // TBD: if not running solver to completion, then:
- // 1. extract unit literals from m_solver.
- // 2. run a cc over the units
- // 3. extract equalities or other assignments over the congruence classes
- // 4. ensure that at least some progress is made over original lits.
- return mbi_undef;
- }
- }
-
- void euf_mbi_plugin::block(expr_ref_vector const& lits) {
- m_solver->assert_expr(mk_not(mk_and(lits)));
- }
-
-
// -------------------------------
// euf_arith_mbi
@@ -219,29 +125,49 @@ namespace qe {
struct euf_arith_mbi_plugin::is_arith_var_proc {
ast_manager& m;
- app_ref_vector& m_pvars;
- app_ref_vector& m_svars;
- arith_util arith;
- obj_hashtable m_shared;
- is_arith_var_proc(func_decl_ref_vector const& shared, app_ref_vector& pvars, app_ref_vector& svars):
- m(pvars.m()), m_pvars(pvars), m_svars(svars), arith(m) {
- for (func_decl* f : shared) m_shared.insert(f);
+ app_ref_vector& m_avars;
+ app_ref_vector& m_proxies;
+ arith_util m_arith;
+ obj_hashtable m_seen;
+ is_arith_var_proc(app_ref_vector& avars, app_ref_vector& proxies):
+ m(avars.m()), m_avars(avars), m_proxies(proxies), m_arith(m) {
}
void operator()(app* a) {
- if (!arith.is_int_real(a) || a->get_family_id() == arith.get_family_id()) {
- // no-op
+ if (is_arith_op(a) || a->get_family_id() == m.get_basic_family_id()) {
+ return;
}
- else if (m_shared.contains(a->get_decl())) {
- m_svars.push_back(a);
+
+ if (m_arith.is_int_real(a)) {
+ m_avars.push_back(a);
}
- else {
- m_pvars.push_back(a);
+ for (expr* arg : *a) {
+ if (is_app(arg) && !m_seen.contains(arg) && m_arith.is_int_real(arg)) {
+ m_proxies.push_back(to_app(arg));
+ m_seen.insert(arg);
+ }
}
}
+ bool is_arith_op(app* a) {
+ return a->get_family_id() == m_arith.get_family_id();
+ }
void operator()(expr*) {}
-
};
+ void euf_arith_mbi_plugin::filter_private_arith(app_ref_vector& avars) {
+ arith_util a(m);
+ unsigned j = 0;
+ obj_hashtable shared;
+ for (func_decl* f : m_shared) shared.insert(f);
+ for (unsigned i = 0; i < avars.size(); ++i) {
+ app* v = avars.get(i);
+ if (!shared.contains(v->get_decl()) &&
+ v->get_family_id() != a.get_family_id()) {
+ avars[j++] = v;
+ }
+ }
+ avars.shrink(j);
+ }
+
euf_arith_mbi_plugin::euf_arith_mbi_plugin(solver* s, solver* sNot):
mbi_plugin(s->get_manager()),
m_atoms(m),
@@ -290,28 +216,15 @@ namespace qe {
}
}
- app_ref_vector euf_arith_mbi_plugin::get_arith_vars(model_ref& mdl, expr_ref_vector& lits) {
- arith_util a(m);
- app_ref_vector pvars(m), svars(m); // private and shared arithmetic variables.
- is_arith_var_proc _proc(m_shared, pvars, svars);
+
+ /**
+ * \brief extract arithmetical variables and arithmetical terms in shared positions.
+ */
+ app_ref_vector euf_arith_mbi_plugin::get_arith_vars(model_ref& mdl, expr_ref_vector& lits, app_ref_vector& proxies) {
+ app_ref_vector avars(m);
+ is_arith_var_proc _proc(avars, proxies);
for_each_expr(_proc, lits);
- rational v1, v2;
- for (expr* p : pvars) {
- VERIFY(a.is_numeral((*mdl)(p), v1));
- for (expr* s : svars) {
- VERIFY(a.is_numeral((*mdl)(s), v2));
- if (v1 < v2) {
- lits.push_back(a.mk_lt(p, s));
- }
- else if (v2 < v1) {
- lits.push_back(a.mk_lt(s, p));
- }
- else {
- lits.push_back(m.mk_eq(s, p));
- }
- }
- }
- return pvars;
+ return avars;
}
mbi_result euf_arith_mbi_plugin::operator()(expr_ref_vector& lits, model_ref& mdl) {
@@ -324,93 +237,13 @@ namespace qe {
TRACE("qe", tout << "unsat core: " << lits << "\n";);
// optionally minimize core using superposition.
return mbi_unsat;
- case l_true: {
+ case l_true:
m_solver->get_model(mdl);
if (!get_literals(mdl, lits)) {
return mbi_undef;
}
- TRACE("qe", tout << lits << "\n";);
-
- // 1. Extract projected variables, add inequalities between
- // projected variables and non-projected terms according to model.
- // 2. Extract disequalities implied by congruence closure.
- // 3. project arithmetic variables from pure literals.
- // 4. Add projected definitions as equalities to EUF.
- // 5. project remaining literals with respect to EUF.
-
- app_ref_vector avars = get_arith_vars(mdl, lits);
- TRACE("qe", tout << "vars: " << avars << " lits: " << lits << "\n";);
-
- // 2.
- term_graph tg1(m);
- func_decl_ref_vector no_shared(m);
- tg1.set_vars(no_shared, false);
- tg1.add_lits(lits);
- arith_util a(m);
- expr_ref_vector foreign = tg1.shared_occurrences(a.get_family_id());
- obj_hashtable _foreign;
- for (expr* e : foreign) _foreign.insert(e);
- vector partition = tg1.get_partition(*mdl);
- expr_ref_vector diseq = tg1.get_ackerman_disequalities();
- lits.append(diseq);
- TRACE("qe", tout << "diseq: " << diseq << "\n";
- tout << "foreign: " << foreign << "\n";
- for (auto const& v : partition) {
- tout << "partition: {";
- bool first = true;
- for (expr* e : v) {
- if (first) first = false; else tout << ", ";
- tout << expr_ref(e, m);
- }
- tout << "}\n";
- }
- );
- vector refined_partition;
- for (auto & p : partition) {
- unsigned j = 0;
- for (expr* e : p) {
- if (_foreign.contains(e) ||
- (is_app(e) && m_shared.contains(to_app(e)->get_decl()))) {
- p[j++] = e;
- }
- }
- p.shrink(j);
- if (!p.empty()) refined_partition.push_back(p);
- }
- TRACE("qe",
- for (auto const& v : refined_partition) {
- tout << "partition: {";
- bool first = true;
- for (expr* e : v) {
- if (first) first = false; else tout << ", ";
- tout << expr_ref(e, m);
- }
- tout << "}\n";
- });
-
-
-
- arith_project_plugin ap(m);
- ap.set_check_purified(false);
-
- // 3.
- auto defs = ap.project(*mdl.get(), avars, lits);
-
- // 4.
- for (auto const& def : defs) {
- lits.push_back(m.mk_eq(def.var, def.term));
- }
- TRACE("qe", tout << "# arith defs " << defs.size() << " avars: " << avars << " " << lits << "\n";);
-
- // 5.
- term_graph tg2(m);
- tg2.set_vars(m_shared, false);
- tg2.add_lits(lits);
- lits.reset();
- lits.append(tg2.project());
- TRACE("qe", tout << "project: " << lits << "\n";);
+ project(mdl, lits);
return mbi_sat;
- }
default:
// TBD: if not running solver to completion, then:
// 1. extract unit literals from m_solver.
@@ -421,6 +254,106 @@ namespace qe {
}
}
+ void euf_arith_mbi_plugin::project(model_ref& mdl, expr_ref_vector& lits) {
+ TRACE("qe", tout << lits << "\n" << *mdl << "\n";);
+ TRACE("qe", tout << m_solver->get_assertions() << "\n";);
+
+
+ // 1. arithmetical variables - atomic and in purified positions
+ app_ref_vector proxies(m);
+ app_ref_vector avars = get_arith_vars(mdl, lits, proxies);
+ TRACE("qe", tout << "vars: " << avars << "\nproxies: " << proxies << "\nlits: " << lits << "\n";);
+
+ // 2. project private non-arithmetical variables from lits
+ project_euf(mdl, lits, avars);
+
+ // 3. Order arithmetical variables and purified positions
+ order_avars(mdl, lits, avars, proxies);
+ TRACE("qe", tout << "ordered: " << lits << "\n";);
+
+ // 4. Perform arithmetical projection
+ arith_project_plugin ap(m);
+ ap.set_check_purified(false);
+ auto defs = ap.project(*mdl.get(), avars, lits);
+ TRACE("qe", tout << "aproject: " << lits << "\n";);
+
+ // 5. Substitute solution into lits
+ substitute(defs, lits);
+ TRACE("qe", tout << "substitute: " << lits << "\n";);
+ }
+
+ /**
+ * \brief substitute solution to arithmetical variables into lits
+ */
+ void euf_arith_mbi_plugin::substitute(vector const& defs, expr_ref_vector& lits) {
+ for (auto const& def : defs) {
+ expr_safe_replace rep(m);
+ rep.insert(def.var, def.term);
+ rep(lits);
+ }
+ }
+
+ /**
+ * \brief project non-arithmetical private symbols.
+ */
+ void euf_arith_mbi_plugin::project_euf(model_ref& mdl, expr_ref_vector& lits, app_ref_vector& avars) {
+ term_graph tg(m);
+ func_decl_ref_vector shared(m_shared);
+ for (app* a : avars) shared.push_back(a->get_decl());
+ tg.set_vars(shared, false);
+ tg.add_lits(lits);
+ lits.reset();
+ lits.append(tg.project(*mdl.get()));
+ TRACE("qe", tout << "project: " << lits << "\n";);
+ }
+
+ /**
+ * \brief Order arithmetical variables:
+ * 1. add literals that order the proxies according to the model.
+ * 2. sort arithmetical terms, such that deepest terms are first.
+ */
+ void euf_arith_mbi_plugin::order_avars(model_ref& mdl, expr_ref_vector& lits, app_ref_vector& avars, app_ref_vector const& proxies) {
+ arith_util a(m);
+ model_evaluator mev(*mdl.get());
+ vector> vals;
+ for (app* v : proxies) {
+ rational val;
+ expr_ref tmp = mev(v);
+ VERIFY(a.is_numeral(tmp, val));
+ vals.push_back(std::make_pair(val, v));
+ }
+ struct compare_first {
+ bool operator()(std::pair const& x,
+ std::pair const& y) const {
+ return x.first < y.first;
+ }
+ };
+ // add linear order between proxies
+ compare_first cmp;
+ std::sort(vals.begin(), vals.end(), cmp);
+ for (unsigned i = 1; i < vals.size(); ++i) {
+ if (vals[i-1].first == vals[i].first) {
+ lits.push_back(m.mk_eq(vals[i-1].second, vals[i].second));
+ }
+ else {
+ lits.push_back(a.mk_lt(vals[i-1].second, vals[i].second));
+ }
+ }
+
+ // filter out only private variables
+ filter_private_arith(avars);
+
+ // sort avars based on depth
+ struct compare_depth {
+ bool operator()(app* x, app* y) const {
+ return x->get_depth() > y->get_depth();
+ }
+ };
+ compare_depth cmpd;
+ std::sort(avars.c_ptr(), avars.c_ptr() + avars.size(), cmpd);
+ TRACE("qe", tout << lits << "\navars:" << avars << "\n" << *mdl << "\n";);
+ }
+
void euf_arith_mbi_plugin::block(expr_ref_vector const& lits) {
collect_atoms(lits);
m_fmls.push_back(mk_not(mk_and(lits)));
diff --git a/src/qe/qe_mbi.h b/src/qe/qe_mbi.h
index 1cc2be0cb..12e6a8080 100644
--- a/src/qe/qe_mbi.h
+++ b/src/qe/qe_mbi.h
@@ -20,6 +20,8 @@ Revision History:
#pragma once
+#include "qe/qe_arith.h"
+
namespace qe {
enum mbi_result {
mbi_sat,
@@ -91,17 +93,6 @@ namespace qe {
void block(expr_ref_vector const& lits) override;
};
- class euf_mbi_plugin : public mbi_plugin {
- expr_ref_vector m_atoms;
- solver_ref m_solver;
- solver_ref m_dual_solver;
- struct is_atom_proc;
- public:
- euf_mbi_plugin(solver* s, solver* sNot);
- ~euf_mbi_plugin() override {}
- mbi_result operator()(expr_ref_vector& lits, model_ref& mdl) override;
- void block(expr_ref_vector const& lits) override;
- };
class euf_arith_mbi_plugin : public mbi_plugin {
expr_ref_vector m_atoms;
@@ -112,13 +103,18 @@ namespace qe {
struct is_atom_proc;
struct is_arith_var_proc;
- app_ref_vector get_arith_vars(model_ref& mdl, expr_ref_vector& lits);
+ app_ref_vector get_arith_vars(model_ref& mdl, expr_ref_vector& lits, app_ref_vector& proxies);
bool get_literals(model_ref& mdl, expr_ref_vector& lits);
void collect_atoms(expr_ref_vector const& fmls);
+ void project_euf(model_ref& mdl, expr_ref_vector& lits, app_ref_vector& avars);
+ void order_avars(model_ref& mdl, expr_ref_vector& lits, app_ref_vector& avars, app_ref_vector const& proxies);
+ void substitute(vector const& defs, expr_ref_vector& lits);
+ void filter_private_arith(app_ref_vector& avars);
public:
euf_arith_mbi_plugin(solver* s, solver* emptySolver);
~euf_arith_mbi_plugin() override {}
mbi_result operator()(expr_ref_vector& lits, model_ref& mdl) override;
+ void project(model_ref& mdl, expr_ref_vector& lits);
void block(expr_ref_vector const& lits) override;
};
diff --git a/src/qe/qe_mbp.cpp b/src/qe/qe_mbp.cpp
index a0e16727e..becaeb049 100644
--- a/src/qe/qe_mbp.cpp
+++ b/src/qe/qe_mbp.cpp
@@ -501,7 +501,7 @@ public:
expr_ref val(m);
model_evaluator eval(model);
for (expr * f : fmls) {
- VERIFY(model.is_true(f));
+ VERIFY(!model.is_false(f));
}
return true;
}
@@ -657,7 +657,7 @@ public:
other_vars.reset();
}
- SASSERT(eval.is_true(fml));
+ SASSERT(!eval.is_false(fml));
vars.reset ();
vars.append(other_vars);
diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp
index b5de20368..274c25293 100644
--- a/src/qe/qe_term_graph.cpp
+++ b/src/qe/qe_term_graph.cpp
@@ -774,11 +774,13 @@ namespace qe {
TRACE("qe", tout << "literals: " << res << "\n";);
}
- void mk_distinct(expr_ref_vector& res) {
- vector> decl2terms; // terms that use function f
- ptr_vector decls;
- decl2terms.reset();
+ vector> m_decl2terms; // terms that use function f
+ ptr_vector m_decls;
+
+ void collect_decl2terms() {
// Collect the projected function symbols.
+ m_decl2terms.reset();
+ m_decls.reset();
for (term *t : m_tg.m_terms) {
expr* e = t->get_expr();
if (!is_app(e)) continue;
@@ -787,38 +789,61 @@ namespace qe {
func_decl* d = a->get_decl();
if (d->get_arity() == 0) continue;
unsigned id = d->get_decl_id();
- decl2terms.reserve(id+1);
- if (decl2terms[id].empty()) decls.push_back(d);
- decl2terms[id].push_back(t);
+ m_decl2terms.reserve(id+1);
+ if (m_decl2terms[id].empty()) m_decls.push_back(d);
+ m_decl2terms[id].push_back(t);
}
-
+ }
+
+ void args_are_distinct(expr_ref_vector& res) {
//
// for each projected function that occurs
// (may occur) in multiple congruence classes,
// produce assertions that non-congruent arguments
- // are forced distinct.
+ // are distinct.
//
- for (func_decl* d : decls) {
+ for (func_decl* d : m_decls) {
unsigned id = d->get_decl_id();
- ptr_vector const& terms = decl2terms[id];
+ ptr_vector const& terms = m_decl2terms[id];
if (terms.size() <= 1) continue;
unsigned arity = d->get_arity();
for (unsigned i = 0; i < arity; ++i) {
- obj_hashtable roots;
+ obj_hashtable roots, root_vals;
+ expr_ref_vector pinned(m);
for (term* t : terms) {
expr* arg = to_app(t->get_expr())->get_arg(i);
term const& root = m_tg.get_term(arg)->get_root();
- roots.insert(root.get_expr());
+ expr* r = root.get_expr();
+ // if a model is given, then use the equivalence class induced
+ // by the model. Otherwise, use the congruence class.
+ if (m_model) {
+ expr_ref tmp(m);
+ tmp = (*m_model)(r);
+ if (!root_vals.contains(tmp)) {
+ root_vals.insert(tmp);
+ roots.insert(r);
+ pinned.push_back(tmp);
+ }
+ }
+ else {
+ roots.insert(r);
+ }
}
if (roots.size() > 1) {
ptr_buffer args;
for (expr* r : roots) {
args.push_back(r);
}
+ TRACE("qe", tout << "function: " << d->get_name() << "\n";);
res.push_back(m.mk_distinct(args.size(), args.c_ptr()));
}
}
}
+ }
+
+ void mk_distinct(expr_ref_vector& res) {
+ collect_decl2terms();
+ args_are_distinct(res);
TRACE("qe", tout << res << "\n";);
}
@@ -965,6 +990,7 @@ namespace qe {
m_pinned.reset();
m_model.reset();
}
+
expr_ref_vector project() {
expr_ref_vector res(m);
purify();
diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp
index 2ad5b9b96..d1816d807 100644
--- a/src/qe/qsat.cpp
+++ b/src/qe/qsat.cpp
@@ -549,9 +549,15 @@ namespace qe {
solver& s() { return *m_solver; }
solver const& s() const { return *m_solver; }
- void reset() {
+ void init() {
m_solver = mk_smt_solver(m, m_params, symbol::null);
}
+ void reset_statistics() {
+ init();
+ }
+ void clear() {
+ m_solver = nullptr;
+ }
void assert_expr(expr* e) {
m_solver->assert_expr(e);
}
@@ -696,7 +702,7 @@ namespace qe {
m_level -= num_scopes;
}
- void reset() override {
+ void clear() {
m_st.reset();
m_fa.s().collect_statistics(m_st);
m_ex.s().collect_statistics(m_st);
@@ -707,9 +713,15 @@ namespace qe {
m_pred_abs.reset();
m_vars.reset();
m_model = nullptr;
- m_fa.reset();
- m_ex.reset();
m_free_vars.reset();
+ m_fa.clear();
+ m_ex.clear();
+ }
+
+ void reset() override {
+ clear();
+ m_fa.init();
+ m_ex.init();
}
/**
@@ -1198,7 +1210,7 @@ namespace qe {
}
~qsat() override {
- reset();
+ clear();
}
void updt_params(params_ref const & p) override {
@@ -1294,8 +1306,8 @@ namespace qe {
void reset_statistics() override {
m_stats.reset();
- m_fa.reset();
- m_ex.reset();
+ m_fa.reset_statistics();
+ m_ex.reset_statistics();
}
void cleanup() override {
diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp
index 762939b74..d97e3ee94 100644
--- a/src/sat/ba_solver.cpp
+++ b/src/sat/ba_solver.cpp
@@ -676,7 +676,6 @@ namespace sat {
verbose_stream() << "alit: " << alit << "\n";
verbose_stream() << "num watch " << num_watch << "\n");
UNREACHABLE();
- exit(0);
return l_undef;
}
@@ -1066,7 +1065,7 @@ namespace sat {
uint64_t ba_solver::get_coeff(literal lit) const {
int64_t c1 = get_coeff(lit.var());
- SASSERT(c1 < 0 == lit.sign());
+ SASSERT((c1 < 0) == lit.sign());
int64_t c = std::abs(c1);
m_overflow |= (c != c1);
return static_cast(c);
@@ -2606,7 +2605,6 @@ namespace sat {
IF_VERBOSE(0, s().display_watches(verbose_stream()));
UNREACHABLE();
- exit(1);
return false;
}
}
@@ -2839,7 +2837,7 @@ namespace sat {
void ba_solver::simplify() {
if (!s().at_base_lvl()) s().pop_to_base_level();
- unsigned trail_sz;
+ unsigned trail_sz, count = 0;
do {
trail_sz = s().init_trail_size();
m_simplify_change = false;
@@ -2857,8 +2855,9 @@ namespace sat {
cleanup_clauses();
cleanup_constraints();
update_pure();
+ ++count;
}
- while (m_simplify_change || trail_sz < s().init_trail_size());
+ while (count < 10 && (m_simplify_change || trail_sz < s().init_trail_size()));
IF_VERBOSE(1, verbose_stream() << "(ba.simplify"
<< " :vars " << s().num_vars() - trail_sz
@@ -4141,6 +4140,10 @@ namespace sat {
return out << index2constraint(idx);
}
+ std::ostream& ba_solver::display_constraint(std::ostream& out, ext_constraint_idx idx) const {
+ return out << index2constraint(idx);
+ }
+
void ba_solver::display(std::ostream& out, constraint const& c, bool values) const {
switch (c.tag()) {
case card_t: display(out, c.to_card(), values); break;
diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h
index 141ca0887..dbbc48993 100644
--- a/src/sat/ba_solver.h
+++ b/src/sat/ba_solver.h
@@ -547,6 +547,7 @@ namespace sat {
void flush_roots() override;
std::ostream& display(std::ostream& out) const override;
std::ostream& display_justification(std::ostream& out, ext_justification_idx idx) const override;
+ std::ostream& display_constraint(std::ostream& out, ext_constraint_idx idx) const override;
void collect_statistics(statistics& st) const override;
extension* copy(solver* s) override;
extension* copy(lookahead* s, bool learned) override;
diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp
index 941426321..f89b20897 100644
--- a/src/sat/sat_asymm_branch.cpp
+++ b/src/sat/sat_asymm_branch.cpp
@@ -44,26 +44,32 @@ namespace sat {
unsigned m_elim_literals;
unsigned m_elim_learned_literals;
unsigned m_tr;
+ unsigned m_units;
report(asymm_branch & a):
m_asymm_branch(a),
m_elim_literals(a.m_elim_literals),
- m_elim_learned_literals(a.m_elim_learned_literals),
- m_tr(a.m_tr) {
+ m_elim_learned_literals(a.m_elim_learned_literals),
+ m_tr(a.m_tr),
+ m_units(a.s.init_trail_size()) {
m_watch.start();
}
~report() {
m_watch.stop();
- IF_VERBOSE(SAT_VB_LVL,
+ IF_VERBOSE(2,
unsigned num_learned = (m_asymm_branch.m_elim_learned_literals - m_elim_learned_literals);
unsigned num_total = (m_asymm_branch.m_elim_literals - m_elim_literals);
- verbose_stream()
- << " (sat-asymm-branch :elim-literals " << (num_total - num_learned)
- << " :elim-learned-literals " << num_learned
- << " :hte " << (m_asymm_branch.m_tr - m_tr)
- << " :cost " << m_asymm_branch.m_counter
- << mem_stat()
- << " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << ")\n";);
+ unsigned num_units = (m_asymm_branch.s.init_trail_size() - m_units);
+ unsigned elim_lits = (num_total - num_learned);
+ unsigned tr = (m_asymm_branch.m_tr - m_tr);
+ verbose_stream() << " (sat-asymm-branch";
+ if (elim_lits > 0) verbose_stream() << " :elim-literals " << elim_lits;
+ if (num_learned > 0) verbose_stream() << " :elim-learned-literals " << num_learned;
+ if (num_units > 0) verbose_stream() << " :units " << num_units;
+ if (tr > 0) verbose_stream() << " :hte " << tr;
+ verbose_stream() << " :cost " << m_asymm_branch.m_counter;
+ verbose_stream() << mem_stat();
+ verbose_stream() << m_watch << ")\n";);
}
};
@@ -84,11 +90,11 @@ namespace sat {
if (s.m_inconsistent)
break;
unsigned num_elim = m_elim_literals + m_tr - elim;
- IF_VERBOSE(1, verbose_stream() << "(sat-asymm-branch-step :elim " << num_elim << ")\n";);
+ IF_VERBOSE(4, verbose_stream() << "(sat-asymm-branch-step :elim " << num_elim << ")\n";);
if (num_elim == 0)
break;
}
- IF_VERBOSE(1, if (m_elim_learned_literals > eliml0)
+ IF_VERBOSE(4, if (m_elim_learned_literals > eliml0)
verbose_stream() << "(sat-asymm-branch :elim " << m_elim_learned_literals - eliml0 << ")\n";);
return m_elim_literals > elim0;
}
@@ -98,7 +104,7 @@ namespace sat {
unsigned elim = m_elim_literals;
process(nullptr, s.m_clauses);
s.propagate(false);
- IF_VERBOSE(1, if (m_elim_learned_literals > eliml0)
+ IF_VERBOSE(4, if (m_elim_learned_literals > eliml0)
verbose_stream() << "(sat-asymm-branch :elim " << m_elim_learned_literals - eliml0 << ")\n";);
return m_elim_literals > elim;
}
@@ -342,7 +348,10 @@ namespace sat {
break;
default:
if (!m_to_delete.contains(lit)) {
- c[j++] = lit;
+ if (i != j) {
+ std::swap(c[i], c[j]);
+ }
+ j++;
}
break;
}
@@ -358,7 +367,7 @@ namespace sat {
bool asymm_branch::propagate_literal(clause const& c, literal l) {
SASSERT(!s.inconsistent());
TRACE("asymm_branch_detail", tout << "assigning: " << l << "\n";);
- s.assign(l, justification());
+ s.assign_scoped(l);
s.propagate_core(false); // must not use propagate(), since check_missed_propagation may fail for c
return s.inconsistent();
}
@@ -406,18 +415,19 @@ namespace sat {
bool asymm_branch::re_attach(scoped_detach& scoped_d, clause& c, unsigned new_sz) {
VERIFY(s.m_trail.size() == s.m_qhead);
- m_elim_literals += c.size() - new_sz;
+ unsigned old_sz = c.size();
+ m_elim_literals += old_sz - new_sz;
if (c.is_learned()) {
- m_elim_learned_literals += c.size() - new_sz;
+ m_elim_learned_literals += old_sz - new_sz;
}
- switch(new_sz) {
+ switch (new_sz) {
case 0:
- s.set_conflict(justification());
+ s.set_conflict();
return false;
case 1:
TRACE("asymm_branch", tout << "produced unit clause: " << c[0] << "\n";);
- s.assign(c[0], justification());
+ s.assign_unit(c[0]);
s.propagate_core(false);
scoped_d.del_clause();
return false; // check_missed_propagation() may fail, since m_clauses is not in a consistent state.
@@ -430,8 +440,12 @@ namespace sat {
return false;
default:
c.shrink(new_sz);
- if (s.m_config.m_drat) s.m_drat.add(c, true);
- // if (s.m_config.m_drat) s.m_drat.del(c0); // TBD
+ if (s.m_config.m_drat && new_sz < old_sz) {
+ s.m_drat.add(c, true);
+ c.restore(old_sz);
+ s.m_drat.del(c);
+ c.shrink(new_sz);
+ }
return true;
}
}
@@ -502,8 +516,8 @@ namespace sat {
}
void asymm_branch::collect_statistics(statistics & st) const {
- st.update("elim literals", m_elim_literals);
- st.update("tr", m_tr);
+ st.update("sat elim literals", m_elim_literals);
+ st.update("sat tr", m_tr);
}
void asymm_branch::reset_statistics() {
diff --git a/src/sat/sat_big.cpp b/src/sat/sat_big.cpp
index c1eeecd27..f327bc607 100644
--- a/src/sat/sat_big.cpp
+++ b/src/sat/sat_big.cpp
@@ -164,22 +164,23 @@ namespace sat {
DEBUG_CODE(for (unsigned i = 0; i < num_lits; ++i) { VERIFY(m_left[i] < m_right[i]);});
}
- // svector> big::s_del_bin;
bool big::in_del(literal u, literal v) const {
if (u.index() > v.index()) std::swap(u, v);
- return m_del_bin.contains(std::make_pair(u, v));
+ return m_del_bin[u.index()].contains(v);
}
void big::add_del(literal u, literal v) {
if (u.index() > v.index()) std::swap(u, v);
- m_del_bin.push_back(std::make_pair(u, v));
+
+ m_del_bin[u.index()].push_back(v);
}
unsigned big::reduce_tr(solver& s) {
unsigned idx = 0;
unsigned elim = 0;
m_del_bin.reset();
+ m_del_bin.reserve(s.m_watches.size());
for (watch_list & wlist : s.m_watches) {
if (s.inconsistent()) break;
literal u = to_literal(idx++);
@@ -198,7 +199,7 @@ namespace sat {
s.add_ate(~u, v);
if (find_binary_watch(wlist, ~v)) {
IF_VERBOSE(10, verbose_stream() << "binary: " << ~u << "\n");
- s.assign(~u, justification());
+ s.assign_unit(~u);
}
// could turn non-learned non-binary tautology into learned binary.
s.get_wlist(~v).erase(watched(~u, w.is_learned()));
@@ -210,23 +211,6 @@ namespace sat {
}
wlist.set_end(itprev);
}
-
-#if 0
- s_del_bin.append(m_del_bin);
- IF_VERBOSE(1,
- display(verbose_stream() << "Learned: " << learned() << ":");
- verbose_stream() << "del-bin\n";
- for (auto p : m_del_bin) {
- verbose_stream() << p.first << " " << p.second << "\n";
- if (safe_reach(~p.first, p.second)) {
- display_path(verbose_stream(), ~p.first, p.second) << " " << "\n";
- }
- else {
- display_path(verbose_stream(), ~p.second, p.first) << " " << "\n";
- }
- }
- );
-#endif
s.propagate(false);
return elim;
}
diff --git a/src/sat/sat_big.h b/src/sat/sat_big.h
index 25093fd60..e682f9dfc 100644
--- a/src/sat/sat_big.h
+++ b/src/sat/sat_big.h
@@ -36,7 +36,7 @@ namespace sat {
bool m_learned;
bool m_include_cardinality;
- svector> m_del_bin;
+ vector > m_del_bin;
void init_dfs_num();
diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp
index 3cbd3015b..d27820e71 100644
--- a/src/sat/sat_clause.cpp
+++ b/src/sat/sat_clause.cpp
@@ -94,6 +94,11 @@ namespace sat {
mark_strengthened();
}
}
+
+ void clause::restore(unsigned num_lits) {
+ SASSERT(num_lits <= m_capacity);
+ m_size = num_lits;
+ }
bool clause::satisfied_by(model const & m) const {
for (literal l : *this) {
@@ -111,7 +116,7 @@ namespace sat {
clause_offset clause::get_new_offset() const {
unsigned o1 = m_lits[0].index();
-#if defined(_AMD64_) || defined(_M_IA64)
+#if defined(__LP64__) || defined(_WIN64)
if (sizeof(clause_offset) == 8) {
unsigned o2 = m_lits[1].index();
return (clause_offset)o1 + (((clause_offset)o2) << 32);
@@ -122,7 +127,7 @@ namespace sat {
void clause::set_new_offset(clause_offset offset) {
m_lits[0] = to_literal(static_cast(offset));
-#if defined(_AMD64_) || defined(_M_IA64)
+#if defined(__LP64__) || defined(_WIN64)
if (sizeof(offset) == 8) {
m_lits[1] = to_literal(static_cast(offset >> 32));
}
diff --git a/src/sat/sat_clause.h b/src/sat/sat_clause.h
index f95696b3d..ca46063ac 100644
--- a/src/sat/sat_clause.h
+++ b/src/sat/sat_clause.h
@@ -68,6 +68,7 @@ namespace sat {
bool is_learned() const { return m_learned; }
void set_learned(bool l) { SASSERT(is_learned() != l); m_learned = l; }
void shrink(unsigned num_lits);
+ void restore(unsigned num_lits);
bool strengthened() const { return m_strengthened; }
void mark_strengthened() { m_strengthened = true; update_approx(); }
void unmark_strengthened() { m_strengthened = false; }
diff --git a/src/sat/sat_cleaner.cpp b/src/sat/sat_cleaner.cpp
index c0c6fabe4..093e6221f 100644
--- a/src/sat/sat_cleaner.cpp
+++ b/src/sat/sat_cleaner.cpp
@@ -88,12 +88,10 @@ namespace sat {
CTRACE("sat_cleaner_frozen", c.frozen(), tout << c << "\n";);
unsigned sz = c.size();
unsigned i = 0, j = 0;
- bool sat = false;
m_cleanup_counter += sz;
for (; i < sz; i++) {
switch (s.value(c[i])) {
case l_true:
- sat = true;
goto end_loop;
case l_false:
m_elim_literals++;
@@ -108,9 +106,9 @@ namespace sat {
}
end_loop:
CTRACE("sat_cleaner_frozen", c.frozen(),
- tout << "sat: " << sat << ", new_size: " << j << "\n";
+ tout << "sat: " << (i < sz) << ", new_size: " << j << "\n";
tout << mk_lits_pp(j, c.begin()) << "\n";);
- if (sat) {
+ if (i < sz) {
m_elim_clauses++;
s.del_clause(c);
}
@@ -119,34 +117,35 @@ namespace sat {
CTRACE("sat_cleaner_bug", new_sz < 2, tout << "new_sz: " << new_sz << "\n";
if (c.size() > 0) tout << "unit: " << c[0] << "\n";
s.display_watches(tout););
- if (new_sz == 0) {
- s.set_conflict(justification());
+ switch (new_sz) {
+ case 0:
+ s.set_conflict();
s.del_clause(c);
- }
- else if (new_sz == 1) {
- s.assign(c[0], justification());
+ break;
+ case 1:
+ s.assign_unit(c[0]);
s.del_clause(c);
- }
- else {
+ break;
+ case 2:
SASSERT(s.value(c[0]) == l_undef && s.value(c[1]) == l_undef);
- if (new_sz == 2) {
- TRACE("cleanup_bug", tout << "clause became binary: " << c[0] << " " << c[1] << "\n";);
- s.mk_bin_clause(c[0], c[1], c.is_learned());
- s.del_clause(c);
+ TRACE("cleanup_bug", tout << "clause became binary: " << c[0] << " " << c[1] << "\n";);
+ s.mk_bin_clause(c[0], c[1], c.is_learned());
+ s.del_clause(c);
+ break;
+ default:
+ c.shrink(new_sz);
+ *it2 = *it;
+ it2++;
+ if (!c.frozen()) {
+ s.attach_clause(c);
}
- else {
+ if (s.m_config.m_drat && new_sz < sz) {
+ s.m_drat.add(c, true);
+ c.restore(sz);
+ s.m_drat.del(c);
c.shrink(new_sz);
- *it2 = *it;
- it2++;
- if (!c.frozen()) {
- s.attach_clause(c);
- }
- if (s.m_config.m_drat) {
- // for optimization, could also report deletion
- // of previous version of clause.
- s.m_drat.add(c, true);
- }
}
+ break;
}
}
}
@@ -166,12 +165,11 @@ namespace sat {
}
~report() {
m_watch.stop();
- IF_VERBOSE(SAT_VB_LVL,
- verbose_stream() << " (sat-cleaner :elim-literals " << (m_cleaner.m_elim_literals - m_elim_literals)
- << " :elim-clauses " << (m_cleaner.m_elim_clauses - m_elim_clauses)
- << " :cost " << m_cleaner.m_cleanup_counter
- << mk_stat(m_cleaner.s)
- << " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << ")\n";);
+ IF_VERBOSE(2,
+ verbose_stream() << " (sat-cleaner";
+ verbose_stream() << " :elim-literals " << (m_cleaner.m_elim_literals - m_elim_literals);
+ verbose_stream() << " :elim-clauses " << (m_cleaner.m_elim_clauses - m_elim_clauses);
+ verbose_stream() << " :cost " << m_cleaner.m_cleanup_counter << m_watch << ")\n";);
}
};
@@ -192,10 +190,14 @@ namespace sat {
report rpt(*this);
m_last_num_units = trail_sz;
m_cleanup_counter = 0;
- cleanup_watches();
- cleanup_clauses(s.m_clauses);
- cleanup_clauses(s.m_learned);
- s.propagate(false);
+ do {
+ trail_sz = s.m_trail.size();
+ cleanup_watches();
+ cleanup_clauses(s.m_clauses);
+ cleanup_clauses(s.m_learned);
+ s.propagate(false);
+ }
+ while (trail_sz < s.m_trail.size());
CASSERT("cleaner_bug", s.check_invariant());
return true;
}
@@ -206,8 +208,8 @@ namespace sat {
}
void cleaner::collect_statistics(statistics & st) const {
- st.update("elim clauses", m_elim_clauses);
- st.update("elim literals", m_elim_literals);
+ st.update("sat elim clauses", m_elim_clauses);
+ st.update("sat elim literals", m_elim_literals);
}
};
diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp
index 423a5f532..08336b1e4 100644
--- a/src/sat/sat_config.cpp
+++ b/src/sat/sat_config.cpp
@@ -90,6 +90,7 @@ namespace sat {
m_unit_walk = p.unit_walk();
m_unit_walk_threads = p.unit_walk_threads();
m_lookahead_simplify = p.lookahead_simplify();
+ m_lookahead_double = p.lookahead_double();
m_lookahead_simplify_bca = p.lookahead_simplify_bca();
if (p.lookahead_reward() == symbol("heule_schur"))
m_lookahead_reward = heule_schur_reward;
@@ -123,13 +124,16 @@ namespace sat {
m_lookahead_cube_psat_clause_base = p.lookahead_cube_psat_clause_base();
m_lookahead_cube_psat_trigger = p.lookahead_cube_psat_trigger();
m_lookahead_global_autarky = p.lookahead_global_autarky();
+ m_lookahead_delta_fraction = p.lookahead_delta_fraction();
m_lookahead_use_learned = p.lookahead_use_learned();
-
+ if (m_lookahead_delta_fraction < 0 || m_lookahead_delta_fraction > 1.0) {
+ throw sat_param_exception("invalid value for delta fraction. It should be a number in the interval 0 to 1");
+ }
// These parameters are not exposed
- m_next_simplify1 = _p.get_uint("next_simplify", 30000);
+ m_next_simplify1 = _p.get_uint("next_simplify", 90000);
m_simplify_mult2 = _p.get_double("simplify_mult2", 1.5);
- m_simplify_max = _p.get_uint("simplify_max", 500000);
+ m_simplify_max = _p.get_uint("simplify_max", 1000000);
// --------------------------------
m_simplify_delay = p.simplify_delay();
@@ -162,6 +166,7 @@ namespace sat {
m_drat_check_sat = p.drat_check_sat();
m_drat_file = p.drat_file();
m_drat = (m_drat_check_unsat || m_drat_file != symbol("") || m_drat_check_sat) && p.threads() == 1;
+ m_drat_binary = p.drat_binary();
m_dyn_sub_res = p.dyn_sub_res();
// Parameters used in Liang, Ganesh, Poupart, Czarnecki AAAI 2016.
diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h
index 4d33225f0..b8d0ca0f5 100644
--- a/src/sat/sat_config.h
+++ b/src/sat/sat_config.h
@@ -128,7 +128,9 @@ namespace sat {
double m_lookahead_cube_psat_clause_base;
double m_lookahead_cube_psat_trigger;
reward_t m_lookahead_reward;
+ bool m_lookahead_double;
bool m_lookahead_global_autarky;
+ double m_lookahead_delta_fraction;
bool m_lookahead_use_learned;
bool m_incremental;
@@ -155,6 +157,7 @@ namespace sat {
bool m_core_minimize;
bool m_core_minimize_partial;
bool m_drat;
+ bool m_drat_binary;
symbol m_drat_file;
bool m_drat_check_unsat;
bool m_drat_check_sat;
diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp
index 932e9b35e..ac05b50f1 100644
--- a/src/sat/sat_drat.cpp
+++ b/src/sat/sat_drat.cpp
@@ -27,18 +27,26 @@ namespace sat {
drat::drat(solver& s):
s(s),
m_out(nullptr),
+ m_bout(nullptr),
m_inconsistent(false),
m_check_unsat(false),
m_check_sat(false),
m_check(false)
{
if (s.m_config.m_drat && s.m_config.m_drat_file != symbol()) {
- m_out = alloc(std::ofstream, s.m_config.m_drat_file.str().c_str());
+ auto mode = s.m_config.m_drat_binary ? (std::ios_base::binary | std::ios_base::out | std::ios_base::trunc) : std::ios_base::out;
+ m_out = alloc(std::ofstream, s.m_config.m_drat_file.str().c_str(), mode);
+ if (s.m_config.m_drat_binary) {
+ std::swap(m_out, m_bout);
+ }
}
}
drat::~drat() {
+ if (m_out) m_out->flush();
+ if (m_bout) m_bout->flush();
dealloc(m_out);
+ dealloc(m_bout);
for (unsigned i = 0; i < m_proof.size(); ++i) {
clause* c = m_proof[i];
if (c && (c->size() == 2 || m_status[i] == status::deleted || m_status[i] == status::external)) {
@@ -64,14 +72,75 @@ namespace sat {
}
void drat::dump(unsigned n, literal const* c, status st) {
+ if (st == status::asserted || st == status::external) {
+ return;
+ }
+
+ char buffer[10000];
+ char digits[20]; // enough for storing unsigned
+ char* lastd = digits + sizeof(digits);
+
+ int len = 0;
+ if (st == status::deleted) {
+ buffer[0] = 'd';
+ buffer[1] = ' ';
+ len = 2;
+ }
+ for (unsigned i = 0; i < n; ++i) {
+ literal lit = c[i];
+ unsigned v = lit.var();
+ if (lit.sign()) buffer[len++] = '-';
+ char* d = lastd;
+ while (v > 0) {
+ d--;
+ *d = (v % 10) + '0';
+ v /= 10;
+ SASSERT(d > digits);
+ }
+ SASSERT(len + lastd - d < sizeof(buffer));
+ memcpy(buffer + len, d, lastd - d);
+ len += static_cast(lastd - d);
+ buffer[len++] = ' ';
+ if (len + 50 > sizeof(buffer)) {
+ m_out->write(buffer, len);
+ len = 0;
+ }
+ }
+ buffer[len++] = '0';
+ buffer[len++] = '\n';
+ m_out->write(buffer, len);
+ }
+
+ void drat::bdump(unsigned n, literal const* c, status st) {
+ unsigned char ch = 0;
switch (st) {
case status::asserted: return;
- case status::external: return; // requires extension to drat format.
- case status::learned: break;
- case status::deleted: (*m_out) << "d "; break;
+ case status::external: return;
+ case status::learned: ch = 'a'; break;
+ case status::deleted: ch = 'd'; break;
+ default: UNREACHABLE(); break;
}
- for (unsigned i = 0; i < n; ++i) (*m_out) << c[i] << " ";
- (*m_out) << "0\n";
+ char buffer[10000];
+ int len = 0;
+ buffer[len++] = ch;
+
+ for (unsigned i = 0; i < n; ++i) {
+ literal lit = c[i];
+ unsigned v = 2 * lit.var() + (lit.sign() ? 1 : 0);
+ do {
+ ch = static_cast(v & 255);
+ v >>= 7;
+ if (v) ch |= 128;
+ buffer[len++] = ch;
+ if (len == sizeof(buffer)) {
+ m_bout->write(buffer, len);
+ len = 0;
+ }
+ }
+ while (v);
+ }
+ buffer[len++] = 0;
+ m_bout->write(buffer, len);
}
bool drat::is_cleaned(clause& c) const {
@@ -104,7 +173,13 @@ namespace sat {
if (st == status::deleted) {
return;
}
- assign_propagate(l);
+ if (m_check_unsat) {
+ assign_propagate(l);
+ }
+
+ clause* c = s.alloc_clause(1, &l, st == status::learned);
+ m_proof.push_back(c);
+ m_status.push_back(st);
}
void drat::append(literal l1, literal l2, status st) {
@@ -121,6 +196,7 @@ namespace sat {
clause* c = s.alloc_clause(2, lits, st == status::learned);
m_proof.push_back(c);
m_status.push_back(st);
+ if (!m_check_unsat) return;
unsigned idx = m_watched_clauses.size();
m_watched_clauses.push_back(watched_clause(c, l1, l2));
m_watches[(~l1).index()].push_back(idx);
@@ -143,14 +219,14 @@ namespace sat {
IF_VERBOSE(20, trace(verbose_stream(), n, c.begin(), st););
if (st == status::learned) {
- verify(n, c.begin());
+ verify(c);
}
m_status.push_back(st);
m_proof.push_back(&c);
if (st == status::deleted) {
- del_watch(c, c[0]);
- del_watch(c, c[1]);
+ if (n > 0) del_watch(c, c[0]);
+ if (n > 1) del_watch(c, c[1]);
return;
}
unsigned num_watch = 0;
@@ -215,16 +291,70 @@ namespace sat {
if (!m_inconsistent) {
DEBUG_CODE(validate_propagation(););
}
- for (unsigned i = 0; i < m_units.size(); ++i) {
- SASSERT(m_assignment[m_units[i].var()] != l_undef);
+ DEBUG_CODE(
+ for (literal u : m_units) {
+ SASSERT(m_assignment[u.var()] != l_undef);
+ });
+
+#if 0
+ if (!m_inconsistent) {
+ literal_vector lits(n, c);
+ IF_VERBOSE(0, verbose_stream() << "not drup " << lits << "\n");
+ for (unsigned v = 0; v < m_assignment.size(); ++v) {
+ lbool val = m_assignment[v];
+ if (val != l_undef) {
+ IF_VERBOSE(0, verbose_stream() << literal(v, false) << " |-> " << val << "\n");
+ }
+ }
+ for (clause* cp : s.m_clauses) {
+ clause& cl = *cp;
+ bool found = false;
+ for (literal l : cl) {
+ if (m_assignment[l.var()] != (l.sign() ? l_true : l_false)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ IF_VERBOSE(0, verbose_stream() << "Clause is false under assignment: " << cl << "\n");
+ }
+ }
+ for (clause* cp : s.m_learned) {
+ clause& cl = *cp;
+ bool found = false;
+ for (literal l : cl) {
+ if (m_assignment[l.var()] != (l.sign() ? l_true : l_false)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ IF_VERBOSE(0, verbose_stream() << "Clause is false under assignment: " << cl << "\n");
+ }
+ }
+ svector bin;
+ s.collect_bin_clauses(bin, true);
+ for (auto & b : bin) {
+ bool found = false;
+ if (m_assignment[b.first.var()] != (b.first.sign() ? l_true : l_false)) found = true;
+ if (m_assignment[b.second.var()] != (b.second.sign() ? l_true : l_false)) found = true;
+ if (!found) {
+ IF_VERBOSE(0, verbose_stream() << "Bin clause is false under assignment: " << b.first << " " << b.second << "\n");
+ }
+ }
+ IF_VERBOSE(0, s.display(verbose_stream()));
+ exit(0);
}
+#endif
for (unsigned i = num_units; i < m_units.size(); ++i) {
m_assignment[m_units[i].var()] = l_undef;
}
- m_units.resize(num_units);
+ m_units.shrink(num_units);
bool ok = m_inconsistent;
+ IF_VERBOSE(9, verbose_stream() << "is-drup " << m_inconsistent << "\n");
m_inconsistent = false;
+
return ok;
}
@@ -239,7 +369,7 @@ namespace sat {
void drat::validate_propagation() const {
for (unsigned i = 0; i < m_proof.size(); ++i) {
status st = m_status[i];
- if (m_proof[i] && st != status::deleted) {
+ if (m_proof[i] && m_proof[i]->size() > 1 && st != status::deleted) {
clause& c = *m_proof[i];
unsigned num_undef = 0, num_true = 0;
for (unsigned j = 0; j < c.size(); ++j) {
@@ -262,7 +392,7 @@ namespace sat {
SASSERT(lits.size() == n);
for (unsigned i = 0; i < m_proof.size(); ++i) {
status st = m_status[i];
- if (m_proof[i] && (st == status::asserted || st == status::external)) {
+ if (m_proof[i] && m_proof[i]->size() > 1 && (st == status::asserted || st == status::external)) {
clause& c = *m_proof[i];
unsigned j = 0;
for (; j < c.size() && c[j] != ~l; ++j) {}
@@ -279,8 +409,18 @@ namespace sat {
}
void drat::verify(unsigned n, literal const* c) {
- if (m_check_unsat && !is_drup(n, c) && !is_drat(n, c)) {
- std::cout << "Verification failed\n";
+ if (!m_check_unsat) {
+ return;
+ }
+ for (unsigned i = 0; i < n; ++i) {
+ declare(c[i]);
+ }
+ if (!is_drup(n, c) && !is_drat(n, c)) {
+ literal_vector lits(n, c);
+ std::cout << "Verification of " << lits << " failed\n";
+ s.display(std::cout);
+ SASSERT(false);
+ exit(0);
UNREACHABLE();
//display(std::cout);
TRACE("sat",
@@ -288,10 +428,39 @@ namespace sat {
display(tout);
s.display(tout););
UNREACHABLE();
- exit(0);
}
}
+ bool drat::contains(unsigned n, literal const* lits) {
+ if (!m_check) return true;
+ for (unsigned i = m_proof.size(); i-- > 0; ) {
+ clause& c = *m_proof[i];
+ status st = m_status[i];
+ if (match(n, lits, c)) {
+ return st != status::deleted;
+ }
+ }
+ return false;
+ }
+
+ bool drat::match(unsigned n, literal const* lits, clause const& c) const {
+ if (n == c.size()) {
+ for (unsigned i = 0; i < n; ++i) {
+ literal lit1 = lits[i];
+ bool found = false;
+ for (literal lit2 : c) {
+ if (lit1 == lit2) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
void drat::display(std::ostream& out) const {
out << "units: " << m_units << "\n";
for (unsigned i = 0; i < m_assignment.size(); ++i) {
@@ -421,22 +590,27 @@ namespace sat {
void drat::add() {
if (m_out) (*m_out) << "0\n";
+ if (m_bout) bdump(0, nullptr, status::learned);
if (m_check_unsat) {
SASSERT(m_inconsistent);
}
}
void drat::add(literal l, bool learned) {
+ TRACE("sat", tout << "add: " << l << " " << (learned?"l":"t") << "\n";);
declare(l);
status st = get_status(learned);
if (m_out) dump(1, &l, st);
+ if (m_bout) bdump(1, &l, st);
if (m_check) append(l, st);
}
void drat::add(literal l1, literal l2, bool learned) {
+ TRACE("sat", tout << "add: " << l1 << " " << l2 << " " << (learned?"l":"t") << "\n";);
declare(l1);
declare(l2);
literal ls[2] = {l1, l2};
status st = get_status(learned);
if (m_out) dump(2, ls, st);
+ if (m_bout) bdump(2, ls, st);
if (m_check) append(l1, l2, st);
}
void drat::add(clause& c, bool learned) {
@@ -444,6 +618,7 @@ namespace sat {
for (unsigned i = 0; i < c.size(); ++i) declare(c[i]);
status st = get_status(learned);
if (m_out) dump(c.size(), c.begin(), st);
+ if (m_bout) bdump(c.size(), c.begin(), st);
if (m_check_unsat) append(c, get_status(learned));
}
void drat::add(literal_vector const& lits, svector const& premises) {
@@ -462,6 +637,7 @@ namespace sat {
void drat::add(literal_vector const& c) {
for (unsigned i = 0; i < c.size(); ++i) declare(c[i]);
if (m_out) dump(c.size(), c.begin(), status::learned);
+ if (m_bout) bdump(c.size(), c.begin(), status::learned);
if (m_check) {
switch (c.size()) {
case 0: add(); break;
@@ -478,25 +654,39 @@ namespace sat {
void drat::del(literal l) {
if (m_out) dump(1, &l, status::deleted);
+ if (m_bout) bdump(1, &l, status::deleted);
if (m_check_unsat) append(l, status::deleted);
}
void drat::del(literal l1, literal l2) {
literal ls[2] = {l1, l2};
if (m_out) dump(2, ls, status::deleted);
- if (m_check)
- append(l1, l2, status::deleted);
+ if (m_bout) bdump(2, ls, status::deleted);
+ if (m_check) append(l1, l2, status::deleted);
}
+
void drat::del(clause& c) {
+
+#if 0
+ // check_duplicates:
+ for (literal lit : c) {
+ VERIFY(!m_seen[lit.index()]);
+ m_seen[lit.index()] = true;
+ }
+ for (literal lit : c) {
+ m_seen[lit.index()] = false;
+ }
+#endif
+
TRACE("sat", tout << "del: " << c << "\n";);
if (m_out) dump(c.size(), c.begin(), status::deleted);
+ if (m_bout) bdump(c.size(), c.begin(), status::deleted);
if (m_check) {
clause* c1 = s.alloc_clause(c.size(), c.begin(), c.is_learned());
append(*c1, status::deleted);
}
}
- void drat::check_model(model const& m) {
- std::cout << "check model on " << m_proof.size() << "\n";
+ void drat::check_model(model const& m) {
}
}
diff --git a/src/sat/sat_drat.h b/src/sat/sat_drat.h
index 64d796839..35e5a0655 100644
--- a/src/sat/sat_drat.h
+++ b/src/sat/sat_drat.h
@@ -46,6 +46,7 @@ namespace sat {
typedef svector watch;
solver& s;
std::ostream* m_out;
+ std::ostream* m_bout;
ptr_vector m_proof;
svector m_status;
literal_vector m_units;
@@ -55,6 +56,7 @@ namespace sat {
bool m_check_unsat, m_check_sat, m_check;
void dump(unsigned n, literal const* c, status st);
+ void bdump(unsigned n, literal const* c, status st);
void append(literal l, status st);
void append(literal l1, literal l2, status st);
void append(clause& c, status st);
@@ -67,7 +69,6 @@ namespace sat {
void propagate(literal l);
void assign_propagate(literal l);
void del_watch(clause& c, literal l);
- void verify(unsigned n, literal const* c);
bool is_drup(unsigned n, literal const* c);
bool is_drat(unsigned n, literal const* c);
bool is_drat(unsigned n, literal const* c, unsigned pos);
@@ -75,6 +76,7 @@ namespace sat {
void trace(std::ostream& out, unsigned n, literal const* c, status st);
void display(std::ostream& out) const;
void validate_propagation() const;
+ bool match(unsigned n, literal const* lits, clause const& c) const;
public:
drat(solver& s);
@@ -93,6 +95,16 @@ namespace sat {
void del(literal l1, literal l2);
void del(clause& c);
+ void verify(clause const& c) { verify(c.size(), c.begin()); }
+ void verify(unsigned n, literal const* c);
+ void verify(literal l1, literal l2) { literal lits[2] = {l1, l2}; verify(2, lits); }
+ void verify(literal l1, literal l2, literal l3) { literal lits[3] = {l1, l2, l3}; verify(3, lits); }
+
+ bool contains(clause const& c) { return contains(c.size(), c.begin()); }
+ bool contains(unsigned n, literal const* c);
+ bool contains(literal l1, literal l2) { literal lits[2] = {l1, l2}; return contains(2, lits); }
+ bool contains(literal l1, literal l2, literal l3) { literal lits[3] = {l1, l2, l3}; return contains(3, lits); }
+
void check_model(model const& m);
};
diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp
index 870aa7fe2..bc69c1f5d 100644
--- a/src/sat/sat_elim_eqs.cpp
+++ b/src/sat/sat_elim_eqs.cpp
@@ -23,9 +23,15 @@ Revision History:
namespace sat {
elim_eqs::elim_eqs(solver & s):
- m_solver(s) {
+ m_solver(s),
+ m_to_delete(nullptr) {
}
+ elim_eqs::~elim_eqs() {
+ dealloc(m_to_delete);
+ }
+
+
inline literal norm(literal_vector const & roots, literal l) {
if (l.sign())
return ~roots[l.var()];
@@ -47,7 +53,7 @@ namespace sat {
literal l2 = it->get_literal();
literal r2 = norm(roots, l2);
if (r1 == r2) {
- m_solver.assign(r1, justification());
+ m_solver.assign_unit(r1);
if (m_solver.inconsistent())
return;
// consume unit
@@ -86,6 +92,12 @@ namespace sat {
m_new_bin.reset();
}
+ void elim_eqs::drat_delete_clause() {
+ if (m_solver.m_config.m_drat) {
+ m_solver.m_drat.del(*m_to_delete->get());
+ }
+ }
+
void elim_eqs::cleanup_clauses(literal_vector const & roots, clause_vector & cs) {
clause_vector::iterator it = cs.begin();
clause_vector::iterator it2 = it;
@@ -107,8 +119,16 @@ namespace sat {
it2++;
continue;
}
- if (!c.frozen())
+ if (!c.frozen()) {
m_solver.detach_clause(c);
+ }
+
+ // save clause to be deleted for drat
+ if (m_solver.m_config.m_drat) {
+ if (!m_to_delete) m_to_delete = alloc(tmp_clause);
+ m_to_delete->set(sz, c.begin(), c.is_learned());
+ }
+
// apply substitution
for (i = 0; i < sz; i++) {
literal lit = c[i];
@@ -124,60 +144,72 @@ namespace sat {
CTRACE("sat", l != norm(roots, l), tout << l << " " << norm(roots, l) << "\n"; tout.flush(););
SASSERT(l == norm(roots, l));
} });
+
// remove duplicates, and check if it is a tautology
- literal l_prev = null_literal;
unsigned j = 0;
+ literal l_prev = null_literal;
for (i = 0; i < sz; i++) {
literal l = c[i];
- if (l == l_prev)
- continue;
- if (l == ~l_prev)
+ if (l == ~l_prev) {
break;
+ }
+ if (l == l_prev) {
+ continue;
+ }
+ SASSERT(l != ~l_prev);
l_prev = l;
lbool val = m_solver.value(l);
- if (val == l_true)
- break; // clause was satisfied
- if (val == l_false)
+ if (val == l_true) {
+ break;
+ }
+ if (val == l_false) {
continue; // skip
+ }
c[j] = l;
j++;
}
+ TRACE("elim_eqs", tout << "after removing duplicates: " << c << " j: " << j << "\n";);
+
if (i < sz) {
- // clause is a tautology or was simplified to true
+ drat_delete_clause();
+ c.set_removed(true);
m_solver.del_clause(c);
continue;
}
- if (j == 0) {
- // empty clause
- m_solver.set_conflict(justification());
+
+ switch (j) {
+ case 0:
+ m_solver.set_conflict();
for (; it != end; ++it) {
*it2 = *it;
it2++;
}
cs.set_end(it2);
- return;
- }
- TRACE("elim_eqs", tout << "after removing duplicates: " << c << " j: " << j << "\n";);
-
- SASSERT(j >= 1);
- switch (j) {
+ return;
case 1:
- m_solver.assign(c[0], justification());
+ m_solver.assign_unit(c[0]);
+ drat_delete_clause();
+ c.set_removed(true);
m_solver.del_clause(c);
break;
case 2:
m_solver.mk_bin_clause(c[0], c[1], c.is_learned());
+ drat_delete_clause();
+ c.set_removed(true);
m_solver.del_clause(c);
break;
default:
SASSERT(*it == &c);
if (j < sz) {
- if (m_solver.m_config.m_drat) m_solver.m_drat.del(c);
c.shrink(j);
- if (m_solver.m_config.m_drat) m_solver.m_drat.add(c, true);
}
- else
+ else {
c.update_approx();
+ }
+ if (m_solver.m_config.m_drat) {
+ m_solver.m_drat.add(c, true);
+ drat_delete_clause();
+ }
DEBUG_CODE(for (literal l : c) VERIFY(l == norm(roots, l)););
diff --git a/src/sat/sat_elim_eqs.h b/src/sat/sat_elim_eqs.h
index 143fcbb3f..ac132b213 100644
--- a/src/sat/sat_elim_eqs.h
+++ b/src/sat/sat_elim_eqs.h
@@ -23,6 +23,7 @@ Revision History:
namespace sat {
class solver;
+ class tmp_clause;
class elim_eqs {
struct bin {
@@ -32,6 +33,8 @@ namespace sat {
};
svector m_new_bin;
solver & m_solver;
+ tmp_clause* m_to_delete;
+ void drat_delete_clause();
void save_elim(literal_vector const & roots, bool_var_vector const & to_elim);
void cleanup_clauses(literal_vector const & roots, clause_vector & cs);
void cleanup_bin_watches(literal_vector const & roots);
@@ -39,6 +42,7 @@ namespace sat {
bool check_clause(clause const& c, literal_vector const& roots) const;
public:
elim_eqs(solver & s);
+ ~elim_eqs();
void operator()(literal_vector const & roots, bool_var_vector const & to_elim);
};
diff --git a/src/sat/sat_elim_vars.cpp b/src/sat/sat_elim_vars.cpp
index 299fbace1..1759ec2ad 100644
--- a/src/sat/sat_elim_vars.cpp
+++ b/src/sat/sat_elim_vars.cpp
@@ -167,10 +167,9 @@ namespace sat{
if (simp.cleanup_clause(c))
return;
- if (v0 == 39063) IF_VERBOSE(0, verbose_stream() << "bdd: " << c << "\n");
switch (c.size()) {
case 0:
- s.set_conflict(justification());
+ s.set_conflict();
break;
case 1:
simp.propagate_unit(c[0]);
diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h
index 41aebb97e..446569e84 100644
--- a/src/sat/sat_extension.h
+++ b/src/sat/sat_extension.h
@@ -70,6 +70,7 @@ namespace sat {
virtual lbool get_phase(bool_var v) = 0;
virtual std::ostream& display(std::ostream& out) const = 0;
virtual std::ostream& display_justification(std::ostream& out, ext_justification_idx idx) const = 0;
+ virtual std::ostream& display_constraint(std::ostream& out, ext_constraint_idx idx) const = 0;
virtual void collect_statistics(statistics& st) const = 0;
virtual extension* copy(solver* s) = 0;
virtual extension* copy(lookahead* s, bool learned) = 0;
diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp
index b65abfd23..cdb90e2a0 100644
--- a/src/sat/sat_local_search.cpp
+++ b/src/sat/sat_local_search.cpp
@@ -26,7 +26,8 @@ Notes:
namespace sat {
void local_search::init() {
-
+ flet _init(m_initializing, true);
+ m_unsat_stack.reset();
for (unsigned i = 0; i < m_assumptions.size(); ++i) {
add_clause(1, m_assumptions.c_ptr() + i);
}
@@ -37,7 +38,7 @@ namespace sat {
if (m_config.phase_sticky()) {
for (var_info& vi : m_vars)
if (!vi.m_unit)
- vi.m_value = vi.m_bias < 100;
+ vi.m_value = vi.m_bias > 50;
}
else {
for (var_info& vi : m_vars)
@@ -45,42 +46,14 @@ namespace sat {
vi.m_value = (0 == (m_rand() % 2));
}
- m_best_solution.resize(num_vars() + 1, false);
m_index_in_unsat_stack.resize(num_constraints(), 0);
- coefficient_in_ob_constraint.resize(num_vars() + 1, 0);
-
- if (m_config.mode() == local_search_mode::gsat) {
- uint_set is_neighbor;
- for (bool_var v = 0; v < num_vars(); ++v) {
- is_neighbor.reset();
- bool pol = true;
- var_info& vi = m_vars[v];
- for (unsigned k = 0; k < 2; pol = !pol, k++) {
- for (auto const& wi : m_vars[v].m_watch[pol]) {
- constraint const& c = m_constraints[wi.m_constraint_id];
- for (literal lit : c) {
- bool_var w = lit.var();
- if (w == v || is_neighbor.contains(w)) continue;
- is_neighbor.insert(w);
- vi.m_neighbors.push_back(w);
- }
- }
- }
- }
- }
-
- for (auto const& c : ob_constraint) {
- coefficient_in_ob_constraint[c.var_id] = c.coefficient;
- }
-
set_parameters();
}
void local_search::init_cur_solution() {
for (var_info& vi : m_vars) {
- // use bias with a small probability
if (!vi.m_unit) {
- if (m_rand() % 10 < 5 || m_config.phase_sticky()) {
+ if (m_config.phase_sticky()) {
vi.m_value = ((unsigned)(m_rand() % 100) < vi.m_bias);
}
else {
@@ -116,7 +89,6 @@ namespace sat {
coeff_vector& falsep = m_vars[v].m_watch[!is_true];
for (auto const& coeff : falsep) {
constraint& c = m_constraints[coeff.m_constraint_id];
- //SASSERT(falsep[i].m_coeff == 1);
// will --slack
if (c.m_slack <= 0) {
dec_slack_score(v);
@@ -125,7 +97,6 @@ namespace sat {
}
}
for (auto const& coeff : truep) {
- //SASSERT(coeff.m_coeff == 1);
constraint& c = m_constraints[coeff.m_constraint_id];
// will --true_terms_count[c]
// will ++slack
@@ -151,22 +122,19 @@ namespace sat {
void local_search::reinit() {
- IF_VERBOSE(1, verbose_stream() << "(sat-local-search reinit)\n";);
- if (true || !m_is_pb) {
- //
- // the following methods does NOT converge for pseudo-boolean
- // can try other way to define "worse" and "better"
- // the current best noise is below 1000
- //
- if (m_best_unsat_rate > m_last_best_unsat_rate) {
- // worse
- m_noise -= m_noise * 2 * m_noise_delta;
- m_best_unsat_rate *= 1000.0;
- }
- else {
- // better
- m_noise += (10000 - m_noise) * m_noise_delta;
- }
+ //
+ // the following methods does NOT converge for pseudo-boolean
+ // can try other way to define "worse" and "better"
+ // the current best noise is below 1000
+ //
+ if (m_best_unsat_rate > m_last_best_unsat_rate) {
+ // worse
+ m_noise -= m_noise * 2 * m_noise_delta;
+ m_best_unsat_rate *= 1000.0;
+ }
+ else {
+ // better
+ m_noise += (10000 - m_noise) * m_noise_delta;
}
for (constraint & c : m_constraints) {
@@ -186,11 +154,9 @@ namespace sat {
m_vars.back().m_score = INT_MIN;
m_vars.back().m_conf_change = false;
m_vars.back().m_slack_score = INT_MIN;
- m_vars.back().m_cscc = 0;
m_vars.back().m_time_stamp = m_max_steps + 1;
for (unsigned i = 0; i < num_vars(); ++i) {
m_vars[i].m_time_stamp = 0;
- m_vars[i].m_cscc = 1;
m_vars[i].m_conf_change = true;
m_vars[i].m_in_goodvar_stack = false;
m_vars[i].m_score = 0;
@@ -208,6 +174,7 @@ namespace sat {
if (m_is_unsat) {
IF_VERBOSE(0, verbose_stream() << "unsat during reinit\n");
}
+ DEBUG_CODE(verify_slack(););
}
bool local_search::propagate(literal lit) {
@@ -230,9 +197,9 @@ namespace sat {
return false;
}
if (unit) {
- for (literal lit : m_prop_queue) {
- VERIFY(is_true(lit));
- add_unit(lit);
+ for (literal lit2 : m_prop_queue) {
+ VERIFY(is_true(lit2));
+ add_unit(lit2, lit);
}
}
return true;
@@ -253,32 +220,7 @@ namespace sat {
constraint const& c = m_constraints[m_unsat_stack[0]];
IF_VERBOSE(2, display(verbose_stream() << "single unsat:", c));
}
- }
-
- void local_search::calculate_and_update_ob() {
- unsigned i, v;
- int objective_value = 0;
- for (i = 0; i < ob_constraint.size(); ++i) {
- v = ob_constraint[i].var_id;
- if (cur_solution(v))
- objective_value += ob_constraint[i].coefficient;
- }
- if (objective_value > m_best_objective_value) {
- m_best_solution.reset();
- for (unsigned v = 0; v < num_vars(); ++v) {
- m_best_solution.push_back(cur_solution(v));
- }
- m_best_objective_value = objective_value;
- }
- }
-
- bool local_search::all_objectives_are_met() const {
- for (unsigned i = 0; i < ob_constraint.size(); ++i) {
- bool_var v = ob_constraint[i].var_id;
- if (!cur_solution(v)) return false;
- }
- return true;
- }
+ }
void local_search::verify_solution() const {
IF_VERBOSE(0, verbose_stream() << "verifying solution\n");
@@ -289,10 +231,24 @@ namespace sat {
void local_search::verify_unsat_stack() const {
for (unsigned i : m_unsat_stack) {
constraint const& c = m_constraints[i];
+ if (c.m_k >= constraint_value(c)) {
+ IF_VERBOSE(0, display(verbose_stream() << i << " ", c) << "\n");
+ IF_VERBOSE(0, verbose_stream() << "units " << m_units << "\n");
+ }
VERIFY(c.m_k < constraint_value(c));
}
}
+ bool local_search::verify_goodvar() const {
+ unsigned g = 0;
+ for (unsigned v = 0; v < num_vars(); ++v) {
+ if (conf_change(v) && score(v) > 0) {
+ ++g;
+ }
+ }
+ return g == m_goodvar_stack.size();
+ }
+
unsigned local_search::constraint_coeff(constraint const& c, literal l) const {
for (auto const& pb : m_vars[l.var()].m_watch[is_pos(l)]) {
if (pb.m_constraint_id == c.m_id) return pb.m_coeff;
@@ -301,6 +257,24 @@ namespace sat {
return 0;
}
+ void local_search::verify_constraint(constraint const& c) const {
+ unsigned value = constraint_value(c);
+ IF_VERBOSE(11, display(verbose_stream() << "verify ", c););
+ TRACE("sat", display(verbose_stream() << "verify ", c););
+ if (c.m_k < value) {
+ IF_VERBOSE(0, display(verbose_stream() << "violated constraint: ", c) << "value: " << value << "\n";);
+ }
+ }
+
+ void local_search::verify_slack(constraint const& c) const {
+ VERIFY(constraint_value(c) + c.m_slack == c.m_k);
+ }
+
+ void local_search::verify_slack() const {
+ for (constraint const& c : m_constraints) {
+ verify_slack(c);
+ }
+ }
unsigned local_search::constraint_value(constraint const& c) const {
unsigned value = 0;
@@ -311,15 +285,6 @@ namespace sat {
}
return value;
}
-
- void local_search::verify_constraint(constraint const& c) const {
- unsigned value = constraint_value(c);
- IF_VERBOSE(11, display(verbose_stream() << "verify ", c););
- TRACE("sat", display(verbose_stream() << "verify ", c););
- if (c.m_k < value) {
- IF_VERBOSE(0, display(verbose_stream() << "violated constraint: ", c) << "value: " << value << "\n";);
- }
- }
void local_search::add_clause(unsigned sz, literal const* c) {
add_cardinality(sz, c, sz - 1);
@@ -328,7 +293,7 @@ namespace sat {
// ~c <= k
void local_search::add_cardinality(unsigned sz, literal const* c, unsigned k) {
if (sz == 1 && k == 0) {
- add_unit(c[0]);
+ add_unit(c[0], null_literal);
return;
}
if (k == 1 && sz == 2) {
@@ -353,7 +318,7 @@ namespace sat {
// c * coeffs <= k
void local_search::add_pb(unsigned sz, literal const* c, unsigned const* coeffs, unsigned k) {
if (sz == 1 && k == 0) {
- add_unit(~c[0]);
+ add_unit(~c[0], null_literal);
return;
}
unsigned id = m_constraints.size();
@@ -366,15 +331,19 @@ namespace sat {
}
}
- void local_search::add_unit(literal lit) {
+ void local_search::add_unit(literal lit, literal exp) {
bool_var v = lit.var();
if (is_unit(lit)) return;
- VERIFY(!m_units.contains(v));
- m_vars[v].m_bias = lit.sign() ? 0 : 100;
+ SASSERT(!m_units.contains(v));
+ if (m_vars[v].m_value == lit.sign() && !m_initializing) {
+ flip_walksat(v);
+ }
m_vars[v].m_value = !lit.sign();
+ m_vars[v].m_bias = lit.sign() ? 0 : 100;
m_vars[v].m_unit = true;
+ m_vars[v].m_explain = exp;
m_units.push_back(v);
- verify_unsat_stack();
+ DEBUG_CODE(verify_unsat_stack(););
}
local_search::local_search() :
@@ -383,19 +352,19 @@ namespace sat {
}
void local_search::import(solver& s, bool _init) {
+ flet linit(m_initializing, true);
m_is_pb = false;
m_vars.reset();
m_constraints.reset();
m_units.reset();
m_unsat_stack.reset();
-
m_vars.reserve(s.num_vars());
+ m_config.set_config(s.get_config());
+
if (m_config.phase_sticky()) {
unsigned v = 0;
for (var_info& vi : m_vars) {
- if (!vi.m_unit)
- vi.m_bias = s.m_phase[v] == POS_PHASE ? 100 : 0;
- ++v;
+ vi.m_bias = s.m_phase[v++] == POS_PHASE ? 98 : 2;
}
}
@@ -524,9 +493,6 @@ namespace sat {
local_search::~local_search() {
}
- void local_search::add_soft(bool_var v, int weight) {
- ob_constraint.push_back(ob_term(v, weight));
- }
lbool local_search::check() {
return check(0, nullptr);
@@ -534,7 +500,7 @@ namespace sat {
#define PROGRESS(tries, flips) \
if (tries % 10 == 0 || m_unsat_stack.empty()) { \
- IF_VERBOSE(1, verbose_stream() << "(sat-local-search" \
+ IF_VERBOSE(1, verbose_stream() << "(sat.local-search" \
<< " :flips " << flips \
<< " :noise " << m_noise \
<< " :unsat " << /*m_unsat_stack.size()*/ m_best_unsat \
@@ -547,10 +513,9 @@ namespace sat {
m_last_best_unsat_rate = 1;
reinit();
+ DEBUG_CODE(verify_slack(););
timer timer;
- timer.start();
unsigned step = 0, total_flips = 0, tries = 0;
- PROGRESS(tries, total_flips);
for (tries = 1; !m_unsat_stack.empty() && m_limit.inc(); ++tries) {
++m_stats.m_num_restarts;
@@ -572,39 +537,7 @@ namespace sat {
reinit();
}
}
- }
-
- void local_search::gsat() {
- reinit();
- bool_var flipvar;
- timer timer;
- timer.start();
- unsigned tries, step = 0, total_flips = 0;
- for (tries = 1; m_limit.inc() && !m_unsat_stack.empty(); ++tries) {
- reinit();
- for (step = 1; step <= m_max_steps; ) {
- // feasible
- if (m_unsat_stack.empty()) {
- calculate_and_update_ob();
- if (m_best_objective_value >= m_best_known_value) {
- break;
- }
- }
- if (m_unsat_stack.size() < m_best_unsat) {
- set_best_unsat();
- }
- flipvar = pick_var_gsat();
- flip_gsat(flipvar);
- m_vars[flipvar].m_time_stamp = step++;
- }
- total_flips += step;
- PROGRESS(tries, total_flips);
-
- // tell the SAT solvers about the phase of variables.
- if (m_par && tries % 10 == 0) {
- m_par->get_phase(*this);
- }
- }
+ PROGRESS(0, total_flips);
}
lbool local_search::check(unsigned sz, literal const* assumptions, parallel* p) {
@@ -612,28 +545,24 @@ namespace sat {
m_model.reset();
m_assumptions.reset();
m_assumptions.append(sz, assumptions);
+ unsigned num_units = m_units.size();
init();
-
- switch (m_config.mode()) {
- case local_search_mode::gsat:
- gsat();
- break;
- case local_search_mode::wsat:
- walksat();
- break;
+ walksat();
+
+ // remove unit clauses
+ for (unsigned i = m_units.size(); i-- > num_units; ) {
+ m_vars[m_units[i]].m_unit = false;
}
-
- // remove unit clauses from assumptions.
- m_constraints.shrink(num_constraints() - sz);
+ m_units.shrink(num_units);
+ m_vars.pop_back(); // remove sentinel variable
TRACE("sat", display(tout););
lbool result;
if (m_is_unsat) {
- // result = l_false;
- result = l_undef;
+ result = l_false;
}
- else if (m_unsat_stack.empty() && all_objectives_are_met()) {
+ else if (m_unsat_stack.empty()) {
verify_solution();
extract_model();
result = l_true;
@@ -641,7 +570,7 @@ namespace sat {
else {
result = l_undef;
}
- IF_VERBOSE(1, verbose_stream() << "(sat-local-search " << result << ")\n";);
+ IF_VERBOSE(1, verbose_stream() << "(sat.local-search " << result << ")\n";);
IF_VERBOSE(20, display(verbose_stream()););
return result;
}
@@ -661,18 +590,40 @@ namespace sat {
m_unsat_stack.push_back(c);
}
+ void local_search::pick_flip_lookahead() {
+ unsigned num_unsat = m_unsat_stack.size();
+ constraint const& c = m_constraints[m_unsat_stack[m_rand() % num_unsat]];
+ literal best = null_literal;
+ unsigned best_make = UINT_MAX;
+ for (literal lit : c.m_literals) {
+ if (!is_unit(lit) && is_true(lit)) {
+ flip_walksat(lit.var());
+ if (propagate(~lit) && best_make > m_unsat_stack.size()) {
+ best = lit;
+ best_make = m_unsat_stack.size();
+ }
+ flip_walksat(lit.var());
+ propagate(lit);
+ }
+ }
+ if (best != null_literal) {
+ flip_walksat(best.var());
+ propagate(~best);
+ }
+ else {
+ std::cout << "no best\n";
+ }
+ }
+
void local_search::pick_flip_walksat() {
reflip:
bool_var best_var = null_bool_var;
unsigned n = 1;
bool_var v = null_bool_var;
unsigned num_unsat = m_unsat_stack.size();
- constraint const& c = m_constraints[m_unsat_stack[m_rand() % m_unsat_stack.size()]];
- // VERIFY(c.m_k < constraint_value(c));
+ constraint const& c = m_constraints[m_unsat_stack[m_rand() % num_unsat]];
unsigned reflipped = 0;
bool is_core = m_unsat_stack.size() <= 10;
- // TBD: dynamic noise strategy
- //if (m_rand() % 100 < 98) {
if (m_rand() % 10000 <= m_noise) {
// take this branch with 98% probability.
// find the first one, to fast break the rest
@@ -763,7 +714,7 @@ namespace sat {
if (is_true(lit)) {
flip_walksat(best_var);
}
- add_unit(~lit);
+ add_unit(~lit, null_literal);
if (!propagate(~lit)) {
IF_VERBOSE(0, verbose_stream() << "unsat\n");
m_is_unsat = true;
@@ -779,6 +730,7 @@ namespace sat {
}
void local_search::flip_walksat(bool_var flipvar) {
+
++m_stats.m_num_flips;
VERIFY(!is_unit(flipvar));
m_vars[flipvar].m_value = !cur_solution(flipvar);
@@ -794,6 +746,7 @@ namespace sat {
constraint& c = m_constraints[ci];
int old_slack = c.m_slack;
c.m_slack -= pbc.m_coeff;
+ DEBUG_CODE(verify_slack(c););
if (c.m_slack < 0 && old_slack >= 0) { // from non-negative to negative: sat -> unsat
unsat(ci);
}
@@ -803,220 +756,21 @@ namespace sat {
constraint& c = m_constraints[ci];
int old_slack = c.m_slack;
c.m_slack += pbc.m_coeff;
+ DEBUG_CODE(verify_slack(c););
if (c.m_slack >= 0 && old_slack < 0) { // from negative to non-negative: unsat -> sat
sat(ci);
}
}
- // verify_unsat_stack();
- }
-
- void local_search::flip_gsat(bool_var flipvar) {
- // already changed truth value!!!!
- m_vars[flipvar].m_value = !cur_solution(flipvar);
-
- unsigned v;
- int org_flipvar_score = score(flipvar);
- int org_flipvar_slack_score = slack_score(flipvar);
-
- bool flip_is_true = cur_solution(flipvar);
- coeff_vector& truep = m_vars[flipvar].m_watch[flip_is_true];
- coeff_vector& falsep = m_vars[flipvar].m_watch[!flip_is_true];
-
- // update related clauses and neighbor vars
- for (unsigned i = 0; i < truep.size(); ++i) {
- constraint & c = m_constraints[truep[i].m_constraint_id];
- //++true_terms_count[c];
- --c.m_slack;
- switch (c.m_slack) {
- case -2: // from -1 to -2
- for (literal l : c) {
- v = l.var();
- // flipping the slack increasing var will no longer satisfy this constraint
- if (is_true(l)) {
- //score[v] -= constraint_weight[c];
- dec_score(v);
- }
- }
- break;
- case -1: // from 0 to -1: sat -> unsat
- for (literal l : c) {
- v = l.var();
- inc_cscc(v);
- //score[v] += constraint_weight[c];
- inc_score(v);
- // slack increasing var
- if (is_true(l))
- inc_slack_score(v);
- }
- unsat(truep[i].m_constraint_id);
- break;
- case 0: // from 1 to 0
- for (literal l : c) {
- v = l.var();
- // flip the slack decreasing var will falsify this constraint
- if (is_false(l)) {
- // score[v] -= constraint_weight[c];
- dec_score(v);
- dec_slack_score(v);
- }
- }
- break;
- default:
- break;
- }
- }
- for (pbcoeff const& f : falsep) {
- constraint& c = m_constraints[f.m_constraint_id];
- //--true_terms_count[c];
- ++c.m_slack;
- switch (c.m_slack) {
- case 1: // from 0 to 1
- for (literal l : c) {
- v = l.var();
- // flip the slack decreasing var will no long falsify this constraint
- if (is_false(l)) {
- //score[v] += constraint_weight[c];
- inc_score(v);
- inc_slack_score(v);
- }
- }
- break;
- case 0: // from -1 to 0: unsat -> sat
- for (literal l : c) {
- v = l.var();
- inc_cscc(v);
- //score[v] -= constraint_weight[c];
- dec_score(v);
- // slack increasing var no longer sat this var
- if (is_true(l))
- dec_slack_score(v);
- }
- sat(f.m_constraint_id);
- break;
- case -1: // from -2 to -1
- for (literal l : c) {
- v = l.var();
- // flip the slack increasing var will satisfy this constraint
- if (is_true(l)) {
- //score[v] += constraint_weight[c];
- inc_score(v);
- }
- }
- break;
- default:
- break;
- }
- }
- m_vars[flipvar].m_score = -org_flipvar_score;
- m_vars[flipvar].m_slack_score = -org_flipvar_slack_score;
- m_vars[flipvar].m_conf_change = false;
- m_vars[flipvar].m_cscc = 0;
-
- /* update CCD */
- // remove the vars no longer goodvar in goodvar stack
- for (unsigned i = m_goodvar_stack.size(); i > 0;) {
- --i;
- v = m_goodvar_stack[i];
- if (score(v) <= 0) {
- m_goodvar_stack[i] = m_goodvar_stack.back();
- m_goodvar_stack.pop_back();
- m_vars[v].m_in_goodvar_stack = false;
- }
- }
- // update all flipvar's neighbor's conf_change to true, add goodvar/okvar
-
- var_info& vi = m_vars[flipvar];
- for (auto v : vi.m_neighbors) {
- m_vars[v].m_conf_change = true;
- if (score(v) > 0 && !already_in_goodvar_stack(v)) {
- m_goodvar_stack.push_back(v);
- m_vars[v].m_in_goodvar_stack = true;
- }
- }
- }
-
- bool local_search::tie_breaker_sat(bool_var v, bool_var best_var) {
- // most improvement on objective value
- int v_imp = cur_solution(v) ? -coefficient_in_ob_constraint.get(v, 0) : coefficient_in_ob_constraint.get(v, 0);
- int b_imp = cur_solution(best_var) ? -coefficient_in_ob_constraint.get(best_var, 0) : coefficient_in_ob_constraint.get(best_var, 0);
- // std::cout << v_imp << "\n";
- // break tie 1: max imp
- // break tie 2: conf_change
- // break tie 3: time_stamp
-
- return
- (v_imp > b_imp) ||
- ((v_imp == b_imp) &&
- ((conf_change(v) && !conf_change(best_var)) ||
- ((conf_change(v) == conf_change(best_var)) &&
- (time_stamp(v) < time_stamp(best_var)))));
- }
-
- bool local_search::tie_breaker_ccd(bool_var v, bool_var best_var) {
- // break tie 1: max score
- // break tie 2: max slack_score
- // break tie 3: cscc
- // break tie 4: oldest one
- return
- ((score(v) > score(best_var)) ||
- ((score(v) == score(best_var)) &&
- ((slack_score(v) > slack_score(best_var)) ||
- ((slack_score(v) == slack_score(best_var)) &&
- ((cscc(v) > cscc(best_var)) ||
- ((cscc(v) == cscc(best_var)) &&
- (time_stamp(v) < time_stamp(best_var))))))));
- }
-
- bool_var local_search::pick_var_gsat() {
- bool_var best_var = m_vars.size()-1; // sentinel variable
- // SAT Mode
- if (m_unsat_stack.empty()) {
- //std::cout << "as\t";
- for (auto const& c : ob_constraint) {
- bool_var v = c.var_id;
- if (tie_breaker_sat(v, best_var))
- best_var = v;
- }
- return best_var;
- }
-
- // Unsat Mode: CCD > RD
- // CCD mode
- if (!m_goodvar_stack.empty()) {
- //++ccd;
- best_var = m_goodvar_stack[0];
- for (bool_var v : m_goodvar_stack) {
- if (tie_breaker_ccd(v, best_var))
- best_var = v;
- }
- return best_var;
- }
-
- // Diversification Mode
- constraint const& c = m_constraints[m_unsat_stack[m_rand() % m_unsat_stack.size()]]; // a random unsat constraint
- // Within c, from all slack increasing var, choose the oldest one
- for (literal l : c) {
- bool_var v = l.var();
- if (is_true(l) && time_stamp(v) < time_stamp(best_var))
- best_var = v;
- }
- return best_var;
+ DEBUG_CODE(verify_unsat_stack(););
}
void local_search::set_parameters() {
m_rand.set_seed(m_config.random_seed());
m_best_known_value = m_config.best_known_value();
- switch (m_config.mode()) {
- case local_search_mode::gsat:
- m_max_steps = 2 * num_vars();
- break;
- case local_search_mode::wsat:
- m_max_steps = std::min(static_cast(20 * num_vars()), static_cast(1 << 17)); // cut steps off at 100K
- break;
- }
-
+ m_max_steps = std::min(static_cast(20 * num_vars()), static_cast(1 << 17)); // cut steps off at 100K
+
TRACE("sat",
tout << "seed:\t" << m_config.random_seed() << '\n';
tout << "best_known_value:\t" << m_config.best_known_value() << '\n';
@@ -1062,7 +816,9 @@ namespace sat {
}
std::ostream& local_search::display(std::ostream& out, unsigned v, var_info const& vi) const {
- return out << "v" << v << " := " << (vi.m_value?"true":"false") << " bias: " << vi.m_bias << "\n";
+ out << "v" << v << " := " << (vi.m_value?"true":"false") << " bias: " << vi.m_bias;
+ if (vi.m_unit) out << " u " << vi.m_explain;
+ return out << "\n";
}
void local_search::collect_statistics(statistics& st) const {
@@ -1078,26 +834,6 @@ namespace sat {
}
- bool local_search::check_goodvar() {
- unsigned g = 0;
- for (unsigned v = 0; v < num_vars(); ++v) {
- if (conf_change(v) && score(v) > 0) {
- ++g;
- if (!already_in_goodvar_stack(v))
- std::cout << "3\n";
- }
- }
- if (g == m_goodvar_stack.size())
- return true;
- else {
- if (g < m_goodvar_stack.size())
- std::cout << "1\n";
- else
- std::cout << "2\n"; // delete too many
- return false;
- }
- }
-
void local_search::set_phase(bool_var v, lbool f) {
unsigned& bias = m_vars[v].m_bias;
if (f == l_true && bias < 100) bias++;
@@ -1105,4 +841,13 @@ namespace sat {
// f == l_undef ?
}
+ void local_search::set_bias(bool_var v, lbool f) {
+ switch (f) {
+ case l_true: m_vars[v].m_bias = 99; break;
+ case l_false: m_vars[v].m_bias = 1; break;
+ default: break;
+ }
+
+ }
+
}
diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h
index 849b4f26b..00c38e481 100644
--- a/src/sat/sat_local_search.h
+++ b/src/sat/sat_local_search.h
@@ -36,6 +36,16 @@ namespace sat {
local_search_mode m_mode;
bool m_phase_sticky;
bool m_dbg_flips;
+
+ friend class local_search;
+
+ void set_config(config const& cfg) {
+ m_mode = cfg.m_local_search_mode;
+ m_random_seed = cfg.m_random_seed;
+ m_phase_sticky = cfg.m_phase_sticky;
+ m_dbg_flips = cfg.m_local_search_dbg_flips;
+ }
+
public:
local_search_config() {
m_random_seed = 0;
@@ -54,12 +64,6 @@ namespace sat {
void set_random_seed(unsigned s) { m_random_seed = s; }
void set_best_known_value(unsigned v) { m_best_known_value = v; }
- void set_config(config const& cfg) {
- m_mode = cfg.m_local_search_mode;
- m_random_seed = cfg.m_random_seed;
- m_phase_sticky = cfg.m_phase_sticky;
- m_dbg_flips = cfg.m_local_search_dbg_flips;
- }
};
@@ -74,12 +78,6 @@ namespace sat {
typedef svector bool_vector;
typedef svector coeff_vector;
- // data structure for a term in objective function
- struct ob_term {
- bool_var var_id; // variable id, begin with 1
- int coefficient; // non-zero integer
- ob_term(bool_var v, int c): var_id(v), coefficient(c) {}
- };
struct stats {
unsigned m_num_flips;
@@ -93,12 +91,12 @@ namespace sat {
unsigned m_bias; // bias for current solution in percentage.
// if bias is 0, then value is always false, if 100, then always true
bool m_unit; // is this a unit literal
+ literal m_explain; // explanation for unit assignment
bool m_conf_change; // whether its configure changes since its last flip
bool m_in_goodvar_stack;
int m_score;
int m_slack_score;
int m_time_stamp; // the flip time stamp
- int m_cscc; // how many times its constraint state configure changes since its last flip
bool_var_vector m_neighbors; // neighborhood variables
coeff_vector m_watch[2];
literal_vector m_bin[2];
@@ -112,7 +110,6 @@ namespace sat {
m_in_goodvar_stack(false),
m_score(0),
m_slack_score(0),
- m_cscc(0),
m_flips(0),
m_slow_break(1e-5)
{}
@@ -132,19 +129,44 @@ namespace sat {
literal const* end() const { return m_literals.end(); }
};
- stats m_stats;
- local_search_config m_config;
-
- // objective function: maximize
- svector ob_constraint; // the objective function *constraint*, sorted in descending order
-
- // information about the variable
- int_vector coefficient_in_ob_constraint; // var! initialized to be 0
+ stats m_stats;
+ local_search_config m_config;
+ vector m_vars; // variables
+ svector m_units; // unit clauses
+ vector m_constraints; // all constraints
+ literal_vector m_assumptions; // temporary assumptions
+ literal_vector m_prop_queue; // propagation queue
+ unsigned m_num_non_binary_clauses;
+ bool m_is_pb;
+ bool m_is_unsat;
+ unsigned_vector m_unsat_stack; // store all the unsat constraints
+ unsigned_vector m_index_in_unsat_stack; // which position is a constraint in the unsat_stack
+
+ // configuration changed decreasing variables (score>0 and conf_change==true)
+ bool_var_vector m_goodvar_stack;
+ bool m_initializing;
+
+
+ // information about solution
+ unsigned m_best_unsat;
+ double m_best_unsat_rate;
+ double m_last_best_unsat_rate;
+ // for non-known instance, set as maximal
+ int m_best_known_value = INT_MAX; // best known value for this instance
+
+ unsigned m_max_steps = (1 << 30);
+
+ // dynamic noise
+ double m_noise = 9800; // normalized by 10000
+ double m_noise_delta = 0.05;
+
+ reslimit m_limit;
+ random_gen m_rand;
+ parallel* m_par;
+ model m_model;
- vector m_vars;
- svector m_units;
inline int score(bool_var v) const { return m_vars[v].m_score; }
inline void inc_score(bool_var v) { m_vars[v].m_score++; }
@@ -157,21 +179,10 @@ namespace sat {
inline bool already_in_goodvar_stack(bool_var v) const { return m_vars[v].m_in_goodvar_stack; }
inline bool conf_change(bool_var v) const { return m_vars[v].m_conf_change; }
inline int time_stamp(bool_var v) const { return m_vars[v].m_time_stamp; }
- inline int cscc(bool_var v) const { return m_vars[v].m_cscc; }
- inline void inc_cscc(bool_var v) { m_vars[v].m_cscc++; }
-
- inline bool cur_solution(bool_var v) const { return m_vars[v].m_value; }
inline void set_best_unsat();
/* TBD: other scores */
- vector m_constraints;
-
- literal_vector m_assumptions;
- literal_vector m_prop_queue;
-
- unsigned m_num_non_binary_clauses;
- bool m_is_pb;
inline bool is_pos(literal t) const { return !t.sign(); }
inline bool is_true(bool_var v) const { return cur_solution(v); }
@@ -182,101 +193,38 @@ namespace sat {
unsigned num_constraints() const { return m_constraints.size(); } // constraint index from 1 to num_constraint
-
unsigned constraint_slack(unsigned ci) const { return m_constraints[ci].m_slack; }
- // unsat constraint stack
- bool m_is_unsat;
- unsigned_vector m_unsat_stack; // store all the unsat constraints
- unsigned_vector m_index_in_unsat_stack; // which position is a constraint in the unsat_stack
-
- // configuration changed decreasing variables (score>0 and conf_change==true)
- bool_var_vector m_goodvar_stack;
-
-
- // information about solution
- unsigned m_best_unsat;
- double m_best_unsat_rate;
- double m_last_best_unsat_rate;
- int m_objective_value; // the objective function value corresponds to the current solution
- bool_vector m_best_solution; // !var: the best solution so far
- int m_best_objective_value = -1; // the objective value corresponds to the best solution so far
- // for non-known instance, set as maximal
- int m_best_known_value = INT_MAX; // best known value for this instance
-
- unsigned m_max_steps = (1 << 30);
-
- // dynamic noise
- double m_noise = 9800; // normalized by 10000
- double m_noise_delta = 0.05;
-
- reslimit m_limit;
- random_gen m_rand;
- parallel* m_par;
- model m_model;
-
void init();
void reinit();
void reinit_orig();
void init_cur_solution();
void init_slack();
void init_scores();
- void init_goodvars();
-
- bool_var pick_var_gsat();
-
- void flip_gsat(bool_var v);
-
+ void init_goodvars();
+ void pick_flip_lookahead();
void pick_flip_walksat();
-
void flip_walksat(bool_var v);
-
bool propagate(literal lit);
-
void add_propagation(literal lit);
-
void walksat();
-
- void gsat();
-
void unsat(unsigned c);
-
void sat(unsigned c);
-
- bool tie_breaker_sat(bool_var v1, bool_var v2);
-
- bool tie_breaker_ccd(bool_var v1, bool_var v2);
-
void set_parameters();
-
- void calculate_and_update_ob();
-
- bool all_objectives_are_met() const;
-
void verify_solution() const;
-
void verify_unsat_stack() const;
-
void verify_constraint(constraint const& c) const;
-
+ void verify_slack(constraint const& c) const;
+ void verify_slack() const;
+ bool verify_goodvar() const;
unsigned constraint_value(constraint const& c) const;
-
unsigned constraint_coeff(constraint const& c, literal l) const;
-
void print_info(std::ostream& out);
-
void extract_model();
-
- bool check_goodvar();
-
void add_clause(unsigned sz, literal const* c);
-
- void add_unit(literal lit);
-
+ void add_unit(literal lit, literal explain);
std::ostream& display(std::ostream& out) const;
-
std::ostream& display(std::ostream& out, constraint const& c) const;
-
std::ostream& display(std::ostream& out, unsigned v, var_info const& vi) const;
public:
@@ -287,8 +235,6 @@ namespace sat {
~local_search();
- void add_soft(bool_var v, int weight);
-
void add_cardinality(unsigned sz, literal const* c, unsigned k);
void add_pb(unsigned sz, literal const* c, unsigned const* coeffs, unsigned k);
@@ -307,8 +253,14 @@ namespace sat {
void set_phase(bool_var v, lbool f);
+ void set_bias(bool_var v, lbool f);
+
bool get_phase(bool_var v) const { return is_true(v); }
+ inline bool cur_solution(bool_var v) const { return m_vars[v].m_value; }
+
+ double break_count(bool_var v) const { return m_vars[v].m_slow_break; }
+
model& get_model() { return m_model; }
void collect_statistics(statistics& st) const;
diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp
index 389cdb19b..74ac831d8 100644
--- a/src/sat/sat_lookahead.cpp
+++ b/src/sat/sat_lookahead.cpp
@@ -92,7 +92,7 @@ namespace sat {
m_binary[(~l2).index()].push_back(l1);
m_binary_trail.push_back((~l1).index());
++m_stats.m_add_binary;
- if (m_s.m_config.m_drat) validate_binary(l1, l2);
+ if (m_s.m_config.m_drat && m_search_mode == lookahead_mode::searching) validate_binary(l1, l2);
}
void lookahead::del_binary(unsigned idx) {
@@ -110,13 +110,11 @@ namespace sat {
void lookahead::validate_binary(literal l1, literal l2) {
- if (m_search_mode == lookahead_mode::searching) {
- m_assumptions.push_back(l1);
- m_assumptions.push_back(l2);
- m_drat.add(m_assumptions);
- m_assumptions.pop_back();
- m_assumptions.pop_back();
- }
+ m_assumptions.push_back(l1);
+ m_assumptions.push_back(l2);
+ m_s.m_drat.add(m_assumptions);
+ m_assumptions.pop_back();
+ m_assumptions.pop_back();
}
void lookahead::inc_bstamp() {
@@ -323,9 +321,9 @@ namespace sat {
double sum = 0;
unsigned skip_candidates = 0;
bool autarky = get_config().m_lookahead_global_autarky;
- for (bool_var x : m_freevars) {
- SASSERT(is_undef(x));
- if (!m_select_lookahead_vars.empty()) {
+ if (!m_select_lookahead_vars.empty()) {
+ for (bool_var x : m_freevars) {
+ SASSERT(is_undef(x));
if (m_select_lookahead_vars.contains(x)) {
if (!autarky || newbies || in_reduced_clause(x)) {
m_candidates.push_back(candidate(x, m_rating[x]));
@@ -336,10 +334,15 @@ namespace sat {
}
}
}
- else if (newbies || active_prefix(x)) {
- m_candidates.push_back(candidate(x, m_rating[x]));
- sum += m_rating[x];
- }
+ }
+ if (m_candidates.empty() && (m_select_lookahead_vars.empty() || newbies)) {
+ for (bool_var x : m_freevars) {
+ SASSERT(is_undef(x));
+ if (newbies || active_prefix(x)) {
+ m_candidates.push_back(candidate(x, m_rating[x]));
+ sum += m_rating[x];
+ }
+ }
}
TRACE("sat", display_candidates(tout << "sum: " << sum << "\n"););
if (skip_candidates > 0) {
@@ -997,6 +1000,7 @@ namespace sat {
void lookahead::init(bool learned) {
m_delta_trigger = 0.0;
m_delta_decrease = 0.0;
+ m_delta_fraction = m_s.m_config.m_lookahead_delta_fraction;
m_config.m_dl_success = 0.8;
m_inconsistent = false;
m_qhead = 0;
@@ -1031,7 +1035,7 @@ namespace sat {
for (unsigned i = 0; i < trail_sz; ++i) {
literal l = m_s.m_trail[i];
if (!m_s.was_eliminated(l.var())) {
- if (m_s.m_config.m_drat) m_drat.add(l, false);
+ if (m_s.m_config.m_drat) m_s.m_drat.add(l, false);
assign(l);
}
}
@@ -1064,7 +1068,7 @@ namespace sat {
case 3: add_ternary(c[0],c[1],c[2]); break;
default: if (!learned) add_clause(c); break;
}
- if (m_s.m_config.m_drat) m_drat.add(c, false);
+ // if (m_s.m_config.m_drat) m_s.m_drat.add(c, false);
}
}
@@ -1808,13 +1812,13 @@ namespace sat {
unsigned lookahead::do_double(literal l, unsigned& base) {
unsigned num_units = 0;
- if (!inconsistent() && dl_enabled(l)) {
+ if (!inconsistent() && dl_enabled(l) && get_config().m_lookahead_double) {
if (get_lookahead_reward(l) > m_delta_trigger) {
if (dl_no_overflow(base)) {
++m_stats.m_double_lookahead_rounds;
num_units = double_look(l, base);
if (!inconsistent()) {
- m_delta_trigger = get_lookahead_reward(l);
+ m_delta_trigger = m_delta_fraction*get_lookahead_reward(l);
dl_disable(l);
}
}
@@ -1845,13 +1849,15 @@ namespace sat {
unsigned num_iterations = 0;
while (change && num_iterations < m_config.m_dl_max_iterations && !inconsistent()) {
num_iterations++;
- for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) {
- literal lit = m_lookahead[i].m_lit;
+ for (auto const& lh : m_lookahead) {
+ if (inconsistent()) break;
+
+ literal lit = lh.m_lit;
if (lit == last_changed) {
SASSERT(change == false);
break;
}
- unsigned level = base + m_lookahead[i].m_offset;
+ unsigned level = base + lh.m_offset;
if (level + m_lookahead.size() >= dl_truth) {
change = false;
break;
@@ -1869,6 +1875,7 @@ namespace sat {
++m_stats.m_double_lookahead_propagations;
SASSERT(m_level == dl_truth);
lookahead_backtrack();
+ if (m_s.m_config.m_drat) validate_binary(~l, ~lit);
assign(~lit);
propagate();
change = true;
@@ -1926,7 +1933,7 @@ namespace sat {
void lookahead::validate_assign(literal l) {
if (m_s.m_config.m_drat && m_search_mode == lookahead_mode::searching) {
m_assumptions.push_back(l);
- m_drat.add(m_assumptions);
+ m_s.m_drat.add(m_assumptions);
m_assumptions.pop_back();
}
}
@@ -2006,6 +2013,7 @@ namespace sat {
}
bool lookahead::backtrack(literal_vector& trail, svector & is_decision) {
+ m_cube_state.m_backtracks++;
while (inconsistent()) {
if (trail.empty()) return false;
if (is_decision.back()) {
@@ -2026,6 +2034,7 @@ namespace sat {
void lookahead::update_cube_statistics(statistics& st) {
st.update("lh cube cutoffs", m_cube_state.m_cutoffs);
st.update("lh cube conflicts", m_cube_state.m_conflicts);
+ st.update("lh cube backtracks", m_cube_state.m_backtracks);
}
double lookahead::psat_heur() {
@@ -2098,7 +2107,9 @@ namespace sat {
m_cube_state.m_freevars_threshold = m_freevars.size();
m_cube_state.m_psat_threshold = m_config.m_cube_cutoff == adaptive_psat_cutoff ? psat_heur() : dbl_max; // MN. only compute PSAT if enabled
m_cube_state.inc_conflict();
- if (!backtrack(m_cube_state.m_cube, m_cube_state.m_is_decision)) return l_false;
+ if (!backtrack(m_cube_state.m_cube, m_cube_state.m_is_decision)) {
+ return l_false;
+ }
continue;
}
pick_up_work:
@@ -2131,7 +2142,9 @@ namespace sat {
m_cube_state.m_freevars_threshold = prev_nfreevars;
m_cube_state.m_psat_threshold = prev_psat;
m_cube_state.inc_conflict();
- if (!backtrack(m_cube_state.m_cube, m_cube_state.m_is_decision)) return l_false;
+ if (!backtrack(m_cube_state.m_cube, m_cube_state.m_is_decision)) {
+ return l_false;
+ }
continue;
}
if (lit == null_literal) {
@@ -2160,7 +2173,7 @@ namespace sat {
if (is_undef(lit)) {
val = l_undef;
}
- if (is_true(lit)) {
+ else if (is_true(lit)) {
val = l_true;
}
else {
@@ -2279,7 +2292,7 @@ namespace sat {
for (unsigned i = 0; i < m_trail.size() && !m_s.inconsistent(); ++i) {
literal lit = m_trail[i];
if (m_s.value(lit) == l_undef && !m_s.was_eliminated(lit.var())) {
- m_s.assign(lit, justification());
+ m_s.assign_scoped(lit);
++num_units;
}
}
@@ -2457,7 +2470,7 @@ namespace sat {
for (unsigned i = 0; i < m_watches.size(); ++i) {
watch_list const& wl = m_watches[i];
if (!wl.empty()) {
- sat::display_watch_list(out << to_literal(i) << " -> ", dummy_allocator, wl);
+ sat::display_watch_list(out << to_literal(i) << " -> ", dummy_allocator, wl, nullptr);
out << "\n";
}
}
diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h
index 046750832..f6103ee7c 100644
--- a/src/sat/sat_lookahead.h
+++ b/src/sat/sat_lookahead.h
@@ -181,6 +181,7 @@ namespace sat {
double m_psat_threshold;
unsigned m_conflicts;
unsigned m_cutoffs;
+ unsigned m_backtracks;
cube_state() { reset(); }
void reset() {
m_first = true;
@@ -190,7 +191,7 @@ namespace sat {
m_psat_threshold = dbl_max;
reset_stats();
}
- void reset_stats() { m_conflicts = 0; m_cutoffs = 0; }
+ void reset_stats() { m_conflicts = 0; m_cutoffs = 0; m_backtracks = 0;}
void inc_conflict() { ++m_conflicts; }
void inc_cutoff() { ++m_cutoffs; }
};
@@ -198,8 +199,8 @@ namespace sat {
config m_config;
double m_delta_trigger;
double m_delta_decrease;
+ double m_delta_fraction;
- drat m_drat;
literal_vector m_assumptions;
literal_vector m_trail; // trail of units
@@ -564,7 +565,6 @@ namespace sat {
lookahead(solver& s) :
m_s(s),
m_num_vars(s.num_vars()),
- m_drat(s),
m_num_tc1(0),
m_level(2),
m_last_prefix_length(0),
diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp
index d132f1cd4..577588305 100644
--- a/src/sat/sat_model_converter.cpp
+++ b/src/sat/sat_model_converter.cpp
@@ -95,7 +95,7 @@ namespace sat {
IF_VERBOSE(0, display(verbose_stream() << "violated ate\n", *it) << "\n");
IF_VERBOSE(0, for (unsigned v = 0; v < m.size(); ++v) verbose_stream() << v << " := " << m[v] << "\n";);
IF_VERBOSE(0, display(verbose_stream()));
- exit(0);
+ UNREACHABLE();
first = false;
}
if (!sat && it->get_kind() != ATE && v0 != null_bool_var) {
@@ -264,7 +264,7 @@ namespace sat {
}
void model_converter::insert(entry & e, literal_vector const& c) {
- SASSERT(c.contains(literal(e.var(), false)) || c.contains(literal(e.var(), true)));
+ SASSERT(e.var() == null_bool_var || c.contains(literal(e.var(), false)) || c.contains(literal(e.var(), true)));
SASSERT(m_entries.begin() <= &e);
SASSERT(&e < m_entries.end());
for (literal l : c) e.m_clauses.push_back(l);
diff --git a/src/sat/sat_model_converter.h b/src/sat/sat_model_converter.h
index 65e132729..2ca340e5d 100644
--- a/src/sat/sat_model_converter.h
+++ b/src/sat/sat_model_converter.h
@@ -119,6 +119,7 @@ namespace sat {
void add_ate(clause const& c);
bool empty() const { return m_entries.empty(); }
+ unsigned size() const { return m_entries.size(); }
void reset();
bool check_invariant(unsigned num_vars) const;
diff --git a/src/sat/sat_parallel.cpp b/src/sat/sat_parallel.cpp
index ce2080f8c..77a5f973d 100644
--- a/src/sat/sat_parallel.cpp
+++ b/src/sat/sat_parallel.cpp
@@ -113,7 +113,7 @@ namespace sat {
s.m_params.set_sym("phase", symbol("random"));
}
m_solvers[i] = alloc(sat::solver, s.m_params, m_limits[i]);
- m_solvers[i]->copy(s);
+ m_solvers[i]->copy(s, true);
m_solvers[i]->set_par(this, i);
push_child(m_solvers[i]->rlimit());
}
@@ -235,7 +235,7 @@ namespace sat {
// there could be multiple local search engines running at the same time.
IF_VERBOSE(1, verbose_stream() << "(sat-parallel refresh :from " << m_num_clauses << " :to " << s.m_clauses.size() << ")\n";);
m_solver_copy = alloc(solver, s.m_params, s.rlimit());
- m_solver_copy->copy(s);
+ m_solver_copy->copy(s, true);
m_num_clauses = s.m_clauses.size();
}
}
@@ -292,7 +292,7 @@ namespace sat {
{
m_consumer_ready = true;
if (m_solver_copy && s.m_clauses.size() > m_solver_copy->m_clauses.size()) {
- s.copy(*m_solver_copy);
+ s.copy(*m_solver_copy, true);
copied = true;
m_num_clauses = s.m_clauses.size();
}
diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg
index acde7e30c..88b196d04 100644
--- a/src/sat/sat_params.pyg
+++ b/src/sat/sat_params.pyg
@@ -39,6 +39,7 @@ def_module_params('sat',
('threads', UINT, 1, 'number of parallel threads to use'),
('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'),
('drat.file', SYMBOL, '', 'file to dump DRAT proofs'),
+ ('drat.binary', BOOL, False, 'use Binary DRAT output format'),
('drat.check_unsat', BOOL, False, 'build up internal proof and check'),
('drat.check_sat', BOOL, False, 'build up internal trace, check satisfying model'),
('cardinality.solver', BOOL, True, 'use cardinality solver'),
@@ -71,9 +72,11 @@ def_module_params('sat',
('lookahead.cube.psat.trigger', DOUBLE, 5, 'trigger value to create lookahead cubes for PSAT cutoff. Used when lookahead.cube.cutoff is psat'),
('lookahead.preselect', BOOL, False, 'use pre-selection of subset of variables for branching'),
('lookahead_simplify', BOOL, False, 'use lookahead solver during simplification'),
+ ('lookahead.double', BOOL, True, 'enable doubld lookahead'),
('lookahead.use_learned', BOOL, False, 'use learned clauses when selecting lookahead literal'),
('lookahead_simplify.bca', BOOL, True, 'add learned binary clauses as part of lookahead simplification'),
('lookahead.global_autarky', BOOL, False, 'prefer to branch on variables that occur in clauses that are reduced'),
+ ('lookahead.delta_fraction', DOUBLE, 1.0, 'number between 0 and 1, the smaller the more literals are selected for double lookahead'),
('lookahead.reward', SYMBOL, 'march_cu', 'select lookahead heuristic: ternary, heule_schur (Heule Schur), heuleu (Heule Unit), unit, or march_cu'))
# reward function used to determine which literal to cube on.
# - ternary: reward function useful for random 3-SAT instances. Used by Heule and Knuth in March.
diff --git a/src/sat/sat_probing.cpp b/src/sat/sat_probing.cpp
index 52ab9f9f7..5689112d4 100644
--- a/src/sat/sat_probing.cpp
+++ b/src/sat/sat_probing.cpp
@@ -65,7 +65,11 @@ namespace sat {
if (implied_lits) {
for (literal lit : *implied_lits) {
if (m_assigned.contains(lit)) {
- s.assign(lit, justification());
+ if (s.m_config.m_drat) {
+ s.m_drat.add(l, lit, true);
+ s.m_drat.add(~l, lit, true);
+ }
+ s.assign_scoped(lit);
m_num_assigned++;
}
}
@@ -73,14 +77,14 @@ namespace sat {
else {
m_to_assert.reset();
s.push();
- s.assign(l, justification());
+ s.assign_scoped(l);
m_counter--;
unsigned old_tr_sz = s.m_trail.size();
s.propagate(false);
if (s.inconsistent()) {
// ~l must be true
s.pop(1);
- s.assign(~l, justification());
+ s.assign_scoped(~l);
s.propagate(false);
return false;
}
@@ -95,8 +99,12 @@ namespace sat {
cache_bins(l, old_tr_sz);
s.pop(1);
- for (literal l : m_to_assert) {
- s.assign(l, justification());
+ for (literal lit : m_to_assert) {
+ if (s.m_config.m_drat) {
+ s.m_drat.add(l, lit, true);
+ s.m_drat.add(~l, lit, true);
+ }
+ s.assign_scoped(lit);
m_num_assigned++;
}
}
@@ -111,13 +119,13 @@ namespace sat {
m_counter--;
s.push();
literal l(v, false);
- s.assign(l, justification());
+ s.assign_scoped(l);
unsigned old_tr_sz = s.m_trail.size();
s.propagate(false);
if (s.inconsistent()) {
// ~l must be true
s.pop(1);
- s.assign(~l, justification());
+ s.assign_scoped(~l);
s.propagate(false);
m_num_assigned++;
return;
@@ -168,7 +176,7 @@ namespace sat {
struct probing::report {
probing & m_probing;
stopwatch m_watch;
- unsigned m_num_assigned;
+ unsigned m_num_assigned;
report(probing & p):
m_probing(p),
m_num_assigned(p.m_num_assigned) {
@@ -177,12 +185,13 @@ namespace sat {
~report() {
m_watch.stop();
- IF_VERBOSE(SAT_VB_LVL,
- verbose_stream() << " (sat-probing :probing-assigned "
- << (m_probing.m_num_assigned - m_num_assigned)
- << " :cost " << m_probing.m_counter;
+ unsigned units = (m_probing.m_num_assigned - m_num_assigned);
+ IF_VERBOSE(2,
+ verbose_stream() << " (sat-probing";
+ if (units > 0) verbose_stream() << " :probing-assigned " << units;
+ verbose_stream() << " :cost " << m_probing.m_counter;
if (m_probing.m_stopped_at != 0) verbose_stream() << " :stopped-at " << m_probing.m_stopped_at;
- verbose_stream() << mem_stat() << " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << ")\n";);
+ verbose_stream() << mem_stat() << m_watch << ")\n";);
}
};
@@ -259,7 +268,7 @@ namespace sat {
}
void probing::collect_statistics(statistics & st) const {
- st.update("probing assigned", m_num_assigned);
+ st.update("sat probing assigned", m_num_assigned);
}
void probing::reset_statistics() {
diff --git a/src/sat/sat_scc.cpp b/src/sat/sat_scc.cpp
index e430bcb47..7ce073975 100644
--- a/src/sat/sat_scc.cpp
+++ b/src/sat/sat_scc.cpp
@@ -47,20 +47,23 @@ namespace sat {
stopwatch m_watch;
unsigned m_num_elim;
unsigned m_num_elim_bin;
+ unsigned m_trail_size;
report(scc & c):
m_scc(c),
m_num_elim(c.m_num_elim),
- m_num_elim_bin(c.m_num_elim_bin) {
+ m_num_elim_bin(c.m_num_elim_bin),
+ m_trail_size(c.m_solver.init_trail_size()) {
m_watch.start();
}
~report() {
m_watch.stop();
unsigned elim_bin = m_scc.m_num_elim_bin - m_num_elim_bin;
- IF_VERBOSE(SAT_VB_LVL,
+ unsigned num_units = m_scc.m_solver.init_trail_size() - m_trail_size;
+ IF_VERBOSE(2,
verbose_stream() << " (sat-scc :elim-vars " << (m_scc.m_num_elim - m_num_elim);
if (elim_bin > 0) verbose_stream() << " :elim-bin " << elim_bin;
- verbose_stream() << mk_stat(m_scc.m_solver)
- << " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << ")\n";);
+ if (num_units > 0) verbose_stream() << " :units " << num_units;
+ verbose_stream() << m_watch << ")\n";);
}
};
@@ -178,7 +181,7 @@ namespace sat {
l2_idx = s[j];
j--;
if (to_literal(l2_idx) == ~l) {
- m_solver.set_conflict(justification());
+ m_solver.set_conflict();
return 0;
}
if (m_solver.is_external(to_literal(l2_idx).var())) {
@@ -244,15 +247,15 @@ namespace sat {
}
void scc::reduce_tr() {
- unsigned quota = 0, num_reduced = 0;
- while ((num_reduced = reduce_tr(false)) > quota) { quota = std::max(100u, num_reduced / 2); }
- quota = 0;
- while ((num_reduced = reduce_tr(true)) > quota) { quota = std::max(100u, num_reduced / 2); }
+ unsigned quota = 0, num_reduced = 0, count = 0;
+ while ((num_reduced = reduce_tr(false)) > quota && count++ < 10) { quota = std::max(100u, num_reduced / 2); }
+ quota = 0; count = 0;
+ while ((num_reduced = reduce_tr(true)) > quota && count++ < 10) { quota = std::max(100u, num_reduced / 2); }
}
void scc::collect_statistics(statistics & st) const {
- st.update("elim bool vars scc", m_num_elim);
- st.update("elim binary", m_num_elim_bin);
+ st.update("sat scc elim vars", m_num_elim);
+ st.update("sat scc elim binary", m_num_elim_bin);
}
void scc::reset_statistics() {
diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp
index 21d264af5..58dab0ff5 100644
--- a/src/sat/sat_simplifier.cpp
+++ b/src/sat/sat_simplifier.cpp
@@ -124,23 +124,20 @@ namespace sat {
}
}
- inline void simplifier::remove_clause_core(clause & c) {
- for (literal l : c)
- insert_elim_todo(l.var());
- m_sub_todo.erase(c);
- c.set_removed(true);
- TRACE("resolution_bug", tout << "del_clause: " << c << "\n";);
- m_need_cleanup = true;
- }
-
inline void simplifier::remove_clause(clause & c) {
- remove_clause_core(c);
- m_use_list.erase(c);
- }
-
- inline void simplifier::remove_clause(clause & c, literal l) {
- remove_clause_core(c);
- m_use_list.erase(c, l);
+ if (!c.was_removed()) {
+ if (s.m_config.m_drat) {
+ s.m_drat.del(c);
+ }
+ for (literal l : c) {
+ insert_elim_todo(l.var());
+ }
+ m_sub_todo.erase(c);
+ c.set_removed(true);
+ TRACE("resolution_bug", tout << "del_clause: " << c << "\n";);
+ m_need_cleanup = true;
+ m_use_list.erase(c);
+ }
}
inline void simplifier::set_learned(clause & c) {
@@ -247,8 +244,8 @@ namespace sat {
cleanup_watches();
move_clauses(s.m_learned, true);
move_clauses(s.m_clauses, false);
- cleanup_clauses(s.m_learned, true, vars_eliminated, m_learned_in_use_lists);
- cleanup_clauses(s.m_clauses, false, vars_eliminated, true);
+ cleanup_clauses(s.m_learned, true, vars_eliminated);
+ cleanup_clauses(s.m_clauses, false, vars_eliminated);
}
CASSERT("sat_solver", s.check_invariant());
@@ -304,7 +301,7 @@ namespace sat {
cs.set_end(it2);
}
- void simplifier::cleanup_clauses(clause_vector & cs, bool learned, bool vars_eliminated, bool in_use_lists) {
+ void simplifier::cleanup_clauses(clause_vector & cs, bool learned, bool vars_eliminated) {
TRACE("sat", tout << "cleanup_clauses\n";);
clause_vector::iterator it = cs.begin();
clause_vector::iterator it2 = it;
@@ -330,35 +327,43 @@ namespace sat {
}
}
- if (cleanup_clause(c, in_use_lists)) {
+ unsigned sz0 = c.size();
+ if (cleanup_clause(c)) {
s.del_clause(c);
continue;
}
unsigned sz = c.size();
- if (sz == 0) {
- s.set_conflict(justification());
+ switch(sz) {
+ case 0:
+ s.set_conflict();
for (; it != end; ++it, ++it2) {
*it2 = *it;
}
+ cs.set_end(it2);
+ return;
+ case 1:
+ s.assign_unit(c[0]);
+ c.restore(sz0);
+ s.del_clause(c);
break;
- }
- if (sz == 1) {
- s.assign(c[0], justification());
- s.del_clause(c);
- continue;
- }
- if (sz == 2) {
+ case 2:
s.mk_bin_clause(c[0], c[1], c.is_learned());
+ c.restore(sz0);
s.del_clause(c);
- continue;
- }
- *it2 = *it;
- it2++;
- if (!c.frozen()) {
- s.attach_clause(c);
- if (s.m_config.m_drat) {
+ break;
+ default:
+ if (s.m_config.m_drat && sz0 != sz) {
s.m_drat.add(c, true);
+ c.restore(sz0);
+ s.m_drat.del(c);
+ c.shrink(sz);
}
+ *it2 = *it;
+ it2++;
+ if (!c.frozen()) {
+ s.attach_clause(c);
+ }
+ break;
}
}
cs.set_end(it2);
@@ -468,8 +473,9 @@ namespace sat {
clause & c2 = *(*it);
if (!c2.was_removed() && *l_it == null_literal) {
// c2 was subsumed
- if (c1.is_learned() && !c2.is_learned())
+ if (c1.is_learned() && !c2.is_learned()) {
s.set_learned(c1, false);
+ }
TRACE("subsumption", tout << c1 << " subsumed " << c2 << "\n";);
remove_clause(c2);
m_num_subsumed++;
@@ -581,7 +587,7 @@ namespace sat {
Return true if the clause is satisfied
*/
- bool simplifier::cleanup_clause(clause & c, bool in_use_list) {
+ bool simplifier::cleanup_clause(clause & c) {
bool r = false;
unsigned sz = c.size();
unsigned j = 0;
@@ -596,11 +602,6 @@ namespace sat {
break;
case l_false:
m_need_cleanup = true;
- if (in_use_list && !c.frozen()) {
- // Remark: if in_use_list is false, then the given clause was not added to the use lists.
- // Remark: frozen clauses are not added to the use lists.
- m_use_list.get(l).erase_not_removed(c);
- }
break;
case l_true:
r = true;
@@ -611,10 +612,8 @@ namespace sat {
break;
}
}
- if (j < sz) {
- if (s.m_config.m_drat) s.m_drat.del(c);
+ if (j < sz && !r) {
c.shrink(j);
- if (s.m_config.m_drat) s.m_drat.add(c, true);
}
return r;
}
@@ -648,7 +647,7 @@ namespace sat {
inline void simplifier::propagate_unit(literal l) {
unsigned old_trail_sz = s.m_trail.size();
- s.assign(l, justification());
+ s.assign_scoped(l);
s.propagate_core(false); // must not use propagate(), since s.m_clauses is not in a consistent state.
if (s.inconsistent())
return;
@@ -663,7 +662,7 @@ namespace sat {
for (auto it = cs.mk_iterator(); !it.at_end(); ) {
clause & c = it.curr();
it.next();
- remove_clause(c, l);
+ remove_clause(c);
}
cs.reset();
}
@@ -674,39 +673,55 @@ namespace sat {
m_need_cleanup = true;
m_num_elim_lits++;
insert_elim_todo(l.var());
- c.elim(l);
- if (s.m_config.m_drat) s.m_drat.add(c, true);
- // if (s.m_config.m_drat) s.m_drat.del(c0); // can delete previous version
+ if (s.m_config.m_drat && c.contains(l)) {
+ m_dummy.set(c.size(), c.begin(), c.is_learned());
+ c.elim(l);
+ s.m_drat.add(c, true);
+ s.m_drat.del(*m_dummy.get());
+ }
+ else {
+ c.elim(l);
+ }
clause_use_list & occurs = m_use_list.get(l);
occurs.erase_not_removed(c);
m_sub_counter -= occurs.size()/2;
- if (cleanup_clause(c, true /* clause is in the use lists */)) {
+
+ unsigned sz0 = c.size();
+ if (cleanup_clause(c)) {
// clause was satisfied
TRACE("elim_lit", tout << "clause was satisfied\n";);
remove_clause(c);
return;
}
- switch (c.size()) {
+ unsigned sz = c.size();
+ switch (sz) {
case 0:
TRACE("elim_lit", tout << "clause is empty\n";);
- s.set_conflict(justification());
- return;
+ s.set_conflict();
+ break;
case 1:
TRACE("elim_lit", tout << "clause became unit: " << c[0] << "\n";);
+ c.restore(sz0);
propagate_unit(c[0]);
- // propagate_unit will delete c.
- // remove_clause(c);
- return;
+ // unit propagation removes c
+ break;
case 2:
TRACE("elim_lit", tout << "clause became binary: " << c[0] << " " << c[1] << "\n";);
+ c.restore(sz0);
s.mk_bin_clause(c[0], c[1], c.is_learned());
- m_sub_bin_todo.push_back(bin_clause(c[0], c[1], c.is_learned()));
+ m_sub_bin_todo.push_back(bin_clause(c[0], c[1], c.is_learned()));
remove_clause(c);
- return;
+ break;
default:
+ if (s.m_config.m_drat && sz0 != sz) {
+ s.m_drat.add(c, true);
+ c.restore(sz0);
+ s.m_drat.del(c);
+ c.shrink(sz);
+ }
TRACE("elim_lit", tout << "result: " << c << "\n";);
m_sub_todo.insert(c);
- return;
+ break;
}
}
@@ -871,27 +886,36 @@ namespace sat {
m_sub_counter--;
TRACE("subsumption", tout << "next: " << c << "\n";);
if (s.m_trail.size() > m_last_sub_trail_sz) {
- if (cleanup_clause(c, true /* clause is in the use_lists */)) {
+ unsigned sz0 = c.size();
+ if (cleanup_clause(c)) {
remove_clause(c);
continue;
}
unsigned sz = c.size();
- if (sz == 0) {
- s.set_conflict(justification());
+ switch (sz) {
+ case 0:
+ s.set_conflict();
return;
- }
- if (sz == 1) {
+ case 1:
+ c.restore(sz0);
propagate_unit(c[0]);
- // propagate_unit will delete c.
- // remove_clause(c);
+ // unit propagation removes c
continue;
- }
- if (sz == 2) {
+ case 2:
TRACE("subsumption", tout << "clause became binary: " << c << "\n";);
s.mk_bin_clause(c[0], c[1], c.is_learned());
m_sub_bin_todo.push_back(bin_clause(c[0], c[1], c.is_learned()));
+ c.restore(sz0);
remove_clause(c);
continue;
+ default:
+ if (s.m_config.m_drat && sz != sz0) {
+ s.m_drat.add(c, true);
+ c.restore(sz0);
+ s.m_drat.del(c);
+ c.shrink(sz);
+ }
+ break;
}
}
TRACE("subsumption", tout << "using: " << c << "\n";);
@@ -991,6 +1015,9 @@ namespace sat {
svector m_in_intersection;
unsigned m_ala_qhead;
clause_wrapper m_clause;
+ unsigned m_ala_cost;
+ unsigned m_ala_benefit;
+ unsigned m_ala_max_cost;
blocked_clause_elim(simplifier & _s, unsigned limit, model_converter & _mc, use_list & l,
vector & wlist):
@@ -998,12 +1025,15 @@ namespace sat {
m_counter(limit),
m_mc(_mc),
m_queue(l, wlist),
- m_clause(null_literal, null_literal) {
+ m_clause(null_literal, null_literal),
+ m_ala_cost(0),
+ m_ala_benefit(0) {
m_in_intersection.resize(s.s.num_vars() * 2, false);
+ m_ala_max_cost = (s.s.m_clauses.size() * s.m_num_calls)/5;
}
void insert(literal l) {
- VERIFY(process_var(l.var()));
+ SASSERT(process_var(l.var()));
m_queue.insert(l);
}
@@ -1011,6 +1041,10 @@ namespace sat {
return !s.s.is_assumption(v) && !s.was_eliminated(v) && !s.is_external(v) && s.value(v) == l_undef;
}
+ bool reached_max_cost() {
+ return m_ala_benefit <= m_ala_cost * 100 && m_ala_cost > m_ala_max_cost;
+ }
+
enum elim_type {
bce_t,
cce_t,
@@ -1042,6 +1076,7 @@ namespace sat {
}
void insert_queue() {
+ m_queue.reset();
unsigned num_vars = s.s.num_vars();
for (bool_var v = 0; v < num_vars; v++) {
if (process_var(v)) {
@@ -1130,7 +1165,6 @@ namespace sat {
if (m_intersection.empty() && !first) {
m_tautology.shrink(tsz);
}
- // if (first) IF_VERBOSE(0, verbose_stream() << "taut: " << m_tautology << "\n";);
return first;
}
@@ -1188,9 +1222,6 @@ namespace sat {
RI literals.
*/
void minimize_covered_clause(unsigned idx) {
- // IF_VERBOSE(0, verbose_stream() << "minimize: " << m_covered_clause
- // << " @ " << idx << "\n" << "tautology: " << m_tautology << "\n";);
- literal _blocked = m_covered_clause[idx];
for (literal l : m_tautology) VERIFY(s.is_marked(l));
for (literal l : m_covered_clause) s.unmark_visited(l);
for (literal l : m_tautology) s.mark_visited(l);
@@ -1200,14 +1231,6 @@ namespace sat {
if (m_covered_antecedent[i] == clause_ante()) s.mark_visited(lit);
if (s.is_marked(lit)) idx = i;
}
- if (false && _blocked.var() == 8074) {
- IF_VERBOSE(0, verbose_stream() << "covered: " << m_covered_clause << "\n";
- verbose_stream() << "tautology: " << m_tautology << "\n";
- verbose_stream() << "index: " << idx << "\n";
- for (unsigned i = idx; i > 0; --i) {
- m_covered_antecedent[i].display(verbose_stream(), m_covered_clause[i]);
- });
- }
for (unsigned i = idx; i > 0; --i) {
literal lit = m_covered_clause[i];
//s.mark_visited(lit);
@@ -1251,10 +1274,6 @@ namespace sat {
// unsigned sz0 = m_covered_clause.size();
m_covered_clause.resize(j);
VERIFY(j >= m_clause.size());
- if (false && _blocked.var() == 16774) {
- IF_VERBOSE(0, verbose_stream() << "covered: " << m_covered_clause << "\n");
- }
- // IF_VERBOSE(0, verbose_stream() << "reduced from size " << sz0 << " to " << m_covered_clause << "\n" << m_clause << "\n";);
}
/*
@@ -1272,17 +1291,19 @@ namespace sat {
* unless C contains lit, and it is a tautology.
*/
bool add_ala() {
- for (; m_ala_qhead < m_covered_clause.size(); ++m_ala_qhead) {
+ unsigned init_size = m_covered_clause.size();
+ for (; m_ala_qhead < m_covered_clause.size() && m_ala_qhead < 5*init_size && !reached_max_cost(); ++m_ala_qhead) {
+ ++m_ala_cost;
literal l = m_covered_clause[m_ala_qhead];
for (watched & w : s.get_wlist(~l)) {
if (w.is_binary_non_learned_clause()) {
literal lit = w.get_literal();
if (revisit_binary(l, lit)) continue;
if (s.is_marked(lit)) {
+ ++m_ala_benefit;
return true;
}
if (!s.is_marked(~lit)) {
- // if (m_covered_clause[0].var() == 10219) IF_VERBOSE(0, verbose_stream() << "ala: " << l << " " << lit << "\n");
m_covered_clause.push_back(~lit);
m_covered_antecedent.push_back(clause_ante(l, false));
s.mark_visited(~lit);
@@ -1310,9 +1331,9 @@ namespace sat {
}
if (!ok) continue;
if (lit1 == null_literal) {
+ ++m_ala_benefit;
return true;
}
- // if (m_covered_clause[0].var() == 10219) IF_VERBOSE(0, verbose_stream() << "ala: " << c << " " << lit1 << "\n");
m_covered_clause.push_back(~lit1);
m_covered_antecedent.push_back(clause_ante(c));
s.mark_visited(~lit1);
@@ -1349,7 +1370,6 @@ namespace sat {
}
bool above_threshold(unsigned sz0) const {
- // if (sz0 * 400 < m_covered_clause.size()) IF_VERBOSE(0, verbose_stream() << "above threshold " << sz0 << " " << m_covered_clause.size() << "\n";);
return sz0 * 400 < m_covered_clause.size();
}
@@ -1420,19 +1440,6 @@ namespace sat {
if (check_abce_tautology(m_covered_clause[i])) {
blocked = m_covered_clause[i];
reset_mark();
-#if 0
- if (sz0 == 3 && blocked.var() == 10219) {
- IF_VERBOSE(0, verbose_stream() << "abce: " << m_covered_clause << "\n";
- for (literal l : m_covered_clause) verbose_stream() << s.value(l) << "\n";
- );
- literal l = blocked;
- clause_use_list & neg_occs = s.m_use_list.get(~l);
- for (auto it = neg_occs.mk_iterator(); !it.at_end(); it.next()) {
- clause & c = it.curr();
- IF_VERBOSE(0, verbose_stream() << c << "\n");
- }
- }
-#endif
m_covered_clause.shrink(sz0);
if (et == bce_t) return bce_t;
k = model_converter::ABCE;
@@ -1495,7 +1502,9 @@ namespace sat {
template
void cce_binary() {
- while (!m_queue.empty() && m_counter >= 0) {
+ m_ala_cost = 0;
+ m_ala_benefit = 0;
+ while (!m_queue.empty() && m_counter >= 0 && !reached_max_cost()) {
s.checkpoint();
process_cce_binary(m_queue.next());
}
@@ -1507,7 +1516,7 @@ namespace sat {
watch_list & wlist = s.get_wlist(~l);
m_counter -= wlist.size();
model_converter::kind k;
- for (watched & w : wlist) {
+ for (watched& w : wlist) {
if (!w.is_binary_non_learned_clause()) continue;
if (!select_clause(2)) continue;
literal l2 = w.get_literal();
@@ -1527,15 +1536,20 @@ namespace sat {
block_covered_binary(w, l, blocked, k);
break;
}
+ s.checkpoint();
}
}
template
void cce_clauses() {
literal blocked;
+ m_ala_cost = 0;
+ m_ala_benefit = 0;
model_converter::kind k;
- for (clause* cp : s.s.m_clauses) {
- clause& c = *cp;
+ unsigned start = s.s.m_rand();
+ unsigned sz = s.s.m_clauses.size();
+ for (unsigned i = 0; i < sz; ++i) {
+ clause& c = *s.s.m_clauses[(i + start) % sz];
if (c.was_removed() || c.is_learned()) continue;
if (!select_clause(c.size())) continue;
elim_type r = cce(c, blocked, k);
@@ -1552,7 +1566,11 @@ namespace sat {
s.set_learned(c);
break;
}
- }
+ s.checkpoint();
+ if (reached_max_cost()) {
+ break;
+ }
+ }
}
void inc_bc(elim_type et) {
@@ -1574,15 +1592,6 @@ namespace sat {
}
void block_covered_clause(clause& c, literal l, model_converter::kind k) {
- if (false) {
- IF_VERBOSE(0, verbose_stream() << "blocked: " << l << " @ " << c << " :covered " << m_covered_clause << "\n";
- s.m_use_list.display(verbose_stream() << "use " << l << ":", l);
- s.m_use_list.display(verbose_stream() << "use " << ~l << ":", ~l);
- s.s.display_watch_list(verbose_stream() << ~l << ": ", s.get_wlist(l)) << "\n";
- s.s.display_watch_list(verbose_stream() << l << ": ", s.get_wlist(~l)) << "\n";
- );
-
- }
TRACE("blocked_clause", tout << "new blocked clause: " << c << "\n";);
SASSERT(!s.is_external(l));
model_converter::entry& new_entry = m_mc.mk(k, l.var());
@@ -1841,36 +1850,7 @@ namespace sat {
}
void simplifier::add_non_learned_binary_clause(literal l1, literal l2) {
-#if 0
- if ((l1.var() == 2039 || l2.var() == 2039) &&
- (l1.var() == 27042 || l2.var() == 27042)) {
- IF_VERBOSE(1, verbose_stream() << "add_bin: " << l1 << " " << l2 << "\n");
- }
-#endif
-#if 0
- watched* w;
- watch_list & wlist1 = get_wlist(~l1);
- watch_list & wlist2 = get_wlist(~l2);
- w = find_binary_watch(wlist1, l2);
- if (w) {
- if (w->is_learned())
- w->set_learned(false);
- }
- else {
- wlist1.push_back(watched(l2, false));
- }
-
- w = find_binary_watch(wlist2, l1);
- if (w) {
- if (w->is_learned())
- w->set_learned(false);
- }
- else {
- wlist2.push_back(watched(l1, false));
- }
-#else
s.mk_bin_clause(l1, l2, false);
-#endif
}
/**
@@ -1881,17 +1861,13 @@ namespace sat {
for (auto & w : wlist) {
if (w.is_binary_clause()) {
literal l2 = w.get_literal();
+ // m_drat.del(l, l2);
watch_list & wlist2 = get_wlist(~l2);
watch_list::iterator it2 = wlist2.begin();
watch_list::iterator itprev = it2;
watch_list::iterator end2 = wlist2.end();
for (; it2 != end2; ++it2) {
if (it2->is_binary_clause() && it2->get_literal() == l) {
- if ((l.var() == 2039 || l2.var() == 2039) &&
- (l.var() == 27042 || l2.var() == 27042)) {
- IF_VERBOSE(1, verbose_stream() << "remove_bin: " << l << " " << l2 << "\n");
- }
-
TRACE("bin_clause_bug", tout << "removing: " << l << " " << it2->get_literal() << "\n";);
m_sub_bin_todo.erase(bin_clause(l2, l, it2->is_learned()));
continue;
@@ -1915,11 +1891,16 @@ namespace sat {
clause & c = it.curr();
it.next();
SASSERT(c.contains(l));
- c.set_removed(true);
- m_use_list.erase(c, l);
- m_sub_todo.erase(c);
- TRACE("resolution_bug", tout << "del_clause (elim_var): " << c << "\n";);
- m_need_cleanup = true;
+ if (!c.was_removed()) {
+ if (s.m_config.m_drat) {
+ s.m_drat.del(c);
+ }
+ c.set_removed(true);
+ m_use_list.erase(c, l);
+ m_sub_todo.erase(c);
+ TRACE("resolution_bug", tout << "del_clause (elim_var): " << c << "\n";);
+ m_need_cleanup = true;
+ }
}
}
@@ -1992,41 +1973,27 @@ namespace sat {
m_elim_counter -= num_pos * num_neg + before_lits;
- if (false) {
- literal l(v, false);
- IF_VERBOSE(0,
- verbose_stream() << "elim: " << l << "\n";
- s.display_watch_list(verbose_stream() << ~l << ": ", get_wlist(l)) << "\n";
- s.display_watch_list(verbose_stream() << l << ": ", get_wlist(~l)) << "\n";);
- }
// eliminate variable
++s.m_stats.m_elim_var_res;
VERIFY(!is_external(v));
model_converter::entry & mc_entry = s.m_mc.mk(model_converter::ELIM_VAR, v);
save_clauses(mc_entry, m_pos_cls);
save_clauses(mc_entry, m_neg_cls);
- s.m_eliminated[v] = true;
- remove_bin_clauses(pos_l);
- remove_bin_clauses(neg_l);
- remove_clauses(pos_occs, pos_l);
- remove_clauses(neg_occs, neg_l);
- pos_occs.reset();
- neg_occs.reset();
-
+ s.m_eliminated[v] = true;
m_elim_counter -= num_pos * num_neg + before_lits;
for (auto & c1 : m_pos_cls) {
for (auto & c2 : m_neg_cls) {
m_new_cls.reset();
if (!resolve(c1, c2, pos_l, m_new_cls))
- continue;
- if (false && v == 767) IF_VERBOSE(0, verbose_stream() << "elim: " << c1 << " + " << c2 << " -> " << m_new_cls << "\n");
+ continue;
TRACE("resolution_new_cls", tout << c1 << "\n" << c2 << "\n-->\n" << m_new_cls << "\n";);
- if (cleanup_clause(m_new_cls))
+ if (cleanup_clause(m_new_cls)) {
continue; // clause is already satisfied.
+ }
switch (m_new_cls.size()) {
case 0:
- s.set_conflict(justification());
+ s.set_conflict();
break;
case 1:
propagate_unit(m_new_cls[0]);
@@ -2057,6 +2024,12 @@ namespace sat {
return true;
}
}
+ remove_bin_clauses(pos_l);
+ remove_bin_clauses(neg_l);
+ remove_clauses(pos_occs, pos_l);
+ remove_clauses(neg_occs, neg_l);
+ pos_occs.reset();
+ neg_occs.reset();
return true;
}
@@ -2142,15 +2115,15 @@ namespace sat {
}
void simplifier::collect_statistics(statistics & st) const {
- st.update("subsumed", m_num_subsumed);
- st.update("subsumption resolution", m_num_sub_res);
- st.update("elim literals", m_num_elim_lits);
- st.update("bce", m_num_bce);
- st.update("cce", m_num_cce);
- st.update("acce", m_num_acce);
- st.update("abce", m_num_abce);
- st.update("bca", m_num_bca);
- st.update("ate", m_num_ate);
+ st.update("sat subsumed", m_num_subsumed);
+ st.update("sat subs resolution", m_num_sub_res);
+ st.update("sat elim literals", m_num_elim_lits);
+ st.update("sat bce", m_num_bce);
+ st.update("sat cce", m_num_cce);
+ st.update("sat acce", m_num_acce);
+ st.update("sat abce", m_num_abce);
+ st.update("sat bca", m_num_bca);
+ st.update("sat ate", m_num_ate);
}
void simplifier::reset_statistics() {
diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h
index 990b87b10..2aa2b4252 100644
--- a/src/sat/sat_simplifier.h
+++ b/src/sat/sat_simplifier.h
@@ -133,9 +133,7 @@ namespace sat {
void register_clauses(clause_vector & cs);
- void remove_clause_core(clause & c);
void remove_clause(clause & c);
- void remove_clause(clause & c, literal l);
void set_learned(clause & c);
void set_learned(literal l1, literal l2);
@@ -154,7 +152,7 @@ namespace sat {
void collect_subsumed0(clause const & c1, clause_vector & out);
void back_subsumption0(clause & c1);
- bool cleanup_clause(clause & c, bool in_use_list);
+ bool cleanup_clause(clause & c);
bool cleanup_clause(literal_vector & c);
void elim_lit(clause & c, literal l);
void elim_dup_bins();
@@ -164,7 +162,7 @@ namespace sat {
void cleanup_watches();
void move_clauses(clause_vector & cs, bool learned);
- void cleanup_clauses(clause_vector & cs, bool learned, bool vars_eliminated, bool in_use_lists);
+ void cleanup_clauses(clause_vector & cs, bool learned, bool vars_eliminated);
bool is_external(bool_var v) const;
bool is_external(literal l) const { return is_external(l.var()); }
diff --git a/src/sat/sat_simplifier_params.pyg b/src/sat/sat_simplifier_params.pyg
index 3757aad2d..60ca4a49b 100644
--- a/src/sat/sat_simplifier_params.pyg
+++ b/src/sat/sat_simplifier_params.pyg
@@ -2,7 +2,7 @@ def_module_params(module_name='sat',
class_name='sat_simplifier_params',
export=True,
params=(('bce', BOOL, False, 'eliminate blocked clauses'),
- ('abce', BOOL, False, 'eliminate blocked clauses using asymmmetric literals'),
+ ('abce', BOOL, False, 'eliminate blocked clauses using asymmetric literals'),
('cce', BOOL, False, 'eliminate covered clauses'),
('ate', BOOL, True, 'asymmetric tautology elimination'),
('acce', BOOL, False, 'eliminate covered clauses using asymmetric added literals'),
@@ -11,7 +11,7 @@ def_module_params(module_name='sat',
('bce_delay', UINT, 2, 'delay eliminate blocked clauses until simplification round'),
('retain_blocked_clauses', BOOL, True, 'retain blocked clauses as lemmas'),
('blocked_clause_limit', UINT, 100000000, 'maximum number of literals visited during blocked clause elimination'),
- ('override_incremental', BOOL, False, 'override incemental safety gaps. Enable elimination of blocked clauses and variables even if solver is reused'),
+ ('override_incremental', BOOL, False, 'override incremental safety gaps. Enable elimination of blocked clauses and variables even if solver is reused'),
('resolution.limit', UINT, 500000000, 'approx. maximum number of literals visited during variable elimination'),
('resolution.occ_cutoff', UINT, 10, 'first cutoff (on number of positive/negative occurrences) for Boolean variable elimination'),
('resolution.occ_cutoff_range1', UINT, 8, 'second cutoff (number of positive/negative occurrences) for Boolean variable elimination, for problems containing less than res_cls_cutoff1 clauses'),
diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp
index ee3bc7880..8b7d53897 100644
--- a/src/sat/sat_solver.cpp
+++ b/src/sat/sat_solver.cpp
@@ -27,6 +27,9 @@ Revision History:
#include "util/trace.h"
#include "util/max_cliques.h"
#include "util/gparams.h"
+#ifdef _MSC_VER
+# include
+#endif
// define to update glue during propagation
#define UPDATE_GLUE
@@ -34,7 +37,7 @@ Revision History:
namespace sat {
solver::solver(params_ref const & p, reslimit& l):
- m_rlimit(l),
+ solver_core(l),
m_checkpoint_enabled(true),
m_config(p),
m_par(nullptr),
@@ -95,7 +98,7 @@ namespace sat {
if (ext) ext->set_solver(this);
}
- void solver::copy(solver const & src) {
+ void solver::copy(solver const & src, bool copy_learned) {
pop_to_base_level();
del_clauses(m_clauses);
del_clauses(m_learned);
@@ -120,6 +123,11 @@ namespace sat {
m_qhead = 0;
m_trail.reset();
m_scopes.reset();
+
+ if (src.inconsistent()) {
+ set_conflict();
+ return;
+ }
// create new vars
for (bool_var v = num_vars(); v < src.num_vars(); v++) {
@@ -132,11 +140,9 @@ namespace sat {
m_phase[v] = src.m_phase[v];
m_prev_phase[v] = src.m_prev_phase[v];
-#if 1
// inherit activity:
m_activity[v] = src.m_activity[v];
m_case_split_queue.activity_changed_eh(v, false);
-#endif
}
//
@@ -149,7 +155,7 @@ namespace sat {
unsigned trail_sz = src.init_trail_size();
for (unsigned i = 0; i < trail_sz; ++i) {
- assign(src.m_trail[i], justification());
+ assign_unit(src.m_trail[i]);
}
// copy binary clauses
@@ -187,7 +193,7 @@ namespace sat {
// copy high quality lemmas
unsigned num_learned = 0;
for (clause* c : src.m_learned) {
- if (c->glue() <= 2 || (c->size() <= 40 && c->glue() <= 8)) {
+ if (c->glue() <= 2 || (c->size() <= 40 && c->glue() <= 8) || copy_learned) {
buffer.reset();
for (literal l : *c) buffer.push_back(l);
clause* c1 = mk_clause_core(buffer.size(), buffer.c_ptr(), true);
@@ -198,7 +204,7 @@ namespace sat {
}
}
}
- IF_VERBOSE(1, verbose_stream() << "(sat.copy :learned " << num_learned << ")\n";);
+ IF_VERBOSE(2, verbose_stream() << "(sat.copy :learned " << num_learned << ")\n";);
}
m_user_scope_literals.reset();
@@ -270,7 +276,7 @@ namespace sat {
}
}
- void solver::mk_clause(unsigned num_lits, literal * lits, bool learned) {
+ clause* solver::mk_clause(unsigned num_lits, literal * lits, bool learned) {
m_model_is_current = false;
DEBUG_CODE({
for (unsigned i = 0; i < num_lits; i++)
@@ -278,24 +284,24 @@ namespace sat {
});
if (m_user_scope_literals.empty()) {
- mk_clause_core(num_lits, lits, learned);
+ return mk_clause_core(num_lits, lits, learned);
}
else {
m_aux_literals.reset();
m_aux_literals.append(num_lits, lits);
m_aux_literals.append(m_user_scope_literals);
- mk_clause_core(m_aux_literals.size(), m_aux_literals.c_ptr(), learned);
+ return mk_clause_core(m_aux_literals.size(), m_aux_literals.c_ptr(), learned);
}
}
- void solver::mk_clause(literal l1, literal l2, bool learned) {
+ clause* solver::mk_clause(literal l1, literal l2, bool learned) {
literal ls[2] = { l1, l2 };
- mk_clause(2, ls, learned);
+ return mk_clause(2, ls, learned);
}
- void solver::mk_clause(literal l1, literal l2, literal l3, bool learned) {
+ clause* solver::mk_clause(literal l1, literal l2, literal l3, bool learned) {
literal ls[3] = { l1, l2, l3 };
- mk_clause(3, ls, learned);
+ return mk_clause(3, ls, learned);
}
void solver::del_clause(clause& c) {
@@ -305,31 +311,38 @@ namespace sat {
if (c.frozen()) {
--m_num_frozen;
}
- if (m_config.m_drat && !m_drat.is_cleaned(c)) {
+ if (!c.was_removed() && m_config.m_drat && !m_drat.is_cleaned(c)) {
m_drat.del(c);
}
- dealloc_clause(&c);
- m_stats.m_del_clause++;
+ dealloc_clause(&c);
+ if (m_searching)
+ m_stats.m_del_clause++;
}
clause * solver::mk_clause_core(unsigned num_lits, literal * lits, bool learned) {
TRACE("sat", tout << "mk_clause: " << mk_lits_pp(num_lits, lits) << (learned?" learned":" aux") << "\n";);
if (!learned) {
+ unsigned old_sz = num_lits;
bool keep = simplify_clause(num_lits, lits);
TRACE("sat_mk_clause", tout << "mk_clause (after simp), keep: " << keep << "\n" << mk_lits_pp(num_lits, lits) << "\n";);
if (!keep) {
return nullptr; // clause is equivalent to true.
}
+ // if an input clause is simplified, then log the simplified version as learned
+ if (!learned && old_sz > num_lits && m_config.m_drat) {
+ m_lemma.reset();
+ m_lemma.append(num_lits, lits);
+ m_drat.add(m_lemma);
+ }
++m_stats.m_non_learned_generation;
}
switch (num_lits) {
case 0:
- if (m_config.m_drat) m_drat.add();
- set_conflict(justification());
+ set_conflict();
return nullptr;
case 1:
- assign(lits[0], justification());
+ assign_unit(lits[0]);
return nullptr;
case 2:
mk_bin_clause(lits[0], lits[1], learned);
@@ -343,12 +356,12 @@ namespace sat {
}
void solver::mk_bin_clause(literal l1, literal l2, bool learned) {
- if (find_binary_watch(get_wlist(~l1), ~l2)) {
- assign(l1, justification());
+ if (find_binary_watch(get_wlist(~l1), ~l2) && value(l1) == l_undef) {
+ assign_core(l1, 0, justification(l2));
return;
}
- if (find_binary_watch(get_wlist(~l2), ~l1)) {
- assign(l2, justification());
+ if (find_binary_watch(get_wlist(~l2), ~l1) && value(l2) == l_undef) {
+ assign_core(l2, 0, justification(l1));
return;
}
watched* w0 = find_binary_watch(get_wlist(~l1), l2);
@@ -534,7 +547,7 @@ namespace sat {
void solver::defrag_clauses() {
if (memory_pressure()) return;
pop(scope_lvl());
- IF_VERBOSE(1, verbose_stream() << "(sat-defrag)\n");
+ IF_VERBOSE(2, verbose_stream() << "(sat-defrag)\n");
clause_allocator& alloc = m_cls_allocator[!m_cls_allocator_idx];
ptr_vector new_clauses, new_learned;
for (clause* c : m_clauses) c->unmark_used();
@@ -690,7 +703,7 @@ namespace sat {
for (; i < num_lits; i++) {
literal curr = lits[i];
lbool val = value(curr);
- if (!lvl0 && m_level[curr.var()] > 0)
+ if (!lvl0 && lvl(curr) > 0)
val = l_undef;
switch (val) {
case l_false:
@@ -701,7 +714,7 @@ namespace sat {
if (curr != prev) {
prev = curr;
if (i != j)
- lits[j] = lits[i];
+ std::swap(lits[j], lits[i]);
j++;
}
break;
@@ -759,17 +772,20 @@ namespace sat {
m_not_l = not_l;
}
- void solver::assign_core(literal l, unsigned lvl, justification j) {
+ void solver::assign_core(literal l, unsigned _lvl, justification j) {
SASSERT(value(l) == l_undef);
- TRACE("sat_assign_core", tout << l << " " << j << " level: " << lvl << "\n";);
+ TRACE("sat_assign_core", tout << l << " " << j << " level: " << _lvl << "\n";);
+ if (_lvl == 0 && m_config.m_drat) {
+ m_drat.add(l, !j.is_none());
+ }
+
if (at_base_lvl()) {
- if (m_config.m_drat) m_drat.add(l, !j.is_none());
j = justification(); // erase justification for level 0
}
m_assignment[l.index()] = l_true;
m_assignment[(~l).index()] = l_false;
bool_var v = l.var();
- m_level[v] = lvl;
+ m_level[v] = scope_lvl();
m_justification[v] = j;
m_phase[v] = static_cast(l.sign());
m_assigned_since_gc[v] = true;
@@ -1023,7 +1039,7 @@ namespace sat {
m_cuber = nullptr;
if (is_first) {
pop_to_base_level();
- set_conflict(justification());
+ set_conflict();
}
break;
case l_true: {
@@ -1058,7 +1074,7 @@ namespace sat {
init_reason_unknown();
pop_to_base_level();
m_stats.m_units = init_trail_size();
- IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver)\n";);
+ IF_VERBOSE(2, verbose_stream() << "(sat.solver)\n";);
SASSERT(at_base_lvl());
if (m_config.m_local_search) {
@@ -1144,6 +1160,7 @@ namespace sat {
}
catch (const abort_solver &) {
m_reason_unknown = "sat.giveup";
+ IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort giveup\")\n";);
return l_undef;
}
}
@@ -1158,7 +1175,6 @@ namespace sat {
SASSERT(!m_local_search);
m_local_search = alloc(local_search);
local_search& srch = *m_local_search;
- srch.config().set_config(m_config);
srch.import(*this, false);
scoped_rl.push_child(&srch.rlimit());
lbool r = srch.check(num_lits, lits, nullptr);
@@ -1183,9 +1199,8 @@ namespace sat {
int num_threads = num_extra_solvers + 1 + num_local_search + num_unit_walk;
for (int i = 0; i < num_local_search; ++i) {
local_search* l = alloc(local_search);
- l->config().set_config(m_config);
- l->config().set_random_seed(m_config.m_random_seed + i);
l->import(*this, false);
+ l->config().set_random_seed(m_config.m_random_seed + i);
ls.push_back(l);
}
@@ -1337,7 +1352,7 @@ namespace sat {
SASSERT(lit.var() < m_par_num_vars);
if (lvl(lit.var()) != 0 || value(lit) != l_true) {
++num_in;
- assign(lit, justification());
+ assign_unit(lit);
}
}
if (num_in > 0 || num_out > 0) {
@@ -1423,8 +1438,8 @@ namespace sat {
SASSERT(phase != l_undef);
literal next_lit(next, phase == l_false);
- assign(next_lit, justification());
TRACE("sat_decide", tout << scope_lvl() << ": next-case-split: " << next_lit << "\n";);
+ assign_scoped(next_lit);
return true;
}
@@ -1451,14 +1466,13 @@ namespace sat {
lbool solver::propagate_and_backjump_step(bool& done) {
done = true;
propagate(true);
- if (!inconsistent())
- return l_true;
+ if (!inconsistent()) {
+ return should_restart() ? l_undef : l_true;
+ }
if (!resolve_conflict())
return l_false;
if (reached_max_conflicts())
return l_undef;
- if (should_restart())
- return l_undef;
if (at_base_lvl()) {
cleanup(false); // cleaner may propagate frozen clauses
if (inconsistent()) {
@@ -1526,14 +1540,14 @@ namespace sat {
for (unsigned i = 0; !inconsistent() && i < m_user_scope_literals.size(); ++i) {
literal nlit = ~m_user_scope_literals[i];
- assign(nlit, justification());
+ assign_scoped(nlit);
}
for (unsigned i = 0; !inconsistent() && i < num_lits; ++i) {
literal lit = lits[i];
SASSERT(is_external(lit.var()));
add_assumption(lit);
- assign(lit, justification());
+ assign_scoped(lit);
}
m_search_lvl = scope_lvl();
SASSERT(m_search_lvl == 1);
@@ -1572,7 +1586,7 @@ namespace sat {
for (literal lit : m_min_core) {
SASSERT(is_external(lit.var()));
add_assumption(lit);
- assign(lit, justification());
+ assign_scoped(lit);
}
propagate(false);
SASSERT(inconsistent());
@@ -1585,11 +1599,11 @@ namespace sat {
push();
for (literal lit : m_user_scope_literals) {
if (inconsistent()) break;
- assign(~lit, justification());
+ assign_scoped(~lit);
}
for (literal lit : m_assumptions) {
if (inconsistent()) break;
- assign(lit, justification());
+ assign_scoped(lit);
}
TRACE("sat",
for (literal a : m_assumptions) {
@@ -1609,6 +1623,12 @@ namespace sat {
return tracking_assumptions() && m_assumption_set.contains(l);
}
+ void solver::set_activity(bool_var v, unsigned act) {
+ unsigned old_act = m_activity[v];
+ m_activity[v] = act;
+ m_case_split_queue.activity_changed_eh(v, act > old_act);
+ }
+
bool solver::is_assumption(bool_var v) const {
return is_assumption(literal(v, false)) || is_assumption(literal(v, true));
}
@@ -1623,6 +1643,8 @@ namespace sat {
m_gc_threshold = m_config.m_gc_initial;
m_defrag_threshold = 2;
m_restarts = 0;
+ m_last_position_log = 0;
+ m_restart_logs = 0;
m_simplifications = 0;
m_conflicts_since_init = 0;
m_next_simplify = m_config.m_simplify_delay;
@@ -1638,6 +1660,7 @@ namespace sat {
m_min_core.reset();
m_simplifier.init_search();
TRACE("sat", display(tout););
+
}
/**
@@ -1647,6 +1670,7 @@ namespace sat {
if (m_conflicts_since_init < m_next_simplify) {
return;
}
+ log_stats();
m_simplifications++;
IF_VERBOSE(2, verbose_stream() << "(sat.simplify :simplifications " << m_simplifications << ")\n";);
@@ -1691,8 +1715,6 @@ namespace sat {
lh.collect_statistics(m_aux_stats);
}
- TRACE("sat", display(tout << "consistent: " << (!inconsistent()) << "\n"););
-
reinit_assumptions();
if (m_next_simplify == 0) {
@@ -1704,7 +1726,6 @@ namespace sat {
m_next_simplify = m_conflicts_since_init + m_config.m_simplify_max;
}
-
if (m_par) m_par->set_phase(*this);
#if 0
@@ -1762,39 +1783,31 @@ namespace sat {
}
#endif
- IF_VERBOSE(10, verbose_stream() << "\"checking model\"\n";);
- if (!check_clauses(m_model)) {
- throw solver_exception("check model failed");
- }
-
- if (m_config.m_drat) m_drat.check_model(m_model);
-
- // m_mc.set_solver(nullptr);
- m_mc(m_model);
-
- if (!check_clauses(m_model)) {
- IF_VERBOSE(0, verbose_stream() << "failure checking clauses on transformed model\n";);
- IF_VERBOSE(10, m_mc.display(verbose_stream()));
- //IF_VERBOSE(0, display_units(verbose_stream()));
- //IF_VERBOSE(0, display(verbose_stream()));
- IF_VERBOSE(0, for (bool_var v = 0; v < num; v++) verbose_stream() << v << ": " << m_model[v] << "\n";);
-
- throw solver_exception("check model failed");
- }
-
- TRACE("sat", for (bool_var v = 0; v < num; v++) tout << v << ": " << m_model[v] << "\n";);
-
if (m_clone) {
- IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "\"checking model (on original set of clauses)\"\n";);
- if (!m_clone->check_model(m_model)) {
- //IF_VERBOSE(0, display(verbose_stream()));
- //IF_VERBOSE(0, display_watches(verbose_stream()));
- IF_VERBOSE(0, m_mc.display(verbose_stream()));
- IF_VERBOSE(0, display_units(verbose_stream()));
- //IF_VERBOSE(0, m_clone->display(verbose_stream() << "clone\n"));
- throw solver_exception("check model failed (for cloned solver)");
+ IF_VERBOSE(10, verbose_stream() << "\"checking model\"\n";);
+ if (!check_clauses(m_model)) {
+ throw solver_exception("check model failed");
}
}
+
+ if (m_config.m_drat) {
+ m_drat.check_model(m_model);
+ }
+
+ m_mc(m_model);
+
+ if (m_clone && !check_clauses(m_model)) {
+ IF_VERBOSE(1, verbose_stream() << "failure checking clauses on transformed model\n";);
+ IF_VERBOSE(10, m_mc.display(verbose_stream()));
+ IF_VERBOSE(10, display_model(verbose_stream()));
+ throw solver_exception("check model failed");
+ }
+
+ if (m_clone && !m_clone->check_model(m_model)) {
+ IF_VERBOSE(1, m_mc.display(verbose_stream()));
+ IF_VERBOSE(1, display_units(verbose_stream()));
+ throw solver_exception("check model failed (for cloned solver)");
+ }
}
bool solver::check_clauses(model const& m) const {
@@ -1802,7 +1815,7 @@ namespace sat {
for (clause const* cp : m_clauses) {
clause const & c = *cp;
if (!c.satisfied_by(m)) {
- IF_VERBOSE(0, verbose_stream() << "failed clause " << c.id() << ": " << c << "\n";);
+ IF_VERBOSE(1, verbose_stream() << "failed clause " << c.id() << ": " << c << "\n";);
TRACE("sat", tout << "failed: " << c << "\n";
tout << "assumptions: " << m_assumptions << "\n";
tout << "trail: " << m_trail << "\n";
@@ -1810,7 +1823,7 @@ namespace sat {
m_mc.display(tout);
);
for (literal l : c) {
- if (was_eliminated(l.var())) IF_VERBOSE(0, verbose_stream() << "eliminated: " << l << "\n";);
+ if (was_eliminated(l.var())) IF_VERBOSE(1, verbose_stream() << "eliminated: " << l << "\n";);
}
ok = false;
}
@@ -1826,8 +1839,8 @@ namespace sat {
if (l.index() > l2.index())
continue;
if (value_at(l2, m) != l_true) {
- IF_VERBOSE(0, verbose_stream() << "failed binary: " << l << " := " << value_at(l, m) << " " << l2 << " := " << value_at(l2, m) << "\n");
- IF_VERBOSE(0, verbose_stream() << "elim l1: " << was_eliminated(l.var()) << " elim l2: " << was_eliminated(l2) << "\n");
+ IF_VERBOSE(1, verbose_stream() << "failed binary: " << l << " := " << value_at(l, m) << " " << l2 << " := " << value_at(l2, m) << "\n");
+ IF_VERBOSE(1, verbose_stream() << "elim l1: " << was_eliminated(l.var()) << " elim l2: " << was_eliminated(l2) << "\n");
TRACE("sat", m_mc.display(tout << "failed binary: " << l << " " << l2 << "\n"););
ok = false;
}
@@ -1838,7 +1851,7 @@ namespace sat {
for (literal l : m_assumptions) {
if (value_at(l, m) != l_true) {
VERIFY(is_external(l.var()));
- IF_VERBOSE(0, verbose_stream() << "assumption: " << l << " does not model check " << value_at(l, m) << "\n";);
+ IF_VERBOSE(1, verbose_stream() << "assumption: " << l << " does not model check " << value_at(l, m) << "\n";);
TRACE("sat",
tout << l << " does not model check\n";
tout << "trail: " << m_trail << "\n";
@@ -1859,8 +1872,8 @@ namespace sat {
if (ok && !m_mc.check_model(m)) {
ok = false;
TRACE("sat", tout << "model: " << m << "\n"; m_mc.display(tout););
+ IF_VERBOSE(0, verbose_stream() << "model check failed\n");
}
- IF_VERBOSE(1, verbose_stream() << "model check " << (ok?"OK":"failed") << "\n";);
return ok;
}
@@ -1873,17 +1886,84 @@ namespace sat {
m_config.m_restart_margin * m_slow_glue_avg <= m_fast_glue_avg;
}
+ void solver::log_stats() {
+ m_restart_logs++;
+
+ std::stringstream strm;
+ strm << "(sat.stats " << std::setw(6) << m_stats.m_conflict << " "
+ << std::setw(6) << m_stats.m_decision << " "
+ << std::setw(4) << m_stats.m_restart
+ << mk_stat(*this)
+ << " " << std::setw(6) << std::setprecision(2) << m_stopwatch.get_current_seconds() << ")\n";
+ std::string str(strm.str());
+ svector nums;
+ for (size_t i = 0; i < str.size(); ++i) {
+ while (i < str.size() && str[i] != ' ') ++i;
+ while (i < str.size() && str[i] == ' ') ++i;
+ // position of first character after space
+ if (i < str.size()) {
+ nums.push_back(i);
+ }
+ }
+ bool same = m_last_positions.size() == nums.size();
+ size_t diff = 0;
+ for (unsigned i = 0; i < nums.size() && same; ++i) {
+ if (m_last_positions[i] > nums[i]) diff += m_last_positions[i] - nums[i];
+ if (m_last_positions[i] < nums[i]) diff += nums[i] - m_last_positions[i];
+ }
+ if (m_last_positions.empty() ||
+ m_restart_logs >= 20 + m_last_position_log ||
+ (m_restart_logs >= 6 + m_last_position_log && (!same || diff > 3))) {
+ m_last_position_log = m_restart_logs;
+ // conflicts restarts learned gc time
+ // decisions clauses units memory
+ int adjust[9] = { -3, -3, -3, -1, -3, -2, -1, -2, -1 };
+ char const* tag[9] = { ":conflicts ", ":decisions ", ":restarts ", ":clauses/bin ", ":learned/bin ", ":units ", ":gc ", ":memory ", ":time" };
+ std::stringstream l1, l2;
+ l1 << "(sat.stats ";
+ l2 << "(sat.stats ";
+ size_t p1 = 11, p2 = 11;
+ SASSERT(nums.size() == 9);
+ for (unsigned i = 0; i < 9 && i < nums.size(); ++i) {
+ size_t p = nums[i];
+ if (i & 0x1) {
+ // odd positions
+ for (; p2 < p + adjust[i]; ++p2) l2 << " ";
+ p2 += strlen(tag[i]);
+ l2 << tag[i];
+ }
+ else {
+ // even positions
+ for (; p1 < p + adjust[i]; ++p1) l1 << " ";
+ p1 += strlen(tag[i]);
+ l1 << tag[i];
+ }
+ }
+ for (; p1 + 2 < str.size(); ++p1) l1 << " ";
+ for (; p2 + 2 < str.size(); ++p2) l2 << " ";
+ l1 << ")\n";
+ l2 << ")\n";
+ IF_VERBOSE(1, verbose_stream() << l1.str() << l2.str());
+ m_last_positions.reset();
+ m_last_positions.append(nums);
+ }
+ IF_VERBOSE(1, verbose_stream() << str);
+ }
+
void solver::restart(bool to_base) {
m_stats.m_restart++;
m_restarts++;
- if (m_conflicts_since_init > m_restart_next_out + 500) {
- m_restart_next_out = m_conflicts_since_init;
- IF_VERBOSE(1,
- verbose_stream() << "(sat-restart :conflicts " << m_stats.m_conflict << " :decisions " << m_stats.m_decision
- << " :restarts " << m_stats.m_restart << mk_stat(*this)
- << " :time " << std::fixed << std::setprecision(2) << m_stopwatch.get_current_seconds() << ")\n";);
+ if (m_conflicts_since_init >= m_restart_next_out && get_verbosity_level() >= 1) {
+ if (0 == m_restart_next_out) {
+ m_restart_next_out = 1;
+ }
+ else {
+ m_restart_next_out = std::min(m_conflicts_since_init + 50000, (3*m_restart_next_out)/2 + 1);
+ }
+ log_stats();
}
IF_VERBOSE(30, display_status(verbose_stream()););
+ TRACE("sat", tout << "restart " << restart_level(to_base) << "\n";);
pop_reinit(restart_level(to_base));
set_next_restart();
}
@@ -2206,19 +2286,24 @@ namespace sat {
unsigned new_sz = j;
switch (new_sz) {
case 0:
- set_conflict(justification());
+ if (m_config.m_drat) m_drat.add();
+ set_conflict();
return false;
case 1:
- assign(c[0], justification());
+ assign_unit(c[0]);
return false;
case 2:
mk_bin_clause(c[0], c[1], true);
return false;
default:
if (new_sz != sz) {
- if (m_config.m_drat) m_drat.del(c);
c.shrink(new_sz);
- if (m_config.m_drat) m_drat.add(c, true);
+ if (m_config.m_drat) {
+ m_drat.add(c, true);
+ c.restore(sz);
+ m_drat.del(c);
+ c.shrink(new_sz);
+ }
}
attach_clause(c);
return true;
@@ -2262,7 +2347,6 @@ namespace sat {
}
bool solver::resolve_conflict_core() {
-
m_conflicts_since_init++;
m_conflicts_since_restart++;
m_conflicts_since_gc++;
@@ -2272,7 +2356,7 @@ namespace sat {
}
m_conflict_lvl = get_max_lvl(m_not_l, m_conflict);
- TRACE("sat", tout << "conflict detected at level " << m_conflict_lvl << " for ";
+ TRACE("sat_verbose", tout << "conflict detected at level " << m_conflict_lvl << " for ";
if (m_not_l == literal()) tout << "null literal\n";
else tout << m_not_l << "\n";);
@@ -2409,15 +2493,15 @@ namespace sat {
unsigned glue = num_diff_levels(m_lemma.size(), m_lemma.c_ptr());
m_fast_glue_avg.update(glue);
m_slow_glue_avg.update(glue);
-
pop_reinit(m_scope_lvl - new_scope_lvl);
- TRACE("sat_conflict_detail", tout << new_scope_lvl << "\n"; display(tout););
+ TRACE("sat_conflict_detail", tout << glue << " " << new_scope_lvl << "\n";);
// unsound: m_asymm_branch.minimize(m_scc, m_lemma);
clause * lemma = mk_clause_core(m_lemma.size(), m_lemma.c_ptr(), true);
if (lemma) {
lemma->set_glue(glue);
if (m_par) m_par->share_clause(*this, *lemma);
}
+ TRACE("sat_conflict_detail", tout << new_scope_lvl << "\n";);
decay_activity();
updt_phase_counters();
}
@@ -2487,8 +2571,8 @@ namespace sat {
TRACE("sat", display(tout);
unsigned level = 0;
for (literal l : m_trail) {
- if (level != m_level[l.var()]) {
- level = m_level[l.var()];
+ if (level != lvl(l)) {
+ level = lvl(l);
tout << level << ": ";
}
tout << l;
@@ -2498,6 +2582,7 @@ namespace sat {
tout << " ";
}
tout << "\n";
+ tout << "conflict level: " << m_conflict_lvl << "\n";
);
m_core.reset();
@@ -2564,7 +2649,7 @@ namespace sat {
if (m_config.m_core_minimize) {
if (m_min_core_valid && m_min_core.size() < m_core.size()) {
- IF_VERBOSE(1, verbose_stream() << "(sat.updating core " << m_min_core.size() << " " << m_core.size() << ")\n";);
+ IF_VERBOSE(2, verbose_stream() << "(sat.updating core " << m_min_core.size() << " " << m_core.size() << ")\n";);
m_core.reset();
m_core.append(m_min_core);
}
@@ -2665,7 +2750,7 @@ namespace sat {
for (unsigned i = head; i < sz; i++) {
literal l = m_trail[i];
bool_var v = l.var();
- TRACE("forget_phase", tout << "forgeting phase of l: " << l << "\n";);
+ TRACE("forget_phase", tout << "forgetting phase of l: " << l << "\n";);
m_phase[v] = PHASE_NOT_AVAILABLE;
}
}
@@ -2879,20 +2964,15 @@ namespace sat {
void solver::minimize_lemma() {
SASSERT(!m_lemma.empty());
SASSERT(m_unmark.empty());
- //m_unmark.reset();
updt_lemma_lvl_set();
unsigned sz = m_lemma.size();
unsigned i = 1; // the first literal is the FUIP
unsigned j = 1;
- //bool drop = false;
- //unsigned bound = sz/5+10;
for (; i < sz; i++) {
literal l = m_lemma[i];
if (implied_by_marked(l)) {
- TRACE("sat", tout << "drop: " << l << "\n";);
m_unmark.push_back(l.var());
- //drop = true;
}
else {
if (j != i) {
@@ -2900,12 +2980,6 @@ namespace sat {
}
j++;
}
-#if 0
- if (!drop && i >= bound) {
- j = sz;
- break;
- }
-#endif
}
reset_unmark(0);
@@ -3254,7 +3328,7 @@ namespace sat {
bool_var solver::max_var(bool learned, bool_var v) {
m_user_bin_clauses.reset();
- collect_bin_clauses(m_user_bin_clauses, learned);
+ collect_bin_clauses(m_user_bin_clauses, learned, false);
for (unsigned i = 0; i < m_user_bin_clauses.size(); ++i) {
literal l1 = m_user_bin_clauses[i].first;
literal l2 = m_user_bin_clauses[i].second;
@@ -3465,6 +3539,14 @@ namespace sat {
return true;
}
+ std::ostream& solver::display_model(std::ostream& out) const {
+ unsigned num = num_vars();
+ for (bool_var v = 0; v < num; v++) {
+ out << v << ": " << m_model[v] << "\n";
+ }
+ return out;
+}
+
void solver::display_binary(std::ostream & out) const {
unsigned sz = m_watches.size();
for (unsigned l_idx = 0; l_idx < sz; l_idx++) {
@@ -3510,16 +3592,39 @@ namespace sat {
}
std::ostream& solver::display_justification(std::ostream & out, justification const& js) const {
- out << js;
- if (js.is_clause()) {
- out << get_clause(js);
+ switch (js.get_kind()) {
+ case justification::NONE:
+ out << "none "; // << js.level();
+ break;
+ case justification::BINARY:
+ out << "binary " << js.get_literal() << "@" << lvl(js.get_literal());
+ break;
+ case justification::TERNARY:
+ out << "ternary " << js.get_literal1() << "@" << lvl(js.get_literal1()) << " ";
+ out << js.get_literal2() << "@" << lvl(js.get_literal2());
+ break;
+ case justification::CLAUSE: {
+ out << "(";
+ bool first = true;
+ for (literal l : get_clause(js)) {
+ if (first) first = false; else out << " ";
+ out << l << "@" << lvl(l);
+ }
+ out << ")";
+ break;
}
- else if (js.is_ext_justification() && m_ext) {
- m_ext->display_justification(out << " ", js.get_ext_justification_idx());
+ case justification::EXT_JUSTIFICATION:
+ if (m_ext) {
+ m_ext->display_justification(out << " ", js.get_ext_justification_idx());
+ }
+ break;
+ default:
+ break;
}
return out;
}
+
unsigned solver::num_clauses() const {
unsigned num_cls = m_trail.size(); // units;
unsigned l_idx = 0;
@@ -3624,7 +3729,7 @@ namespace sat {
}
std::ostream& solver::display_watch_list(std::ostream& out, watch_list const& wl) const {
- return sat::display_watch_list(out, cls_allocator(), wl);
+ return sat::display_watch_list(out, cls_allocator(), wl, m_ext.get());
}
void solver::display_assignment(std::ostream & out) const {
@@ -3730,7 +3835,7 @@ namespace sat {
max_cliques mc;
m_user_bin_clauses.reset();
m_binary_clause_graph.reset();
- collect_bin_clauses(m_user_bin_clauses, true);
+ collect_bin_clauses(m_user_bin_clauses, true, false);
hashtable, default_eq > seen_bc;
for (auto const& b : m_user_bin_clauses) {
literal l1 = b.first;
@@ -3914,7 +4019,7 @@ namespace sat {
m_reason_unknown = "sat.max.conflicts";
IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-conflicts = " << m_conflicts_since_init << "\")\n";);
}
- return true;
+ return !inconsistent();
}
return false;
}
@@ -4033,7 +4138,7 @@ namespace sat {
}
push();
++num_assigned;
- assign(~lit, justification());
+ assign_scoped(~lit);
propagate(false);
while (inconsistent()) {
if (!resolve_conflict()) {
@@ -4309,24 +4414,24 @@ namespace sat {
}
void stats::collect_statistics(statistics & st) const {
- st.update("mk bool var", m_mk_var);
- st.update("mk binary clause", m_mk_bin_clause);
- st.update("mk ternary clause", m_mk_ter_clause);
- st.update("mk clause", m_mk_clause);
- st.update("gc clause", m_gc_clause);
- st.update("del clause", m_del_clause);
- st.update("conflicts", m_conflict);
- st.update("propagations", m_propagate);
- st.update("decisions", m_decision);
- st.update("binary propagations", m_bin_propagate);
- st.update("ternary propagations", m_ter_propagate);
- st.update("restarts", m_restart);
- st.update("minimized lits", m_minimized_lits);
- st.update("dyn subsumption resolution", m_dyn_sub_res);
- st.update("blocked correction sets", m_blocked_corr_sets);
- st.update("units", m_units);
- st.update("elim bool vars res", m_elim_var_res);
- st.update("elim bool vars bdd", m_elim_var_bdd);
+ st.update("sat mk clause 2ary", m_mk_bin_clause);
+ st.update("sat mk clause 3ary", m_mk_ter_clause);
+ st.update("sat mk clause nary", m_mk_clause);
+ st.update("sat mk var", m_mk_var);
+ st.update("sat gc clause", m_gc_clause);
+ st.update("sat del clause", m_del_clause);
+ st.update("sat conflicts", m_conflict);
+ st.update("sat decisions", m_decision);
+ st.update("sat propagations 2ary", m_bin_propagate);
+ st.update("sat propagations 3ary", m_ter_propagate);
+ st.update("sat propagations nary", m_propagate);
+ st.update("sat restarts", m_restart);
+ st.update("sat minimized lits", m_minimized_lits);
+ st.update("sat subs resolution dyn", m_dyn_sub_res);
+ st.update("sat blocked correction sets", m_blocked_corr_sets);
+ st.update("sat units", m_units);
+ st.update("sat elim bool vars res", m_elim_var_res);
+ st.update("sat elim bool vars bdd", m_elim_var_bdd);
}
void stats::reset() {
@@ -4336,16 +4441,11 @@ namespace sat {
void mk_stat::display(std::ostream & out) const {
unsigned given, learned;
m_solver.num_binary(given, learned);
- if (!m_solver.m_clauses.empty())
- out << " :clauses " << m_solver.m_clauses.size() + given << "/" << given;
- if (!m_solver.m_learned.empty()) {
- out << " :learned " << (m_solver.m_learned.size() + learned - m_solver.m_num_frozen) << "/" << learned;
- if (m_solver.m_num_frozen > 0)
- out << " :frozen " << m_solver.m_num_frozen;
- }
- out << " :units " << m_solver.init_trail_size();
- out << " :gc-clause " << m_solver.m_stats.m_gc_clause;
- out << mem_stat();
+ out << " " << std::setw(5) << m_solver.m_clauses.size() + given << "/" << given;
+ out << " " << std::setw(5) << (m_solver.m_learned.size() + learned - m_solver.m_num_frozen) << "/" << learned;
+ out << " " << std::setw(3) << m_solver.init_trail_size();
+ out << " " << std::setw(7) << m_solver.m_stats.m_gc_clause << " ";
+ out << " " << std::setw(7) << mem_stat();
}
std::ostream & operator<<(std::ostream & out, mk_stat const & stat) {
diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h
index 8402fc898..c000ccb79 100644
--- a/src/sat/sat_solver.h
+++ b/src/sat/sat_solver.h
@@ -37,6 +37,7 @@ Revision History:
#include "sat/sat_drat.h"
#include "sat/sat_parallel.h"
#include "sat/sat_local_search.h"
+#include "sat/sat_solver_core.h"
#include "util/params.h"
#include "util/statistics.h"
#include "util/stopwatch.h"
@@ -75,11 +76,10 @@ namespace sat {
void collect_statistics(statistics & st) const;
};
- class solver {
+ class solver : public solver_core {
public:
struct abort_solver {};
protected:
- reslimit& m_rlimit;
bool m_checkpoint_enabled;
config m_config;
stats m_stats;
@@ -190,19 +190,19 @@ namespace sat {
friend class scoped_detach;
public:
solver(params_ref const & p, reslimit& l);
- ~solver();
+ ~solver() override;
// -----------------------
//
// Misc
//
// -----------------------
- void updt_params(params_ref const & p);
+ void updt_params(params_ref const & p) override;
static void collect_param_descrs(param_descrs & d);
- void collect_statistics(statistics & st) const;
+ void collect_statistics(statistics & st) const override;
void reset_statistics();
- void display_status(std::ostream & out) const;
+ void display_status(std::ostream & out) const override;
/**
\brief Copy (non learned) clauses from src to this solver.
@@ -210,18 +210,23 @@ namespace sat {
\pre the model converter of src and this must be empty
*/
- void copy(solver const & src);
+ void copy(solver const & src, bool copy_learned = false);
// -----------------------
//
// Variable & Clause creation
//
// -----------------------
+ void add_clause(unsigned num_lits, literal * lits, bool learned) override { mk_clause(num_lits, lits, learned); }
+ bool_var add_var(bool ext) override { return mk_var(ext, true); }
+
bool_var mk_var(bool ext = false, bool dvar = true);
- void mk_clause(literal_vector const& lits, bool learned = false) { mk_clause(lits.size(), lits.c_ptr(), learned); }
- void mk_clause(unsigned num_lits, literal * lits, bool learned = false);
- void mk_clause(literal l1, literal l2, bool learned = false);
- void mk_clause(literal l1, literal l2, literal l3, bool learned = false);
+ clause* mk_clause(literal_vector const& lits, bool learned = false) { return mk_clause(lits.size(), lits.c_ptr(), learned); }
+ clause* mk_clause(unsigned num_lits, literal * lits, bool learned = false);
+ clause* mk_clause(literal l1, literal l2, bool learned = false);
+ clause* mk_clause(literal l1, literal l2, literal l3, bool learned = false);
+
+ random_gen& rand() { return m_rand; }
protected:
inline clause_allocator& cls_allocator() { return m_cls_allocator[m_cls_allocator_idx]; }
@@ -279,28 +284,28 @@ namespace sat {
//
// -----------------------
public:
- bool inconsistent() const { return m_inconsistent; }
- unsigned num_vars() const { return m_level.size(); }
- unsigned num_clauses() const;
+ bool inconsistent() const override { return m_inconsistent; }
+ unsigned num_vars() const override { return m_level.size(); }
+ unsigned num_clauses() const override;
void num_binary(unsigned& given, unsigned& learned) const;
unsigned num_restarts() const { return m_restarts; }
- bool is_external(bool_var v) const { return m_external[v] != 0; }
- bool is_external(literal l) const { return is_external(l.var()); }
- void set_external(bool_var v);
- void set_non_external(bool_var v);
+ bool is_external(bool_var v) const override { return m_external[v] != 0; }
+ void set_external(bool_var v) override;
+ void set_non_external(bool_var v) override;
bool was_eliminated(bool_var v) const { return m_eliminated[v] != 0; }
- void set_eliminated(bool_var v, bool f) { m_eliminated[v] = f; }
+ void set_eliminated(bool_var v, bool f) override { m_eliminated[v] = f; }
bool was_eliminated(literal l) const { return was_eliminated(l.var()); }
unsigned scope_lvl() const { return m_scope_lvl; }
unsigned search_lvl() const { return m_search_lvl; }
bool at_search_lvl() const { return m_scope_lvl == m_search_lvl; }
- bool at_base_lvl() const { return m_scope_lvl == 0; }
+ bool at_base_lvl() const override { return m_scope_lvl == 0; }
lbool value(literal l) const { return static_cast(m_assignment[l.index()]); }
lbool value(bool_var v) const { return static_cast(m_assignment[literal(v, false).index()]); }
unsigned lvl(bool_var v) const { return m_level[v]; }
unsigned lvl(literal l) const { return m_level[l.var()]; }
- unsigned init_trail_size() const { return at_base_lvl() ? m_trail.size() : m_scopes[0].m_trail_lim; }
- literal trail_literal(unsigned i) const { return m_trail[i]; }
+ unsigned init_trail_size() const override { return at_base_lvl() ? m_trail.size() : m_scopes[0].m_trail_lim; }
+ unsigned trail_size() const { return m_trail.size(); }
+ literal trail_literal(unsigned i) const override { return m_trail[i]; }
literal scope_literal(unsigned n) const { return m_trail[m_scopes[n].m_trail_lim]; }
void assign(literal l, justification j) {
TRACE("sat_assign", tout << l << " previous value: " << value(l) << "\n";);
@@ -311,8 +316,11 @@ namespace sat {
}
}
void assign_core(literal l, unsigned lvl, justification jst);
+ void assign_unit(literal l) { assign(l, justification()); }
+ void assign_scoped(literal l) { assign(l, justification()); }
void set_conflict(justification c, literal not_l);
void set_conflict(justification c) { set_conflict(c, null_literal); }
+ void set_conflict() { set_conflict(justification()); }
lbool status(clause const & c) const;
clause_offset get_offset(clause const & c) const { return cls_allocator().get_offset(&c); }
void checkpoint() {
@@ -320,6 +328,7 @@ namespace sat {
if (!m_rlimit.inc()) {
m_mc.reset();
m_model_is_current = false;
+ TRACE("sat", tout << "canceled\n";);
throw solver_exception(Z3_CANCELED_MSG);
}
++m_num_checkpoints;
@@ -332,8 +341,8 @@ namespace sat {
config const& get_config() const { return m_config; }
void set_incremental(bool b) { m_config.m_incremental = b; }
bool is_incremental() const { return m_config.m_incremental; }
- extension* get_extension() const { return m_ext.get(); }
- void set_extension(extension* e);
+ extension* get_extension() const override { return m_ext.get(); }
+ void set_extension(extension* e) override;
bool set_root(literal l, literal r);
void flush_roots();
typedef std::pair bin_clause;
@@ -368,17 +377,18 @@ namespace sat {
//
// -----------------------
public:
- lbool check(unsigned num_lits = 0, literal const* lits = nullptr);
+ lbool check(unsigned num_lits = 0, literal const* lits = nullptr) override;
- model const & get_model() const { return m_model; }
+ model const & get_model() const override { return m_model; }
bool model_is_current() const { return m_model_is_current; }
- literal_vector const& get_core() const { return m_core; }
+ literal_vector const& get_core() const override { return m_core; }
model_converter const & get_model_converter() const { return m_mc; }
- void flush(model_converter& mc) { mc.flush(m_mc); }
+ void flush(model_converter& mc) override { mc.flush(m_mc); }
void set_model(model const& mdl);
- char const* get_reason_unknown() const { return m_reason_unknown.c_str(); }
+ char const* get_reason_unknown() const override { return m_reason_unknown.c_str(); }
bool check_clauses(model const& m) const;
bool is_assumption(bool_var v) const;
+ void set_activity(bool_var v, unsigned act);
lbool cube(bool_var_vector& vars, literal_vector& lits, unsigned backtrack_level);
@@ -421,7 +431,11 @@ namespace sat {
void mk_model();
bool check_model(model const & m) const;
void restart(bool to_base);
+ svector m_last_positions;
+ unsigned m_last_position_log;
+ unsigned m_restart_logs;
unsigned restart_level(bool to_base);
+ void log_stats();
bool should_restart() const;
void set_next_restart();
bool reached_max_conflicts();
@@ -540,10 +554,10 @@ namespace sat {
bool_var max_var(bool learned, bool_var v);
public:
- void user_push();
- void user_pop(unsigned num_scopes);
- void pop_to_base_level();
- unsigned num_user_scopes() const { return m_user_scope_literals.size(); }
+ void user_push() override;
+ void user_pop(unsigned num_scopes) override;
+ void pop_to_base_level() override;
+ unsigned num_user_scopes() const override { return m_user_scope_literals.size(); }
reslimit& rlimit() { return m_rlimit; }
// -----------------------
//
@@ -640,8 +654,9 @@ namespace sat {
clause * const * begin_learned() const { return m_learned.begin(); }
clause * const * end_learned() const { return m_learned.end(); }
clause_vector const& learned() const { return m_learned; }
- clause_vector const& clauses() const { return m_clauses; }
- void collect_bin_clauses(svector & r, bool learned, bool learned_only = false) const;
+ clause_vector const& clauses() const override { return m_clauses; }
+ void collect_bin_clauses(svector & r, bool learned, bool learned_only) const override;
+
// -----------------------
//
@@ -649,11 +664,12 @@ namespace sat {
//
// -----------------------
public:
- bool check_invariant() const;
+ bool check_invariant() const override;
void display(std::ostream & out) const;
void display_watches(std::ostream & out) const;
void display_watches(std::ostream & out, literal lit) const;
- void display_dimacs(std::ostream & out) const;
+ void display_dimacs(std::ostream & out) const override;
+ std::ostream& display_model(std::ostream& out) const;
void display_wcnf(std::ostream & out, unsigned sz, literal const* lits, unsigned const* weights) const;
void display_assignment(std::ostream & out) const;
std::ostream& display_justification(std::ostream & out, justification const& j) const;
diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp
index df2da82e7..9ca1150a9 100644
--- a/src/sat/sat_solver/inc_sat_solver.cpp
+++ b/src/sat/sat_solver/inc_sat_solver.cpp
@@ -60,6 +60,7 @@ class inc_sat_solver : public solver {
atom2bool_var m_map;
scoped_ptr m_bb_rewriter;
tactic_ref m_preprocess;
+ bool m_is_cnf;
unsigned m_num_scopes;
sat::literal_vector m_asms;
goal_ref_buffer m_subgoals;
@@ -88,6 +89,7 @@ public:
m_fmls_head(0),
m_core(m),
m_map(m),
+ m_is_cnf(true),
m_num_scopes(0),
m_unknown("no reason given"),
m_internalized_converted(false),
@@ -164,7 +166,7 @@ public:
(m.is_not(e, e) && is_uninterp_const(e));
}
- lbool check_sat(unsigned sz, expr * const * assumptions) override {
+ lbool check_sat_core(unsigned sz, expr * const * assumptions) override {
m_solver.pop_to_base_level();
m_core.reset();
if (m_solver.inconsistent()) return l_false;
@@ -262,7 +264,19 @@ public:
void assert_expr_core2(expr * t, expr * a) override {
if (a) {
m_asmsf.push_back(a);
- assert_expr_core(m.mk_implies(a, t));
+ if (m_is_cnf && is_literal(t) && is_literal(a)) {
+ assert_expr_core(m.mk_or(::mk_not(m, a), t));
+ }
+ else if (m_is_cnf && m.is_or(t) && is_clause(t) && is_literal(a)) {
+ expr_ref_vector args(m);
+ args.push_back(::mk_not(m, a));
+ args.append(to_app(t)->get_num_args(), to_app(t)->get_args());
+ assert_expr_core(m.mk_or(args.size(), args.c_ptr()));
+ }
+ else {
+ m_is_cnf = false;
+ assert_expr_core(m.mk_implies(a, t));
+ }
}
else {
assert_expr_core(t);
@@ -272,6 +286,7 @@ public:
ast_manager& get_manager() const override { return m; }
void assert_expr_core(expr * t) override {
TRACE("goal2sat", tout << mk_pp(t, m) << "\n";);
+ m_is_cnf &= is_clause(t);
m_fmls.push_back(t);
}
void set_produce_models(bool f) override {}
@@ -303,6 +318,39 @@ public:
r.reset();
r.append(m_core.size(), m_core.c_ptr());
}
+
+ void get_levels(ptr_vector const& vars, unsigned_vector& depth) override {
+ unsigned sz = vars.size();
+ depth.resize(sz);
+ for (unsigned i = 0; i < sz; ++i) {
+ auto bv = m_map.to_bool_var(vars[i]);
+ depth[i] = bv == sat::null_bool_var ? UINT_MAX : m_solver.lvl(bv);
+ }
+ }
+
+ expr_ref_vector get_trail() override {
+ expr_ref_vector result(m);
+ unsigned sz = m_solver.trail_size();
+ expr_ref_vector lit2expr(m);
+ lit2expr.resize(m_solver.num_vars() * 2);
+ m_map.mk_inv(lit2expr);
+ for (unsigned i = 0; i < sz; ++i) {
+ sat::literal lit = m_solver.trail_literal(i);
+ result.push_back(lit2expr[lit.index()].get());
+ }
+ return result;
+ }
+
+ void set_activity(expr* var, double activity) override {
+ m.is_not(var, var);
+ sat::bool_var v = m_map.to_bool_var(var);
+ if (v == sat::null_bool_var) {
+ v = m_solver.add_var(true);
+ m_map.insert(var, v);
+ }
+ m_solver.set_activity(v, static_cast(activity));
+ }
+
proof * get_proof() override {
UNREACHABLE();
return nullptr;
@@ -332,18 +380,6 @@ public:
}
sat::literal_vector lits;
lbool result = m_solver.cube(vars, lits, backtrack_level);
- switch (result) {
- case l_true:
- return last_cube(true);
- case l_false:
- return last_cube(false);
- default:
- break;
- }
- if (lits.empty()) {
- set_reason_unknown(m_solver.get_reason_unknown());
- return expr_ref_vector(m);
- }
expr_ref_vector fmls(m);
expr_ref_vector lit2expr(m);
lit2expr.resize(m_solver.num_vars() * 2);
@@ -358,6 +394,17 @@ public:
vs.push_back(x);
}
}
+ switch (result) {
+ case l_true:
+ return last_cube(true);
+ case l_false:
+ return last_cube(false);
+ default:
+ break;
+ }
+ if (lits.empty()) {
+ set_reason_unknown(m_solver.get_reason_unknown());
+ }
return fmls;
}
@@ -546,7 +593,12 @@ private:
SASSERT(!g->proofs_enabled());
TRACE("sat", m_solver.display(tout); g->display(tout););
try {
- (*m_preprocess)(g, m_subgoals);
+ if (m_is_cnf) {
+ m_subgoals.push_back(g.get());
+ }
+ else {
+ (*m_preprocess)(g, m_subgoals);
+ }
}
catch (tactic_exception & ex) {
IF_VERBOSE(0, verbose_stream() << "exception in tactic " << ex.msg() << "\n";);
@@ -706,6 +758,25 @@ private:
}
}
+ bool is_literal(expr* n) {
+ return is_uninterp_const(n) || (m.is_not(n, n) && is_uninterp_const(n));
+ }
+
+ bool is_clause(expr* fml) {
+ if (is_literal(fml)) {
+ return true;
+ }
+ if (!m.is_or(fml)) {
+ return false;
+ }
+ for (expr* n : *to_app(fml)) {
+ if (!is_literal(n)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
lbool internalize_formulas() {
if (m_fmls_head == m_fmls.size()) {
return l_true;
@@ -713,7 +784,8 @@ private:
dep2asm_t dep2asm;
goal_ref g = alloc(goal, m, true, false); // models, maybe cores are enabled
for (unsigned i = m_fmls_head ; i < m_fmls.size(); ++i) {
- g->assert_expr(m_fmls[i].get());
+ expr* fml = m_fmls.get(i);
+ g->assert_expr(fml);
}
lbool res = internalize_goal(g, dep2asm, false);
if (res != l_undef) {
@@ -814,12 +886,11 @@ private:
}
sat::model const & ll_m = m_solver.get_model();
mdl = alloc(model, m);
- for (auto const& kv : m_map) {
- expr * n = kv.m_key;
- if (is_app(n) && to_app(n)->get_num_args() > 0) {
+ for (sat::bool_var v = 0; v < ll_m.size(); ++v) {
+ expr* n = m_sat_mc->var2expr(v);
+ if (!n || !is_app(n) || to_app(n)->get_num_args() > 0) {
continue;
}
- sat::bool_var v = kv.m_value;
switch (sat::value_at(v, ll_m)) {
case l_true:
mdl->register_decl(to_app(n)->get_decl(), m.mk_true());
@@ -831,23 +902,23 @@ private:
break;
}
}
- //IF_VERBOSE(0, model_v2_pp(verbose_stream(), *mdl, true););
if (m_sat_mc) {
- //IF_VERBOSE(0, m_sat_mc->display(verbose_stream() << "satmc\n"););
+ // IF_VERBOSE(0, m_sat_mc->display(verbose_stream() << "satmc\n"););
(*m_sat_mc)(mdl);
}
if (m_mcs.back()) {
//IF_VERBOSE(0, m_mc0->display(verbose_stream() << "mc0\n"););
(*m_mcs.back())(mdl);
}
- TRACE("sat", model_smt2_pp(tout, m, *mdl, 0););
-
+ TRACE("sat", model_smt2_pp(tout, m, *mdl, 0););
- if (!gparams::get_ref().get_bool("model_validate", false)) return;
+ if (!gparams::get_ref().get_bool("model_validate", false)) {
+ return;
+ }
IF_VERBOSE(1, verbose_stream() << "Verifying solution\n";);
model_evaluator eval(*mdl);
- eval.set_model_completion(false);
+ // eval.set_model_completion(false);
bool all_true = true;
//unsigned i = 0;
for (expr * f : m_fmls) {
@@ -857,14 +928,15 @@ private:
tout << "Evaluation failed: " << mk_pp(f, m) << " to " << mk_pp(f, m) << "\n";
model_smt2_pp(tout, m, *(mdl.get()), 0););
if (!m.is_true(tmp)) {
- IF_VERBOSE(0, verbose_stream() << "failed to verify: " << mk_pp(f, m) << "\n";);
+ IF_VERBOSE(0, verbose_stream() << "failed to verify: " << mk_pp(f, m) << "\n");
+ IF_VERBOSE(0, verbose_stream() << "evaluated to " << tmp << "\n");
all_true = false;
}
//IF_VERBOSE(0, verbose_stream() << (i++) << ": " << mk_pp(f, m) << "\n");
}
if (!all_true) {
IF_VERBOSE(0, verbose_stream() << m_params << "\n");
- IF_VERBOSE(0, m_sat_mc->display(verbose_stream() << "sat mc\n"));
+ // IF_VERBOSE(0, m_sat_mc->display(verbose_stream() << "sat mc\n"));
IF_VERBOSE(0, if (m_mcs.back()) m_mcs.back()->display(verbose_stream() << "mc0\n"));
//IF_VERBOSE(0, m_solver.display(verbose_stream()));
IF_VERBOSE(0, for (auto const& kv : m_map) verbose_stream() << mk_pp(kv.m_key, m) << " |-> " << kv.m_value << "\n");
diff --git a/src/sat/sat_solver_core.h b/src/sat/sat_solver_core.h
new file mode 100644
index 000000000..b3c43ea6a
--- /dev/null
+++ b/src/sat/sat_solver_core.h
@@ -0,0 +1,118 @@
+/*++
+Copyright (c) 2011 Microsoft Corporation
+
+Module Name:
+
+ sat_solver_core.h
+
+Abstract:
+
+ SAT solver API class.
+
+Author:
+
+ Nikolaj Bjorner (nbjorner) 2019-02-06
+
+Revision History:
+
+--*/
+#ifndef SAT_SOLVER_CORE_H_
+#define SAT_SOLVER_CORE_H_
+
+
+#include "sat/sat_types.h"
+
+namespace sat {
+
+ class solver_core {
+ protected:
+ reslimit& m_rlimit;
+ public:
+ solver_core(reslimit& l) : m_rlimit(l) {}
+ virtual ~solver_core() {}
+
+ virtual void pop_to_base_level() {}
+ virtual bool at_base_lvl() const { return true; }
+
+ // retrieve model if solver return sat
+ virtual model const & get_model() const = 0;
+
+ // retrieve core from assumptions
+ virtual literal_vector const& get_core() const = 0;
+
+ // is the state inconsistent?
+ virtual bool inconsistent() const = 0;
+
+ // number of variables and clauses
+ virtual unsigned num_vars() const = 0;
+ virtual unsigned num_clauses() const = 0;
+
+ // check satisfiability
+ virtual lbool check(unsigned num_lits = 0, literal const* lits = nullptr) = 0;
+
+ virtual char const* get_reason_unknown() const { return "reason unavailable"; }
+
+ // add clauses
+ virtual void add_clause(unsigned n, literal* lits, bool is_redundant) = 0;
+ void add_clause(literal l1, literal l2, bool is_redundant) {
+ literal lits[2] = {l1, l2};
+ add_clause(2, lits, is_redundant);
+ }
+ void add_clause(literal l1, literal l2, literal l3, bool is_redundant) {
+ literal lits[3] = {l1, l2, l3};
+ add_clause(3, lits, is_redundant);
+ }
+ // create boolean variable, tagged as external (= true) or internal (can be eliminated).
+ virtual bool_var add_var(bool ext) = 0;
+
+ // update parameters
+ virtual void updt_params(params_ref const& p) {}
+
+
+ virtual bool check_invariant() const { return true; }
+ virtual void display_status(std::ostream& out) const {}
+ virtual void display_dimacs(std::ostream& out) const {}
+
+ virtual bool is_external(bool_var v) const { return true; }
+ bool is_external(literal l) const { return is_external(l.var()); }
+ virtual void set_external(bool_var v) {}
+ virtual void set_non_external(bool_var v) {}
+ virtual void set_eliminated(bool_var v, bool f) {}
+
+ // optional support for user-scopes. Not relevant for sat_tactic integration.
+ // it is only relevant for incremental mode SAT, which isn't wrapped (yet)
+ virtual void user_push() { throw default_exception("optional API not supported"); }
+ virtual void user_pop(unsigned num_scopes) {};
+ virtual unsigned num_user_scopes() const { return 0;}
+
+ // hooks for extension solver. really just ba_solver atm.
+ virtual extension* get_extension() const { return nullptr; }
+ virtual void set_extension(extension* e) { if (e) throw default_exception("optional API not supported"); }
+
+
+ // The following methods are used when converting the state from the SAT solver back
+ // to a set of assertions.
+
+ // retrieve model converter that handles variable elimination and other transformations
+ virtual void flush(model_converter& mc) {}
+
+ // size of initial trail containing unit clauses
+ virtual unsigned init_trail_size() const = 0;
+
+ // literal at trail index i
+ virtual literal trail_literal(unsigned i) const = 0;
+
+ // collect n-ary clauses
+ virtual clause_vector const& clauses() const = 0;
+
+ // collect binary clauses
+ typedef std::pair bin_clause;
+ virtual void collect_bin_clauses(svector & r, bool learned, bool learned_only) const = 0;
+
+ // collect statistics from sat solver
+ virtual void collect_statistics(statistics & st) const {}
+
+ };
+};
+
+#endif
diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h
index 002e49006..cbe0cab4c 100644
--- a/src/sat/sat_types.h
+++ b/src/sat/sat_types.h
@@ -26,6 +26,7 @@ Revision History:
#include "util/common_msgs.h"
#include "util/vector.h"
#include "util/uint_set.h"
+#include "util/stopwatch.h"
#include
namespace sat {
@@ -220,8 +221,11 @@ namespace sat {
inline std::ostream & operator<<(std::ostream & out, mem_stat const & m) {
double mem = static_cast(memory::get_allocation_size())/static_cast(1024*1024);
- out << " :memory " << std::fixed << std::setprecision(2) << mem;
- return out;
+ return out << std::fixed << std::setprecision(2) << mem;
+ }
+
+ inline std::ostream& operator<<(std::ostream& out, stopwatch const& sw) {
+ return out << " :time " << std::fixed << std::setprecision(2) << sw.get_seconds();
}
struct dimacs_lit {
diff --git a/src/sat/sat_unit_walk.cpp b/src/sat/sat_unit_walk.cpp
index 4a3cda47c..8c7a6c6f9 100644
--- a/src/sat/sat_unit_walk.cpp
+++ b/src/sat/sat_unit_walk.cpp
@@ -8,6 +8,7 @@ Module Name:
Abstract:
unit walk local search procedure.
+
A variant of UnitWalk. Hirsch and Kojevinkov, SAT 2001.
This version uses a trail to reset assignments and integrates directly with the
watch list structure. Thus, assignments are not delayed and we avoid treating
@@ -16,11 +17,9 @@ Abstract:
It uses standard DPLL approach for backracking, flipping the last decision literal that
lead to a conflict. It restarts after evern 100 conflicts.
- It does not attempt to add conflict clauses or alternate with
- walksat.
+ It does not attempt to add conflict clauses
- It can receive conflict clauses from a concurrent CDCL solver and does not
- create its own conflict clauses.
+ It can receive conflict clauses from a concurrent CDCL solver
The phase of variables is optionally sticky between rounds. We use a decay rate
to compute stickiness of a variable.
@@ -31,21 +30,52 @@ Author:
Revision History:
+ 2018-11-5:
+ change reinitialization to use local search with limited timeouts to find phase and ordering of variables.
+
--*/
-#include "sat_unit_walk.h"
+#include "sat/sat_unit_walk.h"
+#include "util/luby.h"
+
namespace sat {
+ bool_var unit_walk::var_priority::peek(solver& s) {
+ while (m_head < m_vars.size()) {
+ bool_var v = m_vars[m_head];
+ unsigned idx = literal(v, false).index();
+ if (s.m_assignment[idx] == l_undef)
+ return v;
+ ++m_head;
+ }
+ for (bool_var v : m_vars) {
+ if (s.m_assignment[literal(v, false).index()] == l_undef) {
+ IF_VERBOSE(0, verbose_stream() << "unassigned: " << v << "\n");
+ }
+ }
+ IF_VERBOSE(0, verbose_stream() << "(sat.unit-walk sat)\n");
+ return null_bool_var;
+ }
+
+ void unit_walk::var_priority::set_vars(solver& s) {
+ m_vars.reset();
+ for (unsigned v = 0; v < s.num_vars(); ++v) {
+ if (!s.was_eliminated(v) && s.m_assignment[v] == l_undef) {
+ add(v);
+ }
+ }
+ }
+
+ bool_var unit_walk::var_priority::next(solver& s) {
+ bool_var v = peek(s);
+ ++m_head;
+ return v;
+ }
+
unit_walk::unit_walk(solver& s):
- s(s)
- {
- m_runs = 0;
- m_periods = 0;
- m_max_runs = UINT_MAX;
- m_max_periods = 5000; // UINT_MAX; // TBD configure
- m_max_conflicts = 100;
- m_sticky_phase = s.get_config().m_phase_sticky;
+ s(s) {
+ m_max_conflicts = 10000;
m_flips = 0;
}
@@ -63,112 +93,254 @@ namespace sat {
lbool unit_walk::operator()() {
scoped_set_unit_walk _scoped_set(this, s);
init_runs();
- for (m_runs = 0; m_runs < m_max_runs || m_max_runs == UINT_MAX; ++m_runs) {
- init_propagation();
- init_phase();
- for (m_periods = 0; m_periods < m_max_periods || m_max_periods == UINT_MAX; ++m_periods) {
- if (!s.rlimit().inc()) return l_undef;
- lbool r = unit_propagation();
- if (r != l_undef) return r;
- }
+ init_propagation();
+ init_phase();
+ lbool st = l_undef;
+ while (s.rlimit().inc() && st == l_undef) {
+ if (inconsistent() && !m_decisions.empty()) do_pop();
+ else if (inconsistent()) st = l_false;
+ else if (should_restart()) restart();
+ else if (should_backjump()) st = do_backjump();
+ else st = decide();
}
+ log_status();
+ return st;
+ }
+
+ void unit_walk::do_pop() {
+ update_max_trail();
+ ++s.m_stats.m_conflict;
+ pop();
+ propagate();
+ }
+
+ lbool unit_walk::decide() {
+ bool_var v = pqueue().next(s);
+ if (v == null_bool_var) {
+ return l_true;
+ }
+ literal lit(v, !m_phase[v]);
+ ++s.m_stats.m_decision;
+ m_decisions.push_back(lit);
+ pqueue().push();
+ assign(lit);
+ propagate();
return l_undef;
}
- lbool unit_walk::unit_propagation() {
- init_propagation();
- while (!m_freevars.empty() && !inconsistent()) {
- bool_var v = m_freevars.begin()[m_rand(m_freevars.size())];
- literal lit(v, !m_phase[v]);
- ++s.m_stats.m_decision;
- m_decisions.push_back(lit);
- assign(lit);
- propagate();
- while (inconsistent() && !m_decisions.empty()) {
- ++m_conflicts;
- backtrack();
- propagate();
- }
- if (m_conflicts >= m_max_conflicts && !m_freevars.empty()) {
- set_conflict();
- break;
- }
- }
- if (!inconsistent()) {
- log_status();
- IF_VERBOSE(1, verbose_stream() << "(sat-unit-walk sat)\n";);
- s.mk_model();
- return l_true;
+ bool unit_walk::should_backjump() {
+ return
+ s.m_stats.m_conflict >= m_max_conflicts && m_decisions.size() > 20;
+ }
+
+ lbool unit_walk::do_backjump() {
+ unsigned backjump_level = m_decisions.size(); // - (m_decisions.size()/20);
+ switch (update_priority(backjump_level)) {
+ case l_true: return l_true;
+ case l_false: break; // TBD
+ default: break;
}
+ refresh_solver();
return l_undef;
}
+ void unit_walk::pop() {
+ SASSERT (!m_decisions.empty());
+ literal dlit = m_decisions.back();
+ pop_decision();
+ assign(~dlit);
+ }
+
+ void unit_walk::pop_decision() {
+ SASSERT (!m_decisions.empty());
+ literal dlit = m_decisions.back();
+ literal lit;
+ do {
+ SASSERT(!m_trail.empty());
+ lit = m_trail.back();
+ s.m_assignment[lit.index()] = l_undef;
+ s.m_assignment[(~lit).index()] = l_undef;
+ m_trail.pop_back();
+ }
+ while (lit != dlit);
+ m_qhead = m_trail.size();
+ m_decisions.pop_back();
+ pqueue().pop();
+ m_inconsistent = false;
+ }
+
void unit_walk::init_runs() {
- m_freevars.reset();
+ m_luby_index = 0;
+ m_restart_threshold = 1000;
+ m_max_trail = 0;
m_trail.reset();
m_decisions.reset();
m_phase.resize(s.num_vars());
- double2 d2;
- d2.t = 1.0;
- d2.f = 1.0;
- m_phase_tf.resize(s.num_vars(), d2);
- for (unsigned i = 0; i < s.num_vars(); ++i) {
- literal l(i, false);
- if (!s.was_eliminated(l.var()) && s.m_assignment[l.index()] == l_undef)
- m_freevars.insert(l.var());
+ m_phase_tf.resize(s.num_vars(), ema(1e-5));
+ pqueue().reset();
+ pqueue().set_vars(s);
+ for (unsigned v = 0; v < s.num_vars(); ++v) {
+ m_phase_tf[v].update(50);
}
- IF_VERBOSE(1, verbose_stream() << "num vars: " << s.num_vars() << " free vars: " << m_freevars.size() << "\n";);
+ m_ls.import(s, true);
+ m_rand.set_seed(s.rand()());
+ update_priority(0);
+ }
+
+ lbool unit_walk::do_local_search(unsigned num_rounds) {
+ unsigned prefix_length = (0*m_trail.size())/10;
+ for (unsigned v = 0; v < s.num_vars(); ++v) {
+ m_ls.set_bias(v, m_phase_tf[v] >= 50 ? l_true : l_false);
+ }
+ for (literal lit : m_trail) {
+ m_ls.set_bias(lit.var(), lit.sign() ? l_false : l_true);
+ }
+ m_ls.rlimit().push(num_rounds);
+ lbool is_sat = m_ls.check(prefix_length, m_trail.c_ptr(), nullptr);
+ m_ls.rlimit().pop();
+ return is_sat;
+ }
+
+ lbool unit_walk::update_priority(unsigned level) {
+
+ while (m_decisions.size() > level) {
+ pop_decision();
+ }
+ IF_VERBOSE(1, verbose_stream() << "(sat.unit-walk :update-priority " << m_decisions.size() << "\n");
+
+ unsigned num_rounds = 50;
+ log_status();
+
+ lbool is_sat = do_local_search(num_rounds);
+ switch (is_sat) {
+ case l_true:
+ for (unsigned v = 0; v < s.num_vars(); ++v) {
+ s.m_assignment[v] = m_ls.get_phase(v) ? l_true : l_false;
+ }
+ return l_true;
+ case l_false:
+ if (m_decisions.empty()) {
+ return l_false;
+ }
+ else {
+ pop();
+ return l_undef;
+ }
+ default:
+ update_pqueue();
+ return l_undef;
+ }
+ }
+
+ /**
+ * \brief Reshuffle variables in the priority queue using the break counts from local search.
+ */
+ struct compare_break {
+ local_search& ls;
+ compare_break(local_search& ls): ls(ls) {}
+ int operator()(bool_var v, bool_var w) const {
+ double diff = ls.break_count(v) - ls.break_count(w);
+ return diff > 0;
+ }
+ };
+
+ void unit_walk::update_pqueue() {
+ compare_break cb(m_ls);
+ std::sort(pqueue().begin(), pqueue().end(), cb);
+ for (bool_var v : pqueue()) {
+ m_phase_tf[v].update(m_ls.cur_solution(v) ? 100 : 0);
+ m_phase[v] = m_ls.cur_solution(v);
+ }
+ pqueue().rewind();
}
void unit_walk::init_phase() {
- m_max_trail = 0;
- if (m_sticky_phase) {
- for (bool_var v : m_freevars) {
- if (s.m_phase[v] == POS_PHASE) {
- m_phase[v] = true;
- }
- else if (s.m_phase[v] == NEG_PHASE) {
- m_phase[v] = false;
- }
- else {
- m_phase[v] = m_rand(100 * static_cast(m_phase_tf[v].t + m_phase_tf[v].f)) <= 100 * m_phase_tf[v].t;
- }
+ for (bool_var v : pqueue()) {
+ if (s.m_phase[v] == POS_PHASE) {
+ m_phase[v] = true;
+ }
+ else if (s.m_phase[v] == NEG_PHASE) {
+ m_phase[v] = false;
+ }
+ else {
+ m_phase[v] = m_rand(100) < m_phase_tf[v];
}
}
- else {
- for (bool_var v : m_freevars)
- m_phase[v] = (m_rand(2) == 0);
+ }
+
+ void unit_walk::refresh_solver() {
+ m_max_conflicts += m_conflict_offset ;
+ m_conflict_offset += 10000;
+ if (s.m_par && s.m_par->copy_solver(s)) {
+ IF_VERBOSE(1, verbose_stream() << "(sat.unit-walk fresh copy)\n";);
+ if (s.get_extension()) s.get_extension()->set_unit_walk(this);
+ init_runs();
+ init_phase();
+ }
+ }
+
+ bool unit_walk::should_restart() {
+ if (s.m_stats.m_conflict >= m_restart_threshold) {
+ m_restart_threshold = s.get_config().m_restart_initial * get_luby(m_luby_index);
+ ++m_luby_index;
+ return true;
+ }
+ return false;
+ }
+
+ void unit_walk::restart() {
+ while (!m_decisions.empty()) {
+ pop_decision();
+ }
+ }
+
+ void unit_walk::update_max_trail() {
+ if (m_max_trail == 0 || m_trail.size() > m_max_trail) {
+ m_max_trail = m_trail.size();
+ m_restart_threshold += 10000;
+ m_max_conflicts = s.m_stats.m_conflict + 20000;
+ log_status();
}
}
void unit_walk::init_propagation() {
if (s.m_par && s.m_par->copy_solver(s)) {
- IF_VERBOSE(1, verbose_stream() << "(sat-unit-walk fresh copy)\n";);
+ IF_VERBOSE(1, verbose_stream() << "(sat.unit-walk fresh copy)\n";);
if (s.get_extension()) s.get_extension()->set_unit_walk(this);
init_runs();
init_phase();
}
- if (m_max_trail == 0 || m_trail.size() > m_max_trail) {
- m_max_trail = m_trail.size();
- log_status();
- }
for (literal lit : m_trail) {
s.m_assignment[lit.index()] = l_undef;
s.m_assignment[(~lit).index()] = l_undef;
- m_freevars.insert(lit.var());
}
m_flips = 0;
m_trail.reset();
- m_conflicts = 0;
+ s.m_stats.m_conflict = 0;
+ m_conflict_offset = 10000;
m_decisions.reset();
m_qhead = 0;
m_inconsistent = false;
}
void unit_walk::propagate() {
- while (m_qhead < m_trail.size() && !inconsistent())
- propagate(choose_literal());
- // IF_VERBOSE(1, verbose_stream() << m_trail.size() << " " << inconsistent() << "\n";);
+ while (m_qhead < m_trail.size() && !inconsistent()) {
+ propagate(m_trail[m_qhead++]);
+ }
+ }
+
+ std::ostream& unit_walk::display(std::ostream& out) const {
+ unsigned i = 0;
+ out << "num decisions: " << m_decisions.size() << "\n";
+ for (literal lit : m_trail) {
+ if (i < m_decisions.size() && m_decisions[i] == lit) {
+ out << "d " << i << ": ";
+ ++i;
+ }
+ out << lit << "\n";
+ }
+ s.display(verbose_stream());
+ return out;
}
void unit_walk::propagate(literal l) {
@@ -289,48 +461,36 @@ namespace sat {
}
void unit_walk::assign(literal lit) {
- SASSERT(value(lit) == l_undef);
+ VERIFY(value(lit) == l_undef);
s.m_assignment[lit.index()] = l_true;
s.m_assignment[(~lit).index()] = l_false;
m_trail.push_back(lit);
- m_freevars.remove(lit.var());
if (s.get_extension() && s.is_external(lit.var())) {
s.get_extension()->asserted(lit);
}
if (m_phase[lit.var()] == lit.sign()) {
++m_flips;
flip_phase(lit);
+ m_phase_tf[lit.var()].update(m_phase[lit.var()] ? 100 : 0);
}
}
void unit_walk::flip_phase(literal l) {
bool_var v = l.var();
m_phase[v] = !m_phase[v];
- if (m_sticky_phase) {
- m_phase_tf[v].f *= 0.98;
- m_phase_tf[v].t *= 0.98;
- if (m_phase[v]) m_phase_tf[v].t += 1; else m_phase_tf[v].f += 1;
- }
}
void unit_walk::log_status() {
- IF_VERBOSE(1, verbose_stream() << "(sat-unit-walk :trail " << m_max_trail
- << " :branches " << m_decisions.size()
- << " :free " << m_freevars.size()
- << " :periods " << m_periods
+ IF_VERBOSE(1, verbose_stream()
+ << "(sat.unit-walk"
+ << " :trail " << m_trail.size()
+ << " :depth " << m_decisions.size()
<< " :decisions " << s.m_stats.m_decision
<< " :propagations " << s.m_stats.m_propagate
+ << " :conflicts " << s.m_stats.m_conflict
<< ")\n";);
}
- literal unit_walk::choose_literal() {
- SASSERT(m_qhead < m_trail.size());
- unsigned idx = m_rand(m_trail.size() - m_qhead);
- std::swap(m_trail[m_qhead], m_trail[m_qhead + idx]);
- literal lit = m_trail[m_qhead++];
- return lit;
- }
-
void unit_walk::set_conflict(literal l1, literal l2) {
set_conflict();
}
@@ -346,25 +506,6 @@ namespace sat {
void unit_walk::set_conflict() {
m_inconsistent = true;
}
-
- void unit_walk::backtrack() {
- if (m_decisions.empty()) return;
- literal dlit = m_decisions.back();
- literal lit;
- do {
- SASSERT(!m_trail.empty());
- lit = m_trail.back();
- s.m_assignment[lit.index()] = l_undef;
- s.m_assignment[(~lit).index()] = l_undef;
- m_freevars.insert(lit.var());
- m_trail.pop_back();
- }
- while (lit != dlit);
- m_inconsistent = false;
- m_decisions.pop_back();
- m_qhead = m_trail.size();
- assign(~dlit);
- }
};
diff --git a/src/sat/sat_unit_walk.h b/src/sat/sat_unit_walk.h
index 8ab9bab70..14588a63c 100644
--- a/src/sat/sat_unit_walk.h
+++ b/src/sat/sat_unit_walk.h
@@ -20,51 +20,83 @@ Revision History:
#define SAT_UNIT_WALK_H_
#include "sat/sat_solver.h"
+#include "sat/sat_local_search.h"
+#include "util/ema.h"
namespace sat {
class unit_walk {
+#if 0
struct double2 {
double t, f;
};
+#endif
+ class var_priority {
+ svector m_vars;
+ unsigned_vector m_lim;
+ unsigned m_head;
+ public:
+ var_priority() { m_head = 0; }
+ void reset() { m_lim.reset(); m_head = 0;}
+ void rewind() { for (unsigned& l : m_lim) l = 0; m_head = 0;}
+ void add(bool_var v) { m_vars.push_back(v); }
+ bool_var next(solver& s);
+ bool_var peek(solver& s);
+ void set_vars(solver& s);
+ void push() { m_lim.push_back(m_head); }
+ void pop() { m_head = m_lim.back(); m_lim.pop_back(); }
+ bool empty() const { return m_lim.empty(); }
+ bool_var const* begin() const { return m_vars.begin(); }
+ bool_var const* end() const { return m_vars.end(); }
+ bool_var* begin() { return m_vars.begin(); }
+ bool_var* end() { return m_vars.end(); }
+ };
+
solver& s;
+ local_search m_ls;
random_gen m_rand;
svector m_phase;
- svector m_phase_tf;
- indexed_uint_set m_freevars;
- unsigned m_runs;
- unsigned m_periods;
+ svector m_phase_tf;
+ var_priority m_priorities;
+ unsigned m_luby_index;
+ unsigned m_restart_threshold;
// settings
- unsigned m_max_runs;
- unsigned m_max_periods;
unsigned m_max_conflicts;
- bool m_sticky_phase;
- unsigned m_propagations;
unsigned m_flips;
unsigned m_max_trail;
unsigned m_qhead;
literal_vector m_trail;
bool m_inconsistent;
literal_vector m_decisions;
- unsigned m_conflicts;
+ unsigned m_conflict_offset;
- void push();
- void backtrack();
+ bool should_restart();
+ void do_pop();
+ bool should_backjump();
+ lbool do_backjump();
+ lbool do_local_search(unsigned num_rounds);
+ lbool decide();
+ void restart();
+ void pop();
+ void pop_decision();
void init_runs();
+ lbool update_priority(unsigned level);
+ void update_pqueue();
void init_phase();
void init_propagation();
+ void refresh_solver();
+ void update_max_trail();
void flip_phase(literal l);
- lbool unit_propagation();
void propagate();
void propagate(literal lit);
- literal choose_literal();
void set_conflict(literal l1, literal l2);
void set_conflict(literal l1, literal l2, literal l3);
void set_conflict(clause const& c);
inline lbool value(literal lit) { return s.value(lit); }
void log_status();
+ var_priority& pqueue() { return m_priorities; }
public:
unit_walk(solver& s);
diff --git a/src/sat/sat_watched.cpp b/src/sat/sat_watched.cpp
index 199d12797..966bd8325 100644
--- a/src/sat/sat_watched.cpp
+++ b/src/sat/sat_watched.cpp
@@ -18,6 +18,7 @@ Revision History:
--*/
#include "sat/sat_watched.h"
#include "sat/sat_clause.h"
+#include "sat/sat_extension.h"
namespace sat {
@@ -96,7 +97,7 @@ namespace sat {
}
- std::ostream& display_watch_list(std::ostream & out, clause_allocator const & ca, watch_list const & wlist) {
+ std::ostream& display_watch_list(std::ostream & out, clause_allocator const & ca, watch_list const & wlist, extension* ext) {
bool first = true;
for (watched const& w : wlist) {
if (first)
@@ -116,7 +117,12 @@ namespace sat {
out << "(" << w.get_blocked_literal() << " " << *(ca.get_clause(w.get_clause_offset())) << ")";
break;
case watched::EXT_CONSTRAINT:
- out << "ext: " << w.get_ext_constraint_idx();
+ if (ext) {
+ ext->display_constraint(out, w.get_ext_constraint_idx());
+ }
+ else {
+ out << "ext: " << w.get_ext_constraint_idx();
+ }
break;
default:
UNREACHABLE();
diff --git a/src/sat/sat_watched.h b/src/sat/sat_watched.h
index 09ad22ffd..a05e7c365 100644
--- a/src/sat/sat_watched.h
+++ b/src/sat/sat_watched.h
@@ -35,6 +35,9 @@ namespace sat {
Remark: there are no clause objects for binary clauses.
*/
+
+ class extension;
+
class watched {
public:
enum kind {
@@ -138,7 +141,7 @@ namespace sat {
void set_ternary_learned(watch_list& wlist, literal l1, literal l2, bool learned);
class clause_allocator;
- std::ostream& display_watch_list(std::ostream & out, clause_allocator const & ca, watch_list const & wlist);
+ std::ostream& display_watch_list(std::ostream & out, clause_allocator const & ca, watch_list const & wlist, extension* ext);
void conflict_cleanup(watch_list::iterator it, watch_list::iterator it2, watch_list& wlist);
};
diff --git a/src/sat/tactic/atom2bool_var.cpp b/src/sat/tactic/atom2bool_var.cpp
index b79eaa251..cd6ab776d 100644
--- a/src/sat/tactic/atom2bool_var.cpp
+++ b/src/sat/tactic/atom2bool_var.cpp
@@ -38,9 +38,13 @@ void atom2bool_var::mk_var_inv(app_ref_vector & var2expr) const {
}
sat::bool_var atom2bool_var::to_bool_var(expr * n) const {
- sat::bool_var v = sat::null_bool_var;
- m_mapping.find(n, v);
- return v;
+ unsigned idx = m_id2map.get(n->get_id(), UINT_MAX);
+ if (idx == UINT_MAX) {
+ return sat::null_bool_var;
+ }
+ else {
+ return m_mapping[idx].m_value;
+ }
}
struct collect_boolean_interface_proc {
diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp
index 68e18375f..b9adba7cf 100644
--- a/src/sat/tactic/goal2sat.cpp
+++ b/src/sat/tactic/goal2sat.cpp
@@ -57,10 +57,10 @@ struct goal2sat::imp {
svector m_result_stack;
obj_map m_cache;
obj_hashtable m_interface_vars;
- sat::solver & m_solver;
+ sat::solver_core & m_solver;
atom2bool_var & m_map;
dep2asm_map & m_dep2asm;
- sat::bool_var m_true;
+ sat::literal m_true;
bool m_ite_extra;
unsigned long long m_max_memory;
expr_ref_vector m_trail;
@@ -69,7 +69,7 @@ struct goal2sat::imp {
bool m_xor_solver;
bool m_is_lemma;
- imp(ast_manager & _m, params_ref const & p, sat::solver & s, atom2bool_var & map, dep2asm_map& dep2asm, bool default_external):
+ imp(ast_manager & _m, params_ref const & p, sat::solver_core & s, atom2bool_var & map, dep2asm_map& dep2asm, bool default_external):
m(_m),
pb(m),
m_ext(nullptr),
@@ -81,14 +81,14 @@ struct goal2sat::imp {
m_default_external(default_external),
m_is_lemma(false) {
updt_params(p);
- m_true = sat::null_bool_var;
- mk_true();
+ m_true = sat::null_literal;
}
void updt_params(params_ref const & p) {
m_ite_extra = p.get_bool("ite_extra", true);
m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX));
m_xor_solver = p.get_bool("xor_solver", false);
+ if (m_xor_solver) ensure_extension();
}
void throw_op_not_handled(std::string const& s) {
@@ -98,31 +98,31 @@ struct goal2sat::imp {
void mk_clause(sat::literal l) {
TRACE("goal2sat", tout << "mk_clause: " << l << "\n";);
- m_solver.mk_clause(1, &l);
+ m_solver.add_clause(1, &l, false);
}
void set_lemma_mode(bool f) { m_is_lemma = f; }
void mk_clause(sat::literal l1, sat::literal l2) {
TRACE("goal2sat", tout << "mk_clause: " << l1 << " " << l2 << "\n";);
- m_solver.mk_clause(l1, l2, m_is_lemma);
+ m_solver.add_clause(l1, l2, m_is_lemma);
}
void mk_clause(sat::literal l1, sat::literal l2, sat::literal l3) {
TRACE("goal2sat", tout << "mk_clause: " << l1 << " " << l2 << " " << l3 << "\n";);
- m_solver.mk_clause(l1, l2, l3, m_is_lemma);
+ m_solver.add_clause(l1, l2, l3, m_is_lemma);
}
void mk_clause(unsigned num, sat::literal * lits) {
TRACE("goal2sat", tout << "mk_clause: "; for (unsigned i = 0; i < num; i++) tout << lits[i] << " "; tout << "\n";);
- m_solver.mk_clause(num, lits, m_is_lemma);
+ m_solver.add_clause(num, lits, m_is_lemma);
}
- sat::bool_var mk_true() {
- if (m_true == sat::null_bool_var) {
+ sat::literal mk_true() {
+ if (m_true == sat::null_literal) {
// create fake variable to represent true;
- m_true = m_solver.mk_var(false);
- mk_clause(sat::literal(m_true, false)); // v is true
+ m_true = sat::literal(m_solver.add_var(false), false);
+ mk_clause(m_true); // v is true
}
return m_true;
}
@@ -133,14 +133,14 @@ struct goal2sat::imp {
sat::bool_var v = m_map.to_bool_var(t);
if (v == sat::null_bool_var) {
if (m.is_true(t)) {
- l = sat::literal(mk_true(), sign);
+ l = sign ? ~mk_true() : mk_true();
}
else if (m.is_false(t)) {
- l = sat::literal(mk_true(), !sign);
+ l = sign ? mk_true() : ~mk_true();
}
else {
bool ext = m_default_external || !is_uninterp_const(t) || m_interface_vars.contains(t);
- sat::bool_var v = m_solver.mk_var(ext);
+ sat::bool_var v = m_solver.add_var(ext);
m_map.insert(t, v);
l = sat::literal(v, sign);
TRACE("sat", tout << "new_var: " << v << ": " << mk_ismt2_pp(t, m) << "\n";);
@@ -248,7 +248,7 @@ struct goal2sat::imp {
}
else {
SASSERT(num <= m_result_stack.size());
- sat::bool_var k = m_solver.mk_var();
+ sat::bool_var k = m_solver.add_var(false);
sat::literal l(k, false);
m_cache.insert(t, l);
sat::literal * lits = m_result_stack.end() - num;
@@ -287,7 +287,7 @@ struct goal2sat::imp {
}
else {
SASSERT(num <= m_result_stack.size());
- sat::bool_var k = m_solver.mk_var();
+ sat::bool_var k = m_solver.add_var(false);
sat::literal l(k, false);
m_cache.insert(t, l);
// l => /\ lits
@@ -330,7 +330,7 @@ struct goal2sat::imp {
m_result_stack.reset();
}
else {
- sat::bool_var k = m_solver.mk_var();
+ sat::bool_var k = m_solver.add_var(false);
sat::literal l(k, false);
m_cache.insert(n, l);
mk_clause(~l, ~c, t);
@@ -367,7 +367,7 @@ struct goal2sat::imp {
m_result_stack.reset();
}
else {
- sat::bool_var k = m_solver.mk_var();
+ sat::bool_var k = m_solver.add_var(false);
sat::literal l(k, false);
m_cache.insert(t, l);
mk_clause(~l, l1, ~l2);
@@ -391,7 +391,7 @@ struct goal2sat::imp {
return;
}
sat::literal_vector lits;
- sat::bool_var v = m_solver.mk_var(true);
+ sat::bool_var v = m_solver.add_var(true);
lits.push_back(sat::literal(v, true));
convert_pb_args(num, lits);
// ensure that = is converted to xor
@@ -473,7 +473,7 @@ struct goal2sat::imp {
m_ext->add_pb_ge(sat::null_bool_var, wlits, k1);
}
else {
- sat::bool_var v = m_solver.mk_var(true);
+ sat::bool_var v = m_solver.add_var(true);
sat::literal lit(v, sign);
m_ext->add_pb_ge(v, wlits, k.get_unsigned());
TRACE("goal2sat", tout << "root: " << root << " lit: " << lit << "\n";);
@@ -504,7 +504,7 @@ struct goal2sat::imp {
m_ext->add_pb_ge(sat::null_bool_var, wlits, k1);
}
else {
- sat::bool_var v = m_solver.mk_var(true);
+ sat::bool_var v = m_solver.add_var(true);
sat::literal lit(v, sign);
m_ext->add_pb_ge(v, wlits, k.get_unsigned());
TRACE("goal2sat", tout << "root: " << root << " lit: " << lit << "\n";);
@@ -519,8 +519,8 @@ struct goal2sat::imp {
svector wlits;
convert_pb_args(t, wlits);
bool base_assert = (root && !sign && m_solver.num_user_scopes() == 0);
- sat::bool_var v1 = base_assert ? sat::null_bool_var : m_solver.mk_var(true);
- sat::bool_var v2 = base_assert ? sat::null_bool_var : m_solver.mk_var(true);
+ sat::bool_var v1 = base_assert ? sat::null_bool_var : m_solver.add_var(true);
+ sat::bool_var v2 = base_assert ? sat::null_bool_var : m_solver.add_var(true);
m_ext->add_pb_ge(v1, wlits, k.get_unsigned());
k.neg();
for (wliteral& wl : wlits) {
@@ -534,7 +534,7 @@ struct goal2sat::imp {
}
else {
sat::literal l1(v1, false), l2(v2, false);
- sat::bool_var v = m_solver.mk_var();
+ sat::bool_var v = m_solver.add_var(false);
sat::literal l(v, false);
mk_clause(~l, l1);
mk_clause(~l, l2);
@@ -554,7 +554,7 @@ struct goal2sat::imp {
m_ext->add_at_least(sat::null_bool_var, lits, k.get_unsigned());
}
else {
- sat::bool_var v = m_solver.mk_var(true);
+ sat::bool_var v = m_solver.add_var(true);
sat::literal lit(v, false);
m_ext->add_at_least(v, lits, k.get_unsigned());
m_cache.insert(t, lit);
@@ -576,7 +576,7 @@ struct goal2sat::imp {
m_ext->add_at_least(sat::null_bool_var, lits, lits.size() - k.get_unsigned());
}
else {
- sat::bool_var v = m_solver.mk_var(true);
+ sat::bool_var v = m_solver.add_var(true);
sat::literal lit(v, false);
m_ext->add_at_least(v, lits, lits.size() - k.get_unsigned());
m_cache.insert(t, lit);
@@ -589,8 +589,8 @@ struct goal2sat::imp {
SASSERT(k.is_unsigned());
sat::literal_vector lits;
convert_pb_args(t->get_num_args(), lits);
- sat::bool_var v1 = (root && !sign) ? sat::null_bool_var : m_solver.mk_var(true);
- sat::bool_var v2 = (root && !sign) ? sat::null_bool_var : m_solver.mk_var(true);
+ sat::bool_var v1 = (root && !sign) ? sat::null_bool_var : m_solver.add_var(true);
+ sat::bool_var v2 = (root && !sign) ? sat::null_bool_var : m_solver.add_var(true);
m_ext->add_at_least(v1, lits, k.get_unsigned());
for (sat::literal& l : lits) {
l.neg();
@@ -603,7 +603,7 @@ struct goal2sat::imp {
}
else {
sat::literal l1(v1, false), l2(v2, false);
- sat::bool_var v = m_solver.mk_var();
+ sat::bool_var v = m_solver.add_var(false);
sat::literal l(v, false);
mk_clause(~l, l1);
mk_clause(~l, l2);
@@ -898,7 +898,7 @@ struct goal2sat::scoped_set_imp {
};
-void goal2sat::operator()(goal const & g, params_ref const & p, sat::solver & t, atom2bool_var & m, dep2asm_map& dep2asm, bool default_external, bool is_lemma) {
+void goal2sat::operator()(goal const & g, params_ref const & p, sat::solver_core & t, atom2bool_var & m, dep2asm_map& dep2asm, bool default_external, bool is_lemma) {
imp proc(g.m(), p, t, m, dep2asm, default_external);
scoped_set_imp set(this, &proc);
proc.set_lemma_mode(is_lemma);
@@ -917,7 +917,7 @@ void goal2sat::get_interpreted_atoms(expr_ref_vector& atoms) {
sat2goal::mc::mc(ast_manager& m): m(m), m_var2expr(m) {}
-void sat2goal::mc::flush_smc(sat::solver& s, atom2bool_var const& map) {
+void sat2goal::mc::flush_smc(sat::solver_core& s, atom2bool_var const& map) {
s.flush(m_smc);
m_var2expr.resize(s.num_vars());
map.mk_var_inv(m_var2expr);
@@ -1158,13 +1158,14 @@ struct sat2goal::imp {
r.assert_expr(fml);
}
- void assert_clauses(ref& mc, sat::solver const & s, sat::clause_vector const& clauses, goal & r, bool asserted) {
+ void assert_clauses(ref& mc, sat::solver_core const & s, sat::clause_vector const& clauses, goal & r, bool asserted) {
ptr_buffer lits;
+ unsigned small_lbd = 3; // s.get_config().m_gc_small_lbd;
for (sat::clause* cp : clauses) {
checkpoint();
lits.reset();
sat::clause const & c = *cp;
- if (asserted || m_learned || c.glue() <= s.get_config().m_gc_small_lbd) {
+ if (asserted || m_learned || c.glue() <= small_lbd) {
for (sat::literal l : c) {
lits.push_back(lit2expr(mc, l));
}
@@ -1173,11 +1174,11 @@ struct sat2goal::imp {
}
}
- sat::ba_solver* get_ba_solver(sat::solver const& s) {
+ sat::ba_solver* get_ba_solver(sat::solver_core const& s) {
return dynamic_cast(s.get_extension());
}
- void operator()(sat::solver & s, atom2bool_var const & map, goal & r, ref & mc) {
+ void operator()(sat::solver_core & s, atom2bool_var const & map, goal & r, ref & mc) {
if (s.at_base_lvl() && s.inconsistent()) {
r.assert_expr(m.mk_false());
return;
@@ -1197,7 +1198,7 @@ struct sat2goal::imp {
// collect binary clauses
svector bin_clauses;
- s.collect_bin_clauses(bin_clauses, m_learned);
+ s.collect_bin_clauses(bin_clauses, m_learned, false);
for (sat::solver::bin_clause const& bc : bin_clauses) {
checkpoint();
r.assert_expr(m.mk_or(lit2expr(mc, bc.first), lit2expr(mc, bc.second)));
@@ -1263,7 +1264,7 @@ struct sat2goal::scoped_set_imp {
}
};
-void sat2goal::operator()(sat::solver & t, atom2bool_var const & m, params_ref const & p,
+void sat2goal::operator()(sat::solver_core & t, atom2bool_var const & m, params_ref const & p,
goal & g, ref & mc) {
imp proc(g.m(), p);
scoped_set_imp set(this, &proc);
diff --git a/src/sat/tactic/goal2sat.h b/src/sat/tactic/goal2sat.h
index 514b65311..78884051e 100644
--- a/src/sat/tactic/goal2sat.h
+++ b/src/sat/tactic/goal2sat.h
@@ -62,7 +62,7 @@ public:
\warning conversion throws a tactic_exception, if it is interrupted (by set_cancel),
an unsupported operator is found, or memory consumption limit is reached (set with param :max-memory).
*/
- void operator()(goal const & g, params_ref const & p, sat::solver & t, atom2bool_var & m, dep2asm_map& dep2asm, bool default_external = false, bool is_lemma = false);
+ void operator()(goal const & g, params_ref const & p, sat::solver_core & t, atom2bool_var & m, dep2asm_map& dep2asm, bool default_external = false, bool is_lemma = false);
void get_interpreted_atoms(expr_ref_vector& atoms);
@@ -88,7 +88,7 @@ public:
mc(ast_manager& m);
~mc() override {}
// flush model converter from SAT solver to this structure.
- void flush_smc(sat::solver& s, atom2bool_var const& map);
+ void flush_smc(sat::solver_core& s, atom2bool_var const& map);
void operator()(model_ref& md) override;
void operator()(expr_ref& fml) override;
model_converter* translate(ast_translation& translator) override;
@@ -113,7 +113,7 @@ public:
\warning conversion throws a tactic_exception, if it is interrupted (by set_cancel),
or memory consumption limit is reached (set with param :max-memory).
*/
- void operator()(sat::solver & t, atom2bool_var const & m, params_ref const & p, goal & s, ref & mc);
+ void operator()(sat::solver_core & t, atom2bool_var const & m, params_ref const & p, goal & s, ref & mc);
};
diff --git a/src/sat/tactic/sat_tactic.cpp b/src/sat/tactic/sat_tactic.cpp
index ef8a9e77e..2739932e6 100644
--- a/src/sat/tactic/sat_tactic.cpp
+++ b/src/sat/tactic/sat_tactic.cpp
@@ -21,6 +21,7 @@ Notes:
#include "tactic/tactical.h"
#include "sat/tactic/goal2sat.h"
#include "sat/sat_solver.h"
+#include "sat/sat_params.hpp"
class sat_tactic : public tactic {
@@ -28,14 +29,15 @@ class sat_tactic : public tactic {
ast_manager & m;
goal2sat m_goal2sat;
sat2goal m_sat2goal;
- sat::solver m_solver;
+ scoped_ptr m_solver;
params_ref m_params;
imp(ast_manager & _m, params_ref const & p):
m(_m),
- m_solver(p, m.limit()),
+ m_solver(alloc(sat::solver, p, m.limit())),
m_params(p) {
SASSERT(!m.proofs_enabled());
+ updt_params(p);
}
void operator()(goal_ref const & g,
@@ -49,7 +51,7 @@ class sat_tactic : public tactic {
atom2bool_var map(m);
obj_map dep2asm;
sat::literal_vector assumptions;
- m_goal2sat(*g, m_params, m_solver, map, dep2asm);
+ m_goal2sat(*g, m_params, *m_solver, map, dep2asm);
TRACE("sat_solver_unknown", tout << "interpreted_atoms: " << map.interpreted_atoms() << "\n";
for (auto const& kv : map) {
if (!is_uninterp_const(kv.m_key))
@@ -58,15 +60,16 @@ class sat_tactic : public tactic {
g->reset();
g->m().compact_memory();
- CASSERT("sat_solver", m_solver.check_invariant());
- IF_VERBOSE(TACTIC_VERBOSITY_LVL, m_solver.display_status(verbose_stream()););
- TRACE("sat_dimacs", m_solver.display_dimacs(tout););
+ CASSERT("sat_solver", m_solver->check_invariant());
+ IF_VERBOSE(TACTIC_VERBOSITY_LVL, m_solver->display_status(verbose_stream()););
+ TRACE("sat_dimacs", m_solver->display_dimacs(tout););
dep2assumptions(dep2asm, assumptions);
- lbool r = m_solver.check(assumptions.size(), assumptions.c_ptr());
+ lbool r = m_solver->check(assumptions.size(), assumptions.c_ptr());
+ TRACE("sat", tout << "result of checking: " << r << " " << m_solver->get_reason_unknown() << "\n";);
if (r == l_false) {
expr_dependency * lcore = nullptr;
if (produce_core) {
- sat::literal_vector const& ucore = m_solver.get_core();
+ sat::literal_vector const& ucore = m_solver->get_core();
u_map