From c77af6b75f5ae321d862b685b21d9d9af82efa23 Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Mon, 10 Sep 2018 02:49:22 +0800 Subject: [PATCH 001/318] api: dotnet: switch to multi-targeting project and modern cmake-dotnet integration. --- cmake/modules/DotnetImports.props.in | 7 + cmake/modules/FindDotnet.cmake | 304 +++++++++++++ src/api/dotnet/CMakeLists.txt | 176 +------- src/api/dotnet/Microsoft.Z3.csproj | 417 ------------------ src/api/dotnet/Microsoft.Z3.csproj.in | 73 +++ src/api/dotnet/Microsoft.Z3.props | 22 + src/api/dotnet/Microsoft.Z3.targets | 11 + src/api/dotnet/Properties/AssemblyInfo.cs.in | 38 -- src/api/dotnet/core/DummyContracts.cs | 65 --- src/api/dotnet/core/README.txt | 9 - src/api/dotnet/core/project.json | 22 - src/api/dotnet/dotnet35/Example/App.config | 6 - .../dotnet/dotnet35/Example/Example.csproj | 78 ---- .../Example/Properties/AssemblyInfo.cs | 36 -- .../dotnet/dotnet35/Microsoft.Z3.NET35.csproj | 347 --------------- .../dotnet/dotnet35/Microsoft.Z3.NET35.sln | 48 -- .../dotnet35/Properties/AssemblyInfo.cs | 38 -- .../dotnet35/Properties/AssemblyInfo.cs.in | 38 -- src/api/dotnet/dotnet35/Readme.NET35 | 10 - src/api/dotnet/dotnet35/packages.config | 4 - 20 files changed, 438 insertions(+), 1311 deletions(-) create mode 100644 cmake/modules/DotnetImports.props.in create mode 100644 cmake/modules/FindDotnet.cmake delete mode 100644 src/api/dotnet/Microsoft.Z3.csproj create mode 100644 src/api/dotnet/Microsoft.Z3.csproj.in create mode 100644 src/api/dotnet/Microsoft.Z3.props create mode 100644 src/api/dotnet/Microsoft.Z3.targets delete mode 100644 src/api/dotnet/Properties/AssemblyInfo.cs.in delete mode 100644 src/api/dotnet/core/DummyContracts.cs delete mode 100644 src/api/dotnet/core/README.txt delete mode 100644 src/api/dotnet/core/project.json delete mode 100644 src/api/dotnet/dotnet35/Example/App.config delete mode 100644 src/api/dotnet/dotnet35/Example/Example.csproj delete mode 100644 src/api/dotnet/dotnet35/Example/Properties/AssemblyInfo.cs delete mode 100644 src/api/dotnet/dotnet35/Microsoft.Z3.NET35.csproj delete mode 100644 src/api/dotnet/dotnet35/Microsoft.Z3.NET35.sln delete mode 100644 src/api/dotnet/dotnet35/Properties/AssemblyInfo.cs delete mode 100644 src/api/dotnet/dotnet35/Properties/AssemblyInfo.cs.in delete mode 100644 src/api/dotnet/dotnet35/Readme.NET35 delete mode 100644 src/api/dotnet/dotnet35/packages.config diff --git a/cmake/modules/DotnetImports.props.in b/cmake/modules/DotnetImports.props.in new file mode 100644 index 000000000..fba9ae301 --- /dev/null +++ b/cmake/modules/DotnetImports.props.in @@ -0,0 +1,7 @@ + + + ${_DN_OUTPUT_PATH}/ + ${XPLAT_LIB_DIR}/ + ${_DN_VERSION} + + diff --git a/cmake/modules/FindDotnet.cmake b/cmake/modules/FindDotnet.cmake new file mode 100644 index 000000000..a3d0c2dd1 --- /dev/null +++ b/cmake/modules/FindDotnet.cmake @@ -0,0 +1,304 @@ +#.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... ]) +# ``` +# +# 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( +# [ARGUMENTS program_args...] +# [OUTPUT outputs...]) +# ``` +# +# 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... ]) +# ``` +# +# DOTNET_REGISTER_LOCAL_REPOSITORY -- register a local NuGet package repository. +# +# ``` +# DOTNET_REGISTER_LOCAL_REPOSITORY(repo_name repo_path) +# ``` +# +# 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. +# +# 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) + 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) + FILE(GLOB_RECURSE DOTNET_deps *.cs *.fs *.xaml *.csproj *.fsproj *.tsl) + LIST(FILTER DOTNET_deps EXCLUDE REGEX /obj/) + CMAKE_PARSE_ARGUMENTS( + # prefix + _DN + # options (flags) + "RELEASE;DEBUG;X86;X64;ANYCPU;NETCOREAPP" + # oneValueArgs + "CONFIG;PLATFORM;VERSION" + # multiValueArgs + "PACKAGE;DEPENDS;ARGUMENTS;OUTPUT" + # the input arguments + ${arguments}) + + GET_FILENAME_COMPONENT(_DN_abs_proj "${_DN_PROJECT}" ABSOLUTE) + GET_FILENAME_COMPONENT(_DN_proj_dir "${_DN_PROJECT}" DIRECTORY) + GET_FILENAME_COMPONENT(_DN_projname "${DOTNET_PROJECT}" NAME) + STRING(REGEX REPLACE "\\.[^.]*$" "" _DN_projname_noext ${_DN_projname}) + + IF(_DN_RELEASE) + SET(_DN_CONFIG Release) + ELSEIF(_DN_DEBUG) + SET(_DN_CONFIG Debug) + ENDIF() + + IF(NOT _DN_CONFIG) + SET(_DN_CONFIG $) + IF(_DN_CONFIG STREQUAL "RelWithDebInfo" OR _DN_CONFIG STREQUAL "RelMinSize" OR NOT _DN_CONFIG) + SET(_DN_CONFIG "Release") + ENDIF() + 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 "Any CPU") + 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() + + GET_FILENAME_COMPONENT(_DN_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/bin ABSOLUTE) + + 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_RUN_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 ${DOTNET_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(DOTNET_BUILD_PROPERTIES ${_DN_PLATFORM_PROP} ${_DN_TFMS_PROP} "/p:DirectoryBuildPropsPath=${_DN_IMPORT_PROP}" "/p:DOTNET_PACKAGE_VERSION=${_DN_VERSION}" PARENT_SCOPE) + SET(DOTNET_BUILD_OPTIONS ${_DN_BUILD_OPTIONS} PARENT_SCOPE) + SET(DOTNET_PACK_OPTIONS ${_DN_PACK_OPTIONS} PARENT_SCOPE) + +ENDFUNCTION() + +MACRO(ADD_DOTNET_DEPENDENCY_TARGETS) + FOREACH(pkg_dep ${DOTNET_DEPENDS}) + ADD_DEPENDENCIES(BUILD_${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(BUILD_${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} BUILD_${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 ${DOTNET_PROJPATH} + COMMAND ${DOTNET_EXE} msbuild ${DOTNET_PROJPATH} /t:Clean /p:Configuration="${DOTNET_CONFIG}" + COMMAND ${DOTNET_EXE} msbuild ${DOTNET_PROJPATH} /t:Build ${DOTNET_BUILD_PROPERTIES} /p:Configuration="${DOTNET_CONFIG}") + 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} + 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}) + SET(build_dotnet_type "dotnet") + ENDIF() + + IF(NOT "${DOTNET_PACKAGES}" STREQUAL "") + MESSAGE("-- Adding ${build_dotnet_type} project ${DOTNET_PROJPATH} (version ${DOTNET_PACKAGE_VERSION})") + SET(_DOTNET_OUTPUTS "") + FOREACH(pkg ${DOTNET_PACKAGES}) + LIST(APPEND _DOTNET_OUTPUTS ${DOTNET_OUTPUT_PATH}/${pkg}.${DOTNET_PACKAGE_VERSION}.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}) + LIST(APPEND build_dotnet_cmds COMMAND ${CMAKE_COMMAND} -E copy ${_DOTNET_OUTPUTS} ${CMAKE_BINARY_DIR}) + ELSE() + + MESSAGE("-- Adding ${build_dotnet_type} project ${DOTNET_PROJPATH} (no nupkg)") + SET(_DOTNET_OUTPUTS ${CMAKE_CURRENT_BINARY_DIR}/${DOTNET_PROJNAME}.buildtimestamp) + LIST(APPEND build_dotnet_cmds COMMAND ${CMAKE_COMMAND} -E touch ${_DOTNET_OUTPUTS}) + 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() +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() +ENDFUNCTION() + +FUNCTION(RUN_DOTNET DOTNET_PROJECT) + DOTNET_GET_DEPS(${DOTNET_PROJECT} "${ARGN}") + ADD_CUSTOM_COMMAND( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${DOTNET_PROJNAME}.runtimestamp ${DOTNET_RUN_OUTPUT} + DEPENDS ${DOTNET_deps} + COMMAND ${DOTNET_EXE} run ${DOTNET_RUN_ARGUMENTS} + COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/${DOTNET_PROJNAME}.runtimestamp + WORKING_DIRECTORY ${DOTNET_PROJDIR}) + ADD_CUSTOM_TARGET( + RUN_${DOTNET_PROJNAME} + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${DOTNET_PROJNAME}.runtimestamp ${DOTNET_RUN_OUTPUT}) + ADD_DEPENDENCIES(RUN_${DOTNET_PROJNAME} BUILD_${DOTNET_PROJNAME}) +ENDFUNCTION() + +MESSAGE("-- Found .NET toolchain: ${DOTNET_EXE} (version ${DOTNET_VERSION})") +SET(DOTNET_FOUND TRUE) diff --git a/src/api/dotnet/CMakeLists.txt b/src/api/dotnet/CMakeLists.txt index 50f643c8d..987ef3dff 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,165 +125,33 @@ 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" - ) - # FIXME: This flag only works when the working directory of csc.exe is - # the directory containing the ``libz3`` target. I can't get this to work - # correctly with multi-configuration generators (i.e. Visual Studio) so - # just don't set the flag for now. - #list(APPEND CSC_FLAGS "/linkresource:$") -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" - ) -else() - message(FATAL_ERROR "Unknown .NET toolchain") -endif() -# Common flags -list(APPEND CSC_FLAGS - "/unsafe+" - "/nowarn:1701,1702" - "/errorreport:prompt" - "/warn:4" - "/reference:System.Core.dll" - "/reference:System.dll" - "/reference:System.Numerics.dll" - "/filealign:512" # Why? - "/target:library" -) +# FindDotnet.cmake forwards CMake build type to MSBuild. +# And thus we can put the conditional properties in the project file. -# 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+>" -) +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 + # note, nuget package file names do not have the ${VER_REV} part. + VERSION "${VER_MAJOR}.${VER_MINOR}.${VER_BUILD}" + PACKAGE Microsoft.Z3) -# 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}\"" -) +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/buildtimestamp + DEPENDS ${Z3_DOTNET_ASSEMBLY_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/Microsoft.Z3.csproj.in + COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/buildtimestamp) +add_custom_target(Z3_DOTNET_BUILD_DUMMY ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/buildtimestamp) +add_dependencies(BUILD_Microsoft.Z3 Z3_DOTNET_BUILD_DUMMY 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) -############################################################################### -# Install -############################################################################### -option(INSTALL_DOTNET_BINDINGS "Install .NET bindings when invoking install target" ON) -set(GAC_PKG_NAME "Microsoft.Z3.Sharp") -set(PREFIX "${CMAKE_INSTALL_PREFIX}") -set(VERSION "${Z3_VERSION}") -set(Z3_DOTNET_PKGCONFIG_FILE "${CMAKE_CURRENT_BINARY_DIR}/Microsoft.Z3.Sharp.pc") -configure_file("Microsoft.Z3.Sharp.pc.in" "${Z3_DOTNET_PKGCONFIG_FILE}" @ONLY) - -if (DOTNET_TOOLCHAIN_IS_MONO) - message(STATUS "Emitting install rules for .NET bindings") - # Install pkgconfig file for the assembly. This is needed by Monodevelop - # to find the assembly - install(FILES "${Z3_DOTNET_PKGCONFIG_FILE}" DESTINATION "${CMAKE_INSTALL_PKGCONFIGDIR}") - - # Configure the install and uninstall scripts. - # 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") -endif() +#TODO install diff --git a/src/api/dotnet/Microsoft.Z3.csproj b/src/api/dotnet/Microsoft.Z3.csproj deleted file mode 100644 index cde8b78c9..000000000 --- a/src/api/dotnet/Microsoft.Z3.csproj +++ /dev/null @@ -1,417 +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..b2fda27e4 --- /dev/null +++ b/src/api/dotnet/Microsoft.Z3.csproj.in @@ -0,0 +1,73 @@ + + + + + + Microsoft.Z3 + Microsoft.Z3 + + Z3 .NET Interface + Z3 .NET Interface + + Z3 + + .NET Interface to the Z3 Theorem Prover + .NET Interface to the Z3 Theorem Prover + + Copyright (C) 2006-2015 Microsoft Corporation + Copyright (C) 2006-2015 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} + + + + + + + netstandard2.0;net461;net45 + library + True + 1701,1702 + 4 + FRAMEWORK_LT_4 + + + + +${Z3_DOTNET_COMPILE_ITEMS} + + + + + + build + + + build + + + + + + + + runtimes\win-x64\native + + + + + + + + + + diff --git a/src/api/dotnet/Microsoft.Z3.props b/src/api/dotnet/Microsoft.Z3.props new file mode 100644 index 000000000..67bb471ba --- /dev/null +++ b/src/api/dotnet/Microsoft.Z3.props @@ -0,0 +1,22 @@ + + + + + + true + true + true + + + $(MSBuildThisFileDirectory)..\..\ + $(Z3_PACKAGE_PATH)runtimes\win-x64\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..80179ce4c --- /dev/null +++ b/src/api/dotnet/Microsoft.Z3.targets @@ -0,0 +1,11 @@ + + + + + + %(RecursiveDir)%(FileName)%(Extension) + PreserveNewest + + + + diff --git a/src/api/dotnet/Properties/AssemblyInfo.cs.in b/src/api/dotnet/Properties/AssemblyInfo.cs.in deleted file mode 100644 index e5a85f16f..000000000 --- a/src/api/dotnet/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/core/DummyContracts.cs b/src/api/dotnet/core/DummyContracts.cs deleted file mode 100644 index 103cc1288..000000000 --- a/src/api/dotnet/core/DummyContracts.cs +++ /dev/null @@ -1,65 +0,0 @@ -/*++ -Copyright () 2016 Microsoft Corporation - -Module Name: - - Contracts.cs - -Abstract: - - Z3 Managed API: Dummy Code Contracts class for .NET - frameworks that don't support them (e.g., CoreCLR). - -Author: - - Christoph Wintersteiger (cwinter) 2016-10-06 - -Notes: - ---*/ - -namespace System.Diagnostics.Contracts -{ - public class ContractClass : Attribute - { - public ContractClass(Type t) { } - } - - public class ContractClassFor : Attribute - { - public ContractClassFor(Type t) { } - } - - public class ContractInvariantMethod : Attribute - { - public ContractInvariantMethod() { } - } - - public class ContractVerification : Attribute - { - public ContractVerification(bool b) { } - } - - public class Pure : Attribute { } - - public static class Contract - { - [Conditional("false")] - public static void Ensures(bool b) { } - [Conditional("false")] - public static void Requires(bool b) { } - [Conditional("false")] - public static void Assume(bool b, string msg) { } - [Conditional("false")] - public static void Assert(bool b) { } - public static bool ForAll(bool b) { return true; } - public static bool ForAll(Object c, Func p) { return true; } - public static bool ForAll(int from, int to, Predicate p) { return true; } - [Conditional("false")] - public static void Invariant(bool b) { } - public static T[] Result() { return new T[1]; } - [Conditional("false")] - public static void EndContractBlock() { } - public static T ValueAtReturn(out T v) { T[] t = new T[1]; v = t[0]; return v; } - } -} diff --git a/src/api/dotnet/core/README.txt b/src/api/dotnet/core/README.txt deleted file mode 100644 index 72331d7f9..000000000 --- a/src/api/dotnet/core/README.txt +++ /dev/null @@ -1,9 +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 project.json diff --git a/src/api/dotnet/core/project.json b/src/api/dotnet/core/project.json deleted file mode 100644 index d54b6877b..000000000 --- a/src/api/dotnet/core/project.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "version": "1.0.0-*", - "buildOptions": { - "debugType": "portable", - "emitEntryPoint": false, - "outputName": "Microsoft.Z3", - "compile": [ "../*.cs", "*.cs" ], - "define": ["DOTNET_CORE"] - }, - "dependencies": { }, - "frameworks": { - "netcoreapp1.0": { - "dependencies": { - "Microsoft.NETCore.App": { - "type": "platform", - "version": "1.0.1" - } - }, - "imports": "dnxcore50" - } - } -} 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 @@ - - - - From 232a88101bf6a5867f0e038746decefee86fd47b Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Mon, 10 Sep 2018 08:57:28 +0800 Subject: [PATCH 002/318] api: dotnet: ADD_DOTNET should be uppercased. --- src/api/dotnet/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/dotnet/CMakeLists.txt b/src/api/dotnet/CMakeLists.txt index 987ef3dff..2d9b32a2f 100644 --- a/src/api/dotnet/CMakeLists.txt +++ b/src/api/dotnet/CMakeLists.txt @@ -139,7 +139,7 @@ endforeach() # And thus we can put the conditional properties in the project file. 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 +ADD_DOTNET(${CMAKE_CURRENT_BINARY_DIR}/build/Microsoft.Z3.csproj # note, nuget package file names do not have the ${VER_REV} part. VERSION "${VER_MAJOR}.${VER_MINOR}.${VER_BUILD}" PACKAGE Microsoft.Z3) From 90890e46a95a66660035f926b6713e558091a017 Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Mon, 10 Sep 2018 09:34:28 +0800 Subject: [PATCH 003/318] api: dotnet: FindDotnet.cmake now handles 'REQUIRED' option. --- cmake/modules/FindDotnet.cmake | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cmake/modules/FindDotnet.cmake b/cmake/modules/FindDotnet.cmake index a3d0c2dd1..4ca792ed6 100644 --- a/cmake/modules/FindDotnet.cmake +++ b/cmake/modules/FindDotnet.cmake @@ -56,7 +56,7 @@ # # Require 3.5 for batch copy multiple files -CMAKE_MINIMUM_REQUIRED(VERSION 3.5.0) +cmake_minimum_required(VERSION 3.5.0) IF(DOTNET_FOUND) RETURN() @@ -68,6 +68,9 @@ 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() From 969a922145e3f7a96298143ac03cd31fb61ab5b9 Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Mon, 10 Sep 2018 13:19:48 +0800 Subject: [PATCH 004/318] api: dotnet: install nuget package and register local repo; xplat native assembly detection --- cmake/modules/FindDotnet.cmake | 12 ++++++---- src/api/dotnet/CMakeLists.txt | 33 +++++++++++++++++++-------- src/api/dotnet/Microsoft.Z3.csproj.in | 10 ++++---- 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/cmake/modules/FindDotnet.cmake b/cmake/modules/FindDotnet.cmake index 4ca792ed6..ed1186999 100644 --- a/cmake/modules/FindDotnet.cmake +++ b/cmake/modules/FindDotnet.cmake @@ -22,7 +22,8 @@ # [PLATFORM platform] # [PACKAGE output_nuget_packages... ] # [VERSION nuget_package_version] -# [DEPENDS depend_nuget_packages... ]) +# [DEPENDS depend_nuget_packages... ] +# [SOURCES additional_file_dependencies... ]) # ``` # # RUN_DOTNET -- Run a project with `dotnet run`. The `OUTPUT` argument represents artifacts @@ -41,7 +42,8 @@ # [CONFIG configuration] # [PLATFORM platform] # [PACKAGE output_nuget_packages... ] -# [DEPENDS depend_nuget_packages... ]) +# [DEPENDS depend_nuget_packages... ] +# [SOURCES additional_file_dependencies... ]) # ``` # # DOTNET_REGISTER_LOCAL_REPOSITORY -- register a local NuGet package repository. @@ -110,7 +112,6 @@ ENDFUNCTION() FUNCTION(DOTNET_GET_DEPS _DN_PROJECT arguments) FILE(GLOB_RECURSE DOTNET_deps *.cs *.fs *.xaml *.csproj *.fsproj *.tsl) - LIST(FILTER DOTNET_deps EXCLUDE REGEX /obj/) CMAKE_PARSE_ARGUMENTS( # prefix _DN @@ -119,10 +120,13 @@ FUNCTION(DOTNET_GET_DEPS _DN_PROJECT arguments) # oneValueArgs "CONFIG;PLATFORM;VERSION" # multiValueArgs - "PACKAGE;DEPENDS;ARGUMENTS;OUTPUT" + "PACKAGE;DEPENDS;ARGUMENTS;OUTPUT;SOURCES" # the input arguments ${arguments}) + LIST(APPEND DOTNET_deps ${_DN_SOURCES}) + LIST(FILTER DOTNET_deps EXCLUDE REGEX /obj/) + GET_FILENAME_COMPONENT(_DN_abs_proj "${_DN_PROJECT}" ABSOLUTE) GET_FILENAME_COMPONENT(_DN_proj_dir "${_DN_PROJECT}" DIRECTORY) GET_FILENAME_COMPONENT(_DN_projname "${DOTNET_PROJECT}" NAME) diff --git a/src/api/dotnet/CMakeLists.txt b/src/api/dotnet/CMakeLists.txt index 2d9b32a2f..6a70f43b5 100644 --- a/src/api/dotnet/CMakeLists.txt +++ b/src/api/dotnet/CMakeLists.txt @@ -137,21 +137,34 @@ endforeach() # 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}") 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 - # note, nuget package file names do not have the ${VER_REV} part. - VERSION "${VER_MAJOR}.${VER_MINOR}.${VER_BUILD}" + VERSION ${Z3_DOTNET_NUPKG_VERSION} + SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Microsoft.Z3.csproj.in PACKAGE Microsoft.Z3) -add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/buildtimestamp - DEPENDS ${Z3_DOTNET_ASSEMBLY_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/Microsoft.Z3.csproj.in - COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/buildtimestamp) -add_custom_target(Z3_DOTNET_BUILD_DUMMY ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/buildtimestamp) -add_dependencies(BUILD_Microsoft.Z3 Z3_DOTNET_BUILD_DUMMY libz3) +add_dependencies(BUILD_Microsoft.Z3 libz3) # Convenient top-level target add_custom_target(build_z3_dotnet_bindings ALL DEPENDS BUILD_Microsoft.Z3) -#TODO 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) + +if(INSTALL_DOTNET_BINDINGS) + install(FILES "${CMAKE_BINARY_DIR}/Microsoft.Z3.${Z3_DOTNET_NUPKG_VERSION}.nupkg" DESTINATION "${CMAKE_INSTALL_LIBDIR}/z3.nuget") + install(CODE "include(${CMAKE_CURRENT_LIST_DIR}/../../../cmake/modules/FindDotnet.cmake)\n DOTNET_REGISTER_LOCAL_REPOSITORY(Microsoft.Z3.LocalBuild ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/z3.nuget)") +# TODO docs? +# install(FILES "${Z3_DOTNET_ASSEMBLY_DLL_DOC}" DESTINATION "${CMAKE_INSTALL_LIBDIR}") +# 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/Microsoft.Z3.csproj.in b/src/api/dotnet/Microsoft.Z3.csproj.in index b2fda27e4..cbbddc63f 100644 --- a/src/api/dotnet/Microsoft.Z3.csproj.in +++ b/src/api/dotnet/Microsoft.Z3.csproj.in @@ -1,4 +1,4 @@ - + @@ -58,11 +58,13 @@ ${Z3_DOTNET_COMPILE_ITEMS} - - + + runtimes\win-x64\native - + + runtimes\linux-x64\native + From 534de98ff36a89613ecdfefaf83faf204983f4b6 Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Mon, 10 Sep 2018 15:05:22 +0800 Subject: [PATCH 005/318] fine-tune native assembly packing --- src/api/dotnet/CMakeLists.txt | 2 +- src/api/dotnet/Microsoft.Z3.csproj.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/dotnet/CMakeLists.txt b/src/api/dotnet/CMakeLists.txt index 6a70f43b5..07091cab9 100644 --- a/src/api/dotnet/CMakeLists.txt +++ b/src/api/dotnet/CMakeLists.txt @@ -142,7 +142,7 @@ set(Z3_DOTNET_NUPKG_VERSION "${VER_MAJOR}.${VER_MINOR}.${VER_BUILD}") 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} - SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Microsoft.Z3.csproj.in + SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Microsoft.Z3.csproj.in ${Z3_DOTNET_ASSEMBLY_SOURCES} PACKAGE Microsoft.Z3) add_dependencies(BUILD_Microsoft.Z3 libz3) diff --git a/src/api/dotnet/Microsoft.Z3.csproj.in b/src/api/dotnet/Microsoft.Z3.csproj.in index cbbddc63f..01d18def9 100644 --- a/src/api/dotnet/Microsoft.Z3.csproj.in +++ b/src/api/dotnet/Microsoft.Z3.csproj.in @@ -59,7 +59,7 @@ ${Z3_DOTNET_COMPILE_ITEMS} - + runtimes\win-x64\native From 5c81559f71c5278284cad64e4037a55feafd304c Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Mon, 10 Sep 2018 16:02:09 +0800 Subject: [PATCH 006/318] api: dotnet: copy native binary to output folder only for non-netstandard, non-netcoreapp TFMs. --- src/api/dotnet/Microsoft.Z3.targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/dotnet/Microsoft.Z3.targets b/src/api/dotnet/Microsoft.Z3.targets index 80179ce4c..9eba049c6 100644 --- a/src/api/dotnet/Microsoft.Z3.targets +++ b/src/api/dotnet/Microsoft.Z3.targets @@ -1,7 +1,7 @@ - + %(RecursiveDir)%(FileName)%(Extension) PreserveNewest From e787c01d4128056870539353e2c7d84fc51a92e1 Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Mon, 10 Sep 2018 16:40:22 +0800 Subject: [PATCH 007/318] ... --- src/api/dotnet/CMakeLists.txt | 5 ++++- src/api/dotnet/Microsoft.Z3.targets | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/api/dotnet/CMakeLists.txt b/src/api/dotnet/CMakeLists.txt index 07091cab9..b2909f03c 100644 --- a/src/api/dotnet/CMakeLists.txt +++ b/src/api/dotnet/CMakeLists.txt @@ -142,7 +142,10 @@ set(Z3_DOTNET_NUPKG_VERSION "${VER_MAJOR}.${VER_MINOR}.${VER_BUILD}") 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} - SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Microsoft.Z3.csproj.in ${Z3_DOTNET_ASSEMBLY_SOURCES} + 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) add_dependencies(BUILD_Microsoft.Z3 libz3) diff --git a/src/api/dotnet/Microsoft.Z3.targets b/src/api/dotnet/Microsoft.Z3.targets index 9eba049c6..38e56b350 100644 --- a/src/api/dotnet/Microsoft.Z3.targets +++ b/src/api/dotnet/Microsoft.Z3.targets @@ -1,7 +1,7 @@ - + %(RecursiveDir)%(FileName)%(Extension) PreserveNewest From a162a60d9ce372da826d65eb2e637011ff3f48d7 Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Tue, 11 Sep 2018 23:16:45 +0800 Subject: [PATCH 008/318] CI: trying to incorporate .net sdk into travis build --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 9ec6132b6..7776c3f58 100644 --- a/.travis.yml +++ b/.travis.yml @@ -74,6 +74,8 @@ env: - LINUX_BASE=ubuntu_14.04 C_COMPILER=/usr/bin/gcc-4.8 CXX_COMPILER=/usr/bin/g++-4.8 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=RelWithDebInfo # 64-bit GCC 4.8 Debug - LINUX_BASE=ubuntu_14.04 C_COMPILER=/usr/bin/gcc-4.8 CXX_COMPILER=/usr/bin/g++-4.8 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug RUN_UNIT_TESTS=BUILD_ONLY + include: + - dotnet: 2.1.4 # macOS (a.k.a OSX) support matrix: @@ -85,6 +87,7 @@ matrix: osx_image: xcode8.3 # Note: Apple Clang does not support OpenMP env: Z3_BUILD_TYPE=RelWithDebInfo USE_OPENMP=0 DOTNET_BINDINGS=0 + - dotnet: 2.1.4 script: # Use `travis_wait` when doing LTO builds because this configuration will # have long link times during which it will not show any output which From 538272d2d5526f19853e5d801889c2d332e76212 Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Tue, 11 Sep 2018 23:32:29 +0800 Subject: [PATCH 009/318] CI: 2nd attempt: trying to incorporate .net sdk into travis build --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7776c3f58..51e08a703 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ cache: - $DOCKER_TRAVIS_CI_CACHE_DIR sudo: required language: cpp +dotnet: 2.1.4 services: - docker env: @@ -74,8 +75,6 @@ env: - LINUX_BASE=ubuntu_14.04 C_COMPILER=/usr/bin/gcc-4.8 CXX_COMPILER=/usr/bin/g++-4.8 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=RelWithDebInfo # 64-bit GCC 4.8 Debug - LINUX_BASE=ubuntu_14.04 C_COMPILER=/usr/bin/gcc-4.8 CXX_COMPILER=/usr/bin/g++-4.8 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug RUN_UNIT_TESTS=BUILD_ONLY - include: - - dotnet: 2.1.4 # macOS (a.k.a OSX) support matrix: @@ -87,8 +86,9 @@ matrix: osx_image: xcode8.3 # Note: Apple Clang does not support OpenMP env: Z3_BUILD_TYPE=RelWithDebInfo USE_OPENMP=0 DOTNET_BINDINGS=0 - - dotnet: 2.1.4 script: + # Add at least one dotnet command invocation to activate the build env. + - dotnet restore # Use `travis_wait` when doing LTO builds because this configuration will # have long link times during which it will not show any output which # TravisCI might kill due to perceived inactivity. From 44e21d99489a6a12d020ad890bb952fda8d41ec2 Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Tue, 11 Sep 2018 23:37:26 +0800 Subject: [PATCH 010/318] CI: 3rd attempt: trying to incorporate .net sdk into travis build --- .travis.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 51e08a703..038874c0d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,6 @@ cache: - $DOCKER_TRAVIS_CI_CACHE_DIR sudo: required language: cpp -dotnet: 2.1.4 services: - docker env: @@ -86,9 +85,15 @@ matrix: osx_image: xcode8.3 # Note: Apple Clang does not support OpenMP env: Z3_BUILD_TYPE=RelWithDebInfo USE_OPENMP=0 DOTNET_BINDINGS=0 + +matrix: + include: + - language: csharp + dotnet: 2.1.4 + script: + # Add at least one dotnet command invocation to activate the build env. + - dotnet restore script: - # Add at least one dotnet command invocation to activate the build env. - - dotnet restore # Use `travis_wait` when doing LTO builds because this configuration will # have long link times during which it will not show any output which # TravisCI might kill due to perceived inactivity. From 5bc7a5d67324c14059ec9edaaf778f6f7fddcf44 Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Wed, 12 Sep 2018 00:29:58 +0800 Subject: [PATCH 011/318] CI: configure dotnet via docker --- .travis.yml | 7 ------- contrib/ci/Dockerfiles/z3_base_ubuntu32_16.04.Dockerfile | 5 +++-- contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile | 8 ++++++-- contrib/ci/Dockerfiles/z3_base_ubuntu_16.04.Dockerfile | 8 ++++++-- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index 038874c0d..076b3a554 100644 --- a/.travis.yml +++ b/.travis.yml @@ -86,13 +86,6 @@ matrix: # Note: Apple Clang does not support OpenMP env: Z3_BUILD_TYPE=RelWithDebInfo USE_OPENMP=0 DOTNET_BINDINGS=0 -matrix: - include: - - language: csharp - dotnet: 2.1.4 - script: - # Add at least one dotnet command invocation to activate the build env. - - dotnet restore script: # Use `travis_wait` when doing LTO builds because this configuration will # have long link times during which it will not show any output which 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..15144fa8e 100644 --- a/contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile +++ b/contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile @@ -1,5 +1,9 @@ FROM ubuntu:14.04 +RUN wget -q https://packages.microsoft.com/config/ubuntu/16.04/packages-microsoft-prod.deb && \ + dpkg -i packages-microsoft-prod.deb && \ + apt-get install apt-transport-https + RUN apt-get update && \ apt-get -y --no-install-recommends install \ binutils \ @@ -18,12 +22,12 @@ RUN apt-get update && \ lib32gomp1 \ llvm-3.9 \ make \ - mono-devel \ ninja-build \ python3 \ python3-setuptools \ python2.7 \ - python-setuptools + python-setuptools \ + dotnet-sdk-2.1 # Create `user` user for container with password `user`. and give it # password-less sudo access diff --git a/contrib/ci/Dockerfiles/z3_base_ubuntu_16.04.Dockerfile b/contrib/ci/Dockerfiles/z3_base_ubuntu_16.04.Dockerfile index 08686e275..1963a4ad3 100644 --- a/contrib/ci/Dockerfiles/z3_base_ubuntu_16.04.Dockerfile +++ b/contrib/ci/Dockerfiles/z3_base_ubuntu_16.04.Dockerfile @@ -1,5 +1,9 @@ FROM ubuntu:16.04 +RUN wget -q https://packages.microsoft.com/config/ubuntu/16.04/packages-microsoft-prod.deb && \ + dpkg -i packages-microsoft-prod.deb && \ + apt-get install apt-transport-https + RUN apt-get update && \ apt-get -y --no-install-recommends install \ binutils \ @@ -20,13 +24,13 @@ RUN apt-get update && \ libomp-dev \ llvm-3.9 \ make \ - mono-devel \ ninja-build \ python3 \ python3-setuptools \ python2.7 \ python-setuptools \ - sudo + sudo \ + dotnet-sdk-2.1 # Create `user` user for container with password `user`. and give it # password-less sudo access From 5fdf3ff7996a9ce7e58f4990a21dca3f3e735597 Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Wed, 12 Sep 2018 00:37:06 +0800 Subject: [PATCH 012/318] CI: Dockerfile: use curl instead of wget --- contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile | 2 +- contrib/ci/Dockerfiles/z3_base_ubuntu_16.04.Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile b/contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile index 15144fa8e..ce78e7fb9 100644 --- a/contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile +++ b/contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile @@ -1,6 +1,6 @@ FROM ubuntu:14.04 -RUN wget -q https://packages.microsoft.com/config/ubuntu/16.04/packages-microsoft-prod.deb && \ +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 install apt-transport-https diff --git a/contrib/ci/Dockerfiles/z3_base_ubuntu_16.04.Dockerfile b/contrib/ci/Dockerfiles/z3_base_ubuntu_16.04.Dockerfile index 1963a4ad3..efa1d5600 100644 --- a/contrib/ci/Dockerfiles/z3_base_ubuntu_16.04.Dockerfile +++ b/contrib/ci/Dockerfiles/z3_base_ubuntu_16.04.Dockerfile @@ -1,6 +1,6 @@ FROM ubuntu:16.04 -RUN wget -q https://packages.microsoft.com/config/ubuntu/16.04/packages-microsoft-prod.deb && \ +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 install apt-transport-https From 5474e1675a8b75f4e01ae3620c27f435d6466c77 Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Wed, 12 Sep 2018 00:53:10 +0800 Subject: [PATCH 013/318] CI: Dockerfile: install curl before dotnet --- .../ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile | 14 ++++++++------ .../ci/Dockerfiles/z3_base_ubuntu_16.04.Dockerfile | 14 ++++++++------ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile b/contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile index ce78e7fb9..f6541a2c9 100644 --- a/contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile +++ b/contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile @@ -1,14 +1,12 @@ FROM ubuntu:14.04 -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 install apt-transport-https - 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 \ @@ -26,8 +24,12 @@ RUN apt-get update && \ python3 \ python3-setuptools \ python2.7 \ - python-setuptools \ - dotnet-sdk-2.1 + python-setuptools + +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 diff --git a/contrib/ci/Dockerfiles/z3_base_ubuntu_16.04.Dockerfile b/contrib/ci/Dockerfiles/z3_base_ubuntu_16.04.Dockerfile index efa1d5600..f4d9c873a 100644 --- a/contrib/ci/Dockerfiles/z3_base_ubuntu_16.04.Dockerfile +++ b/contrib/ci/Dockerfiles/z3_base_ubuntu_16.04.Dockerfile @@ -1,15 +1,13 @@ FROM ubuntu:16.04 -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 install apt-transport-https - 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 \ @@ -29,8 +27,12 @@ RUN apt-get update && \ python3-setuptools \ python2.7 \ python-setuptools \ - sudo \ - dotnet-sdk-2.1 + 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 From 20c128d3fa2212fa937a6de7d6b4a5317526aa6e Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Wed, 12 Sep 2018 01:28:42 +0800 Subject: [PATCH 014/318] replace LIST FILTER with handrolled implementation to cancel cmake v3.6+ dependency --- cmake/modules/FindDotnet.cmake | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cmake/modules/FindDotnet.cmake b/cmake/modules/FindDotnet.cmake index ed1186999..625317a41 100644 --- a/cmake/modules/FindDotnet.cmake +++ b/cmake/modules/FindDotnet.cmake @@ -125,7 +125,12 @@ FUNCTION(DOTNET_GET_DEPS _DN_PROJECT arguments) ${arguments}) LIST(APPEND DOTNET_deps ${_DN_SOURCES}) - LIST(FILTER DOTNET_deps EXCLUDE REGEX /obj/) + SET(_DN_deps "") + FOREACH(dep ${DOTNET_deps}) + IF(NOT dep MATCHES /obj/) + LIST(APPEND _DN_deps ${dep}) + ENDIF() + ENDFOREACH() GET_FILENAME_COMPONENT(_DN_abs_proj "${_DN_PROJECT}" ABSOLUTE) GET_FILENAME_COMPONENT(_DN_proj_dir "${_DN_PROJECT}" DIRECTORY) @@ -178,7 +183,7 @@ FUNCTION(DOTNET_GET_DEPS _DN_PROJECT arguments) 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 ${DOTNET_deps} PARENT_SCOPE) + SET(DOTNET_deps ${_DN_deps} PARENT_SCOPE) IF(_DN_PLATFORM) SET(_DN_PLATFORM_PROP "/p:Platform=${_DN_PLATFORM}") From aae28bd0eb6f2b2be9107ec59ad650c87690f8b7 Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Wed, 12 Sep 2018 14:26:21 +0800 Subject: [PATCH 015/318] CI: update dotnet example to coreclr 2.0 --- contrib/ci/scripts/test_z3_examples_cmake.sh | 4 ++-- examples/dotnet/dotnet.csproj | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 examples/dotnet/dotnet.csproj diff --git a/contrib/ci/scripts/test_z3_examples_cmake.sh b/contrib/ci/scripts/test_z3_examples_cmake.sh index 687efebb4..a1de9f375 100755 --- a/contrib/ci/scripts/test_z3_examples_cmake.sh +++ b/contrib/ci/scripts/test_z3_examples_cmake.sh @@ -91,8 +91,8 @@ 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 + # Build & Run .NET example + run_quiet run_non_native_binding dotnet run -p ${Z3_SRC_DIR}/examples/dotnet/dotnet.csproj fi if [ "X${JAVA_BINDINGS}" = "X1" ]; then diff --git a/examples/dotnet/dotnet.csproj b/examples/dotnet/dotnet.csproj new file mode 100644 index 000000000..0dc4ee2ec --- /dev/null +++ b/examples/dotnet/dotnet.csproj @@ -0,0 +1,12 @@ + + + + Exe + netcoreapp2.0 + + + + + + + From 461c32e11e5fa529475962f830664fcd0a1d9bea Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Wed, 12 Sep 2018 16:07:45 +0800 Subject: [PATCH 016/318] ... --- contrib/ci/scripts/test_z3_examples_cmake.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/contrib/ci/scripts/test_z3_examples_cmake.sh b/contrib/ci/scripts/test_z3_examples_cmake.sh index a1de9f375..679fc4a69 100755 --- a/contrib/ci/scripts/test_z3_examples_cmake.sh +++ b/contrib/ci/scripts/test_z3_examples_cmake.sh @@ -88,9 +88,6 @@ 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 # Build & Run .NET example run_quiet run_non_native_binding dotnet run -p ${Z3_SRC_DIR}/examples/dotnet/dotnet.csproj fi From 519098b73d5f555dc833b861fb3fed96734a4cbd Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Wed, 17 Oct 2018 11:27:20 +0800 Subject: [PATCH 017/318] fix nuget props package path detection --- src/api/dotnet/Microsoft.Z3.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/dotnet/Microsoft.Z3.props b/src/api/dotnet/Microsoft.Z3.props index 67bb471ba..290cc5f86 100644 --- a/src/api/dotnet/Microsoft.Z3.props +++ b/src/api/dotnet/Microsoft.Z3.props @@ -7,8 +7,8 @@ true true - - $(MSBuildThisFileDirectory)..\..\ + + $(MSBuildThisFileDirectory)..\ $(Z3_PACKAGE_PATH)runtimes\win-x64\native\libz3.dll $(Z3_PACKAGE_PATH)runtimes\linux-x64\native\libz3.so From 16be5b0e7de0316e0ad39d8cac8842eee71d490e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 25 Nov 2018 14:04:17 -0800 Subject: [PATCH 018/318] fix #1816 - m_parent_selects gets updated while accessing an interator, fix is to rely on the size of the vector for iteration Signed-off-by: Nikolaj Bjorner --- src/smt/theory_array_full.cpp | 10 ++- src/smt/theory_seq.cpp | 137 ++++++++++++++-------------------- src/util/ref_vector.h | 12 +++ 3 files changed, 75 insertions(+), 84 deletions(-) diff --git a/src/smt/theory_array_full.cpp b/src/smt/theory_array_full.cpp index d0a37175d..4e1de7b90 100644 --- a/src/smt/theory_array_full.cpp +++ b/src/smt/theory_array_full.cpp @@ -65,10 +65,14 @@ namespace smt { bool result = false; var_data * d = m_var_data[v]; var_data_full * d_full = m_var_data_full[v]; - for (enode* pm : d_full->m_parent_maps) - for (enode* ps : d->m_parent_selects) + for (unsigned i = 0; i < d_full->m_parent_maps.size(); ++i) { + enode* pm = d_full->m_parent_maps[i]; + for (unsigned j = 0; j < d->m_parent_selects.size(); ++j) { + enode* ps = d->m_parent_selects[j]; if (instantiate_select_map_axiom(ps, pm)) - result = true; + result = true; + } + } return result; } diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 2bce6cf56..410910a19 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -495,6 +495,9 @@ void theory_seq::branch_unit_variable(dependency* dep, expr* X, expr_ref_vector } bool theory_seq::branch_ternary_variable1() { + + //std::function branch = [&](eq const& e) { return branch_ternary_variable(e) || branch_ternary_variable2(e); }; + //return m_eqs.exists(branch); for (auto const& e : m_eqs) { if (branch_ternary_variable(e) || branch_ternary_variable2(e)) { return true; @@ -1085,73 +1088,53 @@ bool theory_seq::find_better_rep(expr_ref_vector const& ls, expr_ref_vector cons expr* r_fst = find_fst_non_empty_var(rs); if (!r_fst) return false; expr_ref len_r_fst = mk_len(r_fst); + expr_ref len_l_fst(m); enode * root2; - if (!ctx.e_internalized(len_r_fst)) + if (!ctx.e_internalized(len_r_fst)) { return false; - else - root2 = get_root(len_r_fst); + } + if (l_fst) { + len_l_fst = mk_len(l_fst); + } + + root2 = get_root(len_r_fst); // Offset = 0, No change - if (l_fst) { - expr_ref len_l_fst = mk_len(l_fst); - if (ctx.e_internalized(len_l_fst)) { - enode * root1 = get_root(len_l_fst); - if (root1 == root2) { - TRACE("seq", tout << "(" << mk_pp(l_fst, m) << ", " << mk_pp(r_fst,m) << ")\n";); - return false; - } - } + if (l_fst && get_root(len_l_fst) == root2) { + TRACE("seq", tout << "(" << mk_pp(l_fst, m) << ", " << mk_pp(r_fst,m) << ")\n";); + return false; } // Offset = 0, Changed - { - for (unsigned i = 0; i < idx; ++i) { - eq const& e = m_eqs[i]; - if (e.ls().size() == ls.size()) { - bool flag = true; - for (unsigned j = 0; j < ls.size(); ++j) - if (e.ls().get(j) != ls.get(j)) { - flag = false; - break; - } - if (flag) { - expr* nl_fst = nullptr; - if (e.rs().size()>1 && is_var(e.rs().get(0))) - nl_fst = e.rs().get(0); - if (nl_fst && nl_fst != r_fst) { - expr_ref len_nl_fst = mk_len(nl_fst); - if (ctx.e_internalized(len_nl_fst)) { - enode * root1 = get_root(len_nl_fst); - if (root1 == root2) { - res.reset(); - res.append(e.rs().size(), e.rs().c_ptr()); - deps = m_dm.mk_join(e.dep(), deps); - return true; - } - } - } - } - } + + for (unsigned i = 0; i < idx; ++i) { + eq const& e = m_eqs[i]; + if (e.ls() != ls) continue; + expr* nl_fst = nullptr; + if (e.rs().size() > 1 && is_var(e.rs().get(0))) + nl_fst = e.rs().get(0); + if (nl_fst && nl_fst != r_fst && root2 == get_root(mk_len(nl_fst))) { + res.reset(); + res.append(e.rs().size(), e.rs().c_ptr()); + deps = m_dm.mk_join(e.dep(), deps); + return true; } } // Offset != 0, No change - if (l_fst) { - expr_ref len_l_fst = mk_len(l_fst); - if (ctx.e_internalized(len_l_fst)) { - enode * root1 = get_root(len_l_fst); - obj_map tmp; - int offset; - if (!m_autil.is_numeral(root1->get_owner()) && !m_autil.is_numeral(root2->get_owner())) { - if (m_len_offset.find(root1, tmp) && tmp.find(root2, offset)) { - TRACE("seq", tout << "(" << mk_pp(l_fst, m) << ", " << mk_pp(r_fst,m) << ")\n";); - find_max_eq_len(ls, rs); - return false; - } - else if (m_len_offset.find(root2, tmp) && tmp.find(root1, offset)) { - TRACE("seq", tout << "(" << mk_pp(r_fst, m) << ", " << mk_pp(l_fst,m) << ")\n";); - find_max_eq_len(ls ,rs); - return false; - } + if (l_fst && ctx.e_internalized(len_l_fst)) { + enode * root1 = get_root(len_l_fst); + obj_map tmp; + int offset; + if (!m_autil.is_numeral(root1->get_owner()) && !m_autil.is_numeral(root2->get_owner())) { + if (m_len_offset.find(root1, tmp) && tmp.find(root2, offset)) { + TRACE("seq", tout << "(" << mk_pp(l_fst, m) << ", " << mk_pp(r_fst,m) << ")\n";); + find_max_eq_len(ls, rs); + return false; + } + else if (m_len_offset.find(root2, tmp) && tmp.find(root1, offset)) { + TRACE("seq", tout << "(" << mk_pp(r_fst, m) << ", " << mk_pp(l_fst,m) << ")\n";); + find_max_eq_len(ls ,rs); + return false; } } } @@ -1160,30 +1143,21 @@ bool theory_seq::find_better_rep(expr_ref_vector const& ls, expr_ref_vector cons if (!m_autil.is_numeral(root2->get_owner()) && m_len_offset.find(root2, tmp)) { for (unsigned i = 0; i < idx; ++i) { eq const& e = m_eqs[i]; - if (e.ls().size() == ls.size()) { - bool flag = true; - for (unsigned j = 0; j < ls.size(); ++j) - if (e.ls().get(j) != ls.get(j)) { - flag = false; - break; - } - if (flag) { - expr* nl_fst = nullptr; - if (e.rs().size()>1 && is_var(e.rs().get(0))) - nl_fst = e.rs().get(0); - if (nl_fst && nl_fst != r_fst) { - int offset; - expr_ref len_nl_fst = mk_len(nl_fst); - if (ctx.e_internalized(len_nl_fst)) { - enode * root1 = ctx.get_enode(len_nl_fst)->get_root(); - if (!m_autil.is_numeral(root1->get_owner()) && tmp.find(root1, offset)) { - res.reset(); - res.append(e.rs().size(), e.rs().c_ptr()); - deps = m_dm.mk_join(e.dep(), deps); - find_max_eq_len(res, rs); - return true; - } - } + if (e.ls() != ls) continue; + expr* nl_fst = nullptr; + if (e.rs().size()>1 && is_var(e.rs().get(0))) + nl_fst = e.rs().get(0); + if (nl_fst && nl_fst != r_fst) { + int offset; + expr_ref len_nl_fst = mk_len(nl_fst); + if (ctx.e_internalized(len_nl_fst)) { + enode * root1 = ctx.get_enode(len_nl_fst)->get_root(); + if (!m_autil.is_numeral(root1->get_owner()) && tmp.find(root1, offset)) { + res.reset(); + res.append(e.rs().size(), e.rs().c_ptr()); + deps = m_dm.mk_join(e.dep(), deps); + find_max_eq_len(res, rs); + return true; } } } @@ -1255,6 +1229,7 @@ bool theory_seq::len_based_split() { } } } + std::function split = [&](eq const& e) { return len_based_split(e); }; for (auto const& e : m_eqs) { if (len_based_split(e)) { diff --git a/src/util/ref_vector.h b/src/util/ref_vector.h index 02803a514..b259cd468 100644 --- a/src/util/ref_vector.h +++ b/src/util/ref_vector.h @@ -306,6 +306,18 @@ public: // prevent abuse: ref_vector & operator=(ref_vector const & other) = delete; + bool operator==(ref_vector const& other) const { + if (other.size() != size()) return false; + for (unsigned i = size(); i-- > 0; ) { + if (other[i] != (*this)[i]) return false; + } + return true; + } + + bool operator!=(ref_vector const& other) const { + return !(*this == other); + } + bool forall(std::function& predicate) const { for (T* t : *this) if (!predicate(t)) From 88fd088a09d95b122581e50d69cdeabd87c8200b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 25 Nov 2018 14:15:10 -0800 Subject: [PATCH 019/318] conditional flattening Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 50 +++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 410910a19..5a85628e8 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -1169,40 +1169,41 @@ bool theory_seq::find_better_rep(expr_ref_vector const& ls, expr_ref_vector cons bool theory_seq::has_len_offset(expr_ref_vector const& ls, expr_ref_vector const& rs, int & offset) { context& ctx = get_context(); - if (ls.size() == 0 || rs.size() == 0) + if (ls.empty() || rs.empty()) return false; expr* l_fst = ls[0]; expr* r_fst = rs[0]; if (!is_var(l_fst) || !is_var(r_fst)) return false; + expr_ref len_l_fst = mk_len(l_fst); + if (!ctx.e_internalized(len_l_fst)) + return false; + enode * root1 = ctx.get_enode(len_l_fst)->get_root(); + expr_ref len_r_fst = mk_len(r_fst); - enode * root2; if (!ctx.e_internalized(len_r_fst)) return false; - else - root2 = ctx.get_enode(len_r_fst)->get_root(); + enode* root2 = ctx.get_enode(len_r_fst)->get_root(); - expr_ref len_l_fst = mk_len(l_fst); - if (ctx.e_internalized(len_l_fst)) { - enode * root1 = ctx.get_enode(len_l_fst)->get_root(); - if (root1 == root2) { - TRACE("seq", tout << "(" << mk_pp(l_fst, m) << ", " << mk_pp(r_fst,m) << ")\n";); - offset = 0; - return true; - } - obj_map tmp; - if (!m_autil.is_numeral(root1->get_owner()) && !m_autil.is_numeral(root2->get_owner())) { - if (m_len_offset.find(root1, tmp) && tmp.find(root2, offset)) { - TRACE("seq", tout << "(" << mk_pp(l_fst, m) << ", " << mk_pp(r_fst,m) << ")\n";); - return true; - } - else if (m_len_offset.find(root2, tmp) && tmp.find(root1, offset)) { - offset = -offset; - TRACE("seq", tout << "(" << mk_pp(r_fst, m) << ", " << mk_pp(l_fst,m) << ")\n";); - return true; - } - } + if (root1 == root2) { + TRACE("seq", tout << "(" << mk_pp(l_fst, m) << ", " << mk_pp(r_fst,m) << ")\n";); + offset = 0; + return true; + } + + if (m_autil.is_numeral(root1->get_owner()) || m_autil.is_numeral(root2->get_owner())) + return false; + + obj_map tmp; + if (m_len_offset.find(root1, tmp) && tmp.find(root2, offset)) { + TRACE("seq", tout << "(" << mk_pp(l_fst, m) << ", " << mk_pp(r_fst,m) << ")\n";); + return true; + } + if (m_len_offset.find(root2, tmp) && tmp.find(root1, offset)) { + offset = -offset; + TRACE("seq", tout << "(" << mk_pp(r_fst, m) << ", " << mk_pp(l_fst,m) << ")\n";); + return true; } return false; } @@ -1229,7 +1230,6 @@ bool theory_seq::len_based_split() { } } } - std::function split = [&](eq const& e) { return len_based_split(e); }; for (auto const& e : m_eqs) { if (len_based_split(e)) { From 8e83d04e027f9a7b9c5c1e3539c8363ae711a549 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 25 Nov 2018 14:22:22 -0800 Subject: [PATCH 020/318] this->size() Signed-off-by: Nikolaj Bjorner --- src/util/ref_vector.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/ref_vector.h b/src/util/ref_vector.h index b259cd468..d0e9a8f55 100644 --- a/src/util/ref_vector.h +++ b/src/util/ref_vector.h @@ -307,8 +307,8 @@ public: ref_vector & operator=(ref_vector const & other) = delete; bool operator==(ref_vector const& other) const { - if (other.size() != size()) return false; - for (unsigned i = size(); i-- > 0; ) { + if (other.size() != this->size()) return false; + for (unsigned i = this->size(); i-- > 0; ) { if (other[i] != (*this)[i]) return false; } return true; From e026f96ed42444ed1def9e892ac95ad0e4c855a3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 25 Nov 2018 14:30:30 -0800 Subject: [PATCH 021/318] code review updates for #1963 Signed-off-by: Nikolaj Bjorner --- src/smt/smt_quantifier.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index f74c9d4c9..14dc27c79 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -110,17 +110,20 @@ namespace smt { equivalence class are in the log and up-to-date. */ void log_justification_to_root(std::ostream & log, enode *en, obj_hashtable &already_visited) { - enode *root = en->get_root(); + enode* root = en->get_root(); for (enode *it = en; it != root; it = it->get_trans_justification().m_target) { - if (already_visited.find(it) == already_visited.end()) already_visited.insert(it); - else break; + if (already_visited.contains(it)) + break; + already_visited.insert(it); if (!it->m_proof_is_logged) { log_single_justification(log, it, already_visited); it->m_proof_is_logged = true; - } else if (it->get_trans_justification().m_justification.get_kind() == smt::eq_justification::kind::CONGRUENCE) { + } + else if (it->get_trans_justification().m_justification.get_kind() == smt::eq_justification::kind::CONGRUENCE) { - // When the justification of an argument changes m_proof_is_logged is not reset => We need to check if the proofs of all arguments are logged. + // When the justification of an argument changes m_proof_is_logged + // is not reset => We need to check if the proofs of all arguments are logged. const unsigned num_args = it->get_num_args(); enode *target = it->get_trans_justification().m_target; @@ -128,7 +131,7 @@ namespace smt { log_justification_to_root(log, it->get_arg(i), already_visited); log_justification_to_root(log, target->get_arg(i), already_visited); } - it->m_proof_is_logged = true; + SASSERT(it->m_proof_is_logged); } } if (!root->m_proof_is_logged) { From b2123136b1f07b2d46a19b5373e8339f2efbfe68 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Mon, 26 Nov 2018 09:20:04 +0700 Subject: [PATCH 022/318] Remove unused DEFINE_VOID macro. --- src/api/z3_macros.h | 4 ---- 1 file changed, 4 deletions(-) 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 From f18227bf2ddeaa5e268233dfce373bb23da8c2e4 Mon Sep 17 00:00:00 2001 From: Nicola Mometto Date: Mon, 26 Nov 2018 17:01:09 +0000 Subject: [PATCH 023/318] Add Memory.reset to OCaml API --- src/api/ml/z3.ml | 4 ++++ src/api/ml/z3.mli | 8 ++++++++ 2 files changed, 12 insertions(+) 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..6d478c57f 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 resourced **) + val reset : unit -> unit +end From 503bedbc7a7c597a04ec3b39431b03bcdd505d21 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 26 Nov 2018 21:12:47 -0800 Subject: [PATCH 024/318] fix #1967: Signed-off-by: Nikolaj Bjorner --- src/smt/smt_quantifier.cpp | 110 ++++++++++++++++++++----------------- src/smt/theory_seq.cpp | 71 +++++++++++++----------- src/smt/theory_seq.h | 2 +- 3 files changed, 99 insertions(+), 84 deletions(-) diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index 14dc27c79..ce621144e 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -109,15 +109,14 @@ namespace smt { \brief Ensures that all relevant proof steps to explain why the enode is equal to the root of its equivalence class are in the log and up-to-date. */ - void log_justification_to_root(std::ostream & log, enode *en, obj_hashtable &already_visited) { + void log_justification_to_root(std::ostream & out, enode *en, obj_hashtable &visited) { enode* root = en->get_root(); - for (enode *it = en; it != root; it = it->get_trans_justification().m_target) { - if (already_visited.contains(it)) - break; - already_visited.insert(it); + for (enode *it = en; it != root && !visited.contains(it); it = it->get_trans_justification().m_target) { + + visited.insert(it); if (!it->m_proof_is_logged) { - log_single_justification(log, it, already_visited); + log_single_justification(out, it, visited); it->m_proof_is_logged = true; } else if (it->get_trans_justification().m_justification.get_kind() == smt::eq_justification::kind::CONGRUENCE) { @@ -128,14 +127,14 @@ namespace smt { enode *target = it->get_trans_justification().m_target; for (unsigned i = 0; i < num_args; ++i) { - log_justification_to_root(log, it->get_arg(i), already_visited); - log_justification_to_root(log, target->get_arg(i), already_visited); + log_justification_to_root(out, it->get_arg(i), visited); + log_justification_to_root(out, target->get_arg(i), visited); } SASSERT(it->m_proof_is_logged); } } if (!root->m_proof_is_logged) { - log << "[eq-expl] #" << root->get_owner_id() << " root\n"; + out << "[eq-expl] #" << root->get_owner_id() << " root\n"; root->m_proof_is_logged = true; } } @@ -144,7 +143,7 @@ namespace smt { \brief Logs a single equality explanation step and, if necessary, recursively calls log_justification_to_root to log equalities needed by the step (e.g. argument equalities for congruence steps). */ - void log_single_justification(std::ostream & out, enode *en, obj_hashtable &already_visited) { + void log_single_justification(std::ostream & out, enode *en, obj_hashtable &visited) { smt::literal lit; unsigned num_args; enode *target = en->get_trans_justification().m_target; @@ -163,8 +162,8 @@ namespace smt { num_args = en->get_num_args(); for (unsigned i = 0; i < num_args; ++i) { - log_justification_to_root(out, en->get_arg(i), already_visited); - log_justification_to_root(out, target->get_arg(i), already_visited); + log_justification_to_root(out, en->get_arg(i), visited); + log_justification_to_root(out, target->get_arg(i), visited); } out << "[eq-expl] #" << en->get_owner_id() << " cg"; @@ -193,6 +192,53 @@ namespace smt { } } + void log_add_instance( + fingerprint* f, + quantifier * q, app * pat, + unsigned num_bindings, + enode * const * bindings, + vector> & used_enodes) { + + std::ostream & out = trace_stream(); + + obj_hashtable visited; + + // In the term produced by the quantifier instantiation the root of + // the equivalence class of the terms bound to the quantified variables + // is used. We need to make sure that all of these equalities appear in the log. + for (unsigned i = 0; i < num_bindings; ++i) { + log_justification_to_root(out, bindings[i], visited); + } + + for (auto n : used_enodes) { + enode *orig = std::get<0>(n); + enode *substituted = std::get<1>(n); + if (orig != nullptr) { + log_justification_to_root(out, orig, visited); + log_justification_to_root(out, substituted, visited); + } + } + + // At this point all relevant equalities for the match are logged. + out << "[new-match] " << static_cast(f) << " #" << q->get_id() << " #" << pat->get_id(); + for (unsigned i = 0; i < num_bindings; i++) { + // I don't want to use mk_pp because it creates expressions for pretty printing. + // This nasty side-effect may change the behavior of Z3. + out << " #" << bindings[i]->get_owner_id(); + } + out << " ;"; + for (auto n : used_enodes) { + enode *orig = std::get<0>(n); + enode *substituted = std::get<1>(n); + if (orig == nullptr) + out << " #" << substituted->get_owner_id(); + else { + out << " (#" << orig->get_owner_id() << " #" << substituted->get_owner_id() << ")"; + } + } + out << "\n"; + } + bool add_instance(quantifier * q, app * pat, unsigned num_bindings, enode * const * bindings, @@ -209,43 +255,7 @@ namespace smt { fingerprint * f = m_context.add_fingerprint(q, q->get_id(), num_bindings, bindings, def); if (f) { if (has_trace_stream()) { - std::ostream & out = trace_stream(); - - obj_hashtable already_visited; - - // In the term produced by the quantifier instantiation the root of the equivalence class of the terms bound to the quantified variables - // is used. We need to make sure that all of these equalities appear in the log. - for (unsigned i = 0; i < num_bindings; ++i) { - log_justification_to_root(out, bindings[i], already_visited); - } - - for (auto n : used_enodes) { - enode *orig = std::get<0>(n); - enode *substituted = std::get<1>(n); - if (orig != nullptr) { - log_justification_to_root(out, orig, already_visited); - log_justification_to_root(out, substituted, already_visited); - } - } - - // At this point all relevant equalities for the match are logged. - out << "[new-match] " << static_cast(f) << " #" << q->get_id() << " #" << pat->get_id(); - for (unsigned i = 0; i < num_bindings; i++) { - // I don't want to use mk_pp because it creates expressions for pretty printing. - // This nasty side-effect may change the behavior of Z3. - out << " #" << bindings[i]->get_owner_id(); - } - out << " ;"; - for (auto n : used_enodes) { - enode *orig = std::get<0>(n); - enode *substituted = std::get<1>(n); - if (orig == nullptr) - out << " #" << substituted->get_owner_id(); - else { - out << " (#" << orig->get_owner_id() << " #" << substituted->get_owner_id() << ")"; - } - } - out << "\n"; + log_add_instance(f, q, pat, num_bindings, bindings, used_enodes); } m_qi_queue.insert(f, pat, max_generation, min_top_generation, max_top_generation); // TODO m_num_instances++; @@ -256,7 +266,7 @@ namespace smt { tout << mk_pp(bindings[i]->get_owner(), m()) << " "; } tout << "\n"; - tout << "inserted: " << (f != 0) << "\n"; + tout << "inserted: " << (f != nullptr) << "\n"; ); return f != nullptr; diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 5a85628e8..f3a88c5b1 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -1487,8 +1487,7 @@ bool theory_seq::enforce_length(expr_ref_vector const& es, vector & le bool all_have_length = true; rational val; zstring s; - for (unsigned i = 0; i < es.size(); ++i) { - expr* e = es[i]; + for (expr* e : es) { if (m_util.str.is_unit(e)) { len.push_back(rational(1)); } @@ -3397,6 +3396,7 @@ bool theory_seq::check_int_string() { bool theory_seq::check_int_string(expr* e) { return + get_context().inconsistent() || (m_util.str.is_itos(e) && add_itos_val_axiom(e)) || (m_util.str.is_stoi(e) && add_stoi_val_axiom(e)); } @@ -3410,9 +3410,33 @@ void theory_seq::add_stoi_axiom(expr* e) { // stoi(s) >= -1 literal l = mk_simplified_literal(m_autil.mk_ge(e, m_autil.mk_int(-1))); add_axiom(l); - + + // stoi("") = -1 + add_axiom(mk_eq(m_util.str.mk_stoi(m_util.str.mk_empty(m.get_sort(s))), m_autil.mk_int(-1), false)); } +void theory_seq::add_itos_axiom(expr* e) { + rational val; + expr* n = nullptr; + TRACE("seq", tout << mk_pp(e, m) << "\n";); + VERIFY(m_util.str.is_itos(e, n)); + + // itos(n) = "" <=> n < 0 + expr_ref zero(m_autil.mk_int(0), m); + literal eq1 = mk_literal(m_util.str.mk_is_empty(e)); + literal ge0 = mk_literal(m_autil.mk_ge(n, zero)); + // n >= 0 => itos(n) != "" + // itos(n) = "" or n >= 0 + add_axiom(~eq1, ~ge0); + add_axiom(eq1, ge0); + + // n >= 0 => stoi(itos(n)) = n + app_ref stoi(m_util.str.mk_stoi(e), m); + add_axiom(~ge0, mk_preferred_eq(stoi, n)); + +} + + void theory_seq::ensure_digit_axiom() { if (m_si_axioms.empty()) { @@ -3425,7 +3449,7 @@ void theory_seq::ensure_digit_axiom() { } bool theory_seq::add_itos_val_axiom(expr* e) { - rational val; + rational val, val2; expr* n = nullptr; TRACE("seq", tout << mk_pp(e, m) << "\n";); VERIFY(m_util.str.is_itos(e, n)); @@ -3435,11 +3459,11 @@ bool theory_seq::add_itos_val_axiom(expr* e) { } enforce_length(e); - if (get_length(e, val) && val.is_pos() && val.is_unsigned() && !m_si_axioms.contains(e)) { + if (get_length(e, val) && val.is_pos() && val.is_unsigned() && (!m_si_axioms.find(e, val2) || val != val2)) { add_si_axiom(e, n, val.get_unsigned()); - m_si_axioms.insert(e); + m_si_axioms.insert(e, val); m_trail_stack.push(push_replay(alloc(replay_is_axiom, m, e))); - m_trail_stack.push(insert_map, expr*>(m_si_axioms, e)); + m_trail_stack.push(insert_map, expr*>(m_si_axioms, e)); return true; } @@ -3449,20 +3473,21 @@ bool theory_seq::add_itos_val_axiom(expr* e) { bool theory_seq::add_stoi_val_axiom(expr* e) { context& ctx = get_context(); expr* n = nullptr; - rational val; - TRACE("seq", tout << mk_pp(e, m) << " " << ctx.get_scope_level () << "\n";); + rational val, val2; VERIFY(m_util.str.is_stoi(e, n)); + TRACE("seq", tout << mk_pp(e, m) << " " << ctx.get_scope_level () << " " << get_length(n, val) << " " << val << "\n";); + if (m_util.str.is_itos(n)) { return false; } enforce_length(n); - if (get_length(n, val) && val.is_pos() && val.is_unsigned() && !m_si_axioms.contains(e)) { + if (get_length(n, val) && val.is_pos() && val.is_unsigned() && (!m_si_axioms.find(e, val2) || val2 != val)) { add_si_axiom(n, e, val.get_unsigned()); - m_si_axioms.insert(e); + m_si_axioms.insert(e, val); m_trail_stack.push(push_replay(alloc(replay_is_axiom, m, e))); - m_trail_stack.push(insert_map, expr*>(m_si_axioms, e)); + m_trail_stack.push(insert_map, expr*>(m_si_axioms, e)); return true; } @@ -3487,26 +3512,6 @@ expr_ref theory_seq::digit2int(expr* ch) { return expr_ref(mk_skolem(symbol("seq.digit2int"), ch, nullptr, nullptr, nullptr, m_autil.mk_int()), m); } -void theory_seq::add_itos_axiom(expr* e) { - rational val; - expr* n = nullptr; - TRACE("seq", tout << mk_pp(e, m) << "\n";); - VERIFY(m_util.str.is_itos(e, n)); - - // itos(n) = "" <=> n < 0 - expr_ref zero(arith_util(m).mk_int(0), m); - literal eq1 = mk_literal(m_util.str.mk_is_empty(e)); - literal ge0 = mk_literal(m_autil.mk_ge(n, zero)); - // n >= 0 => itos(n) != "" - // itos(n) = "" or n >= 0 - add_axiom(~eq1, ~ge0); - add_axiom(eq1, ge0); - - // n >= 0 => stoi(itos(n)) = n - app_ref stoi(m_util.str.mk_stoi(e), m); - add_axiom(~ge0, mk_preferred_eq(stoi, n)); - -} // n >= 0 & len(e) = k => is_digit(e_i) for i = 0..k-1 @@ -3550,7 +3555,7 @@ void theory_seq::add_si_axiom(expr* e, expr* n, unsigned k) { SASSERT(k > 0); rational lb = power(rational(10), k - 1); rational ub = power(rational(10), k) - 1; - arith_util a (m); + arith_util& a = m_autil; literal lbl = mk_literal(a.mk_ge(n, a.mk_int(lb))); literal ubl = mk_literal(a.mk_le(n, a.mk_int(ub))); literal ge_k = mk_literal(a.mk_ge(len, a.mk_int(k))); diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index aa278e972..75ba54381 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -343,7 +343,7 @@ namespace smt { unsigned m_axioms_head; // index of first axiom to add. bool m_incomplete; // is the solver (clearly) incomplete for the fragment. expr_ref_vector m_int_string; - obj_hashtable m_si_axioms; + obj_map m_si_axioms; obj_hashtable m_length; // is length applied scoped_ptr_vector m_replay; // set of actions to replay model_generator* m_mg; From 29a28f544df0e71c82de58dec0d5f9f110a46bfc Mon Sep 17 00:00:00 2001 From: Nicola Mometto Date: Tue, 27 Nov 2018 12:15:33 +0000 Subject: [PATCH 025/318] catch and print exceptions in Z3_mk_config instead of letting them bubble up the stack --- src/api/api_config_params.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) 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) { From 21158d87e30a7c6683d8505254e4d10f53361a50 Mon Sep 17 00:00:00 2001 From: Nicola Mometto Date: Tue, 27 Nov 2018 12:15:57 +0000 Subject: [PATCH 026/318] override n_mk_config in ml bindings to catch exception path --- scripts/update_api.py | 8 ++++++++ src/api/ml/z3native_stubs.c.pre | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/scripts/update_api.py b/scripts/update_api.py index 901ea4fda..65791399c 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -1335,6 +1335,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 +1350,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) diff --git a/src/api/ml/z3native_stubs.c.pre b/src/api/ml/z3native_stubs.c.pre index 71ee18ce9..4d221aac3 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"), "internal error"); + } + + /* 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); +} From e5709406622434cd2371d1e2ba108d6cb2ab647b Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 27 Nov 2018 21:42:04 +0700 Subject: [PATCH 027/318] Prefer using empty rather than size comparisons. --- src/api/api_model.cpp | 2 +- src/ast/ast_smt_pp.cpp | 6 ++-- src/ast/expr2polynomial.cpp | 4 +-- src/ast/proofs/proof_utils.cpp | 2 +- src/cmd_context/basic_cmds.cpp | 2 +- src/cmd_context/cmd_context.cpp | 2 +- src/cmd_context/tactic_cmds.cpp | 2 +- src/math/polynomial/polynomial.cpp | 2 +- src/math/polynomial/upolynomial.cpp | 2 +- .../polynomial/upolynomial_factorization.cpp | 2 +- .../upolynomial_factorization_int.h | 2 +- src/math/realclosure/realclosure.cpp | 4 +-- src/model/model.cpp | 2 +- src/muz/base/dl_rule_set.h | 2 +- src/muz/bmc/dl_bmc_engine.cpp | 2 +- src/muz/fp/datalog_parser.cpp | 2 +- src/muz/rel/dl_finite_product_relation.cpp | 2 +- src/muz/rel/dl_sieve_relation.h | 2 +- src/muz/rel/dl_sparse_table.cpp | 2 +- src/muz/rel/dl_sparse_table.h | 2 +- src/muz/spacer/spacer_context.cpp | 2 +- src/muz/spacer/spacer_iuc_solver.cpp | 2 +- .../transforms/dl_mk_array_instantiation.cpp | 2 +- src/opt/opt_context.cpp | 2 +- src/qe/nlarith_util.cpp | 4 +-- src/qe/qe_arith.cpp | 2 +- src/smt/proto_model/array_factory.cpp | 2 +- src/smt/smt_case_split_queue.cpp | 2 +- src/smt/theory_arith_aux.h | 4 +-- src/smt/theory_array_full.cpp | 2 +- src/smt/theory_recfun.h | 2 +- src/smt/theory_seq.cpp | 10 +++---- src/smt/theory_str.cpp | 24 ++++++++-------- src/smt/theory_utvpi_def.h | 2 +- src/solver/tactic2solver.cpp | 2 +- src/tactic/bv/bv_bound_chk_tactic.cpp | 2 +- src/tactic/sls/sls_engine.cpp | 2 +- src/tactic/sls/sls_tracker.h | 2 +- src/tactic/tactic.cpp | 2 +- src/test/bit_vector.cpp | 4 +-- src/test/chashtable.cpp | 2 +- src/test/lp/argument_parser.h | 10 +++---- src/test/lp/lp.cpp | 28 +++++++++---------- src/test/lp/smt_reader.h | 8 +++--- src/test/vector.cpp | 2 +- src/util/lp/core_solver_pretty_printer_def.h | 4 +-- src/util/lp/eta_matrix_def.h | 2 +- src/util/lp/general_matrix.h | 2 +- src/util/lp/lar_term.h | 2 +- src/util/lp/lp_dual_core_solver_def.h | 4 +-- src/util/lp/lp_primal_core_solver_def.h | 4 +-- src/util/lp/lp_solver_def.h | 4 +-- src/util/lp/matrix_def.h | 2 +- src/util/lp/mps_reader.h | 4 +-- src/util/lp/square_sparse_matrix_def.h | 4 +-- src/util/mpn.cpp | 2 +- 56 files changed, 104 insertions(+), 104 deletions(-) diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index c7347f299..664022f2e 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -472,7 +472,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/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/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/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/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index ea5994ece..981698db7 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)) { diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index fb81c673e..8675365c9 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -2108,7 +2108,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/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/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..5a7ed0dc1 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]); diff --git a/src/math/polynomial/upolynomial_factorization.cpp b/src/math/polynomial/upolynomial_factorization.cpp index 5d9d3f1f1..57106e22d 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; 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..0bc3b43d3 100644 --- a/src/math/realclosure/realclosure.cpp +++ b/src/math/realclosure/realclosure.cpp @@ -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/model/model.cpp b/src/model/model.cpp index 2efc39db8..86ff64ea3 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; 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..cc0a60335 100644 --- a/src/muz/fp/datalog_parser.cpp +++ b/src/muz/fp/datalog_parser.cpp @@ -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_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_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..32f33f773 100644 --- a/src/muz/spacer/spacer_iuc_solver.cpp +++ b/src/muz/spacer/spacer_iuc_solver.cpp @@ -72,7 +72,7 @@ app* iuc_solver::mk_proxy (expr *v) if (is_uninterp_const(e)) { return to_app(v); } } - def_manager &def = m_defs.size () > 0 ? m_defs.back () : m_base_defs; + def_manager &def = !m_defs.empty() ? m_defs.back () : m_base_defs; return def.mk_proxy (v); } 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/opt/opt_context.cpp b/src/opt/opt_context.cpp index a6f3d8152..d418bd437 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -481,7 +481,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; 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_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/smt/proto_model/array_factory.cpp b/src/smt/proto_model/array_factory.cpp index dc3e0f89c..141021006 100644 --- a/src/smt/proto_model/array_factory.cpp +++ b/src/smt/proto_model/array_factory.cpp @@ -104,7 +104,7 @@ bool array_factory::mk_two_diff_values_for(sort * s) { bool array_factory::get_some_values(sort * s, expr_ref & v1, expr_ref & v2) { value_set * set = nullptr; - if (!m_sort2value_set.find(s, set) || set->size() == 0) { + if (!m_sort2value_set.find(s, set) || set->empty()) { if (!mk_two_diff_values_for(s)) return false; } diff --git a/src/smt/smt_case_split_queue.cpp b/src/smt/smt_case_split_queue.cpp index 5c51b906f..6290ed14d 100644 --- a/src/smt/smt_case_split_queue.cpp +++ b/src/smt/smt_case_split_queue.cpp @@ -281,7 +281,7 @@ namespace smt { } } if (order == 1) { - if (undef_children.size() == 0) { + if (undef_children.empty()) { // a bug? } else if (undef_children.size() == 1) { undef_child = undef_children[0]; diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index f70e50ece..ae0286c59 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -548,7 +548,7 @@ namespace smt { if (!it->is_dead()) { row const & r = m_rows[it->m_row_id]; theory_var s = r.get_base_var(); - if (is_quasi_base(s) && m_var_occs[s].size() == 0) + if (is_quasi_base(s) && m_var_occs[s].empty()) continue; if (is_int(v)) { numeral const & c = r[it->m_row_idx].m_coeff; @@ -574,7 +574,7 @@ namespace smt { TRACE("move_unconstrained_to_base", tout << "before...\n"; display(tout);); int num = get_num_vars(); for (theory_var v = 0; v < num; v++) { - if (m_var_occs[v].size() == 0 && is_free(v)) { + if (m_var_occs[v].empty() && is_free(v)) { switch (get_var_kind(v)) { case QUASI_BASE: break; diff --git a/src/smt/theory_array_full.cpp b/src/smt/theory_array_full.cpp index 4e1de7b90..3e474df81 100644 --- a/src/smt/theory_array_full.cpp +++ b/src/smt/theory_array_full.cpp @@ -141,7 +141,7 @@ namespace smt { } void theory_array_full::set_prop_upward(theory_var v, var_data* d) { - if (m_params.m_array_always_prop_upward || d->m_stores.size() >= 1) { + if (m_params.m_array_always_prop_upward || !d->m_stores.empty()) { theory_array::set_prop_upward(v, d); } else { diff --git a/src/smt/theory_recfun.h b/src/smt/theory_recfun.h index 46392c6d2..95b20eb4b 100644 --- a/src/smt/theory_recfun.h +++ b/src/smt/theory_recfun.h @@ -125,7 +125,7 @@ namespace smt { literal mk_eq_lit(expr* l, expr* r); bool is_standard_order(recfun::vars const& vars) const { - return vars.size() == 0 || vars[vars.size()-1]->get_idx() == 0; + return vars.empty() || vars[vars.size()-1]->get_idx() == 0; } protected: void push_case_expand(case_expansion* e) { m_q_case_expand.push_back(e); } diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 5a85628e8..947eb44ad 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -3570,18 +3570,18 @@ void theory_seq::apply_sort_cnstr(enode* n, sort* s) { } void theory_seq::display(std::ostream & out) const { - if (m_eqs.size() == 0 && - m_nqs.size() == 0 && + if (m_eqs.empty() && + m_nqs.empty() && m_rep.empty() && m_exclude.empty()) { return; } out << "Theory seq\n"; - if (m_eqs.size() > 0) { + if (!m_eqs.empty()) { out << "Equations:\n"; display_equations(out); } - if (m_nqs.size() > 0) { + if (!m_nqs.empty()) { display_disequations(out); } if (!m_re2aut.empty()) { @@ -3655,7 +3655,7 @@ std::ostream& theory_seq::display_disequation(std::ostream& out, ne const& e) co for (literal lit : e.lits()) { out << lit << " "; } - if (e.lits().size() > 0) { + if (!e.lits().empty()) { out << "\n"; } for (unsigned j = 0; j < e.ls().size(); ++j) { diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index f0e11c248..3ee780366 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -2501,7 +2501,7 @@ namespace smt { } } - if (resolvedMap.size() == 0) { + if (resolvedMap.empty()) { // no simplification possible return node; } else { @@ -5452,7 +5452,7 @@ namespace smt { } if (implyR) { - if (litems1.size() == 0) { + if (litems1.empty()) { assert_axiom(implyR); } else { assert_implication(mk_and(litems1), implyR); @@ -7020,7 +7020,7 @@ namespace smt { bool theory_str::refine_automaton_lower_bound(eautomaton * aut, rational current_lower_bound, rational & refined_lower_bound) { ENSURE(aut != nullptr); - if (aut->final_states().size() < 1) { + if (aut->final_states().empty()) { // no solutions at all refined_lower_bound = rational::minus_one(); return false; @@ -8168,13 +8168,13 @@ namespace smt { // step 2: Concat == Constant - if (eqc_const_lhs.size() != 0) { + if (!eqc_const_lhs.empty()) { expr * conStr = *(eqc_const_lhs.begin()); std::set::iterator itor2 = eqc_concat_rhs.begin(); for (; itor2 != eqc_concat_rhs.end(); itor2++) { solve_concat_eq_str(*itor2, conStr); } - } else if (eqc_const_rhs.size() != 0) { + } else if (!eqc_const_rhs.empty()) { expr* conStr = *(eqc_const_rhs.begin()); std::set::iterator itor1 = eqc_concat_lhs.begin(); for (; itor1 != eqc_concat_lhs.end(); itor1++) { @@ -8250,7 +8250,7 @@ namespace smt { ast_manager & m = get_manager(); int hasCommon = 0; - if (eqc_concat_lhs.size() != 0 && eqc_concat_rhs.size() != 0) { + if (!eqc_concat_lhs.empty() && !eqc_concat_rhs.empty()) { std::set::iterator itor1 = eqc_concat_lhs.begin(); std::set::iterator itor2 = eqc_concat_rhs.begin(); for (; itor1 != eqc_concat_lhs.end(); itor1++) { @@ -8570,13 +8570,13 @@ namespace smt { obj_map >::iterator varItor = cut_var_map.begin(); while (varItor != cut_var_map.end()) { std::stack & val = cut_var_map[varItor->m_key]; - while ((val.size() > 0) && (val.top()->level != 0) && (val.top()->level >= sLevel)) { + while ((!val.empty()) && (val.top()->level != 0) && (val.top()->level >= sLevel)) { // TRACE("str", tout << "remove cut info for " << mk_pp(e, get_manager()) << std::endl; print_cut_var(e, tout);); // T_cut * aCut = val.top(); val.pop(); // dealloc(aCut); } - if (val.size() == 0) { + if (val.empty()) { cutvarmap_removes.insert(varItor->m_key); } varItor++; @@ -9402,7 +9402,7 @@ namespace smt { } } - if (depMap.size() == 0) { + if (depMap.empty()) { std::map::iterator itor = strVarMap.begin(); for (; itor != strVarMap.end(); itor++) { expr * var = get_alias_index_ast(aliasIndexMap, itor->first); @@ -10801,7 +10801,7 @@ namespace smt { expr * var = fvIt2->first; tmpSet.clear(); get_eqc_allUnroll(var, constValue, tmpSet); - if (tmpSet.size() > 0) { + if (!tmpSet.empty()) { fv_unrolls_map[var] = tmpSet; } } @@ -10935,7 +10935,7 @@ namespace smt { expr * var = fvIt1->first; fSimpUnroll.clear(); get_eqc_simpleUnroll(var, constValue, fSimpUnroll); - if (fSimpUnroll.size() == 0) { + if (fSimpUnroll.empty()) { gen_assign_unroll_reg(fv_unrolls_map[var]); } else { expr * toAssert = gen_assign_unroll_Str2Reg(var, fSimpUnroll); @@ -11548,7 +11548,7 @@ namespace smt { unroll_tries_map[var][unrolls].erase(e); } - if (unroll_tries_map[var][unrolls].size() == 0) { + if (unroll_tries_map[var][unrolls].empty()) { unroll_tries_map[var][unrolls].push_back(mk_unroll_test_var()); } diff --git a/src/smt/theory_utvpi_def.h b/src/smt/theory_utvpi_def.h index b051c504a..fba549412 100644 --- a/src/smt/theory_utvpi_def.h +++ b/src/smt/theory_utvpi_def.h @@ -618,7 +618,7 @@ namespace smt { th_var v1 = null_theory_var, v2 = null_theory_var; bool pos1 = true, pos2 = true; - if (terms.size() >= 1) { + if (!terms.empty()) { v1 = terms[0].first; pos1 = terms[0].second.is_one(); SASSERT(v1 != null_theory_var); diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 3a905bafd..492ddd443 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -170,7 +170,7 @@ lbool tactic2solver::check_sat_core(unsigned num_assumptions, expr * const * ass break; default: m_result->set_status(l_undef); - if (reason_unknown != "") + if (!reason_unknown.empty()) m_result->m_unknown = reason_unknown; if (num_assumptions == 0 && m_scopes.empty()) { m_assertions.reset(); diff --git a/src/tactic/bv/bv_bound_chk_tactic.cpp b/src/tactic/bv/bv_bound_chk_tactic.cpp index 75b772720..cf35afef4 100644 --- a/src/tactic/bv/bv_bound_chk_tactic.cpp +++ b/src/tactic/bv/bv_bound_chk_tactic.cpp @@ -74,7 +74,7 @@ struct bv_bound_chk_rewriter_cfg : public default_rewriter_cfg { bv_bounds bvb(m()); const br_status rv = bvb.rewrite(m_bv_ineq_consistency_test_max, f, num, args, result); if (rv != BR_FAILED && (m_m.is_false(result) || m_m.is_true(result))) m_stats.m_unsats++; - else if (rv != BR_FAILED && bvb.singletons().size()) m_stats.m_singletons++; + else if (rv != BR_FAILED && !bvb.singletons().empty()) m_stats.m_singletons++; else if (rv != BR_FAILED && is_app(result) && to_app(result)->get_num_args() < num) m_stats.m_reduces++; return rv; } diff --git a/src/tactic/sls/sls_engine.cpp b/src/tactic/sls/sls_engine.cpp index 1285e46cf..2aeb355ed 100644 --- a/src/tactic/sls/sls_engine.cpp +++ b/src/tactic/sls/sls_engine.cpp @@ -440,7 +440,7 @@ lbool sls_engine::search() { // get candidate variables ptr_vector & to_evaluate = m_tracker.get_unsat_constants(m_assertions); - if (!to_evaluate.size()) + if (to_evaluate.empty()) { res = l_true; goto bailout; diff --git a/src/tactic/sls/sls_tracker.h b/src/tactic/sls/sls_tracker.h index b730e78da..e10c91729 100644 --- a/src/tactic/sls/sls_tracker.h +++ b/src/tactic/sls/sls_tracker.h @@ -1003,7 +1003,7 @@ public: } ptr_vector & get_unsat_constants_walksat(expr * e) { - if (!e || m_temp_constants.size()) + if (!e || !m_temp_constants.empty()) return m_temp_constants; ptr_vector const & this_decls = m_constants_occ.find(e); unsigned sz = this_decls.size(); diff --git a/src/tactic/tactic.cpp b/src/tactic/tactic.cpp index 3b3c2444f..4a51c701a 100644 --- a/src/tactic/tactic.cpp +++ b/src/tactic/tactic.cpp @@ -191,7 +191,7 @@ lbool check_sat(tactic & t, goal_ref & g, model_ref & md, labels_vec & labels, p return l_false; } else { - if (models_enabled && r.size() >= 1) { + if (models_enabled && !r.empty()) { model_converter_ref mc = r[0]->mc(); model_converter2model(m, mc.get(), md); if (mc) diff --git a/src/test/bit_vector.cpp b/src/test/bit_vector.cpp index 487f6cdd0..db6270b35 100644 --- a/src/test/bit_vector.cpp +++ b/src/test/bit_vector.cpp @@ -35,7 +35,7 @@ static void tst1() { } else if (op <= 3) { ENSURE(v1.size() == v2.size()); - if (v1.size() > 0) { + if (!v1.empty()) { bool val = (rand()%2) != 0; unsigned idx = rand()%v1.size(); ENSURE(v1.get(idx) == v2[idx]); @@ -46,7 +46,7 @@ static void tst1() { } else if (op <= 4) { ENSURE(v1.size() == v2.size()); - if (v1.size() > 0) { + if (!v1.empty()) { unsigned idx = rand()%v1.size(); VERIFY(v1.get(idx) == v2[idx]); } diff --git a/src/test/chashtable.cpp b/src/test/chashtable.cpp index 0ccf2c177..8e4dadf99 100644 --- a/src/test/chashtable.cpp +++ b/src/test/chashtable.cpp @@ -102,7 +102,7 @@ static void tst3() { ENSURE(t.contains(12)); t.erase(12); t.erase(10); - ENSURE(t.size() == 0); + ENSURE(t.empty()); ENSURE(t.empty()); ENSURE(t.used_slots() == 0); t.insert(10); diff --git a/src/test/lp/argument_parser.h b/src/test/lp/argument_parser.h index ce59632d2..f2a74f122 100644 --- a/src/test/lp/argument_parser.h +++ b/src/test/lp/argument_parser.h @@ -117,7 +117,7 @@ public: unknown_options.push_back(t); } } - if (unknown_options.size()) { + if (!unknown_options.empty()) { ret = "Unknown options:"; } for (const auto & unknownOption : unknown_options) { @@ -127,15 +127,15 @@ public: ret += "\n"; ret += "Usage:\n"; for (auto allowed_option : m_options) - ret += allowed_option.first + " " + (allowed_option.second.size() == 0 ? std::string("") : std::string("/") + allowed_option.second) + std::string("\n"); + ret += allowed_option.first + " " + (allowed_option.second.empty() ? std::string("") : std::string("/") + allowed_option.second) + std::string("\n"); for (auto s : m_options_with_after_string) { - ret += s.first + " " + (s.second.size() == 0? " \"option value\"":("\""+ s.second+"\"")) + "\n"; + ret += s.first + " " + (s.second.empty()? " \"option value\"":("\""+ s.second+"\"")) + "\n"; } return ret; } void print() { - if (m_used_options.size() == 0 && m_used_options_with_after_string.size() == 0 && m_free_args.size() == 0) { + if (m_used_options.empty() && m_used_options_with_after_string.empty() && m_free_args.empty()) { std::cout << "no options are given" << std::endl; return; } @@ -146,7 +146,7 @@ public: for (auto & t : m_used_options_with_after_string) { std::cout << t.first << " " << t.second << std::endl; } - if (m_free_args.size() > 0) { + if (!m_free_args.empty()) { std::cout << "free arguments are: " << std::endl; for (auto & t : m_free_args) { std::cout << t << " " << std::endl; diff --git a/src/test/lp/lp.cpp b/src/test/lp/lp.cpp index 192bd46b0..f43aff668 100644 --- a/src/test/lp/lp.cpp +++ b/src/test/lp/lp.cpp @@ -1091,7 +1091,7 @@ void lp_solver_test() { bool get_int_from_args_parser(const char * option, argument_parser & args_parser, unsigned & n) { std::string s = args_parser.get_option_value(option); - if (s.size() > 0) { + if (!s.empty()) { n = atoi(s.c_str()); return true; } @@ -1100,7 +1100,7 @@ bool get_int_from_args_parser(const char * option, argument_parser & args_parser bool get_double_from_args_parser(const char * option, argument_parser & args_parser, double & n) { std::string s = args_parser.get_option_value(option); - if (s.size() > 0) { + if (!s.empty()) { n = atof(s.c_str()); return true; } @@ -1830,7 +1830,7 @@ std::unordered_map * get_solution_from_glpsol_output(std::s return nullptr; } auto split = string_split(s, " \t", false); - if (split.size() == 0) { + if (split.empty()) { return ret; } @@ -2050,14 +2050,14 @@ void finalize(unsigned ret) { void get_time_limit_and_max_iters_from_parser(argument_parser & args_parser, unsigned & time_limit, unsigned & max_iters) { std::string s = args_parser.get_option_value("--max_iters"); - if (s.size() > 0) { + if (!s.empty()) { max_iters = atoi(s.c_str()); } else { max_iters = 0; } std::string time_limit_string = args_parser.get_option_value("--time_limit"); - if (time_limit_string.size() > 0) { + if (!time_limit_string.empty()) { time_limit = atoi(time_limit_string.c_str()); } else { time_limit = 0; @@ -2156,7 +2156,7 @@ double get_lp_tst_cost(std::string file_name) { cost_string = str; } } - if (cost_string.size() == 0) { + if (cost_string.empty()) { std::cout << "cannot find the cost line in " << file_name << std::endl; throw 0; } @@ -2377,7 +2377,7 @@ std::unordered_map get_solution_map(lp_solver * reader) { std::string maxng = args_parser.get_option_value("--maxng"); - if (maxng.size() > 0) { + if (!maxng.empty()) { solver->settings().max_number_of_iterations_with_no_improvements = atoi(maxng.c_str()); } if (args_parser.option_is_used("-pd")){ @@ -2385,7 +2385,7 @@ void run_lar_solver(argument_parser & args_parser, lar_solver * solver, mps_read } std::string iter = args_parser.get_option_value("--max_iters"); - if (iter.size() > 0) { + if (!iter.empty()) { solver->settings().max_total_number_of_iterations = atoi(iter.c_str()); } if (args_parser.option_is_used("--compare_with_primal")){ @@ -2470,7 +2470,7 @@ vector get_file_names_from_file_list(std::string filelist) { std::string s = read_line(end, file); if (end) break; - if (s.size() == 0) + if (s.empty()) break; ret.push_back(s); } while (true); @@ -2480,13 +2480,13 @@ vector get_file_names_from_file_list(std::string filelist) { void test_lar_solver(argument_parser & args_parser) { std::string file_name = args_parser.get_option_value("--file"); - if (file_name.size() > 0) { + if (!file_name.empty()) { test_lar_on_file(file_name, args_parser); return; } std::string file_list = args_parser.get_option_value("--filelist"); - if (file_list.size() > 0) { + if (!file_list.empty()) { for (const std::string & fn : get_file_names_from_file_list(file_list)) test_lar_on_file(fn, args_parser); return; @@ -3600,7 +3600,7 @@ void test_lp_local(int argn, char**argv) { std::string lufile = args_parser.get_option_value("--checklu"); - if (lufile.size()) { + if (!lufile.empty()) { check_lu_from_file(lufile); return finalize(0); } @@ -3623,7 +3623,7 @@ void test_lp_local(int argn, char**argv) { return finalize(0); } std::string file_list = args_parser.get_option_value("--filelist"); - if (file_list.size() > 0) { + if (!file_list.empty()) { for (const std::string & fn : get_file_names_from_file_list(file_list)) solve_mps(fn, args_parser); return finalize(0); @@ -3704,7 +3704,7 @@ void test_lp_local(int argn, char**argv) { bool dual = args_parser.option_is_used("--dual"); bool solve_for_rational = args_parser.option_is_used("--mpq"); std::string file_name = args_parser.get_option_value("--file"); - if (file_name.size() > 0) { + if (!file_name.empty()) { solve_mps(file_name, args_parser.option_is_used("--min"), max_iters, time_limit, solve_for_rational, dual, args_parser.option_is_used("--compare_with_primal"), args_parser); ret = 0; return finalize(ret); diff --git a/src/test/lp/smt_reader.h b/src/test/lp/smt_reader.h index 16f44e3b3..5d386862c 100644 --- a/src/test/lp/smt_reader.h +++ b/src/test/lp/smt_reader.h @@ -52,7 +52,7 @@ namespace lp { std::string m_head; std::vector m_elems; void print() { - if (m_elems.size()) { + if (!m_elems.empty()) { std::cout << '('; std::cout << m_head << ' '; for (auto & el : m_elems) @@ -133,7 +133,7 @@ namespace lp { lm.m_head = m_line.substr(0, separator); m_line = m_line.substr(lm.m_head.size()); eat_blanks(); - while (m_line.size()) { + while (!m_line.empty()) { if (m_line[0] == '(') { lisp_elem el; fill_nested_elem(el); @@ -152,7 +152,7 @@ namespace lp { } void eat_blanks() { - while (m_line.size()) { + while (!m_line.empty()) { if (m_line[0] == ' ') m_line = m_line.substr(1); else @@ -205,7 +205,7 @@ namespace lp { bool is_integer(std::string & s) { - if (s.size() == 0) return false; + if (s.empty()) return false; return atoi(s.c_str()) != 0 || isdigit(s.c_str()[0]); } diff --git a/src/test/vector.cpp b/src/test/vector.cpp index 4632a9c29..c9a93dee4 100644 --- a/src/test/vector.cpp +++ b/src/test/vector.cpp @@ -41,7 +41,7 @@ static void tst1() { v1.pop_back(); } ENSURE(v1.empty()); - ENSURE(v1.size() == 0); + ENSURE(v1.empty()); unsigned i = 1000000000; while (true) { std::cout << "resize " << i << "\n"; diff --git a/src/util/lp/core_solver_pretty_printer_def.h b/src/util/lp/core_solver_pretty_printer_def.h index dcf3e0a11..5453c6085 100644 --- a/src/util/lp/core_solver_pretty_printer_def.h +++ b/src/util/lp/core_solver_pretty_printer_def.h @@ -183,7 +183,7 @@ template unsigned core_solver_pretty_printer:: ge } if (!m_core_solver.use_tableau()) { w = std::max(w, (unsigned)T_to_string(m_exact_column_norms[column]).size()); - if (m_core_solver.m_column_norms.size() > 0) + if (!m_core_solver.m_column_norms.empty()) w = std::max(w, (unsigned)T_to_string(m_core_solver.m_column_norms[column]).size()); } return w; @@ -339,7 +339,7 @@ template void core_solver_pretty_printer::print() print_lows(); print_upps(); print_exact_norms(); - if (m_core_solver.m_column_norms.size() > 0) + if (!m_core_solver.m_column_norms.empty()) print_approx_norms(); m_out << std::endl; } diff --git a/src/util/lp/eta_matrix_def.h b/src/util/lp/eta_matrix_def.h index 5c7661e24..774cc89dc 100644 --- a/src/util/lp/eta_matrix_def.h +++ b/src/util/lp/eta_matrix_def.h @@ -81,7 +81,7 @@ void eta_matrix::apply_from_right(vector & w) { } template void eta_matrix::apply_from_right(indexed_vector & w) { - if (w.m_index.size() == 0) + if (w.m_index.empty()) return; #ifdef Z3DEBUG // vector wcopy(w.m_data); diff --git a/src/util/lp/general_matrix.h b/src/util/lp/general_matrix.h index 1c643161a..f6f93c705 100644 --- a/src/util/lp/general_matrix.h +++ b/src/util/lp/general_matrix.h @@ -51,7 +51,7 @@ public: unsigned row_count() const { return m_data.size(); } - unsigned column_count() const { return m_data.size() > 0? m_data[0].size() : 0; } + unsigned column_count() const { return !m_data.empty()? m_data[0].size() : 0; } class ref_row { general_matrix& m_matrix; diff --git a/src/util/lp/lar_term.h b/src/util/lp/lar_term.h index e9259b8c0..64243f4e2 100644 --- a/src/util/lp/lar_term.h +++ b/src/util/lp/lar_term.h @@ -37,7 +37,7 @@ struct lar_term { } bool is_empty() const { - return m_coeffs.size() == 0; // && is_zero(m_v); + return m_coeffs.empty(); // && is_zero(m_v); } unsigned size() const { return static_cast(m_coeffs.size()); } diff --git a/src/util/lp/lp_dual_core_solver_def.h b/src/util/lp/lp_dual_core_solver_def.h index e7ab73928..984f2e560 100644 --- a/src/util/lp/lp_dual_core_solver_def.h +++ b/src/util/lp/lp_dual_core_solver_def.h @@ -665,7 +665,7 @@ template bool lp_dual_core_solver::ratio_test() { m_flipped_boxed.clear(); int initial_delta_sign = m_delta >= numeric_traits::zero()? 1: -1; do { - if (m_breakpoint_set.size() == 0) { + if (m_breakpoint_set.empty()) { set_status_to_tentative_dual_unbounded_or_dual_unbounded(); return false; } @@ -697,7 +697,7 @@ template void lp_dual_core_solver::update_d_and_x this->m_d[j] -= m_theta_D * this->m_pivot_row[j]; } this->m_d[m_p] = - m_theta_D; - if (m_flipped_boxed.size() > 0) { + if (!m_flipped_boxed.empty()) { process_flipped(); update_xb_after_bound_flips(); } diff --git a/src/util/lp/lp_primal_core_solver_def.h b/src/util/lp/lp_primal_core_solver_def.h index d86ebf548..a43764172 100644 --- a/src/util/lp/lp_primal_core_solver_def.h +++ b/src/util/lp/lp_primal_core_solver_def.h @@ -504,7 +504,7 @@ lp_primal_core_solver::get_bound_on_variable_and_update_leaving_precisely( X tt = - (this->m_lower_bounds[j] - this->m_x[j]) / m; if (numeric_traits::is_neg(tt)) tt = zero_of_type(); - if (leavings.size() == 0 || tt < t || (tt == t && m > abs_of_d_of_leaving)) { + if (leavings.empty() || tt < t || (tt == t && m > abs_of_d_of_leaving)) { t = tt; abs_of_d_of_leaving = m; leavings.clear(); @@ -524,7 +524,7 @@ lp_primal_core_solver::get_bound_on_variable_and_update_leaving_precisely( X tt = (this->m_upper_bounds[j] - this->m_x[j]) / m; if (numeric_traits::is_neg(tt)) tt = zero_of_type(); - if (leavings.size() == 0 || tt < t || (tt == t && - m > abs_of_d_of_leaving)) { + if (leavings.empty() || tt < t || (tt == t && - m > abs_of_d_of_leaving)) { t = tt; abs_of_d_of_leaving = - m; leavings.clear(); diff --git a/src/util/lp/lp_solver_def.h b/src/util/lp/lp_solver_def.h index 9b385dee6..21a86efba 100644 --- a/src/util/lp/lp_solver_def.h +++ b/src/util/lp/lp_solver_def.h @@ -103,7 +103,7 @@ template void lp_solver::flip_costs() { template bool lp_solver::problem_is_empty() { for (auto & c : m_A_values) - if (c.second.size()) + if (!c.second.empty()) return false; return true; } @@ -387,7 +387,7 @@ template unsigned lp_solver::try_to_remove_some_r return 0; } } - if (rows_to_delete.size() > 0) { + if (!rows_to_delete.empty()) { for (unsigned k : rows_to_delete) { m_A_values.erase(k); } diff --git a/src/util/lp/matrix_def.h b/src/util/lp/matrix_def.h index 361540cae..b74e59443 100644 --- a/src/util/lp/matrix_def.h +++ b/src/util/lp/matrix_def.h @@ -97,7 +97,7 @@ void print_matrix_with_widths(vector> & A, vector void print_string_matrix(vector> & A, std::ostream & out, unsigned blanks_in_front) { vector widths; - if (A.size() > 0) + if (!A.empty()) for (unsigned j = 0; j < A[0].size(); j++) { widths.push_back(get_width_of_column(j, A)); } diff --git a/src/util/lp/mps_reader.h b/src/util/lp/mps_reader.h index 09762cd5e..2ef07af6e 100644 --- a/src/util/lp/mps_reader.h +++ b/src/util/lp/mps_reader.h @@ -220,7 +220,7 @@ class mps_reader { *m_message_stream << "cannot read from file" << std::endl; } m_line_number++; - if (m_line.size() != 0 && m_line[0] != '*' && !all_white_space()) + if (!m_line.empty() && m_line[0] != '*' && !all_white_space()) break; } } @@ -514,7 +514,7 @@ class mps_reader { lp_assert(m_line.size() >= 14); vector bound_string = split_and_trim(m_line.substr(name_offset, m_line.size())); - if (bound_string.size() == 0) { + if (bound_string.empty()) { set_m_ok_to_false(); (*m_message_stream) << "error at line " << m_line_number << std::endl; throw m_line; diff --git a/src/util/lp/square_sparse_matrix_def.h b/src/util/lp/square_sparse_matrix_def.h index cc6625453..2fc101666 100644 --- a/src/util/lp/square_sparse_matrix_def.h +++ b/src/util/lp/square_sparse_matrix_def.h @@ -248,7 +248,7 @@ void square_sparse_matrix::put_max_index_to_0(vector> & r template void square_sparse_matrix::set_max_in_row(vector> & row_vals) { - if (row_vals.size() == 0) + if (row_vals.empty()) return; T max_val = abs(row_vals[0].m_value); unsigned max_index = 0; @@ -386,7 +386,7 @@ bool square_sparse_matrix::set_row_from_work_vector_and_clean_work_vector_ } work_vec.m_index.clear(); auto & row_vals = m_rows[i0]; - if (row_vals.size() == 0) { + if (row_vals.empty()) { return false; } set_max_in_row(row_vals); // it helps to find larger pivots diff --git a/src/util/mpn.cpp b/src/util/mpn.cpp index b8cab4a9f..25445bc89 100644 --- a/src/util/mpn.cpp +++ b/src/util/mpn.cpp @@ -381,7 +381,7 @@ char * mpn_manager::to_string(mpn_digit const * a, size_t const lng, char * buf, div_1(t_numer, t_denom[0], &temp[0]); div_unnormalize(t_numer, t_denom, d, &rem); buf[j++] = '0' + rem; - while (temp.size() > 0 && temp.back() == 0) + while (!temp.empty() && temp.back() == 0) temp.pop_back(); } buf[j] = 0; From 64ac92930139a4cb83a3885102ddd95714b7cc82 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 27 Nov 2018 22:07:14 +0700 Subject: [PATCH 028/318] Use 'override' in new code. --- src/ast/recfun_decl_plugin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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; From 7fb0106ead4ef5e88c605c49fd02ca529e68511d Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 27 Nov 2018 22:14:41 +0700 Subject: [PATCH 029/318] Fix typo in OCaml API docs. --- src/api/ml/z3.mli | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli index 6d478c57f..4b6d8bc25 100644 --- a/src/api/ml/z3.mli +++ b/src/api/ml/z3.mli @@ -3477,6 +3477,6 @@ val disable_trace : string -> unit (** Memory management **) module Memory : sig - (** Reset all allocated resourced **) + (** Reset all allocated resources **) val reset : unit -> unit end From ad49c3269a7a0e238d27e06532eb15482e285de2 Mon Sep 17 00:00:00 2001 From: Nicola Mometto Date: Tue, 27 Nov 2018 18:08:22 +0000 Subject: [PATCH 030/318] Guard against null wrapped functions in OCaml API --- scripts/update_api.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/update_api.py b/scripts/update_api.py index 901ea4fda..bf5d89219 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -1528,6 +1528,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') From 2b34e4f7381e3ee16810fd1c8714be7cabf42474 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 27 Nov 2018 10:36:03 -0800 Subject: [PATCH 031/318] fix #1968 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index f3a88c5b1..1cb0c88d2 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2133,6 +2133,7 @@ void theory_seq::propagate_lit(dependency* dep, unsigned n, literal const* _lits if (!linearize(dep, eqs, lits)) return; TRACE("seq", + tout << "scope: " << ctx.get_scope_level() << "\n"; ctx.display_detailed_literal(tout << "assert:", lit); ctx.display_literals_verbose(tout << " <- ", lits); if (!lits.empty()) tout << "\n"; display_deps(tout, dep);); @@ -5509,16 +5510,18 @@ void theory_seq::propagate_step(literal lit, expr* step) { void theory_seq::propagate_accept(literal lit, expr* acc) { expr *e = nullptr, *idx = nullptr, *re = nullptr; unsigned src = 0; + context& ctx = get_context(); rational _idx; eautomaton* aut = nullptr; VERIFY(is_accept(acc, e, idx, re, src, aut)); + VERIFY(m_autil.is_numeral(idx, _idx)); VERIFY(aut); if (aut->is_sink_state(src)) { propagate_lit(nullptr, 1, &lit, false_literal); return; } - VERIFY(m_autil.is_numeral(idx, _idx)); - if (_idx.get_unsigned() > m_max_unfolding_depth && m_max_unfolding_lit != null_literal) { + if (_idx.get_unsigned() > m_max_unfolding_depth && + m_max_unfolding_lit != null_literal && ctx.get_scope_level() > 0) { propagate_lit(nullptr, 1, &lit, ~m_max_unfolding_lit); return; } @@ -5540,11 +5543,11 @@ void theory_seq::propagate_accept(literal lit, expr* acc) { for (auto const& mv : mvs) { expr_ref nth = mk_nth(e, idx); expr_ref t = mv.t()->accept(nth); - get_context().get_rewriter()(t); + ctx.get_rewriter()(t); literal step = mk_literal(mk_step(e, idx, re, src, mv.dst(), t)); lits.push_back(step); } - get_context().mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); + ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); } void theory_seq::add_theory_assumptions(expr_ref_vector & assumptions) { From b83d6d77c98bd2716b2db11999cbe8ac1a31fda9 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Wed, 28 Nov 2018 14:57:01 +0700 Subject: [PATCH 032/318] Use nullptr rather than 0/NULL. --- src/ast/rewriter/bv_bounds.cpp | 2 +- src/ast/rewriter/bv_trailing.cpp | 2 +- src/muz/fp/datalog_parser.cpp | 2 +- src/smt/theory_recfun.h | 2 +- src/smt/theory_str.cpp | 34 +++++++++++++------------- src/tactic/smtlogics/qfufbv_tactic.cpp | 2 +- src/util/array.h | 2 +- src/util/scoped_timer.cpp | 12 ++++----- src/util/warning.cpp | 2 +- 9 files changed, 30 insertions(+), 30 deletions(-) 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_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/muz/fp/datalog_parser.cpp b/src/muz/fp/datalog_parser.cpp index cc0a60335..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); diff --git a/src/smt/theory_recfun.h b/src/smt/theory_recfun.h index 95b20eb4b..c233da059 100644 --- a/src/smt/theory_recfun.h +++ b/src/smt/theory_recfun.h @@ -69,7 +69,7 @@ namespace smt { recfun::case_def const * m_cdef; ptr_vector m_args; - body_expansion(recfun::util& u, app * n) : m_pred(n), m_cdef(0), m_args() { + body_expansion(recfun::util& u, app * n) : m_pred(n), m_cdef(nullptr), m_args() { m_cdef = &u.get_case_def(n); m_args.append(n->get_num_args(), n->get_args()); } diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 3ee780366..444de1e18 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -505,7 +505,7 @@ namespace smt { app * a = mk_fresh_const(name.c_str(), int_sort); ctx.internalize(a, false); - SASSERT(ctx.get_enode(a) != NULL); + SASSERT(ctx.get_enode(a) != nullptr); SASSERT(ctx.e_internalized(a)); ctx.mark_as_relevant(a); // I'm assuming that this combination will do the correct thing in the integer theory. @@ -544,7 +544,7 @@ namespace smt { // I have a hunch that this may not get internalized for free... ctx.internalize(a, false); - SASSERT(ctx.get_enode(a) != NULL); + SASSERT(ctx.get_enode(a) != nullptr); SASSERT(ctx.e_internalized(a)); // this might help?? mk_var(ctx.get_enode(a)); @@ -566,7 +566,7 @@ namespace smt { m_trail.push_back(a); ctx.internalize(a, false); - SASSERT(ctx.get_enode(a) != NULL); + SASSERT(ctx.get_enode(a) != nullptr); SASSERT(ctx.e_internalized(a)); mk_var(ctx.get_enode(a)); m_basicstr_axiom_todo.push_back(ctx.get_enode(a)); @@ -617,7 +617,7 @@ namespace smt { app * a = mk_fresh_const(name.c_str(), string_sort); ctx.internalize(a, false); - SASSERT(ctx.get_enode(a) != NULL); + SASSERT(ctx.get_enode(a) != nullptr); // this might help?? mk_var(ctx.get_enode(a)); @@ -710,7 +710,7 @@ namespace smt { * Returns the simplified concatenation of two expressions, * where either both expressions are constant strings * or one expression is the empty string. - * If this precondition does not hold, the function returns NULL. + * If this precondition does not hold, the function returns nullptr. * (note: this function was strTheory::Concat()) */ expr * theory_str::mk_concat_const_str(expr * n1, expr * n2) { @@ -2148,7 +2148,7 @@ namespace smt { // Evaluates the concatenation (n1 . n2) with respect to // the current equivalence classes of n1 and n2. // Returns a constant string expression representing this concatenation - // if one can be determined, or NULL if this is not possible. + // if one can be determined, or nullptr if this is not possible. expr * theory_str::eval_concat(expr * n1, expr * n2) { bool n1HasEqcValue = false; bool n2HasEqcValue = false; @@ -2222,7 +2222,7 @@ namespace smt { for (enode_vector::iterator parent_it = current_parents.begin(); parent_it != current_parents.end(); ++parent_it) { enode * e_parent = *parent_it; - SASSERT(e_parent != NULL); + SASSERT(e_parent != nullptr); app * a_parent = e_parent->get_owner(); TRACE("str", tout << "considering parent " << mk_ismt2_pp(a_parent, m) << std::endl;); @@ -5575,7 +5575,7 @@ namespace smt { tout << " " << mk_pp(el, m); } tout << std::endl; - if (constStrAst == NULL) { + if (constStrAst == nullptr) { tout << "constStrAst = NULL" << std::endl; } else { tout << "constStrAst = " << mk_pp(constStrAst, m) << std::endl; @@ -7787,7 +7787,7 @@ namespace smt { generate_mutual_exclusion(arrangement_disjunction); } } /* (arg1Len != 1 || arg2Len != 1) */ - } /* if (Concat(arg1, arg2) == NULL) */ + } /* if (Concat(arg1, arg2) == nullptr) */ } } } @@ -10417,12 +10417,12 @@ namespace smt { } } // foreach(term in str_in_re_terms) - eautomaton * aut_inter = NULL; + eautomaton * aut_inter = nullptr; CTRACE("str", !intersect_constraints.empty(), tout << "check intersection of automata constraints for " << mk_pp(str, m) << std::endl;); for (svector::iterator aut_it = intersect_constraints.begin(); aut_it != intersect_constraints.end(); ++aut_it) { regex_automaton_under_assumptions aut = *aut_it; - if (aut_inter == NULL) { + if (aut_inter == nullptr) { // start somewhere aut_inter = aut.get_automaton(); used_intersect_constraints.push_back(aut); @@ -10472,7 +10472,7 @@ namespace smt { } } } // foreach(entry in intersect_constraints) - if (aut_inter != NULL) { + if (aut_inter != nullptr) { aut_inter->compress(); } TRACE("str", tout << "intersected " << used_intersect_constraints.size() << " constraints" << std::endl;); @@ -10503,7 +10503,7 @@ namespace smt { } conflict_lhs = mk_and(conflict_terms); - if (used_intersect_constraints.size() > 1 && aut_inter != NULL) { + if (used_intersect_constraints.size() > 1 && aut_inter != nullptr) { // check whether the intersection is only the empty string unsigned initial_state = aut_inter->init(); if (aut_inter->final_states().size() == 1 && aut_inter->is_final_state(initial_state)) { @@ -10521,7 +10521,7 @@ namespace smt { } } - if (aut_inter != NULL && aut_inter->is_empty()) { + if (aut_inter != nullptr && aut_inter->is_empty()) { TRACE("str", tout << "product automaton is empty; asserting conflict clause" << std::endl;); expr_ref conflict_clause(m.mk_not(mk_and(conflict_terms)), m); assert_axiom(conflict_clause); @@ -11809,7 +11809,7 @@ namespace smt { expr_ref assertL(mk_and(and_items_LHS), m); SASSERT(assertL); expr * finalAxiom = m.mk_or(m.mk_not(assertL), lenTestAssert.get()); - SASSERT(finalAxiom != NULL); + SASSERT(finalAxiom != nullptr); TRACE("str", tout << "crash avoidance finalAxiom: " << mk_pp(finalAxiom, m) << std::endl;); return finalAxiom; } else { @@ -12095,7 +12095,7 @@ namespace smt { lenTester_fvar_map.insert(indicator, freeVar); expr * lenTestAssert = gen_len_test_options(freeVar, indicator, testNum); - SASSERT(lenTestAssert != NULL); + SASSERT(lenTestAssert != nullptr); return lenTestAssert; } else { TRACE("str", tout << "found previous in-scope length assertions" << std::endl;); @@ -12201,7 +12201,7 @@ namespace smt { testNum = i + 1; } expr * lenTestAssert = gen_len_test_options(freeVar, indicator, testNum); - SASSERT(lenTestAssert != NULL); + SASSERT(lenTestAssert != nullptr); return lenTestAssert; } else { // if we are performing automata-based reasoning and the term associated with diff --git a/src/tactic/smtlogics/qfufbv_tactic.cpp b/src/tactic/smtlogics/qfufbv_tactic.cpp index 38eaa25fb..8dd77cba2 100644 --- a/src/tactic/smtlogics/qfufbv_tactic.cpp +++ b/src/tactic/smtlogics/qfufbv_tactic.cpp @@ -121,7 +121,7 @@ private: tactic_ref t = mk_qfaufbv_tactic(m_m, m_p); sat = mk_tactic2solver(m_m, t.get(), m_p); } - SASSERT(sat != NULL); + SASSERT(sat != nullptr); sat->set_produce_models(true); return sat; } diff --git a/src/util/array.h b/src/util/array.h index cf82e123c..9f0321777 100644 --- a/src/util/array.h +++ b/src/util/array.h @@ -154,7 +154,7 @@ public: return static_cast(reinterpret_cast(m_data)[SIZE_IDX]); } - bool empty() const { return m_data == 0; } + bool empty() const { return m_data == nullptr; } T & operator[](unsigned idx) { SASSERT(idx < size()); diff --git a/src/util/scoped_timer.cpp b/src/util/scoped_timer.cpp index 9850699be..871356d25 100644 --- a/src/util/scoped_timer.cpp +++ b/src/util/scoped_timer.cpp @@ -146,7 +146,7 @@ struct scoped_timer::imp { #if defined(_WINDOWS) || defined(_CYGWIN) m_first = true; CreateTimerQueueTimer(&m_timer, - NULL, + nullptr, abort_proc, this, 0, @@ -180,9 +180,9 @@ struct scoped_timer::imp { m_ms = ms; m_initialized = false; m_signal_sent = false; - ENSURE(pthread_mutex_init(&m_mutex, NULL) == 0); - ENSURE(pthread_cond_init(&m_cond, NULL) == 0); - ENSURE(pthread_create(&m_thread_id, NULL, &thread_func, this) == 0); + ENSURE(pthread_mutex_init(&m_mutex, nullptr) == 0); + ENSURE(pthread_cond_init(&m_cond, nullptr) == 0); + ENSURE(pthread_create(&m_thread_id, nullptr, &thread_func, this) == 0); #else // Other platforms #endif @@ -190,7 +190,7 @@ struct scoped_timer::imp { ~imp() { #if defined(_WINDOWS) || defined(_CYGWIN) - DeleteTimerQueueTimer(NULL, + DeleteTimerQueueTimer(nullptr, m_timer, INVALID_HANDLE_VALUE); #elif defined(__APPLE__) && defined(__MACH__) @@ -242,7 +242,7 @@ struct scoped_timer::imp { // Perform signal outside of lock to avoid waking timing thread twice. pthread_cond_signal(&m_cond); - pthread_join(m_thread_id, NULL); + pthread_join(m_thread_id, nullptr); pthread_cond_destroy(&m_cond); pthread_mutex_destroy(&m_mutex); #else diff --git a/src/util/warning.cpp b/src/util/warning.cpp index 1e9f8a484..5ffc38527 100644 --- a/src/util/warning.cpp +++ b/src/util/warning.cpp @@ -88,7 +88,7 @@ void format2ostream(std::ostream & out, char const* msg, va_list args) { #ifdef _WINDOWS size_t msg_len = _vscprintf(msg, args_copy); #else - size_t msg_len = vsnprintf(NULL, 0, msg, args_copy); + size_t msg_len = vsnprintf(nullptr, 0, msg, args_copy); #endif va_end(args_copy); From 090f14e7bc46d8a47cf3043c34edcbe19b0ef1f0 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Wed, 28 Nov 2018 14:58:04 +0700 Subject: [PATCH 033/318] Fix a couple of typos. --- src/sat/sat_simplifier_params.pyg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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'), From 2016f48dc9e53b0977f3202e0bdefb0e48b5a005 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Wed, 28 Nov 2018 19:07:33 +0700 Subject: [PATCH 034/318] Avoid const params in decls. Const-qualification of parameters only has an effect in function definitions. --- src/ackermannization/lackr.h | 2 +- src/muz/rel/dl_compiler.h | 2 +- src/muz/rel/dl_instruction.h | 2 +- src/util/mpn.h | 44 ++++++++++++++++++------------------ 4 files changed, 25 insertions(+), 25 deletions(-) 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/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_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/util/mpn.h b/src/util/mpn.h index a5d3c30d8..ea20fc42b 100644 --- a/src/util/mpn.h +++ b/src/util/mpn.h @@ -37,29 +37,29 @@ public: mpn_manager(); ~mpn_manager(); - int compare(mpn_digit const * a, size_t const lnga, - mpn_digit const * b, size_t const lngb) const; + int compare(mpn_digit const * a, size_t lnga, + mpn_digit const * b, size_t lngb) const; - bool add(mpn_digit const * a, size_t const lnga, - mpn_digit const * b, size_t const lngb, - mpn_digit *c, size_t const lngc_alloc, + bool add(mpn_digit const * a, size_t lnga, + mpn_digit const * b, size_t lngb, + mpn_digit *c, size_t lngc_alloc, size_t * plngc) const; - bool sub(mpn_digit const * a, size_t const lnga, - mpn_digit const * b, size_t const lngb, + bool sub(mpn_digit const * a, size_t lnga, + mpn_digit const * b, size_t lngb, mpn_digit * c, mpn_digit * pborrow) const; - bool mul(mpn_digit const * a, size_t const lnga, - mpn_digit const * b, size_t const lngb, + bool mul(mpn_digit const * a, size_t lnga, + mpn_digit const * b, size_t lngb, mpn_digit * c) const; - bool div(mpn_digit const * numer, size_t const lnum, - mpn_digit const * denom, size_t const lden, + bool div(mpn_digit const * numer, size_t lnum, + mpn_digit const * denom, size_t lden, mpn_digit * quot, mpn_digit * rem); - char * to_string(mpn_digit const * a, size_t const lng, - char * buf, size_t const lbuf) const; + char * to_string(mpn_digit const * a, size_t lng, + char * buf, size_t lbuf) const; private: #ifdef _AMD64_ class mpn_sbuffer : public sbuffer { @@ -88,29 +88,29 @@ private: static const mpn_digit zero; mpn_sbuffer u, v, t_ms, t_ab; - void display_raw(std::ostream & out, mpn_digit const * a, size_t const lng) const; + void display_raw(std::ostream & out, mpn_digit const * a, size_t lng) const; - size_t div_normalize(mpn_digit const * numer, size_t const lnum, - mpn_digit const * denom, size_t const lden, + size_t div_normalize(mpn_digit const * numer, size_t lnum, + mpn_digit const * denom, size_t lden, mpn_sbuffer & n_numer, mpn_sbuffer & n_denom) const; void div_unnormalize(mpn_sbuffer & numer, mpn_sbuffer & denom, - size_t const d, mpn_digit * rem) const; + size_t d, mpn_digit * rem) const; - bool div_1(mpn_sbuffer & numer, mpn_digit const denom, + bool div_1(mpn_sbuffer & numer, mpn_digit denom, mpn_digit * quot) const; bool div_n(mpn_sbuffer & numer, mpn_sbuffer const & denom, mpn_digit * quot, mpn_digit * rem, mpn_sbuffer & ms, mpn_sbuffer & ab) const; - void trace(mpn_digit const * a, size_t const lnga, - mpn_digit const * b, size_t const lngb, + void trace(mpn_digit const * a, size_t lnga, + mpn_digit const * b, size_t lngb, const char * op) const; - void trace(mpn_digit const * a, size_t const lnga) const; - void trace_nl(mpn_digit const * a, size_t const lnga) const; + void trace(mpn_digit const * a, size_t lnga) const; + void trace_nl(mpn_digit const * a, size_t lnga) const; }; #endif From a3281a02db32578c30180c7e126749b685571176 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Wed, 28 Nov 2018 20:12:47 +0700 Subject: [PATCH 035/318] mk_coeffs_without was inadvertently copying src. Pass it via ref. --- src/math/simplex/model_based_opt.cpp | 2 +- src/math/simplex/model_based_opt.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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(); From e76e5012167e4b26456aec7fc47153418581ef79 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Wed, 28 Nov 2018 14:42:19 -0500 Subject: [PATCH 036/318] Z3str3: correct str.replace semantics --- src/smt/theory_str.cpp | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index f0e11c248..738dbd942 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -1661,53 +1661,66 @@ namespace smt { } } + // (str.replace s t t') is the string obtained by replacing the first occurrence + // of t in s, if any, by t'. Note that if t is empty, the result is to prepend + // t' to s; also, if t does not occur in s then the result is s. void theory_str::instantiate_axiom_Replace(enode * e) { context & ctx = get_context(); ast_manager & m = get_manager(); - app * expr = e->get_owner(); - if (axiomatized_terms.contains(expr)) { - TRACE("str", tout << "already set up Replace axiom for " << mk_pp(expr, m) << std::endl;); + app * ex = e->get_owner(); + if (axiomatized_terms.contains(ex)) { + TRACE("str", tout << "already set up Replace axiom for " << mk_pp(ex, m) << std::endl;); return; } - axiomatized_terms.insert(expr); + axiomatized_terms.insert(ex); - TRACE("str", tout << "instantiate Replace axiom for " << mk_pp(expr, m) << std::endl;); + TRACE("str", tout << "instantiate Replace axiom for " << mk_pp(ex, m) << std::endl;); expr_ref x1(mk_str_var("x1"), m); expr_ref x2(mk_str_var("x2"), m); expr_ref i1(mk_int_var("i1"), m); expr_ref result(mk_str_var("result"), m); + expr * replaceS; + expr * replaceT; + expr * replaceTPrime; + u.str.is_replace(ex, replaceS, replaceT, replaceTPrime); + + // t empty => result = (str.++ t' s) + expr_ref emptySrcAst(ctx.mk_eq_atom(replaceT, mk_string("")), m); + expr_ref prependTPrimeToS(ctx.mk_eq_atom(result, mk_concat(replaceTPrime, replaceS)), m); + // condAst = Contains(args[0], args[1]) - expr_ref condAst(mk_contains(expr->get_arg(0), expr->get_arg(1)), m); + expr_ref condAst(mk_contains(ex->get_arg(0), ex->get_arg(1)), m); // ----------------------- // true branch expr_ref_vector thenItems(m); // args[0] = x1 . args[1] . x2 - thenItems.push_back(ctx.mk_eq_atom(expr->get_arg(0), mk_concat(x1, mk_concat(expr->get_arg(1), x2)))); + thenItems.push_back(ctx.mk_eq_atom(ex->get_arg(0), mk_concat(x1, mk_concat(ex->get_arg(1), x2)))); // i1 = |x1| thenItems.push_back(ctx.mk_eq_atom(i1, mk_strlen(x1))); // args[0] = x3 . x4 /\ |x3| = |x1| + |args[1]| - 1 /\ ! contains(x3, args[1]) expr_ref x3(mk_str_var("x3"), m); expr_ref x4(mk_str_var("x4"), m); - expr_ref tmpLen(m_autil.mk_add(i1, mk_strlen(expr->get_arg(1)), mk_int(-1)), m); - thenItems.push_back(ctx.mk_eq_atom(expr->get_arg(0), mk_concat(x3, x4))); + expr_ref tmpLen(m_autil.mk_add(i1, mk_strlen(ex->get_arg(1)), mk_int(-1)), m); + thenItems.push_back(ctx.mk_eq_atom(ex->get_arg(0), mk_concat(x3, x4))); thenItems.push_back(ctx.mk_eq_atom(mk_strlen(x3), tmpLen)); - thenItems.push_back(mk_not(m, mk_contains(x3, expr->get_arg(1)))); - thenItems.push_back(ctx.mk_eq_atom(result, mk_concat(x1, mk_concat(expr->get_arg(2), x2)))); + thenItems.push_back(mk_not(m, mk_contains(x3, ex->get_arg(1)))); + thenItems.push_back(ctx.mk_eq_atom(result, mk_concat(x1, mk_concat(ex->get_arg(2), x2)))); // ----------------------- // false branch - expr_ref elseBranch(ctx.mk_eq_atom(result, expr->get_arg(0)), m); + expr_ref elseBranch(ctx.mk_eq_atom(result, ex->get_arg(0)), m); th_rewriter rw(m); - expr_ref breakdownAssert(m.mk_ite(condAst, m.mk_and(thenItems.size(), thenItems.c_ptr()), elseBranch), m); + expr_ref breakdownAssert(m.mk_ite(emptySrcAst, prependTPrimeToS, + m.mk_ite(condAst, mk_and(thenItems), elseBranch)), m); expr_ref breakdownAssert_rw(breakdownAssert, m); rw(breakdownAssert_rw); assert_axiom(breakdownAssert_rw); - expr_ref reduceToResult(ctx.mk_eq_atom(expr, result), m); + expr_ref reduceToResult(ctx.mk_eq_atom(ex, result), m); expr_ref reduceToResult_rw(reduceToResult, m); rw(reduceToResult_rw); assert_axiom(reduceToResult_rw); From 5dc1337476ce434670887e969ffd7a72eb08332e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 28 Nov 2018 13:49:53 -0800 Subject: [PATCH 037/318] fix #1984 - already fixed in private branch, but wasn't propagated to master Signed-off-by: Nikolaj Bjorner --- src/smt/arith_eq_solver.cpp | 9 +++------ src/smt/theory_lra.cpp | 7 +++++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/smt/arith_eq_solver.cpp b/src/smt/arith_eq_solver.cpp index 4b1c6e4a6..677132804 100644 --- a/src/smt/arith_eq_solver.cpp +++ b/src/smt/arith_eq_solver.cpp @@ -608,8 +608,8 @@ bool arith_eq_solver::solve_integer_equations_gcd( return false; } live.erase(live.begin()+live_pos); - for (j = 0; j < live.size(); ++j) { - row& r = rows[live[j]]; + for (unsigned l : live) { + row& r = rows[l]; if (!r[i].is_zero()) { substitute(r, r0, i); gcd_normalize(r); @@ -625,10 +625,7 @@ bool arith_eq_solver::solve_integer_equations_gcd( TRACE("arith_eq_solver", tout << ((live.size()<=1)?"solved ":"incomplete check ") << live.size() << "\n"; - for (unsigned i = 0; i < live.size(); ++i) { - print_row(tout, rows[live[i]]); - } - ); + for (unsigned l : live) print_row(tout, rows[l]); ); return true; } diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 0b25aa626..818a20d93 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -323,6 +323,10 @@ class theory_lra::imp { m_solver->settings().m_int_run_gcd_test = ctx().get_fparams().m_arith_gcd_test; m_solver->settings().set_random_seed(ctx().get_fparams().m_random_seed); m_lia = alloc(lp::int_solver, m_solver.get()); + get_one(true); + get_zero(true); + get_one(false); + get_zero(false); } void ensure_nra() { @@ -346,6 +350,7 @@ class theory_lra::imp { var = m_solver->add_var(v, true); m_theory_var2var_index.setx(v, var, UINT_MAX); m_var_index2theory_var.setx(var, v, UINT_MAX); + TRACE("arith", tout << v << " internal: " << var << "\n";); m_var_trail.push_back(v); add_def_constraint(m_solver->add_var_bound(var, lp::GE, rational(c))); add_def_constraint(m_solver->add_var_bound(var, lp::LE, rational(c))); @@ -662,6 +667,7 @@ class theory_lra::imp { m_has_int |= is_int(v); m_theory_var2var_index.setx(v, result, UINT_MAX); m_var_index2theory_var.setx(result, v, UINT_MAX); + TRACE("arith", tout << v << " internal: " << result << "\n";); m_var_trail.push_back(v); } return result; @@ -828,6 +834,7 @@ class theory_lra::imp { SASSERT(!m_left_side.empty()); vi = m_solver->add_term(m_left_side); m_theory_var2var_index.setx(v, vi, UINT_MAX); + TRACE("arith", tout << v << " internal: " << vi << "\n";); if (m_solver->is_term(vi)) { m_term_index2theory_var.setx(m_solver->adjust_term_index(vi), v, UINT_MAX); } From 8248ec879e19fd306ce625a390bc2cf1eea0b1eb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 28 Nov 2018 15:35:46 -0800 Subject: [PATCH 038/318] fix qsat destructor memory allocation #1948 Signed-off-by: Nikolaj Bjorner --- src/qe/qsat.cpp | 26 +++++++++++++++++++------- src/smt/theory_lra.cpp | 3 --- 2 files changed, 19 insertions(+), 10 deletions(-) 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/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 818a20d93..a62c82aeb 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -350,7 +350,6 @@ class theory_lra::imp { var = m_solver->add_var(v, true); m_theory_var2var_index.setx(v, var, UINT_MAX); m_var_index2theory_var.setx(var, v, UINT_MAX); - TRACE("arith", tout << v << " internal: " << var << "\n";); m_var_trail.push_back(v); add_def_constraint(m_solver->add_var_bound(var, lp::GE, rational(c))); add_def_constraint(m_solver->add_var_bound(var, lp::LE, rational(c))); @@ -667,7 +666,6 @@ class theory_lra::imp { m_has_int |= is_int(v); m_theory_var2var_index.setx(v, result, UINT_MAX); m_var_index2theory_var.setx(result, v, UINT_MAX); - TRACE("arith", tout << v << " internal: " << result << "\n";); m_var_trail.push_back(v); } return result; @@ -834,7 +832,6 @@ class theory_lra::imp { SASSERT(!m_left_side.empty()); vi = m_solver->add_term(m_left_side); m_theory_var2var_index.setx(v, vi, UINT_MAX); - TRACE("arith", tout << v << " internal: " << vi << "\n";); if (m_solver->is_term(vi)) { m_term_index2theory_var.setx(m_solver->adjust_term_index(vi), v, UINT_MAX); } From e96f9de70b56554ec6564741607041a5c12f795e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 29 Nov 2018 06:02:32 -0800 Subject: [PATCH 039/318] perf #1988 Signed-off-by: Nikolaj Bjorner --- src/ast/seq_decl_plugin.cpp | 8 ++++---- src/ast/seq_decl_plugin.h | 1 + src/smt/theory_seq.cpp | 11 +++++++++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 8fc130ef1..c4813f9f7 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -435,7 +435,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 +445,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 +474,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); } diff --git a/src/ast/seq_decl_plugin.h b/src/ast/seq_decl_plugin.h index f8107f1e0..4b23f81d0 100644 --- a/src/ast/seq_decl_plugin.h +++ b/src/ast/seq_decl_plugin.h @@ -140,6 +140,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; diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 44acfdfd6..ccd85c42a 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -5553,8 +5553,15 @@ void theory_seq::propagate_accept(literal lit, expr* acc) { void theory_seq::add_theory_assumptions(expr_ref_vector & assumptions) { TRACE("seq", tout << "add_theory_assumption " << m_util.has_re() << "\n";); if (m_util.has_re()) { - expr_ref dlimit = mk_max_unfolding_depth(); - m_max_unfolding_lit = mk_literal(dlimit); + expr_ref dlimit(m); + if (m_max_unfolding_lit != null_literal && + m_max_unfolding_depth == 1) { + dlimit = mk_max_unfolding_depth(); + m_max_unfolding_lit = mk_literal(dlimit); + } + else { + dlimit = get_context().bool_var2expr(m_max_unfolding_lit.var()); + } TRACE("seq", tout << "add_theory_assumption " << dlimit << " " << assumptions << "\n";); assumptions.push_back(dlimit); } From ba06d22557890347f7a83e061ec919715328dd19 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 29 Nov 2018 10:24:19 -0800 Subject: [PATCH 040/318] revert stale reference to literal Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index ccd85c42a..d61f615ec 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -5554,14 +5554,8 @@ void theory_seq::add_theory_assumptions(expr_ref_vector & assumptions) { TRACE("seq", tout << "add_theory_assumption " << m_util.has_re() << "\n";); if (m_util.has_re()) { expr_ref dlimit(m); - if (m_max_unfolding_lit != null_literal && - m_max_unfolding_depth == 1) { - dlimit = mk_max_unfolding_depth(); - m_max_unfolding_lit = mk_literal(dlimit); - } - else { - dlimit = get_context().bool_var2expr(m_max_unfolding_lit.var()); - } + dlimit = mk_max_unfolding_depth(); + m_max_unfolding_lit = mk_literal(dlimit); TRACE("seq", tout << "add_theory_assumption " << dlimit << " " << assumptions << "\n";); assumptions.push_back(dlimit); } From 67f22d8d659e4ef287dcdc8e9123aa2fb3bee932 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 29 Nov 2018 11:32:52 -0800 Subject: [PATCH 041/318] improving performance for length constraints Signed-off-by: Nikolaj Bjorner --- src/ast/seq_decl_plugin.cpp | 4 +- src/smt/smt_arith_value.cpp | 85 ++++++++++++--------- src/smt/smt_arith_value.h | 17 ++++- src/smt/theory_jobscheduler.cpp | 9 ++- src/smt/theory_seq.cpp | 130 +++++++++++++++----------------- src/smt/theory_seq.h | 11 ++- src/smt/theory_str.cpp | 10 ++- 7 files changed, 142 insertions(+), 124 deletions(-) diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index c4813f9f7..0bfc94e11 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -377,8 +377,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; diff --git a/src/smt/smt_arith_value.cpp b/src/smt/smt_arith_value.cpp index 443112ecc..50fe6340a 100644 --- a/src/smt/smt_arith_value.cpp +++ b/src/smt/smt_arith_value.cpp @@ -18,30 +18,32 @@ Revision History: --*/ #include "smt/smt_arith_value.h" -#include "smt/theory_lra.h" -#include "smt/theory_arith.h" namespace smt { - arith_value::arith_value(context& ctx): - m_ctx(ctx), m(ctx.get_manager()), a(m) {} + arith_value::arith_value(ast_manager& m): + m_ctx(nullptr), m(m), a(m) {} - bool arith_value::get_lo(expr* e, rational& lo, bool& is_strict) { - if (!m_ctx.e_internalized(e)) return false; + void arith_value::init(context* ctx) { + m_ctx = ctx; family_id afid = a.get_family_id(); + theory* th = m_ctx->get_theory(afid); + m_tha = dynamic_cast(th); + m_thi = dynamic_cast(th); + m_thr = dynamic_cast(th); + } + + bool arith_value::get_lo_equiv(expr* e, rational& lo, bool& is_strict) { + if (!m_ctx->e_internalized(e)) return false; is_strict = false; - enode* next = m_ctx.get_enode(e), *n = next; + enode* next = m_ctx->get_enode(e), *n = next; bool found = false; bool is_strict1; rational lo1; - theory* th = m_ctx.get_theory(afid); - theory_mi_arith* tha = dynamic_cast(th); - theory_i_arith* thi = dynamic_cast(th); - theory_lra* thr = dynamic_cast(th); do { - if ((tha && tha->get_lower(next, lo1, is_strict1)) || - (thi && thi->get_lower(next, lo1, is_strict1)) || - (thr && thr->get_lower(next, lo1, is_strict1))) { + if ((m_tha && m_tha->get_lower(next, lo1, is_strict1)) || + (m_thi && m_thi->get_lower(next, lo1, is_strict1)) || + (m_thr && m_thr->get_lower(next, lo1, is_strict1))) { if (!found || lo1 > lo || (lo == lo1 && is_strict1)) lo = lo1, is_strict = is_strict1; found = true; } @@ -51,21 +53,16 @@ namespace smt { return found; } - bool arith_value::get_up(expr* e, rational& up, bool& is_strict) { - if (!m_ctx.e_internalized(e)) return false; - family_id afid = a.get_family_id(); + bool arith_value::get_up_equiv(expr* e, rational& up, bool& is_strict) { + if (!m_ctx->e_internalized(e)) return false; is_strict = false; - enode* next = m_ctx.get_enode(e), *n = next; + enode* next = m_ctx->get_enode(e), *n = next; bool found = false, is_strict1; rational up1; - theory* th = m_ctx.get_theory(afid); - theory_mi_arith* tha = dynamic_cast(th); - theory_i_arith* thi = dynamic_cast(th); - theory_lra* thr = dynamic_cast(th); do { - if ((tha && tha->get_upper(next, up1, is_strict1)) || - (thi && thi->get_upper(next, up1, is_strict1)) || - (thr && thr->get_upper(next, up1, is_strict1))) { + if ((m_tha && m_tha->get_upper(next, up1, is_strict1)) || + (m_thi && m_thi->get_upper(next, up1, is_strict1)) || + (m_thr && m_thr->get_upper(next, up1, is_strict1))) { if (!found || up1 < up || (up1 == up && is_strict1)) up = up1, is_strict = is_strict1; found = true; } @@ -75,20 +72,36 @@ namespace smt { return found; } + bool arith_value::get_up(expr* e, rational& up, bool& is_strict) const { + if (!m_ctx->e_internalized(e)) return false; + is_strict = false; + enode* n = m_ctx->get_enode(e); + if (m_tha) return m_tha->get_upper(n, up, is_strict); + if (m_thi) return m_thi->get_upper(n, up, is_strict); + if (m_thr) return m_thr->get_upper(n, up, is_strict); + return false; + } + + bool arith_value::get_lo(expr* e, rational& up, bool& is_strict) const { + if (!m_ctx->e_internalized(e)) return false; + is_strict = false; + enode* n = m_ctx->get_enode(e); + if (m_tha) return m_tha->get_lower(n, up, is_strict); + if (m_thi) return m_thi->get_lower(n, up, is_strict); + if (m_thr) return m_thr->get_lower(n, up, is_strict); + return false; + } + + bool arith_value::get_value(expr* e, rational& val) { - if (!m_ctx.e_internalized(e)) return false; + if (!m_ctx->e_internalized(e)) return false; expr_ref _val(m); - enode* next = m_ctx.get_enode(e), *n = next; - family_id afid = a.get_family_id(); - theory* th = m_ctx.get_theory(afid); - theory_mi_arith* tha = dynamic_cast(th); - theory_i_arith* thi = dynamic_cast(th); - theory_lra* thr = dynamic_cast(th); + enode* next = m_ctx->get_enode(e), *n = next; do { e = next->get_owner(); - if (tha && tha->get_value(next, _val) && a.is_numeral(_val, val)) return true; - if (thi && thi->get_value(next, _val) && a.is_numeral(_val, val)) return true; - if (thr && thr->get_value(next, val)) return true; + if (m_tha && m_tha->get_value(next, _val) && a.is_numeral(_val, val)) return true; + if (m_thi && m_thi->get_value(next, _val) && a.is_numeral(_val, val)) return true; + if (m_thr && m_thr->get_value(next, val)) return true; next = next->get_next(); } while (next != n); @@ -97,7 +110,7 @@ namespace smt { final_check_status arith_value::final_check() { family_id afid = a.get_family_id(); - theory * th = m_ctx.get_theory(afid); + theory * th = m_ctx->get_theory(afid); return th->final_check_eh(); } }; diff --git a/src/smt/smt_arith_value.h b/src/smt/smt_arith_value.h index b819b2b9a..ddaa113ea 100644 --- a/src/smt/smt_arith_value.h +++ b/src/smt/smt_arith_value.h @@ -21,18 +21,27 @@ Revision History: #include "ast/arith_decl_plugin.h" #include "smt/smt_context.h" +#include "smt/theory_lra.h" +#include "smt/theory_arith.h" namespace smt { class arith_value { - context& m_ctx; + context* m_ctx; ast_manager& m; arith_util a; + theory_mi_arith* m_tha; + theory_i_arith* m_thi; + theory_lra* m_thr; public: - arith_value(context& ctx); - bool get_lo(expr* e, rational& lo, bool& strict); - bool get_up(expr* e, rational& up, bool& strict); + arith_value(ast_manager& m); + void init(context* ctx); + bool get_lo_equiv(expr* e, rational& lo, bool& strict); + bool get_up_equiv(expr* e, rational& up, bool& strict); bool get_value(expr* e, rational& value); + bool get_lo(expr* e, rational& lo, bool& strict) const; + bool get_up(expr* e, rational& up, bool& strict) const; + bool get_fixed(expr* e, rational& value) const; final_check_status final_check(); }; }; diff --git a/src/smt/theory_jobscheduler.cpp b/src/smt/theory_jobscheduler.cpp index 3b218f56d..152eb715b 100644 --- a/src/smt/theory_jobscheduler.cpp +++ b/src/smt/theory_jobscheduler.cpp @@ -551,7 +551,8 @@ namespace smt { } time_t theory_jobscheduler::get_lo(expr* e) { - arith_value av(get_context()); + arith_value av(m); + av.init(&get_context()); rational val; bool is_strict; if (av.get_lo(e, val, is_strict) && !is_strict && val.is_uint64()) { @@ -561,7 +562,8 @@ namespace smt { } time_t theory_jobscheduler::get_up(expr* e) { - arith_value av(get_context()); + arith_value av(m); + av.init(&get_context()); rational val; bool is_strict; if (av.get_up(e, val, is_strict) && !is_strict && val.is_uint64()) { @@ -571,7 +573,8 @@ namespace smt { } time_t theory_jobscheduler::get_value(expr* e) { - arith_value av(get_context()); + arith_value av(get_manager()); + av.init(&get_context()); rational val; if (av.get_value(e, val) && val.is_uint64()) { return val.get_uint64(); diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index ccd85c42a..40ce87e13 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -209,10 +209,12 @@ theory_seq::theory_seq(ast_manager& m, theory_seq_params const & params): m_axioms_head(0), m_int_string(m), m_mg(nullptr), + m_length(m), m_rewrite(m), m_seq_rewrite(m), m_util(m), m_autil(m), + m_arith_value(m), m_trail_stack(*this), m_ls(m), m_rs(m), m_lhs(m), m_rhs(m), @@ -245,6 +247,7 @@ theory_seq::~theory_seq() { void theory_seq::init(context* ctx) { theory::init(ctx); + m_arith_value.init(ctx); } final_check_status theory_seq::final_check_eh() { @@ -991,8 +994,9 @@ void theory_seq::find_max_eq_len(expr_ref_vector const& ls, expr_ref_vector cons hi = 1; } else { - lower_bound(ls.get(j), lo); - upper_bound(ls.get(j), hi); + expr_ref len_s = mk_len(ls.get(j)); + lower_bound(len_s, lo); + upper_bound(len_s, hi); } if (!lo.is_minus_one()) { if (lo1.is_minus_one()) @@ -1024,8 +1028,9 @@ void theory_seq::find_max_eq_len(expr_ref_vector const& ls, expr_ref_vector cons hi = 1; } else { - lower_bound(rs.get(j), lo); - upper_bound(rs.get(j), hi); + expr_ref len_s = mk_len(rs.get(j)); + lower_bound(len_s, lo); + upper_bound(len_s, hi); } if (!lo.is_minus_one()) { if (lo2.is_minus_one()) @@ -1729,7 +1734,7 @@ bool theory_seq::propagate_length_coherence(expr* e) { } TRACE("seq", tout << "Unsolved " << mk_pp(e, m); if (!lower_bound2(e, lo)) lo = -rational::one(); - if (!upper_bound(e, hi)) hi = -rational::one(); + if (!upper_bound(mk_len(e), hi)) hi = -rational::one(); tout << " lo: " << lo << " hi: " << hi << "\n"; ); @@ -1747,9 +1752,10 @@ bool theory_seq::propagate_length_coherence(expr* e) { // len(e) >= low => e = tail; literal low(mk_literal(m_autil.mk_ge(mk_len(e), m_autil.mk_numeral(lo, true)))); add_axiom(~low, mk_seq_eq(e, tail)); - if (upper_bound(e, hi)) { + expr_ref len_e = mk_len(e); + if (upper_bound(len_e, hi)) { // len(e) <= hi => len(tail) <= hi - lo - expr_ref high1(m_autil.mk_le(mk_len(e), m_autil.mk_numeral(hi, true)), m); + expr_ref high1(m_autil.mk_le(len_e, m_autil.mk_numeral(hi, true)), m); if (hi == lo) { add_axiom(~mk_literal(high1), mk_seq_eq(seq, emp)); } @@ -1799,13 +1805,17 @@ bool theory_seq::check_length_coherence0(expr* e) { bool theory_seq::check_length_coherence() { #if 1 - for (auto e : m_length) { + for (expr* l : m_length) { + expr* e = nullptr; + VERIFY(m_util.str.is_length(l, e)); if (check_length_coherence0(e)) { return true; } } #endif - for (auto e : m_length) { + for (expr* l : m_length) { + expr* e = nullptr; + VERIFY(m_util.str.is_length(l, e)); if (check_length_coherence(e)) { return true; } @@ -1823,9 +1833,11 @@ bool theory_seq::fixed_length(bool is_zero) { return found; } -bool theory_seq::fixed_length(expr* e, bool is_zero) { +bool theory_seq::fixed_length(expr* len_e, bool is_zero) { rational lo, hi; - if (!(is_var(e) && lower_bound(e, lo) && upper_bound(e, hi) && lo == hi + expr* e = nullptr; + VERIFY(m_util.str.is_length(len_e, e)); + if (!(is_var(e) && lower_bound(len_e, lo) && upper_bound(len_e, hi) && lo == hi && ((is_zero && lo.is_zero()) || (!is_zero && lo.is_unsigned())))) { return false; } @@ -1858,9 +1870,9 @@ bool theory_seq::fixed_length(expr* e, bool is_zero) { seq = mk_concat(elems.size(), elems.c_ptr()); } TRACE("seq", tout << "Fixed: " << mk_pp(e, m) << " " << lo << "\n";); - add_axiom(~mk_eq(mk_len(e), m_autil.mk_numeral(lo, true), false), mk_seq_eq(seq, e)); + add_axiom(~mk_eq(len_e, m_autil.mk_numeral(lo, true), false), mk_seq_eq(seq, e)); if (!ctx.at_base_level()) { - m_trail_stack.push(push_replay(alloc(replay_fixed_length, m, e))); + m_trail_stack.push(push_replay(alloc(replay_fixed_length, m, len_e))); } return true; } @@ -3354,10 +3366,14 @@ bool theory_seq::internalize_term(app* term) { return true; } -void theory_seq::add_length(expr* e) { - SASSERT(!has_length(e)); - m_length.insert(e); - m_trail_stack.push(insert_obj_trail(m_length, e)); +void theory_seq::add_length(expr* l) { + expr* e = nullptr; + VERIFY(m_util.str.is_length(l, e)); + SASSERT(!m_length.contains(l)); + m_length.push_back(l); + m_has_length.insert(e); + m_trail_stack.push(insert_obj_trail(m_has_length, e)); + m_trail_stack.push(push_back_vector(m_length)); } @@ -3372,7 +3388,7 @@ void theory_seq::enforce_length(expr* e) { if (!has_length(o)) { expr_ref len = mk_len(o); enque_axiom(len); - add_length(o); + add_length(len); } n = n->get_next(); } @@ -3609,14 +3625,12 @@ void theory_seq::display(std::ostream & out) const { m_exclude.display(out); } - if (!m_length.empty()) { - for (auto e : m_length) { - rational lo(-1), hi(-1); - lower_bound(e, lo); - upper_bound(e, hi); - if (lo.is_pos() || !hi.is_minus_one()) { - out << mk_pp(e, m) << " [" << lo << ":" << hi << "]\n"; - } + for (auto e : m_length) { + rational lo(-1), hi(-1); + lower_bound(e, lo); + upper_bound(e, hi); + if (lo.is_pos() || !hi.is_minus_one()) { + out << mk_pp(e, m) << " [" << lo << ":" << hi << "]\n"; } } @@ -4215,7 +4229,7 @@ void theory_seq::deque_axiom(expr* n) { if (m_util.str.is_length(n)) { add_length_axiom(n); } - else if (m_util.str.is_empty(n) && !has_length(n) && !m_length.empty()) { + else if (m_util.str.is_empty(n) && !has_length(n) && !m_has_length.empty()) { enforce_length(n); } else if (m_util.str.is_index(n)) { @@ -4648,24 +4662,21 @@ bool theory_seq::get_num_value(expr* e, rational& val) const { return false; } -bool theory_seq::lower_bound(expr* _e, rational& lo) const { - context& ctx = get_context(); - expr_ref e = mk_len(_e); - expr_ref _lo(m); - family_id afid = m_autil.get_family_id(); - do { - theory_mi_arith* tha = get_th_arith(ctx, afid, e); - if (tha && tha->get_lower(ctx.get_enode(e), _lo)) break; - theory_i_arith* thi = get_th_arith(ctx, afid, e); - if (thi && thi->get_lower(ctx.get_enode(e), _lo)) break; - theory_lra* thr = get_th_arith(ctx, afid, e); - if (thr && thr->get_lower(ctx.get_enode(e), _lo)) break; - return false; - } - while (false); - return m_autil.is_numeral(_lo, lo) && lo.is_int(); +bool theory_seq::lower_bound(expr* e, rational& lo) const { + VERIFY(m_autil.is_int(e)); + bool is_strict = true; + return m_arith_value.get_lo(e, lo, is_strict) && !is_strict && lo.is_int(); + } +bool theory_seq::upper_bound(expr* e, rational& hi) const { + VERIFY(m_autil.is_int(e)); + bool is_strict = true; + return m_arith_value.get_up(e, hi, is_strict) && !is_strict && hi.is_int(); +} + + + // The difference with lower_bound function is that since in some cases, // the lower bound is not updated for all the enodes in the same eqc, // we have to traverse the eqc to query for the better lower bound. @@ -4705,23 +4716,6 @@ bool theory_seq::lower_bound2(expr* _e, rational& lo) { return true; } -bool theory_seq::upper_bound(expr* _e, rational& hi) const { - context& ctx = get_context(); - expr_ref e = mk_len(_e); - family_id afid = m_autil.get_family_id(); - expr_ref _hi(m); - do { - theory_mi_arith* tha = get_th_arith(ctx, afid, e); - if (tha && tha->get_upper(ctx.get_enode(e), _hi)) break; - theory_i_arith* thi = get_th_arith(ctx, afid, e); - if (thi && thi->get_upper(ctx.get_enode(e), _hi)) break; - theory_lra* thr = get_th_arith(ctx, afid, e); - if (thr && thr->get_upper(ctx.get_enode(e), _hi)) break; - return false; - } - while (false); - return m_autil.is_numeral(_hi, hi) && hi.is_int(); -} bool theory_seq::get_length(expr* e, rational& val) const { context& ctx = get_context(); @@ -5485,14 +5479,15 @@ void theory_seq::propagate_step(literal lit, expr* step) { TRACE("seq", tout << mk_pp(step, m) << " -> " << mk_pp(t, m) << "\n";); propagate_lit(nullptr, 1, &lit, mk_literal(t)); + expr_ref len_s = mk_len(s); rational lo; rational _idx; VERIFY(m_autil.is_numeral(idx, _idx)); - if (lower_bound(s, lo) && lo.is_unsigned() && lo >= _idx) { + if (lower_bound(len_s, lo) && lo.is_unsigned() && lo >= _idx) { // skip } else { - propagate_lit(nullptr, 1, &lit, ~mk_literal(m_autil.mk_le(mk_len(s), idx))); + propagate_lit(nullptr, 1, &lit, ~mk_literal(m_autil.mk_le(len_s, idx))); } ensure_nth(lit, s, idx); @@ -5554,15 +5549,8 @@ void theory_seq::add_theory_assumptions(expr_ref_vector & assumptions) { TRACE("seq", tout << "add_theory_assumption " << m_util.has_re() << "\n";); if (m_util.has_re()) { expr_ref dlimit(m); - if (m_max_unfolding_lit != null_literal && - m_max_unfolding_depth == 1) { - dlimit = mk_max_unfolding_depth(); - m_max_unfolding_lit = mk_literal(dlimit); - } - else { - dlimit = get_context().bool_var2expr(m_max_unfolding_lit.var()); - } - TRACE("seq", tout << "add_theory_assumption " << dlimit << " " << assumptions << "\n";); + dlimit = mk_max_unfolding_depth(); + m_max_unfolding_lit = mk_literal(dlimit); assumptions.push_back(dlimit); } } diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 75ba54381..9df28acf5 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -19,9 +19,7 @@ Revision History: #ifndef THEORY_SEQ_H_ #define THEORY_SEQ_H_ -#include "smt/smt_theory.h" #include "ast/seq_decl_plugin.h" -#include "smt/theory_seq_empty.h" #include "ast/rewriter/th_rewriter.h" #include "ast/ast_trail.h" #include "util/scoped_vector.h" @@ -30,6 +28,9 @@ Revision History: #include "ast/rewriter/seq_rewriter.h" #include "util/union_find.h" #include "util/obj_ref_hashtable.h" +#include "smt/smt_theory.h" +#include "smt/smt_arith_value.h" +#include "smt/theory_seq_empty.h" namespace smt { @@ -344,13 +345,15 @@ namespace smt { bool m_incomplete; // is the solver (clearly) incomplete for the fragment. expr_ref_vector m_int_string; obj_map m_si_axioms; - obj_hashtable m_length; // is length applied + obj_hashtable m_has_length; // is length applied + expr_ref_vector m_length; // length applications themselves scoped_ptr_vector m_replay; // set of actions to replay model_generator* m_mg; th_rewriter m_rewrite; seq_rewriter m_seq_rewrite; seq_util m_util; arith_util m_autil; + arith_value m_arith_value; th_trail_stack m_trail_stack; stats m_stats; symbol m_prefix, m_suffix, m_accept, m_reject; @@ -557,7 +560,7 @@ namespace smt { bool is_extract_suffix(expr* s, expr* i, expr* l); - bool has_length(expr *e) const { return m_length.contains(e); } + bool has_length(expr *e) const { return m_has_length.contains(e); } void add_length(expr* e); void enforce_length(expr* n); bool enforce_length(expr_ref_vector const& es, vector& len); diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 18267c4fc..0e5393ac7 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -4874,9 +4874,10 @@ namespace smt { return false; } - arith_value v(get_context()); + arith_value v(get_manager()); + v.init(&get_context()); bool strict; - return v.get_lo(_e, lo, strict); + return v.get_lo_equiv(_e, lo, strict); } bool theory_str::upper_bound(expr* _e, rational& hi) { @@ -4885,9 +4886,10 @@ namespace smt { return false; } - arith_value v(get_context()); + arith_value v(get_manager()); + v.init(&get_context()); bool strict; - return v.get_up(_e, hi, strict); + return v.get_up_equiv(_e, hi, strict); } bool theory_str::get_len_value(expr* e, rational& val) { From 1d4d95aea2698b97a3cf94889058b0b65e6da41e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 29 Nov 2018 16:10:02 -0800 Subject: [PATCH 042/318] fix #1989 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_lra.cpp | 52 ++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index a62c82aeb..ddf3e6fd2 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -2672,14 +2672,12 @@ public: if (propagate_eqs()) { rational const& value = b.get_value(); if (k == lp::GE) { - set_lower_bound(vi, ci, value); - if (has_upper_bound(vi, ci, value)) { + if (set_lower_bound(vi, ci, value) && has_upper_bound(vi, ci, value)) { fixed_var_eh(b.get_var(), value); } } else if (k == lp::LE) { - set_upper_bound(vi, ci, value); - if (has_lower_bound(vi, ci, value)) { + if (set_upper_bound(vi, ci, value) && has_lower_bound(vi, ci, value)) { fixed_var_eh(b.get_var(), value); } } @@ -2698,25 +2696,39 @@ public: bool use_tableau() const { return lp_params(ctx().get_params()).simplex_strategy() < 2; } - void set_upper_bound(lp::var_index vi, lp::constraint_index ci, rational const& v) { set_bound(vi, ci, v, false); } + bool set_upper_bound(lp::var_index vi, lp::constraint_index ci, rational const& v) { return set_bound(vi, ci, v, false); } - void set_lower_bound(lp::var_index vi, lp::constraint_index ci, rational const& v) { set_bound(vi, ci, v, true); } + bool set_lower_bound(lp::var_index vi, lp::constraint_index ci, rational const& v) { return set_bound(vi, ci, v, true); } - void set_bound(lp::var_index vi, lp::constraint_index ci, rational const& v, bool is_lower) { - if (!m_solver->is_term(vi)) { + bool set_bound(lp::var_index vi, lp::constraint_index ci, rational const& v, bool is_lower) { + + if (m_solver->is_term(vi)) { + lp::var_index ti = m_solver->adjust_term_index(vi); + auto& vec = is_lower ? m_lower_terms : m_upper_terms; + if (vec.size() <= ti) { + vec.resize(ti + 1, constraint_bound(UINT_MAX, rational())); + } + constraint_bound& b = vec[ti]; + if (b.first == UINT_MAX || (is_lower? b.second < v : b.second > v)) { + TRACE("arith", tout << "tighter bound " << vi << "\n";); + ctx().push_trail(vector_value_trail(vec, ti)); + b.first = ci; + b.second = v; + } + return true; + } + else { + TRACE("arith", tout << "not a term " << vi << "\n";); // m_solver already tracks bounds on proper variables, but not on terms. - return; - } - lp::var_index ti = m_solver->adjust_term_index(vi); - auto& vec = is_lower ? m_lower_terms : m_upper_terms; - if (vec.size() <= ti) { - vec.resize(ti + 1, constraint_bound(UINT_MAX, rational())); - } - constraint_bound& b = vec[ti]; - if (b.first == UINT_MAX || (is_lower? b.second < v : b.second > v)) { - ctx().push_trail(vector_value_trail(vec, ti)); - b.first = ci; - b.second = v; + bool is_strict = false; + rational b; + if (is_lower) { + return m_solver->has_lower_bound(vi, ci, b, is_strict) && !is_strict && b == v; + } + else { + return m_solver->has_upper_bound(vi, ci, b, is_strict) && !is_strict && b == v; + } + } } From 656769819960bdcd2715a002625badd7b46c53d6 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Fri, 30 Nov 2018 08:10:49 +0700 Subject: [PATCH 043/318] Fix initialization order on theory_seq. --- src/smt/theory_seq.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 40ce87e13..04abe5949 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -208,8 +208,8 @@ theory_seq::theory_seq(ast_manager& m, theory_seq_params const & params): m_axioms(m), m_axioms_head(0), m_int_string(m), - m_mg(nullptr), m_length(m), + m_mg(nullptr), m_rewrite(m), m_seq_rewrite(m), m_util(m), From 38ca9ddfeb1f07bad5264d2879c440a007acfdc8 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Fri, 30 Nov 2018 08:42:01 +0700 Subject: [PATCH 044/318] Swapped significand and exponent in call to Context.mkFPNumeral. Fixes #973. --- src/api/java/Context.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/java/Context.java b/src/api/java/Context.java index ede494598..ee7536eeb 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -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); } From afc9de960c6d495da52700f2ef3e6e534454c03d Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Fri, 30 Nov 2018 08:42:28 +0700 Subject: [PATCH 045/318] Improve JavaDoc. --- src/api/java/Context.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/api/java/Context.java b/src/api/java/Context.java index ee7536eeb..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 From 3db73e442c13c76185fe4c271234448d7fddc7c2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 29 Nov 2018 21:04:43 -0800 Subject: [PATCH 046/318] reset max unfolding literal on backtrack Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 04abe5949..4ff0fb7bc 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -5550,6 +5550,7 @@ void theory_seq::add_theory_assumptions(expr_ref_vector & assumptions) { if (m_util.has_re()) { expr_ref dlimit(m); dlimit = mk_max_unfolding_depth(); + m_trail_stack.push(value_trail(m_max_unfolding_lit)); m_max_unfolding_lit = mk_literal(dlimit); assumptions.push_back(dlimit); } From fbc33b20c869ece56ee6b7a985e846b61a02a14b Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Fri, 30 Nov 2018 19:52:57 +0700 Subject: [PATCH 047/318] cmake: Allow saving clang's optimization records. This gives some insight into what the compiler has decided to do or not do. --- CMakeLists.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index bc5eecdef..34d2c689d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -425,6 +425,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). ################################################################################ From 3149d7f7a4962dc9865999b28d829972786fce2e Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Fri, 30 Nov 2018 22:19:30 +0700 Subject: [PATCH 048/318] Fix typos. --- src/ast/datatype_decl_plugin.cpp | 2 +- src/math/realclosure/realclosure.cpp | 10 +++++----- src/sat/tactic/sat_tactic.cpp | 2 +- src/smt/smt_setup.cpp | 2 +- src/smt/theory_str.cpp | 26 +++++++++++++------------- src/tactic/sls/sls_engine.cpp | 2 +- src/test/lp/smt_reader.h | 4 ++-- 7 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index 9cb685ccc..0271d8311 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -682,7 +682,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/math/realclosure/realclosure.cpp b/src/math/realclosure/realclosure.cpp index 0bc3b43d3..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; diff --git a/src/sat/tactic/sat_tactic.cpp b/src/sat/tactic/sat_tactic.cpp index ef8a9e77e..e6369a918 100644 --- a/src/sat/tactic/sat_tactic.cpp +++ b/src/sat/tactic/sat_tactic.cpp @@ -105,7 +105,7 @@ class sat_tactic : public tactic { else { // get simplified problem. #if 0 - IF_VERBOSE(TACTIC_VERBOSITY_LVL, verbose_stream() << "\"formula constains interpreted atoms, recovering formula from sat solver...\"\n";); + IF_VERBOSE(TACTIC_VERBOSITY_LVL, verbose_stream() << "\"formula constrains interpreted atoms, recovering formula from sat solver...\"\n";); #endif m_solver.pop_to_base_level(); ref mc; diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 2cf0e2651..a6b27784f 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -209,7 +209,7 @@ namespace smt { static void check_no_arithmetic(static_features const & st, char const * logic) { if (st.m_num_arith_ineqs > 0 || st.m_num_arith_terms > 0 || st.m_num_arith_eqs > 0) - throw default_exception("Benchmark constains arithmetic, but specified logic does not support it."); + throw default_exception("Benchmark constrains arithmetic, but specified logic does not support it."); } void setup::setup_QF_UF() { diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 0e5393ac7..2ae445561 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -9424,15 +9424,15 @@ namespace smt { if (lrConstrainedMap.find(var) == lrConstrainedMap.end()) { freeVarMap[var] = 1; } else { - int lrConstainted = 0; + int lrConstrained = 0; std::map::iterator lrit = freeVarMap.begin(); for (; lrit != freeVarMap.end(); lrit++) { if (lrConstrainedMap[var].find(lrit->first) != lrConstrainedMap[var].end()) { - lrConstainted = 1; + lrConstrained = 1; break; } } - if (lrConstainted == 0) { + if (lrConstrained == 0) { freeVarMap[var] = 1; } } @@ -9451,15 +9451,15 @@ namespace smt { if (lrConstrainedMap.find(var) == lrConstrainedMap.end()) { freeVarMap[var] = 1; } else { - int lrConstainted = 0; + int lrConstrained = 0; std::map::iterator lrit = freeVarMap.begin(); for (; lrit != freeVarMap.end(); lrit++) { if (lrConstrainedMap[var].find(lrit->first) != lrConstrainedMap[var].end()) { - lrConstainted = 1; + lrConstrained = 1; break; } } - if (lrConstainted == 0) { + if (lrConstrained == 0) { freeVarMap[var] = 1; } } @@ -9471,15 +9471,15 @@ namespace smt { if (lrConstrainedMap.find(var) == lrConstrainedMap.end()) { freeVarMap[var] = 1; } else { - int lrConstainted = 0; + int lrConstrained = 0; std::map::iterator lrit = freeVarMap.begin(); for (; lrit != freeVarMap.end(); lrit++) { if (lrConstrainedMap[var].find(lrit->first) != lrConstrainedMap[var].end()) { - lrConstainted = 1; + lrConstrained = 1; break; } } - if (lrConstainted == 0) { + if (lrConstrained == 0) { freeVarMap[var] = 1; } } @@ -9500,15 +9500,15 @@ namespace smt { if (lrConstrainedMap.find(var) == lrConstrainedMap.end()) { freeVarMap[var] = 1; } else { - int lrConstainted = 0; + int lrConstrained = 0; std::map::iterator lrit = freeVarMap.begin(); for (; lrit != freeVarMap.end(); lrit++) { if (lrConstrainedMap[var].find(lrit->first) != lrConstrainedMap[var].end()) { - lrConstainted = 1; + lrConstrained = 1; break; } } - if (lrConstainted == 0) { + if (lrConstrained == 0) { freeVarMap[var] = 1; } } @@ -9762,7 +9762,7 @@ namespace smt { expr_ref concatlenExpr (mk_strlen(concat), m) ; bool allLeafResolved = true; if (! get_arith_value(concatlenExpr, lenValue)) { - // the length fo concat is unresolved yet + // the length of concat is unresolved yet if (get_len_value(concat, lenValue)) { // but all leaf nodes have length information TRACE("str", tout << "* length pop-up: " << mk_ismt2_pp(concat, m) << "| = " << lenValue << std::endl;); diff --git a/src/tactic/sls/sls_engine.cpp b/src/tactic/sls/sls_engine.cpp index 2aeb355ed..f55aa41aa 100644 --- a/src/tactic/sls/sls_engine.cpp +++ b/src/tactic/sls/sls_engine.cpp @@ -492,7 +492,7 @@ lbool sls_engine::search() { score = m_tracker.get_top_sum(); - // update assertion weights if a weigthing is enabled (sp < 1024) + // update assertion weights if a weighting is enabled (sp < 1024) if (m_paws) { for (unsigned i = 0; i < sz; i++) diff --git a/src/test/lp/smt_reader.h b/src/test/lp/smt_reader.h index 5d386862c..4bce99765 100644 --- a/src/test/lp/smt_reader.h +++ b/src/test/lp/smt_reader.h @@ -193,14 +193,14 @@ namespace lp { } } - void adjust_rigth_side(formula_constraint & /* c*/, lisp_elem & /*el*/) { + void adjust_right_side(formula_constraint & /* c*/, lisp_elem & /*el*/) { // lp_assert(el.m_head == "0"); // do nothing for the time being } void set_constraint_coeffs(formula_constraint & c, lisp_elem & el) { lp_assert(el.m_elems.size() == 2); set_constraint_coeffs_on_coeff_element(c, el.m_elems[0]); - adjust_rigth_side(c, el.m_elems[1]); + adjust_right_side(c, el.m_elems[1]); } From dbfeeb8b1c58be0e2b0c868b7df6facb480c2d5b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 30 Nov 2018 07:43:42 -0800 Subject: [PATCH 049/318] fix #1994 Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 389cdb19b..c3bbe4d1d 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -2160,7 +2160,7 @@ namespace sat { if (is_undef(lit)) { val = l_undef; } - if (is_true(lit)) { + else if (is_true(lit)) { val = l_true; } else { From bcfa8045fabbdf0bab640a3b8082db11f7603604 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Fri, 30 Nov 2018 23:12:21 +0700 Subject: [PATCH 050/318] Sink some values into loops. This removes some dead stores that happen prior to the loop and ensure that no one is looking at the values outside of the loop. --- src/math/polynomial/upolynomial.cpp | 6 ++---- src/smt/theory_lra.cpp | 10 ++++------ 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/math/polynomial/upolynomial.cpp b/src/math/polynomial/upolynomial.cpp index 5a7ed0dc1..0290a5924 100644 --- a/src/math/polynomial/upolynomial.cpp +++ b/src/math/polynomial/upolynomial.cpp @@ -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) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index ddf3e6fd2..c9db3f6b0 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -2283,16 +2283,14 @@ public: iterator lo_inf = begin1, lo_sup = begin1; iterator hi_inf = begin2, hi_sup = begin2; - iterator lo_inf1 = begin1, lo_sup1 = begin1; - iterator hi_inf1 = begin2, hi_sup1 = begin2; bool flo_inf, fhi_inf, flo_sup, fhi_sup; ptr_addr_hashtable visited; for (unsigned i = 0; i < atoms.size(); ++i) { lp_api::bound* a1 = atoms[i]; - lo_inf1 = next_inf(a1, lp_api::lower_t, lo_inf, end, flo_inf); - hi_inf1 = next_inf(a1, lp_api::upper_t, hi_inf, end, fhi_inf); - lo_sup1 = next_sup(a1, lp_api::lower_t, lo_sup, end, flo_sup); - hi_sup1 = next_sup(a1, lp_api::upper_t, hi_sup, end, fhi_sup); + iterator lo_inf1 = next_inf(a1, lp_api::lower_t, lo_inf, end, flo_inf); + iterator hi_inf1 = next_inf(a1, lp_api::upper_t, hi_inf, end, fhi_inf); + iterator lo_sup1 = next_sup(a1, lp_api::lower_t, lo_sup, end, flo_sup); + iterator hi_sup1 = next_sup(a1, lp_api::upper_t, hi_sup, end, fhi_sup); if (lo_inf1 != end) lo_inf = lo_inf1; if (lo_sup1 != end) lo_sup = lo_sup1; if (hi_inf1 != end) hi_inf = hi_inf1; From c51caad5ad606747b050fa5e2bf247184397f4cf Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Fri, 30 Nov 2018 23:12:55 +0700 Subject: [PATCH 051/318] Remove duplicate initialization of a sort variable. --- src/smt/theory_bv.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index 33207d15a..0f4a6480b 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -1083,7 +1083,6 @@ namespace smt { for (unsigned i = 0; i <= num_args; i++) { expr* arg = (i == num_args)?n:n->get_arg(i); sort* s = get_manager().get_sort(arg); - s = get_manager().get_sort(arg); if (m_util.is_bv_sort(s) && m_util.get_bv_size(arg) > m_params.m_bv_blast_max_size) { if (!m_approximates_large_bvs) { TRACE("bv", tout << "found large size bit-vector:\n" << mk_pp(n, get_manager()) << "\n";); From 2faf5ef995ad69dc7faa8ee168b89d2b25345681 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Fri, 30 Nov 2018 23:13:22 +0700 Subject: [PATCH 052/318] Remove unused iPos. This was incremented, but never actually used, so remove it. --- src/smt/theory_str.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 2ae445561..bd0885fa4 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -7501,15 +7501,12 @@ namespace smt { expr_ref newConcat(m); if (arg1 != a1 || arg2 != a2) { TRACE("str", tout << "resolved concat argument(s) to eqc string constants" << std::endl;); - int iPos = 0; expr_ref_vector item1(m); if (a1 != arg1) { item1.push_back(ctx.mk_eq_atom(a1, arg1)); - iPos += 1; } if (a2 != arg2) { item1.push_back(ctx.mk_eq_atom(a2, arg2)); - iPos += 1; } expr_ref implyL1(mk_and(item1), m); newConcat = mk_concat(arg1, arg2); From a3ece29628501b405cb065f535ab0a003672fec0 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Sat, 1 Dec 2018 20:39:03 +0700 Subject: [PATCH 053/318] Remove include of immintrin.h. This file doesn't appear to be used and isn't available on all platforms. --- src/util/mpz.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index 32a074eb3..47c88560c 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -30,7 +30,6 @@ Revision History: #else #error No multi-precision library selected. #endif -#include // Available GCD algorithms // #define EUCLID_GCD From 150fe881ce968427fbf7b13c1b2a794ea350fa5d Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Sat, 1 Dec 2018 21:06:16 +0700 Subject: [PATCH 054/318] Fix typo. --- src/util/hwf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/hwf.cpp b/src/util/hwf.cpp index 32b1343e3..e6393adbd 100644 --- a/src/util/hwf.cpp +++ b/src/util/hwf.cpp @@ -303,7 +303,7 @@ void hwf_manager::round_to_integral(mpf_rounding_mode rm, hwf const & x, hwf & o // CMW: modf is not the right function here. // modf(x.value, &o.value); - // According to the Intel Architecture manual, the x87-instrunction FRNDINT is the + // According to the Intel Architecture manual, the x87-instruction FRNDINT is the // same in 32-bit and 64-bit mode. The _mm_round_* intrinsics are SSE4 extensions. #ifdef _WINDOWS #if defined(USE_INTRINSICS) && \ From dad58073d33c1459ce1abc9a784b7d53e548e651 Mon Sep 17 00:00:00 2001 From: Travis Nielsen Date: Sat, 1 Dec 2018 16:47:19 -0600 Subject: [PATCH 055/318] Fix typo --- scripts/mk_genfile_common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_genfile_common.py b/scripts/mk_genfile_common.py index c42eaf86d..a65b41026 100644 --- a/scripts/mk_genfile_common.py +++ b/scripts/mk_genfile_common.py @@ -719,7 +719,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') From a0a940f9388196667e3c7b7d67714498e989217b Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Sun, 2 Dec 2018 13:58:31 +0700 Subject: [PATCH 056/318] Remove unused THREAD_LOCAL macro. --- src/util/util.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/util/util.h b/src/util/util.h index b9f3bdc28..0ca02bc84 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -63,14 +63,6 @@ static_assert(sizeof(int64_t) == 8, "64 bits"); #define VEC2PTR(_x_) ((_x_).size() ? &(_x_)[0] : 0) -#ifdef _WINDOWS -// Disable thread local declspec as it seems to not work downlevel. -// #define THREAD_LOCAL __declspec(thread) -#define THREAD_LOCAL -#else -#define THREAD_LOCAL -#endif - #ifdef _MSC_VER # define STD_CALL __cdecl #else From a332eb10bc938909f75ace5780541e2ac83e0aff Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Sun, 2 Dec 2018 22:10:37 +0700 Subject: [PATCH 057/318] Use C++11 thread_local for portability. This should work on all supported compilers rather than using __declspec(thread) and __thread. --- src/util/memory_manager.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/util/memory_manager.cpp b/src/util/memory_manager.cpp index 148306fbd..5d494834e 100644 --- a/src/util/memory_manager.cpp +++ b/src/util/memory_manager.cpp @@ -241,15 +241,8 @@ void * memory::allocate(char const* file, int line, char const* obj, size_t s) { // when the local counter > SYNCH_THRESHOLD #define SYNCH_THRESHOLD 100000 -#ifdef _WINDOWS -// Actually this is VS specific instead of Windows specific. -__declspec(thread) long long g_memory_thread_alloc_size = 0; -__declspec(thread) long long g_memory_thread_alloc_count = 0; -#else -// GCC style -__thread long long g_memory_thread_alloc_size = 0; -__thread long long g_memory_thread_alloc_count = 0; -#endif +thread_local long long g_memory_thread_alloc_size = 0; +thread_local long long g_memory_thread_alloc_count = 0; static void synchronize_counters(bool allocating) { #ifdef PROFILE_MEMORY From f40eed99f7115654b0672f6bd8983ef139896c05 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Sun, 2 Dec 2018 23:48:46 +0700 Subject: [PATCH 058/318] Remove unused nl_purify_tactic.cpp This file wasn't built and won't compile as the header for it is missing. Most of the related code was removed in df6b1a707ebc406bf47bc9ed1bdbeb98248ca39c. --- src/tactic/nlsat_smt/nl_purify_tactic.cpp | 799 ---------------------- src/tactic/tactic.h | 1 - 2 files changed, 800 deletions(-) delete mode 100644 src/tactic/nlsat_smt/nl_purify_tactic.cpp diff --git a/src/tactic/nlsat_smt/nl_purify_tactic.cpp b/src/tactic/nlsat_smt/nl_purify_tactic.cpp deleted file mode 100644 index a02c2d327..000000000 --- a/src/tactic/nlsat_smt/nl_purify_tactic.cpp +++ /dev/null @@ -1,799 +0,0 @@ -/*++ -Copyright (c) 2015 Microsoft Corporation - -Module Name: - - nl_purify_tactic.cpp - -Abstract: - - Tactic for purifying quantifier-free formulas that mix QF_NRA and other theories. - It is designed to allow cooperation between the nlsat solver and other theories - in a decoupled way. - - Let goal be formula F. - Let NL goal be formula G. - Assume F is in NNF. - Assume F does not contain mix of real/integers. - Assume F is quantifier-free (please, otherwise we need to reprocess from instantiated satisfiable formula) - - For each atomic nl formula f, - - introduce a propositional variable p - - replace f by p - - add clauses p => f to G - - For each interface term t, - - introduce interface variable v (or use t if it is already a variable) - - replace t by v - - Check satisfiability of G. - If satisfiable, then check assignment to p and interface equalities on F - If unsat: - Retrieve core and add core to G. - else: - For interface equalities from model of F that are not equal in G, add - For interface variables that are equal under one model, but not the other model, - create interface predicate p_vw => v = w, add to both F, G. - Add interface equations to assumptions, recheck F. - If unsat retrieve core add to G. - -Author: - - Nikolaj Bjorner (nbjorner) 2015-5-5. - -Revision History: - ---*/ -#include "tactic/tactical.h" -#include "tactic/nlsat_smt/nl_purify_tactic.h" -#include "smt/tactic/smt_tactic.h" -#include "ast/rewriter/rewriter.h" -#include "nlsat/tactic/nlsat_tactic.h" -#include "tactic/filter_model_converter.h" -#include "util/obj_pair_hashtable.h" -#include "ast/rewriter/rewriter_def.h" -#include "ast/ast_pp.h" -#include "util/trace.h" -#include "smt/smt_solver.h" -#include "solver/solver.h" -#include "model/model_smt2_pp.h" -#include "ast/rewriter/expr_safe_replace.h" -#include "ast/ast_util.h" -#include "solver/solver2tactic.h" - -class nl_purify_tactic : public tactic { - - enum polarity_t { - pol_pos, - pol_neg, - pol_dual - }; - - ast_manager & m; - arith_util m_util; - params_ref m_params; - bool m_produce_proofs; - ref m_fmc; - tactic_ref m_nl_tac; // nlsat tactic - goal_ref m_nl_g; // nlsat goal - ref m_solver; // SMT solver - expr_ref_vector m_eq_preds; // predicates for equality between pairs of interface variables - svector m_eq_values; // truth value of the equality predicates in nlsat - app_ref_vector m_new_reals; // interface real variables - app_ref_vector m_new_preds; // abstraction predicates for smt_solver (hide real constraints) - expr_ref_vector m_asms; // assumptions to pass to SMT solver - ptr_vector m_ctx_asms; // assumptions passed by context - obj_hashtable m_ctx_asms_set; // assumptions passed by context - obj_hashtable m_used_asms; - obj_map m_bool2dep; - obj_pair_map m_eq_pairs; // map pairs of interface variables to auxiliary predicates - obj_map m_interface_cache; // map of compound real expression to interface variable. - obj_map m_polarities; // polarities of sub-expressions - -public: - struct rw_cfg : public default_rewriter_cfg { - enum mode_t { - mode_interface_var, - mode_bool_preds - }; - ast_manager& m; - nl_purify_tactic & m_owner; - app_ref_vector& m_new_reals; - app_ref_vector& m_new_preds; - obj_map& m_polarities; - obj_map& m_interface_cache; - expr_ref_vector m_args; - proof_ref_vector m_proofs; - mode_t m_mode; - - rw_cfg(nl_purify_tactic & o): - m(o.m), - m_owner(o), - m_new_reals(o.m_new_reals), - m_new_preds(o.m_new_preds), - m_polarities(o.m_polarities), - m_interface_cache(o.m_interface_cache), - m_args(m), - m_proofs(m), - m_mode(mode_interface_var) { - } - - virtual ~rw_cfg() {} - - arith_util & u() { return m_owner.m_util; } - - expr * mk_interface_var(expr* arg, proof_ref& arg_pr) { - expr* r; - if (m_interface_cache.find(arg, r)) { - return r; - } - if (is_uninterp_const(arg)) { - m_interface_cache.insert(arg, arg); - return arg; - } - r = m.mk_fresh_const(nullptr, u().mk_real()); - m_new_reals.push_back(to_app(r)); - m_owner.m_fmc->insert(to_app(r)->get_decl()); - m_interface_cache.insert(arg, r); - expr_ref eq(m); - eq = m.mk_eq(r, arg); - if (is_real_expression(arg)) { - m_owner.m_nl_g->assert_expr(eq); // m.mk_oeq(r, arg) - } - else { - m_owner.m_solver->assert_expr(eq); - } - if (m_owner.m_produce_proofs) { - arg_pr = m.mk_oeq(arg, r); - } - return r; - } - - bool is_real_expression(expr* e) { - return is_app(e) && (to_app(e)->get_family_id() == u().get_family_id()); - } - - void mk_interface_bool(func_decl * f, unsigned num, expr* const* args, expr_ref& result, proof_ref& pr) { - expr_ref old_pred(m.mk_app(f, num, args), m); - polarity_t pol = m_polarities.find(old_pred); - result = m.mk_fresh_const(nullptr, m.mk_bool_sort()); - m_polarities.insert(result, pol); - m_new_preds.push_back(to_app(result)); - m_owner.m_fmc->insert(to_app(result)->get_decl()); - if (pol != pol_neg) { - m_owner.m_nl_g->assert_expr(m.mk_or(m.mk_not(result), old_pred)); - } - if (pol != pol_pos) { - m_owner.m_nl_g->assert_expr(m.mk_or(result, m.mk_not(old_pred))); - } - if (m_owner.m_produce_proofs) { - pr = m.mk_oeq(old_pred, result); - } - TRACE("nlsat_smt", tout << old_pred << " : " << result << "\n";); - } - - bool reduce_quantifier(quantifier * old_q, - expr * new_body, - expr * const * new_patterns, - expr * const * new_no_patterns, - expr_ref & result, - proof_ref & result_pr) { - throw tactic_exception("quantifiers are not supported in mixed-mode nlsat engine"); - } - - br_status reduce_app(func_decl * f, unsigned num, expr* const* args, expr_ref& result, proof_ref & pr) { - if (m_mode == mode_bool_preds) { - return reduce_app_bool(f, num, args, result, pr); - } - else { - return reduce_app_real(f, num, args, result, pr); - } - } - - br_status reduce_app_bool(func_decl * f, unsigned num, expr* const* args, expr_ref& result, proof_ref & pr) { - if (f->get_family_id() == m.get_basic_family_id()) { - if (f->get_decl_kind() == OP_EQ && u().is_real(args[0])) { - mk_interface_bool(f, num, args, result, pr); - return BR_DONE; - } - else { - return BR_FAILED; - } - } - if (f->get_family_id() == u().get_family_id()) { - switch (f->get_decl_kind()) { - case OP_LE: case OP_GE: case OP_LT: case OP_GT: - // these are the only real cases of non-linear atomic formulas besides equality. - mk_interface_bool(f, num, args, result, pr); - return BR_DONE; - default: - return BR_FAILED; - } - } - return BR_FAILED; - } - - // (+ (f x) y) - // (f (+ x y)) - // - bool is_arith_op(expr* e) { - return is_app(e) && to_app(e)->get_family_id() == u().get_family_id(); - } - - br_status reduce_app_real(func_decl * f, unsigned num, expr* const* args, expr_ref& result, proof_ref & pr) { - bool has_interface = false; - bool is_arith = false; - if (f->get_family_id() == u().get_family_id()) { - switch (f->get_decl_kind()) { - case OP_NUM: - case OP_IRRATIONAL_ALGEBRAIC_NUM: - return BR_FAILED; - default: - is_arith = true; - break; - } - } - m_args.reset(); - m_proofs.reset(); - for (unsigned i = 0; i < num; ++i) { - expr* arg = args[i]; - proof_ref arg_pr(m); - if (is_arith && !is_arith_op(arg)) { - has_interface = true; - m_args.push_back(mk_interface_var(arg, arg_pr)); - } - else if (!is_arith && u().is_real(arg)) { - has_interface = true; - m_args.push_back(mk_interface_var(arg, arg_pr)); - } - else { - m_args.push_back(arg); - } - if (arg_pr) { - m_proofs.push_back(arg_pr); - } - } - if (has_interface) { - result = m.mk_app(f, num, m_args.c_ptr()); - if (m_owner.m_produce_proofs) { - pr = m.mk_oeq_congruence(m.mk_app(f, num, args), to_app(result), m_proofs.size(), m_proofs.c_ptr()); - } - TRACE("nlsat_smt", tout << result << "\n";); - return BR_DONE; - } - else { - return BR_FAILED; - } - } - }; - -private: - - class rw : public rewriter_tpl { - rw_cfg m_cfg; - public: - rw(nl_purify_tactic & o): - rewriter_tpl(o.m, o.m_produce_proofs, m_cfg), - m_cfg(o) { - } - void set_bool_mode() { - m_cfg.m_mode = rw_cfg::mode_bool_preds; - } - void set_interface_var_mode() { - m_cfg.m_mode = rw_cfg::mode_interface_var; - } - }; - - - arith_util & u() { return m_util; } - - void check_point() { - if (m.canceled()) { - throw tactic_exception(Z3_CANCELED_MSG); - } - } - - void display_result(std::ostream& out, goal_ref_buffer const& result) { - for (unsigned i = 0; i < result.size(); ++i) { - result[i]->display_with_dependencies(out << "goal\n"); - } - } - - void update_eq_values(model_ref& mdl) { - expr_ref tmp(m); - for (unsigned i = 0; i < m_eq_preds.size(); ++i) { - expr* pred = m_eq_preds[i].get(); - m_eq_values[i] = l_undef; - if (mdl->eval(pred, tmp)) { - if (m.is_true(tmp)) { - m_eq_values[i] = l_true; - } - else if (m.is_false(tmp)) { - m_eq_values[i] = l_false; - } - } - } - } - - void solve( - goal_ref const& g, - goal_ref_buffer& result, - expr_dependency_ref& core, - model_converter_ref& mc) { - - while (true) { - check_point(); - TRACE("nlsat_smt", m_solver->display(tout << "SMT:\n"); m_nl_g->display(tout << "\nNL:\n"); ); - goal_ref tmp_nl = alloc(goal, m, true, false); - model_converter_ref nl_mc; - proof_converter_ref nl_pc; - expr_dependency_ref nl_core(m); - result.reset(); - tmp_nl->copy_from(*m_nl_g.get()); - (*m_nl_tac)(tmp_nl, result, nl_mc, nl_pc, nl_core); - - if (is_decided_unsat(result)) { - core2result(core, g, result); - TRACE("nlsat_smt", tout << "unsat\n";); - break; - } - if (!is_decided_sat(result)) { - TRACE("nlsat_smt", tout << "not a unit\n";); - break; - } - // extract evaluation on interface variables. - // assert booleans that evaluate to true. - // assert equalities between equal interface real variables. - - model_ref mdl_nl, mdl_smt; - if (nl_mc.get()) { - model_converter2model(m, nl_mc.get(), mdl_nl); - update_eq_values(mdl_nl); - enforce_equalities(mdl_nl, m_nl_g); - - setup_assumptions(mdl_nl); - - TRACE("nlsat_smt", - model_smt2_pp(tout << "nl model\n", m, *mdl_nl.get(), 0); - m_solver->display(tout << "smt goal:\n"); tout << "\n";); - } - result.reset(); - lbool r = m_solver->check_sat(m_asms.size(), m_asms.c_ptr()); - if (r == l_false) { - // extract the core from the result - ptr_vector ecore, asms; - expr_ref_vector clause(m); - expr_ref fml(m); - get_unsat_core(ecore, asms); - - // - // assumptions should also be used for the nlsat tactic, - // but since it does not support assumptions at this time - // we overapproximate the necessary core and accumulate - // all assumptions that are ever used. - // - for (unsigned i = 0; i < asms.size(); ++i) { - m_used_asms.insert(asms[i]); - } - if (ecore.empty()) { - core2result(core, g, result); - break; - } - for (unsigned i = 0; i < ecore.size(); ++i) { - clause.push_back(mk_not(m, ecore[i])); - } - fml = mk_or(m, clause.size(), clause.c_ptr()); - m_nl_g->assert_expr(fml); - continue; - } - else if (r == l_true) { - m_solver->get_model(mdl_smt); - if (enforce_equalities(mdl_smt, m_nl_g)) { - // SMT enforced a new equality that wasn't true for nlsat. - continue; - } - TRACE("nlsat_smt", - m_fmc->display(tout << "joint state is sat\n"); - nl_mc->display(tout << "nl\n");); - if (mdl_nl.get()) { - merge_models(*mdl_nl.get(), mdl_smt); - } - mc = m_fmc.get(); - apply(mc, mdl_smt, 0); - mc = model2model_converter(mdl_smt.get()); - result.push_back(alloc(goal, m)); - } - else { - TRACE("nlsat_smt", tout << "unknown\n";); - } - break; - } - TRACE("nlsat_smt", display_result(tout, result);); - } - - void get_unsat_core(ptr_vector& core, ptr_vector& asms) { - m_solver->get_unsat_core(core); - for (unsigned i = 0; i < core.size(); ++i) { - if (m_ctx_asms_set.contains(core[i])) { - asms.push_back(core[i]); - core[i] = core.back(); - core.pop_back(); - --i; - } - } - } - - void core2result(expr_dependency_ref & lcore, goal_ref const& g, goal_ref_buffer& result) { - result.reset(); - proof * pr = nullptr; - lcore = nullptr; - g->reset(); - obj_hashtable::iterator it = m_used_asms.begin(), end = m_used_asms.end(); - for (; it != end; ++it) { - lcore = m.mk_join(lcore, m.mk_leaf(m_bool2dep.find(*it))); - } - g->assert_expr(m.mk_false(), pr, lcore); - TRACE("nlsat_smt", g->display_with_dependencies(tout);); - result.push_back(g.get()); - } - - void setup_assumptions(model_ref& mdl) { - m_asms.reset(); - m_asms.append(m_ctx_asms.size(), m_ctx_asms.c_ptr()); - app_ref_vector const& fresh_preds = m_new_preds; - expr_ref tmp(m); - for (unsigned i = 0; i < fresh_preds.size(); ++i) { - expr* pred = fresh_preds[i]; - if (mdl->eval(pred, tmp)) { - polarity_t pol = m_polarities.find(pred); - // if assumption literals are used to satisfy NL state, - // we have to assume them when satisfying SMT state - if (pol != pol_neg && m.is_false(tmp)) { - m_asms.push_back(m.mk_not(pred)); - } - else if (pol != pol_pos && m.is_true(tmp)) { - m_asms.push_back(pred); - } - } - } - for (unsigned i = 0; i < m_eq_preds.size(); ++i) { - expr* pred = m_eq_preds[i].get(); - switch (m_eq_values[i]) { - case l_true: - m_asms.push_back(pred); - break; - case l_false: - m_asms.push_back(m.mk_not(pred)); - break; - default: - break; - } - } - TRACE("nlsat_smt", - tout << "assumptions:\n" << m_asms << "\n";); - } - - bool enforce_equalities(model_ref& mdl, goal_ref const& nl_g) { - TRACE("nlsat_smt", tout << "Enforce equalities " << m_interface_cache.size() << "\n";); - bool new_equality = false; - expr_ref_vector nums(m); - obj_map num2var; - obj_map::iterator it = m_interface_cache.begin(), end = m_interface_cache.end(); - for (; it != end; ++it) { - expr_ref r(m); - expr* v, *w, *pred; - w = it->m_value; - VERIFY(mdl->eval(w, r)); - TRACE("nlsat_smt", tout << mk_pp(w, m) << " |-> " << r << "\n";); - nums.push_back(r); - if (num2var.find(r, v)) { - if (!m_eq_pairs.find(v, w, pred)) { - pred = m.mk_fresh_const(nullptr, m.mk_bool_sort()); - m_eq_preds.push_back(pred); - m_eq_values.push_back(l_true); - m_fmc->insert(to_app(pred)->get_decl()); - nl_g->assert_expr(m.mk_or(m.mk_not(pred), m.mk_eq(w, v))); - nl_g->assert_expr(m.mk_or(pred, m.mk_not(m.mk_eq(w, v)))); - m_solver->assert_expr(m.mk_iff(pred, m.mk_eq(w, v))); - new_equality = true; - m_eq_pairs.insert(v, w, pred); - } - else { - // interface equality is already enforced. - } - } - else { - num2var.insert(r, w); - } - } - return new_equality; - } - - void merge_models(model const& mdl_nl, model_ref& mdl_smt) { - expr_safe_replace num2num(m); - expr_ref result(m), val2(m); - expr_ref_vector args(m); - unsigned sz = mdl_nl.get_num_constants(); - for (unsigned i = 0; i < sz; ++i) { - func_decl* v = mdl_nl.get_constant(i); - if (u().is_real(v->get_range())) { - expr* val = mdl_nl.get_const_interp(v); - if (mdl_smt->eval(v, val2)) { - if (val != val2) { - num2num.insert(val2, val); - } - } - } - } - sz = mdl_smt->get_num_functions(); - for (unsigned i = 0; i < sz; ++i) { - func_decl* f = mdl_smt->get_function(i); - if (has_real(f)) { - unsigned arity = f->get_arity(); - func_interp* f1 = mdl_smt->get_func_interp(f); - func_interp* f2 = alloc(func_interp, m, f->get_arity()); - for (unsigned j = 0; j < f1->num_entries(); ++j) { - args.reset(); - func_entry const* entry = f1->get_entry(j); - for (unsigned k = 0; k < arity; ++k) { - translate(num2num, entry->get_arg(k), result); - args.push_back(result); - } - translate(num2num, entry->get_result(), result); - f2->insert_entry(args.c_ptr(), result); - } - translate(num2num, f1->get_else(), result); - f2->set_else(result); - mdl_smt->register_decl(f, f2); - } - } - mdl_smt->copy_const_interps(mdl_nl); - } - - bool has_real(func_decl* f) { - for (unsigned i = 0; i < f->get_arity(); ++i) { - if (u().is_real(f->get_domain(i))) return true; - } - return u().is_real(f->get_range()); - } - - void translate(expr_safe_replace& num2num, expr* e, expr_ref& result) { - result = nullptr; - if (e) { - num2num(e, result); - } - } - - void get_polarities(goal const& g) { - ptr_vector forms; - svector pols; - unsigned sz = g.size(); - for (unsigned i = 0; i < sz; ++i) { - forms.push_back(g.form(i)); - pols.push_back(pol_pos); - } - polarity_t p, q; - while (!forms.empty()) { - expr* e = forms.back(); - p = pols.back(); - forms.pop_back(); - pols.pop_back(); - if (m_polarities.find(e, q)) { - if (p == q || q == pol_dual) continue; - p = pol_dual; - } - TRACE("nlsat_smt_verbose", tout << mk_pp(e, m) << "\n";); - m_polarities.insert(e, p); - if (is_quantifier(e) || is_var(e)) { - throw tactic_exception("nl-purify tactic does not support quantifiers"); - } - SASSERT(is_app(e)); - app* a = to_app(e); - func_decl* f = a->get_decl(); - if (f->get_family_id() == m.get_basic_family_id() && p != pol_dual) { - switch(f->get_decl_kind()) { - case OP_NOT: - p = neg(p); - break; - case OP_AND: - case OP_OR: - break; - default: - p = pol_dual; - break; - } - } - else { - p = pol_dual; - } - for (unsigned i = 0; i < a->get_num_args(); ++i) { - forms.push_back(a->get_arg(i)); - pols.push_back(p); - } - } - } - - polarity_t neg(polarity_t p) { - switch (p) { - case pol_pos: return pol_neg; - case pol_neg: return pol_pos; - case pol_dual: return pol_dual; - } - return pol_dual; - } - - polarity_t join(polarity_t p, polarity_t q) { - if (p == q) return p; - return pol_dual; - } - - void rewrite_goal(rw& r, goal_ref const& g) { - r.reset(); - expr_ref new_curr(m); - proof_ref new_pr(m); - unsigned sz = g->size(); - for (unsigned i = 0; i < sz; i++) { - expr * curr = g->form(i); - r(curr, new_curr, new_pr); - if (m_produce_proofs) { - proof * pr = g->pr(i); - new_pr = m.mk_modus_ponens(pr, new_pr); - } - g->update(i, new_curr, new_pr, g->dep(i)); - } - } - - void remove_pure_arith(goal_ref const& g) { - obj_map is_pure; - unsigned sz = g->size(); - for (unsigned i = 0; i < sz; i++) { - expr * curr = g->form(i); - if (is_pure_arithmetic(is_pure, curr)) { - m_nl_g->assert_expr(curr, g->pr(i), g->dep(i)); - g->update(i, m.mk_true(), g->pr(i), g->dep(i)); - } - } - } - - bool is_pure_arithmetic(obj_map& is_pure, expr* e0) { - ptr_vector todo; - todo.push_back(e0); - while (!todo.empty()) { - expr* e = todo.back(); - if (is_pure.contains(e)) { - todo.pop_back(); - continue; - } - if (!is_app(e)) { - todo.pop_back(); - is_pure.insert(e, false); - continue; - } - app* a = to_app(e); - bool pure = false, all_found = true, p; - pure |= (a->get_family_id() == u().get_family_id()) && u().is_real(a); - pure |= (m.is_eq(e) && u().is_real(a->get_arg(0))); - pure |= (a->get_family_id() == u().get_family_id()) && m.is_bool(a) && u().is_real(a->get_arg(0)); - pure |= (a->get_family_id() == m.get_basic_family_id()); - pure |= is_uninterp_const(a) && u().is_real(a); - for (unsigned i = 0; i < a->get_num_args(); ++i) { - if (!is_pure.find(a->get_arg(i), p)) { - todo.push_back(a->get_arg(i)); - all_found = false; - } - else { - pure &= p; - } - } - if (all_found) { - is_pure.insert(e, pure); - todo.pop_back(); - } - } - return is_pure.find(e0); - } - -public: - - nl_purify_tactic(ast_manager & m, params_ref const& p): - m(m), - m_util(m), - m_params(p), - m_fmc(nullptr), - m_nl_tac(mk_nlsat_tactic(m, p)), - m_nl_g(nullptr), - m_solver(mk_smt_solver(m, p, symbol::null)), - m_eq_preds(m), - m_new_reals(m), - m_new_preds(m), - m_asms(m) - {} - - ~nl_purify_tactic() override {} - - void updt_params(params_ref const & p) override { - m_params = p; - } - - tactic * translate(ast_manager& m) override { - return alloc(nl_purify_tactic, m, m_params); - } - - void collect_statistics(statistics & st) const override { - m_nl_tac->collect_statistics(st); - m_solver->collect_statistics(st); - } - - void reset_statistics() override { - m_nl_tac->reset_statistics(); - } - - - void cleanup() override { - m_solver = mk_smt_solver(m, m_params, symbol::null); - m_nl_tac->cleanup(); - m_eq_preds.reset(); - m_eq_values.reset(); - m_new_reals.reset(); - m_new_preds.reset(); - m_eq_pairs.reset(); - m_polarities.reset(); - m_ctx_asms.reset(); - m_ctx_asms_set.reset(); - m_used_asms.reset(); - m_bool2dep.reset(); - } - - void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) override { - - tactic_report report("qfufnl-purify", *g); - TRACE("nlsat_smt", g->display(tout);); - - m_produce_proofs = g->proofs_enabled(); - mc = nullptr; pc = nullptr; core = nullptr; - - fail_if_proof_generation("qfufnra-purify", g); - // fail_if_unsat_core_generation("qfufnra-purify", g); - rw r(*this); - expr_ref_vector clauses(m); - m_nl_g = alloc(goal, m, true, false); - m_fmc = alloc(filter_model_converter, m); - - // first hoist interface variables, - // then annotate subformulas by polarities, - // finally extract polynomial inequalities by - // creating a place-holder predicate inside the - // original goal and extracting pure nlsat clauses. - r.set_interface_var_mode(); - rewrite_goal(r, g); - if (!g->unsat_core_enabled()) { - remove_pure_arith(g); - } - get_polarities(*g.get()); - r.set_bool_mode(); - rewrite_goal(r, g); - - extract_clauses_and_dependencies(g, clauses, m_ctx_asms, m_bool2dep, m_fmc); - - TRACE("nlsat_smt", tout << clauses << "\n";); - - for (unsigned i = 0; i < m_ctx_asms.size(); ++i) { - m_ctx_asms_set.insert(m_ctx_asms[i]); - } - - for (unsigned i = 0; i < clauses.size(); ++i) { - m_solver->assert_expr(clauses[i].get()); - } - g->inc_depth(); - solve(g, result, core, mc); - } -}; - - -tactic * mk_nl_purify_tactic(ast_manager& m, params_ref const& p) { - return alloc(nl_purify_tactic, m, p); -} diff --git a/src/tactic/tactic.h b/src/tactic/tactic.h index 92cc7315f..dd6557dcc 100644 --- a/src/tactic/tactic.h +++ b/src/tactic/tactic.h @@ -78,7 +78,6 @@ protected: friend class nary_tactical; friend class binary_tactical; friend class unary_tactical; - friend class nl_purify_tactic; }; From 742efd5104c67c045172d880154c29b04c133ee7 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Mon, 3 Dec 2018 12:32:45 +0700 Subject: [PATCH 059/318] Remove undef max/min on macOS. This is no longer needed. --- src/util/trace.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/util/trace.h b/src/util/trace.h index 1a245036f..77c66afd4 100644 --- a/src/util/trace.h +++ b/src/util/trace.h @@ -24,10 +24,6 @@ Revision History: #undef max #undef min #endif -#ifdef __APPLE__ -#undef max -#undef min -#endif #include #ifdef _TRACE From a0264c08a872ddb83230be49fc501ae14429797b Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Mon, 3 Dec 2018 22:15:14 +0700 Subject: [PATCH 060/318] Windows builds need immintrin.h Fixes issue #2006. --- src/util/mpz.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index 47c88560c..af95e1a2a 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -45,6 +45,11 @@ Revision History: #define LEHMER_GCD #endif +#ifdef _WINDOWS +// This is needed for _tzcnt_u32 and friends. +#include +#endif + #if defined(__GNUC__) #define _trailing_zeros32(X) __builtin_ctz(X) #else From 2aa7ccc4a9b2f562af00748c5b8c31a210f2b3d0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 3 Dec 2018 08:45:17 -0800 Subject: [PATCH 061/318] hide bit-vector dependencies under seq_util Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 34 +++++------ src/ast/rewriter/seq_rewriter.h | 1 - src/ast/seq_decl_plugin.cpp | 19 +++++++ src/ast/seq_decl_plugin.h | 4 +- src/opt/opt_context.cpp | 1 - src/opt/pb_sls.cpp | 6 +- src/sat/ba_solver.cpp | 2 - src/sat/sat_drat.cpp | 1 - src/sat/sat_model_converter.cpp | 2 +- src/smt/smt_arith_value.cpp | 12 +++- src/smt/smt_arith_value.h | 3 +- src/smt/theory_bv.cpp | 1 + src/smt/theory_jobscheduler.cpp | 2 +- src/smt/theory_seq.cpp | 95 +++++++++++-------------------- src/smt/theory_seq.h | 2 +- src/solver/solver.cpp | 1 - 16 files changed, 89 insertions(+), 97 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index b67163f7c..bbb225387 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -45,14 +45,13 @@ expr_ref sym_expr::accept(expr* e) { 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)) { + seq_util u(m); + unsigned r1, r2, r3; + 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; } @@ -190,7 +189,7 @@ public: }*/ }; -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 +247,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(); @@ -463,14 +461,12 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con * (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; } @@ -1977,15 +1973,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..c2b2227b2 100644 --- a/src/ast/rewriter/seq_rewriter.h +++ b/src/ast/rewriter/seq_rewriter.h @@ -77,7 +77,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; diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 0bfc94e11..2210fc04b 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) { @@ -967,6 +968,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) && 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()); diff --git a/src/ast/seq_decl_plugin.h b/src/ast/seq_decl_plugin.h index 4b23f81d0..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 { @@ -221,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/opt/opt_context.cpp b/src/opt/opt_context.cpp index d418bd437..5d1ec835b 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -1573,7 +1573,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); } } } 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/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 762939b74..b1502d98e 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; } @@ -2606,7 +2605,6 @@ namespace sat { IF_VERBOSE(0, s().display_watches(verbose_stream())); UNREACHABLE(); - exit(1); return false; } } diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index 932e9b35e..529a6bc57 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -288,7 +288,6 @@ namespace sat { display(tout); s.display(tout);); UNREACHABLE(); - exit(0); } } diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index d132f1cd4..17885f4e5 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) { diff --git a/src/smt/smt_arith_value.cpp b/src/smt/smt_arith_value.cpp index 50fe6340a..8dfca3ebb 100644 --- a/src/smt/smt_arith_value.cpp +++ b/src/smt/smt_arith_value.cpp @@ -92,8 +92,18 @@ namespace smt { return false; } + bool arith_value::get_value(expr* e, rational& val) const { + if (!m_ctx->e_internalized(e)) return false; + expr_ref _val(m); + enode* n = m_ctx->get_enode(e); + if (m_tha && m_tha->get_value(n, _val) && a.is_numeral(_val, val)) return true; + if (m_thi && m_thi->get_value(n, _val) && a.is_numeral(_val, val)) return true; + if (m_thr && m_thr->get_value(n, val)) return true; + return false; + } - bool arith_value::get_value(expr* e, rational& val) { + + bool arith_value::get_value_equiv(expr* e, rational& val) const { if (!m_ctx->e_internalized(e)) return false; expr_ref _val(m); enode* next = m_ctx->get_enode(e), *n = next; diff --git a/src/smt/smt_arith_value.h b/src/smt/smt_arith_value.h index ddaa113ea..7fa1ecc31 100644 --- a/src/smt/smt_arith_value.h +++ b/src/smt/smt_arith_value.h @@ -38,9 +38,10 @@ namespace smt { void init(context* ctx); bool get_lo_equiv(expr* e, rational& lo, bool& strict); bool get_up_equiv(expr* e, rational& up, bool& strict); - bool get_value(expr* e, rational& value); + bool get_value_equiv(expr* e, rational& value) const; bool get_lo(expr* e, rational& lo, bool& strict) const; bool get_up(expr* e, rational& up, bool& strict) const; + bool get_value(expr* e, rational& value) const; bool get_fixed(expr* e, rational& value) const; final_check_status final_check(); }; diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index 33207d15a..2cc88b901 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -20,6 +20,7 @@ Revision History: #include "smt/theory_bv.h" #include "ast/ast_ll_pp.h" #include "ast/ast_pp.h" +#include "ast/bv_decl_plugin.h" #include "smt/smt_model_generator.h" #include "util/stats.h" diff --git a/src/smt/theory_jobscheduler.cpp b/src/smt/theory_jobscheduler.cpp index 152eb715b..1499c102d 100644 --- a/src/smt/theory_jobscheduler.cpp +++ b/src/smt/theory_jobscheduler.cpp @@ -576,7 +576,7 @@ namespace smt { arith_value av(get_manager()); av.init(&get_context()); rational val; - if (av.get_value(e, val) && val.is_uint64()) { + if (av.get_value_equiv(e, val) && val.is_uint64()) { return val.get_uint64(); } return 0; diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 4ff0fb7bc..298502fe8 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -3457,9 +3457,8 @@ void theory_seq::add_itos_axiom(expr* e) { void theory_seq::ensure_digit_axiom() { if (m_si_axioms.empty()) { - bv_util bv(m); for (unsigned i = 0; i < 10; ++i) { - expr_ref cnst(bv.mk_numeral(rational('0'+i), bv.mk_sort(8)), m); + expr_ref cnst(m_util.mk_char('0'+i), m); add_axiom(mk_eq(digit2int(cnst), m_autil.mk_int(i), false)); } } @@ -3512,11 +3511,10 @@ bool theory_seq::add_stoi_val_axiom(expr* e) { } literal theory_seq::is_digit(expr* ch) { - bv_util bv(m); literal isd = mk_literal(mk_skolem(symbol("seq.is_digit"), ch, nullptr, nullptr, nullptr, m.mk_bool_sort())); expr_ref d2i = digit2int(ch); - expr_ref _lo(bv.mk_ule(bv.mk_numeral(rational('0'), bv.mk_sort(8)), ch), m); - expr_ref _hi(bv.mk_ule(ch, bv.mk_numeral(rational('9'), bv.mk_sort(8))), m); + expr_ref _lo(m_util.mk_le(m_util.mk_char('0'), ch), m); + expr_ref _hi(m_util.mk_le(ch, m_util.mk_char('9')), m); literal lo = mk_literal(_lo); literal hi = mk_literal(_hi); add_axiom(~lo, ~hi, isd); @@ -3817,18 +3815,17 @@ public: SASSERT(values.size() == m_dependencies.size()); expr_ref_vector args(th.m); unsigned j = 0, k = 0; + rational val; bool is_string = th.m_util.is_string(m_sort); expr_ref result(th.m); if (is_string) { unsigned_vector sbuffer; - bv_util bv(th.m); - rational val; - unsigned sz; + unsigned ch; for (source_t src : m_source) { switch (src) { case unit_source: { - VERIFY(bv.is_numeral(values[j++], val, sz)); - sbuffer.push_back(val.get_unsigned()); + VERIFY(th.m_util.is_const_char(values[j++], ch)); + sbuffer.push_back(ch); break; } case string_source: { @@ -4634,32 +4631,9 @@ static T* get_th_arith(context& ctx, theory_id afid, expr* e) { } } -static bool get_arith_value(context& ctx, theory_id afid, expr* e, expr_ref& v) { - theory_mi_arith* tha = get_th_arith(ctx, afid, e); - if (tha) return tha->get_value(ctx.get_enode(e), v); - theory_i_arith* thi = get_th_arith(ctx, afid, e); - if (thi) return thi->get_value(ctx.get_enode(e), v); - theory_lra* thr = get_th_arith(ctx, afid, e); - if (thr) return thr->get_value(ctx.get_enode(e), v); - TRACE("seq", tout << "no arithmetic theory\n";); - return false; -} bool theory_seq::get_num_value(expr* e, rational& val) const { - context& ctx = get_context(); - expr_ref _val(m); - if (!ctx.e_internalized(e)) - return false; - enode* next = ctx.get_enode(e), *n = next; - do { - if (get_arith_value(ctx, m_autil.get_family_id(), next->get_owner(), _val) && m_autil.is_numeral(_val, val) && val.is_int()) { - return true; - } - next = next->get_next(); - } - while (next != n); - TRACE("seq", tout << "no value for " << mk_pp(e, m) << "\n";); - return false; + return m_arith_value.get_value_equiv(e, val) && val.is_int(); } bool theory_seq::lower_bound(expr* e, rational& lo) const { @@ -4748,9 +4722,7 @@ bool theory_seq::get_length(expr* e, rational& val) const { } else { len = mk_len(c); - if (ctx.e_internalized(len) && - get_arith_value(ctx, m_autil.get_family_id(), len, len_val) && - m_autil.is_numeral(len_val, val1)) { + if (m_arith_value.get_value(len, val1)) { val += val1; } else { @@ -5050,13 +5022,14 @@ void theory_seq::add_axiom(literal l1, literal l2, literal l3, literal l4, liter ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); } -expr* theory_seq::coalesce_chars(expr* const& e) { +expr_ref theory_seq::coalesce_chars(expr* const& e) { context& ctx = get_context(); expr* s; + unsigned ch; + expr_ref result(m); if (m_util.str.is_concat(e)) { - expr_ref_vector concats(m); + expr_ref_vector rs(m), concats(m); m_util.str.get_concat(e, concats); - expr_ref_vector result(m); for (unsigned i = 0; i < concats.size(); ++i) { expr_ref tmp(coalesce_chars(concats[i].get()), m); if (m_util.str.is_empty(tmp)) continue; @@ -5076,32 +5049,30 @@ expr* theory_seq::coalesce_chars(expr* const& e) { } } if (flag) { - result.push_back(m_util.str.mk_string(zs)); + rs.push_back(m_util.str.mk_string(zs)); if (i < concats.size()) - result.push_back(tmp); + rs.push_back(tmp); } else - result.push_back(tmp); + rs.push_back(tmp); } - SASSERT(result.size() > 0); - if (result.size() > 1) - return m_util.str.mk_concat(result.size(), result.c_ptr()); - else - return e; - } - else if (m_util.str.is_unit(e, s)) { - bv_util bvu(m); - if (bvu.is_bv(s)) { - expr_ref result(m); - expr * args[1] = {s}; - if (BR_FAILED != m_seq_rewrite.mk_app_core(to_app(e)->get_decl(), 1, args, result)) { - if (!ctx.e_internalized(result)) - ctx.internalize(result, false); - return result; - } + SASSERT(rs.size() > 0); + if (rs.size() > 1) { + return expr_ref(m_util.str.mk_concat(rs.size(), rs.c_ptr()), m); + } + else { + result = e; + return result; } } - return e; + else if (m_util.str.is_unit(e, s) && m_util.is_const_char(s, ch) && + BR_FAILED != m_seq_rewrite.mk_app_core(to_app(e)->get_decl(), 1, &s, result)) { + if (!ctx.e_internalized(result)) + ctx.internalize(result, false); + return result; + } + result = e; + return result; } expr_ref theory_seq::mk_skolem(symbol const& name, expr* e1, expr* e2, expr* e3, expr*e4, sort* range) { @@ -5111,9 +5082,11 @@ expr_ref theory_seq::mk_skolem(symbol const& name, expr* e1, expr* e2, expr* e3, if (!range) { range = m.get_sort(e1); } + expr_ref_vector pinned(m); if (name == m_seq_align) { for (unsigned i = 0; i < len; ++i) { - es[i] = coalesce_chars(es[i]); + pinned.push_back(coalesce_chars(es[i])); + es[i] = pinned.back(); TRACE("seq", tout << mk_pp(es[i], m) << "\n";); } } diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 9df28acf5..929626757 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -606,7 +606,7 @@ namespace smt { bool get_length(expr* s, rational& val) const; void mk_decompose(expr* e, expr_ref& head, expr_ref& tail); - expr* coalesce_chars(expr* const& str); + expr_ref coalesce_chars(expr* const& str); expr_ref mk_skolem(symbol const& s, expr* e1, expr* e2 = nullptr, expr* e3 = nullptr, expr* e4 = nullptr, sort* range = nullptr); bool is_skolem(symbol const& s, expr* e) const; diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 0e2128990..fc6ec6f7a 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -209,7 +209,6 @@ void solver::assert_expr(expr* f, expr* t) { expr_ref a(t, m); if (m_enforce_model_conversion) { IF_VERBOSE(0, verbose_stream() << "enforce model conversion\n";); - exit(0); model_converter_ref mc = get_model_converter(); if (mc) { (*mc)(fml); From 030f45801786e8b943b966c752804f0c7d9857b1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 3 Dec 2018 09:15:30 -0800 Subject: [PATCH 062/318] add vs2013 specific def for thread local Signed-off-by: Nikolaj Bjorner --- src/util/memory_manager.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/util/memory_manager.cpp b/src/util/memory_manager.cpp index 5d494834e..1be76728c 100644 --- a/src/util/memory_manager.cpp +++ b/src/util/memory_manager.cpp @@ -241,8 +241,15 @@ void * memory::allocate(char const* file, int line, char const* obj, size_t s) { // when the local counter > SYNCH_THRESHOLD #define SYNCH_THRESHOLD 100000 +#ifdef _WINDOWS +// This is VS2013 specific instead of Windows specific. +// It can go away with VS2017 builds +__declspec(thread) long long g_memory_thread_alloc_size = 0; +__declspec(thread) long long g_memory_thread_alloc_count = 0; +#else thread_local long long g_memory_thread_alloc_size = 0; thread_local long long g_memory_thread_alloc_count = 0; +#endif static void synchronize_counters(bool allocating) { #ifdef PROFILE_MEMORY From ea0d253308b281fb0f3fbffb46897c83189ac6a6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 3 Dec 2018 11:56:20 -0800 Subject: [PATCH 063/318] fix const-char test Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 12 ++++++++---- src/ast/seq_decl_plugin.cpp | 2 +- src/smt/theory_seq.cpp | 2 ++ src/smt/theory_str.cpp | 25 ++++++++++--------------- 4 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index bbb225387..b8a2d3ce5 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -307,6 +307,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; } @@ -1234,6 +1237,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; } @@ -1250,6 +1254,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; } @@ -1301,17 +1306,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); diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 2210fc04b..eaedd22ba 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -972,7 +972,7 @@ 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) && r.is_unsigned(), c = r.get_unsigned(), true; + 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 { diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 298502fe8..2f7a82f2d 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -3737,6 +3737,7 @@ void theory_seq::collect_statistics(::statistics & st) const { st.update("seq extensionality", m_stats.m_extensionality); st.update("seq fixed length", m_stats.m_fixed_length); st.update("seq int.to.str", m_stats.m_int_string); + st.update("seq automata", m_stats.m_propagate_automata); } void theory_seq::init_search_eh() { @@ -5476,6 +5477,7 @@ void theory_seq::propagate_step(literal lit, expr* step) { acc(s, idx, re, i) -> idx < max_unfolding */ void theory_seq::propagate_accept(literal lit, expr* acc) { + ++m_stats.m_propagate_automata; expr *e = nullptr, *idx = nullptr, *re = nullptr; unsigned src = 0; context& ctx = get_context(); diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index bd0885fa4..02801648a 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -7219,20 +7219,18 @@ namespace smt { expr_ref theory_str::aut_path_rewrite_constraint(expr * cond, expr * ch_var) { context & ctx = get_context(); ast_manager & m = get_manager(); - bv_util bvu(m); expr_ref retval(m); - - rational char_val; - unsigned int bv_width; + + unsigned char_val = 0; expr * lhs; expr * rhs; - if (bvu.is_numeral(cond, char_val, bv_width)) { - SASSERT(char_val.is_nonneg() && char_val.get_unsigned() < 256); + if (u.is_const_char(cond, char_val)) { + SASSERT(char_val < 256); TRACE("str", tout << "rewrite character constant " << char_val << std::endl;); - zstring str_const(char_val.get_unsigned()); + zstring str_const(char_val); retval = u.str.mk_string(str_const); return retval; } else if (is_var(cond)) { @@ -7377,23 +7375,20 @@ namespace smt { } else if (mv.t()->is_range()) { expr_ref range_lo(mv.t()->get_lo(), m); expr_ref range_hi(mv.t()->get_hi(), m); - bv_util bvu(m); - rational lo_val, hi_val; - unsigned int bv_width; + unsigned lo_val, hi_val; - if (bvu.is_numeral(range_lo, lo_val, bv_width) && bvu.is_numeral(range_hi, hi_val, bv_width)) { + if (u.is_const_char(range_lo, lo_val) && u.is_const_char(range_hi, hi_val)) { TRACE("str", tout << "make range predicate from " << lo_val << " to " << hi_val << std::endl;); expr_ref cond_rhs(m); if (hi_val < lo_val) { - rational tmp = lo_val; - lo_val = hi_val; - hi_val = tmp; + // NSB: why? The range would be empty. + std::swap(lo_val, hi_val); } expr_ref_vector cond_rhs_terms(m); - for (unsigned i = lo_val.get_unsigned(); i <= hi_val.get_unsigned(); ++i) { + for (unsigned i = lo_val; i <= hi_val; ++i) { zstring str_const(i); expr_ref str_expr(u.str.mk_string(str_const), m); cond_rhs_terms.push_back(ctx.mk_eq_atom(ch, str_expr)); From 42d2a46826297775b4f071727f8a6ab680132184 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 4 Dec 2018 09:12:12 +0700 Subject: [PATCH 064/318] Mark up Z3_L_TRUE and friends correctly in the docs. --- src/api/z3_api.h | 8 ++++---- src/api/z3_fixedpoint.h | 18 +++++++++--------- src/api/z3_optimization.h | 2 +- src/api/z3_spacer.h | 8 ++++---- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 6e3ce57a1..7ba88a92d 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -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))) */ @@ -6227,7 +6227,7 @@ extern "C" { 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 +6269,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 +6342,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))) diff --git a/src/api/z3_fixedpoint.h b/src/api/z3_fixedpoint.h index 393cba224..a256c873e 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) )) */ diff --git a/src/api/z3_optimization.h b/src/api/z3_optimization.h index 750f286a5..8f1275774 100644 --- a/src/api/z3_optimization.h +++ b/src/api/z3_optimization.h @@ -142,7 +142,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) )) */ diff --git a/src/api/z3_spacer.h b/src/api/z3_spacer.h index 88129d095..bd6b7d01d 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))) */ From 6c21d3d9e87e7ee5c846c5601ec685dd8323e6da Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 4 Dec 2018 12:24:42 +0700 Subject: [PATCH 065/318] Z3_fixedpoint_add_constraint: decl missing Z3_API. --- src/api/z3_fixedpoint.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/z3_fixedpoint.h b/src/api/z3_fixedpoint.h index a256c873e..54a42e9bf 100644 --- a/src/api/z3_fixedpoint.h +++ b/src/api/z3_fixedpoint.h @@ -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); /*@}*/ /*@}*/ From 15e1a5ee863bb855f7f1d346322f1da8ce6e6728 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 4 Dec 2018 12:23:18 +0700 Subject: [PATCH 066/318] Fix up more documentation formatting. --- src/api/z3_api.h | 28 +++---- src/api/z3_fpa.h | 152 +++++++++++++++++++------------------- src/api/z3_optimization.h | 6 +- src/api/z3_polynomial.h | 5 +- src/api/z3_rcf.h | 30 ++++---- src/api/z3_spacer.h | 2 +- 6 files changed, 111 insertions(+), 112 deletions(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 7ba88a92d..f3d61c1cf 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),)) @@ -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))) */ 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_optimization.h b/src/api/z3_optimization.h index 8f1275774..a8ffd45ab 100644 --- a/src/api/z3_optimization.h +++ b/src/api/z3_optimization.h @@ -228,8 +228,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 +330,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 bd6b7d01d..09cbe6a51 100644 --- a/src/api/z3_spacer.h +++ b/src/api/z3_spacer.h @@ -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 \c 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))) */ From 374b80f37f48dfd468782f3312fcb0d31e263d9c Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 4 Dec 2018 21:38:33 +0700 Subject: [PATCH 067/318] Remove Z3_get_manager. This was publicly exported from the shared library, but it isn't in any header files and isn't used anywhere in the repository. --- src/api/api_context.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 0b1bf4490..2de93677d 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -489,9 +489,3 @@ extern "C" { } }; - -Z3_API ast_manager& Z3_get_manager(Z3_context c) { - return mk_c(c)->m(); -} - - From 5fa861fa9556146ccdec102f38326003dc2ace4d Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 4 Dec 2018 22:41:31 +0700 Subject: [PATCH 068/318] Simplify some boolean returns. --- src/api/api_model.cpp | 6 +----- src/muz/rel/dl_base.h | 10 ++-------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index 664022f2e..c95a36df5 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); } 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 From 924776eaa6693b108ad82a7a0171d4f73a40dcd8 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 4 Dec 2018 22:43:01 +0700 Subject: [PATCH 069/318] Use nullptr, not 0 in the C++ API impl. --- src/api/c++/z3++.h | 68 +++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index d5d3bc1ff..e1a26ea06 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -159,7 +159,7 @@ namespace z3 { m_ctx = Z3_mk_context_rc(c); m_enable_exceptions = true; m_rounding_mode = RNA; - Z3_set_error_handler(m_ctx, 0); + Z3_set_error_handler(m_ctx, nullptr); Z3_set_ast_print_mode(m_ctx, Z3_PRINT_SMTLIB2_COMPLIANT); } @@ -483,12 +483,12 @@ namespace z3 { protected: Z3_ast m_ast; public: - ast(context & c):object(c), m_ast(0) {} + ast(context & c):object(c), m_ast(nullptr) {} ast(context & c, Z3_ast n):object(c), m_ast(n) { Z3_inc_ref(ctx(), m_ast); } ast(ast const & s):object(s), m_ast(s.m_ast) { Z3_inc_ref(ctx(), m_ast); } ~ast() { if (m_ast) Z3_dec_ref(*m_ctx, m_ast); } operator Z3_ast() const { return m_ast; } - operator bool() const { return m_ast != 0; } + operator bool() const { return m_ast != nullptr; } ast & operator=(ast const & s) { Z3_inc_ref(s.ctx(), s.m_ast); if (m_ast) Z3_dec_ref(ctx(), m_ast); m_ctx = s.m_ctx; m_ast = s.m_ast; return *this; } Z3_ast_kind kind() const { Z3_ast_kind r = Z3_get_ast_kind(ctx(), m_ast); check_error(); return r; } unsigned hash() const { unsigned r = Z3_get_ast_hash(ctx(), m_ast); check_error(); return r; } @@ -1264,7 +1264,7 @@ namespace z3 { inline expr operator+(expr const & a, expr const & b) { check_context(a, b); - Z3_ast r = 0; + Z3_ast r = nullptr; if (a.is_arith() && b.is_arith()) { Z3_ast args[2] = { a, b }; r = Z3_mk_add(a.ctx(), 2, args); @@ -1294,7 +1294,7 @@ namespace z3 { inline expr operator*(expr const & a, expr const & b) { check_context(a, b); - Z3_ast r = 0; + Z3_ast r = nullptr; if (a.is_arith() && b.is_arith()) { Z3_ast args[2] = { a, b }; r = Z3_mk_mul(a.ctx(), 2, args); @@ -1318,7 +1318,7 @@ namespace z3 { inline expr operator>=(expr const & a, expr const & b) { check_context(a, b); - Z3_ast r = 0; + Z3_ast r = nullptr; if (a.is_arith() && b.is_arith()) { r = Z3_mk_ge(a.ctx(), a, b); } @@ -1335,7 +1335,7 @@ namespace z3 { inline expr operator/(expr const & a, expr const & b) { check_context(a, b); - Z3_ast r = 0; + Z3_ast r = nullptr; if (a.is_arith() && b.is_arith()) { r = Z3_mk_div(a.ctx(), a, b); } @@ -1356,7 +1356,7 @@ namespace z3 { inline expr operator/(int a, expr const & b) { return b.ctx().num_val(a, b.get_sort()) / b; } inline expr operator-(expr const & a) { - Z3_ast r = 0; + Z3_ast r = nullptr; if (a.is_arith()) { r = Z3_mk_unary_minus(a.ctx(), a); } @@ -1376,7 +1376,7 @@ namespace z3 { inline expr operator-(expr const & a, expr const & b) { check_context(a, b); - Z3_ast r = 0; + Z3_ast r = nullptr; if (a.is_arith() && b.is_arith()) { Z3_ast args[2] = { a, b }; r = Z3_mk_sub(a.ctx(), 2, args); @@ -1399,7 +1399,7 @@ namespace z3 { inline expr operator<=(expr const & a, expr const & b) { check_context(a, b); - Z3_ast r = 0; + Z3_ast r = nullptr; if (a.is_arith() && b.is_arith()) { r = Z3_mk_le(a.ctx(), a, b); } @@ -1424,7 +1424,7 @@ namespace z3 { inline expr operator<(expr const & a, expr const & b) { check_context(a, b); - Z3_ast r = 0; + Z3_ast r = nullptr; if (a.is_arith() && b.is_arith()) { r = Z3_mk_lt(a.ctx(), a, b); } @@ -1446,7 +1446,7 @@ namespace z3 { inline expr operator>(expr const & a, expr const & b) { check_context(a, b); - Z3_ast r = 0; + Z3_ast r = nullptr; if (a.is_arith() && b.is_arith()) { r = Z3_mk_gt(a.ctx(), a, b); } @@ -1771,50 +1771,50 @@ namespace z3 { inline expr forall(expr const & x, expr const & b) { check_context(x, b); Z3_app vars[] = {(Z3_app) x}; - Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 1, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); + Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 1, vars, 0, nullptr, b); b.check_error(); return expr(b.ctx(), r); } inline expr forall(expr const & x1, expr const & x2, expr const & b) { check_context(x1, b); check_context(x2, b); Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2}; - Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 2, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); + Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 2, vars, 0, nullptr, b); b.check_error(); return expr(b.ctx(), r); } inline expr forall(expr const & x1, expr const & x2, expr const & x3, expr const & b) { check_context(x1, b); check_context(x2, b); check_context(x3, b); Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3 }; - Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 3, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); + Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 3, vars, 0, nullptr, b); b.check_error(); return expr(b.ctx(), r); } inline expr forall(expr const & x1, expr const & x2, expr const & x3, expr const & x4, expr const & b) { check_context(x1, b); check_context(x2, b); check_context(x3, b); check_context(x4, b); Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3, (Z3_app) x4 }; - Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 4, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); + Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 4, vars, 0, nullptr, b); b.check_error(); return expr(b.ctx(), r); } inline expr forall(expr_vector const & xs, expr const & b) { array vars(xs); - Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, vars.size(), vars.ptr(), 0, 0, b); b.check_error(); return expr(b.ctx(), r); + Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, vars.size(), vars.ptr(), 0, nullptr, b); b.check_error(); return expr(b.ctx(), r); } inline expr exists(expr const & x, expr const & b) { check_context(x, b); Z3_app vars[] = {(Z3_app) x}; - Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 1, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); + Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 1, vars, 0, nullptr, b); b.check_error(); return expr(b.ctx(), r); } inline expr exists(expr const & x1, expr const & x2, expr const & b) { check_context(x1, b); check_context(x2, b); Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2}; - Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 2, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); + Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 2, vars, 0, nullptr, b); b.check_error(); return expr(b.ctx(), r); } inline expr exists(expr const & x1, expr const & x2, expr const & x3, expr const & b) { check_context(x1, b); check_context(x2, b); check_context(x3, b); Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3 }; - Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 3, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); + Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 3, vars, 0, nullptr, b); b.check_error(); return expr(b.ctx(), r); } inline expr exists(expr const & x1, expr const & x2, expr const & x3, expr const & x4, expr const & b) { check_context(x1, b); check_context(x2, b); check_context(x3, b); check_context(x4, b); Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3, (Z3_app) x4 }; - Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 4, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); + Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 4, vars, 0, nullptr, b); b.check_error(); return expr(b.ctx(), r); } inline expr exists(expr_vector const & xs, expr const & b) { array vars(xs); - Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, vars.size(), vars.ptr(), 0, 0, b); b.check_error(); return expr(b.ctx(), r); + Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, vars.size(), vars.ptr(), 0, nullptr, b); b.check_error(); return expr(b.ctx(), r); } inline expr lambda(expr const & x, expr const & b) { check_context(x, b); @@ -2035,7 +2035,7 @@ namespace z3 { expr eval(expr const & n, bool model_completion=false) const { check_context(*this, n); - Z3_ast r = 0; + Z3_ast r = nullptr; bool status = Z3_model_eval(ctx(), m_model, n, model_completion, &r); check_error(); if (status == false && ctx().enable_exceptions()) @@ -2098,7 +2098,7 @@ namespace z3 { Z3_stats_inc_ref(ctx(), m_stats); } public: - stats(context & c):object(c), m_stats(0) {} + stats(context & c):object(c), m_stats(nullptr) {} stats(context & c, Z3_stats e):object(c) { init(e); } stats(stats const & s):object(s) { init(s.m_stats); } ~stats() { if (m_stats) Z3_stats_dec_ref(ctx(), m_stats); } @@ -2216,7 +2216,7 @@ namespace z3 { std::string to_smt2(char const* status = "unknown") { array es(assertions()); Z3_ast const* fmls = es.ptr(); - Z3_ast fml = 0; + Z3_ast fml = nullptr; unsigned sz = es.size(); if (sz > 0) { --sz; @@ -2366,7 +2366,7 @@ namespace z3 { return model(ctx(), new_m); } model get_model() const { - Z3_model new_m = Z3_goal_convert_model(ctx(), m_goal, 0); + Z3_model new_m = Z3_goal_convert_model(ctx(), m_goal, nullptr); check_error(); return model(ctx(), new_m); } @@ -2607,11 +2607,11 @@ namespace z3 { assert(e.is_bool()); std::stringstream strm; strm << weight; - return handle(Z3_optimize_assert_soft(ctx(), m_opt, e, strm.str().c_str(), 0)); + return handle(Z3_optimize_assert_soft(ctx(), m_opt, e, strm.str().c_str(), nullptr)); } handle add(expr const& e, char const* weight) { assert(e.is_bool()); - return handle(Z3_optimize_assert_soft(ctx(), m_opt, e, weight, 0)); + return handle(Z3_optimize_assert_soft(ctx(), m_opt, e, weight, nullptr)); } handle maximize(expr const& e) { return handle(Z3_optimize_maximize(ctx(), m_opt, e)); @@ -2625,7 +2625,7 @@ namespace z3 { void pop() { Z3_optimize_pop(ctx(), m_opt); } - check_result check() { Z3_lbool r = Z3_optimize_check(ctx(), m_opt, 0, 0); check_error(); return to_check_result(r); } + check_result check() { Z3_lbool r = Z3_optimize_check(ctx(), m_opt, 0, nullptr); check_error(); return to_check_result(r); } check_result check(expr_vector const& asms) { unsigned n = asms.size(); array _asms(n); @@ -2694,7 +2694,7 @@ namespace z3 { void set(params const & p) { Z3_fixedpoint_set_params(ctx(), m_fp, p); check_error(); } std::string help() const { return Z3_fixedpoint_get_help(ctx(), m_fp); } param_descrs get_param_descrs() { return param_descrs(ctx(), Z3_fixedpoint_get_param_descrs(ctx(), m_fp)); } - std::string to_string() { return Z3_fixedpoint_to_string(ctx(), m_fp, 0, 0); } + std::string to_string() { return Z3_fixedpoint_to_string(ctx(), m_fp, 0, nullptr); } std::string to_string(expr_vector const& queries) { array qs(queries); return Z3_fixedpoint_to_string(ctx(), m_fp, qs.size(), qs.ptr()); @@ -2702,7 +2702,7 @@ namespace z3 { void push() { Z3_fixedpoint_push(ctx(), m_fp); check_error(); } void pop() { Z3_fixedpoint_pop(ctx(), m_fp); check_error(); } }; - inline std::ostream & operator<<(std::ostream & out, fixedpoint const & f) { return out << Z3_fixedpoint_to_string(f.ctx(), f, 0, 0); } + inline std::ostream & operator<<(std::ostream & out, fixedpoint const & f) { return out << Z3_fixedpoint_to_string(f.ctx(), f, 0, nullptr); } inline tactic fail_if(probe const & p) { Z3_tactic r = Z3_tactic_fail_if(p.ctx(), p); @@ -2969,7 +2969,7 @@ namespace z3 { return expr(ctx(), r); } inline expr func_decl::operator()() const { - Z3_ast r = Z3_mk_app(ctx(), *this, 0, 0); + Z3_ast r = Z3_mk_app(ctx(), *this, 0, nullptr); ctx().check_error(); return expr(ctx(), r); } @@ -3253,13 +3253,13 @@ namespace z3 { inline expr_vector context::parse_string(char const* s) { - Z3_ast_vector r = Z3_parse_smtlib2_string(*this, s, 0, 0, 0, 0, 0, 0); + Z3_ast_vector r = Z3_parse_smtlib2_string(*this, s, 0, nullptr, nullptr, 0, nullptr, nullptr); check_error(); return expr_vector(*this, r); } inline expr_vector context::parse_file(char const* s) { - Z3_ast_vector r = Z3_parse_smtlib2_file(*this, s, 0, 0, 0, 0, 0, 0); + Z3_ast_vector r = Z3_parse_smtlib2_file(*this, s, 0, nullptr, nullptr, 0, nullptr, nullptr); check_error(); return expr_vector(*this, r); } From 9e5aaf074e248084a1dc1555109d5ff66301f73f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 4 Dec 2018 10:13:55 -0800 Subject: [PATCH 070/318] perf improvements for #1979 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 92 ++++++++++++++++++------ src/ast/rewriter/seq_rewriter.h | 25 ++++--- src/smt/theory_seq.cpp | 114 ++++++++++++++++-------------- 3 files changed, 149 insertions(+), 82 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index b8a2d3ce5..906b647fe 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -33,20 +33,23 @@ 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: { - seq_util u(m); - unsigned r1, r2, r3; + 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)); } @@ -55,7 +58,7 @@ expr_ref sym_expr::accept(expr* e) { } break; } - } + return result; } @@ -64,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"; } @@ -79,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); @@ -93,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; @@ -102,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); @@ -110,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()) { @@ -147,6 +184,7 @@ public: } } } + T mk_or(unsigned sz, T const* ts) override { switch (sz) { case 0: return mk_false(); @@ -160,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; } @@ -177,16 +224,11 @@ 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), m_ba(nullptr), m_sa(nullptr) {} @@ -1434,6 +1476,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; } diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h index c2b2227b2..83793a594 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 { diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 2f7a82f2d..19ef14c3a 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -51,6 +51,7 @@ public: m_kernel.assert_expr(e); lbool r = m_kernel.check(); m_kernel.pop(1); + IF_VERBOSE(11, verbose_stream() << "is " << r << " " << mk_pp(e, m_kernel.m()) << "\n"); return r; } }; @@ -250,6 +251,9 @@ void theory_seq::init(context* ctx) { m_arith_value.init(ctx); } +#define TRACEFIN(s) { TRACE("seq", tout << ">>" << s << "\n";); IF_VERBOSE(10, verbose_stream() << s << "\n"); } + + final_check_status theory_seq::final_check_eh() { if (m_reset_cache) { m_rep.reset_cache(); @@ -260,79 +264,79 @@ final_check_status theory_seq::final_check_eh() { TRACE("seq_verbose", get_context().display(tout);); if (simplify_and_solve_eqs()) { ++m_stats.m_solve_eqs; - TRACE("seq", tout << ">>solve_eqs\n";); + TRACEFIN("solve_eqs"); return FC_CONTINUE; } if (check_contains()) { ++m_stats.m_propagate_contains; - TRACE("seq", tout << ">>propagate_contains\n";); + TRACEFIN("propagate_contains"); return FC_CONTINUE; } if (solve_nqs(0)) { ++m_stats.m_solve_nqs; - TRACE("seq", tout << ">>solve_nqs\n";); + TRACEFIN("solve_nqs"); return FC_CONTINUE; } if (fixed_length(true)) { ++m_stats.m_fixed_length; - TRACE("seq", tout << ">>zero_length\n";); + TRACEFIN("zero_length"); return FC_CONTINUE; } if (m_params.m_split_w_len && len_based_split()) { ++m_stats.m_branch_variable; - TRACE("seq", tout << ">>split_based_on_length\n";); + TRACEFIN("split_based_on_length"); return FC_CONTINUE; } if (fixed_length()) { ++m_stats.m_fixed_length; - TRACE("seq", tout << ">>fixed_length\n";); + TRACEFIN("fixed_length"); return FC_CONTINUE; } if (check_int_string()) { ++m_stats.m_int_string; - TRACE("seq", tout << ">>int_string\n";); + TRACEFIN("int_string"); return FC_CONTINUE; } if (reduce_length_eq()) { ++m_stats.m_branch_variable; - TRACE("seq", tout << ">>reduce length\n";); + TRACEFIN("reduce_length"); return FC_CONTINUE; } if (branch_unit_variable()) { ++m_stats.m_branch_variable; - TRACE("seq", tout << ">>branch_unit_variable\n";); + TRACEFIN("ranch_unit_variable"); return FC_CONTINUE; } if (branch_binary_variable()) { ++m_stats.m_branch_variable; - TRACE("seq", tout << ">>branch_binary_variable\n";); + TRACEFIN("branch_binary_variable"); return FC_CONTINUE; } if (branch_ternary_variable1() || branch_ternary_variable2() || branch_quat_variable()) { ++m_stats.m_branch_variable; - TRACE("seq", tout << ">>split_based_on_alignment\n";); + TRACEFIN("split_based_on_alignment"); return FC_CONTINUE; } if (branch_variable_mb() || branch_variable()) { ++m_stats.m_branch_variable; - TRACE("seq", tout << ">>branch_variable\n";); + TRACEFIN("branch_variable"); return FC_CONTINUE; } if (check_length_coherence()) { ++m_stats.m_check_length_coherence; - TRACE("seq", tout << ">>check_length_coherence\n";); + TRACEFIN("check_length_coherence"); return FC_CONTINUE; } if (!check_extensionality()) { ++m_stats.m_extensionality; - TRACE("seq", tout << ">>extensionality\n";); + TRACEFIN("extensionality"); return FC_CONTINUE; } if (is_solved()) { - TRACE("seq", tout << ">>is_solved\n";); + TRACEFIN("is_solved"); return FC_DONE; } - TRACE("seq", tout << ">>give_up\n";); + TRACEFIN("give_up"); return FC_GIVEUP; } @@ -4518,8 +4522,6 @@ void theory_seq::add_itos_length_axiom(expr* len) { void theory_seq::propagate_in_re(expr* n, bool is_true) { TRACE("seq", tout << mk_pp(n, m) << " <- " << (is_true?"true":"false") << "\n";); - expr* s = nullptr, *re = nullptr; - VERIFY(m_util.str.is_in_re(n, s, re)); expr_ref tmp(n, m); m_rewrite(tmp); @@ -4540,43 +4542,39 @@ void theory_seq::propagate_in_re(expr* n, bool is_true) { return; } - expr_ref e3(re, m); + expr* s = nullptr, *_re = nullptr; + VERIFY(m_util.str.is_in_re(n, s, _re)); + expr_ref re(_re, m); context& ctx = get_context(); literal lit = ctx.get_literal(n); if (!is_true) { - e3 = m_util.re.mk_complement(re); + re = m_util.re.mk_complement(re); lit.neg(); } - literal_vector lits; - - enode_pair_vector eqs; + literal_vector lits; for (unsigned i = 0; i < m_s_in_re.size(); ++i) { auto const& entry = m_s_in_re[i]; - if (entry.m_active && get_root(entry.m_s) == get_root(s)) { + if (entry.m_active && get_root(entry.m_s) == get_root(s) && entry.m_re != re) { m_trail_stack.push(vector_value_trail(m_s_in_re, i)); m_s_in_re[i].m_active = false; - e3 = m_util.re.mk_inter(entry.m_re, e3); + IF_VERBOSE(11, verbose_stream() << "intersect " << re << " " << mk_pp(entry.m_re, m) << " " << mk_pp(s, m) << " " << mk_pp(entry.m_s, m) << "\n";); + re = m_util.re.mk_inter(entry.m_re, re); + m_rewrite(re); lits.push_back(entry.m_lit); - eqs.push_back(enode_pair(ensure_enode(entry.m_s), ensure_enode(s))); + enode* n1 = ensure_enode(entry.m_s); + enode* n2 = ensure_enode(s); + if (n1 != n2) { + lits.push_back(mk_eq(n1->get_owner(), n2->get_owner(), false)); + } } } - if (!lits.empty()) { - TRACE("seq", tout << "creating intersection " << e3 << "\n";); - lits.push_back(lit); - literal inter = mk_literal(m_util.re.mk_in_re(s, e3)); - justification* js = - ctx.mk_justification( - ext_theory_propagation_justification( - get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), eqs.size(), eqs.c_ptr(), inter)); - ctx.assign(inter, js); - return; - } - eautomaton* a = get_automaton(e3); + IF_VERBOSE(11, verbose_stream() << mk_pp(s, m) << " in " << re << "\n"); + eautomaton* a = get_automaton(re); if (!a) return; - m_s_in_re.push_back(s_in_re(lit, s, e3, a)); + m_s_in_re.push_back(s_in_re(lit, s, re, a)); m_trail_stack.push(push_back_vector>(m_s_in_re)); expr_ref len = mk_len(s); @@ -4587,7 +4585,7 @@ void theory_seq::propagate_in_re(expr* n, bool is_true) { lits.push_back(~lit); for (unsigned st : states) { - lits.push_back(mk_accept(s, zero, e3, st)); + lits.push_back(mk_accept(s, zero, re, st)); } if (lits.size() == 2) { propagate_lit(nullptr, 1, &lit, lits[1]); @@ -4906,24 +4904,36 @@ void theory_seq::add_extract_suffix_axiom(expr* e, expr* s, expr* i) { void theory_seq::add_at_axiom(expr* e) { expr* s = nullptr, *i = nullptr; VERIFY(m_util.str.is_at(e, s, i)); - expr_ref len_e = mk_len(e); - expr_ref len_s = mk_len(s); expr_ref zero(m_autil.mk_int(0), m); expr_ref one(m_autil.mk_int(1), m); - expr_ref x = mk_skolem(m_pre, s, i); - //expr_ref y = mk_skolem(m_post, s, mk_sub(mk_sub(len_s, i), one)); - expr_ref y = mk_skolem(m_tail, s, i); - expr_ref xey = mk_concat(x, e, y); - expr_ref len_x = mk_len(x); expr_ref emp(m_util.str.mk_empty(m.get_sort(e)), m); - + expr_ref len_s = mk_len(s); literal i_ge_0 = mk_simplified_literal(m_autil.mk_ge(i, zero)); literal i_ge_len_s = mk_simplified_literal(m_autil.mk_ge(mk_sub(i, mk_len(s)), zero)); - - add_axiom(~i_ge_0, i_ge_len_s, mk_seq_eq(s, xey)); - add_axiom(~i_ge_0, i_ge_len_s, mk_eq(one, len_e, false)); - add_axiom(~i_ge_0, i_ge_len_s, mk_eq(i, len_x, false)); + rational iv; + if (m_autil.is_numeral(i, iv) && iv.is_int() && !iv.is_neg()) { + expr_ref_vector es(m); + expr_ref nth(m); + unsigned k = iv.get_unsigned(); + for (unsigned j = 0; j <= k; ++j) { + es.push_back(m_util.str.mk_unit(mk_nth(s, m_autil.mk_int(j)))); + } + nth = es.back(); + es.push_back(mk_skolem(m_tail, s, m_autil.mk_int(k))); + add_axiom(~i_ge_0, i_ge_len_s, mk_seq_eq(s, m_util.str.mk_concat(es))); + add_axiom(~i_ge_0, i_ge_len_s, mk_seq_eq(nth, e)); + } + else { + expr_ref len_e = mk_len(e); + expr_ref x = mk_skolem(m_pre, s, i); + expr_ref y = mk_skolem(m_tail, s, i); + expr_ref xey = mk_concat(x, e, y); + expr_ref len_x = mk_len(x); + add_axiom(~i_ge_0, i_ge_len_s, mk_seq_eq(s, xey)); + add_axiom(~i_ge_0, i_ge_len_s, mk_eq(one, len_e, false)); + add_axiom(~i_ge_0, i_ge_len_s, mk_eq(i, len_x, false)); + } add_axiom(i_ge_0, mk_eq(e, emp, false)); add_axiom(~i_ge_len_s, mk_eq(e, emp, false)); From 3b545753405109cf3033a7966e4ecce57032fec0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 4 Dec 2018 12:06:44 -0800 Subject: [PATCH 071/318] Revert "Use nullptr, not 0 in the C++ API impl." --- src/api/c++/z3++.h | 68 +++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index e1a26ea06..d5d3bc1ff 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -159,7 +159,7 @@ namespace z3 { m_ctx = Z3_mk_context_rc(c); m_enable_exceptions = true; m_rounding_mode = RNA; - Z3_set_error_handler(m_ctx, nullptr); + Z3_set_error_handler(m_ctx, 0); Z3_set_ast_print_mode(m_ctx, Z3_PRINT_SMTLIB2_COMPLIANT); } @@ -483,12 +483,12 @@ namespace z3 { protected: Z3_ast m_ast; public: - ast(context & c):object(c), m_ast(nullptr) {} + ast(context & c):object(c), m_ast(0) {} ast(context & c, Z3_ast n):object(c), m_ast(n) { Z3_inc_ref(ctx(), m_ast); } ast(ast const & s):object(s), m_ast(s.m_ast) { Z3_inc_ref(ctx(), m_ast); } ~ast() { if (m_ast) Z3_dec_ref(*m_ctx, m_ast); } operator Z3_ast() const { return m_ast; } - operator bool() const { return m_ast != nullptr; } + operator bool() const { return m_ast != 0; } ast & operator=(ast const & s) { Z3_inc_ref(s.ctx(), s.m_ast); if (m_ast) Z3_dec_ref(ctx(), m_ast); m_ctx = s.m_ctx; m_ast = s.m_ast; return *this; } Z3_ast_kind kind() const { Z3_ast_kind r = Z3_get_ast_kind(ctx(), m_ast); check_error(); return r; } unsigned hash() const { unsigned r = Z3_get_ast_hash(ctx(), m_ast); check_error(); return r; } @@ -1264,7 +1264,7 @@ namespace z3 { inline expr operator+(expr const & a, expr const & b) { check_context(a, b); - Z3_ast r = nullptr; + Z3_ast r = 0; if (a.is_arith() && b.is_arith()) { Z3_ast args[2] = { a, b }; r = Z3_mk_add(a.ctx(), 2, args); @@ -1294,7 +1294,7 @@ namespace z3 { inline expr operator*(expr const & a, expr const & b) { check_context(a, b); - Z3_ast r = nullptr; + Z3_ast r = 0; if (a.is_arith() && b.is_arith()) { Z3_ast args[2] = { a, b }; r = Z3_mk_mul(a.ctx(), 2, args); @@ -1318,7 +1318,7 @@ namespace z3 { inline expr operator>=(expr const & a, expr const & b) { check_context(a, b); - Z3_ast r = nullptr; + Z3_ast r = 0; if (a.is_arith() && b.is_arith()) { r = Z3_mk_ge(a.ctx(), a, b); } @@ -1335,7 +1335,7 @@ namespace z3 { inline expr operator/(expr const & a, expr const & b) { check_context(a, b); - Z3_ast r = nullptr; + Z3_ast r = 0; if (a.is_arith() && b.is_arith()) { r = Z3_mk_div(a.ctx(), a, b); } @@ -1356,7 +1356,7 @@ namespace z3 { inline expr operator/(int a, expr const & b) { return b.ctx().num_val(a, b.get_sort()) / b; } inline expr operator-(expr const & a) { - Z3_ast r = nullptr; + Z3_ast r = 0; if (a.is_arith()) { r = Z3_mk_unary_minus(a.ctx(), a); } @@ -1376,7 +1376,7 @@ namespace z3 { inline expr operator-(expr const & a, expr const & b) { check_context(a, b); - Z3_ast r = nullptr; + Z3_ast r = 0; if (a.is_arith() && b.is_arith()) { Z3_ast args[2] = { a, b }; r = Z3_mk_sub(a.ctx(), 2, args); @@ -1399,7 +1399,7 @@ namespace z3 { inline expr operator<=(expr const & a, expr const & b) { check_context(a, b); - Z3_ast r = nullptr; + Z3_ast r = 0; if (a.is_arith() && b.is_arith()) { r = Z3_mk_le(a.ctx(), a, b); } @@ -1424,7 +1424,7 @@ namespace z3 { inline expr operator<(expr const & a, expr const & b) { check_context(a, b); - Z3_ast r = nullptr; + Z3_ast r = 0; if (a.is_arith() && b.is_arith()) { r = Z3_mk_lt(a.ctx(), a, b); } @@ -1446,7 +1446,7 @@ namespace z3 { inline expr operator>(expr const & a, expr const & b) { check_context(a, b); - Z3_ast r = nullptr; + Z3_ast r = 0; if (a.is_arith() && b.is_arith()) { r = Z3_mk_gt(a.ctx(), a, b); } @@ -1771,50 +1771,50 @@ namespace z3 { inline expr forall(expr const & x, expr const & b) { check_context(x, b); Z3_app vars[] = {(Z3_app) x}; - Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 1, vars, 0, nullptr, b); b.check_error(); return expr(b.ctx(), r); + Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 1, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); } inline expr forall(expr const & x1, expr const & x2, expr const & b) { check_context(x1, b); check_context(x2, b); Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2}; - Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 2, vars, 0, nullptr, b); b.check_error(); return expr(b.ctx(), r); + Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 2, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); } inline expr forall(expr const & x1, expr const & x2, expr const & x3, expr const & b) { check_context(x1, b); check_context(x2, b); check_context(x3, b); Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3 }; - Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 3, vars, 0, nullptr, b); b.check_error(); return expr(b.ctx(), r); + Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 3, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); } inline expr forall(expr const & x1, expr const & x2, expr const & x3, expr const & x4, expr const & b) { check_context(x1, b); check_context(x2, b); check_context(x3, b); check_context(x4, b); Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3, (Z3_app) x4 }; - Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 4, vars, 0, nullptr, b); b.check_error(); return expr(b.ctx(), r); + Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 4, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); } inline expr forall(expr_vector const & xs, expr const & b) { array vars(xs); - Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, vars.size(), vars.ptr(), 0, nullptr, b); b.check_error(); return expr(b.ctx(), r); + Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, vars.size(), vars.ptr(), 0, 0, b); b.check_error(); return expr(b.ctx(), r); } inline expr exists(expr const & x, expr const & b) { check_context(x, b); Z3_app vars[] = {(Z3_app) x}; - Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 1, vars, 0, nullptr, b); b.check_error(); return expr(b.ctx(), r); + Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 1, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); } inline expr exists(expr const & x1, expr const & x2, expr const & b) { check_context(x1, b); check_context(x2, b); Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2}; - Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 2, vars, 0, nullptr, b); b.check_error(); return expr(b.ctx(), r); + Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 2, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); } inline expr exists(expr const & x1, expr const & x2, expr const & x3, expr const & b) { check_context(x1, b); check_context(x2, b); check_context(x3, b); Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3 }; - Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 3, vars, 0, nullptr, b); b.check_error(); return expr(b.ctx(), r); + Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 3, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); } inline expr exists(expr const & x1, expr const & x2, expr const & x3, expr const & x4, expr const & b) { check_context(x1, b); check_context(x2, b); check_context(x3, b); check_context(x4, b); Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3, (Z3_app) x4 }; - Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 4, vars, 0, nullptr, b); b.check_error(); return expr(b.ctx(), r); + Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 4, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); } inline expr exists(expr_vector const & xs, expr const & b) { array vars(xs); - Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, vars.size(), vars.ptr(), 0, nullptr, b); b.check_error(); return expr(b.ctx(), r); + Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, vars.size(), vars.ptr(), 0, 0, b); b.check_error(); return expr(b.ctx(), r); } inline expr lambda(expr const & x, expr const & b) { check_context(x, b); @@ -2035,7 +2035,7 @@ namespace z3 { expr eval(expr const & n, bool model_completion=false) const { check_context(*this, n); - Z3_ast r = nullptr; + Z3_ast r = 0; bool status = Z3_model_eval(ctx(), m_model, n, model_completion, &r); check_error(); if (status == false && ctx().enable_exceptions()) @@ -2098,7 +2098,7 @@ namespace z3 { Z3_stats_inc_ref(ctx(), m_stats); } public: - stats(context & c):object(c), m_stats(nullptr) {} + stats(context & c):object(c), m_stats(0) {} stats(context & c, Z3_stats e):object(c) { init(e); } stats(stats const & s):object(s) { init(s.m_stats); } ~stats() { if (m_stats) Z3_stats_dec_ref(ctx(), m_stats); } @@ -2216,7 +2216,7 @@ namespace z3 { std::string to_smt2(char const* status = "unknown") { array es(assertions()); Z3_ast const* fmls = es.ptr(); - Z3_ast fml = nullptr; + Z3_ast fml = 0; unsigned sz = es.size(); if (sz > 0) { --sz; @@ -2366,7 +2366,7 @@ namespace z3 { return model(ctx(), new_m); } model get_model() const { - Z3_model new_m = Z3_goal_convert_model(ctx(), m_goal, nullptr); + Z3_model new_m = Z3_goal_convert_model(ctx(), m_goal, 0); check_error(); return model(ctx(), new_m); } @@ -2607,11 +2607,11 @@ namespace z3 { assert(e.is_bool()); std::stringstream strm; strm << weight; - return handle(Z3_optimize_assert_soft(ctx(), m_opt, e, strm.str().c_str(), nullptr)); + return handle(Z3_optimize_assert_soft(ctx(), m_opt, e, strm.str().c_str(), 0)); } handle add(expr const& e, char const* weight) { assert(e.is_bool()); - return handle(Z3_optimize_assert_soft(ctx(), m_opt, e, weight, nullptr)); + return handle(Z3_optimize_assert_soft(ctx(), m_opt, e, weight, 0)); } handle maximize(expr const& e) { return handle(Z3_optimize_maximize(ctx(), m_opt, e)); @@ -2625,7 +2625,7 @@ namespace z3 { void pop() { Z3_optimize_pop(ctx(), m_opt); } - check_result check() { Z3_lbool r = Z3_optimize_check(ctx(), m_opt, 0, nullptr); check_error(); return to_check_result(r); } + check_result check() { Z3_lbool r = Z3_optimize_check(ctx(), m_opt, 0, 0); check_error(); return to_check_result(r); } check_result check(expr_vector const& asms) { unsigned n = asms.size(); array _asms(n); @@ -2694,7 +2694,7 @@ namespace z3 { void set(params const & p) { Z3_fixedpoint_set_params(ctx(), m_fp, p); check_error(); } std::string help() const { return Z3_fixedpoint_get_help(ctx(), m_fp); } param_descrs get_param_descrs() { return param_descrs(ctx(), Z3_fixedpoint_get_param_descrs(ctx(), m_fp)); } - std::string to_string() { return Z3_fixedpoint_to_string(ctx(), m_fp, 0, nullptr); } + std::string to_string() { return Z3_fixedpoint_to_string(ctx(), m_fp, 0, 0); } std::string to_string(expr_vector const& queries) { array qs(queries); return Z3_fixedpoint_to_string(ctx(), m_fp, qs.size(), qs.ptr()); @@ -2702,7 +2702,7 @@ namespace z3 { void push() { Z3_fixedpoint_push(ctx(), m_fp); check_error(); } void pop() { Z3_fixedpoint_pop(ctx(), m_fp); check_error(); } }; - inline std::ostream & operator<<(std::ostream & out, fixedpoint const & f) { return out << Z3_fixedpoint_to_string(f.ctx(), f, 0, nullptr); } + inline std::ostream & operator<<(std::ostream & out, fixedpoint const & f) { return out << Z3_fixedpoint_to_string(f.ctx(), f, 0, 0); } inline tactic fail_if(probe const & p) { Z3_tactic r = Z3_tactic_fail_if(p.ctx(), p); @@ -2969,7 +2969,7 @@ namespace z3 { return expr(ctx(), r); } inline expr func_decl::operator()() const { - Z3_ast r = Z3_mk_app(ctx(), *this, 0, nullptr); + Z3_ast r = Z3_mk_app(ctx(), *this, 0, 0); ctx().check_error(); return expr(ctx(), r); } @@ -3253,13 +3253,13 @@ namespace z3 { inline expr_vector context::parse_string(char const* s) { - Z3_ast_vector r = Z3_parse_smtlib2_string(*this, s, 0, nullptr, nullptr, 0, nullptr, nullptr); + Z3_ast_vector r = Z3_parse_smtlib2_string(*this, s, 0, 0, 0, 0, 0, 0); check_error(); return expr_vector(*this, r); } inline expr_vector context::parse_file(char const* s) { - Z3_ast_vector r = Z3_parse_smtlib2_file(*this, s, 0, nullptr, nullptr, 0, nullptr, nullptr); + Z3_ast_vector r = Z3_parse_smtlib2_file(*this, s, 0, 0, 0, 0, 0, 0); check_error(); return expr_vector(*this, r); } From dc775797077fd63c75fd3d15ae75d0cf5cf2391b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 4 Dec 2018 23:41:03 -0800 Subject: [PATCH 072/318] delta faction to control double lookahead eagerness Signed-off-by: Nikolaj Bjorner --- src/sat/sat_config.cpp | 5 ++++- src/sat/sat_config.h | 1 + src/sat/sat_lookahead.cpp | 11 ++++++++--- src/sat/sat_lookahead.h | 1 + src/sat/sat_params.pyg | 1 + src/sat/sat_solver/inc_sat_solver.cpp | 23 +++++++++++------------ 6 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 423a5f532..5516cdb7c 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -123,8 +123,11 @@ 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); diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 4d33225f0..deb67b197 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -129,6 +129,7 @@ namespace sat { double m_lookahead_cube_psat_trigger; reward_t m_lookahead_reward; bool m_lookahead_global_autarky; + double m_lookahead_delta_fraction; bool m_lookahead_use_learned; bool m_incremental; diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index c3bbe4d1d..0e364180c 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -997,6 +997,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; @@ -1814,7 +1815,7 @@ namespace sat { ++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); } } @@ -2098,7 +2099,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 +2134,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) { diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 046750832..2d725f415 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -198,6 +198,7 @@ namespace sat { config m_config; double m_delta_trigger; double m_delta_decrease; + double m_delta_fraction; drat m_drat; literal_vector m_assumptions; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index acde7e30c..cca45aa72 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -74,6 +74,7 @@ def_module_params('sat', ('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_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index df2da82e7..a4131ccaf 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -332,18 +332,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 +346,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; } From 9635ddd8fceb6bdde7dc7725e696e6c123af22f4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 5 Dec 2018 00:54:10 -0800 Subject: [PATCH 073/318] fix #2018 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 19ef14c3a..abfb28a49 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -4561,11 +4561,11 @@ void theory_seq::propagate_in_re(expr* n, bool is_true) { IF_VERBOSE(11, verbose_stream() << "intersect " << re << " " << mk_pp(entry.m_re, m) << " " << mk_pp(s, m) << " " << mk_pp(entry.m_s, m) << "\n";); re = m_util.re.mk_inter(entry.m_re, re); m_rewrite(re); - lits.push_back(entry.m_lit); + lits.push_back(~entry.m_lit); enode* n1 = ensure_enode(entry.m_s); enode* n2 = ensure_enode(s); if (n1 != n2) { - lits.push_back(mk_eq(n1->get_owner(), n2->get_owner(), false)); + lits.push_back(~mk_eq(n1->get_owner(), n2->get_owner(), false)); } } } From 4bc1b0b8c88d851c88d390bcf13b005ffcab95f6 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Mon, 3 Dec 2018 11:38:36 +0700 Subject: [PATCH 074/318] Fix typos. --- src/api/dotnet/Context.cs | 2 +- src/api/dotnet/Optimize.cs | 2 +- src/api/dotnet/dotnet35/Readme.NET35 | 2 +- src/qe/qe.h | 2 +- src/util/memory_manager.cpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) 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/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/dotnet35/Readme.NET35 b/src/api/dotnet/dotnet35/Readme.NET35 index f8c2958ee..75210f8b6 100644 --- a/src/api/dotnet/dotnet35/Readme.NET35 +++ b/src/api/dotnet/dotnet35/Readme.NET35 @@ -4,7 +4,7 @@ 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 +- Under 'Build': Add FRAMEWORK_LT_4 to the conditional 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/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/util/memory_manager.cpp b/src/util/memory_manager.cpp index 1be76728c..6ef94e880 100644 --- a/src/util/memory_manager.cpp +++ b/src/util/memory_manager.cpp @@ -18,7 +18,7 @@ Copyright (c) 2015 Microsoft Corporation // ADD_INITIALIZER('rational::initialize();') // ADD_FINALIZER('rational::finalize();') // Thus, any executable or shared object (DLL) that depends on rational.h -// will have an automalically generated file mem_initializer.cpp containing +// will have an automatically generated file mem_initializer.cpp containing // mem_initialize() // mem_finalize() // and these functions will include the statements: From 5690dbcbfdeed8abf094d6b8b5c3e7311a77497f Mon Sep 17 00:00:00 2001 From: Sebastian Buchwald Date: Thu, 6 Dec 2018 00:01:01 +0100 Subject: [PATCH 075/318] Fix enum type of case labels --- src/api/api_numeral.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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; From 9a0a1dd8186a380f3abde2e11b5b8290eac83c4b Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Thu, 6 Dec 2018 16:19:03 +0100 Subject: [PATCH 076/318] Changes to NuGet release script. --- scripts/mk_nuget_release.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/mk_nuget_release.py b/scripts/mk_nuget_release.py index 7ce14bf5d..c5079ed2c 100644 --- a/scripts/mk_nuget_release.py +++ b/scripts/mk_nuget_release.py @@ -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") From 0231bc44bcb8df1e2d2e227064cc367ae3a2c59b Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Fri, 7 Dec 2018 22:06:51 +0700 Subject: [PATCH 077/318] Simplify boolean code. Now that the C API is using bool, this can be simplified. --- src/api/api_fpa.cpp | 12 ++++++------ src/api/api_params.cpp | 2 +- src/api/api_rcf.cpp | 2 +- src/api/c++/z3++.h | 32 ++++++++++++++++---------------- 4 files changed, 24 insertions(+), 24 deletions(-) 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_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/c++/z3++.h b/src/api/c++/z3++.h index d5d3bc1ff..7d45c9707 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -505,7 +505,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); } /** @@ -713,10 +713,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 +736,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 +753,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 @@ -2073,7 +2073,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 +2112,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); @@ -2353,12 +2353,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); From a20e68facc92e60a71d6b61dc0e2cc1e0dd501f1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 7 Dec 2018 17:54:49 +0000 Subject: [PATCH 078/318] throttel extract/ite rewriting to avoid perf-bug exposed in example from Lucas Cordeiro and Alessandro Trindade Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/bv_rewriter.cpp | 13 ++-- src/ast/rewriter/seq_rewriter.cpp | 114 ++++++++++++++++++------------ src/smt/theory_seq.cpp | 1 + 3 files changed, 79 insertions(+), 49 deletions(-) diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index 81226b010..f5d76f7e6 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -779,11 +779,14 @@ 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))); - return BR_REWRITE2; + expr* c = nullptr, *t = nullptr, *e = nullptr; + if (m().is_ite(arg, c, t, e)) { + if ((t->get_ref_count() == 1 && e->get_ref_count() == 1) || + (!m().is_ite(t) && !m().is_ite(e))) { + //std::cout << "n-ite\n"; + result = m().mk_ite(c, m_mk_extract(high, low, t), m_mk_extract(high, low, e)); + return BR_REWRITE2; + } } return BR_FAILED; diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 906b647fe..2406e92ed 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -387,8 +387,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); @@ -448,7 +449,8 @@ 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); @@ -499,7 +501,8 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con case _OP_STRING_STRIDOF: UNREACHABLE(); } - return BR_FAILED; + TRACE("seq", tout << result << "\n";); + return st; } /* @@ -607,6 +610,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()) ) { @@ -615,7 +619,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; } @@ -623,52 +627,74 @@ 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 len1(m()), pos1(m()); + pos1 = m_autil.mk_sub(b, m_autil.mk_int(offset)); + len1 = m_autil.mk_sub(c, 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, len1); + return BR_REWRITE3; } bool seq_rewriter::cannot_contain_suffix(expr* a, expr* b) { diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index abfb28a49..54d1811e6 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2396,6 +2396,7 @@ bool theory_seq::is_var(expr* a) const { !m_util.str.is_string(a) && !m_util.str.is_unit(a) && !m_util.str.is_itos(a) && + !m_util.str.is_extract(a) && !m.is_ite(a); } From 38b5e6de568459ca24af0fdd95dc0f685fb4aa70 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 8 Dec 2018 13:57:35 +0100 Subject: [PATCH 079/318] fix #2019 - insufficient axioms for special cases Signed-off-by: Nikolaj Bjorner --- src/ast/ast_smt2_pp.cpp | 2 +- src/ast/rewriter/bv_rewriter.cpp | 12 +++++------- src/smt/theory_seq.cpp | 17 +++++++++++------ 3 files changed, 17 insertions(+), 14 deletions(-) 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/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index f5d76f7e6..3dc76da5e 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -780,13 +780,11 @@ br_status bv_rewriter::mk_extract(unsigned high, unsigned low, expr * arg, expr_ } expr* c = nullptr, *t = nullptr, *e = nullptr; - if (m().is_ite(arg, c, t, e)) { - if ((t->get_ref_count() == 1 && e->get_ref_count() == 1) || - (!m().is_ite(t) && !m().is_ite(e))) { - //std::cout << "n-ite\n"; - result = m().mk_ite(c, m_mk_extract(high, low, t), m_mk_extract(high, low, e)); - return BR_REWRITE2; - } + 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; } return BR_FAILED; diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 54d1811e6..9be03ad6e 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2396,7 +2396,6 @@ bool theory_seq::is_var(expr* a) const { !m_util.str.is_string(a) && !m_util.str.is_unit(a) && !m_util.str.is_itos(a) && - !m_util.str.is_extract(a) && !m.is_ite(a); } @@ -4812,11 +4811,15 @@ void theory_seq::add_extract_axiom(expr* e) { void theory_seq::add_tail_axiom(expr* e, expr* s) { expr_ref head(m), tail(m); mk_decompose(s, head, tail); - add_axiom(mk_eq_empty(s), mk_seq_eq(s, mk_concat(head, e))); + literal emp = mk_eq_empty(s); + add_axiom(emp, mk_seq_eq(s, mk_concat(head, e))); + add_axiom(~emp, mk_eq_empty(e)); } void theory_seq::add_drop_last_axiom(expr* e, expr* s) { - add_axiom(mk_eq_empty(s), mk_seq_eq(s, mk_concat(e, m_util.str.mk_unit(mk_last(s))))); + literal emp = mk_eq_empty(s); + add_axiom(emp, mk_seq_eq(s, mk_concat(e, m_util.str.mk_unit(mk_last(s))))); + add_axiom(~emp, mk_eq_empty(e)); } bool theory_seq::is_drop_last(expr* s, expr* i, expr* l) { @@ -4857,6 +4860,7 @@ bool theory_seq::is_extract_suffix(expr* s, expr* i, expr* l) { /* 0 <= l <= len(s) => s = ey & l = len(e) len(s) < l => s = e + l < 0 => e = empty */ void theory_seq::add_extract_prefix_axiom(expr* e, expr* s, expr* l) { TRACE("seq", tout << mk_pp(e, m) << " " << mk_pp(s, m) << " " << mk_pp(l, m) << "\n";); @@ -4872,12 +4876,13 @@ void theory_seq::add_extract_prefix_axiom(expr* e, expr* s, expr* l) { add_axiom(~l_ge_0, ~l_le_s, mk_eq(l, le, false)); add_axiom(~l_ge_0, ~l_le_s, mk_eq(ls_minus_l, mk_len(y), false)); add_axiom(l_le_s, mk_eq(e, s, false)); + add_axiom(l_ge_0, mk_eq_empty(e)); } /* 0 <= i <= len(s) => s = xe & i = len(x) - i < 0 => len(e) = 0 - i > len(s) => len(e) = 0 + i < 0 => e = empty + i > len(s) => e = empty */ void theory_seq::add_extract_suffix_axiom(expr* e, expr* s, expr* i) { expr_ref x(mk_skolem(m_pre, s, i), m); @@ -4885,7 +4890,7 @@ void theory_seq::add_extract_suffix_axiom(expr* e, expr* s, expr* i) { expr_ref ls = mk_len(s); expr_ref zero(m_autil.mk_int(0), m); expr_ref xe = mk_concat(x, e); - literal le_is_0 = mk_eq(zero, mk_len(e), false); + literal le_is_0 = mk_eq_empty(e); literal i_ge_0 = mk_simplified_literal(m_autil.mk_ge(i, zero)); literal i_le_s = mk_simplified_literal(m_autil.mk_le(mk_sub(i, ls), zero)); add_axiom(~i_ge_0, ~i_le_s, mk_seq_eq(s, xe)); From 559f57470e125ad3e8c8b6813a762df241da4272 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 9 Dec 2018 08:21:48 +0100 Subject: [PATCH 080/318] fix #2031 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 5 ++--- src/smt/theory_seq.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 2406e92ed..857cc0e36 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -689,11 +689,10 @@ br_status seq_rewriter::mk_seq_extract(expr* a, expr* b, expr* c, expr_ref& resu if (offset == 0) { return BR_FAILED; } - expr_ref len1(m()), pos1(m()); + expr_ref pos1(m()); pos1 = m_autil.mk_sub(b, m_autil.mk_int(offset)); - len1 = m_autil.mk_sub(c, 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, len1); + result = m_util.str.mk_substr(result, pos1, c); return BR_REWRITE3; } diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 9be03ad6e..d9bb352aa 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -4735,7 +4735,6 @@ bool theory_seq::get_length(expr* e, rational& val) const { } /* - TBD: check semantics of extract. let e = extract(s, i, l) @@ -4797,15 +4796,16 @@ void theory_seq::add_extract_axiom(expr* e) { literal li_ge_ls = mk_simplified_literal(m_autil.mk_ge(ls_minus_i_l, zero)); literal l_ge_zero = mk_simplified_literal(m_autil.mk_ge(l, zero)); literal ls_le_0 = mk_simplified_literal(m_autil.mk_le(ls, zero)); + literal le_is_0 = mk_eq(le, zero, false); add_axiom(~i_ge_0, ~ls_le_i, mk_seq_eq(xey, s)); add_axiom(~i_ge_0, ~ls_le_i, mk_eq(lx, i, false)); add_axiom(~i_ge_0, ~ls_le_i, ~l_ge_zero, ~li_ge_ls, mk_eq(le, l, false)); add_axiom(~i_ge_0, ~ls_le_i, li_ge_ls, mk_eq(le, mk_sub(ls, i), false)); add_axiom(~i_ge_0, ~ls_le_i, l_ge_zero, mk_eq(le, zero, false)); - add_axiom(i_ge_0, mk_eq(le, zero, false)); - add_axiom(ls_le_i, mk_eq(le, zero, false)); - add_axiom(~ls_le_0, mk_eq(le, zero, false)); + add_axiom(i_ge_0, le_is_0); + add_axiom(ls_le_i, le_is_0); + add_axiom(~ls_le_0, le_is_0); } void theory_seq::add_tail_axiom(expr* e, expr* s) { From 51a947b73d9d597029c30c62fe8d59d013a48f3c Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Sun, 9 Dec 2018 16:16:20 +0700 Subject: [PATCH 081/318] Change how 64 bit builds are detected. Instead of doing this at configure time, we look at the actual compile time status. This also avoids hardcoding checks based on what CPU architecture is present, which doesn't work when Z3 is being built on non-x86_64 platforms. --- CMakeLists.txt | 3 --- scripts/mk_util.py | 5 ++--- scripts/update_api.py | 2 +- src/api/java/CMakeLists.txt | 3 +-- src/sat/sat_clause.cpp | 4 ++-- src/shell/main.cpp | 4 ++-- src/smt/watch_list.cpp | 6 +++--- src/util/hwf.cpp | 4 ++-- src/util/machine.h | 2 +- src/util/mpn.h | 2 +- src/util/mpz.cpp | 2 +- src/util/symbol.h | 2 +- 12 files changed, 17 insertions(+), 22 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 34d2c689d..9877af89e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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() ################################################################################ diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 83ae3d455..b3e75af32 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2635,7 +2635,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 +2660,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 +2782,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: diff --git a/scripts/update_api.py b/scripts/update_api.py index 13f1aaf9c..161c783e8 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -584,7 +584,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') 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/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index 3cbd3015b..31a4bba72 100644 --- a/src/sat/sat_clause.cpp +++ b/src/sat/sat_clause.cpp @@ -111,7 +111,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 +122,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/shell/main.cpp b/src/shell/main.cpp index 3b97d4462..b036628b1 100644 --- a/src/shell/main.cpp +++ b/src/shell/main.cpp @@ -60,7 +60,7 @@ void error(const char * msg) { void display_usage() { std::cout << "Z3 [version " << Z3_MAJOR_VERSION << "." << Z3_MINOR_VERSION << "." << Z3_BUILD_NUMBER; std::cout << " - "; -#ifdef _AMD64_ +#if defined(__LP64__) || defined(_WIN64) std::cout << "64"; #else std::cout << "32"; @@ -161,7 +161,7 @@ void parse_cmd_line_args(int argc, char ** argv) { if (strcmp(opt_name, "version") == 0) { std::cout << "Z3 version " << Z3_MAJOR_VERSION << "." << Z3_MINOR_VERSION << "." << Z3_BUILD_NUMBER; std::cout << " - "; -#ifdef _AMD64_ +#if defined(__LP64__) || defined(_WIN64) std::cout << "64"; #else std::cout << "32"; diff --git a/src/smt/watch_list.cpp b/src/smt/watch_list.cpp index 778e93021..f95e1c571 100644 --- a/src/smt/watch_list.cpp +++ b/src/smt/watch_list.cpp @@ -21,7 +21,7 @@ Revision History: namespace smt { #define DEFAULT_WATCH_LIST_SIZE (sizeof(clause *) * 4) -#ifdef _AMD64_ +#if defined(__LP64__) || defined(_WIN64) // make sure data is aligned in 64 bit machines #define HEADER_SIZE (4 * sizeof(unsigned)) #else @@ -38,7 +38,7 @@ namespace smt { if (m_data == nullptr) { unsigned size = DEFAULT_WATCH_LIST_SIZE + HEADER_SIZE; unsigned * mem = reinterpret_cast(alloc_svect(char, size)); -#ifdef _AMD64_ +#if defined(__LP64__) || defined(_WIN64) ++mem; // make sure data is aligned in 64 bit machines #endif *mem = 0; @@ -61,7 +61,7 @@ namespace smt { unsigned new_capacity = (((curr_capacity * 3 + sizeof(clause *)) >> 1)+3)&~3U; unsigned * mem = reinterpret_cast(alloc_svect(char, new_capacity + HEADER_SIZE)); unsigned curr_end_cls = end_cls_core(); -#ifdef _AMD64_ +#if defined(__LP64__) || defined(_WIN64) ++mem; // make sure data is aligned in 64 bit machines #endif *mem = curr_end_cls; diff --git a/src/util/hwf.cpp b/src/util/hwf.cpp index e6393adbd..4a7a0b7e4 100644 --- a/src/util/hwf.cpp +++ b/src/util/hwf.cpp @@ -61,7 +61,7 @@ hwf_manager::hwf_manager() : m_mpz_manager(m_mpq_manager) { #ifdef _WINDOWS -#if defined(_AMD64_) || defined(_M_IA64) +#if defined(_WIN64) // Precision control is not supported on x64. // See: http://msdn.microsoft.com/en-us/library/e9b52ceh(VS.110).aspx // CMW: I think this is okay though, the compiler will chose the right instructions @@ -557,7 +557,7 @@ void hwf_manager::mk_ninf(hwf & o) { } #ifdef _WINDOWS -#if defined(_AMD64_) || defined(_M_IA64) +#if defined(_WIN64) #ifdef USE_INTRINSICS #define SETRM(RM) _MM_SET_ROUNDING_MODE(RM) #else diff --git a/src/util/machine.h b/src/util/machine.h index 70baee41e..1ccff6330 100644 --- a/src/util/machine.h +++ b/src/util/machine.h @@ -20,7 +20,7 @@ Revision History: #ifndef MACHINE_H_ #define MACHINE_H_ -#ifdef _AMD64_ +#if defined(__LP64__) || defined(_WIN64) #define PTR_ALIGNMENT 3 #else #define PTR_ALIGNMENT 2 diff --git a/src/util/mpn.h b/src/util/mpn.h index ea20fc42b..bae972b0c 100644 --- a/src/util/mpn.h +++ b/src/util/mpn.h @@ -61,7 +61,7 @@ public: char * to_string(mpn_digit const * a, size_t lng, char * buf, size_t lbuf) const; private: - #ifdef _AMD64_ + #if defined(__LP64__) || defined(_WIN64) class mpn_sbuffer : public sbuffer { public: mpn_sbuffer() : sbuffer() {} diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index af95e1a2a..0d3a6040d 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -56,7 +56,7 @@ Revision History: #define _trailing_zeros32(X) _tzcnt_u32(X) #endif -#if defined(_AMD64_) +#if defined(__LP64__) || defined(_WIN64) #if defined(__GNUC__) #define _trailing_zeros64(X) __builtin_ctzll(X) #else diff --git a/src/util/symbol.h b/src/util/symbol.h index 40844cf3b..90a4eeb38 100644 --- a/src/util/symbol.h +++ b/src/util/symbol.h @@ -56,7 +56,7 @@ public: explicit symbol(char const * d); explicit symbol(unsigned idx): m_data(BOXTAGINT(char const *, idx, 1)) { -#ifndef _AMD64_ +#if !defined(__LP64__) && !defined(_WIN64) SASSERT(idx < (SIZE_MAX >> PTR_ALIGNMENT)); #endif } From 1b91694d9b83167679b63124f36863da9fc55a3a Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Sun, 9 Dec 2018 21:02:06 +0700 Subject: [PATCH 082/318] Enable dl_table tests on non-Windows/Cygwin. --- src/test/dl_table.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/test/dl_table.cpp b/src/test/dl_table.cpp index 326be5d04..8eb864f7b 100644 --- a/src/test/dl_table.cpp +++ b/src/test/dl_table.cpp @@ -1,8 +1,6 @@ /*++ Copyright (c) 2015 Microsoft Corporation --*/ -#if defined(_WINDOWS) || defined(_CYGWIN) - #include "muz/base/dl_context.h" #include "muz/rel/dl_table.h" #include "muz/fp/dl_register_engine.h" @@ -98,7 +96,3 @@ void test_dl_bitvector_table() { void tst_dl_table() { test_dl_bitvector_table(); } -#else -void tst_dl_table() { -} -#endif From 604e5dd0bbb288b34c154d75b27a9747b87b9ccc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 9 Dec 2018 12:56:21 -0800 Subject: [PATCH 083/318] fixing #2030 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 2 +- src/smt/theory_seq.cpp | 47 ++++++++++++++++++++----------- src/smt/theory_seq.h | 4 +-- 3 files changed, 34 insertions(+), 19 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 857cc0e36..1ad526dc3 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -501,7 +501,7 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con case _OP_STRING_STRIDOF: UNREACHABLE(); } - TRACE("seq", tout << result << "\n";); + CTRACE("seq", st != BR_FAILED, tout << result << "\n";); return st; } diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index d9bb352aa..5a2225aa1 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -3767,6 +3767,8 @@ void theory_seq::finalize_model(model_generator& mg) { } void theory_seq::init_model(model_generator & mg) { + enable_trace("seq"); + TRACE("seq", display(tout << "level: " << get_context().get_scope_level() << "\n");); m_rep.push_scope(); m_factory = alloc(seq_factory, get_manager(), get_family_id(), mg.get_model()); mg.register_factory(m_factory); @@ -3884,28 +3886,35 @@ public: th.m_rewrite(result); } th.m_factory->add_trail(result); + TRACE("seq", tout << result << "\n";); return to_app(result); } }; +app* theory_seq::get_ite_value(expr* e) { + expr* e1, *e2, *e3; + while (m.is_ite(e, e1, e2, e3)) { + if (get_root(e2) == get_root(e)) { + e = e2; + } + else if (get_root(e3) == get_root(e)) { + e = e3; + } + else { + break; + } + } + return to_app(e); +} model_value_proc * theory_seq::mk_value(enode * n, model_generator & mg) { app* e = n->get_owner(); context& ctx = get_context(); - expr* e1, *e2, *e3; - if (m.is_ite(e, e1, e2, e3) && ctx.e_internalized(e2) && ctx.e_internalized(e3) && - (get_root(e2) == n->get_root() || - get_root(e3) == n->get_root())) { - if (ctx.get_enode(e2)->get_root() == n->get_root()) { - return mk_value(ctx.get_enode(e2), mg); - } - else { - return mk_value(ctx.get_enode(e3), mg); - } - } - else if (m_util.is_seq(e)) { + TRACE("seq", tout << mk_pp(n->get_owner(), m) << "\n";); + e = get_ite_value(e); + if (m_util.is_seq(e)) { ptr_vector concats; - get_concat(e, concats); + get_ite_concat(e, concats); sort* srt = m.get_sort(e); seq_value_proc* sv = alloc(seq_value_proc, *this, srt); @@ -3940,11 +3949,16 @@ model_value_proc * theory_seq::mk_value(enode * n, model_generator & mg) { app* theory_seq::mk_value(app* e) { expr_ref result(m); + context& ctx = get_context(); + e = get_ite_value(e); result = m_rep.find(e); + if (is_var(result)) { SASSERT(m_factory); expr_ref val(m); val = m_factory->get_some_value(m.get_sort(result)); + std::cout << "is-var " << result << "\n"; + std::cout << "val " << val << "\n"; if (val) { result = val; } @@ -5643,15 +5657,16 @@ bool theory_seq::canonizes(bool sign, expr* e) { } -void theory_seq::get_concat(expr* e, ptr_vector& concats) { +void theory_seq::get_ite_concat(expr* e, ptr_vector& concats) { expr* e1 = nullptr, *e2 = nullptr; while (true) { e = m_rep.find(e); + e = get_ite_value(e); if (m_util.str.is_concat(e, e1, e2)) { - get_concat(e1, concats); + get_ite_concat(e1, concats); e = e2; continue; - } + } concats.push_back(e); return; } diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 929626757..c5cb242b3 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -404,6 +404,8 @@ namespace smt { void init_search_eh() override; void init_model(expr_ref_vector const& es); + app* get_ite_value(expr* a); + void get_ite_concat(expr* e, ptr_vector& concats); void len_offset(expr* e, rational val); void prop_arith_to_len_offset(); @@ -539,8 +541,6 @@ namespace smt { expr_ref expand1(expr* e, dependency*& eqs); expr_ref try_expand(expr* e, dependency*& eqs); void add_dependency(dependency*& dep, enode* a, enode* b); - - void get_concat(expr* e, ptr_vector& concats); // terms whose meaning are encoded using axioms. void enque_axiom(expr* e); From f2a7bcaf5d433fec269ac7a8d144bb5d1c40d1ea Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 9 Dec 2018 14:38:45 -0800 Subject: [PATCH 084/318] remove prints Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 5a2225aa1..06e05315d 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -3957,8 +3957,6 @@ app* theory_seq::mk_value(app* e) { SASSERT(m_factory); expr_ref val(m); val = m_factory->get_some_value(m.get_sort(result)); - std::cout << "is-var " << result << "\n"; - std::cout << "val " << val << "\n"; if (val) { result = val; } From 68ace83893aed1302883903810a5a102d5c9bc6a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 10 Dec 2018 07:34:56 -0800 Subject: [PATCH 085/318] remove enable trace Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 06e05315d..a26626224 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -3767,8 +3767,6 @@ void theory_seq::finalize_model(model_generator& mg) { } void theory_seq::init_model(model_generator & mg) { - enable_trace("seq"); - TRACE("seq", display(tout << "level: " << get_context().get_scope_level() << "\n");); m_rep.push_scope(); m_factory = alloc(seq_factory, get_manager(), get_family_id(), mg.get_model()); mg.register_factory(m_factory); From b40c2b2926edcb88de170b54942a2e796e78e41e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 10 Dec 2018 14:11:00 -0800 Subject: [PATCH 086/318] fix #876 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 11 +++-- src/smt/theory_seq.cpp | 75 ++++++++++++++++++++++--------- src/smt/theory_seq.h | 1 + 3 files changed, 63 insertions(+), 24 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 1ad526dc3..25fc5c119 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -386,7 +386,7 @@ 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()); - + TRACE("seq", tout << f->get_name() << "\n";); br_status st = BR_FAILED; switch(f->get_decl_kind()) { @@ -400,16 +400,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; diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index a26626224..e60281bfa 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -5272,6 +5272,26 @@ void theory_seq::new_eq_eh(theory_var v1, theory_var v2) { new_eq_eh(deps, n1, n2); } +lbool theory_seq::regex_are_equal(expr* r1, expr* r2) { + if (r1 == r2) { + return l_true; + } + expr* d1 = m_util.re.mk_inter(r1, m_util.re.mk_complement(r2)); + expr* d2 = m_util.re.mk_inter(r2, m_util.re.mk_complement(r1)); + expr_ref diff(m_util.re.mk_union(d1, d2), m); + eautomaton* aut = get_automaton(diff); + if (!aut) { + return l_undef; + } + else if (aut->is_empty()) { + return l_true; + } + else { + return l_false; + } +} + + void theory_seq::new_eq_eh(dependency* deps, enode* n1, enode* n2) { TRACE("seq", tout << expr_ref(n1->get_owner(), m) << " = " << expr_ref(n2->get_owner(), m) << "\n";); if (n1 != n2 && m_util.is_seq(n1->get_owner())) { @@ -5292,28 +5312,23 @@ void theory_seq::new_eq_eh(dependency* deps, enode* n1, enode* n2) { // create an expression for the symmetric difference and imply it is empty. enode_pair_vector eqs; literal_vector lits; - if (!linearize(deps, eqs, lits)) - return; context& ctx = get_context(); - eqs.push_back(enode_pair(n1, n2)); - expr_ref r1(n1->get_owner(), m); - expr_ref r2(n2->get_owner(), m); - ctx.get_rewriter()(r1); - ctx.get_rewriter()(r2); - if (r1 == r2) { - return; + switch (regex_are_equal(n1->get_owner(), n2->get_owner())) { + case l_true: + break; + case l_false: + if (!linearize(deps, eqs, lits)) { + throw default_exception("could not linearlize assumptions"); + } + eqs.push_back(enode_pair(n1, n2)); + ctx.set_conflict( + ctx.mk_justification( + ext_theory_conflict_justification( + get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), eqs.size(), eqs.c_ptr(), 0, nullptr))); + break; + default: + throw default_exception("convert regular expressions into automata"); } -#if 0 - expr* d1 = m_util.re.mk_inter(r1, m_util.re.mk_complement(r2)); - expr* d2 = m_util.re.mk_inter(r2, m_util.re.mk_complement(r1)); - expr_ref diff(m_util.re.mk_union(d1, d2), m); - lit = mk_literal(m_util.re.mk_is_empty(diff)); - justification* js = - ctx.mk_justification( - ext_theory_propagation_justification( - get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), eqs.size(), eqs.c_ptr(), lit)); - ctx.assign(lit, js); -#endif } } @@ -5323,6 +5338,26 @@ void theory_seq::new_diseq_eh(theory_var v1, theory_var v2) { expr_ref e1(n1->get_owner(), m); expr_ref e2(n2->get_owner(), m); SASSERT(n1->get_root() != n2->get_root()); + if (m_util.is_re(n1->get_owner())) { + enode_pair_vector eqs; + literal_vector lits; + context& ctx = get_context(); + switch (regex_are_equal(e1, e2)) { + case l_false: + return; + case l_true: { + literal lit = mk_eq(e1, e2, false); + lits.push_back(~lit); + ctx.set_conflict( + ctx.mk_justification( + ext_theory_conflict_justification( + get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), eqs.size(), eqs.c_ptr(), 0, nullptr))); + return; + } + default: + throw default_exception("convert regular expressions into automata"); + } + } m_exclude.update(e1, e2); expr_ref eq(m.mk_eq(e1, e2), m); TRACE("seq", tout << "new disequality " << get_context().get_scope_level() << ": " << eq << "\n";); diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index c5cb242b3..254b6e2fe 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -451,6 +451,7 @@ namespace smt { vector const& ll, vector const& rl); bool set_empty(expr* x); bool is_complex(eq const& e); + lbool regex_are_equal(expr* r1, expr* r2); bool check_extensionality(); bool check_contains(); From 092c25d5963a0d645b8df7064f5254efd18ee9e9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 10 Dec 2018 18:37:30 -0800 Subject: [PATCH 087/318] fix #2007 Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 3 +++ src/api/api_context.h | 21 +++++++++++++++++++++ src/api/api_model.cpp | 5 ++++- src/cmd_context/cmd_context.h | 21 +++++++++++++++++++++ src/cmd_context/eval_cmd.cpp | 1 + src/cmd_context/simplify_cmd.cpp | 19 ------------------- src/model/model.cpp | 4 ++++ src/model/model.h | 1 + src/model/model_evaluator.cpp | 4 ++++ src/model/model_evaluator.h | 3 +++ 10 files changed, 62 insertions(+), 20 deletions(-) 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_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_model.cpp b/src/api/api_model.cpp index c95a36df5..0937e668e 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -161,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()); diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index b2ed1e5cb..124821561 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" @@ -493,4 +494,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/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/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/model/model.cpp b/src/model/model.cpp index 86ff64ea3..de6bb4db8 100644 --- a/src/model/model.cpp +++ b/src/model/model.cpp @@ -468,6 +468,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..b0e97e5e4 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -627,3 +627,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. */ From 06fc94818f477cd143fb114e9cde26ccc08320b1 Mon Sep 17 00:00:00 2001 From: Nicola Mometto Date: Tue, 11 Dec 2018 12:09:22 +0000 Subject: [PATCH 088/318] Change error message from "internal failure" to "Object allocation failed" For consistency with https://github.com/Z3Prover/z3/commit/ad49c3269a7a0e238d27e06532eb15482e285de2 and Java/dotNet APIs --- src/api/ml/z3native_stubs.c.pre | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/ml/z3native_stubs.c.pre b/src/api/ml/z3native_stubs.c.pre index 4d221aac3..5c1a3bd06 100644 --- a/src/api/ml/z3native_stubs.c.pre +++ b/src/api/ml/z3native_stubs.c.pre @@ -458,7 +458,7 @@ CAMLprim DLL_PUBLIC value n_mk_config() { z3rv = Z3_mk_config(); if (z3rv == NULL) { - caml_raise_with_string(*caml_named_value("Z3EXCEPTION"), "internal error"); + caml_raise_with_string(*caml_named_value("Z3EXCEPTION"), "Object allocation failed"); } /* construct simple return value */ From 796689f708a8248a46cc080cb1b8cdb1b816f283 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 11 Dec 2018 09:08:53 -0800 Subject: [PATCH 089/318] #1948 remove memory allocation in nlsat::solver::~solver Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_solver.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index f430f3a0c..882025024 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,11 @@ namespace nlsat { m_assignment.reset(); } + void clear() { + undo_until_size(0); + del_clauses(); + del_unref_atoms(); + } void checkpoint() { if (!m_rlimit.inc()) throw solver_exception(m_rlimit.get_cancel_msg()); From a3f9e3168dfee8f2be7491022c8e89a7adb8cb6c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 11 Dec 2018 09:29:59 -0800 Subject: [PATCH 090/318] simplify ~context #1948 Signed-off-by: Nikolaj Bjorner --- src/api/api_context.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 2de93677d..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(); } } From 045fef35ed379628a65c5bf325270bd8518b05de Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 11 Dec 2018 09:35:27 -0800 Subject: [PATCH 091/318] fix build break Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_solver.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index 882025024..6ea764a0a 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -231,6 +231,9 @@ namespace nlsat { } void clear() { + m_explain.reset(); + m_lemma.reset(); + m_lazy_clause.reset(); undo_until_size(0); del_clauses(); del_unref_atoms(); From bfcea7a8198efd9ff4b0da6e30266a350cefa503 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 11 Dec 2018 09:38:36 -0800 Subject: [PATCH 092/318] perf improvements by reordering variable branching #1676 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 66 ++++++++++++++++++++++++++---------------- src/smt/theory_seq.h | 5 ++-- 2 files changed, 44 insertions(+), 27 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index e60281bfa..05248c6c4 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -312,12 +312,7 @@ final_check_status theory_seq::final_check_eh() { TRACEFIN("branch_binary_variable"); return FC_CONTINUE; } - if (branch_ternary_variable1() || branch_ternary_variable2() || branch_quat_variable()) { - ++m_stats.m_branch_variable; - TRACEFIN("split_based_on_alignment"); - return FC_CONTINUE; - } - if (branch_variable_mb() || branch_variable()) { + if (branch_variable()) { ++m_stats.m_branch_variable; TRACEFIN("branch_variable"); return FC_CONTINUE; @@ -387,7 +382,7 @@ bool theory_seq::branch_binary_variable(eq const& e) { rational lenX, lenY; context& ctx = get_context(); - if (branch_variable(e)) { + if (branch_variable_eq(e)) { return true; } if (!get_length(x, lenX)) { @@ -457,6 +452,9 @@ bool theory_seq::is_unit_eq(expr_ref_vector const& ls, expr_ref_vector const& rs if (ls.empty() || !is_var(ls[0])) { return false; } + //std::function is_unit = [&](expr* elem) { return m_util.str.is_unit(elem); } + //return rs.forall(is_unit); + for (auto const& elem : rs) { if (!m_util.str.is_unit(elem)) { return false; @@ -502,10 +500,9 @@ void theory_seq::branch_unit_variable(dependency* dep, expr* X, expr_ref_vector } bool theory_seq::branch_ternary_variable1() { - - //std::function branch = [&](eq const& e) { return branch_ternary_variable(e) || branch_ternary_variable2(e); }; - //return m_eqs.exists(branch); - for (auto const& e : m_eqs) { + int start = get_context().get_random_value(); + for (unsigned i = 0; i < m_eqs.size(); ++i) { + eq const& e = m_eqs[(i + start) % m_eqs.size()]; if (branch_ternary_variable(e) || branch_ternary_variable2(e)) { return true; } @@ -514,7 +511,9 @@ bool theory_seq::branch_ternary_variable1() { } bool theory_seq::branch_ternary_variable2() { - for (auto const& e : m_eqs) { + int start = get_context().get_random_value(); + for (unsigned i = 0; i < m_eqs.size(); ++i) { + eq const& e = m_eqs[(i + start) % m_eqs.size()]; if (branch_ternary_variable(e, true)) { return true; } @@ -1339,6 +1338,20 @@ bool theory_seq::len_based_split(eq const& e) { return true; } +/** + \brief select branching on variable equality. + preference mb > eq > ternary > quat + this performs much better on #1628 +*/ +bool theory_seq::branch_variable() { + if (branch_variable_mb()) return true; + if (branch_variable_eq()) return true; + if (branch_ternary_variable1()) return true; + if (branch_ternary_variable2()) return true; + if (branch_quat_variable()) return true; + return false; +} + bool theory_seq::branch_variable_mb() { bool change = false; for (auto const& e : m_eqs) { @@ -1517,7 +1530,7 @@ bool theory_seq::enforce_length(expr_ref_vector const& es, vector & le return all_have_length; } -bool theory_seq::branch_variable() { +bool theory_seq::branch_variable_eq() { context& ctx = get_context(); unsigned sz = m_eqs.size(); int start = ctx.get_random_value(); @@ -1526,24 +1539,15 @@ bool theory_seq::branch_variable() { unsigned k = (i + start) % sz; eq const& e = m_eqs[k]; - if (branch_variable(e)) { + if (branch_variable_eq(e)) { TRACE("seq", tout << "branch variable\n";); return true; } - -#if 0 - if (!has_length(e.ls())) { - enforce_length(e.ls()); - } - if (!has_length(e.rs())) { - enforce_length(e.rs()); - } -#endif } return ctx.inconsistent(); } -bool theory_seq::branch_variable(eq const& e) { +bool theory_seq::branch_variable_eq(eq const& e) { unsigned id = e.id(); unsigned s = find_branch_start(2*id); TRACE("seq", tout << s << " " << id << ": " << e.ls() << " = " << e.rs() << "\n";); @@ -4450,6 +4454,7 @@ expr_ref theory_seq::add_elim_string_axiom(expr* n) { - len(str) = str.length() if x = str - len(empty) = 0 if x = empty - len(int.to.str(i)) >= 1 if x = int.to.str(i) and more generally if i = 0 then 1 else 1+floor(log(|i|)) + - len(substr(s,i,l)) <= l if x = substr(s,i,l) - len(x) >= 0 otherwise */ void theory_seq::add_length_axiom(expr* n) { @@ -4467,8 +4472,13 @@ void theory_seq::add_length_axiom(expr* n) { } else if (m_util.str.is_itos(x)) { add_itos_length_axiom(n); - } + } else { + expr* s = nullptr, *i = nullptr, *l = nullptr; + if (m_util.str.is_extract(x, s, i, l)) { + literal len_le_l = mk_simplified_literal(m_autil.mk_ge(mk_sub(l, n), m_autil.mk_int(0))); + add_axiom(len_le_l); + } add_axiom(mk_literal(m_autil.mk_ge(n, m_autil.mk_int(0)))); } if (!ctx.at_base_level()) { @@ -5186,6 +5196,8 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { f = mk_skolem(m_prefix, e1, e2); f = mk_concat(e1, f); propagate_eq(lit, f, e2, true); + //literal len1_le_len2 = mk_simplified_literal(m_autil.mk_ge(mk_sub(mk_len(e2), mk_len(e1)), m_autil.mk_int(0))); + //add_axiom(~lit, len1_le_len2); } else { propagate_not_prefix(e); @@ -5196,6 +5208,8 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { f = mk_skolem(m_suffix, e1, e2); f = mk_concat(f, e1); propagate_eq(lit, f, e2, true); + //literal len1_le_len2 = mk_simplified_literal(m_autil.mk_ge(mk_sub(mk_len(e2), mk_len(e1)), m_autil.mk_int(0))); + //add_axiom(~lit, len1_le_len2); } else { propagate_not_suffix(e); @@ -5222,6 +5236,8 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { expr_ref f2 = mk_skolem(m_indexof_right, e1, e2); f = mk_concat(f1, e2, f2); propagate_eq(lit, f, e1, true); + //literal len2_le_len1 = mk_simplified_literal(m_autil.mk_ge(mk_sub(mk_len(e1), mk_len(e2)), m_autil.mk_int(0))); + //add_axiom(~lit, len2_le_len1); } else if (!canonizes(false, e)) { propagate_non_empty(lit, e2); diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 254b6e2fe..9925188b6 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -420,12 +420,13 @@ namespace smt { bool reduce_length_eq(); bool branch_unit_variable(); // branch on XYZ = abcdef bool branch_binary_variable(); // branch on abcX = Ydefg + bool branch_variable(); // branch on bool branch_ternary_variable1(); // branch on XabcY = Zdefg or XabcY = defgZ bool branch_ternary_variable2(); // branch on XabcY = defgZmnpq bool branch_quat_variable(); // branch on XabcY = ZdefgT bool len_based_split(); // split based on len offset bool branch_variable_mb(); // branch on a variable, model based on length - bool branch_variable(); // branch on a variable + bool branch_variable_eq(); // branch on a variable, by an alignment among variable boundaries. bool is_solved(); bool check_length_coherence(); bool check_length_coherence0(expr* e); @@ -433,7 +434,7 @@ namespace smt { bool fixed_length(bool is_zero = false); bool fixed_length(expr* e, bool is_zero); void branch_unit_variable(dependency* dep, expr* X, expr_ref_vector const& units); - bool branch_variable(eq const& e); + bool branch_variable_eq(eq const& e); bool branch_binary_variable(eq const& e); bool eq_unit(expr* const& l, expr* const &r) const; unsigned_vector overlap(expr_ref_vector const& ls, expr_ref_vector const& rs); From 93c59ffbd94190ab244972beb63fbb364dda6171 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 11 Dec 2018 15:48:33 -0800 Subject: [PATCH 093/318] update script to sign assembly Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 83ae3d455..e4e8728fe 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1867,6 +1867,7 @@ class DotNetCoreDLLComponent(Component): key = "" if not self.key_file is None: key = "%s" % self.key_file + key += "\ntrue" if VS_X64: platform = 'x64' From 02f01fcef1ac7f390bcd54dd9113a53e8e75bcfa Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 11 Dec 2018 17:31:09 -0800 Subject: [PATCH 094/318] adding esrp feature Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 78 +++++++++++++++++++++++++++++++++++++++--- scripts/mk_win_dist.py | 11 +++++- 2 files changed, 84 insertions(+), 5 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index e4e8728fe..ad643c9ba 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -90,6 +90,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 +707,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 +752,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'): @@ -1922,10 +1925,76 @@ 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 = BUILD_DIR + assemblySignStr = """ +{ + "Version": "1.0.0", + "SignBatches" + : + [ + { + "SourceLocationType": "UNC", + "SourceRootDirectory": "c:\\ESRP\\input", + "DestinationLocationType": "UNC", + "DestinationRootDirectory": "c:\\ESRP\\output", + "SignRequestFiles": [ + { + "CustomerCorrelationId": "%s", + "SourceLocation": "%s\\libz3.dll", + "DestinationLocation": "%s\\libz3.dll" + }, + { + "CustomerCorrelationId": "%s", + "SourceLocation": "%s\\Microsoft.Z3.dll", + "DestinationLocation": "%s\\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" + } + ] + } + } + ] +} """ % (guid, path, path, guid, path, path) + assemblySign = os.path.join('dotnet', 'assembly-sign-input.json') + with open(os.path.join(BUILD_DIR, assemblySign), 'w') as ous: + ous.write(assemblySignStr) + outputFile = os.path.join(BUILD_DIR, 'dotnet', "output.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)) + def main_component(self): return is_dotnet_core_enabled() @@ -1934,6 +2003,7 @@ class DotNetCoreDLLComponent(Component): # TBD: is this required for dotnet core given that version numbers are in z3.csproj file? return True + def mk_win_dist(self, build_path, dist_path): if is_dotnet_core_enabled(): mk_dir(os.path.join(dist_path, INSTALL_BIN_DIR)) 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: From b3d0ed6143420fbb174a62da7ab62aa525b7022d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 11 Dec 2018 20:27:28 -0800 Subject: [PATCH 095/318] fix #2035 regression. correct axiom is |extract(s,i,l)| <= l or l < 0, but it is subsumed by encoding of extract, so new axiom is not useful Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 05248c6c4..283bd4e57 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -4454,7 +4454,6 @@ expr_ref theory_seq::add_elim_string_axiom(expr* n) { - len(str) = str.length() if x = str - len(empty) = 0 if x = empty - len(int.to.str(i)) >= 1 if x = int.to.str(i) and more generally if i = 0 then 1 else 1+floor(log(|i|)) - - len(substr(s,i,l)) <= l if x = substr(s,i,l) - len(x) >= 0 otherwise */ void theory_seq::add_length_axiom(expr* n) { @@ -4474,11 +4473,6 @@ void theory_seq::add_length_axiom(expr* n) { add_itos_length_axiom(n); } else { - expr* s = nullptr, *i = nullptr, *l = nullptr; - if (m_util.str.is_extract(x, s, i, l)) { - literal len_le_l = mk_simplified_literal(m_autil.mk_ge(mk_sub(l, n), m_autil.mk_int(0))); - add_axiom(len_le_l); - } add_axiom(mk_literal(m_autil.mk_ge(n, m_autil.mk_int(0)))); } if (!ctx.at_base_level()) { @@ -4801,6 +4795,7 @@ void theory_seq::add_extract_axiom(expr* e) { add_extract_suffix_axiom(e, s, i); return; } + expr_ref x(mk_skolem(m_pre, s, i), m); expr_ref ls = mk_len(s); expr_ref lx = mk_len(x); From 8d23ad2f7ed42d8cd4a1d86721c0a3b50509158d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 12 Dec 2018 10:14:38 -0800 Subject: [PATCH 096/318] fix generation of assembly-sign-input to take escape sequences and absolute paths Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 023158573..7d9050f6d 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1937,7 +1937,7 @@ class DotNetCoreDLLComponent(Component): import uuid guid = str(uuid.uuid4()) - path = BUILD_DIR + path = os.path.abspath(BUILD_DIR).replace("\\","\\\\") assemblySignStr = """ { "Version": "1.0.0", @@ -1946,19 +1946,19 @@ class DotNetCoreDLLComponent(Component): [ { "SourceLocationType": "UNC", - "SourceRootDirectory": "c:\\ESRP\\input", + "SourceRootDirectory": "c:\\\\ESRP\\\\input", "DestinationLocationType": "UNC", - "DestinationRootDirectory": "c:\\ESRP\\output", + "DestinationRootDirectory": "c:\\\\ESRP\\\\output", "SignRequestFiles": [ { "CustomerCorrelationId": "%s", - "SourceLocation": "%s\\libz3.dll", - "DestinationLocation": "%s\\libz3.dll" + "SourceLocation": "%s\\\\libz3.dll", + "DestinationLocation": "%s\\\\libz3.dll" }, { "CustomerCorrelationId": "%s", - "SourceLocation": "%s\\Microsoft.Z3.dll", - "DestinationLocation": "%s\\Microsoft.Z3.dll" + "SourceLocation": "%s\\\\Microsoft.Z3.dll", + "DestinationLocation": "%s\\\\Microsoft.Z3.dll" } ], "SigningInfo": { @@ -1969,9 +1969,9 @@ class DotNetCoreDLLComponent(Component): "Parameters" : { "OpusName": "Microsoft", "OpusInfo": "http://www.microsoft.com", - "FileDigest": "/fd \"SHA256\"", + "FileDigest": "/fd \\"SHA256\\"", "PageHash": "/NPH", - "TimeStamp": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256" + "TimeStamp": "/tr \\"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\\" /td sha256" }, "ToolName" : "sign", "ToolVersion" : "1.0" @@ -1988,10 +1988,10 @@ class DotNetCoreDLLComponent(Component): } ] } """ % (guid, path, path, guid, path, path) - assemblySign = os.path.join('dotnet', 'assembly-sign-input.json') - with open(os.path.join(BUILD_DIR, assemblySign), 'w') as ous: + 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(BUILD_DIR, 'dotnet', "output.json") + 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)) From c5ada288c2c46d8c6f6d80b12bc2a3824b12d66a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 12 Dec 2018 12:46:28 -0800 Subject: [PATCH 097/318] updated script Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 7d9050f6d..9076b582f 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1946,19 +1946,19 @@ class DotNetCoreDLLComponent(Component): [ { "SourceLocationType": "UNC", - "SourceRootDirectory": "c:\\\\ESRP\\\\input", + "SourceRootDirectory": "%s", "DestinationLocationType": "UNC", "DestinationRootDirectory": "c:\\\\ESRP\\\\output", "SignRequestFiles": [ { "CustomerCorrelationId": "%s", - "SourceLocation": "%s\\\\libz3.dll", - "DestinationLocation": "%s\\\\libz3.dll" + "SourceLocation": "libz3.dll", + "DestinationLocation": "libz3.dll" }, { "CustomerCorrelationId": "%s", - "SourceLocation": "%s\\\\Microsoft.Z3.dll", - "DestinationLocation": "%s\\\\Microsoft.Z3.dll" + "SourceLocation": "Microsoft.Z3.dll", + "DestinationLocation": "Microsoft.Z3.dll" } ], "SigningInfo": { @@ -1987,13 +1987,15 @@ class DotNetCoreDLLComponent(Component): } } ] -} """ % (guid, path, path, guid, path, path) +} """ % (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): From 58b9fc437d95c1f1c0fa3442ebc13d0b49d60fbe Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 13 Dec 2018 16:09:08 -0600 Subject: [PATCH 098/318] add sin/cos axiom regardless of whether sin/cos can be eliminated. fix #2037 Signed-off-by: Nikolaj Bjorner --- src/tactic/arith/purify_arith_tactic.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/tactic/arith/purify_arith_tactic.cpp b/src/tactic/arith/purify_arith_tactic.cpp index 67dadd34b..14b6c6b41 100644 --- a/src/tactic/arith/purify_arith_tactic.cpp +++ b/src/tactic/arith/purify_arith_tactic.cpp @@ -509,6 +509,9 @@ struct purify_arith_proc { return BR_DONE; } else { + expr_ref s(u().mk_sin(theta), m()); + expr_ref c(u().mk_cos(theta), m()); + push_cnstr(EQ(mk_real_one(), u().mk_add(u().mk_mul(s, s), u().mk_mul(c, c)))); return BR_FAILED; } } @@ -777,11 +780,10 @@ struct purify_arith_proc { if (produce_models && !m_sin_cos.empty()) { generic_model_converter* emc = alloc(generic_model_converter, m(), "purify_sin_cos"); mc = concat(mc.get(), emc); - obj_map >::iterator it = m_sin_cos.begin(), end = m_sin_cos.end(); - for (; it != end; ++it) { - emc->add(it->m_key->get_decl(), - m().mk_ite(u().mk_ge(it->m_value.first, mk_real_zero()), u().mk_acos(it->m_value.second), - u().mk_add(u().mk_acos(u().mk_uminus(it->m_value.second)), u().mk_pi()))); + for (auto const& kv : m_sin_cos) { + emc->add(kv.m_key->get_decl(), + m().mk_ite(u().mk_ge(kv.m_value.first, mk_real_zero()), u().mk_acos(kv.m_value.second), + u().mk_add(u().mk_acos(u().mk_uminus(kv.m_value.second)), u().mk_pi()))); } } From f56749a241a6786b357d5d41bddf4f922a251dad Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 16 Dec 2018 15:18:49 -0800 Subject: [PATCH 099/318] fix #2041, fix #2043 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/rewriter_def.h | 7 +- src/ast/seq_decl_plugin.cpp | 25 ++--- src/smt/theory_pb.cpp | 179 +++----------------------------- src/smt/theory_pb.h | 9 +- 4 files changed, 31 insertions(+), 189 deletions(-) diff --git a/src/ast/rewriter/rewriter_def.h b/src/ast/rewriter/rewriter_def.h index 3ee1e4caf..dfa0c5467 100644 --- a/src/ast/rewriter/rewriter_def.h +++ b/src/ast/rewriter/rewriter_def.h @@ -514,7 +514,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/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index eaedd22ba..20e1fb36c 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -69,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; @@ -296,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; } @@ -325,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(); } @@ -556,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); @@ -1063,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/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 90d1a5481..8a880b1cf 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -523,21 +523,15 @@ namespace smt { SASSERT(pb.is_at_least_k(atom) || pb.is_ge(atom) || pb.is_eq(atom)); } TRACE("pb", display(tout, *c, true);); - //app_ref fml1(m), fml2(m); - //fml1 = c->to_expr(ctx, m); c->unique(); lbool is_true = c->normalize(); c->prune(); c->post_prune(); - //fml2 = c->to_expr(ctx, m); - //expr_ref validate_pb = pb_rewriter(m).mk_validate_rewrite(fml1, fml2); - //pb_rewriter(m).dump_pb_rewrite(validate_pb); literal lit(abv); - TRACE("pb", display(tout, *c); tout << " := " << lit << "\n";); - switch(is_true) { + switch (is_true) { case l_false: lit = ~lit; // fall-through @@ -590,14 +584,11 @@ namespace smt { else { c->m_compilation_threshold = UINT_MAX; } - init_watch_var(*c); + init_watch_ineq(*c); init_watch(abv); m_var_infos[abv].m_ineq = c; m_ineqs_trail.push_back(abv); - - TRACE("pb", display(tout, *c);); - return true; } @@ -699,50 +690,40 @@ namespace smt { } } - void theory_pb::watch_literal(literal lit, ineq* c) { init_watch(lit.var()); ptr_vector* ineqs = m_var_infos[lit.var()].m_lit_watch[lit.sign()]; + TRACE("pb", display(tout << "watch " << lit << " " << (c), *c);); if (ineqs == nullptr) { ineqs = alloc(ptr_vector); m_var_infos[lit.var()].m_lit_watch[lit.sign()] = ineqs; } - ineqs->push_back(c); - } - - - void theory_pb::watch_var(bool_var v, ineq* c) { - init_watch(v); - ptr_vector* ineqs = m_var_infos[v].m_var_watch; - if (ineqs == nullptr) { - ineqs = alloc(ptr_vector); - m_var_infos[v].m_var_watch = ineqs; + for (auto* c1 : *ineqs) { + //if (c1 == c) return; + SASSERT (c1 != c); } ineqs->push_back(c); } - void theory_pb::unwatch_var(bool_var v, ineq* c) { - ptr_vector* ineqs = m_var_infos[v].m_var_watch; - if (ineqs) { - remove(*ineqs, c); - } - } - void theory_pb::unwatch_literal(literal lit, ineq* c) { ptr_vector* ineqs = m_var_infos[lit.var()].m_lit_watch[lit.sign()]; if (ineqs) { + TRACE("pb", display(tout << "unwatch " << lit << " " << (c), *c);); remove(*ineqs, c); } } void theory_pb::remove(ptr_vector& ineqs, ineq* c) { - for (unsigned j = 0; j < ineqs.size(); ++j) { + unsigned sz = ineqs.size(); + for (unsigned j = 0; j < sz; ++j) { if (ineqs[j] == c) { - std::swap(ineqs[j], ineqs[ineqs.size()-1]); + std::swap(ineqs[j], ineqs[sz-1]); ineqs.pop_back(); - break; + TRACE("pb", tout << "removed\n";); + return; } } + TRACE("pb", tout << "not removed\n";); } // ---------------------------- @@ -1042,13 +1023,6 @@ namespace smt { } } } - ineqs = m_var_infos[v].m_var_watch; - if (ineqs != nullptr) { - for (unsigned i = 0; i < ineqs->size(); ++i) { - ineq* c = (*ineqs)[i]; - assign_watch(v, is_true, *c); - } - } ineq* c = m_var_infos[v].m_ineq; if (c != nullptr) { if (c->is_ge()) { @@ -1143,19 +1117,6 @@ namespace smt { return lits; } - class theory_pb::rewatch_vars : public trail { - theory_pb& pb; - ineq& c; - public: - rewatch_vars(theory_pb& p, ineq& c): pb(p), c(c) {} - void undo(context& ctx) override { - for (unsigned i = 0; i < c.size(); ++i) { - pb.watch_var(c.lit(i).var(), &c); - } - } - }; - - class theory_pb::negate_ineq : public trail { ineq& c; public: @@ -1176,7 +1137,6 @@ namespace smt { ctx.push_trail(value_trail(c.m_max_sum)); ctx.push_trail(value_trail(c.m_min_sum)); ctx.push_trail(value_trail(c.m_nfixed)); - ctx.push_trail(rewatch_vars(*this, c)); SASSERT(c.is_ge()); unsigned sz = c.size(); @@ -1227,104 +1187,7 @@ namespace smt { */ void theory_pb::assign_eq(ineq& c, bool is_true) { SASSERT(c.is_eq()); - - } - - /** - Propagation rules: - - nfixed = N & minsum = k -> T - nfixed = N & minsum != k -> F - - minsum > k or maxsum < k -> F - minsum = k & = -> fix 0 variables - nfixed+1 = N & = -> fix unassigned variable or conflict - nfixed+1 = N & != -> maybe forced unassigned to ensure disequal - minsum >= k -> T - maxsum < k -> F - */ - - void theory_pb::assign_watch(bool_var v, bool is_true, ineq& c) { - - context& ctx = get_context(); - unsigned i; - literal l = c.lit(); - lbool asgn = ctx.get_assignment(l); - - if (c.max_sum() < c.mpz_k() && asgn == l_false) { - return; - } - if (c.is_ge() && c.min_sum() >= c.mpz_k() && asgn == l_true) { - return; - } - for (i = 0; i < c.size(); ++i) { - if (c.lit(i).var() == v) { - break; - } - } - - TRACE("pb", display(tout << "assign watch " << literal(v,!is_true) << " ", c, true);); - - SASSERT(i < c.size()); - if (c.lit(i).sign() == is_true) { - ctx.push_trail(value_trail(c.m_max_sum)); - c.m_max_sum -= c.ncoeff(i); - } - else { - ctx.push_trail(value_trail(c.m_min_sum)); - c.m_min_sum += c.ncoeff(i); - } - DEBUG_CODE( - scoped_mpz sum(m_mpz_mgr); - scoped_mpz maxs(m_mpz_mgr); - for (unsigned i = 0; i < c.size(); ++i) { - if (ctx.get_assignment(c.lit(i)) == l_true) sum += c.ncoeff(i); - if (ctx.get_assignment(c.lit(i)) != l_false) maxs += c.ncoeff(i); - } - CTRACE("pb", (maxs > c.max_sum()), display(tout, c, true);); - SASSERT(c.min_sum() <= sum); - SASSERT(sum <= maxs); - SASSERT(maxs <= c.max_sum()); - ); - SASSERT(c.min_sum() <= c.max_sum()); - SASSERT(!m_mpz_mgr.is_neg(c.min_sum())); - ctx.push_trail(value_trail(c.m_nfixed)); - ++c.m_nfixed; - SASSERT(c.nfixed() <= c.size()); - if (c.is_ge() && c.min_sum() >= c.mpz_k() && asgn != l_true) { - TRACE("pb", display(tout << "Set " << l << "\n", c, true);); - add_assign(c, get_helpful_literals(c, false), l); - } - else if (c.max_sum() < c.mpz_k() && asgn != l_false) { - TRACE("pb", display(tout << "Set " << ~l << "\n", c, true);); - add_assign(c, get_unhelpful_literals(c, true), ~l); - } - else if (c.is_eq() && c.nfixed() == c.size() && c.min_sum() == c.mpz_k() && asgn != l_true) { - TRACE("pb", display(tout << "Set " << l << "\n", c, true);); - add_assign(c, get_all_literals(c, false), l); - } - else if (c.is_eq() && c.nfixed() == c.size() && c.min_sum() != c.mpz_k() && asgn != l_false) { - TRACE("pb", display(tout << "Set " << ~l << "\n", c, true);); - add_assign(c, get_all_literals(c, false), ~l); - } -#if 0 - else if (c.is_eq() && c.min_sum() > c.mpz_k() && asgn != l_false) { - TRACE("pb", display(tout << "Set " << ~l << "\n", c, true);); - add_assign(c, get_all_literals(c, false), ~l); - } - else if (c.is_eq() && asgn == l_true && c.min_sum() == c.mpz_k() && c.max_sum() > c.mpz_k()) { - literal_vector& lits = get_all_literals(c, false); - lits.push_back(c.lit()); - for (unsigned i = 0; i < c.size(); ++i) { - if (ctx.get_assignment(c.lit(i)) == l_undef) { - add_assign(c, lits, ~c.lit(i)); - } - } - } -#endif - else { - IF_VERBOSE(14, display(verbose_stream() << "no propagation ", c, true);); - } + UNREACHABLE(); } @@ -1682,7 +1545,6 @@ namespace smt { void theory_pb::clear_watch(ineq& c) { for (unsigned i = 0; i < c.size(); ++i) { literal w = c.lit(i); - unwatch_var(w.var(), &c); unwatch_literal(w, &c); } c.m_watch_sum.reset(); @@ -1728,7 +1590,7 @@ namespace smt { ctx.push_trail(unwatch_ge(*this, c)); } - void theory_pb::init_watch_var(ineq& c) { + void theory_pb::init_watch_ineq(ineq& c) { c.m_min_sum.reset(); c.m_max_sum.reset(); c.m_nfixed = 0; @@ -1736,7 +1598,6 @@ namespace smt { c.m_max_watch.reset(); c.m_watch_sz = 0; for (unsigned i = 0; i < c.size(); ++i) { - watch_var(c.lit(i).var(), &c); c.m_max_sum += c.ncoeff(i); } } @@ -2757,16 +2618,6 @@ namespace smt { display_watch(out, vi, false); display_watch(out, vi, true); } - for (unsigned vi = 0; vi < m_var_infos.size(); ++vi) { - ineq_watch const* w = m_var_infos[vi].m_var_watch; - if (!w) continue; - out << "watch (v): " << literal(vi) << " |-> "; - ineq_watch const& wl = *w; - for (unsigned i = 0; i < wl.size(); ++i) { - out << wl[i]->lit() << " "; - } - out << "\n"; - } for (unsigned vi = 0; vi < m_var_infos.size(); ++vi) { ineq* c = m_var_infos[vi].m_ineq; if (c) { diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index c20683d73..e7b95bf94 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -252,13 +252,12 @@ namespace smt { struct var_info { ineq_watch* m_lit_watch[2]; - ineq_watch* m_var_watch; ineq* m_ineq; card_watch* m_lit_cwatch[2]; card* m_card; - var_info(): m_var_watch(nullptr), m_ineq(nullptr), m_card(nullptr) + var_info(): m_ineq(nullptr), m_card(nullptr) { m_lit_watch[0] = nullptr; m_lit_watch[1] = nullptr; @@ -269,7 +268,6 @@ namespace smt { void reset() { dealloc(m_lit_watch[0]); dealloc(m_lit_watch[1]); - dealloc(m_var_watch); dealloc(m_ineq); dealloc(m_lit_cwatch[0]); dealloc(m_lit_cwatch[1]); @@ -305,16 +303,13 @@ namespace smt { void add_watch(ineq& c, unsigned index); void del_watch(ineq_watch& watch, unsigned index, ineq& c, unsigned ineq_index); void init_watch_literal(ineq& c); - void init_watch_var(ineq& c); + void init_watch_ineq(ineq& c); void clear_watch(ineq& c); void watch_literal(literal lit, ineq* c); - void watch_var(bool_var v, ineq* c); void unwatch_literal(literal w, ineq* c); - void unwatch_var(bool_var v, ineq* c); void remove(ptr_vector& ineqs, ineq* c); bool assign_watch_ge(bool_var v, bool is_true, ineq_watch& watch, unsigned index); - void assign_watch(bool_var v, bool is_true, ineq& c); void assign_ineq(ineq& c, bool is_true); void assign_eq(ineq& c, bool is_true); From 82a89120b09625c77742046b5817eac4e754ef9f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 16 Dec 2018 15:26:40 -0800 Subject: [PATCH 100/318] fix #2042 Signed-off-by: Nikolaj Bjorner --- src/ast/pattern/pattern_inference.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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; } } From 2dcf36e96cd73b076c83a6c108f3e2f2cc8e9875 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 16 Dec 2018 15:32:38 -0800 Subject: [PATCH 101/318] fix #2044 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 5d1ec835b..66c175ac8 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -300,6 +300,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()); From f4d03edf22c322934568d2581274eee13f013493 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 16 Dec 2018 15:54:30 -0800 Subject: [PATCH 102/318] remove unreachable Signed-off-by: Nikolaj Bjorner --- src/math/polynomial/upolynomial_factorization.cpp | 2 +- src/smt/theory_pb.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/math/polynomial/upolynomial_factorization.cpp b/src/math/polynomial/upolynomial_factorization.cpp index 57106e22d..5eaf10c88 100644 --- a/src/math/polynomial/upolynomial_factorization.cpp +++ b/src/math/polynomial/upolynomial_factorization.cpp @@ -1072,7 +1072,7 @@ 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) { + while (trials <= params.m_p_trials) { upm.checkpoint(); // construct prime to check uint64_t next_prime = prime_it.next(); diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 8a880b1cf..e0ba902b3 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1187,7 +1187,7 @@ namespace smt { */ void theory_pb::assign_eq(ineq& c, bool is_true) { SASSERT(c.is_eq()); - UNREACHABLE(); + } From bd96eaff47522dbafc2cd13bf6f162f6833ac1ee Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 17 Dec 2018 08:26:59 -0800 Subject: [PATCH 103/318] axiomatize pb-eq Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index e0ba902b3..81cf4c815 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -465,7 +465,9 @@ namespace smt { bool theory_pb::internalize_atom(app * atom, bool gate_ctx) { context& ctx = get_context(); - TRACE("pb", tout << mk_pp(atom, get_manager()) << "\n";); + ast_manager& m = get_manager(); + + TRACE("pb", tout << mk_pp(atom, m) << "\n";); if (ctx.b_internalized(atom)) { return true; } @@ -490,12 +492,37 @@ namespace smt { unsigned num_args = atom->get_num_args(); bool_var abv = ctx.mk_bool_var(atom); ctx.set_var_theory(abv, get_id()); + literal lit(abv); + + + if (pb.is_eq(atom)) { + expr_ref_vector args(m); + vector coeffs; + unsigned n = atom->get_num_args(); + for (unsigned i = 0; i < n; ++i) { + args.push_back(atom->get_arg(i)); + coeffs.push_back(pb.get_coeff(atom, i)); + } + expr_ref le(pb.mk_le(n, coeffs.c_ptr(), args.c_ptr(), pb.get_k(atom)), m); + expr_ref ge(pb.mk_ge(n, coeffs.c_ptr(), args.c_ptr(), pb.get_k(atom)), m); + ctx.internalize(le, false); + ctx.internalize(ge, false); + literal le_lit = ctx.get_literal(le); + literal ge_lit = ctx.get_literal(ge); + ctx.mark_as_relevant(le_lit); + ctx.mark_as_relevant(ge_lit); + ctx.mk_th_axiom(get_id(), ~lit, le_lit); + ctx.mk_th_axiom(get_id(), ~lit, ge_lit); + ctx.mk_th_axiom(get_id(), ~le_lit, ~ge_lit, lit); + return true; + } ineq* c = alloc(ineq, m_mpz_mgr, literal(abv), pb.is_eq(atom)); c->m_args[0].m_k = pb.get_k(atom); numeral& k = c->m_args[0].m_k; arg_t& args = c->m_args[0]; + // extract literals and coefficients. for (unsigned i = 0; i < num_args; ++i) { expr* arg = atom->get_arg(i); @@ -528,7 +555,6 @@ namespace smt { c->prune(); c->post_prune(); - literal lit(abv); TRACE("pb", display(tout, *c); tout << " := " << lit << "\n";); switch (is_true) { @@ -693,7 +719,6 @@ namespace smt { void theory_pb::watch_literal(literal lit, ineq* c) { init_watch(lit.var()); ptr_vector* ineqs = m_var_infos[lit.var()].m_lit_watch[lit.sign()]; - TRACE("pb", display(tout << "watch " << lit << " " << (c), *c);); if (ineqs == nullptr) { ineqs = alloc(ptr_vector); m_var_infos[lit.var()].m_lit_watch[lit.sign()] = ineqs; @@ -708,7 +733,6 @@ namespace smt { void theory_pb::unwatch_literal(literal lit, ineq* c) { ptr_vector* ineqs = m_var_infos[lit.var()].m_lit_watch[lit.sign()]; if (ineqs) { - TRACE("pb", display(tout << "unwatch " << lit << " " << (c), *c);); remove(*ineqs, c); } } @@ -719,11 +743,9 @@ namespace smt { if (ineqs[j] == c) { std::swap(ineqs[j], ineqs[sz-1]); ineqs.pop_back(); - TRACE("pb", tout << "removed\n";); return; } - } - TRACE("pb", tout << "not removed\n";); + } } // ---------------------------- @@ -773,8 +795,6 @@ namespace smt { return m.mk_th_lemma(m_fid, fact, prs.size(), prs.c_ptr()); } } - - }; From 360d6f963e41507444569c59a9ce5856c05fb42a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 17 Dec 2018 17:05:48 -0800 Subject: [PATCH 104/318] reduce output Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 9 ++++----- src/test/heap.cpp | 2 +- src/test/theory_pb.cpp | 10 ++++------ 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 81cf4c815..de86ef7e3 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1436,7 +1436,7 @@ namespace smt { } } - std::cout << "zs: " << z << " nzs: " << nz << " lemmas: " << ctx.get_lemmas().size() << " trail: " << m_card_trail.size() << "\n"; + //std::cout << "zs: " << z << " nzs: " << nz << " lemmas: " << ctx.get_lemmas().size() << " trail: " << m_card_trail.size() << "\n"; return z*10 >= nz; m_occs.reset(); @@ -1739,7 +1739,7 @@ namespace smt { k.assert_expr(notB); lbool is_sat = k.check(); validating = false; - std::cout << is_sat << "\n"; + // std::cout << is_sat << "\n"; if (is_sat == l_true) { std::cout << A << "\n"; std::cout << B << "\n"; @@ -2010,7 +2010,6 @@ namespace smt { m_coeffs[m_active_vars[i]] /= g; } m_bound = (m_bound + g - 1) / g; - std::cout << "CUT " << g << "\n"; TRACE("pb", display_resolved_lemma(tout << "cut\n");); } } @@ -2032,7 +2031,7 @@ namespace smt { for (unsigned i = 0; i < m_antecedent_exprs.size(); ++i) { expr* a = m_antecedent_exprs[i].get(); if (!ctx.b_internalized(a)) { - std::cout << "not internalized " << mk_pp(a, m) << "\n"; + // std::cout << "not internalized " << mk_pp(a, m) << "\n"; return; } m_antecedents.push_back(~literal(ctx.get_bool_var(a), m_antecedent_signs[i])); @@ -2040,7 +2039,7 @@ namespace smt { for (unsigned i = 0; i < m_cardinality_exprs.size(); ++i) { expr* a = m_cardinality_exprs[i].get(); if (!ctx.b_internalized(a)) { - std::cout << "not internalized " << mk_pp(a, m) << "\n"; + // std::cout << "not internalized " << mk_pp(a, m) << "\n"; return; } if (m_cardinality_signs[i]) { diff --git a/src/test/heap.cpp b/src/test/heap.cpp index 2c77b939e..6a5bc7b9f 100644 --- a/src/test/heap.cpp +++ b/src/test/heap.cpp @@ -88,7 +88,7 @@ static void tst2() { int_heap2 h(N); for (int i = 0; i < N * 10; i++) { - if (i % 1 == 0) std::cout << "i: " << i << std::endl; + // if (i % 1 == 0) std::cout << "i: " << i << std::endl; if (i % 1000 == 0) std::cout << "i: " << i << std::endl; int cmd = heap_rand() % 10; if (cmd <= 3) { diff --git a/src/test/theory_pb.cpp b/src/test/theory_pb.cpp index 7010b96d0..f0604df73 100644 --- a/src/test/theory_pb.cpp +++ b/src/test/theory_pb.cpp @@ -11,7 +11,7 @@ Copyright (c) 2015 Microsoft Corporation #include "smt/theory_pb.h" #include "ast/rewriter/th_rewriter.h" -unsigned populate_literals(unsigned k, smt::literal_vector& lits) { +static unsigned populate_literals(unsigned k, smt::literal_vector& lits) { ENSURE(k < (1u << lits.size())); unsigned t = 0; for (unsigned i = 0; i < lits.size(); ++i) { @@ -84,6 +84,7 @@ private: } std::cout << "(assert " << fml << ")\n"; ctx.assert_expr(fml); + std::cout << ";asserted\n"; } @@ -138,11 +139,8 @@ void tst_theory_pb() { unsigned k = populate_literals(i, lits); std::cout << "k:" << k << " " << N << "\n"; std::cout.flush(); - TRACE("pb", tout << "k " << k << ": "; - for (unsigned j = 0; j < lits.size(); ++j) { - tout << lits[j] << " "; - } - tout << "\n";); + TRACE("pb", tout << "k " << k << ": " << lits << "\n";); + { smt::context ctx(m, params); ctx.push(); From b6bf299b8b453d5ff5aef7ee840301385f72dc16 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 17 Dec 2018 17:41:50 -0800 Subject: [PATCH 105/318] update upolynmial test Signed-off-by: Nikolaj Bjorner --- src/math/polynomial/upolynomial_factorization.cpp | 1 + src/test/main.cpp | 2 +- src/test/upolynomial.cpp | 7 ++++--- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/math/polynomial/upolynomial_factorization.cpp b/src/math/polynomial/upolynomial_factorization.cpp index 5eaf10c88..45cc3f86d 100644 --- a/src/math/polynomial/upolynomial_factorization.cpp +++ b/src/math/polynomial/upolynomial_factorization.cpp @@ -1072,6 +1072,7 @@ 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; + TRACE("polynomial::factorization::bughunt", tout << "trials: " << params.m_p_trials << "\n";); while (trials <= params.m_p_trials) { upm.checkpoint(); // construct prime to check diff --git a/src/test/main.cpp b/src/test/main.cpp index 811b67407..4aeee185b 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -143,7 +143,6 @@ int main(int argc, char ** argv) { bool test_all = false; parse_cmd_line_args(argc, argv, do_display_usage, test_all); TST(random); - TST(vector); TST(symbol_table); TST(region); TST(symbol); @@ -213,6 +212,7 @@ int main(int argc, char ** argv) { if (test_all) return 0; TST(ext_numeral); TST(interval); + TST(vector); TST(f2n); TST(hwf); TST(trigo); diff --git a/src/test/upolynomial.cpp b/src/test/upolynomial.cpp index fa106fe3f..f8500dfa9 100644 --- a/src/test/upolynomial.cpp +++ b/src/test/upolynomial.cpp @@ -891,6 +891,7 @@ static void tst_fact(polynomial_ref const & p, unsigned num_distinct_factors, up for (unsigned i = 0; i < fs.distinct_factors(); i++) { std::cout << "*("; um.display(std::cout, fs[i]); std::cout << ")^" << fs.get_degree(i) << std::endl; } + std::cout << fs.distinct_factors() << " " << num_distinct_factors << "\n"; ENSURE(fs.distinct_factors() == num_distinct_factors); upolynomial::scoped_numeral_vector _r(um); fs.multiply(_r); @@ -906,10 +907,10 @@ static void tst_fact() { x0 = m.mk_polynomial(m.mk_var()); tst_fact((x0^4) + (x0^2) - 20, 3); tst_fact((x0^4) + (x0^2) - 20, 1, upolynomial::factor_params(5, 1, 1000)); - tst_fact((x0^4) + (x0^2) - 20, 3, upolynomial::factor_params(7, 1, 1000)); + tst_fact((x0^4) + (x0^2) - 20, 1, upolynomial::factor_params(7, 1, 1000)); tst_fact((x0^70) - 6*(x0^65) - (x0^60) + 60*(x0^55) - 54*(x0^50) - 230*(x0^45) + 274*(x0^40) + 542*(x0^35) - 615*(x0^30) - 1120*(x0^25) + 1500*(x0^20) - 160*(x0^15) - 395*(x0^10) + 76*(x0^5) + 34, 1, upolynomial::factor_params(3, 1, 20)); - tst_fact((x0^70) - 6*(x0^65) - (x0^60) + 60*(x0^55) - 54*(x0^50) - 230*(x0^45) + 274*(x0^40) + 542*(x0^35) - 615*(x0^30) - 1120*(x0^25) + 1500*(x0^20) - 160*(x0^15) - 395*(x0^10) + 76*(x0^5) + 34, 2, upolynomial::factor_params(3, 1, 72)); - tst_fact((x0^70) - 6*(x0^65) - (x0^60) + 60*(x0^55) - 54*(x0^50) - 230*(x0^45) + 274*(x0^40) + 542*(x0^35) - 615*(x0^30) - 1120*(x0^25) + 1500*(x0^20) - 160*(x0^15) - 395*(x0^10) + 76*(x0^5) + 34, 3, upolynomial::factor_params(3, 1, 80)); + tst_fact((x0^70) - 6*(x0^65) - (x0^60) + 60*(x0^55) - 54*(x0^50) - 230*(x0^45) + 274*(x0^40) + 542*(x0^35) - 615*(x0^30) - 1120*(x0^25) + 1500*(x0^20) - 160*(x0^15) - 395*(x0^10) + 76*(x0^5) + 34, 1, upolynomial::factor_params(3, 1, 72)); + tst_fact((x0^70) - 6*(x0^65) - (x0^60) + 60*(x0^55) - 54*(x0^50) - 230*(x0^45) + 274*(x0^40) + 542*(x0^35) - 615*(x0^30) - 1120*(x0^25) + 1500*(x0^20) - 160*(x0^15) - 395*(x0^10) + 76*(x0^5) + 34, 1, upolynomial::factor_params(3, 1, 80)); tst_fact( (x0^10) - 10*(x0^8) + 38*(x0^6) - 2*(x0^5) - 100*(x0^4) - 40*(x0^3) + 121*(x0^2) - 38*x0 - 17, 1); tst_fact( (x0^4) - 404*(x0^2) + 39204, 2); tst_fact(((x0^5) - (x0^2) + 1)*((-1)*x0 + 1)*((x0^2) - 2*x0 + 3), 3); From 35e8decdb15e046071f22937eea8a32f61aa1bb5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 18 Dec 2018 11:27:04 -0800 Subject: [PATCH 106/318] for #2039 Signed-off-by: Nikolaj Bjorner --- src/api/api_seq.cpp | 4 ++-- src/api/python/z3/z3.py | 2 ++ src/ast/rewriter/seq_rewriter.cpp | 1 - src/smt/asserted_formulas.cpp | 6 ++---- 4 files changed, 6 insertions(+), 7 deletions(-) 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/python/z3/z3.py b/src/api/python/z3/z3.py index ffd9c27a1..4e515b433 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -9914,6 +9914,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()) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 25fc5c119..d46f234e2 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -386,7 +386,6 @@ 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()); - TRACE("seq", tout << f->get_name() << "\n";); br_status st = BR_FAILED; switch(f->get_decl_kind()) { diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index d364404da..164d36ae2 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -449,7 +449,7 @@ void asserted_formulas::propagate_values() { m_expr2depth.reset(); m_scoped_substitution.push(); unsigned prop = num_prop; - TRACE("propagate_values", tout << "before:\n"; display(tout);); + TRACE("propagate_values", display(tout << "before:\n");); unsigned i = m_qhead; unsigned sz = m_formulas.size(); for (; i < sz; i++) { @@ -482,15 +482,13 @@ unsigned asserted_formulas::propagate_values(unsigned i) { expr_ref new_n(m); proof_ref new_pr(m); m_rewriter(n, new_n, new_pr); + TRACE("propagate_values", tout << n << "\n" << new_n << "\n";); if (m.proofs_enabled()) { proof * pr = m_formulas[i].get_proof(); new_pr = m.mk_modus_ponens(pr, new_pr); } justified_expr j(m, new_n, new_pr); m_formulas[i] = j; - if (m_formulas[i].get_fml() != new_n) { - std::cout << "NOT updated\n"; - } if (m.is_false(j.get_fml())) { m_inconsistent = true; } From a63d1b184800954aef888fb76d531237f574f957 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 18 Dec 2018 11:57:20 -0800 Subject: [PATCH 107/318] update doctest Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 4e515b433..523d40842 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -3836,7 +3836,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) @@ -9995,8 +9995,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 @@ -10082,7 +10080,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): From d6df51951f4cdc95f0dfd3b1297d04a465d8f2ca Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 20 Dec 2018 10:32:36 -0800 Subject: [PATCH 108/318] release notes Signed-off-by: Nikolaj Bjorner --- RELEASE_NOTES | 10 ++++++++++ 1 file changed, 10 insertions(+) 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 From e1dc5532289e2ca73af4644221d07945b26d1e45 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 20 Dec 2018 13:15:50 -0800 Subject: [PATCH 109/318] inc version Signed-off-by: Nikolaj Bjorner --- CMakeLists.txt | 2 +- scripts/mk_project.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9877af89e..5934b7c17 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 diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 8cf60ab62..58d087f32 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(): From 52f960a7c874f710e775558a7016c5cc9dd93477 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 21 Dec 2018 19:48:18 +0000 Subject: [PATCH 110/318] elim_uncnstr_tactic: remove m_imp idiom to reduce mem alloc --- src/tactic/core/elim_uncnstr_tactic.cpp | 1633 +++++++++++------------ src/tactic/core/elim_uncnstr_tactic.h | 5 +- 2 files changed, 806 insertions(+), 832 deletions(-) diff --git a/src/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp index 577db30cd..5b77fb9a2 100644 --- a/src/tactic/core/elim_uncnstr_tactic.cpp +++ b/src/tactic/core/elim_uncnstr_tactic.cpp @@ -28,881 +28,864 @@ Notes: #include "ast/ast_smt2_pp.h" #include "ast/ast_ll_pp.h" +namespace { class elim_uncnstr_tactic : public tactic { - struct imp { - // unconstrained vars collector + // unconstrained vars collector - typedef generic_model_converter mc; + typedef generic_model_converter mc; - struct rw_cfg : public default_rewriter_cfg { - bool m_produce_proofs; - obj_hashtable & m_vars; - ref m_mc; - arith_util m_a_util; - bv_util m_bv_util; - array_util m_ar_util; - datatype_util m_dt_util; - app_ref_vector m_fresh_vars; - obj_map m_cache; - app_ref_vector m_cache_domain; - unsigned long long m_max_memory; - unsigned m_max_steps; - - rw_cfg(ast_manager & m, bool produce_proofs, obj_hashtable & vars, mc * _m, - unsigned long long max_memory, unsigned max_steps): - m_produce_proofs(produce_proofs), - m_vars(vars), - m_mc(_m), - m_a_util(m), - m_bv_util(m), - m_ar_util(m), - m_dt_util(m), - m_fresh_vars(m), - m_cache_domain(m), - m_max_memory(max_memory), - m_max_steps(max_steps) { - } - - ast_manager & m() const { return m_a_util.get_manager(); } - - bool max_steps_exceeded(unsigned num_steps) const { - cooperate("elim-uncnstr-vars"); - if (memory::get_allocation_size() > m_max_memory) - throw tactic_exception(TACTIC_MAX_MEMORY_MSG); - return num_steps > m_max_steps; - } - - bool uncnstr(expr * arg) const { - return m_vars.contains(arg); - } - - bool uncnstr(unsigned num, expr * const * args) const { - for (unsigned i = 0; i < num; i++) - if (!uncnstr(args[i])) - return false; - return true; - } - - /** - \brief Create a fresh variable for abstracting (f args[0] ... args[num-1]) - Return true if it a new variable was created, and false if the variable already existed for this - application. Store the variable in v - */ - bool mk_fresh_uncnstr_var_for(app * t, app * & v) { - if (m_cache.find(t, v)) { - return false; // variable already existed for this application - } - - v = m().mk_fresh_const(nullptr, m().get_sort(t)); - TRACE("elim_uncnstr_bug", tout << "eliminating:\n" << mk_ismt2_pp(t, m()) << "\n";); - TRACE("elim_uncnstr_bug_ll", tout << "eliminating:\n" << mk_bounded_pp(t, m()) << "\n";); - m_fresh_vars.push_back(v); - if (m_mc) m_mc->hide(v); - m_cache_domain.push_back(t); - m_cache.insert(t, v); - return true; - } - - bool mk_fresh_uncnstr_var_for(func_decl * f, unsigned num, expr * const * args, app * & v) { - return mk_fresh_uncnstr_var_for(m().mk_app(f, num, args), v); - } - - bool mk_fresh_uncnstr_var_for(func_decl * f, expr * arg1, expr * arg2, app * & v) { - return mk_fresh_uncnstr_var_for(m().mk_app(f, arg1, arg2), v); - } - - bool mk_fresh_uncnstr_var_for(func_decl * f, expr * arg, app * & v) { - return mk_fresh_uncnstr_var_for(m().mk_app(f, arg), v); - } - - void add_def(expr * v, expr * def) { - SASSERT(uncnstr(v)); - SASSERT(to_app(v)->get_num_args() == 0); - if (m_mc) - m_mc->add(to_app(v)->get_decl(), def); - } - - void add_defs(unsigned num, expr * const * args, expr * u, expr * identity) { - if (m_mc) { - add_def(args[0], u); - for (unsigned i = 1; i < num; i++) - add_def(args[i], identity); - } - } - - // return a term that is different from t. - bool mk_diff(expr * t, expr_ref & r) { - sort * s = m().get_sort(t); - if (m().is_bool(s)) { - r = m().mk_not(t); - return true; - } - family_id fid = s->get_family_id(); - if (fid == m_a_util.get_family_id()) { - r = m_a_util.mk_add(t, m_a_util.mk_numeral(rational(1), s)); - return true; - } - if (fid == m_bv_util.get_family_id()) { - r = m().mk_app(m_bv_util.get_family_id(), OP_BNOT, t); - return true; - } - if (fid == m_ar_util.get_family_id()) { - if (m().is_uninterp(get_array_range(s))) - return false; - unsigned arity = get_array_arity(s); - for (unsigned i = 0; i < arity; i++) - if (m().is_uninterp(get_array_domain(s, i))) - return false; - // building - // r = (store t i1 ... in d) - // where i1 ... in are arbitrary values - // and d is a term different from (select t i1 ... in) - ptr_buffer new_args; - new_args.push_back(t); - for (unsigned i = 0; i < arity; i++) - new_args.push_back(m().get_some_value(get_array_domain(s, i))); - expr_ref sel(m()); - sel = m().mk_app(fid, OP_SELECT, new_args.size(), new_args.c_ptr()); - expr_ref diff_sel(m()); - if (!mk_diff(sel, diff_sel)) - return false; - new_args.push_back(diff_sel); - r = m().mk_app(fid, OP_STORE, new_args.size(), new_args.c_ptr()); - return true; - } - if (fid == m_dt_util.get_family_id()) { - // In the current implementation, I only handle the case where - // the datatype has a recursive constructor. - ptr_vector const & constructors = *m_dt_util.get_datatype_constructors(s); - for (func_decl * constructor : constructors) { - unsigned num = constructor->get_arity(); - unsigned target = UINT_MAX; - for (unsigned i = 0; i < num; i++) { - sort * s_arg = constructor->get_domain(i); - if (s == s_arg) { - target = i; - continue; - } - if (m().is_uninterp(s_arg)) - break; - } - if (target == UINT_MAX) - continue; - // use the constructor the distinct term constructor(...,t,...) - ptr_buffer new_args; - for (unsigned i = 0; i < num; i++) { - if (i == target) { - new_args.push_back(t); - } - else { - new_args.push_back(m().get_some_value(constructor->get_domain(i))); - } - } - r = m().mk_app(constructor, new_args.size(), new_args.c_ptr()); - return true; - } - // TODO: handle more cases. + struct rw_cfg : public default_rewriter_cfg { + bool m_produce_proofs; + obj_hashtable & m_vars; + ref m_mc; + arith_util m_a_util; + bv_util m_bv_util; + array_util m_ar_util; + datatype_util m_dt_util; + app_ref_vector m_fresh_vars; + obj_map m_cache; + app_ref_vector m_cache_domain; + unsigned long long m_max_memory; + unsigned m_max_steps; + + rw_cfg(ast_manager & m, bool produce_proofs, obj_hashtable & vars, mc * _m, + unsigned long long max_memory, unsigned max_steps): + m_produce_proofs(produce_proofs), + m_vars(vars), + m_mc(_m), + m_a_util(m), + m_bv_util(m), + m_ar_util(m), + m_dt_util(m), + m_fresh_vars(m), + m_cache_domain(m), + m_max_memory(max_memory), + m_max_steps(max_steps) { + } + + ast_manager & m() const { return m_a_util.get_manager(); } + + bool max_steps_exceeded(unsigned num_steps) const { + cooperate("elim-uncnstr-vars"); + if (memory::get_allocation_size() > m_max_memory) + throw tactic_exception(TACTIC_MAX_MEMORY_MSG); + return num_steps > m_max_steps; + } + + bool uncnstr(expr * arg) const { + return m_vars.contains(arg); + } + + bool uncnstr(unsigned num, expr * const * args) const { + for (unsigned i = 0; i < num; i++) + if (!uncnstr(args[i])) return false; + return true; + } + + /** + \brief Create a fresh variable for abstracting (f args[0] ... args[num-1]) + Return true if it a new variable was created, and false if the variable already existed for this + application. Store the variable in v + */ + bool mk_fresh_uncnstr_var_for(app * t, app * & v) { + if (m_cache.find(t, v)) { + return false; // variable already existed for this application + } + + v = m().mk_fresh_const(nullptr, m().get_sort(t)); + TRACE("elim_uncnstr_bug", tout << "eliminating:\n" << mk_ismt2_pp(t, m()) << "\n";); + TRACE("elim_uncnstr_bug_ll", tout << "eliminating:\n" << mk_bounded_pp(t, m()) << "\n";); + m_fresh_vars.push_back(v); + if (m_mc) m_mc->hide(v); + m_cache_domain.push_back(t); + m_cache.insert(t, v); + return true; + } + + bool mk_fresh_uncnstr_var_for(func_decl * f, unsigned num, expr * const * args, app * & v) { + return mk_fresh_uncnstr_var_for(m().mk_app(f, num, args), v); + } + + bool mk_fresh_uncnstr_var_for(func_decl * f, expr * arg1, expr * arg2, app * & v) { + return mk_fresh_uncnstr_var_for(m().mk_app(f, arg1, arg2), v); + } + + bool mk_fresh_uncnstr_var_for(func_decl * f, expr * arg, app * & v) { + return mk_fresh_uncnstr_var_for(m().mk_app(f, arg), v); + } + + void add_def(expr * v, expr * def) { + SASSERT(uncnstr(v)); + SASSERT(to_app(v)->get_num_args() == 0); + if (m_mc) + m_mc->add(to_app(v)->get_decl(), def); + } + + void add_defs(unsigned num, expr * const * args, expr * u, expr * identity) { + if (m_mc) { + add_def(args[0], u); + for (unsigned i = 1; i < num; i++) + add_def(args[i], identity); + } + } + + // return a term that is different from t. + bool mk_diff(expr * t, expr_ref & r) { + sort * s = m().get_sort(t); + if (m().is_bool(s)) { + r = m().mk_not(t); + return true; + } + family_id fid = s->get_family_id(); + if (fid == m_a_util.get_family_id()) { + r = m_a_util.mk_add(t, m_a_util.mk_numeral(rational(1), s)); + return true; + } + if (fid == m_bv_util.get_family_id()) { + r = m().mk_app(m_bv_util.get_family_id(), OP_BNOT, t); + return true; + } + if (fid == m_ar_util.get_family_id()) { + if (m().is_uninterp(get_array_range(s))) + return false; + unsigned arity = get_array_arity(s); + for (unsigned i = 0; i < arity; i++) + if (m().is_uninterp(get_array_domain(s, i))) + return false; + // building + // r = (store t i1 ... in d) + // where i1 ... in are arbitrary values + // and d is a term different from (select t i1 ... in) + ptr_buffer new_args; + new_args.push_back(t); + for (unsigned i = 0; i < arity; i++) + new_args.push_back(m().get_some_value(get_array_domain(s, i))); + expr_ref sel(m()); + sel = m().mk_app(fid, OP_SELECT, new_args.size(), new_args.c_ptr()); + expr_ref diff_sel(m()); + if (!mk_diff(sel, diff_sel)) + return false; + new_args.push_back(diff_sel); + r = m().mk_app(fid, OP_STORE, new_args.size(), new_args.c_ptr()); + return true; + } + if (fid == m_dt_util.get_family_id()) { + // In the current implementation, I only handle the case where + // the datatype has a recursive constructor. + ptr_vector const & constructors = *m_dt_util.get_datatype_constructors(s); + for (func_decl * constructor : constructors) { + unsigned num = constructor->get_arity(); + unsigned target = UINT_MAX; + for (unsigned i = 0; i < num; i++) { + sort * s_arg = constructor->get_domain(i); + if (s == s_arg) { + target = i; + continue; + } + if (m().is_uninterp(s_arg)) + break; + } + if (target == UINT_MAX) + continue; + // use the constructor the distinct term constructor(...,t,...) + ptr_buffer new_args; + for (unsigned i = 0; i < num; i++) { + if (i == target) { + new_args.push_back(t); + } + else { + new_args.push_back(m().get_some_value(constructor->get_domain(i))); + } + } + r = m().mk_app(constructor, new_args.size(), new_args.c_ptr()); + return true; } + // TODO: handle more cases. return false; } + return false; + } - app * process_eq(func_decl * f, expr * arg1, expr * arg2) { - expr * v; - expr * t; - if (uncnstr(arg1)) { - v = arg1; - t = arg2; - } - else if (uncnstr(arg2)) { - v = arg2; - t = arg1; - } - else { - return nullptr; - } - - sort * s = m().get_sort(arg1); - - // Remark: - // I currently do not support unconstrained vars that have - // uninterpreted sorts, for the following reasons: - // - Soundness - // (forall ((x S) (y S)) (= x y)) - // (not (= c1 c2)) - // - // The constants c1 and c2 have only one occurrence in - // the formula above, but they are not really unconstrained. - // The quantifier forces S to have interpretations of size 1. - // If we replace (= c1 c2) with fresh k. The formula will - // become satisfiable. - // - // - Even if the formula is quantifier free, I would still - // have to build an interpretation for the eliminated - // variables. - // - if (!m().is_fully_interp(s)) - return nullptr; - - // If the interpreted sort has only one element, - // then it is unsound to eliminate the unconstrained variable in the equality - sort_size sz = s->get_num_elements(); - - if (sz.is_finite() && sz.size() <= 1) - return nullptr; - - if (!m_mc) { - // easy case, model generation is disabled. - app * u; - mk_fresh_uncnstr_var_for(f, arg1, arg2, u); - return u; - } - - expr_ref d(m()); - if (mk_diff(t, d)) { - app * u; - if (!mk_fresh_uncnstr_var_for(f, arg1, arg2, u)) - return u; - add_def(v, m().mk_ite(u, t, d)); - return u; - } + app * process_eq(func_decl * f, expr * arg1, expr * arg2) { + expr * v; + expr * t; + if (uncnstr(arg1)) { + v = arg1; + t = arg2; + } + else if (uncnstr(arg2)) { + v = arg2; + t = arg1; + } + else { return nullptr; } - app * process_basic_app(func_decl * f, unsigned num, expr * const * args) { - SASSERT(f->get_family_id() == m().get_basic_family_id()); - switch (f->get_decl_kind()) { - case OP_ITE: - SASSERT(num == 3); - if (uncnstr(args[1]) && uncnstr(args[2])) { - app * r; - if (!mk_fresh_uncnstr_var_for(f, num, args, r)) - return r; - add_def(args[1], r); - add_def(args[2], r); - return r; - } - if (uncnstr(args[0]) && uncnstr(args[1])) { - app * r; - if (!mk_fresh_uncnstr_var_for(f, num, args, r)) - return r; - add_def(args[0], m().mk_true()); - add_def(args[1], r); - return r; - } - if (uncnstr(args[0]) && uncnstr(args[2])) { - app * r; - if (!mk_fresh_uncnstr_var_for(f, num, args, r)) - return r; - add_def(args[0], m().mk_false()); - add_def(args[2], r); - return r; - } - return nullptr; - case OP_NOT: - SASSERT(num == 1); - if (uncnstr(args[0])) { - app * r; - if (!mk_fresh_uncnstr_var_for(f, num, args, r)) - return r; - if (m_mc) - add_def(args[0], m().mk_not(r)); - return r; - } - return nullptr; - case OP_AND: - if (num > 0 && uncnstr(num, args)) { - app * r; - if (!mk_fresh_uncnstr_var_for(f, num, args, r)) - return r; - if (m_mc) - add_defs(num, args, r, m().mk_true()); - return r; - } - return nullptr; - case OP_OR: - if (num > 0 && uncnstr(num, args)) { - app * r; - if (!mk_fresh_uncnstr_var_for(f, num, args, r)) - return r; - if (m_mc) - add_defs(num, args, r, m().mk_false()); - return r; - } - return nullptr; - case OP_EQ: - SASSERT(num == 2); - return process_eq(f, args[0], args[1]); - default: - return nullptr; - } + sort * s = m().get_sort(arg1); + + // Remark: + // I currently do not support unconstrained vars that have + // uninterpreted sorts, for the following reasons: + // - Soundness + // (forall ((x S) (y S)) (= x y)) + // (not (= c1 c2)) + // + // The constants c1 and c2 have only one occurrence in + // the formula above, but they are not really unconstrained. + // The quantifier forces S to have interpretations of size 1. + // If we replace (= c1 c2) with fresh k. The formula will + // become satisfiable. + // + // - Even if the formula is quantifier free, I would still + // have to build an interpretation for the eliminated + // variables. + // + if (!m().is_fully_interp(s)) + return nullptr; + + // If the interpreted sort has only one element, + // then it is unsound to eliminate the unconstrained variable in the equality + sort_size sz = s->get_num_elements(); + + if (sz.is_finite() && sz.size() <= 1) + return nullptr; + + if (!m_mc) { + // easy case, model generation is disabled. + app * u; + mk_fresh_uncnstr_var_for(f, arg1, arg2, u); + return u; } - - app * process_le_ge(func_decl * f, expr * arg1, expr * arg2, bool le) { - expr * v; - expr * t; - if (uncnstr(arg1)) { - v = arg1; - t = arg2; - } - else if (uncnstr(arg2)) { - v = arg2; - t = arg1; - le = !le; - } - else { - return nullptr; - } + + expr_ref d(m()); + if (mk_diff(t, d)) { app * u; if (!mk_fresh_uncnstr_var_for(f, arg1, arg2, u)) return u; - if (!m_mc) - return u; - // v = ite(u, t, t + 1) if le - // v = ite(u, t, t - 1) if !le - add_def(v, m().mk_ite(u, t, m_a_util.mk_add(t, m_a_util.mk_numeral(rational(le ? 1 : -1), m().get_sort(arg1))))); + add_def(v, m().mk_ite(u, t, d)); return u; } + return nullptr; + } + + app * process_basic_app(func_decl * f, unsigned num, expr * const * args) { + SASSERT(f->get_family_id() == m().get_basic_family_id()); + switch (f->get_decl_kind()) { + case OP_ITE: + SASSERT(num == 3); + if (uncnstr(args[1]) && uncnstr(args[2])) { + app * r; + if (!mk_fresh_uncnstr_var_for(f, num, args, r)) + return r; + add_def(args[1], r); + add_def(args[2], r); + return r; + } + if (uncnstr(args[0]) && uncnstr(args[1])) { + app * r; + if (!mk_fresh_uncnstr_var_for(f, num, args, r)) + return r; + add_def(args[0], m().mk_true()); + add_def(args[1], r); + return r; + } + if (uncnstr(args[0]) && uncnstr(args[2])) { + app * r; + if (!mk_fresh_uncnstr_var_for(f, num, args, r)) + return r; + add_def(args[0], m().mk_false()); + add_def(args[2], r); + return r; + } + return nullptr; + case OP_NOT: + SASSERT(num == 1); + if (uncnstr(args[0])) { + app * r; + if (!mk_fresh_uncnstr_var_for(f, num, args, r)) + return r; + if (m_mc) + add_def(args[0], m().mk_not(r)); + return r; + } + return nullptr; + case OP_AND: + if (num > 0 && uncnstr(num, args)) { + app * r; + if (!mk_fresh_uncnstr_var_for(f, num, args, r)) + return r; + if (m_mc) + add_defs(num, args, r, m().mk_true()); + return r; + } + return nullptr; + case OP_OR: + if (num > 0 && uncnstr(num, args)) { + app * r; + if (!mk_fresh_uncnstr_var_for(f, num, args, r)) + return r; + if (m_mc) + add_defs(num, args, r, m().mk_false()); + return r; + } + return nullptr; + case OP_EQ: + SASSERT(num == 2); + return process_eq(f, args[0], args[1]); + default: + return nullptr; + } + } - app * process_add(family_id fid, decl_kind add_k, decl_kind sub_k, unsigned num, expr * const * args) { - if (num == 0) - return nullptr; - unsigned i; - expr * v = nullptr; - for (i = 0; i < num; i++) { - expr * arg = args[i]; - if (uncnstr(arg)) { - v = arg; - break; - } - } - if (v == nullptr) - return nullptr; - app * u; - if (!mk_fresh_uncnstr_var_for(m().mk_app(fid, add_k, num, args), u)) - return u; - if (!m_mc) - return u; - ptr_buffer new_args; - for (unsigned j = 0; j < num; j++) { - if (j == i) - continue; - new_args.push_back(args[j]); - } - if (new_args.empty()) { - add_def(v, u); - } - else { - expr * rest; - if (new_args.size() == 1) - rest = new_args[0]; - else - rest = m().mk_app(fid, add_k, new_args.size(), new_args.c_ptr()); - add_def(v, m().mk_app(fid, sub_k, u, rest)); - } + app * process_le_ge(func_decl * f, expr * arg1, expr * arg2, bool le) { + expr * v; + expr * t; + if (uncnstr(arg1)) { + v = arg1; + t = arg2; + } + else if (uncnstr(arg2)) { + v = arg2; + t = arg1; + le = !le; + } + else { + return nullptr; + } + app * u; + if (!mk_fresh_uncnstr_var_for(f, arg1, arg2, u)) return u; - } - - app * process_arith_mul(func_decl * f, unsigned num, expr * const * args) { - if (num == 0) - return nullptr; - sort * s = m().get_sort(args[0]); - if (uncnstr(num, args)) { - app * r; - if (!mk_fresh_uncnstr_var_for(f, num, args, r)) - return r; - if (m_mc) - add_defs(num, args, r, m_a_util.mk_numeral(rational(1), s)); - return r; - } - // c * v case for reals - bool is_int; - rational val; - if (num == 2 && uncnstr(args[1]) && m_a_util.is_numeral(args[0], val, is_int) && !is_int) { - if (val.is_zero()) - return nullptr; - app * r; - if (!mk_fresh_uncnstr_var_for(f, num, args, r)) - return r; - if (m_mc) { - val = rational(1) / val; - add_def(args[1], m_a_util.mk_mul(m_a_util.mk_numeral(val, false), r)); - } - return r; - } + if (!m_mc) + return u; + // v = ite(u, t, t + 1) if le + // v = ite(u, t, t - 1) if !le + add_def(v, m().mk_ite(u, t, m_a_util.mk_add(t, m_a_util.mk_numeral(rational(le ? 1 : -1), m().get_sort(arg1))))); + return u; + } + + app * process_add(family_id fid, decl_kind add_k, decl_kind sub_k, unsigned num, expr * const * args) { + if (num == 0) return nullptr; - } - - app * process_arith_app(func_decl * f, unsigned num, expr * const * args) { - - SASSERT(f->get_family_id() == m_a_util.get_family_id()); - switch (f->get_decl_kind()) { - case OP_ADD: - return process_add(f->get_family_id(), OP_ADD, OP_SUB, num, args); - case OP_MUL: - return process_arith_mul(f, num, args); - case OP_LE: - SASSERT(num == 2); - return process_le_ge(f, args[0], args[1], true); - case OP_GE: - SASSERT(num == 2); - return process_le_ge(f, args[0], args[1], false); - default: - return nullptr; + unsigned i; + expr * v = nullptr; + for (i = 0; i < num; i++) { + expr * arg = args[i]; + if (uncnstr(arg)) { + v = arg; + break; } } - - app * process_bv_mul(func_decl * f, unsigned num, expr * const * args) { - if (num == 0) - return nullptr; - if (uncnstr(num, args)) { - sort * s = m().get_sort(args[0]); - app * r; - if (!mk_fresh_uncnstr_var_for(f, num, args, r)) - return r; - if (m_mc) - add_defs(num, args, r, m_bv_util.mk_numeral(rational(1), s)); - return r; - } - // c * v (c is even) case - unsigned bv_size; - rational val; - rational inv; - if (num == 2 && - uncnstr(args[1]) && - m_bv_util.is_numeral(args[0], val, bv_size) && - m_bv_util.mult_inverse(val, bv_size, inv)) { - app * r; - if (!mk_fresh_uncnstr_var_for(f, num, args, r)) - return r; - sort * s = m().get_sort(args[1]); - if (m_mc) - add_def(args[1], m_bv_util.mk_bv_mul(m_bv_util.mk_numeral(inv, s), r)); - return r; - } + if (v == nullptr) return nullptr; + app * u; + if (!mk_fresh_uncnstr_var_for(m().mk_app(fid, add_k, num, args), u)) + return u; + if (!m_mc) + return u; + ptr_buffer new_args; + for (unsigned j = 0; j < num; j++) { + if (j == i) + continue; + new_args.push_back(args[j]); } - - app * process_extract(func_decl * f, expr * arg) { - if (!uncnstr(arg)) - return nullptr; + if (new_args.empty()) { + add_def(v, u); + } + else { + expr * rest; + if (new_args.size() == 1) + rest = new_args[0]; + else + rest = m().mk_app(fid, add_k, new_args.size(), new_args.c_ptr()); + add_def(v, m().mk_app(fid, sub_k, u, rest)); + } + return u; + } + + app * process_arith_mul(func_decl * f, unsigned num, expr * const * args) { + if (num == 0) + return nullptr; + sort * s = m().get_sort(args[0]); + if (uncnstr(num, args)) { app * r; - if (!mk_fresh_uncnstr_var_for(f, arg, r)) + if (!mk_fresh_uncnstr_var_for(f, num, args, r)) return r; - if (!m_mc) - return r; - unsigned high = m_bv_util.get_extract_high(f); - unsigned low = m_bv_util.get_extract_low(f); - unsigned bv_size = m_bv_util.get_bv_size(m().get_sort(arg)); - if (bv_size == high - low + 1) { - add_def(arg, r); - } - else { - ptr_buffer args; - if (high < bv_size - 1) - args.push_back(m_bv_util.mk_numeral(rational(0), bv_size - high - 1)); - args.push_back(r); - if (low > 0) - args.push_back(m_bv_util.mk_numeral(rational(0), low)); - add_def(arg, m_bv_util.mk_concat(args.size(), args.c_ptr())); - } + if (m_mc) + add_defs(num, args, r, m_a_util.mk_numeral(rational(1), s)); return r; } - - app * process_bv_div(func_decl * f, expr * arg1, expr * arg2) { - if (uncnstr(arg1) && uncnstr(arg2)) { - sort * s = m().get_sort(arg1); - app * r; - if (!mk_fresh_uncnstr_var_for(f, arg1, arg2, r)) - return r; - if (!m_mc) - return r; - add_def(arg1, r); - add_def(arg2, m_bv_util.mk_numeral(rational(1), s)); - return r; - } - return nullptr; - } - - app * process_concat(func_decl * f, unsigned num, expr * const * args) { - if (num == 0) - return nullptr; - if (!uncnstr(num, args)) + // c * v case for reals + bool is_int; + rational val; + if (num == 2 && uncnstr(args[1]) && m_a_util.is_numeral(args[0], val, is_int) && !is_int) { + if (val.is_zero()) return nullptr; app * r; if (!mk_fresh_uncnstr_var_for(f, num, args, r)) return r; if (m_mc) { - unsigned i = num; - unsigned low = 0; - while (i > 0) { - --i; - expr * arg = args[i]; - unsigned sz = m_bv_util.get_bv_size(arg); - add_def(arg, m_bv_util.mk_extract(low + sz - 1, low, r)); - low += sz; - } + val = rational(1) / val; + add_def(args[1], m_a_util.mk_mul(m_a_util.mk_numeral(val, false), r)); } return r; } + return nullptr; + } + + app * process_arith_app(func_decl * f, unsigned num, expr * const * args) { - app * process_bv_le(func_decl * f, expr * arg1, expr * arg2, bool is_signed) { - if (m_produce_proofs) { - // The result of bv_le is not just introducing a new fresh name, - // we need a side condition. - // TODO: the correct proof step - return nullptr; - } - if (uncnstr(arg1)) { - // v <= t - expr * v = arg1; - expr * t = arg2; - // v <= t ---> (u or t == MAX) u is fresh - // add definition v = ite(u or t == MAX, t, t+1) - unsigned bv_sz = m_bv_util.get_bv_size(arg1); - rational MAX; - if (is_signed) - MAX = rational::power_of_two(bv_sz - 1) - rational(1); - else - MAX = rational::power_of_two(bv_sz) - rational(1); - app * u; - bool is_new = mk_fresh_uncnstr_var_for(f, arg1, arg2, u); - app * r = m().mk_or(u, m().mk_eq(t, m_bv_util.mk_numeral(MAX, bv_sz))); - if (m_mc && is_new) - add_def(v, m().mk_ite(r, t, m_bv_util.mk_bv_add(t, m_bv_util.mk_numeral(rational(1), bv_sz)))); - return r; - } - if (uncnstr(arg2)) { - // v >= t - expr * v = arg2; - expr * t = arg1; - // v >= t ---> (u ot t == MIN) u is fresh - // add definition v = ite(u or t == MIN, t, t-1) - unsigned bv_sz = m_bv_util.get_bv_size(arg1); - rational MIN; - if (is_signed) - MIN = -rational::power_of_two(bv_sz - 1); - else - MIN = rational(0); - app * u; - bool is_new = mk_fresh_uncnstr_var_for(f, arg1, arg2, u); - app * r = m().mk_or(u, m().mk_eq(t, m_bv_util.mk_numeral(MIN, bv_sz))); - if (m_mc && is_new) - add_def(v, m().mk_ite(r, t, m_bv_util.mk_bv_sub(t, m_bv_util.mk_numeral(rational(1), bv_sz)))); - return r; - } + SASSERT(f->get_family_id() == m_a_util.get_family_id()); + switch (f->get_decl_kind()) { + case OP_ADD: + return process_add(f->get_family_id(), OP_ADD, OP_SUB, num, args); + case OP_MUL: + return process_arith_mul(f, num, args); + case OP_LE: + SASSERT(num == 2); + return process_le_ge(f, args[0], args[1], true); + case OP_GE: + SASSERT(num == 2); + return process_le_ge(f, args[0], args[1], false); + default: return nullptr; } - - app * process_bv_app(func_decl * f, unsigned num, expr * const * args) { - SASSERT(f->get_family_id() == m_bv_util.get_family_id()); - switch (f->get_decl_kind()) { - case OP_BADD: - return process_add(f->get_family_id(), OP_BADD, OP_BSUB, num, args); - case OP_BMUL: - return process_bv_mul(f, num, args); - case OP_BSDIV: - case OP_BUDIV: - case OP_BSDIV_I: - case OP_BUDIV_I: - SASSERT(num == 2); - return process_bv_div(f, args[0], args[1]); - case OP_SLEQ: - SASSERT(num == 2); - return process_bv_le(f, args[0], args[1], true); - case OP_ULEQ: - SASSERT(num == 2); - return process_bv_le(f, args[0], args[1], false); - case OP_CONCAT: - return process_concat(f, num, args); - case OP_EXTRACT: - SASSERT(num == 1); - return process_extract(f, args[0]); - case OP_BNOT: - SASSERT(num == 1); - if (uncnstr(args[0])) { - app * r; - if (!mk_fresh_uncnstr_var_for(f, num, args, r)) - return r; - if (m_mc) - add_def(args[0], m().mk_app(f, r)); - return r; - } - return nullptr; - case OP_BOR: - if (num > 0 && uncnstr(num, args)) { - sort * s = m().get_sort(args[0]); - app * r; - if (!mk_fresh_uncnstr_var_for(f, num, args, r)) - return r; - if (m_mc) - add_defs(num, args, r, m_bv_util.mk_numeral(rational(0), s)); - return r; - } - return nullptr; - default: - return nullptr; + } + + app * process_bv_mul(func_decl * f, unsigned num, expr * const * args) { + if (num == 0) + return nullptr; + if (uncnstr(num, args)) { + sort * s = m().get_sort(args[0]); + app * r; + if (!mk_fresh_uncnstr_var_for(f, num, args, r)) + return r; + if (m_mc) + add_defs(num, args, r, m_bv_util.mk_numeral(rational(1), s)); + return r; + } + // c * v (c is even) case + unsigned bv_size; + rational val; + rational inv; + if (num == 2 && + uncnstr(args[1]) && + m_bv_util.is_numeral(args[0], val, bv_size) && + m_bv_util.mult_inverse(val, bv_size, inv)) { + app * r; + if (!mk_fresh_uncnstr_var_for(f, num, args, r)) + return r; + sort * s = m().get_sort(args[1]); + if (m_mc) + add_def(args[1], m_bv_util.mk_bv_mul(m_bv_util.mk_numeral(inv, s), r)); + return r; + } + return nullptr; + } + + app * process_extract(func_decl * f, expr * arg) { + if (!uncnstr(arg)) + return nullptr; + app * r; + if (!mk_fresh_uncnstr_var_for(f, arg, r)) + return r; + if (!m_mc) + return r; + unsigned high = m_bv_util.get_extract_high(f); + unsigned low = m_bv_util.get_extract_low(f); + unsigned bv_size = m_bv_util.get_bv_size(m().get_sort(arg)); + if (bv_size == high - low + 1) { + add_def(arg, r); + } + else { + ptr_buffer args; + if (high < bv_size - 1) + args.push_back(m_bv_util.mk_numeral(rational(0), bv_size - high - 1)); + args.push_back(r); + if (low > 0) + args.push_back(m_bv_util.mk_numeral(rational(0), low)); + add_def(arg, m_bv_util.mk_concat(args.size(), args.c_ptr())); + } + return r; + } + + app * process_bv_div(func_decl * f, expr * arg1, expr * arg2) { + if (uncnstr(arg1) && uncnstr(arg2)) { + sort * s = m().get_sort(arg1); + app * r; + if (!mk_fresh_uncnstr_var_for(f, arg1, arg2, r)) + return r; + if (!m_mc) + return r; + add_def(arg1, r); + add_def(arg2, m_bv_util.mk_numeral(rational(1), s)); + return r; + } + return nullptr; + } + + app * process_concat(func_decl * f, unsigned num, expr * const * args) { + if (num == 0) + return nullptr; + if (!uncnstr(num, args)) + return nullptr; + app * r; + if (!mk_fresh_uncnstr_var_for(f, num, args, r)) + return r; + if (m_mc) { + unsigned i = num; + unsigned low = 0; + while (i > 0) { + --i; + expr * arg = args[i]; + unsigned sz = m_bv_util.get_bv_size(arg); + add_def(arg, m_bv_util.mk_extract(low + sz - 1, low, r)); + low += sz; } } - - app * process_array_app(func_decl * f, unsigned num, expr * const * args) { - SASSERT(f->get_family_id() == m_ar_util.get_family_id()); - switch (f->get_decl_kind()) { - case OP_SELECT: - if (uncnstr(args[0])) { - app * r; - if (!mk_fresh_uncnstr_var_for(f, num, args, r)) - return r; - sort * s = m().get_sort(args[0]); - if (m_mc) - add_def(args[0], m_ar_util.mk_const_array(s, r)); - return r; - } - return nullptr; - case OP_STORE: - if (uncnstr(args[0]) && uncnstr(args[num-1])) { - app * r; - if (!mk_fresh_uncnstr_var_for(f, num, args, r)) - return r; - if (m_mc) { - add_def(args[num-1], m().mk_app(m_ar_util.get_family_id(), OP_SELECT, num-1, args)); - add_def(args[0], r); - } - return r; - } - default: - return nullptr; - } - } - - app * process_datatype_app(func_decl * f, unsigned num, expr * const * args) { - if (m_dt_util.is_recognizer(f)) { - SASSERT(num == 1); - if (uncnstr(args[0])) { - if (!m_mc) { - app * r; - mk_fresh_uncnstr_var_for(f, num, args, r); - return r; - } - // TODO: handle model generation - } - } - else if (m_dt_util.is_accessor(f)) { - SASSERT(num == 1); - if (uncnstr(args[0])) { - if (!m_mc) { - app * r; - mk_fresh_uncnstr_var_for(f, num, args, r); - return r; - } - func_decl * c = m_dt_util.get_accessor_constructor(f); - for (unsigned i = 0; i < c->get_arity(); i++) - if (!m().is_fully_interp(c->get_domain(i))) - return nullptr; - app * u; - if (!mk_fresh_uncnstr_var_for(f, num, args, u)) - return u; - ptr_vector const & accs = *m_dt_util.get_constructor_accessors(c); - ptr_buffer new_args; - for (unsigned i = 0; i < accs.size(); i++) { - if (accs[i] == f) - new_args.push_back(u); - else - new_args.push_back(m().get_some_value(c->get_domain(i))); - } - add_def(args[0], m().mk_app(c, new_args.size(), new_args.c_ptr())); - return u; - } - } - else if (m_dt_util.is_constructor(f)) { - if (uncnstr(num, args)) { - app * u; - if (!mk_fresh_uncnstr_var_for(f, num, args, u)) - return u; - if (!m_mc) - return u; - ptr_vector const & accs = *m_dt_util.get_constructor_accessors(f); - for (unsigned i = 0; i < num; i++) { - add_def(args[i], m().mk_app(accs[i], u)); - } - return u; - } - } + return r; + } + + app * process_bv_le(func_decl * f, expr * arg1, expr * arg2, bool is_signed) { + if (m_produce_proofs) { + // The result of bv_le is not just introducing a new fresh name, + // we need a side condition. + // TODO: the correct proof step return nullptr; } - - br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - if (num == 0) - return BR_FAILED; - family_id fid = f->get_family_id(); - if (fid == null_family_id) - return BR_FAILED; - - for (unsigned i = 0; i < num; i++) { - if (!is_ground(args[i])) - return BR_FAILED; // non-ground terms are not handled. - } - - app * u = nullptr; - - if (fid == m().get_basic_family_id()) - u = process_basic_app(f, num, args); - else if (fid == m_a_util.get_family_id()) - u = process_arith_app(f, num, args); - else if (fid == m_bv_util.get_family_id()) - u = process_bv_app(f, num, args); - else if (fid == m_ar_util.get_family_id()) - u = process_array_app(f, num, args); - else if (fid == m_dt_util.get_family_id()) - u = process_datatype_app(f, num, args); - - if (u == nullptr) - return BR_FAILED; - - result = u; - if (m_produce_proofs) { - expr * s = m().mk_app(f, num, args); - expr * eq = m().mk_eq(s, u); - proof * pr1 = m().mk_def_intro(eq); - result_pr = m().mk_apply_def(s, u, pr1); - } - - return BR_DONE; - } - }; - - class rw : public rewriter_tpl { - rw_cfg m_cfg; - public: - rw(ast_manager & m, bool produce_proofs, obj_hashtable & vars, mc * _m, - unsigned long long max_memory, unsigned max_steps): - rewriter_tpl(m, produce_proofs, m_cfg), - m_cfg(m, produce_proofs, vars, _m, max_memory, max_steps) { - } - }; - - ast_manager & m_manager; - ref m_mc; - obj_hashtable m_vars; - scoped_ptr m_rw; - unsigned m_num_elim_apps; - unsigned long long m_max_memory; - unsigned m_max_steps; - - imp(ast_manager & m, params_ref const & p): - m_manager(m), - m_num_elim_apps(0) { - updt_params(p); - } - - void updt_params(params_ref const & p) { - m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX)); - m_max_steps = p.get_uint("max_steps", UINT_MAX); - } - - ast_manager & m() { return m_manager; } - - void init_mc(bool produce_models) { - m_mc = nullptr; - if (produce_models) { - m_mc = alloc(mc, m(), "elim_uncstr"); - } - } - - void init_rw(bool produce_proofs) { - m_rw = alloc(rw, m(), produce_proofs, m_vars, m_mc.get(), m_max_memory, m_max_steps); - } - - void operator()(goal_ref const & g, goal_ref_buffer & result) { - bool produce_proofs = g->proofs_enabled(); - - TRACE("elim_uncnstr_bug", g->display(tout);); - tactic_report report("elim-uncnstr-vars", *g); - m_vars.reset(); - collect_occs p; - p(*g, m_vars); - if (m_vars.empty()) { - result.push_back(g.get()); - // did not increase depth since it didn't do anything. - return; - } - bool modified = true; - TRACE("elim_uncnstr", tout << "unconstrained variables...\n"; - for (expr * v : m_vars) tout << mk_ismt2_pp(v, m()) << " "; - tout << "\n";); - init_mc(g->models_enabled()); - init_rw(produce_proofs); - - expr_ref new_f(m()); - proof_ref new_pr(m()); - unsigned round = 0; - unsigned size = g->size(); - unsigned idx = 0; - while (true) { - for (; idx < size; idx++) { - expr * f = g->form(idx); - m_rw->operator()(f, new_f, new_pr); - if (f == new_f) - continue; - modified = true; - if (produce_proofs) { - proof * pr = g->pr(idx); - new_pr = m().mk_modus_ponens(pr, new_pr); - } - g->update(idx, new_f, new_pr, g->dep(idx)); - } - if (!modified) { - if (round == 0) { - } - else { - m_num_elim_apps = m_rw->cfg().m_fresh_vars.size(); - g->add(m_mc.get()); - } - TRACE("elim_uncnstr", if (m_mc) m_mc->display(tout); else tout << "no mc\n";); - m_mc = nullptr; - m_rw = nullptr; - result.push_back(g.get()); - g->inc_depth(); - return; - } - modified = false; - round ++; - size = g->size(); - m_rw->reset(); // reset cache - m_vars.reset(); - { - collect_occs p; - p(*g, m_vars); - } - if (m_vars.empty()) - idx = size; // force to finish + if (uncnstr(arg1)) { + // v <= t + expr * v = arg1; + expr * t = arg2; + // v <= t ---> (u or t == MAX) u is fresh + // add definition v = ite(u or t == MAX, t, t+1) + unsigned bv_sz = m_bv_util.get_bv_size(arg1); + rational MAX; + if (is_signed) + MAX = rational::power_of_two(bv_sz - 1) - rational(1); else - idx = 0; + MAX = rational::power_of_two(bv_sz) - rational(1); + app * u; + bool is_new = mk_fresh_uncnstr_var_for(f, arg1, arg2, u); + app * r = m().mk_or(u, m().mk_eq(t, m_bv_util.mk_numeral(MAX, bv_sz))); + if (m_mc && is_new) + add_def(v, m().mk_ite(r, t, m_bv_util.mk_bv_add(t, m_bv_util.mk_numeral(rational(1), bv_sz)))); + return r; + } + if (uncnstr(arg2)) { + // v >= t + expr * v = arg2; + expr * t = arg1; + // v >= t ---> (u ot t == MIN) u is fresh + // add definition v = ite(u or t == MIN, t, t-1) + unsigned bv_sz = m_bv_util.get_bv_size(arg1); + rational MIN; + if (is_signed) + MIN = -rational::power_of_two(bv_sz - 1); + else + MIN = rational(0); + app * u; + bool is_new = mk_fresh_uncnstr_var_for(f, arg1, arg2, u); + app * r = m().mk_or(u, m().mk_eq(t, m_bv_util.mk_numeral(MIN, bv_sz))); + if (m_mc && is_new) + add_def(v, m().mk_ite(r, t, m_bv_util.mk_bv_sub(t, m_bv_util.mk_numeral(rational(1), bv_sz)))); + return r; + } + return nullptr; + } + + app * process_bv_app(func_decl * f, unsigned num, expr * const * args) { + SASSERT(f->get_family_id() == m_bv_util.get_family_id()); + switch (f->get_decl_kind()) { + case OP_BADD: + return process_add(f->get_family_id(), OP_BADD, OP_BSUB, num, args); + case OP_BMUL: + return process_bv_mul(f, num, args); + case OP_BSDIV: + case OP_BUDIV: + case OP_BSDIV_I: + case OP_BUDIV_I: + SASSERT(num == 2); + return process_bv_div(f, args[0], args[1]); + case OP_SLEQ: + SASSERT(num == 2); + return process_bv_le(f, args[0], args[1], true); + case OP_ULEQ: + SASSERT(num == 2); + return process_bv_le(f, args[0], args[1], false); + case OP_CONCAT: + return process_concat(f, num, args); + case OP_EXTRACT: + SASSERT(num == 1); + return process_extract(f, args[0]); + case OP_BNOT: + SASSERT(num == 1); + if (uncnstr(args[0])) { + app * r; + if (!mk_fresh_uncnstr_var_for(f, num, args, r)) + return r; + if (m_mc) + add_def(args[0], m().mk_app(f, r)); + return r; + } + return nullptr; + case OP_BOR: + if (num > 0 && uncnstr(num, args)) { + sort * s = m().get_sort(args[0]); + app * r; + if (!mk_fresh_uncnstr_var_for(f, num, args, r)) + return r; + if (m_mc) + add_defs(num, args, r, m_bv_util.mk_numeral(rational(0), s)); + return r; + } + return nullptr; + default: + return nullptr; } } + + app * process_array_app(func_decl * f, unsigned num, expr * const * args) { + SASSERT(f->get_family_id() == m_ar_util.get_family_id()); + switch (f->get_decl_kind()) { + case OP_SELECT: + if (uncnstr(args[0])) { + app * r; + if (!mk_fresh_uncnstr_var_for(f, num, args, r)) + return r; + sort * s = m().get_sort(args[0]); + if (m_mc) + add_def(args[0], m_ar_util.mk_const_array(s, r)); + return r; + } + return nullptr; + case OP_STORE: + if (uncnstr(args[0]) && uncnstr(args[num-1])) { + app * r; + if (!mk_fresh_uncnstr_var_for(f, num, args, r)) + return r; + if (m_mc) { + add_def(args[num-1], m().mk_app(m_ar_util.get_family_id(), OP_SELECT, num-1, args)); + add_def(args[0], r); + } + return r; + } + default: + return nullptr; + } + } + + app * process_datatype_app(func_decl * f, unsigned num, expr * const * args) { + if (m_dt_util.is_recognizer(f)) { + SASSERT(num == 1); + if (uncnstr(args[0])) { + if (!m_mc) { + app * r; + mk_fresh_uncnstr_var_for(f, num, args, r); + return r; + } + // TODO: handle model generation + } + } + else if (m_dt_util.is_accessor(f)) { + SASSERT(num == 1); + if (uncnstr(args[0])) { + if (!m_mc) { + app * r; + mk_fresh_uncnstr_var_for(f, num, args, r); + return r; + } + func_decl * c = m_dt_util.get_accessor_constructor(f); + for (unsigned i = 0; i < c->get_arity(); i++) + if (!m().is_fully_interp(c->get_domain(i))) + return nullptr; + app * u; + if (!mk_fresh_uncnstr_var_for(f, num, args, u)) + return u; + ptr_vector const & accs = *m_dt_util.get_constructor_accessors(c); + ptr_buffer new_args; + for (unsigned i = 0; i < accs.size(); i++) { + if (accs[i] == f) + new_args.push_back(u); + else + new_args.push_back(m().get_some_value(c->get_domain(i))); + } + add_def(args[0], m().mk_app(c, new_args.size(), new_args.c_ptr())); + return u; + } + } + else if (m_dt_util.is_constructor(f)) { + if (uncnstr(num, args)) { + app * u; + if (!mk_fresh_uncnstr_var_for(f, num, args, u)) + return u; + if (!m_mc) + return u; + ptr_vector const & accs = *m_dt_util.get_constructor_accessors(f); + for (unsigned i = 0; i < num; i++) { + add_def(args[i], m().mk_app(accs[i], u)); + } + return u; + } + } + return nullptr; + } + + br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { + if (num == 0) + return BR_FAILED; + family_id fid = f->get_family_id(); + if (fid == null_family_id) + return BR_FAILED; + for (unsigned i = 0; i < num; i++) { + if (!is_ground(args[i])) + return BR_FAILED; // non-ground terms are not handled. + } + + app * u = nullptr; + + if (fid == m().get_basic_family_id()) + u = process_basic_app(f, num, args); + else if (fid == m_a_util.get_family_id()) + u = process_arith_app(f, num, args); + else if (fid == m_bv_util.get_family_id()) + u = process_bv_app(f, num, args); + else if (fid == m_ar_util.get_family_id()) + u = process_array_app(f, num, args); + else if (fid == m_dt_util.get_family_id()) + u = process_datatype_app(f, num, args); + + if (u == nullptr) + return BR_FAILED; + + result = u; + if (m_produce_proofs) { + expr * s = m().mk_app(f, num, args); + expr * eq = m().mk_eq(s, u); + proof * pr1 = m().mk_def_intro(eq); + result_pr = m().mk_apply_def(s, u, pr1); + } + + return BR_DONE; + } }; - imp * m_imp; + class rw : public rewriter_tpl { + rw_cfg m_cfg; + public: + rw(ast_manager & m, bool produce_proofs, obj_hashtable & vars, mc * _m, + unsigned long long max_memory, unsigned max_steps): + rewriter_tpl(m, produce_proofs, m_cfg), + m_cfg(m, produce_proofs, vars, _m, max_memory, max_steps) { + } + }; + + ast_manager & m_manager; + ref m_mc; + obj_hashtable m_vars; + scoped_ptr m_rw; + unsigned m_num_elim_apps = 0; + unsigned long long m_max_memory; + unsigned m_max_steps; + + ast_manager & m() { return m_manager; } + + void init_mc(bool produce_models) { + m_mc = nullptr; + if (produce_models) { + m_mc = alloc(mc, m(), "elim_uncstr"); + } + } + + void init_rw(bool produce_proofs) { + m_rw = alloc(rw, m(), produce_proofs, m_vars, m_mc.get(), m_max_memory, m_max_steps); + } + + void run(goal_ref const & g, goal_ref_buffer & result) { + bool produce_proofs = g->proofs_enabled(); + + TRACE("elim_uncnstr_bug", g->display(tout);); + tactic_report report("elim-uncnstr-vars", *g); + m_vars.reset(); + collect_occs p; + p(*g, m_vars); + if (m_vars.empty()) { + result.push_back(g.get()); + // did not increase depth since it didn't do anything. + return; + } + bool modified = true; + TRACE("elim_uncnstr", tout << "unconstrained variables...\n"; + for (expr * v : m_vars) tout << mk_ismt2_pp(v, m()) << " "; + tout << "\n";); + init_mc(g->models_enabled()); + init_rw(produce_proofs); + + expr_ref new_f(m()); + proof_ref new_pr(m()); + unsigned round = 0; + unsigned size = g->size(); + unsigned idx = 0; + while (true) { + for (; idx < size; idx++) { + expr * f = g->form(idx); + m_rw->operator()(f, new_f, new_pr); + if (f == new_f) + continue; + modified = true; + if (produce_proofs) { + proof * pr = g->pr(idx); + new_pr = m().mk_modus_ponens(pr, new_pr); + } + g->update(idx, new_f, new_pr, g->dep(idx)); + } + if (!modified) { + if (round == 0) { + } + else { + m_num_elim_apps = m_rw->cfg().m_fresh_vars.size(); + g->add(m_mc.get()); + } + TRACE("elim_uncnstr", if (m_mc) m_mc->display(tout); else tout << "no mc\n";); + m_mc = nullptr; + m_rw = nullptr; + result.push_back(g.get()); + g->inc_depth(); + return; + } + modified = false; + round ++; + size = g->size(); + m_rw->reset(); // reset cache + m_vars.reset(); + { + collect_occs p; + p(*g, m_vars); + } + if (m_vars.empty()) + idx = size; // force to finish + else + idx = 0; + } + } + params_ref m_params; public: elim_uncnstr_tactic(ast_manager & m, params_ref const & p): - m_params(p) { - m_imp = alloc(imp, m, p); + m_manager(m), m_params(p) { + updt_params(p); } tactic * translate(ast_manager & m) override { return alloc(elim_uncnstr_tactic, m, m_params); } - - ~elim_uncnstr_tactic() override { - dealloc(m_imp); - } void updt_params(params_ref const & p) override { m_params = p; - m_imp->updt_params(p); + m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX)); + m_max_steps = p.get_uint("max_steps", UINT_MAX); } void collect_param_descrs(param_descrs & r) override { @@ -912,32 +895,26 @@ public: void operator()(goal_ref const & g, goal_ref_buffer & result) override { - (*m_imp)(g, result); - report_tactic_progress(":num-elim-apps", get_num_elim_apps()); + run(g, result); + report_tactic_progress(":num-elim-apps", m_num_elim_apps); } void cleanup() override { - unsigned num_elim_apps = get_num_elim_apps(); - ast_manager & m = m_imp->m_manager; - imp * d = alloc(imp, m, m_params); - std::swap(d, m_imp); - dealloc(d); - m_imp->m_num_elim_apps = num_elim_apps; - } - - unsigned get_num_elim_apps() const { - return m_imp->m_num_elim_apps; + m_mc = nullptr; + m_rw = nullptr; + m_vars.reset(); } void collect_statistics(statistics & st) const override { - st.update("eliminated applications", get_num_elim_apps()); + st.update("eliminated applications", m_num_elim_apps); } void reset_statistics() override { - m_imp->m_num_elim_apps = 0; + m_num_elim_apps = 0; } }; +} tactic * mk_elim_uncnstr_tactic(ast_manager & m, params_ref const & p) { return clean(alloc(elim_uncnstr_tactic, m, p)); diff --git a/src/tactic/core/elim_uncnstr_tactic.h b/src/tactic/core/elim_uncnstr_tactic.h index 19f9021ac..5824a6974 100644 --- a/src/tactic/core/elim_uncnstr_tactic.h +++ b/src/tactic/core/elim_uncnstr_tactic.h @@ -16,8 +16,7 @@ Author: Notes: --*/ -#ifndef ELIM_UNCNSTR_TACTIC_H_ -#define ELIM_UNCNSTR_TACTIC_H_ +#pragma once #include "util/params.h" @@ -29,5 +28,3 @@ tactic * mk_elim_uncnstr_tactic(ast_manager & m, params_ref const & p = params_r /* ADD_TACTIC("elim-uncnstr", "eliminate application containing unconstrained variables.", "mk_elim_uncnstr_tactic(m, p)") */ -#endif - From 178e5b31e8fbc7073cefd4c85de8371721819442 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 21 Dec 2018 22:49:06 +0000 Subject: [PATCH 111/318] spread a few anonymous namespaces and remove some m_imp idioms --- .gitignore | 1 + src/qe/qe_lite.cpp | 8 +- src/qe/qe_lite.h | 5 +- src/tactic/bv/bv_size_reduction_tactic.cpp | 64 +++++------- src/tactic/bv/bv_size_reduction_tactic.h | 5 +- src/tactic/bv/elim_small_bv_tactic.cpp | 108 ++++++++------------- src/tactic/bv/elim_small_bv_tactic.h | 5 +- 7 files changed, 71 insertions(+), 125 deletions(-) diff --git a/.gitignore b/.gitignore index b7e4a0186..e189a9569 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 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/tactic/bv/bv_size_reduction_tactic.cpp b/src/tactic/bv/bv_size_reduction_tactic.cpp index 964102825..fd1d1499b 100644 --- a/src/tactic/bv/bv_size_reduction_tactic.cpp +++ b/src/tactic/bv/bv_size_reduction_tactic.cpp @@ -27,28 +27,8 @@ Notes: #include "tactic/generic_model_converter.h" #include "ast/ast_smt2_pp.h" +namespace { class bv_size_reduction_tactic : public tactic { - struct imp; - imp * m_imp; -public: - bv_size_reduction_tactic(ast_manager & m); - - tactic * translate(ast_manager & m) override { - return alloc(bv_size_reduction_tactic, m); - } - - ~bv_size_reduction_tactic() override; - - void operator()(goal_ref const & g, goal_ref_buffer & result) override; - - void cleanup() override; -}; - -tactic * mk_bv_size_reduction_tactic(ast_manager & m, params_ref const & p) { - return clean(alloc(bv_size_reduction_tactic, m)); -} - -struct bv_size_reduction_tactic::imp { typedef rational numeral; typedef generic_model_converter bv_size_reduction_mc; @@ -63,12 +43,29 @@ struct bv_size_reduction_tactic::imp { scoped_ptr m_replacer; bool m_produce_models; - imp(ast_manager & _m): - m(_m), +public: + bv_size_reduction_tactic(ast_manager & m) : + m(m), m_util(m), m_replacer(mk_default_expr_replacer(m)) { } + tactic * translate(ast_manager & m) override { + return alloc(bv_size_reduction_tactic, m); + } + + void operator()(goal_ref const & g, goal_ref_buffer & result) override; + + void cleanup() override { + m_signed_lowers.reset(); + m_signed_uppers.reset(); + m_unsigned_lowers.reset(); + m_unsigned_uppers.reset(); + m_mc = nullptr; + m_fmc = nullptr; + m_replacer->reset(); + } + void update_signed_lower(app * v, numeral const & k) { // k <= v obj_map::obj_map_entry * entry = m_signed_lowers.insert_if_not_there2(v, k); @@ -178,7 +175,7 @@ struct bv_size_reduction_tactic::imp { throw tactic_exception(m.limit().get_cancel_msg()); } - void operator()(goal & g, model_converter_ref & mc) { + void run(goal & g, model_converter_ref & mc) { if (g.inconsistent()) return; TRACE("before_bv_size_reduction", g.display(tout);); @@ -373,14 +370,6 @@ struct bv_size_reduction_tactic::imp { }; -bv_size_reduction_tactic::bv_size_reduction_tactic(ast_manager & m) { - m_imp = alloc(imp, m); -} - -bv_size_reduction_tactic::~bv_size_reduction_tactic() { - dealloc(m_imp); -} - void bv_size_reduction_tactic::operator()(goal_ref const & g, goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); @@ -388,17 +377,14 @@ void bv_size_reduction_tactic::operator()(goal_ref const & g, fail_if_unsat_core_generation("bv-size-reduction", g); result.reset(); model_converter_ref mc; - m_imp->operator()(*(g.get()), mc); + run(*(g.get()), mc); g->inc_depth(); g->add(mc.get()); result.push_back(g.get()); SASSERT(g->is_well_sorted()); } - - -void bv_size_reduction_tactic::cleanup() { - ast_manager & m = m_imp->m; - m_imp->~imp(); - new (m_imp) imp(m); } +tactic * mk_bv_size_reduction_tactic(ast_manager & m, params_ref const & p) { + return clean(alloc(bv_size_reduction_tactic, m)); +} diff --git a/src/tactic/bv/bv_size_reduction_tactic.h b/src/tactic/bv/bv_size_reduction_tactic.h index 4a24a1d78..1bb512f3f 100644 --- a/src/tactic/bv/bv_size_reduction_tactic.h +++ b/src/tactic/bv/bv_size_reduction_tactic.h @@ -21,8 +21,7 @@ Author: Notes: --*/ -#ifndef BV_SIZE_REDUCTION_TACTIC_H_ -#define BV_SIZE_REDUCTION_TACTIC_H_ +#pragma once #include "util/params.h" class ast_manager; @@ -32,5 +31,3 @@ tactic * mk_bv_size_reduction_tactic(ast_manager & m, params_ref const & p = par /* ADD_TACTIC("reduce-bv-size", "try to reduce bit-vector sizes using inequalities.", "mk_bv_size_reduction_tactic(m, p)") */ - -#endif diff --git a/src/tactic/bv/elim_small_bv_tactic.cpp b/src/tactic/bv/elim_small_bv_tactic.cpp index 0b5b98308..38b4638ee 100644 --- a/src/tactic/bv/elim_small_bv_tactic.cpp +++ b/src/tactic/bv/elim_small_bv_tactic.cpp @@ -28,6 +28,7 @@ Revision History: #include "tactic/bv/elim_small_bv_tactic.h" +namespace { class elim_small_bv_tactic : public tactic { struct rw_cfg : public default_rewriter_cfg { @@ -183,20 +184,6 @@ class elim_small_bv_tactic : public tactic { return true; } - bool pre_visit(expr * t) { - TRACE("elim_small_bv_pre", tout << "pre_visit: " << mk_ismt2_pp(t, m) << std::endl;); - if (is_quantifier(t)) { - quantifier * q = to_quantifier(t); - TRACE("elim_small_bv", tout << "pre_visit quantifier [" << q->get_id() << "]: " << mk_ismt2_pp(q->get_expr(), m) << std::endl;); - sort_ref_vector new_bindings(m); - for (unsigned i = 0; i < q->get_num_decls(); i++) - new_bindings.push_back(q->get_decl_sort(i)); - SASSERT(new_bindings.size() == q->get_num_decls()); - m_bindings.append(new_bindings); - } - return true; - } - void updt_params(params_ref const & p) { m_params = p; m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX)); @@ -214,69 +201,24 @@ class elim_small_bv_tactic : public tactic { } }; - struct imp { - ast_manager & m; - rw m_rw; + ast_manager & m; + rw m_rw; + params_ref m_params; - imp(ast_manager & _m, params_ref const & p) : - m(_m), - m_rw(m, p) { - } - - void updt_params(params_ref const & p) { - m_rw.cfg().updt_params(p); - } - - void operator()(goal_ref const & g, goal_ref_buffer & result) { - SASSERT(g->is_well_sorted()); - tactic_report report("elim-small-bv", *g); - bool produce_proofs = g->proofs_enabled(); - fail_if_proof_generation("elim-small-bv", g); - fail_if_unsat_core_generation("elim-small-bv", g); - m_rw.cfg().m_produce_models = g->models_enabled(); - - m_rw.m_cfg.m_goal = g.get(); - expr_ref new_curr(m); - proof_ref new_pr(m); - unsigned size = g->size(); - for (unsigned idx = 0; idx < size; idx++) { - expr * curr = g->form(idx); - m_rw(curr, new_curr, new_pr); - if (produce_proofs) { - proof * pr = g->pr(idx); - new_pr = m.mk_modus_ponens(pr, new_pr); - } - g->update(idx, new_curr, new_pr, g->dep(idx)); - } - g->add(m_rw.m_cfg.m_mc.get()); - - report_tactic_progress(":elim-small-bv-num-eliminated", m_rw.m_cfg.m_num_eliminated); - g->inc_depth(); - result.push_back(g.get()); - TRACE("elim-small-bv", g->display(tout);); - SASSERT(g->is_well_sorted()); - } - }; - - imp * m_imp; - params_ref m_params; public: elim_small_bv_tactic(ast_manager & m, params_ref const & p) : + m(m), + m_rw(m, p), m_params(p) { - m_imp = alloc(imp, m, p); } tactic * translate(ast_manager & m) override { return alloc(elim_small_bv_tactic, m, m_params); } - ~elim_small_bv_tactic() override { - dealloc(m_imp); - } - void updt_params(params_ref const & p) override { m_params = p; - m_imp->m_rw.cfg().updt_params(p); + m_rw.cfg().updt_params(p); } void collect_param_descrs(param_descrs & r) override { @@ -285,18 +227,44 @@ public: r.insert("max_bits", CPK_UINT, "(default: 4) maximum bit-vector size of quantified bit-vectors to be eliminated."); } - void operator()(goal_ref const & in, + void operator()(goal_ref const & g, goal_ref_buffer & result) override { - (*m_imp)(in, result); + SASSERT(g->is_well_sorted()); + tactic_report report("elim-small-bv", *g); + bool produce_proofs = g->proofs_enabled(); + fail_if_proof_generation("elim-small-bv", g); + fail_if_unsat_core_generation("elim-small-bv", g); + m_rw.cfg().m_produce_models = g->models_enabled(); + + m_rw.m_cfg.m_goal = g.get(); + expr_ref new_curr(m); + proof_ref new_pr(m); + unsigned size = g->size(); + for (unsigned idx = 0; idx < size; idx++) { + expr * curr = g->form(idx); + m_rw(curr, new_curr, new_pr); + if (produce_proofs) { + proof * pr = g->pr(idx); + new_pr = m.mk_modus_ponens(pr, new_pr); + } + g->update(idx, new_curr, new_pr, g->dep(idx)); + } + g->add(m_rw.m_cfg.m_mc.get()); + + report_tactic_progress(":elim-small-bv-num-eliminated", m_rw.m_cfg.m_num_eliminated); + g->inc_depth(); + result.push_back(g.get()); + TRACE("elim-small-bv", g->display(tout);); + SASSERT(g->is_well_sorted()); } void cleanup() override { - ast_manager & m = m_imp->m; - m_imp->~imp(); - m_imp = new (m_imp) imp(m, m_params); + m_rw.~rw(); + new (&m_rw) rw(m, m_params); } }; +} tactic * mk_elim_small_bv_tactic(ast_manager & m, params_ref const & p) { return clean(alloc(elim_small_bv_tactic, m, p)); diff --git a/src/tactic/bv/elim_small_bv_tactic.h b/src/tactic/bv/elim_small_bv_tactic.h index 675ec3de7..e4a91f70f 100644 --- a/src/tactic/bv/elim_small_bv_tactic.h +++ b/src/tactic/bv/elim_small_bv_tactic.h @@ -16,8 +16,7 @@ Author: Revision History: --*/ -#ifndef ELIM_SMALL_BV_H_ -#define ELIM_SMALL_BV_H_ +#pragma once #include "util/params.h" class ast_manager; @@ -28,5 +27,3 @@ tactic * mk_elim_small_bv_tactic(ast_manager & m, params_ref const & p = params_ /* ADD_TACTIC("elim-small-bv", "eliminate small, quantified bit-vectors by expansion.", "mk_elim_small_bv_tactic(m, p)") */ - -#endif From 3104291b807aaa1dc9737c2b01b3f93a067080a0 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 21 Dec 2018 23:02:15 +0000 Subject: [PATCH 112/318] spread a few anonymous namespaces and remove some m_imp idioms --- src/tactic/core/propagate_values_tactic.cpp | 375 ++++++++++---------- src/tactic/core/propagate_values_tactic.h | 5 +- 2 files changed, 179 insertions(+), 201 deletions(-) diff --git a/src/tactic/core/propagate_values_tactic.cpp b/src/tactic/core/propagate_values_tactic.cpp index 41e48d864..14c715f03 100644 --- a/src/tactic/core/propagate_values_tactic.cpp +++ b/src/tactic/core/propagate_values_tactic.cpp @@ -25,224 +25,206 @@ Revision History: #include "tactic/goal_shared_occs.h" #include "ast/pb_decl_plugin.h" +namespace { class propagate_values_tactic : public tactic { - struct imp { - ast_manager & m; - th_rewriter m_r; - scoped_ptr m_subst; - goal * m_goal; - goal_shared_occs m_occs; - unsigned m_idx; - unsigned m_max_rounds; - bool m_modified; - - imp(ast_manager & m, params_ref const & p): - m(m), - m_r(m, p), - m_goal(nullptr), - m_occs(m, true /* track atoms */) { - updt_params_core(p); - } + ast_manager & m; + th_rewriter m_r; + scoped_ptr m_subst; + goal * m_goal; + goal_shared_occs m_occs; + unsigned m_idx; + unsigned m_max_rounds; + bool m_modified; + params_ref m_params; - ~imp() { } + void updt_params_core(params_ref const & p) { + m_max_rounds = p.get_uint("max_rounds", 4); + } - void updt_params_core(params_ref const & p) { - m_max_rounds = p.get_uint("max_rounds", 4); - } - - void updt_params(params_ref const & p) { - m_r.updt_params(p); - updt_params_core(p); - } - - - bool is_shared(expr * t) { - return m_occs.is_shared(t); - } - - bool is_shared_neg(expr * t, expr * & atom) { - if (!m.is_not(t, atom)) - return false; - return is_shared(atom); - } + bool is_shared(expr * t) { + return m_occs.is_shared(t); + } - bool is_shared_eq(expr * t, expr * & lhs, expr * & value) { - expr* arg1, *arg2; - if (!m.is_eq(t, arg1, arg2)) - return false; - if (m.is_value(arg1) && is_shared(arg2)) { - lhs = arg2; - value = arg1; - return true; - } - if (m.is_value(arg2) && is_shared(arg1)) { - lhs = arg1; - value = arg2; - return true; - } + bool is_shared_neg(expr * t, expr * & atom) { + if (!m.is_not(t, atom)) return false; + return is_shared(atom); + } + + bool is_shared_eq(expr * t, expr * & lhs, expr * & value) { + expr* arg1, *arg2; + if (!m.is_eq(t, arg1, arg2)) + return false; + if (m.is_value(arg1) && is_shared(arg2)) { + lhs = arg2; + value = arg1; + return true; + } + if (m.is_value(arg2) && is_shared(arg1)) { + lhs = arg1; + value = arg2; + return true; + } + return false; + } + + void push_result(expr * new_curr, proof * new_pr) { + if (m_goal->proofs_enabled()) { + proof * pr = m_goal->pr(m_idx); + new_pr = m.mk_modus_ponens(pr, new_pr); } - void push_result(expr * new_curr, proof * new_pr) { - if (m_goal->proofs_enabled()) { - proof * pr = m_goal->pr(m_idx); - new_pr = m.mk_modus_ponens(pr, new_pr); + expr_dependency_ref new_d(m); + if (m_goal->unsat_core_enabled()) { + new_d = m_goal->dep(m_idx); + expr_dependency * used_d = m_r.get_used_dependencies(); + if (used_d != nullptr) { + new_d = m.mk_join(new_d, used_d); + m_r.reset_used_dependencies(); } - - expr_dependency_ref new_d(m); - if (m_goal->unsat_core_enabled()) { - new_d = m_goal->dep(m_idx); - expr_dependency * used_d = m_r.get_used_dependencies(); - if (used_d != nullptr) { - new_d = m.mk_join(new_d, used_d); - m_r.reset_used_dependencies(); + } + + m_goal->update(m_idx, new_curr, new_pr, new_d); + + if (is_shared(new_curr)) { + m_subst->insert(new_curr, m.mk_true(), m.mk_iff_true(new_pr), new_d); + } + expr * atom; + if (is_shared_neg(new_curr, atom)) { + m_subst->insert(atom, m.mk_false(), m.mk_iff_false(new_pr), new_d); + } + expr * lhs, * value; + if (is_shared_eq(new_curr, lhs, value)) { + TRACE("shallow_context_simplifier_bug", tout << "found eq:\n" << mk_ismt2_pp(new_curr, m) << "\n";); + m_subst->insert(lhs, value, new_pr, new_d); + } + } + + void process_current() { + expr * curr = m_goal->form(m_idx); + expr_ref new_curr(m); + proof_ref new_pr(m); + + if (!m_subst->empty()) { + m_r(curr, new_curr, new_pr); + } + else { + new_curr = curr; + if (m.proofs_enabled()) + new_pr = m.mk_reflexivity(curr); + } + + TRACE("shallow_context_simplifier_bug", tout << mk_ismt2_pp(curr, m) << "\n---->\n" << mk_ismt2_pp(new_curr, m) << "\n";); + if (new_curr != curr) { + m_modified = true; + //if (has_pb(curr)) + // IF_VERBOSE(0, verbose_stream() << mk_ismt2_pp(curr, m) << "\n---->\n" << mk_ismt2_pp(new_curr, m) << "\n"); + } + push_result(new_curr, new_pr); + } + + bool has_pb(expr* e) { + pb_util pb(m); + if (pb.is_ge(e)) return true; + if (m.is_or(e)) { + for (expr* a : *to_app(e)) { + if (pb.is_ge(a)) return true; + } + } + return false; + } + + void run(goal_ref const & g, goal_ref_buffer & result) { + SASSERT(g->is_well_sorted()); + tactic_report report("propagate-values", *g); + m_goal = g.get(); + + bool forward = true; + expr_ref new_curr(m); + proof_ref new_pr(m); + unsigned size = m_goal->size(); + m_idx = 0; + m_modified = false; + unsigned round = 0; + + + if (m_goal->inconsistent()) + goto end; + + if (m_max_rounds == 0) + goto end; + + m_subst = alloc(expr_substitution, m, g->unsat_core_enabled(), g->proofs_enabled()); + m_r.set_substitution(m_subst.get()); + m_occs(*m_goal); + + while (true) { + TRACE("propagate_values", tout << "while(true) loop\n"; m_goal->display_with_dependencies(tout);); + if (forward) { + for (; m_idx < size; m_idx++) { + process_current(); + if (m_goal->inconsistent()) + goto end; } - } - - m_goal->update(m_idx, new_curr, new_pr, new_d); - - if (is_shared(new_curr)) { - m_subst->insert(new_curr, m.mk_true(), m.mk_iff_true(new_pr), new_d); - } - expr * atom; - if (is_shared_neg(new_curr, atom)) { - m_subst->insert(atom, m.mk_false(), m.mk_iff_false(new_pr), new_d); - } - expr * lhs, * value; - if (is_shared_eq(new_curr, lhs, value)) { - TRACE("shallow_context_simplifier_bug", tout << "found eq:\n" << mk_ismt2_pp(new_curr, m) << "\n";); - m_subst->insert(lhs, value, new_pr, new_d); - } - } - - void process_current() { - expr * curr = m_goal->form(m_idx); - expr_ref new_curr(m); - proof_ref new_pr(m); - - if (!m_subst->empty()) { - m_r(curr, new_curr, new_pr); + if (m_subst->empty() && !m_modified) + goto end; + m_occs(*m_goal); + m_idx = m_goal->size(); + forward = false; + m_subst->reset(); + m_r.set_substitution(m_subst.get()); // reset, but keep substitution } else { - new_curr = curr; - if (m.proofs_enabled()) - new_pr = m.mk_reflexivity(curr); - } - - TRACE("shallow_context_simplifier_bug", tout << mk_ismt2_pp(curr, m) << "\n---->\n" << mk_ismt2_pp(new_curr, m) << "\n";); - if (new_curr != curr) { - m_modified = true; - //if (has_pb(curr)) - // IF_VERBOSE(0, verbose_stream() << mk_ismt2_pp(curr, m) << "\n---->\n" << mk_ismt2_pp(new_curr, m) << "\n"); - } - push_result(new_curr, new_pr); - } - - bool has_pb(expr* e) { - pb_util pb(m); - if (pb.is_ge(e)) return true; - if (m.is_or(e)) { - for (expr* a : *to_app(e)) { - if (pb.is_ge(a)) return true; - } - } - return false; - } - - void operator()(goal_ref const & g, - goal_ref_buffer & result) { - SASSERT(g->is_well_sorted()); - tactic_report report("propagate-values", *g); - m_goal = g.get(); - - bool forward = true; - expr_ref new_curr(m); - proof_ref new_pr(m); - unsigned size = m_goal->size(); - m_idx = 0; - m_modified = false; - unsigned round = 0; - - - if (m_goal->inconsistent()) - goto end; - - if (m_max_rounds == 0) - goto end; - - m_subst = alloc(expr_substitution, m, g->unsat_core_enabled(), g->proofs_enabled()); - m_r.set_substitution(m_subst.get()); - m_occs(*m_goal); - - while (true) { - TRACE("propagate_values", tout << "while(true) loop\n"; m_goal->display_with_dependencies(tout);); - if (forward) { - for (; m_idx < size; m_idx++) { - process_current(); - if (m_goal->inconsistent()) - goto end; - } - if (m_subst->empty() && !m_modified) + while (m_idx > 0) { + m_idx--; + process_current(); + if (m_goal->inconsistent()) goto end; - m_occs(*m_goal); - m_idx = m_goal->size(); - forward = false; - m_subst->reset(); - m_r.set_substitution(m_subst.get()); // reset, but keep substitution } - else { - while (m_idx > 0) { - m_idx--; - process_current(); - if (m_goal->inconsistent()) - goto end; - } - if (!m_modified) - goto end; - m_subst->reset(); - m_r.set_substitution(m_subst.get()); // reset, but keep substitution - m_modified = false; - m_occs(*m_goal); - m_idx = 0; - size = m_goal->size(); - forward = true; - } - round++; - if (round >= m_max_rounds) - break; - IF_VERBOSE(100, verbose_stream() << "starting new round, goal size: " << m_goal->num_exprs() << std::endl;); - TRACE("propagate_values", tout << "round finished\n"; m_goal->display(tout); tout << "\n";); + if (!m_modified) + goto end; + m_subst->reset(); + m_r.set_substitution(m_subst.get()); // reset, but keep substitution + m_modified = false; + m_occs(*m_goal); + m_idx = 0; + size = m_goal->size(); + forward = true; } - end: - m_goal->elim_redundancies(); - m_goal->inc_depth(); - result.push_back(m_goal); - SASSERT(m_goal->is_well_sorted()); - TRACE("propagate_values", tout << "end\n"; m_goal->display(tout);); - TRACE("propagate_values_core", m_goal->display_with_dependencies(tout);); - m_goal = nullptr; + round++; + if (round >= m_max_rounds) + break; + IF_VERBOSE(100, verbose_stream() << "starting new round, goal size: " << m_goal->num_exprs() << std::endl;); + TRACE("propagate_values", tout << "round finished\n"; m_goal->display(tout); tout << "\n";); } - }; + end: + m_goal->elim_redundancies(); + m_goal->inc_depth(); + result.push_back(m_goal); + SASSERT(m_goal->is_well_sorted()); + TRACE("propagate_values", tout << "end\n"; m_goal->display(tout);); + TRACE("propagate_values_core", m_goal->display_with_dependencies(tout);); + m_goal = nullptr; + } - imp * m_imp; - params_ref m_params; public: propagate_values_tactic(ast_manager & m, params_ref const & p): + m(m), + m_r(m, p), + m_goal(nullptr), + m_occs(m, true /* track atoms */), m_params(p) { - m_imp = alloc(imp, m, p); + updt_params_core(p); } tactic * translate(ast_manager & m) override { return alloc(propagate_values_tactic, m, m_params); } - - ~propagate_values_tactic() override { - dealloc(m_imp); - } void updt_params(params_ref const & p) override { m_params = p; - m_imp->updt_params(p); + m_r.updt_params(p); + updt_params_core(p); } void collect_param_descrs(param_descrs & r) override { @@ -252,7 +234,7 @@ public: void operator()(goal_ref const & in, goal_ref_buffer & result) override { try { - (*m_imp)(in, result); + run(in, result); } catch (rewriter_exception & ex) { throw tactic_exception(ex.msg()); @@ -260,15 +242,14 @@ public: } void cleanup() override { - ast_manager & m = m_imp->m; - params_ref p = std::move(m_params); - m_imp->~imp(); - new (m_imp) imp(m, p); + m_r.cleanup(); + m_subst = nullptr; + m_occs.cleanup(); } }; +} tactic * mk_propagate_values_tactic(ast_manager & m, params_ref const & p) { return alloc(propagate_values_tactic, m, p); } - diff --git a/src/tactic/core/propagate_values_tactic.h b/src/tactic/core/propagate_values_tactic.h index 635b0a36f..d9324ff82 100644 --- a/src/tactic/core/propagate_values_tactic.h +++ b/src/tactic/core/propagate_values_tactic.h @@ -17,8 +17,7 @@ Author: Revision History: --*/ -#ifndef PROPAGATE_VALUES_TACTIC_H_ -#define PROPAGATE_VALUES_TACTIC_H_ +#pragma once #include "util/params.h" class ast_manager; @@ -29,5 +28,3 @@ tactic * mk_propagate_values_tactic(ast_manager & m, params_ref const & p = para /* ADD_TACTIC("propagate-values", "propagate constants.", "mk_propagate_values_tactic(m, p)") */ - -#endif From b0b6394c6c9ea838f75254ff81b779ee8e3efda9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 21 Dec 2018 17:10:37 -0800 Subject: [PATCH 113/318] fixing #1971 Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 1 + src/sat/sat_model_converter.h | 1 + src/sat/sat_solver.cpp | 2 +- src/sat/sat_solver/inc_sat_solver.cpp | 26 ++++++++++++-------------- src/solver/solver.cpp | 1 - 5 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 067c4d127..1f2f40941 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1388,6 +1388,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) { 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_solver.cpp b/src/sat/sat_solver.cpp index ee3bc7880..d48a6410c 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1785,7 +1785,7 @@ namespace sat { 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_VERBOSE(1, 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())); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index a4131ccaf..87bcf4056 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -813,12 +813,9 @@ 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) { - continue; - } - sat::bool_var v = kv.m_value; + 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; switch (sat::value_at(v, ll_m)) { case l_true: mdl->register_decl(to_app(n)->get_decl(), m.mk_true()); @@ -830,23 +827,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) { @@ -856,14 +853,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/solver/solver.cpp b/src/solver/solver.cpp index fc6ec6f7a..f8c2f8072 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -208,7 +208,6 @@ void solver::assert_expr(expr* f, expr* t) { expr_ref fml(f, m); expr_ref a(t, m); if (m_enforce_model_conversion) { - IF_VERBOSE(0, verbose_stream() << "enforce model conversion\n";); model_converter_ref mc = get_model_converter(); if (mc) { (*mc)(fml); From 99cc4747c56e6f605502fe158bf6c72128669851 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 21 Dec 2018 17:21:04 -0800 Subject: [PATCH 114/318] fixing #1971 Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver/inc_sat_solver.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 87bcf4056..13780529a 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -815,7 +815,9 @@ private: mdl = alloc(model, m); 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; + if (!n || !is_app(n) || to_app(n)->get_num_args() > 0) { + continue; + } switch (sat::value_at(v, ll_m)) { case l_true: mdl->register_decl(to_app(n)->get_decl(), m.mk_true()); From 9379ec3a68dab059a75655dee66b9b994f11b135 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 21 Dec 2018 18:52:09 -0800 Subject: [PATCH 115/318] add back pre_visit, which does get called from rewriter_def/rewriter.h Signed-off-by: Nikolaj Bjorner --- src/tactic/bv/elim_small_bv_tactic.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/tactic/bv/elim_small_bv_tactic.cpp b/src/tactic/bv/elim_small_bv_tactic.cpp index 38b4638ee..a9f94ca3f 100644 --- a/src/tactic/bv/elim_small_bv_tactic.cpp +++ b/src/tactic/bv/elim_small_bv_tactic.cpp @@ -184,6 +184,20 @@ class elim_small_bv_tactic : public tactic { return true; } + bool pre_visit(expr * t) { + TRACE("elim_small_bv_pre", tout << "pre_visit: " << mk_ismt2_pp(t, m) << std::endl;); + if (is_quantifier(t)) { + quantifier * q = to_quantifier(t); + TRACE("elim_small_bv", tout << "pre_visit quantifier [" << q->get_id() << "]: " << mk_ismt2_pp(q->get_expr(), m) << std::endl;); + sort_ref_vector new_bindings(m); + for (unsigned i = 0; i < q->get_num_decls(); i++) + new_bindings.push_back(q->get_decl_sort(i)); + SASSERT(new_bindings.size() == q->get_num_decls()); + m_bindings.append(new_bindings); + } + return true; + } + void updt_params(params_ref const & p) { m_params = p; m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX)); From 44bc00f13dcee1ed8198f0dd72f687bf57784647 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Sun, 23 Dec 2018 21:58:57 -0500 Subject: [PATCH 116/318] Fix typos. --- examples/c/test_capi.c | 2 +- .../msf/SolverFoundation.Plugin.Z3/Z3MILPSolver.cs | 4 ++-- .../msf/SolverFoundation.Plugin.Z3/Z3TermSolver.cs | 4 ++-- src/api/z3_api.h | 2 +- src/ast/dl_decl_plugin.cpp | 12 ++++++------ src/muz/base/dl_context.cpp | 4 ++-- src/sat/sat_solver.cpp | 2 +- src/smt/smt_context.cpp | 8 ++++---- src/smt/smt_model_finder.cpp | 2 +- 9 files changed, 20 insertions(+), 20 deletions(-) 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/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/src/api/z3_api.h b/src/api/z3_api.h index f3d61c1cf..5ee7fcb99 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -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). 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/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/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index d48a6410c..fc5fce252 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -2665,7 +2665,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; } } diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 7ee6d4a92..3c601f400 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -1813,7 +1813,7 @@ namespace smt { } /** - \brief Execute next clase split, return false if there are no + \brief Execute next case split, return false if there are no more case splits to be performed. */ bool context::decide() { @@ -1858,7 +1858,7 @@ namespace smt { if (is_quantifier(m_bool_var2expr[var])) { // Overriding any decision on how to assign the quantifier. - // assigining a quantifier to false is equivalent to make it irrelevant. + // assigning a quantifier to false is equivalent to make it irrelevant. phase = l_false; } @@ -2134,7 +2134,7 @@ namespace smt { \brief When a clause is reinitialized (see reinit_clauses) enodes and literals may need to be recreated. When an enode is recreated, I want to use the same generation number it had before being deleted. Otherwise the generation will be 0, and will affect - the loop prevetion heuristics used to control quantifier instantiation. + the loop prevention heuristics used to control quantifier instantiation. Thus, I cache the generation number of enodes that will be deleted during backtracking and recreated by reinit_clauses. */ @@ -3872,7 +3872,7 @@ namespace smt { for (unsigned i = head; i < sz; i++) { literal l = m_assigned_literals[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_bdata[v].m_phase_available = false; } } diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index 30ea7b18e..111b9a0c0 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -1703,7 +1703,7 @@ namespace smt { friend class quantifier_analyzer; void checkpoint() { - m_mf.checkpoint("quantifer_info"); + m_mf.checkpoint("quantifier_info"); } void insert_qinfo(qinfo * qi) { From 076cfa5813d5653bb9d95055fd78aac624210f0b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 26 Dec 2018 21:04:35 +0800 Subject: [PATCH 117/318] working on revising project0 to project Signed-off-by: Nikolaj Bjorner --- src/qe/qe_mbi.cpp | 252 ++++++++++++++++++++++++++------------- src/qe/qe_mbi.h | 3 + src/qe/qe_term_graph.cpp | 2 + 3 files changed, 177 insertions(+), 80 deletions(-) diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index b7f0d0d49..f66240226 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" @@ -329,86 +330,7 @@ namespace qe { 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";); + project0(mdl, lits); return mbi_sat; } default: @@ -421,6 +343,176 @@ namespace qe { } } + /** + 1. extract arithmetical variables, purify. + 2. project private variables from lits + 3. Order arithmetical variables. + 4. Perform arithmetical projection. + 5. Substitute solution into lits + */ + void euf_arith_mbi_plugin::project(model_ref& mdl, expr_ref_vector& lits) { + TRACE("qe", tout << lits << "\n" << *mdl << "\n";); + + // 1. arithmetical variables + app_ref_vector avars = get_arith_vars(mdl, lits); + TRACE("qe", tout << "vars: " << avars << " lits: " << lits << "\n";); + + + // 2. project private variables from lits + { + 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";); + } + + // 3. Order arithmetical variables + order_avars(mdl, lits, avars); + + // 4. Arithmetical projection + arith_project_plugin ap(m); + ap.set_check_purified(false); + auto defs = ap.project(*mdl.get(), avars, lits); + + // 5. Substitute solution + for (auto const& def : defs) { + expr_safe_replace rep(m); + rep.insert(def.var, def.term); + for (unsigned i = 0; i < lits.size(); ++i) { + expr_ref tmp(m); + rep(lits.get(i), tmp); + lits[i] = tmp; + } + } + } + + void euf_arith_mbi_plugin::order_avars(model_ref& mdl, expr_ref_vector& lits, app_ref_vector& avars) { + arith_util a(m); + model_evaluator mev(*mdl.get()); + vector> vals; + for (app* v : avars) { + 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 avars + 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)); + } + } + // 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::project0(model_ref& mdl, expr_ref_vector& lits) { + TRACE("qe", tout << lits << "\n" << *mdl << "\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";); + } + 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..3563c472a 100644 --- a/src/qe/qe_mbi.h +++ b/src/qe/qe_mbi.h @@ -115,6 +115,9 @@ namespace qe { app_ref_vector get_arith_vars(model_ref& mdl, expr_ref_vector& lits); bool get_literals(model_ref& mdl, expr_ref_vector& lits); void collect_atoms(expr_ref_vector const& fmls); + void project0(model_ref& mdl, expr_ref_vector& lits); + void project(model_ref& mdl, expr_ref_vector& lits); + void order_avars(model_ref& mdl, expr_ref_vector& lits, app_ref_vector& avars); public: euf_arith_mbi_plugin(solver* s, solver* emptySolver); ~euf_arith_mbi_plugin() override {} diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index b5de20368..a5b01e59d 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -815,6 +815,7 @@ namespace qe { 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())); } } @@ -965,6 +966,7 @@ namespace qe { m_pinned.reset(); m_model.reset(); } + expr_ref_vector project() { expr_ref_vector res(m); purify(); From 877df0f1cce5d26cd7a5b8709d3c8ad542fe3c2d Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Sat, 1 Dec 2018 20:45:41 +0700 Subject: [PATCH 118/318] If NO_Z3_DEBUGGER, also drop defining invoke_gdb. --- src/util/debug.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/debug.cpp b/src/util/debug.cpp index 4434cb19f..3e40e412c 100644 --- a/src/util/debug.cpp +++ b/src/util/debug.cpp @@ -69,7 +69,7 @@ bool is_debug_enabled(const char * tag) { return g_enabled_debug_tags->contains(const_cast(tag)); } -#ifndef _WINDOWS +#if !defined(_WINDOWS) && !defined(NO_Z3_DEBUGGER) void invoke_gdb() { char buffer[1024]; int * x = nullptr; From 947687d35069f0ea46cc38393a05e4a793668c9d Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Wed, 26 Dec 2018 23:01:20 -0500 Subject: [PATCH 119/318] Allow emscripten builds. --- CMakeLists.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5934b7c17..188d8dfde 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -254,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() From 8829fa96de68261007d3cb8450ea774cc37f0c71 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 28 Dec 2018 09:38:17 +0800 Subject: [PATCH 120/318] change projection function Signed-off-by: Nikolaj Bjorner --- src/qe/qe_mbi.cpp | 10 ++------ src/qe/qe_term_graph.cpp | 50 +++++++++++++++++++++++++++++----------- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index f66240226..f94b4f257 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -325,20 +325,14 @@ 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; } - project0(mdl, lits); + project(mdl, lits); 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; } } diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index a5b01e59d..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,28 +789,45 @@ 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; @@ -820,6 +839,11 @@ namespace qe { } } } + } + + void mk_distinct(expr_ref_vector& res) { + collect_decl2terms(); + args_are_distinct(res); TRACE("qe", tout << res << "\n";); } From da95fd7d837fcdc273ba0aa74dedfcf441bd75d8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 28 Dec 2018 11:23:52 +0800 Subject: [PATCH 121/318] fixing get-arith-vars and extraction of private variables Signed-off-by: Nikolaj Bjorner --- src/qe/qe_mbi.cpp | 74 ++++++++++++++++++++++++++++++++++++++++++----- src/qe/qe_mbi.h | 7 +++-- 2 files changed, 72 insertions(+), 9 deletions(-) diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index f94b4f257..557735cde 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -218,13 +218,13 @@ namespace qe { void operator()(expr*) {} }; - struct euf_arith_mbi_plugin::is_arith_var_proc { + struct euf_arith_mbi_plugin::is_arith_var_proc1 { 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): + is_arith_var_proc1(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); } @@ -240,9 +240,54 @@ namespace qe { } } void operator()(expr*) {} - }; + struct euf_arith_mbi_plugin::is_arith_var_proc2 { + ast_manager& m; + app_ref_vector& m_avars; + arith_util arith; + obj_hashtable m_seen; + is_arith_var_proc2(app_ref_vector& avars): + m(avars.m()), m_avars(avars), arith(m) { + } + void operator()(app* a) { + if (is_arith_op(a) || a->get_family_id() == m.get_basic_family_id()) { + // no-op + } + else if (!arith.is_int_real(a)) { + for (expr* arg : *a) { + if (is_app(arg) && !m_seen.contains(arg) && is_arith_op(to_app(arg))) { + m_avars.push_back(to_app(arg)); + m_seen.insert(arg); + } + } + } + else if (!m_seen.contains(a)) { + m_seen.insert(a); + m_avars.push_back(a); + } + } + bool is_arith_op(app* a) { + return a->get_family_id() == 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), @@ -291,10 +336,10 @@ namespace qe { } } - app_ref_vector euf_arith_mbi_plugin::get_arith_vars(model_ref& mdl, expr_ref_vector& lits) { + app_ref_vector euf_arith_mbi_plugin::get_arith_vars1(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); + is_arith_var_proc1 _proc(m_shared, pvars, svars); for_each_expr(_proc, lits); rational v1, v2; for (expr* p : pvars) { @@ -315,6 +360,14 @@ namespace qe { return pvars; } + app_ref_vector euf_arith_mbi_plugin::get_arith_vars2(model_ref& mdl, expr_ref_vector& lits) { + arith_util a(m); + app_ref_vector avars(m); // arithmetic variables. + is_arith_var_proc2 _proc(avars); + for_each_expr(_proc, lits); + return avars; + } + mbi_result euf_arith_mbi_plugin::operator()(expr_ref_vector& lits, model_ref& mdl) { lbool r = m_solver->check_sat(lits); @@ -348,7 +401,7 @@ namespace qe { TRACE("qe", tout << lits << "\n" << *mdl << "\n";); // 1. arithmetical variables - app_ref_vector avars = get_arith_vars(mdl, lits); + app_ref_vector avars = get_arith_vars2(mdl, lits); TRACE("qe", tout << "vars: " << avars << " lits: " << lits << "\n";); @@ -366,22 +419,26 @@ namespace qe { // 3. Order arithmetical variables order_avars(mdl, lits, avars); + TRACE("qe", tout << "ordered: " << lits << "\n";); // 4. 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 for (auto const& def : defs) { expr_safe_replace rep(m); rep.insert(def.var, def.term); + TRACE("qe", tout << def.var << " -> " << def.term << "\n";); for (unsigned i = 0; i < lits.size(); ++i) { expr_ref tmp(m); rep(lits.get(i), tmp); lits[i] = tmp; } } + TRACE("qe", tout << "substitute: " << lits << "\n";); } void euf_arith_mbi_plugin::order_avars(model_ref& mdl, expr_ref_vector& lits, app_ref_vector& avars) { @@ -411,6 +468,9 @@ namespace qe { 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 { @@ -434,7 +494,7 @@ namespace qe { // 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); + app_ref_vector avars = get_arith_vars1(mdl, lits); TRACE("qe", tout << "vars: " << avars << " lits: " << lits << "\n";); // 2. diff --git a/src/qe/qe_mbi.h b/src/qe/qe_mbi.h index 3563c472a..66d37dd14 100644 --- a/src/qe/qe_mbi.h +++ b/src/qe/qe_mbi.h @@ -110,14 +110,17 @@ namespace qe { solver_ref m_solver; solver_ref m_dual_solver; struct is_atom_proc; - struct is_arith_var_proc; + struct is_arith_var_proc1; + struct is_arith_var_proc2; - app_ref_vector get_arith_vars(model_ref& mdl, expr_ref_vector& lits); + app_ref_vector get_arith_vars1(model_ref& mdl, expr_ref_vector& lits); + app_ref_vector get_arith_vars2(model_ref& mdl, expr_ref_vector& lits); bool get_literals(model_ref& mdl, expr_ref_vector& lits); void collect_atoms(expr_ref_vector const& fmls); void project0(model_ref& mdl, expr_ref_vector& lits); void project(model_ref& mdl, expr_ref_vector& lits); void order_avars(model_ref& mdl, expr_ref_vector& lits, app_ref_vector& avars); + void filter_private_arith(app_ref_vector& avars); public: euf_arith_mbi_plugin(solver* s, solver* emptySolver); ~euf_arith_mbi_plugin() override {} From 6a2d54b31e5ae48e291ff3028990634039894d85 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 28 Dec 2018 11:59:17 +0800 Subject: [PATCH 122/318] cleanup and doc Signed-off-by: Nikolaj Bjorner --- src/qe/qe_mbi.cpp | 225 +++++++++++----------------------------------- src/qe/qe_mbi.h | 11 +-- 2 files changed, 58 insertions(+), 178 deletions(-) diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index 557735cde..3619b0130 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -218,36 +218,12 @@ namespace qe { void operator()(expr*) {} }; - struct euf_arith_mbi_plugin::is_arith_var_proc1 { - ast_manager& m; - app_ref_vector& m_pvars; - app_ref_vector& m_svars; - arith_util arith; - obj_hashtable m_shared; - is_arith_var_proc1(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); - } - void operator()(app* a) { - if (!arith.is_int_real(a) || a->get_family_id() == arith.get_family_id()) { - // no-op - } - else if (m_shared.contains(a->get_decl())) { - m_svars.push_back(a); - } - else { - m_pvars.push_back(a); - } - } - void operator()(expr*) {} - }; - - struct euf_arith_mbi_plugin::is_arith_var_proc2 { + struct euf_arith_mbi_plugin::is_arith_var_proc { ast_manager& m; app_ref_vector& m_avars; arith_util arith; obj_hashtable m_seen; - is_arith_var_proc2(app_ref_vector& avars): + is_arith_var_proc(app_ref_vector& avars): m(avars.m()), m_avars(avars), arith(m) { } void operator()(app* a) { @@ -336,34 +312,13 @@ namespace qe { } } - app_ref_vector euf_arith_mbi_plugin::get_arith_vars1(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_proc1 _proc(m_shared, pvars, svars); - 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; - } - app_ref_vector euf_arith_mbi_plugin::get_arith_vars2(model_ref& mdl, expr_ref_vector& lits) { - arith_util a(m); - app_ref_vector avars(m); // arithmetic variables. - is_arith_var_proc2 _proc(avars); + /** + * \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 avars(m); + is_arith_var_proc _proc(avars); for_each_expr(_proc, lits); return avars; } @@ -390,57 +345,66 @@ namespace qe { } } - /** - 1. extract arithmetical variables, purify. - 2. project private variables from lits - 3. Order arithmetical variables. - 4. Perform arithmetical projection. - 5. Substitute solution into lits - */ void euf_arith_mbi_plugin::project(model_ref& mdl, expr_ref_vector& lits) { TRACE("qe", tout << lits << "\n" << *mdl << "\n";); - // 1. arithmetical variables - app_ref_vector avars = get_arith_vars2(mdl, lits); + // 1. arithmetical variables - atomic and in purified positions + app_ref_vector avars = get_arith_vars(mdl, lits); TRACE("qe", tout << "vars: " << avars << " lits: " << lits << "\n";); + // 2. project private non-arithmetical variables from lits + project_euf(mdl, lits, avars); - // 2. project private variables from lits - { - 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";); - } - - // 3. Order arithmetical variables + // 3. Order arithmetical variables and purified positions order_avars(mdl, lits, avars); TRACE("qe", tout << "ordered: " << lits << "\n";); - // 4. Arithmetical projection + // 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 - for (auto const& def : defs) { - expr_safe_replace rep(m); - rep.insert(def.var, def.term); - TRACE("qe", tout << def.var << " -> " << def.term << "\n";); - for (unsigned i = 0; i < lits.size(); ++i) { - expr_ref tmp(m); - rep(lits.get(i), tmp); - lits[i] = tmp; - } - } + + // 5. Substitute solution into lits + substitute(defs, lits); TRACE("qe", tout << "substitute: " << lits << "\n";); } + /** + * \brief subistute 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); + for (unsigned j = 0; j < lits.size(); ++j) { + expr_ref tmp(m); + rep(lits.get(j), tmp); + lits[j] = tmp; + } + } + } + + /** + * \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 variable according to the model. + * 2. remove non-atomic arithmetical terms from projection. + * 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) { arith_util a(m); model_evaluator mev(*mdl.get()); @@ -482,91 +446,6 @@ namespace qe { TRACE("qe", tout << lits << "\navars:" << avars << "\n" << *mdl << "\n";); } - - void euf_arith_mbi_plugin::project0(model_ref& mdl, expr_ref_vector& lits) { - TRACE("qe", tout << lits << "\n" << *mdl << "\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_vars1(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";); - } - 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 66d37dd14..c21200927 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, @@ -110,16 +112,15 @@ namespace qe { solver_ref m_solver; solver_ref m_dual_solver; struct is_atom_proc; - struct is_arith_var_proc1; - struct is_arith_var_proc2; + struct is_arith_var_proc; - app_ref_vector get_arith_vars1(model_ref& mdl, expr_ref_vector& lits); - app_ref_vector get_arith_vars2(model_ref& mdl, expr_ref_vector& lits); + app_ref_vector get_arith_vars(model_ref& mdl, expr_ref_vector& lits); bool get_literals(model_ref& mdl, expr_ref_vector& lits); void collect_atoms(expr_ref_vector const& fmls); - void project0(model_ref& mdl, expr_ref_vector& lits); void project(model_ref& mdl, expr_ref_vector& lits); + 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); + 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); From 0628711c4a888048e68501530f8b3a35b7ee5fcf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 28 Dec 2018 12:18:29 +0800 Subject: [PATCH 123/318] simplify Signed-off-by: Nikolaj Bjorner --- src/qe/qe_mbi.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index 3619b0130..f7c50e4c9 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -377,11 +377,7 @@ namespace qe { for (auto const& def : defs) { expr_safe_replace rep(m); rep.insert(def.var, def.term); - for (unsigned j = 0; j < lits.size(); ++j) { - expr_ref tmp(m); - rep(lits.get(j), tmp); - lits[j] = tmp; - } + rep(lits); } } From 64103038a7528b0b2c1c37a14fdc5dd72666068a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 28 Dec 2018 12:20:53 +0800 Subject: [PATCH 124/318] simplify Signed-off-by: Nikolaj Bjorner --- src/qe/qe_mbi.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index f7c50e4c9..61d6c5ff4 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -350,7 +350,7 @@ namespace qe { // 1. arithmetical variables - atomic and in purified positions app_ref_vector avars = get_arith_vars(mdl, lits); - TRACE("qe", tout << "vars: " << avars << " lits: " << lits << "\n";); + TRACE("qe", tout << "vars: " << avars << "\nlits: " << lits << "\n";); // 2. project private non-arithmetical variables from lits project_euf(mdl, lits, avars); @@ -371,7 +371,7 @@ namespace qe { } /** - * \brief subistute solution to arithmetical variables into lits + * \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) { From e40884725b7ac78477a37f43e1420b806b502b5a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 28 Dec 2018 19:47:48 +0800 Subject: [PATCH 125/318] remove unused euf-mbi Signed-off-by: Nikolaj Bjorner --- src/qe/qe_mbi.cpp | 100 +++------------------------------------------- src/qe/qe_mbi.h | 11 ----- 2 files changed, 5 insertions(+), 106 deletions(-) diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index 61d6c5ff4..b7de8d302 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -96,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 @@ -341,6 +246,11 @@ namespace qe { project(mdl, lits); 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; } } diff --git a/src/qe/qe_mbi.h b/src/qe/qe_mbi.h index c21200927..23294ee6e 100644 --- a/src/qe/qe_mbi.h +++ b/src/qe/qe_mbi.h @@ -93,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; From b083c7546eb6aeccc4f13d4f7354800d4c4ab918 Mon Sep 17 00:00:00 2001 From: Huanyi Chen Date: Fri, 28 Dec 2018 12:40:44 -0500 Subject: [PATCH 126/318] Substitue Vars in queries Replace Vars that are representing primary inputs as "i#" when query solvers. --- examples/python/mini_ic3.py | 41 +++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/examples/python/mini_ic3.py b/examples/python/mini_ic3.py index 5a8ea566b..a509d6ff8 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 @@ -319,7 +344,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 +373,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 @@ -435,4 +460,4 @@ class Quip(MiniIC3): else: return is_sat -""" \ No newline at end of file +""" From 300e99b67ad07757b7d8820770157b8ded12cb9b Mon Sep 17 00:00:00 2001 From: Huanyi Chen Date: Fri, 28 Dec 2018 12:42:28 -0500 Subject: [PATCH 127/318] Make sure init is included when generalize --- examples/python/mini_ic3.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/python/mini_ic3.py b/examples/python/mini_ic3.py index a509d6ff8..a62df48da 100644 --- a/examples/python/mini_ic3.py +++ b/examples/python/mini_ic3.py @@ -331,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 From 4b29b208ad1754c81df21936ac41c7464a10c6a2 Mon Sep 17 00:00:00 2001 From: Huanyi Chen Date: Fri, 28 Dec 2018 13:24:39 -0500 Subject: [PATCH 128/318] Add few more testcases --- examples/python/data/horn3.smt2 | 17 ++ examples/python/data/horn4.smt2 | 99 +++++++++++ examples/python/data/horn5.smt2 | 21 +++ examples/python/data/horn6.smt2 | 292 ++++++++++++++++++++++++++++++++ examples/python/mini_ic3.py | 4 + 5 files changed, 433 insertions(+) create mode 100644 examples/python/data/horn3.smt2 create mode 100644 examples/python/data/horn4.smt2 create mode 100644 examples/python/data/horn5.smt2 create mode 100644 examples/python/data/horn6.smt2 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/mini_ic3.py b/examples/python/mini_ic3.py index a62df48da..048e8e518 100644 --- a/examples/python/mini_ic3.py +++ b/examples/python/mini_ic3.py @@ -391,6 +391,10 @@ def test(file): test("data/horn1.smt2") test("data/horn2.smt2") +test("data/horn3.smt2") +test("data/horn4.smt2") +test("data/horn5.smt2") +test("data/horn6.smt2") From f8a33000262074fb7309c047aa01e9b65a992dd7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 29 Dec 2018 11:13:15 +0800 Subject: [PATCH 129/318] introduce proxies to differentiate from arithmetical variables Signed-off-by: Nikolaj Bjorner --- src/qe/qe_mbi.cpp | 50 +++++++++++++++++++------------------- src/qe/qe_mbi.h | 4 +-- src/smt/smt_context_pp.cpp | 1 + src/smt/theory_bv.cpp | 30 +++++++++++++++++++---- 4 files changed, 53 insertions(+), 32 deletions(-) diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index b7de8d302..dd0d36418 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -126,30 +126,29 @@ namespace qe { struct euf_arith_mbi_plugin::is_arith_var_proc { ast_manager& m; app_ref_vector& m_avars; - arith_util arith; + app_ref_vector& m_proxies; + arith_util m_arith; obj_hashtable m_seen; - is_arith_var_proc(app_ref_vector& avars): - m(avars.m()), m_avars(avars), arith(m) { + 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 (is_arith_op(a) || a->get_family_id() == m.get_basic_family_id()) { - // no-op + return; } - else if (!arith.is_int_real(a)) { - for (expr* arg : *a) { - if (is_app(arg) && !m_seen.contains(arg) && is_arith_op(to_app(arg))) { - m_avars.push_back(to_app(arg)); - m_seen.insert(arg); - } - } - } - else if (!m_seen.contains(a)) { - m_seen.insert(a); + + if (m_arith.is_int_real(a)) { m_avars.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() == arith.get_family_id(); + return a->get_family_id() == m_arith.get_family_id(); } void operator()(expr*) {} }; @@ -221,9 +220,9 @@ namespace qe { /** * \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 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); + is_arith_var_proc _proc(avars, proxies); for_each_expr(_proc, lits); return avars; } @@ -259,14 +258,15 @@ namespace qe { TRACE("qe", tout << lits << "\n" << *mdl << "\n";); // 1. arithmetical variables - atomic and in purified positions - app_ref_vector avars = get_arith_vars(mdl, lits); - TRACE("qe", tout << "vars: " << avars << "\nlits: " << lits << "\n";); + 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); + order_avars(mdl, lits, avars, proxies); TRACE("qe", tout << "ordered: " << lits << "\n";); // 4. Perform arithmetical projection @@ -307,15 +307,14 @@ namespace qe { /** * \brief Order arithmetical variables: - * 1. add literals that order the variable according to the model. - * 2. remove non-atomic arithmetical terms from projection. + * 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) { + 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 : avars) { + for (app* v : proxies) { rational val; expr_ref tmp = mev(v); VERIFY(a.is_numeral(tmp, val)); @@ -327,7 +326,7 @@ namespace qe { return x.first < y.first; } }; - // add linear order between avars + // add linear order between proxies compare_first cmp; std::sort(vals.begin(), vals.end(), cmp); for (unsigned i = 1; i < vals.size(); ++i) { @@ -338,6 +337,7 @@ namespace qe { lits.push_back(a.mk_lt(vals[i-1].second, vals[i].second)); } } + // filter out only private variables filter_private_arith(avars); diff --git a/src/qe/qe_mbi.h b/src/qe/qe_mbi.h index 23294ee6e..aa5d935b4 100644 --- a/src/qe/qe_mbi.h +++ b/src/qe/qe_mbi.h @@ -103,12 +103,12 @@ 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(model_ref& mdl, expr_ref_vector& lits); 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); + 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: diff --git a/src/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index 5dea80f5e..c79068298 100644 --- a/src/smt/smt_context_pp.cpp +++ b/src/smt/smt_context_pp.cpp @@ -200,6 +200,7 @@ namespace smt { out << "current assignment:\n"; for (literal lit : m_assigned_literals) { display_literal(out, lit); + if (!is_relevant(lit)) out << " n "; out << ": "; display_verbose(out, m_manager, 1, &lit, m_bool_var2expr.c_ptr()); out << "\n"; diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index 6e1626cc1..3a5f5e709 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -53,6 +53,7 @@ namespace smt { unsigned bv_size = get_bv_size(n); context & ctx = get_context(); literal_vector & bits = m_bits[v]; + TRACE("bv", tout << "v" << v << "\n";); bits.reset(); for (unsigned i = 0; i < bv_size; i++) { app * bit = mk_bit2bool(owner, i); @@ -77,6 +78,7 @@ namespace smt { context & ctx = get_context(); SASSERT(!ctx.b_internalized(n)); + TRACE("bv", tout << "bit2bool: " << mk_pp(n, ctx.get_manager()) << "\n";); expr* first_arg = n->get_arg(0); if (!ctx.e_internalized(first_arg)) { @@ -98,17 +100,20 @@ namespace smt { rational val; unsigned sz; if (!ctx.b_internalized(n) && m_util.is_numeral(first_arg, val, sz)) { + + TRACE("bv", tout << "bit2bool constants\n";); theory_var v = first_arg_enode->get_th_var(get_id()); app* owner = first_arg_enode->get_owner(); for (unsigned i = 0; i < sz; ++i) { - ctx.internalize(mk_bit2bool(owner, i), true); + app* e = mk_bit2bool(owner, i); + ctx.internalize(e, true); } m_bits[v].reset(); rational bit; for (unsigned i = 0; i < sz; ++i) { div(val, rational::power_of_two(i), bit); mod(bit, rational(2), bit); - m_bits[v].push_back(bit.is_zero()?false_literal:true_literal); + m_bits[v].push_back(bit.is_zero()?false_literal:true_literal); } } } @@ -135,6 +140,18 @@ namespace smt { SASSERT(a->m_occs == 0); a->m_occs = new (get_region()) var_pos_occ(v_arg, idx); } + rational val; + unsigned sz; + if (m_util.is_numeral(first_arg, val, sz)) { + rational bit; + unsigned idx = n->get_decl()->get_parameter(0).get_int(); + div(val, rational::power_of_two(idx), bit); + mod(bit, rational(2), bit); + literal lit = ctx.get_literal(n); + if (bit.is_zero()) lit.neg(); + ctx.mark_as_relevant(lit); + ctx.mk_th_axiom(get_id(), 1, &lit); + } } void theory_bv::process_args(app * n) { @@ -622,7 +639,9 @@ namespace smt { context& ctx = get_context(); process_args(n); mk_enode(n); - mk_bits(ctx.get_enode(n)->get_th_var(get_id())); + theory_var v = ctx.get_enode(n)->get_th_var(get_id()); + mk_bits(v); + if (!ctx.relevancy()) { assert_int2bv_axiom(n); } @@ -1179,7 +1198,7 @@ namespace smt { m_prop_queue.push_back(var_pos(curr->m_var, curr->m_idx)); curr = curr->m_next; } - TRACE("bv", tout << m_prop_queue.size() << "\n";); + TRACE("bv", tout << "prop queue size: " << m_prop_queue.size() << "\n";); propagate_bits(); } } @@ -1196,7 +1215,7 @@ namespace smt { literal_vector & bits = m_bits[v]; literal bit = bits[idx]; - lbool val = ctx.get_assignment(bit); + lbool val = ctx.get_assignment(bit); if (val == l_undef) { continue; } @@ -1213,6 +1232,7 @@ namespace smt { SASSERT(bit != ~bit2); lbool val2 = ctx.get_assignment(bit2); TRACE("bv_bit_prop", tout << "propagating #" << get_enode(v2)->get_owner_id() << "[" << idx << "] = " << val2 << "\n";); + TRACE("bv", tout << bit << " " << bit2 << "\n";); if (val != val2) { literal consequent = bit2; From b72cb96ee3a94d8a9402b2f87a499c975ce828f0 Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Sat, 29 Dec 2018 16:43:08 +0800 Subject: [PATCH 130/318] update dotnet cmake module --- cmake/modules/FindDotnet.cmake | 179 ++++++++++++++++++++++++++++----- src/api/dotnet/CMakeLists.txt | 2 + 2 files changed, 158 insertions(+), 23 deletions(-) diff --git a/cmake/modules/FindDotnet.cmake b/cmake/modules/FindDotnet.cmake index 625317a41..f424d3f23 100644 --- a/cmake/modules/FindDotnet.cmake +++ b/cmake/modules/FindDotnet.cmake @@ -23,6 +23,8 @@ # [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... ]) # ``` # @@ -43,18 +45,58 @@ # [PLATFORM platform] # [PACKAGE output_nuget_packages... ] # [DEPENDS depend_nuget_packages... ] +# [CUSTOM_BUILDPROPS value....] # [SOURCES additional_file_dependencies... ]) # ``` # +# 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] +# [CONFIG configuration] +# [PLATFORM platform] +# [PACKAGE output_nuget_packages... ] +# [VERSION nuget_package_version] +# [DEPENDS depend_nuget_packages... ] +# [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...]) +# ``` # -# 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. +# 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 build root directory (overridden by OUTPUT_PATH). 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 @@ -118,9 +160,9 @@ FUNCTION(DOTNET_GET_DEPS _DN_PROJECT arguments) # options (flags) "RELEASE;DEBUG;X86;X64;ANYCPU;NETCOREAPP" # oneValueArgs - "CONFIG;PLATFORM;VERSION" + "CONFIG;PLATFORM;VERSION;OUTPUT_PATH" # multiValueArgs - "PACKAGE;DEPENDS;ARGUMENTS;OUTPUT;SOURCES" + "PACKAGE;DEPENDS;ARGUMENTS;OUTPUT;SOURCES;CUSTOM_BUILDPROPS" # the input arguments ${arguments}) @@ -170,7 +212,19 @@ FUNCTION(DOTNET_GET_DEPS _DN_PROJECT arguments) SET(_DN_VERSION "1.0.0") ENDIF() - GET_FILENAME_COMPONENT(_DN_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/bin ABSOLUTE) + # Set the output path to the current 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 "bin") + ENDIF() + + GET_FILENAME_COMPONENT(_DN_OUTPUT_PATH ${CMAKE_CURRENT_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) @@ -200,16 +254,18 @@ FUNCTION(DOTNET_GET_DEPS _DN_PROJECT arguments) 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_BUILD_PROPERTIES ${_DN_PLATFORM_PROP} ${_DN_TFMS_PROP} "/p:DirectoryBuildPropsPath=${_DN_IMPORT_PROP}" "/p:DOTNET_PACKAGE_VERSION=${_DN_VERSION}" PARENT_SCOPE) + 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 ${_DN_PACK_OPTIONS} PARENT_SCOPE) + SET(DOTNET_PACK_OPTIONS --include-symbols ${_DN_PACK_OPTIONS} PARENT_SCOPE) ENDFUNCTION() -MACRO(ADD_DOTNET_DEPENDENCY_TARGETS) +MACRO(ADD_DOTNET_DEPENDENCY_TARGETS tgt) FOREACH(pkg_dep ${DOTNET_DEPENDS}) - ADD_DEPENDENCIES(BUILD_${DOTNET_PROJNAME} PKG_${pkg_dep}) + ADD_DEPENDENCIES(${tgt}_${DOTNET_PROJNAME} PKG_${pkg_dep}) MESSAGE(" ${DOTNET_PROJNAME} <- ${pkg_dep}") ENDFOREACH() @@ -227,11 +283,11 @@ MACRO(ADD_DOTNET_DEPENDENCY_TARGETS) COMMAND ${rm_command} DEPENDS ${DOTNET_deps} ) - ADD_DEPENDENCIES(BUILD_${DOTNET_PROJNAME} DOTNET_PURGE_${pkg}) + 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} BUILD_${DOTNET_PROJNAME}) + ADD_DEPENDENCIES(PKG_${pkg} ${tgt}_${DOTNET_PROJNAME}) MESSAGE("==== ${DOTNET_PROJNAME} -> ${pkg}") ENDFOREACH() ENDMACRO() @@ -240,42 +296,45 @@ 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 ${DOTNET_PROJPATH} + COMMAND ${NUGET_EXE} restore ${DOTNET_PROJPATH} -PackagesDirectory packages COMMAND ${DOTNET_EXE} msbuild ${DOTNET_PROJPATH} /t:Clean /p:Configuration="${DOTNET_CONFIG}" COMMAND ${DOTNET_EXE} msbuild ${DOTNET_PROJPATH} /t:Build ${DOTNET_BUILD_PROPERTIES} /p:Configuration="${DOTNET_CONFIG}") 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} + 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}) SET(build_dotnet_type "dotnet") ENDIF() + # DOTNET_OUTPUTS refer to artifacts produced, that the BUILD_proj_name target depends on. + SET(DOTNET_OUTPUTS "") IF(NOT "${DOTNET_PACKAGES}" STREQUAL "") MESSAGE("-- Adding ${build_dotnet_type} project ${DOTNET_PROJPATH} (version ${DOTNET_PACKAGE_VERSION})") - SET(_DOTNET_OUTPUTS "") + SET(_DN_OUTPUTS "") FOREACH(pkg ${DOTNET_PACKAGES}) - LIST(APPEND _DOTNET_OUTPUTS ${DOTNET_OUTPUT_PATH}/${pkg}.${DOTNET_PACKAGE_VERSION}.nupkg) + LIST(APPEND _DN_OUTPUTS ${DOTNET_OUTPUT_PATH}/${pkg}.${DOTNET_PACKAGE_VERSION}.nupkg) + LIST(APPEND DOTNET_OUTPUTS ${CMAKE_BINARY_DIR}/${pkg}.${DOTNET_PACKAGE_VERSION}.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}) - LIST(APPEND build_dotnet_cmds COMMAND ${CMAKE_COMMAND} -E copy ${_DOTNET_OUTPUTS} ${CMAKE_BINARY_DIR}) + LIST(APPEND build_dotnet_cmds COMMAND ${CMAKE_COMMAND} -E copy ${_DN_OUTPUTS} ${CMAKE_BINARY_DIR}) ELSE() MESSAGE("-- Adding ${build_dotnet_type} project ${DOTNET_PROJPATH} (no nupkg)") - SET(_DOTNET_OUTPUTS ${CMAKE_CURRENT_BINARY_DIR}/${DOTNET_PROJNAME}.buildtimestamp) - LIST(APPEND build_dotnet_cmds COMMAND ${CMAKE_COMMAND} -E touch ${_DOTNET_OUTPUTS}) + SET(DOTNET_OUTPUTS ${CMAKE_CURRENT_BINARY_DIR}/${DOTNET_PROJNAME}.buildtimestamp) + LIST(APPEND build_dotnet_cmds COMMAND ${CMAKE_COMMAND} -E touch ${DOTNET_OUTPUTS}) ENDIF() ADD_CUSTOM_COMMAND( - OUTPUT ${_DOTNET_OUTPUTS} + OUTPUT ${DOTNET_OUTPUTS} DEPENDS ${DOTNET_deps} ${build_dotnet_cmds} ) ADD_CUSTOM_TARGET( BUILD_${DOTNET_PROJNAME} ALL - DEPENDS ${_DOTNET_OUTPUTS}) + DEPENDS ${DOTNET_OUTPUTS}) ENDMACRO() @@ -283,7 +342,7 @@ FUNCTION(ADD_DOTNET DOTNET_PROJECT) DOTNET_GET_DEPS(${DOTNET_PROJECT} "${ARGN}") SET(DOTNET_IS_MSBUILD FALSE) DOTNET_BUILD_COMMANDS() - ADD_DOTNET_DEPENDENCY_TARGETS() + ADD_DOTNET_DEPENDENCY_TARGETS(BUILD) ENDFUNCTION() FUNCTION(ADD_MSBUILD DOTNET_PROJECT) @@ -295,7 +354,7 @@ FUNCTION(ADD_MSBUILD DOTNET_PROJECT) DOTNET_GET_DEPS(${DOTNET_PROJECT} "${ARGN}") SET(DOTNET_IS_MSBUILD TRUE) DOTNET_BUILD_COMMANDS() - ADD_DOTNET_DEPENDENCY_TARGETS() + ADD_DOTNET_DEPENDENCY_TARGETS(BUILD) ENDFUNCTION() FUNCTION(RUN_DOTNET DOTNET_PROJECT) @@ -312,5 +371,79 @@ FUNCTION(RUN_DOTNET DOTNET_PROJECT) ADD_DEPENDENCIES(RUN_${DOTNET_PROJNAME} BUILD_${DOTNET_PROJNAME}) 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_RUN_ARGUMENTS} + WORKING_DIRECTORY ${DOTNET_PROJDIR}) + +ENDFUNCTION() + +SET(DOTNET_LAST_SMOKETEST "") + +FUNCTION(SMOKETEST_DOTNET DOTNET_PROJECT) + IF(WIN32) + ADD_DOTNET(${DOTNET_PROJECT} "${ARGN}") + # TODO should run on all targeted frameworks + RUN_DOTNET(${DOTNET_PROJECT} "${ARGN}" ARGUMENTS -f netcoreapp2.0) + ELSE() + ADD_DOTNET(${DOTNET_PROJECT} "${ARGN}" NETCOREAPP) + RUN_DOTNET(${DOTNET_PROJECT} "${ARGN}" ARGUMENTS -f netcoreapp2.0) + 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) + IF(DOTNET_LAST_SMOKETEST) + ADD_DEPENDENCIES(SMOKETEST_${DOTNET_PROJNAME} ${DOTNET_LAST_SMOKETEST}) + ENDIF() + # Chain the smoke tests together so they are executed sequentially + SET(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/src/api/dotnet/CMakeLists.txt b/src/api/dotnet/CMakeLists.txt index b2909f03c..b9e26ec9e 100644 --- a/src/api/dotnet/CMakeLists.txt +++ b/src/api/dotnet/CMakeLists.txt @@ -138,6 +138,8 @@ endforeach() # 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. + +# TODO how to receive "configuration" and "platform" from here? set(Z3_DOTNET_NUPKG_VERSION "${VER_MAJOR}.${VER_MINOR}.${VER_BUILD}") 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 From 815faa96d99c383309d8a57554ac22a5417e707f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 29 Dec 2018 16:44:03 +0800 Subject: [PATCH 131/318] remove dotnet35 support Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/dotnet35/Example/App.config | 6 - .../dotnet/dotnet35/Example/Example.csproj | 78 ---- .../Example/Properties/AssemblyInfo.cs | 36 -- .../dotnet/dotnet35/Microsoft.Z3.NET35.csproj | 347 ------------------ .../dotnet/dotnet35/Microsoft.Z3.NET35.sln | 48 --- .../dotnet35/Properties/AssemblyInfo.cs | 38 -- .../dotnet35/Properties/AssemblyInfo.cs.in | 38 -- src/api/dotnet/dotnet35/Readme.NET35 | 10 - src/api/dotnet/dotnet35/packages.config | 4 - 9 files changed, 605 deletions(-) delete mode 100644 src/api/dotnet/dotnet35/Example/App.config delete mode 100644 src/api/dotnet/dotnet35/Example/Example.csproj delete mode 100644 src/api/dotnet/dotnet35/Example/Properties/AssemblyInfo.cs delete mode 100644 src/api/dotnet/dotnet35/Microsoft.Z3.NET35.csproj delete mode 100644 src/api/dotnet/dotnet35/Microsoft.Z3.NET35.sln delete mode 100644 src/api/dotnet/dotnet35/Properties/AssemblyInfo.cs delete mode 100644 src/api/dotnet/dotnet35/Properties/AssemblyInfo.cs.in delete mode 100644 src/api/dotnet/dotnet35/Readme.NET35 delete mode 100644 src/api/dotnet/dotnet35/packages.config 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 75210f8b6..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 conditional 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 @@ - - - - From b533ba39d64af84fc5a792f15a8ac98fac86b9bb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 29 Dec 2018 17:13:32 +0800 Subject: [PATCH 132/318] use private rewriter to avoid surprises Signed-off-by: Nikolaj Bjorner --- src/smt/theory_bv.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index 3a5f5e709..711c15a33 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -81,6 +81,8 @@ namespace smt { TRACE("bv", tout << "bit2bool: " << mk_pp(n, ctx.get_manager()) << "\n";); expr* first_arg = n->get_arg(0); + SASSERT(!m_util.is_numeral(first_arg)); + if (!ctx.e_internalized(first_arg)) { // This may happen if bit2bool(x) is in a conflict // clause that is being reinitialized, and x was not reinitialized @@ -96,6 +98,9 @@ namespace smt { // This will also force the creation of all bits for x. enode * first_arg_enode = ctx.get_enode(first_arg); get_var(first_arg_enode); +#if 0 + // constant axiomatization moved to catch all case in the end of function. + // numerals are not blasted into bit2bool, so we do this directly. rational val; unsigned sz; @@ -116,6 +121,7 @@ namespace smt { m_bits[v].push_back(bit.is_zero()?false_literal:true_literal); } } +#endif } enode * arg = ctx.get_enode(first_arg); @@ -140,6 +146,7 @@ namespace smt { SASSERT(a->m_occs == 0); a->m_occs = new (get_region()) var_pos_occ(v_arg, idx); } + // axiomatize bit2bool on constants. rational val; unsigned sz; if (m_util.is_numeral(first_arg, val, sz)) { @@ -619,8 +626,8 @@ namespace smt { num *= numeral(2); } expr_ref sum(m_autil.mk_add(sz, args.c_ptr()), m); - arith_rewriter arw(m); - ctx.get_rewriter()(sum); + th_rewriter rw(m); + rw(sum); literal l(mk_eq(n, sum, false)); TRACE("bv", tout << mk_pp(n, m) << "\n"; From 878f297dac0ad623a5670d5d2b1c29304515daba Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Tue, 1 Jan 2019 17:20:33 +0100 Subject: [PATCH 133/318] Make Ubuntu package more generic. --- scripts/mk_nuget_release.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/scripts/mk_nuget_release.py b/scripts/mk_nuget_release.py index c5079ed2c..ba0d44c3e 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'), @@ -91,11 +91,7 @@ def create_nuget_spec(): 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 From 0d400a5ad61ee457f3c53399461d347adcf0d604 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 4 Jan 2019 07:46:53 -0800 Subject: [PATCH 134/318] fix bit2bool bug reported by Jianying Li Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/bv_rewriter.cpp | 16 ++++++++++++++++ src/ast/rewriter/bv_rewriter.h | 1 + src/cmd_context/extra_cmds/dbg_cmds.cpp | 20 +++++++++++++++----- src/qe/qe_arrays.cpp | 4 ++-- src/qe/qe_mbi.cpp | 2 ++ src/qe/qe_mbi.h | 2 +- src/smt/theory_pb.cpp | 9 +++++---- src/smt/theory_seq.cpp | 5 +---- src/smt/theory_str.cpp | 10 ++++++---- 9 files changed, 49 insertions(+), 20 deletions(-) diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index 3dc76da5e..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: @@ -2203,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/cmd_context/extra_cmds/dbg_cmds.cpp b/src/cmd_context/extra_cmds/dbg_cmds.cpp index bdd2c8b97..6170a231e 100644 --- a/src/cmd_context/extra_cmds/dbg_cmds.cpp +++ b/src/cmd_context/extra_cmds/dbg_cmds.cpp @@ -524,11 +524,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"; } }; 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_mbi.cpp b/src/qe/qe_mbi.cpp index dd0d36418..77f910260 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -256,6 +256,8 @@ 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); diff --git a/src/qe/qe_mbi.h b/src/qe/qe_mbi.h index aa5d935b4..12e6a8080 100644 --- a/src/qe/qe_mbi.h +++ b/src/qe/qe_mbi.h @@ -106,7 +106,6 @@ namespace qe { 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(model_ref& mdl, expr_ref_vector& lits); 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); @@ -115,6 +114,7 @@ namespace qe { 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/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index de86ef7e3..671184633 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -723,10 +723,11 @@ namespace smt { ineqs = alloc(ptr_vector); m_var_infos[lit.var()].m_lit_watch[lit.sign()] = ineqs; } - for (auto* c1 : *ineqs) { - //if (c1 == c) return; - SASSERT (c1 != c); - } + DEBUG_CODE( + for (auto* c1 : *ineqs) { + //if (c1 == c) return; + SASSERT (c1 != c); + }); ineqs->push_back(c); } diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 283bd4e57..e8af44d7e 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -3495,12 +3495,11 @@ bool theory_seq::add_itos_val_axiom(expr* e) { } bool theory_seq::add_stoi_val_axiom(expr* e) { - context& ctx = get_context(); expr* n = nullptr; rational val, val2; VERIFY(m_util.str.is_stoi(e, n)); - TRACE("seq", tout << mk_pp(e, m) << " " << ctx.get_scope_level () << " " << get_length(n, val) << " " << val << "\n";); + TRACE("seq", tout << mk_pp(e, m) << " " << get_context().get_scope_level () << " " << get_length(n, val) << " " << val << "\n";); if (m_util.str.is_itos(n)) { return false; @@ -3951,7 +3950,6 @@ model_value_proc * theory_seq::mk_value(enode * n, model_generator & mg) { app* theory_seq::mk_value(app* e) { expr_ref result(m); - context& ctx = get_context(); e = get_ite_value(e); result = m_rep.find(e); @@ -4705,7 +4703,6 @@ bool theory_seq::lower_bound2(expr* _e, rational& lo) { bool theory_seq::get_length(expr* e, rational& val) const { - context& ctx = get_context(); rational val1; expr_ref len(m), len_val(m); expr* e1 = nullptr, *e2 = nullptr; diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 02801648a..75ca7cf47 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -1682,10 +1682,10 @@ namespace smt { expr_ref i1(mk_int_var("i1"), m); expr_ref result(mk_str_var("result"), m); - expr * replaceS; - expr * replaceT; - expr * replaceTPrime; - u.str.is_replace(ex, replaceS, replaceT, replaceTPrime); + expr * replaceS = nullptr; + expr * replaceT = nullptr; + expr * replaceTPrime = nullptr; + VERIFY(u.str.is_replace(ex, replaceS, replaceT, replaceTPrime)); // t empty => result = (str.++ t' s) expr_ref emptySrcAst(ctx.mk_eq_atom(replaceT, mk_string("")), m); @@ -4851,6 +4851,7 @@ namespace smt { bool theory_str::get_arith_value(expr* e, rational& val) const { context& ctx = get_context(); ast_manager & m = get_manager(); + (void)m; if (!ctx.e_internalized(e)) { return false; } @@ -8255,6 +8256,7 @@ namespace smt { void theory_str::check_eqc_concat_concat(std::set & eqc_concat_lhs, std::set & eqc_concat_rhs) { ast_manager & m = get_manager(); + (void)m; int hasCommon = 0; if (!eqc_concat_lhs.empty() && !eqc_concat_rhs.empty()) { From fb397cbe25f9e20c541ba0880e0c4b2c2f05bce5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 4 Jan 2019 08:18:40 -0800 Subject: [PATCH 135/318] remove incorrect assertion Signed-off-by: Nikolaj Bjorner --- src/smt/theory_bv.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index 711c15a33..8db1df26b 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -81,8 +81,6 @@ namespace smt { TRACE("bv", tout << "bit2bool: " << mk_pp(n, ctx.get_manager()) << "\n";); expr* first_arg = n->get_arg(0); - SASSERT(!m_util.is_numeral(first_arg)); - if (!ctx.e_internalized(first_arg)) { // This may happen if bit2bool(x) is in a conflict // clause that is being reinitialized, and x was not reinitialized From 83e3a79bd1cf925324bb63a214da7d78ed1653f7 Mon Sep 17 00:00:00 2001 From: Huanyi Chen Date: Fri, 4 Jan 2019 17:26:00 -0500 Subject: [PATCH 136/318] Remove testcase that takes long time to finish --- examples/python/mini_ic3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/python/mini_ic3.py b/examples/python/mini_ic3.py index 048e8e518..39756d207 100644 --- a/examples/python/mini_ic3.py +++ b/examples/python/mini_ic3.py @@ -394,7 +394,7 @@ test("data/horn2.smt2") test("data/horn3.smt2") test("data/horn4.smt2") test("data/horn5.smt2") -test("data/horn6.smt2") +# test("data/horn6.smt2") # takes long time to finish From 19471f9fa374b79a85227a9a454d9f184a79608d Mon Sep 17 00:00:00 2001 From: Huanyi Chen Date: Sat, 29 Dec 2018 15:44:42 -0500 Subject: [PATCH 137/318] Implement mini_quip --- examples/python/mini_ic3.py | 72 ---- examples/python/mini_quip.py | 786 +++++++++++++++++++++++++++++++++++ 2 files changed, 786 insertions(+), 72 deletions(-) create mode 100644 examples/python/mini_quip.py diff --git a/examples/python/mini_ic3.py b/examples/python/mini_ic3.py index 39756d207..b7b732459 100644 --- a/examples/python/mini_ic3.py +++ b/examples/python/mini_ic3.py @@ -395,75 +395,3 @@ test("data/horn3.smt2") test("data/horn4.smt2") test("data/horn5.smt2") # test("data/horn6.smt2") # takes long time to finish - - - -""" -# 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 - -""" 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 From e1a9154555486ec574b10d0d23e043f748f61683 Mon Sep 17 00:00:00 2001 From: Carsten Varming Date: Fri, 4 Jan 2019 17:02:56 -0500 Subject: [PATCH 138/318] Specify UTF-8 encoding in python build scripts --- scripts/mk_genfile_common.py | 7 ++++--- scripts/mk_util.py | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/scripts/mk_genfile_common.py b/scripts/mk_genfile_common.py index a65b41026..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: @@ -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_util.py b/scripts/mk_util.py index 9076b582f..6552a942f 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 @@ -806,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) From a06bc497102cdfbf49e086b33d196e8bb38f8d54 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Sun, 6 Jan 2019 12:15:31 +0700 Subject: [PATCH 139/318] Let str_hashtable store `const char*`. This removes some boilerplate const casting. --- src/util/debug.cpp | 6 +++--- src/util/str_hashtable.h | 2 +- src/util/symbol.cpp | 9 ++++----- src/util/trace.cpp | 6 +++--- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/util/debug.cpp b/src/util/debug.cpp index 3e40e412c..1b85fbbbb 100644 --- a/src/util/debug.cpp +++ b/src/util/debug.cpp @@ -56,17 +56,17 @@ void finalize_debug() { void enable_debug(const char * tag) { init_debug_table(); - g_enabled_debug_tags->insert(const_cast(tag)); + g_enabled_debug_tags->insert(tag); } void disable_debug(const char * tag) { init_debug_table(); - g_enabled_debug_tags->erase(const_cast(tag)); + g_enabled_debug_tags->erase(tag); } bool is_debug_enabled(const char * tag) { init_debug_table(); - return g_enabled_debug_tags->contains(const_cast(tag)); + return g_enabled_debug_tags->contains(tag); } #if !defined(_WINDOWS) && !defined(NO_Z3_DEBUGGER) diff --git a/src/util/str_hashtable.h b/src/util/str_hashtable.h index e12cdc7a7..111d54ac8 100644 --- a/src/util/str_hashtable.h +++ b/src/util/str_hashtable.h @@ -28,7 +28,7 @@ struct str_hash_proc { unsigned operator()(char const * s) const { return string_hash(s, static_cast(strlen(s)), 17); } }; struct str_eq_proc { bool operator()(char const * s1, char const * s2) const { return strcmp(s1, s2) == 0; } }; -typedef ptr_hashtable str_hashtable; +typedef ptr_hashtable str_hashtable; #endif /* STR_HASHTABLE_H_ */ diff --git a/src/util/symbol.cpp b/src/util/symbol.cpp index 90b245e6c..3f0e7c967 100644 --- a/src/util/symbol.cpp +++ b/src/util/symbol.cpp @@ -35,20 +35,19 @@ class internal_symbol_table { public: char const * get_str(char const * d) { - char * result; + const char * result; #pragma omp critical (cr_symbol) { - char * r_d = const_cast(d); str_hashtable::entry * e; - if (m_table.insert_if_not_there_core(r_d, e)) { + if (m_table.insert_if_not_there_core(d, e)) { // new entry size_t l = strlen(d); // store the hash-code before the string size_t * mem = static_cast(m_region.allocate(l + 1 + sizeof(size_t))); *mem = e->get_hash(); mem++; - result = reinterpret_cast(mem); - memcpy(result, d, l+1); + result = reinterpret_cast(mem); + memcpy(mem, d, l+1); // update the entry with the new ptr. e->set_data(result); } diff --git a/src/util/trace.cpp b/src/util/trace.cpp index 68437ab92..e4b210021 100644 --- a/src/util/trace.cpp +++ b/src/util/trace.cpp @@ -38,7 +38,7 @@ void finalize_trace() { } void enable_trace(const char * tag) { - get_enabled_trace_tags().insert(const_cast(tag)); + get_enabled_trace_tags().insert(tag); } void enable_all_trace(bool flag) { @@ -46,12 +46,12 @@ void enable_all_trace(bool flag) { } void disable_trace(const char * tag) { - get_enabled_trace_tags().erase(const_cast(tag)); + get_enabled_trace_tags().erase(tag); } bool is_trace_enabled(const char * tag) { return g_enable_all_trace_tags || - (g_enabled_trace_tags && get_enabled_trace_tags().contains(const_cast(tag))); + (g_enabled_trace_tags && get_enabled_trace_tags().contains(tag)); } void close_trace() { From 7e1ce2a16c2ccbeeece41b4457e6451f4e7faa8b Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Sun, 6 Jan 2019 12:06:53 +0700 Subject: [PATCH 140/318] Define NO_Z3_DEBUGGER for iOS builds. This is defined because we can't call `system` (via `invoke_gdb`) on iOS and related platforms. --- src/util/debug.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/util/debug.h b/src/util/debug.h index 536df4588..ea702e8a7 100644 --- a/src/util/debug.h +++ b/src/util/debug.h @@ -44,6 +44,13 @@ bool assertions_enabled(); #define DEBUG_CODE(CODE) ((void) 0) #endif +#ifdef __APPLE__ +#include +#if !TARGET_OS_OSX +#define NO_Z3_DEBUGGER +#endif +#endif + #ifdef NO_Z3_DEBUGGER #define INVOKE_DEBUGGER() exit(ERR_INTERNAL_FATAL) #else From 71e239c08efb201640bb4c0224e87a5c03291964 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 6 Jan 2019 11:49:47 -0800 Subject: [PATCH 141/318] fix #2061 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 35 +++++++++++++++++++++++++++++++ src/ast/rewriter/seq_rewriter.h | 1 + src/qe/qe_mbp.cpp | 4 ++-- 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index d46f234e2..68ddad07d 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -459,6 +459,9 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con case OP_SEQ_AT: SASSERT(num_args == 2); return mk_seq_at(args[0], args[1], result); + case OP_SEQ_NTH: + SASSERT(num_args == 2); + return mk_seq_nth(args[0], args[1], result); case OP_SEQ_PREFIX: SASSERT(num_args == 2); return mk_seq_prefix(args[0], args[1], result); @@ -877,6 +880,38 @@ 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_REWRITE1; + } + } + else if (i > 0) { + SASSERT(len >= i); + result = m_util.str.mk_concat(as.size() - i, as.c_ptr() + i); + result = m().mk_app(m_util.get_family_id(), OP_SEQ_NTH, result, m_autil.mk_int(len - i)); + return BR_REWRITE2; + } + 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; diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h index 83793a594..25b8979fc 100644 --- a/src/ast/rewriter/seq_rewriter.h +++ b/src/ast/rewriter/seq_rewriter.h @@ -114,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/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); From a87f7a14d33a6f9fe8c97b2ab583b85eaec5b862 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 6 Jan 2019 13:46:04 -0800 Subject: [PATCH 142/318] ever so gentle slap over the fingers for not using real regular expressions, #2058 Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 4 ++++ src/smt/theory_seq.cpp | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 7d45c9707..49d545894 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1720,6 +1720,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 { diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index e8af44d7e..e384c7b1f 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -4584,7 +4584,12 @@ void theory_seq::propagate_in_re(expr* n, bool is_true) { IF_VERBOSE(11, verbose_stream() << mk_pp(s, m) << " in " << re << "\n"); eautomaton* a = get_automaton(re); - if (!a) return; + if (!a) { + std::stringstream strm; + strm << "expression " << re << " does not correspond to a supported regular expression"; + TRACE("seq", tout << strm.str() << "\n";); + throw default_exception(strm.str()); + } m_s_in_re.push_back(s_in_re(lit, s, re, a)); m_trail_stack.push(push_back_vector>(m_s_in_re)); From ea48d0a95a32401f74cb20eece3422a7b3030346 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 6 Jan 2019 18:55:00 -0800 Subject: [PATCH 143/318] add set method to iterator, #2068, a set method to the vector template was also added Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 49d545894..e541080c9 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1750,6 +1750,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]; } From 611314913895c4fca80dde62c07c1fb4d2eddc59 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 6 Jan 2019 20:20:34 -0800 Subject: [PATCH 144/318] fix #2060. Code comment was right, code wasn't. Code comment and code could also be tuned Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index e384c7b1f..c3274d7ab 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -3536,7 +3536,7 @@ expr_ref theory_seq::digit2int(expr* ch) { -// n >= 0 & len(e) = k => is_digit(e_i) for i = 0..k-1 +// n >= 0 & len(e) >= i + 1 => is_digit(e_i) for i = 0..k-1 // n >= 0 & len(e) = k => n = sum 10^i*digit(e_i) // n < 0 & len(e) = k => \/_i ~is_digit(e_i) for i = 0..k-1 // 10^k <= n < 10^{k+1}-1 => len(e) = k @@ -3556,7 +3556,9 @@ void theory_seq::add_si_axiom(expr* e, expr* n, unsigned k) { for (unsigned i = 0; i < k; ++i) { ith_char = mk_nth(e, m_autil.mk_int(i)); literal isd = is_digit(ith_char); - add_axiom(~len_eq_k, ~ge0, isd); + literal len_ge_i1 = mk_literal(m_autil.mk_ge(len, m_autil.mk_int(i+1))); + add_axiom(~len_ge_i1, ~ge0, isd); + digits.push_back(~isd); chars.push_back(m_util.str.mk_unit(ith_char)); nums.push_back(digit2int(ith_char)); } From d757c342d59edf29d0ba9af57adc4fa492f9e65e Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Mon, 7 Jan 2019 23:13:09 +0700 Subject: [PATCH 145/318] Define NO_Z3_DEBUGGER for emscripten builds. --- src/util/debug.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/util/debug.h b/src/util/debug.h index ea702e8a7..613328013 100644 --- a/src/util/debug.h +++ b/src/util/debug.h @@ -51,6 +51,10 @@ bool assertions_enabled(); #endif #endif +#ifdef __EMSCRIPTEN__ +#define NO_Z3_DEBUGGER +#endif + #ifdef NO_Z3_DEBUGGER #define INVOKE_DEBUGGER() exit(ERR_INTERNAL_FATAL) #else From cec34c745a7e34d07f2390f4b6e7f9dca4626fb3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 7 Jan 2019 09:00:11 -0800 Subject: [PATCH 146/318] defer blocking propagation until all properties of literal have been axiomatized. Deals with seq part of #2071 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index e8af44d7e..259901340 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -262,6 +262,7 @@ final_check_status theory_seq::final_check_eh() { m_new_propagation = false; TRACE("seq", display(tout << "level: " << get_context().get_scope_level() << "\n");); TRACE("seq_verbose", get_context().display(tout);); + if (simplify_and_solve_eqs()) { ++m_stats.m_solve_eqs; TRACEFIN("solve_eqs"); @@ -5559,14 +5560,9 @@ void theory_seq::propagate_accept(literal lit, expr* acc) { propagate_lit(nullptr, 1, &lit, false_literal); return; } - if (_idx.get_unsigned() > m_max_unfolding_depth && - m_max_unfolding_lit != null_literal && ctx.get_scope_level() > 0) { - propagate_lit(nullptr, 1, &lit, ~m_max_unfolding_lit); - return; - } + expr_ref len = mk_len(e); - literal_vector lits; lits.push_back(~lit); if (aut->is_final_state(src)) { @@ -5576,9 +5572,11 @@ void theory_seq::propagate_accept(literal lit, expr* acc) { else { propagate_lit(nullptr, 1, &lit, ~mk_literal(m_autil.mk_le(len, idx))); } + + eautomaton::moves mvs; aut->get_moves_from(src, mvs); - TRACE("seq", tout << mvs.size() << "\n";); + TRACE("seq", tout << mk_pp(acc, m) << " #moves " << mvs.size() << "\n";); for (auto const& mv : mvs) { expr_ref nth = mk_nth(e, idx); expr_ref t = mv.t()->accept(nth); @@ -5587,6 +5585,11 @@ void theory_seq::propagate_accept(literal lit, expr* acc) { lits.push_back(step); } ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); + + if (_idx.get_unsigned() > m_max_unfolding_depth && + m_max_unfolding_lit != null_literal && ctx.get_scope_level() > 0) { + propagate_lit(nullptr, 1, &lit, ~m_max_unfolding_lit); + } } void theory_seq::add_theory_assumptions(expr_ref_vector & assumptions) { From b63a0e31d3e2162049d9a424cc5be2bb10f20d26 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 7 Jan 2019 16:30:04 -0800 Subject: [PATCH 147/318] fix regression from #2061 breaking #2074 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 10 +++------- src/smt/theory_seq.cpp | 15 +++++++++++++++ src/smt/theory_seq.h | 1 + 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 68ddad07d..cb915d86b 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -459,9 +459,11 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con 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); @@ -896,15 +898,9 @@ br_status seq_rewriter::mk_seq_nth(expr* a, expr* b, expr_ref& result) { if (m_util.str.is_unit(a, u)) { if (len == i) { result = u; - return BR_REWRITE1; + return BR_DONE; } } - else if (i > 0) { - SASSERT(len >= i); - result = m_util.str.mk_concat(as.size() - i, as.c_ptr() + i); - result = m().mk_app(m_util.get_family_id(), OP_SEQ_NTH, result, m_autil.mk_int(len - i)); - return BR_REWRITE2; - } else { return BR_FAILED; } diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 71d448960..936953d0a 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -4261,6 +4261,9 @@ void theory_seq::deque_axiom(expr* n) { else if (m_util.str.is_at(n)) { add_at_axiom(n); } + else if (m_util.str.is_nth(n)) { + add_nth_axiom(n); + } else if (m_util.str.is_string(n)) { add_elim_string_axiom(n); } @@ -4965,6 +4968,17 @@ void theory_seq::add_at_axiom(expr* e) { add_axiom(~i_ge_len_s, mk_eq(e, emp, false)); } +void theory_seq::add_nth_axiom(expr* e) { + expr* s = nullptr, *i = nullptr; + rational n; + zstring str; + VERIFY(m_util.str.is_nth(e, s, i)); + if (m_util.str.is_string(s, str) && m_autil.is_numeral(i, n) && n.is_unsigned() && n.get_unsigned() < str.length()) { + app_ref ch(m_util.str.mk_char(str[n.get_unsigned()]), m); + add_axiom(mk_eq(ch, e, false)); + } +} + /* lit => s = (nth s 0) ++ (nth s 1) ++ ... ++ (nth s idx) ++ (tail s idx) @@ -5431,6 +5445,7 @@ void theory_seq::relevant_eh(app* n) { m_util.str.is_replace(n) || m_util.str.is_extract(n) || m_util.str.is_at(n) || + m_util.str.is_nth(n) || m_util.str.is_empty(n) || m_util.str.is_string(n) || m_util.str.is_itos(n) || diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 9925188b6..242d24e4f 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -575,6 +575,7 @@ namespace smt { expr_ref add_elim_string_axiom(expr* n); void add_at_axiom(expr* n); + void add_nth_axiom(expr* n); void add_in_re_axiom(expr* n); void add_itos_axiom(expr* n); void add_stoi_axiom(expr* n); From 9c318ed304579b6101207cf52535fc2a1128a76c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 9 Jan 2019 15:43:45 -0800 Subject: [PATCH 148/318] fix #2076, add option to handle .cnf files into dimacs parser Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 2 +- src/smt/theory_pb.cpp | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index a5ad7b525..8f92d5bb4 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -181,7 +181,7 @@ extern "C" { if (!is) { SET_ERROR_CODE(Z3_FILE_ACCESS_ERROR, nullptr); } - else if (ext && std::string("dimacs") == ext) { + else if (ext && (std::string("dimacs") == ext || std::string("cnf") == ext)) { ast_manager& m = to_solver_ref(s)->get_manager(); std::stringstream err; sat::solver solver(to_solver_ref(s)->get_params(), m.limit()); diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 671184633..182324832 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1197,8 +1197,11 @@ namespace smt { literal_vector& lits = get_unhelpful_literals(c, true); lits.push_back(c.lit()); for (unsigned i = 0; i < sz; ++i) { - DEBUG_CODE(validate_assign(c, lits, c.lit(i));); - add_assign(c, lits, c.lit(i)); + literal lit = c.lit(i); + if (ctx.get_assignment(lit) == l_undef) { + DEBUG_CODE(validate_assign(c, lits, lit);); + add_assign(c, lits, c.lit(i)); + } } } } From efaab6d8fd9e2166b3497233c1bad7637e253c7b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 10 Jan 2019 11:38:35 -0800 Subject: [PATCH 149/318] have sat cleaner use a fixed-point Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 31 +++---------- src/ast/datatype_decl_plugin.cpp | 74 +++++++++++++++++++++++++++++++- src/ast/datatype_decl_plugin.h | 57 +++--------------------- src/sat/sat_cleaner.cpp | 12 ++++-- 4 files changed, 94 insertions(+), 80 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 523d40842..65f634b6b 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 @@ -6664,17 +6665,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 @@ -7063,17 +7058,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""" @@ -7410,17 +7399,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.""" diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index 0271d8311..a7f6fb07b 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 { @@ -667,7 +737,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) { diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index fc98c97e7..16d1f74c0 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/sat/sat_cleaner.cpp b/src/sat/sat_cleaner.cpp index c0c6fabe4..e13a117fd 100644 --- a/src/sat/sat_cleaner.cpp +++ b/src/sat/sat_cleaner.cpp @@ -192,10 +192,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; } From 59b0b56b421af33ba02e9662a19c3d69ef4bf371 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 10 Jan 2019 12:08:38 -0800 Subject: [PATCH 150/318] add checkpoints to blocked clause elimination to handle timeouts, #2080 Signed-off-by: Nikolaj Bjorner --- src/sat/sat_simplifier.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 21d264af5..ca29a8501 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1527,6 +1527,7 @@ namespace sat { block_covered_binary(w, l, blocked, k); break; } + s.checkpoint(); } } @@ -1552,6 +1553,7 @@ namespace sat { s.set_learned(c); break; } + s.checkpoint(); } } From b12c1b1cbac974efb27298a7c9d0123ea2714082 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 10 Jan 2019 13:38:45 -0800 Subject: [PATCH 151/318] set a throttle on ala Signed-off-by: Nikolaj Bjorner --- src/sat/sat_simplifier.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index ca29a8501..ca9b71a2d 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1272,7 +1272,8 @@ 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; ++m_ala_qhead) { literal l = m_covered_clause[m_ala_qhead]; for (watched & w : s.get_wlist(~l)) { if (w.is_binary_non_learned_clause()) { @@ -1282,7 +1283,6 @@ namespace sat { 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); @@ -1312,7 +1312,6 @@ namespace sat { if (lit1 == null_literal) { 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); From 6e60926cc38361f411b6a709a1c36c902aeb7ded Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 10 Jan 2019 15:25:10 -0800 Subject: [PATCH 152/318] fix drat output for elim_eqs Signed-off-by: Nikolaj Bjorner --- src/sat/sat_elim_eqs.cpp | 77 +++++++++++++++++++++++++++------------- src/sat/sat_elim_eqs.h | 4 +++ src/sat/sat_solver.cpp | 4 +-- src/sat/sat_solver.h | 2 +- 4 files changed, 60 insertions(+), 27 deletions(-) diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index 870aa7fe2..8633f04d3 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()]; @@ -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,69 @@ 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 - m_solver.del_clause(c); + drat_delete_clause(); + m_solver.del_clause(c, false); continue; } - if (j == 0) { - // empty clause + + switch (j) { + case 0: m_solver.set_conflict(justification()); 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.del_clause(c); + m_solver.del_clause(c, false); + drat_delete_clause(); break; case 2: m_solver.mk_bin_clause(c[0], c[1], c.is_learned()); - m_solver.del_clause(c); + m_solver.del_clause(c, false); + drat_delete_clause(); 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_solver.cpp b/src/sat/sat_solver.cpp index fc5fce252..6731adc92 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -298,14 +298,14 @@ namespace sat { mk_clause(3, ls, learned); } - void solver::del_clause(clause& c) { + void solver::del_clause(clause& c, bool enable_drat) { if (!c.is_learned()) { m_stats.m_non_learned_generation++; } if (c.frozen()) { --m_num_frozen; } - if (m_config.m_drat && !m_drat.is_cleaned(c)) { + if (enable_drat && m_config.m_drat && !m_drat.is_cleaned(c)) { m_drat.del(c); } dealloc_clause(&c); diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 8402fc898..3937c67e8 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -232,7 +232,7 @@ namespace sat { void defrag_clauses(); bool should_defrag(); bool memory_pressure(); - void del_clause(clause & c); + void del_clause(clause & c, bool enable_drat = true); clause * mk_clause_core(unsigned num_lits, literal * lits, bool learned); clause * mk_clause_core(literal_vector const& lits) { return mk_clause_core(lits.size(), lits.c_ptr()); } clause * mk_clause_core(unsigned num_lits, literal * lits) { return mk_clause_core(num_lits, lits, false); } From 434eb25004fdd1cd24fb0c9319c897a8206cdf31 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 10 Jan 2019 17:20:01 -0800 Subject: [PATCH 153/318] add useful div lemma for case #2079 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith_core.h | 14 +++++++++++++- src/smt/theory_seq.cpp | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index f3a3e9238..55adc8370 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -482,12 +482,12 @@ namespace smt { template void theory_arith::mk_idiv_mod_axioms(expr * dividend, expr * divisor) { + th_rewriter & s = get_context().get_rewriter(); if (!m_util.is_zero(divisor)) { ast_manager & m = get_manager(); // if divisor is zero, then idiv and mod are uninterpreted functions. expr_ref div(m), mod(m), zero(m), abs_divisor(m), one(m); expr_ref eqz(m), eq(m), lower(m), upper(m); - th_rewriter & s = get_context().get_rewriter(); div = m_util.mk_idiv(dividend, divisor); mod = m_util.mk_mod(dividend, divisor); zero = m_util.mk_int(0); @@ -508,6 +508,17 @@ namespace smt { mk_axiom(eqz, upper, !m_util.is_numeral(abs_divisor)); rational k; context& ctx = get_context(); + + if (!m_util.is_numeral(divisor)) { + // (=> (> y 0) (<= (* y (div x y)) x)) + // (=> (< y 0) ???) + expr_ref div_ge(m), div_non_pos(m); + div_ge = m_util.mk_ge(m_util.mk_sub(dividend, m_util.mk_mul(divisor, div)), zero); + s(div_ge); + div_non_pos = m_util.mk_le(divisor, zero); + mk_axiom(div_non_pos, div_ge, false); + } + (void)ctx; if (m_params.m_arith_enum_const_mod && m_util.is_numeral(divisor, k) && k.is_pos() && k < rational(8)) { @@ -542,6 +553,7 @@ namespace smt { } #endif } + #if 0 // e-matching is too restrictive for multiplication. // also suffers from use-after free so formulas have to be pinned in solver. diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 936953d0a..10b2992fe 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -251,7 +251,7 @@ void theory_seq::init(context* ctx) { m_arith_value.init(ctx); } -#define TRACEFIN(s) { TRACE("seq", tout << ">>" << s << "\n";); IF_VERBOSE(10, verbose_stream() << s << "\n"); } +#define TRACEFIN(s) { TRACE("seq", tout << ">>" << s << "\n";); IF_VERBOSE(11, verbose_stream() << s << "\n"); } final_check_status theory_seq::final_check_eh() { From f1c3e1aa7725ed12987ceeb7c0fdcb04a1f64a3e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 11 Jan 2019 04:58:40 -0800 Subject: [PATCH 154/318] fix #2077 Signed-off-by: Nikolaj Bjorner --- src/ast/datatype_decl_plugin.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index 0271d8311..f88256835 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -584,13 +584,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(); From 9bd4050e0c221f7f9bb1409401f321c394cf70f4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 11 Jan 2019 13:43:39 -0800 Subject: [PATCH 155/318] use ref-vector for shared occurrences to avoid hash-table overhead Signed-off-by: Nikolaj Bjorner --- src/ast/shared_occs.cpp | 20 ++++++++++++-------- src/ast/shared_occs.h | 11 +++++------ src/cmd_context/extra_cmds/dbg_cmds.cpp | 20 -------------------- 3 files changed, 17 insertions(+), 34 deletions(-) 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/extra_cmds/dbg_cmds.cpp b/src/cmd_context/extra_cmds/dbg_cmds.cpp index 6170a231e..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; @@ -550,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)); From b8d18c6c6d150ad73747e90ccaa272b66a1f7b89 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 11 Jan 2019 20:52:19 -0800 Subject: [PATCH 156/318] speed-up handling of cnf input to inc_sat_solver Signed-off-by: Nikolaj Bjorner --- src/ast/expr2var.cpp | 47 +++++++++++++++++------- src/ast/expr2var.h | 10 +++-- src/sat/sat_cleaner.cpp | 53 ++++++++++++++------------- src/sat/sat_simplifier.cpp | 16 +++++--- src/sat/sat_solver/inc_sat_solver.cpp | 46 +++++++++++++++++++++-- src/sat/tactic/atom2bool_var.cpp | 10 +++-- src/smt/theory_pb.cpp | 8 ++-- 7 files changed, 133 insertions(+), 57 deletions(-) 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/sat/sat_cleaner.cpp b/src/sat/sat_cleaner.cpp index e13a117fd..4a3fb82b4 100644 --- a/src/sat/sat_cleaner.cpp +++ b/src/sat/sat_cleaner.cpp @@ -78,6 +78,7 @@ namespace sat { } void cleaner::cleanup_clauses(clause_vector & cs) { + tmp_clause tmp; clause_vector::iterator it = cs.begin(); clause_vector::iterator it2 = it; clause_vector::iterator end = cs.end(); @@ -88,12 +89,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 +107,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,33 +118,37 @@ 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) { + switch (new_sz) { + case 0: s.set_conflict(justification()); s.del_clause(c); - } - else if (new_sz == 1) { + break; + case 1: s.assign(c[0], justification()); 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: + SASSERT(s.value(c[0]) == l_undef && s.value(c[1]) == l_undef); + if (s.m_config.m_drat && new_sz < i) { + tmp.set(c.size(), c.begin(), c.is_learned()); } - else { - 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); - } + c.shrink(new_sz); + *it2 = *it; + it2++; + if (!c.frozen()) { + s.attach_clause(c); + } + if (s.m_config.m_drat && new_sz < i) { + // for optimization, could also report deletion + // of previous version of clause. + s.m_drat.add(c, true); + s.m_drat.del(*tmp.get()); } } } diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index ca9b71a2d..4feeb4b05 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -349,7 +349,7 @@ namespace sat { } if (sz == 2) { s.mk_bin_clause(c[0], c[1], c.is_learned()); - s.del_clause(c); + s.del_clause(c, false); continue; } *it2 = *it; @@ -611,10 +611,15 @@ namespace sat { break; } } - if (j < sz) { - if (s.m_config.m_drat) s.m_drat.del(c); + if (j < sz && !r) { + if (s.m_config.m_drat) { + m_dummy.set(c.size(), c.begin(), c.is_learned()); + } c.shrink(j); - if (s.m_config.m_drat) s.m_drat.add(c, true); + if (s.m_config.m_drat) { + s.m_drat.add(c, true); + s.m_drat.del(*m_dummy.get()); + } } return r; } @@ -2020,8 +2025,7 @@ namespace sat { 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)) continue; // clause is already satisfied. diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 13780529a..5eb613ac2 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), @@ -262,9 +264,22 @@ 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 { + m_is_cnf &= is_clause(t); assert_expr_core(t); } } @@ -545,7 +560,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";); @@ -705,6 +725,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; @@ -712,7 +751,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) { 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/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 182324832..dea698f3f 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -966,9 +966,9 @@ namespace smt { justification* js = nullptr; c.inc_propagations(*this); if (!resolve_conflict(c, lits)) { - if (proofs_enabled()) { - js = alloc(theory_lemma_justification, get_id(), ctx, lits.size(), lits.c_ptr()); - } + if (proofs_enabled()) { + js = alloc(theory_lemma_justification, get_id(), ctx, lits.size(), lits.c_ptr()); + } ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, nullptr); } SASSERT(ctx.inconsistent()); @@ -1195,7 +1195,9 @@ namespace smt { // perform unit propagation if (maxsum >= c.mpz_k() && maxsum - mininc < c.mpz_k()) { literal_vector& lits = get_unhelpful_literals(c, true); + // for (literal lit : lits) SASSERT(ctx.get_assignment(lit) == l_true); lits.push_back(c.lit()); + // SASSERT(ctx.get_assignment(c.lit()) == l_true); for (unsigned i = 0; i < sz; ++i) { literal lit = c.lit(i); if (ctx.get_assignment(lit) == l_undef) { From 63d480fd92989381db5e6e3c827de19d6a630d1c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 11 Jan 2019 21:17:39 -0800 Subject: [PATCH 157/318] fix cnf check Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 2 +- src/sat/sat_drat.cpp | 85 ++++++++++++++++++++++++++- src/sat/sat_drat.h | 12 +++- src/sat/sat_solver/inc_sat_solver.cpp | 2 +- 4 files changed, 96 insertions(+), 5 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 66c175ac8..d23fd5043 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -361,7 +361,7 @@ namespace opt { 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) { diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index 529a6bc57..4707fa0ac 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -143,7 +143,7 @@ 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); @@ -225,6 +225,55 @@ namespace sat { m_units.resize(num_units); bool ok = m_inconsistent; m_inconsistent = false; + + if (!ok) { + 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); + } return ok; } @@ -280,7 +329,10 @@ 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"; + literal_vector lits(n, c); + std::cout << "Verification of " << lits << " failed\n"; + s.display(std::cout); + exit(0); UNREACHABLE(); //display(std::cout); TRACE("sat", @@ -291,6 +343,35 @@ namespace sat { } } + bool drat::contains(unsigned n, literal const* lits) { + 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) { diff --git a/src/sat/sat_drat.h b/src/sat/sat_drat.h index 64d796839..35da0c31a 100644 --- a/src/sat/sat_drat.h +++ b/src/sat/sat_drat.h @@ -67,7 +67,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 +74,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 +93,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_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 5eb613ac2..8823c40c5 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -279,7 +279,6 @@ public: } } else { - m_is_cnf &= is_clause(t); assert_expr_core(t); } } @@ -287,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 {} From ffd26e5a563aa2c464014261c5774435a3e9bcc6 Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Sat, 12 Jan 2019 15:01:05 +0800 Subject: [PATCH 158/318] .net: remove net35 related build props; drop src/api/dotnet/core --- .gitignore | 2 + CMakeSettings.json | 17 +++ cmake/modules/DotnetImports.props.in | 3 +- cmake/modules/FindDotnet.cmake | 97 +++++++++------ src/api/dotnet/Microsoft.Z3.csproj.in | 165 +------------------------- src/api/dotnet/core/README.txt | 15 --- src/api/dotnet/core/core.csproj | 18 --- src/api/dotnet/dotnet35/Readme.NET35 | 10 -- 8 files changed, 86 insertions(+), 241 deletions(-) create mode 100644 CMakeSettings.json delete mode 100644 src/api/dotnet/core/README.txt delete mode 100644 src/api/dotnet/core/core.csproj delete mode 100644 src/api/dotnet/dotnet35/Readme.NET35 diff --git a/.gitignore b/.gitignore index e189a9569..9b239a566 100644 --- a/.gitignore +++ b/.gitignore @@ -76,3 +76,5 @@ src/api/ml/z3.mllib *.bak doc/api doc/code +.vs +examples/**/obj diff --git a/CMakeSettings.json b/CMakeSettings.json new file mode 100644 index 000000000..f8c4fa7c6 --- /dev/null +++ b/CMakeSettings.json @@ -0,0 +1,17 @@ +{ + "configurations": [ + { + "name": "x64-Release", + "generator": "Visual Studio 15 2017 Win64", + "configurationType": "RelWithDebInfo", + "inheritEnvironments": [ + "msvc_x64_x64" + ], + "buildRoot": "F:\\b\\z3\\build\\${name}", + "installRoot": "F:\\b\\z3\\install\\${name}", + "cmakeCommandArgs": "", + "buildCommandArgs": "", + "ctestCommandArgs": "" + } + ] +} \ No newline at end of file diff --git a/cmake/modules/DotnetImports.props.in b/cmake/modules/DotnetImports.props.in index fba9ae301..090d46502 100644 --- a/cmake/modules/DotnetImports.props.in +++ b/cmake/modules/DotnetImports.props.in @@ -1,7 +1,8 @@ ${_DN_OUTPUT_PATH}/ - ${XPLAT_LIB_DIR}/ + ${_DN_XPLAT_LIB_DIR}/ ${_DN_VERSION} + ${_DN_CUSTOM_BUILDPROPS} diff --git a/cmake/modules/FindDotnet.cmake b/cmake/modules/FindDotnet.cmake index f424d3f23..4bcfe2215 100644 --- a/cmake/modules/FindDotnet.cmake +++ b/cmake/modules/FindDotnet.cmake @@ -32,9 +32,15 @@ # produced by running the .NET program, and can be consumed from other build steps. # # ``` -# RUN_DOTNET( +# RUN_DOTNET( [RELEASE|DEBUG] [X86|X64|ANYCPU] [NETCOREAPP] # [ARGUMENTS program_args...] -# [OUTPUT outputs...]) +# [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. @@ -54,11 +60,11 @@ # 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] -# [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... ]) # @@ -81,7 +87,8 @@ # # ``` # TEST_DOTNET( -# [ARGUMENTS additional_dotnet_test_args...]) +# [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: @@ -153,7 +160,6 @@ FUNCTION(DOTNET_REGISTER_LOCAL_REPOSITORY repo_name repo_path) ENDFUNCTION() FUNCTION(DOTNET_GET_DEPS _DN_PROJECT arguments) - FILE(GLOB_RECURSE DOTNET_deps *.cs *.fs *.xaml *.csproj *.fsproj *.tsl) CMAKE_PARSE_ARGUMENTS( # prefix _DN @@ -166,18 +172,29 @@ FUNCTION(DOTNET_GET_DEPS _DN_PROJECT arguments) # 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/) + IF(NOT dep MATCHES /obj/ AND NOT dep MATCHES /bin/) LIST(APPEND _DN_deps ${dep}) ENDIF() ENDFOREACH() - GET_FILENAME_COMPONENT(_DN_abs_proj "${_DN_PROJECT}" ABSOLUTE) - GET_FILENAME_COMPONENT(_DN_proj_dir "${_DN_PROJECT}" DIRECTORY) - GET_FILENAME_COMPONENT(_DN_projname "${DOTNET_PROJECT}" NAME) - STRING(REGEX REPLACE "\\.[^.]*$" "" _DN_projname_noext ${_DN_projname}) IF(_DN_RELEASE) SET(_DN_CONFIG Release) @@ -186,10 +203,7 @@ FUNCTION(DOTNET_GET_DEPS _DN_PROJECT arguments) ENDIF() IF(NOT _DN_CONFIG) - SET(_DN_CONFIG $) - IF(_DN_CONFIG STREQUAL "RelWithDebInfo" OR _DN_CONFIG STREQUAL "RelMinSize" OR NOT _DN_CONFIG) - SET(_DN_CONFIG "Release") - ENDIF() + SET(_DN_CONFIG Release) ENDIF() # If platform is not specified, do not pass the Platform property. @@ -217,7 +231,7 @@ FUNCTION(DOTNET_GET_DEPS _DN_PROJECT arguments) # Later we then copy the outputs to the destination. IF(NOT _DN_OUTPUT_PATH) - SET(_DN_OUTPUT_PATH "bin") + SET(_DN_OUTPUT_PATH ${_DN_projname_noext}) ENDIF() GET_FILENAME_COMPONENT(_DN_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/${_DN_OUTPUT_PATH} ABSOLUTE) @@ -295,14 +309,14 @@ 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 ${DOTNET_PROJPATH} -PackagesDirectory packages - COMMAND ${DOTNET_EXE} msbuild ${DOTNET_PROJPATH} /t:Clean /p:Configuration="${DOTNET_CONFIG}" + 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}") 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 ${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}) @@ -310,21 +324,22 @@ MACRO(DOTNET_BUILD_COMMANDS) ENDIF() # DOTNET_OUTPUTS refer to artifacts produced, that the BUILD_proj_name target depends on. - SET(DOTNET_OUTPUTS "") + 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})") SET(_DN_OUTPUTS "") FOREACH(pkg ${DOTNET_PACKAGES}) LIST(APPEND _DN_OUTPUTS ${DOTNET_OUTPUT_PATH}/${pkg}.${DOTNET_PACKAGE_VERSION}.nupkg) LIST(APPEND DOTNET_OUTPUTS ${CMAKE_BINARY_DIR}/${pkg}.${DOTNET_PACKAGE_VERSION}.nupkg) + + LIST(APPEND _DN_OUTPUTS ${DOTNET_OUTPUT_PATH}/${pkg}.${DOTNET_PACKAGE_VERSION}.symbols.nupkg) + LIST(APPEND DOTNET_OUTPUTS ${CMAKE_BINARY_DIR}/${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}) LIST(APPEND build_dotnet_cmds COMMAND ${CMAKE_COMMAND} -E copy ${_DN_OUTPUTS} ${CMAKE_BINARY_DIR}) ELSE() - MESSAGE("-- Adding ${build_dotnet_type} project ${DOTNET_PROJPATH} (no nupkg)") - SET(DOTNET_OUTPUTS ${CMAKE_CURRENT_BINARY_DIR}/${DOTNET_PROJNAME}.buildtimestamp) - LIST(APPEND build_dotnet_cmds COMMAND ${CMAKE_COMMAND} -E touch ${DOTNET_OUTPUTS}) ENDIF() ADD_CUSTOM_COMMAND( @@ -358,17 +373,23 @@ FUNCTION(ADD_MSBUILD DOTNET_PROJECT) ENDFUNCTION() FUNCTION(RUN_DOTNET DOTNET_PROJECT) - DOTNET_GET_DEPS(${DOTNET_PROJECT} "${ARGN}") + 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} run ${DOTNET_RUN_ARGUMENTS} + 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_RUN_ARGUMENTS} COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/${DOTNET_PROJNAME}.runtimestamp - WORKING_DIRECTORY ${DOTNET_PROJDIR}) + WORKING_DIRECTORY ${DOTNET_OUTPUT_PATH}) ADD_CUSTOM_TARGET( RUN_${DOTNET_PROJNAME} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${DOTNET_PROJNAME}.runtimestamp ${DOTNET_RUN_OUTPUT}) - ADD_DEPENDENCIES(RUN_${DOTNET_PROJNAME} BUILD_${DOTNET_PROJNAME}) + ADD_DOTNET_DEPENDENCY_TARGETS(RUN) ENDFUNCTION() FUNCTION(TEST_DOTNET DOTNET_PROJECT) @@ -382,20 +403,18 @@ FUNCTION(TEST_DOTNET DOTNET_PROJECT) ADD_TEST(NAME ${DOTNET_PROJNAME} COMMAND ${DOTNET_EXE} test ${test_framework_args} --results-directory "${CMAKE_BINARY_DIR}" --logger trx ${DOTNET_RUN_ARGUMENTS} - WORKING_DIRECTORY ${DOTNET_PROJDIR}) + WORKING_DIRECTORY ${DOTNET_OUTPUT_PATH}) ENDFUNCTION() -SET(DOTNET_LAST_SMOKETEST "") +SET_PROPERTY(GLOBAL PROPERTY DOTNET_LAST_SMOKETEST "") FUNCTION(SMOKETEST_DOTNET DOTNET_PROJECT) + MESSAGE("-- Adding dotnet smoke test project ${DOTNET_PROJECT}") IF(WIN32) - ADD_DOTNET(${DOTNET_PROJECT} "${ARGN}") - # TODO should run on all targeted frameworks - RUN_DOTNET(${DOTNET_PROJECT} "${ARGN}" ARGUMENTS -f netcoreapp2.0) + RUN_DOTNET(${DOTNET_PROJECT} "${ARGN}") ELSE() - ADD_DOTNET(${DOTNET_PROJECT} "${ARGN}" NETCOREAPP) - RUN_DOTNET(${DOTNET_PROJECT} "${ARGN}" ARGUMENTS -f netcoreapp2.0) + RUN_DOTNET(${DOTNET_PROJECT} "${ARGN}") ENDIF() DOTNET_GET_DEPS(${DOTNET_PROJECT} "${ARGN}") @@ -404,11 +423,13 @@ FUNCTION(SMOKETEST_DOTNET DOTNET_PROJECT) ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${DOTNET_PROJNAME}.runtimestamp) ADD_DOTNET_DEPENDENCY_TARGETS(SMOKETEST) - IF(DOTNET_LAST_SMOKETEST) - ADD_DEPENDENCIES(SMOKETEST_${DOTNET_PROJNAME} ${DOTNET_LAST_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(DOTNET_LAST_SMOKETEST SMOKETEST_${DOTNET_PROJNAME}) + SET_PROPERTY(GLOBAL PROPERTY DOTNET_LAST_SMOKETEST SMOKETEST_${DOTNET_PROJNAME}) ENDFUNCTION() diff --git a/src/api/dotnet/Microsoft.Z3.csproj.in b/src/api/dotnet/Microsoft.Z3.csproj.in index ee7b9237d..34321e90b 100644 --- a/src/api/dotnet/Microsoft.Z3.csproj.in +++ b/src/api/dotnet/Microsoft.Z3.csproj.in @@ -15,8 +15,8 @@ .NET Interface to the Z3 Theorem Prover .NET Interface to the Z3 Theorem Prover - Copyright (C) 2006-2015 Microsoft Corporation - Copyright (C) 2006-2015 Microsoft Corporation + Copyright (C) 2006-2019 Microsoft Corporation + Copyright (C) 2006-2019 Microsoft Corporation Microsoft Corporation Microsoft Corporation @@ -36,163 +36,19 @@ false - - 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 - - - true - GlobalSuppressions.cs - 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 - - - true - GlobalSuppressions.cs - 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 - + - true - GlobalSuppressions.cs - 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 - - true - GlobalSuppressions.cs - 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 - GlobalSuppressions.cs - 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 - - - + netstandard2.0;net461;net45 library True 1701,1702 4 - FRAMEWORK_LT_4 true $(OutputPath)\Microsoft.Z3.xml @@ -224,20 +80,11 @@ ${Z3_DOTNET_COMPILE_ITEMS} - - + + runtimes\win-x86\native - - runtimes\linux-x86\native - - - - - - - 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/Readme.NET35 b/src/api/dotnet/dotnet35/Readme.NET35 deleted file mode 100644 index 75210f8b6..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 conditional 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 From 836f156d545d7418da71fb7b70da879507431e8f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 12 Jan 2019 00:12:20 -0800 Subject: [PATCH 159/318] fix drat for units learned from binary clause resolution Signed-off-by: Nikolaj Bjorner --- src/sat/sat_clause.cpp | 5 +++ src/sat/sat_clause.h | 1 + src/sat/sat_cleaner.cpp | 4 +-- src/sat/sat_drat.cpp | 26 +++++++------- src/sat/sat_simplifier.cpp | 73 +++++++++++++++++++++++--------------- src/sat/sat_solver.cpp | 26 ++++++-------- 6 files changed, 76 insertions(+), 59 deletions(-) diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index 31a4bba72..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) { 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 4a3fb82b4..f0c76b466 100644 --- a/src/sat/sat_cleaner.cpp +++ b/src/sat/sat_cleaner.cpp @@ -135,7 +135,7 @@ namespace sat { break; default: SASSERT(s.value(c[0]) == l_undef && s.value(c[1]) == l_undef); - if (s.m_config.m_drat && new_sz < i) { + if (s.m_config.m_drat && new_sz < sz) { tmp.set(c.size(), c.begin(), c.is_learned()); } c.shrink(new_sz); @@ -144,7 +144,7 @@ namespace sat { if (!c.frozen()) { s.attach_clause(c); } - if (s.m_config.m_drat && new_sz < i) { + if (s.m_config.m_drat && new_sz < sz) { // for optimization, could also report deletion // of previous version of clause. s.m_drat.add(c, true); diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index 4707fa0ac..ca45bd971 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -68,7 +68,7 @@ namespace sat { 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::deleted: return; (*m_out) << "d "; break; } for (unsigned i = 0; i < n; ++i) (*m_out) << c[i] << " "; (*m_out) << "0\n"; @@ -215,18 +215,12 @@ 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); + }); - for (unsigned i = num_units; i < m_units.size(); ++i) { - m_assignment[m_units[i].var()] = l_undef; - } - m_units.resize(num_units); - bool ok = m_inconsistent; - m_inconsistent = false; - - if (!ok) { + 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) { @@ -274,6 +268,13 @@ namespace sat { IF_VERBOSE(0, s.display(verbose_stream())); exit(0); } + for (unsigned i = num_units; i < m_units.size(); ++i) { + m_assignment[m_units[i].var()] = l_undef; + } + m_units.resize(num_units); + bool ok = m_inconsistent; + m_inconsistent = false; + return ok; } @@ -344,6 +345,7 @@ namespace sat { } 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]; diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 4feeb4b05..34f89c3aa 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -125,8 +125,9 @@ namespace sat { } inline void simplifier::remove_clause_core(clause & c) { - for (literal l : 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";); @@ -330,35 +331,40 @@ namespace sat { } } + unsigned sz0 = c.size(); if (cleanup_clause(c, in_use_lists)) { s.del_clause(c); continue; } unsigned sz = c.size(); - if (sz == 0) { + switch(sz) { + case 0: s.set_conflict(justification()); for (; it != end; ++it, ++it2) { *it2 = *it; } - break; - } - if (sz == 1) { + cs.set_end(it2); + return; + case 1: s.assign(c[0], justification()); + c.restore(sz0); s.del_clause(c); - continue; - } - if (sz == 2) { + break; + case 2: s.mk_bin_clause(c[0], c[1], c.is_learned()); - s.del_clause(c, false); - continue; - } - *it2 = *it; - it2++; - if (!c.frozen()) { - s.attach_clause(c); - if (s.m_config.m_drat) { - s.m_drat.add(c, true); + c.restore(sz0); + s.del_clause(c, true); + break; + default: + *it2 = *it; + it2++; + if (!c.frozen()) { + s.attach_clause(c); + if (sz != sz0 && s.m_config.m_drat) { + s.m_drat.add(c, true); + } } + break; } } cs.set_end(it2); @@ -679,9 +685,15 @@ 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; @@ -695,23 +707,23 @@ namespace sat { case 0: TRACE("elim_lit", tout << "clause is empty\n";); s.set_conflict(justification()); - return; + break; case 1: TRACE("elim_lit", tout << "clause became unit: " << c[0] << "\n";); propagate_unit(c[0]); // propagate_unit will delete c. // remove_clause(c); - return; + break; case 2: TRACE("elim_lit", tout << "clause became binary: " << c[0] << " " << c[1] << "\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())); remove_clause(c); - return; + break; default: TRACE("elim_lit", tout << "result: " << c << "\n";); m_sub_todo.insert(c); - return; + break; } } @@ -876,27 +888,30 @@ namespace sat { m_sub_counter--; TRACE("subsumption", tout << "next: " << c << "\n";); if (s.m_trail.size() > m_last_sub_trail_sz) { + unsigned sz0 = c.size(); if (cleanup_clause(c, true /* clause is in the use_lists */)) { remove_clause(c); continue; } unsigned sz = c.size(); - if (sz == 0) { + switch (sz) { + case 0: s.set_conflict(justification()); return; - } - if (sz == 1) { + case 1: propagate_unit(c[0]); // propagate_unit will delete c. // remove_clause(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: + break; } } TRACE("subsumption", tout << "using: " << c << "\n";); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 6731adc92..6f181dcc9 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -344,11 +344,11 @@ namespace sat { void solver::mk_bin_clause(literal l1, literal l2, bool learned) { if (find_binary_watch(get_wlist(~l1), ~l2)) { - assign(l1, justification()); + assign_core(l1, 0, justification(l2)); return; } if (find_binary_watch(get_wlist(~l2), ~l1)) { - assign(l2, justification()); + assign_core(l2, 0, justification(l1)); return; } watched* w0 = find_binary_watch(get_wlist(~l1), l2); @@ -759,17 +759,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";); + 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; @@ -2263,6 +2266,7 @@ namespace sat { bool solver::resolve_conflict_core() { + m_conflicts_since_init++; m_conflicts_since_restart++; m_conflicts_since_gc++; @@ -2378,6 +2382,7 @@ namespace sat { while (num_marks > 0); m_lemma[0] = ~consequent; + m_drat.verify(m_lemma.size(), m_lemma.c_ptr()); learn_lemma_and_backjump(); return true; } @@ -2409,7 +2414,6 @@ 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);); // unsound: m_asymm_branch.minimize(m_scc, m_lemma); @@ -2879,20 +2883,16 @@ 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 +2900,6 @@ namespace sat { } j++; } -#if 0 - if (!drop && i >= bound) { - j = sz; - break; - } -#endif } reset_unmark(0); From 0b8dbf28545eaea8820715224b65ea371e892dad Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 12 Jan 2019 00:30:21 -0800 Subject: [PATCH 160/318] fixing drat proofs Signed-off-by: Nikolaj Bjorner --- src/sat/sat_drat.cpp | 7 ++++++- src/sat/sat_simplifier.cpp | 9 ++------- src/sat/sat_solver.cpp | 1 - 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index ca45bd971..608728002 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -68,7 +68,7 @@ namespace sat { case status::asserted: return; case status::external: return; // requires extension to drat format. case status::learned: break; - case status::deleted: return; (*m_out) << "d "; break; + case status::deleted: (*m_out) << "d "; break; } for (unsigned i = 0; i < n; ++i) (*m_out) << c[i] << " "; (*m_out) << "0\n"; @@ -220,6 +220,7 @@ namespace sat { 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"); @@ -268,6 +269,8 @@ namespace sat { 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; } @@ -568,7 +571,9 @@ namespace sat { if (m_check) append(l1, l2, status::deleted); } + void drat::del(clause& c) { + TRACE("sat", tout << "del: " << c << "\n";); if (m_out) dump(c.size(), c.begin(), status::deleted); if (m_check) { diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 34f89c3aa..2c5059b18 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -347,22 +347,17 @@ namespace sat { return; case 1: s.assign(c[0], justification()); - c.restore(sz0); - s.del_clause(c); + s.del_clause(c, false); break; case 2: s.mk_bin_clause(c[0], c[1], c.is_learned()); - c.restore(sz0); - s.del_clause(c, true); + s.del_clause(c, false); break; default: *it2 = *it; it2++; if (!c.frozen()) { s.attach_clause(c); - if (sz != sz0 && s.m_config.m_drat) { - s.m_drat.add(c, true); - } } break; } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 6f181dcc9..2e4e4c299 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -2382,7 +2382,6 @@ namespace sat { while (num_marks > 0); m_lemma[0] = ~consequent; - m_drat.verify(m_lemma.size(), m_lemma.c_ptr()); learn_lemma_and_backjump(); return true; } From 3c96b51e979143733fc082949543324eb0a2cfb9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 12 Jan 2019 00:40:36 -0800 Subject: [PATCH 161/318] lvl -> _lvl Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 2e4e4c299..c9b535997 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -761,7 +761,7 @@ namespace sat { 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()); } From e623f1e9c950c79fd85d783c8a16a0660ea56ccd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 12 Jan 2019 01:01:49 -0800 Subject: [PATCH 162/318] restoring clause sizes after deletion Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 2 +- src/sat/sat_simplifier.cpp | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index b1502d98e..47fc2c27f 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1065,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); diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 2c5059b18..f0b024817 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -351,7 +351,8 @@ namespace sat { break; case 2: s.mk_bin_clause(c[0], c[1], c.is_learned()); - s.del_clause(c, false); + c.restore(sz0); + s.del_clause(c, true); break; default: *it2 = *it; @@ -613,13 +614,9 @@ namespace sat { } } if (j < sz && !r) { - if (s.m_config.m_drat) { - m_dummy.set(c.size(), c.begin(), c.is_learned()); - } c.shrink(j); if (s.m_config.m_drat) { s.m_drat.add(c, true); - s.m_drat.del(*m_dummy.get()); } } return r; @@ -692,6 +689,7 @@ namespace sat { clause_use_list & occurs = m_use_list.get(l); occurs.erase_not_removed(c); m_sub_counter -= occurs.size()/2; + unsigned sz0 = c.size(); if (cleanup_clause(c, true /* clause is in the use lists */)) { // clause was satisfied TRACE("elim_lit", tout << "clause was satisfied\n";); @@ -707,12 +705,12 @@ namespace sat { TRACE("elim_lit", tout << "clause became unit: " << c[0] << "\n";); propagate_unit(c[0]); // propagate_unit will delete c. - // remove_clause(c); break; case 2: TRACE("elim_lit", tout << "clause became binary: " << c[0] << " " << c[1] << "\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())); + m_sub_bin_todo.push_back(bin_clause(c[0], c[1], c.is_learned())); + c.restore(sz0); remove_clause(c); break; default: From 53eaab4709b4402951030bbcde9a5b49d35aa3d1 Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Sat, 12 Jan 2019 17:38:24 +0800 Subject: [PATCH 163/318] dotnet: update build scripts --- .gitignore | 1 + CMakeSettings.json | 17 ----------------- cmake/modules/FindDotnet.cmake | 17 ++++++----------- src/api/dotnet/CMakeLists.txt | 9 +++++---- src/api/dotnet/Microsoft.Z3.csproj.in | 11 ++++++++--- 5 files changed, 20 insertions(+), 35 deletions(-) delete mode 100644 CMakeSettings.json diff --git a/.gitignore b/.gitignore index 9b239a566..88ccbb56f 100644 --- a/.gitignore +++ b/.gitignore @@ -78,3 +78,4 @@ doc/api doc/code .vs examples/**/obj +CMakeSettings.json diff --git a/CMakeSettings.json b/CMakeSettings.json deleted file mode 100644 index f8c4fa7c6..000000000 --- a/CMakeSettings.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "configurations": [ - { - "name": "x64-Release", - "generator": "Visual Studio 15 2017 Win64", - "configurationType": "RelWithDebInfo", - "inheritEnvironments": [ - "msvc_x64_x64" - ], - "buildRoot": "F:\\b\\z3\\build\\${name}", - "installRoot": "F:\\b\\z3\\install\\${name}", - "cmakeCommandArgs": "", - "buildCommandArgs": "", - "ctestCommandArgs": "" - } - ] -} \ No newline at end of file diff --git a/cmake/modules/FindDotnet.cmake b/cmake/modules/FindDotnet.cmake index 4bcfe2215..bc53bf9df 100644 --- a/cmake/modules/FindDotnet.cmake +++ b/cmake/modules/FindDotnet.cmake @@ -95,7 +95,7 @@ # - 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 build root directory (overridden by OUTPUT_PATH). Therefore, projects built without cmake will consistently output +# - 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. # @@ -203,7 +203,7 @@ FUNCTION(DOTNET_GET_DEPS _DN_PROJECT arguments) ENDIF() IF(NOT _DN_CONFIG) - SET(_DN_CONFIG Release) + SET(_DN_CONFIG $,Debug,Release>) ENDIF() # If platform is not specified, do not pass the Platform property. @@ -226,7 +226,7 @@ FUNCTION(DOTNET_GET_DEPS _DN_PROJECT arguments) SET(_DN_VERSION "1.0.0") ENDIF() - # Set the output path to the current binary directory. + # 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. @@ -234,7 +234,7 @@ FUNCTION(DOTNET_GET_DEPS _DN_PROJECT arguments) SET(_DN_OUTPUT_PATH ${_DN_projname_noext}) ENDIF() - GET_FILENAME_COMPONENT(_DN_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/${_DN_OUTPUT_PATH} ABSOLUTE) + 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. @@ -328,16 +328,11 @@ MACRO(DOTNET_BUILD_COMMANDS) 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})") - SET(_DN_OUTPUTS "") FOREACH(pkg ${DOTNET_PACKAGES}) - LIST(APPEND _DN_OUTPUTS ${DOTNET_OUTPUT_PATH}/${pkg}.${DOTNET_PACKAGE_VERSION}.nupkg) - LIST(APPEND DOTNET_OUTPUTS ${CMAKE_BINARY_DIR}/${pkg}.${DOTNET_PACKAGE_VERSION}.nupkg) - - LIST(APPEND _DN_OUTPUTS ${DOTNET_OUTPUT_PATH}/${pkg}.${DOTNET_PACKAGE_VERSION}.symbols.nupkg) - LIST(APPEND DOTNET_OUTPUTS ${CMAKE_BINARY_DIR}/${pkg}.${DOTNET_PACKAGE_VERSION}.symbols.nupkg) + 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) 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}) - LIST(APPEND build_dotnet_cmds COMMAND ${CMAKE_COMMAND} -E copy ${_DN_OUTPUTS} ${CMAKE_BINARY_DIR}) ELSE() MESSAGE("-- Adding ${build_dotnet_type} project ${DOTNET_PROJPATH} (no nupkg)") ENDIF() diff --git a/src/api/dotnet/CMakeLists.txt b/src/api/dotnet/CMakeLists.txt index b9e26ec9e..26991bee7 100644 --- a/src/api/dotnet/CMakeLists.txt +++ b/src/api/dotnet/CMakeLists.txt @@ -139,8 +139,10 @@ endforeach() # And thus we can put the conditional properties in the project file. # Note, nuget package file names do not have the ${VER_REV} part. -# TODO how to receive "configuration" and "platform" from here? set(Z3_DOTNET_NUPKG_VERSION "${VER_MAJOR}.${VER_MINOR}.${VER_BUILD}") + +# TODO conditional for signing. we can then enable the ``Release_delaysign`` configuration + 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} @@ -163,10 +165,9 @@ add_custom_target(build_z3_dotnet_bindings ALL DEPENDS BUILD_Microsoft.Z3) option(INSTALL_DOTNET_BINDINGS "Install .NET bindings when invoking install target" ON) if(INSTALL_DOTNET_BINDINGS) - install(FILES "${CMAKE_BINARY_DIR}/Microsoft.Z3.${Z3_DOTNET_NUPKG_VERSION}.nupkg" DESTINATION "${CMAKE_INSTALL_LIBDIR}/z3.nuget") + install(FILES "${CMAKE_BINARY_DIR}/Microsoft.Z3/Microsoft.Z3.${Z3_DOTNET_NUPKG_VERSION}.nupkg" DESTINATION "${CMAKE_INSTALL_LIBDIR}/z3.nuget") install(CODE "include(${CMAKE_CURRENT_LIST_DIR}/../../../cmake/modules/FindDotnet.cmake)\n DOTNET_REGISTER_LOCAL_REPOSITORY(Microsoft.Z3.LocalBuild ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/z3.nuget)") -# TODO docs? -# install(FILES "${Z3_DOTNET_ASSEMBLY_DLL_DOC}" DESTINATION "${CMAKE_INSTALL_LIBDIR}") + 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}") diff --git a/src/api/dotnet/Microsoft.Z3.csproj.in b/src/api/dotnet/Microsoft.Z3.csproj.in index 34321e90b..5af2ac5f3 100644 --- a/src/api/dotnet/Microsoft.Z3.csproj.in +++ b/src/api/dotnet/Microsoft.Z3.csproj.in @@ -12,7 +12,7 @@ Z3 - .NET Interface to the Z3 Theorem Prover + Z3 is a satisfiability modulo theories solver from Microsoft Research. .NET Interface to the Z3 Theorem Prover Copyright (C) 2006-2019 Microsoft Corporation @@ -28,17 +28,22 @@ @VER_MAJOR@.@VER_MINOR@.@VER_BUILD@.@VER_REVISION@ ${DOTNET_PACKAGE_VERSION} + smt constraint solver theorem prover + + Microsoft + Microsoft - + false - false DELAYSIGN + true + true From e5f65263bb4989773f9b5b3d370cce1d557aaba1 Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Sat, 12 Jan 2019 19:22:38 +0800 Subject: [PATCH 164/318] dotnet: reigster local repo for nupkg --- src/api/dotnet/CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/api/dotnet/CMakeLists.txt b/src/api/dotnet/CMakeLists.txt index 26991bee7..77f5bbc16 100644 --- a/src/api/dotnet/CMakeLists.txt +++ b/src/api/dotnet/CMakeLists.txt @@ -157,6 +157,10 @@ add_dependencies(BUILD_Microsoft.Z3 libz3) # Convenient top-level target 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: register a local nuget repo and install our package. # the build step depends on the 'purge' target, making sure that @@ -166,7 +170,8 @@ option(INSTALL_DOTNET_BINDINGS "Install .NET bindings when invoking install targ if(INSTALL_DOTNET_BINDINGS) install(FILES "${CMAKE_BINARY_DIR}/Microsoft.Z3/Microsoft.Z3.${Z3_DOTNET_NUPKG_VERSION}.nupkg" DESTINATION "${CMAKE_INSTALL_LIBDIR}/z3.nuget") - install(CODE "include(${CMAKE_CURRENT_LIST_DIR}/../../../cmake/modules/FindDotnet.cmake)\n DOTNET_REGISTER_LOCAL_REPOSITORY(Microsoft.Z3.LocalBuild ${CMAKE_INSTALL_PREFIX}/${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") From 3767c311aa58c0d6c17d75f823abff93544ebd90 Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Sat, 12 Jan 2019 19:35:08 +0800 Subject: [PATCH 165/318] FindDotnet: generator expression IF is not available for older cmake versions --- cmake/modules/FindDotnet.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/modules/FindDotnet.cmake b/cmake/modules/FindDotnet.cmake index bc53bf9df..615962f19 100644 --- a/cmake/modules/FindDotnet.cmake +++ b/cmake/modules/FindDotnet.cmake @@ -203,7 +203,7 @@ FUNCTION(DOTNET_GET_DEPS _DN_PROJECT arguments) ENDIF() IF(NOT _DN_CONFIG) - SET(_DN_CONFIG $,Debug,Release>) + SET(_DN_CONFIG "$<$:Debug>$<$>:Release>") ENDIF() # If platform is not specified, do not pass the Platform property. From 4b3189f3e2094a71c63e4204083c5e9258088e19 Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Sat, 12 Jan 2019 20:04:44 +0800 Subject: [PATCH 166/318] dotnet: identifies arch-specific native libraries --- src/api/dotnet/CMakeLists.txt | 5 +++++ src/api/dotnet/Microsoft.Z3.csproj.in | 2 +- src/api/dotnet/Microsoft.Z3.props | 3 ++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/api/dotnet/CMakeLists.txt b/src/api/dotnet/CMakeLists.txt index 77f5bbc16..cf40170cd 100644 --- a/src/api/dotnet/CMakeLists.txt +++ b/src/api/dotnet/CMakeLists.txt @@ -140,6 +140,11 @@ endforeach() # 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() + set(Z3_DOTNET_PLATFORM "Any CPU") +endif() # TODO conditional for signing. we can then enable the ``Release_delaysign`` configuration diff --git a/src/api/dotnet/Microsoft.Z3.csproj.in b/src/api/dotnet/Microsoft.Z3.csproj.in index 5af2ac5f3..ecae050d7 100644 --- a/src/api/dotnet/Microsoft.Z3.csproj.in +++ b/src/api/dotnet/Microsoft.Z3.csproj.in @@ -76,7 +76,7 @@ ${Z3_DOTNET_COMPILE_ITEMS} - + runtimes\win-x64\native diff --git a/src/api/dotnet/Microsoft.Z3.props b/src/api/dotnet/Microsoft.Z3.props index 290cc5f86..a5db71359 100644 --- a/src/api/dotnet/Microsoft.Z3.props +++ b/src/api/dotnet/Microsoft.Z3.props @@ -9,7 +9,8 @@ $(MSBuildThisFileDirectory)..\ - $(Z3_PACKAGE_PATH)runtimes\win-x64\native\libz3.dll + $(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 From 55f92f3658ce01be3f6b21a2297dd85dcf4b3112 Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Sat, 12 Jan 2019 21:33:09 +0800 Subject: [PATCH 167/318] dotnet: remove stale packages before pack; relay cmake config generator expression into msbuild property.. --- cmake/modules/FindDotnet.cmake | 24 +++++++++++++++--------- src/api/dotnet/CMakeLists.txt | 5 ++++- src/api/dotnet/Microsoft.Z3.csproj.in | 6 +++--- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/cmake/modules/FindDotnet.cmake b/cmake/modules/FindDotnet.cmake index 615962f19..191364858 100644 --- a/cmake/modules/FindDotnet.cmake +++ b/cmake/modules/FindDotnet.cmake @@ -25,7 +25,9 @@ # [DEPENDS depend_nuget_packages... ] # [OUTPUT_PATH output_path relative to cmake binary output dir] # [CUSTOM_BUILDPROPS value....] -# [SOURCES additional_file_dependencies... ]) +# [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 @@ -52,7 +54,9 @@ # [PACKAGE output_nuget_packages... ] # [DEPENDS depend_nuget_packages... ] # [CUSTOM_BUILDPROPS value....] -# [SOURCES additional_file_dependencies... ]) +# [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, @@ -168,7 +172,7 @@ FUNCTION(DOTNET_GET_DEPS _DN_PROJECT arguments) # oneValueArgs "CONFIG;PLATFORM;VERSION;OUTPUT_PATH" # multiValueArgs - "PACKAGE;DEPENDS;ARGUMENTS;OUTPUT;SOURCES;CUSTOM_BUILDPROPS" + "PACKAGE;DEPENDS;ARGUMENTS;PACK_ARGUMENTS;OUTPUT;SOURCES;CUSTOM_BUILDPROPS" # the input arguments ${arguments}) @@ -247,7 +251,7 @@ FUNCTION(DOTNET_GET_DEPS _DN_PROJECT arguments) 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_RUN_ARGUMENTS ${_DN_ARGUMENTS} 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) @@ -273,7 +277,7 @@ FUNCTION(DOTNET_GET_DEPS _DN_PROJECT arguments) 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} PARENT_SCOPE) + SET(DOTNET_PACK_OPTIONS --include-symbols ${_DN_PACK_OPTIONS} ${_DN_PACK_ARGUMENTS} PARENT_SCOPE) ENDFUNCTION() @@ -312,14 +316,14 @@ MACRO(DOTNET_BUILD_COMMANDS) 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}") + 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}) + 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() @@ -331,6 +335,8 @@ MACRO(DOTNET_BUILD_COMMANDS) 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() @@ -378,7 +384,7 @@ FUNCTION(RUN_DOTNET DOTNET_PROJECT) 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_RUN_ARGUMENTS} + 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( @@ -397,7 +403,7 @@ FUNCTION(TEST_DOTNET DOTNET_PROJECT) ENDIF() ADD_TEST(NAME ${DOTNET_PROJNAME} - COMMAND ${DOTNET_EXE} test ${test_framework_args} --results-directory "${CMAKE_BINARY_DIR}" --logger trx ${DOTNET_RUN_ARGUMENTS} + COMMAND ${DOTNET_EXE} test ${test_framework_args} --results-directory "${CMAKE_BINARY_DIR}" --logger trx ${DOTNET_ARGUMENTS} WORKING_DIRECTORY ${DOTNET_OUTPUT_PATH}) ENDFUNCTION() diff --git a/src/api/dotnet/CMakeLists.txt b/src/api/dotnet/CMakeLists.txt index cf40170cd..68f7b9335 100644 --- a/src/api/dotnet/CMakeLists.txt +++ b/src/api/dotnet/CMakeLists.txt @@ -151,11 +151,14 @@ endif() 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) + PACKAGE Microsoft.Z3 + PACK_ARGUMENTS "/p:_DN_CMAKE_CONFIG=$" + ) add_dependencies(BUILD_Microsoft.Z3 libz3) diff --git a/src/api/dotnet/Microsoft.Z3.csproj.in b/src/api/dotnet/Microsoft.Z3.csproj.in index ecae050d7..fc6d6a978 100644 --- a/src/api/dotnet/Microsoft.Z3.csproj.in +++ b/src/api/dotnet/Microsoft.Z3.csproj.in @@ -49,7 +49,7 @@ - netstandard2.0;net461;net45 + netstandard2.0;net45 library True 1701,1702 @@ -77,7 +77,7 @@ ${Z3_DOTNET_COMPILE_ITEMS} - + runtimes\win-x64\native @@ -87,7 +87,7 @@ ${Z3_DOTNET_COMPILE_ITEMS} - + runtimes\win-x86\native From 5e79dba3d6d1fe1bdc7486f9e9d2c4dd9f485675 Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Sun, 13 Jan 2019 00:03:37 +0800 Subject: [PATCH 168/318] dotnet: move example project build to cmake --- contrib/ci/scripts/test_z3_examples_cmake.sh | 4 ++-- examples/dotnet/dotnet.csproj | 2 +- src/api/dotnet/CMakeLists.txt | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/contrib/ci/scripts/test_z3_examples_cmake.sh b/contrib/ci/scripts/test_z3_examples_cmake.sh index 679fc4a69..1e75a5701 100755 --- a/contrib/ci/scripts/test_z3_examples_cmake.sh +++ b/contrib/ci/scripts/test_z3_examples_cmake.sh @@ -88,8 +88,8 @@ if [ "X${PYTHON_BINDINGS}" = "X1" ]; then fi if [ "X${DOTNET_BINDINGS}" = "X1" ]; then - # Build & Run .NET example - run_quiet run_non_native_binding dotnet run -p ${Z3_SRC_DIR}/examples/dotnet/dotnet.csproj + # Run .NET example + run_quiet run_non_native_binding dotnet ${Z3_BUILD_DIR}/dotnet/netcoreapp2.0/dotnet.dll fi if [ "X${JAVA_BINDINGS}" = "X1" ]; then diff --git a/examples/dotnet/dotnet.csproj b/examples/dotnet/dotnet.csproj index 0dc4ee2ec..7776259ea 100644 --- a/examples/dotnet/dotnet.csproj +++ b/examples/dotnet/dotnet.csproj @@ -6,7 +6,7 @@ - + diff --git a/src/api/dotnet/CMakeLists.txt b/src/api/dotnet/CMakeLists.txt index 68f7b9335..db5a53259 100644 --- a/src/api/dotnet/CMakeLists.txt +++ b/src/api/dotnet/CMakeLists.txt @@ -159,6 +159,10 @@ ADD_DOTNET(${CMAKE_CURRENT_BINARY_DIR}/build/Microsoft.Z3.csproj PACKAGE Microsoft.Z3 PACK_ARGUMENTS "/p:_DN_CMAKE_CONFIG=$" ) +ADD_DOTNET(${CMAKE_SOURCE_DIR}/examples/dotnet/dotnet.csproj + PLATFORM ${Z3_DOTNET_PLATFORM} + CUSTOM_BUILDPROPS "${VER_MAJOR}.${VER_MINOR}.${VER_BUILD}" + DEPENDS Microsoft.Z3) add_dependencies(BUILD_Microsoft.Z3 libz3) From 0a6a76734a8321a73e00d1ee0c8078da2c8138c6 Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Sun, 13 Jan 2019 00:08:32 +0800 Subject: [PATCH 169/318] docker: ubuntu 14.04 dotnet source fix --- contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile b/contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile index f6541a2c9..8a4812de2 100644 --- a/contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile +++ b/contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile @@ -26,7 +26,7 @@ RUN apt-get update && \ python2.7 \ python-setuptools -RUN curl -SL https://packages.microsoft.com/config/ubuntu/16.04/packages-microsoft-prod.deb --output packages-microsoft-prod.deb && \ +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 From e4d6aa07dcf1e67a77b60a3152f46641428229f3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 12 Jan 2019 11:05:00 -0800 Subject: [PATCH 170/318] use vectors instead of hash-tables in dimacs serialization to avoid hash-table contention Signed-off-by: Nikolaj Bjorner --- src/sat/sat_drat.cpp | 13 ++++++++++++- src/sat/sat_solver.cpp | 4 ++-- src/tactic/goal.cpp | 23 ++++++++++++----------- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index 608728002..eea88bde7 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -332,10 +332,17 @@ namespace sat { } void drat::verify(unsigned n, literal const* c) { - if (m_check_unsat && !is_drup(n, c) && !is_drat(n, c)) { + 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); @@ -476,6 +483,10 @@ namespace sat { literal lit = c[i]; if (lit != wc.m_l1 && lit != wc.m_l2 && value(lit) != l_false) { wc.m_l2 = lit; + if (m_watches.size() <= (~lit).index()) + { + IF_VERBOSE(0, verbose_stream() << m_watches.size() << " " << lit << " " << (~lit).index() << "\n"); + } m_watches[(~lit).index()].push_back(idx); done = true; } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index c9b535997..43adebb25 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -344,11 +344,11 @@ namespace sat { void solver::mk_bin_clause(literal l1, literal l2, bool learned) { if (find_binary_watch(get_wlist(~l1), ~l2)) { - assign_core(l1, 0, justification(l2)); + assign_core(l1, 0, justification(l1)); return; } if (find_binary_watch(get_wlist(~l2), ~l1)) { - assign_core(l2, 0, justification(l1)); + assign_core(l2, 0, justification(l2)); return; } watched* w0 = find_binary_watch(get_wlist(~l1), l2); diff --git a/src/tactic/goal.cpp b/src/tactic/goal.cpp index dfe63e29a..6444cbc05 100644 --- a/src/tactic/goal.cpp +++ b/src/tactic/goal.cpp @@ -434,7 +434,8 @@ void goal::display_ll(std::ostream & out) const { \brief Assumes that the formula is already in CNF. */ void goal::display_dimacs(std::ostream & out) const { - obj_map expr2var; + unsigned_vector expr2var; + ptr_vector exprs; unsigned num_vars = 0; unsigned num_cls = size(); for (unsigned i = 0; i < num_cls; i++) { @@ -453,10 +454,11 @@ void goal::display_dimacs(std::ostream & out) const { expr * l = lits[j]; if (m().is_not(l)) l = to_app(l)->get_arg(0); - if (expr2var.contains(l)) - continue; - num_vars++; - expr2var.insert(l, num_vars); + 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"; @@ -478,17 +480,16 @@ void goal::display_dimacs(std::ostream & out) const { out << "-"; l = to_app(l)->get_arg(0); } - unsigned id = UINT_MAX; - expr2var.find(l, id); + unsigned id = expr2var[l->get_id()]; SASSERT(id != UINT_MAX); out << id << " "; } out << "0\n"; } - for (auto const& kv : expr2var) { - expr* key = kv.m_key; - if (is_app(key)) - out << "c " << kv.m_value << " " << to_app(key)->get_decl()->get_name() << "\n"; + for (expr* e : exprs) { + if (e && is_app(e)) { + out << "c " << expr2var[e->get_id()] << " " << to_app(e)->get_decl()->get_name() << "\n"; + } } } From f835a3c2b2a959abeca4d4e1b9e19e6d8e31405b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 12 Jan 2019 11:08:35 -0800 Subject: [PATCH 171/318] revert assumption tracking choice in unit literals inferred from binary clauses Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 43adebb25..c9b535997 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -344,11 +344,11 @@ namespace sat { void solver::mk_bin_clause(literal l1, literal l2, bool learned) { if (find_binary_watch(get_wlist(~l1), ~l2)) { - assign_core(l1, 0, justification(l1)); + assign_core(l1, 0, justification(l2)); return; } if (find_binary_watch(get_wlist(~l2), ~l1)) { - assign_core(l2, 0, justification(l2)); + assign_core(l2, 0, justification(l1)); return; } watched* w0 = find_binary_watch(get_wlist(~l1), l2); From dc5e4ca1c5267e78b74951092b7e1de14333eff1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 12 Jan 2019 13:19:09 -0800 Subject: [PATCH 172/318] fix drat generation in asymmetric branch simplification Signed-off-by: Nikolaj Bjorner --- src/sat/sat_asymm_branch.cpp | 20 ++++++++++++++------ src/sat/sat_drat.cpp | 15 ++++++++++++++- src/tactic/goal.cpp | 8 ++++---- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index 941426321..e25a79d5b 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -342,7 +342,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; } @@ -406,12 +409,13 @@ 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()); return false; @@ -430,8 +434,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; } } diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index eea88bde7..110ad3b8a 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -585,8 +585,21 @@ namespace sat { 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_out) { + dump(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); diff --git a/src/tactic/goal.cpp b/src/tactic/goal.cpp index 6444cbc05..8f8b86a65 100644 --- a/src/tactic/goal.cpp +++ b/src/tactic/goal.cpp @@ -480,15 +480,15 @@ void goal::display_dimacs(std::ostream & out) const { out << "-"; l = to_app(l)->get_arg(0); } - unsigned id = expr2var[l->get_id()]; - SASSERT(id != UINT_MAX); - out << id << " "; + SASSERT(exprs[l->get_id()]); + out << expr2var[l->get_id()] << " "; } out << "0\n"; } for (expr* e : exprs) { if (e && is_app(e)) { - out << "c " << expr2var[e->get_id()] << " " << to_app(e)->get_decl()->get_name() << "\n"; + symbol const& n = to_app(e)->get_decl()->get_name(); + out << "c " << expr2var[e->get_id()] << " " << n << "\n"; } } } From 4b35ef29c9b96a150a9edf6dc899c62fb04b7bdf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 13 Jan 2019 01:18:03 -0800 Subject: [PATCH 173/318] fix #2081 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb_rewriter.cpp | 2 +- src/opt/opt_context.cpp | 2 +- src/opt/wmax.cpp | 4 +- src/smt/theory_pb.cpp | 95 +++++++++++++++++++++++--------- src/smt/theory_pb.h | 1 + src/smt/theory_wmaxsat.cpp | 10 ++-- 6 files changed, 78 insertions(+), 36 deletions(-) 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/opt/opt_context.cpp b/src/opt/opt_context.cpp index d23fd5043..50b61a8e2 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -437,7 +437,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; } diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp index ee7f92a23..aa539bc44 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; diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index dea698f3f..25b0bfe03 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -467,7 +467,6 @@ namespace smt { context& ctx = get_context(); ast_manager& m = get_manager(); - TRACE("pb", tout << mk_pp(atom, m) << "\n";); if (ctx.b_internalized(atom)) { return true; } @@ -494,17 +493,25 @@ namespace smt { ctx.set_var_theory(abv, get_id()); literal lit(abv); - if (pb.is_eq(atom)) { - expr_ref_vector args(m); + expr_ref_vector args(m), nargs(m); vector coeffs; - unsigned n = atom->get_num_args(); - for (unsigned i = 0; i < n; ++i) { + rational sum(0); + for (unsigned i = 0; i < num_args; ++i) { args.push_back(atom->get_arg(i)); - coeffs.push_back(pb.get_coeff(atom, i)); + nargs.push_back(::mk_not(m, atom->get_arg(i))); + rational c = pb.get_coeff(atom, i); + coeffs.push_back(c); + sum += c; } - expr_ref le(pb.mk_le(n, coeffs.c_ptr(), args.c_ptr(), pb.get_k(atom)), m); - expr_ref ge(pb.mk_ge(n, coeffs.c_ptr(), args.c_ptr(), pb.get_k(atom)), m); + rational k = pb.get_k(atom); + // ax + by + cz <= k + // <=> + // -ax - by - cz >= -k + // <=> + // a(1-x) + b(1-y) + c(1-z) >= a + b + c - k + expr_ref le(pb.mk_ge(num_args, coeffs.c_ptr(), nargs.c_ptr(), sum - k), m); + expr_ref ge(pb.mk_ge(num_args, coeffs.c_ptr(), args.c_ptr(), k), m); ctx.internalize(le, false); ctx.internalize(ge, false); literal le_lit = ctx.get_literal(le); @@ -540,23 +547,24 @@ namespace smt { } } if (pb.is_at_most_k(atom) || pb.is_le(atom)) { - // turn W <= k into -W >= -k - for (unsigned i = 0; i < args.size(); ++i) { - args[i].second = -args[i].second; - } + IF_VERBOSE(0, verbose_stream() << "***le\n"); k = -k; + for (auto& a : args) { + a.first.neg(); + k += a.second; + } } else { SASSERT(pb.is_at_least_k(atom) || pb.is_ge(atom) || pb.is_eq(atom)); } - TRACE("pb", display(tout, *c, true);); + TRACE("pb", display(tout << "inconsistent: " << ctx.inconsistent() << " ", *c, true);); c->unique(); lbool is_true = c->normalize(); c->prune(); c->post_prune(); - TRACE("pb", display(tout, *c); tout << " := " << lit << "\n";); + TRACE("pb", display(tout, *c); tout << " := " << lit << " " << is_true << "\n";); switch (is_true) { case l_false: lit = ~lit; @@ -584,8 +592,8 @@ namespace smt { // maximal coefficient: scoped_mpz& max_watch = c->m_max_watch; max_watch.reset(); - for (unsigned i = 0; i < args.size(); ++i) { - mpz const& num = args[i].second.to_mpq().numerator(); + for (auto const& a : args) { + mpz const& num = a.second.to_mpq().numerator(); if (m_mpz_mgr.lt(max_watch, num)) { max_watch = num; } @@ -1046,12 +1054,8 @@ namespace smt { } ineq* c = m_var_infos[v].m_ineq; if (c != nullptr) { - if (c->is_ge()) { - assign_ineq(*c, is_true); - } - else { - assign_eq(*c, is_true); - } + VERIFY(c->is_ge()); + assign_ineq(*c, is_true); } ptr_vector* cards = m_var_infos[v].m_lit_cwatch[nlit.sign()]; @@ -1213,7 +1217,7 @@ namespace smt { */ void theory_pb::assign_eq(ineq& c, bool is_true) { SASSERT(c.is_eq()); - + UNREACHABLE(); } @@ -2363,21 +2367,58 @@ namespace smt { } void theory_pb::validate_final_check() { - for (unsigned i = 0; i < m_var_infos.size(); ++i) { - ineq* c = m_var_infos[i].m_ineq; - if (c) { - validate_final_check(*c); + TRACE("pb", tout << "validate " << m_var_infos.size() << "\n";); + for (auto & vi : m_var_infos) { + if (vi.m_ineq) { + validate_final_check(*vi.m_ineq); + } + if (vi.m_card) { + validate_final_check(*vi.m_card); } } } + void theory_pb::validate_final_check(card& c) { + context& ctx = get_context(); + if (ctx.get_assignment(c.lit()) == l_undef) { + TRACE("pb", display(tout << "is undef ", c, true);); + return; + } + if (!ctx.is_relevant(c.lit())) { + TRACE("pb", display(tout << "not relevant ", c, true);); + return; + } + + unsigned sum = 0, maxsum = 0; + for (unsigned i = 0; i < c.size(); ++i) { + switch(ctx.get_assignment(c.lit(i))) { + case l_true: + ++sum; + case l_undef: + ++maxsum; + break; + case l_false: + break; + } + } + TRACE("pb", display(tout << "validate: ", c, true); + tout << "sum: " << sum << " " << maxsum << " "; + tout << ctx.get_assignment(c.lit()) << "\n";); + + SASSERT(sum <= maxsum); + SASSERT((sum >= c.k()) == (ctx.get_assignment(c.lit()) == l_true)); + SASSERT((maxsum < c.k()) == (ctx.get_assignment(c.lit()) == l_false)); + } + void theory_pb::validate_final_check(ineq& c) { context& ctx = get_context(); if (ctx.get_assignment(c.lit()) == l_undef) { + TRACE("pb", tout << c.lit() << " is undef\n";); return; } if (!ctx.is_relevant(c.lit())) { + TRACE("pb", tout << c.lit() << " is not relevant\n";); return; } numeral sum = numeral::zero(), maxsum = numeral::zero(); diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index e7b95bf94..2012c8fa2 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -406,6 +406,7 @@ namespace smt { bool validate_lemma(); void validate_final_check(); void validate_final_check(ineq& c); + void validate_final_check(card& c); void validate_assign(ineq const& c, literal_vector const& lits, literal l) const; void validate_watch(ineq const& c) const; bool validate_unit_propagation(card const& c); diff --git a/src/smt/theory_wmaxsat.cpp b/src/smt/theory_wmaxsat.cpp index 75528a07e..53172b07e 100644 --- a/src/smt/theory_wmaxsat.cpp +++ b/src/smt/theory_wmaxsat.cpp @@ -103,8 +103,8 @@ namespace smt { m_normalize = true; bool_var bv = register_var(var, true); (void)bv; - TRACE("opt", tout << "enable: v" << m_bool2var[bv] << " b" << bv << " " << mk_pp(var, get_manager()) << "\n"; - tout << wfml << "\n";); + TRACE("opt", tout << "inc: " << ctx.inconsistent() << " enable: v" << m_bool2var[bv] + << " b" << bv << " " << mk_pp(var, get_manager()) << "\n" << wfml << "\n";); return var; } @@ -134,8 +134,10 @@ namespace smt { theory_var v = mk_var(x); ctx.attach_th_var(x, this, v); m_bool2var.insert(bv, v); - SASSERT(v == static_cast(m_var2bool.size())); - m_var2bool.push_back(bv); + while (m_var2bool.size() <= static_cast(v)) { + m_var2bool.push_back(null_bool_var); + } + m_var2bool[v] = bv; SASSERT(ctx.bool_var2enode(bv)); } return bv; From 4159b987cea41450027e1590f339729f42005d49 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 13 Jan 2019 03:23:57 -0800 Subject: [PATCH 174/318] purge unused code from theory_pb, fix bug reported by Mark Dunlop Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 6 +- src/smt/params/smt_params_helper.pyg | 2 - src/smt/params/theory_pb_params.cpp | 6 +- src/smt/params/theory_pb_params.h | 6 +- src/smt/theory_pb.cpp | 298 ++------------------------- src/smt/theory_pb.h | 19 -- 6 files changed, 18 insertions(+), 319 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 75a42886c..86eab4eea 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); @@ -698,8 +699,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; @@ -833,7 +833,7 @@ public: void commit_assignment() override { if (m_found_feasible_optimum) { - TRACE("opt", tout << "Committing feasible solution\n" << m_defs << " " << m_asms;); + TRACE("opt", tout << "Committing feasible solution\ndefs:" << m_defs << "\nasms:" << m_asms << "\n";); add(m_defs); add(m_asms); } diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 6b4aee1c3..53249e1f0 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -58,8 +58,6 @@ def_module_params(module_name='smt', ('arith.auto_config_simplex', BOOL, False, 'force simplex solver in auto_config'), ('pb.conflict_frequency', UINT, 1000, 'conflict frequency for Pseudo-Boolean theory'), ('pb.learn_complements', BOOL, True, 'learn complement literals for Pseudo-Boolean theory'), - ('pb.enable_compilation', BOOL, True, 'enable compilation into sorting circuits for Pseudo-Boolean'), - ('pb.enable_simplex', BOOL, False, 'enable simplex to check rational feasibility'), ('array.weak', BOOL, False, 'weak array theory'), ('array.extensional', BOOL, True, 'extensional array theory'), ('dack', UINT, 1, '0 - disable dynamic ackermannization, 1 - expand Leibniz\'s axiom if a congruence is the root of a conflict, 2 - expand Leibniz\'s axiom if a congruence is used during conflict resolution'), diff --git a/src/smt/params/theory_pb_params.cpp b/src/smt/params/theory_pb_params.cpp index b285429d9..45a6ede10 100644 --- a/src/smt/params/theory_pb_params.cpp +++ b/src/smt/params/theory_pb_params.cpp @@ -23,8 +23,6 @@ void theory_pb_params::updt_params(params_ref const & _p) { smt_params_helper p(_p); m_pb_conflict_frequency = p.pb_conflict_frequency(); m_pb_learn_complements = p.pb_learn_complements(); - m_pb_enable_compilation = p.pb_enable_compilation(); - m_pb_enable_simplex = p.pb_enable_simplex(); } #define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; @@ -32,6 +30,4 @@ void theory_pb_params::updt_params(params_ref const & _p) { void theory_pb_params::display(std::ostream & out) const { DISPLAY_PARAM(m_pb_conflict_frequency); DISPLAY_PARAM(m_pb_learn_complements); - DISPLAY_PARAM(m_pb_enable_compilation); - DISPLAY_PARAM(m_pb_enable_simplex); -} \ No newline at end of file +} diff --git a/src/smt/params/theory_pb_params.h b/src/smt/params/theory_pb_params.h index 9bfd262c4..98c190b33 100644 --- a/src/smt/params/theory_pb_params.h +++ b/src/smt/params/theory_pb_params.h @@ -25,13 +25,9 @@ Revision History: struct theory_pb_params { unsigned m_pb_conflict_frequency; bool m_pb_learn_complements; - bool m_pb_enable_compilation; - bool m_pb_enable_simplex; theory_pb_params(params_ref const & p = params_ref()): m_pb_conflict_frequency(1000), - m_pb_learn_complements(true), - m_pb_enable_compilation(true), - m_pb_enable_simplex(false) + m_pb_learn_complements(true) {} void updt_params(params_ref const & p); diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 25b0bfe03..03f4b62c3 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -158,8 +158,6 @@ namespace smt { m_watch_sz = 0; m_watch_sum.reset(); m_num_propagations = 0; - m_compilation_threshold = UINT_MAX; - m_compiled = l_false; m_args[0].reset(); m_args[0].m_k.reset(); m_args[1].reset(); @@ -430,10 +428,6 @@ namespace smt { void theory_pb::card::inc_propagations(theory_pb& th) { ++m_num_propagations; - if (m_compiled == l_false && m_num_propagations >= m_compilation_threshold) { - // m_compiled = l_undef; - // th.m_to_compile.push_back(&c); - } } // ------------------------ @@ -443,8 +437,6 @@ namespace smt { theory(m.mk_family_id("pb")), m_params(p), pb(m), - m_max_compiled_coeff(rational(8)), - m_cardinality_lemma(false), m_restart_lim(3), m_restart_inc(0), m_antecedent_exprs(m), @@ -452,7 +444,6 @@ namespace smt { { m_learn_complements = p.m_pb_learn_complements; m_conflict_frequency = p.m_pb_conflict_frequency; - m_enable_compilation = p.m_pb_enable_compilation; } theory_pb::~theory_pb() { @@ -529,7 +520,6 @@ namespace smt { numeral& k = c->m_args[0].m_k; arg_t& args = c->m_args[0]; - // extract literals and coefficients. for (unsigned i = 0; i < num_args; ++i) { expr* arg = atom->get_arg(i); @@ -546,28 +536,23 @@ namespace smt { break; } } + if (pb.is_at_most_k(atom) || pb.is_le(atom)) { - IF_VERBOSE(0, verbose_stream() << "***le\n"); k = -k; for (auto& a : args) { a.first.neg(); k += a.second; } } - else { - SASSERT(pb.is_at_least_k(atom) || pb.is_ge(atom) || pb.is_eq(atom)); - } - TRACE("pb", display(tout << "inconsistent: " << ctx.inconsistent() << " ", *c, true);); c->unique(); lbool is_true = c->normalize(); c->prune(); c->post_prune(); - TRACE("pb", display(tout, *c); tout << " := " << lit << " " << is_true << "\n";); switch (is_true) { case l_false: - lit = ~lit; + lit.neg(); // fall-through case l_true: ctx.mk_th_axiom(get_id(), 1, &lit); @@ -599,25 +584,6 @@ namespace smt { } } - // pre-compile threshold for cardinality - bool enable_compile = m_enable_compilation && c->is_ge() && !c->k().is_one(); - for (unsigned i = 0; enable_compile && i < args.size(); ++i) { - enable_compile = (args[i].second <= m_max_compiled_coeff); - } - if (enable_compile) { - unsigned log = 1, n = 1; - while (n <= args.size()) { - ++log; - n *= 2; - } - unsigned th = args.size()*log*log; - c->m_compilation_threshold = th; - IF_VERBOSE(2, verbose_stream() << "(smt.pb setting compilation threshold to " << th << ")\n";); - TRACE("pb", tout << "compilation threshold: " << th << "\n";); - } - else { - c->m_compilation_threshold = UINT_MAX; - } init_watch_ineq(*c); init_watch(abv); m_var_infos[abv].m_ineq = c; @@ -1007,9 +973,6 @@ namespace smt { st.update("pb conflicts", m_stats.m_num_conflicts); st.update("pb propagations", m_stats.m_num_propagations); st.update("pb predicates", m_stats.m_num_predicates); - st.update("pb compilations", m_stats.m_num_compiles); - st.update("pb compiled clauses", m_stats.m_num_compiled_clauses); - st.update("pb compiled vars", m_stats.m_num_compiled_vars); } void theory_pb::reset_eh() { @@ -1022,8 +985,6 @@ namespace smt { m_card_trail.reset(); m_card_lim.reset(); m_stats.reset(); - m_to_compile.reset(); - m_cardinality_lemma = false; } void theory_pb::new_eq_eh(theory_var v1, theory_var v2) { @@ -1372,31 +1333,9 @@ namespace smt { void theory_pb::inc_propagations(ineq& c) { ++c.m_num_propagations; - if (c.m_compiled == l_false && c.m_num_propagations >= c.m_compilation_threshold) { - c.m_compiled = l_undef; - m_to_compile.push_back(&c); - } } void theory_pb::restart_eh() { - for (unsigned i = 0; i < m_to_compile.size(); ++i) { - compile_ineq(*m_to_compile[i]); - } - m_to_compile.reset(); - - return; - - if (m_restart_lim <= m_restart_inc) { - m_restart_inc = 0; - if (gc()) { - m_restart_lim = 3; - } - else { - m_restart_lim *= 4; - m_restart_lim /= 3; - } - } - ++m_restart_inc; } bool theory_pb::gc() { @@ -1461,76 +1400,6 @@ namespace smt { } - void theory_pb::compile_ineq(ineq& c) { - ++m_stats.m_num_compiles; - context& ctx = get_context(); - // only cardinality constraints are compiled. - SASSERT(c.m_compilation_threshold < UINT_MAX); - DEBUG_CODE(for (unsigned i = 0; i < c.size(); ++i) SASSERT(c.coeff(i).is_int()); ); - unsigned k = c.k().get_unsigned(); - unsigned num_args = c.size(); - - - literal thl = c.lit(); - literal at_least_k; - - literal_vector in; - for (unsigned i = 0; i < num_args; ++i) { - rational n = c.coeff(i); - literal lit = c.lit(i); - lbool val = ctx.get_assignment(lit); - if (val != l_undef && ctx.get_assign_level(lit) == ctx.get_base_level()) { - if (val == l_true) { - unsigned m = n.get_unsigned(); - if (k < m) { - return; - } - k -= m; - } - continue; - } - while (n.is_pos()) { - in.push_back(c.lit(i)); - n -= rational::one(); - } - } - - TRACE("pb", tout << in << " >= " << k << "\n";); - - - psort_expr ps(ctx, *this); - psort_nw sortnw(ps); - sortnw.m_stats.reset(); - - if (ctx.get_assignment(thl) == l_true && - ctx.get_assign_level(thl) == ctx.get_base_level()) { - at_least_k = sortnw.ge(false, k, in.size(), in.c_ptr()); - TRACE("pb", tout << ~thl << " " << at_least_k << "\n";); - ctx.mk_clause(~thl, at_least_k, justify(~thl, at_least_k)); - } - else { - literal at_least_k = sortnw.ge(true, k, in.size(), in.c_ptr()); - TRACE("pb", tout << ~thl << " " << at_least_k << "\n";); - ctx.mk_clause(~thl, at_least_k, justify(~thl, at_least_k)); - ctx.mk_clause(~at_least_k, thl, justify(thl, ~at_least_k)); - } - m_stats.m_num_compiled_vars += sortnw.m_stats.m_num_compiled_vars; - m_stats.m_num_compiled_clauses += sortnw.m_stats.m_num_compiled_clauses; - - IF_VERBOSE(2, verbose_stream() - << "(smt.pb compile sorting network bound: " - << k << " literals: " << in.size() - << " clauses: " << sortnw.m_stats.m_num_compiled_clauses - << " vars: " << sortnw.m_stats.m_num_compiled_vars << ")\n";); - - // auxiliary clauses get removed when popping scopes. - // we have to recompile the circuit after back-tracking. - c.m_compiled = l_false; - ctx.push_trail(value_trail(c.m_compiled)); - c.m_compiled = l_true; - } - - void theory_pb::init_search_eh() { } @@ -1550,7 +1419,6 @@ namespace smt { clear_watch(*c); m_var_infos[v].m_ineq = nullptr; m_ineqs_trail.pop_back(); - m_to_compile.erase(c); dealloc(c); } m_ineqs_lim.resize(new_lim); @@ -1869,82 +1737,6 @@ namespace smt { return true; } - void theory_pb::add_cardinality_lemma() { - context& ctx = get_context(); - normalize_active_coeffs(); - int s = 0; - int new_bound = 0; - if (!init_arg_max()) { - return; - } - // TBD: can be optimized - while (s < m_bound) { - int coeff; - int arg = arg_max(coeff); - if (arg == -1) break; - s += coeff; - ++new_bound; - } - int slack = m_active_coeffs.empty() ? m_bound : (std::min(m_bound, static_cast(m_active_coeffs[0]) - 1)); - reset_arg_max(); - - while (slack > 0) { - bool found = false; - int v = 0; - int coeff = 0; - for (unsigned i = 0; !found && i < m_active_vars.size(); ++i) { - bool_var v = m_active_vars[i]; - coeff = get_abs_coeff(v); - if (0 < coeff && coeff < slack) { - found = true; - } - } - if (!found) { - break; - } - slack -= coeff; - m_coeffs[v] = 0; // deactivate coefficient. - } - for (unsigned i = 0; i < m_active_vars.size(); ++i) { - bool_var v = m_active_vars[i]; - int coeff = get_coeff(v); - if (coeff < 0) { - m_coeffs[v] = -1; - } - else if (coeff > 0) { - m_coeffs[v] = 1; - } - } - - m_bound = new_bound; - if (!validate_lemma()) { - return; - } - SASSERT(m_bound > 0); - if (m_bound > static_cast(m_active_vars.size())) { - return; - } - if (m_bound == static_cast(m_active_vars.size())) { - return; - } - - m_antecedent_exprs.reset(); - m_antecedent_signs.reset(); - m_cardinality_exprs.reset(); - m_cardinality_signs.reset(); - for (unsigned i = 0; i < m_antecedents.size(); ++i) { - literal lit = m_antecedents[i]; - m_antecedent_exprs.push_back(ctx.bool_var2expr(lit.var())); - m_antecedent_signs.push_back(lit.sign()); - } - for (unsigned i = 0; i < m_active_vars.size(); ++i) { - bool_var v = m_active_vars[i]; - m_cardinality_exprs.push_back(ctx.bool_var2expr(v)); - m_cardinality_signs.push_back(get_coeff(v) < 0); - } - m_cardinality_lemma = true; - } - void theory_pb::normalize_active_coeffs() { while (!m_active_var_set.empty()) m_active_var_set.erase(); unsigned i = 0, j = 0, sz = m_active_vars.size(); @@ -2024,48 +1816,9 @@ namespace smt { } } - bool theory_pb::can_propagate() { return m_cardinality_lemma; } + bool theory_pb::can_propagate() { return false; } - void theory_pb::propagate() { - context& ctx = get_context(); - ast_manager& m = get_manager(); - if (!m_cardinality_lemma) { - return; - } - m_cardinality_lemma = false; - if (ctx.inconsistent()) { - return; - } - m_antecedents.reset(); - - for (unsigned i = 0; i < m_antecedent_exprs.size(); ++i) { - expr* a = m_antecedent_exprs[i].get(); - if (!ctx.b_internalized(a)) { - // std::cout << "not internalized " << mk_pp(a, m) << "\n"; - return; - } - m_antecedents.push_back(~literal(ctx.get_bool_var(a), m_antecedent_signs[i])); - } - for (unsigned i = 0; i < m_cardinality_exprs.size(); ++i) { - expr* a = m_cardinality_exprs[i].get(); - if (!ctx.b_internalized(a)) { - // std::cout << "not internalized " << mk_pp(a, m) << "\n"; - return; - } - if (m_cardinality_signs[i]) { - m_cardinality_exprs[i] = m.mk_not(a); - } - } - app_ref atl(pb.mk_at_least_k(m_cardinality_exprs.size(), m_cardinality_exprs.c_ptr(), m_bound), m); - VERIFY(internalize_card(atl, false)); - bool_var abv = ctx.get_bool_var(atl); - m_antecedents.push_back(literal(abv)); - justification* js = nullptr; - if (proofs_enabled()) { - js = nullptr; - } - ctx.mk_clause(m_antecedents.size(), m_antecedents.c_ptr(), js, CLS_AUX_LEMMA, nullptr); - } + void theory_pb::propagate() { } bool theory_pb::resolve_conflict(card& c, literal_vector const& confl) { @@ -2075,9 +1828,7 @@ namespace smt { context& ctx = get_context(); ast_manager& m = get_manager(); m_conflict_lvl = 0; - m_cardinality_lemma = false; - for (unsigned i = 0; i < confl.size(); ++i) { - literal lit = confl[i]; + for (literal lit : confl) { SASSERT(ctx.get_assignment(lit) == l_false); m_conflict_lvl = std::max(m_conflict_lvl, ctx.get_assign_level(lit)); } @@ -2244,66 +1995,41 @@ namespace smt { slack += get_abs_coeff(v); } -#if 1 - //std::cout << slack << " " << m_bound << "\n"; unsigned i = 0; literal_vector const& alits = ctx.assigned_literals(); literal alit = get_asserting_literal(~conseq); slack -= get_abs_coeff(alit.var()); - for (i = alits.size(); 0 <= slack && i > 0; ) { - --i; + for (i = alits.size(); 0 <= slack && i-- > 0; ) { literal lit = alits[i]; bool_var v = lit.var(); // -3*x >= k if (m_active_var_set.contains(v) && v != alit.var()) { int coeff = get_coeff(v); - //std::cout << coeff << " " << lit << "\n"; if (coeff < 0 && !lit.sign()) { slack += coeff; m_antecedents.push_back(lit); - //std::cout << "ante: " << lit << "\n"; } else if (coeff > 0 && lit.sign()) { slack -= coeff; m_antecedents.push_back(lit); - //std::cout << "ante: " << lit << "\n"; } } } SASSERT(slack < 0); -#else - - literal alit = get_asserting_literal(~conseq); - slack -= get_abs_coeff(alit.var()); - - for (unsigned i = 0; 0 <= slack; ++i) { - SASSERT(i < m_active_vars.size()); - bool_var v = m_active_vars[i]; - literal lit(v, get_coeff(v) < 0); - if (v != alit.var() && ctx.get_assignment(lit) == l_false) { - m_antecedents.push_back(~lit); - slack -= get_abs_coeff(v); - } - if (slack < 0) { - std::cout << i << " " << m_active_vars.size() << "\n"; - } - } -#endif SASSERT(validate_antecedents(m_antecedents)); ctx.assign(alit, ctx.mk_justification(theory_propagation_justification(get_id(), ctx.get_region(), m_antecedents.size(), m_antecedents.c_ptr(), alit, 0, nullptr))); DEBUG_CODE( m_antecedents.push_back(~alit); expr_ref_vector args(m); - for (unsigned i = 0; i < m_antecedents.size(); ++i) { - args.push_back(literal2expr(m_antecedents[i])); + for (literal lit : m_antecedents) { + args.push_back(literal2expr(lit)); } B = m.mk_not(m.mk_and(args.size(), args.c_ptr())); validate_implies(A, B); ); - // add_cardinality_lemma(); return true; } @@ -2446,8 +2172,8 @@ namespace smt { bool theory_pb::validate_antecedents(literal_vector const& lits) { context& ctx = get_context(); - for (unsigned i = 0; i < lits.size(); ++i) { - if (ctx.get_assignment(lits[i]) != l_true) { + for (literal lit : lits) { + if (ctx.get_assignment(lit) != l_true) { return false; } } @@ -2457,7 +2183,9 @@ namespace smt { bool theory_pb::validate_unit_propagation(card const& c) { context& ctx = get_context(); for (unsigned i = c.k(); i < c.size(); ++i) { - VERIFY(ctx.get_assignment(c.lit(i)) == l_false); + if (ctx.get_assignment(c.lit(i)) != l_false) { + return false; + } } return true; } diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 2012c8fa2..6b9b28100 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -97,9 +97,6 @@ namespace smt { unsigned m_num_conflicts; unsigned m_num_propagations; unsigned m_num_predicates; - unsigned m_num_compiles; - unsigned m_num_compiled_vars; - unsigned m_num_compiled_clauses; void reset() { memset(this, 0, sizeof(*this)); } stats() { reset(); } }; @@ -120,8 +117,6 @@ namespace smt { scoped_mpz m_max_sum; // maximal possible sum. scoped_mpz m_min_sum; // minimal possible sum. unsigned m_num_propagations; - unsigned m_compilation_threshold; - lbool m_compiled; ineq(unsynch_mpz_manager& m, literal l, bool is_eq) : m_mpz(m), m_lit(l), m_is_eq(is_eq), @@ -197,8 +192,6 @@ namespace smt { unsigned m_bound; unsigned m_num_propagations; unsigned m_all_propagations; - unsigned m_compilation_threshold; - lbool m_compiled; bool m_aux; public: @@ -207,8 +200,6 @@ namespace smt { m_bound(bound), m_num_propagations(0), m_all_propagations(0), - m_compilation_threshold(0), - m_compiled(l_false), m_aux(is_aux) { SASSERT(bound > 0); @@ -284,13 +275,9 @@ namespace smt { literal_vector m_literals; // temporary vector pb_util pb; stats m_stats; - ptr_vector m_to_compile; // inequalities to compile. unsigned m_conflict_frequency; bool m_learn_complements; - bool m_enable_compilation; - rational m_max_compiled_coeff; - bool m_cardinality_lemma; unsigned m_restart_lim; unsigned m_restart_inc; uint_set m_occs; @@ -352,11 +339,6 @@ namespace smt { literal_vector& get_helpful_literals(ineq& c, bool negate); literal_vector& get_unhelpful_literals(ineq& c, bool negate); - // - // Utilities to compile cardinality - // constraints into a sorting network. - // - void compile_ineq(ineq& c); void inc_propagations(ineq& c); // @@ -391,7 +373,6 @@ namespace smt { void reset_arg_max(); void reset_coeffs(); - void add_cardinality_lemma(); literal get_asserting_literal(literal conseq); bool resolve_conflict(card& c, literal_vector const& conflict_clause); From 46bfcbd4f8231db4b340fb96cda7e50efaea7675 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 13 Jan 2019 03:46:11 -0800 Subject: [PATCH 175/318] fix #2082 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/arith_rewriter.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index a19074c51..d56d37041 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -861,7 +861,8 @@ bool arith_rewriter::divides(expr* num, expr* den, expr_ref& result) { if (m_util.is_numeral(arg, num_r)) num_e = arg; } for (expr* arg : args2) { - if (mark.is_marked(arg)) { + // dont remove divisor on (div (* -1 x) (* -1 y)) because rewriting would diverge. + if (mark.is_marked(arg) && (!m_util.is_numeral(arg, num_r) || !num_r.is_minus_one())) { result = remove_divisor(arg, num, den); return true; } @@ -900,7 +901,14 @@ expr_ref arith_rewriter::remove_divisor(expr* arg, expr* num, expr* den) { expr_ref zero(m_util.mk_int(0), m()); num = args1.empty() ? m_util.mk_int(1) : m_util.mk_mul(args1.size(), args1.c_ptr()); den = args2.empty() ? m_util.mk_int(1) : m_util.mk_mul(args2.size(), args2.c_ptr()); - return expr_ref(m().mk_ite(m().mk_eq(zero, arg), m_util.mk_idiv(zero, zero), m_util.mk_idiv(num, den)), m()); + expr_ref d(m_util.mk_idiv(num, den), m()); + expr_ref nd(m_util.mk_idiv(m_util.mk_uminus(num), m_util.mk_uminus(den)), m()); + return expr_ref(m().mk_ite(m().mk_eq(zero, arg), + m_util.mk_idiv(zero, zero), + m().mk_ite(m_util.mk_ge(arg, zero), + d, + m_util.mk_uminus(nd))), + m()); } void arith_rewriter::flat_mul(expr* e, ptr_buffer& args) { From 8ebde41f3581287c8ea556bf3cccca1c7f505b1b Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Sun, 13 Jan 2019 22:45:05 +0800 Subject: [PATCH 176/318] dotnet: example: copy to binary dir before build --- examples/CMakeLists.txt | 7 +++++++ examples/dotnet/CMakeLists.txt | 15 +++++++++++++++ examples/dotnet/README | 3 +-- src/api/dotnet/CMakeLists.txt | 5 ----- 4 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 examples/dotnet/CMakeLists.txt 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/dotnet/CMakeLists.txt b/examples/dotnet/CMakeLists.txt new file mode 100644 index 000000000..d0cd2bb15 --- /dev/null +++ b/examples/dotnet/CMakeLists.txt @@ -0,0 +1,15 @@ +find_package(Dotnet REQUIRED) + +if("${TARGET_ARCHITECTURE}" STREQUAL "i686") + set(Z3_DOTNET_PLATFORM "x86") +else() + set(Z3_DOTNET_PLATFORM "Any CPU") +endif() + +configure_file(dotnet.csproj dotnet.csproj COPYONLY) +configure_file(program.cs program.cs COPYONLY) + +ADD_DOTNET(${CMAKE_CURRENT_BINARY_DIR}/dotnet.csproj + PLATFORM ${Z3_DOTNET_PLATFORM} + CUSTOM_BUILDPROPS "${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}.${Z3_VERSION_PATCH}" + DEPENDS Microsoft.Z3) 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/src/api/dotnet/CMakeLists.txt b/src/api/dotnet/CMakeLists.txt index db5a53259..4f4230ff2 100644 --- a/src/api/dotnet/CMakeLists.txt +++ b/src/api/dotnet/CMakeLists.txt @@ -159,11 +159,6 @@ ADD_DOTNET(${CMAKE_CURRENT_BINARY_DIR}/build/Microsoft.Z3.csproj PACKAGE Microsoft.Z3 PACK_ARGUMENTS "/p:_DN_CMAKE_CONFIG=$" ) -ADD_DOTNET(${CMAKE_SOURCE_DIR}/examples/dotnet/dotnet.csproj - PLATFORM ${Z3_DOTNET_PLATFORM} - CUSTOM_BUILDPROPS "${VER_MAJOR}.${VER_MINOR}.${VER_BUILD}" - DEPENDS Microsoft.Z3) - add_dependencies(BUILD_Microsoft.Z3 libz3) # Convenient top-level target From 08adc1bf97bc825452c9311f9bdcf0c29453c79e Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Sun, 13 Jan 2019 23:15:40 +0800 Subject: [PATCH 177/318] ... --- examples/dotnet/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/dotnet/CMakeLists.txt b/examples/dotnet/CMakeLists.txt index d0cd2bb15..57a1ba7ac 100644 --- a/examples/dotnet/CMakeLists.txt +++ b/examples/dotnet/CMakeLists.txt @@ -6,8 +6,8 @@ else() set(Z3_DOTNET_PLATFORM "Any CPU") endif() -configure_file(dotnet.csproj dotnet.csproj COPYONLY) -configure_file(program.cs program.cs COPYONLY) +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} From f0f9a16f85ecddc13f16d48247c3f2adf57a97f1 Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Mon, 14 Jan 2019 00:22:51 +0800 Subject: [PATCH 178/318] cmake: dotnet: example: program -> Program --- examples/dotnet/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/dotnet/CMakeLists.txt b/examples/dotnet/CMakeLists.txt index 57a1ba7ac..c89c90f2f 100644 --- a/examples/dotnet/CMakeLists.txt +++ b/examples/dotnet/CMakeLists.txt @@ -7,7 +7,7 @@ else() endif() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/dotnet.csproj dotnet.csproj COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/program.cs program.cs COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Program.cs Program.cs COPYONLY) ADD_DOTNET(${CMAKE_CURRENT_BINARY_DIR}/dotnet.csproj PLATFORM ${Z3_DOTNET_PLATFORM} From 209ebecb867013519ade81445146438fe710ccb4 Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Mon, 14 Jan 2019 00:51:44 +0800 Subject: [PATCH 179/318] cmake: dotnet: example: dotnet.csproj is NETCOREAPP --- examples/dotnet/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/dotnet/CMakeLists.txt b/examples/dotnet/CMakeLists.txt index c89c90f2f..d145a2269 100644 --- a/examples/dotnet/CMakeLists.txt +++ b/examples/dotnet/CMakeLists.txt @@ -11,5 +11,6 @@ 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) From eaa80d5b0211e21bfdd5e36b01ce66b49d5dc54b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 13 Jan 2019 11:33:23 -0800 Subject: [PATCH 180/318] fix test build Signed-off-by: Nikolaj Bjorner --- src/test/theory_pb.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/test/theory_pb.cpp b/src/test/theory_pb.cpp index f0604df73..bff5c3809 100644 --- a/src/test/theory_pb.cpp +++ b/src/test/theory_pb.cpp @@ -36,7 +36,6 @@ class pb_fuzzer { public: pb_fuzzer(ast_manager& m): m(m), rand(0), ctx(m, params), vars(m) { params.m_model = true; - params.m_pb_enable_simplex = true; unsigned N = 3; for (unsigned i = 0; i < N; ++i) { std::stringstream strm; @@ -48,7 +47,6 @@ public: void fuzz() { enable_trace("pb"); - enable_trace("simplex"); unsigned nr = 0; for (unsigned i = 0; i < 100000; ++i) { fuzz_round(nr, 2); From 58e8b2b8d57c217b02f1a9e9da000902b4c7f9c2 Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Mon, 14 Jan 2019 14:02:58 +0800 Subject: [PATCH 181/318] Dockerfile: update ubuntu 14.04 image with cmake 3.12 --- .travis.yml | 2 +- contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 076b3a554..bdd572852 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,7 @@ env: # 64-bit UBSan Debug build - LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/clang-3.9 CXX_COMPILER=/usr/bin/clang++-3.9 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug UBSAN_BUILD=1 RUN_UNIT_TESTS=SKIP # 64-bit ASan Debug build - - LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/clang-3.9 CXX_COMPILER=/usr/bin/clang++-3.9 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug ASAN_BUILD=1 RUN_UNIT_TESTS=SKIP ASAN_DSO=/usr/lib/clang/3.9/lib/linux/libclang_rt.asan-x86_64.so + - LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/clang-3.9 CXX_COMPILER=/usr/bin/clang++-3.9 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug ASAN_BUILD=1 RUN_UNIT_TESTS=SKIP ASAN_DSO=/usr/lib/clang/3.9/lib/linux/libclang_rt.asan-x86_64.so DOTNET_BINDINGS=0 # Build for running unit tests under ASan/UBSan # FIXME: We should really be doing a debug build but the unit tests run too # slowly when we do that. diff --git a/contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile b/contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile index 8a4812de2..9c6bdc054 100644 --- a/contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile +++ b/contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile @@ -5,7 +5,6 @@ RUN apt-get update && \ apt-transport-https \ binutils \ clang-3.9 \ - cmake \ curl \ doxygen \ default-jdk \ @@ -31,6 +30,9 @@ RUN curl -SL https://packages.microsoft.com/config/ubuntu/14.04/packages-microso 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 && \ From 0b84c6088604da58885a4cda2ad9faf94fc157bd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 14 Jan 2019 01:25:25 -0800 Subject: [PATCH 182/318] fix another bug uncovered by Dunlop, prepare grounds for equality solving within NNFs Signed-off-by: Nikolaj Bjorner --- src/ackermannization/ackr_bound_probe.cpp | 2 +- src/ackermannization/ackr_model_converter.cpp | 8 +- src/ackermannization/lackr.cpp | 60 +++--- src/cmd_context/check_logic.cpp | 10 +- src/opt/maxres.cpp | 10 +- src/opt/opt_context.cpp | 3 +- src/opt/optsmt.cpp | 11 +- src/smt/smt_context_pp.cpp | 10 +- src/smt/theory_pb.cpp | 21 +- src/tactic/core/propagate_values_tactic.cpp | 14 -- src/tactic/core/solve_eqs_tactic.cpp | 199 ++++++++++++++++-- src/tactic/smtlogics/qfaufbv_tactic.cpp | 42 ++-- src/tactic/tactic.cpp | 15 +- 13 files changed, 283 insertions(+), 122 deletions(-) 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..a965fc261 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,19 +107,19 @@ 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); @@ -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/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/opt/maxres.cpp b/src/opt/maxres.cpp index 86eab4eea..b507d6f54 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -383,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; @@ -517,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); @@ -847,7 +852,10 @@ public: _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"); + 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);); VERIFY(is_sat == l_false); } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 50b61a8e2..ffb8754a2 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -383,7 +383,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()) { @@ -1604,6 +1604,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) { diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index a461d4a22..7feb8f615 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -171,6 +171,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 +190,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 +223,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; @@ -574,7 +581,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/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index c79068298..20a084c81 100644 --- a/src/smt/smt_context_pp.cpp +++ b/src/smt/smt_context_pp.cpp @@ -567,12 +567,9 @@ namespace smt { case b_justification::AXIOM: out << "axiom"; break; - case b_justification::BIN_CLAUSE: { - literal l2 = j.get_literal(); - out << "bin-clause "; - display_literal(out, l2); + case b_justification::BIN_CLAUSE: + out << "bin " << j.get_literal(); break; - } case b_justification::CLAUSE: { clause * cls = j.get_clause(); out << "clause "; @@ -580,10 +577,9 @@ namespace smt { break; } case b_justification::JUSTIFICATION: { - out << "justification " << j.get_justification()->get_from_theory() << ": "; literal_vector lits; const_cast(*m_conflict_resolution).justification2literals(j.get_justification(), lits); - display_literals(out, lits); + out << "justification " << j.get_justification()->get_from_theory() << ": " << lits; break; } default: diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 03f4b62c3..86d84c60a 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1836,8 +1836,6 @@ namespace smt { return false; } - // std::cout << c.lit() << "\n"; - reset_coeffs(); m_num_marks = 0; m_bound = c.k(); @@ -1936,7 +1934,10 @@ namespace smt { } if (pbj == nullptr) { TRACE("pb", tout << "skip justification for " << conseq << "\n";); - inc_coeff(conseq, offset); + // this is possible when conseq is an assumption. + // The justification of conseq is itself, + // don't increment the cofficient here because it assumes + // conseq is justified further. it isnt'. conseq becomes part of the lemma. } else { card& c2 = pbj->get_card(); @@ -1944,7 +1945,6 @@ namespace smt { bound = c2.k(); } - // std::cout << " offset: " << offset << " bound: " << bound << "\n"; break; } default: @@ -2020,6 +2020,7 @@ namespace smt { SASSERT(slack < 0); SASSERT(validate_antecedents(m_antecedents)); + TRACE("pb", tout << "antecedents " << m_antecedents << "\n";); ctx.assign(alit, ctx.mk_justification(theory_propagation_justification(get_id(), ctx.get_region(), m_antecedents.size(), m_antecedents.c_ptr(), alit, 0, nullptr))); DEBUG_CODE( @@ -2127,7 +2128,7 @@ namespace smt { break; } } - TRACE("pb", display(tout << "validate: ", c, true); + TRACE("pb_verbose", display(tout << "validate: ", c, true); tout << "sum: " << sum << " " << maxsum << " "; tout << ctx.get_assignment(c.lit()) << "\n";); @@ -2215,15 +2216,11 @@ namespace smt { void theory_pb::display_resolved_lemma(std::ostream& out) const { context& ctx = get_context(); - bool_var v; - unsigned lvl; out << "num marks: " << m_num_marks << "\n"; out << "conflict level: " << m_conflict_lvl << "\n"; - for (unsigned i = 0; i < m_resolved.size(); ++i) { - v = m_resolved[i].var(); - lvl = ctx.get_assign_level(v); - out << lvl << ": " << m_resolved[i] << " "; - ctx.display(out, ctx.get_justification(v)); + for (literal r : m_resolved) { + out << ctx.get_assign_level(r) << ": " << r << " "; + ctx.display(out, ctx.get_justification(r.var())); } if (!m_antecedents.empty()) { diff --git a/src/tactic/core/propagate_values_tactic.cpp b/src/tactic/core/propagate_values_tactic.cpp index 14c715f03..f9712120f 100644 --- a/src/tactic/core/propagate_values_tactic.cpp +++ b/src/tactic/core/propagate_values_tactic.cpp @@ -23,7 +23,6 @@ Revision History: #include "ast/ast_smt2_pp.h" #include "ast/expr_substitution.h" #include "tactic/goal_shared_occs.h" -#include "ast/pb_decl_plugin.h" namespace { class propagate_values_tactic : public tactic { @@ -117,23 +116,10 @@ class propagate_values_tactic : public tactic { TRACE("shallow_context_simplifier_bug", tout << mk_ismt2_pp(curr, m) << "\n---->\n" << mk_ismt2_pp(new_curr, m) << "\n";); if (new_curr != curr) { m_modified = true; - //if (has_pb(curr)) - // IF_VERBOSE(0, verbose_stream() << mk_ismt2_pp(curr, m) << "\n---->\n" << mk_ismt2_pp(new_curr, m) << "\n"); } push_result(new_curr, new_pr); } - bool has_pb(expr* e) { - pb_util pb(m); - if (pb.is_ge(e)) return true; - if (m.is_or(e)) { - for (expr* a : *to_app(e)) { - if (pb.is_ge(a)) return true; - } - } - return false; - } - void run(goal_ref const & g, goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); tactic_report report("propagate-values", *g); diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index f665fe509..1ed230886 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -16,14 +16,15 @@ Author: Revision History: --*/ -#include "tactic/tactical.h" #include "ast/rewriter/expr_replacer.h" -#include "tactic/generic_model_converter.h" -#include "ast/occurs.h" #include "util/cooperate.h" -#include "tactic/goal_shared_occs.h" +#include "ast/occurs.h" +#include "ast/ast_util.h" #include "ast/ast_pp.h" #include "ast/pb_decl_plugin.h" +#include "tactic/goal_shared_occs.h" +#include "tactic/tactical.h" +#include "tactic/generic_model_converter.h" class solve_eqs_tactic : public tactic { struct imp { @@ -384,6 +385,20 @@ class solve_eqs_tactic : public tactic { return false; } + + void insert_solution(goal const& g, unsigned idx, expr* f, app* var, expr* def, proof* pr) { + m_vars.push_back(var); + m_candidates.push_back(f); + m_candidate_set.mark(f); + m_candidate_vars.mark(var); + if (m_produce_proofs) { + if (!pr) + pr = g.pr(idx); + else + pr = m().mk_modus_ponens(g.pr(idx), pr); + } + m_subst->insert(var, def, pr, g.dep(idx)); + } /** \brief Start collecting candidates @@ -408,17 +423,7 @@ class solve_eqs_tactic : public tactic { checkpoint(); expr * f = g.form(idx); if (solve(f, var, def, pr)) { - m_vars.push_back(var); - m_candidates.push_back(f); - m_candidate_set.mark(f); - m_candidate_vars.mark(var); - if (m_produce_proofs) { - if (pr == 0) - pr = g.pr(idx); - else - pr = m().mk_modus_ponens(g.pr(idx), pr); - } - m_subst->insert(var, def, pr, g.dep(idx)); + insert_solution(g, idx, f, var, def, pr); } m_num_steps++; } @@ -430,6 +435,163 @@ class solve_eqs_tactic : public tactic { } tout << "\n";); } + + struct nnf_context { + bool m_is_and; + expr_ref_vector m_args; + unsigned m_index; + nnf_context(bool is_and, expr_ref_vector const& args, unsigned idx): + m_is_and(is_and), + m_args(args), + m_index(idx) + {} + }; + + bool is_compatible(goal const& g, unsigned idx, vector const & path, expr* v, expr* eq) { + return is_goal_compatible(g, idx, v, eq) && is_path_compatible(path, v, eq); + } + + bool is_goal_compatible(goal const& g, unsigned idx, expr* v, expr* eq) { + bool all_e = false; + for (unsigned j = 0; j < g.size(); ++j) { + if (j != idx && !check_eq_compat(g.form(j), v, eq, all_e)) { + TRACE("solve_eqs", tout << "occurs goal " << mk_pp(eq, m()) << "\n";); + return false; + } + } + return true; + } + + // + // all_e := all disjunctions contain eq + // + // or, all_e -> skip if all disjunctions contain eq + // or, all_e -> fail if some disjunction contains v but not eq + // or, all_e -> all_e := false if some disjunction does not contain v + // and, all_e -> all_e + // + + bool is_path_compatible(vector const & path, expr* v, expr* eq) { + bool all_e = true; + for (unsigned i = path.size(); i-- > 0; ) { + auto const& p = path[i]; + auto const& args = p.m_args; + if (p.m_is_and && !all_e) { + for (unsigned j = 0; j < args.size(); ++j) { + if (j != p.m_index && occurs(v, args[j])) { + TRACE("solve_eqs", tout << "occurs and " << mk_pp(eq, m()) << " " << mk_pp(args[j], m()) << "\n";); + return false; + } + } + } + else if (!p.m_is_and) { + for (unsigned j = 0; j < args.size(); ++j) { + if (j != p.m_index) { + if (occurs(v, args[j])) { + if (!check_eq_compat(args[j], v, eq, all_e)) { + TRACE("solve_eqs", tout << "occurs or " << mk_pp(eq, m()) << " " << mk_pp(args[j], m()) << "\n";); + return false; + } + } + else { + all_e = false; + } + } + } + } + } + return true; + } + + bool check_eq_compat(expr* f, expr* v, expr* eq, bool& all) { + expr_ref_vector args(m()); + expr* f1 = nullptr; + if (!occurs(v, f)) { + all = false; + return true; + } + if (m().is_not(f, f1) && m().is_or(f1)) { + flatten_and(f, args); + for (expr* arg : args) { + if (arg == eq) { + return true; + } + } + } + else if (m().is_or(f)) { + flatten_or(f, args); + } + else { + return false; + } + + for (expr* arg : args) { + if (!check_eq_compat(arg, v, eq, all)) { + return false; + } + } + return true; + } + + void hoist_nnf(goal const& g, expr* f, vector & path, unsigned idx, unsigned depth) { + if (depth > 4) { + return; + } + app_ref var(m()); + expr_ref def(m()); + proof_ref pr(m()); + expr_ref_vector args(m()); + expr* f1 = nullptr; + + if (m().is_not(f, f1) && m().is_or(f1)) { + flatten_and(f, args); + for (unsigned i = 0; i < args.size(); ++i) { + expr* arg = args.get(i), *lhs = nullptr, *rhs = nullptr; + if (m().is_eq(arg, lhs, rhs)) { + if (trivial_solve1(lhs, rhs, var, def, pr) && is_compatible(g, idx, path, var, arg)) { + insert_solution(g, idx, arg, var, def, pr); + } + else if (trivial_solve1(rhs, lhs, var, def, pr) && is_compatible(g, idx, path, var, arg)) { + insert_solution(g, idx, arg, var, def, pr); + } + else { + IF_VERBOSE(0, + verbose_stream() << "eq not solved " << mk_pp(arg, m()) << "\n"; + verbose_stream() << is_uninterp_const(lhs) << " " << !m_candidate_vars.is_marked(lhs) << " " + << !occurs(lhs, rhs) << " " << check_occs(lhs) << "\n";); + } + } + else { + path.push_back(nnf_context(true, args, i)); + hoist_nnf(g, arg, path, idx, depth + 1); + path.pop_back(); + } + } + } + else if (m().is_or(f)) { + flatten_or(f, args); + //std::cout << "hoist or " << args.size() << "\n"; + for (unsigned i = 0; i < args.size(); ++i) { + path.push_back(nnf_context(false, args, i)); + hoist_nnf(g, args.get(i), path, idx, depth + 1); + path.pop_back(); + } + } + else { + // std::cout << "no hoist " << mk_pp(f, m()) << "\n"; + } + } + + bool collect_hoist(goal const& g) { + bool change = false; + unsigned size = g.size(); + vector path; + for (unsigned idx = 0; idx < size; idx++) { + checkpoint(); + hoist_nnf(g, g.form(idx), path, idx, 0); + } + return change; + } void sort_vars() { SASSERT(m_candidates.size() == m_vars.size()); @@ -564,6 +726,10 @@ class solve_eqs_tactic : public tactic { ++idx; } + IF_VERBOSE(10, + verbose_stream() << "ordered vars: "; + for (app* v : m_ordered_vars) verbose_stream() << mk_pp(v, m()) << " "; + verbose_stream() << "\n";); TRACE("solve_eqs", tout << "ordered vars:\n"; for (app* v : m_ordered_vars) { @@ -756,6 +922,8 @@ class solve_eqs_tactic : public tactic { while (true) { collect_num_occs(*g); collect(*g); + // TBD Disabled until tested more: + // collect_hoist(*g); if (m_subst->empty()) break; sort_vars(); @@ -773,6 +941,7 @@ class solve_eqs_tactic : public tactic { g->inc_depth(); g->add(mc.get()); result.push_back(g.get()); + //IF_VERBOSE(0, g->display(verbose_stream())); TRACE("solve_eqs", g->display(tout);); SASSERT(g->is_well_sorted()); } diff --git a/src/tactic/smtlogics/qfaufbv_tactic.cpp b/src/tactic/smtlogics/qfaufbv_tactic.cpp index b35bc1f20..e3d7ec953 100644 --- a/src/tactic/smtlogics/qfaufbv_tactic.cpp +++ b/src/tactic/smtlogics/qfaufbv_tactic.cpp @@ -24,13 +24,10 @@ Notes: #include "tactic/bv/max_bv_sharing_tactic.h" #include "tactic/bv/bv_size_reduction_tactic.h" #include "tactic/core/ctx_simplify_tactic.h" -#include "sat/tactic/sat_tactic.h" +#include "ackermannization/ackermannize_bv_tactic.h" #include "smt/tactic/smt_tactic.h" -tactic * mk_qfaufbv_tactic(ast_manager & m, params_ref const & p) { - params_ref main_p; - main_p.set_bool("elim_and", true); - main_p.set_bool("sort_store", true); +static tactic * mk_qfaufbv_preamble(ast_manager & m, params_ref const & p) { params_ref simp2_p = p; simp2_p.set_bool("som", true); @@ -39,26 +36,27 @@ tactic * mk_qfaufbv_tactic(ast_manager & m, params_ref const & p) { simp2_p.set_bool("local_ctx", true); simp2_p.set_uint("local_ctx_limit", 10000000); - params_ref ctx_simp_p; - ctx_simp_p.set_uint("max_depth", 32); - ctx_simp_p.set_uint("max_steps", 5000000); - params_ref solver_p; - solver_p.set_bool("array.simplify", false); // disable array simplifications at old_simplify module + return and_then(mk_simplify_tactic(m), + mk_propagate_values_tactic(m), + mk_solve_eqs_tactic(m), + mk_elim_uncnstr_tactic(m), + // sound to use? if_no_proofs(if_no_unsat_cores(mk_reduce_args_tactic(m))), + if_no_proofs(if_no_unsat_cores(mk_bv_size_reduction_tactic(m))), + using_params(mk_simplify_tactic(m), simp2_p), + mk_max_bv_sharing_tactic(m), + if_no_proofs(if_no_unsat_cores(mk_ackermannize_bv_tactic(m, p))) + ); +} - tactic * preamble_st = and_then(mk_simplify_tactic(m), - mk_propagate_values_tactic(m), - // using_params(mk_ctx_simplify_tactic(m), ctx_simp_p), - mk_solve_eqs_tactic(m), - mk_elim_uncnstr_tactic(m), - if_no_proofs(if_no_unsat_cores(mk_bv_size_reduction_tactic(m))), - using_params(mk_simplify_tactic(m), simp2_p), - mk_max_bv_sharing_tactic(m) - ); +tactic * mk_qfaufbv_tactic(ast_manager & m, params_ref const & p) { + params_ref main_p; + main_p.set_bool("elim_and", true); + main_p.set_bool("sort_store", true); - tactic * st = using_params(and_then(preamble_st, - using_params(mk_smt_tactic(m), solver_p)), - main_p); + tactic * preamble_st = mk_qfaufbv_preamble(m, p); + + tactic * st = using_params(and_then(preamble_st, mk_smt_tactic(m)), main_p); st->updt_params(p); return st; diff --git a/src/tactic/tactic.cpp b/src/tactic/tactic.cpp index 4a51c701a..95eeaa251 100644 --- a/src/tactic/tactic.cpp +++ b/src/tactic/tactic.cpp @@ -39,13 +39,14 @@ struct tactic_report::imp { ~imp() { m_watch.stop(); double end_memory = static_cast(memory::get_allocation_size())/static_cast(1024*1024); - verbose_stream() << "(" << m_id - << " :num-exprs " << m_goal.num_exprs() - << " :num-asts " << m_goal.m().get_num_asts() - << " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() - << " :before-memory " << std::fixed << std::setprecision(2) << m_start_memory - << " :after-memory " << std::fixed << std::setprecision(2) << end_memory - << ")" << std::endl; + IF_VERBOSE(0, + verbose_stream() << "(" << m_id + << " :num-exprs " << m_goal.num_exprs() + << " :num-asts " << m_goal.m().get_num_asts() + << " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() + << " :before-memory " << std::fixed << std::setprecision(2) << m_start_memory + << " :after-memory " << std::fixed << std::setprecision(2) << end_memory + << ")" << std::endl); } }; From 43ee345f01e2ecb7b3d93fa90c0a8cc639afde97 Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Tue, 15 Jan 2019 03:06:36 +0900 Subject: [PATCH 183/318] dotnet deps hack for test --- .travis.yml | 2 +- cmake/modules/FindDotnet.cmake | 2 +- contrib/ci/scripts/test_z3_examples_cmake.sh | 8 +++++++- examples/dotnet/CMakeLists.txt | 20 +++++++++++++++++++- src/api/dotnet/CMakeLists.txt | 2 +- 5 files changed, 29 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index bdd572852..12e62ed3d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,7 @@ env: # 64-bit UBSan Debug build - LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/clang-3.9 CXX_COMPILER=/usr/bin/clang++-3.9 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug UBSAN_BUILD=1 RUN_UNIT_TESTS=SKIP # 64-bit ASan Debug build - - LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/clang-3.9 CXX_COMPILER=/usr/bin/clang++-3.9 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug ASAN_BUILD=1 RUN_UNIT_TESTS=SKIP ASAN_DSO=/usr/lib/clang/3.9/lib/linux/libclang_rt.asan-x86_64.so DOTNET_BINDINGS=0 + - LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/clang-3.9 CXX_COMPILER=/usr/bin/clang++-3.9 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug ASAN_BUILD=1 RUN_UNIT_TESTS=SKIP ASAN_DSO=/usr/lib/clang/3.9/lib/linux/libclang_rt.asan-x86_64.so # Build for running unit tests under ASan/UBSan # FIXME: We should really be doing a debug build but the unit tests run too # slowly when we do that. diff --git a/cmake/modules/FindDotnet.cmake b/cmake/modules/FindDotnet.cmake index 191364858..98c5f2079 100644 --- a/cmake/modules/FindDotnet.cmake +++ b/cmake/modules/FindDotnet.cmake @@ -218,7 +218,7 @@ FUNCTION(DOTNET_GET_DEPS _DN_PROJECT arguments) ELSEIF(_DN_X64) SET(_DN_PLATFORM x64) ELSEIF(_DN_ANYCPU) - SET(_DN_PLATFORM "Any CPU") + SET(_DN_PLATFORM "AnyCPU") ENDIF() # If package version is not set, first fallback to DOTNET_PACKAGE_VERSION diff --git a/contrib/ci/scripts/test_z3_examples_cmake.sh b/contrib/ci/scripts/test_z3_examples_cmake.sh index 1e75a5701..a149a1d83 100755 --- a/contrib/ci/scripts/test_z3_examples_cmake.sh +++ b/contrib/ci/scripts/test_z3_examples_cmake.sh @@ -89,7 +89,13 @@ fi if [ "X${DOTNET_BINDINGS}" = "X1" ]; then # Run .NET example - run_quiet run_non_native_binding dotnet ${Z3_BUILD_DIR}/dotnet/netcoreapp2.0/dotnet.dll + 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/examples/dotnet/CMakeLists.txt b/examples/dotnet/CMakeLists.txt index d145a2269..108326f83 100644 --- a/examples/dotnet/CMakeLists.txt +++ b/examples/dotnet/CMakeLists.txt @@ -3,7 +3,7 @@ find_package(Dotnet REQUIRED) if("${TARGET_ARCHITECTURE}" STREQUAL "i686") set(Z3_DOTNET_PLATFORM "x86") else() - set(Z3_DOTNET_PLATFORM "Any CPU") + set(Z3_DOTNET_PLATFORM "AnyCPU") endif() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/dotnet.csproj dotnet.csproj COPYONLY) @@ -14,3 +14,21 @@ ADD_DOTNET(${CMAKE_CURRENT_BINARY_DIR}/dotnet.csproj 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/src/api/dotnet/CMakeLists.txt b/src/api/dotnet/CMakeLists.txt index 4f4230ff2..3ff1a484a 100644 --- a/src/api/dotnet/CMakeLists.txt +++ b/src/api/dotnet/CMakeLists.txt @@ -143,7 +143,7 @@ set(Z3_DOTNET_NUPKG_VERSION "${VER_MAJOR}.${VER_MINOR}.${VER_BUILD}") if("${TARGET_ARCHITECTURE}" STREQUAL "i686") set(Z3_DOTNET_PLATFORM "x86") else() - set(Z3_DOTNET_PLATFORM "Any CPU") + set(Z3_DOTNET_PLATFORM "AnyCPU") endif() # TODO conditional for signing. we can then enable the ``Release_delaysign`` configuration From a686aa7f5628248eb8819dfc96845c25b73c5e19 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 14 Jan 2019 10:56:10 -0800 Subject: [PATCH 184/318] produce binary clauses for DRAT for units produced by probing Signed-off-by: Nikolaj Bjorner --- src/sat/sat_drat.cpp | 4 ---- src/sat/sat_probing.cpp | 12 ++++++++++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index 110ad3b8a..e7b9088d5 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -483,10 +483,6 @@ namespace sat { literal lit = c[i]; if (lit != wc.m_l1 && lit != wc.m_l2 && value(lit) != l_false) { wc.m_l2 = lit; - if (m_watches.size() <= (~lit).index()) - { - IF_VERBOSE(0, verbose_stream() << m_watches.size() << " " << lit << " " << (~lit).index() << "\n"); - } m_watches[(~lit).index()].push_back(idx); done = true; } diff --git a/src/sat/sat_probing.cpp b/src/sat/sat_probing.cpp index 52ab9f9f7..e76a3f7c4 100644 --- a/src/sat/sat_probing.cpp +++ b/src/sat/sat_probing.cpp @@ -65,6 +65,10 @@ namespace sat { if (implied_lits) { for (literal lit : *implied_lits) { if (m_assigned.contains(lit)) { + if (s.m_config.m_drat) { + s.m_drat.add(l, lit, true); + s.m_drat.add(~l, lit, true); + } s.assign(lit, justification()); m_num_assigned++; } @@ -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(lit, justification()); m_num_assigned++; } } From e954f59052fd2aee193527a0503a8b5a8575343b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 14 Jan 2019 13:50:17 -0800 Subject: [PATCH 185/318] ensure that solver objects have timeout/rlimit/ctrl-c exposed as possible parameters Signed-off-by: Nikolaj Bjorner --- src/cmd_context/context_params.cpp | 4 ++-- src/solver/solver.cpp | 9 +++++++++ src/util/params.cpp | 7 ++++++- src/util/params.h | 1 + 4 files changed, 18 insertions(+), 3 deletions(-) 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/solver/solver.cpp b/src/solver/solver.cpp index f8c2f8072..f3c533704 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -217,8 +217,17 @@ void solver::assert_expr(expr* f, expr* t) { assert_expr_core2(fml, a); } +static void insert_ctrl_c(param_descrs & r) { + r.insert("ctrl_c", CPK_BOOL, "enable interrupts from ctrl-c", "false"); +} + + void solver::collect_param_descrs(param_descrs & r) { r.insert("solver.enforce_model_conversion", CPK_BOOL, "(default: false) enforce model conversion when asserting formulas"); + insert_timeout(r); + insert_rlimit(r); + insert_max_memory(r); + insert_ctrl_c(r); } void solver::reset_params(params_ref const & p) { diff --git a/src/util/params.cpp b/src/util/params.cpp index 43f53514a..bfb6095d6 100644 --- a/src/util/params.cpp +++ b/src/util/params.cpp @@ -298,9 +298,14 @@ void insert_produce_proofs(param_descrs & r) { } void insert_timeout(param_descrs & r) { - r.insert("timeout", CPK_UINT, "(default: infty) timeout in milliseconds."); + r.insert("timeout", CPK_UINT, "(default: infty) timeout in milliseconds.", "4294967295"); } +void insert_rlimit(param_descrs & r) { + r.insert("rlimit", CPK_UINT, "default resource limit used for solvers. Unrestricted when set to 0.", "0"); +} + + class params { friend class params_ref; struct value { diff --git a/src/util/params.h b/src/util/params.h index 0a68a9606..5330993c1 100644 --- a/src/util/params.h +++ b/src/util/params.h @@ -139,5 +139,6 @@ void insert_max_steps(param_descrs & r); void insert_produce_models(param_descrs & r); void insert_produce_proofs(param_descrs & r); void insert_timeout(param_descrs & r); +void insert_rlimit(param_descrs & r); #endif From 54a125063b285deafeabd100225894830811a94f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 14 Jan 2019 15:00:25 -0800 Subject: [PATCH 186/318] remove produce interpolants Signed-off-by: Nikolaj Bjorner --- src/cmd_context/basic_cmds.cpp | 11 +---- src/shell/dimacs_frontend.cpp | 77 ++++++++++++++++++++++++++++++---- 2 files changed, 71 insertions(+), 17 deletions(-) diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index 981698db7..80cd6373e 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -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/shell/dimacs_frontend.cpp b/src/shell/dimacs_frontend.cpp index 738566ce2..9a4e65896 100644 --- a/src/shell/dimacs_frontend.cpp +++ b/src/shell/dimacs_frontend.cpp @@ -23,23 +23,35 @@ Revision History: #include "util/rlimit.h" #include "util/gparams.h" #include "sat/dimacs.h" +#include "sat/sat_params.hpp" #include "sat/sat_solver.h" +#include "sat/ba_solver.h" +#include "sat/tactic/goal2sat.h" +#include "ast/reg_decl_plugins.h" +#include "tactic/tactic.h" +#include "tactic/fd_solver/fd_solver.h" + extern bool g_display_statistics; static sat::solver * g_solver = nullptr; static clock_t g_start_time; +static tactic_ref g_tac; +static statistics g_st; static void display_statistics() { clock_t end_time = clock(); + if (g_tac && g_display_statistics) { + g_tac->collect_statistics(g_st); + } if (g_solver && g_display_statistics) { std::cout.flush(); std::cerr.flush(); - statistics st; - g_solver->collect_statistics(st); - st.update("total time", ((static_cast(end_time) - static_cast(g_start_time)) / CLOCKS_PER_SEC)); - st.display_smt2(std::cout); + g_solver->collect_statistics(g_st); + g_st.update("total time", ((static_cast(end_time) - static_cast(g_start_time)) / CLOCKS_PER_SEC)); + g_st.display_smt2(std::cout); } + g_display_statistics = false; } static void on_timeout() { @@ -162,14 +174,63 @@ void verify_solution(char const * file_name) { } } +lbool solve_parallel(sat::solver& s) { + params_ref p = gparams::get_module("sat"); + ast_manager m; + reg_decl_plugins(m); + sat2goal s2g; + ref mc; + atom2bool_var a2b(m); + for (unsigned v = 0; v < s.num_vars(); ++v) { + a2b.insert(m.mk_const(symbol(v), m.mk_bool_sort()), v); + } + goal_ref g = alloc(goal, m); + s2g(s, a2b, p, *g, mc); + + g_tac = mk_parallel_qffd_tactic(m, p); + std::string reason_unknown; + model_ref md; + labels_vec labels; + proof_ref pr(m); + expr_dependency_ref core(m); + lbool r = check_sat(*g_tac, g, md, labels, pr, core, reason_unknown); + switch (r) { + case l_true: + if (gparams::get_ref().get_bool("model_validate", false)) { + // populate the SAT solver with the model obtained from parallel execution. + for (auto const& kv : a2b) { + sat::literal lit; + bool is_true = m.is_true((*md)(kv.m_key)); + lit = sat::literal(kv.m_value, !is_true); + s.mk_clause(1, &lit); + } + // VERIFY(l_true == s.check()); + } + break; + case l_false: + break; + default: + break; + } + display_statistics(); + g_display_statistics = false; + g_tac = nullptr; + return r; +} + unsigned read_dimacs(char const * file_name) { g_start_time = clock(); register_on_timeout_proc(on_timeout); signal(SIGINT, on_ctrl_c); params_ref p = gparams::get_module("sat"); + params_ref par = gparams::get_module("parallel"); p.set_bool("produce_models", true); + sat_params sp(p); reslimit limit; sat::solver solver(p, limit); + if (sp.xor_solver()) { + solver.set_extension(alloc(sat::ba_solver)); + } g_solver = &solver; if (file_name) { @@ -194,13 +255,16 @@ unsigned read_dimacs(char const * file_name) { track_clauses(solver, solver2, assumptions, tracking_clauses); r = g_solver->check(assumptions.size(), assumptions.c_ptr()); } + else if (par.get_bool("enable", false)) { + r = solve_parallel(solver); + } else { r = g_solver->check(); } switch (r) { case l_true: std::cout << "sat\n"; - if (file_name) verify_solution(file_name); + if (file_name && gparams::get_ref().get_bool("model_validate", false)) verify_solution(file_name); display_model(*g_solver); break; case l_undef: @@ -213,7 +277,6 @@ unsigned read_dimacs(char const * file_name) { } break; } - if (g_display_statistics) - display_statistics(); + display_statistics(); return 0; } From ee07008fb9ffe16726d1721dc16382de8a442c12 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 14 Jan 2019 15:04:46 -0800 Subject: [PATCH 187/318] import files from csp Signed-off-by: Nikolaj Bjorner --- src/shell/smtlib_frontend.cpp | 1 - src/util/ema.h | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/shell/smtlib_frontend.cpp b/src/shell/smtlib_frontend.cpp index 7218558fa..0f156bced 100644 --- a/src/shell/smtlib_frontend.cpp +++ b/src/shell/smtlib_frontend.cpp @@ -73,7 +73,6 @@ unsigned read_smtlib2_commands(char const * file_name) { cmd_context ctx; ctx.set_solver_factory(mk_smt_strategic_solver_factory()); - ctx.set_interpolating_solver_factory(mk_smt_solver_factory()); install_dl_cmds(ctx); install_dbg_cmds(ctx); diff --git a/src/util/ema.h b/src/util/ema.h index 5a32e021c..7391d8ea0 100644 --- a/src/util/ema.h +++ b/src/util/ema.h @@ -51,6 +51,10 @@ class ema { m_beta *= 0.5; if (m_beta < m_alpha) m_beta = m_alpha; } + + void set(double x) { + m_value = x; + } }; #endif From b11ec3bfbf2378a8f29f8ae3097e154cfbd4011c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 14 Jan 2019 15:17:42 -0800 Subject: [PATCH 188/318] merge sat_tactic from csp Signed-off-by: Nikolaj Bjorner --- src/sat/tactic/sat_tactic.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/sat/tactic/sat_tactic.cpp b/src/sat/tactic/sat_tactic.cpp index e6369a918..bd100d620 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 { @@ -36,6 +37,7 @@ class sat_tactic : public tactic { m_solver(p, m.limit()), m_params(p) { SASSERT(!m.proofs_enabled()); + updt_params(p); } void operator()(goal_ref const & g, @@ -130,13 +132,20 @@ class sat_tactic : public tactic { lit2asm.insert(kv.m_value.index(), kv.m_key); } } + + void updt_params(params_ref const& p) { + m_solver.updt_params(p); + } + }; + struct scoped_set_imp { sat_tactic * m_owner; scoped_set_imp(sat_tactic * o, imp * i):m_owner(o) { - m_owner->m_imp = i; + m_owner->m_imp = i; + m_owner->updt_params(m_owner->m_params); } ~scoped_set_imp() { @@ -152,6 +161,8 @@ public: sat_tactic(ast_manager & m, params_ref const & p): m_imp(nullptr), m_params(p) { + sat_params p1(p); + m_params.set_bool("xor_solver", p1.xor_solver()); } tactic * translate(ast_manager & m) override { @@ -164,6 +175,9 @@ public: void updt_params(params_ref const & p) override { m_params = p; + sat_params p1(p); + m_params.set_bool("xor_solver", p1.xor_solver()); + if (m_imp) m_imp->updt_params(p); } void collect_param_descrs(param_descrs & r) override { From ed7cac8cc0c90218fddff50bb0972a7bf33436f8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 14 Jan 2019 16:42:13 -0800 Subject: [PATCH 189/318] neatify logging Signed-off-by: Nikolaj Bjorner --- src/sat/sat_asymm_branch.cpp | 6 +- src/sat/sat_solver.cpp | 124 ++++++++++++++++++++++++++++------- src/sat/sat_solver.h | 3 + src/sat/sat_types.h | 3 +- 4 files changed, 109 insertions(+), 27 deletions(-) diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index e25a79d5b..4cec57b57 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -84,11 +84,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(2, 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(2, 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 +98,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(2, if (m_elim_learned_literals > eliml0) verbose_stream() << "(sat-asymm-branch :elim " << m_elim_learned_literals - eliml0 << ")\n";); return m_elim_literals > elim; } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index c9b535997..aa4866a78 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -534,7 +534,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(); @@ -1626,6 +1626,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; @@ -1879,12 +1881,72 @@ namespace sat { 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) { + m_restart_logs++; + if (0 == m_restart_next_out) { + m_restart_next_out = 1; + } + else { + m_restart_next_out = (3*m_restart_next_out)/2 + 1; + } + + 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* 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); } IF_VERBOSE(30, display_status(verbose_stream());); pop_reinit(restart_level(to_base)); @@ -3503,16 +3565,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; @@ -4329,16 +4414,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 3937c67e8..f3fe3eb37 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -421,6 +421,9 @@ 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); bool should_restart() const; void set_next_restart(); diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index 002e49006..7710d62d2 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -220,8 +220,7 @@ 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; } struct dimacs_lit { From f23846059785e9bf4233bb98a5503384f508a2a9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 14 Jan 2019 16:45:04 -0800 Subject: [PATCH 190/318] neatify statistics Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index aa4866a78..66655e2aa 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -4387,24 +4387,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() { From 65bd427e469e6238cd378eed14f9e26a1978ca64 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 14 Jan 2019 16:48:48 -0800 Subject: [PATCH 191/318] neatify statistics Signed-off-by: Nikolaj Bjorner --- src/sat/sat_asymm_branch.cpp | 4 ++-- src/sat/sat_cleaner.cpp | 4 ++-- src/sat/sat_probing.cpp | 2 +- src/sat/sat_scc.cpp | 4 ++-- src/sat/sat_simplifier.cpp | 18 +++++++++--------- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index 4cec57b57..60362363c 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -510,8 +510,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_cleaner.cpp b/src/sat/sat_cleaner.cpp index f0c76b466..afdccc4c2 100644 --- a/src/sat/sat_cleaner.cpp +++ b/src/sat/sat_cleaner.cpp @@ -213,8 +213,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_probing.cpp b/src/sat/sat_probing.cpp index e76a3f7c4..15d8e8e7e 100644 --- a/src/sat/sat_probing.cpp +++ b/src/sat/sat_probing.cpp @@ -267,7 +267,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..e2d05385b 100644 --- a/src/sat/sat_scc.cpp +++ b/src/sat/sat_scc.cpp @@ -251,8 +251,8 @@ namespace sat { } 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 f0b024817..bc92401ff 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -2155,15 +2155,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() { From 161c83795fe697ecbb47c6849e478cc6dc169472 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 15 Jan 2019 08:34:55 -0800 Subject: [PATCH 192/318] remember inconsistent states when cloning Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 66655e2aa..f6a8698f4 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -120,6 +120,11 @@ namespace sat { m_qhead = 0; m_trail.reset(); m_scopes.reset(); + + if (src.inconsistent()) { + set_conflict(justification()); + return; + } // create new vars for (bool_var v = num_vars(); v < src.num_vars(); v++) { From 5328454c7783bc3d8fed6729917b84842fb4d1e6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 15 Jan 2019 08:37:23 -0800 Subject: [PATCH 193/318] const Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index f6a8698f4..61f43fddd 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1922,7 +1922,7 @@ namespace sat { // conflicts restarts learned gc time // decisions clauses units memory int adjust[9] = { -3, -3, -3, -1, -3, -2, -1, -2, -1 }; - char* tag[9] = { ":conflicts ", ":decisions ", ":restarts ", ":clauses/bin ", ":learned/bin ", ":units ", ":gc ", ":memory ", ":time" }; + 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 "; From 3298486136da1ae966998258e6f4db33b3efb45c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 15 Jan 2019 08:40:38 -0800 Subject: [PATCH 194/318] don't reach max conflicts if state is inconsistent Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 61f43fddd..588d57bad 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -3997,7 +3997,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; } From b33f5f879e5cf662b854d9c9e3ff968abdb50f1a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 15 Jan 2019 17:57:11 -0800 Subject: [PATCH 195/318] fix another bug reported by Mark Dunlop Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index ffb8754a2..55b2a33ec 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -854,7 +854,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); @@ -996,13 +999,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)) { From e01a668da0f9a57d096c2f212a2b25d169c4a30a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 16 Jan 2019 02:29:33 -0800 Subject: [PATCH 196/318] coordinate drat with clause removal Signed-off-by: Nikolaj Bjorner --- src/sat/sat_elim_eqs.cpp | 11 +-- src/sat/sat_simplifier.cpp | 142 ++++++++++++++++++------------------- src/sat/sat_simplifier.h | 6 +- src/sat/sat_solver.cpp | 4 +- src/sat/sat_solver.h | 2 +- 5 files changed, 82 insertions(+), 83 deletions(-) diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index 8633f04d3..612c337c8 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -94,7 +94,7 @@ namespace sat { void elim_eqs::drat_delete_clause() { if (m_solver.m_config.m_drat) { - m_solver.m_drat.del(*m_to_delete->get()); + m_solver.m_drat.del(*m_to_delete->get()); } } @@ -172,7 +172,8 @@ namespace sat { if (i < sz) { drat_delete_clause(); - m_solver.del_clause(c, false); + c.set_removed(true); + m_solver.del_clause(c); continue; } @@ -187,13 +188,15 @@ namespace sat { return; case 1: m_solver.assign(c[0], justification()); - m_solver.del_clause(c, false); 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()); - m_solver.del_clause(c, false); drat_delete_clause(); + c.set_removed(true); + m_solver.del_clause(c); break; default: SASSERT(*it == &c); diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index bc92401ff..465618c5f 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -124,24 +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) { @@ -248,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()); @@ -305,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; @@ -332,7 +328,7 @@ namespace sat { } unsigned sz0 = c.size(); - if (cleanup_clause(c, in_use_lists)) { + if (cleanup_clause(c)) { s.del_clause(c); continue; } @@ -347,14 +343,21 @@ namespace sat { return; case 1: s.assign(c[0], justification()); - s.del_clause(c, false); + c.restore(sz0); + s.del_clause(c); break; case 2: s.mk_bin_clause(c[0], c[1], c.is_learned()); c.restore(sz0); - s.del_clause(c, true); + s.del_clause(c); 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()) { @@ -583,7 +586,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; @@ -598,11 +601,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; @@ -615,9 +613,6 @@ namespace sat { } if (j < sz && !r) { c.shrink(j); - if (s.m_config.m_drat) { - s.m_drat.add(c, true); - } } return r; } @@ -666,7 +661,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(); } @@ -689,31 +684,40 @@ namespace sat { clause_use_list & occurs = m_use_list.get(l); occurs.erase_not_removed(c); m_sub_counter -= occurs.size()/2; + unsigned sz0 = c.size(); - if (cleanup_clause(c, true /* clause is in the use lists */)) { + 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()); 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. + // 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())); - c.restore(sz0); remove_clause(c); 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); break; @@ -882,7 +886,7 @@ namespace sat { TRACE("subsumption", tout << "next: " << c << "\n";); if (s.m_trail.size() > m_last_sub_trail_sz) { unsigned sz0 = c.size(); - if (cleanup_clause(c, true /* clause is in the use_lists */)) { + if (cleanup_clause(c)) { remove_clause(c); continue; } @@ -892,9 +896,9 @@ namespace sat { s.set_conflict(justification()); return; case 1: + c.restore(sz0); propagate_unit(c[0]); - // propagate_unit will delete c. - // remove_clause(c); + // unit propagation removes c continue; case 2: TRACE("subsumption", tout << "clause became binary: " << c << "\n";); @@ -904,6 +908,12 @@ namespace sat { 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; } } @@ -1432,19 +1442,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; @@ -1895,17 +1892,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; @@ -1929,11 +1922,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; + } } } @@ -2019,14 +2017,7 @@ namespace sat { 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) { @@ -2035,8 +2026,9 @@ namespace sat { if (!resolve(c1, c2, pos_l, m_new_cls)) 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()); @@ -2070,6 +2062,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; } 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_solver.cpp b/src/sat/sat_solver.cpp index 588d57bad..5fdd05884 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -303,14 +303,14 @@ namespace sat { mk_clause(3, ls, learned); } - void solver::del_clause(clause& c, bool enable_drat) { + void solver::del_clause(clause& c) { if (!c.is_learned()) { m_stats.m_non_learned_generation++; } if (c.frozen()) { --m_num_frozen; } - if (enable_drat && 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); diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index f3fe3eb37..48fc54598 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -232,7 +232,7 @@ namespace sat { void defrag_clauses(); bool should_defrag(); bool memory_pressure(); - void del_clause(clause & c, bool enable_drat = true); + void del_clause(clause & c); clause * mk_clause_core(unsigned num_lits, literal * lits, bool learned); clause * mk_clause_core(literal_vector const& lits) { return mk_clause_core(lits.size(), lits.c_ptr()); } clause * mk_clause_core(unsigned num_lits, literal * lits) { return mk_clause_core(num_lits, lits, false); } From 038971c029c0835e69e1dce5e54359dad585f9ee Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 16 Jan 2019 10:21:56 -0800 Subject: [PATCH 197/318] Revert "api: dotnet: switch to multi-targeting project and modern cmake-dotnet integration." --- .gitignore | 3 - .travis.yml | 3 +- cmake/modules/DotnetImports.props.in | 8 - cmake/modules/FindDotnet.cmake | 471 ------------------ .../z3_base_ubuntu32_16.04.Dockerfile | 5 +- .../z3_base_ubuntu_14.04.Dockerfile | 12 +- .../z3_base_ubuntu_16.04.Dockerfile | 8 +- contrib/ci/scripts/test_z3_examples_cmake.sh | 11 +- examples/CMakeLists.txt | 7 - examples/dotnet/CMakeLists.txt | 34 -- examples/dotnet/README | 3 +- examples/dotnet/dotnet.csproj | 12 - src/api/dotnet/CMakeLists.txt | 190 +++++-- src/api/dotnet/Microsoft.Z3.csproj | 418 ++++++++++++++++ src/api/dotnet/Microsoft.Z3.csproj.in | 95 ---- src/api/dotnet/Microsoft.Z3.props | 23 - src/api/dotnet/Microsoft.Z3.targets | 11 - src/api/dotnet/Properties/AssemblyInfo.cs.in | 38 ++ src/api/dotnet/core/README.txt | 15 + src/api/dotnet/core/core.csproj | 18 + 20 files changed, 645 insertions(+), 740 deletions(-) delete mode 100644 cmake/modules/DotnetImports.props.in delete mode 100644 cmake/modules/FindDotnet.cmake delete mode 100644 examples/dotnet/CMakeLists.txt delete mode 100644 examples/dotnet/dotnet.csproj create mode 100644 src/api/dotnet/Microsoft.Z3.csproj delete mode 100644 src/api/dotnet/Microsoft.Z3.csproj.in delete mode 100644 src/api/dotnet/Microsoft.Z3.props delete mode 100644 src/api/dotnet/Microsoft.Z3.targets create mode 100644 src/api/dotnet/Properties/AssemblyInfo.cs.in create mode 100644 src/api/dotnet/core/README.txt create mode 100644 src/api/dotnet/core/core.csproj diff --git a/.gitignore b/.gitignore index 88ccbb56f..e189a9569 100644 --- a/.gitignore +++ b/.gitignore @@ -76,6 +76,3 @@ src/api/ml/z3.mllib *.bak doc/api doc/code -.vs -examples/**/obj -CMakeSettings.json diff --git a/.travis.yml b/.travis.yml index 12e62ed3d..9ec6132b6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,7 @@ env: # 64-bit UBSan Debug build - LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/clang-3.9 CXX_COMPILER=/usr/bin/clang++-3.9 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug UBSAN_BUILD=1 RUN_UNIT_TESTS=SKIP # 64-bit ASan Debug build - - LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/clang-3.9 CXX_COMPILER=/usr/bin/clang++-3.9 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug ASAN_BUILD=1 RUN_UNIT_TESTS=SKIP ASAN_DSO=/usr/lib/clang/3.9/lib/linux/libclang_rt.asan-x86_64.so + - LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/clang-3.9 CXX_COMPILER=/usr/bin/clang++-3.9 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug ASAN_BUILD=1 RUN_UNIT_TESTS=SKIP ASAN_DSO=/usr/lib/clang/3.9/lib/linux/libclang_rt.asan-x86_64.so # Build for running unit tests under ASan/UBSan # FIXME: We should really be doing a debug build but the unit tests run too # slowly when we do that. @@ -85,7 +85,6 @@ matrix: osx_image: xcode8.3 # Note: Apple Clang does not support OpenMP env: Z3_BUILD_TYPE=RelWithDebInfo USE_OPENMP=0 DOTNET_BINDINGS=0 - script: # Use `travis_wait` when doing LTO builds because this configuration will # have long link times during which it will not show any output which diff --git a/cmake/modules/DotnetImports.props.in b/cmake/modules/DotnetImports.props.in deleted file mode 100644 index 090d46502..000000000 --- a/cmake/modules/DotnetImports.props.in +++ /dev/null @@ -1,8 +0,0 @@ - - - ${_DN_OUTPUT_PATH}/ - ${_DN_XPLAT_LIB_DIR}/ - ${_DN_VERSION} - ${_DN_CUSTOM_BUILDPROPS} - - diff --git a/cmake/modules/FindDotnet.cmake b/cmake/modules/FindDotnet.cmake deleted file mode 100644 index 98c5f2079..000000000 --- a/cmake/modules/FindDotnet.cmake +++ /dev/null @@ -1,471 +0,0 @@ -#.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 6012bb25f..87e3c8d67 100644 --- a/contrib/ci/Dockerfiles/z3_base_ubuntu32_16.04.Dockerfile +++ b/contrib/ci/Dockerfiles/z3_base_ubuntu32_16.04.Dockerfile @@ -32,6 +32,7 @@ RUN apt-get update && \ libomp-dev \ llvm-3.9 \ make \ + mono-devel \ ninja-build \ python3 \ python3-setuptools \ @@ -47,6 +48,4 @@ RUN useradd -m user && \ echo 'user ALL=(root) NOPASSWD: ALL' >> /etc/sudoers USER user WORKDIR /home/user -# 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 +ENV ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-3.9/bin/llvm-symbolizer diff --git a/contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile b/contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile index 9c6bdc054..c963ce255 100644 --- a/contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile +++ b/contrib/ci/Dockerfiles/z3_base_ubuntu_14.04.Dockerfile @@ -2,10 +2,9 @@ FROM ubuntu:14.04 RUN apt-get update && \ apt-get -y --no-install-recommends install \ - apt-transport-https \ binutils \ clang-3.9 \ - curl \ + cmake \ doxygen \ default-jdk \ gcc-multilib \ @@ -19,20 +18,13 @@ 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 f4d9c873a..08686e275 100644 --- a/contrib/ci/Dockerfiles/z3_base_ubuntu_16.04.Dockerfile +++ b/contrib/ci/Dockerfiles/z3_base_ubuntu_16.04.Dockerfile @@ -2,12 +2,10 @@ 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 \ @@ -22,6 +20,7 @@ RUN apt-get update && \ libomp-dev \ llvm-3.9 \ make \ + mono-devel \ ninja-build \ python3 \ python3-setuptools \ @@ -29,11 +28,6 @@ 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 a149a1d83..687efebb4 100755 --- a/contrib/ci/scripts/test_z3_examples_cmake.sh +++ b/contrib/ci/scripts/test_z3_examples_cmake.sh @@ -88,14 +88,11 @@ 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 - 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 + run_quiet run_non_native_binding mono ./dotnet_test.exe fi if [ "X${JAVA_BINDINGS}" = "X1" ]; then diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 5d06029f9..6c50320ed 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -112,10 +112,3 @@ 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/dotnet/CMakeLists.txt b/examples/dotnet/CMakeLists.txt deleted file mode 100644 index 108326f83..000000000 --- a/examples/dotnet/CMakeLists.txt +++ /dev/null @@ -1,34 +0,0 @@ -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 b42156761..3f7e989df 100644 --- a/examples/dotnet/README +++ b/examples/dotnet/README @@ -1,6 +1,7 @@ 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 a .net core 2.0 app. +It will create the executable dotnet_example.exe diff --git a/examples/dotnet/dotnet.csproj b/examples/dotnet/dotnet.csproj deleted file mode 100644 index 7776259ea..000000000 --- a/examples/dotnet/dotnet.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - - Exe - netcoreapp2.0 - - - - - - - diff --git a/src/api/dotnet/CMakeLists.txt b/src/api/dotnet/CMakeLists.txt index 3ff1a484a..20621e4fc 100644 --- a/src/api/dotnet/CMakeLists.txt +++ b/src/api/dotnet/CMakeLists.txt @@ -1,10 +1,12 @@ -find_package(Dotnet REQUIRED) +find_package(DotNetToolchain REQUIRED) # Configure AssemblyInfo.cs set(VER_MAJOR "${Z3_VERSION_MAJOR}") set(VER_MINOR "${Z3_VERSION_MINOR}") set(VER_BUILD "${Z3_VERSION_PATCH}") set(VER_REVISION "${Z3_VERSION_TWEAK}") +set(Z3_DOTNET_ASSEMBLY_INFO_FILE "${CMAKE_CURRENT_BINARY_DIR}/Properties/AssemblyInfo.cs") +configure_file("Properties/AssemblyInfo.cs.in" "${Z3_DOTNET_ASSEMBLY_INFO_FILE}" @ONLY) # Generate Native.cs set(Z3_DOTNET_NATIVE_FILE "${CMAKE_CURRENT_BINARY_DIR}/Native.cs") @@ -125,64 +127,160 @@ endforeach() list(APPEND Z3_DOTNET_ASSEMBLY_SOURCES "${Z3_DOTNET_CONST_FILE}" "${Z3_DOTNET_NATIVE_FILE}" + "${Z3_DOTNET_ASSEMBLY_INFO_FILE}" ) - -# Generate items -set(Z3_DOTNET_COMPILE_ITEMS "") -foreach(csfile ${Z3_DOTNET_ASSEMBLY_SOURCES}) - set(Z3_DOTNET_COMPILE_ITEMS "${Z3_DOTNET_COMPILE_ITEMS}\n ") +# ``csc.exe`` doesn't like UNIX style paths so convert them +# if necessary first to native paths. +set(Z3_DOTNET_ASSEMBLY_SOURCES_NATIVE_PATH "") +foreach (csfile_path ${Z3_DOTNET_ASSEMBLY_SOURCES}) + file(TO_NATIVE_PATH "${csfile_path}" csfile_path_native) + list(APPEND Z3_DOTNET_ASSEMBLY_SOURCES_NATIVE_PATH "${csfile_path_native}") endforeach() - -# 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") +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" + ) else() - set(Z3_DOTNET_PLATFORM "AnyCPU") + message(FATAL_ERROR "Unknown .NET toolchain") endif() -# TODO conditional for signing. we can then enable the ``Release_delaysign`` configuration +# 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" +) -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) +# 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}\"" +) # Convenient top-level target -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}) +add_custom_target(build_z3_dotnet_bindings + ALL + DEPENDS + "${Z3_DOTNET_ASSEMBLY_DLL}" +) ############################################################################### -# 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. +# Install ############################################################################### option(INSTALL_DOTNET_BINDINGS "Install .NET bindings when invoking install target" ON) +set(GAC_PKG_NAME "Microsoft.Z3.Sharp") +set(PREFIX "${CMAKE_INSTALL_PREFIX}") +set(VERSION "${Z3_VERSION}") +set(Z3_DOTNET_PKGCONFIG_FILE "${CMAKE_CURRENT_BINARY_DIR}/Microsoft.Z3.Sharp.pc") +configure_file("Microsoft.Z3.Sharp.pc.in" "${Z3_DOTNET_PKGCONFIG_FILE}" @ONLY) -if(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}") +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") endif() - diff --git a/src/api/dotnet/Microsoft.Z3.csproj b/src/api/dotnet/Microsoft.Z3.csproj new file mode 100644 index 000000000..045c610dd --- /dev/null +++ b/src/api/dotnet/Microsoft.Z3.csproj @@ -0,0 +1,418 @@ + + + + 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 deleted file mode 100644 index fc6d6a978..000000000 --- a/src/api/dotnet/Microsoft.Z3.csproj.in +++ /dev/null @@ -1,95 +0,0 @@ - - - - - - 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 deleted file mode 100644 index a5db71359..000000000 --- a/src/api/dotnet/Microsoft.Z3.props +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - 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 deleted file mode 100644 index 38e56b350..000000000 --- a/src/api/dotnet/Microsoft.Z3.targets +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - %(RecursiveDir)%(FileName)%(Extension) - PreserveNewest - - - - diff --git a/src/api/dotnet/Properties/AssemblyInfo.cs.in b/src/api/dotnet/Properties/AssemblyInfo.cs.in new file mode 100644 index 000000000..e5a85f16f --- /dev/null +++ b/src/api/dotnet/Properties/AssemblyInfo.cs.in @@ -0,0 +1,38 @@ +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/core/README.txt b/src/api/dotnet/core/README.txt new file mode 100644 index 000000000..fa274f72b --- /dev/null +++ b/src/api/dotnet/core/README.txt @@ -0,0 +1,15 @@ +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 new file mode 100644 index 000000000..5fa3275cf --- /dev/null +++ b/src/api/dotnet/core/core.csproj @@ -0,0 +1,18 @@ + + + + netcoreapp1.0 + $(DefineConstants);DOTNET_CORE + portable + Microsoft.Z3 + Library + core + $(PackageTargetFallback);dnxcore50 + 1.0.4 + + + + + + + From 247980c5a28e44ff367ce9a3dbbcfc6a85d73d66 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 16 Jan 2019 11:41:32 -0800 Subject: [PATCH 198/318] don't assign already assigned literals Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 5fdd05884..3c97a985f 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -348,11 +348,11 @@ namespace sat { } void solver::mk_bin_clause(literal l1, literal l2, bool learned) { - if (find_binary_watch(get_wlist(~l1), ~l2)) { + 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)) { + if (find_binary_watch(get_wlist(~l2), ~l1) && value(l2) == l_undef) { assign_core(l2, 0, justification(l1)); return; } From f2e636c598d298ef72a0f21d172bfbbd856ab354 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 16 Jan 2019 16:37:21 -0800 Subject: [PATCH 199/318] record simplified input clauses as lemmas Signed-off-by: Nikolaj Bjorner --- src/sat/sat_cleaner.cpp | 12 ++++-------- src/sat/sat_solver.cpp | 9 ++++++++- src/smt/mam.cpp | 2 +- src/smt/smt_clause.cpp | 20 ++++++++++++++++---- src/smt/smt_clause.h | 6 ++++-- src/smt/smt_context_pp.cpp | 9 ++++++++- src/smt/smt_quantifier.cpp | 19 +++++++++++++------ 7 files changed, 54 insertions(+), 23 deletions(-) diff --git a/src/sat/sat_cleaner.cpp b/src/sat/sat_cleaner.cpp index afdccc4c2..728931f15 100644 --- a/src/sat/sat_cleaner.cpp +++ b/src/sat/sat_cleaner.cpp @@ -78,7 +78,6 @@ namespace sat { } void cleaner::cleanup_clauses(clause_vector & cs) { - tmp_clause tmp; clause_vector::iterator it = cs.begin(); clause_vector::iterator it2 = it; clause_vector::iterator end = cs.end(); @@ -134,10 +133,6 @@ namespace sat { s.del_clause(c); break; default: - SASSERT(s.value(c[0]) == l_undef && s.value(c[1]) == l_undef); - if (s.m_config.m_drat && new_sz < sz) { - tmp.set(c.size(), c.begin(), c.is_learned()); - } c.shrink(new_sz); *it2 = *it; it2++; @@ -145,11 +140,12 @@ namespace sat { s.attach_clause(c); } if (s.m_config.m_drat && new_sz < sz) { - // for optimization, could also report deletion - // of previous version of clause. s.m_drat.add(c, true); - s.m_drat.del(*tmp.get()); + c.restore(sz); + s.m_drat.del(c); + c.shrink(new_sz); } + break; } } } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 3c97a985f..fa1d9352d 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -320,11 +320,18 @@ namespace sat { 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; } @@ -706,7 +713,7 @@ namespace sat { if (curr != prev) { prev = curr; if (i != j) - lits[j] = lits[i]; + std::swap(lits[j], lits[i]); j++; } break; diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index a6b5e5515..836c1dfcc 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -3915,7 +3915,7 @@ namespace smt { SASSERT(bindings[i]->get_generation() <= max_generation); } #endif - unsigned min_gen, max_gen; + unsigned min_gen = 0, max_gen = 0; m_interpreter.get_min_max_top_generation(min_gen, max_gen); m_context.add_instance(qa, pat, num_bindings, bindings, nullptr, max_generation, min_gen, max_gen, used_enodes); } diff --git a/src/smt/smt_clause.cpp b/src/smt/smt_clause.cpp index 2b9b8dd3e..a1f1f9f03 100644 --- a/src/smt/smt_clause.cpp +++ b/src/smt/smt_clause.cpp @@ -19,6 +19,7 @@ Revision History: #include "smt/smt_clause.h" #include "smt/smt_justification.h" #include "ast/ast_ll_pp.h" +#include "ast/ast_pp.h" namespace smt { /** @@ -96,22 +97,33 @@ namespace smt { } } - void clause::display(std::ostream & out, ast_manager & m, expr * const * bool_var2expr_map) const { + std::ostream& clause::display(std::ostream & out, ast_manager & m, expr * const * bool_var2expr_map) const { out << "(clause"; for (unsigned i = 0; i < m_num_literals; i++) { out << " "; m_lits[i].display(out, m, bool_var2expr_map); } - out << ")"; + return out << ")"; } - void clause::display_compact(std::ostream & out, ast_manager & m, expr * const * bool_var2expr_map) const { + std::ostream& clause::display_compact(std::ostream & out, ast_manager & m, expr * const * bool_var2expr_map) const { out << "(clause"; for (unsigned i = 0; i < m_num_literals; i++) { out << " "; m_lits[i].display_compact(out, bool_var2expr_map); } - out << ")"; + return out << ")"; + } + + std::ostream& clause::display_smt2(std::ostream & out, ast_manager & m, expr * const * bool_var2expr_map) const { + expr_ref_vector args(m); + for (unsigned i = 0; i < m_num_literals; i++) { + literal lit = m_lits[i]; + args.push_back(bool_var2expr_map[lit.var()]); + if (lit.sign()) args[args.size()-1] = m.mk_not(args.back()); + } + expr_ref disj(m.mk_or(args.size(), args.c_ptr()), m); + return out << disj; } }; diff --git a/src/smt/smt_clause.h b/src/smt/smt_clause.h index f0b352e05..025e2389d 100644 --- a/src/smt/smt_clause.h +++ b/src/smt/smt_clause.h @@ -239,9 +239,11 @@ namespace smt { set_activity(get_activity() + 1); } - void display(std::ostream & out, ast_manager & m, expr * const * bool_var2expr_map) const; + std::ostream& display(std::ostream & out, ast_manager & m, expr * const * bool_var2expr_map) const; + + std::ostream& display_smt2(std::ostream & out, ast_manager & m, expr * const * bool_var2expr_map) const; - void display_compact(std::ostream & out, ast_manager & m, expr * const * bool_var2expr_map) const; + std::ostream& display_compact(std::ostream & out, ast_manager & m, expr * const * bool_var2expr_map) const; unsigned hash() const { return get_ptr_hash(this); diff --git a/src/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index 20a084c81..4eb997c2e 100644 --- a/src/smt/smt_context_pp.cpp +++ b/src/smt/smt_context_pp.cpp @@ -160,7 +160,7 @@ namespace smt { } void context::display_clause(std::ostream & out, clause const * cls) const { - cls->display_compact(out, m_manager, m_bool_var2expr.c_ptr()); + cls->display_smt2(out, m_manager, m_bool_var2expr.c_ptr()); } void context::display_clauses(std::ostream & out, ptr_vector const & v) const { @@ -185,11 +185,18 @@ namespace smt { out << "binary clauses:\n"; first = false; } + expr_ref t1(m_manager), t2(m_manager); + literal2expr(neg_l1, t1); + literal2expr(l2, t2); + expr_ref disj(m_manager.mk_or(t1, t2), m_manager); + out << disj << "\n"; +#if 0 out << "(clause "; display_literal(out, neg_l1); out << " "; display_literal(out, l2); out << ")\n"; +#endif } } } diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index ce621144e..68c58d330 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -17,7 +17,7 @@ Revision History: --*/ #include "ast/ast_pp.h" -#include "ast/ast_smt2_pp.h" +#include "ast/ast_ll_pp.h" #include "smt/smt_quantifier.h" #include "smt/smt_context.h" #include "smt/smt_quantifier_stat.h" @@ -260,13 +260,20 @@ namespace smt { m_qi_queue.insert(f, pat, max_generation, min_top_generation, max_top_generation); // TODO m_num_instances++; } - TRACE("quantifier", - tout << mk_pp(q, m()) << " "; + static unsigned count = 0; + CTRACE("quantifier", f != nullptr, + tout << (count++) << " " << q->get_id() << "\n"; + if (q->get_id() == 28 || true) { + tout << mk_ll_pp(q, m()) << "\n"; + } + ); + + CTRACE("quantifier_", f != nullptr, + tout << expr_ref(q, m()) << " "; for (unsigned i = 0; i < num_bindings; ++i) { - tout << mk_pp(bindings[i]->get_owner(), m()) << " "; + tout << expr_ref(bindings[i]->get_owner(), m()) << " "; } tout << "\n"; - tout << "inserted: " << (f != nullptr) << "\n"; ); return f != nullptr; @@ -646,7 +653,7 @@ namespace smt { m_lazy_mam->add_pattern(q, mp); } else { - TRACE("quantifier", tout << "adding:\n" << mk_ismt2_pp(mp, m) << "\n";); + TRACE("quantifier", tout << "adding:\n" << expr_ref(mp, m) << "\n";); m_mam->add_pattern(q, mp); } if (!unary) From 442e47dfced2b010b47b27401d8ba6c892b1f230 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 17 Jan 2019 16:34:26 -0800 Subject: [PATCH 200/318] fix datatype occurs check bug reported by Gerhard Schellhorn Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 1 - src/smt/smt_conflict_resolution.cpp | 8 ++--- src/smt/smt_context.cpp | 2 ++ src/smt/smt_context_pp.cpp | 2 +- src/smt/theory_datatype.cpp | 49 ++++++++++++++++++----------- src/smt/theory_datatype.h | 3 +- 6 files changed, 40 insertions(+), 25 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 1f2f40941..a974e8b78 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -2138,7 +2138,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/smt/smt_conflict_resolution.cpp b/src/smt/smt_conflict_resolution.cpp index 93c172bf1..7fdfbf9aa 100644 --- a/src/smt/smt_conflict_resolution.cpp +++ b/src/smt/smt_conflict_resolution.cpp @@ -311,7 +311,7 @@ namespace smt { bool_var var = antecedent.var(); unsigned lvl = m_ctx.get_assign_level(var); SASSERT(var < static_cast(m_ctx.get_num_bool_vars())); - TRACE("conflict", tout << "processing antecedent (level " << lvl << "):"; + TRACE("conflict_", tout << "processing antecedent (level " << lvl << "):"; m_ctx.display_literal(tout, antecedent); m_ctx.display_detailed_literal(tout << " ", antecedent) << "\n";); @@ -429,7 +429,7 @@ namespace smt { void conflict_resolution::finalize_resolve(b_justification conflict, literal not_l) { unmark_justifications(0); - TRACE("conflict", m_ctx.display_literals(tout << "before minimization:\n", m_lemma) << "\n";); + TRACE("conflict", m_ctx.display_literals(tout << "before minimization:\n", m_lemma) << "\n" << m_lemma << "\n";); TRACE("conflict_verbose",m_ctx.display_literals_verbose(tout << "before minimization:\n", m_lemma) << "\n";); @@ -484,7 +484,7 @@ namespace smt { unsigned num_marks = 0; if (not_l != null_literal) { - TRACE("conflict", tout << "not_l: "; m_ctx.display_literal_verbose(tout, not_l); tout << "\n";); + TRACE("conflict", tout << "not_l: "; m_ctx.display_literal_verbose(tout, not_l) << "\n";); process_antecedent(not_l, num_marks); } @@ -497,7 +497,7 @@ namespace smt { } TRACE("conflict", tout << "processing consequent id: " << idx << " lit: " << consequent << " "; m_ctx.display_literal(tout, consequent); - m_ctx.display_literal_verbose(tout, consequent) << "\n"; + m_ctx.display_literal_verbose(tout << " ", consequent) << "\n"; tout << "num_marks: " << num_marks << ", js kind: " << js.get_kind() << " level: " << m_ctx.get_assign_level(consequent) << "\n"; ); SASSERT(js != null_b_justification); diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 3c601f400..38a25c874 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3918,6 +3918,8 @@ namespace smt { conflict_lvl > m_search_lvl + 1 && !m_manager.proofs_enabled() && m_units_to_reassert.size() < m_fparams.m_delay_units_threshold; + + TRACE("conflict", tout << delay_forced_restart << "\n";); if (delay_forced_restart) { new_lvl = conflict_lvl - 1; } diff --git a/src/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index 4eb997c2e..72cc2404c 100644 --- a/src/smt/smt_context_pp.cpp +++ b/src/smt/smt_context_pp.cpp @@ -263,7 +263,7 @@ namespace smt { for (unsigned i = 0; i < sz; i++) { expr * n = m_b_internalized_stack.get(i); bool_var v = get_bool_var_of_id(n->get_id()); - out << "(#" << n->get_id() << " -> p!" << v << ") "; + out << "(#" << n->get_id() << " -> " << literal(v, false) << ") "; } out << "\n"; } diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index 6aa49efae..e907b4462 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -455,33 +455,46 @@ namespace smt { return d->m_constructor; } + void theory_datatype::explain_is_child(enode* parent, enode* child) { + enode * parentc = oc_get_cstor(parent); + if (parent != parentc) { + m_used_eqs.push_back(enode_pair(parent, parentc)); + } + + // collect equalities on all children that may have been used. + bool found = false; + for (enode * arg : enode::args(parentc)) { + // found an argument which is equal to root + if (arg->get_root() == child->get_root()) { + if (arg != child) { + m_used_eqs.push_back(enode_pair(arg, child)); + } + found = true; + } + } + VERIFY(found); + } + // explain the cycle root -> ... -> app -> root void theory_datatype::occurs_check_explain(enode * app, enode * root) { TRACE("datatype", tout << "occurs_check_explain " << mk_bounded_pp(app->get_owner(), get_manager()) << " <-> " << mk_bounded_pp(root->get_owner(), get_manager()) << "\n";); - enode* app_parent = nullptr; // first: explain that root=v, given that app=cstor(...,v,...) - for (enode * arg : enode::args(oc_get_cstor(app))) { - // found an argument which is equal to root - if (arg->get_root() == root->get_root()) { - if (arg != root) - m_used_eqs.push_back(enode_pair(arg, root)); - break; - } - } + + explain_is_child(app, root); // now explain app=cstor(..,v,..) where v=root, and recurse with parent of app while (app->get_root() != root->get_root()) { - enode * app_cstor = oc_get_cstor(app); - if (app != app_cstor) - m_used_eqs.push_back(enode_pair(app, app_cstor)); - app_parent = m_parent[app->get_root()]; - app = app_parent; + enode* parent_app = m_parent[app->get_root()]; + explain_is_child(parent_app, app); + SASSERT(is_constructor(parent_app)); + app = parent_app; } SASSERT(app->get_root() == root->get_root()); - if (app != root) + if (app != root) { m_used_eqs.push_back(enode_pair(app, root)); + } TRACE("datatype", tout << "occurs_check\n"; @@ -706,11 +719,11 @@ namespace smt { sort * s = recognizer->get_decl()->get_domain(0); if (d->m_recognizers.empty()) { SASSERT(m_util.is_datatype(s)); - d->m_recognizers.resize(m_util.get_datatype_num_constructors(s)); + d->m_recognizers.resize(m_util.get_datatype_num_constructors(s), nullptr); } SASSERT(d->m_recognizers.size() == m_util.get_datatype_num_constructors(s)); unsigned c_idx = m_util.get_recognizer_constructor_idx(recognizer->get_decl()); - if (d->m_recognizers[c_idx] == 0) { + if (d->m_recognizers[c_idx] == nullptr) { lbool val = ctx.get_assignment(recognizer); TRACE("datatype", tout << "adding recognizer to v" << v << " rec: #" << recognizer->get_owner_id() << " val: " << val << "\n";); if (val == l_true) { @@ -782,7 +795,7 @@ namespace smt { region & reg = ctx.get_region(); TRACE("datatype_conflict", tout << mk_ismt2_pp(recognizer->get_owner(), get_manager()) << "\n"; for (literal l : lits) { - ctx.display_detailed_literal(tout, l); tout << "\n"; + ctx.display_detailed_literal(tout, l) << "\n"; } for (auto const& p : eqs) { tout << enode_eq_pp(p, ctx); diff --git a/src/smt/theory_datatype.h b/src/smt/theory_datatype.h index 010e78cb3..67cf5cfee 100644 --- a/src/smt/theory_datatype.h +++ b/src/smt/theory_datatype.h @@ -73,7 +73,7 @@ namespace smt { void sign_recognizer_conflict(enode * c, enode * r); typedef enum { ENTER, EXIT } stack_op; - typedef map, ptr_eq > parent_tbl; + typedef obj_map parent_tbl; typedef std::pair stack_entry; ptr_vector m_to_unmark; @@ -102,6 +102,7 @@ namespace smt { bool occurs_check(enode * n); bool occurs_check_enter(enode * n); void occurs_check_explain(enode * top, enode * root); + void explain_is_child(enode* parent, enode* child); void mk_split(theory_var v); From 947fe2ff9c7451d2f192d3453ed4d1eb347cd0f3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 17 Jan 2019 16:35:07 -0800 Subject: [PATCH 201/318] fix datatype occurs check bug reported by Gerhard Schellhorn Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 38a25c874..f9df954fa 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3919,7 +3919,6 @@ namespace smt { !m_manager.proofs_enabled() && m_units_to_reassert.size() < m_fparams.m_delay_units_threshold; - TRACE("conflict", tout << delay_forced_restart << "\n";); if (delay_forced_restart) { new_lvl = conflict_lvl - 1; } From 4caadc65197439042fa2fba4bcdea91f7da89609 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 18 Jan 2019 10:13:04 -0800 Subject: [PATCH 202/318] add note about libgomp dependency Signed-off-by: Nikolaj Bjorner --- scripts/mk_nuget_release.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/mk_nuget_release.py b/scripts/mk_nuget_release.py index ba0d44c3e..db7a1af64 100644 --- a/scripts/mk_nuget_release.py +++ b/scripts/mk_nuget_release.py @@ -85,7 +85,12 @@ 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 From c45ab6efed55cecc13a2d41fd60ded2d9a9eccad Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 18 Jan 2019 15:12:08 -0800 Subject: [PATCH 203/318] add setting to dump intermediary models #2087 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 17 ++++++++++++++++- src/opt/opt_context.h | 2 +- src/opt/opt_params.pyg | 1 + src/opt/optsmt.cpp | 5 ++++- src/opt/optsmt.h | 7 +++++-- 5 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 55b2a33ec..9acd93a01 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -125,7 +125,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(), @@ -357,6 +357,17 @@ 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); @@ -1062,6 +1073,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; @@ -1074,6 +1088,7 @@ namespace opt { out << *mdl; out.close(); } +#endif } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index fe0d4a13e..796e83535 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -189,7 +189,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..623eefea3 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)'), diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 7feb8f615..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" @@ -362,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); } } 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); From 2f0d2ec385ffa5e2e97071cc3ce884d1d8800a2b Mon Sep 17 00:00:00 2001 From: Titus Barik Date: Fri, 18 Jan 2019 16:18:16 -0800 Subject: [PATCH 204/318] PYTHON_PATH should say PYTHONPATH. --- examples/python/example.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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). From 0b7021d2c8481a4a4b67b1f831bf837782e8b7cc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 18 Jan 2019 18:09:19 -0800 Subject: [PATCH 205/318] na Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 55b2a33ec..4d3e5d312 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -1636,7 +1636,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";); + SASSERT(value0 == value); break; } } From 37d9e6d8112ca7a21a223bb0cb2fea4d9c93acf5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Jan 2019 10:40:11 -0800 Subject: [PATCH 206/318] incrementally adding files from dotnet core pull request from @yatli Signed-off-by: Nikolaj Bjorner --- .gitignore | 3 + cmake/modules/DotnetImports.props.in | 8 + cmake/modules/FindDotnet.cmake | 471 ++++++++++++++++++ .../z3_base_ubuntu32_16.04.Dockerfile | 3 +- examples/dotnet/CMakeLists.txt | 34 ++ 5 files changed, 518 insertions(+), 1 deletion(-) create mode 100644 cmake/modules/DotnetImports.props.in create mode 100644 cmake/modules/FindDotnet.cmake create mode 100644 examples/dotnet/CMakeLists.txt diff --git a/.gitignore b/.gitignore index e189a9569..88ccbb56f 100644 --- a/.gitignore +++ b/.gitignore @@ -76,3 +76,6 @@ src/api/ml/z3.mllib *.bak doc/api doc/code +.vs +examples/**/obj +CMakeSettings.json 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..50763e8da 100644 --- a/contrib/ci/Dockerfiles/z3_base_ubuntu32_16.04.Dockerfile +++ b/contrib/ci/Dockerfiles/z3_base_ubuntu32_16.04.Dockerfile @@ -48,4 +48,5 @@ 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 +# dotnet core doesn't support x86 +ENV ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-3.9/bin/llvm-symbolizer DOTNET_BINDINGS=0 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() + From cabe0ee4479452792f80e43ddea753cf8a4de319 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Jan 2019 10:51:44 -0800 Subject: [PATCH 207/318] integrating additional changes from @yatli pull request #1815 Signed-off-by: Nikolaj Bjorner --- examples/CMakeLists.txt | 7 + examples/dotnet/dotnet.csproj | 12 + src/api/dotnet/Microsoft.Z3.Sharp.pc.in | 7 - src/api/dotnet/Microsoft.Z3.csproj | 418 ------------------------ src/api/dotnet/Microsoft.Z3.csproj.in | 95 ++++++ src/api/dotnet/Microsoft.Z3.props | 23 ++ src/api/dotnet/Microsoft.Z3.targets | 11 + src/api/dotnet/core/README.txt | 15 - src/api/dotnet/core/core.csproj | 18 - 9 files changed, 148 insertions(+), 458 deletions(-) create mode 100644 examples/dotnet/dotnet.csproj delete mode 100644 src/api/dotnet/Microsoft.Z3.Sharp.pc.in delete mode 100644 src/api/dotnet/Microsoft.Z3.csproj create mode 100644 src/api/dotnet/Microsoft.Z3.csproj.in create mode 100644 src/api/dotnet/Microsoft.Z3.props create mode 100644 src/api/dotnet/Microsoft.Z3.targets delete mode 100644 src/api/dotnet/core/README.txt delete mode 100644 src/api/dotnet/core/core.csproj diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 6c50320ed..17c8e7c3f 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/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/src/api/dotnet/Microsoft.Z3.Sharp.pc.in b/src/api/dotnet/Microsoft.Z3.Sharp.pc.in deleted file mode 100644 index 8ca4e788b..000000000 --- a/src/api/dotnet/Microsoft.Z3.Sharp.pc.in +++ /dev/null @@ -1,7 +0,0 @@ -prefix=@PREFIX@ -assemblies_dir=${prefix}/lib/mono/@GAC_PKG_NAME@ - -Name: @GAC_PKG_NAME@ -Description: .NET bindings for The Microsoft Z3 SMT solver -Version: @VERSION@ -Libs: -r:${assemblies_dir}/Microsoft.Z3.dll 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/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 - - - - - - - From 9dd41ba554c9ddc616e2ce02c0cf8daa36b12266 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Jan 2019 11:13:03 -0800 Subject: [PATCH 208/318] remove offending assert, disable assembly-info for dotnet core Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 2 +- scripts/mk_util.py | 32 ++++++++++++++++++-------------- src/opt/opt_context.cpp | 2 +- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 58d087f32..2748e30a1 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -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 6552a942f..2e827a7f3 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1774,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)) @@ -2004,7 +2020,7 @@ class DotNetCoreDLLComponent(Component): 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): @@ -3093,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/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 2d406e0b4..98884d311 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -1614,7 +1614,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); } } } From 5cdbb1f7be7efaf55312fb7a608ca9977ba0bd80 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Jan 2019 11:25:34 -0800 Subject: [PATCH 209/318] this is still used Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Microsoft.Z3.Sharp.pc.in | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/api/dotnet/Microsoft.Z3.Sharp.pc.in diff --git a/src/api/dotnet/Microsoft.Z3.Sharp.pc.in b/src/api/dotnet/Microsoft.Z3.Sharp.pc.in new file mode 100644 index 000000000..8ca4e788b --- /dev/null +++ b/src/api/dotnet/Microsoft.Z3.Sharp.pc.in @@ -0,0 +1,7 @@ +prefix=@PREFIX@ +assemblies_dir=${prefix}/lib/mono/@GAC_PKG_NAME@ + +Name: @GAC_PKG_NAME@ +Description: .NET bindings for The Microsoft Z3 SMT solver +Version: @VERSION@ +Libs: -r:${assemblies_dir}/Microsoft.Z3.dll From 785fe2f6f7271ff85cf7eb2dbe3b78aa4d5f85c4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Jan 2019 12:43:05 -0800 Subject: [PATCH 210/318] add main remaining updates from #1815 Signed-off-by: Nikolaj Bjorner --- .../z3_base_ubuntu32_16.04.Dockerfile | 4 +- .../z3_base_ubuntu_14.04.Dockerfile | 12 +- .../z3_base_ubuntu_16.04.Dockerfile | 8 +- contrib/ci/scripts/test_z3_examples_cmake.sh | 11 +- examples/CMakeLists.txt | 6 +- examples/dotnet/README | 3 +- src/api/dotnet/CMakeLists.txt | 190 +++++------------- 7 files changed, 76 insertions(+), 158 deletions(-) diff --git a/contrib/ci/Dockerfiles/z3_base_ubuntu32_16.04.Dockerfile b/contrib/ci/Dockerfiles/z3_base_ubuntu32_16.04.Dockerfile index 50763e8da..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,5 +47,6 @@ RUN useradd -m user && \ echo 'user ALL=(root) NOPASSWD: ALL' >> /etc/sudoers USER user WORKDIR /home/user -# dotnet core doesn't support x86 +# 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/examples/CMakeLists.txt b/examples/CMakeLists.txt index 17c8e7c3f..5d06029f9 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -116,6 +116,6 @@ endif() ################################################################################ # Build dotnet examples ################################################################################ -#if (BUILD_DOTNET_BINDINGS) -# add_subdirectory(dotnet) -#endif() \ No newline at end of file +if (BUILD_DOTNET_BINDINGS) + add_subdirectory(dotnet) +endif() \ No newline at end of file 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/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() + From 8566d88b992610060a6523f28272d3384a2f2471 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Jan 2019 12:49:04 -0800 Subject: [PATCH 211/318] remove validation assert Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 98884d311..cc1456ac9 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -1654,7 +1654,7 @@ namespace opt { maxsmt& ms = *m_maxsmts.find(obj.m_id); rational value0 = ms.get_lower(); TRACE("opt", tout << "value " << value << " other " << value0 << "\n";); - SASSERT(value0 == value); + // TBD SASSERT(value0 == value); break; } } From 6bd87f837a143ec5321d598202591d6ae84d432f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Jan 2019 14:14:26 -0800 Subject: [PATCH 212/318] fix Boolean argument Signed-off-by: Nikolaj Bjorner --- src/solver/parallel_tactic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solver/parallel_tactic.cpp b/src/solver/parallel_tactic.cpp index 4ee93ff37..5fccadcbd 100644 --- a/src/solver/parallel_tactic.cpp +++ b/src/solver/parallel_tactic.cpp @@ -213,7 +213,7 @@ class parallel_tactic : public tactic { solver_state* clone() { SASSERT(!m_cubes.empty()); ast_manager& m = m_solver->get_manager(); - ast_manager* new_m = alloc(ast_manager, m, m.proof_mode()); + ast_manager* new_m = alloc(ast_manager, m, true); ast_translation tr(m, *new_m); solver* s = m_solver.get()->translate(*new_m, m_params); solver_state* st = alloc(solver_state, new_m, s, m_params); From 49a51a075776cd37126bf868cd92184e484752a7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 22 Jan 2019 07:06:40 -0800 Subject: [PATCH 213/318] fix #2096, introduced when fixing #2082 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/arith_rewriter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index d56d37041..21707d3c2 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -907,7 +907,7 @@ expr_ref arith_rewriter::remove_divisor(expr* arg, expr* num, expr* den) { m_util.mk_idiv(zero, zero), m().mk_ite(m_util.mk_ge(arg, zero), d, - m_util.mk_uminus(nd))), + nd)), m()); } From f9195c77a7ac88fea0bde163bf04256b969619f5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 22 Jan 2019 09:46:04 -0800 Subject: [PATCH 214/318] remove not-handled clause from mod with non-numerals Signed-off-by: Nikolaj Bjorner --- src/smt/theory_lra.cpp | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index c9db3f6b0..01330269c 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -483,22 +483,6 @@ class theory_lra::imp { if (ctx().relevancy()) ctx().add_relevancy_dependency(n, mod); } else if (a.is_mod(n, n1, n2)) { - bool is_num = a.is_numeral(n2, r) && !r.is_zero(); - if (!is_num) { - found_not_handled(n); - } -#if 0 - else { - app_ref div(a.mk_idiv(n1, n2), m); - mk_enode(div); - theory_var w = mk_var(div); - theory_var u = mk_var(n1); - // add axioms: - // u = v + r*w - // abs(r) > v >= 0 - assert_idiv_mod_axioms(u, v, w, r); - } -#endif if (!ctx().relevancy()) mk_idiv_mod_axioms(n1, n2); } else if (a.is_rem(n, n1, n2)) { From 412eee0dace45c2d7c13a6fbdc0a6d83e7a021d2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 22 Jan 2019 18:12:39 -0800 Subject: [PATCH 215/318] throttle number of rounds of ba simplification Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 47fc2c27f..7315f913b 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -2837,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; @@ -2855,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 From 8e5c1fcfd150e6b51040f1802f86e831e674f134 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 Jan 2019 16:06:25 -0800 Subject: [PATCH 216/318] make context_solve configurable and exposed as top-level tactic parameter Signed-off-by: Nikolaj Bjorner --- src/tactic/CMakeLists.txt | 2 ++ src/tactic/core/blast_term_ite_tactic.cpp | 13 ++++----- src/tactic/core/propagate_values_tactic.cpp | 6 +++-- src/tactic/core/solve_eqs_tactic.cpp | 29 ++++++++++----------- 4 files changed, 27 insertions(+), 23 deletions(-) diff --git a/src/tactic/CMakeLists.txt b/src/tactic/CMakeLists.txt index c9554b76a..495078afc 100644 --- a/src/tactic/CMakeLists.txt +++ b/src/tactic/CMakeLists.txt @@ -22,4 +22,6 @@ z3_add_component(tactic probe.h sine_filter.h tactic.h + PYG_FILES + tactic_params.pyg ) diff --git a/src/tactic/core/blast_term_ite_tactic.cpp b/src/tactic/core/blast_term_ite_tactic.cpp index eefb9418e..259b479c5 100644 --- a/src/tactic/core/blast_term_ite_tactic.cpp +++ b/src/tactic/core/blast_term_ite_tactic.cpp @@ -16,11 +16,12 @@ Author: Notes: --*/ -#include "tactic/tactical.h" +#include "util/cooperate.h" #include "ast/normal_forms/defined_names.h" #include "ast/rewriter/rewriter_def.h" -#include "util/cooperate.h" #include "ast/scoped_proof.h" +#include "tactic/tactical.h" +#include "tactic/tactic_params.hpp" @@ -50,9 +51,10 @@ class blast_term_ite_tactic : public tactic { } void updt_params(params_ref const & p) { + tactic_params tp(p); m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX)); - m_max_steps = p.get_uint("max_steps", UINT_MAX); - m_max_inflation = p.get_uint("max_inflation", UINT_MAX); // multiplicative factor of initial term size. + m_max_steps = p.get_uint("max_steps", tp.blast_term_ite_max_steps()); + m_max_inflation = p.get_uint("max_inflation", tp.blast_term_ite_max_inflation()); // multiplicative factor of initial term size. } @@ -182,8 +184,7 @@ public: void collect_param_descrs(param_descrs & r) override { insert_max_memory(r); insert_max_steps(r); - r.insert("max_args", CPK_UINT, - "(default: 128) maximum number of arguments (per application) that will be considered by the greedy (quadratic) heuristic."); + r.insert("max_inflation", CPK_UINT, "(default: infinity) multiplicative factor of initial term size."); } void operator()(goal_ref const & in, goal_ref_buffer & result) override { diff --git a/src/tactic/core/propagate_values_tactic.cpp b/src/tactic/core/propagate_values_tactic.cpp index f9712120f..351b606e6 100644 --- a/src/tactic/core/propagate_values_tactic.cpp +++ b/src/tactic/core/propagate_values_tactic.cpp @@ -23,6 +23,7 @@ Revision History: #include "ast/ast_smt2_pp.h" #include "ast/expr_substitution.h" #include "tactic/goal_shared_occs.h" +#include "tactic/tactic_params.hpp" namespace { class propagate_values_tactic : public tactic { @@ -37,7 +38,8 @@ class propagate_values_tactic : public tactic { params_ref m_params; void updt_params_core(params_ref const & p) { - m_max_rounds = p.get_uint("max_rounds", 4); + tactic_params tp(p); + m_max_rounds = p.get_uint("max_rounds", tp.propagate_values_max_rounds()); } bool is_shared(expr * t) { @@ -215,7 +217,7 @@ public: void collect_param_descrs(param_descrs & r) override { th_rewriter::get_param_descrs(r); - r.insert("max_rounds", CPK_UINT, "(default: 2) maximum number of rounds."); + r.insert("max_rounds", CPK_UINT, "(default: 4) maximum number of rounds."); } void operator()(goal_ref const & in, goal_ref_buffer & result) override { diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index 1ed230886..623f83db4 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -25,6 +25,7 @@ Revision History: #include "tactic/goal_shared_occs.h" #include "tactic/tactical.h" #include "tactic/generic_model_converter.h" +#include "tactic/tactic_params.hpp" class solve_eqs_tactic : public tactic { struct imp { @@ -40,6 +41,7 @@ class solve_eqs_tactic : public tactic { bool m_theory_solver; bool m_ite_solver; unsigned m_max_occs; + bool m_context_solve; scoped_ptr m_subst; scoped_ptr m_norm_subst; expr_sparse_mark m_candidate_vars; @@ -72,9 +74,11 @@ class solve_eqs_tactic : public tactic { ast_manager & m() const { return m_manager; } void updt_params(params_ref const & p) { - m_ite_solver = p.get_bool("ite_solver", true); - m_theory_solver = p.get_bool("theory_solver", true); - m_max_occs = p.get_uint("solve_eqs_max_occs", UINT_MAX); + tactic_params tp(p); + m_ite_solver = p.get_bool("ite_solver", tp.solve_eqs_ite_solver()); + m_theory_solver = p.get_bool("theory_solver", tp.solve_eqs_theory_solver()); + m_max_occs = p.get_uint("solve_eqs_max_occs", tp.solve_eqs_max_occs()); + m_context_solve = p.get_bool("context_solve", tp.solve_eqs_context_solve()); } void checkpoint() { @@ -555,7 +559,7 @@ class solve_eqs_tactic : public tactic { insert_solution(g, idx, arg, var, def, pr); } else { - IF_VERBOSE(0, + IF_VERBOSE(10000, verbose_stream() << "eq not solved " << mk_pp(arg, m()) << "\n"; verbose_stream() << is_uninterp_const(lhs) << " " << !m_candidate_vars.is_marked(lhs) << " " << !occurs(lhs, rhs) << " " << check_occs(lhs) << "\n";); @@ -726,7 +730,7 @@ class solve_eqs_tactic : public tactic { ++idx; } - IF_VERBOSE(10, + IF_VERBOSE(10000, verbose_stream() << "ordered vars: "; for (app* v : m_ordered_vars) verbose_stream() << mk_pp(v, m()) << " "; verbose_stream() << "\n";); @@ -811,12 +815,6 @@ class solve_eqs_tactic : public tactic { } m_r->operator()(f, new_f, new_pr, new_dep); -#if 0 - pb_util pb(m()); - if (pb.is_ge(f) && f != new_f) { - IF_VERBOSE(0, verbose_stream() << mk_ismt2_pp(f, m()) << "\n--->\n" << mk_ismt2_pp(new_f, m()) << "\n"); - } -#endif TRACE("solve_eqs_subst", tout << mk_ismt2_pp(f, m()) << "\n--->\n" << mk_ismt2_pp(new_f, m()) << "\n";); m_num_steps += m_r->get_num_steps() + 1; @@ -922,8 +920,9 @@ class solve_eqs_tactic : public tactic { while (true) { collect_num_occs(*g); collect(*g); - // TBD Disabled until tested more: - // collect_hoist(*g); + if (m_context_solve) { + collect_hoist(*g); + } if (m_subst->empty()) break; sort_vars(); @@ -941,7 +940,6 @@ class solve_eqs_tactic : public tactic { g->inc_depth(); g->add(mc.get()); result.push_back(g.get()); - //IF_VERBOSE(0, g->display(verbose_stream())); TRACE("solve_eqs", g->display(tout);); SASSERT(g->is_well_sorted()); } @@ -968,10 +966,11 @@ public: m_imp->updt_params(p); } - void collect_param_descrs(param_descrs & r) override { + void collect_param_descrs(param_descrs & r) override { r.insert("solve_eqs_max_occs", CPK_UINT, "(default: infty) maximum number of occurrences for considering a variable for gaussian eliminations."); r.insert("theory_solver", CPK_BOOL, "(default: true) use theory solvers."); r.insert("ite_solver", CPK_BOOL, "(default: true) use if-then-else solver."); + r.insert("context_solve", CPK_BOOL, "(default: false) solve equalities under disjunctions."); } void operator()(goal_ref const & in, From 9c07167ff8b1a60b3a990ed6666f725c9176f508 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 Jan 2019 16:06:44 -0800 Subject: [PATCH 217/318] add new pyg file Signed-off-by: Nikolaj Bjorner --- src/tactic/tactic_params.pyg | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/tactic/tactic_params.pyg diff --git a/src/tactic/tactic_params.pyg b/src/tactic/tactic_params.pyg new file mode 100644 index 000000000..5dfc6e5e8 --- /dev/null +++ b/src/tactic/tactic_params.pyg @@ -0,0 +1,20 @@ + +def_module_params('tactic', + description='tactic parameters', + export=True, + params=(('solve_eqs.context_solve', BOOL, False, "solve equalities within disjunctions."), + ('solve_eqs.theory_solver', BOOL, True, "use theory solvers."), + ('solve_eqs.ite_solver', BOOL, True, "use if-then-else solvers."), + ('solve_eqs.max_occs', UINT, UINT_MAX, "maximum number of occurrences for considering a variable for gaussian eliminations."), + ('blast_term_ite.max_inflation', UINT, UINT_MAX, "multiplicative factor of initial term size."), + ('blast_term_ite.max_steps', UINT, UINT_MAX, "maximal number of steps allowed for tactic."), + ('propagate_values.max_rounds', UINT, 4, "maximal number of rounds to propagate values."), + # ('aig.per_assertion', BOOL, True, "process one assertion at a time"), + # ('add_bounds.lower, INT, -2, "lower bound to be added to unbounded variables."), + # ('add_bounds.upper, INT, 2, "upper bound to be added to unbounded variables."), + # ('fm.real_only', BOOL, True, "consider only real variables for FM"), + # ('fm.occ', BOOL, False, "consider inequalities occurring in clauses for FM."), + # ('fm.limit', UINT, 5000000, "maximal number of constraints, monomials, clauses visited during FM."), + # etc: lia2card, factor, nla2bv, normalize_bounds, pb2bv, purify_arith, bit_blaster, bv_bounds + )) + From f7746e22848ea318a8a094e30a002e022aef1d85 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 Jan 2019 16:58:00 -0800 Subject: [PATCH 218/318] address perf #2098 Signed-off-by: Nikolaj Bjorner --- src/sat/sat_big.cpp | 22 +++------------------- src/sat/sat_big.h | 2 +- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/src/sat/sat_big.cpp b/src/sat/sat_big.cpp index c1eeecd27..1aa923f1f 100644 --- a/src/sat/sat_big.cpp +++ b/src/sat/sat_big.cpp @@ -164,22 +164,22 @@ 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++); @@ -211,22 +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(); From 498864c582e2897d7246b0124a9b48fb8643d16b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 Jan 2019 12:21:23 -0800 Subject: [PATCH 219/318] adding dump facility for cancelation #2095, easing dimacs in/out Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 66 +- src/api/c++/z3++.h | 2 + src/api/python/z3/z3.py | 4 + src/api/z3_api.h | 8 + src/ast/CMakeLists.txt | 1 + src/ast/display_dimacs.cpp | 81 ++ src/ast/display_dimacs.h | 26 + src/muz/spacer/spacer_iuc_solver.cpp | 791 +++++++++--------- src/muz/spacer/spacer_iuc_solver.h | 2 +- src/opt/opt_solver.cpp | 2 +- src/opt/opt_solver.h | 2 +- src/sat/sat_solver/inc_sat_solver.cpp | 2 +- src/smt/smt_solver.cpp | 2 +- src/solver/CMakeLists.txt | 2 + src/solver/combined_solver.cpp | 10 +- src/solver/solver.cpp | 49 +- src/solver/solver.h | 16 +- src/solver/solver_na2as.cpp | 4 +- src/solver/solver_na2as.h | 5 +- src/solver/solver_params.pyg | 8 + src/solver/solver_pool.cpp | 2 +- src/solver/tactic2solver.cpp | 4 +- .../fd_solver/bounded_int2bv_solver.cpp | 4 +- src/tactic/fd_solver/enum2bv_solver.cpp | 4 +- src/tactic/fd_solver/pb2bv_solver.cpp | 4 +- src/tactic/goal.cpp | 65 +- src/tactic/goal.h | 4 +- src/util/chashtable.h | 1 + 28 files changed, 653 insertions(+), 518 deletions(-) create mode 100644 src/ast/display_dimacs.cpp create mode 100644 src/ast/display_dimacs.h create mode 100644 src/solver/solver_params.pyg diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 8f92d5bb4..330d0f2bc 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -163,12 +163,46 @@ 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) { + std::cout << c_str << "\n"; + 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; } @@ -182,24 +216,7 @@ extern "C" { SET_ERROR_CODE(Z3_FILE_ACCESS_ERROR, nullptr); } else if (ext && (std::string("dimacs") == ext || std::string("cnf") == 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)); - } + solver_from_dimacs_stream(c, s, is); } else { solver_from_stream(c, s, is); @@ -532,6 +549,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 e541080c9..9847e4264 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -2240,6 +2240,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)); } diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 65f634b6b..1886bc475 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -6800,6 +6800,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() diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 5ee7fcb99..cd52d2d86 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -6368,6 +6368,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/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/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/muz/spacer/spacer_iuc_solver.cpp b/src/muz/spacer/spacer_iuc_solver.cpp index 32f33f773..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.empty() ? 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..a51bfbef9 100644 --- a/src/muz/spacer/spacer_iuc_solver.h +++ b/src/muz/spacer/spacer_iuc_solver.h @@ -127,7 +127,7 @@ public: 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/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index e61a02d80..78851f5cb 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) { diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 39562ec54..8d2abdb93 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; diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 8823c40c5..34348f0fc 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -166,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; diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 48f6053fc..5d32d1bed 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -185,7 +185,7 @@ namespace smt { m_context.pop(n); } - lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) override { + lbool check_sat_core2(unsigned num_assumptions, expr * const * assumptions) override { TRACE("solver_na2as", tout << "smt_solver::check_sat_core: " << num_assumptions << "\n";); return m_context.check(num_assumptions, assumptions); } diff --git a/src/solver/CMakeLists.txt b/src/solver/CMakeLists.txt index c8e206f7f..281a34018 100644 --- a/src/solver/CMakeLists.txt +++ b/src/solver/CMakeLists.txt @@ -16,5 +16,7 @@ z3_add_component(solver PYG_FILES combined_solver_params.pyg parallel_params.pyg + PYG_FILES + solver_params.pyg ) diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index e8fb34815..813b2be18 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -218,7 +218,7 @@ public: return l_undef; } - lbool check_sat(unsigned num_assumptions, expr * const * assumptions) override { + lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) override { m_check_sat_executed = true; m_use_solver1_results = false; @@ -227,13 +227,13 @@ public: m_ignore_solver1) { // must use incremental solver switch_inc_mode(); - return m_solver2->check_sat(num_assumptions, assumptions); + return m_solver2->check_sat_core(num_assumptions, assumptions); } if (m_inc_mode) { if (m_inc_timeout == UINT_MAX) { IF_VERBOSE(PS_VB_LVL, verbose_stream() << "(combined-solver \"using solver 2 (without a timeout)\")\n";); - lbool r = m_solver2->check_sat(num_assumptions, assumptions); + lbool r = m_solver2->check_sat_core(num_assumptions, assumptions); if (r != l_undef || !use_solver1_when_undef() || get_manager().canceled()) { return r; } @@ -244,7 +244,7 @@ public: lbool r = l_undef; try { scoped_timer timer(m_inc_timeout, &eh); - r = m_solver2->check_sat(num_assumptions, assumptions); + r = m_solver2->check_sat_core(num_assumptions, assumptions); } catch (z3_exception&) { if (!eh.m_canceled) { @@ -260,7 +260,7 @@ public: IF_VERBOSE(PS_VB_LVL, verbose_stream() << "(combined-solver \"using solver 1\")\n";); m_use_solver1_results = true; - return m_solver1->check_sat(num_assumptions, assumptions); + return m_solver1->check_sat_core(num_assumptions, assumptions); } void set_progress_callback(progress_callback * callback) override { diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index f3c533704..6f4880d38 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -3,7 +3,7 @@ Copyright (c) 2011 Microsoft Corporation Module Name: - solver.h + solver.cpp Abstract: @@ -21,25 +21,25 @@ Notes: #include "ast/ast_util.h" #include "ast/ast_pp.h" #include "ast/ast_pp_util.h" +#include "ast/display_dimacs.h" #include "tactic/model_converter.h" #include "solver/solver.h" +#include "solver/solver_params.hpp" #include "model/model_evaluator.h" unsigned solver::get_num_assertions() const { - NOT_IMPLEMENTED_YET(); + UNREACHABLE(); return 0; } expr * solver::get_assertion(unsigned idx) const { - NOT_IMPLEMENTED_YET(); + UNREACHABLE(); return nullptr; } std::ostream& solver::display(std::ostream & out, unsigned n, expr* const* assumptions) const { expr_ref_vector fmls(get_manager()); - stopwatch sw; - sw.start(); get_assertions(fmls); ast_pp_util visitor(get_manager()); model_converter_ref mc = get_model_converter(); @@ -57,6 +57,12 @@ std::ostream& solver::display(std::ostream & out, unsigned n, expr* const* assum return out; } +std::ostream& solver::display_dimacs(std::ostream& out) const { + expr_ref_vector fmls(get_manager()); + get_assertions(fmls); + return ::display_dimacs(out, fmls); +} + void solver::get_assertions(expr_ref_vector& fmls) const { unsigned sz = get_num_assertions(); for (unsigned i = 0; i < sz; ++i) { @@ -232,12 +238,16 @@ void solver::collect_param_descrs(param_descrs & r) { void solver::reset_params(params_ref const & p) { m_params = p; - m_enforce_model_conversion = m_params.get_bool("solver.enforce_model_conversion", false); + solver_params sp(m_params); + m_enforce_model_conversion = sp.enforce_model_conversion(); + m_cancel_backup_file = sp.cancel_backup_file(); } void solver::updt_params(params_ref const & p) { m_params.copy(p); - m_enforce_model_conversion = m_params.get_bool("solver.enforce_model_conversion", false); + solver_params sp(m_params); + m_enforce_model_conversion = sp.enforce_model_conversion(); + m_cancel_backup_file = sp.cancel_backup_file(); } @@ -309,3 +319,28 @@ expr_ref_vector solver::get_non_units(ast_manager& m) { } return result; } + +lbool solver::check_sat(unsigned num_assumptions, expr * const * assumptions) { + lbool r = l_undef; + try { + r = check_sat_core(num_assumptions, assumptions); + } + catch (...) { + if (get_manager().canceled()) { + dump_state(num_assumptions, assumptions); + } + throw; + } + if (r == l_undef && get_manager().canceled()) { + dump_state(num_assumptions, assumptions); + } + return r; +} + +void solver::dump_state(unsigned sz, expr* const* assumptions) { + std::string file = m_cancel_backup_file.str(); + if (file != "") { + std::ofstream ous(file); + display(ous, sz, assumptions); + } +} diff --git a/src/solver/solver.h b/src/solver/solver.h index 7437a5a08..161677cb5 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -44,8 +44,9 @@ public: - results based on check_sat_result API */ class solver : public check_sat_result { - params_ref m_params; - bool m_enforce_model_conversion; + params_ref m_params; + bool m_enforce_model_conversion; + symbol m_cancel_backup_file; public: solver(): m_enforce_model_conversion(false) {} ~solver() override {} @@ -140,7 +141,8 @@ public: If it is unsatisfiable, and unsat-core generation is enabled. Then, the unsat-core is a subset of these assumptions. */ - virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions) = 0; + + lbool check_sat(unsigned num_assumptions, expr * const * assumptions); lbool check_sat(expr_ref_vector const& asms) { return check_sat(asms.size(), asms.c_ptr()); } @@ -227,6 +229,11 @@ public: */ virtual std::ostream& display(std::ostream & out, unsigned n = 0, expr* const* assumptions = nullptr) const; + /** + \brief Display the content of this solver in DIMACS format + */ + std::ostream& display_dimacs(std::ostream & out) const; + /** \brief expose model converter when solver produces partially reduced set of assertions. */ @@ -249,14 +256,17 @@ public: void disable_pop() { m_nopop = true; } }; + virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) = 0; protected: virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences); + void dump_state(unsigned sz, expr* const* assumptions); bool is_literal(ast_manager& m, expr* e); + }; typedef ref solver_ref; diff --git a/src/solver/solver_na2as.cpp b/src/solver/solver_na2as.cpp index a3fcd0e0b..6173dfddf 100644 --- a/src/solver/solver_na2as.cpp +++ b/src/solver/solver_na2as.cpp @@ -61,10 +61,10 @@ struct append_assumptions { } }; -lbool solver_na2as::check_sat(unsigned num_assumptions, expr * const * assumptions) { +lbool solver_na2as::check_sat_core(unsigned num_assumptions, expr * const * assumptions) { append_assumptions app(m_assumptions, num_assumptions, assumptions); TRACE("solver_na2as", display(tout);); - return check_sat_core(m_assumptions.size(), m_assumptions.c_ptr()); + return check_sat_core2(m_assumptions.size(), m_assumptions.c_ptr()); } lbool solver_na2as::check_sat_cc(const expr_ref_vector &assumptions, vector const &clauses) { diff --git a/src/solver/solver_na2as.h b/src/solver/solver_na2as.h index d1515a206..67ec004cc 100644 --- a/src/solver/solver_na2as.h +++ b/src/solver/solver_na2as.h @@ -35,10 +35,9 @@ public: ~solver_na2as() override; void assert_expr_core2(expr * t, expr * a) override; - // virtual void assert_expr_core(expr * t) = 0; // Subclasses of solver_na2as should redefine the following *_core methods instead of these ones. - 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 &assumptions, vector const &clauses) override; void push() override; void pop(unsigned n) override; @@ -49,7 +48,7 @@ public: lbool get_consequences(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) override; lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) override; protected: - virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) = 0; + virtual lbool check_sat_core2(unsigned num_assumptions, expr * const * assumptions) = 0; virtual lbool check_sat_cc_core(const expr_ref_vector &assumptions, vector const &clauses) { NOT_IMPLEMENTED_YET(); } virtual void push_core() = 0; virtual void pop_core(unsigned n) = 0; diff --git a/src/solver/solver_params.pyg b/src/solver/solver_params.pyg new file mode 100644 index 000000000..29690a164 --- /dev/null +++ b/src/solver/solver_params.pyg @@ -0,0 +1,8 @@ + +def_module_params('solver', + description='solver parameters', + export=True, + params=(('enforce_model_conversion', BOOL, False, "apply model transformation on new assertions"), + ('cancel_backup_file', SYMBOL, '', "file to save partial search state if search is canceled"), + )) + diff --git a/src/solver/solver_pool.cpp b/src/solver/solver_pool.cpp index 598bb6c02..0495e8a3d 100644 --- a/src/solver/solver_pool.cpp +++ b/src/solver/solver_pool.cpp @@ -119,7 +119,7 @@ public: } } - lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) override { + lbool check_sat_core2(unsigned num_assumptions, expr * const * assumptions) override { SASSERT(!m_pushed || get_scope_level() > 0); m_proof.reset(); scoped_watch _t_(m_pool.m_check_watch); diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 492ddd443..298ed9bc5 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -62,7 +62,7 @@ public: 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 collect_statistics(statistics & st) const override; void get_unsat_core(expr_ref_vector & r) override; @@ -136,7 +136,7 @@ void tactic2solver::pop_core(unsigned n) { m_result = nullptr; } -lbool tactic2solver::check_sat_core(unsigned num_assumptions, expr * const * assumptions) { +lbool tactic2solver::check_sat_core2(unsigned num_assumptions, expr * const * assumptions) { if (m_tactic.get() == nullptr) return l_false; ast_manager & m = m_assertions.m(); diff --git a/src/tactic/fd_solver/bounded_int2bv_solver.cpp b/src/tactic/fd_solver/bounded_int2bv_solver.cpp index 8791a6282..45d1344ba 100644 --- a/src/tactic/fd_solver/bounded_int2bv_solver.cpp +++ b/src/tactic/fd_solver/bounded_int2bv_solver.cpp @@ -137,9 +137,9 @@ public: } } - lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) override { + lbool check_sat_core2(unsigned num_assumptions, expr * const * assumptions) override { flush_assertions(); - return m_solver->check_sat(num_assumptions, assumptions); + return m_solver->check_sat_core(num_assumptions, assumptions); } void updt_params(params_ref const & p) override { solver::updt_params(p); m_solver->updt_params(p); } diff --git a/src/tactic/fd_solver/enum2bv_solver.cpp b/src/tactic/fd_solver/enum2bv_solver.cpp index 185f23d13..b9a564542 100644 --- a/src/tactic/fd_solver/enum2bv_solver.cpp +++ b/src/tactic/fd_solver/enum2bv_solver.cpp @@ -78,9 +78,9 @@ public: m_rewriter.pop(n); } - lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) override { + lbool check_sat_core2(unsigned num_assumptions, expr * const * assumptions) override { m_solver->updt_params(get_params()); - return m_solver->check_sat(num_assumptions, assumptions); + return m_solver->check_sat_core(num_assumptions, assumptions); } void updt_params(params_ref const & p) override { solver::updt_params(p); m_solver->updt_params(p); } diff --git a/src/tactic/fd_solver/pb2bv_solver.cpp b/src/tactic/fd_solver/pb2bv_solver.cpp index fd4fb8e73..b3620c8ec 100644 --- a/src/tactic/fd_solver/pb2bv_solver.cpp +++ b/src/tactic/fd_solver/pb2bv_solver.cpp @@ -75,9 +75,9 @@ public: m_rewriter.pop(n); } - lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) override { + lbool check_sat_core2(unsigned num_assumptions, expr * const * assumptions) override { flush_assertions(); - return m_solver->check_sat(num_assumptions, assumptions); + return m_solver->check_sat_core(num_assumptions, assumptions); } void updt_params(params_ref const & p) override { solver::updt_params(p); m_rewriter.updt_params(p); m_solver->updt_params(p); } diff --git a/src/tactic/goal.cpp b/src/tactic/goal.cpp index 8f8b86a65..c2d93fa2a 100644 --- a/src/tactic/goal.cpp +++ b/src/tactic/goal.cpp @@ -20,6 +20,7 @@ Revision History: #include "ast/ast_smt2_pp.h" #include "ast/for_each_expr.h" #include "ast/well_sorted.h" +#include "ast/display_dimacs.h" #include "tactic/goal.h" goal::precision goal::mk_union(precision p1, precision p2) { @@ -262,14 +263,14 @@ void goal::assert_expr(expr * f, expr_dependency * d) { assert_expr(f, proofs_enabled() ? m().mk_asserted(f) : nullptr, d); } -void goal::get_formulas(ptr_vector & result) { +void goal::get_formulas(ptr_vector & result) const { unsigned sz = size(); for (unsigned i = 0; i < sz; i++) { result.push_back(form(i)); } } -void goal::get_formulas(expr_ref_vector & result) { +void goal::get_formulas(expr_ref_vector & result) const { unsigned sz = size(); for (unsigned i = 0; i < sz; i++) { result.push_back(form(i)); @@ -434,63 +435,9 @@ void goal::display_ll(std::ostream & out) const { \brief Assumes that the formula is already in CNF. */ void goal::display_dimacs(std::ostream & out) const { - unsigned_vector expr2var; - ptr_vector exprs; - unsigned num_vars = 0; - unsigned num_cls = size(); - for (unsigned i = 0; i < num_cls; i++) { - expr * f = form(i); - 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 (unsigned i = 0; i < num_cls; i++) { - expr * f = form(i); - 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"; - } - } + expr_ref_vector fmls(m()); + get_formulas(fmls); + ::display_dimacs(out, fmls); } unsigned goal::num_exprs() const { diff --git a/src/tactic/goal.h b/src/tactic/goal.h index fa2f16eb6..33f9298ab 100644 --- a/src/tactic/goal.h +++ b/src/tactic/goal.h @@ -126,8 +126,8 @@ public: void update(unsigned i, expr * f, proof * pr = nullptr, expr_dependency * dep = nullptr); - void get_formulas(ptr_vector & result); - void get_formulas(expr_ref_vector & result); + void get_formulas(ptr_vector & result) const; + void get_formulas(expr_ref_vector & result) const; void elim_true(); void elim_redundancies(); diff --git a/src/util/chashtable.h b/src/util/chashtable.h index e49ac3bd4..19ff1ef51 100644 --- a/src/util/chashtable.h +++ b/src/util/chashtable.h @@ -32,6 +32,7 @@ Revision History: #include "util/debug.h" #include "util/trace.h" #include "util/tptr.h" +#include "util/util.h" #ifdef Z3DEBUG #include "util/hashtable.h" #endif From 8da1d6070b1d8287330b066ceb77a817a51b0d8d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 Jan 2019 14:00:56 -0800 Subject: [PATCH 220/318] throttle big-reductions #2101 #2098 Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 16 ++++++++++++++++ src/sat/sat_big.cpp | 2 +- src/sat/sat_scc.cpp | 8 ++++---- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 9847e4264..a307df4bb 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -518,6 +518,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 +621,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); } @@ -771,6 +782,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 diff --git a/src/sat/sat_big.cpp b/src/sat/sat_big.cpp index 1aa923f1f..833c83820 100644 --- a/src/sat/sat_big.cpp +++ b/src/sat/sat_big.cpp @@ -172,6 +172,7 @@ namespace sat { void big::add_del(literal u, literal v) { if (u.index() > v.index()) std::swap(u, v); + m_del_bin[u.index()].push_back(v); } @@ -210,7 +211,6 @@ namespace sat { } wlist.set_end(itprev); } - s.propagate(false); return elim; } diff --git a/src/sat/sat_scc.cpp b/src/sat/sat_scc.cpp index e2d05385b..52641736a 100644 --- a/src/sat/sat_scc.cpp +++ b/src/sat/sat_scc.cpp @@ -244,10 +244,10 @@ 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 { From ad81fee118628fbe0ace97865948ff9b8cbc8df7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 Jan 2019 19:26:44 -0800 Subject: [PATCH 221/318] adding maxlex, throttle use of asymmetric literal addition Signed-off-by: Nikolaj Bjorner --- src/opt/CMakeLists.txt | 1 + src/opt/maxlex.cpp | 185 +++++++++++++++++++++++++++++++++++++ src/opt/maxlex.h | 32 +++++++ src/opt/maxres.cpp | 8 +- src/opt/maxsmt.cpp | 22 +++-- src/opt/maxsmt.h | 13 ++- src/opt/sortmax.cpp | 2 +- src/opt/wmax.cpp | 2 +- src/sat/sat_simplifier.cpp | 36 ++++++-- 9 files changed, 274 insertions(+), 27 deletions(-) create mode 100644 src/opt/maxlex.cpp create mode 100644 src/opt/maxlex.h 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..3cf9cea5a --- /dev/null +++ b/src/opt/maxlex.cpp @@ -0,0 +1,185 @@ +/*++ +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_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 set_value(soft& soft, lbool v) { + soft.set_value(v); + assert_value(soft); + } + + void update_assignment(model_ref & mdl) { + for (auto & soft : m_soft) { + switch (soft.value) { + case l_undef: + if (mdl->is_true(soft.s)) { + set_value(soft, l_true); + } + else { + update_bounds(); + return; + } + break; + case l_true: + break; + case l_false: + break; + } + } + update_bounds(); + } + + void update_bounds() { + m_lower.reset(); + m_upper.reset(); + bool prefix_defined = true; + for (auto & soft : m_soft) { + if (!prefix_defined) { + m_upper += soft.weight; + continue; + } + switch (soft.value) { + case l_undef: + prefix_defined = false; + 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() { + model_ref mdl; + s().get_model(mdl); + update_assignment(mdl); + } + + 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) { + cmp_soft cmp; + std::sort(m_soft.begin(), m_soft.end(), cmp); + } + + + lbool operator()() override { + init(); + + for (auto & soft : m_soft) { + if (soft.value == l_true) { + continue; + } + SASSERT(soft.value() == l_undef); + expr* a = soft.s; + lbool is_sat = s().check_sat(1, &a); + switch (is_sat) { + case l_false: + set_value(soft, l_false); + update_bounds(); + break; + case l_true: + update_assignment(); + SASSERT(soft.value == l_true); + break; + case l_undef: + return l_undef; + } + } + return l_true; + } + + 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 b507d6f54..789aaf8db 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -329,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; } } @@ -764,7 +764,7 @@ public: TRACE("opt", tout << "updated upper: " << upper << "\nmodel\n" << *m_model;); 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(); @@ -878,7 +878,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..329e7979c 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; } @@ -234,7 +235,10 @@ namespace opt { 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 (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/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 aa539bc44..9fb683179 100644 --- a/src/opt/wmax.cpp +++ b/src/opt/wmax.cpp @@ -122,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/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 465618c5f..96b1588a2 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1014,6 +1014,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): @@ -1021,8 +1024,11 @@ 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) { @@ -1034,6 +1040,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, @@ -1296,13 +1306,15 @@ namespace sat { */ bool add_ala() { unsigned init_size = m_covered_clause.size(); - for (; m_ala_qhead < m_covered_clause.size() && m_ala_qhead < 5*init_size; ++m_ala_qhead) { + 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)) { @@ -1333,6 +1345,7 @@ namespace sat { } if (!ok) continue; if (lit1 == null_literal) { + ++m_ala_benefit; return true; } m_covered_clause.push_back(~lit1); @@ -1504,7 +1517,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()); } @@ -1516,7 +1531,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(); @@ -1543,9 +1558,13 @@ namespace sat { 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); @@ -1563,7 +1582,10 @@ namespace sat { break; } s.checkpoint(); - } + if (reached_max_cost()) { + break; + } + } } void inc_bc(elim_type et) { From b4f4a1f316772c1bb18ba414127c242d01b493d1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 Jan 2019 19:47:50 -0800 Subject: [PATCH 222/318] adding maxlex, throttle use of asymmetric literal addition Signed-off-by: Nikolaj Bjorner --- src/opt/maxlex.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/opt/maxlex.cpp b/src/opt/maxlex.cpp index 3cf9cea5a..89cebaa37 100644 --- a/src/opt/maxlex.cpp +++ b/src/opt/maxlex.cpp @@ -55,6 +55,7 @@ namespace opt { model_ref mdl; s().get_model(mdl); if (mdl) { + m_model = mdl; m_c.model_updated(mdl.get()); update_assignment(mdl); } @@ -79,16 +80,16 @@ namespace opt { } void update_assignment(model_ref & mdl) { + bool prefix_defined = true; for (auto & soft : m_soft) { + if (!prefix_defined) { + set_value(soft, l_undef); + continue; + } switch (soft.value) { case l_undef: - if (mdl->is_true(soft.s)) { - set_value(soft, l_true); - } - else { - update_bounds(); - return; - } + prefix_defined = mdl->is_true(soft.s); + set_value(soft, prefix_defined ? l_true : l_undef); break; case l_true: break; @@ -127,19 +128,20 @@ namespace opt { void init() { model_ref mdl; s().get_model(mdl); - update_assignment(mdl); + update_assignment(mdl); } + 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(); @@ -167,6 +169,7 @@ namespace opt { return l_true; } + void commit_assignment() override { for (auto & soft : m_soft) { if (soft.value == l_undef) { @@ -175,7 +178,6 @@ namespace opt { assert_value(soft); } } - }; maxsmt_solver_base* mk_maxlex(maxsat_context& c, unsigned id, weights_t & ws, expr_ref_vector const& soft) { From d3d392da41c5e3e3bd51de3c5cb2b5265b4ef273 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 Jan 2019 21:36:40 -0800 Subject: [PATCH 223/318] adding maxlex, delay mk_true() calls in goal2sat Signed-off-by: Nikolaj Bjorner --- src/opt/maxlex.cpp | 115 +++++++++++++++++++++++++++++++----- src/sat/tactic/goal2sat.cpp | 1 - 2 files changed, 100 insertions(+), 16 deletions(-) diff --git a/src/opt/maxlex.cpp b/src/opt/maxlex.cpp index 89cebaa37..1604db161 100644 --- a/src/opt/maxlex.cpp +++ b/src/opt/maxlex.cpp @@ -26,6 +26,10 @@ Author: namespace opt { bool is_maxlex(weights_t & _ws) { + // disable for now +#if true + return false; +#else vector ws(_ws); std::sort(ws.begin(), ws.end()); ws.reverse(); @@ -38,6 +42,7 @@ namespace opt { sum -= w; } return true; +#endif } class maxlex : public maxsmt_solver_base { @@ -131,21 +136,7 @@ namespace opt { update_assignment(mdl); } - - 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(); - + lbool maxlex1() { for (auto & soft : m_soft) { if (soft.value == l_true) { continue; @@ -169,6 +160,100 @@ namespace opt { return l_true; } + // try two literals per round. + // doesn't seem to make a difference based on sample test. + lbool maxlex2() { + unsigned sz = m_soft.size(); + for (unsigned i = 0; i < sz; ++i) { + auto& soft = m_soft[i]; + if (soft.value != l_undef) { + continue; + } + SASSERT(soft.value() == l_undef); + if (i + 1 == sz) { + expr* a = soft.s; + lbool is_sat = s().check_sat(1, &a); + switch (is_sat) { + case l_false: + set_value(soft, l_false); + update_bounds(); + break; + case l_true: + update_assignment(); + SASSERT(soft.value == l_true); + break; + case l_undef: + return l_undef; + } + } + else { + auto& soft2 = m_soft[i+1]; + expr_ref_vector core(m); + expr* a = soft.s; + expr* b = soft2.s; + expr* asms[2] = { a, b }; + lbool is_sat = s().check_sat(2, asms); + switch (is_sat) { + case l_true: + update_assignment(); + SASSERT(soft.value == l_true); + SASSERT(soft2.value == l_true); + break; + case l_false: + s().get_unsat_core(core); + if (core.contains(b)) { + expr_ref not_b(mk_not(m, b), m); + asms[1] = not_b; + switch (s().check_sat(2, asms)) { + case l_true: + // a, b is unsat, a, not b is sat. + set_value(soft2, l_false); + update_assignment(); + SASSERT(soft.value == l_true); + SASSERT(soft2.value == l_false); + break; + case l_false: + // a, b is unsat, a, not b is unsat -> a is unsat + // b is unsat, a, not b is unsat -> not a, not b + set_value(soft, l_false); + if (!core.contains(a)) { + set_value(soft2, l_false); + } + update_bounds(); + break; + case l_undef: + return l_undef; + } + } + else { + set_value(soft, l_false); + 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 maxlex1(); + } + void commit_assignment() override { for (auto & soft : m_soft) { diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 68e18375f..419952f99 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -82,7 +82,6 @@ struct goal2sat::imp { m_is_lemma(false) { updt_params(p); m_true = sat::null_bool_var; - mk_true(); } void updt_params(params_ref const & p) { From a785ffe0bae5c22454b638045310a78954f3b16a Mon Sep 17 00:00:00 2001 From: Alcides Fonseca Date: Fri, 25 Jan 2019 14:42:22 +0000 Subject: [PATCH 224/318] Updated deepcopy to the latest Python API --- src/api/python/z3/z3.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 65f634b6b..556c920f6 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -5340,7 +5340,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): @@ -5528,7 +5528,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): @@ -5872,7 +5872,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): @@ -6168,7 +6168,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): @@ -6786,7 +6786,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): From 1ed68906faab97f8022e61b41caf24b71cb4d7b8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 Jan 2019 08:23:41 -0800 Subject: [PATCH 225/318] fix debug assertion code, make maxlex optional Signed-off-by: Nikolaj Bjorner --- src/opt/maxlex.cpp | 9 ++------- src/opt/maxsmt.cpp | 3 ++- src/opt/opt_params.pyg | 1 + 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/opt/maxlex.cpp b/src/opt/maxlex.cpp index 1604db161..30b4dbfc6 100644 --- a/src/opt/maxlex.cpp +++ b/src/opt/maxlex.cpp @@ -26,10 +26,6 @@ Author: namespace opt { bool is_maxlex(weights_t & _ws) { - // disable for now -#if true - return false; -#else vector ws(_ws); std::sort(ws.begin(), ws.end()); ws.reverse(); @@ -42,7 +38,6 @@ namespace opt { sum -= w; } return true; -#endif } class maxlex : public maxsmt_solver_base { @@ -141,7 +136,7 @@ namespace opt { if (soft.value == l_true) { continue; } - SASSERT(soft.value() == l_undef); + SASSERT(soft.value == l_undef); expr* a = soft.s; lbool is_sat = s().check_sat(1, &a); switch (is_sat) { @@ -169,7 +164,7 @@ namespace opt { if (soft.value != l_undef) { continue; } - SASSERT(soft.value() == l_undef); + SASSERT(soft.value == l_undef); if (i + 1 == sz) { expr* a = soft.s; lbool is_sat = s().check_sat(1, &a); diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 329e7979c..5441c4def 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -232,10 +232,11 @@ 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 (is_maxlex(m_weights)) { + 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) { diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 623eefea3..4235deb3d 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -14,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, False, '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'), From 121211a51cec7bf67dcbd87e8c99658b80856d8a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 Jan 2019 20:01:38 -0800 Subject: [PATCH 226/318] maxlexN Signed-off-by: Nikolaj Bjorner --- src/opt/maxlex.cpp | 89 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 70 insertions(+), 19 deletions(-) diff --git a/src/opt/maxlex.cpp b/src/opt/maxlex.cpp index 30b4dbfc6..1ee9db090 100644 --- a/src/opt/maxlex.cpp +++ b/src/opt/maxlex.cpp @@ -80,21 +80,23 @@ namespace opt { } void update_assignment(model_ref & mdl) { - bool prefix_defined = true; + bool first_undef = true, second_undef = false; for (auto & soft : m_soft) { - if (!prefix_defined) { - set_value(soft, l_undef); + if (first_undef && soft.value != l_undef) { continue; } - switch (soft.value) { - case l_undef: - prefix_defined = mdl->is_true(soft.s); - set_value(soft, prefix_defined ? l_true : l_undef); - break; - case l_true: - break; - case l_false: - break; + 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 { + set_value(soft, v); // also update constraints + } } } update_bounds(); @@ -103,15 +105,9 @@ namespace opt { void update_bounds() { m_lower.reset(); m_upper.reset(); - bool prefix_defined = true; for (auto & soft : m_soft) { - if (!prefix_defined) { - m_upper += soft.weight; - continue; - } switch (soft.value) { case l_undef: - prefix_defined = false; m_upper += soft.weight; break; case l_true: @@ -126,6 +122,9 @@ namespace opt { } void init() { + for (auto & soft : m_soft) { + soft.set_value(l_undef); + } model_ref mdl; s().get_model(mdl); update_assignment(mdl); @@ -211,9 +210,20 @@ namespace opt { // a, b is unsat, a, not b is unsat -> a is unsat // b is unsat, a, not b is unsat -> not a, not b set_value(soft, l_false); + // core1 = { b } + // core2 = { a, not b } if (!core.contains(a)) { set_value(soft2, l_false); } + else { + // core1 = { a, b} + // core2 = { not_b } + core.reset(); + s().get_unsat_core(core); + if (!core.contains(a)) { + set_value(soft2, l_true); + } + } update_bounds(); break; case l_undef: @@ -233,6 +243,47 @@ namespace opt { return l_true; } + // every time probing whether to include soft_i, + // include suffix that is known to be assignable to T + 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); + for (unsigned j = i + 1; j < sz; ++j) { + auto& soft2 = m_soft[j]; + if (soft2.value == l_true) { + asms.push_back(soft2.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: + set_value(soft, l_false); + 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): @@ -246,7 +297,7 @@ namespace opt { lbool operator()() override { init(); - return maxlex1(); + return maxlexN(); } From 4fb729a7d2ff62487e9598db8637b54caac35c64 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 Jan 2019 20:27:32 -0800 Subject: [PATCH 227/318] value() Signed-off-by: Nikolaj Bjorner --- src/opt/maxlex.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/opt/maxlex.cpp b/src/opt/maxlex.cpp index 1604db161..d8dab9a03 100644 --- a/src/opt/maxlex.cpp +++ b/src/opt/maxlex.cpp @@ -141,7 +141,7 @@ namespace opt { if (soft.value == l_true) { continue; } - SASSERT(soft.value() == l_undef); + SASSERT(soft.value == l_undef); expr* a = soft.s; lbool is_sat = s().check_sat(1, &a); switch (is_sat) { @@ -169,7 +169,7 @@ namespace opt { if (soft.value != l_undef) { continue; } - SASSERT(soft.value() == l_undef); + SASSERT(soft.value == l_undef); if (i + 1 == sz) { expr* a = soft.s; lbool is_sat = s().check_sat(1, &a); From cf6119cdfd235d36276d9076cabdd0eedf3e4628 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 Jan 2019 21:02:25 -0800 Subject: [PATCH 228/318] fix #2102 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 10b2992fe..6ac1ad4b8 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -3148,6 +3148,9 @@ bool theory_seq::solve_nc(unsigned idx) { if (!linearize(deps, eqs, lits)) { return false; } + for (literal& lit : lits) { + lit.neg(); + } for (enode_pair const& p : eqs) { lits.push_back(~mk_eq(p.first->get_owner(), p.second->get_owner(), false)); } From 1297eeb817c7b0340f187bee35888c3f51bce569 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 26 Jan 2019 11:55:32 -0800 Subject: [PATCH 229/318] fix #2104 Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 2 +- src/smt/theory_seq.cpp | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index f9df954fa..c8b8d27de 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -1774,7 +1774,7 @@ namespace smt { void context::set_conflict(const b_justification & js, literal not_l) { if (!inconsistent()) { - TRACE("set_conflict", display_literal_verbose(tout, not_l); display(tout << " ", js); ); + TRACE("set_conflict", display_literal_verbose(tout << m_scope_lvl << " ", not_l); display(tout << " ", js); ); m_conflict = js; m_not_l = not_l; } diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 6ac1ad4b8..2864182eb 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -340,6 +340,7 @@ bool theory_seq::reduce_length_eq() { context& ctx = get_context(); int start = ctx.get_random_value(); + TRACE("seq", tout << "reduce length eq\n";); for (unsigned i = 0; !ctx.inconsistent() && i < m_eqs.size(); ++i) { eq const& e = m_eqs[(i + start) % m_eqs.size()]; if (reduce_length_eq(e.ls(), e.rs(), e.dep())) { @@ -2688,8 +2689,8 @@ bool theory_seq::reduce_length_eq(expr_ref_vector const& ls, expr_ref_vector con rhs.append(rs.size()-1, rs.c_ptr()); SASSERT(!lhs.empty() || !rhs.empty()); deps = mk_join(deps, lits); + TRACE("seq", tout << "Propagate equal lengths " << l << " " << r << "\n" << "ls: " << ls << "\nrs: " << rs << "\n";); m_eqs.push_back(eq(m_eq_id++, lhs, rhs, deps)); - TRACE("seq", tout << "Propagate equal lengths " << l << " " << r << "\n";); propagate_eq(deps, lits, l, r, true); return true; } @@ -2762,10 +2763,6 @@ bool theory_seq::reduce_length(unsigned i, unsigned j, bool front, expr_ref_vect expr_ref lenr = mk_len(r); literal lit = mk_eq(lenl, lenr, false); if (ctx.get_assignment(lit) == l_true) { -// expr_ref len_eq(m.mk_eq(lenl, lenr), m); -// if (ctx.find_assignment(len_eq) == l_true) { -// literal lit = mk_eq(lenl, lenr, false); -// literal_vector lits; expr_ref_vector lhs(m), rhs(m); lhs.append(l2, ls2); rhs.append(r2, rs2); @@ -2776,7 +2773,6 @@ bool theory_seq::reduce_length(unsigned i, unsigned j, bool front, expr_ref_vect return true; } else { - //TRACE("seq", tout << "Assignment: " << lenl << " = " << lenr << " " << ctx.get_assignment(lit) << "\n";); return false; } } @@ -2909,13 +2905,16 @@ bool theory_seq::get_length(expr* e, expr_ref& len, literal_vector& lits) { TRACE("seq", ctx.display_literals_verbose(tout, 2, _lits); tout << "\n";); } else if (is_skolem(m_tail, e)) { + // e = tail(s, l), len(s) > l => + // len(tail(s, l)) = len(s) - l - 1 s = to_app(e)->get_arg(0); l = to_app(e)->get_arg(1); expr_ref len_s = mk_len(s); - literal len_s_ge_l = mk_simplified_literal(m_autil.mk_ge(mk_sub(len_s, l), m_autil.mk_int(0))); - if (ctx.get_assignment(len_s_ge_l) == l_true) { - len = mk_sub(len_s, l); - lits.push_back(len_s_ge_l); + literal len_s_gt_l = mk_simplified_literal(m_autil.mk_ge(mk_sub(len_s, l), m_autil.mk_int(1))); + if (ctx.get_assignment(len_s_gt_l) == l_true) { + len = mk_sub(len_s, mk_sub(l, m_autil.mk_int(1))); + TRACE("seq", tout << len_s << " " << len << " " << len_s_gt_l << "\n";); + lits.push_back(len_s_gt_l); return true; } } @@ -4952,7 +4951,7 @@ void theory_seq::add_at_axiom(expr* e) { es.push_back(m_util.str.mk_unit(mk_nth(s, m_autil.mk_int(j)))); } nth = es.back(); - es.push_back(mk_skolem(m_tail, s, m_autil.mk_int(k))); + es.push_back(mk_skolem(m_tail, s, i)); add_axiom(~i_ge_0, i_ge_len_s, mk_seq_eq(s, m_util.str.mk_concat(es))); add_axiom(~i_ge_0, i_ge_len_s, mk_seq_eq(nth, e)); } @@ -4987,6 +4986,7 @@ void theory_seq::add_nth_axiom(expr* e) { lit => s = (nth s 0) ++ (nth s 1) ++ ... ++ (nth s idx) ++ (tail s idx) */ void theory_seq::ensure_nth(literal lit, expr* s, expr* idx) { + TRACE("seq", tout << "ensure-nth: " << lit << " " << mk_pp(s, m) << " " << mk_pp(idx, m) << "\n";); rational r; SASSERT(get_context().get_assignment(lit) == l_true); VERIFY(m_autil.is_numeral(idx, r) && r.is_unsigned()); From d0b2f73c0cdd265e7143b21473c2b9b2ce6163d1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 26 Jan 2019 13:02:25 -0800 Subject: [PATCH 230/318] change opt.maxlen.enable default to true to prefer this over all other heuristics Signed-off-by: Nikolaj Bjorner --- src/opt/opt_params.pyg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 4235deb3d..dd9e26aae 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -14,7 +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, False, 'enable maxlex heuristic for lexicographic MaxSAT problems'), + ('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'), From 94dae2da3a8e3571637707cb5a1c34357ee83bd2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 27 Jan 2019 18:11:18 -0800 Subject: [PATCH 231/318] fix fourth bug produced by repros by Mark Dunlop Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 18 +++++++++++------- src/smt/smt_conflict_resolution.cpp | 4 ++-- src/smt/smt_context.h | 2 +- src/smt/smt_context_pp.cpp | 15 ++++++++------- src/smt/theory_pb.cpp | 2 ++ src/smt/theory_seq.cpp | 15 ++++++++++++--- 6 files changed, 36 insertions(+), 20 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 789aaf8db..25b51372e 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -375,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";); @@ -738,7 +738,7 @@ public: m_correction_set_size = correction_set_size; } - TRACE("opt", tout << *mdl;); + TRACE("opt_verbose", tout << *mdl;); rational upper(0); @@ -761,7 +761,7 @@ 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.set_value(m_model->is_true(s.s)); @@ -838,16 +838,17 @@ public: void commit_assignment() override { if (m_found_feasible_optimum) { - TRACE("opt", tout << "Committing feasible solution\ndefs:" << m_defs << "\nasms:" << m_asms << "\n";); 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); @@ -855,8 +856,11 @@ public: 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);); - VERIFY(is_sat == l_false); + _solver->display(tout); + tout << "other solver\n"; + s().display(tout); + ); + VERIFY(is_sat == l_false || m.canceled()); } void verify_assumptions() { diff --git a/src/smt/smt_conflict_resolution.cpp b/src/smt/smt_conflict_resolution.cpp index 7fdfbf9aa..9a3ae7728 100644 --- a/src/smt/smt_conflict_resolution.cpp +++ b/src/smt/smt_conflict_resolution.cpp @@ -1372,7 +1372,7 @@ namespace smt { } while (true) { - TRACE("unsat_core_bug", tout << consequent << " js.get_kind(): " << js.get_kind() << ", idx: " << idx << "\n";); + TRACE("unsat_core_bug", tout << consequent << ", idx: " << idx << " " << js.get_kind() << "\n";); switch (js.get_kind()) { case b_justification::CLAUSE: { clause * cls = js.get_clause(); @@ -1417,7 +1417,7 @@ namespace smt { } while (idx >= 0) { literal l = m_assigned_literals[idx]; - TRACE("unsat_core_bug", tout << "l: " << l << ", get_assign_level(l): " << m_ctx.get_assign_level(l) << ", is_marked(l): " << m_ctx.is_marked(l.var()) << "\n";); + CTRACE("unsat_core_bug", m_ctx.is_marked(l.var()), tout << "l: " << l << ", get_assign_level(l): " << m_ctx.get_assign_level(l) << "\n";); if (m_ctx.get_assign_level(l) < search_lvl) goto end_unsat_core; if (m_ctx.is_marked(l.var())) diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 6f382a5f6..ef018b895 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1358,7 +1358,7 @@ namespace smt { void display_profile(std::ostream & out) const; - void display(std::ostream& out, b_justification j) const; + std::ostream& display(std::ostream& out, b_justification j) const; // ----------------------------------- // diff --git a/src/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index 72cc2404c..c40b829a7 100644 --- a/src/smt/smt_context_pp.cpp +++ b/src/smt/smt_context_pp.cpp @@ -356,9 +356,9 @@ namespace smt { } void context::display_unsat_core(std::ostream & out) const { - unsigned sz = m_unsat_core.size(); - for (unsigned i = 0; i < sz; i++) - out << mk_pp(m_unsat_core.get(i), m_manager) << "\n"; + for (expr* c : m_unsat_core) { + out << mk_pp(c, m_manager) << "\n"; + } } void context::collect_statistics(::statistics & st) const { @@ -563,13 +563,14 @@ namespace smt { } out << "\n"; if (is_app(n)) { - for (unsigned i = 0; i < to_app(n)->get_num_args(); i++) - todo.push_back(to_app(n)->get_arg(i)); + for (expr* arg : *to_app(n)) { + todo.push_back(arg); + } } } } - void context::display(std::ostream& out, b_justification j) const { + std::ostream& context::display(std::ostream& out, b_justification j) const { switch (j.get_kind()) { case b_justification::AXIOM: out << "axiom"; @@ -593,7 +594,7 @@ namespace smt { UNREACHABLE(); break; } - out << "\n"; + return out << "\n"; } void context::trace_assign(literal l, b_justification j, bool decision) const { diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 86d84c60a..875fe8de4 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1924,6 +1924,7 @@ namespace smt { process_antecedent(~js.get_literal(), offset); break; case b_justification::AXIOM: + bound = 0; break; case b_justification::JUSTIFICATION: { justification* j = js.get_justification(); @@ -1934,6 +1935,7 @@ namespace smt { } if (pbj == nullptr) { TRACE("pb", tout << "skip justification for " << conseq << "\n";); + bound = 0; // this is possible when conseq is an assumption. // The justification of conseq is itself, // don't increment the cofficient here because it assumes diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 2864182eb..37297997a 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2905,17 +2905,26 @@ bool theory_seq::get_length(expr* e, expr_ref& len, literal_vector& lits) { TRACE("seq", ctx.display_literals_verbose(tout, 2, _lits); tout << "\n";); } else if (is_skolem(m_tail, e)) { - // e = tail(s, l), len(s) > l => - // len(tail(s, l)) = len(s) - l - 1 + // e = tail(s, l), len(s) > l => len(tail(s, l)) = len(s) - l - 1 + // e = tail(s, l), len(s) <= l => len(tail(s, l)) = 0 + s = to_app(e)->get_arg(0); l = to_app(e)->get_arg(1); expr_ref len_s = mk_len(s); literal len_s_gt_l = mk_simplified_literal(m_autil.mk_ge(mk_sub(len_s, l), m_autil.mk_int(1))); - if (ctx.get_assignment(len_s_gt_l) == l_true) { + switch (ctx.get_assignment(len_s_gt_l)) { + case l_true: len = mk_sub(len_s, mk_sub(l, m_autil.mk_int(1))); TRACE("seq", tout << len_s << " " << len << " " << len_s_gt_l << "\n";); lits.push_back(len_s_gt_l); return true; + case l_false: + len = m_autil.mk_int(0); + TRACE("seq", tout << len_s << " " << len << " " << len_s_gt_l << "\n";); + lits.push_back(~len_s_gt_l); + return true; + default: + break; } } else if (m_util.str.is_unit(e)) { From 4f988595c7800dafd63e81015cbce1e0cd32ec3b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 27 Jan 2019 19:45:19 -0800 Subject: [PATCH 232/318] fix #2107 Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index c8b8d27de..9d4c9f852 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3244,8 +3244,13 @@ namespace smt { proof * pr = m_manager.mk_asserted(curr_assumption); internalize_assertion(curr_assumption, pr, 0); literal l = get_literal(curr_assumption); + if (l == true_literal) + continue; + if (l == false_literal) { + set_conflict(b_justification::mk_axiom()); + break; + } m_literal2assumption.insert(l.index(), orig_assumption); - // mark_as_relevant(l); <<< not needed // internalize_assertion marked l as relevant. SASSERT(is_relevant(l)); TRACE("assumptions", tout << l << ":" << curr_assumption << " " << mk_pp(orig_assumption, m_manager) << "\n";); From 58f5531cfff1324aa001cd1da6c750669510a87b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 29 Jan 2019 08:18:03 -0800 Subject: [PATCH 233/318] fix #2114 introduced while working on #2095 Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 125 ++++++++++++++++++++++------------------- src/sat/sat_solver.h | 1 + src/solver/solver.cpp | 7 ++- 3 files changed, 72 insertions(+), 61 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index fa1d9352d..dd25c9d2b 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1664,6 +1664,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";); @@ -1890,75 +1891,81 @@ 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 && get_verbosity_level() >= 1) { - m_restart_logs++; if (0 == m_restart_next_out) { m_restart_next_out = 1; } else { m_restart_next_out = (3*m_restart_next_out)/2 + 1; } - - 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); + log_stats(); } IF_VERBOSE(30, display_status(verbose_stream());); pop_reinit(restart_level(to_base)); diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 48fc54598..96cc53b4a 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -425,6 +425,7 @@ namespace sat { 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(); diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 6f4880d38..9126ab1a2 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -338,8 +338,11 @@ lbool solver::check_sat(unsigned num_assumptions, expr * const * assumptions) { } void solver::dump_state(unsigned sz, expr* const* assumptions) { - std::string file = m_cancel_backup_file.str(); - if (file != "") { + if ((symbol::null != m_cancel_backup_file) && + !m_cancel_backup_file.is_numerical() && + m_cancel_backup_file.c_ptr() && + m_cancel_backup_file.bare_str()[0]) { + std::string file = m_cancel_backup_file.str(); std::ofstream ous(file); display(ous, sz, assumptions); } From 8d203107580cd4845e121c5e8b4146869a386459 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 29 Jan 2019 14:45:51 -0800 Subject: [PATCH 234/318] adding trail/levels Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 38 ++++++++++++++++++- src/api/z3_api.h | 16 ++++++++ src/muz/spacer/spacer_iuc_solver.h | 2 + src/opt/opt_solver.cpp | 3 ++ src/opt/opt_solver.h | 2 + src/sat/sat_solver.h | 1 + src/sat/sat_solver/inc_sat_solver.cpp | 23 +++++++++++ src/smt/smt_context.cpp | 16 ++++++++ src/smt/smt_context.h | 4 ++ src/smt/smt_internalizer.cpp | 2 +- src/smt/smt_kernel.cpp | 17 +++++++++ src/smt/smt_kernel.h | 10 +++++ src/smt/smt_solver.cpp | 8 ++++ src/solver/combined_solver.cpp | 14 +++++++ src/solver/solver.cpp | 7 +++- src/solver/solver.h | 8 +++- src/solver/solver_pool.cpp | 8 ++++ src/solver/tactic2solver.cpp | 8 ++++ .../fd_solver/bounded_int2bv_solver.cpp | 6 +++ src/tactic/fd_solver/enum2bv_solver.cpp | 6 +++ src/tactic/fd_solver/pb2bv_solver.cpp | 7 ++++ 21 files changed, 199 insertions(+), 7 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 330d0f2bc..8be818e5e 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -386,7 +386,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); } @@ -401,7 +401,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); } @@ -409,6 +409,40 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } + void Z3_API Z3_solver_get_levels(Z3_context c, Z3_solver s, unsigned sz, Z3_ast literals[], unsigned levels[]) { + Z3_TRY; + LOG_Z3_solver_get_levels(c, s, sz, literals, levels); + RESET_ERROR_CODE(); + init_solver(c, s); + ptr_vector _vars; + for (unsigned i = 0; i < sz; ++i) { + expr* e = to_expr(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; + } + + 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]))) { diff --git a/src/api/z3_api.h b/src/api/z3_api.h index cd52d2d86..b7e043f00 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -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,6 +6228,15 @@ 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(UINT), _in_array(2, AST), _in_array(2, UINT))) + */ + void Z3_API Z3_solver_get_levels(Z3_context c, Z3_solver s, unsigned sz, Z3_ast literals[], unsigned levels[]); + + /** \brief Check whether the assertions in a given solver are consistent or not. diff --git a/src/muz/spacer/spacer_iuc_solver.h b/src/muz/spacer/spacer_iuc_solver.h index a51bfbef9..67fdc0fc3 100644 --- a/src/muz/spacer/spacer_iuc_solver.h +++ b/src/muz/spacer/spacer_iuc_solver.h @@ -122,6 +122,8 @@ 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() { return m_solver.get_trail(); } void push() override; void pop(unsigned n) override; diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 78851f5cb..80a81ba3a 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -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 8d2abdb93..9eda063e9 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -108,6 +108,8 @@ 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(); } expr_ref_vector cube(expr_ref_vector&, unsigned) override { return expr_ref_vector(m); } void set_logic(symbol const& logic); diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 96cc53b4a..dd81bac2e 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -300,6 +300,7 @@ namespace sat { 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; } + unsigned trail_size() const { return m_trail.size(); } literal trail_literal(unsigned i) const { 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) { diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 34348f0fc..fd795dbc7 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -318,6 +318,29 @@ 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 = 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; + } + proof * get_proof() override { UNREACHABLE(); return nullptr; diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 9d4c9f852..86b3374fc 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -4423,6 +4423,22 @@ namespace smt { m = const_cast(m_model.get()); } + void context::get_levels(ptr_vector const& vars, unsigned_vector& depth) { + unsigned sz = vars.size(); + depth.resize(sz); + for (unsigned i = 0; i < sz; ++i) { + expr* v = vars[i]; + bool_var bv = m_expr2bool_var.get(v->get_id(), null_bool_var); + depth[i] = bv == null_bool_var ? UINT_MAX : get_assign_level(bv); + } + } + + expr_ref_vector context::get_trail() { + expr_ref_vector result(get_manager()); + get_assignments(result); + return result; + } + void context::get_proto_model(proto_model_ref & m) const { m = const_cast(m_proto_model.get()); } diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index ef018b895..d935bf53e 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1575,6 +1575,10 @@ namespace smt { return m_unsat_core.get(idx); } + void get_levels(ptr_vector const& vars, unsigned_vector& depth); + + expr_ref_vector get_trail(); + void get_model(model_ref & m) const; bool update_model(bool refinalize); diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index 4a6cd086c..1cf816d55 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -196,7 +196,7 @@ namespace smt { TRACE("incompleteness_bug", tout << "[internalize-assertion]: #" << n->get_id() << "\n";); flet l(m_generation, generation); m_stats.m_max_generation = std::max(m_generation, m_stats.m_max_generation); - if (get_depth(n) > DEEP_EXPR_THRESHOLD) { + if (::get_depth(n) > DEEP_EXPR_THRESHOLD) { // if the expression is deep, then execute topological sort to avoid // stack overflow. // a caveat is that theory internalizers do rely on recursive descent so diff --git a/src/smt/smt_kernel.cpp b/src/smt/smt_kernel.cpp index b03604b5b..f2f17321c 100644 --- a/src/smt/smt_kernel.cpp +++ b/src/smt/smt_kernel.cpp @@ -146,6 +146,14 @@ namespace smt { expr * get_unsat_core_expr(unsigned idx) const { return m_kernel.get_unsat_core_expr(idx); } + + void get_levels(ptr_vector const& vars, unsigned_vector& depth) { + m_kernel.get_levels(vars, depth); + } + + expr_ref_vector get_trail() { + return m_kernel.get_trail(); + } failure last_failure() const { return m_kernel.get_last_search_failure(); @@ -396,4 +404,13 @@ namespace smt { return m_imp->m_kernel; } + void kernel::get_levels(ptr_vector const& vars, unsigned_vector& depth) { + m_imp->get_levels(vars, depth); + } + + expr_ref_vector kernel::get_trail() { + return m_imp->get_trail(); + } + + }; diff --git a/src/smt/smt_kernel.h b/src/smt/smt_kernel.h index d78f71e20..6eeb8d728 100644 --- a/src/smt/smt_kernel.h +++ b/src/smt/smt_kernel.h @@ -219,6 +219,16 @@ namespace smt { */ expr* next_decision(); + /** + \brief retrieve depth of variables from decision stack. + */ + void get_levels(ptr_vector const& vars, unsigned_vector& depth); + + /** + \brief retrieve trail of assignment stack. + */ + expr_ref_vector get_trail(); + /** \brief (For debubbing purposes) Prints the state of the kernel */ diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 5d32d1bed..e36858b06 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -195,6 +195,14 @@ namespace smt { return m_context.check(cube, clauses); } + void get_levels(ptr_vector const& vars, unsigned_vector& depth) override { + m_context.get_levels(vars, depth); + } + + expr_ref_vector get_trail() override { + return m_context.get_trail(); + } + struct scoped_minimize_core { smt_solver& s; expr_ref_vector m_assumptions; diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index 813b2be18..b602fe6e1 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -314,6 +314,20 @@ public: m_solver2->get_model(m); } + void get_levels(ptr_vector const& vars, unsigned_vector& depth) override { + if (m_use_solver1_results) + m_solver1->get_levels(vars, depth); + else + m_solver2->get_levels(vars, depth); + } + + expr_ref_vector get_trail() override { + if (m_use_solver1_results) + return m_solver1->get_trail(); + else + return m_solver2->get_trail(); + } + proof * get_proof() override { if (m_use_solver1_results) return m_solver1->get_proof(); diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 9126ab1a2..89421f079 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -251,7 +251,8 @@ void solver::updt_params(params_ref const & p) { } -expr_ref_vector solver::get_units(ast_manager& m) { +expr_ref_vector solver::get_units() { + ast_manager& m = get_manager(); expr_ref_vector fmls(m), result(m), tmp(m); get_assertions(fmls); obj_map units; @@ -284,7 +285,8 @@ expr_ref_vector solver::get_units(ast_manager& m) { } -expr_ref_vector solver::get_non_units(ast_manager& m) { +expr_ref_vector solver::get_non_units() { + ast_manager& m = get_manager(); expr_ref_vector result(m), fmls(m); get_assertions(fmls); family_id bfid = m.get_basic_family_id(); @@ -320,6 +322,7 @@ expr_ref_vector solver::get_non_units(ast_manager& m) { return result; } + lbool solver::check_sat(unsigned num_assumptions, expr * const * assumptions) { lbool r = l_undef; try { diff --git a/src/solver/solver.h b/src/solver/solver.h index 161677cb5..0c509b8c7 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -243,9 +243,13 @@ public: /** \brief extract units from solver. */ - expr_ref_vector get_units(ast_manager& m); + expr_ref_vector get_units(); - expr_ref_vector get_non_units(ast_manager& m); + expr_ref_vector get_non_units(); + + virtual expr_ref_vector get_trail() = 0; // { return expr_ref_vector(get_manager()); } + + virtual void get_levels(ptr_vector const& vars, unsigned_vector& depth) = 0; class scoped_push { solver& s; diff --git a/src/solver/solver_pool.cpp b/src/solver/solver_pool.cpp index 0495e8a3d..7f3882447 100644 --- a/src/solver/solver_pool.cpp +++ b/src/solver/solver_pool.cpp @@ -119,6 +119,14 @@ public: } } + void get_levels(ptr_vector const& vars, unsigned_vector& depth) override { + m_base->get_levels(vars, depth); + } + + expr_ref_vector get_trail() override { + return m_base->get_trail(); + } + lbool check_sat_core2(unsigned num_assumptions, expr * const * assumptions) override { SASSERT(!m_pushed || get_scope_level() > 0); m_proof.reset(); diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 298ed9bc5..8721e106b 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -85,6 +85,14 @@ public: model_converter_ref get_model_converter() const override { return m_mc; } + void get_levels(ptr_vector const& vars, unsigned_vector& depth) override { + throw default_exception("cannot retrieve depth from solvers created using tactics"); + } + + expr_ref_vector get_trail() override { + throw default_exception("cannot retrieve trail from solvers created using tactcis"); + } + }; ast_manager& tactic2solver::get_manager() const { return m_assertions.get_manager(); } diff --git a/src/tactic/fd_solver/bounded_int2bv_solver.cpp b/src/tactic/fd_solver/bounded_int2bv_solver.cpp index 45d1344ba..b19875737 100644 --- a/src/tactic/fd_solver/bounded_int2bv_solver.cpp +++ b/src/tactic/fd_solver/bounded_int2bv_solver.cpp @@ -155,6 +155,12 @@ public: if (mc) (*mc)(mdl); } } + 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(); + } model_converter* external_model_converter() const { return concat(mc0(), local_model_converter()); } diff --git a/src/tactic/fd_solver/enum2bv_solver.cpp b/src/tactic/fd_solver/enum2bv_solver.cpp index b9a564542..d8119ddfd 100644 --- a/src/tactic/fd_solver/enum2bv_solver.cpp +++ b/src/tactic/fd_solver/enum2bv_solver.cpp @@ -178,7 +178,13 @@ public: return r; } + 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(); + } unsigned get_num_assertions() const override { return m_solver->get_num_assertions(); diff --git a/src/tactic/fd_solver/pb2bv_solver.cpp b/src/tactic/fd_solver/pb2bv_solver.cpp index b3620c8ec..29aa573e3 100644 --- a/src/tactic/fd_solver/pb2bv_solver.cpp +++ b/src/tactic/fd_solver/pb2bv_solver.cpp @@ -96,6 +96,13 @@ public: if (mc) (*mc)(mdl); } } + 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(); + } model_converter* external_model_converter() const{ return concat(mc0(), local_model_converter()); From 08ce6f7ac16b3c80ee447db91db727aa05955dbd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 Jan 2019 08:54:59 -0800 Subject: [PATCH 235/318] working on binary drat format Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 10 ++++--- src/api/c++/z3++.h | 11 ++++++++ src/api/python/z3/z3.py | 13 +++++++++ src/api/z3_api.h | 4 +-- src/sat/sat_config.cpp | 1 + src/sat/sat_config.h | 1 + src/sat/sat_drat.cpp | 50 ++++++++++++++++++++++++++++++----- src/sat/sat_drat.h | 2 ++ src/sat/sat_params.pyg | 1 + src/sat/sat_solver.cpp | 2 +- src/shell/dimacs_frontend.cpp | 6 ++++- 11 files changed, 88 insertions(+), 13 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 8be818e5e..ddaaf71f9 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -409,14 +409,18 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } - void Z3_API Z3_solver_get_levels(Z3_context c, Z3_solver s, unsigned sz, Z3_ast literals[], unsigned levels[]) { + 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, sz, literals, levels); + 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(literals[i]); + expr* e = to_expr(Z3_ast_vector_get(c, literals, i)); mk_c(c)->m().is_not(e, e); _vars.push_back(e); } diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index a307df4bb..f1053fc0c 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -2233,6 +2233,17 @@ 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 = array(sz); + Z3_solver_get_levels(ctx(), m_solver, r, sz, levels.c_ptr()); + check_error(); + return result; + } 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); diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 6147dbd65..04d7456b8 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -6727,6 +6727,19 @@ 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 statistics(self): """Return statistics for the last `check()`. diff --git a/src/api/z3_api.h b/src/api/z3_api.h index b7e043f00..6f65e4a37 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -6232,9 +6232,9 @@ extern "C" { \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(UINT), _in_array(2, AST), _in_array(2, UINT))) + 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, unsigned sz, Z3_ast literals[], unsigned levels[]); + void Z3_API Z3_solver_get_levels(Z3_context c, Z3_solver s, Z3_ast_vector literals, unsigned sz, unsigned levels[]); /** diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 5516cdb7c..6e415e7f3 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -165,6 +165,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 deb67b197..79baa621e 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -156,6 +156,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 e7b9088d5..ebd8b8660 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -27,18 +27,24 @@ 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() { 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)) { @@ -74,6 +80,33 @@ namespace sat { (*m_out) << "0\n"; } + void drat::bdump(unsigned n, literal const* c, status st) { + unsigned char ch = 0; + switch (st) { + case status::asserted: UNREACHABLE(); return; + case status::external: UNREACHABLE(); return; // requires extension to drat format. + case status::learned: ch = 'a'; break; + case status::deleted: ch = 'd'; break; + default: UNREACHABLE(); break; + } + (*m_bout) << 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 & ((1 << 7) - 1)); + v >>= 7; + if (v) ch |= (1 << 7); + //std::cout << std::hex << ((unsigned char)ch) << std::dec << " "; + (*m_bout) << ch; + } + while (v); + } + ch = 0; + (*m_bout) << 0; + } + bool drat::is_cleaned(clause& c) const { literal last = null_literal; unsigned n = c.size(); @@ -513,6 +546,7 @@ namespace sat { void drat::add() { if (m_out) (*m_out) << "0\n"; + if (m_bout) bdump(0, nullptr, learned); if (m_check_unsat) { SASSERT(m_inconsistent); } @@ -521,6 +555,7 @@ namespace sat { 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) { @@ -529,6 +564,7 @@ namespace sat { 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) { @@ -536,6 +572,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) { @@ -554,6 +591,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; @@ -570,11 +608,13 @@ 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_bout) bdump(2, ls, status::deleted); if (m_check) append(l1, l2, status::deleted); } @@ -593,17 +633,15 @@ namespace sat { #endif TRACE("sat", tout << "del: " << c << "\n";); - if (m_out) { - dump(c.size(), c.begin(), status::deleted); - } + 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 35da0c31a..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); diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index cca45aa72..0fdb1aa70 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'), diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index dd25c9d2b..5ea039763 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -337,7 +337,6 @@ namespace sat { switch (num_lits) { case 0: - if (m_config.m_drat) m_drat.add(); set_conflict(justification()); return nullptr; case 1: @@ -2290,6 +2289,7 @@ namespace sat { unsigned new_sz = j; switch (new_sz) { case 0: + if (m_config.m_drat) m_drat.add(); set_conflict(justification()); return false; case 1: diff --git a/src/shell/dimacs_frontend.cpp b/src/shell/dimacs_frontend.cpp index 9a4e65896..114d8daf6 100644 --- a/src/shell/dimacs_frontend.cpp +++ b/src/shell/dimacs_frontend.cpp @@ -248,7 +248,11 @@ unsigned read_dimacs(char const * file_name) { lbool r; vector tracking_clauses; - sat::solver solver2(p, limit); + params_ref p2; + p2.copy(p); + p2.set_sym("drat.file", symbol::null); + + sat::solver solver2(p2, limit); if (p.get_bool("dimacs.core", false)) { g_solver = &solver2; sat::literal_vector assumptions; From 35eb21bc35a996b0fef387062f29673b78a7b189 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 Jan 2019 09:06:41 -0800 Subject: [PATCH 236/318] fix extraction of trail Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 2 +- src/sat/sat_solver/inc_sat_solver.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 04d7456b8..43b361b5f 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -6731,7 +6731,7 @@ class Solver(Z3PPObject): """Return trail and decision levels of the solver state after a check() call. """ trail = self.trail() - levels = (ctypes.c_uint * len(trail)) + levels = (ctypes.c_uint * len(trail))() Z3_solver_get_levels(self.ctx.ref(), self.solver, trail.vector, len(trail), levels) return trail, levels diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index fd795dbc7..f0712da38 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -324,7 +324,7 @@ public: depth.resize(sz); for (unsigned i = 0; i < sz; ++i) { auto bv = m_map.to_bool_var(vars[i]); - depth = bv == sat::null_bool_var ? UINT_MAX : m_solver.lvl(bv); + depth[i] = bv == sat::null_bool_var ? UINT_MAX : m_solver.lvl(bv); } } From e004986e992010a58ff637a430f5a202bd9df1b2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 Jan 2019 09:20:38 -0800 Subject: [PATCH 237/318] fix z3++.h Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index f1053fc0c..d94b4f36b 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_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]; } @@ -2239,8 +2240,8 @@ namespace z3 { check_error(); expr_vector result(ctx(), r); unsigned sz = result.size(); - levels = array(sz); - Z3_solver_get_levels(ctx(), m_solver, r, sz, levels.c_ptr()); + levels.resize(sz); + Z3_solver_get_levels(ctx(), m_solver, r, sz, levels.ptr()); check_error(); return result; } From cb94f82f37f0a8fb0677a3318640d36f7c4bffa6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 Jan 2019 09:31:05 -0800 Subject: [PATCH 238/318] fix #2118 Signed-off-by: Nikolaj Bjorner --- src/opt/maxlex.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/opt/maxlex.cpp b/src/opt/maxlex.cpp index 1ee9db090..b2799f1c8 100644 --- a/src/opt/maxlex.cpp +++ b/src/opt/maxlex.cpp @@ -127,7 +127,7 @@ namespace opt { } model_ref mdl; s().get_model(mdl); - update_assignment(mdl); + if (mdl) update_assignment(mdl); } lbool maxlex1() { From cda78d8d0b0cc8c3f51d7dbd587e6dd93a584940 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 Jan 2019 09:34:45 -0800 Subject: [PATCH 239/318] #2117 Signed-off-by: Nikolaj Bjorner --- src/test/matcher.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/matcher.cpp b/src/test/matcher.cpp index cd220a9c6..68f37ccb6 100644 --- a/src/test/matcher.cpp +++ b/src/test/matcher.cpp @@ -84,7 +84,7 @@ void tst1() { app_ref b( m.mk_const(symbol("b"), s), m); expr_ref x( m.mk_var(0, s), m); expr_ref y( m.mk_var(1, s), m); - app_ref gx( m.mk_app(g, x), m); + app_ref gx( m.mk_app(g.get(), x.get()), m); app_ref fgx_x( m.mk_app(f, gx.get(), x.get()), m); app_ref ha( m.mk_app(h, a.get()), m); app_ref gha( m.mk_app(g, ha.get()), m); From 1e90be62bc8b414ca67a2014ff4ca9225907d03e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 31 Jan 2019 14:58:51 -0800 Subject: [PATCH 240/318] fix drat for lookahead, fixes for binary drat format Signed-off-by: Nikolaj Bjorner --- src/sat/sat_drat.cpp | 11 ++++++----- src/sat/sat_lookahead.cpp | 8 ++++---- src/sat/sat_lookahead.h | 2 -- src/solver/parallel_tactic.cpp | 18 +++++++++++------- 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index ebd8b8660..5b620ed6e 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -43,6 +43,8 @@ namespace sat { } 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) { @@ -83,8 +85,8 @@ namespace sat { void drat::bdump(unsigned n, literal const* c, status st) { unsigned char ch = 0; switch (st) { - case status::asserted: UNREACHABLE(); return; - case status::external: UNREACHABLE(); return; // requires extension to drat format. + case status::asserted: return; + case status::external: return; case status::learned: ch = 'a'; break; case status::deleted: ch = 'd'; break; default: UNREACHABLE(); break; @@ -104,7 +106,7 @@ namespace sat { while (v); } ch = 0; - (*m_bout) << 0; + (*m_bout) << ch; } bool drat::is_cleaned(clause& c) const { @@ -615,8 +617,7 @@ namespace sat { literal ls[2] = {l1, l2}; if (m_out) dump(2, ls, status::deleted); if (m_bout) bdump(2, ls, status::deleted); - if (m_check) - append(l1, l2, status::deleted); + if (m_check) append(l1, l2, status::deleted); } void drat::del(clause& c) { diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 0e364180c..1a2b432df 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -113,7 +113,7 @@ namespace sat { if (m_search_mode == lookahead_mode::searching) { m_assumptions.push_back(l1); m_assumptions.push_back(l2); - m_drat.add(m_assumptions); + m_s.m_drat.add(m_assumptions); m_assumptions.pop_back(); m_assumptions.pop_back(); } @@ -1032,7 +1032,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); } } @@ -1065,7 +1065,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); } } @@ -1927,7 +1927,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(); } } diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 2d725f415..606fd2b8c 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -200,7 +200,6 @@ namespace sat { double m_delta_decrease; double m_delta_fraction; - drat m_drat; literal_vector m_assumptions; literal_vector m_trail; // trail of units @@ -565,7 +564,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/solver/parallel_tactic.cpp b/src/solver/parallel_tactic.cpp index 5fccadcbd..eda80b74b 100644 --- a/src/solver/parallel_tactic.cpp +++ b/src/solver/parallel_tactic.cpp @@ -330,6 +330,7 @@ private: volatile bool m_has_undef; bool m_allsat; unsigned m_num_unsat; + unsigned m_last_depth; int m_exn_code; std::string m_exn_msg; @@ -340,7 +341,8 @@ private: m_has_undef = false; m_allsat = false; m_branches = 0; - m_num_unsat = 0; + m_num_unsat = 0; + m_last_depth = 0; m_backtrack_frequency = pp.conquer_backtrack_frequency(); m_conquer_delay = pp.conquer_delay(); m_exn_code = 0; @@ -350,9 +352,10 @@ private: void log_branches(lbool status) { IF_VERBOSE(0, verbose_stream() << "(tactic.parallel :progress " << m_progress << "% "; - if (status == l_true) verbose_stream() << ":status sat "; - if (status == l_undef) verbose_stream() << ":status unknown "; - verbose_stream() << ":closed " << m_num_unsat << " :open " << m_branches << ")\n";); + if (status == l_true) verbose_stream() << ":status sat"; + if (status == l_undef) verbose_stream() << ":status unknown"; + if (m_num_unsat > 0) verbose_stream() << " :closed " << m_num_unsat << "@" << m_last_depth; + verbose_stream() << " :open " << m_branches << ")\n";); } void add_branches(unsigned b) { @@ -405,13 +408,14 @@ private: } } - void inc_unsat() { + void inc_unsat(solver_state& s) { std::lock_guard lock(m_mutex); ++m_num_unsat; + m_last_depth = s.get_depth(); } void report_unsat(solver_state& s) { - inc_unsat(); + inc_unsat(s); close_branch(s, l_false); if (s.has_assumptions()) { expr_ref_vector core(s.m()); @@ -489,7 +493,7 @@ private: IF_VERBOSE(0, verbose_stream() << "(tactic.parallel :backtrack " << cutoff << " -> " << c.size() << ")\n"); cutoff = c.size(); } - inc_unsat(); + inc_unsat(s); log_branches(l_false); break; From 7fa9768c365dc2a8464df8ec96a934d847a085b8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 1 Feb 2019 09:16:46 -0800 Subject: [PATCH 241/318] improving drat output perf Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 13 ++++++++++++- src/opt/opt_context.h | 8 ++++++-- src/sat/sat_drat.cpp | 36 +++++++++++++++++++++++++++++------- src/sat/sat_lookahead.cpp | 3 +++ 4 files changed, 50 insertions(+), 10 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index cc1456ac9..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) { @@ -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; diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 796e83535..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); diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index 5b620ed6e..1b53875d8 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -72,14 +72,36 @@ namespace sat { } void drat::dump(unsigned n, literal const* c, status st) { - 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; + if (st == status::asserted || st == status::external) { + return; } - for (unsigned i = 0; i < n; ++i) (*m_out) << c[i] << " "; - (*m_out) << "0\n"; + + char buffer[10000]; + int len = 0; + if (st == status::deleted) { + buffer[0] = 'd'; + buffer[1] = ' '; + len = 2; + } + for (unsigned i = 0; i < n && len >= 0; ++i) { + literal lit = c[i]; + int _lit = lit.var(); + if (lit.sign()) _lit = -_lit; + len += snprintf(buffer + len, sizeof(buffer) - len, "%d ", _lit); + } + + if (len >= 0) { + len += snprintf(buffer + len, sizeof(buffer) - len, "0\n"); + } + if (len >= 0) { + m_out->write(buffer, len); + } + else { + if (st == status::deleted) (*m_out) << "d "; + for (unsigned i = 0; i < n; ++i) (*m_out) << c[i] << " "; + (*m_out) << "0\n"; + } + } void drat::bdump(unsigned n, literal const* c, status st) { diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 1a2b432df..8297e2a99 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1701,6 +1701,7 @@ namespace sat { if (is_fixed_at(lit, c_fixed_truth) || is_true_at(lit, level)) continue; bool unsat = false; if (is_false_at(lit, level)) { + if (lit.sign() && lit.var() == 34523) std::cout << "false at " << lit << "\n"; unsat = true; } else { @@ -1708,7 +1709,9 @@ namespace sat { reset_lookahead_reward(lit); unsigned num_units = push_lookahead1(lit, level); update_lookahead_reward(lit, level); + if (lit.sign() && lit.var() == 34523) std::cout << "num units.1 " << num_units << " " << inconsistent() << "\n"; num_units += do_double(lit, dl_lvl); + if (lit.sign() && lit.var() == 34523) std::cout << "num units.2 " << num_units << "\n"; if (dl_lvl > level) { base = dl_lvl; //SASSERT(get_level(m_trail.back()) == base + m_lookahead[i].m_offset); From cca280ac47a62439a59b46bca63ac1e9d1bc6469 Mon Sep 17 00:00:00 2001 From: Daniel Selsam Date: Thu, 31 Jan 2019 16:45:01 -0800 Subject: [PATCH 242/318] do not echo dimacs while parsing --- src/api/api_solver.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index ddaaf71f9..1c0664bb2 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -188,7 +188,6 @@ extern "C" { // 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) { - std::cout << c_str << "\n"; return c_str[0] == 'p' && c_str[1] == ' ' && c_str[2] == 'c'; } From df73c58195762938712dcc143ca527dbccaad8cc Mon Sep 17 00:00:00 2001 From: Daniel Selsam Date: Fri, 1 Feb 2019 09:34:24 -0800 Subject: [PATCH 243/318] array resize must m_size --- src/api/c++/z3++.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index d94b4f36b..1900c6f00 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -388,7 +388,7 @@ namespace z3 { template array(ast_vector_tpl const & v); ~array() { delete[] m_array; } - void resize(unsigned sz) { delete[] m_array; m_array = new T[sz]; } + 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]; } From e07f0c0284ec8561a34858489d02dc05574ffd01 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 1 Feb 2019 13:35:54 -0800 Subject: [PATCH 244/318] tune generation of drat files, add helpful binary clause in lookahead simplification Signed-off-by: Nikolaj Bjorner --- src/sat/sat_drat.cpp | 44 ++++++++++++++++++++++++++++++++------- src/sat/sat_lookahead.cpp | 26 +++++++++++------------ 2 files changed, 49 insertions(+), 21 deletions(-) diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index 1b53875d8..c28c1f487 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -76,24 +76,54 @@ namespace sat { return; } +#if 0 + if (st == status::deleted) (*m_out) << "d "; + for (unsigned i = 0; i < n; ++i) (*m_out) << c[i] << " "; + (*m_out) << "0\n"; + return; +#endif + 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 && len >= 0; ++i) { + for (unsigned i = 0; i < n && len < sizeof(buffer); ++i) { literal lit = c[i]; - int _lit = lit.var(); - if (lit.sign()) _lit = -_lit; - len += snprintf(buffer + len, sizeof(buffer) - len, "%d ", _lit); + 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); + } + if (len + lastd - d < sizeof(buffer)) { + memcpy(buffer + len, d, lastd - d); + len += static_cast(lastd - d); + } + else { + len = sizeof(buffer) + 1; + } + if (len < sizeof(buffer)) { + buffer[len++] = ' '; + } } - if (len >= 0) { - len += snprintf(buffer + len, sizeof(buffer) - len, "0\n"); + if (len < sizeof(buffer) + 2) { + buffer[len++] = '0'; + buffer[len++] = '\n'; } - if (len >= 0) { + else { + len = sizeof(buffer) + 1; + } + if (len <= sizeof(buffer)) { m_out->write(buffer, len); } else { diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 8297e2a99..5c33f8d3d 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_s.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() { @@ -1701,7 +1699,6 @@ namespace sat { if (is_fixed_at(lit, c_fixed_truth) || is_true_at(lit, level)) continue; bool unsat = false; if (is_false_at(lit, level)) { - if (lit.sign() && lit.var() == 34523) std::cout << "false at " << lit << "\n"; unsat = true; } else { @@ -1709,9 +1706,7 @@ namespace sat { reset_lookahead_reward(lit); unsigned num_units = push_lookahead1(lit, level); update_lookahead_reward(lit, level); - if (lit.sign() && lit.var() == 34523) std::cout << "num units.1 " << num_units << " " << inconsistent() << "\n"; num_units += do_double(lit, dl_lvl); - if (lit.sign() && lit.var() == 34523) std::cout << "num units.2 " << num_units << "\n"; if (dl_lvl > level) { base = dl_lvl; //SASSERT(get_level(m_trail.back()) == base + m_lookahead[i].m_offset); @@ -1849,13 +1844,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; @@ -1873,6 +1870,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; From 6c464f8aec5dcbf3d22f33c17d8bbc481a7aeba6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 1 Feb 2019 14:59:36 -0800 Subject: [PATCH 245/318] add assert_and_track to optimize for #2116 Signed-off-by: Nikolaj Bjorner --- src/api/api_opt.cpp | 10 +++++++++ src/api/c++/z3++.h | 5 +++++ src/api/python/z3/z3.py | 30 +++++++++++++++++++++++++ src/api/z3_optimization.h | 12 ++++++++++ src/sat/sat_drat.cpp | 47 ++++++++++----------------------------- 5 files changed, 69 insertions(+), 35 deletions(-) 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/c++/z3++.h b/src/api/c++/z3++.h index 1900c6f00..e711457a3 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -2646,6 +2646,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/python/z3/z3.py b/src/api/python/z3/z3.py index 43b361b5f..725ac33b4 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -7336,6 +7336,36 @@ 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.set(unsat_core=True) + >>> 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 diff --git a/src/api/z3_optimization.h b/src/api/z3_optimization.h index a8ffd45ab..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 diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index c28c1f487..997ee971e 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -76,13 +76,6 @@ namespace sat { return; } -#if 0 - if (st == status::deleted) (*m_out) << "d "; - for (unsigned i = 0; i < n; ++i) (*m_out) << c[i] << " "; - (*m_out) << "0\n"; - return; -#endif - char buffer[10000]; char digits[20]; // enough for storing unsigned char* lastd = digits + sizeof(digits); @@ -93,7 +86,7 @@ namespace sat { buffer[1] = ' '; len = 2; } - for (unsigned i = 0; i < n && len < sizeof(buffer); ++i) { + for (unsigned i = 0; i < n; ++i) { literal lit = c[i]; unsigned v = lit.var(); if (lit.sign()) buffer[len++] = '-'; @@ -104,34 +97,18 @@ namespace sat { v /= 10; SASSERT(d > digits); } - if (len + lastd - d < sizeof(buffer)) { - memcpy(buffer + len, d, lastd - d); - len += static_cast(lastd - d); + 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; } - else { - len = sizeof(buffer) + 1; - } - if (len < sizeof(buffer)) { - buffer[len++] = ' '; - } - } - - if (len < sizeof(buffer) + 2) { - buffer[len++] = '0'; - buffer[len++] = '\n'; - } - else { - len = sizeof(buffer) + 1; - } - if (len <= sizeof(buffer)) { - m_out->write(buffer, len); - } - else { - if (st == status::deleted) (*m_out) << "d "; - for (unsigned i = 0; i < n; ++i) (*m_out) << c[i] << " "; - (*m_out) << "0\n"; - } - + } + buffer[len++] = '0'; + buffer[len++] = '\n'; + m_out->write(buffer, len); } void drat::bdump(unsigned n, literal const* c, status st) { From a76107e50d3a75dc4404d72af6d25e6e42d576cc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 1 Feb 2019 18:44:52 -0800 Subject: [PATCH 246/318] fix build Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 1 - src/muz/spacer/spacer_iuc_solver.h | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 725ac33b4..4de05d31c 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -7344,7 +7344,6 @@ class Optimize(Z3PPObject): >>> x = Int('x') >>> p3 = Bool('p3') >>> s = Optimize() - >>> s.set(unsat_core=True) >>> s.assert_and_track(x > 0, 'p1') >>> s.assert_and_track(x != 1, 'p2') >>> s.assert_and_track(x < 0, p3) diff --git a/src/muz/spacer/spacer_iuc_solver.h b/src/muz/spacer/spacer_iuc_solver.h index 67fdc0fc3..c3561a6d4 100644 --- a/src/muz/spacer/spacer_iuc_solver.h +++ b/src/muz/spacer/spacer_iuc_solver.h @@ -123,7 +123,7 @@ public: 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() { return m_solver.get_trail(); } + expr_ref_vector get_trail() override { return m_solver.get_trail(); } void push() override; void pop(unsigned n) override; From 9fde9fe3a20fcba744363442cffcc8f5062324d8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 2 Feb 2019 19:49:16 +0100 Subject: [PATCH 247/318] fix #2122 for code that isn't exception safe Signed-off-by: Nikolaj Bjorner --- src/math/polynomial/upolynomial.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/math/polynomial/upolynomial.cpp b/src/math/polynomial/upolynomial.cpp index 0290a5924..f300dc4ab 100644 --- a/src/math/polynomial/upolynomial.cpp +++ b/src/math/polynomial/upolynomial.cpp @@ -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) { From 0acc042bf77860dbd9d7d42d6ac4fdae8afb7ca8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Feb 2019 17:15:38 +0100 Subject: [PATCH 248/318] fix #2120 fix #2122 Signed-off-by: Nikolaj Bjorner --- src/math/polynomial/algebraic_numbers.cpp | 11 ++- src/math/polynomial/upolynomial.cpp | 2 +- src/parsers/smt2/smt2parser.cpp | 93 ++++++++++------------- 3 files changed, 51 insertions(+), 55 deletions(-) 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/upolynomial.cpp b/src/math/polynomial/upolynomial.cpp index f300dc4ab..65dbf91f4 100644 --- a/src/math/polynomial/upolynomial.cpp +++ b/src/math/polynomial/upolynomial.cpp @@ -2517,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/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() { From 9cf99e26a6aaa2acc6b5a496088a85d06a1bd16a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Feb 2019 19:54:08 +0100 Subject: [PATCH 249/318] fix #2123 Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 4de05d31c..7185f520b 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -4490,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. From 73f6806371e494cab008e6c226d969c1e4df3376 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 4 Feb 2019 17:42:27 +0000 Subject: [PATCH 250/318] rewrite scoped_timer in C++11 way the code is much smaller and reused across platforms I see a small speedup on linux as well --- scripts/mk_util.py | 2 +- src/util/scoped_timer.cpp | 241 ++++---------------------------------- 2 files changed, 26 insertions(+), 217 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 2e827a7f3..3ef56b4d8 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2905,7 +2905,7 @@ def mk_config(): config.write('LINK=%s\n' % CXX) config.write('LINK_FLAGS=\n') config.write('LINK_OUT_FLAG=-o \n') - config.write('LINK_EXTRA_FLAGS=-lpthread %s\n' % LDFLAGS) + config.write('LINK_EXTRA_FLAGS=%s\n' % LDFLAGS) config.write('SO_EXT=%s\n' % SO_EXT) config.write('SLINK=%s\n' % CXX) config.write('SLINK_FLAGS=%s\n' % SLIBFLAGS) diff --git a/src/util/scoped_timer.cpp b/src/util/scoped_timer.cpp index 871356d25..e3b96fa15 100644 --- a/src/util/scoped_timer.cpp +++ b/src/util/scoped_timer.cpp @@ -16,238 +16,47 @@ Author: Revision History: --*/ -#ifdef _CYGWIN -// Hack to make CreateTimerQueueTimer available on cygwin -#define _WIN32_WINNT 0x0600 -#endif - -#include "util/z3_exception.h" -#include "util/z3_omp.h" -#if defined(_WINDOWS) || defined(_CYGWIN) -// Windows -#include -#elif defined(__APPLE__) && defined(__MACH__) -// macOS -#include -#include -#include -#include -#include -#elif defined(_LINUX_) || defined(_FREEBSD_) || defined(_NetBSD_) -// Linux & FreeBSD & NetBSD -#include -#include -#include -#include -// --------- -#else -// Other platforms -#endif #include "util/scoped_timer.h" -#ifdef _CYGWIN -#undef min -#undef max -#endif #include "util/util.h" -#include -#include "util/z3_omp.h" +#include +#include +#include +#include + struct scoped_timer::imp { event_handler * m_eh; -#if defined(_WINDOWS) || defined(_CYGWIN) - HANDLE m_timer; - bool m_first; -#elif defined(__APPLE__) && defined(__MACH__) - // macOS - pthread_t m_thread_id; - pthread_attr_t m_attributes; - unsigned m_interval; - pthread_mutex_t m_mutex; - pthread_cond_t m_condition_var; - struct timespec m_end_time; -#elif defined(_LINUX_) || defined(_FREEBSD_) || defined(_NETBSD_) - // Linux & FreeBSD & NetBSD - pthread_t m_thread_id; - pthread_mutex_t m_mutex; - pthread_cond_t m_cond; - unsigned m_ms; - bool m_initialized; - bool m_signal_sent; -#else - // Other -#endif + std::thread m_thread; + std::timed_mutex m_mutex; + unsigned m_ms; -#if defined(_WINDOWS) || defined(_CYGWIN) - static void CALLBACK abort_proc(PVOID param, BOOLEAN timer_or_wait_fired) { - imp * obj = static_cast(param); - if (obj->m_first) { - obj->m_first = false; - } - else { - obj->m_eh->operator()(TIMEOUT_EH_CALLER); - } - } -#elif defined(__APPLE__) && defined(__MACH__) - // macOS - static void * thread_func(void * arg) { - scoped_timer::imp * st = static_cast(arg); + static void* thread_func(imp * st) { + auto end = std::chrono::steady_clock::now() + std::chrono::milliseconds(st->m_ms); - pthread_mutex_lock(&st->m_mutex); - - int e = pthread_cond_timedwait(&st->m_condition_var, &st->m_mutex, &st->m_end_time); - if (e != 0 && e != ETIMEDOUT) - throw default_exception("failed to start timed wait"); - st->m_eh->operator()(TIMEOUT_EH_CALLER); - - pthread_mutex_unlock(&st->m_mutex); - - return st; - } -#elif defined(_LINUX_) || defined(_FREEBSD_) || defined(_NETBSD_) - static void* thread_func(void *arg) { - scoped_timer::imp *st = static_cast(arg); - - struct timespec end_time; - clock_gettime(CLOCK_REALTIME, &end_time); - end_time.tv_sec += st->m_ms / 1000u; - end_time.tv_nsec += (st->m_ms % 1000u) * 1000000ull; - // check for overflow - if (end_time.tv_nsec >= 1000000000) { - ++end_time.tv_sec; - end_time.tv_nsec -= 1000000000; - } - - pthread_mutex_lock(&st->m_mutex); - st->m_initialized = true; - int e = 0; - // `pthread_cond_timedwait()` may spuriously wake even if the signal - // was not sent so we loop until a timeout occurs or the signal was - // **really** sent. - while (!(e == 0 && st->m_signal_sent)) { - e = pthread_cond_timedwait(&st->m_cond, &st->m_mutex, &end_time); - ENSURE(e == 0 || e == ETIMEDOUT); - if (e == ETIMEDOUT) - break; - } - pthread_mutex_unlock(&st->m_mutex); - - if (e == ETIMEDOUT) + while (!st->m_mutex.try_lock_until(end)) { + if (std::chrono::steady_clock::now() > end) { st->m_eh->operator()(TIMEOUT_EH_CALLER); - return 0; - } -#else - // Other -#endif + return nullptr; + } + } + st->m_mutex.unlock(); + return nullptr; + } imp(unsigned ms, event_handler * eh): - m_eh(eh) { -#if defined(_WINDOWS) || defined(_CYGWIN) - m_first = true; - CreateTimerQueueTimer(&m_timer, - nullptr, - abort_proc, - this, - 0, - ms, - WT_EXECUTEINTIMERTHREAD); -#elif defined(__APPLE__) && defined(__MACH__) - // macOS - m_interval = ms?ms:0xFFFFFFFF; - if (pthread_attr_init(&m_attributes) != 0) - throw default_exception("failed to initialize timer thread attributes"); - if (pthread_cond_init(&m_condition_var, nullptr) != 0) - throw default_exception("failed to initialize timer condition variable"); - if (pthread_mutex_init(&m_mutex, nullptr) != 0) - throw default_exception("failed to initialize timer mutex"); - - clock_serv_t host_clock; - mach_timespec_t now; - unsigned long long nano = static_cast(m_interval) * 1000000ull; - - host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &host_clock); - m_end_time.tv_sec = nano / 1000000000ull; - m_end_time.tv_nsec = nano % 1000000000ull; - clock_get_time(host_clock, &now); - ADD_MACH_TIMESPEC(&m_end_time, &now); - - - if (pthread_create(&m_thread_id, &m_attributes, &thread_func, this) != 0) - throw default_exception("failed to start timer thread"); -#elif defined(_LINUX_) || defined(_FREEBSD_) || defined(_NETBSD_) - // Linux & FreeBSD & NetBSD - m_ms = ms; - m_initialized = false; - m_signal_sent = false; - ENSURE(pthread_mutex_init(&m_mutex, nullptr) == 0); - ENSURE(pthread_cond_init(&m_cond, nullptr) == 0); - ENSURE(pthread_create(&m_thread_id, nullptr, &thread_func, this) == 0); -#else - // Other platforms -#endif + m_eh(eh), m_ms(ms) { + m_mutex.lock(); + m_thread = std::thread(thread_func, this); } ~imp() { -#if defined(_WINDOWS) || defined(_CYGWIN) - DeleteTimerQueueTimer(nullptr, - m_timer, - INVALID_HANDLE_VALUE); -#elif defined(__APPLE__) && defined(__MACH__) - // macOS - - // If the waiting-thread is not up and waiting yet, - // we can make sure that it finishes quickly by - // setting the end-time to zero. - m_end_time.tv_sec = 0; - m_end_time.tv_nsec = 0; - - // Otherwise it's already up and waiting, and - // we can send a signal on m_condition_var: - pthread_mutex_lock(&m_mutex); - pthread_cond_signal(&m_condition_var); - pthread_mutex_unlock(&m_mutex); - - if (pthread_join(m_thread_id, nullptr) != 0) { - warning_msg("failed to join thread"); - return; + m_mutex.unlock(); + while (!m_thread.joinable()) { + std::this_thread::yield(); } - if (pthread_mutex_destroy(&m_mutex) != 0) { - warning_msg("failed to destroy pthread mutex"); - return; - } - if (pthread_cond_destroy(&m_condition_var) != 0) { - warning_msg("failed to destroy pthread condition variable"); - return; - } - if (pthread_attr_destroy(&m_attributes) != 0) { - warning_msg("failed to destroy pthread attributes object"); - return; - } -#elif defined(_LINUX_) || defined(_FREEBSD_) || defined(_NETBSD_) - // Linux & FreeBSD & NetBSD - bool init = false; - - // spin until timer thread has been created - while (!init) { - pthread_mutex_lock(&m_mutex); - init = m_initialized; - pthread_mutex_unlock(&m_mutex); - if (!init) - sched_yield(); - } - pthread_mutex_lock(&m_mutex); - m_signal_sent = true; - pthread_mutex_unlock(&m_mutex); - // Perform signal outside of lock to avoid waking timing thread twice. - pthread_cond_signal(&m_cond); - - pthread_join(m_thread_id, nullptr); - pthread_cond_destroy(&m_cond); - pthread_mutex_destroy(&m_mutex); -#else - // Other Platforms -#endif + m_thread.join(); } }; From 904bc34139d3982f5cd1880fc973ceb35900a998 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 5 Feb 2019 10:02:58 +0000 Subject: [PATCH 251/318] remove some debug leftover --- src/smt/smt_quantifier.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index 68c58d330..93354bfb4 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -260,13 +260,6 @@ namespace smt { m_qi_queue.insert(f, pat, max_generation, min_top_generation, max_top_generation); // TODO m_num_instances++; } - static unsigned count = 0; - CTRACE("quantifier", f != nullptr, - tout << (count++) << " " << q->get_id() << "\n"; - if (q->get_id() == 28 || true) { - tout << mk_ll_pp(q, m()) << "\n"; - } - ); CTRACE("quantifier_", f != nullptr, tout << expr_ref(q, m()) << " "; From 07912eb02836f36ed0371087d9549d426642d59a Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 5 Feb 2019 11:01:08 +0000 Subject: [PATCH 252/318] revert remove linking with pthread: some gcc implementations require it --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 3ef56b4d8..2e827a7f3 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2905,7 +2905,7 @@ def mk_config(): config.write('LINK=%s\n' % CXX) config.write('LINK_FLAGS=\n') config.write('LINK_OUT_FLAG=-o \n') - config.write('LINK_EXTRA_FLAGS=%s\n' % LDFLAGS) + config.write('LINK_EXTRA_FLAGS=-lpthread %s\n' % LDFLAGS) config.write('SO_EXT=%s\n' % SO_EXT) config.write('SLINK=%s\n' % CXX) config.write('SLINK_FLAGS=%s\n' % SLIBFLAGS) From d04e72819a33d726daa4459a81023462eb136425 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 6 Feb 2019 19:42:01 +0100 Subject: [PATCH 253/318] abstract solver API Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/CMakeLists.txt | 1 + src/sat/sat_solver.cpp | 6 +- src/sat/sat_solver.h | 63 ++++++++------- src/sat/sat_solver_core.h | 116 +++++++++++++++++++++++++++ src/sat/tactic/goal2sat.cpp | 63 ++++++++------- src/sat/tactic/goal2sat.h | 6 +- src/sat/tactic/sat_tactic.cpp | 28 +++---- src/shell/dimacs_frontend.cpp | 2 +- src/smt/smt_cg_table.cpp | 31 +++---- src/smt/smt_cg_table.h | 2 + src/tactic/core/solve_eqs_tactic.cpp | 29 +++++-- 11 files changed, 237 insertions(+), 110 deletions(-) create mode 100644 src/sat/sat_solver_core.h diff --git a/src/ast/rewriter/CMakeLists.txt b/src/ast/rewriter/CMakeLists.txt index 9d80fd5ac..9f98ff0ed 100644 --- a/src/ast/rewriter/CMakeLists.txt +++ b/src/ast/rewriter/CMakeLists.txt @@ -19,6 +19,7 @@ z3_add_component(rewriter factor_equivs.cpp factor_rewriter.cpp fpa_rewriter.cpp + hoist_rewriter.cpp inj_axiom.cpp label_rewriter.cpp maximize_ac_sharing.cpp diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 5ea039763..00ce093be 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -34,7 +34,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), @@ -3328,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; @@ -3827,7 +3827,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; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index dd81bac2e..4249da5ba 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; @@ -197,12 +197,12 @@ namespace sat { // 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. @@ -217,6 +217,9 @@ namespace sat { // 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); @@ -279,29 +282,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; } + 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 { return m_trail[i]; } + 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";); @@ -333,8 +335,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; @@ -369,13 +371,13 @@ 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(); } bool check_clauses(model const& m) const; @@ -545,10 +547,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; } // ----------------------- // @@ -645,8 +647,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; + // ----------------------- // @@ -654,11 +657,11 @@ 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; 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_core.h b/src/sat/sat_solver_core.h new file mode 100644 index 000000000..4f763bd55 --- /dev/null +++ b/src/sat/sat_solver_core.h @@ -0,0 +1,116 @@ +/*++ +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) {} + ~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; + + // 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/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 419952f99..f020fd2ab 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -57,7 +57,7 @@ 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; @@ -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), @@ -97,30 +97,30 @@ 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) { // create fake variable to represent true; - m_true = m_solver.mk_var(false); + m_true = m_solver.add_var(false); mk_clause(sat::literal(m_true, false)); // v is true } return m_true; @@ -139,7 +139,7 @@ struct goal2sat::imp { } 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";); @@ -247,7 +247,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; @@ -286,7 +286,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 @@ -329,7 +329,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); @@ -366,7 +366,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); @@ -390,7 +390,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 @@ -472,7 +472,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";); @@ -503,7 +503,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";); @@ -518,8 +518,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) { @@ -533,7 +533,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); @@ -553,7 +553,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); @@ -575,7 +575,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); @@ -588,8 +588,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(); @@ -602,7 +602,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); @@ -897,7 +897,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); @@ -916,7 +916,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); @@ -1157,13 +1157,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)); } @@ -1172,11 +1173,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; @@ -1196,7 +1197,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))); @@ -1262,7 +1263,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 bd100d620..1f6fe11ad 100644 --- a/src/sat/tactic/sat_tactic.cpp +++ b/src/sat/tactic/sat_tactic.cpp @@ -29,12 +29,12 @@ 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); @@ -51,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)) @@ -60,15 +60,15 @@ 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()); 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 asm2dep; mk_asm2dep(dep2asm, asm2dep); for (unsigned i = 0; i < ucore.size(); ++i) { @@ -83,7 +83,7 @@ class sat_tactic : public tactic { // register model if (produce_models) { model_ref md = alloc(model, m); - sat::model const & ll_m = m_solver.get_model(); + sat::model const & ll_m = m_solver->get_model(); TRACE("sat_tactic", for (unsigned i = 0; i < ll_m.size(); i++) tout << i << ":" << ll_m[i] << " "; tout << "\n";); for (auto const& kv : map) { expr * n = kv.m_key; @@ -109,9 +109,9 @@ class sat_tactic : public tactic { #if 0 IF_VERBOSE(TACTIC_VERBOSITY_LVL, verbose_stream() << "\"formula constrains interpreted atoms, recovering formula from sat solver...\"\n";); #endif - m_solver.pop_to_base_level(); + m_solver->pop_to_base_level(); ref mc; - m_sat2goal(m_solver, map, m_params, *(g.get()), mc); + m_sat2goal(*m_solver, map, m_params, *(g.get()), mc); g->add(mc.get()); } g->inc_depth(); @@ -134,7 +134,7 @@ class sat_tactic : public tactic { } void updt_params(params_ref const& p) { - m_solver.updt_params(p); + m_solver->updt_params(p); } }; @@ -192,10 +192,10 @@ public: scoped_set_imp set(this, &proc); try { proc(g, result); - proc.m_solver.collect_statistics(m_stats); + proc.m_solver->collect_statistics(m_stats); } catch (sat::solver_exception & ex) { - proc.m_solver.collect_statistics(m_stats); + proc.m_solver->collect_statistics(m_stats); throw tactic_exception(ex.msg()); } TRACE("sat_stats", m_stats.display_smt2(tout);); diff --git a/src/shell/dimacs_frontend.cpp b/src/shell/dimacs_frontend.cpp index 114d8daf6..4f032c01e 100644 --- a/src/shell/dimacs_frontend.cpp +++ b/src/shell/dimacs_frontend.cpp @@ -113,7 +113,7 @@ static void track_clauses(sat::solver const& src, sat::clause * const * it = src.begin_clauses(); sat::clause * const * end = src.end_clauses(); svector bin_clauses; - src.collect_bin_clauses(bin_clauses, false); + src.collect_bin_clauses(bin_clauses, false, false); tracking_clauses.reserve(2*src.num_vars() + static_cast(end - it) + bin_clauses.size()); for (sat::bool_var v = 1; v < src.num_vars(); ++v) { diff --git a/src/smt/smt_cg_table.cpp b/src/smt/smt_cg_table.cpp index ad15fd819..b85fed02d 100644 --- a/src/smt/smt_cg_table.cpp +++ b/src/smt/smt_cg_table.cpp @@ -71,10 +71,7 @@ namespace smt { void cg_table::display(std::ostream & out) const { out << "congruence table:\n"; - table::iterator it = m_table.begin(); - table::iterator end = m_table.end(); - for (; it != end; ++it) { - enode * n = *it; + for (enode * n : m_table) { out << mk_pp(n->get_owner(), m_manager) << "\n"; } } @@ -82,10 +79,7 @@ namespace smt { void cg_table::display_compact(std::ostream & out) const { if (!m_table.empty()) { out << "congruence table:\n"; - table::iterator it = m_table.begin(); - table::iterator end = m_table.end(); - for (; it != end; ++it) { - enode * n = *it; + for (enode * n : m_table) { out << "#" << n->get_owner()->get_id() << " "; } out << "\n"; @@ -94,10 +88,7 @@ namespace smt { #ifdef Z3DEBUG bool cg_table::check_invariant() const { - table::iterator it = m_table.begin(); - table::iterator end = m_table.end(); - for (; it != end; ++it) { - enode * n = *it; + for (enode * n : m_table) { CTRACE("cg_table", !contains_ptr(n), tout << "#" << n->get_owner_id() << "\n";); SASSERT(contains_ptr(n)); } @@ -136,9 +127,11 @@ namespace smt { } bool cg_table::cg_eq::operator()(enode * n1, enode * n2) const { - SASSERT(n1->get_num_args() == n2->get_num_args()); SASSERT(n1->get_decl() == n2->get_decl()); unsigned num = n1->get_num_args(); + if (num != n2->get_num_args()) { + return false; + } for (unsigned i = 0; i < num; i++) if (n1->get_arg(i)->get_root() != n2->get_arg(i)->get_root()) return false; @@ -205,10 +198,7 @@ namespace smt { } void cg_table::reset() { - ptr_vector::iterator it = m_tables.begin(); - ptr_vector::iterator end = m_tables.end(); - for (; it != end; ++it) { - void * t = *it; + for (void* t : m_tables) { switch (GET_TAG(t)) { case UNARY: dealloc(UNTAG(unary_table*, t)); @@ -225,10 +215,9 @@ namespace smt { } } m_tables.reset(); - obj_map::iterator it2 = m_func_decl2id.begin(); - obj_map::iterator end2 = m_func_decl2id.end(); - for (; it2 != end2; ++it2) - m_manager.dec_ref(it2->m_key); + for (auto const& kv : m_func_decl2id) { + m_manager.dec_ref(kv.m_key); + } m_func_decl2id.reset(); } diff --git a/src/smt/smt_cg_table.h b/src/smt/smt_cg_table.h index 64c8328d0..4085ccc5f 100644 --- a/src/smt/smt_cg_table.h +++ b/src/smt/smt_cg_table.h @@ -252,6 +252,8 @@ namespace smt { enode_bool_pair insert(enode * n) { // it doesn't make sense to insert a constant. SASSERT(n->get_num_args() > 0); + SASSERT(!m_manager.is_and(n->get_owner())); + SASSERT(!m_manager.is_or(n->get_owner())); enode * n_prime; void * t = get_table(n); switch (static_cast(GET_TAG(t))) { diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index 623f83db4..1fc0c1f41 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -22,6 +22,9 @@ Revision History: #include "ast/ast_util.h" #include "ast/ast_pp.h" #include "ast/pb_decl_plugin.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/rewriter/hoist_rewriter.h" #include "tactic/goal_shared_occs.h" #include "tactic/tactical.h" #include "tactic/generic_model_converter.h" @@ -574,27 +577,36 @@ class solve_eqs_tactic : public tactic { } else if (m().is_or(f)) { flatten_or(f, args); - //std::cout << "hoist or " << args.size() << "\n"; for (unsigned i = 0; i < args.size(); ++i) { path.push_back(nnf_context(false, args, i)); hoist_nnf(g, args.get(i), path, idx, depth + 1); path.pop_back(); } } - else { - // std::cout << "no hoist " << mk_pp(f, m()) << "\n"; - } } - bool collect_hoist(goal const& g) { - bool change = false; + void collect_hoist(goal const& g) { unsigned size = g.size(); vector path; for (unsigned idx = 0; idx < size; idx++) { checkpoint(); hoist_nnf(g, g.form(idx), path, idx, 0); } - return change; + } + + void distribute_and_or(goal & g) { + unsigned size = g.size(); + hoist_rewriter_star rw(m()); + th_rewriter thrw(m()); + expr_ref tmp(m()), tmp2(m()); + for (unsigned idx = 0; idx < size; idx++) { + checkpoint(); + expr* f = g.form(idx); + thrw(f, tmp); + rw(tmp, tmp2); + g.update(idx, tmp2); + } + } void sort_vars() { @@ -918,6 +930,9 @@ class solve_eqs_tactic : public tactic { m_subst = alloc(expr_substitution, m(), m_produce_unsat_cores, m_produce_proofs); m_norm_subst = alloc(expr_substitution, m(), m_produce_unsat_cores, m_produce_proofs); while (true) { + if (m_context_solve) { + distribute_and_or(*(g.get())); + } collect_num_occs(*g); collect(*g); if (m_context_solve) { From 56598037b67f03c59f09a45573432f50389b2001 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 6 Feb 2019 19:42:40 +0100 Subject: [PATCH 254/318] new rewriter Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/hoist_rewriter.cpp | 178 ++++++++++++++++++++++++++++ src/ast/rewriter/hoist_rewriter.h | 80 +++++++++++++ 2 files changed, 258 insertions(+) create mode 100644 src/ast/rewriter/hoist_rewriter.cpp create mode 100644 src/ast/rewriter/hoist_rewriter.h diff --git a/src/ast/rewriter/hoist_rewriter.cpp b/src/ast/rewriter/hoist_rewriter.cpp new file mode 100644 index 000000000..ad7dffbdb --- /dev/null +++ b/src/ast/rewriter/hoist_rewriter.cpp @@ -0,0 +1,178 @@ +/*++ +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_args(m) { + updt_params(p); +} + +br_status hoist_rewriter::mk_or(unsigned num_args, expr * const * args, expr_ref & result) { + if (num_args < 2) { + return BR_FAILED; + } + for (unsigned i = 0; i < num_args; ++i) { + if (!is_and(args[i])) { + 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 }; + VERIFY(is_and(args[0])); + expr* e1, *e2; + for (expr* e : m_args) { + 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); + unsigned v1 = 0, v2 = 0; + VERIFY(is_and(args[j])); + for (expr* e : m_args) { + 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)); + } + } + // p & eqs & (or fmls) + expr_ref_vector fmls(m()), ors(m()); + expr_safe_replace subst(m()); + for (expr * p : (*preds)[turn]) { + 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(args[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()); + 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) { + m_args.reset(); + if (m().is_and(e)) { + m_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)) { + for (expr* arg : *to_app(e)) { + m_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) { + 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..dbaeebd4d --- /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_args; + 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); + + 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 From c6a7dc7b4434c3a4ba8497ff06b31cf0da5b6ed9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 6 Feb 2019 20:05:45 +0100 Subject: [PATCH 255/318] formatting Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver_core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/sat_solver_core.h b/src/sat/sat_solver_core.h index 4f763bd55..619a3e3a0 100644 --- a/src/sat/sat_solver_core.h +++ b/src/sat/sat_solver_core.h @@ -32,7 +32,7 @@ namespace sat { ~solver_core() {} virtual void pop_to_base_level() {} - virtual bool at_base_lvl() const { return true; } + virtual bool at_base_lvl() const { return true; } // retrieve model if solver return sat virtual model const & get_model() const = 0; From 064c9faf116b8bcfb4600feee6b36dad0f3fe1c0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 6 Feb 2019 20:13:21 +0100 Subject: [PATCH 256/318] fix test Signed-off-by: Nikolaj Bjorner --- src/test/cnf_backbones.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/cnf_backbones.cpp b/src/test/cnf_backbones.cpp index 10f3e56a7..9db15c304 100644 --- a/src/test/cnf_backbones.cpp +++ b/src/test/cnf_backbones.cpp @@ -90,7 +90,7 @@ static void track_clauses(sat::solver const& src, sat::clause * const * it = src.begin_clauses(); sat::clause * const * end = src.end_clauses(); svector bin_clauses; - src.collect_bin_clauses(bin_clauses, false); + src.collect_bin_clauses(bin_clauses, false, false); tracking_clauses.reserve(2*src.num_vars() + static_cast(end - it) + bin_clauses.size()); for (sat::bool_var v = 1; v < src.num_vars(); ++v) { From c9ffe7417c1a7789ae16d24634029dbf6d2f8c80 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Feb 2019 07:55:17 +0100 Subject: [PATCH 257/318] mark destructors virtual Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.h | 2 +- src/sat/sat_solver_core.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 4249da5ba..d9f738e6c 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -190,7 +190,7 @@ namespace sat { friend class scoped_detach; public: solver(params_ref const & p, reslimit& l); - ~solver(); + ~solver() override; // ----------------------- // diff --git a/src/sat/sat_solver_core.h b/src/sat/sat_solver_core.h index 619a3e3a0..543a84fa7 100644 --- a/src/sat/sat_solver_core.h +++ b/src/sat/sat_solver_core.h @@ -29,7 +29,7 @@ namespace sat { reslimit& m_rlimit; public: solver_core(reslimit& l) : m_rlimit(l) {} - ~solver_core() {} + virtual ~solver_core() {} virtual void pop_to_base_level() {} virtual bool at_base_lvl() const { return true; } From e22f713b19a73c6e2efd8dd3fe4917c4f8c2ce62 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Feb 2019 12:02:48 +0100 Subject: [PATCH 258/318] tune QF_UFBV Signed-off-by: Nikolaj Bjorner --- src/smt/theory_bv.cpp | 56 ++++++++++++++++++++++++++++++------------- src/smt/theory_bv.h | 6 +++++ 2 files changed, 45 insertions(+), 17 deletions(-) diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index 8db1df26b..7048857f2 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -442,16 +442,21 @@ namespace smt { }; void theory_bv::add_fixed_eq(theory_var v1, theory_var v2) { - ++m_stats.m_num_eq_dynamic; if (v1 > v2) { std::swap(v1, v2); } - unsigned sz = get_bv_size(v1); + + unsigned act = m_eq_activity[hash_u_u(v1, v2) & 0xFF]++; + if (act < 255) { + return; + } + ++m_stats.m_num_eq_dynamic; ast_manager& m = get_manager(); context & ctx = get_context(); app* o1 = get_enode(v1)->get_owner(); app* o2 = get_enode(v2)->get_owner(); literal oeq = mk_eq(o1, o2, true); + unsigned sz = get_bv_size(v1); TRACE("bv", tout << mk_pp(o1, m) << " = " << mk_pp(o2, m) << " " << ctx.get_scope_level() << "\n";); @@ -1146,12 +1151,9 @@ namespace smt { SASSERT(get_bv_size(v1) == get_bv_size(v2)); context & ctx = get_context(); ast_manager & m = get_manager(); -#ifdef _TRACE - unsigned num_bool_vars = ctx.get_num_bool_vars(); -#endif - literal_vector & lits = m_tmp_literals; - lits.reset(); - lits.push_back(mk_eq(get_enode(v1)->get_owner(), get_enode(v2)->get_owner(), true)); + if (v1 > v2) { + std::swap(v1, v2); + } literal_vector const & bits1 = m_bits[v1]; literal_vector::const_iterator it1 = bits1.begin(); literal_vector::const_iterator end1 = bits1.end(); @@ -1159,8 +1161,23 @@ namespace smt { literal_vector::const_iterator it2 = bits2.begin(); for (; it1 != end1; ++it1, ++it2) { if (*it1 == ~(*it2)) - return; // static diseq + return; + lbool v1 = ctx.get_assignment(*it1); + lbool v2 = ctx.get_assignment(*it2); + if (v1 != l_undef && v2 != l_undef && v1 != v2) { + return; + } } + + unsigned h = hash_u_u(v1, v2); + unsigned act = m_diseq_activity[hash_u_u(v1, v2) & 0xFF]++; + if ((act & 0xFF) == 0xFF) { + //m_replay_diseq.push_back(std::make_pair(v1, v2)); + } + + literal_vector & lits = m_tmp_literals; + lits.reset(); + lits.push_back(mk_eq(get_enode(v1)->get_owner(), get_enode(v2)->get_owner(), true)); it1 = bits1.begin(); it2 = bits2.begin(); for (; it1 != end1; ++it1, ++it2) { @@ -1174,14 +1191,6 @@ namespace smt { } m_stats.m_num_diseq_dynamic++; ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); - TRACE_CODE({ - static unsigned num = 0; - static unsigned new_bool_vars = 0; - new_bool_vars += (ctx.get_num_bool_vars() - num_bool_vars); - if (num % 1000 == 0) - TRACE("expand_diseq", tout << "num: " << num << " " << new_bool_vars << "\n";); - num++; - }); } void theory_bv::assign_eh(bool_var v, bool is_true) { @@ -1395,6 +1404,8 @@ namespace smt { m_trail_stack(*this), m_find(*this), m_approximates_large_bvs(false) { + memset(m_eq_activity, 0, sizeof(m_eq_activity)); + memset(m_diseq_activity, 0, sizeof(m_diseq_activity)); } theory_bv::~theory_bv() { @@ -1517,6 +1528,17 @@ namespace smt { return true; } + void theory_bv::propagate() { + unsigned sz = m_replay_diseq.size(); + if (sz > 0) { + for (unsigned i = 0; i < sz; ++i) { + auto const& p = m_replay_diseq[i]; + expand_diseq(p.first, p.second); + } + m_replay_diseq.reset(); + } + } + class bit_eq_justification : public justification { enode * m_v1; enode * m_v2; diff --git a/src/smt/theory_bv.h b/src/smt/theory_bv.h index 23644c6fd..c89a2c967 100644 --- a/src/smt/theory_bv.h +++ b/src/smt/theory_bv.h @@ -124,6 +124,10 @@ namespace smt { value2var m_fixed_var_table; + unsigned char m_eq_activity[256]; + unsigned char m_diseq_activity[256]; + svector> m_replay_diseq; + literal_vector m_tmp_literals; svector m_prop_queue; bool m_approximates_large_bvs; @@ -233,6 +237,8 @@ namespace smt { bool include_func_interp(func_decl* f) override; svector m_merge_aux[2]; //!< auxiliary vector used in merge_zero_one_bits bool merge_zero_one_bits(theory_var r1, theory_var r2); + bool can_propagate() override { return !m_replay_diseq.empty(); } + void propagate() override; // ----------------------------------- // From 1b1ff8dbaba32d5c4b4b9244d6b54af053427c2b Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 7 Feb 2019 14:08:18 +0000 Subject: [PATCH 259/318] Fix bug in qprofdiff --- contrib/qprofdiff/main.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) 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); From 6f9082598cec5d2af34c699e57780c269cea72d9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Feb 2019 08:05:40 -0800 Subject: [PATCH 260/318] tuning relevancy Signed-off-by: Nikolaj Bjorner --- src/smt/smt_relevancy.cpp | 8 ++--- src/smt/theory_bv.cpp | 68 ++++++++++++++++++++++++++++++++++----- src/smt/theory_bv.h | 3 ++ 3 files changed, 67 insertions(+), 12 deletions(-) diff --git a/src/smt/smt_relevancy.cpp b/src/smt/smt_relevancy.cpp index 7db5110ee..75c82fa89 100644 --- a/src/smt/smt_relevancy.cpp +++ b/src/smt/smt_relevancy.cpp @@ -129,7 +129,7 @@ namespace smt { struct relevancy_propagator_imp : public relevancy_propagator { unsigned m_qhead; expr_ref_vector m_relevant_exprs; - obj_hashtable m_is_relevant; + uint_set m_is_relevant; typedef list relevancy_ehs; obj_map m_relevant_ehs; obj_map m_watches[2]; @@ -242,7 +242,7 @@ namespace smt { } } - bool is_relevant_core(expr * n) const { return m_is_relevant.contains(n); } + bool is_relevant_core(expr * n) const { return m_is_relevant.contains(n->get_id()); } bool is_relevant(expr * n) const override { return !enabled() || is_relevant_core(n); @@ -275,7 +275,7 @@ namespace smt { while (i != old_lim) { --i; expr * n = m_relevant_exprs.get(i); - m_is_relevant.erase(n); + m_is_relevant.remove(n->get_id()); TRACE("propagate_relevancy", tout << "unmarking:\n" << mk_ismt2_pp(n, get_manager()) << "\n";); } m_relevant_exprs.shrink(old_lim); @@ -303,7 +303,7 @@ namespace smt { } void set_relevant(expr * n) { - m_is_relevant.insert(n); + m_is_relevant.insert(n->get_id()); m_relevant_exprs.push_back(n); m_context.relevant_eh(n); } diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index 7048857f2..8a2263bf2 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -24,6 +24,7 @@ Revision History: #include "smt/smt_model_generator.h" #include "util/stats.h" +#define WATCH_DISEQ 1 namespace smt { @@ -629,7 +630,7 @@ namespace smt { num *= numeral(2); } expr_ref sum(m_autil.mk_add(sz, args.c_ptr()), m); - th_rewriter rw(m); + th_rewriter rw(m); rw(sum); literal l(mk_eq(n, sum, false)); TRACE("bv", @@ -1159,21 +1160,48 @@ namespace smt { literal_vector::const_iterator end1 = bits1.end(); literal_vector const & bits2 = m_bits[v2]; literal_vector::const_iterator it2 = bits2.begin(); +#if WATCH_DISEQ + bool_var watch_var = null_bool_var; +#endif for (; it1 != end1; ++it1, ++it2) { if (*it1 == ~(*it2)) return; - lbool v1 = ctx.get_assignment(*it1); - lbool v2 = ctx.get_assignment(*it2); - if (v1 != l_undef && v2 != l_undef && v1 != v2) { + lbool val1 = ctx.get_assignment(*it1); + lbool val2 = ctx.get_assignment(*it2); + if (val1 != l_undef && val2 != l_undef && val1 != val2) { return; } +#if WATCH_DISEQ + if (watch_var != null_bool_var) { + // skip + } + else if (val1 == l_undef) { + watch_var = it1->var(); + m_diseq_watch.reserve(watch_var+1); + m_diseq_watch[watch_var].push_back(std::make_pair(v1, v2)); + m_diseq_watch_trail.push_back(watch_var); + } + else if (val2 == l_undef) { + watch_var = it2->var(); + m_diseq_watch.reserve(watch_var+1); + m_diseq_watch[watch_var].push_back(std::make_pair(v1, v2)); + m_diseq_watch_trail.push_back(watch_var); + } +#endif } - unsigned h = hash_u_u(v1, v2); - unsigned act = m_diseq_activity[hash_u_u(v1, v2) & 0xFF]++; - if ((act & 0xFF) == 0xFF) { - //m_replay_diseq.push_back(std::make_pair(v1, v2)); +#if WATCH_DISEQ + if (watch_var != null_bool_var) { + unsigned h = hash_u_u(v1, v2); + unsigned act = m_diseq_activity[hash_u_u(v1, v2) & 0xFF]++; + if ((act & 0x1) == 0x1) { + return; + //m_replay_diseq.push_back(std::make_pair(v1, v2)); + } + m_diseq_watch[watch_var].pop_back(); + m_diseq_watch_trail.pop_back(); } +#endif literal_vector & lits = m_tmp_literals; lits.reset(); @@ -1214,6 +1242,17 @@ namespace smt { } TRACE("bv", tout << "prop queue size: " << m_prop_queue.size() << "\n";); propagate_bits(); + +#if WATCH_DISEQ + if (!get_context().inconsistent() && m_diseq_watch.size() > static_cast(v)) { + unsigned sz = m_diseq_watch[v].size(); + for (unsigned i = 0; i < sz; ++i) { + auto const & p = m_diseq_watch[v][i]; + expand_diseq(p.first, p.second); + } + m_diseq_watch[v].reset(); + } +#endif } } @@ -1353,6 +1392,9 @@ namespace smt { void theory_bv::push_scope_eh() { theory::push_scope_eh(); m_trail_stack.push_scope(); +#if WATCH_DISEQ + m_diseq_watch_lim.push_back(m_diseq_watch_trail.size()); +#endif } void theory_bv::pop_scope_eh(unsigned num_scopes) { @@ -1362,6 +1404,16 @@ namespace smt { m_bits.shrink(num_old_vars); m_wpos.shrink(num_old_vars); m_zero_one_bits.shrink(num_old_vars); +#if WATCH_DISEQ + unsigned old_trail_sz = m_diseq_watch_lim[m_diseq_watch_lim.size()-num_scopes]; + for (unsigned i = m_diseq_watch_trail.size(); i-- > old_trail_sz;) { + if (!m_diseq_watch[m_diseq_watch_trail[i]].empty()) { + m_diseq_watch[m_diseq_watch_trail[i]].pop_back(); + } + } + m_diseq_watch_trail.shrink(old_trail_sz); + m_diseq_watch_lim.shrink(m_diseq_watch_lim.size()-num_scopes); +#endif theory::pop_scope_eh(num_scopes); } diff --git a/src/smt/theory_bv.h b/src/smt/theory_bv.h index c89a2c967..5a4edf4cf 100644 --- a/src/smt/theory_bv.h +++ b/src/smt/theory_bv.h @@ -127,6 +127,9 @@ namespace smt { unsigned char m_eq_activity[256]; unsigned char m_diseq_activity[256]; svector> m_replay_diseq; + vector>> m_diseq_watch; + svector m_diseq_watch_trail; + unsigned_vector m_diseq_watch_lim; literal_vector m_tmp_literals; svector m_prop_queue; From d21fc642b4d95cec3cb72a7d5df4ed39d4857605 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Feb 2019 09:57:24 -0800 Subject: [PATCH 261/318] refactor watch_diseq, disable it completely Signed-off-by: Nikolaj Bjorner --- src/smt/theory_bv.cpp | 54 ++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index 8a2263bf2..9ab625ede 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -24,7 +24,7 @@ Revision History: #include "smt/smt_model_generator.h" #include "util/stats.h" -#define WATCH_DISEQ 1 +#define WATCH_DISEQ 0 namespace smt { @@ -1160,9 +1160,6 @@ namespace smt { literal_vector::const_iterator end1 = bits1.end(); literal_vector const & bits2 = m_bits[v2]; literal_vector::const_iterator it2 = bits2.begin(); -#if WATCH_DISEQ - bool_var watch_var = null_bool_var; -#endif for (; it1 != end1; ++it1, ++it2) { if (*it1 == ~(*it2)) return; @@ -1171,35 +1168,34 @@ namespace smt { if (val1 != l_undef && val2 != l_undef && val1 != val2) { return; } -#if WATCH_DISEQ - if (watch_var != null_bool_var) { - // skip - } - else if (val1 == l_undef) { - watch_var = it1->var(); - m_diseq_watch.reserve(watch_var+1); - m_diseq_watch[watch_var].push_back(std::make_pair(v1, v2)); - m_diseq_watch_trail.push_back(watch_var); - } - else if (val2 == l_undef) { - watch_var = it2->var(); - m_diseq_watch.reserve(watch_var+1); - m_diseq_watch[watch_var].push_back(std::make_pair(v1, v2)); - m_diseq_watch_trail.push_back(watch_var); - } -#endif } #if WATCH_DISEQ - if (watch_var != null_bool_var) { - unsigned h = hash_u_u(v1, v2); - unsigned act = m_diseq_activity[hash_u_u(v1, v2) & 0xFF]++; - if ((act & 0x1) == 0x1) { - return; - //m_replay_diseq.push_back(std::make_pair(v1, v2)); + bool_var watch_var = null_bool_var; + it1 = bits1.begin(); + it2 = bits2.begin(); + unsigned h = hash_u_u(v1, v2); + unsigned act = m_diseq_activity[hash_u_u(v1, v2) & 0xFF]++; + + for (; it1 != end1 && ((act & 0x3) != 0x3); ++it1, ++it2) { + lbool val1 = ctx.get_assignment(*it1); + lbool val2 = ctx.get_assignment(*it2); + + if (val1 == l_undef) { + watch_var = it1->var(); } - m_diseq_watch[watch_var].pop_back(); - m_diseq_watch_trail.pop_back(); + else if (val2 == l_undef) { + watch_var = it2->var(); + } + else { + continue; + } + + m_diseq_watch.reserve(watch_var+1); + m_diseq_watch[watch_var].push_back(std::make_pair(v1, v2)); + m_diseq_watch_trail.push_back(watch_var); + return; + //m_replay_diseq.push_back(std::make_pair(v1, v2)); } #endif From 77942a35dcffad02e508f2fa0a9114a6db46c553 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Feb 2019 11:20:53 -0800 Subject: [PATCH 262/318] fix #2125 Signed-off-by: Nikolaj Bjorner --- src/api/java/Goal.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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; } From d2a3b53d927c8f0d0523b747f2b6d69c99c98695 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Feb 2019 12:28:17 -0800 Subject: [PATCH 263/318] fix remaining incorrect uses of new BoolExpr related to #2125 Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Goal.cs | 2 +- src/api/dotnet/Lambda.cs | 2 +- src/api/dotnet/Quantifier.cs | 2 +- src/api/java/Lambda.java | 4 ++-- src/api/java/Quantifier.java | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) 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/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/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())); } From b17c946acb4f7634e11b66931a643a5f8246f0f8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Feb 2019 14:40:06 -0800 Subject: [PATCH 264/318] fix bug in hoist module, tune num2bits for large bit-vectors Signed-off-by: Nikolaj Bjorner --- .../bit_blaster/bit_blaster_tpl_def.h | 18 ++++++- src/ast/rewriter/hoist_rewriter.cpp | 51 ++++++++++++++----- src/ast/rewriter/hoist_rewriter.h | 4 +- 3 files changed, 55 insertions(+), 18 deletions(-) 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/hoist_rewriter.cpp b/src/ast/rewriter/hoist_rewriter.cpp index ad7dffbdb..5deeebdf4 100644 --- a/src/ast/rewriter/hoist_rewriter.cpp +++ b/src/ast/rewriter/hoist_rewriter.cpp @@ -25,16 +25,16 @@ Notes: hoist_rewriter::hoist_rewriter(ast_manager & m, params_ref const & p): - m_manager(m), m_args(m) { + m_manager(m), m_args1(m), m_args2(m) { updt_params(p); } -br_status hoist_rewriter::mk_or(unsigned num_args, expr * const * args, expr_ref & result) { +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(args[i])) { + if (!is_and(es[i], nullptr)) { return BR_FAILED; } } @@ -48,9 +48,10 @@ br_status hoist_rewriter::mk_or(unsigned num_args, expr * const * args, expr_ref m_var2expr.reset(); basic_union_find* uf[2] = { &m_uf1, &m_uf2 }; obj_hashtable* preds[2] = { &m_preds1, &m_preds2 }; - VERIFY(is_and(args[0])); + expr_ref_vector* args[2] = { &m_args1, &m_args2 }; + VERIFY(is_and(es[0], args[turn])); expr* e1, *e2; - for (expr* e : m_args) { + for (expr* e : *(args[turn])) { if (m().is_eq(e, e1, e2)) { (*uf)[turn].merge(mk_var(e1), mk_var(e2)); } @@ -69,8 +70,9 @@ br_status hoist_rewriter::mk_or(unsigned num_args, expr * const * args, expr_ref (*preds)[turn].reset(); reset(m_uf0); unsigned v1 = 0, v2 = 0; - VERIFY(is_and(args[j])); - for (expr* e : m_args) { + 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)); @@ -79,6 +81,7 @@ br_status hoist_rewriter::mk_or(unsigned num_args, expr * const * args, expr_ref (*preds)[turn].insert(e); } } + if ((*preds)[turn].empty() && m_es.empty()) { return BR_FAILED; } @@ -109,12 +112,21 @@ br_status hoist_rewriter::mk_or(unsigned num_args, expr * const * args, expr_ref 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]) { - subst.insert(p, m().mk_true()); + 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) { @@ -124,11 +136,17 @@ br_status hoist_rewriter::mk_or(unsigned num_args, expr * const * args, expr_ref for (unsigned i = 0; i < num_args; ++i) { expr_ref tmp(m()); - subst(args[i], tmp); + 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; } @@ -154,15 +172,20 @@ br_status hoist_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * c } } -bool hoist_rewriter::is_and(expr * e) { - m_args.reset(); +bool hoist_rewriter::is_and(expr * e, expr_ref_vector* args) { if (m().is_and(e)) { - m_args.append(to_app(e)->get_num_args(), to_app(e)->get_args()); + 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)) { - for (expr* arg : *to_app(e)) { - m_args.push_back(::mk_not(m(), arg)); + if (args) { + args->reset(); + for (expr* arg : *to_app(e)) { + args->push_back(::mk_not(m(), arg)); + } } return true; } diff --git a/src/ast/rewriter/hoist_rewriter.h b/src/ast/rewriter/hoist_rewriter.h index dbaeebd4d..0f45a073c 100644 --- a/src/ast/rewriter/hoist_rewriter.h +++ b/src/ast/rewriter/hoist_rewriter.h @@ -27,7 +27,7 @@ Notes: class hoist_rewriter { ast_manager & m_manager; - expr_ref_vector m_args; + 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; @@ -39,7 +39,7 @@ class hoist_rewriter { br_status mk_or(unsigned num_args, expr * const * args, expr_ref & result); - bool is_and(expr* e); + 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]; } From d2d42f98106de8b83d0d6e8df8c4d709d7708b09 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Feb 2019 08:23:22 -0800 Subject: [PATCH 265/318] fix #2127 fix #2128 Signed-off-by: Nikolaj Bjorner --- src/ast/array_decl_plugin.cpp | 5 +++++ src/ast/array_decl_plugin.h | 2 ++ src/model/model_evaluator.cpp | 24 +++++++++++++++++++++++- src/sat/sat_simplifier.cpp | 3 ++- src/smt/theory_seq.cpp | 34 +++++++++++++++++++++++++++++++--- 5 files changed, 63 insertions(+), 5 deletions(-) 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/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index b0e97e5e4..61bf8df96 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; @@ -59,6 +60,7 @@ struct evaluator_cfg : public default_rewriter_cfg { 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. @@ -200,6 +202,26 @@ struct evaluator_cfg : public default_rewriter_cfg { return BR_REWRITE1; } } + if (st == BR_FAILED && num == 0 && m_ar.is_as_array(f)) { + func_decl* g = nullptr; + VERIFY(m_ar.is_as_array(f, g)); + expr* def = nullptr; + quantifier* q = nullptr; + proof* def_pr = nullptr; + if (get_macro(g, def, q, def_pr)) { + sort_ref_vector vars(m); + svector var_names; + for (unsigned i = 0; i < g->get_arity(); ++i) { + var_names.push_back(symbol(i)); + vars.push_back(g->get_domain(g->get_arity() - i - 1)); + } + result = m.mk_lambda(vars.size(), vars.c_ptr(), var_names.c_ptr(), def); + model_evaluator ev(m_model, m_params); + result = ev(result); + return BR_DONE; + } + } + CTRACE("model_evaluator", st != BR_FAILED, tout << result << "\n";); return st; } @@ -222,7 +244,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";); diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 96b1588a2..9688b1d6e 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1032,7 +1032,7 @@ namespace sat { } void insert(literal l) { - VERIFY(process_var(l.var())); + SASSERT(process_var(l.var())); m_queue.insert(l); } @@ -1075,6 +1075,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)) { diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 37297997a..dc3f80385 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2873,9 +2873,9 @@ bool theory_seq::get_length(expr* e, expr_ref& len, literal_vector& lits) { ctx.get_assignment(i_lt_len_s) == l_true) { len = m_autil.mk_int(1); lits.append(2, _lits); + TRACE("seq", ctx.display_literals_verbose(tout, 2, _lits); tout << "\n";); return true; } - TRACE("seq", ctx.display_literals_verbose(tout, 2, _lits); tout << "\n";); } else if (is_pre(e, s, i)) { expr_ref zero(m_autil.mk_int(0), m); @@ -2887,9 +2887,9 @@ bool theory_seq::get_length(expr* e, expr_ref& len, literal_vector& lits) { ctx.get_assignment(i_lt_len_s) == l_true) { len = i; lits.append(2, _lits); + TRACE("seq", ctx.display_literals_verbose(tout, 2, _lits); tout << "\n";); return true; } - TRACE("seq", ctx.display_literals_verbose(tout, 2, _lits); tout << "\n";); } else if (is_post(e, s, l)) { expr_ref zero(m_autil.mk_int(0), m); @@ -2900,9 +2900,9 @@ bool theory_seq::get_length(expr* e, expr_ref& len, literal_vector& lits) { ctx.get_assignment(l_le_len_s) == l_true) { len = l; lits.append(2, _lits); + TRACE("seq", ctx.display_literals_verbose(tout, 2, _lits); tout << "\n";); return true; } - TRACE("seq", ctx.display_literals_verbose(tout, 2, _lits); tout << "\n";); } else if (is_skolem(m_tail, e)) { // e = tail(s, l), len(s) > l => len(tail(s, l)) = len(s) - l - 1 @@ -4942,6 +4942,7 @@ void theory_seq::add_extract_suffix_axiom(expr* e, expr* s, expr* i) { */ void theory_seq::add_at_axiom(expr* e) { + TRACE("seq", tout << "at-axiom: " << mk_pp(e, m) << "\n";); expr* s = nullptr, *i = nullptr; VERIFY(m_util.str.is_at(e, s, i)); expr_ref zero(m_autil.mk_int(0), m); @@ -5082,9 +5083,36 @@ void theory_seq::add_axiom(literal l1, literal l2, literal l3, literal l4, liter TRACE("seq", ctx.display_literals_verbose(tout << "assert:\n", lits) << "\n";); m_new_propagation = true; ++m_stats.m_add_axiom; + +#if 0 + static unsigned level = 0; + if (level == 0) { + level++; + disable_trace("seq"); + kernel k(m, ctx.get_fparams()); + expr_ref tmp(m); + for (literal lit: lits) { + ctx.literal2expr(~lit, tmp); + k.assert_expr(tmp); + } + lbool r = k.check(); + enable_trace("seq"); + if (r == l_true) { + k.display(std::cout); std::cout << "\n"; + TRACE("seq", k.display(tout << "sat\n"); tout << "\n";); + } + level--; + } +#endif ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); } +#if 0 +void theory_seq::dump_axiom(literal_vector const& lits) { + display_lemma_as_smt_problem(std::cout << "; lemma\n", lits.size(), lits.c_ptr()); +} +#endif + expr_ref theory_seq::coalesce_chars(expr* const& e) { context& ctx = get_context(); expr* s; From 0fd4c4fb067a943cca29147de7f0e2c141e5d1b8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Feb 2019 08:24:14 -0800 Subject: [PATCH 266/318] tidy Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index dc3f80385..cae5e4cbf 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -5083,35 +5083,9 @@ void theory_seq::add_axiom(literal l1, literal l2, literal l3, literal l4, liter TRACE("seq", ctx.display_literals_verbose(tout << "assert:\n", lits) << "\n";); m_new_propagation = true; ++m_stats.m_add_axiom; - -#if 0 - static unsigned level = 0; - if (level == 0) { - level++; - disable_trace("seq"); - kernel k(m, ctx.get_fparams()); - expr_ref tmp(m); - for (literal lit: lits) { - ctx.literal2expr(~lit, tmp); - k.assert_expr(tmp); - } - lbool r = k.check(); - enable_trace("seq"); - if (r == l_true) { - k.display(std::cout); std::cout << "\n"; - TRACE("seq", k.display(tout << "sat\n"); tout << "\n";); - } - level--; - } -#endif ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); } -#if 0 -void theory_seq::dump_axiom(literal_vector const& lits) { - display_lemma_as_smt_problem(std::cout << "; lemma\n", lits.size(), lits.c_ptr()); -} -#endif expr_ref theory_seq::coalesce_chars(expr* const& e) { context& ctx = get_context(); From c7bd985fac833f7f57cad31c24ab4e7499d6ab21 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Feb 2019 08:50:02 -0800 Subject: [PATCH 267/318] remove asserts for ground defs Signed-off-by: Nikolaj Bjorner --- src/model/func_interp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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); From 24dfdfe9bc154c370b7ebaade8904c3018415012 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Feb 2019 16:06:02 -0800 Subject: [PATCH 268/318] disable fixes for #2128 and related as it breaks model evaluation time in regressions, set longer delay for inprocessing in sat solver, report stats Signed-off-by: Nikolaj Bjorner --- src/model/model_evaluator.cpp | 4 +++- src/sat/sat_asymm_branch.cpp | 32 +++++++++++++++++++------------- src/sat/sat_cleaner.cpp | 11 +++++------ src/sat/sat_config.cpp | 4 ++-- src/sat/sat_elim_vars.cpp | 1 - src/sat/sat_probing.cpp | 13 +++++++------ src/sat/sat_scc.cpp | 5 ++--- src/sat/sat_solver.cpp | 3 +-- src/sat/sat_types.h | 5 +++++ 9 files changed, 44 insertions(+), 34 deletions(-) diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index 61bf8df96..415b162b4 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -202,7 +202,8 @@ struct evaluator_cfg : public default_rewriter_cfg { return BR_REWRITE1; } } - if (st == BR_FAILED && num == 0 && m_ar.is_as_array(f)) { +#if 0 + 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; @@ -221,6 +222,7 @@ struct evaluator_cfg : public default_rewriter_cfg { return BR_DONE; } } +#endif CTRACE("model_evaluator", st != BR_FAILED, tout << result << "\n";); return st; diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index 60362363c..d3f7b78a0 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(2, 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(2, 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(2, 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; } diff --git a/src/sat/sat_cleaner.cpp b/src/sat/sat_cleaner.cpp index 728931f15..d8181a8e0 100644 --- a/src/sat/sat_cleaner.cpp +++ b/src/sat/sat_cleaner.cpp @@ -165,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";); } }; diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 6e415e7f3..57adf5132 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -130,9 +130,9 @@ namespace sat { } // 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(); diff --git a/src/sat/sat_elim_vars.cpp b/src/sat/sat_elim_vars.cpp index 299fbace1..4b475a181 100644 --- a/src/sat/sat_elim_vars.cpp +++ b/src/sat/sat_elim_vars.cpp @@ -167,7 +167,6 @@ 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()); diff --git a/src/sat/sat_probing.cpp b/src/sat/sat_probing.cpp index 15d8e8e7e..54c1ee23d 100644 --- a/src/sat/sat_probing.cpp +++ b/src/sat/sat_probing.cpp @@ -176,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) { @@ -185,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";); } }; diff --git a/src/sat/sat_scc.cpp b/src/sat/sat_scc.cpp index 52641736a..79c599609 100644 --- a/src/sat/sat_scc.cpp +++ b/src/sat/sat_scc.cpp @@ -56,11 +56,10 @@ namespace sat { ~report() { m_watch.stop(); unsigned elim_bin = m_scc.m_num_elim_bin - m_num_elim_bin; - IF_VERBOSE(SAT_VB_LVL, + 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";); + verbose_stream() << m_watch << ")\n";); } }; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 00ce093be..7f2fcb45d 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1721,7 +1721,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 @@ -1962,7 +1961,7 @@ namespace sat { m_restart_next_out = 1; } else { - m_restart_next_out = (3*m_restart_next_out)/2 + 1; + m_restart_next_out = std::min(m_conflicts_since_init + 50000, (3*m_restart_next_out)/2 + 1); } log_stats(); } diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index 7710d62d2..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 { @@ -223,6 +224,10 @@ namespace sat { 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 { literal m_lit; dimacs_lit(literal l):m_lit(l) {} From c5df6ce96e068eceb77019e48634721c6a5bb607 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 10 Feb 2019 10:07:24 -0800 Subject: [PATCH 269/318] fix #2131 Signed-off-by: Nikolaj Bjorner --- src/api/python/README.txt | 10 +++------- src/api/python/setup.py | 2 +- src/ast/recfun_decl_plugin.h | 2 +- 3 files changed, 5 insertions(+), 9 deletions(-) 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..063680e2b 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -178,7 +178,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", 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; // Date: Sun, 10 Feb 2019 11:12:26 -0800 Subject: [PATCH 270/318] fix bug in model compression that skips dependencies in function entries. Exposed in t171.smt2 Signed-off-by: Nikolaj Bjorner --- src/model/model.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/model/model.cpp b/src/model/model.cpp index de6bb4db8..e6a3ffedf 100644 --- a/src/model/model.cpp +++ b/src/model/model.cpp @@ -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; } From 3339be6d221567f372fac19ef53215beff8b0164 Mon Sep 17 00:00:00 2001 From: Audrey Dutcher Date: Sun, 10 Feb 2019 14:05:45 -0800 Subject: [PATCH 271/318] Don't delete the reference to the native library in the python bindings --- scripts/update_api.py | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index 161c783e8..557ac4c6c 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -1704,7 +1704,6 @@ def write_exe_c_preamble(exe_c): def write_core_py_post(core_py): core_py.write(""" # Clean up -del _lib del _default_dirs del _all_dirs del _ext From b702cad81ee962b5c23f79bcbc57f3f4aa20fcfe Mon Sep 17 00:00:00 2001 From: Audrey Dutcher Date: Sun, 10 Feb 2019 14:12:27 -0800 Subject: [PATCH 272/318] Append std=c++11 instead of replacing CXXFLAGS; see #2130 --- src/api/python/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/python/setup.py b/src/api/python/setup.py index 063680e2b..9939f5962 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -16,7 +16,7 @@ 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') From 4e687671a5047a26e95d0b22dd0f97d4581a5d9d Mon Sep 17 00:00:00 2001 From: Audrey Dutcher Date: Sun, 10 Feb 2019 14:25:20 -0800 Subject: [PATCH 273/318] Tweak python setup.py clean to properly clean the native build --- src/api/python/setup.py | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/api/python/setup.py b/src/api/python/setup.py index 9939f5962..2d5e5c75d 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -10,6 +10,7 @@ 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 @@ -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 @@ -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}, ) From 6cfe66c3c2fe190448ef04f6ba8137323d9e710f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 10 Feb 2019 18:11:01 -0800 Subject: [PATCH 274/318] re-enabling model evaluation of as-array after tuning normalization Signed-off-by: Nikolaj Bjorner --- src/ast/act_cache.cpp | 34 ++++++++++++++++----------------- src/ast/act_cache.h | 16 ++++++++++++---- src/ast/rewriter/rewriter.cpp | 4 ++-- src/ast/rewriter/rewriter.h | 4 +++- src/ast/rewriter/rewriter_def.h | 13 ++++++++++--- src/model/model_evaluator.cpp | 15 ++++++++++++--- 6 files changed, 56 insertions(+), 30 deletions(-) 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/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 dfa0c5467..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); } } diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index 415b162b4..53defbc3d 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -56,6 +56,8 @@ 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), @@ -72,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); @@ -202,23 +205,29 @@ struct evaluator_cfg : public default_rewriter_cfg { return BR_REWRITE1; } } -#if 0 +#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 vars(m); svector var_names; for (unsigned i = 0; i < g->get_arity(); ++i) { var_names.push_back(symbol(i)); - vars.push_back(g->get_domain(g->get_arity() - i - 1)); + vars.push_back(g->get_domain(i)); } result = m.mk_lambda(vars.size(), vars.c_ptr(), var_names.c_ptr(), def); model_evaluator ev(m_model, m_params); result = ev(result); + m_pinned.push_back(result); + m_def_cache.insert(g, result); return BR_DONE; } } From 93ee05648e1c7e4e61433510b34a7f8e9fffb48e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 11 Feb 2019 10:56:36 -0800 Subject: [PATCH 275/318] add shortcuts for unit assertions, conflicts Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 4 ++ src/sat/ba_solver.h | 1 + src/sat/sat_asymm_branch.cpp | 6 +-- src/sat/sat_big.cpp | 2 +- src/sat/sat_cleaner.cpp | 4 +- src/sat/sat_elim_eqs.cpp | 6 +-- src/sat/sat_elim_vars.cpp | 2 +- src/sat/sat_extension.h | 1 + src/sat/sat_lookahead.cpp | 2 +- src/sat/sat_probing.cpp | 12 +++--- src/sat/sat_scc.cpp | 8 +++- src/sat/sat_simplifier.cpp | 76 ++++-------------------------------- src/sat/sat_solver.cpp | 5 +-- src/sat/sat_solver.h | 3 ++ src/sat/sat_watched.cpp | 10 ++++- src/sat/sat_watched.h | 5 ++- src/smt/theory_bv.cpp | 2 +- 17 files changed, 55 insertions(+), 94 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 7315f913b..d97e3ee94 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -4140,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 d3f7b78a0..f89b20897 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -367,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(); } @@ -423,11 +423,11 @@ namespace sat { 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. diff --git a/src/sat/sat_big.cpp b/src/sat/sat_big.cpp index 833c83820..f327bc607 100644 --- a/src/sat/sat_big.cpp +++ b/src/sat/sat_big.cpp @@ -199,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())); diff --git a/src/sat/sat_cleaner.cpp b/src/sat/sat_cleaner.cpp index d8181a8e0..093e6221f 100644 --- a/src/sat/sat_cleaner.cpp +++ b/src/sat/sat_cleaner.cpp @@ -119,11 +119,11 @@ namespace sat { s.display_watches(tout);); switch (new_sz) { case 0: - s.set_conflict(justification()); + s.set_conflict(); s.del_clause(c); break; case 1: - s.assign(c[0], justification()); + s.assign_unit(c[0]); s.del_clause(c); break; case 2: diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index 612c337c8..bc69c1f5d 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -53,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 @@ -179,7 +179,7 @@ namespace sat { switch (j) { case 0: - m_solver.set_conflict(justification()); + m_solver.set_conflict(); for (; it != end; ++it) { *it2 = *it; it2++; @@ -187,7 +187,7 @@ namespace sat { cs.set_end(it2); 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); diff --git a/src/sat/sat_elim_vars.cpp b/src/sat/sat_elim_vars.cpp index 4b475a181..1759ec2ad 100644 --- a/src/sat/sat_elim_vars.cpp +++ b/src/sat/sat_elim_vars.cpp @@ -169,7 +169,7 @@ namespace sat{ 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_lookahead.cpp b/src/sat/sat_lookahead.cpp index 5c33f8d3d..3536b21db 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -2463,7 +2463,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_probing.cpp b/src/sat/sat_probing.cpp index 54c1ee23d..5689112d4 100644 --- a/src/sat/sat_probing.cpp +++ b/src/sat/sat_probing.cpp @@ -69,7 +69,7 @@ namespace sat { s.m_drat.add(l, lit, true); s.m_drat.add(~l, lit, true); } - s.assign(lit, justification()); + s.assign_scoped(lit); m_num_assigned++; } } @@ -77,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; } @@ -104,7 +104,7 @@ namespace sat { s.m_drat.add(l, lit, true); s.m_drat.add(~l, lit, true); } - s.assign(lit, justification()); + s.assign_scoped(lit); m_num_assigned++; } } @@ -119,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; diff --git a/src/sat/sat_scc.cpp b/src/sat/sat_scc.cpp index 79c599609..7ce073975 100644 --- a/src/sat/sat_scc.cpp +++ b/src/sat/sat_scc.cpp @@ -47,18 +47,22 @@ 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; + 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; + if (num_units > 0) verbose_stream() << " :units " << num_units; verbose_stream() << m_watch << ")\n";); } }; @@ -177,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())) { diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 9688b1d6e..f536dda03 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -335,14 +335,14 @@ namespace sat { unsigned sz = c.size(); switch(sz) { case 0: - s.set_conflict(justification()); + s.set_conflict(); for (; it != end; ++it, ++it2) { *it2 = *it; } cs.set_end(it2); return; case 1: - s.assign(c[0], justification()); + s.assign_unit(c[0]); c.restore(sz0); s.del_clause(c); break; @@ -473,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++; @@ -646,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; @@ -696,7 +697,7 @@ namespace sat { switch (sz) { case 0: TRACE("elim_lit", tout << "clause is empty\n";); - s.set_conflict(justification()); + s.set_conflict(); break; case 1: TRACE("elim_lit", tout << "clause became unit: " << c[0] << "\n";); @@ -893,7 +894,7 @@ namespace sat { unsigned sz = c.size(); switch (sz) { case 0: - s.set_conflict(justification()); + s.set_conflict(); return; case 1: c.restore(sz0); @@ -1164,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; } @@ -1222,8 +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); @@ -1234,14 +1232,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); @@ -1285,10 +1275,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";); } /* @@ -1385,7 +1371,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(); } @@ -1608,15 +1593,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()); @@ -1875,36 +1851,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 } /** @@ -2027,13 +1974,6 @@ 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)); @@ -2054,7 +1994,7 @@ namespace sat { } switch (m_new_cls.size()) { case 0: - s.set_conflict(justification()); + s.set_conflict(); break; case 1: propagate_unit(m_new_cls[0]); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 7f2fcb45d..4354d91ea 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -2356,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";); @@ -2970,7 +2970,6 @@ namespace sat { 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()); } else { @@ -3720,7 +3719,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 { diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index d9f738e6c..c8261397a 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -314,8 +314,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() { 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/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index 9ab625ede..4b9b3d1d0 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -448,7 +448,7 @@ namespace smt { } unsigned act = m_eq_activity[hash_u_u(v1, v2) & 0xFF]++; - if (act < 255) { + if ((act & 0xFF) != 0xFF) { return; } ++m_stats.m_num_eq_dynamic; From 22783a4bcb1f5d814514e928f801edac84301206 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 11 Feb 2019 13:09:28 -0800 Subject: [PATCH 276/318] import more from csp Signed-off-by: Nikolaj Bjorner --- src/sat/sat_drat.cpp | 9 ++++++--- src/sat/sat_parallel.cpp | 6 +++--- src/sat/sat_solver.cpp | 4 ++-- src/sat/sat_solver.h | 2 +- src/sat/tactic/goal2sat.cpp | 17 +++++++++-------- 5 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index 997ee971e..c0799c061 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -213,8 +213,8 @@ namespace sat { 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; @@ -338,8 +338,9 @@ namespace sat { 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; @@ -583,6 +584,7 @@ namespace sat { } } 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); @@ -590,6 +592,7 @@ namespace sat { 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}; 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_solver.cpp b/src/sat/sat_solver.cpp index 4354d91ea..4c5a8ac3d 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -95,7 +95,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); @@ -192,7 +192,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 (copy_learned || c->glue() <= 2 || (c->size() <= 40 && c->glue() <= 8)) { buffer.reset(); for (literal l : *c) buffer.push_back(l); clause* c1 = mk_clause_core(buffer.size(), buffer.c_ptr(), true); diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index c8261397a..379a786d5 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -210,7 +210,7 @@ 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); // ----------------------- // diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index f020fd2ab..b9adba7cf 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -60,7 +60,7 @@ struct goal2sat::imp { 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; @@ -81,13 +81,14 @@ struct goal2sat::imp { m_default_external(default_external), m_is_lemma(false) { updt_params(p); - m_true = sat::null_bool_var; + 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) { @@ -117,11 +118,11 @@ struct goal2sat::imp { 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.add_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; } @@ -132,10 +133,10 @@ 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); From 5fe40a25dccbc9c5a2341538dac6dce89963579c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 11 Feb 2019 13:14:20 -0800 Subject: [PATCH 277/318] revise local search Signed-off-by: Nikolaj Bjorner --- src/sat/sat_local_search.cpp | 478 ++++++++--------------------------- src/sat/sat_local_search.h | 163 +++++------- src/sat/sat_solver.cpp | 4 +- 3 files changed, 159 insertions(+), 486 deletions(-) diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index b65abfd23..47cb29694 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,10 @@ 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 +538,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 +546,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 +571,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; } @@ -763,7 +693,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 +709,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 +725,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 +735,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 +795,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 +813,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 +820,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..f1ef29158 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,37 @@ 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_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 +234,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 +252,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_solver.cpp b/src/sat/sat_solver.cpp index 4c5a8ac3d..f18db1d20 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1172,7 +1172,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); @@ -1197,9 +1196,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); } From 6d893e0599c738a77c82bb8a33aea8f2c9036acf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 11 Feb 2019 13:16:17 -0800 Subject: [PATCH 278/318] revise unit walk Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.h | 2 + src/sat/sat_unit_walk.cpp | 356 ++++++++++++++++++++++++++++---------- src/sat/sat_unit_walk.h | 54 ++++-- 3 files changed, 308 insertions(+), 104 deletions(-) diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 379a786d5..b61258d94 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -226,6 +226,8 @@ namespace sat { void mk_clause(literal l1, literal l2, bool learned = false); void 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]; } inline clause_allocator const& cls_allocator() const { return m_cls_allocator[m_cls_allocator_idx]; } diff --git a/src/sat/sat_unit_walk.cpp b/src/sat/sat_unit_walk.cpp index 4a3cda47c..56f5a2d1e 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,20 +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; + s(s) { + m_max_conflicts = 10000; m_sticky_phase = s.get_config().m_phase_sticky; m_flips = 0; } @@ -63,67 +94,177 @@ 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; - } - } - 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())]; + init_propagation(); + init_phase(); + while (true) { + if (!s.rlimit().inc()) { + log_status(); + return l_undef; + } + bool_var v = pqueue().next(s); + if (v == null_bool_var) { + log_status(); + return l_true; + } literal lit(v, !m_phase[v]); ++s.m_stats.m_decision; m_decisions.push_back(lit); + // IF_VERBOSE(0, verbose_stream() << "push " << lit << " " << m_decisions.size() << "\n"); + pqueue().push(); assign(lit); propagate(); while (inconsistent() && !m_decisions.empty()) { - ++m_conflicts; - backtrack(); + update_max_trail(); + ++s.m_stats.m_conflict; + pop(); + pqueue().pop(); propagate(); } - if (m_conflicts >= m_max_conflicts && !m_freevars.empty()) { - set_conflict(); - break; + if (inconsistent()) { + log_status(); + return l_false; + } + bool do_reinit = s.m_stats.m_conflict >= m_max_conflicts; + if (do_reinit || pqueue().depth() > m_decisions.size()) { // || pqueue().depth() <= 10 + switch (update_priority()) { + case l_true: return l_true; + case l_false: break; // TBD + default: break; + } + } + if (do_reinit) { + refresh_solver(); } } - if (!inconsistent()) { - log_status(); - IF_VERBOSE(1, verbose_stream() << "(sat-unit-walk sat)\n";); - s.mk_model(); - return l_true; + } + + void unit_walk::pop() { + SASSERT (!m_decisions.empty()); + literal dlit = m_decisions.back(); + pop_decision(); + m_inconsistent = false; + assign(~dlit); + } + + void unit_walk::pop_decision() { + SASSERT (!m_decisions.empty()); + literal dlit = m_decisions.back(); + // IF_VERBOSE(0, verbose_stream() << "pop " << dlit << " " << m_decisions.size() << "\n"); + 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(); } - return l_undef; + while (lit != dlit); + m_qhead = m_trail.size(); + m_decisions.pop_back(); } 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(); + } + + lbool unit_walk::update_priority() { + unsigned prefix_length = 0; + if (pqueue().depth() > m_decisions.size()) { + while (pqueue().depth() > m_decisions.size()) { + pqueue().dec_depth(); + } + prefix_length = m_trail.size(); + SASSERT(pqueue().depth() == m_decisions.size()); + } + else if (pqueue().depth() == m_decisions.size()) { + prefix_length = m_trail.size(); + } + else { + literal last = m_decisions[pqueue().depth()]; + while (m_trail[prefix_length++] != last) {} + pqueue().inc_depth(); + } + log_status(); + IF_VERBOSE(1, verbose_stream() << "(sat.unit-walk :update-priority " << pqueue().depth() << ")\n"); + 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(std::max(1u, pqueue().depth())); + lbool is_sat = m_ls.check(0, m_trail.c_ptr(), nullptr); + m_ls.rlimit().pop(); + + TRACE("sat", tout << "result of running bounded local search " << is_sat << "\n";); + IF_VERBOSE(0, verbose_stream() << "result of running local search " << is_sat << "\n";); + if (is_sat != l_undef) { + restart(); + } + if (is_sat == l_true) { + for (unsigned v = 0; v < s.num_vars(); ++v) { + s.m_assignment[v] = m_ls.get_phase(v) ? l_true : l_false; + } + } + + 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; + } + }; + compare_break cb(m_ls); + std::sort(pqueue().begin(), pqueue().end(), cb); + pqueue().rewind(); + // assert variables are sorted from highest to lowest value. + + for (bool_var v : pqueue()) { + if (m_ls.cur_solution(v)) + m_phase_tf[v].update(100); + else + m_phase_tf[v].update(0); + } + init_phase(); + + // restart + bool_var v = pqueue().peek(s); + if (is_sat == l_undef && v != null_bool_var && false) { + unsigned num_levels = 0; + while (m_decisions.size() > 0 && num_levels <= 50) { + bool_var w = m_decisions.back().var(); + if (num_levels >= 15 && m_ls.break_count(w) >= m_ls.break_count(v)) { + break; + } + ++num_levels; + pop_decision(); + if (pqueue().depth() > m_decisions.size()) { + pqueue().pop(); + } + } + IF_VERBOSE(0, verbose_stream() << "backtrack levels " << num_levels << "\n"); + } + return is_sat; } void unit_walk::init_phase() { - m_max_trail = 0; if (m_sticky_phase) { - for (bool_var v : m_freevars) { + for (bool_var v : pqueue()) { if (s.m_phase[v] == POS_PHASE) { m_phase[v] = true; } @@ -131,35 +272,73 @@ namespace sat { 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; + m_phase[v] = m_rand(100) <= m_phase_tf[v]; } } } else { - for (bool_var v : m_freevars) + for (bool_var v : pqueue()) m_phase[v] = (m_rand(2) == 0); } } + void unit_walk::refresh_solver() { + m_max_conflicts += m_conflict_offset ; + m_conflict_offset += 100; // 00; + 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(); + } + if (should_restart()) { + restart(); + } + } + + 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; + } + else { + return false; + } + } + + void unit_walk::restart() { + IF_VERBOSE(1, verbose_stream() << "restart\n"); + while (!m_decisions.empty()) { + pop_decision(); + } + pqueue().reset(); + } + + 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; @@ -171,6 +350,20 @@ namespace sat { // IF_VERBOSE(1, verbose_stream() << m_trail.size() << " " << inconsistent() << "\n";); } + 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) { ++s.m_stats.m_propagate; literal not_l = ~l; @@ -289,11 +482,12 @@ namespace sat { } void unit_walk::assign(literal lit) { - SASSERT(value(lit) == l_undef); + VERIFY(value(lit) == l_undef); + //VERIFY(!m_trail.contains(lit)); + //VERIFY(!m_trail.contains(~lit)); 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); } @@ -307,28 +501,23 @@ namespace sat { 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; + if (m_phase[v]) m_phase_tf[v].update(100); else m_phase_tf[v].update(0); } } 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; + return m_trail[m_qhead++]; } void unit_walk::set_conflict(literal l1, literal l2) { @@ -346,25 +535,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..0551d3192 100644 --- a/src/sat/sat_unit_walk.h +++ b/src/sat/sat_unit_walk.h @@ -20,43 +20,74 @@ 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; + unsigned m_depth; + public: + var_priority() { m_depth = 0; m_head = 0; } + void rewind() { m_head = 0; for (unsigned& l : m_lim) l = 0; } + unsigned depth() const { return m_depth; } + void inc_depth() { ++m_depth; } + void dec_depth() { --m_depth; } + void reset() { m_lim.reset(); m_head = 0; m_depth = 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 restart(); + void pop(); + void pop_decision(); void init_runs(); + lbool update_priority(); 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(); @@ -65,6 +96,7 @@ namespace sat { 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); From 72b220e84a3c023e02df62be5cd2d123a02e9de0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 11 Feb 2019 13:28:13 -0800 Subject: [PATCH 279/318] import improvements to lookahead Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 21 +++++++++++++-------- src/sat/sat_model_converter.cpp | 2 +- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 3536b21db..557624db5 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -321,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])); @@ -334,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) { @@ -2285,7 +2290,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; } } diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index 17885f4e5..577588305 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -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); From d9a51f8f8add96c81d32ea42849a818b5fd7c8fa Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 11 Feb 2019 14:44:12 -0800 Subject: [PATCH 280/318] fix test build Signed-off-by: Nikolaj Bjorner --- src/test/sat_local_search.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/test/sat_local_search.cpp b/src/test/sat_local_search.cpp index ad982d024..46d96d637 100644 --- a/src/test/sat_local_search.cpp +++ b/src/test/sat_local_search.cpp @@ -47,9 +47,6 @@ static bool build_instance(char const * filename, sat::solver& s, sat::local_sea return false; } - for (unsigned i = 0; i < lits.size(); ++i) { - local_search.add_soft(lits[i].var(), coefficients[i]); - } // read the constraints, one at a time int k; From 64d085c18886221038b136e6a1bbfbff4e4726a6 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 12 Feb 2019 14:02:30 +0000 Subject: [PATCH 281/318] Fix bug in fpa2bv_converter, fixes #2136. --- src/ast/fpa/fpa2bv_converter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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); From eec1da5a15769df0cee3bc6409e4ea027b211d66 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 12 Feb 2019 15:49:12 -0800 Subject: [PATCH 282/318] move restart test to after propagation, clean up drat generation Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 89 +++++++++++++++++++++--------------------- src/sat/sat_solver.h | 8 ++-- 2 files changed, 49 insertions(+), 48 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index f18db1d20..9af8774e0 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -122,7 +122,7 @@ namespace sat { m_scopes.reset(); if (src.inconsistent()) { - set_conflict(justification()); + set_conflict(); return; } @@ -137,11 +137,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 } // @@ -154,7 +152,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 @@ -192,7 +190,7 @@ namespace sat { // copy high quality lemmas unsigned num_learned = 0; for (clause* c : src.m_learned) { - if (copy_learned || 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); @@ -203,7 +201,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(); @@ -275,7 +273,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++) @@ -283,24 +281,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) { @@ -313,8 +311,9 @@ namespace sat { 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) { @@ -337,10 +336,10 @@ namespace sat { switch (num_lits) { case 0: - 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); @@ -701,7 +700,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: @@ -1037,7 +1036,7 @@ namespace sat { m_cuber = nullptr; if (is_first) { pop_to_base_level(); - set_conflict(justification()); + set_conflict(); } break; case l_true: { @@ -1072,7 +1071,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) { @@ -1349,7 +1348,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) { @@ -1435,8 +1434,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; } @@ -1463,14 +1462,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()) { @@ -1538,14 +1536,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); @@ -1584,7 +1582,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()); @@ -1597,11 +1595,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) { @@ -1706,8 +1704,6 @@ namespace sat { lh.collect_statistics(m_aux_stats); } - TRACE("sat", display(tout << "consistent: " << (!inconsistent()) << "\n");); - reinit_assumptions(); if (m_next_simplify == 0) { @@ -1964,6 +1960,7 @@ namespace sat { 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(); } @@ -2287,19 +2284,23 @@ namespace sat { switch (new_sz) { case 0: if (m_config.m_drat) m_drat.add(); - set_conflict(justification()); + 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; @@ -2343,8 +2344,6 @@ namespace sat { } bool solver::resolve_conflict_core() { - - m_conflicts_since_init++; m_conflicts_since_restart++; m_conflicts_since_gc++; @@ -2492,13 +2491,14 @@ namespace sat { 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(); } @@ -2568,8 +2568,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; @@ -2579,6 +2579,7 @@ namespace sat { tout << " "; } tout << "\n"; + tout << "conflict level: " << m_conflict_lvl << "\n"; ); m_core.reset(); @@ -2645,7 +2646,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); } @@ -4126,7 +4127,7 @@ namespace sat { } push(); ++num_assigned; - assign(~lit, justification()); + assign_scoped(~lit); propagate(false); while (inconsistent()) { if (!resolve_conflict()) { diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index b61258d94..a977bbbaa 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -221,10 +221,10 @@ namespace sat { 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; } From 5cdfa7cd1cf5e5209213421238ab916eb03d0585 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Feb 2019 17:43:15 -0800 Subject: [PATCH 283/318] variations on unit-walk Signed-off-by: Nikolaj Bjorner --- src/sat/sat_config.cpp | 1 + src/sat/sat_config.h | 1 + src/sat/sat_local_search.cpp | 30 +++- src/sat/sat_local_search.h | 1 + src/sat/sat_lookahead.cpp | 4 +- src/sat/sat_lookahead.h | 3 +- src/sat/sat_params.pyg | 1 + src/sat/sat_unit_walk.cpp | 257 ++++++++++++++++------------------- src/sat/sat_unit_walk.h | 19 +-- 9 files changed, 163 insertions(+), 154 deletions(-) diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 57adf5132..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; diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 79baa621e..b8d0ca0f5 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -128,6 +128,7 @@ 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; diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 47cb29694..7c3ebb688 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -591,18 +591,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 diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index f1ef29158..00c38e481 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -202,6 +202,7 @@ namespace sat { void init_slack(); void init_scores(); void init_goodvars(); + void pick_flip_lookahead(); void pick_flip_walksat(); void flip_walksat(bool_var v); bool propagate(literal lit); diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 557624db5..74ac831d8 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1812,7 +1812,7 @@ 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; @@ -2013,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()) { @@ -2033,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() { diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 606fd2b8c..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; } }; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 0fdb1aa70..88b196d04 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -72,6 +72,7 @@ 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'), diff --git a/src/sat/sat_unit_walk.cpp b/src/sat/sat_unit_walk.cpp index 56f5a2d1e..314c275f3 100644 --- a/src/sat/sat_unit_walk.cpp +++ b/src/sat/sat_unit_walk.cpp @@ -76,7 +76,6 @@ namespace sat { unit_walk::unit_walk(solver& s): s(s) { m_max_conflicts = 10000; - m_sticky_phase = s.get_config().m_phase_sticky; m_flips = 0; } @@ -96,60 +95,64 @@ namespace sat { init_runs(); init_propagation(); init_phase(); - while (true) { - if (!s.rlimit().inc()) { - log_status(); - return l_undef; - } - bool_var v = pqueue().next(s); - if (v == null_bool_var) { - log_status(); - return l_true; - } - literal lit(v, !m_phase[v]); - ++s.m_stats.m_decision; - m_decisions.push_back(lit); - // IF_VERBOSE(0, verbose_stream() << "push " << lit << " " << m_decisions.size() << "\n"); - pqueue().push(); - assign(lit); - propagate(); - while (inconsistent() && !m_decisions.empty()) { - update_max_trail(); - ++s.m_stats.m_conflict; - pop(); - pqueue().pop(); - propagate(); - } - if (inconsistent()) { - log_status(); - return l_false; - } - bool do_reinit = s.m_stats.m_conflict >= m_max_conflicts; - if (do_reinit || pqueue().depth() > m_decisions.size()) { // || pqueue().depth() <= 10 - switch (update_priority()) { - case l_true: return l_true; - case l_false: break; // TBD - default: break; - } - } - if (do_reinit) { - refresh_solver(); - } + 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_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; + } + + 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(); - m_inconsistent = false; assign(~dlit); } void unit_walk::pop_decision() { SASSERT (!m_decisions.empty()); literal dlit = m_decisions.back(); - // IF_VERBOSE(0, verbose_stream() << "pop " << dlit << " " << m_decisions.size() << "\n"); literal lit; do { SASSERT(!m_trail.empty()); @@ -161,6 +164,8 @@ namespace sat { while (lit != dlit); m_qhead = m_trail.size(); m_decisions.pop_back(); + pqueue().pop(); + m_inconsistent = false; } void unit_walk::init_runs() { @@ -178,120 +183,100 @@ namespace sat { } m_ls.import(s, true); m_rand.set_seed(s.rand()()); - update_priority(); + update_priority(0); } - lbool unit_walk::update_priority() { - unsigned prefix_length = 0; - if (pqueue().depth() > m_decisions.size()) { - while (pqueue().depth() > m_decisions.size()) { - pqueue().dec_depth(); - } - prefix_length = m_trail.size(); - SASSERT(pqueue().depth() == m_decisions.size()); - } - else if (pqueue().depth() == m_decisions.size()) { - prefix_length = m_trail.size(); - } - else { - literal last = m_decisions[pqueue().depth()]; - while (m_trail[prefix_length++] != last) {} - pqueue().inc_depth(); - } - log_status(); - IF_VERBOSE(1, verbose_stream() << "(sat.unit-walk :update-priority " << pqueue().depth() << ")\n"); + 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(std::max(1u, pqueue().depth())); - lbool is_sat = m_ls.check(0, m_trail.c_ptr(), nullptr); + m_ls.rlimit().push(num_rounds); + lbool is_sat = m_ls.check(prefix_length, m_trail.c_ptr(), nullptr); m_ls.rlimit().pop(); - - TRACE("sat", tout << "result of running bounded local search " << is_sat << "\n";); - IF_VERBOSE(0, verbose_stream() << "result of running local search " << is_sat << "\n";); - if (is_sat != l_undef) { - restart(); - } - if (is_sat == l_true) { - for (unsigned v = 0; v < s.num_vars(); ++v) { - s.m_assignment[v] = m_ls.get_phase(v) ? l_true : l_false; - } - } - - 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; - } - }; - compare_break cb(m_ls); - std::sort(pqueue().begin(), pqueue().end(), cb); - pqueue().rewind(); - // assert variables are sorted from highest to lowest value. - - for (bool_var v : pqueue()) { - if (m_ls.cur_solution(v)) - m_phase_tf[v].update(100); - else - m_phase_tf[v].update(0); - } - init_phase(); - - // restart - bool_var v = pqueue().peek(s); - if (is_sat == l_undef && v != null_bool_var && false) { - unsigned num_levels = 0; - while (m_decisions.size() > 0 && num_levels <= 50) { - bool_var w = m_decisions.back().var(); - if (num_levels >= 15 && m_ls.break_count(w) >= m_ls.break_count(v)) { - break; - } - ++num_levels; - pop_decision(); - if (pqueue().depth() > m_decisions.size()) { - pqueue().pop(); - } - } - IF_VERBOSE(0, verbose_stream() << "backtrack levels " << num_levels << "\n"); - } return is_sat; } - void unit_walk::init_phase() { - if (m_sticky_phase) { - 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]; - } - } + lbool unit_walk::update_priority(unsigned level) { + + while (m_decisions.size() > level) { + pop_decision(); } - else { - for (bool_var v : pqueue()) - m_phase[v] = (m_rand(2) == 0); + 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() { + 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]; + } } } void unit_walk::refresh_solver() { m_max_conflicts += m_conflict_offset ; - m_conflict_offset += 100; // 00; + 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(); } - if (should_restart()) { + if (false && should_restart()) { restart(); } } @@ -308,11 +293,9 @@ namespace sat { } void unit_walk::restart() { - IF_VERBOSE(1, verbose_stream() << "restart\n"); while (!m_decisions.empty()) { pop_decision(); } - pqueue().reset(); } void unit_walk::update_max_trail() { @@ -483,8 +466,6 @@ namespace sat { void unit_walk::assign(literal lit) { VERIFY(value(lit) == l_undef); - //VERIFY(!m_trail.contains(lit)); - //VERIFY(!m_trail.contains(~lit)); s.m_assignment[lit.index()] = l_true; s.m_assignment[(~lit).index()] = l_false; m_trail.push_back(lit); @@ -494,15 +475,13 @@ namespace sat { 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) { - if (m_phase[v]) m_phase_tf[v].update(100); else m_phase_tf[v].update(0); - } } void unit_walk::log_status() { diff --git a/src/sat/sat_unit_walk.h b/src/sat/sat_unit_walk.h index 0551d3192..2aead871f 100644 --- a/src/sat/sat_unit_walk.h +++ b/src/sat/sat_unit_walk.h @@ -35,14 +35,10 @@ namespace sat { svector m_vars; unsigned_vector m_lim; unsigned m_head; - unsigned m_depth; public: - var_priority() { m_depth = 0; m_head = 0; } - void rewind() { m_head = 0; for (unsigned& l : m_lim) l = 0; } - unsigned depth() const { return m_depth; } - void inc_depth() { ++m_depth; } - void dec_depth() { --m_depth; } - void reset() { m_lim.reset(); m_head = 0; m_depth = 0; } + 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); @@ -67,7 +63,6 @@ namespace sat { // settings unsigned m_max_conflicts; - bool m_sticky_phase; unsigned m_flips; unsigned m_max_trail; @@ -78,11 +73,17 @@ namespace sat { unsigned m_conflict_offset; 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(); + lbool update_priority(unsigned level); + void update_pqueue(); void init_phase(); void init_propagation(); void refresh_solver(); From 96c05b02899cf77bdbf8695d93f6b0ee9e1547cd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 14 Feb 2019 17:00:02 -0800 Subject: [PATCH 284/318] remove reference to deprecated code in cmd_context Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.cpp | 26 +------------------------- src/cmd_context/cmd_context.h | 3 --- src/solver/parallel_tactic.cpp | 13 +++++++++---- 3 files changed, 10 insertions(+), 32 deletions(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 8675365c9..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; diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index 124821561..226ec0480 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -342,14 +342,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; } @@ -365,7 +363,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; diff --git a/src/solver/parallel_tactic.cpp b/src/solver/parallel_tactic.cpp index eda80b74b..d820dbd9b 100644 --- a/src/solver/parallel_tactic.cpp +++ b/src/solver/parallel_tactic.cpp @@ -391,10 +391,15 @@ private: log_branches(status); } - void report_sat(solver_state& s) { + void report_sat(solver_state& s, solver* conquer) { close_branch(s, l_true); model_ref mdl; - s.get_solver().get_model(mdl); + if (conquer) { + conquer->get_model(mdl); + } + else { + s.get_solver().get_model(mdl); + } if (mdl) { std::lock_guard lock(m_mutex); if (&s.m() != &m_manager) { @@ -453,7 +458,7 @@ private: if (canceled(s)) return; switch (s.simplify()) { case l_undef: break; - case l_true: report_sat(s); return; + case l_true: report_sat(s, nullptr); return; case l_false: report_unsat(s); return; } if (canceled(s)) return; @@ -498,7 +503,7 @@ private: break; case l_true: - report_sat(s); + report_sat(s, conquer.get()); if (conquer) { collect_statistics(*conquer.get()); } From 45aa8dd39ae7eb0bad2fe360541fd5700347f6bb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 14 Feb 2019 17:06:38 -0800 Subject: [PATCH 285/318] remove more references Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index 226ec0480..55ea65cb5 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -241,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; @@ -316,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. From e4c6dcd84c93079328249608fcd6194486f3c579 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 14 Feb 2019 17:09:18 -0800 Subject: [PATCH 286/318] import csp progress Signed-off-by: Nikolaj Bjorner --- src/ast/csp_decl_plugin.h | 2 +- src/smt/theory_jobscheduler.cpp | 107 ++++++++++++++++++++++---------- src/smt/theory_jobscheduler.h | 11 ++-- 3 files changed, 83 insertions(+), 37 deletions(-) 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/smt/theory_jobscheduler.cpp b/src/smt/theory_jobscheduler.cpp index 1499c102d..a7f877f15 100644 --- a/src/smt/theory_jobscheduler.cpp +++ b/src/smt/theory_jobscheduler.cpp @@ -305,7 +305,6 @@ namespace smt { literal end_ge_lo = mk_ge(ji.m_end, clb); // Initialization ensures that satisfiable states have completion time below end. - VERIFY(clb <= get_job_resource(j, r).m_end); region& r = ctx.get_region(); ctx.assign(end_ge_lo, ctx.mk_justification( @@ -321,6 +320,10 @@ namespace smt { */ bool theory_jobscheduler::constrain_end_time_interval(unsigned j, unsigned r) { unsigned idx1 = 0, idx2 = 0; + if (!job_has_resource(j, r)) { + IF_VERBOSE(0, verbose_stream() << "job " << j << " assigned non-registered resource " << r << "\n"); + return false; + } time_t s = start(j); job_resource const& jr = get_job_resource(j, r); TRACE("csp", tout << "job: " << j << " resource: " << r << " start: " << s << "\n";); @@ -451,6 +454,7 @@ namespace smt { job_info const& ji = m_jobs[j]; VERIFY(u.is_resource(ji.m_job2resource->get_root()->get_owner(), r)); TRACE("csp", tout << "job: " << j << " resource: " << r << "\n";); + std::cout << j << " -o " << r << "\n"; propagate_job2resource(j, r); } } @@ -458,8 +462,13 @@ namespace smt { void theory_jobscheduler::propagate_job2resource(unsigned j, unsigned r) { job_info const& ji = m_jobs[j]; res_info const& ri = m_resources[r]; - job_resource const& jr = get_job_resource(j, r); literal eq = mk_eq_lit(ji.m_job2resource, ri.m_resource); + if (!job_has_resource(j, r)) { + IF_VERBOSE(0, verbose_stream() << "job " << j << " assigned non-registered resource " << r << "\n"); + return; + } + return; + job_resource const& jr = get_job_resource(j, r); assert_last_end_time(j, r, jr, eq); assert_last_start_time(j, r, eq); assert_first_start_time(j, r, eq); @@ -489,7 +498,7 @@ namespace smt { } std::ostream& theory_jobscheduler::display(std::ostream & out, job_resource const& jr) const { - return out << "r:" << jr.m_resource_id << " cap:" << jr.m_capacity << " load:" << jr.m_loadpct << " end:" << jr.m_end; + return out << "r:" << jr.m_resource_id << " cap:" << jr.m_capacity << " load:" << jr.m_loadpct << " end:" << jr.m_finite_capacity_end; for (auto const& s : jr.m_properties) out << " " << s; out << "\n"; } @@ -620,21 +629,30 @@ namespace smt { } void theory_jobscheduler::set_preemptable(unsigned j, bool is_preemptable) { - m_jobs.reserve(j + 1); - m_jobs[j].m_is_preemptable = is_preemptable; + ensure_job(j).m_is_preemptable = is_preemptable; } - void theory_jobscheduler::add_job_resource(unsigned j, unsigned r, unsigned loadpct, uint64_t cap, time_t end, properties const& ps) { - SASSERT(get_context().at_base_level()); - SASSERT(0 <= loadpct && loadpct <= 100); - SASSERT(0 <= cap); - m_jobs.reserve(j + 1); - m_resources.reserve(r + 1); - job_info& ji = m_jobs[j]; - if (ji.m_resource2index.contains(r)) { - throw default_exception("resource already bound to job"); + theory_jobscheduler::res_info& theory_jobscheduler::ensure_resource(unsigned last) { + while (m_resources.size() <= last) { + unsigned r = m_resources.size(); + m_resources.push_back(res_info()); + res_info& ri = m_resources.back(); + context& ctx = get_context(); + app_ref res(u.mk_resource(r), m); + if (!ctx.e_internalized(res)) ctx.internalize(res, false); + ri.m_resource = ctx.get_enode(res); + app_ref ms(u.mk_makespan(r), m); + if (!ctx.e_internalized(ms)) ctx.internalize(ms, false); + ri.m_makespan = ctx.get_enode(ms); } - if (!ji.m_start) { + return m_resources[last]; + } + + theory_jobscheduler::job_info& theory_jobscheduler::ensure_job(unsigned last) { + while (m_jobs.size() <= last) { + unsigned j = m_jobs.size(); + m_jobs.push_back(job_info()); + job_info& ji = m_jobs.back(); context& ctx = get_context(); app_ref job(u.mk_job(j), m); app_ref start(u.mk_start(j), m); @@ -649,10 +667,22 @@ namespace smt { ji.m_end = ctx.get_enode(end); ji.m_job2resource = ctx.get_enode(res); } + return m_jobs[last]; + } + + void theory_jobscheduler::add_job_resource(unsigned j, unsigned r, unsigned loadpct, uint64_t cap, time_t finite_capacity_end, properties const& ps) { + SASSERT(get_context().at_base_level()); + SASSERT(0 <= loadpct && loadpct <= 100); + SASSERT(0 <= cap); + job_info& ji = ensure_job(j); + res_info& ri = ensure_resource(r); + if (ji.m_resource2index.contains(r)) { + throw default_exception("resource already bound to job"); + } ji.m_resource2index.insert(r, ji.m_resources.size()); - ji.m_resources.push_back(job_resource(r, cap, loadpct, end, ps)); - SASSERT(!m_resources[r].m_jobs.contains(j)); - m_resources[r].m_jobs.push_back(j); + ji.m_resources.push_back(job_resource(r, cap, loadpct, finite_capacity_end, ps)); + SASSERT(!ri.m_jobs.contains(j)); + ri.m_jobs.push_back(j); } @@ -660,17 +690,7 @@ namespace smt { SASSERT(get_context().at_base_level()); SASSERT(1 <= max_loadpct && max_loadpct <= 100); SASSERT(start <= end); - m_resources.reserve(r + 1); - res_info& ri = m_resources[r]; - if (!ri.m_resource) { - context& ctx = get_context(); - app_ref res(u.mk_resource(r), m); - if (!ctx.e_internalized(res)) ctx.internalize(res, false); - ri.m_resource = ctx.get_enode(res); - app_ref ms(u.mk_makespan(r), m); - if (!ctx.e_internalized(ms)) ctx.internalize(ms, false); - ri.m_makespan = ctx.get_enode(ms); - } + res_info& ri = ensure_resource(r); ri.m_available.push_back(res_available(max_loadpct, start, end, ps)); } @@ -718,22 +738,37 @@ namespace smt { for (job_resource const& jr : ji.m_resources) { unsigned r = jr.m_resource_id; res_info const& ri = m_resources[r]; - if (ri.m_available.empty()) continue; + if (ri.m_available.empty()) { + if (jr.m_capacity == 0) { + start_lb = 0; + end_ub = std::numeric_limits::max(); + runtime_lb = 0; + } + continue; + } unsigned idx = 0; if (first_available(jr, ri, idx)) { start_lb = std::min(start_lb, ri.m_available[idx].m_start); } + else { + IF_VERBOSE(0, verbose_stream() << "not first-available\n";); + } idx = ri.m_available.size(); if (last_available(jr, ri, idx)) { end_ub = std::max(end_ub, ri.m_available[idx].m_end); } + else { + IF_VERBOSE(0, verbose_stream() << "not last-available\n";); + } runtime_lb = std::min(runtime_lb, jr.m_capacity); // TBD: more accurate estimates for runtime_lb based on gaps // TBD: correct estimate of runtime_ub taking gaps into account. } CTRACE("csp", (start_lb > end_ub), tout << "there is no associated resource working time\n";); if (start_lb > end_ub) { + IF_VERBOSE(0, verbose_stream() << start_lb << " " << end_ub << "\n"); warning_msg("Job %d has no associated resource working time", job_id); + continue; } // start(j) >= start_lb @@ -755,9 +790,11 @@ namespace smt { // resource(j) = r => end(j) <= end(j, r) void theory_jobscheduler::assert_last_end_time(unsigned j, unsigned r, job_resource const& jr, literal eq) { +#if 0 job_info const& ji = m_jobs[j]; - literal l2 = mk_le(ji.m_end, jr.m_end); + literal l2 = mk_le(ji.m_end, jr.m_finite_capacity_end); get_context().mk_th_axiom(get_id(), ~eq, l2); +#endif } // resource(j) = r => start(j) <= lst(j, r, end(j, r)) @@ -880,6 +917,10 @@ namespace smt { } } + bool theory_jobscheduler::job_has_resource(unsigned j, unsigned r) const { + return m_jobs[j].m_resource2index.contains(r); + } + theory_jobscheduler::job_resource const& theory_jobscheduler::get_job_resource(unsigned j, unsigned r) const { job_info const& ji = m_jobs[j]; return ji.m_resources[ji.m_resource2index[r]]; @@ -1031,7 +1072,9 @@ namespace smt { bool theory_jobscheduler::resource_available(job_resource const& jr, res_available const& ra) const { auto const& jps = jr.m_properties; auto const& rps = ra.m_properties; - if (jps.size() > rps.size()) return false; + if (jps.size() > rps.size()) { + return false; + } unsigned j = 0, i = 0; for (; i < jps.size() && j < rps.size(); ) { if (jps[i] == rps[j]) { diff --git a/src/smt/theory_jobscheduler.h b/src/smt/theory_jobscheduler.h index 3b9a42595..55ece4da4 100644 --- a/src/smt/theory_jobscheduler.h +++ b/src/smt/theory_jobscheduler.h @@ -38,10 +38,10 @@ namespace smt { unsigned m_resource_id; // id of resource time_t m_capacity; // amount of resource to use unsigned m_loadpct; // assuming loadpct - time_t m_end; // must run before + time_t m_finite_capacity_end; properties m_properties; job_resource(unsigned r, time_t cap, unsigned loadpct, time_t end, properties const& ps): - m_resource_id(r), m_capacity(cap), m_loadpct(loadpct), m_end(end), m_properties(ps) {} + m_resource_id(r), m_capacity(cap), m_loadpct(loadpct), m_finite_capacity_end(end), m_properties(ps) {} }; struct job_time { @@ -89,10 +89,9 @@ namespace smt { struct res_info { unsigned_vector m_jobs; // jobs allocated to run on resource vector m_available; // time intervals where resource is available - time_t m_end; // can't run after enode* m_resource; enode* m_makespan; - res_info(): m_end(std::numeric_limits::max()), m_resource(nullptr), m_makespan(nullptr) {} + res_info(): m_resource(nullptr), m_makespan(nullptr) {} }; ast_manager& m; @@ -152,6 +151,9 @@ namespace smt { theory * mk_fresh(context * new_ctx) override; + res_info& ensure_resource(unsigned r); + job_info& ensure_job(unsigned j); + public: // set up job/resource global constraints void set_preemptable(unsigned j, bool is_preemptable); @@ -189,6 +191,7 @@ namespace smt { time_t capacity_used(unsigned j, unsigned r, time_t start, time_t end); // capacity used between start and end job_resource const& get_job_resource(unsigned j, unsigned r) const; + bool job_has_resource(unsigned j, unsigned r) const; // propagation void propagate_end_time(unsigned j, unsigned r); From 89bf2d43687f09afcec4ccf7e0ae5b226bfdd7cc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Feb 2019 12:05:24 -0800 Subject: [PATCH 287/318] add API for setting variable activity Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 9 +++++++ src/api/c++/z3++.h | 1 + src/api/python/z3/z3.py | 6 +++++ src/api/z3_api.h | 6 +++++ src/muz/spacer/spacer_iuc_solver.h | 1 + src/opt/opt_solver.h | 1 + src/sat/sat_solver.cpp | 6 +++++ src/sat/sat_solver.h | 1 + src/sat/sat_solver/inc_sat_solver.cpp | 9 +++++++ src/smt/smt_case_split_queue.cpp | 24 +++++++++++++++++++ src/smt/smt_case_split_queue.h | 1 + src/smt/smt_context.h | 11 ++++++++- src/smt/smt_kernel.cpp | 11 +++++++++ src/smt/smt_kernel.h | 5 ++++ src/smt/smt_solver.cpp | 4 ++++ src/solver/combined_solver.cpp | 5 ++++ src/solver/solver.h | 2 ++ src/solver/solver_pool.cpp | 4 ++++ src/solver/tactic2solver.cpp | 5 ++++ .../fd_solver/bounded_int2bv_solver.cpp | 4 ++++ src/tactic/fd_solver/enum2bv_solver.cpp | 4 ++++ src/tactic/fd_solver/pb2bv_solver.cpp | 6 +++++ 22 files changed, 125 insertions(+), 1 deletion(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 1c0664bb2..cafbfb9ff 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -431,6 +431,15 @@ extern "C" { 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); diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index e711457a3..6113fdbe9 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -2245,6 +2245,7 @@ namespace z3 { 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); diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 7185f520b..f8651ab90 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -6744,6 +6744,12 @@ class Solver(Z3PPObject): """ 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()`. diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 6f65e4a37..e1710b499 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -6236,6 +6236,12 @@ extern "C" { */ 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. diff --git a/src/muz/spacer/spacer_iuc_solver.h b/src/muz/spacer/spacer_iuc_solver.h index c3561a6d4..9b50b4c4e 100644 --- a/src/muz/spacer/spacer_iuc_solver.h +++ b/src/muz/spacer/spacer_iuc_solver.h @@ -124,6 +124,7 @@ public: 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; diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 9eda063e9..be71376ac 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -110,6 +110,7 @@ namespace opt { 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/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 9af8774e0..d917d1ae6 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1619,6 +1619,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)); } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index a977bbbaa..89b161c9f 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -387,6 +387,7 @@ namespace sat { char const* get_reason_unknown() const { 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); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index f0712da38..8a0747d15 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -341,6 +341,15 @@ public: 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) { + throw default_exception("literal does not correspond to a Boolean variable"); + } + m_solver.set_activity(v, activity); + } + proof * get_proof() override { UNREACHABLE(); return nullptr; diff --git a/src/smt/smt_case_split_queue.cpp b/src/smt/smt_case_split_queue.cpp index 6290ed14d..a4cb68506 100644 --- a/src/smt/smt_case_split_queue.cpp +++ b/src/smt/smt_case_split_queue.cpp @@ -80,6 +80,11 @@ namespace smt { m_queue.decreased(v); } + void activity_decreased_eh(bool_var v) override { + if (m_queue.contains(v)) + m_queue.increased(v); + } + void mk_var_eh(bool_var v) override { m_queue.reserve(v+1); SASSERT(!m_queue.contains(v)); @@ -167,6 +172,14 @@ namespace smt { m_delayed_queue.decreased(v); } + void activity_decreased_eh(bool_var v) override { + act_case_split_queue::activity_decreased_eh(v); + if (m_queue.contains(v)) + m_queue.increased(v); + if (m_delayed_queue.contains(v)) + m_delayed_queue.increased(v); + } + void mk_var_eh(bool_var v) override { m_queue.reserve(v+1); m_delayed_queue.reserve(v+1); @@ -324,6 +337,8 @@ namespace smt { void activity_increased_eh(bool_var v) override {} + void activity_decreased_eh(bool_var v) override {} + void mk_var_eh(bool_var v) override {} void del_var_eh(bool_var v) override {} @@ -509,6 +524,8 @@ namespace smt { void activity_increased_eh(bool_var v) override {} + void activity_decreased_eh(bool_var v) override {} + void mk_var_eh(bool_var v) override { if (m_context.is_searching()) { SASSERT(v >= m_bs_num_bool_vars); @@ -753,6 +770,8 @@ namespace smt { void activity_increased_eh(bool_var v) override {} + void activity_decreased_eh(bool_var v) override {} + void mk_var_eh(bool_var v) override {} void del_var_eh(bool_var v) override {} @@ -1133,6 +1152,11 @@ namespace smt { m_queue.decreased(v); } + void activity_decreased_eh(bool_var v) override { + if (m_queue.contains(v)) + m_queue.increased(v); + } + void mk_var_eh(bool_var v) override { m_queue.reserve(v+1); m_queue.insert(v); diff --git a/src/smt/smt_case_split_queue.h b/src/smt/smt_case_split_queue.h index cfa33bfe2..3bad083c8 100644 --- a/src/smt/smt_case_split_queue.h +++ b/src/smt/smt_case_split_queue.h @@ -32,6 +32,7 @@ namespace smt { class case_split_queue { public: virtual void activity_increased_eh(bool_var v) = 0; + virtual void activity_decreased_eh(bool_var v) = 0; virtual void mk_var_eh(bool_var v) = 0; virtual void del_var_eh(bool_var v) = 0; virtual void assign_lit_eh(literal l) {} diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index d935bf53e..dc9e43dca 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -412,10 +412,19 @@ namespace smt { return m_activity[v]; } - void set_activity(bool_var v, double & act) { + void set_activity(bool_var v, double const & act) { m_activity[v] = act; } + void activity_changed(bool_var v, bool increased) { + if (increased) { + m_case_split_queue->activity_increased_eh(v); + } + else { + m_case_split_queue->activity_decreased_eh(v); + } + } + bool is_assumption(bool_var v) const { return get_bdata(v).m_assumption; } diff --git a/src/smt/smt_kernel.cpp b/src/smt/smt_kernel.cpp index f2f17321c..571032039 100644 --- a/src/smt/smt_kernel.cpp +++ b/src/smt/smt_kernel.cpp @@ -154,6 +154,13 @@ namespace smt { expr_ref_vector get_trail() { return m_kernel.get_trail(); } + + void set_activity(expr* lit, double act) { + auto v = m_kernel.get_bool_var(lit); + double old_act = m_kernel.get_activity(v); + m_kernel.set_activity(v, act); + m_kernel.activity_changed(v, act > old_act); + } failure last_failure() const { return m_kernel.get_last_search_failure(); @@ -412,5 +419,9 @@ namespace smt { return m_imp->get_trail(); } + void kernel::set_activity(expr* lit, double activity) { + m_imp->set_activity(lit, activity); + } + }; diff --git a/src/smt/smt_kernel.h b/src/smt/smt_kernel.h index 6eeb8d728..a46195e02 100644 --- a/src/smt/smt_kernel.h +++ b/src/smt/smt_kernel.h @@ -229,6 +229,11 @@ namespace smt { */ expr_ref_vector get_trail(); + /** + \brief set activity of literal + */ + void set_activity(expr* lit, double activity); + /** \brief (For debubbing purposes) Prints the state of the kernel */ diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index e36858b06..0052dd316 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -203,6 +203,10 @@ namespace smt { return m_context.get_trail(); } + void set_activity(expr* lit, double activity) override { + m_context.set_activity(lit, activity); + } + struct scoped_minimize_core { smt_solver& s; expr_ref_vector m_assumptions; diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index b602fe6e1..b939efc6b 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -328,6 +328,11 @@ public: return m_solver2->get_trail(); } + void set_activity(expr* lit, double activity) override { + m_solver1->set_activity(lit, activity); + m_solver2->set_activity(lit, activity); + } + proof * get_proof() override { if (m_use_solver1_results) return m_solver1->get_proof(); diff --git a/src/solver/solver.h b/src/solver/solver.h index 0c509b8c7..be3751bcd 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -251,6 +251,8 @@ public: virtual void get_levels(ptr_vector const& vars, unsigned_vector& depth) = 0; + virtual void set_activity(expr* lit, double activity) = 0; + class scoped_push { solver& s; bool m_nopop; diff --git a/src/solver/solver_pool.cpp b/src/solver/solver_pool.cpp index 7f3882447..4d6724aa7 100644 --- a/src/solver/solver_pool.cpp +++ b/src/solver/solver_pool.cpp @@ -127,6 +127,10 @@ public: return m_base->get_trail(); } + void set_activity(expr* var, double activity) override { + m_base->set_activity(var, activity); + } + lbool check_sat_core2(unsigned num_assumptions, expr * const * assumptions) override { SASSERT(!m_pushed || get_scope_level() > 0); m_proof.reset(); diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 8721e106b..c62e920e7 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -93,6 +93,11 @@ public: throw default_exception("cannot retrieve trail from solvers created using tactcis"); } + void set_activity(expr* var, double activity) override { + throw default_exception("cannot set activity for solvers created using tactcis"); + } + + }; ast_manager& tactic2solver::get_manager() const { return m_assertions.get_manager(); } diff --git a/src/tactic/fd_solver/bounded_int2bv_solver.cpp b/src/tactic/fd_solver/bounded_int2bv_solver.cpp index b19875737..0decaec82 100644 --- a/src/tactic/fd_solver/bounded_int2bv_solver.cpp +++ b/src/tactic/fd_solver/bounded_int2bv_solver.cpp @@ -161,6 +161,10 @@ public: expr_ref_vector get_trail() override { return m_solver->get_trail(); } + void set_activity(expr* var, double activity) override { + m_solver->set_activity(var, activity); + } + model_converter* external_model_converter() const { return concat(mc0(), local_model_converter()); } diff --git a/src/tactic/fd_solver/enum2bv_solver.cpp b/src/tactic/fd_solver/enum2bv_solver.cpp index d8119ddfd..b232d8ea3 100644 --- a/src/tactic/fd_solver/enum2bv_solver.cpp +++ b/src/tactic/fd_solver/enum2bv_solver.cpp @@ -186,6 +186,10 @@ public: return m_solver->get_trail(); } + void set_activity(expr* var, double activity) override { + m_solver->set_activity(var, activity); + } + unsigned get_num_assertions() const override { return m_solver->get_num_assertions(); } diff --git a/src/tactic/fd_solver/pb2bv_solver.cpp b/src/tactic/fd_solver/pb2bv_solver.cpp index 29aa573e3..c6866ecf4 100644 --- a/src/tactic/fd_solver/pb2bv_solver.cpp +++ b/src/tactic/fd_solver/pb2bv_solver.cpp @@ -96,6 +96,7 @@ public: if (mc) (*mc)(mdl); } } + void get_levels(ptr_vector const& vars, unsigned_vector& depth) override { m_solver->get_levels(vars, depth); } @@ -104,9 +105,14 @@ public: return m_solver->get_trail(); } + void set_activity(expr* var, double activity) override { + m_solver->set_activity(var, activity); + } + model_converter* external_model_converter() const{ return concat(mc0(), local_model_converter()); } + model_converter_ref get_model_converter() const override { model_converter_ref mc = external_model_converter(); mc = concat(mc.get(), m_solver->get_model_converter().get()); From 39f73fa5951e69cb93807578756a8a451fac6866 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Feb 2019 16:56:55 -0800 Subject: [PATCH 288/318] ensure that activity works for sat solver from cold state Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 1 + src/sat/sat_solver/inc_sat_solver.cpp | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index d917d1ae6..b933b6ddb 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1656,6 +1656,7 @@ namespace sat { m_min_core.reset(); m_simplifier.init_search(); TRACE("sat", display(tout);); + } /** diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 8a0747d15..9ca1150a9 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -345,9 +345,10 @@ public: m.is_not(var, var); sat::bool_var v = m_map.to_bool_var(var); if (v == sat::null_bool_var) { - throw default_exception("literal does not correspond to a Boolean variable"); + v = m_solver.add_var(true); + m_map.insert(var, v); } - m_solver.set_activity(v, activity); + m_solver.set_activity(v, static_cast(activity)); } proof * get_proof() override { From f84de9400e7d63453234d0648980c5fd595b0e35 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Feb 2019 17:58:26 -0800 Subject: [PATCH 289/318] also deal with initializing boolean variables in smt context Signed-off-by: Nikolaj Bjorner --- src/sat/sat_unit_walk.cpp | 18 +++++------------- src/sat/sat_unit_walk.h | 1 - src/smt/smt_kernel.cpp | 8 ++++++++ 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/sat/sat_unit_walk.cpp b/src/sat/sat_unit_walk.cpp index 314c275f3..8c7a6c6f9 100644 --- a/src/sat/sat_unit_walk.cpp +++ b/src/sat/sat_unit_walk.cpp @@ -99,6 +99,7 @@ namespace sat { 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(); } @@ -276,9 +277,6 @@ namespace sat { init_runs(); init_phase(); } - if (false && should_restart()) { - restart(); - } } bool unit_walk::should_restart() { @@ -287,9 +285,7 @@ namespace sat { ++m_luby_index; return true; } - else { - return false; - } + return false; } void unit_walk::restart() { @@ -328,9 +324,9 @@ namespace sat { } 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 { @@ -495,10 +491,6 @@ namespace sat { << ")\n";); } - literal unit_walk::choose_literal() { - return m_trail[m_qhead++]; - } - void unit_walk::set_conflict(literal l1, literal l2) { set_conflict(); } diff --git a/src/sat/sat_unit_walk.h b/src/sat/sat_unit_walk.h index 2aead871f..14588a63c 100644 --- a/src/sat/sat_unit_walk.h +++ b/src/sat/sat_unit_walk.h @@ -91,7 +91,6 @@ namespace sat { void flip_phase(literal l); 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); diff --git a/src/smt/smt_kernel.cpp b/src/smt/smt_kernel.cpp index 571032039..adcda3979 100644 --- a/src/smt/smt_kernel.cpp +++ b/src/smt/smt_kernel.cpp @@ -156,6 +156,14 @@ namespace smt { } void set_activity(expr* lit, double act) { + SASSERT(m().is_bool(lit)); + m().is_not(lit, lit); + if (!m_kernel.b_internalized(lit)) { + m_kernel.internalize(lit, false); + } + if (!m_kernel.b_internalized(lit)) { + return; + } auto v = m_kernel.get_bool_var(lit); double old_act = m_kernel.get_activity(v); m_kernel.set_activity(v, act); From 4f223542acb829a5085b4437dd6803ed2b7335c5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 16 Feb 2019 09:38:47 -0800 Subject: [PATCH 290/318] fix #2129 Signed-off-by: Nikolaj Bjorner --- src/model/model_evaluator.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index 53defbc3d..968aca51f 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -217,13 +217,18 @@ struct evaluator_cfg : public default_rewriter_cfg { return BR_DONE; } if (get_macro(g, def, q, def_pr)) { - sort_ref_vector vars(m); + sort_ref_vector sorts(m); + expr_ref_vector vars(m); svector var_names; - for (unsigned i = 0; i < g->get_arity(); ++i) { - var_names.push_back(symbol(i)); - vars.push_back(g->get_domain(i)); + 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)); } - result = m.mk_lambda(vars.size(), vars.c_ptr(), var_names.c_ptr(), def); + 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); From 7f51cc79310b8503abb22e37c0feb449dc9b6969 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 16 Feb 2019 09:54:05 -0800 Subject: [PATCH 291/318] fix #2140 Signed-off-by: Nikolaj Bjorner --- src/tactic/portfolio/default_tactic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tactic/portfolio/default_tactic.cpp b/src/tactic/portfolio/default_tactic.cpp index 23334bf07..c2bccd75b 100644 --- a/src/tactic/portfolio/default_tactic.cpp +++ b/src/tactic/portfolio/default_tactic.cpp @@ -35,7 +35,7 @@ Notes: tactic * mk_default_tactic(ast_manager & m, params_ref const & p) { tactic * st = using_params(and_then(mk_simplify_tactic(m), - cond(mk_is_propositional_probe(), if_no_proofs(mk_fd_tactic(m, p)), + cond(mk_and(mk_is_propositional_probe(), mk_not(mk_produce_proofs_probe())), mk_fd_tactic(m, p), cond(mk_is_qfbv_probe(), mk_qfbv_tactic(m), cond(mk_is_qfaufbv_probe(), mk_qfaufbv_tactic(m), cond(mk_is_qflia_probe(), mk_qflia_tactic(m), From 886c62ef41106740589eb5806f579fddc55ba67e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 16 Feb 2019 10:30:44 -0800 Subject: [PATCH 292/318] add example from #2138 Signed-off-by: Nikolaj Bjorner --- examples/c++/example.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) 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"; From c1402ad70fc416b8fc8d814f7b4f85464bb451b0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 16 Feb 2019 20:39:15 -0800 Subject: [PATCH 293/318] tone down verbosity of integrity checking Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index b933b6ddb..541c4f0f5 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1790,11 +1790,11 @@ namespace sat { m_mc(m_model); if (!check_clauses(m_model)) { - IF_VERBOSE(0, verbose_stream() << "failure checking clauses on transformed model\n";); + IF_VERBOSE(1, 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";); + IF_VERBOSE(1, for (bool_var v = 0; v < num; v++) verbose_stream() << v << ": " << m_model[v] << "\n";); throw solver_exception("check model failed"); } @@ -1806,8 +1806,8 @@ namespace sat { 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(1, m_mc.display(verbose_stream())); + IF_VERBOSE(1, display_units(verbose_stream())); //IF_VERBOSE(0, m_clone->display(verbose_stream() << "clone\n")); throw solver_exception("check model failed (for cloned solver)"); } @@ -1819,7 +1819,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"; @@ -1827,7 +1827,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; } @@ -1843,8 +1843,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; } @@ -1855,7 +1855,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"; @@ -1876,8 +1876,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; } From ea778eefb2fdba2102f8c1e6064b4e7968360822 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 16 Feb 2019 20:58:30 -0800 Subject: [PATCH 294/318] skip optimization Signed-off-by: Nikolaj Bjorner --- src/opt/maxlex.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/opt/maxlex.cpp b/src/opt/maxlex.cpp index b2799f1c8..111d6f07a 100644 --- a/src/opt/maxlex.cpp +++ b/src/opt/maxlex.cpp @@ -245,6 +245,7 @@ namespace opt { // every time probing whether to include soft_i, // include suffix that is known to be assignable to T + // lbool maxlexN() { unsigned sz = m_soft.size(); for (unsigned i = 0; i < sz; ++i) { @@ -297,7 +298,7 @@ namespace opt { lbool operator()() override { init(); - return maxlexN(); + return maxlex1(); } From 8c085f1a185087c82075a963e31f0f62acf40c94 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 16 Feb 2019 21:26:29 -0800 Subject: [PATCH 295/318] removing unused and fixing suspect optimization Signed-off-by: Nikolaj Bjorner --- src/opt/maxlex.cpp | 137 +++------------------------------------------ 1 file changed, 8 insertions(+), 129 deletions(-) diff --git a/src/opt/maxlex.cpp b/src/opt/maxlex.cpp index 111d6f07a..56dbfebf5 100644 --- a/src/opt/maxlex.cpp +++ b/src/opt/maxlex.cpp @@ -74,11 +74,6 @@ namespace opt { } } - void set_value(soft& soft, lbool v) { - soft.set_value(v); - assert_value(soft); - } - void update_assignment(model_ref & mdl) { bool first_undef = true, second_undef = false; for (auto & soft : m_soft) { @@ -95,7 +90,9 @@ namespace opt { soft.set_value(v); } else { - set_value(soft, v); // also update constraints + SASSERT(v == l_true); + soft.set_value(v); + assert_value(soft); } } } @@ -130,121 +127,8 @@ namespace opt { if (mdl) update_assignment(mdl); } - lbool maxlex1() { - for (auto & soft : m_soft) { - if (soft.value == l_true) { - continue; - } - SASSERT(soft.value == l_undef); - expr* a = soft.s; - lbool is_sat = s().check_sat(1, &a); - switch (is_sat) { - case l_false: - set_value(soft, l_false); - update_bounds(); - break; - case l_true: - update_assignment(); - SASSERT(soft.value == l_true); - break; - case l_undef: - return l_undef; - } - } - return l_true; - } - - // try two literals per round. - // doesn't seem to make a difference based on sample test. - lbool maxlex2() { - unsigned sz = m_soft.size(); - for (unsigned i = 0; i < sz; ++i) { - auto& soft = m_soft[i]; - if (soft.value != l_undef) { - continue; - } - SASSERT(soft.value == l_undef); - if (i + 1 == sz) { - expr* a = soft.s; - lbool is_sat = s().check_sat(1, &a); - switch (is_sat) { - case l_false: - set_value(soft, l_false); - update_bounds(); - break; - case l_true: - update_assignment(); - SASSERT(soft.value == l_true); - break; - case l_undef: - return l_undef; - } - } - else { - auto& soft2 = m_soft[i+1]; - expr_ref_vector core(m); - expr* a = soft.s; - expr* b = soft2.s; - expr* asms[2] = { a, b }; - lbool is_sat = s().check_sat(2, asms); - switch (is_sat) { - case l_true: - update_assignment(); - SASSERT(soft.value == l_true); - SASSERT(soft2.value == l_true); - break; - case l_false: - s().get_unsat_core(core); - if (core.contains(b)) { - expr_ref not_b(mk_not(m, b), m); - asms[1] = not_b; - switch (s().check_sat(2, asms)) { - case l_true: - // a, b is unsat, a, not b is sat. - set_value(soft2, l_false); - update_assignment(); - SASSERT(soft.value == l_true); - SASSERT(soft2.value == l_false); - break; - case l_false: - // a, b is unsat, a, not b is unsat -> a is unsat - // b is unsat, a, not b is unsat -> not a, not b - set_value(soft, l_false); - // core1 = { b } - // core2 = { a, not b } - if (!core.contains(a)) { - set_value(soft2, l_false); - } - else { - // core1 = { a, b} - // core2 = { not_b } - core.reset(); - s().get_unsat_core(core); - if (!core.contains(a)) { - set_value(soft2, l_true); - } - } - update_bounds(); - break; - case l_undef: - return l_undef; - } - } - else { - set_value(soft, l_false); - update_bounds(); - } - break; - case l_undef: - return l_undef; - } - } - } - return l_true; - } - - // every time probing whether to include soft_i, - // include suffix that is known to be assignable to T + // + // include soft constraints that are known to be assignable to true after failed literal. // lbool maxlexN() { unsigned sz = m_soft.size(); @@ -255,12 +139,6 @@ namespace opt { } expr_ref_vector asms(m); asms.push_back(soft.s); - for (unsigned j = i + 1; j < sz; ++j) { - auto& soft2 = m_soft[j]; - if (soft2.value == l_true) { - asms.push_back(soft2.s); - } - } lbool is_sat = s().check_sat(asms); switch (is_sat) { case l_true: @@ -268,7 +146,8 @@ namespace opt { SASSERT(soft.value == l_true); break; case l_false: - set_value(soft, 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) { @@ -298,7 +177,7 @@ namespace opt { lbool operator()() override { init(); - return maxlex1(); + return maxlexN(); } From 5b57c6b780f156b0d757c3aecf82d080bbc8c71e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 17 Feb 2019 01:30:26 -0800 Subject: [PATCH 296/318] unused variable warnings Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/hoist_rewriter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/rewriter/hoist_rewriter.cpp b/src/ast/rewriter/hoist_rewriter.cpp index 5deeebdf4..31909f12b 100644 --- a/src/ast/rewriter/hoist_rewriter.cpp +++ b/src/ast/rewriter/hoist_rewriter.cpp @@ -69,7 +69,6 @@ br_status hoist_rewriter::mk_or(unsigned num_args, expr * const * es, expr_ref & turn = !turn; (*preds)[turn].reset(); reset(m_uf0); - unsigned v1 = 0, v2 = 0; VERIFY(is_and(es[j], args[turn])); for (expr* e : *args[turn]) { @@ -196,6 +195,7 @@ bool hoist_rewriter::is_and(expr * e, expr_ref_vector* args) { void hoist_rewriter::reset(basic_union_find& uf) { uf.reset(); for (expr* e : m_var2expr) { + (void)e; uf.mk_var(); } } From 0aafa8b7ce3adb82125d72c10370151e35a2fd18 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Feb 2019 15:52:42 +0100 Subject: [PATCH 297/318] optimize binary output Signed-off-by: Nikolaj Bjorner --- src/sat/sat_drat.cpp | 19 ++++++++++++------- src/sat/sat_simplifier.cpp | 1 - 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index c0799c061..f8e04a583 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -120,22 +120,27 @@ namespace sat { case status::deleted: ch = 'd'; break; default: UNREACHABLE(); break; } - (*m_bout) << ch; + 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 & ((1 << 7) - 1)); + ch = static_cast(v & 255); v >>= 7; - if (v) ch |= (1 << 7); - //std::cout << std::hex << ((unsigned char)ch) << std::dec << " "; - (*m_bout) << ch; + if (v) ch |= 128; + buffer[len++] = ch; + if (len == sizeof(buffer)) { + m_bout->write(buffer, len); + len = 0; + } } while (v); } - ch = 0; - (*m_bout) << ch; + buffer[len++] = 0; + m_bout->write(buffer, len); } bool drat::is_cleaned(clause& c) const { diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index f536dda03..58dab0ff5 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1222,7 +1222,6 @@ namespace sat { RI literals. */ void minimize_covered_clause(unsigned idx) { - 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); From 7fb2c6a908d5e1a1c4740e0bd3e1b104e33fff19 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Feb 2019 15:55:24 +0100 Subject: [PATCH 298/318] turn off model validation unless specified by parameter Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 541c4f0f5..779cb7aad 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1788,7 +1788,10 @@ namespace sat { // m_mc.set_solver(nullptr); m_mc(m_model); - + + if (!gparams::get_ref().get_bool("model_validate", false)) { + return; + } if (!check_clauses(m_model)) { IF_VERBOSE(1, verbose_stream() << "failure checking clauses on transformed model\n";); IF_VERBOSE(10, m_mc.display(verbose_stream())); From 591abead4bf9e6c931ec9db691b0ae346e3fc287 Mon Sep 17 00:00:00 2001 From: Audrey Dutcher Date: Mon, 18 Feb 2019 23:51:11 -0700 Subject: [PATCH 299/318] Revert "Don't delete the reference to the native library in the python bindings" This reverts commit 3339be6d221567f372fac19ef53215beff8b0164. --- scripts/update_api.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/update_api.py b/scripts/update_api.py index 557ac4c6c..161c783e8 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -1704,6 +1704,7 @@ def write_exe_c_preamble(exe_c): def write_core_py_post(core_py): core_py.write(""" # Clean up +del _lib del _default_dirs del _all_dirs del _ext From c2cb2c9fad49d59821a8239c3ad0cb4cef0c5b16 Mon Sep 17 00:00:00 2001 From: Audrey Dutcher Date: Mon, 18 Feb 2019 23:59:27 -0700 Subject: [PATCH 300/318] python bindings: add core functions with _bytes suffix that do not decode strings --- scripts/update_api.py | 47 +++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index 161c783e8..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 From 2138a5232f61a3fa5d18b99cfc671e276d069505 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Feb 2019 10:16:50 +0100 Subject: [PATCH 301/318] fix #2142 Signed-off-by: Nikolaj Bjorner --- src/ast/bv_decl_plugin.cpp | 4 ++++ src/sat/sat_drat.cpp | 15 +++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/ast/bv_decl_plugin.cpp b/src/ast/bv_decl_plugin.cpp index 6bbe3ce13..7071f169c 100644 --- a/src/ast/bv_decl_plugin.cpp +++ b/src/ast/bv_decl_plugin.cpp @@ -548,11 +548,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/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index f8e04a583..ac05b50f1 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -173,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) { @@ -190,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); @@ -362,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) { @@ -385,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) {} @@ -583,7 +590,7 @@ namespace sat { void drat::add() { if (m_out) (*m_out) << "0\n"; - if (m_bout) bdump(0, nullptr, learned); + if (m_bout) bdump(0, nullptr, status::learned); if (m_check_unsat) { SASSERT(m_inconsistent); } From 8c2584bcf702859605f0a0a48de3cad0670bd9bd Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 19 Feb 2019 10:51:53 +0000 Subject: [PATCH 302/318] eliminate a few ref incs/decs plus remove unused variable --- src/tactic/bv/elim_small_bv_tactic.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/tactic/bv/elim_small_bv_tactic.cpp b/src/tactic/bv/elim_small_bv_tactic.cpp index a9f94ca3f..9608ab0f7 100644 --- a/src/tactic/bv/elim_small_bv_tactic.cpp +++ b/src/tactic/bv/elim_small_bv_tactic.cpp @@ -37,7 +37,6 @@ class elim_small_bv_tactic : public tactic { bv_util m_util; th_rewriter m_simp; ref m_mc; - goal * m_goal; unsigned m_max_bits; unsigned long long m_max_steps; unsigned long long m_max_memory; // in bytes @@ -53,7 +52,6 @@ class elim_small_bv_tactic : public tactic { m_bindings(_m), m_num_eliminated(0) { updt_params(p); - m_goal = nullptr; m_max_steps = UINT_MAX; } @@ -76,7 +74,7 @@ class elim_small_bv_tactic : public tactic { TRACE("elim_small_bv", tout << "replace idx " << idx << " with " << mk_ismt2_pp(replacement, m) << " in " << mk_ismt2_pp(e, m) << std::endl;); expr_ref res(m); - expr_ref_vector substitution(m); + ptr_vector substitution; substitution.resize(num_decls, nullptr); substitution[num_decls - idx - 1] = replacement; @@ -152,9 +150,7 @@ class elim_small_bv_tactic : public tactic { expr_ref_vector new_bodies(m); for (unsigned j = 0; j < bv_sz && !max_steps_exceeded(num_steps); j ++) { expr_ref n(m_util.mk_numeral(j, bv_sz), m); - expr_ref nb(m); - nb = replace_var(uv, num_decls, max_var_idx_p1, i, s, body, n); - new_bodies.push_back(nb); + new_bodies.push_back(replace_var(uv, num_decls, max_var_idx_p1, i, s, body, n)); num_steps++; } @@ -250,7 +246,6 @@ public: fail_if_unsat_core_generation("elim-small-bv", g); m_rw.cfg().m_produce_models = g->models_enabled(); - m_rw.m_cfg.m_goal = g.get(); expr_ref new_curr(m); proof_ref new_pr(m); unsigned size = g->size(); From 8e4ef19f45380aec024a8835e13150928b5f6ebc Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 19 Feb 2019 10:54:41 +0000 Subject: [PATCH 303/318] fix debug build --- src/tactic/bv/elim_small_bv_tactic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tactic/bv/elim_small_bv_tactic.cpp b/src/tactic/bv/elim_small_bv_tactic.cpp index 9608ab0f7..256586896 100644 --- a/src/tactic/bv/elim_small_bv_tactic.cpp +++ b/src/tactic/bv/elim_small_bv_tactic.cpp @@ -92,7 +92,7 @@ class elim_small_bv_tactic : public tactic { TRACE("elim_small_bv", tout << "substitution: " << std::endl; for (unsigned k = 0; k < substitution.size(); k++) { - expr * se = substitution[k].get(); + expr * se = substitution[k]; tout << k << " = "; if (se == 0) tout << "0"; else tout << mk_ismt2_pp(se, m); From edf0df634d5564cff49b463851081f5a135261f2 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 19 Feb 2019 13:18:20 +0000 Subject: [PATCH 304/318] simplifications to refs --- src/ackermannization/lackr.cpp | 2 +- src/ackermannization/lackr_model_constructor.cpp | 10 +++------- src/util/obj_ref.h | 6 ++---- src/util/ref_buffer.h | 6 ++++++ src/util/ref_vector.h | 4 ++-- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/ackermannization/lackr.cpp b/src/ackermannization/lackr.cpp index a965fc261..4fe7797d4 100644 --- a/src/ackermannization/lackr.cpp +++ b/src/ackermannization/lackr.cpp @@ -122,7 +122,7 @@ bool lackr::ackr(app * const t1, app * const t2) { 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; } 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/util/obj_ref.h b/src/util/obj_ref.h index 8908f2cdd..e3b0d0710 100644 --- a/src/util/obj_ref.h +++ b/src/util/obj_ref.h @@ -94,10 +94,8 @@ public: obj_ref & operator=(obj_ref && n) { SASSERT(&m_manager == &n.m_manager); - if (this != &n) { - std::swap(m_obj, n.m_obj); - n.reset(); - } + std::swap(m_obj, n.m_obj); + n.reset(); return *this; } diff --git a/src/util/ref_buffer.h b/src/util/ref_buffer.h index 4768c3f28..49213cc62 100644 --- a/src/util/ref_buffer.h +++ b/src/util/ref_buffer.h @@ -58,6 +58,12 @@ public: inc_ref(n); m_buffer.push_back(n); } + + template + void push_back(obj_ref && n) { + m_buffer.push_back(n.get()); + n.steal(); + } void pop_back() { SASSERT(!m_buffer.empty()); diff --git a/src/util/ref_vector.h b/src/util/ref_vector.h index d0e9a8f55..732ec20dd 100644 --- a/src/util/ref_vector.h +++ b/src/util/ref_vector.h @@ -99,8 +99,8 @@ public: return *this; } - template - ref_vector_core& push_back(obj_ref && n) { + template + ref_vector_core& push_back(obj_ref && n) { m_nodes.push_back(n.get()); n.steal(); return *this; From 61272fdc0cfa742adc25f8059c40d3d82f7b7888 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 19 Feb 2019 13:36:39 +0000 Subject: [PATCH 305/318] remove a few more inc/dec refs --- src/ast/rewriter/der.cpp | 6 ++---- src/ast/rewriter/distribute_forall.cpp | 3 +-- src/ast/rewriter/var_subst.cpp | 7 ++----- src/tactic/core/distribute_forall_tactic.cpp | 6 ++---- 4 files changed, 7 insertions(+), 15 deletions(-) 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/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/tactic/core/distribute_forall_tactic.cpp b/src/tactic/core/distribute_forall_tactic.cpp index c2688f741..800644d9e 100644 --- a/src/tactic/core/distribute_forall_tactic.cpp +++ b/src/tactic/core/distribute_forall_tactic.cpp @@ -49,8 +49,7 @@ class distribute_forall_tactic : public tactic { expr * not_arg = m.mk_not(arg); quantifier_ref tmp_q(m); tmp_q = m.update_quantifier(old_q, not_arg); - expr_ref new_q = elim_unused_vars(m, tmp_q, params_ref()); - new_args.push_back(new_q); + new_args.push_back(elim_unused_vars(m, tmp_q, params_ref())); } result = m.mk_and(new_args.size(), new_args.c_ptr()); return true; @@ -68,8 +67,7 @@ class distribute_forall_tactic : public tactic { expr * arg = to_app(new_body)->get_arg(i); quantifier_ref tmp_q(m); tmp_q = m.update_quantifier(old_q, arg); - expr_ref new_q = elim_unused_vars(m, tmp_q, params_ref()); - new_args.push_back(new_q); + new_args.push_back(elim_unused_vars(m, tmp_q, params_ref())); } result = m.mk_and(new_args.size(), new_args.c_ptr()); return true; From caa15ea04d555dd494cfe38beb960d6c61716112 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Feb 2019 18:17:07 +0100 Subject: [PATCH 306/318] enable cardinality constraints in nla2bv Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 47 +++++++++++++-------------- src/sat/sat_solver.h | 1 + src/tactic/arith/nla2bv_tactic.cpp | 37 ++++++++++++++------- src/tactic/smtlogics/qfnia_tactic.cpp | 18 ++++++---- 4 files changed, 60 insertions(+), 43 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 779cb7aad..2df184c88 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1779,41 +1779,30 @@ namespace sat { } #endif - IF_VERBOSE(10, verbose_stream() << "\"checking model\"\n";); - if (!check_clauses(m_model)) { - throw solver_exception("check model failed"); + if (m_clone) { + 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); + if (m_config.m_drat) { + m_drat.check_model(m_model); + } - // m_mc.set_solver(nullptr); m_mc(m_model); - if (!gparams::get_ref().get_bool("model_validate", false)) { - return; - } - if (!check_clauses(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(0, display_units(verbose_stream())); - //IF_VERBOSE(0, display(verbose_stream())); - IF_VERBOSE(1, for (bool_var v = 0; v < num; v++) verbose_stream() << v << ": " << m_model[v] << "\n";); - + IF_VERBOSE(10, display_model(verbose_stream())); 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(1, 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(1, m_mc.display(verbose_stream())); - IF_VERBOSE(1, display_units(verbose_stream())); - //IF_VERBOSE(0, m_clone->display(verbose_stream() << "clone\n")); - throw solver_exception("check model failed (for cloned solver)"); - } + 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)"); } } @@ -3546,6 +3535,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++) { diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 89b161c9f..53c3062a8 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -668,6 +668,7 @@ namespace sat { void display_watches(std::ostream & out) const; void display_watches(std::ostream & out, literal lit) 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/tactic/arith/nla2bv_tactic.cpp b/src/tactic/arith/nla2bv_tactic.cpp index 06150e18b..0a58740d1 100644 --- a/src/tactic/arith/nla2bv_tactic.cpp +++ b/src/tactic/arith/nla2bv_tactic.cpp @@ -21,6 +21,7 @@ Notes: #include "tactic/tactical.h" #include "ast/arith_decl_plugin.h" #include "ast/bv_decl_plugin.h" +#include "ast/pb_decl_plugin.h" #include "ast/for_each_expr.h" #include "ast/rewriter/expr_replacer.h" #include "util/optional.h" @@ -85,13 +86,18 @@ class nla2bv_tactic : public tactic { TRACE("nla2bv", g.display(tout); tout << "Muls: " << count_mul(g) << "\n"; ); + tactic_report report("nla->bv", g); m_fmc = alloc(generic_model_converter, m_manager, "nla2bv"); m_bounds(g); collect_power2(g); - if(!collect_vars(g)) { + switch (collect_vars(g)) { + case has_num: + break; + case not_supported: throw tactic_exception("goal is not in the fragment supported by nla2bv"); + case is_bool: + return; } - tactic_report report("nla->bv", g); substitute_vars(g); TRACE("nla2bv", g.display(tout << "substitute vars\n");); reduce_bv2int(g); @@ -308,27 +314,30 @@ class nla2bv_tactic : public tactic { class get_uninterp_proc { imp& m_imp; + arith_util& a; + ast_manager& m; + pb_util pb; ptr_vector m_vars; bool m_in_supported_fragment; public: - get_uninterp_proc(imp& s): m_imp(s), m_in_supported_fragment(true) {} + get_uninterp_proc(imp& s): m_imp(s), a(s.m_arith), m(a.get_manager()), pb(m), m_in_supported_fragment(true) {} ptr_vector const& vars() { return m_vars; } void operator()(var * n) { m_in_supported_fragment = false; } void operator()(app* n) { - arith_util& a = m_imp.m_arith; - ast_manager& m = a.get_manager(); - if (a.is_int(n) && - is_uninterp_const(n)) { + if (a.is_int(n) && is_uninterp_const(n)) { + TRACE("nla2bv", tout << "Not supported: " << mk_ismt2_pp(n, m) << "\n";); m_vars.push_back(n); } - else if (a.is_real(n) && - is_uninterp_const(n)) { + else if (a.is_real(n) && is_uninterp_const(n)) { m_vars.push_back(n); } else if (m.is_bool(n) && is_uninterp_const(n)) { + } + else if (m.is_bool(n) && n->get_decl()->get_family_id() == pb.get_family_id()) { + } else if (!(a.is_mul(n) || a.is_add(n) || @@ -342,7 +351,7 @@ class nla2bv_tactic : public tactic { m_imp.m_bv2real.is_pos_le(n) || m_imp.m_bv2real.is_pos_lt(n) || n->get_family_id() == a.get_manager().get_basic_family_id())) { - TRACE("nla2bv", tout << "Not supported: " << mk_ismt2_pp(n, a.get_manager()) << "\n";); + TRACE("nla2bv", tout << "Not supported: " << mk_ismt2_pp(n, m) << "\n";); m_in_supported_fragment = false; } m_imp.update_num_bits(n); @@ -353,13 +362,17 @@ class nla2bv_tactic : public tactic { bool is_supported() const { return m_in_supported_fragment; } }; - bool collect_vars(goal const & g) { + enum collect_t { has_num, not_supported, is_bool }; + + collect_t collect_vars(goal const & g) { get_uninterp_proc fe_var(*this); for_each_expr_at(fe_var, g); for (unsigned i = 0; i < fe_var.vars().size(); ++i) { add_var(fe_var.vars()[i]); } - return fe_var.is_supported() && !fe_var.vars().empty(); + if (!fe_var.is_supported()) return not_supported; + if (!fe_var.vars().empty()) return is_bool; + return has_num; } class count_mul_proc { diff --git a/src/tactic/smtlogics/qfnia_tactic.cpp b/src/tactic/smtlogics/qfnia_tactic.cpp index d28034a1d..528a6c048 100644 --- a/src/tactic/smtlogics/qfnia_tactic.cpp +++ b/src/tactic/smtlogics/qfnia_tactic.cpp @@ -27,6 +27,7 @@ Notes: #include "sat/tactic/sat_tactic.h" #include "tactic/arith/nla2bv_tactic.h" #include "tactic/arith/lia2card_tactic.h" +#include "tactic/arith/card2bv_tactic.h" #include "tactic/core/ctx_simplify_tactic.h" #include "tactic/core/cofactor_term_ite_tactic.h" #include "nlsat/tactic/qfnra_nlsat_tactic.h" @@ -73,7 +74,8 @@ static tactic * mk_qfnia_premable(ast_manager & m, params_ref const & p_ref) { using_params(mk_ctx_simplify_tactic(m), ctx_simp_p), using_params(mk_simplify_tactic(m), pull_ite_p), mk_elim_uncnstr_tactic(m), - mk_lia2card_tactic(m), + mk_lia2card_tactic(m), + mk_card2bv_tactic(m, p_ref), skip_if_failed(using_params(mk_cofactor_term_ite_tactic(m), elim_p))); } @@ -105,7 +107,9 @@ static tactic * mk_qfnia_nlsat_solver(ast_manager & m, params_ref const & p) { static tactic * mk_qfnia_smt_solver(ast_manager& m, params_ref const& p) { params_ref simp_p = p; simp_p.set_bool("som", true); // expand into sums of monomials - return and_then(using_params(mk_simplify_tactic(m), simp_p), mk_smt_tactic(m)); + return and_then( + using_params(mk_simplify_tactic(m), simp_p), + mk_smt_tactic(m)); } tactic * mk_qfnia_tactic(ast_manager & m, params_ref const & p) { @@ -113,9 +117,11 @@ tactic * mk_qfnia_tactic(ast_manager & m, params_ref const & p) { return and_then( mk_report_verbose_tactic("(qfnia-tactic)", 10), mk_qfnia_premable(m, p), - or_else(mk_qfnia_sat_solver(m, p), - try_for(mk_qfnia_smt_solver(m, p), 2000), - mk_qfnia_nlsat_solver(m, p), - mk_qfnia_smt_solver(m, p)) + mk_qfnia_sat_solver(m, p) + +// or_else(mk_qfnia_sat_solver(m, p), +// try_for(mk_qfnia_smt_solver(m, p), 2000), +// mk_qfnia_nlsat_solver(m, p), +// mk_qfnia_smt_solver(m, p)) ); } From cc216f8cc3c05dcf267a913395be30f893e14f48 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Feb 2019 21:24:44 +0100 Subject: [PATCH 307/318] fix regressions breaking build Signed-off-by: Nikolaj Bjorner --- src/tactic/arith/nla2bv_tactic.cpp | 3 +-- src/tactic/smtlogics/qfnia_tactic.cpp | 9 ++++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/tactic/arith/nla2bv_tactic.cpp b/src/tactic/arith/nla2bv_tactic.cpp index 0a58740d1..c09fc695d 100644 --- a/src/tactic/arith/nla2bv_tactic.cpp +++ b/src/tactic/arith/nla2bv_tactic.cpp @@ -327,7 +327,6 @@ class nla2bv_tactic : public tactic { } void operator()(app* n) { if (a.is_int(n) && is_uninterp_const(n)) { - TRACE("nla2bv", tout << "Not supported: " << mk_ismt2_pp(n, m) << "\n";); m_vars.push_back(n); } else if (a.is_real(n) && is_uninterp_const(n)) { @@ -371,7 +370,7 @@ class nla2bv_tactic : public tactic { add_var(fe_var.vars()[i]); } if (!fe_var.is_supported()) return not_supported; - if (!fe_var.vars().empty()) return is_bool; + if (fe_var.vars().empty()) return is_bool; return has_num; } diff --git a/src/tactic/smtlogics/qfnia_tactic.cpp b/src/tactic/smtlogics/qfnia_tactic.cpp index 528a6c048..a9a6032f1 100644 --- a/src/tactic/smtlogics/qfnia_tactic.cpp +++ b/src/tactic/smtlogics/qfnia_tactic.cpp @@ -117,11 +117,10 @@ tactic * mk_qfnia_tactic(ast_manager & m, params_ref const & p) { return and_then( mk_report_verbose_tactic("(qfnia-tactic)", 10), mk_qfnia_premable(m, p), - mk_qfnia_sat_solver(m, p) -// or_else(mk_qfnia_sat_solver(m, p), -// try_for(mk_qfnia_smt_solver(m, p), 2000), -// mk_qfnia_nlsat_solver(m, p), -// mk_qfnia_smt_solver(m, p)) + or_else(mk_qfnia_sat_solver(m, p), + try_for(mk_qfnia_smt_solver(m, p), 2000), + mk_qfnia_nlsat_solver(m, p), + mk_qfnia_smt_solver(m, p)) ); } From 3548057bd11be58ebc35f65364cae30ef187de13 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 20 Feb 2019 14:00:05 +0100 Subject: [PATCH 308/318] fix detection of arithmetic operations Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 1 + src/sat/sat_solver.h | 3 ++- src/sat/sat_solver_core.h | 2 ++ src/sat/tactic/sat_tactic.cpp | 5 +++++ src/tactic/arith/nla2bv_tactic.cpp | 32 +++++++++++++++++------------- 5 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 2df184c88..3deb6fc17 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1157,6 +1157,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; } } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 53c3062a8..c000ccb79 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -328,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; @@ -384,7 +385,7 @@ namespace sat { model_converter const & get_model_converter() const { return 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); diff --git a/src/sat/sat_solver_core.h b/src/sat/sat_solver_core.h index 543a84fa7..b3c43ea6a 100644 --- a/src/sat/sat_solver_core.h +++ b/src/sat/sat_solver_core.h @@ -50,6 +50,8 @@ namespace sat { // 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) { diff --git a/src/sat/tactic/sat_tactic.cpp b/src/sat/tactic/sat_tactic.cpp index 1f6fe11ad..2739932e6 100644 --- a/src/sat/tactic/sat_tactic.cpp +++ b/src/sat/tactic/sat_tactic.cpp @@ -65,6 +65,7 @@ class sat_tactic : public tactic { TRACE("sat_dimacs", m_solver->display_dimacs(tout);); dep2assumptions(dep2asm, assumptions); lbool r = m_solver->check(assumptions.size(), assumptions.c_ptr()); + TRACE("sat", tout << "result of checking: " << r << " " << m_solver->get_reason_unknown() << "\n";); if (r == l_false) { expr_dependency * lcore = nullptr; if (produce_core) { @@ -198,6 +199,10 @@ public: proc.m_solver->collect_statistics(m_stats); throw tactic_exception(ex.msg()); } + catch (z3_exception& ex) { + TRACE("sat", tout << ex.msg() << "\n";); + throw; + } TRACE("sat_stats", m_stats.display_smt2(tout);); } diff --git a/src/tactic/arith/nla2bv_tactic.cpp b/src/tactic/arith/nla2bv_tactic.cpp index c09fc695d..6662aec33 100644 --- a/src/tactic/arith/nla2bv_tactic.cpp +++ b/src/tactic/arith/nla2bv_tactic.cpp @@ -318,10 +318,12 @@ class nla2bv_tactic : public tactic { ast_manager& m; pb_util pb; ptr_vector m_vars; + bool m_no_arith; bool m_in_supported_fragment; public: - get_uninterp_proc(imp& s): m_imp(s), a(s.m_arith), m(a.get_manager()), pb(m), m_in_supported_fragment(true) {} + get_uninterp_proc(imp& s): m_imp(s), a(s.m_arith), m(a.get_manager()), pb(m), m_no_arith(true), m_in_supported_fragment(true) {} ptr_vector const& vars() { return m_vars; } + bool no_arith() const { return m_no_arith; } void operator()(var * n) { m_in_supported_fragment = false; } @@ -338,18 +340,20 @@ class nla2bv_tactic : public tactic { else if (m.is_bool(n) && n->get_decl()->get_family_id() == pb.get_family_id()) { } - else if (!(a.is_mul(n) || - a.is_add(n) || - a.is_sub(n) || - a.is_le(n) || - a.is_lt(n) || - a.is_ge(n) || - a.is_gt(n) || - a.is_numeral(n) || - a.is_uminus(n) || - m_imp.m_bv2real.is_pos_le(n) || - m_imp.m_bv2real.is_pos_lt(n) || - n->get_family_id() == a.get_manager().get_basic_family_id())) { + else if (a.is_mul(n) || + a.is_add(n) || + a.is_sub(n) || + a.is_le(n) || + a.is_lt(n) || + a.is_ge(n) || + a.is_gt(n) || + a.is_numeral(n) || + a.is_uminus(n) || + m_imp.m_bv2real.is_pos_le(n) || + m_imp.m_bv2real.is_pos_lt(n)) { + m_no_arith = false; + } + else if (n->get_family_id() != m.get_basic_family_id()) { TRACE("nla2bv", tout << "Not supported: " << mk_ismt2_pp(n, m) << "\n";); m_in_supported_fragment = false; } @@ -370,7 +374,7 @@ class nla2bv_tactic : public tactic { add_var(fe_var.vars()[i]); } if (!fe_var.is_supported()) return not_supported; - if (fe_var.vars().empty()) return is_bool; + if (fe_var.vars().empty() && fe_var.no_arith()) return is_bool; return has_num; } From 598fc810b57462552f69f69110fbc0930d772d8d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 20 Feb 2019 15:34:47 +0100 Subject: [PATCH 309/318] adding FP Signed-off-by: Nikolaj Bjorner --- src/solver/smt_logics.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/solver/smt_logics.cpp b/src/solver/smt_logics.cpp index d0fd8f809..a8dcf2f90 100644 --- a/src/solver/smt_logics.cpp +++ b/src/solver/smt_logics.cpp @@ -80,6 +80,7 @@ bool smt_logics::logic_has_arith(symbol const & s) { s == "LRA" || s == "UFIDL" || s == "QF_FP" || + s == "FP" || s == "QF_FPBV" || s == "QF_BVFP" || s == "QF_S" || @@ -101,6 +102,7 @@ bool smt_logics::logic_has_bv(symbol const & s) { s == "QF_AUFBV" || s == "QF_BVRE" || s == "QF_FPBV" || + s == "FP" || s == "QF_BVFP" || logic_is_allcsp(s) || s == "QF_FD" || @@ -138,7 +140,7 @@ bool smt_logics::logic_has_str(symbol const & s) { } bool smt_logics::logic_has_fpa(symbol const & s) { - return s == "QF_FP" || s == "QF_FPBV" || s == "QF_BVFP" || s == "QF_FPLRA" || logic_is_allcsp(s); + return s == "FP" || s == "QF_FP" || s == "QF_FPBV" || s == "QF_BVFP" || s == "QF_FPLRA" || logic_is_allcsp(s); } bool smt_logics::logic_has_uf(symbol const & s) { From f3cd7d646d021a02d6d1dbc6a419ec22668b5158 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 21 Feb 2019 10:42:42 +0000 Subject: [PATCH 310/318] further simplifications to scoped_timer --- src/util/scoped_timer.cpp | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/src/util/scoped_timer.cpp b/src/util/scoped_timer.cpp index e3b96fa15..58416289a 100644 --- a/src/util/scoped_timer.cpp +++ b/src/util/scoped_timer.cpp @@ -26,39 +26,33 @@ Revision History: struct scoped_timer::imp { - event_handler * m_eh; +private: std::thread m_thread; std::timed_mutex m_mutex; - unsigned m_ms; - static void* thread_func(imp * st) { - auto end = std::chrono::steady_clock::now() + std::chrono::milliseconds(st->m_ms); + static void thread_func(unsigned ms, event_handler * eh, std::timed_mutex * mutex) { + auto end = std::chrono::steady_clock::now() + std::chrono::milliseconds(ms); - while (!st->m_mutex.try_lock_until(end)) { - if (std::chrono::steady_clock::now() > end) { - st->m_eh->operator()(TIMEOUT_EH_CALLER); - return nullptr; - } + while (!mutex->try_lock_until(end)) { + if (std::chrono::steady_clock::now() >= end) { + eh->operator()(TIMEOUT_EH_CALLER); + return; + } } - st->m_mutex.unlock(); - return nullptr; + mutex->unlock(); } - imp(unsigned ms, event_handler * eh): - m_eh(eh), m_ms(ms) { +public: + imp(unsigned ms, event_handler * eh) { m_mutex.lock(); - m_thread = std::thread(thread_func, this); + m_thread = std::thread(thread_func, ms, eh, &m_mutex); } ~imp() { m_mutex.unlock(); - while (!m_thread.joinable()) { - std::this_thread::yield(); - } m_thread.join(); } - }; scoped_timer::scoped_timer(unsigned ms, event_handler * eh) { @@ -69,6 +63,5 @@ scoped_timer::scoped_timer(unsigned ms, event_handler * eh) { } scoped_timer::~scoped_timer() { - if (m_imp) - dealloc(m_imp); + dealloc(m_imp); } From a76c0fbbfbb7e0e80c5d491da99fb6b56f408139 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 21 Feb 2019 11:49:41 +0000 Subject: [PATCH 311/318] simplify timeout mechanism and fix race conditions there --- src/shell/main.cpp | 7 +++++-- src/util/timeout.cpp | 26 ++++++++++---------------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/shell/main.cpp b/src/shell/main.cpp index b036628b1..260cf8a79 100644 --- a/src/shell/main.cpp +++ b/src/shell/main.cpp @@ -115,6 +115,7 @@ void display_usage() { } void parse_cmd_line_args(int argc, char ** argv) { + long timeout = 0; int i = 1; char * eq_pos = nullptr; while (i < argc) { @@ -216,8 +217,7 @@ void parse_cmd_line_args(int argc, char ** argv) { else if (strcmp(opt_name, "T") == 0) { if (!opt_arg) error("option argument (-T:timeout) is missing."); - long tm = strtol(opt_arg, nullptr, 10); - set_timeout(tm * 1000); + timeout = strtol(opt_arg, nullptr, 10); } else if (strcmp(opt_name, "t") == 0) { if (!opt_arg) @@ -292,6 +292,9 @@ void parse_cmd_line_args(int argc, char ** argv) { } i++; } + + if (timeout) + set_timeout(timeout * 1000); } diff --git a/src/util/timeout.cpp b/src/util/timeout.cpp index ad02a747d..1a92ae867 100644 --- a/src/util/timeout.cpp +++ b/src/util/timeout.cpp @@ -19,7 +19,6 @@ Revision History: --*/ #include -#include "util/z3_omp.h" #include "util/util.h" #include "util/timeout.h" #include "util/error_codes.h" @@ -34,26 +33,21 @@ namespace { class g_timeout_eh : public event_handler { public: void operator()(event_handler_caller_t caller_id) override { - #pragma omp critical (g_timeout_cs) - { - std::cout << "timeout\n"; - m_caller_id = caller_id; - if (g_on_timeout) - g_on_timeout(); - if (g_timeout) - delete g_timeout; - g_timeout = nullptr; - throw z3_error(ERR_TIMEOUT); - } + std::cout << "timeout\n"; + m_caller_id = caller_id; + if (g_on_timeout) + g_on_timeout(); + throw z3_error(ERR_TIMEOUT); } }; } -void set_timeout(long ms) { - if (g_timeout) - delete g_timeout; +static g_timeout_eh eh; - g_timeout = new scoped_timer(ms, new g_timeout_eh()); +void set_timeout(long ms) { + SASSERT(!g_timeout); + // this is leaked, but since it's only used in the shell, it's ok + g_timeout = new scoped_timer(ms, &eh); } void register_on_timeout_proc(void (*proc)()) { From 3a5263be9544a9801da9cf6b8397e5bf7819e77c Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 21 Feb 2019 13:30:27 +0000 Subject: [PATCH 312/318] modernize stopwatch --- src/util/stopwatch.h | 182 ++++++++----------------------------------- 1 file changed, 33 insertions(+), 149 deletions(-) diff --git a/src/util/stopwatch.h b/src/util/stopwatch.h index a11a87484..44d7a104b 100644 --- a/src/util/stopwatch.h +++ b/src/util/stopwatch.h @@ -20,171 +20,55 @@ Revision History: #ifndef STOPWATCH_H_ #define STOPWATCH_H_ -#if defined(_WINDOWS) || defined(_CYGWIN) || defined(_MINGW) - -// Does this redefinition work? - -#include +#include "util/debug.h" +#include class stopwatch { -private: - LARGE_INTEGER m_elapsed; - LARGE_INTEGER m_last_start_time; - LARGE_INTEGER m_last_stop_time; - LARGE_INTEGER m_frequency; + std::chrono::time_point m_start; + std::chrono::steady_clock::duration m_elapsed; +#if Z3DEBUG + bool m_running = false; +#endif + + static std::chrono::time_point get() { + return std::chrono::steady_clock::now(); + } public: stopwatch() { - QueryPerformanceFrequency(&m_frequency); - reset(); + reset(); } - ~stopwatch() {}; - - void add (const stopwatch &s) {/* TODO */} - - void reset() { m_elapsed.QuadPart = 0; } - - void start() { - QueryPerformanceCounter(&m_last_start_time); - } - - void stop() { - QueryPerformanceCounter(&m_last_stop_time); - m_elapsed.QuadPart += m_last_stop_time.QuadPart - m_last_start_time.QuadPart; + void add(const stopwatch &s) { + m_elapsed += s.m_elapsed; } - double get_seconds() const { - return static_cast(m_elapsed.QuadPart / static_cast(m_frequency.QuadPart)) ; + void reset() { + m_elapsed = std::chrono::steady_clock::duration::zero(); + } + + void start() { + SASSERT(!m_running); + DEBUG_CODE(m_running = true); + m_start = get(); + } + + void stop() { + SASSERT(m_running); + DEBUG_CODE(m_running = false); + m_elapsed += get() - m_start; + } + + double get_seconds() const { + return std::chrono::duration_cast(m_elapsed).count() / 1000.0; } double get_current_seconds() const { - LARGE_INTEGER t; - QueryPerformanceCounter(&t); - return static_cast( (t.QuadPart - m_last_start_time.QuadPart) / static_cast(m_frequency.QuadPart)); + return std::chrono::duration_cast(get() - m_start).count() / 1000.0; } }; -#undef max -#undef min - - -#elif defined(__APPLE__) && defined (__MACH__) // macOS - -#include -#include - -class stopwatch { - unsigned long long m_time; // elapsed time in ns - bool m_running; - clock_serv_t m_host_clock; - mach_timespec_t m_start; - -public: - stopwatch():m_time(0), m_running(false) { - host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &m_host_clock); - } - - ~stopwatch() {} - - void add (const stopwatch &s) {m_time += s.m_time;} - - void reset() { - m_time = 0ull; - } - - void start() { - if (!m_running) { - clock_get_time(m_host_clock, &m_start); - m_running = true; - } - } - - void stop() { - if (m_running) { - mach_timespec_t _stop; - clock_get_time(m_host_clock, &_stop); - m_time += (_stop.tv_sec - m_start.tv_sec) * 1000000000ull; - m_time += (_stop.tv_nsec - m_start.tv_nsec); - m_running = false; - } - } - - double get_seconds() const { - if (m_running) { - const_cast(this)->stop(); - /* update m_time */ - const_cast(this)->start(); - } - return static_cast(m_time)/static_cast(1000000000ull); - } - - double get_current_seconds() const { - return get_seconds(); - } -}; - - -#else // Linux - -#include - -#ifndef CLOCK_PROCESS_CPUTIME_ID -/* BSD */ -# define CLOCK_PROCESS_CPUTIME_ID CLOCK_MONOTONIC -#endif - -class stopwatch { - unsigned long long m_time; // elapsed time in ns - bool m_running; - struct timespec m_start; - -public: - stopwatch():m_time(0), m_running(false) { - } - - ~stopwatch() {} - - void add (const stopwatch &s) {m_time += s.m_time;} - - void reset() { - m_time = 0ull; - } - - void start() { - if (!m_running) { - clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &m_start); - m_running = true; - } - } - - void stop() { - if (m_running) { - struct timespec _stop; - clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &_stop); - m_time += (_stop.tv_sec - m_start.tv_sec) * 1000000000ull; - if (m_time != 0 || _stop.tv_nsec >= m_start.tv_nsec) - m_time += (_stop.tv_nsec - m_start.tv_nsec); - m_running = false; - } - } - - double get_seconds() const { - if (m_running) { - const_cast(this)->stop(); - /* update m_time */ - const_cast(this)->start(); - } - return static_cast(m_time)/static_cast(1000000000ull); - } - - double get_current_seconds() const { - return get_seconds(); - } -}; - -#endif struct scoped_watch { stopwatch &m_sw; From 3a7c467822f6792a57fb9b97a707efec1683bbfa Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 21 Feb 2019 13:33:52 +0000 Subject: [PATCH 313/318] fix debug build.. --- src/util/stopwatch.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/stopwatch.h b/src/util/stopwatch.h index 44d7a104b..e35380153 100644 --- a/src/util/stopwatch.h +++ b/src/util/stopwatch.h @@ -50,13 +50,13 @@ public: void start() { SASSERT(!m_running); - DEBUG_CODE(m_running = true); + DEBUG_CODE(m_running = true;); m_start = get(); } void stop() { SASSERT(m_running); - DEBUG_CODE(m_running = false); + DEBUG_CODE(m_running = false;); m_elapsed += get() - m_start; } From 85162d90d1c68838f150704c672e82a457922e54 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 21 Feb 2019 13:57:38 +0000 Subject: [PATCH 314/318] simplify timer.h --- src/util/timer.cpp | 40 ---------------------------------------- src/util/timer.h | 28 ++++++++++++++++++---------- 2 files changed, 18 insertions(+), 50 deletions(-) delete mode 100644 src/util/timer.cpp diff --git a/src/util/timer.cpp b/src/util/timer.cpp deleted file mode 100644 index 2d80b732c..000000000 --- a/src/util/timer.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - timer.cpp - -Abstract: - - - -Author: - - Leonardo de Moura (leonardo) 2009-01-06. - -Revision History: - ---*/ -#include "util/util.h" -#include "util/memory_manager.h" -#include "util/stopwatch.h" -#include "util/timer.h" - -timer::timer(){ - m_watch = alloc(stopwatch); - start(); -} - -timer::~timer() { - dealloc(m_watch); -} - -void timer::start() { - m_watch->start(); -} - -double timer::get_seconds() { - return m_watch->get_current_seconds(); -} - diff --git a/src/util/timer.h b/src/util/timer.h index b4a69f8bf..37566e613 100644 --- a/src/util/timer.h +++ b/src/util/timer.h @@ -19,21 +19,29 @@ Revision History: #ifndef TIMER_H_ #define TIMER_H_ -class stopwatch; +#include "util/stopwatch.h" /** - \brief Wrapper for the stopwatch class. It hides windows.h dependency. + \brief Wrapper for the stopwatch class. */ class timer { - stopwatch * m_watch; + stopwatch m_watch; public: - timer(); - ~timer(); - void start(); - double get_seconds(); - bool timeout(unsigned secs) { return secs > 0 && secs != UINT_MAX && get_seconds() > secs; } - bool ms_timeout(unsigned ms) { return ms > 0 && ms != UINT_MAX && get_seconds() * 1000 > ms; } + void start() { + m_watch.start(); + } + + double get_seconds() const { + return m_watch.get_current_seconds(); + } + + bool timeout(unsigned secs) const { + return secs != 0 && secs != UINT_MAX && get_seconds() > secs; + } + + bool ms_timeout(unsigned ms) const { + return ms != 0 && ms != UINT_MAX && get_seconds() * 1000 > ms; + } }; #endif /* TIMER_H_ */ - From 2f33bafd5a7696a57a04555bc6521063f069ef59 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 21 Feb 2019 14:59:31 +0000 Subject: [PATCH 315/318] stopwatches: fix a few places that would call start/stop multiple times --- src/muz/rel/dl_instruction.cpp | 11 +++++------ src/sat/sat_local_search.cpp | 1 - src/smt/smt_context.cpp | 1 - src/util/timer.h | 2 +- 4 files changed, 6 insertions(+), 9 deletions(-) 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/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 7c3ebb688..cdb90e2a0 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -515,7 +515,6 @@ namespace sat { reinit(); DEBUG_CODE(verify_slack();); timer timer; - timer.start(); unsigned step = 0, total_flips = 0, tries = 0; for (tries = 1; !m_unsat_stack.empty() && m_limit.inc(); ++tries) { diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 86b3374fc..ecb69b418 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3496,7 +3496,6 @@ namespace smt { m_case_split_queue ->init_search_eh(); m_next_progress_sample = 0; TRACE("literal_occ", display_literal_num_occs(tout);); - m_timer.start(); } void context::end_search() { diff --git a/src/util/timer.h b/src/util/timer.h index 37566e613..e2ddb55e7 100644 --- a/src/util/timer.h +++ b/src/util/timer.h @@ -27,7 +27,7 @@ Revision History: class timer { stopwatch m_watch; public: - void start() { + timer() { m_watch.start(); } From 3d7878bafc228877c77891a8985e78c21f780664 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 21 Feb 2019 15:25:26 +0000 Subject: [PATCH 316/318] hopefully fix build with VS 2012 --- src/util/stopwatch.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/util/stopwatch.h b/src/util/stopwatch.h index e35380153..e8665054b 100644 --- a/src/util/stopwatch.h +++ b/src/util/stopwatch.h @@ -31,7 +31,8 @@ class stopwatch bool m_running = false; #endif - static std::chrono::time_point get() { + // FIXME: just use auto with VS 2015+ + static decltype(std::chrono::steady_clock::now()) get() { return std::chrono::steady_clock::now(); } From 6598aedbb206986a9e48e5c1fe3b7ce807f97895 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 21 Feb 2019 15:52:52 +0000 Subject: [PATCH 317/318] fix VS build, take 2 --- src/sat/sat_solver.cpp | 3 +++ src/util/CMakeLists.txt | 1 - src/util/stopwatch.h | 11 +++++++---- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 3deb6fc17..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 diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index b6abb785f..5b1f336d1 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -56,7 +56,6 @@ z3_add_component(util symbol.cpp timeit.cpp timeout.cpp - timer.cpp trace.cpp util.cpp warning.cpp diff --git a/src/util/stopwatch.h b/src/util/stopwatch.h index e8665054b..5fe10fb3b 100644 --- a/src/util/stopwatch.h +++ b/src/util/stopwatch.h @@ -25,14 +25,17 @@ Revision History: class stopwatch { - std::chrono::time_point m_start; - std::chrono::steady_clock::duration m_elapsed; + typedef decltype(std::chrono::steady_clock::now()) clock_t; + typedef decltype(std::chrono::steady_clock::now() - std::chrono::steady_clock::now()) duration_t; + + clock_t m_start; + duration_t m_elapsed; #if Z3DEBUG bool m_running = false; #endif // FIXME: just use auto with VS 2015+ - static decltype(std::chrono::steady_clock::now()) get() { + static clock_t get() { return std::chrono::steady_clock::now(); } @@ -46,7 +49,7 @@ public: } void reset() { - m_elapsed = std::chrono::steady_clock::duration::zero(); + m_elapsed = duration_t::zero(); } void start() { From bb7aa16223965644a65e7f5f4eaf050fb5ef8058 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 21 Feb 2019 16:38:48 +0000 Subject: [PATCH 318/318] stopwatch: fix debug build crash in sat solver --- src/util/stopwatch.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/stopwatch.h b/src/util/stopwatch.h index 5fe10fb3b..1135c893e 100644 --- a/src/util/stopwatch.h +++ b/src/util/stopwatch.h @@ -50,6 +50,7 @@ public: void reset() { m_elapsed = duration_t::zero(); + DEBUG_CODE(m_running = false;); } void start() {