diff options
319 files changed, 4237 insertions, 17578 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 82916f26b..fedcb9bb4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ jobs: include: - name: ubuntu:production os: ubuntu-latest - config: production --auto-download --all-bindings --editline --docs --static-binary + config: production --auto-download --all-bindings --editline --docs --static cache-key: production python-bindings: true build-documentation: true @@ -19,7 +19,7 @@ jobs: - name: macos:production os: macos-11 - config: production --auto-download --all-bindings --editline --static-binary + config: production --auto-download --all-bindings --editline --static cache-key: production python-bindings: true check-examples: true @@ -38,7 +38,7 @@ jobs: - name: ubuntu:production-dbg os: ubuntu-18.04 - config: production --auto-download --assertions --tracing --unit-testing --editline + config: production --auto-download --assertions --tracing --unit-testing --java-bindings --editline cache-key: dbg check-units: true exclude_regress: 3-4 diff --git a/.github/workflows/docs_upload.yml b/.github/workflows/docs_upload.yml index 9aadd6647..fd489beee 100644 --- a/.github/workflows/docs_upload.yml +++ b/.github/workflows/docs_upload.yml @@ -78,7 +78,7 @@ jobs: SSH_AUTH_SOCK: /tmp/ssh_agent.sock run: | if [ -n "$NAME" ]; then - mv docs-new target/docs-$NAME-$HASH + cp -r docs-new target/docs-$NAME-$HASH cd target/ isdiff=$(diff -r -x "*.zip" docs-master/ docs-$NAME-$HASH >&2; echo $?; exit 0) @@ -106,12 +106,12 @@ jobs: env: SSH_AUTH_SOCK: /tmp/ssh_agent.sock run: | - if [ "$ISTAG" ]; then + if [ "$ISTAG" = true ]; then git clone git@github.com:cvc5/docs-releases.git target-releases/ - mv docs-new target-releases/$NAME + cp -r docs-new target-releases/$NAME cd target-releases/ - git add docs-$NAME + git add $NAME git commit -m "Update docs for $NAME" git push diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f6fa434e..ef3b7636e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,9 +48,6 @@ endif() #-----------------------------------------------------------------------------# # Tell CMake where to find our dependencies -if(ABC_DIR) - list(APPEND CMAKE_PREFIX_PATH "${ABC_DIR}") -endif() if(GLPK_DIR) list(APPEND CMAKE_PREFIX_PATH "${GLPK_DIR}") endif() @@ -86,9 +83,7 @@ cvc5_option(ENABLE_STATISTICS "Enable statistics") cvc5_option(ENABLE_TRACING "Enable tracing") cvc5_option(ENABLE_UNIT_TESTING "Enable unit testing") cvc5_option(ENABLE_VALGRIND "Enable valgrind instrumentation") -cvc5_option(ENABLE_STATIC_LIBRARY "Enable building static library") -cvc5_option(ENABLE_STATIC_BINARY - "Build static binaries with statically linked system libraries") +cvc5_option(ENABLE_STATIC_BUILD "Enable building static libraries and binary") cvc5_option(ENABLE_AUTO_DOWNLOAD "Enable automatic download of dependencies") cvc5_option(ENABLE_IPO "Enable interprocedural optimization") # >> 2-valued: ON OFF @@ -103,7 +98,6 @@ option(ENABLE_PROFILING "Enable support for gprof profiling") # >> 3-valued: IGNORE ON OFF # > allows to detect if set by user (default: IGNORE) # > only necessary for options set for ENABLE_BEST -cvc5_option(USE_ABC "Use ABC for AIG bit-blasting") cvc5_option(USE_CLN "Use CLN instead of GMP") cvc5_option(USE_CRYPTOMINISAT "Use CryptoMiniSat SAT solver") cvc5_option(USE_GLPK "Use GLPK simplex solver") @@ -120,7 +114,6 @@ option(USE_PYTHON2 "Force Python 2 (deprecated)") # installed via the corresponding contrib/get-* script and if not found, we # check the intalled system version. If the user provides a directory we # immediately fail if the dependency was not found at the specified location. -set(ABC_DIR "" CACHE STRING "Set ABC install directory") set(GLPK_DIR "" CACHE STRING "Set GLPK install directory") # Prepend binaries with prefix on make install @@ -184,7 +177,7 @@ include(Config${CMAKE_BUILD_TYPE}) add_check_c_cxx_flag("-O${OPTIMIZATION_LEVEL}") add_check_c_cxx_flag("-Wall") -add_check_c_cxx_flag("-Wno-unused-private-field") +add_check_c_cxx_supression_flag("-Wno-unused-private-field") add_check_c_flag("-fexceptions") add_check_cxx_flag("-Wsuggest-override") add_check_cxx_flag("-Wnon-virtual-dtor") @@ -198,7 +191,7 @@ add_check_cxx_flag("-fno-extern-tls-init") # Temporarily disable -Wclass-memaccess to suppress 'no trivial copy-assignment' # cdlist.h warnings. Remove when fixed. -add_check_cxx_flag("-Wno-class-memaccess") +add_check_cxx_supression_flag("-Wno-class-memaccess") if (WIN32) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--stack,100000000") @@ -224,18 +217,6 @@ if(ENABLE_IPO) set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) endif() - -#-----------------------------------------------------------------------------# -# Option defaults (three-valued options (cvc5_option(...))) -# -# These options are only set if their value is IGNORE. Otherwise, the user -# already set the option, which we don't want to overwrite. - -if(ENABLE_STATIC_BINARY) - message(STATUS "Enable static library for static binary build.") - cvc5_set_option(ENABLE_STATIC_LIBRARY ON) -endif() - #-----------------------------------------------------------------------------# # Only enable unit testing if assertions are enabled. Otherwise, unit tests @@ -384,11 +365,6 @@ if(ENABLE_VALGRIND) add_definitions(-DCVC5_VALGRIND) endif() -if(USE_ABC) - find_package(ABC REQUIRED) - add_definitions(-DCVC5_USE_ABC ${ABC_ARCH_FLAGS}) -endif() - find_package(CaDiCaL REQUIRED) if(USE_CLN) @@ -459,11 +435,12 @@ endif() # Provide targets to inspect iwyu suggestions include(IWYU) +include(fuzzing-murxla) #-----------------------------------------------------------------------------# include(ConfigureCvc5) -if(ENABLE_STATIC_BINARY) +if(ENABLE_STATIC_BUILD) set(CVC5_STATIC_BUILD ON) endif() @@ -504,7 +481,7 @@ include(CMakePackageConfigHelpers) # (in the assumption that only reasonably experienced users use this and # also that custom installation prefixes are not used for longer periods of # time anyway). Also, we print a big warning with further instructions. -if(NOT ENABLE_STATIC_BINARY) +if(NOT ENABLE_STATIC_BUILD) # Get the libraries that cvc5 links against get_target_property(libs cvc5-shared INTERFACE_LINK_LIBRARIES) set(LIBS_SHARED_FROM_DEPS "") @@ -615,14 +592,12 @@ print_config("Profiling (gprof) " ${ENABLE_PROFILING}) print_config("Unit tests " ${ENABLE_UNIT_TESTING}) print_config("Valgrind " ${ENABLE_VALGRIND}) message("") -print_config("Static library " ${ENABLE_STATIC_LIBRARY}) -print_config("Static binary " ${ENABLE_STATIC_BINARY}) +print_config("Static build " ${ENABLE_STATIC_BUILD}) print_config("Python bindings " ${BUILD_BINDINGS_PYTHON}) print_config("Java bindings " ${BUILD_BINDINGS_JAVA}) print_config("Python2 " ${USE_PYTHON2}) print_config("Interprocedural opt. " ${ENABLE_IPO}) message("") -print_config("ABC " ${USE_ABC}) print_config("CryptoMiniSat " ${USE_CRYPTOMINISAT} FOUND_SYSTEM ${CryptoMiniSat_FOUND_SYSTEM}) print_config("GLPK " ${USE_GLPK}) print_config("Kissat " ${USE_KISSAT} FOUND_SYSTEM ${Kissat_FOUND_SYSTEM}) @@ -638,9 +613,6 @@ print_config("Editline " ${USE_EDITLINE}) message("") print_config("Api docs " ${BUILD_DOCS}) message("") -if(ABC_DIR) - print_config("ABC dir " ${ABC_DIR}) -endif() if(GLPK_DIR) print_config("GLPK dir " ${GLPK_DIR}) endif() diff --git a/INSTALL.rst b/INSTALL.rst index 7df21cb4c..106948969 100644 --- a/INSTALL.rst +++ b/INSTALL.rst @@ -33,7 +33,7 @@ dependencies. We also have a Homebrew Tap available at https://github.com/CVC4/homebrew-cvc4 . Note that linking system libraries statically is `strongly discouraged <https://developer.apple.com/library/archive/qa/qa1118/_index.html>`_ -on macOS. Using ``./configure.sh --static-binary`` will thus produce a binary +on macOS. Using ``./configure.sh --static`` will thus produce a binary that uses static versions of all our dependencies, but is still a dynamically linked binary. @@ -45,7 +45,7 @@ Cross-compiling cvc5 with Mingw-w64 can be done as follows: .. code:: bash - ./configure.sh --win64 --static-binary <configure options...> + ./configure.sh --win64 --static <configure options...> cd <build_dir> # default is ./build make # use -jN for parallel build with N threads @@ -174,19 +174,6 @@ cvc5 with GLPK support, you are licensing cvc5 under that same license. (Usually cvc5's license is more permissive; see above discussion.) -ABC library (Improved Bit-Vector Support) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -`ABC <http://www.eecs.berkeley.edu/~alanmi/abc/>`_ (A System for Sequential -Synthesis and Verification) is a library for synthesis and verification of logic -circuits. This dependency may improve performance of the eager bit-vector -solver. When enabled, the bit-blasted formula is encoded into -and-inverter-graphs (AIG) and ABC is used to simplify these AIGs. - -ABC can be installed using the ``contrib/get-abc`` script. Configure cvc5 with -``configure.sh --abc`` to build with this dependency. - - Editline library (Improved Interactive Experience) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -431,6 +418,6 @@ linked LGPL libraries perform the following steps: .. code:: - ./configure.sh --static-binary <options> + ./configure.sh --static <options> 7. Follow remaining steps from `build instructions <#building-cvc5>`_ @@ -31,7 +31,8 @@ Improvements: Changes: * SyGuS: Removed support for SyGuS-IF 1.0. -* Removed Java and Python bindings for the legacy API +* Removed support for the (non-standard) `define` command. +* Removed Java and Python bindings for the legacy API. * Interactive shell: the GPL-licensed Readline library has been replaced the BSD-licensed Editline. Compiling with `--best` now enables Editline, instead of Readline. Without selecting optional GPL components, Editline-enabled CVC4 diff --git a/cmake/ConfigCompetition.cmake b/cmake/ConfigCompetition.cmake index 2b17d8073..e479c15d0 100644 --- a/cmake/ConfigCompetition.cmake +++ b/cmake/ConfigCompetition.cmake @@ -32,7 +32,7 @@ cvc5_set_option(ENABLE_DUMPING OFF) # enable_muzzle=yes cvc5_set_option(ENABLE_MUZZLE ON) # enable_valgrind=no -cvc5_set_option(ENABLE_STATIC_BINARY ON) +cvc5_set_option(ENABLE_STATIC_BUILD ON) cvc5_set_option(ENABLE_UNIT_TESTING OFF) # By default, we include all dependencies in our competition build that are diff --git a/cmake/FindABC.cmake b/cmake/FindABC.cmake deleted file mode 100644 index 4e3b7a397..000000000 --- a/cmake/FindABC.cmake +++ /dev/null @@ -1,40 +0,0 @@ -############################################################################### -# Top contributors (to current version): -# Mathias Preiner -# -# This file is part of the cvc5 project. -# -# Copyright (c) 2009-2021 by the authors listed in the file AUTHORS -# in the top-level source directory and their institutional affiliations. -# All rights reserved. See the file COPYING in the top-level source -# directory for licensing information. -# ############################################################################# -# -# Find ABC -# ABC_FOUND - system has ABC lib -# ABC_INCLUDE_DIR - the ABC include directory -# ABC_LIBRARIES - Libraries needed to use ABC -# ABC_ARCH_FLAGS - Platform specific compile flags -## - -# Note: contrib/get-abc copies header files to deps/install/include/abc. -# However, includes in ABC headers are not prefixed with "abc/" and therefore -# we have to look for headers in include/abc instead of include/. -find_path(ABC_INCLUDE_DIR NAMES base/abc/abc.h PATH_SUFFIXES abc) -find_library(ABC_LIBRARIES NAMES abc) -find_program(ABC_ARCH_FLAGS_PROG NAMES arch_flags) - -if(ABC_ARCH_FLAGS_PROG) - execute_process(COMMAND ${ABC_ARCH_FLAGS_PROG} - OUTPUT_VARIABLE ABC_ARCH_FLAGS) -endif() - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(ABC - DEFAULT_MSG - ABC_INCLUDE_DIR ABC_LIBRARIES ABC_ARCH_FLAGS) - -mark_as_advanced(ABC_INCLUDE_DIR ABC_LIBRARIES ABC_ARCH_FLAGS) -if(ABC_LIBRARIES) - message(STATUS "Found ABC libs: ${ABC_LIBRARIES}") -endif() diff --git a/cmake/FindANTLR3.cmake b/cmake/FindANTLR3.cmake index e389e15f0..bc4afda23 100644 --- a/cmake/FindANTLR3.cmake +++ b/cmake/FindANTLR3.cmake @@ -33,7 +33,7 @@ if(ANTLR3_JAR AND ANTLR3_INCLUDE_DIR AND ANTLR3_LIBRARIES) check_system_version("ANTLR3") endif() -if(ENABLE_STATIC_LIBRARY AND ANTLR3_FOUND_SYSTEM) +if(ENABLE_STATIC_BUILD AND ANTLR3_FOUND_SYSTEM) force_static_library() find_library(ANTLR3_STATIC_LIBRARIES NAMES antlr3c) if(NOT ANTLR3_STATIC_LIBRARIES) diff --git a/cmake/FindCLN.cmake b/cmake/FindCLN.cmake index 11bf8ed98..3f83b61e2 100644 --- a/cmake/FindCLN.cmake +++ b/cmake/FindCLN.cmake @@ -33,7 +33,7 @@ if(CLN_INCLUDE_DIR AND CLN_LIBRARIES) check_system_version("CLN") endif() -if(ENABLE_STATIC_LIBRARY AND CLN_FOUND_SYSTEM) +if(ENABLE_STATIC_BUILD AND CLN_FOUND_SYSTEM) force_static_library() find_library(CLN_STATIC_LIBRARIES NAMES cln) if(NOT CLN_STATIC_LIBRARIES) @@ -94,7 +94,7 @@ set_target_properties(CLN_SHARED PROPERTIES target_link_libraries(CLN_SHARED INTERFACE GMP_SHARED) -if(ENABLE_STATIC_LIBRARY) +if(ENABLE_STATIC_BUILD) add_library(CLN_STATIC STATIC IMPORTED GLOBAL) set_target_properties(CLN_STATIC PROPERTIES IMPORTED_LOCATION "${CLN_STATIC_LIBRARIES}" diff --git a/cmake/FindGMP.cmake b/cmake/FindGMP.cmake index 5a849153b..bea0e1bf1 100644 --- a/cmake/FindGMP.cmake +++ b/cmake/FindGMP.cmake @@ -42,7 +42,7 @@ if(GMP_INCLUDE_DIR AND GMP_LIBRARIES) check_system_version("GMP") endif() -if(ENABLE_STATIC_LIBRARY AND GMP_FOUND_SYSTEM) +if(ENABLE_STATIC_BUILD AND GMP_FOUND_SYSTEM) force_static_library() find_library(GMP_STATIC_LIBRARIES NAMES gmp) if(NOT GMP_STATIC_LIBRARIES) @@ -132,7 +132,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows") set_target_properties(GMP_SHARED PROPERTIES IMPORTED_IMPLIB "${GMP_LIBRARIES}") endif() -if(ENABLE_STATIC_LIBRARY) +if(ENABLE_STATIC_BUILD) add_library(GMP_STATIC STATIC IMPORTED GLOBAL) set_target_properties(GMP_STATIC PROPERTIES IMPORTED_LOCATION "${GMP_STATIC_LIBRARIES}" @@ -150,7 +150,7 @@ if(GMP_FOUND_SYSTEM) else() message(STATUS "Building GMP ${GMP_VERSION}: ${GMP_LIBRARIES}") add_dependencies(GMP_SHARED GMP-EP) - if(ENABLE_STATIC_LIBRARY) + if(ENABLE_STATIC_BUILD) add_dependencies(GMP_STATIC GMP-EP) endif() endif() diff --git a/cmake/FindPoly.cmake b/cmake/FindPoly.cmake index f363147cc..e19e1c57d 100644 --- a/cmake/FindPoly.cmake +++ b/cmake/FindPoly.cmake @@ -37,7 +37,7 @@ if(Poly_INCLUDE_DIR check_system_version("Poly") endif() -if(ENABLE_STATIC_LIBRARY AND Poly_FOUND_SYSTEM) +if(ENABLE_STATIC_BUILD AND Poly_FOUND_SYSTEM) force_static_library() find_library(Poly_STATIC_LIBRARIES NAMES poly) find_library(PolyXX_STATIC_LIBRARIES NAMES polyxx) @@ -158,7 +158,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows") set_target_properties(Polyxx_SHARED PROPERTIES IMPORTED_IMPLIB "${PolyXX_LIBRARIES}") endif() -if(ENABLE_STATIC_LIBRARY) +if(ENABLE_STATIC_BUILD) add_library(Poly_STATIC STATIC IMPORTED GLOBAL) set_target_properties(Poly_STATIC PROPERTIES IMPORTED_LOCATION "${Poly_STATIC_LIBRARIES}" @@ -194,7 +194,7 @@ else() DESTINATION ${CMAKE_INSTALL_LIBDIR} ) - if(ENABLE_STATIC_LIBRARY) + if(ENABLE_STATIC_BUILD) add_dependencies(Poly_STATIC Poly-EP) add_dependencies(Polyxx_STATIC Poly-EP) endif() diff --git a/cmake/Helpers.cmake b/cmake/Helpers.cmake index 283828e29..465967f21 100644 --- a/cmake/Helpers.cmake +++ b/cmake/Helpers.cmake @@ -49,8 +49,8 @@ endmacro() # Check if C flag is supported and add to global list of C flags. macro(add_check_c_flag flag) string(REGEX REPLACE "[-=]" "_" flagname ${flag}) - check_c_compiler_flag("${flag}" HAVE_FLAG${flagname}) - if(HAVE_FLAG${flagname}) + check_c_compiler_flag("${flag}" HAVE_C_FLAG${flagname}) + if(HAVE_C_FLAG${flagname}) add_c_flag(${flag}) endif() endmacro() @@ -58,8 +58,8 @@ endmacro() # Check if CXX flag is supported and add to global list of CXX flags. macro(add_check_cxx_flag flag) string(REGEX REPLACE "[-=]" "_" flagname ${flag}) - check_cxx_compiler_flag("${flag}" HAVE_FLAG${flagname}) - if(HAVE_FLAG${flagname}) + check_cxx_compiler_flag("${flag}" HAVE_CXX_FLAG${flagname}) + if(HAVE_CXX_FLAG${flagname}) add_cxx_flag(${flag}) endif() endmacro() @@ -70,12 +70,47 @@ macro(add_check_c_cxx_flag flag) add_check_cxx_flag(${flag}) endmacro() +# Check if C warning suppression flag is supported and add to global list of C +# flags. +macro(add_check_c_supression_flag supression_flag) + # Obtain the non-supression warning flag name + string(REGEX REPLACE "^-Wno-" "-W" warning_flag ${supression_flag}) + string(REGEX REPLACE "[-=]" "_" warning_flagname ${warning_flag}) + # Check if we have the warning flag + check_c_compiler_flag("${warning_flag}" HAVE_C_FLAG${warning_flagname}) + # Only add the supression flag if we have the warning flag + if(HAVE_C_FLAG${warning_flagname}) + add_c_flag(${supression_flag}) + endif() +endmacro() + +# Check if CXX warning suppression flag is supported and add to global list of +# CXX flags. +macro(add_check_cxx_supression_flag supression_flag) + # Obtain the non-supression warning flag name + string(REGEX REPLACE "^-Wno-" "-W" warning_flag ${supression_flag}) + string(REGEX REPLACE "[-=]" "_" warning_flagname ${warning_flag}) + # Check if we have the warning flag + check_cxx_compiler_flag("${warning_flag}" HAVE_CXX_FLAG${warning_flagname}) + # Only add the supression flag if we have the warning flag + if(HAVE_CXX_FLAG${warning_flagname}) + add_cxx_flag(${supression_flag}) + endif() +endmacro() + +# Check if C/CXX warning supression flag is supported and add to global list of +# C/CXX flags. +macro(add_check_c_cxx_supression_flag supression_flag) + add_check_c_supression_flag(${supression_flag}) + add_check_cxx_supression_flag(${supression_flag}) +endmacro() + # Add required CXX flag. Configuration fails if the CXX flag is not supported # by the compiler. macro(add_required_cxx_flag flag) string(REGEX REPLACE "[-=]" "_" flagnamename ${flag}) - check_cxx_compiler_flag("${flag}" HAVE_FLAG${flagname}) - if (NOT HAVE_FLAG${flagname}) + check_cxx_compiler_flag("${flag}" HAVE_C_FLAG${flagname}) + if (NOT HAVE_C_FLAG${flagname}) message(FATAL_ERROR "Required compiler flag ${flag} not supported") endif() add_cxx_flag(${flag}) @@ -85,8 +120,8 @@ endmacro() # the compiler. macro(add_required_c_flag flag) string(REGEX REPLACE "[-=]" "_" flagname ${flag}) - check_c_compiler_flag("${flag}" HAVE_FLAG${flagname}) - if (NOT HAVE_FLAG${flagname}) + check_c_compiler_flag("${flag}" HAVE_CXX_FLAG${flagname}) + if (NOT HAVE_CXX_FLAG${flagname}) message(FATAL_ERROR "Required compiler flag ${flag} not supported") endif() add_c_flag(${flag}) diff --git a/cmake/fuzzing-murxla.cmake b/cmake/fuzzing-murxla.cmake new file mode 100644 index 000000000..b5699e925 --- /dev/null +++ b/cmake/fuzzing-murxla.cmake @@ -0,0 +1,59 @@ +############################################################################### +# Top contributors (to current version): +# Gereon Kremer +# +# This file is part of the cvc5 project. +# +# Copyright (c) 2009-2021 by the authors listed in the file AUTHORS +# in the top-level source directory and their institutional affiliations. +# All rights reserved. See the file COPYING in the top-level source +# directory for licensing information. +# ############################################################################# +# +# Find Murxla +# Murxla_FOUND - system has Murxla +## + +if(NOT IS_DIRECTORY "${CMAKE_BINARY_DIR}/murxla") + # this is only necessary while the murxla repository is private + add_custom_target(fuzz-murxla + COMMAND echo "To enable make fuzz-murxla run" + COMMAND echo "git clone git@github.com:murxla/murxla.git ${CMAKE_BINARY_DIR}/murxla" + ) + return() +endif() + +include(ExternalProject) + +set(Murxla_COMMIT "afc5744766d6aa61ad5b7ea27007666ac7a5aec2") + +add_custom_target(install-for-murxla + COMMAND ${CMAKE_MAKE_PROGRAM} install DESTDIR=murxla-install + DEPENDS cvc5-bin +) + +ExternalProject_Add( + Murxla-EP + EXCLUDE_FROM_ALL ON + ${COMMON_EP_CONFIG} + #URL https://github.com/murxla/murxla/archive/${Murxla_COMMIT}.tar.gz + #URL_HASH SHA1=da39a3ee5e6b4b0d3255bfef95601890afd80709 + SOURCE_DIR ${CMAKE_BINARY_DIR}/murxla + CMAKE_ARGS + -DCMAKE_PREFIX_PATH=${CMAKE_BINARY_DIR}/murxla-install/usr/local/ + -DENABLE_BITWUZLA=OFF + -DENABLE_BOOLECTOR=OFF + -DENABLE_YICES=OFF + INSTALL_COMMAND + ${CMAKE_COMMAND} -E copy <BINARY_DIR>/bin/murxla <INSTALL_DIR>/bin/murxla + DEPENDS install-for-murxla +) +ExternalProject_Get_Property(Murxla-EP BINARY_DIR) +set(MURXLA_BINARY "deps/bin/murxla") + +add_custom_target(fuzz-murxla + COMMAND echo "" + COMMAND echo "Run Murxla as follows:" + COMMAND echo " LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/murxla-install/usr/local/lib/ ${MURXLA_BINARY} -t 1 --cvc5" + DEPENDS Murxla-EP +)
\ No newline at end of file diff --git a/cmake/version-base.cmake b/cmake/version-base.cmake index 7677706b7..a255f0fbf 100644 --- a/cmake/version-base.cmake +++ b/cmake/version-base.cmake @@ -1,5 +1,5 @@ # These are updated when making a release -set(CVC5_LAST_RELEASE "0.0.2") +set(CVC5_LAST_RELEASE "0.0.3") set(CVC5_IS_RELEASE "false") # These are used in other places in cmake diff --git a/configure.sh b/configure.sh index a8bf19b79..b7a2ca280 100755 --- a/configure.sh +++ b/configure.sh @@ -31,8 +31,6 @@ General options; Features: The following flags enable optional features (disable with --no-<option name>). --static build static libraries and binaries [default=no] - --static-binary statically link against system libraries - (must be disabled for static macOS builds) [default=yes] --auto-download automatically download dependencies if necessary --debug-symbols include debug symbols --valgrind Valgrind instrumentation @@ -59,7 +57,6 @@ Optional Packages: The following flags enable optional packages (disable with --no-<option name>). --cln use CLN instead of GMP --glpk use GLPK simplex solver - --abc use the ABC AIG library --cryptominisat use the CryptoMiniSat SAT solver --kissat use the Kissat SAT solver --poly use the LibPoly library [default=yes] @@ -67,7 +64,6 @@ The following flags enable optional packages (disable with --no-<option name>). --editline support the editline library Optional Path to Optional Packages: - --abc-dir=PATH path to top level of ABC source tree --glpk-dir=PATH path to top level of GLPK installation --dep-path=PATH path to a dependency installation dir @@ -107,7 +103,6 @@ program_prefix="" buildtype=default -abc=default asan=default assertions=default auto_download=default @@ -131,8 +126,7 @@ python2=default python_bindings=default java_bindings=default editline=default -static_library=default -static_binary=default +static=default statistics=default tracing=default tsan=default @@ -144,7 +138,6 @@ arm64=default werror=default ipo=default -abc_dir=default glpk_dir=default #--------------------------------------------------------------------------# @@ -157,9 +150,6 @@ do -h|--help) usage;; - --abc) abc=ON;; - --no-abc) abc=OFF;; - --asan) asan=ON;; --no-asan) asan=OFF;; @@ -180,7 +170,6 @@ do # Best configuration --best) ipo=ON - abc=ON cln=ON cryptominisat=ON glpk=ON @@ -249,11 +238,8 @@ do --muzzle) muzzle=ON;; --no-muzzle) muzzle=OFF;; - --static) static_library=ON; static_binary=ON;; - --no-static) static_library=OFF;; - - --static-binary) static_binary=ON;; - --no-static-binary) static_binary=OFF;; + --static) static=ON;; + --no-static) static=OFF;; --auto-download) auto_download=ON;; --no-auto-download) auto_download=OFF;; @@ -289,9 +275,6 @@ do --editline) editline=ON;; --no-editline) editline=OFF;; - --abc-dir) die "missing argument to $1 (try -h)" ;; - --abc-dir=*) abc_dir=${1##*=} ;; - --glpk-dir) die "missing argument to $1 (try -h)" ;; --glpk-dir=*) glpk_dir=${1##*=} ;; @@ -356,10 +339,8 @@ fi [ $ninja != default ] && cmake_opts="$cmake_opts -G Ninja" [ $muzzle != default ] \ && cmake_opts="$cmake_opts -DENABLE_MUZZLE=$muzzle" -[ $static_library != default ] \ - && cmake_opts="$cmake_opts -DENABLE_STATIC_LIBRARY=$static_library" -[ $static_binary != default ] \ - && cmake_opts="$cmake_opts -DENABLE_STATIC_BINARY=$static_binary" +[ $static != default ] \ + && cmake_opts="$cmake_opts -DENABLE_STATIC_BUILD=$static" [ $statistics != default ] \ && cmake_opts="$cmake_opts -DENABLE_STATISTICS=$statistics" [ $tracing != default ] \ @@ -380,8 +361,6 @@ fi && cmake_opts="$cmake_opts -DENABLE_PROFILING=$profiling" [ $editline != default ] \ && cmake_opts="$cmake_opts -DUSE_EDITLINE=$editline" -[ $abc != default ] \ - && cmake_opts="$cmake_opts -DUSE_ABC=$abc" [ $cln != default ] \ && cmake_opts="$cmake_opts -DUSE_CLN=$cln" [ $cryptominisat != default ] \ @@ -394,8 +373,6 @@ fi && cmake_opts="$cmake_opts -DUSE_POLY=$poly" [ $cocoa != default ] \ && cmake_opts="$cmake_opts -DUSE_COCOA=$cocoa" -[ "$abc_dir" != default ] \ - && cmake_opts="$cmake_opts -DABC_DIR=$abc_dir" [ "$glpk_dir" != default ] \ && cmake_opts="$cmake_opts -DGLPK_DIR=$glpk_dir" [ "$dep_path" != default ] \ diff --git a/contrib/get-abc b/contrib/get-abc deleted file mode 100755 index 6f5987586..000000000 --- a/contrib/get-abc +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env bash -# -source "$(dirname "$0")/get-script-header.sh" - -ABC_DIR="$DEPS_DIR/abc" -commit=3d7034bf619aada30b0ba1e8afcb151d304ab556 - -setup_dep "https://github.com/berkeley-abc/abc/archive/$commit.tar.gz" "$ABC_DIR" -cd "$ABC_DIR" - -# Strip out libSupport.c, it is in charge of loading extensions and we -# don't want different behavior based on ABC_LIB_PATH, or based on what -# .so is in the current directory! -cp src/base/main/module.make src/base/main/module.make.orig -grep -v 'libSupport\.c' src/base/main/module.make.orig > src/base/main/module.make -cp src/base/main/mainInit.c src/base/main/mainInit.c.orig -sed 's,\( *\)\(.*Libs_Init(\),\1//\2,;s,\( *\)\(.*Libs_End(\),\1//\2,' src/base/main/mainInit.c.orig > src/base/main/mainInit.c - -# Build optimized, without readline, without pthreads. -# These aren't necessary for our usage and we don't want the dependencies. -make -j$(nproc) libabc.a OPTFLAGS=-O ABC_USE_NO_READLINE=1 ABC_USE_NO_PTHREADS=1 -mv libabc.a libabc-static.a -install_lib libabc-static.a -make clean - -make -j$(nproc) libabc.a OPTFLAGS='-O -fPIC' ABC_USE_NO_READLINE=1 ABC_USE_NO_PTHREADS=1 -install_lib libabc.a -install_bin arch_flags - -# Copy headers and preserve subdirectories -cd src -mkdir -p "$INSTALL_INCLUDE_DIR/abc" - -if [[ "$OSTYPE" == "darwin"* ]]; then - rsync -R -r $(find . -name '*.h') "$INSTALL_INCLUDE_DIR/abc" -else - cp --parents $(find . -name '*.h') "$INSTALL_INCLUDE_DIR/abc" -fi - -echo -echo ===================== Now configure cvc5 with ===================== -echo ./configure.sh --abc diff --git a/examples/api/java/BitVectors.java b/examples/api/java/BitVectors.java index 6209cf9dd..4d1d9e169 100644 --- a/examples/api/java/BitVectors.java +++ b/examples/api/java/BitVectors.java @@ -22,104 +22,106 @@ public class BitVectors { public static void main(String args[]) throws CVC5ApiException { - Solver slv = new Solver(); - slv.setLogic("QF_BV"); // Set the logic - - // The following example has been adapted from the book A Hacker's Delight by - // Henry S. Warren. - // - // Given a variable x that can only have two values, a or b. We want to - // assign to x a value other than the current one. The straightforward code - // to do that is: - // - //(0) if (x == a ) x = b; - // else x = a; - // - // Two more efficient yet equivalent methods are: - // - //(1) x = a ⊕ b ⊕ x; - // - //(2) x = a + b - x; - // - // We will use cvc5 to prove that the three pieces of code above are all - // equivalent by encoding the problem in the bit-vector theory. - - // Creating a bit-vector type of width 32 - Sort bitvector32 = slv.mkBitVectorSort(32); - - // Variables - Term x = slv.mkConst(bitvector32, "x"); - Term a = slv.mkConst(bitvector32, "a"); - Term b = slv.mkConst(bitvector32, "b"); - - // First encode the assumption that x must be Kind.EQUAL to a or b - Term x_eq_a = slv.mkTerm(Kind.EQUAL, x, a); - Term x_eq_b = slv.mkTerm(Kind.EQUAL, x, b); - Term assumption = slv.mkTerm(Kind.OR, x_eq_a, x_eq_b); - - // Assert the assumption - slv.assertFormula(assumption); - - // Introduce a new variable for the new value of x after assignment. - Term new_x = slv.mkConst(bitvector32, "new_x"); // x after executing code (0) - Term new_x_ = slv.mkConst(bitvector32, "new_x_"); // x after executing code (1) or (2) - - // Encoding code (0) - // new_x = x == a ? b : a; - Term ite = slv.mkTerm(Kind.ITE, x_eq_a, b, a); - Term assignment0 = slv.mkTerm(Kind.EQUAL, new_x, ite); - - // Assert the encoding of code (0) - System.out.println("Asserting " + assignment0 + " to cvc5 "); - slv.assertFormula(assignment0); - System.out.println("Pushing a new context."); - slv.push(); - - // Encoding code (1) - // new_x_ = a xor b xor x - Term a_xor_b_xor_x = slv.mkTerm(Kind.BITVECTOR_XOR, a, b, x); - Term assignment1 = slv.mkTerm(Kind.EQUAL, new_x_, a_xor_b_xor_x); - - // Assert encoding to cvc5 in current context; - System.out.println("Asserting " + assignment1 + " to cvc5 "); - slv.assertFormula(assignment1); - Term new_x_eq_new_x_ = slv.mkTerm(Kind.EQUAL, new_x, new_x_); - - System.out.println(" Check entailment assuming: " + new_x_eq_new_x_); - System.out.println(" Expect ENTAILED. "); - System.out.println(" cvc5: " + slv.checkEntailed(new_x_eq_new_x_)); - System.out.println(" Popping context. "); - slv.pop(); - - // Encoding code (2) - // new_x_ = a + b - x - Term a_plus_b = slv.mkTerm(Kind.BITVECTOR_ADD, a, b); - Term a_plus_b_minus_x = slv.mkTerm(Kind.BITVECTOR_SUB, a_plus_b, x); - Term assignment2 = slv.mkTerm(Kind.EQUAL, new_x_, a_plus_b_minus_x); - - // Assert encoding to cvc5 in current context; - System.out.println("Asserting " + assignment2 + " to cvc5 "); - slv.assertFormula(assignment2); - - System.out.println(" Check entailment assuming: " + new_x_eq_new_x_); - System.out.println(" Expect ENTAILED. "); - System.out.println(" cvc5: " + slv.checkEntailed(new_x_eq_new_x_)); - - Term x_neq_x = slv.mkTerm(Kind.EQUAL, x, x).notTerm(); - Term[] v = new Term[] {new_x_eq_new_x_, x_neq_x}; - System.out.println(" Check entailment assuming: " + v); - System.out.println(" Expect NOT_ENTAILED. "); - System.out.println(" cvc5: " + slv.checkEntailed(v)); - - // Assert that a is odd - Op extract_op = slv.mkOp(Kind.BITVECTOR_EXTRACT, 0, 0); - Term lsb_of_a = slv.mkTerm(extract_op, a); - System.out.println("Sort of " + lsb_of_a + " is " + lsb_of_a.getSort()); - Term a_odd = slv.mkTerm(Kind.EQUAL, lsb_of_a, slv.mkBitVector(1, 1)); - System.out.println("Assert " + a_odd); - System.out.println("Check satisfiability."); - slv.assertFormula(a_odd); - System.out.println(" Expect sat. "); - System.out.println(" cvc5: " + slv.checkSat()); + try (Solver slv = new Solver()) + { + slv.setLogic("QF_BV"); // Set the logic + + // The following example has been adapted from the book A Hacker's Delight by + // Henry S. Warren. + // + // Given a variable x that can only have two values, a or b. We want to + // assign to x a value other than the current one. The straightforward code + // to do that is: + // + //(0) if (x == a ) x = b; + // else x = a; + // + // Two more efficient yet equivalent methods are: + // + //(1) x = a ⊕ b ⊕ x; + // + //(2) x = a + b - x; + // + // We will use cvc5 to prove that the three pieces of code above are all + // equivalent by encoding the problem in the bit-vector theory. + + // Creating a bit-vector type of width 32 + Sort bitvector32 = slv.mkBitVectorSort(32); + + // Variables + Term x = slv.mkConst(bitvector32, "x"); + Term a = slv.mkConst(bitvector32, "a"); + Term b = slv.mkConst(bitvector32, "b"); + + // First encode the assumption that x must be Kind.EQUAL to a or b + Term x_eq_a = slv.mkTerm(Kind.EQUAL, x, a); + Term x_eq_b = slv.mkTerm(Kind.EQUAL, x, b); + Term assumption = slv.mkTerm(Kind.OR, x_eq_a, x_eq_b); + + // Assert the assumption + slv.assertFormula(assumption); + + // Introduce a new variable for the new value of x after assignment. + Term new_x = slv.mkConst(bitvector32, "new_x"); // x after executing code (0) + Term new_x_ = slv.mkConst(bitvector32, "new_x_"); // x after executing code (1) or (2) + + // Encoding code (0) + // new_x = x == a ? b : a; + Term ite = slv.mkTerm(Kind.ITE, x_eq_a, b, a); + Term assignment0 = slv.mkTerm(Kind.EQUAL, new_x, ite); + + // Assert the encoding of code (0) + System.out.println("Asserting " + assignment0 + " to cvc5 "); + slv.assertFormula(assignment0); + System.out.println("Pushing a new context."); + slv.push(); + + // Encoding code (1) + // new_x_ = a xor b xor x + Term a_xor_b_xor_x = slv.mkTerm(Kind.BITVECTOR_XOR, a, b, x); + Term assignment1 = slv.mkTerm(Kind.EQUAL, new_x_, a_xor_b_xor_x); + + // Assert encoding to cvc5 in current context; + System.out.println("Asserting " + assignment1 + " to cvc5 "); + slv.assertFormula(assignment1); + Term new_x_eq_new_x_ = slv.mkTerm(Kind.EQUAL, new_x, new_x_); + + System.out.println(" Check entailment assuming: " + new_x_eq_new_x_); + System.out.println(" Expect ENTAILED. "); + System.out.println(" cvc5: " + slv.checkEntailed(new_x_eq_new_x_)); + System.out.println(" Popping context. "); + slv.pop(); + + // Encoding code (2) + // new_x_ = a + b - x + Term a_plus_b = slv.mkTerm(Kind.BITVECTOR_ADD, a, b); + Term a_plus_b_minus_x = slv.mkTerm(Kind.BITVECTOR_SUB, a_plus_b, x); + Term assignment2 = slv.mkTerm(Kind.EQUAL, new_x_, a_plus_b_minus_x); + + // Assert encoding to cvc5 in current context; + System.out.println("Asserting " + assignment2 + " to cvc5 "); + slv.assertFormula(assignment2); + + System.out.println(" Check entailment assuming: " + new_x_eq_new_x_); + System.out.println(" Expect ENTAILED. "); + System.out.println(" cvc5: " + slv.checkEntailed(new_x_eq_new_x_)); + + Term x_neq_x = slv.mkTerm(Kind.EQUAL, x, x).notTerm(); + Term[] v = new Term[] {new_x_eq_new_x_, x_neq_x}; + System.out.println(" Check entailment assuming: " + v); + System.out.println(" Expect NOT_ENTAILED. "); + System.out.println(" cvc5: " + slv.checkEntailed(v)); + + // Assert that a is odd + Op extract_op = slv.mkOp(Kind.BITVECTOR_EXTRACT, 0, 0); + Term lsb_of_a = slv.mkTerm(extract_op, a); + System.out.println("Sort of " + lsb_of_a + " is " + lsb_of_a.getSort()); + Term a_odd = slv.mkTerm(Kind.EQUAL, lsb_of_a, slv.mkBitVector(1, 1)); + System.out.println("Assert " + a_odd); + System.out.println("Check satisfiability."); + slv.assertFormula(a_odd); + System.out.println(" Expect sat. "); + System.out.println(" cvc5: " + slv.checkSat()); + } } -}
\ No newline at end of file +} diff --git a/examples/api/java/BitVectorsAndArrays.java b/examples/api/java/BitVectorsAndArrays.java index 07b9781d2..c72106082 100644 --- a/examples/api/java/BitVectorsAndArrays.java +++ b/examples/api/java/BitVectorsAndArrays.java @@ -27,73 +27,75 @@ public class BitVectorsAndArrays public static void main(String[] args) throws CVC5ApiException { - Solver slv = new Solver(); - slv.setOption("produce-models", "true"); // Produce Models - slv.setOption("output-language", "smtlib"); // output-language - slv.setLogic("QF_AUFBV"); // Set the logic + try (Solver slv = new Solver()) + { + slv.setOption("produce-models", "true"); // Produce Models + slv.setOption("output-language", "smtlib"); // output-language + slv.setLogic("QF_AUFBV"); // Set the logic - // Consider the following code (where size is some previously defined constant): - // - // - // Assert (current_array[0] > 0); - // for (unsigned i = 1; i < k; ++i) { - // current_array[i] = 2 * current_array[i - 1]; - // Assert (current_array[i-1] < current_array[i]); - // } - // - // We want to check whether the assertion in the body of the for loop holds - // throughout the loop. + // Consider the following code (where size is some previously defined constant): + // + // + // Assert (current_array[0] > 0); + // for (unsigned i = 1; i < k; ++i) { + // current_array[i] = 2 * current_array[i - 1]; + // Assert (current_array[i-1] < current_array[i]); + // } + // + // We want to check whether the assertion in the body of the for loop holds + // throughout the loop. - // Setting up the problem parameters - int k = 4; // number of unrollings (should be a power of 2) - int index_size = log2(k); // size of the index + // Setting up the problem parameters + int k = 4; // number of unrollings (should be a power of 2) + int index_size = log2(k); // size of the index - // Sorts - Sort elementSort = slv.mkBitVectorSort(32); - Sort indexSort = slv.mkBitVectorSort(index_size); - Sort arraySort = slv.mkArraySort(indexSort, elementSort); + // Sorts + Sort elementSort = slv.mkBitVectorSort(32); + Sort indexSort = slv.mkBitVectorSort(index_size); + Sort arraySort = slv.mkArraySort(indexSort, elementSort); - // Variables - Term current_array = slv.mkConst(arraySort, "current_array"); + // Variables + Term current_array = slv.mkConst(arraySort, "current_array"); - // Making a bit-vector constant - Term zero = slv.mkBitVector(index_size, 0); + // Making a bit-vector constant + Term zero = slv.mkBitVector(index_size, 0); - // Asserting that current_array[0] > 0 - Term current_array0 = slv.mkTerm(Kind.SELECT, current_array, zero); - Term current_array0_gt_0 = - slv.mkTerm(Kind.BITVECTOR_SGT, current_array0, slv.mkBitVector(32, 0)); - slv.assertFormula(current_array0_gt_0); + // Asserting that current_array[0] > 0 + Term current_array0 = slv.mkTerm(Kind.SELECT, current_array, zero); + Term current_array0_gt_0 = + slv.mkTerm(Kind.BITVECTOR_SGT, current_array0, slv.mkBitVector(32, 0)); + slv.assertFormula(current_array0_gt_0); - // Building the assertions in the loop unrolling - Term index = slv.mkBitVector(index_size, 0); - Term old_current = slv.mkTerm(Kind.SELECT, current_array, index); - Term two = slv.mkBitVector(32, 2); + // Building the assertions in the loop unrolling + Term index = slv.mkBitVector(index_size, 0); + Term old_current = slv.mkTerm(Kind.SELECT, current_array, index); + Term two = slv.mkBitVector(32, 2); - List<Term> assertions = new ArrayList<Term>(); - for (int i = 1; i < k; ++i) - { - index = slv.mkBitVector(index_size, i); - Term new_current = slv.mkTerm(Kind.BITVECTOR_MULT, two, old_current); - // current[i] = 2 * current[i-1] - current_array = slv.mkTerm(Kind.STORE, current_array, index, new_current); - // current[i-1] < current [i] - Term current_slt_new_current = slv.mkTerm(Kind.BITVECTOR_SLT, old_current, new_current); - assertions.add(current_slt_new_current); + List<Term> assertions = new ArrayList<Term>(); + for (int i = 1; i < k; ++i) + { + index = slv.mkBitVector(index_size, i); + Term new_current = slv.mkTerm(Kind.BITVECTOR_MULT, two, old_current); + // current[i] = 2 * current[i-1] + current_array = slv.mkTerm(Kind.STORE, current_array, index, new_current); + // current[i-1] < current [i] + Term current_slt_new_current = slv.mkTerm(Kind.BITVECTOR_SLT, old_current, new_current); + assertions.add(current_slt_new_current); - old_current = slv.mkTerm(Kind.SELECT, current_array, index); - } + old_current = slv.mkTerm(Kind.SELECT, current_array, index); + } - Term query = slv.mkTerm(Kind.NOT, slv.mkTerm(Kind.AND, assertions.toArray(new Term[0]))); + Term query = slv.mkTerm(Kind.NOT, slv.mkTerm(Kind.AND, assertions.toArray(new Term[0]))); - System.out.println("Asserting " + query + " to cvc5 "); - slv.assertFormula(query); - System.out.println("Expect sat. "); - System.out.println("cvc5: " + slv.checkSatAssuming(slv.mkTrue())); + System.out.println("Asserting " + query + " to cvc5 "); + slv.assertFormula(query); + System.out.println("Expect sat. "); + System.out.println("cvc5: " + slv.checkSatAssuming(slv.mkTrue())); - // Getting the model - System.out.println("The satisfying model is: "); - System.out.println(" current_array = " + slv.getValue(current_array)); - System.out.println(" current_array[0] = " + slv.getValue(current_array0)); + // Getting the model + System.out.println("The satisfying model is: "); + System.out.println(" current_array = " + slv.getValue(current_array)); + System.out.println(" current_array[0] = " + slv.getValue(current_array0)); + } } } diff --git a/examples/api/java/Combination.java b/examples/api/java/Combination.java index 66cd30b2b..03c43521a 100644 --- a/examples/api/java/Combination.java +++ b/examples/api/java/Combination.java @@ -39,89 +39,91 @@ public class Combination public static void main(String[] args) throws CVC5ApiException { - Solver slv = new Solver(); - slv.setOption("produce-models", "true"); // Produce Models - slv.setOption("dag-thresh", "0"); // Disable dagifying the output - slv.setOption("output-language", "smt2"); // use smt-lib v2 as output language - slv.setLogic("QF_UFLIRA"); - - // Sorts - Sort u = slv.mkUninterpretedSort("u"); - Sort integer = slv.getIntegerSort(); - Sort bool = slv.getBooleanSort(); - Sort uToInt = slv.mkFunctionSort(u, integer); - Sort intPred = slv.mkFunctionSort(integer, bool); - - // Variables - Term x = slv.mkConst(u, "x"); - Term y = slv.mkConst(u, "y"); - - // Functions - Term f = slv.mkConst(uToInt, "f"); - Term p = slv.mkConst(intPred, "p"); - - // Constants - Term zero = slv.mkInteger(0); - Term one = slv.mkInteger(1); - - // Terms - Term f_x = slv.mkTerm(Kind.APPLY_UF, f, x); - Term f_y = slv.mkTerm(Kind.APPLY_UF, f, y); - Term sum = slv.mkTerm(Kind.PLUS, f_x, f_y); - Term p_0 = slv.mkTerm(Kind.APPLY_UF, p, zero); - Term p_f_y = slv.mkTerm(Kind.APPLY_UF, p, f_y); - - // Construct the assertions - Term assertions = slv.mkTerm(Kind.AND, - new Term[] { - slv.mkTerm(Kind.LEQ, zero, f_x), // 0 <= f(x) - slv.mkTerm(Kind.LEQ, zero, f_y), // 0 <= f(y) - slv.mkTerm(Kind.LEQ, sum, one), // f(x) + f(y) <= 1 - p_0.notTerm(), // not p(0) - p_f_y // p(f(y)) - }); - slv.assertFormula(assertions); - - System.out.println("Given the following assertions:\n" + assertions + "\n"); - - System.out.println("Prove x /= y is entailed. \n" - + "cvc5: " + slv.checkEntailed(slv.mkTerm(Kind.DISTINCT, x, y)) + ".\n"); - - System.out.println("Call checkSat to show that the assertions are satisfiable. \n" - + "cvc5: " + slv.checkSat() + ".\n"); - - System.out.println("Call slv.getValue(...) on terms of interest."); - System.out.println("slv.getValue(" + f_x + "): " + slv.getValue(f_x)); - System.out.println("slv.getValue(" + f_y + "): " + slv.getValue(f_y)); - System.out.println("slv.getValue(" + sum + "): " + slv.getValue(sum)); - System.out.println("slv.getValue(" + p_0 + "): " + slv.getValue(p_0)); - System.out.println("slv.getValue(" + p_f_y + "): " + slv.getValue(p_f_y) + "\n"); - - System.out.println("Alternatively, iterate over assertions and call slv.getValue(...) " - + "on all terms."); - prefixPrintGetValue(slv, assertions); - - System.out.println(); - System.out.println("You can also use nested loops to iterate over terms."); - Iterator<Term> it1 = assertions.iterator(); - while (it1.hasNext()) + try (Solver slv = new Solver()) { - Term t = it1.next(); - System.out.println("term: " + t); - Iterator<Term> it2 = t.iterator(); - while (it2.hasNext()) + slv.setOption("produce-models", "true"); // Produce Models + slv.setOption("dag-thresh", "0"); // Disable dagifying the output + slv.setOption("output-language", "smt2"); // use smt-lib v2 as output language + slv.setLogic("QF_UFLIRA"); + + // Sorts + Sort u = slv.mkUninterpretedSort("u"); + Sort integer = slv.getIntegerSort(); + Sort bool = slv.getBooleanSort(); + Sort uToInt = slv.mkFunctionSort(u, integer); + Sort intPred = slv.mkFunctionSort(integer, bool); + + // Variables + Term x = slv.mkConst(u, "x"); + Term y = slv.mkConst(u, "y"); + + // Functions + Term f = slv.mkConst(uToInt, "f"); + Term p = slv.mkConst(intPred, "p"); + + // Constants + Term zero = slv.mkInteger(0); + Term one = slv.mkInteger(1); + + // Terms + Term f_x = slv.mkTerm(Kind.APPLY_UF, f, x); + Term f_y = slv.mkTerm(Kind.APPLY_UF, f, y); + Term sum = slv.mkTerm(Kind.PLUS, f_x, f_y); + Term p_0 = slv.mkTerm(Kind.APPLY_UF, p, zero); + Term p_f_y = slv.mkTerm(Kind.APPLY_UF, p, f_y); + + // Construct the assertions + Term assertions = slv.mkTerm(Kind.AND, + new Term[] { + slv.mkTerm(Kind.LEQ, zero, f_x), // 0 <= f(x) + slv.mkTerm(Kind.LEQ, zero, f_y), // 0 <= f(y) + slv.mkTerm(Kind.LEQ, sum, one), // f(x) + f(y) <= 1 + p_0.notTerm(), // not p(0) + p_f_y // p(f(y)) + }); + slv.assertFormula(assertions); + + System.out.println("Given the following assertions:\n" + assertions + "\n"); + + System.out.println("Prove x /= y is entailed. \n" + + "cvc5: " + slv.checkEntailed(slv.mkTerm(Kind.DISTINCT, x, y)) + ".\n"); + + System.out.println("Call checkSat to show that the assertions are satisfiable. \n" + + "cvc5: " + slv.checkSat() + ".\n"); + + System.out.println("Call slv.getValue(...) on terms of interest."); + System.out.println("slv.getValue(" + f_x + "): " + slv.getValue(f_x)); + System.out.println("slv.getValue(" + f_y + "): " + slv.getValue(f_y)); + System.out.println("slv.getValue(" + sum + "): " + slv.getValue(sum)); + System.out.println("slv.getValue(" + p_0 + "): " + slv.getValue(p_0)); + System.out.println("slv.getValue(" + p_f_y + "): " + slv.getValue(p_f_y) + "\n"); + + System.out.println("Alternatively, iterate over assertions and call slv.getValue(...) " + + "on all terms."); + prefixPrintGetValue(slv, assertions); + + System.out.println(); + System.out.println("You can also use nested loops to iterate over terms."); + Iterator<Term> it1 = assertions.iterator(); + while (it1.hasNext()) { - System.out.println(" + child: " + it2.next()); + Term t = it1.next(); + System.out.println("term: " + t); + Iterator<Term> it2 = t.iterator(); + while (it2.hasNext()) + { + System.out.println(" + child: " + it2.next()); + } } - } - System.out.println(); - System.out.println("Alternatively, you can also use for-each loops."); - for (Term t : assertions) - { - System.out.println("term: " + t); - for (Term c : t) + System.out.println(); + System.out.println("Alternatively, you can also use for-each loops."); + for (Term t : assertions) { - System.out.println(" + child: " + c); + System.out.println("term: " + t); + for (Term c : t) + { + System.out.println(" + child: " + c); + } } } } diff --git a/examples/api/java/Datatypes.java b/examples/api/java/Datatypes.java index 85f878098..b29419165 100644 --- a/examples/api/java/Datatypes.java +++ b/examples/api/java/Datatypes.java @@ -123,46 +123,48 @@ public class Datatypes public static void main(String[] args) throws CVC5ApiException { - Solver slv = new Solver(); - // This example builds a simple "cons list" of integers, with - // two constructors, "cons" and "nil." - - // Building a datatype consists of two steps. - // First, the datatype is specified. - // Second, it is "resolved" to an actual sort, at which point function - // symbols are assigned to its constructors, selectors, and testers. - - DatatypeDecl consListSpec = slv.mkDatatypeDecl("list"); // give the datatype a name - DatatypeConstructorDecl cons = slv.mkDatatypeConstructorDecl("cons"); - cons.addSelector("head", slv.getIntegerSort()); - cons.addSelectorSelf("tail"); - consListSpec.addConstructor(cons); - DatatypeConstructorDecl nil = slv.mkDatatypeConstructorDecl("nil"); - consListSpec.addConstructor(nil); - - System.out.println("spec is:" - + "\n" + consListSpec); - - // Keep in mind that "DatatypeDecl" is the specification class for - // datatypes---"DatatypeDecl" is not itself a cvc5 Sort. - // Now that our Datatype is fully specified, we can get a Sort for it. - // This step resolves the "SelfSort" reference and creates - // symbols for all the constructors, etc. - - Sort consListSort = slv.mkDatatypeSort(consListSpec); - - test(slv, consListSort); - - System.out.println("\n" - + ">>> Alternatively, use declareDatatype"); - System.out.println("\n"); - - DatatypeConstructorDecl cons2 = slv.mkDatatypeConstructorDecl("cons"); - cons2.addSelector("head", slv.getIntegerSort()); - cons2.addSelectorSelf("tail"); - DatatypeConstructorDecl nil2 = slv.mkDatatypeConstructorDecl("nil"); - DatatypeConstructorDecl[] ctors = new DatatypeConstructorDecl[] {cons2, nil2}; - Sort consListSort2 = slv.declareDatatype("list2", ctors); - test(slv, consListSort2); + try (Solver slv = new Solver()) + { + // This example builds a simple "cons list" of integers, with + // two constructors, "cons" and "nil." + + // Building a datatype consists of two steps. + // First, the datatype is specified. + // Second, it is "resolved" to an actual sort, at which point function + // symbols are assigned to its constructors, selectors, and testers. + + DatatypeDecl consListSpec = slv.mkDatatypeDecl("list"); // give the datatype a name + DatatypeConstructorDecl cons = slv.mkDatatypeConstructorDecl("cons"); + cons.addSelector("head", slv.getIntegerSort()); + cons.addSelectorSelf("tail"); + consListSpec.addConstructor(cons); + DatatypeConstructorDecl nil = slv.mkDatatypeConstructorDecl("nil"); + consListSpec.addConstructor(nil); + + System.out.println("spec is:" + + "\n" + consListSpec); + + // Keep in mind that "DatatypeDecl" is the specification class for + // datatypes---"DatatypeDecl" is not itself a cvc5 Sort. + // Now that our Datatype is fully specified, we can get a Sort for it. + // This step resolves the "SelfSort" reference and creates + // symbols for all the constructors, etc. + + Sort consListSort = slv.mkDatatypeSort(consListSpec); + + test(slv, consListSort); + + System.out.println("\n" + + ">>> Alternatively, use declareDatatype"); + System.out.println("\n"); + + DatatypeConstructorDecl cons2 = slv.mkDatatypeConstructorDecl("cons"); + cons2.addSelector("head", slv.getIntegerSort()); + cons2.addSelectorSelf("tail"); + DatatypeConstructorDecl nil2 = slv.mkDatatypeConstructorDecl("nil"); + DatatypeConstructorDecl[] ctors = new DatatypeConstructorDecl[] {cons2, nil2}; + Sort consListSort2 = slv.declareDatatype("list2", ctors); + test(slv, consListSort2); + } } } diff --git a/examples/api/java/Exceptions.java b/examples/api/java/Exceptions.java index 2d62a7570..bc142571d 100644 --- a/examples/api/java/Exceptions.java +++ b/examples/api/java/Exceptions.java @@ -21,45 +21,46 @@ public class Exceptions { public static void main(String[] args) { - Solver solver = new Solver(); - - solver.setOption("produce-models", "true"); - - // Setting an invalid option - try - { - solver.setOption("non-existing", "true"); - System.exit(1); - } - catch (Exception e) + try (Solver solver = new Solver()) { - System.out.println(e.toString()); - } + solver.setOption("produce-models", "true"); - // Creating a term with an invalid type - try - { - Sort integer = solver.getIntegerSort(); - Term x = solver.mkVar(integer, "x"); - Term invalidTerm = solver.mkTerm(Kind.AND, x, x); - solver.checkSatAssuming(invalidTerm); - System.exit(1); - } - catch (Exception e) - { - System.out.println(e.toString()); - } + // Setting an invalid option + try + { + solver.setOption("non-existing", "true"); + System.exit(1); + } + catch (Exception e) + { + System.out.println(e.toString()); + } - // Asking for a model after unsat result - try - { - solver.checkSatAssuming(solver.mkBoolean(false)); - solver.getModel(new Sort[] {}, new Term[] {}); - System.exit(1); - } - catch (Exception e) - { - System.out.println(e.toString()); + // Creating a term with an invalid type + try + { + Sort integer = solver.getIntegerSort(); + Term x = solver.mkVar(integer, "x"); + Term invalidTerm = solver.mkTerm(Kind.AND, x, x); + solver.checkSatAssuming(invalidTerm); + System.exit(1); + } + catch (Exception e) + { + System.out.println(e.toString()); + } + + // Asking for a model after unsat result + try + { + solver.checkSatAssuming(solver.mkBoolean(false)); + solver.getModel(new Sort[] {}, new Term[] {}); + System.exit(1); + } + catch (Exception e) + { + System.out.println(e.toString()); + } } } } diff --git a/examples/api/java/Extract.java b/examples/api/java/Extract.java index 0d8d6c2b2..4ec0c100f 100644 --- a/examples/api/java/Extract.java +++ b/examples/api/java/Extract.java @@ -21,32 +21,34 @@ public class Extract { public static void main(String args[]) throws CVC5ApiException { - Solver slv = new Solver(); - slv.setLogic("QF_BV"); // Set the logic + try (Solver slv = new Solver()) + { + slv.setLogic("QF_BV"); // Set the logic - Sort bitvector32 = slv.mkBitVectorSort(32); + Sort bitvector32 = slv.mkBitVectorSort(32); - Term x = slv.mkConst(bitvector32, "a"); + Term x = slv.mkConst(bitvector32, "a"); - Op ext_31_1 = slv.mkOp(Kind.BITVECTOR_EXTRACT, 31, 1); - Term x_31_1 = slv.mkTerm(ext_31_1, x); + Op ext_31_1 = slv.mkOp(Kind.BITVECTOR_EXTRACT, 31, 1); + Term x_31_1 = slv.mkTerm(ext_31_1, x); - Op ext_30_0 = slv.mkOp(Kind.BITVECTOR_EXTRACT, 30, 0); - Term x_30_0 = slv.mkTerm(ext_30_0, x); + Op ext_30_0 = slv.mkOp(Kind.BITVECTOR_EXTRACT, 30, 0); + Term x_30_0 = slv.mkTerm(ext_30_0, x); - Op ext_31_31 = slv.mkOp(Kind.BITVECTOR_EXTRACT, 31, 31); - Term x_31_31 = slv.mkTerm(ext_31_31, x); + Op ext_31_31 = slv.mkOp(Kind.BITVECTOR_EXTRACT, 31, 31); + Term x_31_31 = slv.mkTerm(ext_31_31, x); - Op ext_0_0 = slv.mkOp(Kind.BITVECTOR_EXTRACT, 0, 0); - Term x_0_0 = slv.mkTerm(ext_0_0, x); + Op ext_0_0 = slv.mkOp(Kind.BITVECTOR_EXTRACT, 0, 0); + Term x_0_0 = slv.mkTerm(ext_0_0, x); - Term eq = slv.mkTerm(Kind.EQUAL, x_31_1, x_30_0); - System.out.println(" Asserting: " + eq); - slv.assertFormula(eq); + Term eq = slv.mkTerm(Kind.EQUAL, x_31_1, x_30_0); + System.out.println(" Asserting: " + eq); + slv.assertFormula(eq); - Term eq2 = slv.mkTerm(Kind.EQUAL, x_31_31, x_0_0); - System.out.println(" Check entailment assuming: " + eq2); - System.out.println(" Expect ENTAILED. "); - System.out.println(" cvc5: " + slv.checkEntailed(eq2)); + Term eq2 = slv.mkTerm(Kind.EQUAL, x_31_31, x_0_0); + System.out.println(" Check entailment assuming: " + eq2); + System.out.println(" Expect ENTAILED. "); + System.out.println(" cvc5: " + slv.checkEntailed(eq2)); + } } -}
\ No newline at end of file +} diff --git a/examples/api/java/FloatingPointArith.java b/examples/api/java/FloatingPointArith.java index 88e24cbab..d8ed384d0 100644 --- a/examples/api/java/FloatingPointArith.java +++ b/examples/api/java/FloatingPointArith.java @@ -26,76 +26,78 @@ public class FloatingPointArith { public static void main(String[] args) throws CVC5ApiException { - Solver solver = new Solver(); - solver.setOption("produce-models", "true"); + try (Solver solver = new Solver()) + { + solver.setOption("produce-models", "true"); - // Make single precision floating-point variables - Sort fpt32 = solver.mkFloatingPointSort(8, 24); - Term a = solver.mkConst(fpt32, "a"); - Term b = solver.mkConst(fpt32, "b"); - Term c = solver.mkConst(fpt32, "c"); - Term d = solver.mkConst(fpt32, "d"); - Term e = solver.mkConst(fpt32, "e"); + // Make single precision floating-point variables + Sort fpt32 = solver.mkFloatingPointSort(8, 24); + Term a = solver.mkConst(fpt32, "a"); + Term b = solver.mkConst(fpt32, "b"); + Term c = solver.mkConst(fpt32, "c"); + Term d = solver.mkConst(fpt32, "d"); + Term e = solver.mkConst(fpt32, "e"); - // Assert that floating-point addition is not associative: - // (a + (b + c)) != ((a + b) + c) - Term rm = solver.mkRoundingMode(RoundingMode.ROUND_NEAREST_TIES_TO_EVEN); - Term lhs = solver.mkTerm( - Kind.FLOATINGPOINT_ADD, rm, a, solver.mkTerm(Kind.FLOATINGPOINT_ADD, rm, b, c)); - Term rhs = solver.mkTerm( - Kind.FLOATINGPOINT_ADD, rm, solver.mkTerm(Kind.FLOATINGPOINT_ADD, rm, a, b), c); - solver.assertFormula(solver.mkTerm(Kind.NOT, solver.mkTerm(Kind.EQUAL, a, b))); + // Assert that floating-point addition is not associative: + // (a + (b + c)) != ((a + b) + c) + Term rm = solver.mkRoundingMode(RoundingMode.ROUND_NEAREST_TIES_TO_EVEN); + Term lhs = solver.mkTerm( + Kind.FLOATINGPOINT_ADD, rm, a, solver.mkTerm(Kind.FLOATINGPOINT_ADD, rm, b, c)); + Term rhs = solver.mkTerm( + Kind.FLOATINGPOINT_ADD, rm, solver.mkTerm(Kind.FLOATINGPOINT_ADD, rm, a, b), c); + solver.assertFormula(solver.mkTerm(Kind.NOT, solver.mkTerm(Kind.EQUAL, a, b))); - Result r = solver.checkSat(); // result is sat - assert r.isSat(); + Result r = solver.checkSat(); // result is sat + assert r.isSat(); - System.out.println("a = " + solver.getValue(a)); - System.out.println("b = " + solver.getValue(b)); - System.out.println("c = " + solver.getValue(c)); + System.out.println("a = " + solver.getValue(a)); + System.out.println("b = " + solver.getValue(b)); + System.out.println("c = " + solver.getValue(c)); - // Now, let's restrict `a` to be either NaN or positive infinity - Term nan = solver.mkNaN(8, 24); - Term inf = solver.mkPosInf(8, 24); - solver.assertFormula(solver.mkTerm( - Kind.OR, solver.mkTerm(Kind.EQUAL, a, inf), solver.mkTerm(Kind.EQUAL, a, nan))); + // Now, let's restrict `a` to be either NaN or positive infinity + Term nan = solver.mkNaN(8, 24); + Term inf = solver.mkPosInf(8, 24); + solver.assertFormula(solver.mkTerm( + Kind.OR, solver.mkTerm(Kind.EQUAL, a, inf), solver.mkTerm(Kind.EQUAL, a, nan))); - r = solver.checkSat(); // result is sat - assert r.isSat(); + r = solver.checkSat(); // result is sat + assert r.isSat(); - System.out.println("a = " + solver.getValue(a)); - System.out.println("b = " + solver.getValue(b)); - System.out.println("c = " + solver.getValue(c)); + System.out.println("a = " + solver.getValue(a)); + System.out.println("b = " + solver.getValue(b)); + System.out.println("c = " + solver.getValue(c)); - // And now for something completely different. Let's try to find a (normal) - // floating-point number that rounds to different integer values for - // different rounding modes. - Term rtp = solver.mkRoundingMode(RoundingMode.ROUND_TOWARD_POSITIVE); - Term rtn = solver.mkRoundingMode(RoundingMode.ROUND_TOWARD_NEGATIVE); - Op op = solver.mkOp(Kind.FLOATINGPOINT_TO_SBV, 16); // (_ fp.to_sbv 16) - lhs = solver.mkTerm(op, rtp, d); - rhs = solver.mkTerm(op, rtn, d); - solver.assertFormula(solver.mkTerm(Kind.FLOATINGPOINT_ISN, d)); - solver.assertFormula(solver.mkTerm(Kind.NOT, solver.mkTerm(Kind.EQUAL, lhs, rhs))); + // And now for something completely different. Let's try to find a (normal) + // floating-point number that rounds to different integer values for + // different rounding modes. + Term rtp = solver.mkRoundingMode(RoundingMode.ROUND_TOWARD_POSITIVE); + Term rtn = solver.mkRoundingMode(RoundingMode.ROUND_TOWARD_NEGATIVE); + Op op = solver.mkOp(Kind.FLOATINGPOINT_TO_SBV, 16); // (_ fp.to_sbv 16) + lhs = solver.mkTerm(op, rtp, d); + rhs = solver.mkTerm(op, rtn, d); + solver.assertFormula(solver.mkTerm(Kind.FLOATINGPOINT_ISN, d)); + solver.assertFormula(solver.mkTerm(Kind.NOT, solver.mkTerm(Kind.EQUAL, lhs, rhs))); - r = solver.checkSat(); // result is sat - assert r.isSat(); + r = solver.checkSat(); // result is sat + assert r.isSat(); - // Convert the result to a rational and print it - Term val = solver.getValue(d); - Term realVal = solver.getValue(solver.mkTerm(FLOATINGPOINT_TO_REAL, val)); - System.out.println("d = " + val + " = " + realVal); - System.out.println("((_ fp.to_sbv 16) RTP d) = " + solver.getValue(lhs)); - System.out.println("((_ fp.to_sbv 16) RTN d) = " + solver.getValue(rhs)); + // Convert the result to a rational and print it + Term val = solver.getValue(d); + Term realVal = solver.getValue(solver.mkTerm(FLOATINGPOINT_TO_REAL, val)); + System.out.println("d = " + val + " = " + realVal); + System.out.println("((_ fp.to_sbv 16) RTP d) = " + solver.getValue(lhs)); + System.out.println("((_ fp.to_sbv 16) RTN d) = " + solver.getValue(rhs)); - // For our final trick, let's try to find a floating-point number between - // positive zero and the smallest positive floating-point number - Term zero = solver.mkPosZero(8, 24); - Term smallest = solver.mkFloatingPoint(8, 24, solver.mkBitVector(32, 0b001)); - solver.assertFormula(solver.mkTerm(Kind.AND, - solver.mkTerm(Kind.FLOATINGPOINT_LT, zero, e), - solver.mkTerm(Kind.FLOATINGPOINT_LT, e, smallest))); + // For our final trick, let's try to find a floating-point number between + // positive zero and the smallest positive floating-point number + Term zero = solver.mkPosZero(8, 24); + Term smallest = solver.mkFloatingPoint(8, 24, solver.mkBitVector(32, 0b001)); + solver.assertFormula(solver.mkTerm(Kind.AND, + solver.mkTerm(Kind.FLOATINGPOINT_LT, zero, e), + solver.mkTerm(Kind.FLOATINGPOINT_LT, e, smallest))); - r = solver.checkSat(); // result is unsat - assert !r.isSat(); + r = solver.checkSat(); // result is unsat + assert !r.isSat(); + } } } diff --git a/examples/api/java/HelloWorld.java b/examples/api/java/HelloWorld.java index 966bfb329..7535430e3 100644 --- a/examples/api/java/HelloWorld.java +++ b/examples/api/java/HelloWorld.java @@ -19,9 +19,11 @@ public class HelloWorld { public static void main(String[] args) { - Solver slv = new Solver(); - Term helloworld = slv.mkVar(slv.getBooleanSort(), "Hello World!"); + try (Solver slv = new Solver()) + { + Term helloworld = slv.mkVar(slv.getBooleanSort(), "Hello World!"); - System.out.println(helloworld + " is " + slv.checkEntailed(helloworld)); + System.out.println(helloworld + " is " + slv.checkEntailed(helloworld)); + } } } diff --git a/examples/api/java/LinearArith.java b/examples/api/java/LinearArith.java index 2e67d526f..1f8153e44 100644 --- a/examples/api/java/LinearArith.java +++ b/examples/api/java/LinearArith.java @@ -19,57 +19,59 @@ public class LinearArith { public static void main(String args[]) throws CVC5ApiException { - Solver slv = new Solver(); - slv.setLogic("QF_LIRA"); // Set the logic + try (Solver slv = new Solver()) + { + slv.setLogic("QF_LIRA"); // Set the logic - // Prove that if given x (Integer) and y (Real) then - // the maximum value of y - x is 2/3 + // Prove that if given x (Integer) and y (Real) then + // the maximum value of y - x is 2/3 - // Sorts - Sort real = slv.getRealSort(); - Sort integer = slv.getIntegerSort(); + // Sorts + Sort real = slv.getRealSort(); + Sort integer = slv.getIntegerSort(); - // Variables - Term x = slv.mkConst(integer, "x"); - Term y = slv.mkConst(real, "y"); + // Variables + Term x = slv.mkConst(integer, "x"); + Term y = slv.mkConst(real, "y"); - // Constants - Term three = slv.mkInteger(3); - Term neg2 = slv.mkInteger(-2); - Term two_thirds = slv.mkReal(2, 3); + // Constants + Term three = slv.mkInteger(3); + Term neg2 = slv.mkInteger(-2); + Term two_thirds = slv.mkReal(2, 3); - // Terms - Term three_y = slv.mkTerm(Kind.MULT, three, y); - Term diff = slv.mkTerm(Kind.MINUS, y, x); + // Terms + Term three_y = slv.mkTerm(Kind.MULT, three, y); + Term diff = slv.mkTerm(Kind.MINUS, y, x); - // Formulas - Term x_geq_3y = slv.mkTerm(Kind.GEQ, x, three_y); - Term x_leq_y = slv.mkTerm(Kind.LEQ, x, y); - Term neg2_lt_x = slv.mkTerm(Kind.LT, neg2, x); + // Formulas + Term x_geq_3y = slv.mkTerm(Kind.GEQ, x, three_y); + Term x_leq_y = slv.mkTerm(Kind.LEQ, x, y); + Term neg2_lt_x = slv.mkTerm(Kind.LT, neg2, x); - Term assertions = slv.mkTerm(Kind.AND, x_geq_3y, x_leq_y, neg2_lt_x); + Term assertions = slv.mkTerm(Kind.AND, x_geq_3y, x_leq_y, neg2_lt_x); - System.out.println("Given the assertions " + assertions); - slv.assertFormula(assertions); + System.out.println("Given the assertions " + assertions); + slv.assertFormula(assertions); - slv.push(); - Term diff_leq_two_thirds = slv.mkTerm(Kind.LEQ, diff, two_thirds); - System.out.println("Prove that " + diff_leq_two_thirds + " with cvc5."); - System.out.println("cvc5 should report ENTAILED."); - System.out.println("Result from cvc5 is: " + slv.checkEntailed(diff_leq_two_thirds)); - slv.pop(); + slv.push(); + Term diff_leq_two_thirds = slv.mkTerm(Kind.LEQ, diff, two_thirds); + System.out.println("Prove that " + diff_leq_two_thirds + " with cvc5."); + System.out.println("cvc5 should report ENTAILED."); + System.out.println("Result from cvc5 is: " + slv.checkEntailed(diff_leq_two_thirds)); + slv.pop(); - System.out.println(); + System.out.println(); - slv.push(); - Term diff_is_two_thirds = slv.mkTerm(Kind.EQUAL, diff, two_thirds); - slv.assertFormula(diff_is_two_thirds); - System.out.println("Show that the assertions are consistent with "); - System.out.println(diff_is_two_thirds + " with cvc5."); - System.out.println("cvc5 should report SAT."); - System.out.println("Result from cvc5 is: " + slv.checkSat()); - slv.pop(); + slv.push(); + Term diff_is_two_thirds = slv.mkTerm(Kind.EQUAL, diff, two_thirds); + slv.assertFormula(diff_is_two_thirds); + System.out.println("Show that the assertions are consistent with "); + System.out.println(diff_is_two_thirds + " with cvc5."); + System.out.println("cvc5 should report SAT."); + System.out.println("Result from cvc5 is: " + slv.checkSat()); + slv.pop(); - System.out.println("Thus the maximum value of (y - x) is 2/3."); + System.out.println("Thus the maximum value of (y - x) is 2/3."); + } } }
\ No newline at end of file diff --git a/examples/api/java/QuickStart.java b/examples/api/java/QuickStart.java index 73bddb083..a79263cbf 100644 --- a/examples/api/java/QuickStart.java +++ b/examples/api/java/QuickStart.java @@ -25,123 +25,124 @@ public class QuickStart public static void main(String args[]) throws CVC5ApiException { // Create a solver - Solver solver = new Solver(); - - // We will ask the solver to produce models and unsat cores, - // hence these options should be turned on. - solver.setOption("produce-models", "true"); - solver.setOption("produce-unsat-cores", "true"); - - // The simplest way to set a logic for the solver is to choose "ALL". - // This enables all logics in the solver. - // Alternatively, "QF_ALL" enables all logics without quantifiers. - // To optimize the solver's behavior for a more specific logic, - // use the logic name, e.g. "QF_BV" or "QF_AUFBV". - - // Set the logic - solver.setLogic("ALL"); - - // In this example, we will define constraints over reals and integers. - // Hence, we first obtain the corresponding sorts. - Sort realSort = solver.getRealSort(); - Sort intSort = solver.getIntegerSort(); - - // x and y will be real variables, while a and b will be integer variables. - // Formally, their cpp type is Term, - // and they are called "constants" in SMT jargon: - Term x = solver.mkConst(realSort, "x"); - Term y = solver.mkConst(realSort, "y"); - Term a = solver.mkConst(intSort, "a"); - Term b = solver.mkConst(intSort, "b"); - - // Our constraints regarding x and y will be: - // - // (1) 0 < x - // (2) 0 < y - // (3) x + y < 1 - // (4) x <= y - // - - // Formally, constraints are also terms. Their sort is Boolean. - // We will construct these constraints gradually, - // by defining each of their components. - // We start with the constant numerals 0 and 1: - Term zero = solver.mkReal(0); - Term one = solver.mkReal(1); - - // Next, we construct the term x + y - Term xPlusY = solver.mkTerm(Kind.PLUS, x, y); - - // Now we can define the constraints. - // They use the operators +, <=, and <. - // In the API, these are denoted by PLUS, LEQ, and LT. - // A list of available operators is available in: - // src/api/cpp/cvc5_kind.h - Term constraint1 = solver.mkTerm(Kind.LT, zero, x); - Term constraint2 = solver.mkTerm(Kind.LT, zero, y); - Term constraint3 = solver.mkTerm(Kind.LT, xPlusY, one); - Term constraint4 = solver.mkTerm(Kind.LEQ, x, y); - - // Now we assert the constraints to the solver. - solver.assertFormula(constraint1); - solver.assertFormula(constraint2); - solver.assertFormula(constraint3); - solver.assertFormula(constraint4); - - // Check if the formula is satisfiable, that is, - // are there real values for x and y that satisfy all the constraints? - Result r1 = solver.checkSat(); - - // The result is either SAT, UNSAT, or UNKNOWN. - // In this case, it is SAT. - System.out.println("expected: sat"); - System.out.println("result: " + r1); - - // We can get the values for x and y that satisfy the constraints. - Term xVal = solver.getValue(x); - Term yVal = solver.getValue(y); - - // It is also possible to get values for compound terms, - // even if those did not appear in the original formula. - Term xMinusY = solver.mkTerm(Kind.MINUS, x, y); - Term xMinusYVal = solver.getValue(xMinusY); - - // Further, we can convert the values to java types, - Pair<BigInteger, BigInteger> xRational = xVal.getRealValue(); - Pair<BigInteger, BigInteger> yRational = yVal.getRealValue(); - System.out.println("value for x: " + xRational.first + "/" + xRational.second); - System.out.println("value for y: " + yRational.first + "/" + yRational.second); - - // Next, we will check satisfiability of the same formula, - // only this time over integer variables a and b. - - // We start by resetting assertions added to the solver. - solver.resetAssertions(); - - // Next, we assert the same assertions above with integers. - // This time, we inline the construction of terms - // to the assertion command. - solver.assertFormula(solver.mkTerm(Kind.LT, solver.mkInteger(0), a)); - solver.assertFormula(solver.mkTerm(Kind.LT, solver.mkInteger(0), b)); - solver.assertFormula( - solver.mkTerm(Kind.LT, solver.mkTerm(Kind.PLUS, a, b), solver.mkInteger(1))); - solver.assertFormula(solver.mkTerm(Kind.LEQ, a, b)); - - // We check whether the revised assertion is satisfiable. - Result r2 = solver.checkSat(); - - // This time the formula is unsatisfiable - System.out.println("expected: unsat"); - System.out.println("result: " + r2); - - // We can query the solver for an unsatisfiable core, i.e., a subset - // of the assertions that is already unsatisfiable. - List<Term> unsatCore = Arrays.asList(solver.getUnsatCore()); - System.out.println("unsat core size: " + unsatCore.size()); - System.out.println("unsat core: "); - for (Term t : unsatCore) + try (Solver solver = new Solver()) { - System.out.println(t); + // We will ask the solver to produce models and unsat cores, + // hence these options should be turned on. + solver.setOption("produce-models", "true"); + solver.setOption("produce-unsat-cores", "true"); + + // The simplest way to set a logic for the solver is to choose "ALL". + // This enables all logics in the solver. + // Alternatively, "QF_ALL" enables all logics without quantifiers. + // To optimize the solver's behavior for a more specific logic, + // use the logic name, e.g. "QF_BV" or "QF_AUFBV". + + // Set the logic + solver.setLogic("ALL"); + + // In this example, we will define constraints over reals and integers. + // Hence, we first obtain the corresponding sorts. + Sort realSort = solver.getRealSort(); + Sort intSort = solver.getIntegerSort(); + + // x and y will be real variables, while a and b will be integer variables. + // Formally, their cpp type is Term, + // and they are called "constants" in SMT jargon: + Term x = solver.mkConst(realSort, "x"); + Term y = solver.mkConst(realSort, "y"); + Term a = solver.mkConst(intSort, "a"); + Term b = solver.mkConst(intSort, "b"); + + // Our constraints regarding x and y will be: + // + // (1) 0 < x + // (2) 0 < y + // (3) x + y < 1 + // (4) x <= y + // + + // Formally, constraints are also terms. Their sort is Boolean. + // We will construct these constraints gradually, + // by defining each of their components. + // We start with the constant numerals 0 and 1: + Term zero = solver.mkReal(0); + Term one = solver.mkReal(1); + + // Next, we construct the term x + y + Term xPlusY = solver.mkTerm(Kind.PLUS, x, y); + + // Now we can define the constraints. + // They use the operators +, <=, and <. + // In the API, these are denoted by PLUS, LEQ, and LT. + // A list of available operators is available in: + // src/api/cpp/cvc5_kind.h + Term constraint1 = solver.mkTerm(Kind.LT, zero, x); + Term constraint2 = solver.mkTerm(Kind.LT, zero, y); + Term constraint3 = solver.mkTerm(Kind.LT, xPlusY, one); + Term constraint4 = solver.mkTerm(Kind.LEQ, x, y); + + // Now we assert the constraints to the solver. + solver.assertFormula(constraint1); + solver.assertFormula(constraint2); + solver.assertFormula(constraint3); + solver.assertFormula(constraint4); + + // Check if the formula is satisfiable, that is, + // are there real values for x and y that satisfy all the constraints? + Result r1 = solver.checkSat(); + + // The result is either SAT, UNSAT, or UNKNOWN. + // In this case, it is SAT. + System.out.println("expected: sat"); + System.out.println("result: " + r1); + + // We can get the values for x and y that satisfy the constraints. + Term xVal = solver.getValue(x); + Term yVal = solver.getValue(y); + + // It is also possible to get values for compound terms, + // even if those did not appear in the original formula. + Term xMinusY = solver.mkTerm(Kind.MINUS, x, y); + Term xMinusYVal = solver.getValue(xMinusY); + + // Further, we can convert the values to java types, + Pair<BigInteger, BigInteger> xRational = xVal.getRealValue(); + Pair<BigInteger, BigInteger> yRational = yVal.getRealValue(); + System.out.println("value for x: " + xRational.first + "/" + xRational.second); + System.out.println("value for y: " + yRational.first + "/" + yRational.second); + + // Next, we will check satisfiability of the same formula, + // only this time over integer variables a and b. + + // We start by resetting assertions added to the solver. + solver.resetAssertions(); + + // Next, we assert the same assertions above with integers. + // This time, we inline the construction of terms + // to the assertion command. + solver.assertFormula(solver.mkTerm(Kind.LT, solver.mkInteger(0), a)); + solver.assertFormula(solver.mkTerm(Kind.LT, solver.mkInteger(0), b)); + solver.assertFormula( + solver.mkTerm(Kind.LT, solver.mkTerm(Kind.PLUS, a, b), solver.mkInteger(1))); + solver.assertFormula(solver.mkTerm(Kind.LEQ, a, b)); + + // We check whether the revised assertion is satisfiable. + Result r2 = solver.checkSat(); + + // This time the formula is unsatisfiable + System.out.println("expected: unsat"); + System.out.println("result: " + r2); + + // We can query the solver for an unsatisfiable core, i.e., a subset + // of the assertions that is already unsatisfiable. + List<Term> unsatCore = Arrays.asList(solver.getUnsatCore()); + System.out.println("unsat core size: " + unsatCore.size()); + System.out.println("unsat core: "); + for (Term t : unsatCore) + { + System.out.println(t); + } } } }
\ No newline at end of file diff --git a/examples/api/java/Relations.java b/examples/api/java/Relations.java index f6454c812..0d78562bb 100644 --- a/examples/api/java/Relations.java +++ b/examples/api/java/Relations.java @@ -69,129 +69,131 @@ public class Relations { public static void main(String[] args) throws CVC5ApiException { - Solver solver = new Solver(); - - // Set the logic - solver.setLogic("ALL"); - - // options - solver.setOption("produce-models", "true"); - solver.setOption("finite-model-find", "true"); - solver.setOption("sets-ext", "true"); - solver.setOption("output-language", "smt2"); - - // (declare-sort Person 0) - Sort personSort = solver.mkUninterpretedSort("Person"); - - // (Tuple Person) - Sort tupleArity1 = solver.mkTupleSort(new Sort[] {personSort}); - // (Set (Tuple Person)) - Sort relationArity1 = solver.mkSetSort(tupleArity1); - - // (Tuple Person Person) - Sort tupleArity2 = solver.mkTupleSort(new Sort[] {personSort, personSort}); - // (Set (Tuple Person Person)) - Sort relationArity2 = solver.mkSetSort(tupleArity2); - - // empty set - Term emptySetTerm = solver.mkEmptySet(relationArity1); - - // empty relation - Term emptyRelationTerm = solver.mkEmptySet(relationArity2); - - // universe set - Term universeSet = solver.mkUniverseSet(relationArity1); - - // variables - Term people = solver.mkConst(relationArity1, "people"); - Term males = solver.mkConst(relationArity1, "males"); - Term females = solver.mkConst(relationArity1, "females"); - Term father = solver.mkConst(relationArity2, "father"); - Term mother = solver.mkConst(relationArity2, "mother"); - Term parent = solver.mkConst(relationArity2, "parent"); - Term ancestor = solver.mkConst(relationArity2, "ancestor"); - Term descendant = solver.mkConst(relationArity2, "descendant"); - - Term isEmpty1 = solver.mkTerm(EQUAL, males, emptySetTerm); - Term isEmpty2 = solver.mkTerm(EQUAL, females, emptySetTerm); - - // (assert (= people (as univset (Set (Tuple Person))))) - Term peopleAreTheUniverse = solver.mkTerm(EQUAL, people, universeSet); - // (assert (not (= males (as emptyset (Set (Tuple Person)))))) - Term maleSetIsNotEmpty = solver.mkTerm(NOT, isEmpty1); - // (assert (not (= females (as emptyset (Set (Tuple Person)))))) - Term femaleSetIsNotEmpty = solver.mkTerm(NOT, isEmpty2); - - // (assert (= (intersection males females) (as emptyset (Set (Tuple - // Person))))) - Term malesFemalesIntersection = solver.mkTerm(INTERSECTION, males, females); - Term malesAndFemalesAreDisjoint = solver.mkTerm(EQUAL, malesFemalesIntersection, emptySetTerm); - - // (assert (not (= father (as emptyset (Set (Tuple Person Person)))))) - // (assert (not (= mother (as emptyset (Set (Tuple Person Person)))))) - Term isEmpty3 = solver.mkTerm(EQUAL, father, emptyRelationTerm); - Term isEmpty4 = solver.mkTerm(EQUAL, mother, emptyRelationTerm); - Term fatherIsNotEmpty = solver.mkTerm(NOT, isEmpty3); - Term motherIsNotEmpty = solver.mkTerm(NOT, isEmpty4); - - // fathers are males - // (assert (subset (join father people) males)) - Term fathers = solver.mkTerm(JOIN, father, people); - Term fathersAreMales = solver.mkTerm(SUBSET, fathers, males); - - // mothers are females - // (assert (subset (join mother people) females)) - Term mothers = solver.mkTerm(JOIN, mother, people); - Term mothersAreFemales = solver.mkTerm(SUBSET, mothers, females); - - // (assert (= parent (union father mother))) - Term unionFatherMother = solver.mkTerm(UNION, father, mother); - Term parentIsFatherOrMother = solver.mkTerm(EQUAL, parent, unionFatherMother); - - // (assert (= parent (union father mother))) - Term transitiveClosure = solver.mkTerm(TCLOSURE, parent); - Term descendantFormula = solver.mkTerm(EQUAL, descendant, transitiveClosure); - - // (assert (= parent (union father mother))) - Term transpose = solver.mkTerm(TRANSPOSE, descendant); - Term ancestorFormula = solver.mkTerm(EQUAL, ancestor, transpose); - - // (assert (forall ((x Person)) (not (member (mkTuple x x) ancestor)))) - Term x = solver.mkVar(personSort, "x"); - DatatypeConstructor constructor = tupleArity2.getDatatype().getConstructor(0); - Term xxTuple = solver.mkTerm(APPLY_CONSTRUCTOR, constructor.getConstructorTerm(), x, x); - Term member = solver.mkTerm(MEMBER, xxTuple, ancestor); - Term notMember = solver.mkTerm(NOT, member); - - Term quantifiedVariables = solver.mkTerm(BOUND_VAR_LIST, x); - Term noSelfAncestor = solver.mkTerm(FORALL, quantifiedVariables, notMember); - - // formulas - solver.assertFormula(peopleAreTheUniverse); - solver.assertFormula(maleSetIsNotEmpty); - solver.assertFormula(femaleSetIsNotEmpty); - solver.assertFormula(malesAndFemalesAreDisjoint); - solver.assertFormula(fatherIsNotEmpty); - solver.assertFormula(motherIsNotEmpty); - solver.assertFormula(fathersAreMales); - solver.assertFormula(mothersAreFemales); - solver.assertFormula(parentIsFatherOrMother); - solver.assertFormula(descendantFormula); - solver.assertFormula(ancestorFormula); - solver.assertFormula(noSelfAncestor); - - // check sat - Result result = solver.checkSat(); - - // output - System.out.println("Result = " + result); - System.out.println("people = " + solver.getValue(people)); - System.out.println("males = " + solver.getValue(males)); - System.out.println("females = " + solver.getValue(females)); - System.out.println("father = " + solver.getValue(father)); - System.out.println("mother = " + solver.getValue(mother)); - System.out.println("parent = " + solver.getValue(parent)); - System.out.println("descendant = " + solver.getValue(descendant)); - System.out.println("ancestor = " + solver.getValue(ancestor)); + try (Solver solver = new Solver()) + { + // Set the logic + solver.setLogic("ALL"); + + // options + solver.setOption("produce-models", "true"); + solver.setOption("finite-model-find", "true"); + solver.setOption("sets-ext", "true"); + solver.setOption("output-language", "smt2"); + + // (declare-sort Person 0) + Sort personSort = solver.mkUninterpretedSort("Person"); + + // (Tuple Person) + Sort tupleArity1 = solver.mkTupleSort(new Sort[] {personSort}); + // (Set (Tuple Person)) + Sort relationArity1 = solver.mkSetSort(tupleArity1); + + // (Tuple Person Person) + Sort tupleArity2 = solver.mkTupleSort(new Sort[] {personSort, personSort}); + // (Set (Tuple Person Person)) + Sort relationArity2 = solver.mkSetSort(tupleArity2); + + // empty set + Term emptySetTerm = solver.mkEmptySet(relationArity1); + + // empty relation + Term emptyRelationTerm = solver.mkEmptySet(relationArity2); + + // universe set + Term universeSet = solver.mkUniverseSet(relationArity1); + + // variables + Term people = solver.mkConst(relationArity1, "people"); + Term males = solver.mkConst(relationArity1, "males"); + Term females = solver.mkConst(relationArity1, "females"); + Term father = solver.mkConst(relationArity2, "father"); + Term mother = solver.mkConst(relationArity2, "mother"); + Term parent = solver.mkConst(relationArity2, "parent"); + Term ancestor = solver.mkConst(relationArity2, "ancestor"); + Term descendant = solver.mkConst(relationArity2, "descendant"); + + Term isEmpty1 = solver.mkTerm(EQUAL, males, emptySetTerm); + Term isEmpty2 = solver.mkTerm(EQUAL, females, emptySetTerm); + + // (assert (= people (as univset (Set (Tuple Person))))) + Term peopleAreTheUniverse = solver.mkTerm(EQUAL, people, universeSet); + // (assert (not (= males (as emptyset (Set (Tuple Person)))))) + Term maleSetIsNotEmpty = solver.mkTerm(NOT, isEmpty1); + // (assert (not (= females (as emptyset (Set (Tuple Person)))))) + Term femaleSetIsNotEmpty = solver.mkTerm(NOT, isEmpty2); + + // (assert (= (intersection males females) (as emptyset (Set (Tuple + // Person))))) + Term malesFemalesIntersection = solver.mkTerm(INTERSECTION, males, females); + Term malesAndFemalesAreDisjoint = + solver.mkTerm(EQUAL, malesFemalesIntersection, emptySetTerm); + + // (assert (not (= father (as emptyset (Set (Tuple Person Person)))))) + // (assert (not (= mother (as emptyset (Set (Tuple Person Person)))))) + Term isEmpty3 = solver.mkTerm(EQUAL, father, emptyRelationTerm); + Term isEmpty4 = solver.mkTerm(EQUAL, mother, emptyRelationTerm); + Term fatherIsNotEmpty = solver.mkTerm(NOT, isEmpty3); + Term motherIsNotEmpty = solver.mkTerm(NOT, isEmpty4); + + // fathers are males + // (assert (subset (join father people) males)) + Term fathers = solver.mkTerm(JOIN, father, people); + Term fathersAreMales = solver.mkTerm(SUBSET, fathers, males); + + // mothers are females + // (assert (subset (join mother people) females)) + Term mothers = solver.mkTerm(JOIN, mother, people); + Term mothersAreFemales = solver.mkTerm(SUBSET, mothers, females); + + // (assert (= parent (union father mother))) + Term unionFatherMother = solver.mkTerm(UNION, father, mother); + Term parentIsFatherOrMother = solver.mkTerm(EQUAL, parent, unionFatherMother); + + // (assert (= parent (union father mother))) + Term transitiveClosure = solver.mkTerm(TCLOSURE, parent); + Term descendantFormula = solver.mkTerm(EQUAL, descendant, transitiveClosure); + + // (assert (= parent (union father mother))) + Term transpose = solver.mkTerm(TRANSPOSE, descendant); + Term ancestorFormula = solver.mkTerm(EQUAL, ancestor, transpose); + + // (assert (forall ((x Person)) (not (member (mkTuple x x) ancestor)))) + Term x = solver.mkVar(personSort, "x"); + DatatypeConstructor constructor = tupleArity2.getDatatype().getConstructor(0); + Term xxTuple = solver.mkTerm(APPLY_CONSTRUCTOR, constructor.getConstructorTerm(), x, x); + Term member = solver.mkTerm(MEMBER, xxTuple, ancestor); + Term notMember = solver.mkTerm(NOT, member); + + Term quantifiedVariables = solver.mkTerm(BOUND_VAR_LIST, x); + Term noSelfAncestor = solver.mkTerm(FORALL, quantifiedVariables, notMember); + + // formulas + solver.assertFormula(peopleAreTheUniverse); + solver.assertFormula(maleSetIsNotEmpty); + solver.assertFormula(femaleSetIsNotEmpty); + solver.assertFormula(malesAndFemalesAreDisjoint); + solver.assertFormula(fatherIsNotEmpty); + solver.assertFormula(motherIsNotEmpty); + solver.assertFormula(fathersAreMales); + solver.assertFormula(mothersAreFemales); + solver.assertFormula(parentIsFatherOrMother); + solver.assertFormula(descendantFormula); + solver.assertFormula(ancestorFormula); + solver.assertFormula(noSelfAncestor); + + // check sat + Result result = solver.checkSat(); + + // output + System.out.println("Result = " + result); + System.out.println("people = " + solver.getValue(people)); + System.out.println("males = " + solver.getValue(males)); + System.out.println("females = " + solver.getValue(females)); + System.out.println("father = " + solver.getValue(father)); + System.out.println("mother = " + solver.getValue(mother)); + System.out.println("parent = " + solver.getValue(parent)); + System.out.println("descendant = " + solver.getValue(descendant)); + System.out.println("ancestor = " + solver.getValue(ancestor)); + } } } diff --git a/examples/api/java/Sequences.java b/examples/api/java/Sequences.java index d1bb0440d..0fd578984 100644 --- a/examples/api/java/Sequences.java +++ b/examples/api/java/Sequences.java @@ -21,48 +21,49 @@ public class Sequences { public static void main(String args[]) throws CVC5ApiException { - Solver slv = new Solver(); - - // Set the logic - slv.setLogic("QF_SLIA"); - // Produce models - slv.setOption("produce-models", "true"); - // The option strings-exp is needed - slv.setOption("strings-exp", "true"); - // Set output language to SMTLIB2 - slv.setOption("output-language", "smt2"); + try (Solver slv = new Solver()) + { + // Set the logic + slv.setLogic("QF_SLIA"); + // Produce models + slv.setOption("produce-models", "true"); + // The option strings-exp is needed + slv.setOption("strings-exp", "true"); + // Set output language to SMTLIB2 + slv.setOption("output-language", "smt2"); - // Sequence sort - Sort intSeq = slv.mkSequenceSort(slv.getIntegerSort()); + // Sequence sort + Sort intSeq = slv.mkSequenceSort(slv.getIntegerSort()); - // Sequence variables - Term x = slv.mkConst(intSeq, "x"); - Term y = slv.mkConst(intSeq, "y"); + // Sequence variables + Term x = slv.mkConst(intSeq, "x"); + Term y = slv.mkConst(intSeq, "y"); - // Empty sequence - Term empty = slv.mkEmptySequence(slv.getIntegerSort()); - // Sequence concatenation: x.y.empty - Term concat = slv.mkTerm(SEQ_CONCAT, x, y, empty); - // Sequence length: |x.y.empty| - Term concat_len = slv.mkTerm(SEQ_LENGTH, concat); - // |x.y.empty| > 1 - Term formula1 = slv.mkTerm(GT, concat_len, slv.mkInteger(1)); - // Sequence unit: seq(1) - Term unit = slv.mkTerm(SEQ_UNIT, slv.mkInteger(1)); - // x = seq(1) - Term formula2 = slv.mkTerm(EQUAL, x, unit); + // Empty sequence + Term empty = slv.mkEmptySequence(slv.getIntegerSort()); + // Sequence concatenation: x.y.empty + Term concat = slv.mkTerm(SEQ_CONCAT, x, y, empty); + // Sequence length: |x.y.empty| + Term concat_len = slv.mkTerm(SEQ_LENGTH, concat); + // |x.y.empty| > 1 + Term formula1 = slv.mkTerm(GT, concat_len, slv.mkInteger(1)); + // Sequence unit: seq(1) + Term unit = slv.mkTerm(SEQ_UNIT, slv.mkInteger(1)); + // x = seq(1) + Term formula2 = slv.mkTerm(EQUAL, x, unit); - // Make a query - Term q = slv.mkTerm(AND, formula1, formula2); + // Make a query + Term q = slv.mkTerm(AND, formula1, formula2); - // check sat - Result result = slv.checkSatAssuming(q); - System.out.println("cvc5 reports: " + q + " is " + result + "."); + // check sat + Result result = slv.checkSatAssuming(q); + System.out.println("cvc5 reports: " + q + " is " + result + "."); - if (result.isSat()) - { - System.out.println(" x = " + slv.getValue(x)); - System.out.println(" y = " + slv.getValue(y)); + if (result.isSat()) + { + System.out.println(" x = " + slv.getValue(x)); + System.out.println(" y = " + slv.getValue(y)); + } } } }
\ No newline at end of file diff --git a/examples/api/java/Sets.java b/examples/api/java/Sets.java index 602014c96..3edc49ae6 100644 --- a/examples/api/java/Sets.java +++ b/examples/api/java/Sets.java @@ -21,72 +21,73 @@ public class Sets { public static void main(String args[]) throws CVC5ApiException { - Solver slv = new Solver(); - - // Optionally, set the logic. We need at least UF for equality predicate, - // integers (LIA) and sets (FS). - slv.setLogic("QF_UFLIAFS"); + try (Solver slv = new Solver()) + { + // Optionally, set the logic. We need at least UF for equality predicate, + // integers (LIA) and sets (FS). + slv.setLogic("QF_UFLIAFS"); - // Produce models - slv.setOption("produce-models", "true"); - slv.setOption("output-language", "smt2"); + // Produce models + slv.setOption("produce-models", "true"); + slv.setOption("output-language", "smt2"); - Sort integer = slv.getIntegerSort(); - Sort set = slv.mkSetSort(integer); + Sort integer = slv.getIntegerSort(); + Sort set = slv.mkSetSort(integer); - // Verify union distributions over intersection - // (A union B) intersection C = (A intersection C) union (B intersection C) - { - Term A = slv.mkConst(set, "A"); - Term B = slv.mkConst(set, "B"); - Term C = slv.mkConst(set, "C"); + // Verify union distributions over intersection + // (A union B) intersection C = (A intersection C) union (B intersection C) + { + Term A = slv.mkConst(set, "A"); + Term B = slv.mkConst(set, "B"); + Term C = slv.mkConst(set, "C"); - Term unionAB = slv.mkTerm(UNION, A, B); - Term lhs = slv.mkTerm(INTERSECTION, unionAB, C); + Term unionAB = slv.mkTerm(UNION, A, B); + Term lhs = slv.mkTerm(INTERSECTION, unionAB, C); - Term intersectionAC = slv.mkTerm(INTERSECTION, A, C); - Term intersectionBC = slv.mkTerm(INTERSECTION, B, C); - Term rhs = slv.mkTerm(UNION, intersectionAC, intersectionBC); + Term intersectionAC = slv.mkTerm(INTERSECTION, A, C); + Term intersectionBC = slv.mkTerm(INTERSECTION, B, C); + Term rhs = slv.mkTerm(UNION, intersectionAC, intersectionBC); - Term theorem = slv.mkTerm(EQUAL, lhs, rhs); + Term theorem = slv.mkTerm(EQUAL, lhs, rhs); - System.out.println("cvc5 reports: " + theorem + " is " + slv.checkEntailed(theorem) + "."); - } + System.out.println("cvc5 reports: " + theorem + " is " + slv.checkEntailed(theorem) + "."); + } - // Verify emptset is a subset of any set - { - Term A = slv.mkConst(set, "A"); - Term emptyset = slv.mkEmptySet(set); + // Verify emptset is a subset of any set + { + Term A = slv.mkConst(set, "A"); + Term emptyset = slv.mkEmptySet(set); - Term theorem = slv.mkTerm(SUBSET, emptyset, A); + Term theorem = slv.mkTerm(SUBSET, emptyset, A); - System.out.println("cvc5 reports: " + theorem + " is " + slv.checkEntailed(theorem) + "."); - } + System.out.println("cvc5 reports: " + theorem + " is " + slv.checkEntailed(theorem) + "."); + } - // Find me an element in {1, 2} intersection {2, 3}, if there is one. - { - Term one = slv.mkInteger(1); - Term two = slv.mkInteger(2); - Term three = slv.mkInteger(3); + // Find me an element in {1, 2} intersection {2, 3}, if there is one. + { + Term one = slv.mkInteger(1); + Term two = slv.mkInteger(2); + Term three = slv.mkInteger(3); - Term singleton_one = slv.mkTerm(SINGLETON, one); - Term singleton_two = slv.mkTerm(SINGLETON, two); - Term singleton_three = slv.mkTerm(SINGLETON, three); - Term one_two = slv.mkTerm(UNION, singleton_one, singleton_two); - Term two_three = slv.mkTerm(UNION, singleton_two, singleton_three); - Term intersection = slv.mkTerm(INTERSECTION, one_two, two_three); + Term singleton_one = slv.mkTerm(SINGLETON, one); + Term singleton_two = slv.mkTerm(SINGLETON, two); + Term singleton_three = slv.mkTerm(SINGLETON, three); + Term one_two = slv.mkTerm(UNION, singleton_one, singleton_two); + Term two_three = slv.mkTerm(UNION, singleton_two, singleton_three); + Term intersection = slv.mkTerm(INTERSECTION, one_two, two_three); - Term x = slv.mkConst(integer, "x"); + Term x = slv.mkConst(integer, "x"); - Term e = slv.mkTerm(MEMBER, x, intersection); + Term e = slv.mkTerm(MEMBER, x, intersection); - Result result = slv.checkSatAssuming(e); - System.out.println("cvc5 reports: " + e + " is " + result + "."); + Result result = slv.checkSatAssuming(e); + System.out.println("cvc5 reports: " + e + " is " + result + "."); - if (result.isSat()) - { - System.out.println("For instance, " + slv.getValue(x) + " is a member."); + if (result.isSat()) + { + System.out.println("For instance, " + slv.getValue(x) + " is a member."); + } } } } -}
\ No newline at end of file +} diff --git a/examples/api/java/Statistics.java b/examples/api/java/Statistics.java index e524eb3e3..751dda947 100644 --- a/examples/api/java/Statistics.java +++ b/examples/api/java/Statistics.java @@ -23,43 +23,45 @@ public class Statistics { public static void main(String[] args) { - Solver solver = getSolver(); - // Get the statistics from the `Solver` and iterate over them. The - // `Statistics` class implements the `Iterable<Pair<String, Stat>>` interface. - io.github.cvc5.api.Statistics stats = solver.getStatistics(); - // short version - System.out.println("Short version:"); - System.out.println(stats); + try (Solver solver = new Solver()) + { + // Get the statistics from the `Solver` and iterate over them. The + // `Statistics` class implements the `Iterable<Pair<String, Stat>>` interface. + io.github.cvc5.api.Statistics stats = solver.getStatistics(); + // short version + System.out.println("Short version:"); + System.out.println(stats); - System.out.println("-------------------------------------------------------"); + System.out.println("-------------------------------------------------------"); - System.out.println("Long version:"); + System.out.println("Long version:"); - // long version - for (Pair<String, Stat> pair : stats) - { - Stat stat = pair.second; - if (stat.isInt()) - { - System.out.println(pair.first + " = " + stat.getInt()); - } - else if (stat.isDouble()) - { - System.out.println(pair.first + " = " + stat.getDouble()); - } - else if (stat.isString()) - { - System.out.println(pair.first + " = " + stat.getString()); - } - else if (stat.isHistogram()) + // long version + for (Pair<String, Stat> pair : stats) { - System.out.println("-------------------------------------------------------"); - System.out.println(pair.first + " : Map"); - for (Map.Entry<String, Long> entry : stat.getHistogram().entrySet()) + Stat stat = pair.second; + if (stat.isInt()) + { + System.out.println(pair.first + " = " + stat.getInt()); + } + else if (stat.isDouble()) + { + System.out.println(pair.first + " = " + stat.getDouble()); + } + else if (stat.isString()) + { + System.out.println(pair.first + " = " + stat.getString()); + } + else if (stat.isHistogram()) { - System.out.println(entry.getKey() + " = " + entry.getValue()); + System.out.println("-------------------------------------------------------"); + System.out.println(pair.first + " : Map"); + for (Map.Entry<String, Long> entry : stat.getHistogram().entrySet()) + { + System.out.println(entry.getKey() + " = " + entry.getValue()); + } + System.out.println("-------------------------------------------------------"); } - System.out.println("-------------------------------------------------------"); } } } diff --git a/examples/api/java/Strings.java b/examples/api/java/Strings.java index 6cc152159..28487b852 100644 --- a/examples/api/java/Strings.java +++ b/examples/api/java/Strings.java @@ -21,71 +21,73 @@ public class Strings { public static void main(String args[]) throws CVC5ApiException { - Solver slv = new Solver(); - - // Set the logic - slv.setLogic("QF_SLIA"); - // Produce models - slv.setOption("produce-models", "true"); - // The option strings-exp is needed - slv.setOption("strings-exp", "true"); - // Set output language to SMTLIB2 - slv.setOption("output-language", "smt2"); + try (Solver slv = new Solver()) + { + // Set the logic + slv.setLogic("QF_SLIA"); + // Produce models + slv.setOption("produce-models", "true"); + // The option strings-exp is needed + slv.setOption("strings-exp", "true"); + // Set output language to SMTLIB2 + slv.setOption("output-language", "smt2"); - // String type - Sort string = slv.getStringSort(); + // String type + Sort string = slv.getStringSort(); - // std::string - String str_ab = "ab"; - // String constants - Term ab = slv.mkString(str_ab); - Term abc = slv.mkString("abc"); - // String variables - Term x = slv.mkConst(string, "x"); - Term y = slv.mkConst(string, "y"); - Term z = slv.mkConst(string, "z"); + // std::string + String str_ab = "ab"; + // String constants + Term ab = slv.mkString(str_ab); + Term abc = slv.mkString("abc"); + // String variables + Term x = slv.mkConst(string, "x"); + Term y = slv.mkConst(string, "y"); + Term z = slv.mkConst(string, "z"); - // String concatenation: x.ab.y - Term lhs = slv.mkTerm(STRING_CONCAT, x, ab, y); - // String concatenation: abc.z - Term rhs = slv.mkTerm(STRING_CONCAT, abc, z); - // x.ab.y = abc.z - Term formula1 = slv.mkTerm(EQUAL, lhs, rhs); + // String concatenation: x.ab.y + Term lhs = slv.mkTerm(STRING_CONCAT, x, ab, y); + // String concatenation: abc.z + Term rhs = slv.mkTerm(STRING_CONCAT, abc, z); + // x.ab.y = abc.z + Term formula1 = slv.mkTerm(EQUAL, lhs, rhs); - // Length of y: |y| - Term leny = slv.mkTerm(STRING_LENGTH, y); - // |y| >= 0 - Term formula2 = slv.mkTerm(GEQ, leny, slv.mkInteger(0)); + // Length of y: |y| + Term leny = slv.mkTerm(STRING_LENGTH, y); + // |y| >= 0 + Term formula2 = slv.mkTerm(GEQ, leny, slv.mkInteger(0)); - // Regular expression: (ab[c-e]*f)|g|h - Term r = slv.mkTerm(REGEXP_UNION, - slv.mkTerm(REGEXP_CONCAT, - slv.mkTerm(STRING_TO_REGEXP, slv.mkString("ab")), - slv.mkTerm(REGEXP_STAR, slv.mkTerm(REGEXP_RANGE, slv.mkString("c"), slv.mkString("e"))), - slv.mkTerm(STRING_TO_REGEXP, slv.mkString("f"))), - slv.mkTerm(STRING_TO_REGEXP, slv.mkString("g")), - slv.mkTerm(STRING_TO_REGEXP, slv.mkString("h"))); + // Regular expression: (ab[c-e]*f)|g|h + Term r = slv.mkTerm(REGEXP_UNION, + slv.mkTerm(REGEXP_CONCAT, + slv.mkTerm(STRING_TO_REGEXP, slv.mkString("ab")), + slv.mkTerm( + REGEXP_STAR, slv.mkTerm(REGEXP_RANGE, slv.mkString("c"), slv.mkString("e"))), + slv.mkTerm(STRING_TO_REGEXP, slv.mkString("f"))), + slv.mkTerm(STRING_TO_REGEXP, slv.mkString("g")), + slv.mkTerm(STRING_TO_REGEXP, slv.mkString("h"))); - // String variables - Term s1 = slv.mkConst(string, "s1"); - Term s2 = slv.mkConst(string, "s2"); - // String concatenation: s1.s2 - Term s = slv.mkTerm(STRING_CONCAT, s1, s2); + // String variables + Term s1 = slv.mkConst(string, "s1"); + Term s2 = slv.mkConst(string, "s2"); + // String concatenation: s1.s2 + Term s = slv.mkTerm(STRING_CONCAT, s1, s2); - // s1.s2 in (ab[c-e]*f)|g|h - Term formula3 = slv.mkTerm(STRING_IN_REGEXP, s, r); + // s1.s2 in (ab[c-e]*f)|g|h + Term formula3 = slv.mkTerm(STRING_IN_REGEXP, s, r); - // Make a query - Term q = slv.mkTerm(AND, formula1, formula2, formula3); + // Make a query + Term q = slv.mkTerm(AND, formula1, formula2, formula3); - // check sat - Result result = slv.checkSatAssuming(q); - System.out.println("cvc5 reports: " + q + " is " + result + "."); + // check sat + Result result = slv.checkSatAssuming(q); + System.out.println("cvc5 reports: " + q + " is " + result + "."); - if (result.isSat()) - { - System.out.println(" x = " + slv.getValue(x)); - System.out.println(" s1.s2 = " + slv.getValue(s)); + if (result.isSat()) + { + System.out.println(" x = " + slv.getValue(x)); + System.out.println(" s1.s2 = " + slv.getValue(s)); + } } } -}
\ No newline at end of file +} diff --git a/examples/api/java/SygusFun.java b/examples/api/java/SygusFun.java index 8b96dff50..bc1d7e6b1 100644 --- a/examples/api/java/SygusFun.java +++ b/examples/api/java/SygusFun.java @@ -56,84 +56,85 @@ public class SygusFun { public static void main(String args[]) throws CVC5ApiException { - Solver slv = new Solver(); - - // required options - slv.setOption("lang", "sygus2"); - slv.setOption("incremental", "false"); - - // set the logic - slv.setLogic("LIA"); - - Sort integer = slv.getIntegerSort(); - Sort bool = slv.getBooleanSort(); - - // declare input variables for the functions-to-synthesize - Term x = slv.mkVar(integer, "x"); - Term y = slv.mkVar(integer, "y"); - - // declare the grammar non-terminals - Term start = slv.mkVar(integer, "Start"); - Term start_bool = slv.mkVar(bool, "StartBool"); - - // define the rules - Term zero = slv.mkInteger(0); - Term one = slv.mkInteger(1); - - Term plus = slv.mkTerm(PLUS, start, start); - Term minus = slv.mkTerm(MINUS, start, start); - Term ite = slv.mkTerm(ITE, start_bool, start, start); - - Term And = slv.mkTerm(AND, start_bool, start_bool); - Term Not = slv.mkTerm(NOT, start_bool); - Term leq = slv.mkTerm(LEQ, start, start); - - // create the grammar object - Grammar g = slv.mkSygusGrammar(new Term[] {x, y}, new Term[] {start, start_bool}); - - // bind each non-terminal to its rules - g.addRules(start, new Term[] {zero, one, x, y, plus, minus, ite}); - g.addRules(start_bool, new Term[] {And, Not, leq}); - - // declare the functions-to-synthesize. Optionally, provide the grammar - // constraints - Term max = slv.synthFun("max", new Term[] {x, y}, integer, g); - Term min = slv.synthFun("min", new Term[] {x, y}, integer); - - // declare universal variables. - Term varX = slv.mkSygusVar(integer, "x"); - Term varY = slv.mkSygusVar(integer, "y"); - - Term max_x_y = slv.mkTerm(APPLY_UF, max, varX, varY); - Term min_x_y = slv.mkTerm(APPLY_UF, min, varX, varY); - - // add semantic constraints - // (constraint (>= (max x y) x)) - slv.addSygusConstraint(slv.mkTerm(GEQ, max_x_y, varX)); - - // (constraint (>= (max x y) y)) - slv.addSygusConstraint(slv.mkTerm(GEQ, max_x_y, varY)); - - // (constraint (or (= x (max x y)) - // (= y (max x y)))) - slv.addSygusConstraint( - slv.mkTerm(OR, slv.mkTerm(EQUAL, max_x_y, varX), slv.mkTerm(EQUAL, max_x_y, varY))); - - // (constraint (= (+ (max x y) (min x y)) - // (+ x y))) - slv.addSygusConstraint( - slv.mkTerm(EQUAL, slv.mkTerm(PLUS, max_x_y, min_x_y), slv.mkTerm(PLUS, varX, varY))); - - // print solutions if available - if (slv.checkSynth().isUnsat()) + try (Solver slv = new Solver()) { - // Output should be equivalent to: - // ( - // (define-fun max ((x Int) (y Int)) Int (ite (<= x y) y x)) - // (define-fun min ((x Int) (y Int)) Int (ite (<= x y) x y)) - // ) - Term[] terms = new Term[] {max, min}; - Utils.printSynthSolutions(terms, slv.getSynthSolutions(terms)); + // required options + slv.setOption("lang", "sygus2"); + slv.setOption("incremental", "false"); + + // set the logic + slv.setLogic("LIA"); + + Sort integer = slv.getIntegerSort(); + Sort bool = slv.getBooleanSort(); + + // declare input variables for the functions-to-synthesize + Term x = slv.mkVar(integer, "x"); + Term y = slv.mkVar(integer, "y"); + + // declare the grammar non-terminals + Term start = slv.mkVar(integer, "Start"); + Term start_bool = slv.mkVar(bool, "StartBool"); + + // define the rules + Term zero = slv.mkInteger(0); + Term one = slv.mkInteger(1); + + Term plus = slv.mkTerm(PLUS, start, start); + Term minus = slv.mkTerm(MINUS, start, start); + Term ite = slv.mkTerm(ITE, start_bool, start, start); + + Term And = slv.mkTerm(AND, start_bool, start_bool); + Term Not = slv.mkTerm(NOT, start_bool); + Term leq = slv.mkTerm(LEQ, start, start); + + // create the grammar object + Grammar g = slv.mkSygusGrammar(new Term[] {x, y}, new Term[] {start, start_bool}); + + // bind each non-terminal to its rules + g.addRules(start, new Term[] {zero, one, x, y, plus, minus, ite}); + g.addRules(start_bool, new Term[] {And, Not, leq}); + + // declare the functions-to-synthesize. Optionally, provide the grammar + // constraints + Term max = slv.synthFun("max", new Term[] {x, y}, integer, g); + Term min = slv.synthFun("min", new Term[] {x, y}, integer); + + // declare universal variables. + Term varX = slv.mkSygusVar(integer, "x"); + Term varY = slv.mkSygusVar(integer, "y"); + + Term max_x_y = slv.mkTerm(APPLY_UF, max, varX, varY); + Term min_x_y = slv.mkTerm(APPLY_UF, min, varX, varY); + + // add semantic constraints + // (constraint (>= (max x y) x)) + slv.addSygusConstraint(slv.mkTerm(GEQ, max_x_y, varX)); + + // (constraint (>= (max x y) y)) + slv.addSygusConstraint(slv.mkTerm(GEQ, max_x_y, varY)); + + // (constraint (or (= x (max x y)) + // (= y (max x y)))) + slv.addSygusConstraint( + slv.mkTerm(OR, slv.mkTerm(EQUAL, max_x_y, varX), slv.mkTerm(EQUAL, max_x_y, varY))); + + // (constraint (= (+ (max x y) (min x y)) + // (+ x y))) + slv.addSygusConstraint( + slv.mkTerm(EQUAL, slv.mkTerm(PLUS, max_x_y, min_x_y), slv.mkTerm(PLUS, varX, varY))); + + // print solutions if available + if (slv.checkSynth().isUnsat()) + { + // Output should be equivalent to: + // ( + // (define-fun max ((x Int) (y Int)) Int (ite (<= x y) y x)) + // (define-fun min ((x Int) (y Int)) Int (ite (<= x y) x y)) + // ) + Term[] terms = new Term[] {max, min}; + Utils.printSynthSolutions(terms, slv.getSynthSolutions(terms)); + } } } -}
\ No newline at end of file +} diff --git a/examples/api/java/SygusGrammar.java b/examples/api/java/SygusGrammar.java index fb079d49f..230229fdd 100644 --- a/examples/api/java/SygusGrammar.java +++ b/examples/api/java/SygusGrammar.java @@ -53,77 +53,78 @@ public class SygusGrammar { public static void main(String args[]) throws CVC5ApiException { - Solver slv = new Solver(); - - // required options - slv.setOption("lang", "sygus2"); - slv.setOption("incremental", "false"); + try (Solver slv = new Solver()) + { + // required options + slv.setOption("lang", "sygus2"); + slv.setOption("incremental", "false"); - // set the logic - slv.setLogic("LIA"); + // set the logic + slv.setLogic("LIA"); - Sort integer = slv.getIntegerSort(); - Sort bool = slv.getBooleanSort(); + Sort integer = slv.getIntegerSort(); + Sort bool = slv.getBooleanSort(); - // declare input variable for the function-to-synthesize - Term x = slv.mkVar(integer, "x"); + // declare input variable for the function-to-synthesize + Term x = slv.mkVar(integer, "x"); - // declare the grammar non-terminal - Term start = slv.mkVar(integer, "Start"); + // declare the grammar non-terminal + Term start = slv.mkVar(integer, "Start"); - // define the rules - Term zero = slv.mkInteger(0); - Term neg_x = slv.mkTerm(UMINUS, x); - Term plus = slv.mkTerm(PLUS, x, start); + // define the rules + Term zero = slv.mkInteger(0); + Term neg_x = slv.mkTerm(UMINUS, x); + Term plus = slv.mkTerm(PLUS, x, start); - // create the grammar object - Grammar g1 = slv.mkSygusGrammar(new Term[] {x}, new Term[] {start}); + // create the grammar object + Grammar g1 = slv.mkSygusGrammar(new Term[] {x}, new Term[] {start}); - // bind each non-terminal to its rules - g1.addRules(start, new Term[] {neg_x, plus}); + // bind each non-terminal to its rules + g1.addRules(start, new Term[] {neg_x, plus}); - // copy the first grammar with all of its non-terminals and their rules - Grammar g2 = new Grammar(g1); - Grammar g3 = new Grammar(g1); + // copy the first grammar with all of its non-terminals and their rules + Grammar g2 = new Grammar(g1); + Grammar g3 = new Grammar(g1); - // add parameters as rules for the start symbol. Similar to "(Variable Int)" - g2.addAnyVariable(start); + // add parameters as rules for the start symbol. Similar to "(Variable Int)" + g2.addAnyVariable(start); - // declare the functions-to-synthesize - Term id1 = slv.synthFun("id1", new Term[] {x}, integer, g1); - Term id2 = slv.synthFun("id2", new Term[] {x}, integer, g2); + // declare the functions-to-synthesize + Term id1 = slv.synthFun("id1", new Term[] {x}, integer, g1); + Term id2 = slv.synthFun("id2", new Term[] {x}, integer, g2); - g3.addRule(start, zero); + g3.addRule(start, zero); - Term id3 = slv.synthFun("id3", new Term[] {x}, integer, g3); + Term id3 = slv.synthFun("id3", new Term[] {x}, integer, g3); - // g1 is reusable as long as it remains unmodified after first use - Term id4 = slv.synthFun("id4", new Term[] {x}, integer, g1); + // g1 is reusable as long as it remains unmodified after first use + Term id4 = slv.synthFun("id4", new Term[] {x}, integer, g1); - // declare universal variables. - Term varX = slv.mkSygusVar(integer, "x"); + // declare universal variables. + Term varX = slv.mkSygusVar(integer, "x"); - Term id1_x = slv.mkTerm(APPLY_UF, id1, varX); - Term id2_x = slv.mkTerm(APPLY_UF, id2, varX); - Term id3_x = slv.mkTerm(APPLY_UF, id3, varX); - Term id4_x = slv.mkTerm(APPLY_UF, id4, varX); + Term id1_x = slv.mkTerm(APPLY_UF, id1, varX); + Term id2_x = slv.mkTerm(APPLY_UF, id2, varX); + Term id3_x = slv.mkTerm(APPLY_UF, id3, varX); + Term id4_x = slv.mkTerm(APPLY_UF, id4, varX); - // add semantic constraints - // (constraint (= (id1 x) (id2 x) (id3 x) (id4 x) x)) - slv.addSygusConstraint(slv.mkTerm(EQUAL, new Term[] {id1_x, id2_x, id3_x, id4_x, varX})); + // add semantic constraints + // (constraint (= (id1 x) (id2 x) (id3 x) (id4 x) x)) + slv.addSygusConstraint(slv.mkTerm(EQUAL, new Term[] {id1_x, id2_x, id3_x, id4_x, varX})); - // print solutions if available - if (slv.checkSynth().isUnsat()) - { - // Output should be equivalent to: - // ( - // (define-fun id1 ((x Int)) Int (+ x (+ x (- x)))) - // (define-fun id2 ((x Int)) Int x) - // (define-fun id3 ((x Int)) Int (+ x 0)) - // (define-fun id4 ((x Int)) Int (+ x (+ x (- x)))) - // ) - Term[] terms = new Term[] {id1, id2, id3, id4}; - Utils.printSynthSolutions(terms, slv.getSynthSolutions(terms)); + // print solutions if available + if (slv.checkSynth().isUnsat()) + { + // Output should be equivalent to: + // ( + // (define-fun id1 ((x Int)) Int (+ x (+ x (- x)))) + // (define-fun id2 ((x Int)) Int x) + // (define-fun id3 ((x Int)) Int (+ x 0)) + // (define-fun id4 ((x Int)) Int (+ x (+ x (- x)))) + // ) + Term[] terms = new Term[] {id1, id2, id3, id4}; + Utils.printSynthSolutions(terms, slv.getSynthSolutions(terms)); + } } } -}
\ No newline at end of file +} diff --git a/examples/api/java/SygusInv.java b/examples/api/java/SygusInv.java index 6c66c910b..be1311318 100644 --- a/examples/api/java/SygusInv.java +++ b/examples/api/java/SygusInv.java @@ -44,51 +44,52 @@ public class SygusInv { public static void main(String args[]) throws CVC5ApiException { - Solver slv = new Solver(); - - // required options - slv.setOption("lang", "sygus2"); - slv.setOption("incremental", "false"); + try (Solver slv = new Solver()) + { + // required options + slv.setOption("lang", "sygus2"); + slv.setOption("incremental", "false"); - // set the logic - slv.setLogic("LIA"); + // set the logic + slv.setLogic("LIA"); - Sort integer = slv.getIntegerSort(); - Sort bool = slv.getBooleanSort(); + Sort integer = slv.getIntegerSort(); + Sort bool = slv.getBooleanSort(); - Term zero = slv.mkInteger(0); - Term one = slv.mkInteger(1); - Term ten = slv.mkInteger(10); + Term zero = slv.mkInteger(0); + Term one = slv.mkInteger(1); + Term ten = slv.mkInteger(10); - // declare input variables for functions - Term x = slv.mkVar(integer, "x"); - Term xp = slv.mkVar(integer, "xp"); + // declare input variables for functions + Term x = slv.mkVar(integer, "x"); + Term xp = slv.mkVar(integer, "xp"); - // (ite (< x 10) (= xp (+ x 1)) (= xp x)) - Term ite = slv.mkTerm(ITE, - slv.mkTerm(LT, x, ten), - slv.mkTerm(EQUAL, xp, slv.mkTerm(PLUS, x, one)), - slv.mkTerm(EQUAL, xp, x)); + // (ite (< x 10) (= xp (+ x 1)) (= xp x)) + Term ite = slv.mkTerm(ITE, + slv.mkTerm(LT, x, ten), + slv.mkTerm(EQUAL, xp, slv.mkTerm(PLUS, x, one)), + slv.mkTerm(EQUAL, xp, x)); - // define the pre-conditions, transition relations, and post-conditions - Term pre_f = slv.defineFun("pre-f", new Term[] {x}, bool, slv.mkTerm(EQUAL, x, zero)); - Term trans_f = slv.defineFun("trans-f", new Term[] {x, xp}, bool, ite); - Term post_f = slv.defineFun("post-f", new Term[] {x}, bool, slv.mkTerm(LEQ, x, ten)); + // define the pre-conditions, transition relations, and post-conditions + Term pre_f = slv.defineFun("pre-f", new Term[] {x}, bool, slv.mkTerm(EQUAL, x, zero)); + Term trans_f = slv.defineFun("trans-f", new Term[] {x, xp}, bool, ite); + Term post_f = slv.defineFun("post-f", new Term[] {x}, bool, slv.mkTerm(LEQ, x, ten)); - // declare the invariant-to-synthesize - Term inv_f = slv.synthInv("inv-f", new Term[] {x}); + // declare the invariant-to-synthesize + Term inv_f = slv.synthInv("inv-f", new Term[] {x}); - slv.addSygusInvConstraint(inv_f, pre_f, trans_f, post_f); + slv.addSygusInvConstraint(inv_f, pre_f, trans_f, post_f); - // print solutions if available - if (slv.checkSynth().isUnsat()) - { - // Output should be equivalent to: - // ( - // (define-fun inv-f ((x Int)) Bool (not (>= x 11))) - // ) - Term[] terms = new Term[] {inv_f}; - Utils.printSynthSolutions(terms, slv.getSynthSolutions(terms)); + // print solutions if available + if (slv.checkSynth().isUnsat()) + { + // Output should be equivalent to: + // ( + // (define-fun inv-f ((x Int)) Bool (not (>= x 11))) + // ) + Term[] terms = new Term[] {inv_f}; + Utils.printSynthSolutions(terms, slv.getSynthSolutions(terms)); + } } } -}
\ No newline at end of file +} diff --git a/examples/api/java/Transcendentals.java b/examples/api/java/Transcendentals.java index 026f9b826..a44a1e4c0 100644 --- a/examples/api/java/Transcendentals.java +++ b/examples/api/java/Transcendentals.java @@ -21,32 +21,34 @@ public class Transcendentals { public static void main(String args[]) throws CVC5ApiException { - Solver slv = new Solver(); - slv.setLogic("QF_NRAT"); - - Sort real = slv.getRealSort(); - - // Variables - Term x = slv.mkConst(real, "x"); - Term y = slv.mkConst(real, "y"); - - // Helper terms - Term two = slv.mkReal(2); - Term pi = slv.mkPi(); - Term twopi = slv.mkTerm(MULT, two, pi); - Term ysq = slv.mkTerm(MULT, y, y); - Term sinx = slv.mkTerm(SINE, x); - - // Formulas - Term x_gt_pi = slv.mkTerm(GT, x, pi); - Term x_lt_tpi = slv.mkTerm(LT, x, twopi); - Term ysq_lt_sinx = slv.mkTerm(LT, ysq, sinx); - - slv.assertFormula(x_gt_pi); - slv.assertFormula(x_lt_tpi); - slv.assertFormula(ysq_lt_sinx); - - System.out.println("cvc5 should report UNSAT."); - System.out.println("Result from cvc5 is: " + slv.checkSat()); + try (Solver slv = new Solver()) + { + slv.setLogic("QF_NRAT"); + + Sort real = slv.getRealSort(); + + // Variables + Term x = slv.mkConst(real, "x"); + Term y = slv.mkConst(real, "y"); + + // Helper terms + Term two = slv.mkReal(2); + Term pi = slv.mkPi(); + Term twopi = slv.mkTerm(MULT, two, pi); + Term ysq = slv.mkTerm(MULT, y, y); + Term sinx = slv.mkTerm(SINE, x); + + // Formulas + Term x_gt_pi = slv.mkTerm(GT, x, pi); + Term x_lt_tpi = slv.mkTerm(LT, x, twopi); + Term ysq_lt_sinx = slv.mkTerm(LT, ysq, sinx); + + slv.assertFormula(x_gt_pi); + slv.assertFormula(x_lt_tpi); + slv.assertFormula(ysq_lt_sinx); + + System.out.println("cvc5 should report UNSAT."); + System.out.println("Result from cvc5 is: " + slv.checkSat()); + } } -}
\ No newline at end of file +} diff --git a/examples/api/java/UnsatCores.java b/examples/api/java/UnsatCores.java index cefa90290..feec35dbd 100644 --- a/examples/api/java/UnsatCores.java +++ b/examples/api/java/UnsatCores.java @@ -20,33 +20,34 @@ public class UnsatCores { public static void main(String[] args) throws CVC5ApiException { - Solver solver = new Solver(); - - // Enable the production of unsat cores - solver.setOption("produce-unsat-cores", "true"); + try (Solver solver = new Solver()) + { + // Enable the production of unsat cores + solver.setOption("produce-unsat-cores", "true"); - Sort boolSort = solver.getBooleanSort(); - Term a = solver.mkConst(boolSort, "A"); - Term b = solver.mkConst(boolSort, "B"); + Sort boolSort = solver.getBooleanSort(); + Term a = solver.mkConst(boolSort, "A"); + Term b = solver.mkConst(boolSort, "B"); - // A ^ B - solver.assertFormula(solver.mkTerm(Kind.AND, a, b)); - // ~(A v B) - solver.assertFormula(solver.mkTerm(Kind.NOT, solver.mkTerm(Kind.OR, a, b))); + // A ^ B + solver.assertFormula(solver.mkTerm(Kind.AND, a, b)); + // ~(A v B) + solver.assertFormula(solver.mkTerm(Kind.NOT, solver.mkTerm(Kind.OR, a, b))); - Result res = solver.checkSat(); // result is unsat + Result res = solver.checkSat(); // result is unsat - // Retrieve the unsat core - Term[] unsatCore = solver.getUnsatCore(); + // Retrieve the unsat core + Term[] unsatCore = solver.getUnsatCore(); - // Print the unsat core - System.out.println("Unsat Core: " + Arrays.asList(unsatCore)); + // Print the unsat core + System.out.println("Unsat Core: " + Arrays.asList(unsatCore)); - // Iterate over expressions in the unsat core. - System.out.println("--- Unsat Core ---"); - for (Term e : unsatCore) - { - System.out.println(e); + // Iterate over expressions in the unsat core. + System.out.println("--- Unsat Core ---"); + for (Term e : unsatCore) + { + System.out.println(e); + } } } } diff --git a/examples/api/python/sygus-inv.py b/examples/api/python/sygus-inv.py index 8273aa298..50fa3f04f 100644 --- a/examples/api/python/sygus-inv.py +++ b/examples/api/python/sygus-inv.py @@ -48,9 +48,9 @@ if __name__ == "__main__": slv.mkTerm(kinds.Equal, xp, x)) # define the pre-conditions, transition relations, and post-conditions - pre_f = slv.defineFun("pre-f", {x}, boolean, slv.mkTerm(kinds.Equal, x, zero)) - trans_f = slv.defineFun("trans-f", {x, xp}, boolean, ite) - post_f = slv.defineFun("post-f", {x}, boolean, slv.mkTerm(kinds.Leq, x, ten)) + pre_f = slv.defineFun("pre-f", [x], boolean, slv.mkTerm(kinds.Equal, x, zero)) + trans_f = slv.defineFun("trans-f", [x, xp], boolean, ite) + post_f = slv.defineFun("post-f", [x], boolean, slv.mkTerm(kinds.Leq, x, ten)) # declare the invariant-to-synthesize inv_f = slv.synthInv("inv-f", {x}) diff --git a/proofs/lfsc/signatures/arith_programs.plf b/proofs/lfsc/signatures/arith_programs.plf new file mode 100644 index 000000000..219bbe326 --- /dev/null +++ b/proofs/lfsc/signatures/arith_programs.plf @@ -0,0 +1,80 @@ +; depends: theory_def.plf + +; get the relation symbol from f, for example for (a.>= t1 t2), return a.>= +(program sc_arith_get_rel ((f term)) term + (match f ((apply f1 f2) (match f1 ((apply f11 f12) f11))))) + +; get the left hand side of a relation, for example for (a.>= t1 t2), return t1 +(program sc_arith_get_lhs ((f term)) term + (match f ((apply f1 f2) (match f1 ((apply f11 f12) f12))))) + +; get the right hand side of a relation, for example for (a.>= t1 t2), return t2 +(program sc_arith_get_rhs ((f term)) term + (match f ((apply f1 f2) (match f1 ((apply f11 f12) f2))))) + +; Get the relation entailed by summing two arithmetic relations. +; This side condition handles lower bounds only. +; Note that = summed with = is <= to match internal calculus, although it could +; be =. +(program sc_arith_sum_rels ((r1 term) (r2 term)) term + (match r1 + (f_a.< f_a.<) + (default + (match r2 + (f_a.< f_a.<) + (f_a.<= f_a.<=) + (f_= f_a.<=))))) + +; Get the inverse relation for r, i.e. flips left and right hand side. +(program sc_arith_rel_inv ((r term)) term + (match r + (f_= f_=) + (f_a.< f_a.>) + (f_a.> f_a.<) + (f_a.<= f_a.>=) + (f_a.>= f_a.<=))) + +; Get the negated relation for r, i.e. is equivalent to negating the relation. +(program sc_arith_rel_neg ((r term)) term + (match r + (f_a.< f_a.>=) + (f_a.> f_a.<=) + (f_a.<= f_a.>) + (f_a.>= f_a.<))) + +; A helper for computing the conclusion relation used in the rule +; PfRule::ARITH_TRICHOTOMY. For relations r1 and r2, this returns the +; third possibility for the relationship between two arithmetic terms. +(program sc_arith_rel_trichotomy ((r1 term) (r2 term)) term + (match r1 + (f_= (match r2 (f_a.> f_a.<) (f_a.< f_a.>))) + (f_a.> (match r2 (f_= f_a.<) (f_a.< f_=))) + (f_a.< (match r2 (f_= f_a.>) (f_a.> f_=))))) + +; Add term for t1 and t2. Assumes t2 in n-ary form. +(program sc_arith_add_nary ((t1 term) (t2 term)) term + (a.+ t1 t2)) + +; Multiply term for t1 and t2, where t2 is not in n-ary form. +(program sc_arith_mult ((t1 term) (t2 term)) term + (a.* t1 (a.* t2 (int 1)))) + +; Returns (> t 0). +(program sc_arith_>_zero ((t term)) term + (a.> t (int 0))) + +; Returns (< t 0). +(program sc_arith_<_zero ((t term)) term + (a.< t (int 0))) + +; Get relation for the negation of arithmetic literal f. +(program sc_arith_get_rel_neg ((f term)) term + (match f + ((apply f1 f2) + (ifequal f1 f_not + (sc_arith_get_rel f2) + (sc_arith_rel_neg (sc_arith_get_rel f)))))) + +; Get the atom for possibly negated arithmetic literal f. +(program sc_arith_get_atom ((f term)) term + (match f ((apply f1 f2) (ifequal f1 f_not f2 f)))) diff --git a/proofs/lfsc/signatures/arith_rules.plf b/proofs/lfsc/signatures/arith_rules.plf new file mode 100644 index 000000000..850c2b5e6 --- /dev/null +++ b/proofs/lfsc/signatures/arith_rules.plf @@ -0,0 +1,76 @@ +; depends: arith_programs.plf + +; Computes the conclusion of the PfRule::ARITH_SUM_UB rule. +; Note that f2 is a a.+ application in n-ary form. +(program sc_arith_sum_ub ((f1 term) (f2 term)) term + (let r1 (sc_arith_get_rel f1) + (let lhs1 (sc_arith_get_lhs f1) + (let rhs1 (sc_arith_get_rhs f1) + (let r2 (sc_arith_get_rel f2) + (let lhs2 (sc_arith_get_lhs f2) + (let rhs2 (sc_arith_get_rhs f2) + (apply (apply (sc_arith_sum_rels r1 r2) (sc_arith_add_nary lhs1 lhs2)) (sc_arith_add_nary rhs1 rhs2))))))))) + +(declare arith_sum_ub + (! f1 term + (! f2 term + (! res term + (! p (holds f1) + (! p (holds f2) + (! r (^ (sc_arith_sum_ub f1 f2) res) + (holds res)))))))) + +; Computes the conclusion of the PfRule::ARITH_MULT_POS rule. +(program sc_arith_mult_pos ((m term) (f term)) term + (let r (sc_arith_get_rel f) + (let lhs (sc_arith_get_lhs f) + (let rhs (sc_arith_get_rhs f) + (=> (and (sc_arith_>_zero m) (and f true)) + (apply (apply r (sc_arith_mult m lhs)) (sc_arith_mult m rhs))))))) + +(declare arith_mult_pos + (! res term + (! m term + (! f term + (! r (^ (sc_arith_mult_pos m f) res) + (holds res)))))) + +; Computes the conclusion of the PfRule::ARITH_MULT_NEG rule. +(program sc_arith_mult_neg ((m term) (f term)) term + (let r (sc_arith_get_rel f) + (let lhs (sc_arith_get_lhs f) + (let rhs (sc_arith_get_rhs f) + (=> (and (sc_arith_<_zero m) (and f true)) + (apply (apply (sc_arith_rel_inv r) (sc_arith_mult m lhs)) (sc_arith_mult m rhs))))))) + +(declare arith_mult_neg + (! res term + (! m term + (! f term + (! r (^ (sc_arith_mult_neg m f) res) + (holds res)))))) + +; Computes the conclusion of the PfRule::ARITH_TRICHOTOMY rule. +(program sc_arith_trichotomy ((f1 term) (f2 term)) term + (let r1 (sc_arith_get_rel_neg f1) + (let a1 (sc_arith_get_atom f1) + (let lhs1 (sc_arith_get_lhs a1) + (let rhs1 (sc_arith_get_rhs a1) + (let r2 (sc_arith_get_rel_neg f2) + (let a2 (sc_arith_get_atom f1) + (let lhs2 (sc_arith_get_lhs a2) + (let rhs2 (sc_arith_get_rhs a2) + (ifequal lhs1 lhs2 + (ifequal rhs1 rhs2 + (apply (apply (sc_arith_rel_trichotomy r1 r2) lhs1) rhs1) + (fail term)) + (fail term))))))))))) + +(declare arith_trichotomy + (! res term + (! f1 term + (! f2 term + (! p (holds f1) + (! p (holds f2) + (! r (^ (sc_arith_trichotomy f1 f2) res) + (holds res)))))))) diff --git a/proofs/lfsc/signatures/boolean_programs.plf b/proofs/lfsc/signatures/boolean_programs.plf new file mode 100644 index 000000000..eecc71a98 --- /dev/null +++ b/proofs/lfsc/signatures/boolean_programs.plf @@ -0,0 +1,74 @@ +; depends: nary_programs.plf theory_def.plf + +; This side condition takes two terms c1 and c2. Via nary_intro, +; we consider theses terms to be either non-unit clauses if they are +; or-applications, or otherwise consider them to be unit clauses if they are +; not. For example, if c1 is (= x y), then (nary_intro f_or c1 false) returns +; (or (= x y) false) +; which we use to compute the concatenation described in following. After +; converting to n-ary form for both c1 and c2, we then concatenate the result +; of removing the first occurrence of l from c1, and the first occurrence of the negation of l from v2 +; when pol is tt, or vice versa when pol is ff. Since the resolution may result +; in a singleton list, we run nary_elim as a last step, which ensures that +; we conclude e.g. L and not (or L false), as done in PfRule::RESOLUTION. +; This side condition may fail if c1 or c2 does not contain l with the required +; polarity. +(program sc_resolution ((c1 term) (c2 term) (pol flag) (l term)) term + (nary_elim f_or + (nary_concat f_or + (nary_rm_first_or_self f_or (nary_intro f_or c1 false) (ifequal pol tt l (apply f_not l)) false) + (nary_rm_first_or_self f_or (nary_intro f_or c2 false) (ifequal pol tt (apply f_not l) l) false) + false) + false) +) + +; Helper for sc_not_and below, which pushes a not below an application of and. +; In terms of SMT-LIB, this side condition converts: +; (and F1 ... Fn) to (or (not F1) ... (not Fn)) +; This side condition may fail if t is not an and-application in n-ary form. +(program sc_not_and_rec ((t term)) term + (match t + ((apply t1 t2) + (let t12 (getarg f_and t1) + (apply (apply f_or (apply f_not t12)) (sc_not_and_rec t2)))) ; otherwise not in n-ary form + (true false)) ; note we must flip true to false +) + +; Pushes a not below an application of and. In terms of SMT-LIB syntax, this +; side condition converts: +; (not (and F1 ... Fn)) to (or (not F1) ... (not Fn)) +(program sc_not_and ((t term)) term + (nary_elim f_or (sc_not_and_rec t) false) +) + +; Helper for sc_not_and_rev, which is the inverse of sc_not_and. +; (or (not F1) ... (not Fn)) to (and F1 ... Fn) +; This side condition may fail if t is not an or-application in n-ary form. +(program sc_not_and_rev_rec ((t term)) term + (match t + ((apply t1 t2) + (let t12 (getarg f_or t1) + (let t122 (getarg f_not t12) + (apply (apply f_and t122) (sc_not_and_rev_rec t2))))) ; otherwise not in n-ary form + (false true)) ; note we must flip true to false +) + +; Pulls not from a list of children of an or-application. In terms of SMT-LIB +; syntax, this side condition converts: +; (or (not F1) ... (not Fn)) to (and F1 ... Fn) +(program sc_not_and_rev ((t term)) term + (nary_elim f_and (sc_not_and_rev_rec t) true) +) + +; Process scope side condition. This side condition is used for constructing the +; proven formula for the two cases of PfRule::SCOPE. In particular, it takes: +; - a term t which is expected to be an or-application +; - a term c which is expected to be a suffix of t. +; It may conclude an implication, or the negation of t, based on whether c +; is false, according to the definition of PfRule::SCOPE. +; This side condition may fail if t and c do not have the above properties. +(program sc_process_scope ((t term) (c term)) term + (let premise (sc_not_and_rev (nary_truncate f_or t c false)) + (match c + (false (not premise)) + (default (=> premise c))))) diff --git a/proofs/lfsc/signatures/boolean_rules.plf b/proofs/lfsc/signatures/boolean_rules.plf new file mode 100644 index 000000000..af16af1f9 --- /dev/null +++ b/proofs/lfsc/signatures/boolean_rules.plf @@ -0,0 +1,52 @@ +; depends: boolean_programs.plf theory_def.plf + +(declare resolution (! c1 term (! c2 term (! c term (! p1 (holds c1) (! p2 (holds c2) (! pol flag (! l term (! r (^ (sc_resolution c1 c2 pol l) c) (holds c)))))))))) +(declare reordering (! c1 term (! c2 term (! p1 (holds c1) (! r (^ (nary_is_subset f_or c1 c2) tt) (holds c2)))))) +(declare factoring (! c1 term (! c2 term (! p1 (holds c1) (! r (^ (nary_drop_dups f_or c1 false) c2) (holds c2)))))) + +(declare split (! f term (holds (or f (or (not f) false))))) + +(declare eq_resolve (! f term (! g term (! p1 (holds f) (! p2 (holds (= f g)) (holds g)))))) + +(declare modus_ponens (! f term (! g term (! p1 (holds f) (! p2 (holds (=> f g)) (holds g)))))) + +(declare not_not_elim (! f term (! p (holds (not (not f))) (holds f)))) + +(declare contra (! f term (! p1 (holds f) (! p2 (holds (not f)) (holds false))))) + +(declare and_elim (! f1 term (! f2 term (! n mpz (! p (holds f1) (! r (^ (nary_extract f_and f1 n) f2) (holds f2))))))) + +; And introduction. Since PfRule::AND_INTRO is n-ary, we require n applications +; of the following two rules. The proof (AND_INTRO P1 ... Pn) is translated to +; the LFSC proof: (and_intro2* _ _ P{n-1} (and_intro1 _ Pn)). +(declare and_intro1 (! f term (! p (holds f) (holds (and f true))))) +(declare and_intro2 (! f1 term (! f2 term (! p1 (holds f1) (! p2 (holds f2) (holds (and f1 f2))))))) + +(declare not_or_elim (! f1 term (! f2 term (! n mpz (! p (holds (not f1)) (! r (^ (nary_extract f_or f1 n) f2) (holds (not f2)))))))) + +(declare implies_elim (! f1 term (! f2 term (! p1 (holds (=> f1 f2)) (holds (or (not f1) (or f2 false))))))) +(declare not_implies_elim1 (! f1 term (! f2 term (! p1 (holds (not (=> f1 f2))) (holds f1))))) +(declare not_implies_elim2 (! f1 term (! f2 term (! p1 (holds (not (=> f1 f2))) (holds (not f2)))))) + +(declare equiv_elim1 (! f1 term (! f2 term (! p1 (holds (= f1 f2)) (holds (or (not f1) (or f2 false))))))) +(declare equiv_elim2 (! f1 term (! f2 term (! p1 (holds (= f1 f2)) (holds (or f1 (or (not f2) false))))))) +(declare not_equiv_elim1 (! f1 term (! f2 term (! p1 (holds (not (= f1 f2))) (holds (or f1 (or f2 false))))))) +(declare not_equiv_elim2 (! f1 term (! f2 term (! p1 (holds (not (= f1 f2))) (holds (or (not f1) (or (not f2) false))))))) + +(declare xor_elim1 (! f1 term (! f2 term (! p1 (holds (xor f1 f2)) (holds (or f1 (or f2 false))))))) +(declare xor_elim2 (! f1 term (! f2 term (! p1 (holds (xor f1 f2)) (holds (or (not f1) (or (not f2) false))))))) +(declare not_xor_elim1 (! f1 term (! f2 term (! p1 (holds (not (xor f1 f2))) (holds (or f1 (or (not f2) false))))))) +(declare not_xor_elim2 (! f1 term (! f2 term (! p1 (holds (not (xor f1 f2))) (holds (or (not f1) (or f2 false))))))) + +(declare ite_elim1 (! c term (! f1 term (! f2 term (! p1 (holds (ite c f1 f2)) (holds (or (not c) (or f1 false)))))))) +(declare ite_elim2 (! c term (! f1 term (! f2 term (! p1 (holds (ite c f1 f2)) (holds (or c (or f2 false)))))))) +(declare not_ite_elim1 (! c term (! f1 term (! f2 term (! p1 (holds (not (ite c f1 f2))) (holds (or (not c) (or (not f1) false)))))))) +(declare not_ite_elim2 (! c term (! f1 term (! f2 term (! p1 (holds (not (ite c f1 f2))) (holds (or c (or (not f2) false)))))))) + +(declare not_and (! c1 term (! c2 term (! p1 (holds (not c1)) (! r (^ (sc_not_and c1) c2) (holds c2)))))) + +(declare not_and_rev (! c1 term (! c2 term (! p1 (holds c1) (! r (^ (sc_not_and_rev c1) c2) (holds (not c2))))))) + +; Process scope, which is used to translate PfRule::SCOPE. It runs the side +; condition sc_process_scope on f to generate an equivalent formula g. +(declare process_scope (! f term (! g term (! c term (! p1 (holds f) (! r (^ (sc_process_scope f c) g) (holds g)))))) diff --git a/proofs/lfsc/signatures/cnf_rules.plf b/proofs/lfsc/signatures/cnf_rules.plf new file mode 100644 index 000000000..c593a0a95 --- /dev/null +++ b/proofs/lfsc/signatures/cnf_rules.plf @@ -0,0 +1,28 @@ +; depends: boolean_programs.plf theory_def.plf + +(declare cnf_and_pos (! f1 term (! f2 term (! n mpz (! r (^ (nary_extract f_and f2 n) f1) (holds (or (not f2) (or f1 false)))))))) +; Note that we do not add a null terminator, since f1 is null terminated. +(declare cnf_and_neg (! f1 term (! f2 term (! r (^ (sc_not_and_rec f2) f1) (holds (or f2 f1)))))) +(declare cnf_or_pos (! f term (holds (or (not f) f)))) +(declare cnf_or_neg (! f1 term (! f2 term (! n mpz (! r (^ (nary_extract f_or f2 n) f1) (holds (or f2 (or (not f1) false)))))))) + +(declare cnf_implies_pos (! f1 term (! f2 term (holds (or (not (=> f1 f2)) (or (not f1) (or f2 false))))))) +(declare cnf_implies_neg1 (! f1 term (! f2 term (holds (or (=> f1 f2) (or f1 false)))))) +(declare cnf_implies_neg2 (! f1 term (! f2 term (holds (or (=> f1 f2) (or (not f2) false)))))) + +(declare cnf_equiv_pos1 (! f1 term (! f2 term (holds (or (not (= f1 f2)) (or (not f1) (or f2 false))))))) +(declare cnf_equiv_pos2 (! f1 term (! f2 term (holds (or (not (= f1 f2)) (or f1 (or (not f2) false))))))) +(declare cnf_equiv_neg1 (! f1 term (! f2 term (holds (or (= f1 f2) (or f1 (or f2 false))))))) +(declare cnf_equiv_neg2 (! f1 term (! f2 term (holds (or (= f1 f2) (or (not f1) (or (not f2) false))))))) + +(declare cnf_xor_pos1 (! f1 term (! f2 term (holds (or (not (xor f1 f2)) (or f1 (or f2 false))))))) +(declare cnf_xor_pos2 (! f1 term (! f2 term (holds (or (not (xor f1 f2)) (or (not f1) (or (not f2) false))))))) +(declare cnf_xor_neg1 (! f1 term (! f2 term (holds (or (xor f1 f2) (or (not f1) (or f2 false))))))) +(declare cnf_xor_neg2 (! f1 term (! f2 term (holds (or (xor f1 f2) (or f1 (or (not f2) false))))))) + +(declare cnf_ite_pos1 (! c term (! f1 term (! f2 term (holds (or (not (ite c f1 f2)) (or (not c) (or f1 false))))))) +(declare cnf_ite_pos2 (! c term (! f1 term (! f2 term (holds (or (not (ite c f1 f2)) (or c (or f2 false))))))) +(declare cnf_ite_pos3 (! c term (! f1 term (! f2 term (holds (or (not (ite c f1 f2)) (or f1 (or f2 false))))))) +(declare cnf_ite_neg1 (! c term (! f1 term (! f2 term (holds (or (ite c f1 f2) (or (not c) (or (not f1) false))))))) +(declare cnf_ite_neg2 (! c term (! f1 term (! f2 term (holds (or (ite c f1 f2) (or c (or (not f2) false))))))) +(declare cnf_ite_neg3 (! c term (! f1 term (! f2 term (holds (or (ite c f1 f2) (or (not f1) (or (not f2) false))))))) diff --git a/proofs/lfsc/signatures/equality_rules.plf b/proofs/lfsc/signatures/equality_rules.plf new file mode 100644 index 000000000..3144294d5 --- /dev/null +++ b/proofs/lfsc/signatures/equality_rules.plf @@ -0,0 +1,64 @@ +; depends: theory_def.plf + +; The following encodes the proof rules for the theory of equality in the +; internal proof calculus of cvc5 (see src/proof/proof_rule.h). Rules from +; that calculus are referenced by PfRule::NAME, where NAME is the name of the +; identifier in the PfRule enumeration (see src/proof/proof_rule.h). For this +; and other theory signature definitions, unless otherwise stated, we use a +; naming convention in which the corresponding LFSC rule is the same as the +; PfRule, but converted to lower case. For example, `refl` corresponds to the +; LFSC encoding of PfRule::REFL. We provide documentation when the proof rule +; differs from the original PfRule. + +(declare refl (! t term (holds (= t t)))) + +; symm is a special case of PfRule::SYMM that is applied only to equalties. +(declare symm (! s term + (! t term + (! u (holds (= s t)) + (holds (= t s)))))) + +; neg_symm is a special case of PfRule::SYMM that is applied only to disequalties, +; i.e. negated equalities. +(declare neg_symm (! s term + (! t term + (! u (holds (not (= s t))) + (holds (not (= t s))))))) + +(declare trans (! t1 term + (! t2 term + (! t3 term + (! u1 (holds (= t1 t2)) + (! u2 (holds (= t2 t3)) + (holds (= t1 t3)))))))) + +; In LFSC, congruence is applied to higher-order apply only. Thus, when +; applying congruence to n-ary symbols, we curry the applications of congruence +; e.g. consider (cong _ _ _ _ (cong _ _ _ _ P1 P2) P3) +; where P1 proves (= f g), P2 proves (= a b), P3 proves (= c d). The above +; proof proves (= (apply (apply f a) c) (apply (apply f b) d)), where assuming +; f is binary, is the LFSC encoding of the SMT-LIB equality (= (f a c) (f b d)). +(declare cong (! a1 term + (! b1 term + (! a2 term + (! b2 term + (! u1 (holds (= a1 b1)) + (! u2 (holds (= a2 b2)) + (holds (= (apply a1 a2) (apply b1 b2)))))))))) + +(declare true_intro (! f term + (! u (holds f) + (holds (= f true))))) + +(declare true_elim (! f term + (! u (holds (= f true)) + (holds f)))) + +(declare false_intro (! f term + (! u (holds (not f)) + (holds (= f false))))) + +(declare false_elim (! f term + (! u (holds (= f false)) + (holds (not f))))) + diff --git a/proofs/lfsc/signatures/quantifiers_rules.plf b/proofs/lfsc/signatures/quantifiers_rules.plf new file mode 100644 index 000000000..7bdd6539c --- /dev/null +++ b/proofs/lfsc/signatures/quantifiers_rules.plf @@ -0,0 +1,51 @@ +; depends: theory_def.plf util_defs.plf + +; Substitute, which returns the result of replacing all occurrences of the +; bound variable whose identifier is v with the term s. It is the responsibility +; of the caller to ensure that all occurrences of (bvar v u) in t are such that +; u is the sort of s. Otherwise, this will return a term that is not well +; sorted. +(program sc_substitute ((t term) (v mpz) (s term)) term + (match t + ((bvar v1 u1) (mpz_ifequal v v1 s t)) + ((apply t1 t2) (apply (sc_substitute t1 v s) (sc_substitute t2 v s))) + (default t) + )) + +; Concludes the instantiation for the term of the outermost quantifier in the +; rule PfRule::INSTANTIATE. We do not enforce type checking of term s +; currently, which should be of sort u. +(declare instantiate (! body term + (! v mpz + (! u sort + (! s term + (! bodyi term + (! p (holds (forall v u body)) + (! r (^ (sc_substitute body v s) bodyi) + (holds bodyi))))))))) + +; Concludes the skolemization for the term of the outermost quantifier in the +; rule PfRule::SKOLEMIZE. +(declare skolemize (! body term + (! v mpz + (! s sort + (! bodyi term + (! p (holds (exists v s body)) + (! r (^ (sc_substitute body v (skolem (witness v s body))) bodyi) + (holds bodyi)))))))) + +; We do not enforce type checking of s currently, which should be of +; sort u. +(declare exists_intro (! bodyi term + (! v mpz + (! u sort + (! s term + (! body term + (! p (holds bodyi) + (! r (^ (sc_substitute body v s) bodyi) + (holds (exists v u body))))))))) + +(declare skolem_intro (! u term + (! t term + (! r (^ (sc_mk_skolem t) u) + (holds (= u t)))))) diff --git a/proofs/lfsc/signatures/util_defs.plf b/proofs/lfsc/signatures/util_defs.plf index 5639cc54e..8d1793666 100644 --- a/proofs/lfsc/signatures/util_defs.plf +++ b/proofs/lfsc/signatures/util_defs.plf @@ -25,6 +25,11 @@ (declare bvn bitvec) (declare bvc (! b bit (! v bitvec bitvec))) +; Returns term t if v1 = v2, and term s otherwise. +(program mpz_ifequal ((v1 mpz) (v2 mpz) (t term) (s term)) term + (mp_ifzero (mp_add (mp_neg v1) v2) t s) +) + ;; ---- Side conditions ; Get the argument from an f-application t, fail if t is not an f-application. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2cb3457e1..5f77128a4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -51,8 +51,6 @@ libcvc5_add_sources( omt/omt_optimizer.cpp omt/omt_optimizer.h options/decision_weight.h - options/didyoumean.cpp - options/didyoumean.h options/language.cpp options/language.h options/managed_streams.cpp @@ -75,8 +73,6 @@ libcvc5_add_sources( preprocessing/passes/apply_substs.h preprocessing/passes/bool_to_bv.cpp preprocessing/passes/bool_to_bv.h - preprocessing/passes/bv_abstraction.cpp - preprocessing/passes/bv_abstraction.h preprocessing/passes/bv_eager_atoms.cpp preprocessing/passes/bv_eager_atoms.h preprocessing/passes/bv_gauss.cpp @@ -227,25 +223,6 @@ libcvc5_add_sources( proof/alethe/alethe_post_processor.h proof/alethe/alethe_proof_rule.cpp proof/alethe/alethe_proof_rule.h - prop/bv_sat_solver_notify.h - prop/bvminisat/bvminisat.cpp - prop/bvminisat/bvminisat.h - prop/bvminisat/core/Dimacs.h - prop/bvminisat/core/Solver.cc - prop/bvminisat/core/Solver.h - prop/bvminisat/core/SolverTypes.h - prop/bvminisat/mtl/Alg.h - prop/bvminisat/mtl/Alloc.h - prop/bvminisat/mtl/Heap.h - prop/bvminisat/mtl/IntTypes.h - prop/bvminisat/mtl/Map.h - prop/bvminisat/mtl/Queue.h - prop/bvminisat/mtl/Sort.h - prop/bvminisat/mtl/Vec.h - prop/bvminisat/mtl/XAlloc.h - prop/bvminisat/simp/SimpSolver.cc - prop/bvminisat/simp/SimpSolver.h - prop/bvminisat/utils/Options.h prop/cadical.cpp prop/cadical.h prop/cnf_stream.cpp @@ -379,6 +356,8 @@ libcvc5_add_sources( theory/arith/arith_ite_utils.h theory/arith/arith_msum.cpp theory/arith/arith_msum.h + theory/arith/arith_poly_norm.cpp + theory/arith/arith_poly_norm.h theory/arith/arith_preprocess.cpp theory/arith/arith_preprocess.h theory/arith/arith_rewriter.cpp @@ -605,51 +584,24 @@ libcvc5_add_sources( theory/builtin/theory_builtin_type_rules.h theory/builtin/type_enumerator.cpp theory/builtin/type_enumerator.h - theory/bv/abstraction.cpp - theory/bv/abstraction.h - theory/bv/bitblast/aig_bitblaster.cpp - theory/bv/bitblast/aig_bitblaster.h theory/bv/bitblast/bitblast_proof_generator.cpp theory/bv/bitblast/bitblast_proof_generator.h theory/bv/bitblast/bitblast_strategies_template.h theory/bv/bitblast/bitblast_utils.h theory/bv/bitblast/bitblaster.h - theory/bv/bitblast/eager_bitblaster.cpp - theory/bv/bitblast/eager_bitblaster.h - theory/bv/bitblast/lazy_bitblaster.cpp - theory/bv/bitblast/lazy_bitblaster.h theory/bv/bitblast/node_bitblaster.cpp theory/bv/bitblast/node_bitblaster.h theory/bv/bitblast/proof_bitblaster.cpp theory/bv/bitblast/proof_bitblaster.h - theory/bv/bv_eager_solver.cpp - theory/bv/bv_eager_solver.h - theory/bv/bv_inequality_graph.cpp - theory/bv/bv_inequality_graph.h - theory/bv/bv_quick_check.cpp - theory/bv/bv_quick_check.h theory/bv/bv_solver.h theory/bv/bv_solver_bitblast.cpp theory/bv/bv_solver_bitblast.h theory/bv/bv_solver_bitblast_internal.cpp theory/bv/bv_solver_bitblast_internal.h - theory/bv/bv_solver_layered.cpp - theory/bv/bv_solver_layered.h - theory/bv/bv_subtheory.h - theory/bv/bv_subtheory_algebraic.cpp - theory/bv/bv_subtheory_algebraic.h - theory/bv/bv_subtheory_bitblast.cpp - theory/bv/bv_subtheory_bitblast.h - theory/bv/bv_subtheory_core.cpp - theory/bv/bv_subtheory_core.h - theory/bv/bv_subtheory_inequality.cpp - theory/bv/bv_subtheory_inequality.h theory/bv/int_blaster.cpp theory/bv/int_blaster.h theory/bv/proof_checker.cpp theory/bv/proof_checker.h - theory/bv/slicer.cpp - theory/bv/slicer.h theory/bv/theory_bv.cpp theory/bv/theory_bv.h theory/bv/theory_bv_rewrite_rules.h @@ -1339,7 +1291,7 @@ install(TARGETS cvc5-shared ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) -if(ENABLE_STATIC_LIBRARY) +if(ENABLE_STATIC_BUILD) add_library(cvc5-static STATIC $<TARGET_OBJECTS:cvc5-obj> $<TARGET_OBJECTS:cvc5base> $<TARGET_OBJECTS:cvc5context>) set_target_properties(cvc5-static PROPERTIES OUTPUT_NAME cvc5) target_include_directories(cvc5-static @@ -1360,7 +1312,7 @@ generate_export_header(cvc5-obj BASE_NAME cvc5) add_dependencies(cvc5-obj GMP_SHARED) target_include_directories(cvc5-obj PRIVATE ${GMP_INCLUDE_DIR}) target_link_libraries(cvc5-shared PRIVATE GMP_SHARED) -if(ENABLE_STATIC_LIBRARY) +if(ENABLE_STATIC_BUILD) target_link_libraries(cvc5-static PUBLIC GMP_STATIC) endif() @@ -1368,22 +1320,18 @@ endif() # Note: For glibc < 2.17 we have to additionally link against rt (man clock_gettime). # RT_LIBRARIES should be empty for glibc >= 2.17 target_link_libraries(cvc5-shared PRIVATE ${RT_LIBRARIES}) -if(ENABLE_STATIC_LIBRARY) +if(ENABLE_STATIC_BUILD) target_link_libraries(cvc5-static PRIVATE ${RT_LIBRARIES}) endif() if(ENABLE_VALGRIND) target_include_directories(cvc5-obj PUBLIC ${Valgrind_INCLUDE_DIR}) endif() -if(USE_ABC) - target_include_directories(cvc5-obj PRIVATE ${ABC_INCLUDE_DIR}) - target_link_libraries(cvc5-obj PUBLIC ${ABC_LIBRARIES}) -endif() add_dependencies(cvc5-obj CaDiCaL) target_include_directories(cvc5-obj PRIVATE ${CaDiCaL_INCLUDE_DIR}) target_link_libraries(cvc5-shared PRIVATE CaDiCaL) -if(ENABLE_STATIC_LIBRARY) +if(ENABLE_STATIC_BUILD) target_link_libraries(cvc5-static PUBLIC CaDiCaL) endif() @@ -1391,7 +1339,7 @@ if(USE_CLN) add_dependencies(cvc5-obj CLN_SHARED) target_include_directories(cvc5-obj PRIVATE ${CLN_INCLUDE_DIR}) target_link_libraries(cvc5-shared PRIVATE CLN_SHARED) - if(ENABLE_STATIC_LIBRARY) + if(ENABLE_STATIC_BUILD) target_link_libraries(cvc5-static PUBLIC CLN_STATIC) endif() endif() @@ -1399,7 +1347,7 @@ if(USE_CRYPTOMINISAT) add_dependencies(cvc5-obj CryptoMiniSat) target_include_directories(cvc5-obj PRIVATE ${CryptoMiniSat_INCLUDE_DIR}) target_link_libraries(cvc5-shared PRIVATE CryptoMiniSat) - if(ENABLE_STATIC_LIBRARY) + if(ENABLE_STATIC_BUILD) target_link_libraries(cvc5-static PUBLIC CryptoMiniSat) endif() endif() @@ -1407,14 +1355,14 @@ if(USE_KISSAT) add_dependencies(cvc5-obj Kissat) target_include_directories(cvc5-obj PRIVATE ${Kissat_INCLUDE_DIR}) target_link_libraries(cvc5-shared PRIVATE Kissat) - if(ENABLE_STATIC_LIBRARY) + if(ENABLE_STATIC_BUILD) target_link_libraries(cvc5-static PUBLIC Kissat) endif() endif() if(USE_GLPK) target_include_directories(cvc5-obj PRIVATE ${GLPK_INCLUDE_DIR}) target_link_libraries(cvc5-shared PRIVATE ${GLPK_LIBRARIES}) - if(ENABLE_STATIC_LIBRARY) + if(ENABLE_STATIC_BUILD) target_link_libraries(cvc5-static PUBLIC ${GLPK_LIBRARIES}) endif() endif() @@ -1422,7 +1370,7 @@ if(USE_POLY) add_dependencies(cvc5-obj Polyxx_SHARED) target_include_directories(cvc5-obj PRIVATE ${Poly_INCLUDE_DIR}) target_link_libraries(cvc5-shared PRIVATE Polyxx_SHARED) - if(ENABLE_STATIC_LIBRARY) + if(ENABLE_STATIC_BUILD) target_link_libraries(cvc5-static PUBLIC Polyxx_STATIC) endif() endif() @@ -1430,7 +1378,7 @@ if(USE_COCOA) add_dependencies(cvc5-obj CoCoA) target_include_directories(cvc5-obj PRIVATE ${CoCoA_INCLUDE_DIR}) target_link_libraries(cvc5-shared PRIVATE CoCoA) - if(ENABLE_STATIC_LIBRARY) + if(ENABLE_STATIC_BUILD) target_link_libraries(cvc5-static PUBLIC CoCoA) endif() endif() @@ -1438,7 +1386,7 @@ endif() add_dependencies(cvc5-obj SymFPU) target_include_directories(cvc5-obj PRIVATE ${SymFPU_INCLUDE_DIR}) target_link_libraries(cvc5-shared PRIVATE SymFPU) -if(ENABLE_STATIC_LIBRARY) +if(ENABLE_STATIC_BUILD) target_link_libraries(cvc5-static PUBLIC SymFPU) endif() diff --git a/src/api/cpp/cvc5.cpp b/src/api/cpp/cvc5.cpp index a342cea53..0450ac06a 100644 --- a/src/api/cpp/cvc5.cpp +++ b/src/api/cpp/cvc5.cpp @@ -5056,6 +5056,8 @@ Term Solver::mkBVFromStrHelper(uint32_t size, Term Solver::getValueHelper(const Term& term) const { // Note: Term is checked in the caller to avoid double checks + CVC5_API_RECOVERABLE_CHECK(!expr::hasFreeVar(term.getNode())) + << "Cannot get value of term containing free variables"; //////// all checks before this line Node value = d_slv->getValue(*term.d_node); Term res = Term(this, value); @@ -6716,7 +6718,7 @@ Term Solver::defineFun(const std::string& symbol, CVC5_API_TRY_CATCH_BEGIN; CVC5_API_SOLVER_CHECK_CODOMAIN_SORT(sort); CVC5_API_SOLVER_CHECK_TERM(term); - CVC5_API_CHECK(sort == term.getSort()) + CVC5_API_CHECK(term.getSort().isSubsortOf(sort)) << "Invalid sort of function body '" << term << "', expected '" << sort << "'"; @@ -6743,37 +6745,6 @@ Term Solver::defineFun(const std::string& symbol, CVC5_API_TRY_CATCH_END; } -Term Solver::defineFun(const Term& fun, - const std::vector<Term>& bound_vars, - const Term& term, - bool global) const -{ - CVC5_API_TRY_CATCH_BEGIN; - CVC5_API_SOLVER_CHECK_TERM(fun); - CVC5_API_SOLVER_CHECK_TERM(term); - if (fun.getSort().isFunction()) - { - std::vector<Sort> domain_sorts = fun.getSort().getFunctionDomainSorts(); - CVC5_API_SOLVER_CHECK_BOUND_VARS_DEF_FUN(fun, bound_vars, domain_sorts); - Sort codomain = fun.getSort().getFunctionCodomainSort(); - CVC5_API_CHECK(codomain == term.getSort()) - << "Invalid sort of function body '" << term << "', expected '" - << codomain << "'"; - } - else - { - CVC5_API_SOLVER_CHECK_BOUND_VARS(bound_vars); - CVC5_API_ARG_CHECK_EXPECTED(bound_vars.size() == 0, fun) - << "function or nullary symbol"; - } - //////// all checks before this line - std::vector<Node> ebound_vars = Term::termVectorToNodes(bound_vars); - d_slv->defineFunction(*fun.d_node, ebound_vars, *term.d_node, global); - return fun; - //////// - CVC5_API_TRY_CATCH_END; -} - Term Solver::defineFunRec(const std::string& symbol, const std::vector<Term>& bound_vars, const Sort& sort, @@ -7374,8 +7345,7 @@ Term Solver::getQuantifierEliminationDisjunct(const Term& q) const CVC5_API_TRY_CATCH_END; } -void Solver::declareSeparationHeap(const Sort& locSort, - const Sort& dataSort) const +void Solver::declareSepHeap(const Sort& locSort, const Sort& dataSort) const { CVC5_API_TRY_CATCH_BEGIN; CVC5_API_SOLVER_CHECK_SORT(locSort); @@ -7389,7 +7359,7 @@ void Solver::declareSeparationHeap(const Sort& locSort, CVC5_API_TRY_CATCH_END; } -Term Solver::getSeparationHeap() const +Term Solver::getValueSepHeap() const { CVC5_API_TRY_CATCH_BEGIN; CVC5_API_CHECK(d_slv->getLogicInfo().isTheoryEnabled(theory::THEORY_SEP)) @@ -7406,7 +7376,7 @@ Term Solver::getSeparationHeap() const CVC5_API_TRY_CATCH_END; } -Term Solver::getSeparationNilTerm() const +Term Solver::getValueSepNil() const { CVC5_API_TRY_CATCH_BEGIN; CVC5_API_CHECK(d_slv->getLogicInfo().isTheoryEnabled(theory::THEORY_SEP)) diff --git a/src/api/cpp/cvc5.h b/src/api/cpp/cvc5.h index f0a36b792..f348ae4e5 100644 --- a/src/api/cpp/cvc5.h +++ b/src/api/cpp/cvc5.h @@ -3813,24 +3813,6 @@ class CVC5_EXPORT Solver const Sort& sort, const Term& term, bool global = false) const; - /** - * Define n-ary function. - * SMT-LIB: - * \verbatim - * ( define-fun <function_def> ) - * \endverbatim - * Create parameter 'fun' with mkConst(). - * @param fun the sorted function - * @param bound_vars the parameters to this function - * @param term the function body - * @param global determines whether this definition is global (i.e. persists - * when popping the context) - * @return the function - */ - Term defineFun(const Term& fun, - const std::vector<Term>& bound_vars, - const Term& term, - bool global = false) const; /** * Define recursive function. @@ -4108,19 +4090,19 @@ class CVC5_EXPORT Solver * @param locSort The location sort of the heap * @param dataSort The data sort of the heap */ - void declareSeparationHeap(const Sort& locSort, const Sort& dataSort) const; + void declareSepHeap(const Sort& locSort, const Sort& dataSort) const; /** * When using separation logic, obtain the term for the heap. * @return The term for the heap */ - Term getSeparationHeap() const; + Term getValueSepHeap() const; /** * When using separation logic, obtain the term for nil. * @return The term for nil */ - Term getSeparationNilTerm() const; + Term getValueSepNil() const; /** * Declare a symbolic pool of terms with the given initial value. diff --git a/src/api/cpp/cvc5_checks.h b/src/api/cpp/cvc5_checks.h index c30237ecd..35c21df9c 100644 --- a/src/api/cpp/cvc5_checks.h +++ b/src/api/cpp/cvc5_checks.h @@ -438,8 +438,6 @@ namespace api { CVC5_API_ARG_CHECK_NOT_NULL(sort); \ CVC5_API_CHECK(this == sort.d_solver) \ << "Given sort is not associated with this solver"; \ - CVC5_API_ARG_CHECK_EXPECTED(sort.isFirstClass(), sort) \ - << "first-class sort as codomain sort"; \ CVC5_API_ARG_CHECK_EXPECTED(!sort.isFunction(), sort) \ << "function sort as codomain sort"; \ } while (0) diff --git a/src/api/cpp/cvc5_kind.h b/src/api/cpp/cvc5_kind.h index a01f84c3f..bece49098 100644 --- a/src/api/cpp/cvc5_kind.h +++ b/src/api/cpp/cvc5_kind.h @@ -377,7 +377,12 @@ enum Kind : int32_t */ MULT, /** - * Operator for Integer AND + * Operator for bit-wise AND over integers, parameterized by a (positive) + * bitwidth k. + * + * ((_ iand k) i1 i2) is equivalent to: + * (bv2int (bvand ((_ int2bv k) i1) ((_ int2bv k) i2))) + * for all integers i1, i2. * * Parameters: * - 1: Size of the bit-vector that determines the semantics of the IAND @@ -385,8 +390,8 @@ enum Kind : int32_t * Create with: * - `Solver::mkOp(Kind kind, uint32_t param) const` * - * Apply integer conversion to bit-vector. - + * Apply integer and. + * * Parameters: * - 1: Op of kind IAND * - 2: Integer term @@ -398,16 +403,17 @@ enum Kind : int32_t */ IAND, /** - * Operator for raising 2 to a non-negative integer power + * Operator for raising 2 to a non-negative integer power. * * Create with: * - `Solver::mkOp(Kind kind) const` * - * Parameters: * - 1: Op of kind IAND * - 2: Integer term * + * Apply 2 to the power operator. + * * Create with: * - `Solver::mkTerm(const Op& op, const Term& child) const` * - `Solver::mkTerm(const Op& op, const std::vector<Term>& children) const` diff --git a/src/api/java/io/github/cvc5/api/AbstractPointer.java b/src/api/java/io/github/cvc5/api/AbstractPointer.java index 092e33d43..c627dcf84 100644 --- a/src/api/java/io/github/cvc5/api/AbstractPointer.java +++ b/src/api/java/io/github/cvc5/api/AbstractPointer.java @@ -18,13 +18,24 @@ package io.github.cvc5.api; abstract class AbstractPointer implements IPointer { protected final Solver solver; - protected final long pointer; + protected long pointer; public long getPointer() { return pointer; } + protected abstract void deletePointer(long pointer); + + void deletePointer() + { + if (pointer != 0) + { + deletePointer(pointer); + } + pointer = 0; + } + public Solver getSolver() { return solver; @@ -41,5 +52,6 @@ abstract class AbstractPointer implements IPointer { this.solver = solver; this.pointer = pointer; + solver.addAbstractPointer(this); } } diff --git a/src/api/java/io/github/cvc5/api/Datatype.java b/src/api/java/io/github/cvc5/api/Datatype.java index c5422c215..bc33ba10b 100644 --- a/src/api/java/io/github/cvc5/api/Datatype.java +++ b/src/api/java/io/github/cvc5/api/Datatype.java @@ -26,18 +26,13 @@ public class Datatype extends AbstractPointer implements Iterable<DatatypeConstr super(solver, pointer); } - protected static native void deletePointer(long pointer); + protected native void deletePointer(long pointer); public long getPointer() { return pointer; } - @Override public void finalize() - { - deletePointer(pointer); - } - // endregion /** diff --git a/src/api/java/io/github/cvc5/api/DatatypeConstructor.java b/src/api/java/io/github/cvc5/api/DatatypeConstructor.java index f41acee85..5fd9d8407 100644 --- a/src/api/java/io/github/cvc5/api/DatatypeConstructor.java +++ b/src/api/java/io/github/cvc5/api/DatatypeConstructor.java @@ -26,18 +26,13 @@ public class DatatypeConstructor extends AbstractPointer implements Iterable<Dat super(solver, pointer); } - protected static native void deletePointer(long pointer); + protected native void deletePointer(long pointer); public long getPointer() { return pointer; } - @Override public void finalize() - { - deletePointer(pointer); - } - // endregion /** @return the name of this Datatype constructor. */ diff --git a/src/api/java/io/github/cvc5/api/DatatypeConstructorDecl.java b/src/api/java/io/github/cvc5/api/DatatypeConstructorDecl.java index da3fa3582..e1f5ca746 100644 --- a/src/api/java/io/github/cvc5/api/DatatypeConstructorDecl.java +++ b/src/api/java/io/github/cvc5/api/DatatypeConstructorDecl.java @@ -23,18 +23,13 @@ public class DatatypeConstructorDecl extends AbstractPointer super(solver, pointer); } - protected static native void deletePointer(long pointer); + protected native void deletePointer(long pointer); public long getPointer() { return pointer; } - @Override public void finalize() - { - deletePointer(pointer); - } - // endregion /** diff --git a/src/api/java/io/github/cvc5/api/DatatypeDecl.java b/src/api/java/io/github/cvc5/api/DatatypeDecl.java index ad90c0987..fb8da9abd 100644 --- a/src/api/java/io/github/cvc5/api/DatatypeDecl.java +++ b/src/api/java/io/github/cvc5/api/DatatypeDecl.java @@ -23,18 +23,13 @@ public class DatatypeDecl extends AbstractPointer super(solver, pointer); } - protected static native void deletePointer(long pointer); + protected native void deletePointer(long pointer); public long getPointer() { return pointer; } - @Override public void finalize() - { - deletePointer(pointer); - } - // endregion /** * Add datatype constructor declaration. diff --git a/src/api/java/io/github/cvc5/api/DatatypeSelector.java b/src/api/java/io/github/cvc5/api/DatatypeSelector.java index 7a0907c9d..d388e7f2b 100644 --- a/src/api/java/io/github/cvc5/api/DatatypeSelector.java +++ b/src/api/java/io/github/cvc5/api/DatatypeSelector.java @@ -23,18 +23,13 @@ public class DatatypeSelector extends AbstractPointer super(solver, pointer); } - protected static native void deletePointer(long pointer); + protected native void deletePointer(long pointer); public long getPointer() { return pointer; } - @Override public void finalize() - { - deletePointer(pointer); - } - // endregion /** @return the name of this Datatype selector. */ diff --git a/src/api/java/io/github/cvc5/api/Grammar.java b/src/api/java/io/github/cvc5/api/Grammar.java index 860bb8302..49a29670d 100644 --- a/src/api/java/io/github/cvc5/api/Grammar.java +++ b/src/api/java/io/github/cvc5/api/Grammar.java @@ -30,18 +30,13 @@ public class Grammar extends AbstractPointer private static native long copyGrammar(long pointer); - protected static native void deletePointer(long pointer); + protected native void deletePointer(long pointer); public long getPointer() { return pointer; } - @Override public void finalize() - { - deletePointer(pointer); - } - // endregion /** diff --git a/src/api/java/io/github/cvc5/api/Op.java b/src/api/java/io/github/cvc5/api/Op.java index 86d893785..096fd559d 100644 --- a/src/api/java/io/github/cvc5/api/Op.java +++ b/src/api/java/io/github/cvc5/api/Op.java @@ -23,18 +23,13 @@ public class Op extends AbstractPointer super(solver, pointer); } - protected static native void deletePointer(long pointer); + protected native void deletePointer(long pointer); public long getPointer() { return pointer; } - @Override public void finalize() - { - deletePointer(pointer); - } - // endregion /** diff --git a/src/api/java/io/github/cvc5/api/OptionInfo.java b/src/api/java/io/github/cvc5/api/OptionInfo.java index 76633a8a6..6f6024420 100644 --- a/src/api/java/io/github/cvc5/api/OptionInfo.java +++ b/src/api/java/io/github/cvc5/api/OptionInfo.java @@ -46,18 +46,13 @@ public class OptionInfo extends AbstractPointer this.baseInfo = getBaseInfo(pointer); } - protected static native void deletePointer(long pointer); + protected native void deletePointer(long pointer); public long getPointer() { return pointer; } - @Override public void finalize() - { - deletePointer(pointer); - } - /** * @return a string representation of this optionInfo. */ diff --git a/src/api/java/io/github/cvc5/api/Result.java b/src/api/java/io/github/cvc5/api/Result.java index 500ec7f16..3a34fbda6 100644 --- a/src/api/java/io/github/cvc5/api/Result.java +++ b/src/api/java/io/github/cvc5/api/Result.java @@ -26,18 +26,13 @@ public class Result extends AbstractPointer super(solver, pointer); } - protected static native void deletePointer(long pointer); + protected native void deletePointer(long pointer); public long getPointer() { return pointer; } - @Override public void finalize() - { - deletePointer(pointer); - } - // endregion public enum UnknownExplanation { diff --git a/src/api/java/io/github/cvc5/api/Solver.java b/src/api/java/io/github/cvc5/api/Solver.java index 3a9f450a4..0479dce3d 100644 --- a/src/api/java/io/github/cvc5/api/Solver.java +++ b/src/api/java/io/github/cvc5/api/Solver.java @@ -18,9 +18,9 @@ package io.github.cvc5.api; import java.io.IOException; import java.util.*; -public class Solver implements IPointer +public class Solver implements IPointer, AutoCloseable { - private final long pointer; + private long pointer; public long getPointer() { @@ -31,14 +31,32 @@ public class Solver implements IPointer public void deletePointer() { - deletePointer(pointer); + if (pointer != 0) + { + deletePointer(pointer); + } + pointer = 0; } private static native void deletePointer(long pointer); - @Override public void finalize() + // store pointers for terms, sorts, etc + List<AbstractPointer> abstractPointers = new ArrayList<>(); + + @Override public void close() { - deletePointer(pointer); + // delete heap memory for terms, sorts, etc + for (int i = abstractPointers.size() - 1; i >= 0; i--) + { + abstractPointers.get(i).deletePointer(); + } + // delete the heap memory for this solver + deletePointer(); + } + + void addAbstractPointer(AbstractPointer abstractPointer) + { + abstractPointers.add(abstractPointer); } static @@ -1594,47 +1612,6 @@ public class Solver implements IPointer boolean global); /** - * Define n-ary function in the current context. - * SMT-LIB: - * {@code - * ( define-fun <function_def> ) - * } - * Create parameter 'fun' with mkConst(). - * @param fun the sorted function - * @param boundVars the parameters to this function - * @param term the function body - * @return the function - */ - public Term defineFun(Term fun, Term[] boundVars, Term term) - { - return defineFun(fun, boundVars, term, false); - } - /** - * Define n-ary function. - * SMT-LIB: - * {@code - * ( define-fun <function_def> ) - * } - * Create parameter 'fun' with mkConst(). - * @param fun the sorted function - * @param boundVars the parameters to this function - * @param term the function body - * @param global determines whether this definition is global (i.e. persists - * when popping the context) - * @return the function - */ - public Term defineFun(Term fun, Term[] boundVars, Term term, boolean global) - { - long[] boundVarPointers = Utils.getPointers(boundVars); - long termPointer = - defineFun(pointer, fun.getPointer(), boundVarPointers, term.getPointer(), global); - return new Term(this, termPointer); - } - - private native long defineFun( - long pointer, long funPointer, long[] boundVarPointers, long termPointer, boolean global); - - /** * Define recursive function in the current context. * SMT-LIB: * {@code @@ -2075,37 +2052,36 @@ public class Solver implements IPointer * @param locSort The location sort of the heap * @param dataSort The data sort of the heap */ - public void declareSeparationHeap(Sort locSort, Sort dataSort) + public void declareSepHeap(Sort locSort, Sort dataSort) { - declareSeparationHeap(pointer, locSort.getPointer(), dataSort.getPointer()); + declareSepHeap(pointer, locSort.getPointer(), dataSort.getPointer()); } - private native void declareSeparationHeap( - long pointer, long locSortPointer, long dataSortPointer); + private native void declareSepHeap(long pointer, long locSortPointer, long dataSortPointer); /** * When using separation logic, obtain the term for the heap. * @return The term for the heap */ - public Term getSeparationHeap() + public Term getValueSepHeap() { - long termPointer = getSeparationHeap(pointer); + long termPointer = getValueSepHeap(pointer); return new Term(this, termPointer); } - private native long getSeparationHeap(long pointer); + private native long getValueSepHeap(long pointer); /** * When using separation logic, obtain the term for nil. * @return The term for nil */ - public Term getSeparationNilTerm() + public Term getValueSepNil() { - long termPointer = getSeparationNilTerm(pointer); + long termPointer = getValueSepNil(pointer); return new Term(this, termPointer); } - private native long getSeparationNilTerm(long pointer); + private native long getValueSepNil(long pointer); /** * Declare a symbolic pool of terms with the given initial value. diff --git a/src/api/java/io/github/cvc5/api/Sort.java b/src/api/java/io/github/cvc5/api/Sort.java index ec7091e5c..440b1ba59 100644 --- a/src/api/java/io/github/cvc5/api/Sort.java +++ b/src/api/java/io/github/cvc5/api/Sort.java @@ -25,18 +25,13 @@ public class Sort extends AbstractPointer implements Comparable<Sort> super(solver, pointer); } - protected static native void deletePointer(long pointer); + protected native void deletePointer(long pointer); public long getPointer() { return pointer; } - @Override public void finalize() - { - deletePointer(pointer); - } - // endregion /** @@ -799,4 +794,4 @@ public class Sort extends AbstractPointer implements Comparable<Sort> } private native long[] getTupleSorts(long pointer); -}
\ No newline at end of file +} diff --git a/src/api/java/io/github/cvc5/api/Stat.java b/src/api/java/io/github/cvc5/api/Stat.java index c0c81c472..6bcae5322 100644 --- a/src/api/java/io/github/cvc5/api/Stat.java +++ b/src/api/java/io/github/cvc5/api/Stat.java @@ -34,18 +34,13 @@ public class Stat extends AbstractPointer super(solver, pointer); } - protected static native void deletePointer(long pointer); + protected native void deletePointer(long pointer); public long getPointer() { return pointer; } - @Override public void finalize() - { - deletePointer(pointer); - } - // endregion /** diff --git a/src/api/java/io/github/cvc5/api/Statistics.java b/src/api/java/io/github/cvc5/api/Statistics.java index c874e483a..ad904aa1f 100644 --- a/src/api/java/io/github/cvc5/api/Statistics.java +++ b/src/api/java/io/github/cvc5/api/Statistics.java @@ -26,18 +26,13 @@ public class Statistics extends AbstractPointer implements Iterable<Pair<String, super(solver, pointer); } - protected static native void deletePointer(long pointer); + protected native void deletePointer(long pointer); public long getPointer() { return pointer; } - @Override public void finalize() - { - deletePointer(pointer); - } - // endregion /** diff --git a/src/api/java/io/github/cvc5/api/Term.java b/src/api/java/io/github/cvc5/api/Term.java index 7a1798b65..bbed609f7 100644 --- a/src/api/java/io/github/cvc5/api/Term.java +++ b/src/api/java/io/github/cvc5/api/Term.java @@ -31,18 +31,13 @@ public class Term extends AbstractPointer implements Comparable<Term>, Iterable< super(solver, pointer); } - protected static native void deletePointer(long pointer); + protected native void deletePointer(long pointer); public long getPointer() { return pointer; } - @Override public void finalize() - { - deletePointer(pointer); - } - // endregion /** diff --git a/src/api/java/jni/datatype.cpp b/src/api/java/jni/datatype.cpp index 5efff9f2c..3f340c93c 100644 --- a/src/api/java/jni/datatype.cpp +++ b/src/api/java/jni/datatype.cpp @@ -25,7 +25,7 @@ using namespace cvc5::api; * Signature: (J)V */ JNIEXPORT void JNICALL Java_io_github_cvc5_api_Datatype_deletePointer( - JNIEnv* env, jclass, jlong pointer) + JNIEnv* env, jobject, jlong pointer) { delete ((Datatype*)pointer); } diff --git a/src/api/java/jni/datatype_constructor.cpp b/src/api/java/jni/datatype_constructor.cpp index 853766c3c..7fe5f21c6 100644 --- a/src/api/java/jni/datatype_constructor.cpp +++ b/src/api/java/jni/datatype_constructor.cpp @@ -26,7 +26,7 @@ using namespace cvc5::api; */ JNIEXPORT void JNICALL Java_io_github_cvc5_api_DatatypeConstructor_deletePointer(JNIEnv*, - jclass, + jobject, jlong pointer) { delete ((DatatypeConstructor*)pointer); diff --git a/src/api/java/jni/datatype_constructor_decl.cpp b/src/api/java/jni/datatype_constructor_decl.cpp index b13b75e45..75cdb7aca 100644 --- a/src/api/java/jni/datatype_constructor_decl.cpp +++ b/src/api/java/jni/datatype_constructor_decl.cpp @@ -26,7 +26,7 @@ using namespace cvc5::api; */ JNIEXPORT void JNICALL Java_io_github_cvc5_api_DatatypeConstructorDecl_deletePointer(JNIEnv*, - jclass, + jobject, jlong pointer) { delete ((DatatypeConstructorDecl*)pointer); diff --git a/src/api/java/jni/datatype_decl.cpp b/src/api/java/jni/datatype_decl.cpp index 845afac9d..1940c37e1 100644 --- a/src/api/java/jni/datatype_decl.cpp +++ b/src/api/java/jni/datatype_decl.cpp @@ -25,7 +25,7 @@ using namespace cvc5::api; * Signature: (J)V */ JNIEXPORT void JNICALL Java_io_github_cvc5_api_DatatypeDecl_deletePointer( - JNIEnv*, jclass, jlong pointer) + JNIEnv*, jobject, jlong pointer) { delete ((DatatypeDecl*)pointer); } diff --git a/src/api/java/jni/datatype_selector.cpp b/src/api/java/jni/datatype_selector.cpp index 964eb24f5..4a3358513 100644 --- a/src/api/java/jni/datatype_selector.cpp +++ b/src/api/java/jni/datatype_selector.cpp @@ -25,7 +25,7 @@ using namespace cvc5::api; * Signature: (J)V */ JNIEXPORT void JNICALL Java_io_github_cvc5_api_DatatypeSelector_deletePointer( - JNIEnv*, jclass, jlong pointer) + JNIEnv*, jobject, jlong pointer) { delete ((DatatypeSelector*)pointer); } diff --git a/src/api/java/jni/grammar.cpp b/src/api/java/jni/grammar.cpp index 4bafd54d6..751e5ffdd 100644 --- a/src/api/java/jni/grammar.cpp +++ b/src/api/java/jni/grammar.cpp @@ -40,7 +40,7 @@ Java_io_github_cvc5_api_Grammar_copyGrammar(JNIEnv* env, jclass, jlong pointer) * Signature: (J)V */ JNIEXPORT void JNICALL -Java_io_github_cvc5_api_Grammar_deletePointer(JNIEnv*, jclass, jlong pointer) +Java_io_github_cvc5_api_Grammar_deletePointer(JNIEnv*, jobject, jlong pointer) { delete reinterpret_cast<Grammar*>(pointer); } diff --git a/src/api/java/jni/op.cpp b/src/api/java/jni/op.cpp index cb6a7a728..f34444001 100644 --- a/src/api/java/jni/op.cpp +++ b/src/api/java/jni/op.cpp @@ -25,7 +25,7 @@ using namespace cvc5::api; * Signature: (J)V */ JNIEXPORT void JNICALL Java_io_github_cvc5_api_Op_deletePointer(JNIEnv*, - jclass, + jobject, jlong pointer) { delete reinterpret_cast<Op*>(pointer); diff --git a/src/api/java/jni/option_info.cpp b/src/api/java/jni/option_info.cpp index 031b1bae9..da2a485e3 100644 --- a/src/api/java/jni/option_info.cpp +++ b/src/api/java/jni/option_info.cpp @@ -24,8 +24,8 @@ using namespace cvc5::api; * Method: deletePointer * Signature: (J)V */ -JNIEXPORT void JNICALL -Java_io_github_cvc5_api_OptionInfo_deletePointer(JNIEnv*, jclass, jlong pointer) +JNIEXPORT void JNICALL Java_io_github_cvc5_api_OptionInfo_deletePointer( + JNIEnv*, jobject, jlong pointer) { delete reinterpret_cast<OptionInfo*>(pointer); } diff --git a/src/api/java/jni/result.cpp b/src/api/java/jni/result.cpp index 34b3262ca..0534f240e 100644 --- a/src/api/java/jni/result.cpp +++ b/src/api/java/jni/result.cpp @@ -25,7 +25,7 @@ using namespace cvc5::api; * Signature: (J)V */ JNIEXPORT void JNICALL -Java_io_github_cvc5_api_Result_deletePointer(JNIEnv*, jclass, jlong pointer) +Java_io_github_cvc5_api_Result_deletePointer(JNIEnv*, jobject, jlong pointer) { delete ((Result*)pointer); } diff --git a/src/api/java/jni/solver.cpp b/src/api/java/jni/solver.cpp index af3d7e59e..cb4d58591 100644 --- a/src/api/java/jni/solver.cpp +++ b/src/api/java/jni/solver.cpp @@ -1679,15 +1679,14 @@ JNIEXPORT jlong JNICALL Java_io_github_cvc5_api_Solver_declareSort( * Signature: (JLjava/lang/String;[JJJZ)J */ JNIEXPORT jlong JNICALL -Java_io_github_cvc5_api_Solver_defineFun__JLjava_lang_String_2_3JJJZ( - JNIEnv* env, - jobject, - jlong pointer, - jstring jSymbol, - jlongArray jVars, - jlong sortPointer, - jlong termPointer, - jboolean global) +Java_io_github_cvc5_api_Solver_defineFun(JNIEnv* env, + jobject, + jlong pointer, + jstring jSymbol, + jlongArray jVars, + jlong sortPointer, + jlong termPointer, + jboolean global) { CVC5_JAVA_API_TRY_CATCH_BEGIN; Solver* solver = reinterpret_cast<Solver*>(pointer); @@ -1705,31 +1704,6 @@ Java_io_github_cvc5_api_Solver_defineFun__JLjava_lang_String_2_3JJJZ( /* * Class: io_github_cvc5_api_Solver - * Method: defineFun - * Signature: (JJ[JJZ)J - */ -JNIEXPORT jlong JNICALL -Java_io_github_cvc5_api_Solver_defineFun__JJ_3JJZ(JNIEnv* env, - jobject, - jlong pointer, - jlong funPointer, - jlongArray jVars, - jlong termPointer, - jboolean global) -{ - CVC5_JAVA_API_TRY_CATCH_BEGIN; - Solver* solver = reinterpret_cast<Solver*>(pointer); - Term* fun = reinterpret_cast<Term*>(funPointer); - Term* term = reinterpret_cast<Term*>(termPointer); - std::vector<Term> vars = getObjectsFromPointers<Term>(env, jVars); - Term* retPointer = - new Term(solver->defineFun(*fun, vars, *term, (bool)global)); - return reinterpret_cast<jlong>(retPointer); - CVC5_JAVA_API_TRY_CATCH_END_RETURN(env, 0); -} - -/* - * Class: io_github_cvc5_api_Solver * Method: defineFunRec * Signature: (JLjava/lang/String;[JJJZ)J */ @@ -2132,50 +2106,50 @@ Java_io_github_cvc5_api_Solver_getQuantifierEliminationDisjunct(JNIEnv* env, /* * Class: io_github_cvc5_api_Solver - * Method: declareSeparationHeap + * Method: declareSepHeap * Signature: (JJJ)V */ JNIEXPORT void JNICALL -Java_io_github_cvc5_api_Solver_declareSeparationHeap(JNIEnv* env, - jobject, - jlong pointer, - jlong locSortPointer, - jlong dataSortPointer) +Java_io_github_cvc5_api_Solver_declareSepHeap(JNIEnv* env, + jobject, + jlong pointer, + jlong locSortPointer, + jlong dataSortPointer) { CVC5_JAVA_API_TRY_CATCH_BEGIN; Solver* solver = reinterpret_cast<Solver*>(pointer); Sort* locSort = reinterpret_cast<Sort*>(locSortPointer); Sort* dataSort = reinterpret_cast<Sort*>(dataSortPointer); - solver->declareSeparationHeap(*locSort, *dataSort); + solver->declareSepHeap(*locSort, *dataSort); CVC5_JAVA_API_TRY_CATCH_END(env); } /* * Class: io_github_cvc5_api_Solver - * Method: getSeparationHeap + * Method: getValueSepHeap * Signature: (J)J */ -JNIEXPORT jlong JNICALL Java_io_github_cvc5_api_Solver_getSeparationHeap( +JNIEXPORT jlong JNICALL Java_io_github_cvc5_api_Solver_getValueSepHeap( JNIEnv* env, jobject, jlong pointer) { CVC5_JAVA_API_TRY_CATCH_BEGIN; Solver* solver = reinterpret_cast<Solver*>(pointer); - Term* retPointer = new Term(solver->getSeparationHeap()); + Term* retPointer = new Term(solver->getValueSepHeap()); return reinterpret_cast<jlong>(retPointer); CVC5_JAVA_API_TRY_CATCH_END_RETURN(env, 0); } /* * Class: io_github_cvc5_api_Solver - * Method: getSeparationNilTerm + * Method: getValueSepNil * Signature: (J)J */ -JNIEXPORT jlong JNICALL Java_io_github_cvc5_api_Solver_getSeparationNilTerm( +JNIEXPORT jlong JNICALL Java_io_github_cvc5_api_Solver_getValueSepNil( JNIEnv* env, jobject, jlong pointer) { CVC5_JAVA_API_TRY_CATCH_BEGIN; Solver* solver = reinterpret_cast<Solver*>(pointer); - Term* retPointer = new Term(solver->getSeparationNilTerm()); + Term* retPointer = new Term(solver->getValueSepNil()); return reinterpret_cast<jlong>(retPointer); CVC5_JAVA_API_TRY_CATCH_END_RETURN(env, 0); } diff --git a/src/api/java/jni/sort.cpp b/src/api/java/jni/sort.cpp index e5b4f06fe..2c7ee4fd0 100644 --- a/src/api/java/jni/sort.cpp +++ b/src/api/java/jni/sort.cpp @@ -25,7 +25,7 @@ using namespace cvc5::api; * Signature: (J)V */ JNIEXPORT void JNICALL Java_io_github_cvc5_api_Sort_deletePointer(JNIEnv*, - jclass, + jobject, jlong pointer) { delete reinterpret_cast<Sort*>(pointer); @@ -655,7 +655,7 @@ Java_io_github_cvc5_api_Sort_getConstructorDomainSorts(JNIEnv* env, std::vector<jlong> sortPointers(sorts.size()); for (size_t i = 0; i < sorts.size(); i++) { - sortPointers[i] = reinterpret_cast<jlong> (new Sort(sorts[i])); + sortPointers[i] = reinterpret_cast<jlong>(new Sort(sorts[i])); } jlongArray ret = env->NewLongArray(sorts.size()); env->SetLongArrayRegion(ret, 0, sorts.size(), sortPointers.data()); diff --git a/src/api/java/jni/stat.cpp b/src/api/java/jni/stat.cpp index 5db362ce2..8b9efbd3f 100644 --- a/src/api/java/jni/stat.cpp +++ b/src/api/java/jni/stat.cpp @@ -25,7 +25,7 @@ using namespace cvc5::api; * Signature: (J)V */ JNIEXPORT void JNICALL Java_io_github_cvc5_api_Stat_deletePointer(JNIEnv*, - jclass, + jobject, jlong pointer) { delete reinterpret_cast<Stat*>(pointer); diff --git a/src/api/java/jni/statistics.cpp b/src/api/java/jni/statistics.cpp index 827c3184a..dfea8bf9d 100644 --- a/src/api/java/jni/statistics.cpp +++ b/src/api/java/jni/statistics.cpp @@ -26,8 +26,8 @@ using namespace cvc5::api; * Method: deletePointer * Signature: (J)V */ -JNIEXPORT void JNICALL -Java_io_github_cvc5_api_Statistics_deletePointer(JNIEnv*, jclass, jlong pointer) +JNIEXPORT void JNICALL Java_io_github_cvc5_api_Statistics_deletePointer( + JNIEnv*, jobject, jlong pointer) { delete reinterpret_cast<Statistics*>(pointer); } diff --git a/src/api/java/jni/term.cpp b/src/api/java/jni/term.cpp index 5c8300e17..d54b0a2b5 100644 --- a/src/api/java/jni/term.cpp +++ b/src/api/java/jni/term.cpp @@ -25,7 +25,7 @@ using namespace cvc5::api; * Signature: (J)V */ JNIEXPORT void JNICALL Java_io_github_cvc5_api_Term_deletePointer(JNIEnv* env, - jclass, + jobject, jlong pointer) { delete reinterpret_cast<Term*>(pointer); diff --git a/src/api/python/CMakeLists.txt b/src/api/python/CMakeLists.txt index 74d1d84fc..96fcd67a0 100644 --- a/src/api/python/CMakeLists.txt +++ b/src/api/python/CMakeLists.txt @@ -95,13 +95,25 @@ target_include_directories(pycvc5 target_link_libraries(pycvc5 cvc5-shared) # Disable -Werror and other warnings for code generated by Cython. +set(PY_SRC_FLAGS "") +check_cxx_compiler_flag("-Werror" HAVE_CXX_FLAGWerror) +if(HAVE_CXX_FLAGWerror) + set(PY_SRC_FLAGS "${PY_SRC_FLAGS} -Wno-error") +endif() +check_cxx_compiler_flag("-Wshadow" HAVE_CXX_FLAGWshadow) +if(HAVE_CXX_FLAGWshadow) + set(PY_SRC_FLAGS "${PY_SRC_FLAGS} -Wno-shadow") +endif() +check_cxx_compiler_flag("-Wimplicit-fallthrough" HAVE_CXX_FLAGWimplicit_fallthrough) +if(HAVE_CXX_FLAGWimplicit_fallthrough) + set(PY_SRC_FLAGS "${PY_SRC_FLAGS} -Wno-implicit-fallthrough") +endif() # Note: Visibility is reset to default here since otherwise the PyInit_... # function will not be exported correctly # (https://github.com/cython/cython/issues/3380). set_target_properties(pycvc5 PROPERTIES - COMPILE_FLAGS - "-Wno-error -Wno-shadow -Wno-implicit-fallthrough" + COMPILE_FLAGS "${PY_SRC_FLAGS}" CXX_VISIBILITY_PRESET default VISIBILITY_INLINES_HIDDEN 0 LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/pycvc5") diff --git a/src/api/python/cvc5.pxd b/src/api/python/cvc5.pxd index 42aee08b0..a2c238985 100644 --- a/src/api/python/cvc5.pxd +++ b/src/api/python/cvc5.pxd @@ -266,7 +266,6 @@ cdef extern from "api/cpp/cvc5.h" namespace "cvc5::api": Sort declareSort(const string& symbol, uint32_t arity) except + Term defineFun(const string& symbol, const vector[Term]& bound_vars, Sort sort, Term term, bint glbl) except + - Term defineFun(Term fun, const vector[Term]& bound_vars, Term term, bint glbl) except + Term defineFunRec(const string& symbol, const vector[Term]& bound_vars, Sort sort, Term term, bint glbl) except + Term defineFunRec(Term fun, const vector[Term]& bound_vars, @@ -282,9 +281,9 @@ cdef extern from "api/cpp/cvc5.h" namespace "cvc5::api": vector[Term] getValue(const vector[Term]& terms) except + vector[Term] getModelDomainElements(Sort sort) except + bint isModelCoreSymbol(Term v) except + - void declareSeparationHeap(Sort locSort, Sort dataSort) except + - Term getSeparationHeap() except + - Term getSeparationNilTerm() except + + void declareSepHeap(Sort locSort, Sort dataSort) except + + Term getValueSepHeap() except + + Term getValueSepNil() except + Term declarePool(const string& name, Sort sort, vector[Term]& initValue) except + void pop(uint32_t nscopes) except + void push(uint32_t nscopes) except + diff --git a/src/api/python/cvc5.pxi b/src/api/python/cvc5.pxi index 3367bf47b..05138e9bc 100644 --- a/src/api/python/cvc5.pxi +++ b/src/api/python/cvc5.pxi @@ -1811,14 +1811,8 @@ cdef class Solver: sort.csort = self.csolver.declareSort(symbol.encode(), arity) return sort - def defineFun(self, sym_or_fun, bound_vars, sort_or_term, t=None, glbl=False): - """ - Define n-ary function. - Supports two uses: - - - ``Term defineFun(str symbol, List[Term] bound_vars, Sort sort, Term term, bool glbl)`` - - ``Term defineFun(Term fun, List[Term] bound_vars, Term term, bool glbl)`` - + def defineFun(self, str symbol, list bound_vars, Sort sort, Term term, glbl=False): + """Define n-ary function. SMT-LIB: @@ -1830,27 +1824,20 @@ cdef class Solver: :param bound_vars: the parameters to this function :param sort: the sort of the return value of this function :param term: the function body - :param global: determines whether this definition is global (i.e. persists when popping the context) + :param glbl: determines whether this definition is global (i.e. persists when popping the context) :return: the function """ - cdef Term term = Term(self) + cdef Term fun = Term(self) cdef vector[c_Term] v for bv in bound_vars: v.push_back((<Term?> bv).cterm) - if t is not None: - term.cterm = self.csolver.defineFun((<str?> sym_or_fun).encode(), - <const vector[c_Term] &> v, - (<Sort?> sort_or_term).csort, - (<Term?> t).cterm, - <bint> glbl) - else: - term.cterm = self.csolver.defineFun((<Term?> sym_or_fun).cterm, - <const vector[c_Term]&> v, - (<Term?> sort_or_term).cterm, - <bint> glbl) - - return term + fun.cterm = self.csolver.defineFun(symbol.encode(), + <const vector[c_Term] &> v, + sort.csort, + term.cterm, + <bint> glbl) + return fun def defineFunRec(self, sym_or_fun, bound_vars, sort_or_term, t=None, glbl=False): """Define recursive functions. @@ -2060,25 +2047,25 @@ cdef class Solver: """ return self.csolver.isModelCoreSymbol(v.cterm) - def getSeparationHeap(self): + def getValueSepHeap(self): """When using separation logic, obtain the term for the heap. :return: The term for the heap """ cdef Term term = Term(self) - term.cterm = self.csolver.getSeparationHeap() + term.cterm = self.csolver.getValueSepHeap() return term - def getSeparationNilTerm(self): + def getValueSepNil(self): """When using separation logic, obtain the term for nil. :return: The term for nil """ cdef Term term = Term(self) - term.cterm = self.csolver.getSeparationNilTerm() + term.cterm = self.csolver.getValueSepNil() return term - def declareSeparationHeap(self, Sort locType, Sort dataType): + def declareSepHeap(self, Sort locType, Sort dataType): """ When using separation logic, this sets the location sort and the datatype sort to the given ones. This method should be invoked exactly @@ -2087,7 +2074,7 @@ cdef class Solver: :param locSort: The location sort of the heap :param dataSort: The data sort of the heap """ - self.csolver.declareSeparationHeap(locType.csort, dataType.csort) + self.csolver.declareSepHeap(locType.csort, dataType.csort) def declarePool(self, str symbol, Sort sort, initValue): """Declare a symbolic pool of terms with the given initial value. diff --git a/src/base/configuration.cpp b/src/base/configuration.cpp index c9e650117..6a289ec92 100644 --- a/src/base/configuration.cpp +++ b/src/base/configuration.cpp @@ -110,16 +110,10 @@ std::string Configuration::copyright() { << " See https://github.com/arminbiere/cadical for copyright " << "information.\n\n"; - if (Configuration::isBuiltWithAbc() - || Configuration::isBuiltWithCryptominisat() + if (Configuration::isBuiltWithCryptominisat() || Configuration::isBuiltWithKissat() || Configuration::isBuiltWithEditline()) { - if (Configuration::isBuiltWithAbc()) { - ss << " ABC - A System for Sequential Synthesis and Verification\n" - << " See http://bitbucket.org/alanmi/abc for copyright and\n" - << " licensing information.\n\n"; - } if (Configuration::isBuiltWithCryptominisat()) { ss << " CryptoMiniSat - An Advanced SAT Solver\n" @@ -219,10 +213,6 @@ bool Configuration::isBuiltWithGlpk() { return IS_GLPK_BUILD; } -bool Configuration::isBuiltWithAbc() { - return IS_ABC_BUILD; -} - bool Configuration::isBuiltWithCryptominisat() { return IS_CRYPTOMINISAT_BUILD; } diff --git a/src/base/configuration.h b/src/base/configuration.h index f9a21f77a..a15a52784 100644 --- a/src/base/configuration.h +++ b/src/base/configuration.h @@ -95,8 +95,6 @@ public: static bool isBuiltWithGlpk(); - static bool isBuiltWithAbc(); - static bool isBuiltWithCryptominisat(); static bool isBuiltWithKissat(); diff --git a/src/base/configuration_private.h b/src/base/configuration_private.h index b348da380..0f4384ddd 100644 --- a/src/base/configuration_private.h +++ b/src/base/configuration_private.h @@ -90,12 +90,6 @@ namespace cvc5 { # define IS_GLPK_BUILD false #endif /* CVC5_USE_GLPK */ -#if CVC5_USE_ABC -# define IS_ABC_BUILD true -#else /* CVC5_USE_ABC */ -# define IS_ABC_BUILD false -#endif /* CVC5_USE_ABC */ - #if CVC5_USE_CRYPTOMINISAT # define IS_CRYPTOMINISAT_BUILD true #else /* CVC5_USE_CRYPTOMINISAT */ diff --git a/src/decision/decision_engine_old.cpp b/src/decision/decision_engine_old.cpp index 120fc730b..261d78fdf 100644 --- a/src/decision/decision_engine_old.cpp +++ b/src/decision/decision_engine_old.cpp @@ -30,7 +30,7 @@ DecisionEngineOld::DecisionEngineOld(Env& env) d_result(context(), SAT_VALUE_UNKNOWN), d_engineState(0), d_enabledITEStrategy(nullptr), - d_decisionStopOnly(options::decisionMode() + d_decisionStopOnly(options().decision.decisionMode == options::DecisionMode::STOPONLY_OLD) { Trace("decision") << "Creating decision engine" << std::endl; @@ -39,11 +39,11 @@ DecisionEngineOld::DecisionEngineOld(Env& env) Trace("decision-init") << "DecisionEngineOld::init()" << std::endl; Trace("decision-init") << " * options->decisionMode: " - << options::decisionMode() << std::endl; + << options().decision.decisionMode << std::endl; Trace("decision-init") << " * decisionStopOnly: " << d_decisionStopOnly << std::endl; - if (options::decisionMode() == options::DecisionMode::JUSTIFICATION) + if (options().decision.decisionMode == options::DecisionMode::JUSTIFICATION) { d_enabledITEStrategy.reset(new decision::JustificationHeuristic(env, this)); } diff --git a/src/decision/justification_heuristic.cpp b/src/decision/justification_heuristic.cpp index e04de9ce1..cadb107c3 100644 --- a/src/decision/justification_heuristic.cpp +++ b/src/decision/justification_heuristic.cpp @@ -62,10 +62,11 @@ JustificationHeuristic::~JustificationHeuristic() {} cvc5::prop::SatLiteral JustificationHeuristic::getNext(bool& stopSearch) { - if(options::decisionThreshold() > 0) { + if (options().decision.decisionThreshold > 0) + { bool stopSearchTmp = false; prop::SatLiteral lit = - getNextThresh(stopSearchTmp, options::decisionThreshold()); + getNextThresh(stopSearchTmp, options().decision.decisionThreshold); if (lit != prop::undefSatLiteral) { Assert(stopSearchTmp == false); @@ -252,7 +253,7 @@ DecisionWeight JustificationHeuristic::getWeightPolarized(TNode n, SatValue satV DecisionWeight JustificationHeuristic::getWeightPolarized(TNode n, bool polarity) { - if (options::decisionWeightInternal() + if (options().decision.decisionWeightInternal != options::DecisionWeightInternal::USR1) { return getWeight(n); @@ -304,15 +305,16 @@ DecisionWeight JustificationHeuristic::getWeightPolarized(TNode n, bool polarity DecisionWeight JustificationHeuristic::getWeight(TNode n) { if(!n.hasAttribute(DecisionWeightAttr()) ) { options::DecisionWeightInternal combiningFn = - options::decisionWeightInternal(); + options().decision.decisionWeightInternal; if (combiningFn == options::DecisionWeightInternal::OFF || n.getNumChildren() == 0) { - if (options::decisionRandomWeight() != 0) + if (options().decision.decisionRandomWeight != 0) { n.setAttribute(DecisionWeightAttr(), - Random::getRandom().pick(0, options::decisionRandomWeight()-1)); + Random::getRandom().pick( + 0, options().decision.decisionRandomWeight - 1)); } } else if (combiningFn == options::DecisionWeightInternal::MAX) @@ -340,7 +342,8 @@ DecisionWeight JustificationHeuristic::getWeight(TNode n) { typedef std::vector<TNode> ChildList; TNode JustificationHeuristic::getChildByWeight(TNode n, int i, bool polarity) { - if(options::decisionUseWeight()) { + if (options().decision.decisionUseWeight) + { // TODO: Optimize storing & access if(d_childCache.find(n) == d_childCache.end()) { ChildList list0(n.begin(), n.end()), list1(n.begin(), n.end()); @@ -349,7 +352,9 @@ TNode JustificationHeuristic::getChildByWeight(TNode n, int i, bool polarity) { d_childCache[n] = make_pair(list0, list1); } return polarity ? d_childCache[n].get().second[i] : d_childCache[n].get().first[i]; - } else { + } + else + { return n[i]; } } @@ -612,8 +617,10 @@ JustificationHeuristic::SearchResult JustificationHeuristic::handleBinaryEasy(TN TNode node2, SatValue desiredVal2) { - if(options::decisionUseWeight() && - getWeightPolarized(node1, desiredVal1) > getWeightPolarized(node2, desiredVal2)) { + if (options().decision.decisionUseWeight + && getWeightPolarized(node1, desiredVal1) + > getWeightPolarized(node2, desiredVal2)) + { std::swap(node1, node2); std::swap(desiredVal1, desiredVal2); } @@ -637,8 +644,10 @@ JustificationHeuristic::SearchResult JustificationHeuristic::handleBinaryHard(TN TNode node2, SatValue desiredVal2) { - if(options::decisionUseWeight() && - getWeightPolarized(node1, desiredVal1) > getWeightPolarized(node2, desiredVal2)) { + if (options().decision.decisionUseWeight + && getWeightPolarized(node1, desiredVal1) + > getWeightPolarized(node2, desiredVal2)) + { std::swap(node1, node2); std::swap(desiredVal1, desiredVal2); } @@ -673,13 +682,17 @@ JustificationHeuristic::SearchResult JustificationHeuristic::handleITE(TNode nod if(trueChildVal == desiredVal || falseChildVal == invertValue(desiredVal)) { ifDesiredVal = SAT_VALUE_TRUE; - } else if(trueChildVal == invertValue(desiredVal) || - falseChildVal == desiredVal || - (options::decisionUseWeight() && - getWeightPolarized(node[1], true) > getWeightPolarized(node[2], false)) - ) { + } + else if (trueChildVal == invertValue(desiredVal) + || falseChildVal == desiredVal + || (options().decision.decisionUseWeight + && getWeightPolarized(node[1], true) + > getWeightPolarized(node[2], false))) + { ifDesiredVal = SAT_VALUE_FALSE; - } else { + } + else + { ifDesiredVal = SAT_VALUE_TRUE; } diff --git a/src/decision/justification_heuristic.h b/src/decision/justification_heuristic.h index 303f1a63b..fbba2e33a 100644 --- a/src/decision/justification_heuristic.h +++ b/src/decision/justification_heuristic.h @@ -150,7 +150,7 @@ private: int getPrvsIndex(); DecisionWeight getWeightPolarized(TNode n, bool polarity); DecisionWeight getWeightPolarized(TNode n, prop::SatValue); - static DecisionWeight getWeight(TNode); + DecisionWeight getWeight(TNode); bool compareByWeightFalse(TNode, TNode); bool compareByWeightTrue(TNode, TNode); TNode getChildByWeight(TNode n, int i, bool polarity); diff --git a/src/decision/justification_strategy.cpp b/src/decision/justification_strategy.cpp index d65936964..bced3d662 100644 --- a/src/decision/justification_strategy.cpp +++ b/src/decision/justification_strategy.cpp @@ -28,18 +28,19 @@ JustificationStrategy::JustificationStrategy(Env& env) d_assertions( userContext(), context(), - options::jhRlvOrder()), // assertions are user-context dependent + options() + .decision.jhRlvOrder), // assertions are user-context dependent d_skolemAssertions( context(), context()), // skolem assertions are SAT-context dependent d_justified(context()), d_stack(context()), d_lastDecisionLit(context()), d_currStatusDec(false), - d_useRlvOrder(options::jhRlvOrder()), - d_decisionStopOnly(options::decisionMode() + d_useRlvOrder(options().decision.jhRlvOrder), + d_decisionStopOnly(options().decision.decisionMode == options::DecisionMode::STOPONLY), - d_jhSkMode(options::jhSkolemMode()), - d_jhSkRlvMode(options::jhSkolemRlvMode()) + d_jhSkMode(options().decision.jhSkolemMode), + d_jhSkRlvMode(options().decision.jhSkolemRlvMode) { } diff --git a/src/expr/dtype.cpp b/src/expr/dtype.cpp index d8ec0cb61..4a0ed994f 100644 --- a/src/expr/dtype.cpp +++ b/src/expr/dtype.cpp @@ -867,10 +867,7 @@ Node DType::getSharedSelector(TypeNode dtt, TypeNode t, size_t index) const SkolemManager* sm = nm->getSkolemManager(); TypeNode stype = nm->mkSelectorType(dtt, t); Node nindex = nm->mkConst(Rational(index)); - s = sm->mkSkolemFunction(SkolemFunId::SHARED_SELECTOR, - stype, - nindex, - NodeManager::SKOLEM_NO_NOTIFY); + s = sm->mkSkolemFunction(SkolemFunId::SHARED_SELECTOR, stype, nindex); d_sharedSel[dtt][t][index] = s; Trace("dt-shared-sel") << "Made " << s << " of type " << dtt << " -> " << t << std::endl; diff --git a/src/expr/dtype_cons.cpp b/src/expr/dtype_cons.cpp index ddb88499b..f23cfa4f9 100644 --- a/src/expr/dtype_cons.cpp +++ b/src/expr/dtype_cons.cpp @@ -49,11 +49,10 @@ void DTypeConstructor::addArg(std::string selectorName, TypeNode selectorType) Assert(!isResolved()); Assert(!selectorType.isNull()); SkolemManager* sm = NodeManager::currentNM()->getSkolemManager(); - Node sel = sm->mkDummySkolem( - "unresolved_" + selectorName, - selectorType, - "is an unresolved selector type placeholder", - NodeManager::SKOLEM_EXACT_NAME | NodeManager::SKOLEM_NO_NOTIFY); + Node sel = sm->mkDummySkolem("unresolved_" + selectorName, + selectorType, + "is an unresolved selector type placeholder", + SkolemManager::SKOLEM_EXACT_NAME); // can use null updater for now Node nullNode; Trace("datatypes") << "DTypeConstructor::addArg: " << sel << std::endl; @@ -562,17 +561,15 @@ bool DTypeConstructor::resolve( } // Internally, selectors (and updaters) are fresh internal skolems which // we constructor via mkDummySkolem. - arg->d_selector = sm->mkDummySkolem( - argName, - nm->mkSelectorType(self, range), - "is a selector", - NodeManager::SKOLEM_EXACT_NAME | NodeManager::SKOLEM_NO_NOTIFY); + arg->d_selector = sm->mkDummySkolem(argName, + nm->mkSelectorType(self, range), + "is a selector", + SkolemManager::SKOLEM_EXACT_NAME); std::string updateName("update_" + argName); - arg->d_updater = sm->mkDummySkolem( - updateName, - nm->mkDatatypeUpdateType(self, range), - "is a selector", - NodeManager::SKOLEM_EXACT_NAME | NodeManager::SKOLEM_NO_NOTIFY); + arg->d_updater = sm->mkDummySkolem(updateName, + nm->mkDatatypeUpdateType(self, range), + "is a selector", + SkolemManager::SKOLEM_EXACT_NAME); // must set indices to ensure datatypes::utils::indexOf works arg->d_selector.setAttribute(DTypeConsIndexAttr(), cindex); arg->d_selector.setAttribute(DTypeIndexAttr(), index); @@ -600,16 +597,14 @@ bool DTypeConstructor::resolve( // The name of the tester variable does not matter, it is only used // internally. std::string testerName("is_" + d_name); - d_tester = sm->mkDummySkolem( - testerName, - nm->mkTesterType(self), - "is a tester", - NodeManager::SKOLEM_EXACT_NAME | NodeManager::SKOLEM_NO_NOTIFY); - d_constructor = sm->mkDummySkolem( - getName(), - nm->mkConstructorType(argTypes, self), - "is a constructor", - NodeManager::SKOLEM_EXACT_NAME | NodeManager::SKOLEM_NO_NOTIFY); + d_tester = sm->mkDummySkolem(testerName, + nm->mkTesterType(self), + "is a tester", + SkolemManager::SKOLEM_EXACT_NAME); + d_constructor = sm->mkDummySkolem(getName(), + nm->mkConstructorType(argTypes, self), + "is a constructor", + SkolemManager::SKOLEM_EXACT_NAME); Assert(d_constructor.getType().isConstructor()); // associate constructor with all selectors for (std::shared_ptr<DTypeSelector> sel : d_args) diff --git a/src/expr/node_converter.cpp b/src/expr/node_converter.cpp index 92b459105..eabe1d4f1 100644 --- a/src/expr/node_converter.cpp +++ b/src/expr/node_converter.cpp @@ -25,6 +25,10 @@ NodeConverter::NodeConverter(bool forceIdem) : d_forceIdem(forceIdem) {} Node NodeConverter::convert(Node n) { + if (n.isNull()) + { + return n; + } Trace("nconv-debug") << "NodeConverter::convert: " << n << std::endl; NodeManager* nm = NodeManager::currentNM(); std::unordered_map<Node, Node>::iterator it; diff --git a/src/expr/node_converter.h b/src/expr/node_converter.h index 6edb2522c..a2aaeca6f 100644 --- a/src/expr/node_converter.h +++ b/src/expr/node_converter.h @@ -46,6 +46,8 @@ class NodeConverter /** * This converts node n based on the preConvert/postConvert methods that can * be overriden by instances of this class. + * + * If n is null, this always returns the null node. */ Node convert(Node n); diff --git a/src/expr/node_manager.cpp b/src/expr/node_manager.cpp index a9e5854b0..3734e5860 100644 --- a/src/expr/node_manager.cpp +++ b/src/expr/node_manager.cpp @@ -100,8 +100,7 @@ NodeManager::NodeManager() d_attrManager(new expr::attr::AttributeManager()), d_nodeUnderDeletion(nullptr), d_inReclaimZombies(false), - d_abstractValueCount(0), - d_skolemCounter(0) + d_abstractValueCount(0) { } @@ -503,25 +502,6 @@ TypeNode NodeManager::getType(TNode n, bool check) return typeNode; } -Node NodeManager::mkSkolem(const std::string& prefix, const TypeNode& type, const std::string& comment, int flags) { - Node n = NodeBuilder(this, kind::SKOLEM); - setAttribute(n, TypeAttr(), type); - setAttribute(n, TypeCheckedAttr(), true); - if((flags & SKOLEM_EXACT_NAME) == 0) { - stringstream name; - name << prefix << '_' << ++d_skolemCounter; - setAttribute(n, expr::VarNameAttr(), name.str()); - } else { - setAttribute(n, expr::VarNameAttr(), prefix); - } - if((flags & SKOLEM_NO_NOTIFY) == 0) { - for(vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) { - (*i)->nmNotifyNewSkolem(n, comment, (flags & SKOLEM_IS_GLOBAL) == SKOLEM_IS_GLOBAL); - } - } - return n; -} - TypeNode NodeManager::mkBagType(TypeNode elementType) { CheckArgument( @@ -1061,13 +1041,6 @@ Node NodeManager::mkInstConstant(const TypeNode& type) { return n; } -Node NodeManager::mkBooleanTermVariable() { - Node n = NodeBuilder(this, kind::BOOLEAN_TERM_VARIABLE); - n.setAttribute(TypeAttr(), booleanType()); - n.setAttribute(TypeCheckedAttr(), true); - return n; -} - Node NodeManager::mkNullaryOperator(const TypeNode& type, Kind k) { std::map< TypeNode, Node >::iterator it = d_unique_vars[k].find( type ); if( it==d_unique_vars[k].end() ){ diff --git a/src/expr/node_manager.h b/src/expr/node_manager.h index b526efc80..5b5f07e6f 100644 --- a/src/expr/node_manager.h +++ b/src/expr/node_manager.h @@ -72,8 +72,6 @@ class NodeManagerListener { { } virtual void nmNotifyNewVar(TNode n) {} - virtual void nmNotifyNewSkolem(TNode n, const std::string& comment, - uint32_t flags) {} /** * Notify a listener of a Node that's being GCed. If this function stores a * reference @@ -212,15 +210,6 @@ class NodeManager unsigned d_abstractValueCount; /** - * A counter used to produce unique skolem names. - * - * Note that it is NOT incremented when skolems are created using - * SKOLEM_EXACT_NAME, so it is NOT a count of the skolems produced - * by this node manager. - */ - unsigned d_skolemCounter; - - /** * Look up a NodeValue in the pool associated to this NodeManager. * The NodeValue argument need not be a "completely-constructed" * NodeValue. In particular, "non-inlined" constants are permitted @@ -365,19 +354,6 @@ class NodeManager /** Create a variable with the given type. */ Node mkVar(const TypeNode& type); - /** - * Create a skolem constant with the given name, type, and comment. For - * details, see SkolemManager::mkDummySkolem, which calls this method. - * - * This method is intentionally private. To create skolems, one should - * call a method from SkolemManager for allocating a skolem in a standard - * way, or otherwise use SkolemManager::mkDummySkolem. - */ - Node mkSkolem(const std::string& prefix, - const TypeNode& type, - const std::string& comment = "", - int flags = SKOLEM_DEFAULT); - public: /** * Initialize the node manager by adding a null node to the pool and filling @@ -555,27 +531,9 @@ class NodeManager */ Node mkChain(Kind kind, const std::vector<Node>& children); - /** - * Optional flags used to control behavior of NodeManager::mkSkolem(). - * They should be composed with a bitwise OR (e.g., - * "SKOLEM_NO_NOTIFY | SKOLEM_EXACT_NAME"). Of course, SKOLEM_DEFAULT - * cannot be composed in such a manner. - */ - enum SkolemFlags - { - SKOLEM_DEFAULT = 0, /**< default behavior */ - SKOLEM_NO_NOTIFY = 1, /**< do not notify subscribers */ - SKOLEM_EXACT_NAME = 2, /**< do not make the name unique by adding the id */ - SKOLEM_IS_GLOBAL = 4, /**< global vars appear in models even after a pop */ - SKOLEM_BOOL_TERM_VAR = 8 /**< vars requiring kind BOOLEAN_TERM_VARIABLE */ - }; /* enum SkolemFlags */ - /** Create a instantiation constant with the given type. */ Node mkInstConstant(const TypeNode& type); - /** Create a boolean term variable. */ - Node mkBooleanTermVariable(); - /** Make a new abstract value with the given type. */ Node mkAbstractValue(const TypeNode& type); diff --git a/src/expr/skolem_manager.cpp b/src/expr/skolem_manager.cpp index 80626fbc6..c1741beac 100644 --- a/src/expr/skolem_manager.cpp +++ b/src/expr/skolem_manager.cpp @@ -20,6 +20,7 @@ #include "expr/attribute.h" #include "expr/bound_var_manager.h" #include "expr/node_algorithm.h" +#include "expr/node_manager_attributes.h" using namespace cvc5::kind; @@ -53,6 +54,18 @@ const char* toString(SkolemFunId id) case SkolemFunId::SELECTOR_WRONG: return "SELECTOR_WRONG"; case SkolemFunId::SHARED_SELECTOR: return "SHARED_SELECTOR"; case SkolemFunId::SEQ_NTH_OOB: return "SEQ_NTH_OOB"; + case SkolemFunId::STRINGS_NUM_OCCUR: return "STRINGS_NUM_OCCUR"; + case SkolemFunId::STRINGS_OCCUR_INDEX: return "STRINGS_OCCUR_INDEX"; + case SkolemFunId::STRINGS_OCCUR_LEN: return "STRINGS_OCCUR_LEN"; + case SkolemFunId::STRINGS_DEQ_DIFF: return "STRINGS_DEQ_DIFF"; + case SkolemFunId::STRINGS_REPLACE_ALL_RESULT: + return "STRINGS_REPLACE_ALL_RESULT"; + case SkolemFunId::STRINGS_ITOS_RESULT: return "STRINGS_ITOS_RESULT"; + case SkolemFunId::STRINGS_STOI_RESULT: return "STRINGS_STOI_RESULT"; + case SkolemFunId::STRINGS_STOI_NON_DIGIT: return "STRINGS_STOI_NON_DIGIT"; + case SkolemFunId::SK_FIRST_MATCH_PRE: return "SK_FIRST_MATCH_PRE"; + case SkolemFunId::SK_FIRST_MATCH: return "SK_FIRST_MATCH"; + case SkolemFunId::SK_FIRST_MATCH_POST: return "SK_FIRST_MATCH_POST"; case SkolemFunId::RE_UNFOLD_POS_COMPONENT: return "RE_UNFOLD_POS_COMPONENT"; case SkolemFunId::BAGS_MAP_PREIMAGE: return "BAGS_MAP_PREIMAGE"; case SkolemFunId::BAGS_MAP_SUM: return "BAGS_MAP_SUM"; @@ -67,6 +80,8 @@ std::ostream& operator<<(std::ostream& out, SkolemFunId id) return out; } +SkolemManager::SkolemManager() : d_skolemCounter(0) {} + Node SkolemManager::mkSkolem(Node v, Node pred, const std::string& prefix, @@ -205,10 +220,9 @@ Node SkolemManager::mkSkolemFunction(SkolemFunId id, d_skolemFuns.find(key); if (it == d_skolemFuns.end()) { - NodeManager* nm = NodeManager::currentNM(); std::stringstream ss; ss << "SKOLEM_FUN_" << id; - Node k = nm->mkSkolem(ss.str(), tn, "an internal skolem function", flags); + Node k = mkSkolemNode(ss.str(), tn, "an internal skolem function", flags); d_skolemFuns[key] = k; d_skolemFunMap[k] = key; return k; @@ -221,8 +235,14 @@ Node SkolemManager::mkSkolemFunction(SkolemFunId id, const std::vector<Node>& cacheVals, int flags) { - Assert(cacheVals.size() > 1); - Node cacheVal = NodeManager::currentNM()->mkNode(SEXPR, cacheVals); + Node cacheVal; + // use null node if cacheVals is empty + if (!cacheVals.empty()) + { + cacheVal = cacheVals.size() == 1 + ? cacheVals[0] + : NodeManager::currentNM()->mkNode(SEXPR, cacheVals); + } return mkSkolemFunction(id, tn, cacheVal, flags); } @@ -246,7 +266,7 @@ Node SkolemManager::mkDummySkolem(const std::string& prefix, const std::string& comment, int flags) { - return NodeManager::currentNM()->mkSkolem(prefix, type, comment, flags); + return mkSkolemNode(prefix, type, comment, flags); } ProofGenerator* SkolemManager::getProofGenerator(Node t) const @@ -349,25 +369,15 @@ Node SkolemManager::mkSkolemInternal(Node w, int flags) { // note that witness, original forms are independent, but share skolems - NodeManager* nm = NodeManager::currentNM(); // w is not necessarily a witness term SkolemFormAttribute sfa; - Node k; // could already have a skolem if we used w already if (w.hasAttribute(sfa)) { return w.getAttribute(sfa); } // make the new skolem - if (flags & NodeManager::SKOLEM_BOOL_TERM_VAR) - { - Assert (w.getType().isBoolean()); - k = nm->mkBooleanTermVariable(); - } - else - { - k = nm->mkSkolem(prefix, w.getType(), comment, flags); - } + Node k = mkSkolemNode(prefix, w.getType(), comment, flags); // set skolem form attribute for w w.setAttribute(sfa, k); Trace("sk-manager") << "SkolemManager::mkSkolem: " << k << " : " << w @@ -375,4 +385,35 @@ Node SkolemManager::mkSkolemInternal(Node w, return k; } +Node SkolemManager::mkSkolemNode(const std::string& prefix, + const TypeNode& type, + const std::string& comment, + int flags) +{ + NodeManager* nm = NodeManager::currentNM(); + Node n; + if (flags & SKOLEM_BOOL_TERM_VAR) + { + Assert(type.isBoolean()); + n = NodeBuilder(nm, BOOLEAN_TERM_VARIABLE); + } + else + { + n = NodeBuilder(nm, SKOLEM); + if ((flags & SKOLEM_EXACT_NAME) == 0) + { + std::stringstream name; + name << prefix << '_' << ++d_skolemCounter; + n.setAttribute(expr::VarNameAttr(), name.str()); + } + else + { + n.setAttribute(expr::VarNameAttr(), prefix); + } + } + n.setAttribute(expr::TypeAttr(), type); + n.setAttribute(expr::TypeCheckedAttr(), true); + return n; +} + } // namespace cvc5 diff --git a/src/expr/skolem_manager.h b/src/expr/skolem_manager.h index 90e935767..0556185df 100644 --- a/src/expr/skolem_manager.h +++ b/src/expr/skolem_manager.h @@ -44,6 +44,67 @@ enum class SkolemFunId SHARED_SELECTOR, /** an application of seq.nth that is out of bounds */ SEQ_NTH_OOB, + //----- string skolems are cached based on two strings (a, b) + /** exists k. ( b occurs k times in a ) */ + STRINGS_NUM_OCCUR, + /** For function k: Int -> Int + * exists k. + * forall 0 <= x <= n, + * k(x) is the end index of the x^th occurrence of b in a + * where n is the number of occurrences of b in a, and k(0)=0. + */ + STRINGS_OCCUR_INDEX, + /** + * For function k: Int -> Int + * exists k. + * forall 0 <= x < n, + * k(x) is the length of the x^th occurrence of b in a (excluding + * matches of empty strings) + * where b is a regular expression, n is the number of occurrences of b + * in a, and k(0)=0. + */ + STRINGS_OCCUR_LEN, + /** + * Diff index for disequalities a != b => substr(a,k,1) != substr(b,k,1) + */ + STRINGS_DEQ_DIFF, + //----- + /** + * A function used to define intermediate results of str.replace_all and + * str.replace_re_all applications. + */ + STRINGS_REPLACE_ALL_RESULT, + /** + * A function used to define intermediate results of str.from_int + * applications. + */ + STRINGS_ITOS_RESULT, + /** + * A function used to define intermediate results of str.to_int + * applications. + */ + STRINGS_STOI_RESULT, + /** + * An index containing a non-digit in a string, used when (str.to_int a) = -1. + */ + STRINGS_STOI_NON_DIGIT, + /** + * For sequence a and regular expression b, + * in_re(a, re.++(_*, b, _*)) => + * exists k_pre, k_match, k_post. + * a = k_pre ++ k_match ++ k_post ^ + * len(k_pre) = indexof_re(x, y, 0) ^ + * (forall l. 0 < l < len(k_match) => + * ~in_re(substr(k_match, 0, l), r)) ^ + * in_re(k_match, b) + * + * k_pre is the prefix before the first, shortest match of b in a. k_match + * is the substring of a matched by b. It is either empty or there is no + * shorter string that matches b. + */ + SK_FIRST_MATCH_PRE, + SK_FIRST_MATCH, + SK_FIRST_MATCH_POST, /** * Regular expression unfold component: if (str.in_re t R), where R is * (re.++ r0 ... rn), then the RE_UNFOLD_POS_COMPONENT{t,R,i} is a string @@ -113,8 +174,21 @@ std::ostream& operator<<(std::ostream& out, SkolemFunId id); class SkolemManager { public: - SkolemManager() {} + SkolemManager(); ~SkolemManager() {} + + /** + * Optional flags used to control behavior of skolem creation. + * They should be composed with a bitwise OR (e.g., + * "SKOLEM_BOOL_TERM_VAR | SKOLEM_EXACT_NAME"). Of course, SKOLEM_DEFAULT + * cannot be composed in such a manner. + */ + enum SkolemFlags + { + SKOLEM_DEFAULT = 0, /**< default behavior */ + SKOLEM_EXACT_NAME = 1, /**< do not make the name unique by adding the id */ + SKOLEM_BOOL_TERM_VAR = 2 /**< vars requiring kind BOOLEAN_TERM_VARIABLE */ + }; /** * This makes a skolem of same type as bound variable v, (say its type is T), * whose definition is (witness ((v T)) pred). This definition is maintained @@ -156,7 +230,7 @@ class SkolemManager * variable v. * @param prefix The prefix of the name of the Skolem * @param comment Debug information about the Skolem - * @param flags The flags for the Skolem (see NodeManager::mkSkolem) + * @param flags The flags for the Skolem (see SkolemFlags) * @param pg The proof generator for this skolem. If non-null, this proof * generator must respond to a call to getProofFor(exists v. pred) during * the lifetime of the current node manager. @@ -166,7 +240,7 @@ class SkolemManager Node pred, const std::string& prefix, const std::string& comment = "", - int flags = NodeManager::SKOLEM_DEFAULT, + int flags = SKOLEM_DEFAULT, ProofGenerator* pg = nullptr); /** * Make skolemized form of existentially quantified formula q, and store its @@ -194,7 +268,7 @@ class SkolemManager * @param skolems Vector to add Skolems of q to, * @param prefix The prefix of the name of each of the Skolems * @param comment Debug information about each of the Skolems - * @param flags The flags for the Skolem (see NodeManager::mkSkolem) + * @param flags The flags for the Skolem (see SkolemFlags) * @param pg The proof generator for this skolem. If non-null, this proof * generator must respond to a call to getProofFor(q) during * the lifetime of the current node manager. @@ -204,7 +278,7 @@ class SkolemManager std::vector<Node>& skolems, const std::string& prefix, const std::string& comment = "", - int flags = NodeManager::SKOLEM_DEFAULT, + int flags = SKOLEM_DEFAULT, ProofGenerator* pg = nullptr); /** * Same as above, but for special case of (witness ((x T)) (= x t)) @@ -227,7 +301,7 @@ class SkolemManager Node mkPurifySkolem(Node t, const std::string& prefix, const std::string& comment = "", - int flags = NodeManager::SKOLEM_DEFAULT); + int flags = SKOLEM_DEFAULT); /** * Make skolem function. This method should be used for creating fixed * skolem functions of the forms described in SkolemFunId. The user of this @@ -260,12 +334,12 @@ class SkolemManager Node mkSkolemFunction(SkolemFunId id, TypeNode tn, Node cacheVal = Node::null(), - int flags = NodeManager::SKOLEM_DEFAULT); + int flags = SKOLEM_DEFAULT); /** Same as above, with multiple cache values */ Node mkSkolemFunction(SkolemFunId id, TypeNode tn, const std::vector<Node>& cacheVals, - int flags = NodeManager::SKOLEM_DEFAULT); + int flags = SKOLEM_DEFAULT); /** * Is k a skolem function? Returns true if k was generated by the above call. * Updates the arguments to the values used when constructing it. @@ -287,12 +361,12 @@ class SkolemManager * being dumped, this is included in a comment before the declaration * and can be quite useful for debugging * @param flags an optional mask of bits from SkolemFlags to control - * mkSkolem() behavior + * skolem behavior */ Node mkDummySkolem(const std::string& prefix, const TypeNode& type, const std::string& comment = "", - int flags = NodeManager::SKOLEM_DEFAULT); + int flags = SKOLEM_DEFAULT); /** * Get proof generator for existentially quantified formula q. This returns * the proof generator that was provided in a call to mkSkolem above. @@ -325,11 +399,20 @@ class SkolemManager * Mapping from witness terms to proof generators. */ std::map<Node, ProofGenerator*> d_gens; + + /** + * A counter used to produce unique skolem names. + * + * Note that it is NOT incremented when skolems are created using + * SKOLEM_EXACT_NAME, so it is NOT a count of the skolems produced + * by this node manager. + */ + size_t d_skolemCounter; /** Get or make skolem attribute for term w, which may be a witness term */ - static Node mkSkolemInternal(Node w, - const std::string& prefix, - const std::string& comment, - int flags); + Node mkSkolemInternal(Node w, + const std::string& prefix, + const std::string& comment, + int flags); /** * Skolemize the first variable of existentially quantified formula q. * For example, calling this method on: @@ -347,7 +430,18 @@ class SkolemManager Node& qskolem, const std::string& prefix, const std::string& comment = "", - int flags = NodeManager::SKOLEM_DEFAULT); + int flags = SKOLEM_DEFAULT); + /** + * Create a skolem constant with the given name, type, and comment. + * + * This method is intentionally private. To create skolems, one should + * call a public method from SkolemManager for allocating a skolem in a + * proper way, or otherwise use SkolemManager::mkDummySkolem. + */ + Node mkSkolemNode(const std::string& prefix, + const TypeNode& type, + const std::string& comment = "", + int flags = SKOLEM_DEFAULT); }; } // namespace cvc5 diff --git a/src/main/CMakeLists.txt b/src/main/CMakeLists.txt index a16baeb73..cb83413f9 100644 --- a/src/main/CMakeLists.txt +++ b/src/main/CMakeLists.txt @@ -76,7 +76,7 @@ endif() # use the static system libraries. # https://cmake.org/cmake/help/v3.0/prop_tgt/LINK_SEARCH_START_STATIC.html # https://cmake.org/cmake/help/v3.0/prop_tgt/LINK_SEARCH_END_STATIC.html -if(ENABLE_STATIC_BINARY) +if(ENABLE_STATIC_BUILD) if(NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin") set_target_properties(cvc5-bin PROPERTIES LINK_FLAGS -static) set_target_properties(cvc5-bin PROPERTIES LINK_SEARCH_START_STATIC ON) diff --git a/src/main/command_executor.cpp b/src/main/command_executor.cpp index 8188f247f..f08d9adde 100644 --- a/src/main/command_executor.cpp +++ b/src/main/command_executor.cpp @@ -204,7 +204,11 @@ bool solverInvoke(api::Solver* solver, cmd->toStream(ss); } - if (solver->getOptionInfo("parse-only").boolValue()) + // In parse-only mode, we do not invoke any of the commands except define-fun + // commands. We invoke define-fun commands because they add function names + // to the symbol table. + if (solver->getOptionInfo("parse-only").boolValue() + && dynamic_cast<DefineFunctionCommand*>(cmd) == nullptr) { return true; } diff --git a/src/main/options_template.cpp b/src/main/options_template.cpp index 138821c71..e0429c5f9 100644 --- a/src/main/options_template.cpp +++ b/src/main/options_template.cpp @@ -37,8 +37,8 @@ extern int optreset; #include "base/check.h" #include "base/output.h" -#include "options/didyoumean.h" #include "options/option_exception.h" +#include "util/didyoumean.h" #include <cstring> #include <iostream> diff --git a/src/options/README.md b/src/options/README.md index b0b026166..54d7d4878 100644 --- a/src/options/README.md +++ b/src/options/README.md @@ -5,17 +5,10 @@ Every options module, that is a group of options that belong together in some way, is declared in its own file in `options/{module name}_options.toml`. Each options module starts with the following required attributes: -* `id` (string): ID of the module (e.g., `"arith"`) +* `id` (string): ID of the module (e.g., `"ARITH"`) * `name` (string): name of the module (e.g., `"Arithmetic Theory"`) -Additional, a module can optionally be defined to be public. A public module -includes `cvc5_public.h` instead of `cvc5_private.h` can thus be included from -"external" code like the parser or the main driver. - -* `public` (bool): make option module public - -A module defines 0 or more options. - +A module defines zero or more options. In general, each attribute/value pair is required to be in one line. Comments start with # and are not allowed in attribute/value lines. @@ -34,7 +27,7 @@ Options can be defined within a module file with the `[[option]]` tag, the required attributes for an option are: * `category` (string): one of `common`, `expert`, `regular`, or `undocumented` -* `type` (string): the C++ type of the option value +* `type` (string): the C++ type of the option value, see below for more details. Optional attributes are: @@ -58,27 +51,42 @@ Optional attributes are: value is valid, more details below * `includes` (list): additional header files required by handler or predicate functions +* `minimum` (numeric): impose a minimum value on this option. +* `maximum` (numeric): impose a maximum value on this option. * `help` (string): documentation string (required, unless the `category` is `undocumented`) * `help_mode` (string): documentation for the mode enum (required if `mode` is given) +Option types +------------ + +Though not enforced explicitly, option types are commonly expected to come from +a rather restricted set of C++ types: +some options are merely used to have a handler function called and use `void`; +Boolean options should use `bool`; +numeric options should use one of `int64_t`, `uint64_t` and `double`, possibly +using `minimum` and `maximum` to further restrict the options domain; +mode options should use a fresh type name for the auto-generated enum as +detailed below. + +While other C++ types are allowed, they should only be used in special cases +when the above types are not sufficient. + + Handler functions ----------------- -Custom handler functions are used to turn the option value from a `std::string` +Custom handler functions are used to turn the option value from an `std::string` into the type specified by `type`. Standard handler functions are provided for -basic types (`std::string`, `bool`, integer types and floating point types) as +basic types (`std::string`, `bool`, `int64_t`, `uint64_t`, and `double`) as well as enums specified by `mode`. A custom handler function needs to be member -function of `options::OptionsHandler` with signature `{type} {handler}(const -std::string& option, const std::string& flag, const std::string& optionvalue)`, -or alternatively `void {handler}(const std::string& option, const std::string& -flag)` if the `type` is `void`. The two parameters `option` and `flag` hold the -canonical and the actually used option names, respectively, and they may differ -if an alternative name (from `alias`) was used. While `option` should be used to -identify an option (e.g. by comparing against `*__name`), `flag` should be -usually used in user messages. +function of `options::OptionsHandler` with signature +`{type} {handler}(const std::string& flag, const std::string& optionvalue)`, or +alternatively `void {handler}(const std::string& flag)` if the `type` is `void`. +The parameter `flag` holds the actually used option name, which may be an alias +name, and should only be used in user messages. Predicate functions @@ -87,9 +95,13 @@ Predicate functions Predicate functions are used to check whether an option value is valid after it has been parsed by a (standard or custom) handler function. Like a handler function, a predicate function needs to be a member function of -`options::OptionsHandler` with signature `void {predicate}(const std::string& -option, const std::string& flag, {type} value)`. If the check fails, the -predicate should raise an `OptionException`. +`options::OptionsHandler` with signature +`void {predicate}(const std::string& flag, {type} value)`. +If the check fails, the predicate should raise an `OptionException`. + +Note that a predicate function may not only check the value, but may also +trigger some other action. Examples include enabling trace tags or enforcing +dependencies between several options. Mode options diff --git a/src/options/base_options.toml b/src/options/base_options.toml index 69e0a853b..ec3bd870d 100644 --- a/src/options/base_options.toml +++ b/src/options/base_options.toml @@ -185,7 +185,7 @@ name = "Base" name = "outputTagHolder" category = "undocumented" includes = ["<bitset>"] - type = "std::bitset<OutputTag__numValues>" + type = "std::bitset<static_cast<size_t>(OutputTag::__MAX_VALUE)+1>" [[option]] name = "printSuccess" diff --git a/src/options/bv_options.toml b/src/options/bv_options.toml index dd7c1cd40..00835e719 100644 --- a/src/options/bv_options.toml +++ b/src/options/bv_options.toml @@ -6,7 +6,7 @@ name = "Bitvector Theory" category = "expert" long = "bv-sat-solver=MODE" type = "SatSolverMode" - default = "MINISAT" + default = "CADICAL" predicates = ["checkBvSatSolver"] help = "choose which sat solver to use, see --bv-sat-solver=help" help_mode = "SAT solver for bit-blasting backend." @@ -29,30 +29,12 @@ name = "Bitvector Theory" help_mode = "Bit-blasting modes." [[option.mode.LAZY]] name = "lazy" - help = "Separate boolean structure and term reasoning between the core SAT solver and the bit-vector SAT solver." + help = "Separate Boolean structure and term reasoning between the core SAT solver and the bit-vector SAT solver." [[option.mode.EAGER]] name = "eager" help = "Bitblast eagerly to bit-vector SAT solver." [[option]] - name = "bitvectorAig" - category = "regular" - long = "bitblast-aig" - type = "bool" - default = "false" - predicates = ["abcEnabledBuild", "setBitblastAig"] - help = "bitblast by first converting to AIG (implies --bitblast=eager)" - -[[option]] - name = "bitvectorAigSimplifications" - category = "expert" - long = "bv-aig-simp=COMMAND" - type = "std::string" - default = "\"balance;drw\"" - predicates = ["abcEnabledBuild"] - help = "abc command to run AIG simplifications (implies --bitblast-aig, default is \"balance;drw\")" - -[[option]] name = "bitvectorPropagate" category = "regular" long = "bv-propagate" @@ -61,38 +43,6 @@ name = "Bitvector Theory" help = "use bit-vector propagation in the bit-blaster" [[option]] - name = "bitvectorEqualitySolver" - category = "regular" - long = "bv-eq-solver" - type = "bool" - default = "true" - help = "use the equality engine for the bit-vector theory (only if --bv-solver=layered)" - -[[option]] - name = "bitvectorInequalitySolver" - category = "regular" - long = "bv-inequality-solver" - type = "bool" - default = "true" - help = "turn on the inequality solver for the bit-vector theory (only if --bv-solver=layered)" - -[[option]] - name = "bitvectorAlgebraicSolver" - category = "expert" - long = "bv-algebraic-solver" - type = "bool" - default = "false" - help = "turn on experimental algebraic solver for the bit-vector theory (only if --bv-solver=layered)" - -[[option]] - name = "bitvectorAlgebraicBudget" - category = "expert" - long = "bv-algebraic-budget=N" - type = "uint64_t" - default = "1500" - help = "the budget allowed for the algebraic solver in number of SAT conflicts" - -[[option]] name = "bitvectorToBool" category = "regular" long = "bv-to-bool" @@ -135,46 +85,6 @@ name = "Bitvector Theory" help = "enable rewrite pushing extract [i:0] over arithmetic operations (can blow up)" [[option]] - name = "bvAbstraction" - category = "undocumented" - long = "bv-abstraction" - type = "bool" - default = "false" - help = "mcm benchmark abstraction" - -[[option]] - name = "skolemizeArguments" - category = "undocumented" - long = "bv-skolemize" - type = "bool" - default = "false" - help = "skolemize arguments for bv abstraction (only does something if --bv-abstraction is on)" - -[[option]] - name = "bvNumFunc" - category = "expert" - long = "bv-num-func=N" - type = "uint64_t" - default = "1" - help = "number of function symbols in conflicts that are generalized" - -[[option]] - name = "bvEagerExplanations" - category = "expert" - long = "bv-eager-explanations" - type = "bool" - default = "false" - help = "compute bit-blasting propagation explanations eagerly" - -[[option]] - name = "bitvectorQuickXplain" - category = "expert" - long = "bv-quick-xplain" - type = "bool" - default = "false" - help = "minimize bv conflicts using the QuickXplain algorithm" - -[[option]] name = "bvIntroducePow2" category = "expert" long = "bv-intro-pow2" @@ -212,9 +122,6 @@ name = "Bitvector Theory" [[option.mode.BITBLAST_INTERNAL]] name = "bitblast-internal" help = "Enables bitblasting to internal SAT solver with proof support." -[[option.mode.LAYERED]] - name = "layered" - help = "Enables the layered BV solver." [[option]] name = "bvAssertInput" @@ -224,7 +131,6 @@ name = "Bitvector Theory" default = "false" help = "assert input assertions on user-level 0 instead of assuming them in the bit-vector SAT solver" - [[option]] name = "rwExtendEq" category = "expert" diff --git a/src/options/didyoumean_test.cpp b/src/options/didyoumean_test.cpp index 9da20ce86..dcfaef715 100644 --- a/src/options/didyoumean_test.cpp +++ b/src/options/didyoumean_test.cpp @@ -163,9 +163,6 @@ set<string> getDebugTags() { a.insert("bv-subtheory-inequality"); a.insert("bv-to-bool"); a.insert("bva"); - a.insert("bvminisat"); - a.insert("bvminisat::explain"); - a.insert("bvminisat::search"); a.insert("cegqi"); a.insert("cegqi-debug"); a.insert("cegqi-prop-as-dec"); diff --git a/src/options/mkoptions.py b/src/options/mkoptions.py index 70eb138cc..0db16e7c6 100644 --- a/src/options/mkoptions.py +++ b/src/options/mkoptions.py @@ -292,7 +292,6 @@ def generate_get_impl(modules): def _set_handlers(option): """Render handler call for options::set().""" - optname = option.long_name if option.long else "" if option.handler: if option.type == 'void': return 'opts.handler().{}(name)'.format(option.handler) @@ -307,7 +306,6 @@ def _set_predicates(option): """Render predicate calls for options::set().""" if option.type == 'void': return [] - optname = option.long_name if option.long else "" assert option.type != 'void' res = [] if option.minimum: @@ -419,9 +417,9 @@ def generate_module_includes(module): TPL_MODE_DECL = '''enum class {type} {{ - {values} + {values}, + __MAX_VALUE = {maxvalue} }}; -static constexpr size_t {type}__numValues = {nvalues}; std::ostream& operator<<(std::ostream& os, {type} mode); {type} stringTo{type}(const std::string& optarg); ''' @@ -433,11 +431,11 @@ def generate_module_mode_decl(module): for option in module.options: if option.name is None or not option.mode: continue + values = list(option.mode.keys()) res.append( TPL_MODE_DECL.format(type=option.type, - values=wrap_line( - ', '.join(option.mode.keys()), 2), - nvalues=len(option.mode))) + values=wrap_line(', '.join(values), 2), + maxvalue=values[-1])) return '\n'.join(res) @@ -791,7 +789,7 @@ def generate_sphinx_help(modules): common = [] others = {} for module, option in all_options(modules, False): - if option.type == 'undocumented': + if option.category == 'undocumented': continue if not option.long and not option.short: continue diff --git a/src/options/options_handler.cpp b/src/options/options_handler.cpp index fe0e1d961..2a7331c67 100644 --- a/src/options/options_handler.cpp +++ b/src/options/options_handler.cpp @@ -32,7 +32,6 @@ #include "options/base_options.h" #include "options/bv_options.h" #include "options/decision_options.h" -#include "options/didyoumean.h" #include "options/language.h" #include "options/option_exception.h" #include "options/set_language.h" @@ -40,6 +39,7 @@ #include "options/theory_options.h" #include "smt/command.h" #include "smt/dump.h" +#include "util/didyoumean.h" namespace cvc5 { namespace options { @@ -267,8 +267,11 @@ void OptionsHandler::enableDebugTag(const std::string& flag, void OptionsHandler::enableOutputTag(const std::string& flag, const std::string& optarg) { - d_options->base.outputTagHolder.set( - static_cast<size_t>(stringToOutputTag(optarg))); + size_t tagid = static_cast<size_t>(stringToOutputTag(optarg)); + Assert(d_options->base.outputTagHolder.size() > tagid) + << "Trying to enable an output tag whose value is larger than the bitset " + "that holds it. Maybe someone forgot to update the bitset size?"; + d_options->base.outputTagHolder.set(tagid); } void OptionsHandler::setPrintSuccess(const std::string& flag, bool value) @@ -288,33 +291,6 @@ void OptionsHandler::setResourceWeight(const std::string& flag, d_options->base.resourceWeightHolder.emplace_back(optarg); } -void OptionsHandler::abcEnabledBuild(const std::string& flag, bool value) -{ -#ifndef CVC5_USE_ABC - if(value) { - std::stringstream ss; - ss << "option `" << flag - << "' requires an abc-enabled build of cvc5; this binary was not built " - "with abc support"; - throw OptionException(ss.str()); - } -#endif /* CVC5_USE_ABC */ -} - -void OptionsHandler::abcEnabledBuild(const std::string& flag, - const std::string& value) -{ -#ifndef CVC5_USE_ABC - if(!value.empty()) { - std::stringstream ss; - ss << "option `" << flag - << "' requires an abc-enabled build of cvc5; this binary was not built " - "with abc support"; - throw OptionException(ss.str()); - } -#endif /* CVC5_USE_ABC */ -} - void OptionsHandler::checkBvSatSolver(const std::string& flag, SatSolverMode m) { if (m == SatSolverMode::CRYPTOMINISAT @@ -453,7 +429,6 @@ void OptionsHandler::showConfiguration(const std::string& flag) std::cout << std::endl; - print_config_cond("abc", Configuration::isBuiltWithAbc()); print_config_cond("cln", Configuration::isBuiltWithCln()); print_config_cond("glpk", Configuration::isBuiltWithGlpk()); print_config_cond("cryptominisat", Configuration::isBuiltWithCryptominisat()); diff --git a/src/parser/CMakeLists.txt b/src/parser/CMakeLists.txt index e2cf3d64e..d012851d7 100644 --- a/src/parser/CMakeLists.txt +++ b/src/parser/CMakeLists.txt @@ -88,8 +88,17 @@ foreach(lang Smt2 Tptp) set_source_files_properties(${gen_src_files} PROPERTIES GENERATED TRUE) # We don't want to enable -Wall for code generated by ANTLR. + set(GEN_SRC_FLAGS "") + check_cxx_compiler_flag("-Wall" HAVE_CXX_FLAGWall) + if(HAVE_CXX_FLAGWall) + set(GEN_SRC_FLAGS "${GEN_SRC_FLAGS} -Wno-all") + endif() + check_cxx_compiler_flag("-Werror" HAVE_CXX_FLAGWerror) + if(HAVE_CXX_FLAGWerror) + set(GEN_SRC_FLAGS "${GEN_SRC_FLAGS} -Wno-error") + endif() set_source_files_properties( - ${gen_src_files} PROPERTIES COMPILE_FLAGS "-Wno-all -Wno-error") + ${gen_src_files} PROPERTIES COMPILE_FLAGS "${GEN_SRC_FLAGS}") # Add generated source files to the parser source files list(APPEND libcvc5parser_src_files ${gen_src_files}) @@ -115,7 +124,7 @@ install(TARGETS cvc5parser-shared EXPORT cvc5-targets DESTINATION ${CMAKE_INSTALL_LIBDIR}) -if(ENABLE_STATIC_LIBRARY) +if(ENABLE_STATIC_BUILD) add_library(cvc5parser-static STATIC $<TARGET_OBJECTS:cvc5parser-objs>) set_target_properties(cvc5parser-static PROPERTIES OUTPUT_NAME cvc5parser) target_link_libraries(cvc5parser-static PRIVATE cvc5-static) diff --git a/src/parser/smt2/Smt2.g b/src/parser/smt2/Smt2.g index e3aee250e..daf148100 100644 --- a/src/parser/smt2/Smt2.g +++ b/src/parser/smt2/Smt2.g @@ -314,6 +314,10 @@ command [std::unique_ptr<cvc5::Command>* cmd] } t = PARSER_STATE->mkFlatFunctionType(sorts, t, flattenVars); + if (t.isFunction()) + { + t = t.getFunctionCodomainSort(); + } if (sortedVarNames.size() > 0) { PARSER_STATE->pushScope(); @@ -332,13 +336,7 @@ command [std::unique_ptr<cvc5::Command>* cmd] { PARSER_STATE->popScope(); } - // declare the name down here (while parsing term, signature - // must not be extended with the name itself; no recursion - // permitted) - // we allow overloading for function definitions - api::Term func = PARSER_STATE->bindVar(name, t, false, true); - cmd->reset(new DefineFunctionCommand( - name, func, terms, expr, SYM_MAN->getGlobalDeclarations())); + cmd->reset(new DefineFunctionCommand(name, terms, t, expr)); } | DECLARE_DATATYPE_TOK datatypeDefCommand[false, cmd] | DECLARE_DATATYPES_TOK datatypesDefCommand[false, cmd] @@ -735,10 +733,8 @@ setInfoInternal[std::unique_ptr<cvc5::Command>* cmd] std::string name; api::Term sexpr; } - : KEYWORD symbolicExpr[sexpr] - { name = AntlrInput::tokenText($KEYWORD); - cmd->reset(new SetInfoCommand(name.c_str() + 1, sexprToString(sexpr))); - } + : keyword[name] symbolicExpr[sexpr] + { cmd->reset(new SetInfoCommand(name.c_str() + 1, sexprToString(sexpr))); } ; setOptionInternal[std::unique_ptr<cvc5::Command>* cmd] @@ -836,8 +832,7 @@ smt25Command[std::unique_ptr<cvc5::Command>* cmd] if( !flattenVars.empty() ){ expr = PARSER_STATE->mkHoApply( expr, flattenVars ); } - cmd->reset(new DefineFunctionRecCommand( - func, bvs, expr, SYM_MAN->getGlobalDeclarations())); + cmd->reset(new DefineFunctionRecCommand(func, bvs, expr)); } | DEFINE_FUNS_REC_TOK { PARSER_STATE->checkThatLogicIsSet();} @@ -900,8 +895,7 @@ smt25Command[std::unique_ptr<cvc5::Command>* cmd] "Number of functions defined does not match number listed in " "define-funs-rec")); } - cmd->reset(new DefineFunctionRecCommand( - funcs, formals, func_defs, SYM_MAN->getGlobalDeclarations())); + cmd->reset(new DefineFunctionRecCommand(funcs, formals, func_defs)); } ; @@ -986,48 +980,6 @@ extendedCommand[std::unique_ptr<cvc5::Command>* cmd] )+ RPAREN_TOK { cmd->reset(seq.release()); } - - | DEFINE_TOK { PARSER_STATE->checkThatLogicIsSet(); } - ( // (define f t) - symbol[name,CHECK_UNDECLARED,SYM_VARIABLE] - { PARSER_STATE->checkUserSymbol(name); } - term[e,e2] - { - api::Term func = PARSER_STATE->bindVar(name, e.getSort()); - cmd->reset(new DefineFunctionCommand( - name, func, e, SYM_MAN->getGlobalDeclarations())); - } - | // (define (f (v U) ...) t) - LPAREN_TOK - symbol[name,CHECK_UNDECLARED,SYM_VARIABLE] - { PARSER_STATE->checkUserSymbol(name); } - sortedVarList[sortedVarNames] RPAREN_TOK - { /* add variables to parser state before parsing term */ - Debug("parser") << "define fun: '" << name << "'" << std::endl; - PARSER_STATE->pushScope(); - terms = PARSER_STATE->bindBoundVars(sortedVarNames); - } - term[e,e2] - { - PARSER_STATE->popScope(); - // declare the name down here (while parsing term, signature - // must not be extended with the name itself; no recursion - // permitted) - api::Sort tt = e.getSort(); - if( sortedVarNames.size() > 0 ) { - sorts.reserve(sortedVarNames.size()); - for(std::vector<std::pair<std::string, api::Sort> >::const_iterator - i = sortedVarNames.begin(), iend = sortedVarNames.end(); - i != iend; ++i) { - sorts.push_back((*i).second); - } - tt = SOLVER->mkFunctionSort(sorts, tt); - } - api::Term func = PARSER_STATE->bindVar(name, tt); - cmd->reset(new DefineFunctionCommand( - name, func, terms, e, SYM_MAN->getGlobalDeclarations())); - } - ) | // (define-const x U t) DEFINE_CONST_TOK { PARSER_STATE->checkThatLogicIsSet(); } symbol[name,CHECK_UNDECLARED,SYM_VARIABLE] @@ -1038,9 +990,7 @@ extendedCommand[std::unique_ptr<cvc5::Command>* cmd] // declare the name down here (while parsing term, signature // must not be extended with the name itself; no recursion // permitted) - api::Term func = PARSER_STATE->bindVar(name, t); - cmd->reset(new DefineFunctionCommand( - name, func, terms, e, SYM_MAN->getGlobalDeclarations())); + cmd->reset(new DefineFunctionCommand(name, t, e)); } | SIMPLIFY_TOK { PARSER_STATE->checkThatLogicIsSet(); } @@ -1247,8 +1197,12 @@ simpleSymbolicExprNoKeyword[std::string& s] { s = AntlrInput::tokenText($HEX_LITERAL); } | BINARY_LITERAL { s = AntlrInput::tokenText($BINARY_LITERAL); } - | str[s,false] - | symbol[s,CHECK_NONE,SYM_SORT] + | SIMPLE_SYMBOL + { s = AntlrInput::tokenText($SIMPLE_SYMBOL); } + | QUOTED_SYMBOL + { s = AntlrInput::tokenText($QUOTED_SYMBOL); } + | STRING_LITERAL + { s = AntlrInput::tokenText($STRING_LITERAL); } | tok=(ASSERT_TOK | CHECK_SAT_TOK | CHECK_SAT_ASSUMING_TOK | DECLARE_FUN_TOK | DECLARE_SORT_TOK | DEFINE_FUN_TOK | DEFINE_FUN_REC_TOK | DEFINE_FUNS_REC_TOK @@ -1736,8 +1690,7 @@ identifier[cvc5::ParseOp& p] */ termAtomic[cvc5::api::Term& atomTerm] @init { - cvc5::api::Sort type; - cvc5::api::Sort type2; + cvc5::api::Sort t; std::string s; std::vector<uint64_t> numerals; } @@ -1762,6 +1715,11 @@ termAtomic[cvc5::api::Term& atomTerm] std::string hexStr = AntlrInput::tokenTextSubstr($HEX_LITERAL, 2); atomTerm = PARSER_STATE->mkCharConstant(hexStr); } + | FMF_CARD_TOK sortSymbol[t,CHECK_DECLARED] INTEGER_LITERAL + { + uint32_t ubound = AntlrInput::tokenToUnsigned($INTEGER_LITERAL); + atomTerm = SOLVER->mkCardinalityConstraint(t, ubound); + } | sym=SIMPLE_SYMBOL nonemptyNumeralList[numerals] { atomTerm = @@ -1839,16 +1797,18 @@ attribute[cvc5::api::Term& expr, cvc5::api::Term& retExpr] api::Term n = SOLVER->mkInteger(sIntLit.str()); retExpr = MK_TERM(api::INST_ATTRIBUTE, keyword, n); } - | tok=( ATTRIBUTE_QUANTIFIER_ID_TOK ) symbolicExpr[sexpr] + | tok=( ATTRIBUTE_QUANTIFIER_ID_TOK ) symbol[s,CHECK_UNDECLARED,SYM_VARIABLE] { api::Term keyword = SOLVER->mkString("qid"); - api::Term name = SOLVER->mkString(sexprToString(sexpr)); + api::Term name = SOLVER->mkString(s); retExpr = MK_TERM(api::INST_ATTRIBUTE, keyword, name); } - | ATTRIBUTE_NAMED_TOK symbolicExpr[sexpr] + | ATTRIBUTE_NAMED_TOK symbol[s,CHECK_UNDECLARED,SYM_VARIABLE] { // notify that expression was given a name - PARSER_STATE->notifyNamedExpression(expr, sexprToString(sexpr)); + PARSER_STATE->preemptCommand( + new DefineFunctionCommand(s, expr.getSort(), expr)); + PARSER_STATE->notifyNamedExpression(expr, s); } ; @@ -2275,7 +2235,6 @@ ECHO_TOK : 'echo'; DECLARE_SORTS_TOK : 'declare-sorts'; DECLARE_FUNS_TOK : 'declare-funs'; DECLARE_PREDS_TOK : 'declare-preds'; -DEFINE_TOK : 'define'; DECLARE_CONST_TOK : 'declare-const'; DEFINE_CONST_TOK : 'define-const'; SIMPLIFY_TOK : 'simplify'; @@ -2316,6 +2275,7 @@ FORALL_TOK : 'forall'; CHAR_TOK : { PARSER_STATE->isTheoryEnabled(theory::THEORY_STRINGS) }? 'char'; TUPLE_CONST_TOK: { PARSER_STATE->isTheoryEnabled(theory::THEORY_DATATYPES) }? 'tuple'; TUPLE_PROJECT_TOK: { PARSER_STATE->isTheoryEnabled(theory::THEORY_DATATYPES) }? 'tuple_project'; +FMF_CARD_TOK: { !PARSER_STATE->strictModeEnabled() && PARSER_STATE->hasCardinalityConstraints() }? 'fmf.card'; HO_ARROW_TOK : { PARSER_STATE->isHoEnabled() }? '->'; HO_LAMBDA_TOK : { PARSER_STATE->isHoEnabled() }? 'lambda'; diff --git a/src/parser/smt2/smt2.cpp b/src/parser/smt2/smt2.cpp index 19c3527f7..2fd91e495 100644 --- a/src/parser/smt2/smt2.cpp +++ b/src/parser/smt2/smt2.cpp @@ -323,6 +323,8 @@ bool Smt2::isTheoryEnabled(theory::TheoryId theory) const bool Smt2::isHoEnabled() const { return d_logic.isHigherOrder(); } +bool Smt2::hasCardinalityConstraints() const { return d_logic.hasCardinalityConstraints(); } + bool Smt2::logicIsSet() { return d_logicSet; } @@ -512,11 +514,6 @@ Command* Smt2::setLogic(std::string name, bool fromCommand) if(d_logic.isTheoryEnabled(theory::THEORY_UF)) { Parser::addOperator(api::APPLY_UF); - - if (!strictModeEnabled() && d_logic.hasCardinalityConstraints()) - { - addOperator(api::CARDINALITY_CONSTRAINT, "fmf.card"); - } } if(d_logic.isTheoryEnabled(theory::THEORY_ARITH)) { diff --git a/src/parser/smt2/smt2.h b/src/parser/smt2/smt2.h index 8d8f8febe..58a20cb27 100644 --- a/src/parser/smt2/smt2.h +++ b/src/parser/smt2/smt2.h @@ -105,6 +105,10 @@ class Smt2 : public Parser * @return true if higher-order support is enabled, false otherwise */ bool isHoEnabled() const; + /** + * @return true if cardinality constraints are enabled, false otherwise + */ + bool hasCardinalityConstraints() const; bool logicIsSet() override; diff --git a/src/preprocessing/passes/bv_abstraction.cpp b/src/preprocessing/passes/bv_abstraction.cpp deleted file mode 100644 index cea5bf37c..000000000 --- a/src/preprocessing/passes/bv_abstraction.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Mathias Preiner, Andrew Reynolds, Aina Niemetz - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * The BvAbstraction preprocessing pass. - * - * Abstract common structures over small domains to UF. This preprocessing - * is particularly useful on QF_BV/mcm benchmarks and can be enabled via - * option `--bv-abstraction`. - * For more information see 3.4 Refactoring Isomorphic Circuits in [1]. - * - * [1] Liana Hadarean, An Efficient and Trustworthy Theory Solver for - * Bit-vectors in Satisfiability Modulo Theories - * https://cs.nyu.edu/media/publications/hadarean_liana.pdf - */ - -#include "preprocessing/passes/bv_abstraction.h" - -#include <vector> - -#include "options/bv_options.h" -#include "preprocessing/assertion_pipeline.h" -#include "preprocessing/preprocessing_pass_context.h" -#include "theory/bv/theory_bv.h" -#include "theory/rewriter.h" -#include "theory/theory_engine.h" - -namespace cvc5 { -namespace preprocessing { -namespace passes { - -using namespace cvc5::theory; - -BvAbstraction::BvAbstraction(PreprocessingPassContext* preprocContext) - : PreprocessingPass(preprocContext, "bv-abstraction"){}; - -PreprocessingPassResult BvAbstraction::applyInternal( - AssertionPipeline* assertionsToPreprocess) -{ - std::vector<Node> new_assertions; - std::vector<Node> assertions(assertionsToPreprocess->begin(), - assertionsToPreprocess->end()); - TheoryEngine* te = d_preprocContext->getTheoryEngine(); - bv::TheoryBV* bv_theory = static_cast<bv::TheoryBV*>(te->theoryOf(THEORY_BV)); - bv_theory->applyAbstraction(assertions, new_assertions); - for (unsigned i = 0, size = assertionsToPreprocess->size(); i < size; ++i) - { - assertionsToPreprocess->replace(i, rewrite(new_assertions[i])); - } - return PreprocessingPassResult::NO_CONFLICT; -} - - -} // namespace passes -} // namespace preprocessing -} // namespace cvc5 diff --git a/src/preprocessing/passes/bv_abstraction.h b/src/preprocessing/passes/bv_abstraction.h deleted file mode 100644 index 0f3db2f59..000000000 --- a/src/preprocessing/passes/bv_abstraction.h +++ /dev/null @@ -1,50 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Mathias Preiner - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * The BvAbstraction preprocessing pass. - * - * Abstract common structures over small domains to UF. This preprocessing - * is particularly useful on QF_BV/mcm benchmarks and can be enabled via - * option `--bv-abstraction`. - * For more information see 3.4 Refactoring Isomorphic Circuits in [1]. - * - * [1] Liana Hadarean, An Efficient and Trustworthy Theory Solver for - * Bit-vectors in Satisfiability Modulo Theories - * https://cs.nyu.edu/media/publications/hadarean_liana.pdf - */ - -#include "cvc5_private.h" - -#ifndef CVC5__PREPROCESSING__PASSES__BV_ABSTRACTION_H -#define CVC5__PREPROCESSING__PASSES__BV_ABSTRACTION_H - -#include "preprocessing/preprocessing_pass.h" - -namespace cvc5 { -namespace preprocessing { -namespace passes { - -class BvAbstraction : public PreprocessingPass -{ - public: - BvAbstraction(PreprocessingPassContext* preprocContext); - - protected: - PreprocessingPassResult applyInternal( - AssertionPipeline* assertionsToPreprocess) override; -}; - -} // namespace passes -} // namespace preprocessing -} // namespace cvc5 - -#endif /* CVC5__PREPROCESSING__PASSES__BV_ABSTRACTION_H */ diff --git a/src/preprocessing/passes/miplib_trick.cpp b/src/preprocessing/passes/miplib_trick.cpp index 8202acb15..61be4395b 100644 --- a/src/preprocessing/passes/miplib_trick.cpp +++ b/src/preprocessing/passes/miplib_trick.cpp @@ -76,18 +76,10 @@ MipLibTrick::MipLibTrick(PreprocessingPassContext* preprocContext) : PreprocessingPass(preprocContext, "miplib-trick"), d_statistics(statisticsRegistry()) { - if (!options().base.incrementalSolving) - { - NodeManager::currentNM()->subscribeEvents(this); - } } MipLibTrick::~MipLibTrick() { - if (!options().base.incrementalSolving) - { - NodeManager::currentNM()->unsubscribeEvents(this); - } } /** @@ -166,22 +158,34 @@ size_t MipLibTrick::removeFromConjunction( return 0; } -void MipLibTrick::nmNotifyNewVar(TNode n) +void MipLibTrick::collectBooleanVariables( + AssertionPipeline* assertionsToPreprocess) { - if (n.getType().isBoolean()) + d_boolVars.clear(); + std::unordered_set<TNode> visited; + std::unordered_set<TNode>::iterator it; + std::vector<TNode> visit; + TNode cur; + for (size_t i = 0, size = assertionsToPreprocess->size(); i < size; ++i) { - d_boolVars.push_back(n); + visit.push_back((*assertionsToPreprocess)[i]); } -} - -void MipLibTrick::nmNotifyNewSkolem(TNode n, - const std::string& comment, - uint32_t flags) -{ - if (n.getType().isBoolean()) + do { - d_boolVars.push_back(n); - } + cur = visit.back(); + visit.pop_back(); + it = visited.find(cur); + + if (it == visited.end()) + { + visited.insert(cur); + if (cur.isVar() && cur.getType().isBoolean()) + { + d_boolVars.push_back(cur); + } + visit.insert(visit.end(), cur.begin(), cur.end()); + } + } while (!visit.empty()); } PreprocessingPassResult MipLibTrick::applyInternal( @@ -191,6 +195,9 @@ PreprocessingPassResult MipLibTrick::applyInternal( == assertionsToPreprocess->size()); Assert(!options().base.incrementalSolving); + // collect Boolean variables + collectBooleanVariables(assertionsToPreprocess); + context::Context fakeContext; TheoryEngine* te = d_preprocContext->getTheoryEngine(); booleans::CircuitPropagator* propagator = @@ -529,8 +536,7 @@ PreprocessingPassResult MipLibTrick::applyInternal( Node newVar = sm->mkDummySkolem( ss.str(), nm->integerType(), - "a variable introduced due to scrubbing a miplib encoding", - NodeManager::SKOLEM_EXACT_NAME); + "a variable introduced due to scrubbing a miplib encoding"); Node geq = rewrite(nm->mkNode(kind::GEQ, newVar, zero)); Node leq = rewrite(nm->mkNode(kind::LEQ, newVar, one)); TrustNode tgeq = TrustNode::mkTrustLemma(geq, nullptr); @@ -642,7 +648,7 @@ PreprocessingPassResult MipLibTrick::applyInternal( d_statistics.d_numMiplibAssertionsRemoved += removals; } } - Debug("miplib") << "had: " << assertion[i] << endl; + Debug("miplib") << "had: " << assertion << endl; assertionsToPreprocess->replace( i, rewrite(top_level_substs.apply(assertion))); Debug("miplib") << "now: " << assertion << endl; diff --git a/src/preprocessing/passes/miplib_trick.h b/src/preprocessing/passes/miplib_trick.h index 796063b46..65779f90d 100644 --- a/src/preprocessing/passes/miplib_trick.h +++ b/src/preprocessing/passes/miplib_trick.h @@ -25,18 +25,12 @@ namespace cvc5 { namespace preprocessing { namespace passes { -class MipLibTrick : public PreprocessingPass, public NodeManagerListener +class MipLibTrick : public PreprocessingPass { public: MipLibTrick(PreprocessingPassContext* preprocContext); ~MipLibTrick(); - // NodeManagerListener callbacks to collect d_boolVars. - void nmNotifyNewVar(TNode n) override; - void nmNotifyNewSkolem(TNode n, - const std::string& comment, - uint32_t flags) override; - protected: PreprocessingPassResult applyInternal( AssertionPipeline* assertionsToPreprocess) override; @@ -51,6 +45,10 @@ class MipLibTrick : public PreprocessingPass, public NodeManagerListener size_t removeFromConjunction( Node& n, const std::unordered_set<unsigned long>& toRemove); + /** + * Collect Boolean variables in the given pipeline, store them in d_boolVars. + */ + void collectBooleanVariables(AssertionPipeline* assertionsToPreprocess); Statistics d_statistics; diff --git a/src/preprocessing/preprocessing_pass_registry.cpp b/src/preprocessing/preprocessing_pass_registry.cpp index f0bd5af86..b0f9992ca 100644 --- a/src/preprocessing/preprocessing_pass_registry.cpp +++ b/src/preprocessing/preprocessing_pass_registry.cpp @@ -27,7 +27,6 @@ #include "preprocessing/passes/ackermann.h" #include "preprocessing/passes/apply_substs.h" #include "preprocessing/passes/bool_to_bv.h" -#include "preprocessing/passes/bv_abstraction.h" #include "preprocessing/passes/bv_eager_atoms.h" #include "preprocessing/passes/bv_gauss.h" #include "preprocessing/passes/bv_intro_pow2.h" @@ -137,7 +136,6 @@ PreprocessingPassRegistry::PreprocessingPassRegistry() registerPassInfo("sort-inference", callCtor<SortInferencePass>); registerPassInfo("sep-skolem-emp", callCtor<SepSkolemEmp>); registerPassInfo("rewrite", callCtor<Rewrite>); - registerPassInfo("bv-abstraction", callCtor<BvAbstraction>); registerPassInfo("bv-eager-atoms", callCtor<BvEagerAtoms>); registerPassInfo("pseudo-boolean-processor", callCtor<PseudoBooleanProcessor>); diff --git a/src/printer/printer.cpp b/src/printer/printer.cpp index ec0fdeda1..cc9df91f4 100644 --- a/src/printer/printer.cpp +++ b/src/printer/printer.cpp @@ -411,7 +411,8 @@ void Printer::toStreamCmdGetAbduct(std::ostream& out, } void Printer::toStreamCmdGetQuantifierElimination(std::ostream& out, - Node n) const + Node n, + bool doFull) const { printUnknownCommand(out, "get-quantifier-elimination"); } diff --git a/src/printer/printer.h b/src/printer/printer.h index 8c8118aa9..485cd70e6 100644 --- a/src/printer/printer.h +++ b/src/printer/printer.h @@ -179,11 +179,11 @@ class Printer virtual void toStreamCmdGetModel(std::ostream& out) const; /** Print block-model command */ - void toStreamCmdBlockModel(std::ostream& out) const; + virtual void toStreamCmdBlockModel(std::ostream& out) const; /** Print block-model-values command */ - void toStreamCmdBlockModelValues(std::ostream& out, - const std::vector<Node>& nodes) const; + virtual void toStreamCmdBlockModelValues( + std::ostream& out, const std::vector<Node>& nodes) const; /** Print get-proof command */ virtual void toStreamCmdGetProof(std::ostream& out) const; @@ -192,10 +192,10 @@ class Printer void toStreamCmdGetInstantiations(std::ostream& out) const; /** Print get-interpol command */ - void toStreamCmdGetInterpol(std::ostream& out, - const std::string& name, - Node conj, - TypeNode sygusType) const; + virtual void toStreamCmdGetInterpol(std::ostream& out, + const std::string& name, + Node conj, + TypeNode sygusType) const; /** Print get-abduct command */ virtual void toStreamCmdGetAbduct(std::ostream& out, @@ -204,7 +204,9 @@ class Printer TypeNode sygusType) const; /** Print get-quantifier-elimination command */ - void toStreamCmdGetQuantifierElimination(std::ostream& out, Node n) const; + virtual void toStreamCmdGetQuantifierElimination(std::ostream& out, + Node n, + bool doFull) const; /** Print get-unsat-assumptions command */ virtual void toStreamCmdGetUnsatAssumptions(std::ostream& out) const; diff --git a/src/printer/smt2/smt2_printer.cpp b/src/printer/smt2/smt2_printer.cpp index ccb2ed2c6..da8e56448 100644 --- a/src/printer/smt2/smt2_printer.cpp +++ b/src/printer/smt2/smt2_printer.cpp @@ -332,13 +332,6 @@ void Smt2Printer::toStream(std::ostream& out, out << ss.str(); break; } - case kind::CARDINALITY_CONSTRAINT: - out << "(_ fmf.card "; - out << n.getConst<CardinalityConstraint>().getType(); - out << " "; - out << n.getConst<CardinalityConstraint>().getUpperBound(); - out << ")"; - break; case kind::EMPTYSET: out << "(as emptyset "; toStreamType(out, n.getConst<EmptySet>().getType()); @@ -818,6 +811,15 @@ void Smt2Printer::toStream(std::ostream& out, out << "(as sep.nil " << n.getType() << ")"; break; + // cardinality constraints. + case kind::CARDINALITY_CONSTRAINT: + out << "(_ fmf.card "; + out << n.getOperator().getConst<CardinalityConstraint>().getType(); + out << " "; + out << n.getOperator().getConst<CardinalityConstraint>().getUpperBound(); + out << ")"; + return; + // quantifiers case kind::FORALL: case kind::EXISTS: @@ -1199,7 +1201,7 @@ std::string Smt2Printer::smtKindString(Kind k, Variant v) case kind::SEP_STAR: return "sep"; case kind::SEP_PTO: return "pto"; case kind::SEP_WAND: return "wand"; - case kind::SEP_EMP: return "emp"; + case kind::SEP_EMP: return "sep.emp"; // quantifiers case kind::FORALL: return "forall"; @@ -1437,6 +1439,23 @@ void Smt2Printer::toStreamCmdDeclareFunction(std::ostream& out, out << ") " << type << ')' << std::endl; } +void Smt2Printer::toStreamCmdDeclarePool( + std::ostream& out, + const std::string& id, + TypeNode type, + const std::vector<Node>& initValue) const +{ + out << "(declare-pool " << cvc5::quoteSymbol(id) << ' ' << type << " ("; + for (size_t i = 0, n = initValue.size(); i < n; ++i) + { + if (i != 0) { + out << ' '; + } + out << initValue[i]; + } + out << "))" << std::endl; +} + void Smt2Printer::toStreamCmdDefineFunction(std::ostream& out, const std::string& id, const std::vector<Node>& formals, @@ -1577,6 +1596,26 @@ void Smt2Printer::toStreamCmdGetModel(std::ostream& out) const out << "(get-model)" << std::endl; } +void Smt2Printer::toStreamCmdBlockModel(std::ostream& out) const +{ + out << "(block-model)" << std::endl; +} + +void Smt2Printer::toStreamCmdBlockModelValues( + std::ostream& out, const std::vector<Node>& nodes) const +{ + out << "(block-model-values ("; + for (size_t i = 0, n = nodes.size(); i < n; ++i) + { + if (i != 0) + { + out << ' '; + } + out << nodes[i]; + } + out << "))" << std::endl; +} + void Smt2Printer::toStreamCmdGetAssignment(std::ostream& out) const { out << "(get-assignment)" << std::endl; @@ -1617,8 +1656,7 @@ void Smt2Printer::toStreamCmdSetInfo(std::ostream& out, const std::string& flag, const std::string& value) const { - out << "(set-info :" << flag << " " << cvc5::quoteSymbol(value) << ")" - << std::endl; + out << "(set-info :" << flag << " " << value << ")" << std::endl; } void Smt2Printer::toStreamCmdGetInfo(std::ostream& out, @@ -1859,6 +1897,20 @@ void Smt2Printer::toStreamCmdCheckSynth(std::ostream& out) const out << "(check-synth)" << std::endl; } +void Smt2Printer::toStreamCmdGetInterpol(std::ostream& out, + const std::string& name, + Node conj, + TypeNode sygusType) const +{ + out << "(get-interpol " << cvc5::quoteSymbol(name) << ' ' << conj; + if (!sygusType.isNull()) + { + out << ' '; + toStreamSygusGrammar(out, sygusType); + } + out << ')' << std::endl; +} + void Smt2Printer::toStreamCmdGetAbduct(std::ostream& out, const std::string& name, Node conj, @@ -1876,6 +1928,14 @@ void Smt2Printer::toStreamCmdGetAbduct(std::ostream& out, out << ')' << std::endl; } +void Smt2Printer::toStreamCmdGetQuantifierElimination(std::ostream& out, + Node n, + bool doFull) const +{ + out << '(' << (doFull ? "get-qe" : "get-qe-disjunct") << ' ' << n << ')' + << std::endl; +} + /* -------------------------------------------------------------------------- End of Handling SyGuS commands diff --git a/src/printer/smt2/smt2_printer.h b/src/printer/smt2/smt2_printer.h index e0b6fedbc..2af17ed59 100644 --- a/src/printer/smt2/smt2_printer.h +++ b/src/printer/smt2/smt2_printer.h @@ -74,9 +74,14 @@ class Smt2Printer : public cvc5::Printer const std::string& id, TypeNode type) const override; + /** Print declare-pool command */ + void toStreamCmdDeclarePool(std::ostream& out, + const std::string& id, + TypeNode type, + const std::vector<Node>& initValue) const override; + /** Print declare-sort command */ - void toStreamCmdDeclareType(std::ostream& out, - TypeNode type) const override; + void toStreamCmdDeclareType(std::ostream& out, TypeNode type) const override; /** Print define-sort command */ void toStreamCmdDefineType(std::ostream& out, @@ -114,11 +119,12 @@ class Smt2Printer : public cvc5::Printer TypeNode type) const override; /** Print synth-fun command */ - void toStreamCmdSynthFun(std::ostream& out, - Node f, - const std::vector<Node>& vars, - bool isInv, - TypeNode sygusType = TypeNode::null()) const override; + void toStreamCmdSynthFun( + std::ostream& out, + Node f, + const std::vector<Node>& vars, + bool isInv, + TypeNode sygusType = TypeNode::null()) const override; /** Print constraint command */ void toStreamCmdConstraint(std::ostream& out, Node n) const override; @@ -149,15 +155,33 @@ class Smt2Printer : public cvc5::Printer /** Print get-model command */ void toStreamCmdGetModel(std::ostream& out) const override; + /** Print block-model command */ + void toStreamCmdBlockModel(std::ostream& out) const override; + + /** Print block-model-values command */ + void toStreamCmdBlockModelValues( + std::ostream& out, const std::vector<Node>& nodes) const override; + /** Print get-proof command */ void toStreamCmdGetProof(std::ostream& out) const override; + /** Print get-interpol command */ + void toStreamCmdGetInterpol(std::ostream& out, + const std::string& name, + Node conj, + TypeNode sygusType) const override; + /** Print get-abduct command */ void toStreamCmdGetAbduct(std::ostream& out, const std::string& name, Node conj, TypeNode sygusType) const override; + /** Print get-quantifier-elimination command */ + void toStreamCmdGetQuantifierElimination(std::ostream& out, + Node n, + bool doFull) const override; + /** Print get-unsat-assumptions command */ void toStreamCmdGetUnsatAssumptions(std::ostream& out) const override; diff --git a/src/proof/lfsc/lfsc_node_converter.cpp b/src/proof/lfsc/lfsc_node_converter.cpp index 12326b212..b64506af5 100644 --- a/src/proof/lfsc/lfsc_node_converter.cpp +++ b/src/proof/lfsc/lfsc_node_converter.cpp @@ -226,7 +226,7 @@ Node LfscNodeConverter::postConvert(Node n) { TypeNode btn = nm->booleanType(); TypeNode tnv = nm->mkFunctionType(btn, tn); - TypeNode btnv = nm->mkFunctionType(btn, btn); + TypeNode btnv = nm->mkFunctionType({btn, btn}, btn); BitVector bv = n.getConst<BitVector>(); size_t w = bv.getSize(); Node ret = getSymbolInternal(k, btn, "bvn"); @@ -352,6 +352,21 @@ Node LfscNodeConverter::postConvert(Node n) // currently unsupported return n; } + else if (k == BITVECTOR_BB_TERM) + { + TypeNode btn = nm->booleanType(); + // (bbT t1 ... tn) is (bbT t1 (bbT t2 ... (bbT tn emptybv))) + // where notice that each bbT has a different type + Node curr = getNullTerminator(BITVECTOR_CONCAT, tn); + for (size_t i = 0, nchild = n.getNumChildren(); i < nchild; ++i) + { + TypeNode bvt = nm->mkBitVectorType(i + 1); + TypeNode ftype = nm->mkFunctionType({btn, curr.getType()}, bvt); + Node bbt = getSymbolInternal(k, ftype, "bbT"); + curr = nm->mkNode(APPLY_UF, bbt, n[nchild - (i + 1)], curr); + } + return curr; + } else if (k == SEP_NIL) { Node tnn = typeAsNode(convertType(tn)); @@ -591,8 +606,8 @@ std::string LfscNodeConverter::getNameForUserName(const std::string& name) bool LfscNodeConverter::shouldTraverse(Node n) { Kind k = n.getKind(); - // don't convert bound variable list directly - if (k == BOUND_VAR_LIST) + // don't convert bound variable or instantiation pattern list directly + if (k == BOUND_VAR_LIST || k == INST_PATTERN_LIST) { return false; } diff --git a/src/proof/lfsc/lfsc_post_processor.cpp b/src/proof/lfsc/lfsc_post_processor.cpp index 72db06060..33004e81f 100644 --- a/src/proof/lfsc/lfsc_post_processor.cpp +++ b/src/proof/lfsc/lfsc_post_processor.cpp @@ -16,6 +16,7 @@ #include "options/proof_options.h" #include "proof/lazy_proof.h" +#include "proof/lfsc/lfsc_printer.h" #include "proof/proof_checker.h" #include "proof/proof_node_algorithm.h" #include "proof/proof_node_manager.h" @@ -158,6 +159,8 @@ bool LfscProofPostprocessCallback::update(Node res, { Assert(res.getKind() == EQUAL); Assert(res[0].getOperator() == res[1].getOperator()); + Trace("lfsc-pp-cong") << "Processing congruence for " << res << " " + << res[0].getKind() << std::endl; // different for closures if (res[0].isClosure()) { @@ -210,6 +213,8 @@ bool LfscProofPostprocessCallback::update(Node res, // REFL step. Notice this may be for interpreted or uninterpreted // function symbols. Node op = d_tproc.getOperatorOfTerm(res[0]); + Trace("lfsc-pp-cong") << "Processing cong for op " << op << " " + << op.getType() << std::endl; Assert(!op.isNull()); // initial base step is REFL Node opEq = op.eqNode(op); @@ -245,9 +250,20 @@ bool LfscProofPostprocessCallback::update(Node res, for (size_t i = 0; i < nchildren; i++) { size_t ii = (nchildren - 1) - i; + Node uop = op; + // special case: each bv concat in the chain has a different type, + // so remake the operator here. + if (k == kind::BITVECTOR_CONCAT) + { + // we get the operator of the next argument concatenated with the + // current accumulated remainder. + Node currApp = + nm->mkNode(kind::BITVECTOR_CONCAT, children[ii][0], currEq[0]); + uop = d_tproc.getOperatorOfTerm(currApp); + } Node argAppEq = - nm->mkNode(HO_APPLY, op, children[ii][0]) - .eqNode(nm->mkNode(HO_APPLY, op, children[ii][1])); + nm->mkNode(HO_APPLY, uop, children[ii][0]) + .eqNode(nm->mkNode(HO_APPLY, uop, children[ii][1])); addLfscRule(cdp, argAppEq, {opEq, children[ii]}, LfscRule::CONG, {}); // now, congruence to the current equality Node nextEq; diff --git a/src/proof/proof_ensure_closed.h b/src/proof/proof_ensure_closed.h index cacfeeeed..14850de9b 100644 --- a/src/proof/proof_ensure_closed.h +++ b/src/proof/proof_ensure_closed.h @@ -28,7 +28,7 @@ class ProofNode; /** * Debug check closed on Trace c. Context ctx is string for debugging. * This method throws an assertion failure if pg cannot provide a closed - * proof for fact proven. This is checked only if --proof-eager-checking + * proof for fact proven. This is checked only if --proof-check=eager * is enabled or the Trace c is enabled. * * @param reqGen Whether we consider a null generator to be a failure. diff --git a/src/proof/proof_node_algorithm.cpp b/src/proof/proof_node_algorithm.cpp index ce8ca55c3..069bd1ba2 100644 --- a/src/proof/proof_node_algorithm.cpp +++ b/src/proof/proof_node_algorithm.cpp @@ -106,7 +106,7 @@ void getFreeAssumptionsMap( != traversing.end()) { Unhandled() << "getFreeAssumptionsMap: cyclic proof! (use " - "--proof-eager-checking)" + "--proof-check=eager)" << std::endl; } visit.push_back(cp); diff --git a/src/proof/proof_node_to_sexpr.cpp b/src/proof/proof_node_to_sexpr.cpp index 67a43fedc..e8871af34 100644 --- a/src/proof/proof_node_to_sexpr.cpp +++ b/src/proof/proof_node_to_sexpr.cpp @@ -60,7 +60,7 @@ Node ProofNodeToSExpr::convertToSExpr(const ProofNode* pn) != traversing.end()) { Unhandled() << "ProofNodeToSExpr::convertToSExpr: cyclic proof! (use " - "--proof-eager-checking)" + "--proof-check=eager)" << std::endl; return Node::null(); } diff --git a/src/proof/proof_node_updater.cpp b/src/proof/proof_node_updater.cpp index 561d4a761..47f30f9bb 100644 --- a/src/proof/proof_node_updater.cpp +++ b/src/proof/proof_node_updater.cpp @@ -154,7 +154,7 @@ void ProofNodeUpdater::processInternal(std::shared_ptr<ProofNode> pf, { Unhandled() << "ProofNodeUpdater::processInternal: cyclic proof! (use " - "--proof-eager-checking)" + "--proof-check=eager)" << std::endl; } visit.push_back(cp); diff --git a/src/proof/proof_rule.cpp b/src/proof/proof_rule.cpp index d4e763fe6..c82928dc5 100644 --- a/src/proof/proof_rule.cpp +++ b/src/proof/proof_rule.cpp @@ -171,6 +171,7 @@ const char* toString(PfRule id) case PfRule::ARITH_MULT_NEG: return "ARITH_MULT_NEG"; case PfRule::ARITH_MULT_TANGENT: return "ARITH_MULT_TANGENT"; case PfRule::ARITH_OP_ELIM_AXIOM: return "ARITH_OP_ELIM_AXIOM"; + case PfRule::ARITH_POLY_NORM: return "ARITH_POLY_NORM"; case PfRule::ARITH_TRANS_PI: return "ARITH_TRANS_PI"; case PfRule::ARITH_TRANS_EXP_NEG: return "ARITH_TRANS_EXP_NEG"; case PfRule::ARITH_TRANS_EXP_POSITIVITY: diff --git a/src/proof/proof_rule.h b/src/proof/proof_rule.h index 25bbf3d34..d9e92fa92 100644 --- a/src/proof/proof_rule.h +++ b/src/proof/proof_rule.h @@ -1153,6 +1153,13 @@ enum class PfRule : uint32_t // --------------------- // Conclusion: arith::OperatorElim::getAxiomFor(t) ARITH_OP_ELIM_AXIOM, + // ======== Arithmetic polynomial normalization + // Children: none + // Arguments: ((= t s)) + // --------------------- + // Conclusion: (= t s) + // where arith::PolyNorm::isArithPolyNorm(t, s) = true + ARITH_POLY_NORM, //======== Multiplication sign inference // Children: none diff --git a/src/prop/bv_sat_solver_notify.h b/src/prop/bv_sat_solver_notify.h deleted file mode 100644 index 416a08ef3..000000000 --- a/src/prop/bv_sat_solver_notify.h +++ /dev/null @@ -1,51 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Liana Hadarean, Alex Ozdemir, Mathias Preiner - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * The interface for things that want to recieve notification from the SAT - * solver. - */ - -#include "cvc5_private.h" - -#ifndef CVC5__PROP__BVSATSOLVERNOTIFY_H -#define CVC5__PROP__BVSATSOLVERNOTIFY_H - -#include "prop/sat_solver_types.h" -#include "util/resource_manager.h" - -namespace cvc5 { -namespace prop { - -class BVSatSolverNotify { -public: - - virtual ~BVSatSolverNotify() {}; - - /** - * If the notify returns false, the solver will break out of whatever it's currently doing - * with an "unknown" answer. - */ - virtual bool notify(SatLiteral lit) = 0; - - /** - * Notify about a learnt clause. - */ - virtual void notify(SatClause& clause) = 0; - virtual void spendResource(Resource r) = 0; - virtual void safePoint(Resource r) = 0; - -};/* class BVSatSolverInterface::Notify */ - -} -} // namespace cvc5 - -#endif diff --git a/src/prop/bvminisat/LICENSE b/src/prop/bvminisat/LICENSE deleted file mode 100644 index 22816ff39..000000000 --- a/src/prop/bvminisat/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson - Copyright (c) 2007-2010 Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/src/prop/bvminisat/README b/src/prop/bvminisat/README deleted file mode 100644 index e5e5617d8..000000000 --- a/src/prop/bvminisat/README +++ /dev/null @@ -1,24 +0,0 @@ -================================================================================ -DIRECTORY OVERVIEW: - -mtl/ Mini Template Library -utils/ Generic helper code (I/O, Parsing, CPU-time, etc) -core/ A core version of the solver -simp/ An extended solver with simplification capabilities -README -LICENSE - -================================================================================ -BUILDING: (release version: without assertions, statically linked, etc) - -export MROOT=<minisat-dir> (or setenv in cshell) -cd { core | simp } -gmake rs -cp minisat_static <install-dir>/minisat - -================================================================================ -EXAMPLES: - -Run minisat with same heuristics as version 2.0: - -> minisat <cnf-file> -no-luby -rinc=1.5 -phase-saving=0 -rnd-freq=0.02 diff --git a/src/prop/bvminisat/bvminisat.cpp b/src/prop/bvminisat/bvminisat.cpp deleted file mode 100644 index 77b8c68e0..000000000 --- a/src/prop/bvminisat/bvminisat.cpp +++ /dev/null @@ -1,299 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Liana Hadarean, Dejan Jovanovic, Tim King - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * SAT Solver. - * - * Implementation of the minisat for cvc5 (bit-vectors). - */ - -#include "prop/bvminisat/bvminisat.h" - -#include "prop/bvminisat/simp/SimpSolver.h" -#include "proof/clause_id.h" -#include "util/statistics_registry.h" - -namespace cvc5 { -namespace prop { - -BVMinisatSatSolver::BVMinisatSatSolver(StatisticsRegistry& registry, - context::Context* mainSatContext, - const std::string& name) - : context::ContextNotifyObj(mainSatContext, false), - d_minisat(new BVMinisat::SimpSolver(mainSatContext)), - d_minisatNotify(nullptr), - d_assertionsCount(0), - d_assertionsRealCount(mainSatContext, 0), - d_lastPropagation(mainSatContext, 0), - d_statistics(registry, name) -{ - d_statistics.init(d_minisat.get()); -} - -BVMinisatSatSolver::~BVMinisatSatSolver() { d_statistics.deinit(); } - -void BVMinisatSatSolver::MinisatNotify::notify( - BVMinisat::vec<BVMinisat::Lit>& clause) -{ - SatClause satClause; - for (unsigned i = 0, n = clause.size(); i < n; ++i) - { - satClause.push_back(toSatLiteral(clause[i])); - } - d_notify->notify(satClause); -} - -void BVMinisatSatSolver::setNotify(BVSatSolverNotify* notify) { - d_minisatNotify.reset(new MinisatNotify(notify)); - d_minisat->setNotify(d_minisatNotify.get()); -} - -ClauseId BVMinisatSatSolver::addClause(SatClause& clause, - bool removable) { - Debug("sat::minisat") << "Add clause " << clause <<"\n"; - BVMinisat::vec<BVMinisat::Lit> minisat_clause; - toMinisatClause(clause, minisat_clause); - // for(unsigned i = 0; i < minisat_clause.size(); ++i) { - // d_minisat->setFrozen(BVMinisat::var(minisat_clause[i]), true); - // } - ClauseId clause_id = ClauseIdError; - d_minisat->addClause(minisat_clause, clause_id); - return clause_id; -} - -SatValue BVMinisatSatSolver::propagate() { - return toSatLiteralValue(d_minisat->propagateAssumptions()); -} - -void BVMinisatSatSolver::addMarkerLiteral(SatLiteral lit) { - d_minisat->addMarkerLiteral(BVMinisat::var(toMinisatLit(lit))); - markUnremovable(lit); -} - -void BVMinisatSatSolver::explain(SatLiteral lit, std::vector<SatLiteral>& explanation) { - std::vector<BVMinisat::Lit> minisat_explanation; - d_minisat->explain(toMinisatLit(lit), minisat_explanation); - for (unsigned i = 0; i < minisat_explanation.size(); ++i) { - explanation.push_back(toSatLiteral(minisat_explanation[i])); - } -} - -SatValue BVMinisatSatSolver::assertAssumption(SatLiteral lit, bool propagate) { - d_assertionsCount ++; - d_assertionsRealCount = d_assertionsRealCount + 1; - return toSatLiteralValue(d_minisat->assertAssumption(toMinisatLit(lit), propagate)); -} - -void BVMinisatSatSolver::contextNotifyPop() { - while (d_assertionsCount > d_assertionsRealCount) { - popAssumption(); - d_assertionsCount --; - } -} - -void BVMinisatSatSolver::popAssumption() { - d_minisat->popAssumption(); -} - -SatVariable BVMinisatSatSolver::newVar(bool isTheoryAtom, bool preRegister, bool canErase){ - return d_minisat->newVar(true, true, !canErase); -} - -void BVMinisatSatSolver::markUnremovable(SatLiteral lit){ - d_minisat->setFrozen(BVMinisat::var(toMinisatLit(lit)), true); -} - - -void BVMinisatSatSolver::interrupt(){ - d_minisat->interrupt(); -} - -SatValue BVMinisatSatSolver::solve() -{ - TimerStat::CodeTimer solveTimer(d_statistics.d_statSolveTime); - ++d_statistics.d_statCallsToSolve; - return toSatLiteralValue(d_minisat->solve()); -} - -SatValue BVMinisatSatSolver::solve(long unsigned int& resource){ - Trace("limit") << "MinisatSatSolver::solve(): have limit of " << resource << " conflicts" << std::endl; - TimerStat::CodeTimer solveTimer(d_statistics.d_statSolveTime); - ++d_statistics.d_statCallsToSolve; - if(resource == 0) { - d_minisat->budgetOff(); - } else { - d_minisat->setConfBudget(resource); - } - // BVMinisat::vec<BVMinisat::Lit> empty; - unsigned long conflictsBefore = d_minisat->conflicts; - SatValue result = toSatLiteralValue(d_minisat->solveLimited()); - d_minisat->clearInterrupt(); - resource = d_minisat->conflicts - conflictsBefore; - Trace("limit") << "<MinisatSatSolver::solve(): it took " << resource << " conflicts" << std::endl; - return result; -} - -bool BVMinisatSatSolver::ok() const { return d_minisat->okay(); } - -void BVMinisatSatSolver::getUnsatCore(SatClause& unsatCore) { - // TODO add assertion to check the call was after an unsat call - for (int i = 0; i < d_minisat->conflict.size(); ++i) { - unsatCore.push_back(toSatLiteral(d_minisat->conflict[i])); - } -} - -SatValue BVMinisatSatSolver::value(SatLiteral l){ - return toSatLiteralValue(d_minisat->value(toMinisatLit(l))); -} - -SatValue BVMinisatSatSolver::modelValue(SatLiteral l){ - return toSatLiteralValue(d_minisat->modelValue(toMinisatLit(l))); -} - -void BVMinisatSatSolver::unregisterVar(SatLiteral lit) { - // this should only be called when user context is implemented - // in the BVSatSolver - Unreachable(); -} - -void BVMinisatSatSolver::renewVar(SatLiteral lit, int level) { - // this should only be called when user context is implemented - // in the BVSatSolver - - Unreachable(); -} - -unsigned BVMinisatSatSolver::getAssertionLevel() const { - // we have no user context implemented so far - return 0; -} - -// converting from internal Minisat representation - -SatVariable BVMinisatSatSolver::toSatVariable(BVMinisat::Var var) { - if (var == var_Undef) { - return undefSatVariable; - } - return SatVariable(var); -} - -BVMinisat::Lit BVMinisatSatSolver::toMinisatLit(SatLiteral lit) { - if (lit == undefSatLiteral) { - return BVMinisat::lit_Undef; - } - return BVMinisat::mkLit(lit.getSatVariable(), lit.isNegated()); -} - -SatLiteral BVMinisatSatSolver::toSatLiteral(BVMinisat::Lit lit) { - if (lit == BVMinisat::lit_Undef) { - return undefSatLiteral; - } - - return SatLiteral(SatVariable(BVMinisat::var(lit)), - BVMinisat::sign(lit)); -} - -SatValue BVMinisatSatSolver::toSatLiteralValue(BVMinisat::lbool res) { - if(res == (BVMinisat::lbool((uint8_t)0))) return SAT_VALUE_TRUE; - if(res == (BVMinisat::lbool((uint8_t)2))) return SAT_VALUE_UNKNOWN; - Assert(res == (BVMinisat::lbool((uint8_t)1))); - return SAT_VALUE_FALSE; -} - -void BVMinisatSatSolver::toMinisatClause(SatClause& clause, - BVMinisat::vec<BVMinisat::Lit>& minisat_clause) { - for (unsigned i = 0; i < clause.size(); ++i) { - minisat_clause.push(toMinisatLit(clause[i])); - } - Assert(clause.size() == (unsigned)minisat_clause.size()); -} - -void BVMinisatSatSolver::toSatClause(const BVMinisat::Clause& clause, - SatClause& sat_clause) { - for (int i = 0; i < clause.size(); ++i) { - sat_clause.push_back(toSatLiteral(clause[i])); - } - Assert((unsigned)clause.size() == sat_clause.size()); -} - - -// Satistics for BVMinisatSatSolver - -BVMinisatSatSolver::Statistics::Statistics(StatisticsRegistry& registry, - const std::string& prefix) - : d_statStarts( - registry.registerReference<int64_t>(prefix + "bvminisat::starts")), - d_statDecisions( - registry.registerReference<int64_t>(prefix + "bvminisat::decisions")), - d_statRndDecisions(registry.registerReference<int64_t>( - prefix + "bvminisat::rnd_decisions")), - d_statPropagations(registry.registerReference<int64_t>( - prefix + "bvminisat::propagations")), - d_statConflicts( - registry.registerReference<int64_t>(prefix + "bvminisat::conflicts")), - d_statClausesLiterals(registry.registerReference<int64_t>( - prefix + "bvminisat::clauses_literals")), - d_statLearntsLiterals(registry.registerReference<int64_t>( - prefix + "bvminisat::learnts_literals")), - d_statMaxLiterals(registry.registerReference<int64_t>( - prefix + "bvminisat::max_literals")), - d_statTotLiterals(registry.registerReference<int64_t>( - prefix + "bvminisat::tot_literals")), - d_statEliminatedVars(registry.registerReference<int64_t>( - prefix + "bvminisat::eliminated_vars")), - d_statCallsToSolve( - registry.registerInt(prefix + "bvminisat::calls_to_solve")), - d_statSolveTime(registry.registerTimer(prefix + "bvminisat::solve_time")) -{ - if (!d_registerStats) - { - return; - } -} - -void BVMinisatSatSolver::Statistics::init(BVMinisat::SimpSolver* minisat){ - if (!d_registerStats){ - return; - } - - d_statStarts.set(minisat->starts); - d_statDecisions.set(minisat->decisions); - d_statRndDecisions.set(minisat->rnd_decisions); - d_statPropagations.set(minisat->propagations); - d_statConflicts.set(minisat->conflicts); - d_statClausesLiterals.set(minisat->clauses_literals); - d_statLearntsLiterals.set(minisat->learnts_literals); - d_statMaxLiterals.set(minisat->max_literals); - d_statTotLiterals.set(minisat->tot_literals); - d_statEliminatedVars.set(minisat->eliminated_vars); -} - -void BVMinisatSatSolver::Statistics::deinit() -{ - if (!d_registerStats) - { - return; - } - - d_statStarts.reset(); - d_statDecisions.reset(); - d_statRndDecisions.reset(); - d_statPropagations.reset(); - d_statConflicts.reset(); - d_statClausesLiterals.reset(); - d_statLearntsLiterals.reset(); - d_statMaxLiterals.reset(); - d_statTotLiterals.reset(); - d_statEliminatedVars.reset(); -} - -} // namespace prop -} // namespace cvc5 diff --git a/src/prop/bvminisat/bvminisat.h b/src/prop/bvminisat/bvminisat.h deleted file mode 100644 index 3bfb2d93c..000000000 --- a/src/prop/bvminisat/bvminisat.h +++ /dev/null @@ -1,151 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Mathias Preiner, Liana Hadarean, Tim King - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * SAT Solver. - * - * Implementation of the minisat for cvc5 (bit-vectors). - */ - -#include "cvc5_private.h" - -#pragma once - -#include <memory> - -#include "context/cdo.h" -#include "prop/bv_sat_solver_notify.h" -#include "prop/bvminisat/simp/SimpSolver.h" -#include "prop/sat_solver.h" -#include "util/resource_manager.h" -#include "util/statistics_stats.h" - -namespace cvc5 { -namespace prop { - -class BVMinisatSatSolver : public BVSatSolverInterface, - public context::ContextNotifyObj -{ - private: - class MinisatNotify : public BVMinisat::Notify - { - BVSatSolverNotify* d_notify; - - public: - MinisatNotify(BVSatSolverNotify* notify) : d_notify(notify) {} - bool notify(BVMinisat::Lit lit) override - { - return d_notify->notify(toSatLiteral(lit)); - } - void notify(BVMinisat::vec<BVMinisat::Lit>& clause) override; - void spendResource(Resource r) override - { - d_notify->spendResource(r); - } - void safePoint(Resource r) override - { - d_notify->safePoint(r); - } - }; - - std::unique_ptr<BVMinisat::SimpSolver> d_minisat; - std::unique_ptr<MinisatNotify> d_minisatNotify; - - unsigned d_assertionsCount; - context::CDO<unsigned> d_assertionsRealCount; - context::CDO<unsigned> d_lastPropagation; - -protected: - void contextNotifyPop() override; - -public: - BVMinisatSatSolver(StatisticsRegistry& registry, - context::Context* mainSatContext, - const std::string& name = ""); - virtual ~BVMinisatSatSolver(); - - void setNotify(BVSatSolverNotify* notify) override; - - ClauseId addClause(SatClause& clause, bool removable) override; - - ClauseId addXorClause(SatClause& clause, bool rhs, bool removable) override - { - Unreachable() << "Minisat does not support native XOR reasoning"; - return ClauseIdError; - } - - SatValue propagate() override; - - SatVariable newVar(bool isTheoryAtom = false, - bool preRegister = false, - bool canErase = true) override; - - SatVariable trueVar() override { return d_minisat->trueVar(); } - SatVariable falseVar() override { return d_minisat->falseVar(); } - - void markUnremovable(SatLiteral lit) override; - - void interrupt() override; - - SatValue solve() override; - SatValue solve(long unsigned int&) override; - bool ok() const override; - void getUnsatCore(SatClause& unsatCore) override; - - SatValue value(SatLiteral l) override; - SatValue modelValue(SatLiteral l) override; - - void unregisterVar(SatLiteral lit); - void renewVar(SatLiteral lit, int level = -1); - unsigned getAssertionLevel() const override; - - // helper methods for converting from the internal Minisat representation - - static SatVariable toSatVariable(BVMinisat::Var var); - static BVMinisat::Lit toMinisatLit(SatLiteral lit); - static SatLiteral toSatLiteral(BVMinisat::Lit lit); - static SatValue toSatLiteralValue(BVMinisat::lbool res); - - static void toMinisatClause(SatClause& clause, BVMinisat::vec<BVMinisat::Lit>& minisat_clause); - static void toSatClause (const BVMinisat::Clause& clause, SatClause& sat_clause); - void addMarkerLiteral(SatLiteral lit) override; - - void explain(SatLiteral lit, std::vector<SatLiteral>& explanation) override; - - SatValue assertAssumption(SatLiteral lit, bool propagate) override; - - void popAssumption() override; - - private: - /* Disable the default constructor. */ - BVMinisatSatSolver() = delete; - - class Statistics { - public: - ReferenceStat<int64_t> d_statStarts, d_statDecisions; - ReferenceStat<int64_t> d_statRndDecisions, d_statPropagations; - ReferenceStat<int64_t> d_statConflicts, d_statClausesLiterals; - ReferenceStat<int64_t> d_statLearntsLiterals, d_statMaxLiterals; - ReferenceStat<int64_t> d_statTotLiterals; - ReferenceStat<int64_t> d_statEliminatedVars; - IntStat d_statCallsToSolve; - TimerStat d_statSolveTime; - bool d_registerStats = true; - Statistics(StatisticsRegistry& registry, const std::string& prefix); - void init(BVMinisat::SimpSolver* minisat); - void deinit(); - }; - - Statistics d_statistics; -}; - -} // namespace prop -} // namespace cvc5 diff --git a/src/prop/bvminisat/core/Dimacs.h b/src/prop/bvminisat/core/Dimacs.h deleted file mode 100644 index a660391f7..000000000 --- a/src/prop/bvminisat/core/Dimacs.h +++ /dev/null @@ -1,91 +0,0 @@ -/****************************************************************************************[Dimacs.h] -Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson -Copyright (c) 2007-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#ifndef BVMinisat_Dimacs_h -#define BVMinisat_Dimacs_h - -#include <stdio.h> - -#include "prop/bvminisat/core/SolverTypes.h" -#include "prop/bvminisat/utils/ParseUtils.h" - -namespace cvc5 { -namespace BVMinisat { - -//================================================================================================= -// DIMACS Parser: - -template<class B, class Solver> -static void readClause(B& in, Solver& S, vec<Lit>& lits) { - int parsed_lit, var; - lits.clear(); - for (;;){ - parsed_lit = parseInt(in); - if (parsed_lit == 0) break; - var = abs(parsed_lit)-1; - while (var >= S.nVars()) S.newVar(); - lits.push( (parsed_lit > 0) ? mkLit(var) : ~mkLit(var) ); - } -} - -template<class B, class Solver> -static void parse_DIMACS_main(B& in, Solver& S) { - vec<Lit> lits; - int vars = 0; - int clauses = 0; - int cnt = 0; - for (;;){ - skipWhitespace(in); - if (*in == EOF) break; - else if (*in == 'p'){ - if (eagerMatch(in, "p cnf")){ - vars = parseInt(in); - clauses = parseInt(in); - // SATRACE'06 hack - // if (clauses > 4000000) - // S.eliminate(true); - }else{ - printf("PARSE ERROR! Unexpected char: %c\n", *in), exit(3); - } - } else if (*in == 'c' || *in == 'p') - skipLine(in); - else{ - cnt++; - readClause(in, S, lits); - S.addClause_(lits); } - } - if (vars != S.nVars()) - fprintf(stderr, "WARNING! DIMACS header mismatch: wrong number of variables.\n"); - if (cnt != clauses) - fprintf(stderr, "WARNING! DIMACS header mismatch: wrong number of clauses.\n"); -} - -// Inserts problem into solver. -// -template<class Solver> -static void parse_DIMACS(gzFile input_stream, Solver& S) { - StreamBuffer in(input_stream); - parse_DIMACS_main(in, S); } - -//================================================================================================= -} // namespace BVMinisat -} // namespace cvc5 - -#endif diff --git a/src/prop/bvminisat/core/Solver.cc b/src/prop/bvminisat/core/Solver.cc deleted file mode 100644 index e7d9086bc..000000000 --- a/src/prop/bvminisat/core/Solver.cc +++ /dev/null @@ -1,1421 +0,0 @@ -/***************************************************************************************[Solver.cc] -Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson -Copyright (c) 2007-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#include "prop/bvminisat/core/Solver.h" - -#include <math.h> - -#include <iostream> -#include <vector> - -#include "base/check.h" -#include "base/exception.h" -#include "base/output.h" -#include "options/bv_options.h" -#include "options/smt_options.h" -#include "prop/bvminisat/mtl/Sort.h" -#include "theory/interrupted.h" -#include "util/utility.h" - -namespace cvc5 { -namespace BVMinisat { - -#define OUTPUT_TAG "bvminisat: [a=" << assumptions.size() << ",l=" << decisionLevel() << "] " - -std::ostream& operator << (std::ostream& out, const BVMinisat::Lit& l) { - out << (sign(l) ? "-" : "") << var(l) + 1; - return out; -} - -std::ostream& operator << (std::ostream& out, const BVMinisat::Clause& c) { - for (int i = 0; i < c.size(); i++) { - if (i > 0) { - out << " "; - } - out << c[i]; - } - return out; -} - - -//================================================================================================= -// Options: - - -static const char* _cat = "CORE"; - -static DoubleOption opt_var_decay (_cat, "var-decay", "The variable activity decay factor", 0.95, DoubleRange(0, false, 1, false)); -static DoubleOption opt_clause_decay (_cat, "cla-decay", "The clause activity decay factor", 0.999, DoubleRange(0, false, 1, false)); -static DoubleOption opt_random_var_freq (_cat, "rnd-freq", "The frequency with which the decision heuristic tries to choose a random variable", 0, DoubleRange(0, true, 1, true)); -static DoubleOption opt_random_seed (_cat, "rnd-seed", "Used by the random variable selection", 91648253, DoubleRange(0, false, HUGE_VAL, false)); -static IntOption opt_ccmin_mode (_cat, "ccmin-mode", "Controls conflict clause minimization (0=none, 1=basic, 2=deep)", 2, IntRange(0, 2)); -static IntOption opt_phase_saving (_cat, "phase-saving", "Controls the level of phase saving (0=none, 1=limited, 2=full)", 2, IntRange(0, 2)); -static BoolOption opt_rnd_init_act (_cat, "rnd-init", "Randomize the initial activity", false); -static BoolOption opt_luby_restart (_cat, "luby", "Use the Luby restart sequence", true); -static IntOption opt_restart_first (_cat, "rfirst", "The base restart interval", 25, IntRange(1, INT32_MAX)); -static DoubleOption opt_restart_inc (_cat, "rinc", "Restart interval increase factor", 3, DoubleRange(1, false, HUGE_VAL, false)); -static DoubleOption opt_garbage_frac (_cat, "gc-frac", "The fraction of wasted memory allowed before a garbage collection is triggered", 0.20, DoubleRange(0, false, HUGE_VAL, false)); - -//================================================================================================= -// Proof declarations -CRef Solver::TCRef_Undef = CRef_Undef; -CRef Solver::TCRef_Lazy = CRef_Undef - 1; // no real lazy ref here - - -//================================================================================================= -// Constructor/Destructor: - -Solver::Solver(cvc5::context::Context* context) - : - - // Parameters (user settable): - // - d_notify(nullptr), - c(context), - verbosity(0), - var_decay(opt_var_decay), - clause_decay(opt_clause_decay), - random_var_freq(opt_random_var_freq), - random_seed(opt_random_seed), - luby_restart(opt_luby_restart), - ccmin_mode(opt_ccmin_mode), - phase_saving(opt_phase_saving), - rnd_pol(false), - rnd_init_act(opt_rnd_init_act), - garbage_frac(opt_garbage_frac), - restart_first(opt_restart_first), - restart_inc(opt_restart_inc) - - // Parameters (the rest): - // - , - learntsize_factor((double)1 / (double)3), - learntsize_inc(1.5) - - // Parameters (experimental): - // - , - learntsize_adjust_start_confl(100), - learntsize_adjust_inc(1.5) - - // Statistics: (formerly in 'SolverStats') - // - , - solves(0), - starts(0), - decisions(0), - rnd_decisions(0), - propagations(0), - conflicts(0), - dec_vars(0), - clauses_literals(0), - learnts_literals(0), - max_literals(0), - tot_literals(0) - - , - need_to_propagate(false), - only_bcp(false), - clause_added(false), - ok(true), - cla_inc(1), - var_inc(1), - watches(WatcherDeleted(ca)), - qhead(0), - simpDB_assigns(-1), - simpDB_props(0), - order_heap(VarOrderLt(activity)), - progress_estimate(0), - remove_satisfied(true) - - , - ca() - - // even though these are temporaries and technically should be set - // before calling, lets initialize them. this will reduces chances of - // non-determinism in portfolio (parallel) solver if variables are - // being (incorrectly) used without initialization. - , - seen(), - analyze_stack(), - analyze_toclear(), - add_tmp(), - max_learnts(0.0), - learntsize_adjust_confl(0.0), - learntsize_adjust_cnt(0) - - // Resource constraints: - // - , - conflict_budget(-1), - propagation_budget(-1), - asynch_interrupt(false) -{ - // Create the constant variables - varTrue = newVar(true, false); - varFalse = newVar(false, false); - - // Assert the constants - uncheckedEnqueue(mkLit(varTrue, false)); - uncheckedEnqueue(mkLit(varFalse, true)); -} - - -Solver::~Solver() -{ -} - - -//================================================================================================= -// Minor methods: - - -// Creates a new SAT variable in the solver. If 'decision' is cleared, variable will not be -// used as a decision variable (NOTE! This has effects on the meaning of a SATISFIABLE result). -// -Var Solver::newVar(bool sign, bool dvar) -{ - int v = nVars(); - watches .init(mkLit(v, false)); - watches .init(mkLit(v, true )); - assigns .push(l_Undef); - vardata .push(mkVarData(CRef_Undef, 0)); - marker .push(0); - //activity .push(0); - activity .push(rnd_init_act ? drand(random_seed) * 0.00001 : 0); - seen .push(0); - polarity .push(sign); - decision .push(); - trail .capacity(v+1); - setDecisionVar(v, dvar); - - return v; -} - - -bool Solver::addClause_(vec<Lit>& ps, ClauseId& id) -{ - if (decisionLevel() > 0) { - cancelUntil(0); - } - - if (!ok) { - id = ClauseIdUndef; - return false; - } - - // Check if clause is satisfied and remove false/duplicate literals: - // TODO proof for duplicate literals removal? - sort(ps); - Lit p; int i, j; - int falseLiteralsCount = 0; - - for (i = j = 0, p = lit_Undef; i < ps.size(); i++) { - // tautologies are ignored - if (value(ps[i]) == l_True || ps[i] == ~p) { - id = ClauseIdUndef; - return true; - } - - // Ignore repeated literals - if (ps[i] == p) { - continue; - } - - if (value(ps[i]) == l_False) { - continue; - } - ps[j++] = p = ps[i]; - } - - ps.shrink(i - j); - - clause_added = true; - - if(falseLiteralsCount == 0) { - if (ps.size() == 0) { - return ok = false; - } - else if (ps.size() == 1){ - uncheckedEnqueue(ps[0]); - CRef confl_ref = propagate(); - ok = (confl_ref == CRef_Undef); - return ok; - } else { - CRef cr = ca.alloc(ps, false); - clauses.push(cr); - attachClause(cr); - } - return ok; - } - return ok; -} - -void Solver::attachClause(CRef cr) { - const Clause& clause = ca[cr]; - Assert(clause.size() > 1); - watches[~clause[0]].push(Watcher(cr, clause[1])); - watches[~clause[1]].push(Watcher(cr, clause[0])); - if (clause.learnt()) - learnts_literals += clause.size(); - else - clauses_literals += clause.size(); -} - -void Solver::detachClause(CRef cr, bool strict) { - const Clause& clause = ca[cr]; - - Assert(clause.size() > 1); - - if (strict) - { - remove(watches[~clause[0]], Watcher(cr, clause[1])); - remove(watches[~clause[1]], Watcher(cr, clause[0])); - }else{ - // Lazy detaching: (NOTE! Must clean all watcher lists before garbage collecting this clause) - watches.smudge(~clause[0]); - watches.smudge(~clause[1]); - } - - if (clause.learnt()) - learnts_literals -= clause.size(); - else - clauses_literals -= clause.size(); -} - -void Solver::removeClause(CRef cr) { - Clause& clause = ca[cr]; - detachClause(cr); - // Don't leave pointers to free'd memory! - if (locked(clause)) vardata[var(clause[0])].reason = CRef_Undef; - clause.mark(1); - ca.free(cr); -} - -bool Solver::satisfied(const Clause& clause) const -{ - for (int i = 0; i < clause.size(); i++) - if (value(clause[i]) == l_True) return true; - return false; -} - -// Revert to the state at given level (keeping all assignment at 'level' but not beyond). -// -void Solver::cancelUntil(int level) { - if (decisionLevel() > level){ - Debug("bvminisat::explain") << OUTPUT_TAG << " backtracking to " << level << std::endl; - for (int clause = trail.size() - 1; clause >= trail_lim[level]; clause--) - { - Var x = var(trail[clause]); - assigns[x] = l_Undef; - if (marker[x] == 2) marker[x] = 1; - if (phase_saving > 1 - || ((phase_saving == 1) && clause > trail_lim.last())) - { - polarity[x] = sign(trail[clause]); - } - insertVarOrder(x); - } - qhead = trail_lim[level]; - trail.shrink(trail.size() - trail_lim[level]); - trail_lim.shrink(trail_lim.size() - level); - } -} - - -//================================================================================================= -// Major methods: - - -Lit Solver::pickBranchLit() -{ - Var next = var_Undef; - - // Random decision: - if (drand(random_seed) < random_var_freq && !order_heap.empty()){ - next = order_heap[irand(random_seed,order_heap.size())]; - if (value(next) == l_Undef && decision[next]) - rnd_decisions++; } - - // Activity based decision: - while (next == var_Undef || value(next) != l_Undef || !decision[next]) - if (order_heap.empty()){ - next = var_Undef; - break; - }else - next = order_heap.removeMin(); - - return next == var_Undef ? lit_Undef : mkLit(next, rnd_pol ? drand(random_seed) < 0.5 : polarity[next]); -} - -/*_________________________________________________________________________________________________ -| -| analyze : (confl : Clause*) (out_learnt : vec<Lit>&) (out_btlevel : int&) -> -[void] -| -| Description: -| Analyze conflict and produce a reason clause. -| -| Pre-conditions: -| * 'out_learnt' is assumed to be cleared. -| * Current decision level must be greater than root level. -| -| Post-conditions: -| * 'out_learnt[0]' is the asserting literal at level 'out_btlevel'. -| * If out_learnt.size() > 1 then 'out_learnt[1]' has the greatest decision -level of the | rest of literals. There may be others from the same level -though. -| -|________________________________________________________________________________________________@*/ -void Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel, UIP uip) -{ - int pathC = 0; - Lit p = lit_Undef; - - // Generate conflict clause: - // - out_learnt.push(); // (leave room for the asserting literal) - int index = trail.size() - 1; - - bool done = false; - - do{ - Assert(confl != CRef_Undef); // (otherwise should be UIP) - Clause& clause = ca[confl]; - - if (clause.learnt()) claBumpActivity(clause); - - for (int j = (p == lit_Undef) ? 0 : 1; j < clause.size(); j++) - { - Lit q = clause[j]; - - if (!seen[var(q)] && level(var(q)) > 0) - { - varBumpActivity(var(q)); - seen[var(q)] = 1; - if (level(var(q)) >= decisionLevel()) - pathC++; - else - out_learnt.push(q); - } - } - - // Select next clause to look at: - while (!seen[var(trail[index--])]); - p = trail[index+1]; - confl = reason(var(p)); - seen[var(p)] = 0; - pathC--; - - switch (uip) { - case UIP_FIRST: - done = pathC == 0; - break; - case UIP_LAST: - done = confl == CRef_Undef || (pathC == 0 && marker[var(p)] == 2); - break; - default: - Unreachable(); - break; - } - } while (!done); - out_learnt[0] = ~p; - - // Simplify conflict clause: - // - int i1, j; - out_learnt.copyTo(analyze_toclear); - if (ccmin_mode == 2){ - uint32_t abstract_level = 0; - for (i1 = 1; i1 < out_learnt.size(); i1++) - abstract_level |= abstractLevel( - var(out_learnt[i1])); // (maintain an abstraction of levels - // involved in conflict) - - for (i1 = j = 1; i1 < out_learnt.size(); i1++) - { - if (reason(var(out_learnt[i1])) == CRef_Undef) - { - out_learnt[j++] = out_learnt[i1]; - } - else - { - // Check if the literal is redundant - if (!litRedundant(out_learnt[i1], abstract_level)) - { - // Literal is not redundant - out_learnt[j++] = out_learnt[i1]; - } - } - } - }else if (ccmin_mode == 1){ - Unreachable(); - for (i1 = j = 1; i1 < out_learnt.size(); i1++) - { - Var x = var(out_learnt[i1]); - - if (reason(x) == CRef_Undef) - out_learnt[j++] = out_learnt[i1]; - else - { - Clause& clause = ca[reason(var(out_learnt[i1]))]; - for (int k = 1; k < clause.size(); k++) - if (!seen[var(clause[k])] && level(var(clause[k])) > 0) - { - out_learnt[j++] = out_learnt[i1]; - break; - } - } - } - }else - i1 = j = out_learnt.size(); - - max_literals += out_learnt.size(); - out_learnt.shrink(i1 - j); - tot_literals += out_learnt.size(); - - for (int i2 = 0; i2 < out_learnt.size(); ++i2) - { - if (marker[var(out_learnt[i2])] == 0) - { - break; - } - } - - // Find correct backtrack level: - // - if (out_learnt.size() == 1) { - out_btlevel = 0; - } - else{ - int max_i = 1; - // Find the first literal assigned at the next-highest level: - for (int i3 = 2; i3 < out_learnt.size(); i3++) - if (level(var(out_learnt[i3])) > level(var(out_learnt[max_i]))) - max_i = i3; - // Swap-in this literal at i1 1: - Lit p2 = out_learnt[max_i]; - out_learnt[max_i] = out_learnt[1]; - out_learnt[1] = p2; - out_btlevel = level(var(p2)); - } - - for (int j2 = 0; j2 < analyze_toclear.size(); j2++) - seen[var(analyze_toclear[j2])] = 0; // ('seen[]' is now cleared) -} - - -// Check if 'p' can be removed. 'abstract_levels' is used to abort early if the algorithm is -// visiting literals at levels that cannot be removed later. -bool Solver::litRedundant(Lit p, uint32_t abstract_levels) -{ - analyze_stack.clear(); analyze_stack.push(p); - int top = analyze_toclear.size(); - while (analyze_stack.size() > 0){ - CRef c_reason = reason(var(analyze_stack.last())); - Assert(c_reason != CRef_Undef); - Clause& clause = ca[c_reason]; - int c_size = clause.size(); - analyze_stack.pop(); - - for (int i = 1; i < c_size; i++){ - Lit p2 = clause[i]; - if (!seen[var(p2)] && level(var(p2)) > 0) - { - if (reason(var(p2)) != CRef_Undef - && (abstractLevel(var(p2)) & abstract_levels) != 0) - { - seen[var(p2)] = 1; - analyze_stack.push(p2); - analyze_toclear.push(p2); - } - else - { - for (int j = top; j < analyze_toclear.size(); j++) - seen[var(analyze_toclear[j])] = 0; - analyze_toclear.shrink(analyze_toclear.size() - top); - return false; - } - } - } - } - - return true; -} - -/** - * Specialized analyzeFinal procedure where we test the consistency - * of the assumptions before backtracking bellow the assumption level. - * - * @param p the original uip (may be unit) - * @param confl_clause the conflict clause - * @param out_conflict the conflict in terms of assumptions we are building - */ -void Solver::analyzeFinal2(Lit p, CRef confl_clause, vec<Lit>& out_conflict) { - Assert(confl_clause != CRef_Undef); - Assert(decisionLevel() == assumptions.size()); - Assert(level(var(p)) == assumptions.size()); - - out_conflict.clear(); - - Clause& cl = ca[confl_clause]; - for (int i = 0; i < cl.size(); ++i) { - seen[var(cl[i])] = 1; - } - - int end = trail_lim[0]; - for (int i = trail.size() - 1; i >= end; i--) { - Var x = var(trail[i]); - if (seen[x]) { - if (reason(x) == CRef_Undef) { - // we skip p if was a learnt unit - if (x != var(p)) { - if (marker[x] == 2) { - Assert(level(x) > 0); - out_conflict.push(~trail[i]); - } - } - } else { - Clause& clause = ca[reason(x)]; - - for (int j = 1; j < clause.size(); j++) - { - if (level(var(clause[j])) > 0) seen[var(clause[j])] = 1; - } - } - seen[x] = 0; - } - Assert(seen[x] == 0); - } - Assert(out_conflict.size()); -} - -/*_________________________________________________________________________________________________ -| -| analyzeFinal : (p : Lit) -> [void] -| -| Description: -| Specialized analysis procedure to express the final conflict in terms of -assumptions. | Calculates the (possibly empty) set of assumptions that led to -the assignment of 'p', and | stores the result in 'out_conflict'. -|________________________________________________________________________________________________@*/ -void Solver::analyzeFinal(Lit p, vec<Lit>& out_conflict) -{ - out_conflict.clear(); - if (marker[var(p)] == 2) { - out_conflict.push(p); - } - - if (decisionLevel() == 0) - { - return; - } - - seen[var(p)] = 1; - int end = trail_lim[0]; - - for (int i = trail.size()-1; i >= end; i--){ - Var x = var(trail[i]); - if (seen[x]) { - if (reason(x) == CRef_Undef) { - Assert(marker[x] == 2); - Assert(level(x) > 0); - if (~trail[i] != p) - { - out_conflict.push(~trail[i]); - } - } else { - Clause& clause = ca[reason(x)]; - for (int j = 1; j < clause.size(); j++) - { - if (level(var(clause[j])) > 0) - { - seen[var(clause[j])] = 1; - } - } - } - seen[x] = 0; - } - } - - seen[var(p)] = 0; - Assert(out_conflict.size()); -} - - -void Solver::uncheckedEnqueue(Lit p, CRef from) -{ - Assert(value(p) == l_Undef); - assigns[var(p)] = lbool(!sign(p)); - vardata[var(p)] = mkVarData(from, decisionLevel()); - trail.push_(p); - if (decisionLevel() <= assumptions.size() && marker[var(p)] == 1) - { - if (d_notify) - { - Debug("bvminisat::explain") - << OUTPUT_TAG << "propagating " << p << std::endl; - d_notify->notify(p); - } - } -} - -void Solver::popAssumption() { - assumptions.pop(); - conflict.clear(); - cancelUntil(assumptions.size()); -} - -lbool Solver::propagateAssumptions() { - only_bcp = true; - ccmin_mode = 0; - return search(-1); -} - -lbool Solver::assertAssumption(Lit p, bool propagate) { - // TODO need to somehow mark the assumption as unit in the current context? - // it's not always unit though, but this would be useful for debugging - - // Assert(marker[var(p)] == 1); - - if (decisionLevel() > assumptions.size()) { - cancelUntil(assumptions.size()); - } - - conflict.clear(); - - // add to the assumptions - if (c->getLevel() > 0) { - assumptions.push(p); - } else { - ClauseId id; - if (!addClause(p, id)) { - conflict.push(~p); - return l_False; - } - } - - // run the propagation - if (propagate) { - only_bcp = true; - ccmin_mode = 0; - lbool result = search(-1); - return result; - } else { - return l_True; - } -} - -void Solver::addMarkerLiteral(Var var) { - // make sure it wasn't already marked - Assert(marker[var] == 0); - marker[var] = 1; -} - -/*_________________________________________________________________________________________________ -| -| propagate : [void] -> [Clause*] -| -| Description: -| Propagates all enqueued facts. If a conflict arises, the conflicting clause -is returned, | otherwise CRef_Undef. -| -| Post-conditions: -| * the propagation queue is empty, even if there was a conflict. -|________________________________________________________________________________________________@*/ -CRef Solver::propagate() -{ - CRef confl = CRef_Undef; - int num_props = 0; - watches.cleanAll(); - - while (qhead < trail.size()){ - Lit p = trail[qhead++]; // 'p' is enqueued fact to propagate. - vec<Watcher>& ws = watches[p]; - Watcher *i, *j, *end; - num_props++; - - for (i = j = (Watcher*)ws, end = i + ws.size(); i != end;){ - // Try to avoid inspecting the clause: - Lit blocker = i->blocker; - if (value(blocker) == l_True){ - *j++ = *i++; continue; } - - // Make sure the false literal is data[1]: - CRef cr = i->cref; - Clause& clause = ca[cr]; - Lit false_lit = ~p; - if (clause[0] == false_lit) - clause[0] = clause[1], clause[1] = false_lit; - Assert(clause[1] == false_lit); - i++; - - // If 0th watch is true, then clause is already satisfied. - Lit first = clause[0]; - Watcher w = Watcher(cr, first); - if (first != blocker && value(first) == l_True){ - *j++ = w; continue; } - - // Look for new watch: - for (int k = 2; k < clause.size(); k++) - if (value(clause[k]) != l_False) - { - clause[1] = clause[k]; - clause[k] = false_lit; - watches[~clause[1]].push(w); - goto NextClause; - } - - // Did not find watch -- clause is unit under assignment: - *j++ = w; - if (value(first) == l_False){ - confl = cr; - qhead = trail.size(); - // Copy the remaining watches: - while (i < end) - *j++ = *i++; - }else - uncheckedEnqueue(first, cr); - - NextClause:; - } - ws.shrink(i - j); - } - propagations += num_props; - simpDB_props -= num_props; - - return confl; -} - -/*_________________________________________________________________________________________________ -| -| reduceDB : () -> [void] -| -| Description: -| Remove half of the learnt clauses, minus the clauses locked by the current -assignment. Locked | clauses are clauses that are reason to some assignment. -Binary clauses are never removed. -|________________________________________________________________________________________________@*/ -struct reduceDB_lt -{ - ClauseAllocator& ca; - reduceDB_lt(ClauseAllocator& ca_) : ca(ca_) {} - bool operator()(CRef x, CRef y) - { - return ca[x].size() > 2 - && (ca[y].size() == 2 || ca[x].activity() < ca[y].activity()); - } -}; -void Solver::reduceDB() -{ - int i, j; - double extra_lim = cla_inc / learnts.size(); // Remove any clause below this activity - - sort(learnts, reduceDB_lt(ca)); - // Don't delete binary or locked clauses. From the rest, delete clauses from the first half - // and clauses with activity smaller than 'extra_lim': - for (i = j = 0; i < learnts.size(); i++){ - Clause& clause = ca[learnts[i]]; - if (clause.size() > 2 && !locked(clause) - && (i < learnts.size() / 2 || clause.activity() < extra_lim)) - removeClause(learnts[i]); - else - learnts[j++] = learnts[i]; - } - learnts.shrink(i - j); - checkGarbage(); -} - - -void Solver::removeSatisfied(vec<CRef>& cs) -{ - int i, j; - for (i = j = 0; i < cs.size(); i++){ - Clause& clause = ca[cs[i]]; - if (satisfied(clause)) - { - removeClause(cs[i]); - } - else - cs[j++] = cs[i]; - } - cs.shrink(i - j); -} - - -void Solver::rebuildOrderHeap() -{ - vec<Var> vs; - for (Var v = 0; v < nVars(); v++) - if (decision[v] && value(v) == l_Undef) - vs.push(v); - order_heap.build(vs); -} - -/*_________________________________________________________________________________________________ -| -| simplify : [void] -> [bool] -| -| Description: -| Simplify the clause database according to the current top-level assigment. -Currently, the only | thing done here is the removal of satisfied clauses, -but more things can be put here. -|________________________________________________________________________________________________@*/ -bool Solver::simplify() -{ - Assert(decisionLevel() == 0); - - if (!ok || propagate() != CRef_Undef) return ok = false; - - if (nAssigns() == simpDB_assigns || (simpDB_props > 0)) return true; - - d_notify->spendResource(Resource::BvSatSimplifyStep); - - // Remove satisfied clauses: - removeSatisfied(learnts); - if (remove_satisfied) // Can be turned off. - removeSatisfied(clauses); - checkGarbage(); - rebuildOrderHeap(); - - simpDB_assigns = nAssigns(); - simpDB_props = - clauses_literals + learnts_literals; // (shouldn't depend on stats - // really, but it will do for now) - - return true; -} - -/*_________________________________________________________________________________________________ -| -| search : (nof_conflicts : int) (params : const SearchParams&) -> [lbool] -| -| Description: -| Search for a model the specified number of conflicts. -| NOTE! Use negative value for 'nof_conflicts' indicate infinity. -| -| Output: -| 'l_True' if a partial assigment that is consistent with respect to the -clauseset is found. If | all variables are decision variables, this means -that the clause set is satisfiable. 'l_False' | if the clause set is -unsatisfiable. 'l_Undef' if the bound on number of conflicts is reached. -|________________________________________________________________________________________________@*/ -lbool Solver::search(int nof_conflicts, UIP uip) -{ - Assert(ok); - int backtrack_level; - int conflictC = 0; - vec<Lit> learnt_clause; - starts++; - - for (;;) - { - d_notify->safePoint(Resource::BvSatPropagateStep); - CRef confl = propagate(); - if (confl != CRef_Undef) - { - // CONFLICT - conflicts++; - conflictC++; - - if (decisionLevel() == 0) - { - // can this happen for bv? - return l_False; - } - - learnt_clause.clear(); - analyze(confl, learnt_clause, backtrack_level, uip); - - Lit p = learnt_clause[0]; - // bool assumption = marker[var(p)] == 2; - - CRef cr = CRef_Undef; - if (learnt_clause.size() > 1) - { - cr = ca.alloc(learnt_clause, true); - learnts.push(cr); - attachClause(cr); - claBumpActivity(ca[cr]); - } - - if (learnt_clause.size() == 1) - { - // learning a unit clause - } - - // if the uip was an assumption we are unsat - if (level(var(p)) <= assumptions.size()) - { - for (int i = 0; i < learnt_clause.size(); ++i) - { - Assert(level(var(learnt_clause[i])) <= decisionLevel()); - seen[var(learnt_clause[i])] = 1; - } - - analyzeFinal(p, conflict); - Debug("bvminisat::search") - << OUTPUT_TAG << " conflict on assumptions " << std::endl; - return l_False; - } - - if (!cvc5::options::bvEagerExplanations()) - { - // check if uip leads to a conflict - if (backtrack_level < assumptions.size()) - { - cancelUntil(assumptions.size()); - uncheckedEnqueue(p, cr); - - CRef new_confl = propagate(); - if (new_confl != CRef_Undef) - { - // we have a conflict we now need to explain it - analyzeFinal2(p, new_confl, conflict); - return l_False; - } - } - } - - cancelUntil(backtrack_level); - uncheckedEnqueue(p, cr); - - varDecayActivity(); - claDecayActivity(); - - if (--learntsize_adjust_cnt == 0) - { - learntsize_adjust_confl *= learntsize_adjust_inc; - learntsize_adjust_cnt = (int)learntsize_adjust_confl; - max_learnts *= learntsize_inc; - - if (verbosity >= 1) - printf("| %9d | %7d %8d %8d | %8d %8d %6.0f | %6.3f %% |\n", - (int)conflicts, - (int)dec_vars - - (trail_lim.size() == 0 ? trail.size() : trail_lim[0]), - nClauses(), - (int)clauses_literals, - (int)max_learnts, - nLearnts(), - (double)learnts_literals / nLearnts(), - progressEstimate() * 100); - } - } - else - { - // NO CONFLICT - bool isWithinBudget; - try - { - isWithinBudget = - withinBudget(Resource::BvSatConflictsStep); - } - catch (const cvc5::theory::Interrupted& e) - { - // do some clean-up and rethrow - cancelUntil(assumptions.size()); - throw e; - } - - if ((decisionLevel() > assumptions.size() && nof_conflicts >= 0 - && conflictC >= nof_conflicts) - || !isWithinBudget) - { - // Reached bound on number of conflicts: - Debug("bvminisat::search") << OUTPUT_TAG << " restarting " << std::endl; - progress_estimate = progressEstimate(); - cancelUntil(assumptions.size()); - return l_Undef; - } - - // Simplify the set of problem clauses: - if (decisionLevel() == 0 && !simplify()) - { - Debug("bvminisat::search") - << OUTPUT_TAG << " base level conflict, we're unsat" << std::endl; - return l_False; - } - - // We can't erase clauses if there is unprocessed assumptions, there might - // be some propagationg we need to redu - if (decisionLevel() >= assumptions.size() - && learnts.size() - nAssigns() >= max_learnts) - { - // Reduce the set of learnt clauses: - Debug("bvminisat::search") - << OUTPUT_TAG << " cleaning up database" << std::endl; - reduceDB(); - } - - Lit next = lit_Undef; - while (decisionLevel() < assumptions.size()) - { - // Perform user provided assumption: - Lit p = assumptions[decisionLevel()]; - if (value(p) == l_True) - { - // Dummy decision level: - newDecisionLevel(); - } - else if (value(p) == l_False) - { - marker[var(p)] = 2; - - analyzeFinal(~p, conflict); - Debug("bvminisat::search") - << OUTPUT_TAG << " assumption false, we're unsat" << std::endl; - return l_False; - } - else - { - marker[var(p)] = 2; - next = p; - break; - } - } - - if (next == lit_Undef) - { - if (only_bcp) - { - Debug("bvminisat::search") - << OUTPUT_TAG << " only bcp, skipping rest of the problem" - << std::endl; - return l_True; - } - - // New variable decision: - decisions++; - next = pickBranchLit(); - - if (next == lit_Undef) - { - Debug("bvminisat::search") - << OUTPUT_TAG << " satisfiable" << std::endl; - // Model found: - return l_True; - } - } - - // Increase decision level and enqueue 'next' - newDecisionLevel(); - uncheckedEnqueue(next); - } - } -} - - -double Solver::progressEstimate() const -{ - double progress = 0; - double F = 1.0 / nVars(); - - for (int i = 0; i <= decisionLevel(); i++){ - int beg = i == 0 ? 0 : trail_lim[i - 1]; - int end = i == decisionLevel() ? trail.size() : trail_lim[i]; - progress += pow(F, i) * (end - beg); - } - - return progress / nVars(); -} - -/* - Finite subsequences of the Luby-sequence: - - 0: 1 - 1: 1 1 2 - 2: 1 1 2 1 1 2 4 - 3: 1 1 2 1 1 2 4 1 1 2 1 1 2 4 8 - ... - - - */ - -static double luby(double y, int x){ - - // Find the finite subsequence that contains index 'x', and the - // size of that subsequence: - int size, seq; - for (size = 1, seq = 0; size < x+1; seq++, size = 2*size+1); - - while (size-1 != x){ - size = (size-1)>>1; - seq--; - x = x % size; - } - - return pow(y, seq); -} - -// NOTE: assumptions passed in member-variable 'assumptions'. -lbool Solver::solve_() -{ - Debug("bvminisat") <<"BVMinisat::Solving learned clauses " << learnts.size() <<"\n"; - Debug("bvminisat") <<"BVMinisat::Solving assumptions " << assumptions.size() <<"\n"; - - model.clear(); - conflict.clear(); - - ccmin_mode = 0; - - if (!ok) return l_False; - - solves++; - - max_learnts = nClauses() * learntsize_factor; - learntsize_adjust_confl = learntsize_adjust_start_confl; - learntsize_adjust_cnt = (int)learntsize_adjust_confl; - lbool status = l_Undef; - - if (verbosity >= 1){ - printf("============================[ Search Statistics ]==============================\n"); - printf("| Conflicts | ORIGINAL | LEARNT | Progress |\n"); - printf("| | Vars Clauses Literals | Limit Clauses Lit/Cl | |\n"); - printf("===============================================================================\n"); - } - - // Search: - int curr_restarts = 0; - while (status == l_Undef){ - double rest_base = luby_restart ? luby(restart_inc, curr_restarts) : pow(restart_inc, curr_restarts); - status = search(rest_base * restart_first); - if (!withinBudget(Resource::BvSatConflictsStep)) break; - curr_restarts++; - } - - if (verbosity >= 1) - printf("===============================================================================\n"); - - if (status == l_True){ - // Extend & copy model: - // model.growTo(nVars()); - // for (int i = 0; i < nVars(); i++) model[i] = value(i); - }else if (status == l_False && conflict.size() == 0) - ok = false; - - return status; -} - -//================================================================================================= -// Bitvector propagations -// - -void Solver::explain(Lit p, std::vector<Lit>& explanation) { - Debug("bvminisat::explain") << OUTPUT_TAG << "starting explain of " << p << std::endl; - - // top level fact, no explanation necessary - if (level(var(p)) == 0) { - return; - } - - seen[var(p)] = 1; - - // if we are called at decisionLevel = 0 trail_lim is empty - int bottom = trail_lim[0]; - for (int i = trail.size()-1; i >= bottom; i--){ - Var x = var(trail[i]); - if (seen[x]) { - if (reason(x) == CRef_Undef) { - if (marker[x] == 2) { - Assert(level(x) > 0); - explanation.push_back(trail[i]); - } else { - Assert(level(x) == 0); - } - } else { - Clause& clause = ca[reason(x)]; - for (int j = 1; j < clause.size(); j++) - { - if (level(var(clause[j])) > 0) - { - seen[var(clause[j])] = 1; - } - } - } - seen[x] = 0; - } - } - seen[var(p)] = 0; -} - -//================================================================================================= -// Writing CNF to DIMACS: -// -// FIXME: this needs to be rewritten completely. - -static Var mapVar(Var x, vec<Var>& map, Var& max) -{ - if (map.size() <= x || map[x] == -1){ - map.growTo(x+1, -1); - map[x] = max++; - } - return map[x]; -} - -void Solver::toDimacs(FILE* f, Clause& clause, vec<Var>& map, Var& max) -{ - if (satisfied(clause)) return; - - for (int i = 0; i < clause.size(); i++) - if (value(clause[i]) != l_False) - fprintf(f, - "%s%d ", - sign(clause[i]) ? "-" : "", - mapVar(var(clause[i]), map, max) + 1); - fprintf(f, "0\n"); -} - - -void Solver::toDimacs(const char *file, const vec<Lit>& assumps) -{ - FILE* f = fopen(file, "wr"); - if (f == NULL) - fprintf(stderr, "could not open file %s\n", file), exit(1); - toDimacs(f, assumps); - fclose(f); -} - - -void Solver::toDimacs(FILE* f, const vec<Lit>& assumps) -{ - // Handle case when solver is in contradictory state: - if (!ok){ - fprintf(f, "p cnf 1 2\n1 0\n-1 0\n"); - return; } - - vec<Var> map; Var max = 0; - - // Cannot use removeClauses here because it is not safe - // to deallocate them at this point. Could be improved. - int cnt = 0; - for (int i = 0; i < clauses.size(); i++) - if (!satisfied(ca[clauses[i]])) - cnt++; - - for (int i = 0; i < clauses.size(); i++) - if (!satisfied(ca[clauses[i]])){ - Clause& clause = ca[clauses[i]]; - for (int j = 0; j < clause.size(); j++) - if (value(clause[j]) != l_False) mapVar(var(clause[j]), map, max); - } - - // Assumptions are added as unit clauses: - cnt += assumps.size(); - - fprintf(f, "p cnf %d %d\n", max, cnt); - - for (int i = 0; i < assumps.size(); i++){ - Assert(value(assumps[i]) != l_False); - fprintf(f, - "%s%d 0\n", - sign(assumps[i]) ? "-" : "", - mapVar(var(assumps[i]), map, max) + 1); - } - - for (int i = 0; i < clauses.size(); i++) - toDimacs(f, ca[clauses[i]], map, max); - - if (verbosity > 0) - printf("Wrote %d clauses with %d variables.\n", cnt, max); -} - - -//================================================================================================= -// Garbage Collection methods: - -void Solver::relocAll(ClauseAllocator& to) -{ - // All watchers: - // - // for (int i = 0; i < watches.size(); i++) - watches.cleanAll(); - for (int v = 0; v < nVars(); v++) - for (int s = 0; s < 2; s++){ - Lit p = mkLit(v, s); - // printf(" >>> RELOCING: %s%d\n", sign(p)?"-":"", var(p)+1); - vec<Watcher>& ws = watches[p]; - for (int j = 0; j < ws.size(); j++) ca.reloc(ws[j].cref, to); - } - - // All reasons: - // - for (int i = 0; i < trail.size(); i++){ - Var v = var(trail[i]); - - if (reason(v) != CRef_Undef && (ca[reason(v)].reloced() || locked(ca[reason(v)]))) - ca.reloc(vardata[v].reason, to); - } - - // All learnt: - // - for (int i = 0; i < learnts.size(); i++) ca.reloc(learnts[i], to); - - // All original: - // - for (int i = 0; i < clauses.size(); i++) ca.reloc(clauses[i], to); -} - - -void Solver::garbageCollect() -{ - // Initialize the next region to a size corresponding to the estimated utilization degree. This - // is not precise but should avoid some unnecessary reallocations for the new region: - ClauseAllocator to(ca.size() - ca.wasted()); - Debug("bvminisat") << " BVMinisat::Garbage collection \n"; - relocAll(to); - if (verbosity >= 2) - printf( - "| Garbage collection: %12d bytes => %12d bytes |\n", - ca.size() * ClauseAllocator::Unit_Size, - to.size() * ClauseAllocator::Unit_Size); - to.moveTo(ca); -} - -void ClauseAllocator::reloc(CRef& cr, ClauseAllocator& to) -{ - Clause& c = operator[](cr); - if (c.reloced()) { cr = c.relocation(); return; } - - cr = to.alloc(c, c.learnt()); - c.relocate(cr); - - // Copy extra data-fields: - // (This could be cleaned-up. Generalize Clause-constructor to be applicable - // here instead?) - to[cr].mark(c.mark()); - if (to[cr].learnt()) to[cr].activity() = c.activity(); - else if (to[cr].has_extra()) to[cr].calcAbstraction(); -} - -void Solver::setNotify(Notify* toNotify) { d_notify = toNotify; } -bool Solver::withinBudget(Resource r) const -{ - AlwaysAssert(d_notify); - d_notify->safePoint(r); - - return !asynch_interrupt && - (conflict_budget < 0 || conflicts < conflict_budget) && - (propagation_budget < 0 || - propagations < propagation_budget); -} - -} // namespace BVMinisat -} // namespace cvc5 diff --git a/src/prop/bvminisat/core/Solver.h b/src/prop/bvminisat/core/Solver.h deleted file mode 100644 index 7c08c3bcf..000000000 --- a/src/prop/bvminisat/core/Solver.h +++ /dev/null @@ -1,539 +0,0 @@ -/****************************************************************************************[Solver.h] -Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson -Copyright (c) 2007-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#ifndef BVMinisat_Solver_h -#define BVMinisat_Solver_h - -#include <vector> - -#include "base/check.h" -#include "context/context.h" -#include "proof/clause_id.h" -#include "prop/bvminisat/core/SolverTypes.h" -#include "prop/bvminisat/mtl/Alg.h" -#include "prop/bvminisat/mtl/Heap.h" -#include "prop/bvminisat/mtl/Vec.h" -#include "prop/bvminisat/utils/Options.h" -#include "util/resource_manager.h" - -namespace cvc5 { - -namespace BVMinisat { -class Solver; -} - -namespace BVMinisat { - -/** Interface for minisat callbacks */ -class Notify { - -public: - - virtual ~Notify() {} - - /** - * If the notify returns false, the solver will break out of whatever it's currently doing - * with an "unknown" answer. - */ - virtual bool notify(Lit lit) = 0; - - /** - * Notify about a new learnt clause with marked literals only. - */ - virtual void notify(vec<Lit>& learnt) = 0; - - virtual void spendResource(Resource r) = 0; - virtual void safePoint(Resource r) = 0; -}; - -//================================================================================================= -// Solver -- the main class: -class Solver { -public: - typedef Var TVar; - typedef Lit TLit; - typedef Clause TClause; - typedef CRef TCRef; - typedef vec<Lit> TLitVec; - - static CRef TCRef_Undef; - static CRef TCRef_Lazy; -private: - /** To notify */ - Notify* d_notify; - - /** cvc5 context */ - cvc5::context::Context* c; - - /** True constant */ - Var varTrue; - - /** False constant */ - Var varFalse; - -public: - - // Constructor/Destructor: - // - Solver(cvc5::context::Context* c); - virtual ~Solver(); - - void setNotify(Notify* toNotify); - - // Problem specification: - // - Var newVar(bool polarity = true, - bool dvar = true); // Add a new variable with parameters specifying - // variable mode. - Var trueVar() const { return varTrue; } - Var falseVar() const { return varFalse; } - - bool addClause(const vec<Lit>& ps, - ClauseId& id); // Add a clause to the solver. - bool addEmptyClause(); // Add the empty clause, making the solver - // contradictory. - bool addClause(Lit p, ClauseId& id); // Add a unit clause to the solver. - bool addClause(Lit p, - Lit q, - ClauseId& id); // Add a binary clause to the solver. - bool addClause(Lit p, - Lit q, - Lit r, - ClauseId& id); // Add a ternary clause to the solver. - bool addClause_( - vec<Lit>& ps, - ClauseId& id); // Add a clause to the solver without making superflous - // internal copy. Will change the passed vector 'ps'. - - // Solving: - // - bool simplify(); // Removes already satisfied clauses. - lbool solve(const vec<Lit>& assumps); // Search for a model that respects a - // given set of assumptions. - lbool solveLimited( - const vec<Lit>& assumps); // Search for a model that respects a given set - // of assumptions (With resource constraints). - lbool solve(); // Search without assumptions. - lbool solve(Lit p); // Search for a model that respects a single assumption. - lbool solve(Lit p, - Lit q); // Search for a model that respects two assumptions. - lbool solve(Lit p, - Lit q, - Lit r); // Search for a model that respects three assumptions. - bool okay() const; // FALSE means solver is in a conflicting state - lbool assertAssumption( - Lit p, - bool propagate); // Assert a new assumption, start BCP if propagate = true - lbool propagateAssumptions(); // Do BCP over asserted assumptions - void popAssumption(); // Pop an assumption - - void toDimacs(FILE* f, - const vec<Lit>& assumps); // Write CNF to file in DIMACS-format. - void toDimacs(const char* file, const vec<Lit>& assumps); - void toDimacs(FILE* f, Clause& c, vec<Var>& map, Var& max); - - // Convenience versions of 'toDimacs()': - void toDimacs(const char* file); - void toDimacs(const char* file, Lit p); - void toDimacs(const char* file, Lit p, Lit q); - void toDimacs(const char* file, Lit p, Lit q, Lit r); - - // Variable mode: - // - void setPolarity( - Var v, bool b); // Declare which polarity the decision heuristic should - // use for a variable. Requires mode 'polarity_user'. - void setDecisionVar(Var v, - bool b); // Declare if a variable should be eligible for - // selection in the decision heuristic. - - // Read state: - // - lbool value(Var x) const; // The current value of a variable. - lbool value(Lit p) const; // The current value of a literal. - lbool modelValue( - Var x) const; // The value of a variable in the last model. The last call - // to solve must have been satisfiable. - lbool modelValue( - Lit p) const; // The value of a literal in the last model. The last call - // to solve must have been satisfiable. - int nAssigns() const; // The current number of assigned literals. - int nClauses() const; // The current number of original clauses. - int nLearnts() const; // The current number of learnt clauses. - int nVars() const; // The current number of variables. - int nFreeVars() const; - - // Resource contraints: - // - void setConfBudget(int64_t x); - void setPropBudget(int64_t x); - void budgetOff(); - void interrupt(); // Trigger a (potentially asynchronous) interruption of the - // solver. - void clearInterrupt(); // Clear interrupt indicator flag. - - // Memory managment: - // - virtual void garbageCollect(); - void checkGarbage(double gf); - void checkGarbage(); - - // Extra results: (read-only member variable) - // - vec<lbool> model; // If problem is satisfiable, this vector contains the model - // (if any). - vec<Lit> conflict; // If problem is unsatisfiable (possibly under - // assumptions), this vector represent the final conflict - // clause expressed in the assumptions. - - // Mode of operation: - // - int verbosity; - double var_decay; - double clause_decay; - double random_var_freq; - double random_seed; - bool luby_restart; - int ccmin_mode; // Controls conflict clause minimization (0=none, 1=basic, - // 2=deep). - int phase_saving; // Controls the level of phase saving (0=none, 1=limited, - // 2=full). - bool rnd_pol; // Use random polarities for branching heuristics. - bool - rnd_init_act; // Initialize variable activities with a small random value. - double garbage_frac; // The fraction of wasted memory allowed before a garbage - // collection is triggered. - - int restart_first; // The initial restart limit. (default 100) - double restart_inc; // The factor with which the restart limit is multiplied - // in each restart. (default 1.5) - double - learntsize_factor; // The intitial limit for learnt clauses is a factor of - // the original clauses. (default 1 / 3) - double learntsize_inc; // The limit for learnt clauses is multiplied with this - // factor each restart. (default 1.1) - - int learntsize_adjust_start_confl; - double learntsize_adjust_inc; - - // Statistics: (read-only member variable) - // - int64_t solves, starts, decisions, rnd_decisions, propagations, conflicts; - int64_t dec_vars, clauses_literals, learnts_literals, max_literals, - tot_literals; - - // Bitvector Propagations - // - - void addMarkerLiteral(Var var); - - bool need_to_propagate; // true if we added new clauses, set to true in - // propagation - bool only_bcp; // solving mode in which only boolean constraint propagation is - // done - void setOnlyBCP(bool val) { only_bcp = val; } - void explain(Lit l, std::vector<Lit>& explanation); - -protected: - // has a clause been added - bool clause_added; - - // Helper structures: - // - struct VarData - { - CRef reason; - int level; }; - static inline VarData mkVarData(CRef cr, int l){ VarData d = {cr, l}; return d; } - - struct Watcher { - CRef cref; - Lit blocker; - Watcher(CRef cr, Lit p) : cref(cr), blocker(p) {} - bool operator==(const Watcher& w) const { return cref == w.cref; } - bool operator!=(const Watcher& w) const { return cref != w.cref; } - }; - - struct WatcherDeleted - { - const ClauseAllocator& ca; - WatcherDeleted(const ClauseAllocator& _ca) : ca(_ca) {} - bool operator()(const Watcher& w) const { return ca[w.cref].mark() == 1; } - }; - - struct VarOrderLt { - const vec<double>& activity; - bool operator () (Var x, Var y) const { return activity[x] > activity[y]; } - VarOrderLt(const vec<double>& act) : activity(act) { } - }; - - // Solver state: - // - bool ok; // If FALSE, the constraints are already unsatisfiable. No part of the solver state may be used! - vec<CRef> clauses; // List of problem clauses. - vec<CRef> learnts; // List of learnt clauses. - double cla_inc; // Amount to bump next clause with. - vec<double> activity; // A heuristic measurement of the activity of a variable. - double var_inc; // Amount to bump next variable with. - OccLists<Lit, vec<Watcher>, WatcherDeleted> - watches; // 'watches[lit]' is a list of constraints watching 'lit' (will go there if literal becomes true). - vec<lbool> assigns; // The current assignments. - vec<char> polarity; // The preferred polarity of each variable. - vec<char> marker; // Is the variable a marker literal - vec<char> decision; // Declares if a variable is eligible for selection in the decision heuristic. - vec<Lit> trail; // Assignment stack; stores all assigments made in the order they were made. - vec<int> trail_lim; // Separator indices for different decision levels in 'trail'. - vec<VarData> vardata; // Stores reason and level for each variable. - int qhead; // Head of queue (as index into the trail -- no more explicit propagation queue in MiniSat). - int simpDB_assigns; // Number of top-level assignments since last execution of 'simplify()'. - int64_t simpDB_props; // Remaining number of propagations that must be made before next execution of 'simplify()'. - vec<Lit> assumptions; // Current set of assumptions provided to solve by the user. - Heap<VarOrderLt> order_heap; // A priority queue of variables ordered with respect to the variable activity. - double progress_estimate;// Set by 'search()'. - bool remove_satisfied; // Indicates whether possibly inefficient linear scan for satisfied clauses should be performed in 'simplify'. - - ClauseAllocator ca; - - // Temporaries (to reduce allocation overhead). Each variable is prefixed by the method in which it is - // used, exept 'seen' wich is used in several places. - // - vec<char> seen; - vec<Lit> analyze_stack; - vec<Lit> analyze_toclear; - vec<Lit> add_tmp; - - double max_learnts; - double learntsize_adjust_confl; - int learntsize_adjust_cnt; - - // Resource contraints: - // - int64_t conflict_budget; // -1 means no budget. - int64_t propagation_budget; // -1 means no budget. - bool asynch_interrupt; - - // Main internal methods: - // - void insertVarOrder (Var x); // Insert a variable in the decision order priority queue. - Lit pickBranchLit (); // Return the next decision variable. - void newDecisionLevel (); // Begins a new decision level. - void uncheckedEnqueue (Lit p, CRef from = CRef_Undef); // Enqueue a literal. Assumes value of literal is undefined. - bool enqueue (Lit p, CRef from = CRef_Undef); // Test if fact 'p' contradicts current state, enqueue otherwise. - CRef propagate (); // Perform unit propagation. Returns possibly conflicting clause. - void cancelUntil (int level); // Backtrack until a certain level. - - enum UIP { - UIP_FIRST, - UIP_LAST - }; - - void analyze (CRef confl, vec<Lit>& out_learnt, int& out_btlevel, UIP uip = UIP_FIRST); // (bt = backtrack) - void analyzeFinal (Lit p, vec<Lit>& out_conflict); // COULD THIS BE IMPLEMENTED BY THE ORDINARIY "analyze" BY SOME REASONABLE GENERALIZATION? - void analyzeFinal2(Lit p, CRef confl_clause, vec<Lit>& out_conflict); - bool litRedundant (Lit p, uint32_t abstract_levels); // (helper method for 'analyze()') - lbool search (int nof_conflicts, UIP uip = UIP_FIRST); // Search for a given number of conflicts. - lbool solve_ (); // Main solve method (assumptions given in 'assumptions'). - void reduceDB (); // Reduce the set of learnt clauses. - void removeSatisfied (vec<CRef>& cs); // Shrink 'cs' to contain only non-satisfied clauses. - void rebuildOrderHeap (); - - // Maintaining Variable/Clause activity: - // - void varDecayActivity (); // Decay all variables with the specified factor. Implemented by increasing the 'bump' value instead. - void varBumpActivity (Var v, double inc); // Increase a variable with the current 'bump' value. - void varBumpActivity (Var v); // Increase a variable with the current 'bump' value. - void claDecayActivity (); // Decay all clauses with the specified factor. Implemented by increasing the 'bump' value instead. - void claBumpActivity (Clause& c); // Increase a clause with the current 'bump' value. - - // Operations on clauses: - // - void attachClause (CRef cr); // Attach a clause to watcher lists. - void detachClause (CRef cr, bool strict = false); // Detach a clause to watcher lists. - void removeClause (CRef cr); // Detach and free a clause. - bool locked (const Clause& c) const; // Returns TRUE if a clause is a reason for some implication in the current state. - bool satisfied (const Clause& c) const; // Returns TRUE if a clause is satisfied in the current state. - - void relocAll (ClauseAllocator& to); - - // Misc: - // - int decisionLevel () const; // Gives the current decisionlevel. - uint32_t abstractLevel (Var x) const; // Used to represent an abstraction of sets of decision levels. - CRef reason (Var x) const; - int level (Var x) const; - double progressEstimate () const; // DELETE THIS ?? IT'S NOT VERY USEFUL ... - bool withinBudget(Resource r) const; - - // Static helpers: - // - - // Returns a random float 0 <= x < 1. Seed must never be 0. - static inline double drand(double& seed) { - seed *= 1389796; - int q = (int)(seed / 2147483647); - seed -= (double)q * 2147483647; - return seed / 2147483647; } - - // Returns a random integer 0 <= x < size. Seed must never be 0. - static inline int irand(double& seed, int size) { - return (int)(drand(seed) * size); } - - // Less than for literals in an added clause when proofs are on. - struct assign_lt { - Solver& d_solver; - assign_lt(Solver& solver) : d_solver(solver) {} - bool operator () (Lit x, Lit y) { - lbool x_value = d_solver.value(x); - lbool y_value = d_solver.value(y); - // Two unassigned literals are sorted arbitrarily - if (x_value == l_Undef && y_value == l_Undef) { - return x < y; - } - // Unassigned literals are put to front - if (x_value == l_Undef) return true; - if (y_value == l_Undef) return false; - // Literals of the same value are sorted by decreasing levels - if (x_value == y_value) { - return d_solver.level(var(x)) > d_solver.level(var(y)); - } else { - // True literals go up front - if (x_value == l_True) { - return true; - } else { - return false; - } - } - } - }; - -}; - - -//================================================================================================= -// Implementation of inline methods: - -inline CRef Solver::reason(Var x) const -{ - Assert(x < vardata.size()); - return vardata[x].reason; -} -inline int Solver::level(Var x) const -{ - Assert(x < vardata.size()); - return vardata[x].level; -} - -inline void Solver::insertVarOrder(Var x) { - if (!order_heap.inHeap(x) && decision[x]) order_heap.insert(x); } - -inline void Solver::varDecayActivity() { var_inc *= (1 / var_decay); } -inline void Solver::varBumpActivity(Var v) { varBumpActivity(v, var_inc); } -inline void Solver::varBumpActivity(Var v, double inc) { - if ( (activity[v] += inc) > 1e100 ) { - // Rescale: - for (int i = 0; i < nVars(); i++) - activity[i] *= 1e-100; - var_inc *= 1e-100; } - - // Update order_heap with respect to new activity: - if (order_heap.inHeap(v)) - order_heap.decrease(v); } - -inline void Solver::claDecayActivity() { cla_inc *= (1 / clause_decay); } -inline void Solver::claBumpActivity(Clause& clause) -{ - if ((clause.activity() += cla_inc) > 1e20) - { - // Rescale: - for (int i = 0; i < learnts.size(); i++) ca[learnts[i]].activity() *= 1e-20; - cla_inc *= 1e-20; - } -} - -inline void Solver::checkGarbage(void){ return checkGarbage(garbage_frac); } -inline void Solver::checkGarbage(double gf){ - if (ca.wasted() > ca.size() * gf) - garbageCollect(); } - -// NOTE: enqueue does not set the ok flag! (only public methods do) -inline bool Solver::enqueue (Lit p, CRef from) { return value(p) != l_Undef ? value(p) != l_False : (uncheckedEnqueue(p, from), true); } -inline bool Solver::addClause (const vec<Lit>& ps, ClauseId& id) { ps.copyTo(add_tmp); return addClause_(add_tmp, id); } -inline bool Solver::addEmptyClause () { add_tmp.clear(); ClauseId tmp; return addClause_(add_tmp, tmp); } -inline bool Solver::addClause (Lit p, ClauseId& id) { add_tmp.clear(); add_tmp.push(p); return addClause_(add_tmp, id); } -inline bool Solver::addClause (Lit p, Lit q, ClauseId& id) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); return addClause_(add_tmp, id); } -inline bool Solver::addClause (Lit p, Lit q, Lit r, ClauseId& id) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); return addClause_(add_tmp, id); } -inline bool Solver::locked(const Clause& clause) const -{ - return value(clause[0]) == l_True && reason(var(clause[0])) != CRef_Undef - && ca.lea(reason(var(clause[0]))) == &clause; -} -inline void Solver::newDecisionLevel() { trail_lim.push(trail.size()); } - -inline int Solver::decisionLevel () const { return trail_lim.size(); } -inline uint32_t Solver::abstractLevel (Var x) const { return 1 << (level(x) & 31); } -inline lbool Solver::value (Var x) const { return assigns[x]; } -inline lbool Solver::value (Lit p) const { return assigns[var(p)] ^ sign(p); } -inline lbool Solver::modelValue (Var x) const { return model[x]; } -inline lbool Solver::modelValue (Lit p) const { return model[var(p)] ^ sign(p); } -inline int Solver::nAssigns () const { return trail.size(); } -inline int Solver::nClauses () const { return clauses.size(); } -inline int Solver::nLearnts () const { return learnts.size(); } -inline int Solver::nVars () const { return vardata.size(); } -inline int Solver::nFreeVars () const { return (int)dec_vars - (trail_lim.size() == 0 ? trail.size() : trail_lim[0]); } -inline void Solver::setPolarity (Var v, bool b) { polarity[v] = b; } -inline void Solver::setDecisionVar(Var v, bool b) -{ - if (b && !decision[v]) - dec_vars++; - else if (!b && decision[v]) - dec_vars--; - - decision[v] = b; - insertVarOrder(v); -} -inline void Solver::setConfBudget(int64_t x){ conflict_budget = conflicts + x; } -inline void Solver::setPropBudget(int64_t x){ propagation_budget = propagations + x; } -inline void Solver::interrupt(){ asynch_interrupt = true; } -inline void Solver::clearInterrupt(){ asynch_interrupt = false; } -inline void Solver::budgetOff(){ conflict_budget = propagation_budget = -1; } - -inline lbool Solver::solve () { budgetOff(); return solve_(); } -inline lbool Solver::solve (Lit p) { budgetOff(); assumptions.push(p); return solve_(); } -inline lbool Solver::solve (Lit p, Lit q) { budgetOff(); assumptions.push(p); assumptions.push(q); return solve_(); } -inline lbool Solver::solve (Lit p, Lit q, Lit r) { budgetOff(); assumptions.push(p); assumptions.push(q); assumptions.push(r); return solve_(); } -inline lbool Solver::solve (const vec<Lit>& assumps){ budgetOff(); assumps.copyTo(assumptions); return solve_(); } -inline lbool Solver::solveLimited (const vec<Lit>& assumps){ assumps.copyTo(assumptions); return solve_(); } -inline bool Solver::okay () const { return ok; } - -inline void Solver::toDimacs (const char* file){ vec<Lit> as; toDimacs(file, as); } -inline void Solver::toDimacs (const char* file, Lit p){ vec<Lit> as; as.push(p); toDimacs(file, as); } -inline void Solver::toDimacs (const char* file, Lit p, Lit q){ vec<Lit> as; as.push(p); as.push(q); toDimacs(file, as); } -inline void Solver::toDimacs (const char* file, Lit p, Lit q, Lit r){ vec<Lit> as; as.push(p); as.push(q); as.push(r); toDimacs(file, as); } - - -//================================================================================================= -// Debug etc: - - -//================================================================================================= -} // namespace BVMinisat -} // namespace cvc5 - -#endif diff --git a/src/prop/bvminisat/core/SolverTypes.h b/src/prop/bvminisat/core/SolverTypes.h deleted file mode 100644 index fd0e86116..000000000 --- a/src/prop/bvminisat/core/SolverTypes.h +++ /dev/null @@ -1,435 +0,0 @@ -/***********************************************************************************[SolverTypes.h] -Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson -Copyright (c) 2007-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#ifndef BVMinisat_SolverTypes_h -#define BVMinisat_SolverTypes_h - -#include "base/check.h" -#include "prop/bvminisat/mtl/Alg.h" -#include "prop/bvminisat/mtl/Alloc.h" -#include "prop/bvminisat/mtl/IntTypes.h" -#include "prop/bvminisat/mtl/Map.h" -#include "prop/bvminisat/mtl/Vec.h" - -namespace cvc5 { -namespace BVMinisat { -class Solver; -} -template <class Solver> -class TSatProof; -} // namespace cvc5 - -namespace cvc5 { - -namespace BVMinisat { - -//================================================================================================= -// Variables, literals, lifted booleans, clauses: - - -// NOTE! Variables are just integers. No abstraction here. They should be chosen from 0..N, -// so that they can be used as array indices. - -typedef int Var; -#define var_Undef (-1) - - -struct Lit { - int x; - - // Use this as a constructor: - friend Lit mkLit(Var var, bool sign); - - bool operator == (Lit p) const { return x == p.x; } - bool operator != (Lit p) const { return x != p.x; } - bool operator < (Lit p) const { return x < p.x; } // '<' makes p, ~p adjacent in the ordering. -}; - -inline Lit mkLit (Var var, bool sign = false) { Lit p; p.x = var + var + (int)sign; return p; } -inline Lit operator ~(Lit p) { Lit q; q.x = p.x ^ 1; return q; } -inline Lit operator ^(Lit p, bool b) { Lit q; q.x = p.x ^ (unsigned int)b; return q; } -inline bool sign (Lit p) { return p.x & 1; } -inline int var (Lit p) { return p.x >> 1; } - -// Mapping Literals to and from compact integers suitable for array indexing: -inline int toInt (Var v) { return v; } -inline int toInt (Lit p) { return p.x; } -inline Lit toLit (int i) { Lit p; p.x = i; return p; } - -struct LitHashFunction { - size_t operator () (const Lit& l) const { - return toInt(l); - } -}; - -//const Lit lit_Undef = mkLit(var_Undef, false); // }- Useful special constants. -//const Lit lit_Error = mkLit(var_Undef, true ); // } - -const Lit lit_Undef = { -2 }; // }- Useful special constants. -const Lit lit_Error = { -1 }; // } - -//================================================================================================= -// Lifted booleans: -// -// NOTE: this implementation is optimized for the case when comparisons between -// values are mostly -// between one variable and one constant. Some care had to be taken to -// make sure that gcc does enough constant propagation to produce sensible -// code, and this appears to be somewhat fragile unfortunately. - -#ifndef l_True -#define l_True (lbool((uint8_t)0)) // gcc does not do constant propagation if these are real constants. -#endif - -#ifndef l_False -#define l_False (lbool((uint8_t)1)) -#endif - -#ifndef l_Undef -#define l_Undef (lbool((uint8_t)2)) -#endif - -class lbool { - uint8_t value; - -public: - explicit lbool(uint8_t v) : value(v) { } - - lbool() : value(0) { } - explicit lbool(bool x) : value(!x) { } - - bool operator == (lbool b) const { return ((b.value&2) & (value&2)) | (!(b.value&2)&(value == b.value)); } - bool operator != (lbool b) const { return !(*this == b); } - lbool operator ^ (bool b) const { return lbool((uint8_t)(value^(uint8_t)b)); } - - lbool operator&&(lbool b) const - { - uint8_t sel = (this->value << 1) | (b.value << 3); - uint8_t v = (0xF7F755F4 >> sel) & 3; - return lbool(v); - } - - lbool operator || (lbool b) const { - uint8_t sel = (this->value << 1) | (b.value << 3); - uint8_t v = (0xFCFCF400 >> sel) & 3; - return lbool(v); } - - friend int toInt (lbool l); - friend lbool toLbool(int v); -}; -inline int toInt (lbool l) { return l.value; } -inline lbool toLbool(int v) { return lbool((uint8_t)v); } - -//================================================================================================= -// Clause -- a simple class for representing a clause: - -class Clause; -typedef RegionAllocator<uint32_t>::Ref CRef; - -class Clause { - struct { - unsigned mark : 2; - unsigned learnt : 1; - unsigned has_extra : 1; - unsigned reloced : 1; - unsigned size : 27; } header; - union { Lit lit; float act; uint32_t abs; CRef rel; } data[0]; - - friend class ClauseAllocator; - - // NOTE: This constructor cannot be used directly (doesn't allocate enough memory). - template<class V> - Clause(const V& ps, bool use_extra, bool learnt) { - header.mark = 0; - header.learnt = learnt; - header.has_extra = use_extra; - header.reloced = 0; - header.size = ps.size(); - - for (int i = 0; i < ps.size(); i++) data[i].lit = ps[i]; - - if (header.has_extra){ - if (header.learnt) - data[header.size].act = 0; - else - calcAbstraction(); - } - } - -public: - void calcAbstraction() { - Assert(header.has_extra); - uint32_t abstraction = 0; - for (int i = 0; i < size(); i++) - abstraction |= 1 << (var(data[i].lit) & 31); - data[header.size].abs = abstraction; - } - - int size () const { return header.size; } - void shrink(int i) - { - Assert(i <= size()); - if (header.has_extra) data[header.size - i] = data[header.size]; - header.size -= i; - } - void pop () { shrink(1); } - bool learnt () const { return header.learnt; } - bool has_extra () const { return header.has_extra; } - uint32_t mark () const { return header.mark; } - void mark (uint32_t m) { header.mark = m; } - const Lit& last () const { return data[header.size-1].lit; } - - bool reloced () const { return header.reloced; } - CRef relocation () const { return data[0].rel; } - void relocate (CRef c) { header.reloced = 1; data[0].rel = c; } - - // NOTE: somewhat unsafe to change the clause in-place! Must manually call 'calcAbstraction' afterwards for - // subsumption operations to behave correctly. - Lit& operator [] (int i) { return data[i].lit; } - Lit operator [] (int i) const { return data[i].lit; } - operator const Lit* (void) const { return (Lit*)data; } - - float& activity() - { - Assert(header.has_extra); - return data[header.size].act; - } - uint32_t abstraction() const - { - Assert(header.has_extra); - return data[header.size].abs; - } - - Lit subsumes (const Clause& other) const; - void strengthen (Lit p); -}; - - -//================================================================================================= -// ClauseAllocator -- a simple class for allocating memory for clauses: - - -const CRef CRef_Undef = RegionAllocator<uint32_t>::Ref_Undef; -const CRef CRef_Lazy = RegionAllocator<uint32_t>::Ref_Undef - 1; - -class ClauseAllocator : public RegionAllocator<uint32_t> -{ - static int clauseWord32Size(int size, bool has_extra){ - return (sizeof(Clause) + (sizeof(Lit) * (size + (int)has_extra))) / sizeof(uint32_t); } - public: - bool extra_clause_field; - - ClauseAllocator(uint32_t start_cap) : RegionAllocator<uint32_t>(start_cap), extra_clause_field(false){} - ClauseAllocator() : extra_clause_field(false){} - - void moveTo(ClauseAllocator& to){ - to.extra_clause_field = extra_clause_field; - RegionAllocator<uint32_t>::moveTo(to); } - - template<class Lits> - CRef alloc(const Lits& ps, bool learnt = false) - { - Assert(sizeof(Lit) == sizeof(uint32_t)); - Assert(sizeof(float) == sizeof(uint32_t)); - bool use_extra = learnt | extra_clause_field; - - CRef cid = RegionAllocator<uint32_t>::alloc( - clauseWord32Size(ps.size(), use_extra)); - new (lea(cid)) Clause(ps, use_extra, learnt); - - return cid; - } - - // Deref, Load Effective Address (LEA), Inverse of LEA (AEL): - Clause& operator[](Ref r) { return (Clause&)RegionAllocator<uint32_t>::operator[](r); } - const Clause& operator[](Ref r) const { return (Clause&)RegionAllocator<uint32_t>::operator[](r); } - Clause* lea (Ref r) { return (Clause*)RegionAllocator<uint32_t>::lea(r); } - const Clause* lea (Ref r) const { return (Clause*)RegionAllocator<uint32_t>::lea(r); } - Ref ael (const Clause* t){ return RegionAllocator<uint32_t>::ael((uint32_t*)t); } - - void free(CRef cid) - { - Clause& c = operator[](cid); - RegionAllocator<uint32_t>::free(clauseWord32Size(c.size(), c.has_extra())); - } - - void reloc(CRef& cr, ClauseAllocator& to); -}; - - -//================================================================================================= -// OccLists -- a class for maintaining occurence lists with lazy deletion: - -template<class Idx, class Vec, class Deleted> -class OccLists -{ - vec<Vec> occs; - vec<char> dirty; - vec<Idx> dirties; - Deleted deleted; - - public: - OccLists(const Deleted& d) : deleted(d) {} - - void init (const Idx& idx){ occs.growTo(toInt(idx)+1); dirty.growTo(toInt(idx)+1, 0); } - // Vec& operator[](const Idx& idx){ return occs[toInt(idx)]; } - Vec& operator[](const Idx& idx){ return occs[toInt(idx)]; } - Vec& lookup (const Idx& idx){ if (dirty[toInt(idx)]) clean(idx); return occs[toInt(idx)]; } - - void cleanAll (); - void clean (const Idx& idx); - void smudge (const Idx& idx){ - if (dirty[toInt(idx)] == 0){ - dirty[toInt(idx)] = 1; - dirties.push(idx); - } - } - - void clear(bool free = true){ - occs .clear(free); - dirty .clear(free); - dirties.clear(free); - } -}; - - -template<class Idx, class Vec, class Deleted> -void OccLists<Idx,Vec,Deleted>::cleanAll() -{ - for (int i = 0; i < dirties.size(); i++) - // Dirties may contain duplicates so check here if a variable is already cleaned: - if (dirty[toInt(dirties[i])]) - clean(dirties[i]); - dirties.clear(); -} - - -template<class Idx, class Vec, class Deleted> -void OccLists<Idx,Vec,Deleted>::clean(const Idx& idx) -{ - Vec& vec = occs[toInt(idx)]; - int i, j; - for (i = j = 0; i < vec.size(); i++) - if (!deleted(vec[i])) - vec[j++] = vec[i]; - vec.shrink(i - j); - dirty[toInt(idx)] = 0; -} - - -//================================================================================================= -// CMap -- a class for mapping clauses to values: - - -template<class T> -class CMap -{ - struct CRefHash { - uint32_t operator()(CRef cr) const { return (uint32_t)cr; } }; - - typedef Map<CRef, T, CRefHash> HashTable; - HashTable map; - - public: - // Size-operations: - void clear () { map.clear(); } - int size () const { return map.elems(); } - - // Insert/Remove/Test mapping: - void insert (CRef cr, const T& t){ map.insert(cr, t); } - void growTo (CRef cr, const T& t){ map.insert(cr, t); } // NOTE: for compatibility - void remove (CRef cr) { map.remove(cr); } - bool has (CRef cr, T& t) { return map.peek(cr, t); } - - // Vector interface (the clause 'c' must already exist): - const T& operator [] (CRef cr) const { return map[cr]; } - T& operator [] (CRef cr) { return map[cr]; } - - // Iteration (not transparent at all at the moment): - int bucket_count() const { return map.bucket_count(); } - const vec<typename HashTable::Pair>& bucket(int i) const { return map.bucket(i); } - - // Move contents to other map: - void moveTo(CMap& other){ map.moveTo(other.map); } - - // TMP debug: - void debug(){ - printf(" --- size = %d, bucket_count = %d\n", size(), map.bucket_count()); } -}; - -/*_________________________________________________________________________________________________ -| -| subsumes : (other : const Clause&) -> Lit -| -| Description: -| Checks if clause subsumes 'other', and at the same time, if it can be -used to simplify 'other' | by subsumption resolution. -| -| Result: -| lit_Error - No subsumption or simplification -| lit_Undef - Clause subsumes 'other' -| p - The literal p can be deleted from 'other' -|________________________________________________________________________________________________@*/ -inline Lit Clause::subsumes(const Clause& other) const -{ - //if (other.size() < size() || (extra.abst & ~other.extra.abst) != 0) - //if (other.size() < size() || (!learnt() && !other.learnt() && (extra.abst & ~other.extra.abst) != 0)) - Assert(!header.learnt); - Assert(!other.header.learnt); - Assert(header.has_extra); - Assert(other.header.has_extra); - if (other.header.size < header.size || (data[header.size].abs & ~other.data[other.header.size].abs) != 0) - return lit_Error; - - Lit ret = lit_Undef; - const Lit* c = (const Lit*)(*this); - const Lit* d = (const Lit*)other; - - for (unsigned i = 0; i < header.size; i++) { - // search for c[i] or ~c[i] - for (unsigned j = 0; j < other.header.size; j++) - if (c[i] == d[j]) - goto ok; - else if (ret == lit_Undef && c[i] == ~d[j]){ - ret = c[i]; - goto ok; - } - - // did not find it - return lit_Error; - ok:; - } - - return ret; -} - -inline void Clause::strengthen(Lit p) -{ - remove(*this, p); - calcAbstraction(); -} - - - -//================================================================================================= -} // namespace BVMinisat -} // namespace cvc5 - -#endif diff --git a/src/prop/bvminisat/doc/ReleaseNotes-2.2.0.txt b/src/prop/bvminisat/doc/ReleaseNotes-2.2.0.txt deleted file mode 100644 index 7f084de2b..000000000 --- a/src/prop/bvminisat/doc/ReleaseNotes-2.2.0.txt +++ /dev/null @@ -1,79 +0,0 @@ -Release Notes for MiniSat 2.2.0 -=============================== - -Changes since version 2.0: - - * Started using a more standard release numbering. - - * Includes some now well-known heuristics: phase-saving and luby - restarts. The old heuristics are still present and can be activated - if needed. - - * Detection/Handling of out-of-memory and vector capacity - overflow. This is fairly new and relatively untested. - - * Simple resource controls: CPU-time, memory, number of - conflicts/decisions. - - * CPU-time limiting is implemented by a more general, but simple, - asynchronous interruption feature. This means that the solving - procedure can be interrupted from another thread or in a signal - handler. - - * Improved portability with respect to building on Solaris and with - Visual Studio. This is not regularly tested and chances are that - this have been broken since, but should be fairly easy to fix if - so. - - * Changed C++ file-extention to the less problematic ".cc". - - * Source code is now namespace-protected - - * Introducing a new Clause Memory Allocator that brings reduced - memory consumption on 64-bit architechtures and improved - performance (to some extent). The allocator uses a region-based - approach were all references to clauses are represented as a 32-bit - index into a global memory region that contains all clauses. To - free up and compact memory it uses a simple copying garbage - collector. - - * Improved unit-propagation by Blocking Literals. For each entry in - the watcher lists, pair the pointer to a clause with some - (arbitrary) literal from the clause. The idea is that if the - literal is currently true (i.e. the clause is satisfied) the - watchers of the clause does not need to be altered. This can thus - be detected without touching the clause's memory at all. As often - as can be done cheaply, the blocking literal for entries to the - watcher list of a literal 'p' is set to the other literal watched - in the corresponding clause. - - * Basic command-line/option handling system. Makes it easy to specify - options in the class that they affect, and whenever that class is - used in an executable, parsing of options and help messages are - brought in automatically. - - * General clean-up and various minor bug-fixes. - - * Changed implementation of variable-elimination/model-extension: - - - The interface is changed so that arbitrary remembering is no longer - possible. If you need to mention some variable again in the future, - this variable has to be frozen. - - - When eliminating a variable, only clauses that contain the variable - with one sign is necessary to store. Thereby making the other sign - a "default" value when extending models. - - - The memory consumption for eliminated clauses is further improved - by storing all eliminated clauses in a single contiguous vector. - - * Some common utility code (I/O, Parsing, CPU-time, etc) is ripped - out and placed in a separate "utils" directory. - - * The DIMACS parse is refactored so that it can be reused in other - applications (not very elegant, but at least possible). - - * Some simple improvements to scalability of preprocessing, using - more lazy clause removal from data-structures and a couple of - ad-hoc limits (the longest clause that can be produced in variable - elimination, and the longest clause used in backward subsumption). diff --git a/src/prop/bvminisat/mtl/Alg.h b/src/prop/bvminisat/mtl/Alg.h deleted file mode 100644 index ae72ca878..000000000 --- a/src/prop/bvminisat/mtl/Alg.h +++ /dev/null @@ -1,87 +0,0 @@ -/*******************************************************************************************[Alg.h] -Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson -Copyright (c) 2007-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#ifndef BVMinisat_Alg_h -#define BVMinisat_Alg_h - -#include "base/check.h" -#include "prop/bvminisat/mtl/Vec.h" - -namespace cvc5 { -namespace BVMinisat { - -//================================================================================================= -// Useful functions on vector-like types: - -//================================================================================================= -// Removing and searching for elements: -// - -template<class V, class T> -static inline void remove(V& ts, const T& t) -{ - int j = 0; - for (; j < ts.size() && ts[j] != t; j++); - Assert(j < ts.size()); - for (; j < ts.size()-1; j++) ts[j] = ts[j+1]; - ts.pop(); -} - - -template<class V, class T> -static inline bool find(V& ts, const T& t) -{ - int j = 0; - for (; j < ts.size() && ts[j] != t; j++); - return j < ts.size(); -} - - -//================================================================================================= -// Copying vectors with support for nested vector types: -// - -// Base case: -template<class T> -static inline void copy(const T& from, T& to) -{ - to = from; -} - -// Recursive case: -template<class T> -static inline void copy(const vec<T>& from, vec<T>& to, bool append = false) -{ - if (!append) - to.clear(); - for (int i = 0; i < from.size(); i++){ - to.push(); - copy(from[i], to.last()); - } -} - -template<class T> -static inline void append(const vec<T>& from, vec<T>& to){ copy(from, to, true); } - -//================================================================================================= -} // namespace BVMinisat -} // namespace cvc5 - -#endif diff --git a/src/prop/bvminisat/mtl/Alloc.h b/src/prop/bvminisat/mtl/Alloc.h deleted file mode 100644 index 2697f13b9..000000000 --- a/src/prop/bvminisat/mtl/Alloc.h +++ /dev/null @@ -1,154 +0,0 @@ -/*****************************************************************************************[Alloc.h] -Copyright (c) 2008-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - - -#ifndef BVMinisat_Alloc_h -#define BVMinisat_Alloc_h - -#include "base/check.h" -#include "prop/bvminisat/mtl/Vec.h" -#include "prop/bvminisat/mtl/XAlloc.h" - -namespace cvc5 { -namespace BVMinisat { - -//================================================================================================= -// Simple Region-based memory allocator: - -template<class T> -class RegionAllocator -{ - T* memory; - uint32_t sz; - uint32_t cap; - uint32_t wasted_; - - void capacity(uint32_t min_cap); - - public: - // TODO: make this a class for better type-checking? - typedef uint32_t Ref; - enum { Ref_Undef = UINT32_MAX }; - enum { Unit_Size = sizeof(uint32_t) }; - - explicit RegionAllocator(uint32_t start_cap = 1024*1024) : memory(NULL), sz(0), cap(0), wasted_(0){ capacity(start_cap); } - ~RegionAllocator() - { - if (memory != NULL) - ::free(memory); - } - - - uint32_t size () const { return sz; } - uint32_t wasted () const { return wasted_; } - - Ref alloc (int size); - void free (int size) { wasted_ += size; } - - // Deref, Load Effective Address (LEA), Inverse of LEA (AEL): - T& operator[](Ref r) - { - Assert(r >= 0 && r < sz); - return memory[r]; - } - const T& operator[](Ref r) const - { - Assert(r >= 0 && r < sz); - return memory[r]; - } - - T* lea(Ref r) - { - Assert(r >= 0 && r < sz); - return &memory[r]; - } - const T* lea(Ref r) const - { - Assert(r >= 0 && r < sz); - return &memory[r]; - } - Ref ael(const T* t) - { - Assert((void*)t >= (void*)&memory[0] - && (void*)t < (void*)&memory[sz - 1]); - return (Ref)(t - &memory[0]); - } - - void moveTo(RegionAllocator& to) { - if (to.memory != NULL) ::free(to.memory); - to.memory = memory; - to.sz = sz; - to.cap = cap; - to.wasted_ = wasted_; - - memory = NULL; - sz = cap = wasted_ = 0; - } - - -}; - -template<class T> -void RegionAllocator<T>::capacity(uint32_t min_cap) -{ - if (cap >= min_cap) return; - - uint32_t prev_cap = cap; - while (cap < min_cap){ - // NOTE: Multiply by a factor (13/8) without causing overflow, then add 2 and make the - // result even by clearing the least significant bit. The resulting sequence of capacities - // is carefully chosen to hit a maximum capacity that is close to the '2^32-1' limit when - // using 'uint32_t' as indices so that as much as possible of this space can be used. - uint32_t delta = ((cap >> 1) + (cap >> 3) + 2) & ~1; - cap += delta; - - if (cap <= prev_cap) - throw OutOfMemoryException(); - } - // printf(" .. (%p) cap = %u\n", this, cap); - - Assert(cap > 0); - memory = (T*)xrealloc(memory, sizeof(T)*cap); -} - - -template<class T> -typename RegionAllocator<T>::Ref -RegionAllocator<T>::alloc(int size) -{ - // printf("ALLOC called (this = %p, size = %d)\n", this, size); fflush(stdout); - Assert(size > 0); - capacity(sz + size); - - uint32_t prev_sz = sz; - sz += size; - - // Handle overflow: - if (sz < prev_sz) - throw OutOfMemoryException(); - - return prev_sz; -} - - -//================================================================================================= -} // namespace BVMinisat -} // namespace cvc5 - -#endif diff --git a/src/prop/bvminisat/mtl/Heap.h b/src/prop/bvminisat/mtl/Heap.h deleted file mode 100644 index 73c1f07d2..000000000 --- a/src/prop/bvminisat/mtl/Heap.h +++ /dev/null @@ -1,161 +0,0 @@ -/******************************************************************************************[Heap.h] -Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson -Copyright (c) 2007-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#ifndef BVMinisat_Heap_h -#define BVMinisat_Heap_h - -#include "base/check.h" -#include "prop/bvminisat/mtl/Vec.h" - -namespace cvc5 { -namespace BVMinisat { - -//================================================================================================= -// A heap implementation with support for decrease/increase key. - - -template<class Comp> -class Heap { - Comp lt; // The heap is a minimum-heap with respect to this comparator - vec<int> heap; // Heap of integers - vec<int> indices; // Each integers position (index) in the Heap - - // Index "traversal" functions - static inline int left (int i) { return i*2+1; } - static inline int right (int i) { return (i+1)*2; } - static inline int parent(int i) { return (i-1) >> 1; } - - - void percolateUp(int i) - { - int x = heap[i]; - int p = parent(i); - - while (i != 0 && lt(x, heap[p])){ - heap[i] = heap[p]; - indices[heap[p]] = i; - i = p; - p = parent(p); - } - heap [i] = x; - indices[x] = i; - } - - - void percolateDown(int i) - { - int x = heap[i]; - while (left(i) < heap.size()){ - int child = right(i) < heap.size() && lt(heap[right(i)], heap[left(i)]) ? right(i) : left(i); - if (!lt(heap[child], x)) break; - heap[i] = heap[child]; - indices[heap[i]] = i; - i = child; - } - heap [i] = x; - indices[x] = i; - } - - - public: - Heap(const Comp& c) : lt(c) { } - - int size () const { return heap.size(); } - bool empty () const { return heap.size() == 0; } - bool inHeap (int n) const { return n < indices.size() && indices[n] >= 0; } - int operator[](int index) const - { - Assert(index < heap.size()); - return heap[index]; - } - - void decrease(int n) - { - Assert(inHeap(n)); - percolateUp(indices[n]); - } - void increase(int n) - { - Assert(inHeap(n)); - percolateDown(indices[n]); - } - - // Safe variant of insert/decrease/increase: - void update(int n) - { - if (!inHeap(n)) - insert(n); - else { - percolateUp(indices[n]); - percolateDown(indices[n]); } - } - - - void insert(int n) - { - indices.growTo(n+1, -1); - Assert(!inHeap(n)); - - indices[n] = heap.size(); - heap.push(n); - percolateUp(indices[n]); - } - - - int removeMin() - { - int x = heap[0]; - heap[0] = heap.last(); - indices[heap[0]] = 0; - indices[x] = -1; - heap.pop(); - if (heap.size() > 1) percolateDown(0); - return x; - } - - - // Rebuild the heap from scratch, using the elements in 'ns': - void build(vec<int>& ns) { - for (int i = 0; i < heap.size(); i++) - indices[heap[i]] = -1; - heap.clear(); - - for (int i = 0; i < ns.size(); i++){ - indices[ns[i]] = i; - heap.push(ns[i]); } - - for (int i = heap.size() / 2 - 1; i >= 0; i--) - percolateDown(i); - } - - void clear(bool dealloc = false) - { - for (int i = 0; i < heap.size(); i++) - indices[heap[i]] = -1; - heap.clear(dealloc); - } -}; - - -//================================================================================================= -} // namespace BVMinisat -} // namespace cvc5 - -#endif diff --git a/src/prop/bvminisat/mtl/IntTypes.h b/src/prop/bvminisat/mtl/IntTypes.h deleted file mode 100644 index 7856dc07c..000000000 --- a/src/prop/bvminisat/mtl/IntTypes.h +++ /dev/null @@ -1,50 +0,0 @@ -/**************************************************************************************[IntTypes.h] -Copyright (c) 2009-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#ifndef BVMinisat_IntTypes_h -#define BVMinisat_IntTypes_h - -#ifdef __sun - // Not sure if there are newer versions that support C99 headers. The - // needed features are implemented in the headers below though: - -# include <sys/int_types.h> -# include <sys/int_fmtio.h> -# include <sys/int_limits.h> - -#else - -// In contrast to the original MiniSat source code, we are including the -// cstdint/cinttypes/climits headers instead of stdint.h/inttypes.h/limits.h -// here. This ensures that the macros in cinttypes/inttypes.h, e.g., PRIi64, -// are actually defined. The C99 standard suggested that those macros are only -// defined for C++ code when __STDC_FORMAT_MACROS is defined. This was never -// adopted by a C++ standard (https://en.cppreference.com/w/cpp/types/integer). -// However, certain versions of mingw-w64 seem to require it with inttypes.h -// but not cinttypes. -# include <cstdint> -# include <cinttypes> - -#endif - -#include <climits> - -//================================================================================================= - -#endif diff --git a/src/prop/bvminisat/mtl/Map.h b/src/prop/bvminisat/mtl/Map.h deleted file mode 100644 index 2d5db2561..000000000 --- a/src/prop/bvminisat/mtl/Map.h +++ /dev/null @@ -1,196 +0,0 @@ -/*******************************************************************************************[Map.h] -Copyright (c) 2006-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#ifndef BVMinisat_Map_h -#define BVMinisat_Map_h - -#include "base/check.h" -#include "prop/bvminisat/mtl/IntTypes.h" -#include "prop/bvminisat/mtl/Vec.h" - -namespace cvc5 { -namespace BVMinisat { - -//================================================================================================= -// Default hash/equals functions -// - -static inline uint32_t hash(uint32_t x){ return x; } -static inline uint32_t hash(uint64_t x){ return (uint32_t)x; } -static inline uint32_t hash(int32_t x) { return (uint32_t)x; } -static inline uint32_t hash(int64_t x) { return (uint32_t)x; } - -template<class K> struct Hash { uint32_t operator()(const K& k) const { return hash(k); } }; -template<class K> struct Equal { bool operator()(const K& k1, const K& k2) const { return k1 == k2; } }; - -template<class K> struct DeepHash { uint32_t operator()(const K* k) const { return hash(*k); } }; -template<class K> struct DeepEqual { bool operator()(const K* k1, const K* k2) const { return *k1 == *k2; } }; - - - -//================================================================================================= -// Some primes -// - -static const int nprimes = 25; -static const int primes [nprimes] = { 31, 73, 151, 313, 643, 1291, 2593, 5233, 10501, 21013, 42073, 84181, 168451, 337219, 674701, 1349473, 2699299, 5398891, 10798093, 21596719, 43193641, 86387383, 172775299, 345550609, 691101253 }; - -//================================================================================================= -// Hash table implementation of Maps -// - -template<class K, class D, class H = Hash<K>, class E = Equal<K> > -class Map { - public: - struct Pair { K key; D data; }; - - private: - H hash; - E equals; - - vec<Pair>* table; - int cap; - int size; - - // Don't allow copying (error prone): - Map<K, D, H, E>& operator=(Map<K, D, H, E>& other) { Assert(0); } - Map(Map<K, D, H, E>& other) { Assert(0); } - - bool checkCap(int new_size) const { return new_size > cap; } - - int32_t index (const K& k) const { return hash(k) % cap; } - void _insert (const K& k, const D& d) { - vec<Pair>& ps = table[index(k)]; - ps.push(); ps.last().key = k; ps.last().data = d; } - - void rehash () { - const vec<Pair>* old = table; - - int old_cap = cap; - int newsize = primes[0]; - for (int i = 1; newsize <= cap && i < nprimes; i++) - newsize = primes[i]; - - table = new vec<Pair>[newsize]; - cap = newsize; - - for (int i = 0; i < old_cap; i++){ - for (int j = 0; j < old[i].size(); j++){ - _insert(old[i][j].key, old[i][j].data); }} - - delete [] old; - - // printf(" --- rehashing, old-cap=%d, new-cap=%d\n", cap, newsize); - } - - - public: - - Map () : table(NULL), cap(0), size(0) {} - Map (const H& h, const E& e) : hash(h), equals(e), table(NULL), cap(0), size(0){} - ~Map () { delete [] table; } - - // PRECONDITION: the key must already exist in the map. - const D& operator [] (const K& k) const - { - Assert(size != 0); - const D* res = NULL; - const vec<Pair>& ps = table[index(k)]; - for (int i = 0; i < ps.size(); i++) - if (equals(ps[i].key, k)) res = &ps[i].data; - Assert(res != NULL); - return *res; - } - - // PRECONDITION: the key must already exist in the map. - D& operator [] (const K& k) - { - Assert(size != 0); - D* res = NULL; - vec<Pair>& ps = table[index(k)]; - for (int i = 0; i < ps.size(); i++) - if (equals(ps[i].key, k)) res = &ps[i].data; - Assert(res != NULL); - return *res; - } - - // PRECONDITION: the key must *NOT* exist in the map. - void insert (const K& k, const D& d) { if (checkCap(size+1)) rehash(); _insert(k, d); size++; } - bool peek (const K& k, D& d) const { - if (size == 0) return false; - const vec<Pair>& ps = table[index(k)]; - for (int i = 0; i < ps.size(); i++) - if (equals(ps[i].key, k)){ - d = ps[i].data; - return true; } - return false; - } - - bool has (const K& k) const { - if (size == 0) return false; - const vec<Pair>& ps = table[index(k)]; - for (int i = 0; i < ps.size(); i++) - if (equals(ps[i].key, k)) - return true; - return false; - } - - // PRECONDITION: the key must exist in the map. - void remove(const K& k) { - Assert(table != NULL); - vec<Pair>& ps = table[index(k)]; - int j = 0; - for (; j < ps.size() && !equals(ps[j].key, k); j++) - ; - Assert(j < ps.size()); - ps[j] = ps.last(); - ps.pop(); - size--; - } - - void clear () { - cap = size = 0; - delete [] table; - table = NULL; - } - - int elems() const { return size; } - int bucket_count() const { return cap; } - - // NOTE: the hash and equality objects are not moved by this method: - void moveTo(Map& other){ - delete [] other.table; - - other.table = table; - other.cap = cap; - other.size = size; - - table = NULL; - size = cap = 0; - } - - // NOTE: given a bit more time, I could make a more C++-style iterator out of this: - const vec<Pair>& bucket(int i) const { return table[i]; } -}; - -//================================================================================================= -} // namespace BVMinisat -} // namespace cvc5 - -#endif diff --git a/src/prop/bvminisat/mtl/Queue.h b/src/prop/bvminisat/mtl/Queue.h deleted file mode 100644 index 8407fd7ee..000000000 --- a/src/prop/bvminisat/mtl/Queue.h +++ /dev/null @@ -1,91 +0,0 @@ -/*****************************************************************************************[Queue.h] -Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson -Copyright (c) 2007-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#ifndef BVMinisat_Queue_h -#define BVMinisat_Queue_h - -#include "base/check.h" -#include "prop/bvminisat/mtl/Vec.h" - -namespace cvc5 { -namespace BVMinisat { - -//================================================================================================= - -template<class T> -class Queue { - vec<T> buf; - int first; - int end; - -public: - typedef T Key; - - Queue() : buf(1), first(0), end(0) {} - - void clear (bool dealloc = false) { buf.clear(dealloc); buf.growTo(1); first = end = 0; } - int size () const { return (end >= first) ? end - first : end - first + buf.size(); } - - const T& operator[](int index) const - { - Assert(index >= 0); - Assert(index < size()); - return buf[(first + index) % buf.size()]; - } - T& operator[](int index) - { - Assert(index >= 0); - Assert(index < size()); - return buf[(first + index) % buf.size()]; - } - - T peek() const - { - Assert(first != end); - return buf[first]; - } - void pop() - { - Assert(first != end); - first++; - if (first == buf.size()) first = 0; - } - void insert(T elem) { // INVARIANT: buf[end] is always unused - buf[end++] = elem; - if (end == buf.size()) end = 0; - if (first == end){ // Resize: - vec<T> tmp((buf.size()*3 + 1) >> 1); - //**/printf("queue alloc: %d elems (%.1f MB)\n", tmp.size(), tmp.size() * sizeof(T) / 1000000.0); - int i = 0; - for (int j = first; j < buf.size(); j++) tmp[i++] = buf[j]; - for (int j = 0 ; j < end ; j++) tmp[i++] = buf[j]; - first = 0; - end = buf.size(); - tmp.moveTo(buf); - } - } -}; - - -//================================================================================================= -} // namespace BVMinisat -} // namespace cvc5 - -#endif diff --git a/src/prop/bvminisat/mtl/Sort.h b/src/prop/bvminisat/mtl/Sort.h deleted file mode 100644 index 30b3b5396..000000000 --- a/src/prop/bvminisat/mtl/Sort.h +++ /dev/null @@ -1,99 +0,0 @@ -/******************************************************************************************[Sort.h] -Copyright (c) 2003-2007, Niklas Een, Niklas Sorensson -Copyright (c) 2007-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#ifndef BVMinisat_Sort_h -#define BVMinisat_Sort_h - -#include "prop/bvminisat/mtl/Vec.h" - -//================================================================================================= -// Some sorting algorithms for vec's - -namespace cvc5 { -namespace BVMinisat { - -template<class T> -struct LessThan_default { - bool operator () (T x, T y) { return x < y; } -}; - - -template <class T, class LessThan> -void selectionSort(T* array, int size, LessThan lt) -{ - int i, j, best_i; - T tmp; - - for (i = 0; i < size-1; i++){ - best_i = i; - for (j = i+1; j < size; j++){ - if (lt(array[j], array[best_i])) - best_i = j; - } - tmp = array[i]; array[i] = array[best_i]; array[best_i] = tmp; - } -} -template <class T> static inline void selectionSort(T* array, int size) { - selectionSort(array, size, LessThan_default<T>()); } - -template <class T, class LessThan> -void sort(T* array, int size, LessThan lt) -{ - if (size <= 15) - selectionSort(array, size, lt); - - else{ - T pivot = array[size / 2]; - T tmp; - int i = -1; - int j = size; - - for(;;){ - do i++; while(lt(array[i], pivot)); - do j--; while(lt(pivot, array[j])); - - if (i >= j) break; - - tmp = array[i]; array[i] = array[j]; array[j] = tmp; - } - - sort(array , i , lt); - sort(&array[i], size-i, lt); - } -} -template <class T> static inline void sort(T* array, int size) { - sort(array, size, LessThan_default<T>()); } - - -//================================================================================================= -// For 'vec's: - - -template <class T, class LessThan> void sort(vec<T>& v, LessThan lt) { - sort((T*)v, v.size(), lt); } -template <class T> void sort(vec<T>& v) { - sort(v, LessThan_default<T>()); } - - -//================================================================================================= -} // namespace BVMinisat -} // namespace cvc5 - -#endif diff --git a/src/prop/bvminisat/mtl/Vec.h b/src/prop/bvminisat/mtl/Vec.h deleted file mode 100644 index 047a89991..000000000 --- a/src/prop/bvminisat/mtl/Vec.h +++ /dev/null @@ -1,152 +0,0 @@ -/*******************************************************************************************[Vec.h] -Copyright (c) 2003-2007, Niklas Een, Niklas Sorensson -Copyright (c) 2007-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#ifndef BVMinisat_Vec_h -#define BVMinisat_Vec_h - -#include <new> - -#include "base/check.h" -#include "prop/bvminisat/mtl/IntTypes.h" -#include "prop/bvminisat/mtl/XAlloc.h" - -namespace cvc5 { -namespace BVMinisat { - -//================================================================================================= -// Automatically resizable arrays -// -// NOTE! Don't use this vector on datatypes that cannot be re-located in memory (with realloc) - -template<class T> -class vec { - T* data; - int sz; - int cap; - - // Don't allow copying (error prone): - vec<T>& operator=(vec<T>& other) - { - Assert(0); - return *this; - } - vec(vec<T>& other) { Assert(0); } - - // Helpers for calculating next capacity: - static inline int imax (int x, int y) { int mask = (y-x) >> (sizeof(int)*8-1); return (x&mask) + (y&(~mask)); } - //static inline void nextCap(int& cap){ cap += ((cap >> 1) + 2) & ~1; } - static inline void nextCap(int& cap){ cap += ((cap >> 1) + 2) & ~1; } - -public: - // Constructors: - vec() : data(NULL) , sz(0) , cap(0) { } - explicit vec(int size) : data(NULL) , sz(0) , cap(0) { growTo(size); } - vec(int size, const T& pad) : data(NULL) , sz(0) , cap(0) { growTo(size, pad); } - ~vec() { clear(true); } - - // Pointer to first element: - operator T* (void) { return data; } - - // Size operations: - int size (void) const { return sz; } - void shrink(int nelems) - { - Assert(nelems <= sz); - for (int i = 0; i < nelems; i++) sz--, data[sz].~T(); - } - void shrink_(int nelems) - { - Assert(nelems <= sz); - sz -= nelems; - } - int capacity (void) const { return cap; } - void capacity (int min_cap); - void growTo (int size); - void growTo (int size, const T& pad); - void clear (bool dealloc = false); - - // Stack interface: - void push (void) { if (sz == cap) capacity(sz+1); new (&data[sz]) T(); sz++; } - void push (const T& elem) { if (sz == cap) capacity(sz+1); data[sz++] = elem; } - void push_(const T& elem) - { - Assert(sz < cap); - data[sz++] = elem; - } - void pop(void) - { - Assert(sz > 0); - sz--, data[sz].~T(); - } - // NOTE: it seems possible that overflow can happen in the 'sz+1' expression of 'push()', but - // in fact it can not since it requires that 'cap' is equal to INT_MAX. This in turn can not - // happen given the way capacities are calculated (below). Essentially, all capacities are - // even, but INT_MAX is odd. - - const T& last (void) const { return data[sz-1]; } - T& last (void) { return data[sz-1]; } - - // Vector interface: - const T& operator [] (int index) const { return data[index]; } - T& operator [] (int index) { return data[index]; } - - // Duplicatation (preferred instead): - void copyTo(vec<T>& copy) const { copy.clear(); copy.growTo(sz); for (int i = 0; i < sz; i++) copy[i] = data[i]; } - void moveTo(vec<T>& dest) { dest.clear(true); dest.data = data; dest.sz = sz; dest.cap = cap; data = NULL; sz = 0; cap = 0; } -}; - - -template<class T> -void vec<T>::capacity(int min_cap) { - if (cap >= min_cap) return; - int add = imax((min_cap - cap + 1) & ~1, ((cap >> 1) + 2) & ~1); // NOTE: grow by approximately 3/2 - if (add > INT_MAX - cap || (((data = (T*)::realloc(data, (cap += add) * sizeof(T))) == NULL) && errno == ENOMEM)) - throw OutOfMemoryException(); - } - - -template<class T> -void vec<T>::growTo(int size, const T& pad) { - if (sz >= size) return; - capacity(size); - for (int i = sz; i < size; i++) data[i] = pad; - sz = size; } - - -template<class T> -void vec<T>::growTo(int size) { - if (sz >= size) return; - capacity(size); - for (int i = sz; i < size; i++) new (&data[i]) T(); - sz = size; } - - -template<class T> -void vec<T>::clear(bool dealloc) { - if (data != NULL){ - for (int i = 0; i < sz; i++) data[i].~T(); - sz = 0; - if (dealloc) free(data), data = NULL, cap = 0; } } - -//================================================================================================= -} // namespace BVMinisat -} // namespace cvc5 - -#endif diff --git a/src/prop/bvminisat/mtl/XAlloc.h b/src/prop/bvminisat/mtl/XAlloc.h deleted file mode 100644 index 581915d36..000000000 --- a/src/prop/bvminisat/mtl/XAlloc.h +++ /dev/null @@ -1,47 +0,0 @@ -/****************************************************************************************[XAlloc.h] -Copyright (c) 2009-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - - -#ifndef BVMinisat_XAlloc_h -#define BVMinisat_XAlloc_h - -#include <errno.h> -#include <stdlib.h> - -namespace cvc5 { -namespace BVMinisat { - -//================================================================================================= -// Simple layer on top of malloc/realloc to catch out-of-memory situtaions and provide some typing: - -class OutOfMemoryException{}; -static inline void* xrealloc(void *ptr, size_t size) -{ - void* mem = realloc(ptr, size); - if (mem == NULL && errno == ENOMEM){ - throw OutOfMemoryException(); - }else - return mem; -} - -//================================================================================================= -} // namespace BVMinisat -} // namespace cvc5 - -#endif diff --git a/src/prop/bvminisat/simp/SimpSolver.cc b/src/prop/bvminisat/simp/SimpSolver.cc deleted file mode 100644 index e399fac4c..000000000 --- a/src/prop/bvminisat/simp/SimpSolver.cc +++ /dev/null @@ -1,812 +0,0 @@ -/***********************************************************************************[SimpSolver.cc] -Copyright (c) 2006, Niklas Een, Niklas Sorensson -Copyright (c) 2007-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#include "prop/bvminisat/simp/SimpSolver.h" - -#include "base/check.h" -#include "options/bv_options.h" -#include "options/smt_options.h" -#include "proof/clause_id.h" -#include "prop/bvminisat/mtl/Sort.h" -#include "prop/bvminisat/utils/System.h" - -namespace cvc5 { -namespace BVMinisat { - -//================================================================================================= -// Options: - - -static const char* _cat = "SIMP"; - -static BoolOption opt_use_asymm (_cat, "asymm", "Shrink clauses by asymmetric branching.", false); -static BoolOption opt_use_rcheck (_cat, "rcheck", "Check if a clause is already implied. (costly)", false); -static BoolOption opt_use_elim (_cat, "elim", "Perform variable elimination.", true); -static IntOption opt_grow (_cat, "grow", "Allow a variable elimination step to grow by a number of clauses.", 0); -static IntOption opt_clause_lim (_cat, "cl-lim", "Variables are not eliminated if it produces a resolvent with a length above this limit. -1 means no limit", 20, IntRange(-1, INT32_MAX)); -static IntOption opt_subsumption_lim (_cat, "sub-lim", "Do not check if subsumption against a clause larger than this. -1 means no limit.", 1000, IntRange(-1, INT32_MAX)); -static DoubleOption opt_simp_garbage_frac(_cat, "simp-gc-frac", "The fraction of wasted memory allowed before a garbage collection is triggered during simplification.", 0.5, DoubleRange(0, false, HUGE_VAL, false)); - - -//================================================================================================= -// Constructor/Destructor: - -SimpSolver::SimpSolver(cvc5::context::Context* context) - : Solver(context), - grow(opt_grow), - clause_lim(opt_clause_lim), - subsumption_lim(opt_subsumption_lim), - simp_garbage_frac(opt_simp_garbage_frac), - use_asymm(opt_use_asymm), - use_rcheck(opt_use_rcheck), - use_elim(opt_use_elim - && cvc5::options::bitblastMode() - == cvc5::options::BitblastMode::EAGER - && !cvc5::options::produceModels()), - merges(0), - asymm_lits(0), - eliminated_vars(0), - elimorder(1), - use_simplification(true), - occurs(ClauseDeleted(ca)), - elim_heap(ElimLt(n_occ)), - bwdsub_assigns(0), - n_touched(0) -{ - - vec<Lit> dummy(1,lit_Undef); - ca.extra_clause_field = true; // NOTE: must happen before allocating the dummy clause below. - bwdsub_tmpunit = ca.alloc(dummy); - remove_satisfied = false; - - // add the initialization for all the internal variables - for (int i = frozen.size(); i < vardata.size(); ++ i) { - frozen .push(1); - eliminated.push(0); - if (use_simplification){ - n_occ .push(0); - n_occ .push(0); - occurs .init(i); - touched .push(0); - elim_heap .insert(i); - } - } - -} - - -SimpSolver::~SimpSolver() -{ - // cvc5::StatisticsRegistry::unregisterStat(&total_eliminate_time); -} - - -Var SimpSolver::newVar(bool sign, bool dvar, bool freeze) { - Var v = Solver::newVar(sign, dvar); - - frozen .push((char)false); - eliminated.push((char)false); - - if (use_simplification){ - n_occ .push(0); - n_occ .push(0); - occurs .init(v); - touched .push(0); - elim_heap .insert(v); - if (freeze) { - setFrozen(v, true); - } - } - return v; -} - - - -lbool SimpSolver::solve_(bool do_simp, bool turn_off_simp) -{ - only_bcp = false; - - vec<Var> extra_frozen; - lbool result = l_True; - - do_simp &= use_simplification; - - if (do_simp) { - // Assumptions must be temporarily frozen to run variable elimination: - for (int i = 0; i < assumptions.size(); i++){ - Var v = var(assumptions[i]); - - // If an assumption has been eliminated, remember it. - Assert(!isEliminated(v)); - - if (!frozen[v]){ - // Freeze and store. - setFrozen(v, true); - extra_frozen.push(v); - } } - - if (do_simp && clause_added) { - cancelUntil(0); - result = lbool(eliminate(turn_off_simp)); - clause_added = false; - } - } - - if (result == l_True) - result = Solver::solve_(); - else if (verbosity >= 1) - printf("===============================================================================\n"); - - if (do_simp) - // Unfreeze the assumptions that were frozen: - for (int i = 0; i < extra_frozen.size(); i++) - setFrozen(extra_frozen[i], false); - - return result; -} - - - -bool SimpSolver::addClause_(vec<Lit>& ps, ClauseId& id) -{ -#ifdef CVC5_ASSERTIONS - for (int i = 0; i < ps.size(); i++) Assert(!isEliminated(var(ps[i]))); -#endif - - int nclauses = clauses.size(); - - if (use_rcheck && implied(ps)) - return true; - - if (!Solver::addClause_(ps, id)) - return false; - - if (use_simplification && clauses.size() == nclauses + 1){ - CRef cr = clauses.last(); - const Clause& clause = ca[cr]; - - // NOTE: the clause is added to the queue immediately and then - // again during 'gatherTouchedClauses()'. If nothing happens - // in between, it will only be checked once. Otherwise, it may - // be checked twice unnecessarily. This is an unfortunate - // consequence of how backward subsumption is used to mimic - // forward subsumption. - subsumption_queue.insert(cr); - for (int i = 0; i < clause.size(); i++) - { - occurs[var(clause[i])].push(cr); - n_occ[toInt(clause[i])]++; - touched[var(clause[i])] = 1; - n_touched++; - if (elim_heap.inHeap(var(clause[i]))) - elim_heap.increase(var(clause[i])); - } - } - - return true; -} - - -void SimpSolver::removeClause(CRef cr) -{ - const Clause& clause = ca[cr]; - - if (use_simplification) - { - for (int i = 0; i < clause.size(); i++) - { - n_occ[toInt(clause[i])]--; - updateElimHeap(var(clause[i])); - occurs.smudge(var(clause[i])); - } - } - Solver::removeClause(cr); -} - - -bool SimpSolver::strengthenClause(CRef cr, Lit l) -{ - Clause& clause = ca[cr]; - Assert(decisionLevel() == 0); - Assert(use_simplification); - - // FIX: this is too inefficient but would be nice to have (properly - // implemented) if (!find(subsumption_queue, &clause)) - subsumption_queue.insert(cr); - - if (clause.size() == 2) - { - removeClause(cr); - clause.strengthen(l); - } - else - { - detachClause(cr, true); - clause.strengthen(l); - attachClause(cr); - remove(occurs[var(l)], cr); - n_occ[toInt(l)]--; - updateElimHeap(var(l)); - } - - return clause.size() == 1 ? enqueue(clause[0]) && propagate() == CRef_Undef - : true; -} - - -// Returns FALSE if clause is always satisfied ('out_clause' should not be used). -bool SimpSolver::merge(const Clause& _ps, const Clause& _qs, Var v, vec<Lit>& out_clause) -{ - merges++; - out_clause.clear(); - - bool ps_smallest = _ps.size() < _qs.size(); - const Clause& ps = ps_smallest ? _qs : _ps; - const Clause& qs = ps_smallest ? _ps : _qs; - - for (int i = 0; i < qs.size(); i++) - { - if (var(qs[i]) != v) - { - for (int j = 0; j < ps.size(); j++) - { - if (var(ps[j]) == var(qs[i])) - { - if (ps[j] == ~qs[i]) - return false; - else - goto next; - } - } - out_clause.push(qs[i]); - } - next:; - } - - for (int i = 0; i < ps.size(); i++) - if (var(ps[i]) != v) - out_clause.push(ps[i]); - - return true; -} - - -// Returns FALSE if clause is always satisfied. -bool SimpSolver::merge(const Clause& _ps, const Clause& _qs, Var v, int& size) -{ - merges++; - - bool ps_smallest = _ps.size() < _qs.size(); - const Clause& ps = ps_smallest ? _qs : _ps; - const Clause& qs = ps_smallest ? _ps : _qs; - const Lit* __ps = (const Lit*)ps; - const Lit* __qs = (const Lit*)qs; - - size = ps.size()-1; - - for (int i = 0; i < qs.size(); i++) - { - if (var(__qs[i]) != v) - { - for (int j = 0; j < ps.size(); j++) - { - if (var(__ps[j]) == var(__qs[i])) - { - if (__ps[j] == ~__qs[i]) - return false; - else - goto next; - } - } - size++; - } - next:; - } - - return true; -} - - -void SimpSolver::gatherTouchedClauses() -{ - if (n_touched == 0) return; - - int i,j; - for (i = j = 0; i < subsumption_queue.size(); i++) - if (ca[subsumption_queue[i]].mark() == 0) - ca[subsumption_queue[i]].mark(2); - - for (i = 0; i < touched.size(); i++) - if (touched[i]){ - const vec<CRef>& cs = occurs.lookup(i); - for (j = 0; j < cs.size(); j++) - if (ca[cs[j]].mark() == 0){ - subsumption_queue.insert(cs[j]); - ca[cs[j]].mark(2); - } - touched[i] = 0; - } - - for (i = 0; i < subsumption_queue.size(); i++) - if (ca[subsumption_queue[i]].mark() == 2) - ca[subsumption_queue[i]].mark(0); - - n_touched = 0; -} - -bool SimpSolver::implied(const vec<Lit>& clause) -{ - Assert(decisionLevel() == 0); - - trail_lim.push(trail.size()); - for (int i = 0; i < clause.size(); i++) - { - if (value(clause[i]) == l_True) - { - cancelUntil(0); - return false; - } - else if (value(clause[i]) != l_False) - { - Assert(value(clause[i]) == l_Undef); - uncheckedEnqueue(~clause[i]); - } - } - - bool result = propagate() != CRef_Undef; - cancelUntil(0); - return result; -} - - -// Backward subsumption + backward subsumption resolution -bool SimpSolver::backwardSubsumptionCheck(bool verbose) -{ - int cnt = 0; - int subsumed = 0; - int deleted_literals = 0; - Assert(decisionLevel() == 0); - - while (subsumption_queue.size() > 0 || bwdsub_assigns < trail.size()){ - - // Empty subsumption queue and return immediately on user-interrupt: - if (asynch_interrupt){ - subsumption_queue.clear(); - bwdsub_assigns = trail.size(); - break; } - - // Check top-level assignments by creating a dummy clause and placing it in the queue: - if (subsumption_queue.size() == 0 && bwdsub_assigns < trail.size()){ - Lit l = trail[bwdsub_assigns++]; - ca[bwdsub_tmpunit][0] = l; - ca[bwdsub_tmpunit].calcAbstraction(); - subsumption_queue.insert(bwdsub_tmpunit); } - - CRef cr = subsumption_queue.peek(); subsumption_queue.pop(); - Clause& clause = ca[cr]; - - if (clause.mark()) continue; - - if (verbose && verbosity >= 2 && cnt++ % 1000 == 0) - printf("subsumption left: %10d (%10d subsumed, %10d deleted literals)\r", subsumption_queue.size(), subsumed, deleted_literals); - - Assert(clause.size() > 1 - || value(clause[0]) == l_True); // Unit-clauses should have been - // propagated before this point. - - // Find best variable to scan: - Var best = var(clause[0]); - for (int i = 1; i < clause.size(); i++) - if (occurs[var(clause[i])].size() < occurs[best].size()) - best = var(clause[i]); - - // Search all candidates: - vec<CRef>& _cs = occurs.lookup(best); - CRef* cs = (CRef*)_cs; - - for (int j = 0; j < _cs.size(); j++) - if (clause.mark()) - break; - else if (!ca[cs[j]].mark() && cs[j] != cr - && (subsumption_lim == -1 - || ca[cs[j]].size() < subsumption_lim)) - { - Lit l = clause.subsumes(ca[cs[j]]); - - if (l == lit_Undef) - subsumed++, removeClause(cs[j]); - else if (l != lit_Error) - { - deleted_literals++; - - if (!strengthenClause(cs[j], ~l)) return false; - - // Did current candidate get deleted from cs? Then check candidate - // at index j again: - if (var(l) == best) j--; - } - } - } - - return true; -} - - -bool SimpSolver::asymm(Var v, CRef cr) -{ - Clause& clause = ca[cr]; - Assert(decisionLevel() == 0); - - if (clause.mark() || satisfied(clause)) return true; - - trail_lim.push(trail.size()); - Lit l = lit_Undef; - for (int i = 0; i < clause.size(); i++) - if (var(clause[i]) != v && value(clause[i]) != l_False) - uncheckedEnqueue(~clause[i]); - else - l = clause[i]; - - if (propagate() != CRef_Undef) - { - cancelUntil(0); - asymm_lits++; - if (!strengthenClause(cr, l)) return false; - } - else - cancelUntil(0); - - return true; -} - - -bool SimpSolver::asymmVar(Var v) -{ - Assert(use_simplification); - - const vec<CRef>& cls = occurs.lookup(v); - - if (value(v) != l_Undef || cls.size() == 0) return true; - - for (int i = 0; i < cls.size(); i++) - if (!asymm(v, cls[i])) return false; - - return backwardSubsumptionCheck(); -} - - -static void mkElimClause(vec<uint32_t>& elimclauses, Lit x) -{ - elimclauses.push(toInt(x)); - elimclauses.push(1); -} - -static void mkElimClause(vec<uint32_t>& elimclauses, Var v, Clause& clause) -{ - int first = elimclauses.size(); - int v_pos = -1; - - // Copy clause to elimclauses-vector. Remember position where the - // variable 'v' occurs: - for (int i = 0; i < clause.size(); i++) - { - elimclauses.push(toInt(clause[i])); - if (var(clause[i]) == v) v_pos = i + first; - } - Assert(v_pos != -1); - - // Swap the first literal with the 'v' literal, so that the literal - // containing 'v' will occur first in the clause: - uint32_t tmp = elimclauses[v_pos]; - elimclauses[v_pos] = elimclauses[first]; - elimclauses[first] = tmp; - - // Store the length of the clause last: - elimclauses.push(clause.size()); -} - - - -bool SimpSolver::eliminateVar(Var v) -{ - Assert(!frozen[v]); - Assert(!isEliminated(v)); - Assert(value(v) == l_Undef); - - // Split the occurrences into positive and negative: - // - const vec<CRef>& cls = occurs.lookup(v); - vec<CRef> pos, neg; - for (int i = 0; i < cls.size(); i++) - (find(ca[cls[i]], mkLit(v)) ? pos : neg).push(cls[i]); - - // Check whether the increase in number of clauses stays within the allowed - // ('grow'). Moreover, no clause must exceed the limit on the maximal clause - // size (if it is set): - // - int cnt = 0; - int clause_size = 0; - - for (int i = 0; i < pos.size(); i++) - for (int j = 0; j < neg.size(); j++) - if (merge(ca[pos[i]], ca[neg[j]], v, clause_size) - && (++cnt > cls.size() + grow - || (clause_lim != -1 && clause_size > clause_lim))) - return true; - - // Delete and store old clauses: - eliminated[v] = true; - setDecisionVar(v, false); - eliminated_vars++; - - if (pos.size() > neg.size()) - { - for (int i = 0; i < neg.size(); i++) - mkElimClause(elimclauses, v, ca[neg[i]]); - mkElimClause(elimclauses, mkLit(v)); - } - else - { - for (int i = 0; i < pos.size(); i++) - mkElimClause(elimclauses, v, ca[pos[i]]); - mkElimClause(elimclauses, ~mkLit(v)); - } - - for (int i = 0; i < cls.size(); i++) removeClause(cls[i]); - - // Produce clauses in cross product: - vec<Lit>& resolvent = add_tmp; - for (int i = 0; i < pos.size(); i++) - for (int j = 0; j < neg.size(); j++) { - ClauseId id = -1; - if (merge(ca[pos[i]], ca[neg[j]], v, resolvent) && - !addClause_(resolvent, id)) - return false; - } - - // Free occurs list for this variable: - occurs[v].clear(true); - - // Free watchers lists for this variable, if possible: - if (watches[ mkLit(v)].size() == 0) watches[ mkLit(v)].clear(true); - if (watches[~mkLit(v)].size() == 0) watches[~mkLit(v)].clear(true); - - return backwardSubsumptionCheck(); -} - - -bool SimpSolver::substitute(Var v, Lit x) -{ - Assert(!frozen[v]); - Assert(!isEliminated(v)); - Assert(value(v) == l_Undef); - - if (!ok) return false; - - eliminated[v] = true; - setDecisionVar(v, false); - const vec<CRef>& cls = occurs.lookup(v); - - vec<Lit>& subst_clause = add_tmp; - for (int i = 0; i < cls.size(); i++) - { - Clause& clause = ca[cls[i]]; - - subst_clause.clear(); - for (int j = 0; j < clause.size(); j++) - { - Lit p = clause[j]; - subst_clause.push(var(p) == v ? x ^ sign(p) : p); - } - - removeClause(cls[i]); - ClauseId id; - if (!addClause_(subst_clause, id)) return ok = false; - } - - return true; -} - - -void SimpSolver::extendModel() -{ - int i, j; - Lit x; - - for (i = elimclauses.size()-1; i > 0; i -= j){ - for (j = elimclauses[i--]; j > 1; j--, i--) - if (modelValue(toLit(elimclauses[i])) != l_False) - goto next; - - x = toLit(elimclauses[i]); - model[var(x)] = lbool(!sign(x)); - next:; - } -} - - -bool SimpSolver::eliminate(bool turn_off_elim) -{ - // cvc5::TimerStat::CodeTimer codeTimer(total_eliminate_time); - - if (!simplify()) - return false; - else if (!use_simplification) - return true; - - // Main simplification loop: - // - while (n_touched > 0 || bwdsub_assigns < trail.size() || elim_heap.size() > 0) - { - gatherTouchedClauses(); - // printf(" ## (time = %6.2f s) BWD-SUB: queue = %d, trail = %d\n", - // cpuTime(), subsumption_queue.size(), trail.size() - bwdsub_assigns); - if ((subsumption_queue.size() > 0 || bwdsub_assigns < trail.size()) - && !backwardSubsumptionCheck(true)) - { - ok = false; - goto cleanup; - } - - // Empty elim_heap and return immediately on user-interrupt: - if (asynch_interrupt) - { - Assert(bwdsub_assigns == trail.size()); - Assert(subsumption_queue.size() == 0); - Assert(n_touched == 0); - elim_heap.clear(); - goto cleanup; - } - - // printf(" ## (time = %6.2f s) ELIM: vars = %d\n", cpuTime(), - // elim_heap.size()); - for (int cnt = 0; !elim_heap.empty(); cnt++) - { - Var elim = elim_heap.removeMin(); - - if (asynch_interrupt) break; - - if (isEliminated(elim) || value(elim) != l_Undef) continue; - - if (verbosity >= 2 && cnt % 100 == 0) - printf("elimination left: %10d\r", elim_heap.size()); - - if (use_asymm) - { - // Temporarily freeze variable. Otherwise, it would immediately end up - // on the queue again: - bool was_frozen = frozen[elim]; - frozen[elim] = true; - if (!asymmVar(elim)) - { - ok = false; - goto cleanup; - } - frozen[elim] = was_frozen; - } - - // At this point, the variable may have been set by assymetric branching, - // so check it again. Also, don't eliminate frozen variables: - if (use_elim && value(elim) == l_Undef && !frozen[elim] - && !eliminateVar(elim)) - { - ok = false; - goto cleanup; - } - - checkGarbage(simp_garbage_frac); - } - - Assert(subsumption_queue.size() == 0); - } - cleanup: - - // If no more simplification is needed, free all simplification-related data structures: - if (turn_off_elim){ - touched .clear(true); - occurs .clear(true); - n_occ .clear(true); - elim_heap.clear(true); - subsumption_queue.clear(true); - - use_simplification = false; - remove_satisfied = true; - ca.extra_clause_field = false; - - // Force full cleanup (this is safe and desirable since it only happens once): - rebuildOrderHeap(); - garbageCollect(); - }else{ - // Cheaper cleanup: - cleanUpClauses(); // TODO: can we make 'cleanUpClauses()' not be linear in the problem size somehow? - checkGarbage(); - } - - if (verbosity >= 1 && elimclauses.size() > 0) - printf( - "| Eliminated clauses: %10.2f Mb " - " |\n", - double(elimclauses.size() * sizeof(uint32_t)) / (1024 * 1024)); - - return ok; - - - -} - - -void SimpSolver::cleanUpClauses() -{ - occurs.cleanAll(); - int i,j; - for (i = j = 0; i < clauses.size(); i++) - if (ca[clauses[i]].mark() == 0) - clauses[j++] = clauses[i]; - clauses.shrink(i - j); -} - - -//================================================================================================= -// Garbage Collection methods: - - -void SimpSolver::relocAll(ClauseAllocator& to) -{ - if (!use_simplification) return; - - // All occurs lists: - // - for (int i = 0; i < nVars(); i++){ - vec<CRef>& cs = occurs[i]; - for (int j = 0; j < cs.size(); j++) - ca.reloc(cs[j], to); - } - - // Subsumption queue: - // - for (int i = 0; i < subsumption_queue.size(); i++) - ca.reloc(subsumption_queue[i], to); - - // Temporary clause: - // - ca.reloc(bwdsub_tmpunit, to); -} - - -void SimpSolver::garbageCollect() -{ - // Initialize the next region to a size corresponding to the estimated utilization degree. This - // is not precise but should avoid some unnecessary reallocations for the new region: - ClauseAllocator to(ca.size() - ca.wasted()); - - cleanUpClauses(); - to.extra_clause_field = ca.extra_clause_field; // NOTE: this is important to keep (or lose) the extra fields. - relocAll(to); - Solver::relocAll(to); - if (verbosity >= 2) - printf( - "| Garbage collection: %12d bytes => %12d bytes |\n", - ca.size() * ClauseAllocator::Unit_Size, - to.size() * ClauseAllocator::Unit_Size); - to.moveTo(ca); -} - -} // namespace BVMinisat -} // namespace cvc5 diff --git a/src/prop/bvminisat/simp/SimpSolver.h b/src/prop/bvminisat/simp/SimpSolver.h deleted file mode 100644 index ec6ed375a..000000000 --- a/src/prop/bvminisat/simp/SimpSolver.h +++ /dev/null @@ -1,243 +0,0 @@ -/************************************************************************************[SimpSolver.h] -Copyright (c) 2006, Niklas Een, Niklas Sorensson -Copyright (c) 2007-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#ifndef BVMinisat_SimpSolver_h -#define BVMinisat_SimpSolver_h - -#include "base/check.h" -#include "proof/clause_id.h" -#include "prop/bvminisat/core/Solver.h" -#include "prop/bvminisat/mtl/Queue.h" - -namespace cvc5 { - -namespace context { -class Context; -} - -namespace BVMinisat { - -//================================================================================================= - - -class SimpSolver : public Solver { - public: - // Constructor/Destructor: - // - SimpSolver(cvc5::context::Context* context); - ~SimpSolver(); - - // Problem specification: - // - Var newVar(bool polarity = true, bool dvar = true, bool freeze = false); - bool addClause(const vec<Lit>& ps, ClauseId& id); - bool addEmptyClause(); // Add the empty clause to the solver. - bool addClause(Lit p, ClauseId& id); // Add a unit clause to the solver. - bool addClause(Lit p, - Lit q, - ClauseId& id); // Add a binary clause to the solver. - bool addClause(Lit p, - Lit q, - Lit r, - ClauseId& id); // Add a ternary clause to the solver. - bool addClause_(vec<Lit>& ps, ClauseId& id); - bool substitute(Var v, Lit x); // Replace all occurrences of v with x (may - // cause a contradiction). - - // Variable mode: - // - void setFrozen(Var v, - bool b); // If a variable is frozen it will not be eliminated. - bool isEliminated(Var v) const; - - // Solving: - // - lbool solve(const vec<Lit>& assumps, - bool do_simp = true, - bool turn_off_simp = false); - lbool solveLimited(const vec<Lit>& assumps, - bool do_simp = true, - bool turn_off_simp = false); - lbool solveLimited(bool do_simp = true, bool turn_off_simp = false); - lbool solve(bool do_simp = true, bool turn_off_simp = false); - lbool solve(Lit p, bool do_simp = true, bool turn_off_simp = false); - lbool solve(Lit p, Lit q, bool do_simp = true, bool turn_off_simp = false); - lbool solve( - Lit p, Lit q, Lit r, bool do_simp = true, bool turn_off_simp = false); - bool eliminate(bool turn_off_elim = false); // Perform variable elimination - // based simplification. - - // Memory managment: - // - void garbageCollect() override; - - // Generate a (possibly simplified) DIMACS file: - // -#if 0 - void toDimacs (const char* file, const vec<Lit>& assumps); - void toDimacs (const char* file); - void toDimacs (const char* file, Lit p); - void toDimacs (const char* file, Lit p, Lit q); - void toDimacs (const char* file, Lit p, Lit q, Lit r); -#endif - - // Mode of operation: - // - int grow; // Allow a variable elimination step to grow by a number of clauses (default to zero). - int clause_lim; // Variables are not eliminated if it produces a resolvent with a length above this limit. - // -1 means no limit. - int subsumption_lim; // Do not check if subsumption against a clause larger than this. -1 means no limit. - double simp_garbage_frac; // A different limit for when to issue a GC during simplification (Also see 'garbage_frac'). - - bool use_asymm; // Shrink clauses by asymmetric branching. - bool use_rcheck; // Check if a clause is already implied. Prett costly, and subsumes subsumptions :) - bool use_elim; // Perform variable elimination. - - // Statistics: - // - int merges; - int asymm_lits; - int64_t eliminated_vars; - // cvc5::TimerStat total_eliminate_time; - - protected: - - // Helper structures: - // - struct ElimLt { - const vec<int>& n_occ; - explicit ElimLt(const vec<int>& no) : n_occ(no) {} - - // TODO: are 64-bit operations here noticably bad on 32-bit platforms? Could use a saturating - // 32-bit implementation instead then, but this will have to do for now. - uint64_t cost (Var x) const { return (uint64_t)n_occ[toInt(mkLit(x))] * (uint64_t)n_occ[toInt(~mkLit(x))]; } - bool operator()(Var x, Var y) const { return cost(x) < cost(y); } - - // TODO: investigate this order alternative more. - // bool operator()(Var x, Var y) const { - // int c_x = cost(x); - // int c_y = cost(y); - // return c_x < c_y || c_x == c_y && x < y; } - }; - - struct ClauseDeleted { - const ClauseAllocator& ca; - explicit ClauseDeleted(const ClauseAllocator& _ca) : ca(_ca) {} - bool operator()(const CRef& cr) const { return ca[cr].mark() == 1; } }; - - // Solver state: - // - int elimorder; - bool use_simplification; - vec<uint32_t> elimclauses; - vec<char> touched; - OccLists<Var, vec<CRef>, ClauseDeleted> - occurs; - vec<int> n_occ; - Heap<ElimLt> elim_heap; - Queue<CRef> subsumption_queue; - vec<char> frozen; - vec<char> eliminated; - int bwdsub_assigns; - int n_touched; - - // Temporaries: - // - CRef bwdsub_tmpunit; - - // Main internal methods: - // - lbool solve_ (bool do_simp = true, bool turn_off_simp = false); - bool asymm (Var v, CRef cr); - bool asymmVar (Var v); - void updateElimHeap (Var v); - void gatherTouchedClauses (); - bool merge (const Clause& _ps, const Clause& _qs, Var v, vec<Lit>& out_clause); - bool merge (const Clause& _ps, const Clause& _qs, Var v, int& size); - bool backwardSubsumptionCheck (bool verbose = false); - bool eliminateVar (Var v); - void extendModel (); - - void removeClause (CRef cr); - bool strengthenClause (CRef cr, Lit l); - void cleanUpClauses (); - bool implied (const vec<Lit>& c); - void relocAll (ClauseAllocator& to); -}; - - -//================================================================================================= -// Implementation of inline methods: - - -inline bool SimpSolver::isEliminated (Var v) const { return eliminated[v]; } -inline void SimpSolver::updateElimHeap(Var v) { - Assert(use_simplification); - // if (!frozen[v] && !isEliminated(v) && value(v) == l_Undef) - if (elim_heap.inHeap(v) - || (!frozen[v] && !isEliminated(v) && value(v) == l_Undef)) - elim_heap.update(v); -} - -inline bool SimpSolver::addClause (const vec<Lit>& ps, ClauseId& id) { ps.copyTo(add_tmp); return addClause_(add_tmp, id); } -inline bool SimpSolver::addEmptyClause() { add_tmp.clear(); ClauseId id; return addClause_(add_tmp, id); } -inline bool SimpSolver::addClause (Lit p, ClauseId& id) { add_tmp.clear(); add_tmp.push(p); return addClause_(add_tmp, id); } -inline bool SimpSolver::addClause (Lit p, Lit q, ClauseId& id) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); return addClause_(add_tmp, id); } -inline bool SimpSolver::addClause (Lit p, Lit q, Lit r, ClauseId& id) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); return addClause_(add_tmp, id); } -inline void SimpSolver::setFrozen (Var v, bool b) { frozen[v] = (char)b; if (use_simplification && !b) { updateElimHeap(v); } } - -inline lbool SimpSolver::solve ( bool do_simp, bool turn_off_simp) { - budgetOff(); - return solve_(do_simp, turn_off_simp); - } -inline lbool SimpSolver::solve (Lit p , bool do_simp, bool turn_off_simp) { - budgetOff(); - assumptions.push(p); - return solve_(do_simp, turn_off_simp); - } -inline lbool SimpSolver::solve (Lit p, Lit q, bool do_simp, bool turn_off_simp) { - budgetOff(); - assumptions.push(p); - assumptions.push(q); - return solve_(do_simp, turn_off_simp); - } -inline lbool SimpSolver::solve (Lit p, Lit q, Lit r, bool do_simp, bool turn_off_simp) { - budgetOff(); - assumptions.push(p); - assumptions.push(q); - assumptions.push(r); - return solve_(do_simp, turn_off_simp); - } -inline lbool SimpSolver::solve (const vec<Lit>& assumps, bool do_simp, bool turn_off_simp){ - budgetOff(); assumps.copyTo(assumptions); - return solve_(do_simp, turn_off_simp); -} - -inline lbool SimpSolver::solveLimited (const vec<Lit>& assumps, bool do_simp, bool turn_off_simp){ - assumps.copyTo(assumptions); return solve_(do_simp, turn_off_simp); } - -inline lbool SimpSolver::solveLimited (bool do_simp, bool turn_off_simp){ - return solve_(do_simp, turn_off_simp); } - -//================================================================================================= -} // namespace BVMinisat -} // namespace cvc5 - -#endif diff --git a/src/prop/bvminisat/utils/Options.cc b/src/prop/bvminisat/utils/Options.cc deleted file mode 100644 index 0b05d5cf6..000000000 --- a/src/prop/bvminisat/utils/Options.cc +++ /dev/null @@ -1,94 +0,0 @@ -/**************************************************************************************[Options.cc] -Copyright (c) 2008-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#include "prop/bvminisat/utils/Options.h" -#include "prop/bvminisat/mtl/Sort.h" -#include "prop/bvminisat/utils/ParseUtils.h" - -namespace cvc5 { -namespace BVMinisat { - -void BVMinisat::parseOptions(int& argc, char** argv, bool strict) -{ - int i, j; - for (i = j = 1; i < argc; i++){ - const char* str = argv[i]; - if (match(str, "--") && match(str, Option::getHelpPrefixString()) && match(str, "help")){ - if (*str == '\0') - printUsageAndExit(argc, argv); - else if (match(str, "-verb")) - printUsageAndExit(argc, argv, true); - } else { - bool parsed_ok = false; - - for (int k = 0; !parsed_ok && k < Option::getOptionList().size(); k++){ - parsed_ok = Option::getOptionList()[k]->parse(argv[i]); - - // fprintf(stderr, "checking %d: %s against flag <%s> (%s)\n", i, argv[i], Option::getOptionList()[k]->name, parsed_ok ? "ok" : "skip"); - } - - if (!parsed_ok) - if (strict && match(argv[i], "-")) - fprintf(stderr, "ERROR! Unknown flag \"%s\". Use '--%shelp' for help.\n", argv[i], Option::getHelpPrefixString()), exit(1); - else - argv[j++] = argv[i]; - } - } - - argc -= (i - j); -} - - -void BVMinisat::setUsageHelp (const char* str){ Option::getUsageString() = str; } -void BVMinisat::setHelpPrefixStr (const char* str){ Option::getHelpPrefixString() = str; } -void BVMinisat::printUsageAndExit (int argc, char** argv, bool verbose) -{ - const char* usage = Option::getUsageString(); - if (usage != NULL) - fprintf(stderr, usage, argv[0]); - - sort(Option::getOptionList(), Option::OptionLt()); - - const char* prev_cat = NULL; - const char* prev_type = NULL; - - for (int i = 0; i < Option::getOptionList().size(); i++){ - const char* cat = Option::getOptionList()[i]->category; - const char* type = Option::getOptionList()[i]->type_name; - - if (cat != prev_cat) - fprintf(stderr, "\n%s OPTIONS:\n\n", cat); - else if (type != prev_type) - fprintf(stderr, "\n"); - - Option::getOptionList()[i]->help(verbose); - - prev_cat = Option::getOptionList()[i]->category; - prev_type = Option::getOptionList()[i]->type_name; - } - - fprintf(stderr, "\nHELP OPTIONS:\n\n"); - fprintf(stderr, " --%shelp Print help message.\n", Option::getHelpPrefixString()); - fprintf(stderr, " --%shelp-verb Print verbose help message.\n", Option::getHelpPrefixString()); - fprintf(stderr, "\n"); - exit(0); -} - -} // namespace BVMinisat -} // namespace cvc5 diff --git a/src/prop/bvminisat/utils/Options.h b/src/prop/bvminisat/utils/Options.h deleted file mode 100644 index 033ffb64f..000000000 --- a/src/prop/bvminisat/utils/Options.h +++ /dev/null @@ -1,437 +0,0 @@ -/***************************************************************************************[Options.h] -Copyright (c) 2008-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#ifndef BVMinisat_Options_h -#define BVMinisat_Options_h - -#include <stdlib.h> -#include <stdio.h> -#include <math.h> -#include <string.h> - -#include "prop/bvminisat/mtl/IntTypes.h" -#include "prop/bvminisat/mtl/Vec.h" -#include "prop/bvminisat/utils/ParseUtils.h" - -namespace cvc5 { -namespace BVMinisat { - -//================================================================================================== -// Top-level option parse/help functions: - - -extern void parseOptions (int& argc, char** argv, bool strict = false); -extern void printUsageAndExit(int argc, char** argv, bool verbose = false); -extern void setUsageHelp (const char* str); -extern void setHelpPrefixStr (const char* str); - - -//================================================================================================== -// Options is an abstract class that gives the interface for all types options: - - -class Option -{ - protected: - const char* name; - const char* description; - const char* category; - const char* type_name; - - static vec<Option*>& getOptionList () { static vec<Option*> options; return options; } - static const char*& getUsageString() { static const char* usage_str; return usage_str; } - static const char*& getHelpPrefixString() { static const char* help_prefix_str = ""; return help_prefix_str; } - - struct OptionLt { - bool operator()(const Option* x, const Option* y) { - int test1 = strcmp(x->category, y->category); - return test1 < 0 || (test1 == 0 && strcmp(x->type_name, y->type_name) < 0); - } - }; - - Option(const char* name_, - const char* desc_, - const char* cate_, - const char* type_) : - name (name_) - , description(desc_) - , category (cate_) - , type_name (type_) - { - getOptionList().push(this); - } - - public: - virtual ~Option() {} - - virtual bool parse (const char* str) = 0; - virtual void help (bool verbose = false) = 0; - - friend void parseOptions (int& argc, char** argv, bool strict); - friend void printUsageAndExit (int argc, char** argv, bool verbose); - friend void setUsageHelp (const char* str); - friend void setHelpPrefixStr (const char* str); -}; - - -//================================================================================================== -// Range classes with specialization for floating types: - - -struct IntRange { - int begin; - int end; - IntRange(int b, int e) : begin(b), end(e) {} -}; - -struct Int64Range { - int64_t begin; - int64_t end; - Int64Range(int64_t b, int64_t e) : begin(b), end(e) {} -}; - -struct DoubleRange { - double begin; - double end; - bool begin_inclusive; - bool end_inclusive; - DoubleRange(double b, bool binc, double e, bool einc) : begin(b), end(e), begin_inclusive(binc), end_inclusive(einc) {} -}; - - -//================================================================================================== -// Double options: - - -class DoubleOption : public Option -{ - protected: - DoubleRange range; - double value; - - public: - DoubleOption(const char* c, const char* n, const char* d, double def = double(), DoubleRange r = DoubleRange(-HUGE_VAL, false, HUGE_VAL, false)) - : Option(n, d, c, "<double>"), range(r), value(def) { - // FIXME: set LC_NUMERIC to "C" to make sure that strtof/strtod parses decimal point correctly. - } - - operator double (void) const { return value; } - operator double& (void) { return value; } - DoubleOption& operator=(double x) { value = x; return *this; } - - bool parse(const char* str) override - { - const char* span = str; - - if (!match(span, "-") || !match(span, name) || !match(span, "=")) - return false; - - char* end; - double tmp = strtod(span, &end); - - if (end == NULL) - return false; - else if (tmp >= range.end && (!range.end_inclusive || tmp != range.end)) - { - fprintf(stderr, - "ERROR! value <%s> is too large for option \"%s\".\n", - span, - name); - exit(1); - } - else if (tmp <= range.begin - && (!range.begin_inclusive || tmp != range.begin)) - { - fprintf(stderr, - "ERROR! value <%s> is too small for option \"%s\".\n", - span, - name); - exit(1); - } - - value = tmp; - // fprintf(stderr, "READ VALUE: %g\n", value); - - return true; - } - - void help(bool verbose = false) override - { - fprintf(stderr, - " -%-12s = %-8s %c%4.2g .. %4.2g%c (default: %g)\n", - name, - type_name, - range.begin_inclusive ? '[' : '(', - range.begin, - range.end, - range.end_inclusive ? ']' : ')', - value); - if (verbose) - { - fprintf(stderr, "\n %s\n", description); - fprintf(stderr, "\n"); - } - } -}; - - -//================================================================================================== -// Int options: - - -class IntOption : public Option -{ - protected: - IntRange range; - int32_t value; - - public: - IntOption(const char* c, const char* n, const char* d, int32_t def = int32_t(), IntRange r = IntRange(INT32_MIN, INT32_MAX)) - : Option(n, d, c, "<int32>"), range(r), value(def) {} - - operator int32_t (void) const { return value; } - operator int32_t& (void) { return value; } - IntOption& operator= (int32_t x) { value = x; return *this; } - - bool parse(const char* str) override - { - const char* span = str; - - if (!match(span, "-") || !match(span, name) || !match(span, "=")) - return false; - - char* end; - int32_t tmp = strtol(span, &end, 10); - - if (end == NULL) - return false; - else if (tmp > range.end) - { - fprintf(stderr, - "ERROR! value <%s> is too large for option \"%s\".\n", - span, - name); - exit(1); - } - else if (tmp < range.begin) - { - fprintf(stderr, - "ERROR! value <%s> is too small for option \"%s\".\n", - span, - name); - exit(1); - } - - value = tmp; - - return true; - } - - void help(bool verbose = false) override - { - fprintf(stderr, " -%-12s = %-8s [", name, type_name); - if (range.begin == INT32_MIN) - fprintf(stderr, "imin"); - else - fprintf(stderr, "%4d", range.begin); - - fprintf(stderr, " .. "); - if (range.end == INT32_MAX) - fprintf(stderr, "imax"); - else - fprintf(stderr, "%4d", range.end); - - fprintf(stderr, "] (default: %d)\n", value); - if (verbose) - { - fprintf(stderr, "\n %s\n", description); - fprintf(stderr, "\n"); - } - } -}; - - -// Leave this out for visual C++ until Microsoft implements C99 and gets support for strtoll. -#ifndef _MSC_VER - -class Int64Option : public Option -{ - protected: - Int64Range range; - int64_t value; - - public: - Int64Option(const char* c, const char* n, const char* d, int64_t def = int64_t(), Int64Range r = Int64Range(INT64_MIN, INT64_MAX)) - : Option(n, d, c, "<int64>"), range(r), value(def) {} - - operator int64_t (void) const { return value; } - operator int64_t& (void) { return value; } - Int64Option& operator= (int64_t x) { value = x; return *this; } - - bool parse(const char* str) override - { - const char* span = str; - - if (!match(span, "-") || !match(span, name) || !match(span, "=")) - return false; - - char* end; - int64_t tmp = strtoll(span, &end, 10); - - if (end == NULL) - return false; - else if (tmp > range.end) - { - fprintf(stderr, - "ERROR! value <%s> is too large for option \"%s\".\n", - span, - name); - exit(1); - } - else if (tmp < range.begin) - { - fprintf(stderr, - "ERROR! value <%s> is too small for option \"%s\".\n", - span, - name); - exit(1); - } - - value = tmp; - - return true; - } - - void help(bool verbose = false) override - { - fprintf(stderr, " -%-12s = %-8s [", name, type_name); - if (range.begin == INT64_MIN) - fprintf(stderr, "imin"); - else - fprintf(stderr, "%4" PRIi64, range.begin); - - fprintf(stderr, " .. "); - if (range.end == INT64_MAX) - fprintf(stderr, "imax"); - else - fprintf(stderr, "%4" PRIi64, range.end); - - fprintf(stderr, "] (default: %" PRIi64 ")\n", value); - if (verbose) - { - fprintf(stderr, "\n %s\n", description); - fprintf(stderr, "\n"); - } - } -}; -#endif - -//================================================================================================== -// String option: - - -class StringOption : public Option -{ - const char* value; - public: - StringOption(const char* c, const char* n, const char* d, const char* def = NULL) - : Option(n, d, c, "<string>"), value(def) {} - - operator const char* (void) const { return value; } - operator const char*& (void) { return value; } - StringOption& operator= (const char* x) { value = x; return *this; } - - bool parse(const char* str) override - { - const char* span = str; - - if (!match(span, "-") || !match(span, name) || !match(span, "=")) - return false; - - value = span; - return true; - } - - void help(bool verbose = false) override - { - fprintf(stderr, " -%-10s = %8s\n", name, type_name); - if (verbose) - { - fprintf(stderr, "\n %s\n", description); - fprintf(stderr, "\n"); - } - } -}; - - -//================================================================================================== -// Bool option: - - -class BoolOption : public Option -{ - bool value; - - public: - BoolOption(const char* c, const char* n, const char* d, bool v) - : Option(n, d, c, "<bool>"), value(v) {} - - operator bool (void) const { return value; } - operator bool& (void) { return value; } - BoolOption& operator=(bool b) { value = b; return *this; } - - bool parse(const char* str) override - { - const char* span = str; - - if (match(span, "-")) - { - bool b = !match(span, "no-"); - - if (strcmp(span, name) == 0) - { - value = b; - return true; - } - } - - return false; - } - - void help(bool verbose = false) override - { - fprintf(stderr, " -%s, -no-%s", name, name); - - for (uint32_t i = 0; i < 32 - strlen(name) * 2; i++) fprintf(stderr, " "); - - fprintf(stderr, " "); - fprintf(stderr, "(default: %s)\n", value ? "on" : "off"); - if (verbose) - { - fprintf(stderr, "\n %s\n", description); - fprintf(stderr, "\n"); - } - } -}; - -//================================================================================================= -} // namespace BVMinisat -} // namespace cvc5 - -#endif diff --git a/src/prop/bvminisat/utils/ParseUtils.h b/src/prop/bvminisat/utils/ParseUtils.h deleted file mode 100644 index d69856ebb..000000000 --- a/src/prop/bvminisat/utils/ParseUtils.h +++ /dev/null @@ -1,125 +0,0 @@ -/************************************************************************************[ParseUtils.h] -Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson -Copyright (c) 2007-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#ifndef BVMinisat_ParseUtils_h -#define BVMinisat_ParseUtils_h - -#include <stdlib.h> -#include <stdio.h> - -//#include <zlib.h> -#include <unistd.h> - -namespace cvc5 { -namespace BVMinisat { - -//------------------------------------------------------------------------------------------------- -// A simple buffered character stream class: - -static const int buffer_size = 1048576; - - -class StreamBuffer { - int in; - unsigned char buf[buffer_size]; - int pos; - int size; - - void assureLookahead() { - if (pos >= size) { - pos = 0; - size = read(in, buf, sizeof(buf)); } } - -public: - explicit StreamBuffer(int i) : in(i), pos(0), size(0) { assureLookahead(); } - - int operator * () const { return (pos >= size) ? EOF : buf[pos]; } - void operator ++ () { pos++; assureLookahead(); } - int position () const { return pos; } -}; - - -//------------------------------------------------------------------------------------------------- -// End-of-file detection functions for StreamBuffer and char*: - - -static inline bool isEof(StreamBuffer& in) { return *in == EOF; } -static inline bool isEof(const char* in) { return *in == '\0'; } - -//------------------------------------------------------------------------------------------------- -// Generic parse functions parametrized over the input-stream type. - - -template<class B> -static void skipWhitespace(B& in) { - while ((*in >= 9 && *in <= 13) || *in == 32) - ++in; } - - -template<class B> -static void skipLine(B& in) { - for (;;){ - if (isEof(in)) return; - if (*in == '\n') { ++in; return; } - ++in; } } - - -template<class B> -static int parseInt(B& in) { - int val = 0; - bool neg = false; - skipWhitespace(in); - if (*in == '-') neg = true, ++in; - else if (*in == '+') ++in; - if (*in < '0' || *in > '9') fprintf(stderr, "PARSE ERROR! Unexpected char: %c\n", *in), exit(3); - while (*in >= '0' && *in <= '9') - val = val*10 + (*in - '0'), - ++in; - return neg ? -val : val; } - - -// String matching: in case of a match the input iterator will be advanced the corresponding -// number of characters. -template<class B> -static bool match(B& in, const char* str) { - int i; - for (i = 0; str[i] != '\0'; i++) - if (in[i] != str[i]) - return false; - - in += i; - - return true; -} - -// String matching: consumes characters eagerly, but does not require random access iterator. -template<class B> -static bool eagerMatch(B& in, const char* str) { - for (; *str != '\0'; ++str, ++in) - if (*str != *in) - return false; - return true; } - - -//================================================================================================= -} // namespace BVMinisat -} // namespace cvc5 - -#endif diff --git a/src/prop/bvminisat/utils/System.cc b/src/prop/bvminisat/utils/System.cc deleted file mode 100644 index d86678097..000000000 --- a/src/prop/bvminisat/utils/System.cc +++ /dev/null @@ -1,99 +0,0 @@ -/***************************************************************************************[System.cc] -Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson -Copyright (c) 2007-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#include "prop/bvminisat/utils/System.h" - -#if defined(__linux__) - -#include <stdio.h> -#include <stdlib.h> - -namespace cvc5 { -namespace BVMinisat { - -// TODO: split the memory reading functions into two: one for reading high-watermark of RSS, and -// one for reading the current virtual memory size. - -static inline int memReadStat(int field) -{ - char name[256]; - pid_t pid = getpid(); - int value; - - sprintf(name, "/proc/%d/statm", pid); - FILE* in = fopen(name, "rb"); - if (in == NULL) return 0; - - for (; field >= 0; field--) - if (fscanf(in, "%d", &value) != 1) - printf("ERROR! Failed to parse memory statistics from \"/proc\".\n"), exit(1); - fclose(in); - return value; -} - - -static inline int memReadPeak(void) -{ - char name[256]; - pid_t pid = getpid(); - - sprintf(name, "/proc/%d/status", pid); - FILE* in = fopen(name, "rb"); - if (in == NULL) return 0; - - // Find the correct line, beginning with "VmPeak:": - int peak_kb = 0; - while (!feof(in) && fscanf(in, "VmPeak: %d kB", &peak_kb) != 1) - while (!feof(in) && fgetc(in) != '\n') - ; - fclose(in); - - return peak_kb; -} - -double BVMinisat::memUsed() { return (double)memReadStat(0) * (double)getpagesize() / (1024*1024); } -double BVMinisat::memUsedPeak() { - double peak = memReadPeak() / 1024; - return peak == 0 ? memUsed() : peak; } - -#elif defined(__FreeBSD__) - -double BVMinisat::memUsed(void) { - struct rusage ru; - getrusage(RUSAGE_SELF, &ru); - return (double)ru.ru_maxrss / 1024; } -double MiniSat::memUsedPeak(void) { return memUsed(); } - - -#elif defined(__APPLE__) -#include <malloc/malloc.h> - -double BVMinisat::memUsed(void) { - malloc_statistics_t t; - malloc_zone_statistics(NULL, &t); - return (double)t.max_size_in_use / (1024*1024); } - -#else -double BVMinisat::memUsed() { - return 0; } -#endif - -} /* cvc5::BVMinisat namespace */ -} /* cvc5 namespace */ diff --git a/src/prop/bvminisat/utils/System.h b/src/prop/bvminisat/utils/System.h deleted file mode 100644 index c805c232a..000000000 --- a/src/prop/bvminisat/utils/System.h +++ /dev/null @@ -1,67 +0,0 @@ -/****************************************************************************************[System.h] -Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson -Copyright (c) 2007-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#ifndef BVMinisat_System_h -#define BVMinisat_System_h - -#if defined(__linux__) -#include <fpu_control.h> -#endif - -#include "prop/bvminisat/mtl/IntTypes.h" - -//------------------------------------------------------------------------------------------------- - -namespace cvc5 { -namespace BVMinisat { - -static inline double cpuTime(void); // CPU-time in seconds. -extern double memUsed(); // Memory in mega bytes (returns 0 for unsupported architectures). -extern double memUsedPeak(); // Peak-memory in mega bytes (returns 0 for unsupported architectures). - -} // namespace BVMinisat -} // namespace cvc5 - -//------------------------------------------------------------------------------------------------- -// Implementation of inline functions: - -#if defined(_MSC_VER) || defined(__MINGW32__) -#include <time.h> - -static inline double cvc5::BVMinisat::cpuTime(void) -{ - return (double)clock() / CLOCKS_PER_SEC; -} - -#else -#include <sys/time.h> -#include <sys/resource.h> -#include <unistd.h> - -static inline double cvc5::BVMinisat::cpuTime(void) -{ - struct rusage ru; - getrusage(RUSAGE_SELF, &ru); - return (double)ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec / 1000000; -} - -#endif - -#endif diff --git a/src/prop/sat_solver.h b/src/prop/sat_solver.h index 9ad54e292..4236f0914 100644 --- a/src/prop/sat_solver.h +++ b/src/prop/sat_solver.h @@ -25,7 +25,6 @@ #include "expr/node.h" #include "proof/clause_id.h" #include "proof/proof_node_manager.h" -#include "prop/bv_sat_solver_notify.h" #include "prop/sat_solver_types.h" #include "util/statistics_stats.h" @@ -118,30 +117,6 @@ public: };/* class SatSolver */ -class BVSatSolverInterface: public SatSolver { -public: - - virtual ~BVSatSolverInterface() {} - /** Interface for notifications */ - - virtual void setNotify(BVSatSolverNotify* notify) = 0; - - virtual void markUnremovable(SatLiteral lit) = 0; - - virtual void getUnsatCore(SatClause& unsatCore) = 0; - - virtual void addMarkerLiteral(SatLiteral lit) = 0; - - virtual SatValue propagate() = 0; - - virtual void explain(SatLiteral lit, std::vector<SatLiteral>& explanation) = 0; - - virtual SatValue assertAssumption(SatLiteral lit, bool propagate = false) = 0; - - virtual void popAssumption() = 0; - -};/* class BVSatSolverInterface */ - class CDCLTSatSolverInterface : public SatSolver { public: diff --git a/src/prop/sat_solver_factory.cpp b/src/prop/sat_solver_factory.cpp index 0855cbda5..7852fc4e7 100644 --- a/src/prop/sat_solver_factory.cpp +++ b/src/prop/sat_solver_factory.cpp @@ -15,7 +15,6 @@ #include "prop/sat_solver_factory.h" -#include "prop/bvminisat/bvminisat.h" #include "prop/cadical.h" #include "prop/cryptominisat.h" #include "prop/kissat.h" @@ -24,14 +23,6 @@ namespace cvc5 { namespace prop { -BVSatSolverInterface* SatSolverFactory::createMinisat( - context::Context* mainSatContext, - StatisticsRegistry& registry, - const std::string& name) -{ - return new BVMinisatSatSolver(registry, mainSatContext, name); -} - MinisatSatSolver* SatSolverFactory::createCDCLTMinisat( StatisticsRegistry& registry) { diff --git a/src/prop/sat_solver_factory.h b/src/prop/sat_solver_factory.h index f3376df59..c997a1ab8 100644 --- a/src/prop/sat_solver_factory.h +++ b/src/prop/sat_solver_factory.h @@ -32,10 +32,6 @@ namespace prop { class SatSolverFactory { public: - static BVSatSolverInterface* createMinisat(context::Context* mainSatContext, - StatisticsRegistry& registry, - const std::string& name = ""); - static MinisatSatSolver* createCDCLTMinisat(StatisticsRegistry& registry); static SatSolver* createCryptoMinisat(StatisticsRegistry& registry, diff --git a/src/smt/command.cpp b/src/smt/command.cpp index e8ee6d59c..1794765b4 100644 --- a/src/smt/command.cpp +++ b/src/smt/command.cpp @@ -1168,8 +1168,8 @@ void DeclareFunctionCommand::toStream(std::ostream& out, size_t dag, Language language) const { - Printer::getPrinter(language)->toStreamCmdDeclareFunction(out, - termToNode(d_func)); + Printer::getPrinter(language)->toStreamCmdDeclareFunction( + out, d_symbol, sortToTypeNode(d_func.getSort())); } /* -------------------------------------------------------------------------- */ @@ -1313,46 +1313,44 @@ void DefineSortCommand::toStream(std::ostream& out, /* -------------------------------------------------------------------------- */ DefineFunctionCommand::DefineFunctionCommand(const std::string& id, - api::Term func, - api::Term formula, - bool global) + api::Sort sort, + api::Term formula) : DeclarationDefinitionCommand(id), - d_func(func), d_formals(), - d_formula(formula), - d_global(global) + d_sort(sort), + d_formula(formula) { } DefineFunctionCommand::DefineFunctionCommand( const std::string& id, - api::Term func, const std::vector<api::Term>& formals, - api::Term formula, - bool global) + api::Sort sort, + api::Term formula) : DeclarationDefinitionCommand(id), - d_func(func), d_formals(formals), - d_formula(formula), - d_global(global) + d_sort(sort), + d_formula(formula) { } -api::Term DefineFunctionCommand::getFunction() const { return d_func; } const std::vector<api::Term>& DefineFunctionCommand::getFormals() const { return d_formals; } +api::Sort DefineFunctionCommand::getSort() const { return d_sort; } + api::Term DefineFunctionCommand::getFormula() const { return d_formula; } + void DefineFunctionCommand::invoke(api::Solver* solver, SymbolManager* sm) { try { - if (!d_func.isNull()) - { - solver->defineFun(d_func, d_formals, d_formula, d_global); - } + bool global = sm->getGlobalDeclarations(); + api::Term fun = + solver->defineFun(d_symbol, d_formals, d_sort, d_formula, global); + sm->getSymbolTable()->bind(fun.toString(), fun, global); d_commandStatus = CommandSuccess::instance(); } catch (exception& e) @@ -1363,8 +1361,7 @@ void DefineFunctionCommand::invoke(api::Solver* solver, SymbolManager* sm) Command* DefineFunctionCommand::clone() const { - return new DefineFunctionCommand( - d_symbol, d_func, d_formals, d_formula, d_global); + return new DefineFunctionCommand(d_symbol, d_formals, d_sort, d_formula); } std::string DefineFunctionCommand::getCommandName() const @@ -1377,16 +1374,11 @@ void DefineFunctionCommand::toStream(std::ostream& out, size_t dag, Language language) const { - TypeNode rangeType = termToNode(d_func).getType(); - if (rangeType.isFunction()) - { - rangeType = rangeType.getRangeType(); - } Printer::getPrinter(language)->toStreamCmdDefineFunction( out, - d_func.toString(), + d_symbol, termVectorToNodes(d_formals), - rangeType, + sortToTypeNode(d_sort), termToNode(d_formula)); } @@ -1395,12 +1387,7 @@ void DefineFunctionCommand::toStream(std::ostream& out, /* -------------------------------------------------------------------------- */ DefineFunctionRecCommand::DefineFunctionRecCommand( - - api::Term func, - const std::vector<api::Term>& formals, - api::Term formula, - bool global) - : d_global(global) + api::Term func, const std::vector<api::Term>& formals, api::Term formula) { d_funcs.push_back(func); d_formals.push_back(formals); @@ -1408,12 +1395,10 @@ DefineFunctionRecCommand::DefineFunctionRecCommand( } DefineFunctionRecCommand::DefineFunctionRecCommand( - const std::vector<api::Term>& funcs, const std::vector<std::vector<api::Term>>& formals, - const std::vector<api::Term>& formulas, - bool global) - : d_funcs(funcs), d_formals(formals), d_formulas(formulas), d_global(global) + const std::vector<api::Term>& formulas) + : d_funcs(funcs), d_formals(formals), d_formulas(formulas) { } @@ -1437,7 +1422,8 @@ void DefineFunctionRecCommand::invoke(api::Solver* solver, SymbolManager* sm) { try { - solver->defineFunsRec(d_funcs, d_formals, d_formulas, d_global); + bool global = sm->getGlobalDeclarations(); + solver->defineFunsRec(d_funcs, d_formals, d_formulas, global); d_commandStatus = CommandSuccess::instance(); } catch (exception& e) @@ -1448,7 +1434,7 @@ void DefineFunctionRecCommand::invoke(api::Solver* solver, SymbolManager* sm) Command* DefineFunctionRecCommand::clone() const { - return new DefineFunctionRecCommand(d_funcs, d_formals, d_formulas, d_global); + return new DefineFunctionRecCommand(d_funcs, d_formals, d_formulas); } std::string DefineFunctionRecCommand::getCommandName() const @@ -1484,7 +1470,7 @@ api::Sort DeclareHeapCommand::getDataSort() const { return d_dataSort; } void DeclareHeapCommand::invoke(api::Solver* solver, SymbolManager* sm) { - solver->declareSeparationHeap(d_locSort, d_dataSort); + solver->declareSepHeap(d_locSort, d_dataSort); } Command* DeclareHeapCommand::clone() const @@ -2235,7 +2221,7 @@ void GetQuantifierEliminationCommand::toStream(std::ostream& out, Language language) const { Printer::getPrinter(language)->toStreamCmdGetQuantifierElimination( - out, termToNode(d_term)); + out, termToNode(d_term), d_doFull); } /* -------------------------------------------------------------------------- */ diff --git a/src/smt/command.h b/src/smt/command.h index 400f3492e..5733eb3e5 100644 --- a/src/smt/command.h +++ b/src/smt/command.h @@ -494,17 +494,15 @@ class CVC5_EXPORT DefineFunctionCommand : public DeclarationDefinitionCommand { public: DefineFunctionCommand(const std::string& id, - api::Term func, - api::Term formula, - bool global); + api::Sort sort, + api::Term formula); DefineFunctionCommand(const std::string& id, - api::Term func, const std::vector<api::Term>& formals, - api::Term formula, - bool global); + api::Sort sort, + api::Term formula); - api::Term getFunction() const; const std::vector<api::Term>& getFormals() const; + api::Sort getSort() const; api::Term getFormula() const; void invoke(api::Solver* solver, SymbolManager* sm) override; @@ -516,17 +514,12 @@ class CVC5_EXPORT DefineFunctionCommand : public DeclarationDefinitionCommand Language language = Language::LANG_AUTO) const override; protected: - /** The function we are defining */ - api::Term d_func; /** The formal arguments for the function we are defining */ std::vector<api::Term> d_formals; + /** The co-domain sort of the function we are defining */ + api::Sort d_sort; /** The formula corresponding to the body of the function we are defining */ api::Term d_formula; - /** - * Stores whether this definition is global (i.e. should persist when - * popping the user context. - */ - bool d_global; }; /* class DefineFunctionCommand */ /** @@ -539,12 +532,10 @@ class CVC5_EXPORT DefineFunctionRecCommand : public Command public: DefineFunctionRecCommand(api::Term func, const std::vector<api::Term>& formals, - api::Term formula, - bool global); + api::Term formula); DefineFunctionRecCommand(const std::vector<api::Term>& funcs, const std::vector<std::vector<api::Term> >& formals, - const std::vector<api::Term>& formula, - bool global); + const std::vector<api::Term>& formula); const std::vector<api::Term>& getFunctions() const; const std::vector<std::vector<api::Term> >& getFormals() const; @@ -565,11 +556,6 @@ class CVC5_EXPORT DefineFunctionRecCommand : public Command std::vector<std::vector<api::Term> > d_formals; /** formulas corresponding to the bodies of the functions we are defining */ std::vector<api::Term> d_formulas; - /** - * Stores whether this definition is global (i.e. should persist when - * popping the user context. - */ - bool d_global; }; /* class DefineFunctionRecCommand */ /** diff --git a/src/smt/interpolation_solver.cpp b/src/smt/interpolation_solver.cpp index 51be8db51..36f8e2a8d 100644 --- a/src/smt/interpolation_solver.cpp +++ b/src/smt/interpolation_solver.cpp @@ -41,7 +41,7 @@ bool InterpolationSolver::getInterpol(const std::vector<Node>& axioms, const TypeNode& grammarType, Node& interpol) { - if (options::produceInterpols() == options::ProduceInterpols::NONE) + if (options().smt.produceInterpols == options::ProduceInterpols::NONE) { const char* msg = "Cannot get interpolation when produce-interpol options is off."; @@ -57,7 +57,7 @@ bool InterpolationSolver::getInterpol(const std::vector<Node>& axioms, if (interpolSolver.solveInterpolation( name, axioms, conjn, grammarType, interpol)) { - if (options::checkInterpols()) + if (options().smt.checkInterpols) { checkInterpol(interpol, axioms, conj); } diff --git a/src/smt/listeners.cpp b/src/smt/listeners.cpp index de6368951..7a1951d95 100644 --- a/src/smt/listeners.cpp +++ b/src/smt/listeners.cpp @@ -89,19 +89,5 @@ void SmtNodeManagerListener::nmNotifyNewVar(TNode n) d_dm.addToDump(c); } -void SmtNodeManagerListener::nmNotifyNewSkolem(TNode n, - const std::string& comment, - uint32_t flags) -{ - std::string id = n.getAttribute(expr::VarNameAttr()); - DeclareFunctionNodeCommand c(id, n, n.getType()); - if (Dump.isOn("skolems") && comment != "") - { - d_outMgr.getPrinter().toStreamCmdSetInfo( - d_outMgr.getDumpOut(), "notes", id + " is " + comment); - } - d_dm.addToDump(c, "skolems"); -} - } // namespace smt } // namespace cvc5 diff --git a/src/smt/listeners.h b/src/smt/listeners.h index 60ec6b4ed..df99f8008 100644 --- a/src/smt/listeners.h +++ b/src/smt/listeners.h @@ -61,10 +61,6 @@ class SmtNodeManagerListener : public NodeManagerListener uint32_t flags) override; /** Notify when new variable is created */ void nmNotifyNewVar(TNode n) override; - /** Notify when new skolem is created */ - void nmNotifyNewSkolem(TNode n, - const std::string& comment, - uint32_t flags) override; /** Notify when a term is deleted */ void nmNotifyDeleteNode(TNode n) override {} diff --git a/src/smt/process_assertions.cpp b/src/smt/process_assertions.cpp index 473b53015..47deddac3 100644 --- a/src/smt/process_assertions.cpp +++ b/src/smt/process_assertions.cpp @@ -169,11 +169,6 @@ bool ProcessAssertions::apply(Assertions& as) d_passes["ackermann"]->apply(&assertions); } - if (options().bv.bvAbstraction) - { - d_passes["bv-abstraction"]->apply(&assertions); - } - Debug("smt") << " assertions : " << assertions.size() << endl; bool noConflict = true; diff --git a/src/smt/quant_elim_solver.cpp b/src/smt/quant_elim_solver.cpp index 8bd29b16f..2ffa0d7c1 100644 --- a/src/smt/quant_elim_solver.cpp +++ b/src/smt/quant_elim_solver.cpp @@ -92,11 +92,20 @@ Node QuantElimSolver::getQuantifierElimination(Assertions& as, // version of the input quantified formula q. std::vector<Node> inst_qs; qe->getInstantiatedQuantifiedFormulas(inst_qs); - Assert(inst_qs.size() <= 1); + Node topq; + // Find the quantified formula corresponding to the quantifier elimination + for (const Node& qinst : inst_qs) + { + // Should have the same attribute mark as above + if (qinst.getNumChildren() == 3 && qinst[2] == n_attr) + { + topq = qinst; + break; + } + } Node ret; - if (inst_qs.size() == 1) + if (!topq.isNull()) { - Node topq = inst_qs[0]; Assert(topq.getKind() == FORALL); Trace("smt-qe") << "Get qe based on preprocessed quantified formula " << topq << std::endl; diff --git a/src/smt/set_defaults.cpp b/src/smt/set_defaults.cpp index 19eab3617..b701df173 100644 --- a/src/smt/set_defaults.cpp +++ b/src/smt/set_defaults.cpp @@ -150,17 +150,6 @@ void SetDefaults::setDefaultsPre(Options& opts) } } - if (opts.bv.bitvectorAigSimplificationsWasSetByUser) - { - Notice() << "SolverEngine: setting bitvectorAig" << std::endl; - opts.bv.bitvectorAig = true; - } - if (opts.bv.bitvectorAlgebraicBudgetWasSetByUser) - { - Notice() << "SolverEngine: setting bitvectorAlgebraicSolver" << std::endl; - opts.bv.bitvectorAlgebraicSolver = true; - } - // if we requiring disabling proofs, disable them now if (opts.smt.produceProofs) { @@ -597,14 +586,6 @@ void SetDefaults::setDefaultsPost(const LogicInfo& logic, Options& opts) const opts.bv.boolToBitvector = options::BoolToBVMode::OFF; } - if (!opts.bv.bvEagerExplanationsWasSetByUser - && logic.isTheoryEnabled(THEORY_ARRAYS) - && logic.isTheoryEnabled(THEORY_BV)) - { - Trace("smt") << "enabling eager bit-vector explanations " << std::endl; - opts.bv.bvEagerExplanations = true; - } - // Turn on arith rewrite equalities only for pure arithmetic if (!opts.arith.arithRewriteEqWasSetByUser) { @@ -917,8 +898,7 @@ bool SetDefaults::incompatibleWithProofs(Options& opts, // If proofs are required and the user did not specify a specific BV solver, // we make sure to use the proof producing BITBLAST_INTERNAL solver. if (opts.bv.bvSolver != options::BVSolver::BITBLAST_INTERNAL - && !opts.bv.bvSolverWasSetByUser - && opts.bv.bvSatSolver == options::SatSolverMode::MINISAT) + && !opts.bv.bvSolverWasSetByUser) { Notice() << "Forcing internal bit-vector solver due to proof production." << std::endl; @@ -1017,7 +997,6 @@ bool SetDefaults::incompatibleWithIncremental(const LogicInfo& logic, opts.uf.ufssFairnessMonotone = false; opts.quantifiers.globalNegate = false; opts.quantifiers.cegqiNestedQE = false; - opts.bv.bvAbstraction = false; opts.arith.arithMLTrick = false; return false; @@ -1146,12 +1125,6 @@ bool SetDefaults::incompatibleWithUnsatCores(Options& opts, opts.quantifiers.globalNegate = false; } - if (opts.bv.bitvectorAig) - { - reason << "bitblast-aig"; - return true; - } - if (opts.smt.doITESimp) { reason << "ITE simp"; @@ -1227,14 +1200,8 @@ void SetDefaults::widenLogic(LogicInfo& logic, const Options& opts) const logic = log; logic.lock(); } - if (opts.bv.bvAbstraction) - { - // bv abstraction may require UF - Notice() << "Enabling UF because bvAbstraction requires it." << std::endl; - needsUf = true; - } - else if (opts.quantifiers.preSkolemQuantNested - && opts.quantifiers.preSkolemQuantNestedWasSetByUser) + if (opts.quantifiers.preSkolemQuantNested + && opts.quantifiers.preSkolemQuantNestedWasSetByUser) { // if pre-skolem nested is explictly set, then we require UF. If it is // not explicitly set, it is disabled below if UF is not present. diff --git a/src/smt/term_formula_removal.cpp b/src/smt/term_formula_removal.cpp index 07100576d..c633ecb63 100644 --- a/src/smt/term_formula_removal.cpp +++ b/src/smt/term_formula_removal.cpp @@ -439,7 +439,7 @@ Node RemoveTermFormulas::runCurrentInternal(TNode node, node, "btvK", "a Boolean term variable introduced during term formula removal", - NodeManager::SKOLEM_BOOL_TERM_VAR); + SkolemManager::SKOLEM_BOOL_TERM_VAR); d_skolem_cache.insert(node, skolem); // The new assertion diff --git a/src/theory/arith/arith_poly_norm.cpp b/src/theory/arith/arith_poly_norm.cpp new file mode 100644 index 000000000..81cd3646a --- /dev/null +++ b/src/theory/arith/arith_poly_norm.cpp @@ -0,0 +1,268 @@ +/****************************************************************************** + * Top contributors (to current version): + * Andrew Reynolds + * + * This file is part of the cvc5 project. + * + * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS + * in the top-level source directory and their institutional affiliations. + * All rights reserved. See the file COPYING in the top-level source + * directory for licensing information. + * **************************************************************************** + * + * Arithmetic utility for polynomial normalization + */ + +#include "theory/arith/arith_poly_norm.h" + +using namespace cvc5::kind; + +namespace cvc5 { +namespace theory { +namespace arith { + +void PolyNorm::addMonomial(TNode x, const Rational& c, bool isNeg) +{ + Assert(c.sgn() != 0); + std::unordered_map<Node, Rational>::iterator it = d_polyNorm.find(x); + if (it == d_polyNorm.end()) + { + d_polyNorm[x] = isNeg ? -c : c; + return; + } + Rational res(it->second + (isNeg ? -c : c)); + if (res.sgn() == 0) + { + // cancels + d_polyNorm.erase(it); + } + else + { + d_polyNorm[x] = res; + } +} + +void PolyNorm::multiplyMonomial(TNode x, const Rational& c) +{ + Assert(c.sgn() != 0); + if (x.isNull()) + { + // multiply by constant + for (std::pair<const Node, Rational>& m : d_polyNorm) + { + // c1*x*c2 = (c1*c2)*x + m.second *= c; + } + } + else + { + std::unordered_map<Node, Rational> ptmp = d_polyNorm; + d_polyNorm.clear(); + for (const std::pair<const Node, Rational>& m : ptmp) + { + // c1*x1*c2*x2 = (c1*c2)*(x1*x2) + Node newM = multMonoVar(m.first, x); + d_polyNorm[newM] = m.second * c; + } + } +} + +void PolyNorm::add(const PolyNorm& p) +{ + for (const std::pair<const Node, Rational>& m : p.d_polyNorm) + { + addMonomial(m.first, m.second); + } +} + +void PolyNorm::subtract(const PolyNorm& p) +{ + for (const std::pair<const Node, Rational>& m : p.d_polyNorm) + { + addMonomial(m.first, m.second, true); + } +} + +void PolyNorm::multiply(const PolyNorm& p) +{ + if (p.d_polyNorm.size() == 1) + { + for (const std::pair<const Node, Rational>& m : p.d_polyNorm) + { + multiplyMonomial(m.first, m.second); + } + } + else + { + // If multiplying by sum, must distribute; if multiplying by zero, clear. + // First, remember the current state and clear. + std::unordered_map<Node, Rational> ptmp = d_polyNorm; + d_polyNorm.clear(); + for (const std::pair<const Node, Rational>& m : p.d_polyNorm) + { + PolyNorm pbase; + pbase.d_polyNorm = ptmp; + pbase.multiplyMonomial(m.first, m.second); + // add this to current + add(pbase); + } + } +} + +void PolyNorm::clear() { d_polyNorm.clear(); } + +bool PolyNorm::empty() const { return d_polyNorm.empty(); } + +bool PolyNorm::isEqual(const PolyNorm& p) const +{ + if (d_polyNorm.size() != p.d_polyNorm.size()) + { + return false; + } + std::unordered_map<Node, Rational>::const_iterator it; + for (const std::pair<const Node, Rational>& m : d_polyNorm) + { + Assert(m.second.sgn() != 0); + it = p.d_polyNorm.find(m.first); + if (it == p.d_polyNorm.end() || m.second != it->second) + { + return false; + } + } + return true; +} + +Node PolyNorm::multMonoVar(TNode m1, TNode m2) +{ + std::vector<TNode> vars = getMonoVars(m1); + std::vector<TNode> vars2 = getMonoVars(m2); + vars.insert(vars.end(), vars2.begin(), vars2.end()); + if (vars.empty()) + { + // constants + return Node::null(); + } + else if (vars.size() == 1) + { + return vars[0]; + } + // use default sorting + std::sort(vars.begin(), vars.end()); + return NodeManager::currentNM()->mkNode(NONLINEAR_MULT, vars); +} + +std::vector<TNode> PolyNorm::getMonoVars(TNode m) +{ + std::vector<TNode> vars; + // m is null if this is the empty variable (for constant monomials) + if (!m.isNull()) + { + Kind k = m.getKind(); + Assert(k != CONST_RATIONAL); + if (k == MULT || k == NONLINEAR_MULT) + { + vars.insert(vars.end(), m.begin(), m.end()); + } + else + { + vars.push_back(m); + } + } + return vars; +} + +PolyNorm PolyNorm::mkPolyNorm(TNode n) +{ + Assert(n.getType().isReal()); + Rational one(1); + Node null; + std::unordered_map<TNode, PolyNorm> visited; + std::unordered_map<TNode, PolyNorm>::iterator it; + std::vector<TNode> visit; + TNode cur; + visit.push_back(n); + do + { + cur = visit.back(); + it = visited.find(cur); + Kind k = cur.getKind(); + if (it == visited.end()) + { + if (k == CONST_RATIONAL) + { + Rational r = cur.getConst<Rational>(); + if (r.sgn() == 0) + { + // zero is not an entry + visited[cur] = PolyNorm(); + } + else + { + visited[cur].addMonomial(null, r); + } + } + else if (k == PLUS || k == MINUS || k == UMINUS || k == MULT + || k == NONLINEAR_MULT) + { + visited[cur] = PolyNorm(); + for (const Node& cn : cur) + { + visit.push_back(cn); + } + } + else + { + // it is a leaf + visited[cur].addMonomial(cur, one); + visit.pop_back(); + } + continue; + } + visit.pop_back(); + if (it->second.empty()) + { + PolyNorm& ret = visited[cur]; + switch (k) + { + case PLUS: + case MINUS: + case UMINUS: + case MULT: + case NONLINEAR_MULT: + for (size_t i = 0, nchild = cur.getNumChildren(); i < nchild; i++) + { + it = visited.find(cur[i]); + Assert(it != visited.end()); + if ((k == MINUS && i == 1) || k == UMINUS) + { + ret.subtract(it->second); + } + else if (i > 0 && (k == MULT || k == NONLINEAR_MULT)) + { + ret.multiply(it->second); + } + else + { + ret.add(it->second); + } + } + break; + case CONST_RATIONAL: break; + default: Unhandled() << "Unhandled polynomial operation " << cur; break; + } + } + } while (!visit.empty()); + Assert(visited.find(n) != visited.end()); + return visited[n]; +} + +bool PolyNorm::isArithPolyNorm(TNode a, TNode b) +{ + PolyNorm pa = PolyNorm::mkPolyNorm(a); + PolyNorm pb = PolyNorm::mkPolyNorm(b); + return pa.isEqual(pb); +} + +} // namespace arith +} // namespace theory +} // namespace cvc5 diff --git a/src/theory/arith/arith_poly_norm.h b/src/theory/arith/arith_poly_norm.h new file mode 100644 index 000000000..9c3cbcf95 --- /dev/null +++ b/src/theory/arith/arith_poly_norm.h @@ -0,0 +1,83 @@ +/****************************************************************************** + * Top contributors (to current version): + * Andrew Reynolds + * + * This file is part of the cvc5 project. + * + * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS + * in the top-level source directory and their institutional affiliations. + * All rights reserved. See the file COPYING in the top-level source + * directory for licensing information. + * **************************************************************************** + * + * Arithmetic utility for polynomial normalization + */ + +#include "cvc5_private.h" + +#ifndef CVC5__THEORY__ARITH__POLY_NORM_H +#define CVC5__THEORY__ARITH__POLY_NORM_H + +#include <unordered_map> + +#include "expr/node.h" +#include "util/rational.h" + +namespace cvc5 { +namespace theory { +namespace arith { + +/** + * A utility class for polynomial normalization. This is used by the proof + * rule PfRule::ARITH_POLY_NORM. + */ +class PolyNorm +{ + public: + /** + * Add the monomial x*c to this polynomial. + * If x is null, then x*c is treated as c. + */ + void addMonomial(TNode x, const Rational& c, bool isNeg = false); + /** + * Multiply this polynomial by the monomial x*c, where c is a CONST_RATIONAL. + * If x is null, then x*c is treated as c. + */ + void multiplyMonomial(TNode x, const Rational& c); + /** Add polynomial p to this one. */ + void add(const PolyNorm& p); + /** Subtract polynomial p from this one. */ + void subtract(const PolyNorm& p); + /** Multiply this polynomial by p */ + void multiply(const PolyNorm& p); + /** Clear this polynomial */ + void clear(); + /** Return true if this polynomial is empty */ + bool empty() const; + /** Is this polynomial equal to polynomial p? */ + bool isEqual(const PolyNorm& p) const; + /** + * Make polynomial from real term n. This method normalizes applications + * of operators PLUS, MINUS, UMINUS, MULT, and NONLINEAR_MULT only. + */ + static PolyNorm mkPolyNorm(TNode n); + /** Do a and b normalize to the same polynomial? */ + static bool isArithPolyNorm(TNode a, TNode b); + + private: + /** + * Given two terms that are variables in monomials, return the + * variable for the monomial when they are multiplied. + */ + static Node multMonoVar(TNode m1, TNode m2); + /** Get the list of variables whose product is m */ + static std::vector<TNode> getMonoVars(TNode m); + /** The data, mapping monomial variables to coefficients */ + std::unordered_map<Node, Rational> d_polyNorm; +}; + +} // namespace arith +} // namespace theory +} // namespace cvc5 + +#endif /* CVC5__THEORY__ARITH__POLY_NORM_H */ diff --git a/src/theory/arith/nl/cad_solver.cpp b/src/theory/arith/nl/cad_solver.cpp index 6b1749305..a3dd77fd1 100644 --- a/src/theory/arith/nl/cad_solver.cpp +++ b/src/theory/arith/nl/cad_solver.cpp @@ -38,8 +38,7 @@ CadSolver::CadSolver(Env& env, InferenceManager& im, NlModel& model) { NodeManager* nm = NodeManager::currentNM(); SkolemManager* sm = nm->getSkolemManager(); - d_ranVariable = sm->mkDummySkolem( - "__z", nm->realType(), "", NodeManager::SKOLEM_EXACT_NAME); + d_ranVariable = sm->mkDummySkolem("__z", nm->realType(), ""); #ifdef CVC5_POLY_IMP if (env.isTheoryProofProducing()) { diff --git a/src/theory/arith/nl/ext/monomial_bounds_check.cpp b/src/theory/arith/nl/ext/monomial_bounds_check.cpp index 31bc4c662..bb6a2a5c3 100644 --- a/src/theory/arith/nl/ext/monomial_bounds_check.cpp +++ b/src/theory/arith/nl/ext/monomial_bounds_check.cpp @@ -321,25 +321,80 @@ void MonomialBoundsCheck::checkBounds(const std::vector<Node>& asserts, if (d_data->isProofEnabled()) { proof = d_data->getProof(); + Node simpleeq = nm->mkNode(type, t, rhs); // this is iblem, but uses (type t rhs) instead of the original // variant (which is identical under rewriting) // we first infer the "clean" version of the lemma and then // use MACRO_SR_PRED_TRANSFORM to rewrite - Node tmplem = nm->mkNode( - Kind::IMPLIES, - nm->mkNode(Kind::AND, - nm->mkNode(mmv_sign == 1 ? Kind::GT : Kind::LT, - mult, - d_data->d_zero), - nm->mkNode(type, t, rhs)), - infer); + Node tmplem = nm->mkNode(Kind::IMPLIES, + nm->mkNode(Kind::AND, exp[0], simpleeq), + infer); proof->addStep(tmplem, mmv_sign == 1 ? PfRule::ARITH_MULT_POS : PfRule::ARITH_MULT_NEG, {}, - {mult, nm->mkNode(type, t, rhs)}); - proof->addStep( - iblem, PfRule::MACRO_SR_PRED_TRANSFORM, {tmplem}, {iblem}); + {mult, simpleeq}); + theory::Rewriter* rew = d_data->d_env.getRewriter(); + if (type == Kind::EQUAL + && (rew->rewrite(simpleeq) != rew->rewrite(exp[1]))) + { + // it is not identical under rewriting and we need to do some work here + // The proof looks like this: + // (SCOPE + // (MODUS_PONENS + // <tmplem> + // (AND_INTRO + // <first premise of iblem> + // (ARITH_TRICHOTOMY *** + // (AND_ELIM <second premise of iblem> 1) + // (AND_ELIM <second premise of iblem> 2) + // ) + // ) + // ) + // :args <the two premises of iblem> + // ) + // ***: the result of the AND_ELIM are rewritten forms of what + // ARITH_TRICHOTOMY expects, and also their order is not clear. + // Hence, we apply MACRO_SR_PRED_TRANSFORM to them, and check + // which corresponds to which subterm of the premise. + proof->addStep(exp[1][0], + PfRule::AND_ELIM, + {exp[1]}, + {nm->mkConst(Rational(0))}); + proof->addStep(exp[1][1], + PfRule::AND_ELIM, + {exp[1]}, + {nm->mkConst(Rational(1))}); + Node lb = nm->mkNode(Kind::GEQ, simpleeq[0], simpleeq[1]); + Node rb = nm->mkNode(Kind::LEQ, simpleeq[0], simpleeq[1]); + if (rew->rewrite(lb) == rew->rewrite(exp[1][0])) + { + proof->addStep( + lb, PfRule::MACRO_SR_PRED_TRANSFORM, {exp[1][0]}, {lb}); + proof->addStep( + rb, PfRule::MACRO_SR_PRED_TRANSFORM, {exp[1][1]}, {rb}); + } + else + { + proof->addStep( + lb, PfRule::MACRO_SR_PRED_TRANSFORM, {exp[1][1]}, {lb}); + proof->addStep( + rb, PfRule::MACRO_SR_PRED_TRANSFORM, {exp[1][0]}, {rb}); + } + proof->addStep( + simpleeq, PfRule::ARITH_TRICHOTOMY, {lb, rb}, {simpleeq}); + proof->addStep( + tmplem[0], PfRule::AND_INTRO, {exp[0], simpleeq}, {}); + proof->addStep( + tmplem[1], PfRule::MODUS_PONENS, {tmplem[0], tmplem}, {}); + proof->addStep( + iblem, PfRule::SCOPE, {tmplem[1]}, {exp[0], exp[1]}); + } + else + { + proof->addStep( + iblem, PfRule::MACRO_SR_PRED_TRANSFORM, {tmplem}, {iblem}); + } } d_data->d_im.addPendingLemma(iblem, InferenceId::ARITH_NL_INFER_BOUNDS_NT, diff --git a/src/theory/arith/operator_elim.cpp b/src/theory/arith/operator_elim.cpp index 90f4a2cc7..afbb9b70f 100644 --- a/src/theory/arith/operator_elim.cpp +++ b/src/theory/arith/operator_elim.cpp @@ -462,8 +462,8 @@ Node OperatorElim::mkWitnessTerm(Node v, NodeManager* nm = NodeManager::currentNM(); SkolemManager* sm = nm->getSkolemManager(); // we mark that we should send a lemma - Node k = - sm->mkSkolem(v, pred, prefix, comment, NodeManager::SKOLEM_DEFAULT, this); + Node k = sm->mkSkolem( + v, pred, prefix, comment, SkolemManager::SKOLEM_DEFAULT, this); if (d_pnm != nullptr) { Node lem = SkolemLemma::getSkolemLemmaFor(k); diff --git a/src/theory/arith/proof_checker.cpp b/src/theory/arith/proof_checker.cpp index 58de8e391..171cdf182 100644 --- a/src/theory/arith/proof_checker.cpp +++ b/src/theory/arith/proof_checker.cpp @@ -19,6 +19,7 @@ #include <set> #include "expr/skolem_manager.h" +#include "theory/arith/arith_poly_norm.h" #include "theory/arith/arith_utilities.h" #include "theory/arith/constraint.h" #include "theory/arith/normal_form.h" @@ -38,6 +39,7 @@ void ArithProofRuleChecker::registerTo(ProofChecker* pc) pc->registerChecker(PfRule::ARITH_OP_ELIM_AXIOM, this); pc->registerChecker(PfRule::ARITH_MULT_POS, this); pc->registerChecker(PfRule::ARITH_MULT_NEG, this); + pc->registerChecker(PfRule::ARITH_POLY_NORM, this); } Node ArithProofRuleChecker::checkInternal(PfRule id, @@ -343,6 +345,20 @@ Node ArithProofRuleChecker::checkInternal(PfRule id, Assert(args.size() == 1); return OperatorElim::getAxiomFor(args[0]); } + case PfRule::ARITH_POLY_NORM: + { + Assert(children.empty()); + Assert(args.size() == 1); + if (args[0].getKind() != kind::EQUAL) + { + return Node::null(); + } + if (!PolyNorm::isArithPolyNorm(args[0][0], args[0][1])) + { + return Node::null(); + } + return args[0]; + } default: return Node::null(); } } diff --git a/src/theory/arrays/theory_arrays.cpp b/src/theory/arrays/theory_arrays.cpp index 97cbec1d5..7362e1fba 100644 --- a/src/theory/arrays/theory_arrays.cpp +++ b/src/theory/arrays/theory_arrays.cpp @@ -825,27 +825,6 @@ void TheoryArrays::preRegisterTerm(TNode node) } } -void TheoryArrays::explain(TNode literal, Node& explanation) -{ - ++d_numExplain; - Debug("arrays") << spaces(context()->getLevel()) << "TheoryArrays::explain(" - << literal << ")" << std::endl; - std::vector<TNode> assumptions; - // Do the work - bool polarity = literal.getKind() != kind::NOT; - TNode atom = polarity ? literal : literal[0]; - if (atom.getKind() == kind::EQUAL) - { - d_equalityEngine->explainEquality( - atom[0], atom[1], polarity, assumptions, nullptr); - } - else - { - d_equalityEngine->explainPredicate(atom, polarity, assumptions, nullptr); - } - explanation = mkAnd(assumptions); -} - TrustNode TheoryArrays::explain(TNode literal) { return d_im.explainLit(literal); diff --git a/src/theory/arrays/theory_arrays.h b/src/theory/arrays/theory_arrays.h index c8cff93f8..2ce2344b9 100644 --- a/src/theory/arrays/theory_arrays.h +++ b/src/theory/arrays/theory_arrays.h @@ -208,9 +208,6 @@ class TheoryArrays : public Theory { /** Should be called to propagate the literal. */ bool propagateLit(TNode literal); - /** Explain why this literal is true by building an explanation */ - void explain(TNode literal, Node& exp); - /** For debugging only- checks invariants about when things are preregistered*/ context::CDHashSet<Node> d_isPreRegistered; diff --git a/src/theory/bags/bags_rewriter.cpp b/src/theory/bags/bags_rewriter.cpp index 0be83fb13..2170175b4 100644 --- a/src/theory/bags/bags_rewriter.cpp +++ b/src/theory/bags/bags_rewriter.cpp @@ -173,8 +173,11 @@ BagsRewriteResponse BagsRewriter::rewriteBagCount(const TNode& n) const } if (n[1].getKind() == MK_BAG && n[0] == n[1][0]) { - // (bag.count x (mkBag x c) = c - return BagsRewriteResponse(n[1][1], Rewrite::COUNT_MK_BAG); + // (bag.count x (mkBag x c)) = (ite (>= c 1) c 0) + Node c = n[1][1]; + Node geq = d_nm->mkNode(GEQ, c, d_one); + Node ite = d_nm->mkNode(ITE, geq, c, d_zero); + return BagsRewriteResponse(ite, Rewrite::COUNT_MK_BAG); } return BagsRewriteResponse(n, Rewrite::NONE); } diff --git a/src/theory/bags/bags_rewriter.h b/src/theory/bags/bags_rewriter.h index eb5c9f9ab..3edd5af32 100644 --- a/src/theory/bags/bags_rewriter.h +++ b/src/theory/bags/bags_rewriter.h @@ -56,6 +56,7 @@ class BagsRewriter : public TheoryRewriter * See the rewrite rules for these kinds below. */ RewriteResponse preRewrite(TNode n) override; + private: /** * rewrites for n include: @@ -81,7 +82,7 @@ class BagsRewriter : public TheoryRewriter /** * rewrites for n include: * - (bag.count x emptybag) = 0 - * - (bag.count x (bag x c) = c + * - (bag.count x (bag x c)) = (ite (>= c 1) c 0) * - otherwise = n */ BagsRewriteResponse rewriteBagCount(const TNode& n) const; @@ -214,7 +215,8 @@ class BagsRewriter : public TheoryRewriter /** * rewrites for n include: * - (bag.map (lambda ((x U)) t) emptybag) = emptybag - * - (bag.map (lambda ((x U)) t) (bag y z)) = (bag (apply (lambda ((x U)) t) y) z) + * - (bag.map (lambda ((x U)) t) (bag y z)) = (bag (apply (lambda ((x U)) t) + * y) z) * - (bag.map (lambda ((x U)) t) (union_disjoint A B)) = * (union_disjoint * (bag ((lambda ((x U)) t) "a") 3) diff --git a/src/theory/bags/inference_generator.cpp b/src/theory/bags/inference_generator.cpp index 734572f7c..e88a7e0ca 100644 --- a/src/theory/bags/inference_generator.cpp +++ b/src/theory/bags/inference_generator.cpp @@ -24,6 +24,8 @@ #include "theory/uf/equality_engine.h" #include "util/rational.h" +using namespace cvc5::kind; + namespace cvc5 { namespace theory { namespace bags { @@ -44,38 +46,49 @@ InferInfo InferenceGenerator::nonNegativeCount(Node n, Node e) Assert(e.getType() == n.getType().getBagElementType()); InferInfo inferInfo(d_im, InferenceId::BAGS_NON_NEGATIVE_COUNT); - Node count = d_nm->mkNode(kind::BAG_COUNT, e, n); + Node count = d_nm->mkNode(BAG_COUNT, e, n); - Node gte = d_nm->mkNode(kind::GEQ, count, d_zero); + Node gte = d_nm->mkNode(GEQ, count, d_zero); inferInfo.d_conclusion = gte; return inferInfo; } InferInfo InferenceGenerator::mkBag(Node n, Node e) { - Assert(n.getKind() == kind::MK_BAG); + Assert(n.getKind() == MK_BAG); Assert(e.getType() == n.getType().getBagElementType()); - if (n[0] == e) + Node x = n[0]; + Node c = n[1]; + Node geq = d_nm->mkNode(GEQ, c, d_one); + if (d_state->areEqual(e, x)) + { + // (= (bag.count e skolem) (ite (>= c 1) c 0))) + InferInfo inferInfo(d_im, InferenceId::BAGS_MK_BAG_SAME_ELEMENT); + Node skolem = getSkolem(n, inferInfo); + Node count = getMultiplicityTerm(e, skolem); + Node ite = d_nm->mkNode(ITE, geq, c, d_zero); + inferInfo.d_conclusion = count.eqNode(ite); + return inferInfo; + } + if (d_state->areDisequal(e, x)) { - // TODO issue #78: refactor this with BagRewriter - // (=> true (= (bag.count e (bag e c)) c)) + //(= (bag.count e skolem) 0)) InferInfo inferInfo(d_im, InferenceId::BAGS_MK_BAG_SAME_ELEMENT); Node skolem = getSkolem(n, inferInfo); Node count = getMultiplicityTerm(e, skolem); - inferInfo.d_conclusion = count.eqNode(n[1]); + inferInfo.d_conclusion = count.eqNode(d_zero); return inferInfo; } else { - // (=> - // true - // (= (bag.count e (bag x c)) (ite (= e x) c 0))) + // (= (bag.count e skolem) (ite (and (= e x) (>= c 1)) c 0))) InferInfo inferInfo(d_im, InferenceId::BAGS_MK_BAG); Node skolem = getSkolem(n, inferInfo); Node count = getMultiplicityTerm(e, skolem); - Node same = d_nm->mkNode(kind::EQUAL, n[0], e); - Node ite = d_nm->mkNode(kind::ITE, same, n[1], d_zero); + Node same = d_nm->mkNode(EQUAL, e, x); + Node andNode = same.andNode(geq); + Node ite = d_nm->mkNode(ITE, andNode, c, d_zero); Node equal = count.eqNode(ite); inferInfo.d_conclusion = equal; return inferInfo; @@ -110,7 +123,7 @@ typedef expr::Attribute<BagsDeqAttributeId, Node> BagsDeqAttribute; InferInfo InferenceGenerator::bagDisequality(Node n) { - Assert(n.getKind() == kind::EQUAL && n[0].getType().isBag()); + Assert(n.getKind() == EQUAL && n[0].getType().isBag()); Node A = n[0]; Node B = n[1]; @@ -145,7 +158,7 @@ Node InferenceGenerator::getSkolem(Node& n, InferInfo& inferInfo) InferInfo InferenceGenerator::empty(Node n, Node e) { - Assert(n.getKind() == kind::EMPTYBAG); + Assert(n.getKind() == EMPTYBAG); Assert(e.getType() == n.getType().getBagElementType()); InferInfo inferInfo(d_im, InferenceId::BAGS_EMPTY); @@ -159,7 +172,7 @@ InferInfo InferenceGenerator::empty(Node n, Node e) InferInfo InferenceGenerator::unionDisjoint(Node n, Node e) { - Assert(n.getKind() == kind::UNION_DISJOINT && n[0].getType().isBag()); + Assert(n.getKind() == UNION_DISJOINT && n[0].getType().isBag()); Assert(e.getType() == n[0].getType().getBagElementType()); Node A = n[0]; @@ -172,7 +185,7 @@ InferInfo InferenceGenerator::unionDisjoint(Node n, Node e) Node skolem = getSkolem(n, inferInfo); Node count = getMultiplicityTerm(e, skolem); - Node sum = d_nm->mkNode(kind::PLUS, countA, countB); + Node sum = d_nm->mkNode(PLUS, countA, countB); Node equal = count.eqNode(sum); inferInfo.d_conclusion = equal; @@ -181,7 +194,7 @@ InferInfo InferenceGenerator::unionDisjoint(Node n, Node e) InferInfo InferenceGenerator::unionMax(Node n, Node e) { - Assert(n.getKind() == kind::UNION_MAX && n[0].getType().isBag()); + Assert(n.getKind() == UNION_MAX && n[0].getType().isBag()); Assert(e.getType() == n[0].getType().getBagElementType()); Node A = n[0]; @@ -194,8 +207,8 @@ InferInfo InferenceGenerator::unionMax(Node n, Node e) Node skolem = getSkolem(n, inferInfo); Node count = getMultiplicityTerm(e, skolem); - Node gt = d_nm->mkNode(kind::GT, countA, countB); - Node max = d_nm->mkNode(kind::ITE, gt, countA, countB); + Node gt = d_nm->mkNode(GT, countA, countB); + Node max = d_nm->mkNode(ITE, gt, countA, countB); Node equal = count.eqNode(max); inferInfo.d_conclusion = equal; @@ -204,7 +217,7 @@ InferInfo InferenceGenerator::unionMax(Node n, Node e) InferInfo InferenceGenerator::intersection(Node n, Node e) { - Assert(n.getKind() == kind::INTERSECTION_MIN && n[0].getType().isBag()); + Assert(n.getKind() == INTERSECTION_MIN && n[0].getType().isBag()); Assert(e.getType() == n[0].getType().getBagElementType()); Node A = n[0]; @@ -216,8 +229,8 @@ InferInfo InferenceGenerator::intersection(Node n, Node e) Node skolem = getSkolem(n, inferInfo); Node count = getMultiplicityTerm(e, skolem); - Node lt = d_nm->mkNode(kind::LT, countA, countB); - Node min = d_nm->mkNode(kind::ITE, lt, countA, countB); + Node lt = d_nm->mkNode(LT, countA, countB); + Node min = d_nm->mkNode(ITE, lt, countA, countB); Node equal = count.eqNode(min); inferInfo.d_conclusion = equal; return inferInfo; @@ -225,7 +238,7 @@ InferInfo InferenceGenerator::intersection(Node n, Node e) InferInfo InferenceGenerator::differenceSubtract(Node n, Node e) { - Assert(n.getKind() == kind::DIFFERENCE_SUBTRACT && n[0].getType().isBag()); + Assert(n.getKind() == DIFFERENCE_SUBTRACT && n[0].getType().isBag()); Assert(e.getType() == n[0].getType().getBagElementType()); Node A = n[0]; @@ -237,9 +250,9 @@ InferInfo InferenceGenerator::differenceSubtract(Node n, Node e) Node skolem = getSkolem(n, inferInfo); Node count = getMultiplicityTerm(e, skolem); - Node subtract = d_nm->mkNode(kind::MINUS, countA, countB); - Node gte = d_nm->mkNode(kind::GEQ, countA, countB); - Node difference = d_nm->mkNode(kind::ITE, gte, subtract, d_zero); + Node subtract = d_nm->mkNode(MINUS, countA, countB); + Node gte = d_nm->mkNode(GEQ, countA, countB); + Node difference = d_nm->mkNode(ITE, gte, subtract, d_zero); Node equal = count.eqNode(difference); inferInfo.d_conclusion = equal; return inferInfo; @@ -247,7 +260,7 @@ InferInfo InferenceGenerator::differenceSubtract(Node n, Node e) InferInfo InferenceGenerator::differenceRemove(Node n, Node e) { - Assert(n.getKind() == kind::DIFFERENCE_REMOVE && n[0].getType().isBag()); + Assert(n.getKind() == DIFFERENCE_REMOVE && n[0].getType().isBag()); Assert(e.getType() == n[0].getType().getBagElementType()); Node A = n[0]; @@ -260,8 +273,8 @@ InferInfo InferenceGenerator::differenceRemove(Node n, Node e) Node skolem = getSkolem(n, inferInfo); Node count = getMultiplicityTerm(e, skolem); - Node notInB = d_nm->mkNode(kind::EQUAL, countB, d_zero); - Node difference = d_nm->mkNode(kind::ITE, notInB, countA, d_zero); + Node notInB = d_nm->mkNode(LEQ, countB, d_zero); + Node difference = d_nm->mkNode(ITE, notInB, countA, d_zero); Node equal = count.eqNode(difference); inferInfo.d_conclusion = equal; return inferInfo; @@ -269,7 +282,7 @@ InferInfo InferenceGenerator::differenceRemove(Node n, Node e) InferInfo InferenceGenerator::duplicateRemoval(Node n, Node e) { - Assert(n.getKind() == kind::DUPLICATE_REMOVAL && n[0].getType().isBag()); + Assert(n.getKind() == DUPLICATE_REMOVAL && n[0].getType().isBag()); Assert(e.getType() == n[0].getType().getBagElementType()); Node A = n[0]; @@ -279,8 +292,8 @@ InferInfo InferenceGenerator::duplicateRemoval(Node n, Node e) Node skolem = getSkolem(n, inferInfo); Node count = getMultiplicityTerm(e, skolem); - Node gte = d_nm->mkNode(kind::GEQ, countA, d_one); - Node ite = d_nm->mkNode(kind::ITE, gte, d_one, d_zero); + Node gte = d_nm->mkNode(GEQ, countA, d_one); + Node ite = d_nm->mkNode(ITE, gte, d_one, d_zero); Node equal = count.eqNode(ite); inferInfo.d_conclusion = equal; return inferInfo; @@ -288,14 +301,14 @@ InferInfo InferenceGenerator::duplicateRemoval(Node n, Node e) Node InferenceGenerator::getMultiplicityTerm(Node element, Node bag) { - Node count = d_nm->mkNode(kind::BAG_COUNT, element, bag); + Node count = d_nm->mkNode(BAG_COUNT, element, bag); return count; } std::tuple<InferInfo, Node, Node> InferenceGenerator::mapDownwards(Node n, Node e) { - Assert(n.getKind() == kind::BAG_MAP && n[1].getType().isBag()); + Assert(n.getKind() == BAG_MAP && n[1].getType().isBag()); Assert(n[0].getType().isFunction() && n[0].getType().getArgTypes().size() == 1); Assert(e.getType() == n[0].getType().getRangeType()); @@ -316,8 +329,8 @@ std::tuple<InferInfo, Node, Node> InferenceGenerator::mapDownwards(Node n, Node sum = d_sm->mkSkolemFunction(SkolemFunId::BAGS_MAP_SUM, sumType, {n, e}); // (= (sum 0) 0) - Node sum_zero = d_nm->mkNode(kind::APPLY_UF, sum, d_zero); - Node baseCase = d_nm->mkNode(Kind::EQUAL, sum_zero, d_zero); + Node sum_zero = d_nm->mkNode(APPLY_UF, sum, d_zero); + Node baseCase = d_nm->mkNode(EQUAL, sum_zero, d_zero); // guess the size of the preimage of e Node preImageSize = d_sm->mkDummySkolem("preImageSize", d_nm->integerType()); @@ -325,8 +338,8 @@ std::tuple<InferInfo, Node, Node> InferenceGenerator::mapDownwards(Node n, // (= (sum preImageSize) (bag.count e skolem)) Node mapSkolem = getSkolem(n, inferInfo); Node countE = getMultiplicityTerm(e, mapSkolem); - Node totalSum = d_nm->mkNode(kind::APPLY_UF, sum, preImageSize); - Node totalSumEqualCountE = d_nm->mkNode(kind::EQUAL, totalSum, countE); + Node totalSum = d_nm->mkNode(APPLY_UF, sum, preImageSize); + Node totalSumEqualCountE = d_nm->mkNode(EQUAL, totalSum, countE); // (forall ((i Int)) // (let ((uf_i (uf i))) @@ -347,44 +360,42 @@ std::tuple<InferInfo, Node, Node> InferenceGenerator::mapDownwards(Node n, Node i = bvm->mkBoundVar<FirstIndexVarAttribute>(n, "i", d_nm->integerType()); Node j = bvm->mkBoundVar<SecondIndexVarAttribute>(n, "j", d_nm->integerType()); - Node iList = d_nm->mkNode(kind::BOUND_VAR_LIST, i); - Node jList = d_nm->mkNode(kind::BOUND_VAR_LIST, j); - Node iPlusOne = d_nm->mkNode(kind::PLUS, i, d_one); - Node iMinusOne = d_nm->mkNode(kind::MINUS, i, d_one); - Node uf_i = d_nm->mkNode(kind::APPLY_UF, uf, i); - Node uf_j = d_nm->mkNode(kind::APPLY_UF, uf, j); - Node f_uf_i = d_nm->mkNode(kind::APPLY_UF, f, uf_i); - Node uf_iPlusOne = d_nm->mkNode(kind::APPLY_UF, uf, iPlusOne); - Node uf_iMinusOne = d_nm->mkNode(kind::APPLY_UF, uf, iMinusOne); - Node interval_i = d_nm->mkNode(kind::AND, - d_nm->mkNode(kind::GEQ, i, d_one), - d_nm->mkNode(kind::LEQ, i, preImageSize)); - Node sum_i = d_nm->mkNode(kind::APPLY_UF, sum, i); - Node sum_iPlusOne = d_nm->mkNode(kind::APPLY_UF, sum, iPlusOne); - Node sum_iMinusOne = d_nm->mkNode(kind::APPLY_UF, sum, iMinusOne); - Node count_iMinusOne = d_nm->mkNode(kind::BAG_COUNT, uf_iMinusOne, A); - Node count_uf_i = d_nm->mkNode(kind::BAG_COUNT, uf_i, A); - Node inductiveCase = d_nm->mkNode( - Kind::EQUAL, sum_i, d_nm->mkNode(kind::PLUS, sum_iMinusOne, count_uf_i)); - Node f_iEqualE = d_nm->mkNode(kind::EQUAL, f_uf_i, e); - Node geqOne = d_nm->mkNode(kind::GEQ, count_uf_i, d_one); + Node iList = d_nm->mkNode(BOUND_VAR_LIST, i); + Node jList = d_nm->mkNode(BOUND_VAR_LIST, j); + Node iPlusOne = d_nm->mkNode(PLUS, i, d_one); + Node iMinusOne = d_nm->mkNode(MINUS, i, d_one); + Node uf_i = d_nm->mkNode(APPLY_UF, uf, i); + Node uf_j = d_nm->mkNode(APPLY_UF, uf, j); + Node f_uf_i = d_nm->mkNode(APPLY_UF, f, uf_i); + Node uf_iPlusOne = d_nm->mkNode(APPLY_UF, uf, iPlusOne); + Node uf_iMinusOne = d_nm->mkNode(APPLY_UF, uf, iMinusOne); + Node interval_i = d_nm->mkNode( + AND, d_nm->mkNode(GEQ, i, d_one), d_nm->mkNode(LEQ, i, preImageSize)); + Node sum_i = d_nm->mkNode(APPLY_UF, sum, i); + Node sum_iPlusOne = d_nm->mkNode(APPLY_UF, sum, iPlusOne); + Node sum_iMinusOne = d_nm->mkNode(APPLY_UF, sum, iMinusOne); + Node count_iMinusOne = d_nm->mkNode(BAG_COUNT, uf_iMinusOne, A); + Node count_uf_i = d_nm->mkNode(BAG_COUNT, uf_i, A); + Node inductiveCase = + d_nm->mkNode(EQUAL, sum_i, d_nm->mkNode(PLUS, sum_iMinusOne, count_uf_i)); + Node f_iEqualE = d_nm->mkNode(EQUAL, f_uf_i, e); + Node geqOne = d_nm->mkNode(GEQ, count_uf_i, d_one); // i < j <= preImageSize - Node interval_j = d_nm->mkNode(kind::AND, - d_nm->mkNode(kind::LT, i, j), - d_nm->mkNode(kind::LEQ, j, preImageSize)); + Node interval_j = d_nm->mkNode( + AND, d_nm->mkNode(LT, i, j), d_nm->mkNode(LEQ, j, preImageSize)); // uf(i) != uf(j) - Node uf_i_equals_uf_j = d_nm->mkNode(kind::EQUAL, uf_i, uf_j); - Node notEqual = d_nm->mkNode(kind::EQUAL, uf_i, uf_j).negate(); - Node body_j = d_nm->mkNode(kind::OR, interval_j.negate(), notEqual); + Node uf_i_equals_uf_j = d_nm->mkNode(EQUAL, uf_i, uf_j); + Node notEqual = d_nm->mkNode(EQUAL, uf_i, uf_j).negate(); + Node body_j = d_nm->mkNode(OR, interval_j.negate(), notEqual); Node forAll_j = quantifiers::BoundedIntegers::mkBoundedForall(jList, body_j); Node andNode = - d_nm->mkNode(kind::AND, {f_iEqualE, geqOne, inductiveCase, forAll_j}); - Node body_i = d_nm->mkNode(kind::OR, interval_i.negate(), andNode); + d_nm->mkNode(AND, {f_iEqualE, geqOne, inductiveCase, forAll_j}); + Node body_i = d_nm->mkNode(OR, interval_i.negate(), andNode); Node forAll_i = quantifiers::BoundedIntegers::mkBoundedForall(iList, body_i); - Node preImageGTE_zero = d_nm->mkNode(kind::GEQ, preImageSize, d_zero); + Node preImageGTE_zero = d_nm->mkNode(GEQ, preImageSize, d_zero); Node conclusion = d_nm->mkNode( - kind::AND, {baseCase, totalSumEqualCountE, forAll_i, preImageGTE_zero}); + AND, {baseCase, totalSumEqualCountE, forAll_i, preImageGTE_zero}); inferInfo.d_conclusion = conclusion; std::map<Node, Node> m; @@ -395,7 +406,7 @@ std::tuple<InferInfo, Node, Node> InferenceGenerator::mapDownwards(Node n, InferInfo InferenceGenerator::mapUpwards( Node n, Node uf, Node preImageSize, Node y, Node x) { - Assert(n.getKind() == kind::BAG_MAP && n[1].getType().isBag()); + Assert(n.getKind() == BAG_MAP && n[1].getType().isBag()); Assert(n[0].getType().isFunction() && n[0].getType().getArgTypes().size() == 1); @@ -404,19 +415,16 @@ InferInfo InferenceGenerator::mapUpwards( Node A = n[1]; Node countA = getMultiplicityTerm(x, A); - Node xInA = d_nm->mkNode(kind::GEQ, countA, d_one); - Node notEqual = - d_nm->mkNode(kind::EQUAL, d_nm->mkNode(kind::APPLY_UF, f, x), y).negate(); + Node xInA = d_nm->mkNode(GEQ, countA, d_one); + Node notEqual = d_nm->mkNode(EQUAL, d_nm->mkNode(APPLY_UF, f, x), y).negate(); Node k = d_sm->mkDummySkolem("k", d_nm->integerType()); - Node inRange = d_nm->mkNode(kind::AND, - d_nm->mkNode(kind::GEQ, k, d_one), - d_nm->mkNode(kind::LEQ, k, preImageSize)); - Node equal = - d_nm->mkNode(kind::EQUAL, d_nm->mkNode(kind::APPLY_UF, uf, k), x); - Node andNode = d_nm->mkNode(kind::AND, inRange, equal); - Node orNode = d_nm->mkNode(kind::OR, notEqual, andNode); - Node implies = d_nm->mkNode(kind::IMPLIES, xInA, orNode); + Node inRange = d_nm->mkNode( + AND, d_nm->mkNode(GEQ, k, d_one), d_nm->mkNode(LEQ, k, preImageSize)); + Node equal = d_nm->mkNode(EQUAL, d_nm->mkNode(APPLY_UF, uf, k), x); + Node andNode = d_nm->mkNode(AND, inRange, equal); + Node orNode = d_nm->mkNode(OR, notEqual, andNode); + Node implies = d_nm->mkNode(IMPLIES, xInA, orNode); inferInfo.d_conclusion = implies; std::cout << "Upwards conclusion: " << inferInfo.d_conclusion << std::endl << std::endl; diff --git a/src/theory/bags/inference_generator.h b/src/theory/bags/inference_generator.h index ab3a84b29..3f38d05b9 100644 --- a/src/theory/bags/inference_generator.h +++ b/src/theory/bags/inference_generator.h @@ -50,15 +50,14 @@ class InferenceGenerator /** * @param n is (bag x c) of type (Bag E) * @param e is a node of type E - * @return an inference that represents the following implication - * (=> - * true - * (= (bag.count e skolem) c)) - * if e is exactly node x. Node skolem is a fresh variable equals (bag x c). - * Otherwise the following inference is returned - * (=> - * true - * (= (bag.count e skolem) (ite (= e x) c 0))) + * @return an inference that represents the following cases: + * 1- e, x are in the same equivalent class, then we infer: + * (= (bag.count e skolem) (ite (>= c 1) c 0))) + * 2- e, x are known to be disequal, then we infer: + * (= (bag.count e skolem) 0)) + * 3- if neither holds, we infer: + * (= (bag.count e skolem) (ite (and (= e x) (>= c 1)) c 0))) + * where skolem = (bag x c) is a fresh variable */ InferInfo mkBag(Node n, Node e); /** @@ -146,7 +145,7 @@ class InferenceGenerator * (= * (count e skolem) * (ite - * (= (count e B) 0) + * (<= (count e B) 0) * (count e A) * 0)))) * where skolem is a fresh variable equals (difference_remove A B) diff --git a/src/theory/bags/theory_bags.cpp b/src/theory/bags/theory_bags.cpp index f10144255..9db6149ef 100644 --- a/src/theory/bags/theory_bags.cpp +++ b/src/theory/bags/theory_bags.cpp @@ -185,14 +185,8 @@ bool TheoryBags::collectModelValues(TheoryModel* m, elementReps[key] = value; } Node rep = NormalForm::constructBagFromElements(tn, elementReps); - rep = Rewriter::rewrite(rep); - + rep = rewrite(rep); Trace("bags-model") << "rep of " << n << " is: " << rep << std::endl; - for (std::pair<Node, Node> pair : elementReps) - { - m->assertSkeleton(pair.first); - m->assertSkeleton(pair.second); - } m->assertEquality(rep, n, true); m->assertSkeleton(rep); } diff --git a/src/theory/booleans/proof_circuit_propagator.cpp b/src/theory/booleans/proof_circuit_propagator.cpp index e462414d1..1ec8f7b67 100644 --- a/src/theory/booleans/proof_circuit_propagator.cpp +++ b/src/theory/booleans/proof_circuit_propagator.cpp @@ -206,11 +206,11 @@ std::shared_ptr<ProofNode> ProofCircuitPropagator::xorXFromY(bool negated, parent[1], false)); } - return mkResolution( - mkProof(negated ? PfRule::NOT_XOR_ELIM2 : PfRule::XOR_ELIM1, - {assume(negated ? parent.notNode() : Node(parent))}), - parent[1], - true); + return mkNot( + mkResolution(mkProof(negated ? PfRule::NOT_XOR_ELIM2 : PfRule::XOR_ELIM1, + {assume(negated ? parent.notNode() : Node(parent))}), + parent[1], + true)); } std::shared_ptr<ProofNode> ProofCircuitPropagator::xorYFromX(bool negated, diff --git a/src/theory/bv/abstraction.cpp b/src/theory/bv/abstraction.cpp deleted file mode 100644 index 3d25f19d6..000000000 --- a/src/theory/bv/abstraction.cpp +++ /dev/null @@ -1,1100 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Liana Hadarean, Aina Niemetz, Mathias Preiner - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * [[ Add lengthier description here ]] - * \todo document this file - */ -#include "theory/bv/abstraction.h" - -#include "expr/skolem_manager.h" -#include "options/bv_options.h" -#include "printer/printer.h" -#include "smt/dump.h" -#include "smt/smt_statistics_registry.h" -#include "theory/bv/theory_bv_utils.h" -#include "theory/rewriter.h" -#include "util/bitvector.h" - -using namespace cvc5; -using namespace cvc5::theory; -using namespace cvc5::theory::bv; -using namespace cvc5::context; - -using namespace std; -using namespace cvc5::theory::bv::utils; - -bool AbstractionModule::applyAbstraction(const std::vector<Node>& assertions, - std::vector<Node>& new_assertions) -{ - Debug("bv-abstraction") << "AbstractionModule::applyAbstraction\n"; - - TimerStat::CodeTimer abstractionTimer(d_statistics.d_abstractionTime); - - TNodeSet seen; - for (unsigned i = 0; i < assertions.size(); ++i) - { - if (assertions[i].getKind() == kind::OR) - { - for (unsigned j = 0; j < assertions[i].getNumChildren(); ++j) - { - if (!isConjunctionOfAtoms(assertions[i][j], seen)) - { - continue; - } - Node signature = computeSignature(assertions[i][j]); - storeSignature(signature, assertions[i][j]); - Debug("bv-abstraction") << " assertion: " << assertions[i][j] << "\n"; - Debug("bv-abstraction") << " signature: " << signature << "\n"; - } - } - } - finalizeSignatures(); - - for (unsigned i = 0; i < assertions.size(); ++i) - { - if (assertions[i].getKind() == kind::OR - && assertions[i][0].getKind() == kind::AND) - { - std::vector<Node> new_children; - for (unsigned j = 0; j < assertions[i].getNumChildren(); ++j) - { - if (hasSignature(assertions[i][j])) - { - new_children.push_back(abstractSignatures(assertions[i][j])); - } - else - { - new_children.push_back(assertions[i][j]); - } - } - new_assertions.push_back(utils::mkOr(new_children)); - } - else - { - // assertions that are not changed - new_assertions.push_back(assertions[i]); - } - } - - if (options::skolemizeArguments()) - { - skolemizeArguments(new_assertions); - } - - // if we are using the eager solver reverse the abstraction - if (options::bitblastMode() == options::BitblastMode::EAGER) - { - if (d_funcToSignature.size() == 0) - { - // we did not change anything - return false; - } - NodeNodeMap seen_rev; - for (unsigned i = 0; i < new_assertions.size(); ++i) - { - new_assertions[i] = reverseAbstraction(new_assertions[i], seen_rev); - } - // we undo the abstraction functions so the logic is QF_BV still - return true; - } - - // return true if we have created new function symbols for the problem - return d_funcToSignature.size() != 0; -} - -bool AbstractionModule::isConjunctionOfAtoms(TNode node, TNodeSet& seen) -{ - if (seen.find(node)!= seen.end()) - return true; - - if (!node.getType().isBitVector() && node.getKind() != kind::AND) - { - return utils::isBVPredicate(node); - } - - if (node.getNumChildren() == 0) - return true; - - for (unsigned i = 0; i < node.getNumChildren(); ++i) { - if (!isConjunctionOfAtoms(node[i], seen)) - { - return false; - } - } - seen.insert(node); - return true; -} - - -Node AbstractionModule::reverseAbstraction(Node assertion, NodeNodeMap& seen) { - - if (seen.find(assertion) != seen.end()) - return seen[assertion]; - - if (isAbstraction(assertion)) { - Node interp = getInterpretation(assertion); - seen[assertion] = interp; - Assert(interp.getType() == assertion.getType()); - return interp; - } - - if (assertion.getNumChildren() == 0) { - seen[assertion] = assertion; - return assertion; - } - - NodeBuilder result(assertion.getKind()); - if (assertion.getMetaKind() == kind::metakind::PARAMETERIZED) { - result << assertion.getOperator(); - } - - for (unsigned i = 0; i < assertion.getNumChildren(); ++i) { - result << reverseAbstraction(assertion[i], seen); - } - Node res = result; - seen[assertion] = res; - return res; -} - -void AbstractionModule::skolemizeArguments(std::vector<Node>& assertions) -{ - NodeManager* nm = NodeManager::currentNM(); - for (unsigned i = 0; i < assertions.size(); ++i) - { - TNode assertion = assertions[i]; - if (assertion.getKind() != kind::OR) continue; - - bool is_skolemizable = true; - for (unsigned k = 0; k < assertion.getNumChildren(); ++k) - { - if (assertion[k].getKind() != kind::EQUAL - || assertion[k][0].getKind() != kind::APPLY_UF - || assertion[k][1].getKind() != kind::CONST_BITVECTOR - || assertion[k][1].getConst<BitVector>() != BitVector(1, 1u)) - { - is_skolemizable = false; - break; - } - } - - if (!is_skolemizable) continue; - - ArgsTable assertion_table; - - // collect function symbols and their arguments - for (unsigned j = 0; j < assertion.getNumChildren(); ++j) - { - TNode current = assertion[j]; - Assert(current.getKind() == kind::EQUAL - && current[0].getKind() == kind::APPLY_UF); - TNode func = current[0]; - ArgsVec args; - for (unsigned k = 0; k < func.getNumChildren(); ++k) - { - args.push_back(func[k]); - } - assertion_table.addEntry(func.getOperator(), args); - } - - NodeBuilder assertion_builder(kind::OR); - // construct skolemized assertion - for (ArgsTable::iterator it = assertion_table.begin(); - it != assertion_table.end(); - ++it) - { - // for each function symbol - ++(d_statistics.d_numArgsSkolemized); - TNode func = it->first; - ArgsTableEntry& args = it->second; - NodeBuilder skolem_func(kind::APPLY_UF); - skolem_func << func; - std::vector<Node> skolem_args; - - for (unsigned j = 0; j < args.getArity(); ++j) - { - bool all_same = true; - for (unsigned k = 1; k < args.getNumEntries(); ++k) - { - if (args.getEntry(k)[j] != args.getEntry(0)[j]) all_same = false; - } - Node new_arg = all_same - ? (Node)args.getEntry(0)[j] - : utils::mkVar(utils::getSize(args.getEntry(0)[j])); - skolem_args.push_back(new_arg); - skolem_func << new_arg; - } - - Node skolem_func_eq1 = - nm->mkNode(kind::EQUAL, (Node)skolem_func, utils::mkConst(1, 1u)); - - // enumerate arguments assignments - std::vector<Node> or_assignments; - for (const ArgsVec& av : args) - // for (ArgsTableEntry::iterator it = args.begin(); it != args.end(); - // ++it) - { - NodeBuilder arg_assignment(kind::AND); - // ArgsVec& args = *it; - for (unsigned k = 0; k < av.size(); ++k) - { - Node eq = nm->mkNode(kind::EQUAL, av[k], skolem_args[k]); - arg_assignment << eq; - } - or_assignments.push_back(arg_assignment); - } - - Node new_func_def = - utils::mkAnd(skolem_func_eq1, utils::mkOr(or_assignments)); - assertion_builder << new_func_def; - } - Node new_assertion = assertion_builder; - Debug("bv-abstraction-dbg") << "AbstractionModule::skolemizeArguments " - << assertions[i] << " => \n"; - Debug("bv-abstraction-dbg") << " " << new_assertion; - assertions[i] = new_assertion; - } -} - -void AbstractionModule::storeSignature(Node signature, TNode assertion) { - if(d_signatures.find(signature) == d_signatures.end()) { - d_signatures[signature] = 0; - } - d_signatures[signature] = d_signatures[signature] + 1; - d_assertionToSignature[assertion] = signature; -} - -Node AbstractionModule::computeSignature(TNode node) { - resetSignatureIndex(); - NodeNodeMap cache; - Node sig = computeSignatureRec(node, cache); - return sig; -} - -Node AbstractionModule::getSignatureSkolem(TNode node) -{ - Assert(node.getMetaKind() == kind::metakind::VARIABLE); - NodeManager* nm = NodeManager::currentNM(); - SkolemManager* sm = nm->getSkolemManager(); - unsigned bitwidth = utils::getSize(node); - if (d_signatureSkolems.find(bitwidth) == d_signatureSkolems.end()) - { - d_signatureSkolems[bitwidth] = vector<Node>(); - } - - vector<Node>& skolems = d_signatureSkolems[bitwidth]; - // get the index of bv variables of this size - unsigned index = getBitwidthIndex(bitwidth); - Assert(skolems.size() + 1 >= index); - if (skolems.size() == index) - { - ostringstream os; - os << "sig_" << bitwidth << "_" << index; - skolems.push_back(sm->mkDummySkolem(os.str(), - nm->mkBitVectorType(bitwidth), - "skolem for computing signatures")); - } - ++(d_signatureIndices[bitwidth]); - return skolems[index]; -} - -unsigned AbstractionModule::getBitwidthIndex(unsigned bitwidth) { - if (d_signatureIndices.find(bitwidth) == d_signatureIndices.end()) { - d_signatureIndices[bitwidth] = 0; - } - return d_signatureIndices[bitwidth]; -} - -void AbstractionModule::resetSignatureIndex() { - for (IndexMap::iterator it = d_signatureIndices.begin(); it != d_signatureIndices.end(); ++it) { - it->second = 0; - } -} - -bool AbstractionModule::hasSignature(Node node) { - return d_assertionToSignature.find(node) != d_assertionToSignature.end(); -} - -Node AbstractionModule::getGeneralizedSignature(Node node) { - NodeNodeMap::const_iterator it = d_assertionToSignature.find(node); - Assert(it != d_assertionToSignature.end()); - Node generalized_signature = getGeneralization(it->second); - return generalized_signature; -} - -Node AbstractionModule::computeSignatureRec(TNode node, NodeNodeMap& cache) { - if (cache.find(node) != cache.end()) { - return cache.find(node)->second; - } - - if (node.getNumChildren() == 0) { - if (node.getKind() == kind::CONST_BITVECTOR) - return node; - - Node sig = getSignatureSkolem(node); - cache[node] = sig; - return sig; - } - - NodeBuilder builder(node.getKind()); - if (node.getMetaKind() == kind::metakind::PARAMETERIZED) { - builder << node.getOperator(); - } - for (unsigned i = 0; i < node.getNumChildren(); ++i) { - Node converted = computeSignatureRec(node[i], cache); - builder << converted; - } - Node result = builder; - cache[node] = result; - return result; -} - -/** - * Returns 0, if the two are equal, - * 1 if s is a generalization of t - * 2 if t is a generalization of s - * -1 if the two cannot be unified - * - * @param s - * @param t - * - * @return - */ -int AbstractionModule::comparePatterns(TNode s, TNode t) { - if (s.getKind() == kind::SKOLEM && - t.getKind() == kind::SKOLEM) { - return 0; - } - - if (s.getKind() == kind::CONST_BITVECTOR && - t.getKind() == kind::CONST_BITVECTOR) { - if (s == t) { - return 0; - } else { - return -1; - } - } - - if (s.getKind() == kind::SKOLEM && - t.getKind() == kind::CONST_BITVECTOR) { - return 1; - } - - if (s.getKind() == kind::CONST_BITVECTOR && - t.getKind() == kind::SKOLEM) { - return 2; - } - - if (s.getNumChildren() != t.getNumChildren() || - s.getKind() != t.getKind()) - return -1; - - int unify = 0; - for (unsigned i = 0; i < s.getNumChildren(); ++i) { - int unify_i = comparePatterns(s[i], t[i]); - if (unify_i < 0) - return -1; - if (unify == 0) { - unify = unify_i; - } else if (unify != unify_i && unify_i != 0) { - return -1; - } - } - return unify; -} - -TNode AbstractionModule::getGeneralization(TNode term) { - NodeNodeMap::iterator it = d_sigToGeneralization.find(term); - // if not in the map we add it - if (it == d_sigToGeneralization.end()) { - d_sigToGeneralization[term] = term; - return term; - } - // doesn't have a generalization - if (it->second == term) - return term; - - TNode generalization = getGeneralization(it->second); - Assert(generalization != term); - d_sigToGeneralization[term] = generalization; - return generalization; -} - -void AbstractionModule::storeGeneralization(TNode s, TNode t) { - Assert(s == getGeneralization(s)); - Assert(t == getGeneralization(t)); - d_sigToGeneralization[s] = t; -} - -void AbstractionModule::finalizeSignatures() -{ - NodeManager* nm = NodeManager::currentNM(); - SkolemManager* sm = nm->getSkolemManager(); - Debug("bv-abstraction") - << "AbstractionModule::finalizeSignatures num signatures = " - << d_signatures.size() << "\n"; - TNodeSet new_signatures; - - // "unify" signatures - for (SignatureMap::const_iterator ss = d_signatures.begin(); - ss != d_signatures.end(); - ++ss) - { - for (SignatureMap::const_iterator tt = ss; tt != d_signatures.end(); ++tt) - { - TNode t = getGeneralization(tt->first); - TNode s = getGeneralization(ss->first); - - if (t != s) - { - int status = comparePatterns(s, t); - Assert(status); - if (status < 0) continue; - if (status == 1) - { - storeGeneralization(t, s); - } - else - { - storeGeneralization(s, t); - } - } - } - } - // keep only most general signatures - for (SignatureMap::iterator it = d_signatures.begin(); - it != d_signatures.end();) - { - TNode sig = it->first; - TNode gen = getGeneralization(sig); - if (sig != gen) - { - Assert(d_signatures.find(gen) != d_signatures.end()); - // update the count - d_signatures[gen] += d_signatures[sig]; - d_signatures.erase(it++); - } - else - { - ++it; - } - } - - // remove signatures that are not frequent enough - for (SignatureMap::iterator it = d_signatures.begin(); - it != d_signatures.end();) - { - if (it->second <= 7) - { - d_signatures.erase(it++); - } - else - { - ++it; - } - } - - for (SignatureMap::const_iterator it = d_signatures.begin(); - it != d_signatures.end(); - ++it) - { - TNode signature = it->first; - // we already processed this signature - Assert(d_signatureToFunc.find(signature) == d_signatureToFunc.end()); - - Debug("bv-abstraction") << "Processing signature " << signature << " count " - << it->second << "\n"; - std::vector<TypeNode> arg_types; - TNodeSet seen; - collectArgumentTypes(signature, arg_types, seen); - Assert(signature.getType().isBoolean()); - // make function return a bitvector of size 1 - // Node bv_function = nm->mkNode(kind::ITE, signature, utils::mkConst(1, - // 1u), utils::mkConst(1, 0u)); - TypeNode range = nm->mkBitVectorType(1); - - TypeNode abs_type = nm->mkFunctionType(arg_types, range); - Node abs_func = sm->mkDummySkolem( - "abs_$$", abs_type, "abstraction function for bv theory"); - Debug("bv-abstraction") << " abstracted by function " << abs_func << "\n"; - - // NOTE: signature expression type is BOOLEAN - d_signatureToFunc[signature] = abs_func; - d_funcToSignature[abs_func] = signature; - } - - Debug("bv-abstraction") << "AbstractionModule::finalizeSignatures abstracted " - << d_signatureToFunc.size() << " signatures. \n"; -} - -void AbstractionModule::collectArgumentTypes(TNode sig, std::vector<TypeNode>& types, TNodeSet& seen) { - if (seen.find(sig) != seen.end()) - return; - - if (sig.getKind() == kind::SKOLEM) { - types.push_back(sig.getType()); - seen.insert(sig); - return; - } - - for (unsigned i = 0; i < sig.getNumChildren(); ++i) { - collectArgumentTypes(sig[i], types, seen); - seen.insert(sig); - } -} - -void AbstractionModule::collectArguments(TNode node, TNode signature, std::vector<Node>& args, TNodeSet& seen) { - if (seen.find(node)!= seen.end()) - return; - - if (node.getMetaKind() == kind::metakind::VARIABLE - || node.getKind() == kind::CONST_BITVECTOR) - { - // a constant in the node can either map to an argument of the abstraction - // or can be hard-coded and part of the abstraction - if (signature.getKind() == kind::SKOLEM) { - args.push_back(node); - seen.insert(node); - } else { - Assert(signature.getKind() == kind::CONST_BITVECTOR); - } - // - return; - } - Assert(node.getKind() == signature.getKind() - && node.getNumChildren() == signature.getNumChildren()); - - for (unsigned i = 0; i < node.getNumChildren(); ++i) { - collectArguments(node[i], signature[i], args, seen); - seen.insert(node); - } -} - -Node AbstractionModule::abstractSignatures(TNode assertion) -{ - Debug("bv-abstraction") << "AbstractionModule::abstractSignatures " - << assertion << "\n"; - NodeManager* nm = NodeManager::currentNM(); - // assume the assertion has been fully abstracted - Node signature = getGeneralizedSignature(assertion); - - Debug("bv-abstraction") << " with sig " << signature << "\n"; - NodeNodeMap::iterator it = d_signatureToFunc.find(signature); - if (it != d_signatureToFunc.end()) - { - std::vector<Node> args; - TNode func = it->second; - // pushing the function symbol - args.push_back(func); - TNodeSet seen; - collectArguments(assertion, signature, args, seen); - std::vector<TNode> real_args; - for (unsigned i = 1; i < args.size(); ++i) - { - real_args.push_back(args[i]); - } - d_argsTable.addEntry(func, real_args); - Node result = nm->mkNode( - kind::EQUAL, - nm->mkNode(kind::APPLY_UF, args), utils::mkConst(1, 1u)); - Debug("bv-abstraction") << "=> " << result << "\n"; - Assert(result.getType() == assertion.getType()); - return result; - } - return assertion; -} - -bool AbstractionModule::isAbstraction(TNode node) { - if (node.getKind() != kind::EQUAL) - return false; - if ((node[0].getKind() != kind::CONST_BITVECTOR || - node[1].getKind() != kind::APPLY_UF) && - (node[1].getKind() != kind::CONST_BITVECTOR || - node[0].getKind() != kind::APPLY_UF)) - return false; - - TNode constant = node[0].getKind() == kind::CONST_BITVECTOR ? node[0] : node[1]; - TNode func = node[0].getKind() == kind::APPLY_UF ? node[0] : node[1]; - Assert(constant.getKind() == kind::CONST_BITVECTOR - && func.getKind() == kind::APPLY_UF); - if (utils::getSize(constant) != 1) - return false; - if (constant != utils::mkConst(1, 1u)) - return false; - - TNode func_symbol = func.getOperator(); - if (d_funcToSignature.find(func_symbol) == d_funcToSignature.end()) - return false; - - return true; -} - -Node AbstractionModule::getInterpretation(TNode node) { - Assert(isAbstraction(node)); - TNode constant = node[0].getKind() == kind::CONST_BITVECTOR ? node[0] : node[1]; - TNode apply = node[0].getKind() == kind::APPLY_UF ? node[0] : node[1]; - Assert(constant.getKind() == kind::CONST_BITVECTOR - && apply.getKind() == kind::APPLY_UF); - - Node func = apply.getOperator(); - Assert(d_funcToSignature.find(func) != d_funcToSignature.end()); - - Node sig = d_funcToSignature[func]; - - // substitute arguments in signature - TNodeTNodeMap seen; - unsigned index = 0; - Node result = substituteArguments(sig, apply, index, seen); - Assert(result.getType().isBoolean()); - Assert(index == apply.getNumChildren()); - // Debug("bv-abstraction") << "AbstractionModule::getInterpretation " << node << "\n"; - // Debug("bv-abstraction") << " => " << result << "\n"; - return result; -} - -Node AbstractionModule::substituteArguments(TNode signature, TNode apply, unsigned& index, TNodeTNodeMap& seen) { - if (seen.find(signature) != seen.end()) { - return seen[signature]; - } - - if (signature.getKind() == kind::SKOLEM) { - // return corresponding argument and increment counter - seen[signature] = apply[index]; - return apply[index++]; - } - - if (signature.getNumChildren() == 0) { - Assert(signature.getMetaKind() != kind::metakind::VARIABLE); - seen[signature] = signature; - return signature; - } - - NodeBuilder builder(signature.getKind()); - if (signature.getMetaKind() == kind::metakind::PARAMETERIZED) { - builder << signature.getOperator(); - } - - for (unsigned i = 0; i < signature.getNumChildren(); ++i) { - Node child = substituteArguments(signature[i], apply, index, seen); - builder << child; - } - - Node result = builder; - seen[signature]= result; - - return result; -} - -Node AbstractionModule::simplifyConflict(TNode conflict) { - Debug("bv-abstraction-dbg") << "AbstractionModule::simplifyConflict " << conflict << "\n"; - if (conflict.getKind() != kind::AND) - return conflict; - - std::vector<Node> conjuncts; - for (unsigned i = 0; i < conflict.getNumChildren(); ++i) - conjuncts.push_back(conflict[i]); - - theory::SubstitutionMap subst(new context::Context()); - for (unsigned i = 0; i < conjuncts.size(); ++i) { - TNode conjunct = conjuncts[i]; - // substitute s -> t - Node s, t; - - if (conjunct.getKind() == kind::EQUAL) { - if (conjunct[0].getMetaKind() == kind::metakind::VARIABLE && - conjunct[1].getKind() == kind::CONST_BITVECTOR) { - s = conjunct[0]; - t = conjunct[1]; - } - else if (conjunct[1].getMetaKind() == kind::metakind::VARIABLE && - conjunct[0].getKind() == kind::CONST_BITVECTOR) { - s = conjunct[1]; - t = conjunct[0]; - } else { - continue; - } - - Assert(!subst.hasSubstitution(s)); - Assert(!t.isNull() && !s.isNull() && s != t); - subst.addSubstitution(s, t); - - for (unsigned k = 0; k < conjuncts.size(); k++) { - conjuncts[k] = subst.apply(conjuncts[k]); - } - } - } - Node new_conflict = Rewriter::rewrite(utils::mkAnd(conjuncts)); - - Debug("bv-abstraction") << "AbstractionModule::simplifyConflict conflict " << conflict <<"\n"; - Debug("bv-abstraction") << " => " << new_conflict <<"\n"; - - return new_conflict; -} - -void DebugPrintInstantiations( - const std::vector<std::vector<ArgsVec> >& instantiations, - const std::vector<TNode>& functions) -{ - // print header - Debug("bv-abstraction-dbg") <<"[ "; - for (unsigned i = 0; i < functions.size(); ++i) { - for (unsigned j = 1; j < functions[i].getNumChildren(); ++j) { - Debug("bv-abstraction-dgb") << functions[i][j] <<" "; - } - Debug("bv-abstraction-dgb") << " || "; - } - Debug("bv-abstraction-dbg") <<"]\n"; - - for (unsigned i = 0; i < instantiations.size(); ++i) { - Debug("bv-abstraction-dbg") <<"["; - const std::vector<ArgsVec>& inst = instantiations[i]; - for (unsigned j = 0; j < inst.size(); ++j) { - for (unsigned k = 0; k < inst[j].size(); ++k) { - Debug("bv-abstraction-dbg") << inst[j][k] << " "; - } - Debug("bv-abstraction-dbg") << " || "; - } - Debug("bv-abstraction-dbg") <<"]\n"; - } -} - -void AbstractionModule::generalizeConflict(TNode conflict, std::vector<Node>& lemmas) { - Debug("bv-abstraction") << "AbstractionModule::generalizeConflict " << conflict << "\n"; - std::vector<TNode> functions; - - // collect abstract functions - if (conflict.getKind() != kind::AND) { - if (isAbstraction(conflict)) { - Assert(conflict[0].getKind() == kind::APPLY_UF); - functions.push_back(conflict[0]); - } - } else { - for (unsigned i = 0; i < conflict.getNumChildren(); ++i) { - TNode conjunct = conflict[i]; - if (isAbstraction(conjunct)) { - Assert(conjunct[0].getKind() == kind::APPLY_UF); - functions.push_back(conjunct[0]); - } - } - } - - // if (functions.size() >= 3) { - // // dump conflict - // NodeNodeMap seen; - // Node reversed = reverseAbstraction(conflict, seen); - // std::cout << "CONFLICT " << reversed << "\n"; - // } - - - if (functions.size() == 0 || functions.size() > options::bvNumFunc()) { - return; - } - - - // Skolemize function arguments to avoid confusion in pattern matching - SubstitutionMap skolem_subst(new context::Context()); - SubstitutionMap reverse_skolem(new context::Context()); - makeFreshSkolems(conflict, skolem_subst, reverse_skolem); - - Node skolemized_conflict = skolem_subst.apply(conflict); - for (unsigned i = 0; i < functions.size(); ++i) { - functions[i] = skolem_subst.apply(functions[i]); - } - - conflict = skolem_subst.apply(conflict); - - LemmaInstantiatior inst(functions, d_argsTable, conflict); - std::vector<Node> new_lemmas; - inst.generateInstantiations(new_lemmas); - for (unsigned i = 0; i < new_lemmas.size(); ++i) { - TNode lemma = reverse_skolem.apply(new_lemmas[i]); - if (d_addedLemmas.find(lemma) == d_addedLemmas.end()) { - lemmas.push_back(lemma); - Debug("bv-abstraction-gen") << "adding lemma " << lemma << "\n"; - storeLemma(lemma); - } - } -} - -int AbstractionModule::LemmaInstantiatior::next(int val, int index) { - if (val < d_maxMatch[index] - 1) - return val + 1; - return -1; -} - -/** - * Assumes the stack without top is consistent, and checks that the - * full stack is consistent - * - * @param stack - * - * @return - */ -bool AbstractionModule::LemmaInstantiatior::isConsistent(const vector<int>& stack) { - if (stack.empty()) - return true; - - unsigned current = stack.size() - 1; - TNode func = d_functions[current]; - ArgsTableEntry& matches = d_argsTable.getEntry(func.getOperator()); - ArgsVec& args = matches.getEntry(stack[current]); - Assert(args.size() == func.getNumChildren()); - for (unsigned k = 0; k < args.size(); ++k) { - TNode s = func[k]; - TNode t = args[k]; - - TNode s0 = s; - while (d_subst.hasSubstitution(s0)) { - s0 = d_subst.getSubstitution(s0); - } - - TNode t0 = t; - while (d_subst.hasSubstitution(t0)) { - t0 = d_subst.getSubstitution(t0); - } - - if (s0.isConst() && t0.isConst()) { - if (s0 != t0) - return false; // fail - else - continue; - } - - if(s0.getMetaKind() == kind::metakind::VARIABLE && - t0.isConst()) { - d_subst.addSubstitution(s0, t0); - continue; - } - - if (s0.isConst() && - t0.getMetaKind() == kind::metakind::VARIABLE) { - d_subst.addSubstitution(t0, s0); - continue; - } - - Assert(s0.getMetaKind() == kind::metakind::VARIABLE - && t0.getMetaKind() == kind::metakind::VARIABLE); - - if (s0 != t0) { - d_subst.addSubstitution(s0, t0); - } - } - return true; -} - -bool AbstractionModule::LemmaInstantiatior::accept(const vector<int>& stack) { - return stack.size() == d_functions.size(); -} - -void AbstractionModule::LemmaInstantiatior::mkLemma() { - Node lemma = d_subst.apply(d_conflict); - // Debug("bv-abstraction-gen") << "AbstractionModule::LemmaInstantiatior::mkLemma " << lemma <<"\n"; - d_lemmas.push_back(lemma); -} - -void AbstractionModule::LemmaInstantiatior::backtrack(vector<int>& stack) { - if (!isConsistent(stack)) - return; - - if (accept(stack)) { - mkLemma(); - return; - } - - int x = 0; - while (x != -1) { - d_ctx->push(); - stack.push_back(x); - backtrack(stack); - - d_ctx->pop(); - stack.pop_back(); - x = next(x, stack.size()); - } -} - - -void AbstractionModule::LemmaInstantiatior::generateInstantiations(std::vector<Node>& lemmas) { - Debug("bv-abstraction-gen") << "AbstractionModule::LemmaInstantiatior::generateInstantiations "; - - std::vector<int> stack; - backtrack(stack); - Assert(d_ctx->getLevel() == 0); - Debug("bv-abstraction-gen") << "numLemmas=" << d_lemmas.size() <<"\n"; - lemmas.swap(d_lemmas); -} - -void AbstractionModule::makeFreshSkolems(TNode node, SubstitutionMap& map, SubstitutionMap& reverse_map) { - if (map.hasSubstitution(node)) { - return; - } - if (node.getMetaKind() == kind::metakind::VARIABLE) { - Node skolem = utils::mkVar(utils::getSize(node)); - map.addSubstitution(node, skolem); - reverse_map.addSubstitution(skolem, node); - return; - } - if (node.isConst()) - return; - - for (unsigned i = 0; i < node.getNumChildren(); ++i) { - makeFreshSkolems(node[i], map, reverse_map); - } -} - -void AbstractionModule::makeFreshArgs(TNode func, std::vector<Node>& fresh_args) { - Assert(fresh_args.size() == 0); - Assert(func.getKind() == kind::APPLY_UF); - TNodeNodeMap d_map; - for (unsigned i = 0; i < func.getNumChildren(); ++i) { - TNode arg = func[i]; - if (arg.isConst()) { - fresh_args.push_back(arg); - continue; - } - Assert(arg.getMetaKind() == kind::metakind::VARIABLE); - TNodeNodeMap::iterator it = d_map.find(arg); - if (it != d_map.end()) { - fresh_args.push_back(it->second); - } else { - Node skolem = utils::mkVar(utils::getSize(arg)); - d_map[arg] = skolem; - fresh_args.push_back(skolem); - } - } - Assert(fresh_args.size() == func.getNumChildren()); -} - -Node AbstractionModule::tryMatching(const std::vector<Node>& ss, const std::vector<TNode>& tt, TNode conflict) { - Assert(ss.size() == tt.size()); - - Debug("bv-abstraction-dbg") << "AbstractionModule::tryMatching conflict = " << conflict << "\n"; - if (Debug.isOn("bv-abstraction-dbg")) { - Debug("bv-abstraction-dbg") << " Match: "; - for (unsigned i = 0; i < ss.size(); ++i) { - Debug("bv-abstraction-dbg") << ss[i] <<" "; - - } - Debug("bv-abstraction-dbg") << "\n To: "; - for (unsigned i = 0; i < tt.size(); ++i) { - Debug("bv-abstraction-dbg") << tt[i] <<" "; - } - Debug("bv-abstraction-dbg") <<"\n"; - } - - - SubstitutionMap subst(new context::Context()); - - for (unsigned i = 0; i < ss.size(); ++i) { - TNode s = ss[i]; - TNode t = tt[i]; - - TNode s0 = subst.hasSubstitution(s) ? subst.getSubstitution(s) : s; - TNode t0 = subst.hasSubstitution(t) ? subst.getSubstitution(t) : t; - - if (s0.isConst() && t0.isConst()) { - if (s0 != t0) - return Node(); // fail - else - continue; - } - - if(s0.getMetaKind() == kind::metakind::VARIABLE && - t0.isConst()) { - subst.addSubstitution(s0, t0); - continue; - } - - if (s0.isConst() && - t0.getMetaKind() == kind::metakind::VARIABLE) { - subst.addSubstitution(t0, s0); - continue; - } - - Assert(s0.getMetaKind() == kind::metakind::VARIABLE - && t0.getMetaKind() == kind::metakind::VARIABLE); - - Assert(s0 != t0); - subst.addSubstitution(s0, t0); - } - - Node res = subst.apply(conflict); - Debug("bv-abstraction-dbg") << " Lemma: " << res <<"\n"; - return res; -} - -void AbstractionModule::storeLemma(TNode lemma) { - d_addedLemmas.insert(lemma); - if (lemma.getKind() == kind::AND) { - for (unsigned i = 0; i < lemma.getNumChildren(); i++) { - TNode atom = lemma[i]; - atom = atom.getKind() == kind::NOT ? atom[0] : atom; - Assert(atom.getKind() != kind::NOT); - Assert(utils::isBVPredicate(atom)); - d_lemmaAtoms.insert(atom); - } - } else { - lemma = lemma.getKind() == kind::NOT? lemma[0] : lemma; - Assert(utils::isBVPredicate(lemma)); - d_lemmaAtoms.insert(lemma); - } -} - - -bool AbstractionModule::isLemmaAtom(TNode node) const { - Assert(node.getType().isBoolean()); - node = node.getKind() == kind::NOT? node[0] : node; - - return d_inputAtoms.find(node) == d_inputAtoms.end() && - d_lemmaAtoms.find(node) != d_lemmaAtoms.end(); -} - -void AbstractionModule::addInputAtom(TNode atom) { - if (options::bitblastMode() == options::BitblastMode::LAZY) - { - d_inputAtoms.insert(atom); - } -} - -void AbstractionModule::ArgsTableEntry::addArguments(const ArgsVec& args) { - Assert(args.size() == d_arity); - d_data.push_back(args); -} - -void AbstractionModule::ArgsTable::addEntry(TNode signature, const ArgsVec& args) { - if (d_data.find(signature) == d_data.end()) { - d_data[signature] = ArgsTableEntry(args.size()); - } - ArgsTableEntry& entry = d_data[signature]; - entry.addArguments(args); -} - - -bool AbstractionModule::ArgsTable::hasEntry(TNode signature) const { - return d_data.find(signature) != d_data.end(); -} - -AbstractionModule::ArgsTableEntry& AbstractionModule::ArgsTable::getEntry(TNode signature) { - Assert(hasEntry(signature)); - return d_data.find(signature)->second; -} - -AbstractionModule::Statistics::Statistics( - const std::string& name, const NodeNodeMap& functionsAbstracted) - : d_numFunctionsAbstracted( - smtStatisticsRegistry().registerSize<NodeNodeMap>( - name + "NumFunctionsAbstracted", functionsAbstracted)), - d_numArgsSkolemized( - smtStatisticsRegistry().registerInt(name + "NumArgsSkolemized")), - d_abstractionTime( - smtStatisticsRegistry().registerTimer(name + "AbstractionTime")) -{ -} diff --git a/src/theory/bv/abstraction.h b/src/theory/bv/abstraction.h deleted file mode 100644 index 7eea90cdc..000000000 --- a/src/theory/bv/abstraction.h +++ /dev/null @@ -1,248 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Liana Hadarean, Tim King, Mathias Preiner - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * Bitvector theory. - */ - -#include "cvc5_private.h" - -#ifndef CVC5__THEORY__BV__ABSTRACTION_H -#define CVC5__THEORY__BV__ABSTRACTION_H - -#include <unordered_map> -#include <unordered_set> - -#include "expr/node.h" -#include "theory/substitutions.h" -#include "util/statistics_stats.h" - -namespace cvc5 { -namespace theory { -namespace bv { - -typedef std::vector<TNode> ArgsVec; - -class AbstractionModule { - using NodeVecMap = std::unordered_map<Node, std::vector<Node>>; - using NodeTNodeMap = std::unordered_map<Node, TNode>; - using TNodeTNodeMap = std::unordered_map<TNode, TNode>; - using NodeNodeMap = std::unordered_map<Node, Node>; - using TNodeNodeMap = std::unordered_map<Node, TNode>; - using TNodeSet = std::unordered_set<TNode>; - using IntNodeMap = std::unordered_map<unsigned, Node>; - using IndexMap = std::unordered_map<unsigned, unsigned>; - using SkolemMap = std::unordered_map<unsigned, std::vector<Node> >; - using SignatureMap = std::unordered_map<TNode, unsigned>; - - struct Statistics { - SizeStat<NodeNodeMap> d_numFunctionsAbstracted; - IntStat d_numArgsSkolemized; - TimerStat d_abstractionTime; - Statistics(const std::string& name, const NodeNodeMap& functionsAbstracted); - }; - - - class ArgsTableEntry { - std::vector<ArgsVec> d_data; - unsigned d_arity; - public: - ArgsTableEntry(unsigned n) - : d_arity(n) - {} - ArgsTableEntry() - : d_arity(0) - {} - void addArguments(const ArgsVec& args); - typedef std::vector<ArgsVec>::iterator iterator; - - iterator begin() { return d_data.begin(); } - iterator end() { return d_data.end(); } - unsigned getArity() { return d_arity; } - unsigned getNumEntries() { return d_data.size(); } - ArgsVec& getEntry(unsigned i) - { - Assert(i < d_data.size()); - return d_data[i]; - } - }; - - class ArgsTable { - std::unordered_map<TNode, ArgsTableEntry> d_data; - bool hasEntry(TNode signature) const; - public: - typedef std::unordered_map<TNode, ArgsTableEntry>::iterator iterator; - ArgsTable() {} - void addEntry(TNode signature, const ArgsVec& args); - ArgsTableEntry& getEntry(TNode signature); - iterator begin() { return d_data.begin(); } - iterator end() { return d_data.end(); } - }; - - /** - * Checks if one pattern is a generalization of the other - * - * @param s - * @param t - * - * @return 1 if s :> t, 2 if s <: t, 0 if they equivalent and -1 if they are incomparable - */ - static int comparePatterns(TNode s, TNode t); - - class LemmaInstantiatior { - std::vector<TNode> d_functions; - std::vector<int> d_maxMatch; - ArgsTable& d_argsTable; - context::Context* d_ctx; - theory::SubstitutionMap d_subst; - TNode d_conflict; - std::vector<Node> d_lemmas; - - void backtrack(std::vector<int>& stack); - int next(int val, int index); - bool isConsistent(const std::vector<int>& stack); - bool accept(const std::vector<int>& stack); - void mkLemma(); - public: - LemmaInstantiatior(const std::vector<TNode>& functions, ArgsTable& table, TNode conflict) - : d_functions(functions) - , d_argsTable(table) - , d_ctx(new context::Context()) - , d_subst(d_ctx) - , d_conflict(conflict) - , d_lemmas() - { - Debug("bv-abstraction-gen") << "LemmaInstantiator conflict:" << conflict << "\n"; - // initializing the search space - for (unsigned i = 0; i < functions.size(); ++i) { - TNode func_op = functions[i].getOperator(); - // number of matches for this function - unsigned maxCount = table.getEntry(func_op).getNumEntries(); - d_maxMatch.push_back(maxCount); - } - } - - void generateInstantiations(std::vector<Node>& lemmas); - - }; - - ArgsTable d_argsTable; - - // mapping between signature and uninterpreted function symbol used to - // abstract the signature - NodeNodeMap d_signatureToFunc; - NodeNodeMap d_funcToSignature; - - NodeNodeMap d_assertionToSignature; - SignatureMap d_signatures; - NodeNodeMap d_sigToGeneralization; - TNodeSet d_skolems; - - // skolems maps - IndexMap d_signatureIndices; - SkolemMap d_signatureSkolems; - - void collectArgumentTypes(TNode sig, std::vector<TypeNode>& types, TNodeSet& seen); - void collectArguments(TNode node, TNode sig, std::vector<Node>& args, TNodeSet& seen); - void finalizeSignatures(); - Node abstractSignatures(TNode assertion); - Node computeSignature(TNode node); - - bool isConjunctionOfAtoms(TNode node, TNodeSet& seen); - - TNode getGeneralization(TNode term); - void storeGeneralization(TNode s, TNode t); - - // signature skolem stuff - Node getGeneralizedSignature(Node node); - Node getSignatureSkolem(TNode node); - - unsigned getBitwidthIndex(unsigned bitwidth); - void resetSignatureIndex(); - Node computeSignatureRec(TNode, NodeNodeMap&); - void storeSignature(Node signature, TNode assertion); - bool hasSignature(Node node); - - Node substituteArguments(TNode signature, TNode apply, unsigned& i, TNodeTNodeMap& seen); - - // crazy instantiation methods - void generateInstantiations(unsigned current, - std::vector<ArgsTableEntry>& matches, - std::vector<std::vector<ArgsVec> >& instantiations, - std::vector<std::vector<ArgsVec> >& new_instantiations); - - Node tryMatching(const std::vector<Node>& ss, const std::vector<TNode>& tt, TNode conflict); - void makeFreshArgs(TNode func, std::vector<Node>& fresh_args); - void makeFreshSkolems(TNode node, SubstitutionMap& map, SubstitutionMap& reverse_map); - - void skolemizeArguments(std::vector<Node>& assertions); - Node reverseAbstraction(Node assertion, NodeNodeMap& seen); - - TNodeSet d_addedLemmas; - TNodeSet d_lemmaAtoms; - TNodeSet d_inputAtoms; - void storeLemma(TNode lemma); - - Statistics d_statistics; - -public: - AbstractionModule(const std::string& name) - : d_argsTable(), - d_signatureToFunc(), - d_funcToSignature(), - d_assertionToSignature(), - d_signatures(), - d_sigToGeneralization(), - d_skolems(), - d_signatureIndices(), - d_signatureSkolems(), - d_addedLemmas(), - d_lemmaAtoms(), - d_inputAtoms(), - d_statistics(name + "abstraction::", d_signatureToFunc) - { - } - /** - * returns true if there are new uninterepreted functions symbols in the output - * - * @param assertions - * @param new_assertions - * - * @return - */ - bool applyAbstraction(const std::vector<Node>& assertions, std::vector<Node>& new_assertions); - /** - * Returns true if the node represents an abstraction predicate. - * - * @param node - * - * @return - */ - bool isAbstraction(TNode node); - /** - * Returns the interpretation of the abstraction predicate. - * - * @param node - * - * @return - */ - Node getInterpretation(TNode node); - Node simplifyConflict(TNode conflict); - void generalizeConflict(TNode conflict, std::vector<Node>& lemmas); - void addInputAtom(TNode atom); - bool isLemmaAtom(TNode node) const; -}; - -} -} -} // namespace cvc5 - -#endif diff --git a/src/theory/bv/bitblast/aig_bitblaster.cpp b/src/theory/bv/bitblast/aig_bitblaster.cpp deleted file mode 100644 index 8fece032c..000000000 --- a/src/theory/bv/bitblast/aig_bitblaster.cpp +++ /dev/null @@ -1,492 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Liana Hadarean, Mathias Preiner, Tim King - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * AIG bitblaster. - */ - -#include "theory/bv/bitblast/aig_bitblaster.h" - -#include "base/check.h" -#include "cvc5_private.h" -#include "options/bv_options.h" -#include "prop/cnf_stream.h" -#include "prop/sat_solver.h" -#include "prop/sat_solver_factory.h" -#include "smt/smt_statistics_registry.h" - -#ifdef CVC5_USE_ABC - -extern "C" { -#include "base/abc/abc.h" -#include "base/main/main.h" -#include "sat/cnf/cnf.h" - -extern Aig_Man_t* Abc_NtkToDar(Abc_Ntk_t* pNtk, int fExors, int fRegisters); -} - -// Function is defined as static in ABC. Not sure how else to do this. -static inline int Cnf_Lit2Var(int Lit) -{ - return (Lit & 1) ? -(Lit >> 1) - 1 : (Lit >> 1) + 1; -} - -namespace cvc5 { -namespace theory { -namespace bv { - -template <> inline -std::string toString<Abc_Obj_t*> (const std::vector<Abc_Obj_t*>& bits) { - Unreachable() << "Don't know how to print AIG"; -} - - -template <> inline -Abc_Obj_t* mkTrue<Abc_Obj_t*>() { - return Abc_AigConst1(AigBitblaster::currentAigNtk()); -} - -template <> inline -Abc_Obj_t* mkFalse<Abc_Obj_t*>() { - return Abc_ObjNot(mkTrue<Abc_Obj_t*>()); -} - -template <> inline -Abc_Obj_t* mkNot<Abc_Obj_t*>(Abc_Obj_t* a) { - return Abc_ObjNot(a); -} - -template <> inline -Abc_Obj_t* mkOr<Abc_Obj_t*>(Abc_Obj_t* a, Abc_Obj_t* b) { - return Abc_AigOr(AigBitblaster::currentAigM(), a, b); -} - -template <> inline -Abc_Obj_t* mkOr<Abc_Obj_t*>(const std::vector<Abc_Obj_t*>& children) { - Assert(children.size()); - if (children.size() == 1) - return children[0]; - - Abc_Obj_t* result = children[0]; - for (unsigned i = 1; i < children.size(); ++i) { - result = Abc_AigOr(AigBitblaster::currentAigM(), result, children[i]); - } - return result; -} - - -template <> inline -Abc_Obj_t* mkAnd<Abc_Obj_t*>(Abc_Obj_t* a, Abc_Obj_t* b) { - return Abc_AigAnd(AigBitblaster::currentAigM(), a, b); -} - -template <> inline -Abc_Obj_t* mkAnd<Abc_Obj_t*>(const std::vector<Abc_Obj_t*>& children) { - Assert(children.size()); - if (children.size() == 1) - return children[0]; - - Abc_Obj_t* result = children[0]; - for (unsigned i = 1; i < children.size(); ++i) { - result = Abc_AigAnd(AigBitblaster::currentAigM(), result, children[i]); - } - return result; -} - -template <> inline -Abc_Obj_t* mkXor<Abc_Obj_t*>(Abc_Obj_t* a, Abc_Obj_t* b) { - return Abc_AigXor(AigBitblaster::currentAigM(), a, b); -} - -template <> inline -Abc_Obj_t* mkIff<Abc_Obj_t*>(Abc_Obj_t* a, Abc_Obj_t* b) { - return mkNot(mkXor(a, b)); -} - -template <> inline -Abc_Obj_t* mkIte<Abc_Obj_t*>(Abc_Obj_t* cond, Abc_Obj_t* a, Abc_Obj_t* b) { - return Abc_AigMux(AigBitblaster::currentAigM(), cond, a, b); -} - -thread_local Abc_Ntk_t* AigBitblaster::s_abcAigNetwork = nullptr; - -Abc_Ntk_t* AigBitblaster::currentAigNtk() { - if (!AigBitblaster::s_abcAigNetwork) { - Abc_Start(); - s_abcAigNetwork = Abc_NtkAlloc( ABC_NTK_STRASH, ABC_FUNC_AIG, 1); - char pName[] = "cvc5::theory::bv::AigNetwork"; - s_abcAigNetwork->pName = Extra_UtilStrsav(pName); - } - - return s_abcAigNetwork; -} - - -Abc_Aig_t* AigBitblaster::currentAigM() { - return (Abc_Aig_t*)(currentAigNtk()->pManFunc); -} - -AigBitblaster::AigBitblaster() - : TBitblaster<Abc_Obj_t*>(), - d_nullContext(new context::Context()), - d_aigCache(), - d_bbAtoms(), - d_aigOutputNode(NULL), - d_notify() -{ - prop::SatSolver* solver = nullptr; - switch (options::bvSatSolver()) - { - case options::SatSolverMode::MINISAT: - { - prop::BVSatSolverInterface* minisat = - prop::SatSolverFactory::createMinisat(d_nullContext.get(), - smtStatisticsRegistry(), - "theory::bv::AigBitblaster::"); - d_notify.reset(new MinisatEmptyNotify()); - minisat->setNotify(d_notify.get()); - solver = minisat; - break; - } - case options::SatSolverMode::CADICAL: - solver = prop::SatSolverFactory::createCadical( - smtStatisticsRegistry(), "theory::bv::AigBitblaster::"); - break; - case options::SatSolverMode::CRYPTOMINISAT: - solver = prop::SatSolverFactory::createCryptoMinisat( - smtStatisticsRegistry(), "theory::bv::AigBitblaster::"); - break; - case options::SatSolverMode::KISSAT: - solver = prop::SatSolverFactory::createKissat( - smtStatisticsRegistry(), "theory::bv::AigBitblaster::"); - break; - default: CVC5_FATAL() << "Unknown SAT solver type"; - } - d_satSolver.reset(solver); -} - -AigBitblaster::~AigBitblaster() {} - -Abc_Obj_t* AigBitblaster::bbFormula(TNode node) { - Assert(node.getType().isBoolean()); - Debug("bitvector-bitblast") << "AigBitblaster::bbFormula "<< node << "\n"; - - if (hasAig(node)) - return getAig(node); - - Abc_Obj_t* result = NULL; - - Debug("bitvector-aig") << "AigBitblaster::convertToAig " << node <<"\n"; - switch (node.getKind()) { - case kind::AND: - { - result = bbFormula(node[0]); - for (unsigned i = 1; i < node.getNumChildren(); ++i) { - Abc_Obj_t* child = bbFormula(node[i]); - result = mkAnd(result, child); - } - break; - } - case kind::OR: - { - result = bbFormula(node[0]); - for (unsigned i = 1; i < node.getNumChildren(); ++i) { - Abc_Obj_t* child = bbFormula(node[i]); - result = mkOr(result, child); - } - break; - } - case kind::XOR: - { - result = bbFormula(node[0]); - for (unsigned i = 1; i < node.getNumChildren(); ++i) { - Abc_Obj_t* child = bbFormula(node[i]); - result = mkXor(result, child); - } - break; - } - case kind::IMPLIES: - { - Assert(node.getNumChildren() == 2); - Abc_Obj_t* child1 = bbFormula(node[0]); - Abc_Obj_t* child2 = bbFormula(node[1]); - - result = mkOr(mkNot(child1), child2); - break; - } - case kind::ITE: - { - Assert(node.getNumChildren() == 3); - Abc_Obj_t* a = bbFormula(node[0]); - Abc_Obj_t* b = bbFormula(node[1]); - Abc_Obj_t* c = bbFormula(node[2]); - result = mkIte(a, b, c); - break; - } - case kind::NOT: - { - Abc_Obj_t* child1 = bbFormula(node[0]); - result = mkNot(child1); - break; - } - case kind::CONST_BOOLEAN: - { - result = node.getConst<bool>() ? mkTrue<Abc_Obj_t*>() : mkFalse<Abc_Obj_t*>(); - break; - } - case kind::EQUAL: - { - if( node[0].getType().isBoolean() ){ - Assert(node.getNumChildren() == 2); - Abc_Obj_t* child1 = bbFormula(node[0]); - Abc_Obj_t* child2 = bbFormula(node[1]); - - result = mkIff(child1, child2); - break; - } - //else, continue... - } - default: - if( node.isVar() ){ - result = mkInput(node); - }else{ - bbAtom(node); - result = getBBAtom(node); - } - } - - cacheAig(node, result); - Debug("bitvector-aig") << "AigBitblaster::bbFormula done " << node << " => " << result <<"\n"; - return result; -} - -void AigBitblaster::bbAtom(TNode node) { - if (hasBBAtom(node)) { - return; - } - - Debug("bitvector-bitblast") << "Bitblasting atom " << node <<"\n"; - - // the bitblasted definition of the atom - Node normalized = Rewriter::rewrite(node); - Abc_Obj_t* atom_bb = (d_atomBBStrategies[normalized.getKind()])(normalized, this); - storeBBAtom(node, atom_bb); - Debug("bitvector-bitblast") << "Done bitblasting atom " << node <<"\n"; -} - -void AigBitblaster::bbTerm(TNode node, Bits& bits) { - if (hasBBTerm(node)) { - getBBTerm(node, bits); - return; - } - Assert(node.getType().isBitVector()); - - Debug("bitvector-bitblast") << "Bitblasting term " << node <<"\n"; - d_termBBStrategies[node.getKind()] (node, bits, this); - - Assert(bits.size() == utils::getSize(node)); - storeBBTerm(node, bits); -} - - -void AigBitblaster::cacheAig(TNode node, Abc_Obj_t* aig) { - Assert(!hasAig(node)); - d_aigCache.insert(std::make_pair(node, aig)); -} -bool AigBitblaster::hasAig(TNode node) { - return d_aigCache.find(node) != d_aigCache.end(); -} -Abc_Obj_t* AigBitblaster::getAig(TNode node) { - Assert(hasAig(node)); - Debug("bitvector-aig") << "AigSimplifer::getAig " << node << " => " << d_aigCache.find(node)->second <<"\n"; - return d_aigCache.find(node)->second; -} - -void AigBitblaster::makeVariable(TNode node, Bits& bits) { - - for (unsigned i = 0; i < utils::getSize(node); ++i) { - Node bit = utils::mkBitOf(node, i); - Abc_Obj_t* input = mkInput(bit); - cacheAig(bit, input); - bits.push_back(input); - } -} - -Abc_Obj_t* AigBitblaster::mkInput(TNode input) { - Assert(!hasInput(input)); - Assert(input.getKind() == kind::BITVECTOR_BITOF - || (input.getType().isBoolean() && input.isVar())); - Abc_Obj_t* aig_input = Abc_NtkCreatePi(currentAigNtk()); - // d_aigCache.insert(std::make_pair(input, aig_input)); - d_nodeToAigInput.insert(std::make_pair(input, aig_input)); - Debug("bitvector-aig") << "AigSimplifer::mkInput " << input << " " << aig_input <<"\n"; - return aig_input; -} - -bool AigBitblaster::hasInput(TNode input) { - return d_nodeToAigInput.find(input) != d_nodeToAigInput.end(); -} - -bool AigBitblaster::solve(TNode node) { - // setting output of network to be the query - Assert(d_aigOutputNode == NULL); - Abc_Obj_t* query = bbFormula(node); - d_aigOutputNode = Abc_NtkCreatePo(currentAigNtk()); - Abc_ObjAddFanin(d_aigOutputNode, query); - - simplifyAig(); - convertToCnfAndAssert(); - // no need to use abc anymore - - TimerStat::CodeTimer solveTimer(d_statistics.d_solveTime); - prop::SatValue result = d_satSolver->solve(); - - Assert(result != prop::SAT_VALUE_UNKNOWN); - return result == prop::SAT_VALUE_TRUE; -} - - -void addAliases(Abc_Frame_t* pAbc); - -void AigBitblaster::simplifyAig() { - TimerStat::CodeTimer simpTimer(d_statistics.d_simplificationTime); - - Abc_AigCleanup(currentAigM()); - Assert(Abc_NtkCheck(currentAigNtk())); - - const char* command = options::bitvectorAigSimplifications().c_str(); - Abc_Frame_t* pAbc = Abc_FrameGetGlobalFrame(); - Abc_FrameSetCurrentNetwork(pAbc, currentAigNtk()); - - addAliases(pAbc); - if ( Cmd_CommandExecute( pAbc, command ) ) { - fprintf( stdout, "Cannot execute command \"%s\".\n", command ); - exit(-1); - } - s_abcAigNetwork = Abc_FrameReadNtk(pAbc); -} - - -void AigBitblaster::convertToCnfAndAssert() { - TimerStat::CodeTimer cnfConversionTimer(d_statistics.d_cnfConversionTime); - - Aig_Man_t * pMan = NULL; - Cnf_Dat_t * pCnf = NULL; - Assert(Abc_NtkIsStrash(currentAigNtk())); - - // convert to the AIG manager - pMan = Abc_NtkToDar(currentAigNtk(), 0, 0 ); - Abc_Stop(); - - // // free old network - // Abc_NtkDelete(currentAigNtk()); - // s_abcAigNetwork = NULL; - - Assert(pMan != NULL); - Assert(Aig_ManCheck(pMan)); - pCnf = Cnf_DeriveFast( pMan, 0 ); - - assertToSatSolver(pCnf); - - Cnf_DataFree( pCnf ); - Cnf_ManFree(); - Aig_ManStop(pMan); -} - -void AigBitblaster::assertToSatSolver(Cnf_Dat_t* pCnf) { - unsigned numVariables = pCnf->nVars; - unsigned numClauses = pCnf->nClauses; - - d_statistics.d_numVariables += numVariables; - d_statistics.d_numClauses += numClauses; - - // create variables in the sat solver - std::vector<prop::SatVariable> sat_variables; - for (unsigned i = 0; i < numVariables; ++i) { - sat_variables.push_back(d_satSolver->newVar(false, false, false)); - } - - // construct clauses and add to sat solver - int * pLit, * pStop; - for (unsigned i = 0; i < numClauses; i++ ) { - prop::SatClause clause; - for (pLit = pCnf->pClauses[i], pStop = pCnf->pClauses[i+1]; pLit < pStop; pLit++ ) { - int int_lit = Cnf_Lit2Var(*pLit); - Assert(int_lit != 0); - unsigned index = int_lit < 0? -int_lit : int_lit; - Assert(index - 1 < sat_variables.size()); - prop::SatLiteral lit(sat_variables[index-1], int_lit < 0); - clause.push_back(lit); - } - d_satSolver->addClause(clause, false); - } -} - -void addAliases(Abc_Frame_t* pAbc) { - std::vector<std::string> aliases; - aliases.push_back("alias b balance"); - aliases.push_back("alias rw rewrite"); - aliases.push_back("alias rwz rewrite -z"); - aliases.push_back("alias rf refactor"); - aliases.push_back("alias rfz refactor -z"); - aliases.push_back("alias re restructure"); - aliases.push_back("alias rez restructure -z"); - aliases.push_back("alias rs resub"); - aliases.push_back("alias rsz resub -z"); - aliases.push_back("alias rsk6 rs -K 6"); - aliases.push_back("alias rszk5 rsz -K 5"); - aliases.push_back("alias bl b -l"); - aliases.push_back("alias rwl rw -l"); - aliases.push_back("alias rwzl rwz -l"); - aliases.push_back("alias rwzl rwz -l"); - aliases.push_back("alias rfl rf -l"); - aliases.push_back("alias rfzl rfz -l"); - aliases.push_back("alias brw \"b; rw\""); - - for (unsigned i = 0; i < aliases.size(); ++i) { - if ( Cmd_CommandExecute( pAbc, aliases[i].c_str() ) ) { - fprintf( stdout, "Cannot execute command \"%s\".\n", aliases[i].c_str() ); - exit(-1); - } - } -} - -bool AigBitblaster::hasBBAtom(TNode atom) const { - return d_bbAtoms.find(atom) != d_bbAtoms.end(); -} - -void AigBitblaster::storeBBAtom(TNode atom, Abc_Obj_t* atom_bb) { - d_bbAtoms.insert(std::make_pair(atom, atom_bb)); -} - -Abc_Obj_t* AigBitblaster::getBBAtom(TNode atom) const { - Assert(hasBBAtom(atom)); - return d_bbAtoms.find(atom)->second; -} - -AigBitblaster::Statistics::Statistics() - : d_numClauses(smtStatisticsRegistry().registerInt( - "theory::bv::AigBitblaster::numClauses")), - d_numVariables(smtStatisticsRegistry().registerInt( - "theory::bv::AigBitblaster::numVariables")), - d_simplificationTime(smtStatisticsRegistry().registerTimer( - "theory::bv::AigBitblaster::simplificationTime")), - d_cnfConversionTime(smtStatisticsRegistry().registerTimer( - "theory::bv::AigBitblaster::cnfConversionTime")), - d_solveTime(smtStatisticsRegistry().registerTimer( - "theory::bv::AigBitblaster::solveTime")) -{ -} - -} // namespace bv -} // namespace theory -} // namespace cvc5 -#endif // CVC5_USE_ABC diff --git a/src/theory/bv/bitblast/aig_bitblaster.h b/src/theory/bv/bitblast/aig_bitblaster.h deleted file mode 100644 index bf184585f..000000000 --- a/src/theory/bv/bitblast/aig_bitblaster.h +++ /dev/null @@ -1,124 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Liana Hadarean, Mathias Preiner, Andres Noetzli - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * AIG Bitblaster based on ABC. - */ - -#include "cvc5_private.h" - -#ifndef CVC5__THEORY__BV__BITBLAST__AIG_BITBLASTER_H -#define CVC5__THEORY__BV__BITBLAST__AIG_BITBLASTER_H - -#include "theory/bv/bitblast/bitblaster.h" - -class Abc_Obj_t_; -typedef Abc_Obj_t_ Abc_Obj_t; - -class Abc_Ntk_t_; -typedef Abc_Ntk_t_ Abc_Ntk_t; - -class Abc_Aig_t_; -typedef Abc_Aig_t_ Abc_Aig_t; - -class Cnf_Dat_t_; -typedef Cnf_Dat_t_ Cnf_Dat_t; - -namespace cvc5 { -namespace prop { -class SatSolver; -} -namespace theory { -namespace bv { - -#ifdef CVC5_USE_ABC - -class AigBitblaster : public TBitblaster<Abc_Obj_t*> -{ - public: - AigBitblaster(); - ~AigBitblaster(); - - void makeVariable(TNode node, Bits& bits) override; - void bbTerm(TNode node, Bits& bits) override; - void bbAtom(TNode node) override; - Abc_Obj_t* bbFormula(TNode formula); - bool solve(TNode query); - static Abc_Aig_t* currentAigM(); - static Abc_Ntk_t* currentAigNtk(); - - private: - typedef std::unordered_map<TNode, Abc_Obj_t*> TNodeAigMap; - typedef std::unordered_map<Node, Abc_Obj_t*> NodeAigMap; - - static thread_local Abc_Ntk_t* s_abcAigNetwork; - std::unique_ptr<context::Context> d_nullContext; - std::unique_ptr<prop::SatSolver> d_satSolver; - TNodeAigMap d_aigCache; - NodeAigMap d_bbAtoms; - - NodeAigMap d_nodeToAigInput; - // the thing we are checking for sat - Abc_Obj_t* d_aigOutputNode; - - std::unique_ptr<MinisatEmptyNotify> d_notify; - - void addAtom(TNode atom); - void simplifyAig(); - void storeBBAtom(TNode atom, Abc_Obj_t* atom_bb) override; - Abc_Obj_t* getBBAtom(TNode atom) const override; - bool hasBBAtom(TNode atom) const override; - void cacheAig(TNode node, Abc_Obj_t* aig); - bool hasAig(TNode node); - Abc_Obj_t* getAig(TNode node); - Abc_Obj_t* mkInput(TNode input); - bool hasInput(TNode input); - void convertToCnfAndAssert(); - void assertToSatSolver(Cnf_Dat_t* pCnf); - Node getModelFromSatSolver(TNode a, bool fullModel) override - { - Unreachable(); - } - - prop::SatSolver* getSatSolver() override { return d_satSolver.get(); } - - class Statistics - { - public: - IntStat d_numClauses; - IntStat d_numVariables; - TimerStat d_simplificationTime; - TimerStat d_cnfConversionTime; - TimerStat d_solveTime; - Statistics(); - }; - - Statistics d_statistics; -}; - -#else /* CVC5_USE_ABC */ - -/** - * Dummy version of the AigBitblaster class that cannot be instantiated s.t. we - * can declare `std::unique_ptr<AigBitblaster>` without ABC. - */ -class AigBitblaster : public TBitblaster<Abc_Obj_t*> -{ - AigBitblaster() = delete; -}; - -#endif /* CVC5_USE_ABC */ - -} // namespace bv -} // namespace theory -} // namespace cvc5 - -#endif // CVC5__THEORY__BV__BITBLAST__AIG_BITBLASTER_H diff --git a/src/theory/bv/bitblast/bitblast_proof_generator.cpp b/src/theory/bv/bitblast/bitblast_proof_generator.cpp index 57435f651..c05243e8c 100644 --- a/src/theory/bv/bitblast/bitblast_proof_generator.cpp +++ b/src/theory/bv/bitblast/bitblast_proof_generator.cpp @@ -21,9 +21,10 @@ namespace cvc5 { namespace theory { namespace bv { -BitblastProofGenerator::BitblastProofGenerator(ProofNodeManager* pnm, +BitblastProofGenerator::BitblastProofGenerator(Env& env, + ProofNodeManager* pnm, TConvProofGenerator* tcpg) - : d_pnm(pnm), d_tcpg(tcpg) + : EnvObj(env), d_pnm(pnm), d_tcpg(tcpg) { } @@ -78,7 +79,7 @@ std::shared_ptr<ProofNode> BitblastProofGenerator::getProofFor(Node eq) * sub-terms and recording these bit-blast steps in the conversion proof. */ - Node rwt = Rewriter::rewrite(t); + Node rwt = rewrite(t); std::vector<Node> transSteps; @@ -94,7 +95,7 @@ std::shared_ptr<ProofNode> BitblastProofGenerator::getProofFor(Node eq) transSteps.push_back(rwt.eqNode(bbt)); // Record post-rewrite of bit-blasted term. - Node rwbbt = Rewriter::rewrite(bbt); + Node rwbbt = rewrite(bbt); if (bbt != rwbbt) { cdp.addStep(bbt.eqNode(rwbbt), PfRule::REWRITE, {}, {bbt}); diff --git a/src/theory/bv/bitblast/bitblast_proof_generator.h b/src/theory/bv/bitblast/bitblast_proof_generator.h index 114bf4749..a0627010a 100644 --- a/src/theory/bv/bitblast/bitblast_proof_generator.h +++ b/src/theory/bv/bitblast/bitblast_proof_generator.h @@ -19,6 +19,7 @@ #include "proof/proof_generator.h" #include "proof/proof_node_manager.h" +#include "smt/env_obj.h" namespace cvc5 { @@ -28,10 +29,12 @@ namespace theory { namespace bv { /** Proof generator fot bit-blast proofs. */ -class BitblastProofGenerator : public ProofGenerator +class BitblastProofGenerator : public ProofGenerator, protected EnvObj { public: - BitblastProofGenerator(ProofNodeManager* pnm, TConvProofGenerator* tcpg); + BitblastProofGenerator(Env& env, + ProofNodeManager* pnm, + TConvProofGenerator* tcpg); ~BitblastProofGenerator(){}; /** diff --git a/src/theory/bv/bitblast/bitblaster.h b/src/theory/bv/bitblast/bitblaster.h index 0471f11e5..fddf6c51e 100644 --- a/src/theory/bv/bitblast/bitblaster.h +++ b/src/theory/bv/bitblast/bitblaster.h @@ -23,7 +23,6 @@ #include <vector> #include "expr/node.h" -#include "prop/bv_sat_solver_notify.h" #include "prop/cnf_stream.h" #include "prop/registrar.h" #include "prop/sat_solver.h" @@ -103,20 +102,6 @@ class TBitblaster void invalidateModelCache(); }; -class MinisatEmptyNotify : public prop::BVSatSolverNotify -{ - public: - MinisatEmptyNotify() {} - bool notify(prop::SatLiteral lit) override { return true; } - void notify(prop::SatClause& clause) override {} - void spendResource(Resource r) override - { - smt::currentResourceManager()->spendResource(r); - } - - void safePoint(Resource r) override {} -}; - // Bitblaster implementation template <class T> @@ -214,58 +199,6 @@ void TBitblaster<T>::invalidateModelCache() d_modelCache.clear(); } -template <class T> -Node TBitblaster<T>::getTermModel(TNode node, bool fullModel) -{ - if (d_modelCache.find(node) != d_modelCache.end()) return d_modelCache[node]; - - if (node.isConst()) return node; - - Node value = getModelFromSatSolver(node, false); - if (!value.isNull()) - { - Debug("bv-equality-status") - << "TLazyBitblaster::getTermModel from SatSolver" << node << " => " - << value << "\n"; - d_modelCache[node] = value; - Assert(value.isConst()); - return value; - } - - if (Theory::isLeafOf(node, theory::THEORY_BV)) - { - // if it is a leaf may ask for fullModel - value = getModelFromSatSolver(node, true); - Debug("bv-equality-status") << "TLazyBitblaster::getTermModel from VarValue" - << node << " => " << value << "\n"; - Assert((fullModel && !value.isNull() && value.isConst()) || !fullModel); - if (!value.isNull()) - { - d_modelCache[node] = value; - } - return value; - } - Assert(node.getType().isBitVector()); - - NodeBuilder nb(node.getKind()); - if (node.getMetaKind() == kind::metakind::PARAMETERIZED) - { - nb << node.getOperator(); - } - - for (unsigned i = 0; i < node.getNumChildren(); ++i) - { - nb << getTermModel(node[i], fullModel); - } - value = nb; - value = Rewriter::rewrite(value); - Assert(value.isConst()); - d_modelCache[node] = value; - Debug("bv-term-model") << "TLazyBitblaster::getTermModel Building Value" - << node << " => " << value << "\n"; - return value; -} - } // namespace bv } // namespace theory } // namespace cvc5 diff --git a/src/theory/bv/bitblast/eager_bitblaster.cpp b/src/theory/bv/bitblast/eager_bitblaster.cpp deleted file mode 100644 index 9e3efa3bf..000000000 --- a/src/theory/bv/bitblast/eager_bitblaster.cpp +++ /dev/null @@ -1,294 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Liana Hadarean, Mathias Preiner, Andres Noetzli - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * Bitblaster for the eager bv solver. - */ - -#include "theory/bv/bitblast/eager_bitblaster.h" - -#include "cvc5_private.h" -#include "options/base_options.h" -#include "options/bv_options.h" -#include "options/smt_options.h" -#include "prop/cnf_stream.h" -#include "prop/sat_solver_factory.h" -#include "smt/smt_statistics_registry.h" -#include "smt/solver_engine.h" -#include "theory/bv/bv_solver_layered.h" -#include "theory/bv/theory_bv.h" -#include "theory/theory_model.h" - -namespace cvc5 { -namespace theory { -namespace bv { - -EagerBitblaster::EagerBitblaster(BVSolverLayered* theory_bv, - context::Context* c) - : TBitblaster<Node>(), - d_context(c), - d_satSolver(), - d_bitblastingRegistrar(new BitblastingRegistrar(this)), - d_bv(theory_bv), - d_bbAtoms(), - d_variables(), - d_notify() -{ - prop::SatSolver *solver = nullptr; - switch (options::bvSatSolver()) - { - case options::SatSolverMode::MINISAT: - { - prop::BVSatSolverInterface* minisat = - prop::SatSolverFactory::createMinisat( - d_nullContext.get(), - smtStatisticsRegistry(), - "theory::bv::EagerBitblaster::"); - d_notify.reset(new MinisatEmptyNotify()); - minisat->setNotify(d_notify.get()); - solver = minisat; - break; - } - case options::SatSolverMode::CADICAL: - solver = prop::SatSolverFactory::createCadical( - smtStatisticsRegistry(), "theory::bv::EagerBitblaster::"); - break; - case options::SatSolverMode::CRYPTOMINISAT: - solver = prop::SatSolverFactory::createCryptoMinisat( - smtStatisticsRegistry(), "theory::bv::EagerBitblaster::"); - break; - case options::SatSolverMode::KISSAT: - solver = prop::SatSolverFactory::createKissat( - smtStatisticsRegistry(), "theory::bv::EagerBitblaster::"); - break; - default: Unreachable() << "Unknown SAT solver type"; - } - d_satSolver.reset(solver); - ResourceManager* rm = smt::currentResourceManager(); - d_cnfStream.reset(new prop::CnfStream(d_satSolver.get(), - d_bitblastingRegistrar.get(), - d_nullContext.get(), - nullptr, - rm, - prop::FormulaLitPolicy::INTERNAL, - "EagerBitblaster")); -} - -EagerBitblaster::~EagerBitblaster() {} - -void EagerBitblaster::bbFormula(TNode node) -{ - /* For incremental eager solving we assume formulas at context levels > 1. */ - if (options::incrementalSolving() && d_context->getLevel() > 1) - { - d_cnfStream->ensureLiteral(node); - } - else - { - d_cnfStream->convertAndAssert(node, false, false); - } -} - -/** - * Bitblasts the atom, assigns it a marker literal, adding it to the SAT solver - * NOTE: duplicate clauses are not detected because of marker literal - * @param node the atom to be bitblasted - * - */ -void EagerBitblaster::bbAtom(TNode node) -{ - node = node.getKind() == kind::NOT ? node[0] : node; - if (node.getKind() == kind::BITVECTOR_BITOF - || node.getKind() == kind::CONST_BOOLEAN || hasBBAtom(node)) - { - return; - } - - Debug("bitvector-bitblast") << "Bitblasting node " << node << "\n"; - - // the bitblasted definition of the atom - Node normalized = Rewriter::rewrite(node); - Node atom_bb = - normalized.getKind() != kind::CONST_BOOLEAN - ? d_atomBBStrategies[normalized.getKind()](normalized, this) - : normalized; - - atom_bb = Rewriter::rewrite(atom_bb); - - // asserting that the atom is true iff the definition holds - Node atom_definition = - NodeManager::currentNM()->mkNode(kind::EQUAL, node, atom_bb); - - AlwaysAssert(options::bitblastMode() == options::BitblastMode::EAGER); - storeBBAtom(node, atom_bb); - d_cnfStream->convertAndAssert(atom_definition, false, false); -} - -void EagerBitblaster::storeBBAtom(TNode atom, Node atom_bb) { - d_bbAtoms.insert(atom); -} - -void EagerBitblaster::storeBBTerm(TNode node, const Bits& bits) { - d_termCache.insert(std::make_pair(node, bits)); -} - -bool EagerBitblaster::hasBBAtom(TNode atom) const { - return d_bbAtoms.find(atom) != d_bbAtoms.end(); -} - -void EagerBitblaster::bbTerm(TNode node, Bits& bits) { - Assert(node.getType().isBitVector()); - - if (hasBBTerm(node)) { - getBBTerm(node, bits); - return; - } - - d_bv->spendResource(Resource::BitblastStep); - Debug("bitvector-bitblast") << "Bitblasting node " << node << "\n"; - - d_termBBStrategies[node.getKind()](node, bits, this); - - Assert(bits.size() == utils::getSize(node)); - - storeBBTerm(node, bits); -} - -void EagerBitblaster::makeVariable(TNode var, Bits& bits) { - Assert(bits.size() == 0); - for (unsigned i = 0; i < utils::getSize(var); ++i) { - bits.push_back(utils::mkBitOf(var, i)); - } - d_variables.insert(var); -} - -Node EagerBitblaster::getBBAtom(TNode node) const { return node; } - -/** - * Calls the solve method for the Sat Solver. - * - * @return true for sat, and false for unsat - */ - -bool EagerBitblaster::solve() { - if (Trace.isOn("bitvector")) { - Trace("bitvector") << "EagerBitblaster::solve(). \n"; - } - Debug("bitvector") << "EagerBitblaster::solve(). \n"; - // TODO: clear some memory - // if (something) { - // NodeManager* nm= NodeManager::currentNM(); - // Rewriter::garbageCollect(); - // nm->reclaimZombiesUntil(options::zombieHuntThreshold()); - // } - return prop::SAT_VALUE_TRUE == d_satSolver->solve(); -} - -bool EagerBitblaster::solve(const std::vector<Node>& assumptions) -{ - std::vector<prop::SatLiteral> assumpts; - for (const Node& assumption : assumptions) - { - Assert(d_cnfStream->hasLiteral(assumption)); - assumpts.push_back(d_cnfStream->getLiteral(assumption)); - } - return prop::SAT_VALUE_TRUE == d_satSolver->solve(assumpts); -} - -/** - * Returns the value a is currently assigned to in the SAT solver - * or null if the value is completely unassigned. - * - * @param a - * @param fullModel whether to create a "full model," i.e., add - * constants to equivalence classes that don't already have them - * - * @return - */ -Node EagerBitblaster::getModelFromSatSolver(TNode a, bool fullModel) { - if (!hasBBTerm(a)) { - return fullModel ? utils::mkConst(utils::getSize(a), 0u) : Node(); - } - - Bits bits; - getBBTerm(a, bits); - Integer value(0); - for (int i = bits.size() - 1; i >= 0; --i) { - prop::SatValue bit_value; - if (d_cnfStream->hasLiteral(bits[i])) { - prop::SatLiteral bit = d_cnfStream->getLiteral(bits[i]); - bit_value = d_satSolver->value(bit); - Assert(bit_value != prop::SAT_VALUE_UNKNOWN); - } else { - if (!fullModel) return Node(); - // unconstrained bits default to false - bit_value = prop::SAT_VALUE_FALSE; - } - Integer bit_int = - bit_value == prop::SAT_VALUE_TRUE ? Integer(1) : Integer(0); - value = value * 2 + bit_int; - } - return utils::mkConst(bits.size(), value); -} - -bool EagerBitblaster::collectModelInfo(TheoryModel* m, bool fullModel) -{ - NodeManager* nm = NodeManager::currentNM(); - - // Collect the values for the bit-vector variables - TNodeSet::iterator it = d_variables.begin(); - for (; it != d_variables.end(); ++it) { - TNode var = *it; - if (d_bv->isLeaf(var) || isSharedTerm(var) || - (var.isVar() && var.getType().isBoolean())) { - // only shared terms could not have been bit-blasted - Assert(hasBBTerm(var) || isSharedTerm(var)); - - Node const_value = getModelFromSatSolver(var, true); - - if (const_value != Node()) { - Debug("bitvector-model") - << "EagerBitblaster::collectModelInfo (assert (= " << var << " " - << const_value << "))\n"; - if (!m->assertEquality(var, const_value, true)) - { - return false; - } - } - } - } - - // Collect the values for the Boolean variables - std::vector<TNode> vars; - d_cnfStream->getBooleanVariables(vars); - for (TNode var : vars) - { - Assert(d_cnfStream->hasLiteral(var)); - prop::SatLiteral bit = d_cnfStream->getLiteral(var); - prop::SatValue value = d_satSolver->value(bit); - Assert(value != prop::SAT_VALUE_UNKNOWN); - if (!m->assertEquality( - var, nm->mkConst(value == prop::SAT_VALUE_TRUE), true)) - { - return false; - } - } - return true; -} - -bool EagerBitblaster::isSharedTerm(TNode node) { - return d_bv->d_sharedTermsSet.find(node) != d_bv->d_sharedTermsSet.end(); -} - - -} // namespace bv -} // namespace theory -} // namespace cvc5 diff --git a/src/theory/bv/bitblast/eager_bitblaster.h b/src/theory/bv/bitblast/eager_bitblaster.h deleted file mode 100644 index 71bf50dd0..000000000 --- a/src/theory/bv/bitblast/eager_bitblaster.h +++ /dev/null @@ -1,88 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Mathias Preiner, Liana Hadarean, Tim King - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * Bitblaster for the eager BV solver. - */ - -#include "cvc5_private.h" - -#ifndef CVC5__THEORY__BV__BITBLAST__EAGER_BITBLASTER_H -#define CVC5__THEORY__BV__BITBLAST__EAGER_BITBLASTER_H - -#include <memory> -#include <unordered_set> - -#include "theory/bv/bitblast/bitblaster.h" - -#include "prop/sat_solver.h" - -namespace cvc5 { -namespace theory { -namespace bv { - -class BitblastingRegistrar; -class BVSolverLayered; - -class EagerBitblaster : public TBitblaster<Node> -{ - public: - EagerBitblaster(BVSolverLayered* theory_bv, context::Context* context); - ~EagerBitblaster(); - - void addAtom(TNode atom); - void makeVariable(TNode node, Bits& bits) override; - void bbTerm(TNode node, Bits& bits) override; - void bbAtom(TNode node) override; - Node getBBAtom(TNode node) const override; - bool hasBBAtom(TNode atom) const override; - void bbFormula(TNode formula); - void storeBBAtom(TNode atom, Node atom_bb) override; - void storeBBTerm(TNode node, const Bits& bits) override; - - bool assertToSat(TNode node, bool propagate = true); - bool solve(); - bool solve(const std::vector<Node>& assumptions); - bool collectModelInfo(TheoryModel* m, bool fullModel); - - private: - context::Context* d_context; - - typedef std::unordered_set<TNode> TNodeSet; - std::unique_ptr<prop::SatSolver> d_satSolver; - std::unique_ptr<BitblastingRegistrar> d_bitblastingRegistrar; - - BVSolverLayered* d_bv; - TNodeSet d_bbAtoms; - TNodeSet d_variables; - - // This is either an MinisatEmptyNotify or NULL. - std::unique_ptr<MinisatEmptyNotify> d_notify; - - Node getModelFromSatSolver(TNode a, bool fullModel) override; - prop::SatSolver* getSatSolver() override { return d_satSolver.get(); } - bool isSharedTerm(TNode node); -}; - -class BitblastingRegistrar : public prop::Registrar -{ - public: - BitblastingRegistrar(EagerBitblaster* bb) : d_bitblaster(bb) {} - void preRegister(Node n) override { d_bitblaster->bbAtom(n); } - - private: - EagerBitblaster* d_bitblaster; -}; - -} // namespace bv -} // namespace theory -} // namespace cvc5 -#endif // CVC5__THEORY__BV__BITBLAST__EAGER_BITBLASTER_H diff --git a/src/theory/bv/bitblast/lazy_bitblaster.cpp b/src/theory/bv/bitblast/lazy_bitblaster.cpp deleted file mode 100644 index a61c7a9ab..000000000 --- a/src/theory/bv/bitblast/lazy_bitblaster.cpp +++ /dev/null @@ -1,581 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Liana Hadarean, Aina Niemetz, Mathias Preiner - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * Bitblaster for the layered BV solver. - */ - -#include "theory/bv/bitblast/lazy_bitblaster.h" - -#include "cvc5_private.h" -#include "options/bv_options.h" -#include "prop/cnf_stream.h" -#include "prop/sat_solver.h" -#include "prop/sat_solver_factory.h" -#include "smt/smt_statistics_registry.h" -#include "smt/solver_engine.h" -#include "theory/bv/abstraction.h" -#include "theory/bv/bv_solver_layered.h" -#include "theory/bv/theory_bv.h" -#include "theory/bv/theory_bv_utils.h" -#include "theory/rewriter.h" -#include "theory/theory_model.h" - -namespace cvc5 { -namespace theory { -namespace bv { - -namespace { - -/* Determine the number of uncached nodes that a given node consists of. */ -uint64_t numNodes(TNode node, utils::NodeSet& seen) -{ - std::vector<TNode> stack; - uint64_t res = 0; - - stack.push_back(node); - while (!stack.empty()) - { - Node n = stack.back(); - stack.pop_back(); - - if (seen.find(n) != seen.end()) continue; - - res += 1; - seen.insert(n); - stack.insert(stack.end(), n.begin(), n.end()); - } - return res; -} -} - -TLazyBitblaster::TLazyBitblaster(context::Context* c, - bv::BVSolverLayered* bv, - const std::string name, - bool emptyNotify) - : TBitblaster<Node>(), - d_bv(bv), - d_ctx(c), - d_nullRegistrar(new prop::NullRegistrar()), - d_assertedAtoms(new (true) context::CDList<prop::SatLiteral>(c)), - d_explanations(new (true) ExplanationMap(c)), - d_variables(), - d_bbAtoms(), - d_abstraction(NULL), - d_emptyNotify(emptyNotify), - d_fullModelAssertionLevel(c, 0), - d_name(name), - d_statistics(name + "::") -{ - d_satSolver.reset(prop::SatSolverFactory::createMinisat( - c, smtStatisticsRegistry(), name + "::")); - - ResourceManager* rm = smt::currentResourceManager(); - d_cnfStream.reset(new prop::CnfStream(d_satSolver.get(), - d_nullRegistrar.get(), - d_nullContext.get(), - nullptr, - rm, - prop::FormulaLitPolicy::INTERNAL, - "LazyBitblaster")); - - d_satSolverNotify.reset( - d_emptyNotify - ? (prop::BVSatSolverNotify*)new MinisatEmptyNotify() - : (prop::BVSatSolverNotify*)new MinisatNotify( - d_cnfStream.get(), bv, this)); - - d_satSolver->setNotify(d_satSolverNotify.get()); -} - -void TLazyBitblaster::setAbstraction(AbstractionModule* abs) { - d_abstraction = abs; -} - -TLazyBitblaster::~TLazyBitblaster() -{ - d_assertedAtoms->deleteSelf(); - d_explanations->deleteSelf(); -} - - -/** - * Bitblasts the atom, assigns it a marker literal, adding it to the SAT solver - * NOTE: duplicate clauses are not detected because of marker literal - * @param node the atom to be bitblasted - * - */ -void TLazyBitblaster::bbAtom(TNode node) -{ - NodeManager* nm = NodeManager::currentNM(); - node = node.getKind() == kind::NOT ? node[0] : node; - - if (hasBBAtom(node)) - { - return; - } - - // make sure it is marked as an atom - addAtom(node); - - Debug("bitvector-bitblast") << "Bitblasting node " << node << "\n"; - ++d_statistics.d_numAtoms; - - /// if we are using bit-vector abstraction bit-blast the original - /// interpretation - if (options::bvAbstraction() && d_abstraction != NULL - && d_abstraction->isAbstraction(node)) - { - // node must be of the form P(args) = bv1 - Node expansion = Rewriter::rewrite(d_abstraction->getInterpretation(node)); - - Node atom_bb; - if (expansion.getKind() == kind::CONST_BOOLEAN) - { - atom_bb = expansion; - } - else - { - Assert(expansion.getKind() == kind::AND); - std::vector<Node> atoms; - for (unsigned i = 0; i < expansion.getNumChildren(); ++i) - { - Node normalized_i = Rewriter::rewrite(expansion[i]); - Node atom_i = - normalized_i.getKind() != kind::CONST_BOOLEAN - ? Rewriter::rewrite(d_atomBBStrategies[normalized_i.getKind()]( - normalized_i, this)) - : normalized_i; - atoms.push_back(atom_i); - } - atom_bb = utils::mkAnd(atoms); - } - Assert(!atom_bb.isNull()); - Node atom_definition = nm->mkNode(kind::EQUAL, node, atom_bb); - storeBBAtom(node, atom_bb); - d_cnfStream->convertAndAssert(atom_definition, false, false); - return; - } - - // the bitblasted definition of the atom - Node normalized = Rewriter::rewrite(node); - Node atom_bb = - normalized.getKind() != kind::CONST_BOOLEAN - ? d_atomBBStrategies[normalized.getKind()](normalized, this) - : normalized; - - atom_bb = Rewriter::rewrite(atom_bb); - - // asserting that the atom is true iff the definition holds - Node atom_definition = nm->mkNode(kind::EQUAL, node, atom_bb); - storeBBAtom(node, atom_bb); - d_cnfStream->convertAndAssert(atom_definition, false, false); -} - -void TLazyBitblaster::storeBBAtom(TNode atom, Node atom_bb) { - d_bbAtoms.insert(atom); -} - -void TLazyBitblaster::storeBBTerm(TNode node, const Bits& bits) { - d_termCache.insert(std::make_pair(node, bits)); -} - - -bool TLazyBitblaster::hasBBAtom(TNode atom) const { - return d_bbAtoms.find(atom) != d_bbAtoms.end(); -} - - -void TLazyBitblaster::makeVariable(TNode var, Bits& bits) { - Assert(bits.size() == 0); - for (unsigned i = 0; i < utils::getSize(var); ++i) { - bits.push_back(utils::mkBitOf(var, i)); - } - d_variables.insert(var); -} - -uint64_t TLazyBitblaster::computeAtomWeight(TNode node, NodeSet& seen) -{ - node = node.getKind() == kind::NOT ? node[0] : node; - if (!utils::isBitblastAtom(node)) { return 0; } - Node atom_bb = - Rewriter::rewrite(d_atomBBStrategies[node.getKind()](node, this)); - uint64_t size = numNodes(atom_bb, seen); - return size; -} - -// cnf conversion ensures the atom represents itself -Node TLazyBitblaster::getBBAtom(TNode node) const { - return node; -} - -void TLazyBitblaster::bbTerm(TNode node, Bits& bits) { - - if (hasBBTerm(node)) { - getBBTerm(node, bits); - return; - } - Assert(node.getType().isBitVector()); - - d_bv->spendResource(Resource::BitblastStep); - Debug("bitvector-bitblast") << "Bitblasting term " << node <<"\n"; - ++d_statistics.d_numTerms; - - d_termBBStrategies[node.getKind()] (node, bits,this); - - Assert(bits.size() == utils::getSize(node)); - - storeBBTerm(node, bits); -} -/// Public methods - -void TLazyBitblaster::addAtom(TNode atom) { - d_cnfStream->ensureLiteral(atom); - prop::SatLiteral lit = d_cnfStream->getLiteral(atom); - d_satSolver->addMarkerLiteral(lit); -} - -void TLazyBitblaster::explain(TNode atom, std::vector<TNode>& explanation) { - prop::SatLiteral lit = d_cnfStream->getLiteral(atom); - - ++(d_statistics.d_numExplainedPropagations); - if (options::bvEagerExplanations()) { - Assert(d_explanations->find(lit) != d_explanations->end()); - const std::vector<prop::SatLiteral>& literal_explanation = (*d_explanations)[lit].get(); - for (unsigned i = 0; i < literal_explanation.size(); ++i) { - explanation.push_back(d_cnfStream->getNode(literal_explanation[i])); - } - return; - } - - std::vector<prop::SatLiteral> literal_explanation; - d_satSolver->explain(lit, literal_explanation); - for (unsigned i = 0; i < literal_explanation.size(); ++i) { - explanation.push_back(d_cnfStream->getNode(literal_explanation[i])); - } -} - - -/* - * Asserts the clauses corresponding to the atom to the Sat Solver - * by turning on the marker literal (i.e. setting it to false) - * @param node the atom to be asserted - * - */ - -bool TLazyBitblaster::propagate() { - return d_satSolver->propagate() == prop::SAT_VALUE_TRUE; -} - -bool TLazyBitblaster::assertToSat(TNode lit, bool propagate) { - // strip the not - TNode atom; - if (lit.getKind() == kind::NOT) { - atom = lit[0]; - } else { - atom = lit; - } - Assert(utils::isBitblastAtom(atom)); - - Assert(hasBBAtom(atom)); - - prop::SatLiteral markerLit = d_cnfStream->getLiteral(atom); - - if(lit.getKind() == kind::NOT) { - markerLit = ~markerLit; - } - - Debug("bitvector-bb") - << "BVSolverLayered::TLazyBitblaster::assertToSat asserting node: " - << atom << "\n"; - Debug("bitvector-bb") - << "BVSolverLayered::TLazyBitblaster::assertToSat with literal: " - << markerLit << "\n"; - - prop::SatValue ret = d_satSolver->assertAssumption(markerLit, propagate); - - d_assertedAtoms->push_back(markerLit); - - return ret == prop::SAT_VALUE_TRUE || ret == prop::SAT_VALUE_UNKNOWN; -} - -/** - * Calls the solve method for the Sat Solver. - * passing it the marker literals to be asserted - * - * @return true for sat, and false for unsat - */ - -bool TLazyBitblaster::solve() { - if (Trace.isOn("bitvector")) { - Trace("bitvector") << "TLazyBitblaster::solve() asserted atoms "; - context::CDList<prop::SatLiteral>::const_iterator it = d_assertedAtoms->begin(); - for (; it != d_assertedAtoms->end(); ++it) { - Trace("bitvector") << " " << d_cnfStream->getNode(*it) << "\n"; - } - } - Debug("bitvector") << "TLazyBitblaster::solve() asserted atoms " << d_assertedAtoms->size() <<"\n"; - d_fullModelAssertionLevel.set(d_bv->numAssertions()); - return prop::SAT_VALUE_TRUE == d_satSolver->solve(); -} - -prop::SatValue TLazyBitblaster::solveWithBudget(unsigned long budget) { - if (Trace.isOn("bitvector")) { - Trace("bitvector") << "TLazyBitblaster::solveWithBudget() asserted atoms "; - context::CDList<prop::SatLiteral>::const_iterator it = d_assertedAtoms->begin(); - for (; it != d_assertedAtoms->end(); ++it) { - Trace("bitvector") << " " << d_cnfStream->getNode(*it) << "\n"; - } - } - Debug("bitvector") << "TLazyBitblaster::solveWithBudget() asserted atoms " << d_assertedAtoms->size() <<"\n"; - return d_satSolver->solve(budget); -} - -void TLazyBitblaster::getConflict(std::vector<TNode>& conflict) -{ - NodeManager* nm = NodeManager::currentNM(); - prop::SatClause conflictClause; - d_satSolver->getUnsatCore(conflictClause); - - for (unsigned i = 0; i < conflictClause.size(); i++) - { - prop::SatLiteral lit = conflictClause[i]; - TNode atom = d_cnfStream->getNode(lit); - Node not_atom; - if (atom.getKind() == kind::NOT) - { - not_atom = atom[0]; - } - else - { - not_atom = nm->mkNode(kind::NOT, atom); - } - conflict.push_back(not_atom); - } -} - -TLazyBitblaster::Statistics::Statistics(const std::string& prefix) - : d_numTermClauses( - smtStatisticsRegistry().registerInt(prefix + "NumTermSatClauses")), - d_numAtomClauses( - smtStatisticsRegistry().registerInt(prefix + "NumAtomSatClauses")), - d_numTerms( - smtStatisticsRegistry().registerInt(prefix + "NumBitblastedTerms")), - d_numAtoms( - smtStatisticsRegistry().registerInt(prefix + "NumBitblastedAtoms")), - d_numExplainedPropagations(smtStatisticsRegistry().registerInt( - prefix + "NumExplainedPropagations")), - d_numBitblastingPropagations(smtStatisticsRegistry().registerInt( - prefix + "NumBitblastingPropagations")), - d_bitblastTimer( - smtStatisticsRegistry().registerTimer(prefix + "BitblastTimer")) -{ -} - -bool TLazyBitblaster::MinisatNotify::notify(prop::SatLiteral lit) { - if(options::bvEagerExplanations()) { - // compute explanation - if (d_lazyBB->d_explanations->find(lit) == d_lazyBB->d_explanations->end()) { - std::vector<prop::SatLiteral> literal_explanation; - d_lazyBB->d_satSolver->explain(lit, literal_explanation); - d_lazyBB->d_explanations->insert(lit, literal_explanation); - } else { - // we propagated it at a lower level - return true; - } - } - ++(d_lazyBB->d_statistics.d_numBitblastingPropagations); - TNode atom = d_cnf->getNode(lit); - return d_bv->storePropagation(atom, SUB_BITBLAST); -} - -void TLazyBitblaster::MinisatNotify::notify(prop::SatClause& clause) { - if (clause.size() > 1) { - NodeBuilder lemmab(kind::OR); - for (unsigned i = 0; i < clause.size(); ++ i) { - lemmab << d_cnf->getNode(clause[i]); - } - Node lemma = lemmab; - d_bv->d_im.lemma(lemma, InferenceId::BV_LAYERED_LEMMA); - } else { - d_bv->d_im.lemma(d_cnf->getNode(clause[0]), InferenceId::BV_LAYERED_LEMMA); - } -} - -void TLazyBitblaster::MinisatNotify::spendResource(Resource r) -{ - d_bv->spendResource(r); -} - -void TLazyBitblaster::MinisatNotify::safePoint(Resource r) -{ - d_bv->d_im.safePoint(r); -} - -EqualityStatus TLazyBitblaster::getEqualityStatus(TNode a, TNode b) -{ - int numAssertions = d_bv->numAssertions(); - bool has_full_model = - numAssertions != 0 && d_fullModelAssertionLevel.get() == numAssertions; - - Debug("bv-equality-status") - << "TLazyBitblaster::getEqualityStatus " << a << " = " << b << "\n"; - Debug("bv-equality-status") - << "BVSatSolver has full model? " << has_full_model << "\n"; - - // First check if it trivially rewrites to false/true - Node a_eq_b = - Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::EQUAL, a, b)); - - if (a_eq_b == utils::mkFalse()) return theory::EQUALITY_FALSE; - if (a_eq_b == utils::mkTrue()) return theory::EQUALITY_TRUE; - - if (!has_full_model) - { - return theory::EQUALITY_UNKNOWN; - } - - // Check if cache is valid (invalidated in check and pops) - if (d_bv->d_invalidateModelCache.get()) - { - invalidateModelCache(); - } - d_bv->d_invalidateModelCache.set(false); - - Node a_value = getTermModel(a, true); - Node b_value = getTermModel(b, true); - - Assert(a_value.isConst() && b_value.isConst()); - - if (a_value == b_value) - { - Debug("bv-equality-status") << "theory::EQUALITY_TRUE_IN_MODEL\n"; - return theory::EQUALITY_TRUE_IN_MODEL; - } - Debug("bv-equality-status") << "theory::EQUALITY_FALSE_IN_MODEL\n"; - return theory::EQUALITY_FALSE_IN_MODEL; -} - -bool TLazyBitblaster::isSharedTerm(TNode node) { - return d_bv->d_sharedTermsSet.find(node) != d_bv->d_sharedTermsSet.end(); -} - -bool TLazyBitblaster::hasValue(TNode a) { - Assert(hasBBTerm(a)); - Bits bits; - getBBTerm(a, bits); - for (int i = bits.size() -1; i >= 0; --i) { - prop::SatValue bit_value; - if (d_cnfStream->hasLiteral(bits[i])) { - prop::SatLiteral bit = d_cnfStream->getLiteral(bits[i]); - bit_value = d_satSolver->value(bit); - if (bit_value == prop::SAT_VALUE_UNKNOWN) - return false; - } else { - return false; - } - } - return true; -} -/** - * Returns the value a is currently assigned to in the SAT solver - * or null if the value is completely unassigned. - * - * @param a - * @param fullModel whether to create a "full model," i.e., add - * constants to equivalence classes that don't already have them - * - * @return - */ -Node TLazyBitblaster::getModelFromSatSolver(TNode a, bool fullModel) { - if (!hasBBTerm(a)) { - return fullModel? utils::mkConst(utils::getSize(a), 0u) : Node(); - } - - Bits bits; - getBBTerm(a, bits); - Integer value(0); - for (int i = bits.size() -1; i >= 0; --i) { - prop::SatValue bit_value; - if (d_cnfStream->hasLiteral(bits[i])) { - prop::SatLiteral bit = d_cnfStream->getLiteral(bits[i]); - bit_value = d_satSolver->value(bit); - Assert(bit_value != prop::SAT_VALUE_UNKNOWN); - } else { - if (!fullModel) return Node(); - // unconstrained bits default to false - bit_value = prop::SAT_VALUE_FALSE; - } - Integer bit_int = bit_value == prop::SAT_VALUE_TRUE ? Integer(1) : Integer(0); - value = value * 2 + bit_int; - } - return utils::mkConst(bits.size(), value); -} - -bool TLazyBitblaster::collectModelValues(TheoryModel* m, - const std::set<Node>& termSet) -{ - for (std::set<Node>::const_iterator it = termSet.begin(); it != termSet.end(); ++it) { - TNode var = *it; - // not actually a leaf of the bit-vector theory - if (d_variables.find(var) == d_variables.end()) - continue; - - Assert(Theory::theoryOf(var) == theory::THEORY_BV || isSharedTerm(var)); - // only shared terms could not have been bit-blasted - Assert(hasBBTerm(var) || isSharedTerm(var)); - - Node const_value = getModelFromSatSolver(var, true); - Assert(const_value.isNull() || const_value.isConst()); - if(const_value != Node()) { - Debug("bitvector-model") - << "TLazyBitblaster::collectModelValues (assert (= " << var << " " - << const_value << "))\n"; - if (!m->assertEquality(var, const_value, true)) - { - return false; - } - } - } - return true; -} - -void TLazyBitblaster::clearSolver() { - Assert(d_ctx->getLevel() == 0); - d_assertedAtoms->deleteSelf(); - d_assertedAtoms = new(true) context::CDList<prop::SatLiteral>(d_ctx); - d_explanations->deleteSelf(); - d_explanations = new(true) ExplanationMap(d_ctx); - d_bbAtoms.clear(); - d_variables.clear(); - d_termCache.clear(); - - invalidateModelCache(); - // recreate sat solver - d_satSolver.reset( - prop::SatSolverFactory::createMinisat(d_ctx, smtStatisticsRegistry())); - ResourceManager* rm = smt::currentResourceManager(); - d_cnfStream.reset(new prop::CnfStream(d_satSolver.get(), - d_nullRegistrar.get(), - d_nullContext.get(), - nullptr, - rm)); - d_satSolverNotify.reset( - d_emptyNotify - ? (prop::BVSatSolverNotify*)new MinisatEmptyNotify() - : (prop::BVSatSolverNotify*)new MinisatNotify( - d_cnfStream.get(), d_bv, this)); - d_satSolver->setNotify(d_satSolverNotify.get()); -} - -} // namespace bv -} // namespace theory -} // namespace cvc5 diff --git a/src/theory/bv/bitblast/lazy_bitblaster.h b/src/theory/bv/bitblast/lazy_bitblaster.h deleted file mode 100644 index 8d8723522..000000000 --- a/src/theory/bv/bitblast/lazy_bitblaster.h +++ /dev/null @@ -1,180 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Mathias Preiner, Liana Hadarean, Clark Barrett - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * Bitblaster for the lazy bv solver. - */ - -#include "cvc5_private.h" - -#ifndef CVC5__THEORY__BV__BITBLAST__LAZY_BITBLASTER_H -#define CVC5__THEORY__BV__BITBLAST__LAZY_BITBLASTER_H - -#include "theory/bv/bitblast/bitblaster.h" - -#include "context/cdhashmap.h" -#include "context/cdlist.h" -#include "prop/bv_sat_solver_notify.h" -#include "theory/bv/abstraction.h" - -namespace cvc5 { -namespace prop { -class CnfStream; -class NullRegistrat; -} -namespace theory { -namespace bv { - -class BVSolverLayered; - -class TLazyBitblaster : public TBitblaster<Node> -{ - public: - void bbTerm(TNode node, Bits& bits) override; - void bbAtom(TNode node) override; - Node getBBAtom(TNode atom) const override; - void storeBBAtom(TNode atom, Node atom_bb) override; - void storeBBTerm(TNode node, const Bits& bits) override; - bool hasBBAtom(TNode atom) const override; - - TLazyBitblaster(context::Context* c, - BVSolverLayered* bv, - const std::string name = "", - bool emptyNotify = false); - ~TLazyBitblaster(); - /** - * Pushes the assumption literal associated with node to the SAT - * solver assumption queue. - * - * @param node assumption - * @param propagate run bcp or not - * - * @return false if a conflict detected - */ - bool assertToSat(TNode node, bool propagate = true); - bool propagate(); - bool solve(); - prop::SatValue solveWithBudget(unsigned long conflict_budget); - void getConflict(std::vector<TNode>& conflict); - void explain(TNode atom, std::vector<TNode>& explanation); - void setAbstraction(AbstractionModule* abs); - - theory::EqualityStatus getEqualityStatus(TNode a, TNode b); - - /** - * Adds a constant value for each bit-blasted variable in the model. - * - * @param m the model - * @param termSet the set of relevant terms - */ - bool collectModelValues(TheoryModel* m, - const std::set<Node>& termSet); - - typedef TNodeSet::const_iterator vars_iterator; - vars_iterator beginVars() { return d_variables.begin(); } - vars_iterator endVars() { return d_variables.end(); } - - /** - * Creates the bits corresponding to the variable (or non-bv term). - * - * @param var - */ - void makeVariable(TNode var, Bits& bits) override; - - bool isSharedTerm(TNode node); - uint64_t computeAtomWeight(TNode node, NodeSet& seen); - /** - * Deletes SatSolver and CnfCache, but maintains bit-blasting - * terms cache. - * - */ - void clearSolver(); - - private: - typedef std::vector<Node> Bits; - typedef context::CDList<prop::SatLiteral> AssertionList; - typedef context::CDHashMap<prop::SatLiteral, - std::vector<prop::SatLiteral>, - prop::SatLiteralHashFunction> - ExplanationMap; - /** This class gets callbacks from minisat on propagations */ - class MinisatNotify : public prop::BVSatSolverNotify - { - prop::CnfStream* d_cnf; - BVSolverLayered* d_bv; - TLazyBitblaster* d_lazyBB; - - public: - MinisatNotify(prop::CnfStream* cnf, - BVSolverLayered* bv, - TLazyBitblaster* lbv) - : d_cnf(cnf), d_bv(bv), d_lazyBB(lbv) - { - } - - bool notify(prop::SatLiteral lit) override; - void notify(prop::SatClause& clause) override; - void spendResource(Resource r) override; - void safePoint(Resource r) override; - }; - - BVSolverLayered* d_bv; - context::Context* d_ctx; - - std::unique_ptr<prop::NullRegistrar> d_nullRegistrar; - std::unique_ptr<prop::BVSatSolverInterface> d_satSolver; - std::unique_ptr<prop::BVSatSolverNotify> d_satSolverNotify; - - AssertionList* - d_assertedAtoms; /**< context dependent list storing the atoms - currently asserted by the DPLL SAT solver. */ - ExplanationMap* d_explanations; /**< context dependent list of explanations - for the propagated literals. Only used when - bvEagerPropagate option enabled. */ - TNodeSet d_variables; - TNodeSet d_bbAtoms; - AbstractionModule* d_abstraction; - bool d_emptyNotify; - - // The size of the fact queue when we most recently called solve() in the - // bit-vector SAT solver. This is the level at which we should have - // a full model in the bv SAT solver. - context::CDO<int> d_fullModelAssertionLevel; - - void addAtom(TNode atom); - bool hasValue(TNode a); - Node getModelFromSatSolver(TNode a, bool fullModel) override; - prop::SatSolver* getSatSolver() override { return d_satSolver.get(); } - - class Statistics - { - public: - IntStat d_numTermClauses, d_numAtomClauses; - IntStat d_numTerms, d_numAtoms; - IntStat d_numExplainedPropagations; - IntStat d_numBitblastingPropagations; - TimerStat d_bitblastTimer; - Statistics(const std::string& name); - }; - std::string d_name; - - // NOTE: d_statistics is public since d_bitblastTimer needs to be initalized - // prior to calling bbAtom. As it is now, the timer can't be initialized - // in bbAtom since the method is called recursively and the timer would - // be initialized multiple times, which is not allowed. - public: - Statistics d_statistics; -}; - -} // namespace bv -} // namespace theory -} // namespace cvc5 -#endif // CVC5__THEORY__BV__BITBLAST__LAZY_BITBLASTER_H diff --git a/src/theory/bv/bitblast/proof_bitblaster.cpp b/src/theory/bv/bitblast/proof_bitblaster.cpp index 6119e9d7c..d8f327b29 100644 --- a/src/theory/bv/bitblast/proof_bitblaster.cpp +++ b/src/theory/bv/bitblast/proof_bitblaster.cpp @@ -45,7 +45,8 @@ BBProof::BBProof(Env& env, d_tcontext.get(), false) : nullptr), - d_bbpg(pnm ? new BitblastProofGenerator(pnm, d_tcpg.get()) : nullptr), + d_bbpg(pnm ? new BitblastProofGenerator(env, pnm, d_tcpg.get()) + : nullptr), d_recordFineGrainedProofs(fineGrained) { } @@ -75,7 +76,7 @@ void BBProof::bbAtom(TNode node) NodeManager* nm = NodeManager::currentNM(); // post-rewrite atom - Node rwNode = Rewriter::rewrite(node); + Node rwNode = rewrite(node); // Post-order traversal of `rwNode` to make sure that all subterms are // bit-blasted and recorded. diff --git a/src/theory/bv/bv_eager_solver.cpp b/src/theory/bv/bv_eager_solver.cpp deleted file mode 100644 index 23b98ca54..000000000 --- a/src/theory/bv/bv_eager_solver.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Mathias Preiner, Liana Hadarean, Tim King - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * Eager bit-blasting solver. - */ - -#include "theory/bv/bv_eager_solver.h" - -#include "options/base_options.h" -#include "options/bv_options.h" -#include "options/smt_options.h" -#include "theory/bv/bitblast/aig_bitblaster.h" -#include "theory/bv/bitblast/eager_bitblaster.h" - -using namespace std; - -namespace cvc5 { -namespace theory { -namespace bv { - -EagerBitblastSolver::EagerBitblastSolver(context::Context* c, - BVSolverLayered* bv) - : d_assertionSet(c), - d_assumptionSet(c), - d_context(c), - d_bitblaster(), - d_aigBitblaster(), - d_useAig(options::bitvectorAig()), - d_bv(bv) -{ -} - -EagerBitblastSolver::~EagerBitblastSolver() {} - -void EagerBitblastSolver::turnOffAig() { - Assert(d_aigBitblaster == nullptr && d_bitblaster == nullptr); - d_useAig = false; -} - -void EagerBitblastSolver::initialize() { - Assert(!isInitialized()); - if (d_useAig) { -#ifdef CVC5_USE_ABC - d_aigBitblaster.reset(new AigBitblaster()); -#else - Unreachable(); -#endif - } else { - d_bitblaster.reset(new EagerBitblaster(d_bv, d_context)); - } -} - -bool EagerBitblastSolver::isInitialized() { - const bool init = d_aigBitblaster != nullptr || d_bitblaster != nullptr; - Assert(!init || !d_useAig || d_aigBitblaster); - Assert(!init || d_useAig || d_bitblaster); - return init; -} - -void EagerBitblastSolver::assertFormula(TNode formula) { - d_bv->spendResource(Resource::BvEagerAssertStep); - Assert(isInitialized()); - Debug("bitvector-eager") << "EagerBitblastSolver::assertFormula " << formula - << "\n"; - if (options::incrementalSolving() && d_context->getLevel() > 1) - { - d_assumptionSet.insert(formula); - } - d_assertionSet.insert(formula); - // ensures all atoms are bit-blasted and converted to AIG - if (d_useAig) { -#ifdef CVC5_USE_ABC - d_aigBitblaster->bbFormula(formula); -#else - Unreachable(); -#endif - } - else - { - d_bitblaster->bbFormula(formula); - } -} - -bool EagerBitblastSolver::checkSat() { - Assert(isInitialized()); - if (d_assertionSet.empty()) { - return true; - } - - if (d_useAig) { -#ifdef CVC5_USE_ABC - const std::vector<Node> assertions = {d_assertionSet.key_begin(), - d_assertionSet.key_end()}; - Assert(!assertions.empty()); - - Node query = utils::mkAnd(assertions); - return d_aigBitblaster->solve(query); -#else - Unreachable(); -#endif - } - - if (options::incrementalSolving()) - { - const std::vector<Node> assumptions = {d_assumptionSet.key_begin(), - d_assumptionSet.key_end()}; - return d_bitblaster->solve(assumptions); - } - return d_bitblaster->solve(); -} - -bool EagerBitblastSolver::collectModelInfo(TheoryModel* m, bool fullModel) -{ - AlwaysAssert(!d_useAig && d_bitblaster); - return d_bitblaster->collectModelInfo(m, fullModel); -} - -} // namespace bv -} // namespace theory -} // namespace cvc5 diff --git a/src/theory/bv/bv_eager_solver.h b/src/theory/bv/bv_eager_solver.h deleted file mode 100644 index fec4edee9..000000000 --- a/src/theory/bv/bv_eager_solver.h +++ /dev/null @@ -1,64 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Liana Hadarean, Mathias Preiner, Tim King - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * Eager bit-blasting solver. - */ - -#include "cvc5_private.h" - -#ifndef CVC5__THEORY__BV__BV_EAGER_SOLVER_H -#define CVC5__THEORY__BV__BV_EAGER_SOLVER_H - -#include "expr/node.h" -#include "theory/bv/bv_solver_layered.h" -#include "theory/theory_model.h" - -namespace cvc5 { -namespace theory { -namespace bv { - -class EagerBitblaster; -class AigBitblaster; - -/** - * BitblastSolver - */ -class EagerBitblastSolver { - public: - EagerBitblastSolver(context::Context* c, theory::bv::BVSolverLayered* bv); - ~EagerBitblastSolver(); - bool checkSat(); - void assertFormula(TNode formula); - - void turnOffAig(); - bool isInitialized(); - void initialize(); - bool collectModelInfo(theory::TheoryModel* m, bool fullModel); - - private: - context::CDHashSet<Node> d_assertionSet; - context::CDHashSet<Node> d_assumptionSet; - context::Context* d_context; - - /** Bitblasters */ - std::unique_ptr<EagerBitblaster> d_bitblaster; - std::unique_ptr<AigBitblaster> d_aigBitblaster; - bool d_useAig; - - BVSolverLayered* d_bv; -}; // class EagerBitblastSolver - -} // namespace bv -} // namespace theory -} // namespace cvc5 - -#endif // CVC5__THEORY__BV__BV_EAGER_SOLVER_H diff --git a/src/theory/bv/bv_inequality_graph.cpp b/src/theory/bv/bv_inequality_graph.cpp deleted file mode 100644 index d195169a5..000000000 --- a/src/theory/bv/bv_inequality_graph.cpp +++ /dev/null @@ -1,480 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Liana Hadarean, Aina Niemetz, Mathias Preiner - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * A graph representation of the currently asserted bv inequalities. - */ - -#include "theory/bv/bv_inequality_graph.h" -#include "theory/bv/theory_bv_utils.h" - -using namespace std; -using namespace cvc5; -using namespace cvc5::context; -using namespace cvc5::theory; -using namespace cvc5::theory::bv; -using namespace cvc5::theory::bv::utils; - -const TermId cvc5::theory::bv::UndefinedTermId = -1; -const ReasonId cvc5::theory::bv::UndefinedReasonId = -1; -const ReasonId cvc5::theory::bv::AxiomReasonId = -2; - -bool InequalityGraph::addInequality(TNode a, TNode b, bool strict, TNode reason) { - Debug("bv-inequality") << "InequalityGraph::addInequality " << a << " " << b << " strict: " << strict << "\n"; - - TermId id_a = registerTerm(a); - TermId id_b = registerTerm(b); - ReasonId id_reason = registerReason(reason); - - Assert(!(isConst(id_a) && isConst(id_b))); - BitVector a_val = getValue(id_a); - BitVector b_val = getValue(id_b); - - unsigned bitwidth = utils::getSize(a); - BitVector diff = strict ? BitVector(bitwidth, 1u) : BitVector(bitwidth, 0u); - - if (a_val + diff < a_val) { - // we have an overflow - std::vector<ReasonId> conflict; - conflict.push_back(id_reason); - computeExplanation(UndefinedTermId, id_a, conflict); - setConflict(conflict); - return false; - } - - if (a_val + diff <= b_val) { - // the inequality is true in the current partial model - // we still add the edge because it may not be true later (cardinality) - addEdge(id_a, id_b, strict, id_reason); - return true; - } - - if (isConst(id_b) && a_val + diff > b_val) { - // we must be in a conflict since a has the minimum value that - // satisifes the constraints - std::vector<ReasonId> conflict; - conflict.push_back(id_reason); - computeExplanation(UndefinedTermId, id_a, conflict); - Debug("bv-inequality") << "InequalityGraph::addInequality conflict: constant UB \n"; - setConflict(conflict); - return false; - } - - // add the inequality edge - addEdge(id_a, id_b, strict, id_reason); - BFSQueue queue(&d_modelValues); - Assert(hasModelValue(id_a)); - queue.push(id_a); - return processQueue(queue, id_a); -} - -bool InequalityGraph::updateValue(TermId id, ModelValue new_mv, TermId start, bool& changed) { - BitVector lower_bound = new_mv.value; - - if (isConst(id)) { - if (getValue(id) < lower_bound) { - Debug("bv-inequality") << "Conflict: constant " << getValue(id) << "\n"; - std::vector<ReasonId> conflict; - TermId parent = new_mv.parent; - ReasonId reason = new_mv.reason; - conflict.push_back(reason); - computeExplanation(UndefinedTermId, parent, conflict); - Debug("bv-inequality") << "InequalityGraph::addInequality conflict: constant\n"; - setConflict(conflict); - return false; - } - } else { - // if not constant we can try to update the value - if (getValue(id) < lower_bound) { - // if we are updating the term we started with we must be in a cycle - if (id == start) { - TermId parent = new_mv.parent; - ReasonId reason = new_mv.reason; - std::vector<TermId> conflict; - conflict.push_back(reason); - computeExplanation(id, parent, conflict); - Debug("bv-inequality") << "InequalityGraph::addInequality conflict: cycle \n"; - setConflict(conflict); - return false; - } - Debug("bv-inequality-internal") << "Updating " << getTermNode(id) - << " from " << getValue(id) << "\n" - << " to " << lower_bound << "\n"; - changed = true; - setModelValue(id, new_mv); - } - } - return true; -} - -bool InequalityGraph::processQueue(BFSQueue& queue, TermId start) { - while (!queue.empty()) { - TermId current = queue.top(); - queue.pop(); - Debug("bv-inequality-internal") << "InequalityGraph::processQueue processing " << getTermNode(current) << "\n"; - - BitVector current_value = getValue(current); - - unsigned size = getBitwidth(current); - const BitVector zero(size, 0u); - const BitVector one(size, 1u); - - const Edges& edges = getEdges(current); - for (Edges::const_iterator it = edges.begin(); it!= edges.end(); ++it) { - TermId next = it->next; - ReasonId reason = it->reason; - - const BitVector increment = it->strict ? one : zero; - const BitVector next_lower_bound = current_value + increment; - - if (next_lower_bound < current_value) { - // it means we have an overflow and hence a conflict - std::vector<TermId> conflict; - conflict.push_back(it->reason); - Assert(hasModelValue(start)); - ReasonId start_reason = getModelValue(start).reason; - if (start_reason != UndefinedReasonId) { - conflict.push_back(start_reason); - } - computeExplanation(UndefinedTermId, current, conflict); - Debug("bv-inequality") << "InequalityGraph::addInequality conflict: cycle \n"; - setConflict(conflict); - return false; - } - - ModelValue new_mv(next_lower_bound, current, reason); - bool updated = false; - if (!updateValue(next, new_mv, start, updated)) { - return false; - } - - if (next == start) { - // we know what we didn't update start or we would have had a conflict - // this means we are in a cycle where all the values are forced to be equal - Debug("bv-inequality-internal") << "InequalityGraph::processQueue equal cycle."; - continue; - } - - if (!updated) { - // if we didn't update current we don't need to add to the queue it's children - Debug("bv-inequality-internal") << " unchanged " << getTermNode(next) << "\n"; - continue; - } - - queue.push(next); - Debug("bv-inequality-internal") << " enqueue " << getTermNode(next) << "\n"; - } - } - return true; -} - -void InequalityGraph::computeExplanation(TermId from, TermId to, std::vector<ReasonId>& explanation) { - if(Debug.isOn("bv-inequality")) { - if (from == UndefinedTermId) { - Debug("bv-inequality") << "InequalityGraph::computeExplanation " << getTermNode(to) << "\n"; - } else { - Debug("bv-inequality") << "InequalityGraph::computeExplanation " << getTermNode(from) <<" => " - << getTermNode(to) << "\n"; - } - } - - TermIdSet seen; - - while(hasReason(to) && from != to && !seen.count(to)) { - seen.insert(to); - const ModelValue& exp = getModelValue(to); - Assert(exp.reason != UndefinedReasonId); - explanation.push_back(exp.reason); - Assert(exp.parent != UndefinedTermId); - to = exp.parent; - Debug("bv-inequality-internal") << " parent: " << getTermNode(to) << "\n" - << " reason: " << getReasonNode(exp.reason) << "\n"; - } -} - -void InequalityGraph::addEdge(TermId a, TermId b, bool strict, TermId reason) { - Debug("bv-inequality-internal") << "InequalityGraph::addEdge " << getTermNode(a) << " => " << getTermNode(b) << "\n" - << " strict ? " << strict << "\n"; - Edges& edges = getEdges(a); - InequalityEdge new_edge(b, strict, reason); - edges.push_back(new_edge); - d_undoStack.push_back(std::make_pair(a, new_edge)); - d_undoStackIndex = d_undoStackIndex + 1; -} - -void InequalityGraph::initializeModelValue(TNode node) { - TermId id = getTermId(node); - Assert(!hasModelValue(id)); - bool isConst = node.getKind() == kind::CONST_BITVECTOR; - unsigned size = utils::getSize(node); - BitVector value = isConst? node.getConst<BitVector>() : BitVector(size, 0u); - setModelValue(id, ModelValue(value, UndefinedTermId, UndefinedReasonId)); -} - -bool InequalityGraph::isRegistered(TNode term) const { - return d_termNodeToIdMap.find(term) != d_termNodeToIdMap.end(); -} - -TermId InequalityGraph::registerTerm(TNode term) { - if (d_termNodeToIdMap.find(term) != d_termNodeToIdMap.end()) { - TermId id = d_termNodeToIdMap[term]; - if (!hasModelValue(id)) { - // we could have backtracked and - initializeModelValue(term); - } - return id; - } - - // store in node mapping - TermId id = d_termNodes.size(); - Debug("bv-inequality-internal") << "InequalityGraph::registerTerm " << term << " => id"<< id << "\n"; - - d_termNodes.push_back(term); - d_termNodeToIdMap[term] = id; - - // create InequalityNode - unsigned size = utils::getSize(term); - - bool isConst = term.getKind() == kind::CONST_BITVECTOR; - InequalityNode ineq = InequalityNode(id, size, isConst); - - Assert(d_ineqNodes.size() == id); - d_ineqNodes.push_back(ineq); - - Assert(d_ineqEdges.size() == id); - d_ineqEdges.push_back(Edges()); - - initializeModelValue(term); - - return id; -} - -ReasonId InequalityGraph::registerReason(TNode reason) { - if (d_reasonToIdMap.find(reason) != d_reasonToIdMap.end()) { - return d_reasonToIdMap[reason]; - } - d_reasonSet.insert(reason); - ReasonId id = d_reasonNodes.size(); - d_reasonNodes.push_back(reason); - d_reasonToIdMap[reason] = id; - Debug("bv-inequality-internal") << "InequalityGraph::registerReason " << reason << " => id"<< id << "\n"; - return id; -} - -TNode InequalityGraph::getReasonNode(ReasonId id) const { - Assert(d_reasonNodes.size() > id); - return d_reasonNodes[id]; -} - -TNode InequalityGraph::getTermNode(TermId id) const { - Assert(d_termNodes.size() > id); - return d_termNodes[id]; -} - -TermId InequalityGraph::getTermId(TNode node) const { - Assert(d_termNodeToIdMap.find(node) != d_termNodeToIdMap.end()); - return d_termNodeToIdMap.find(node)->second; -} - -void InequalityGraph::setConflict(const std::vector<ReasonId>& conflict) { - Assert(!d_inConflict); - d_inConflict = true; - d_conflict.clear(); - for (unsigned i = 0; i < conflict.size(); ++i) { - if (conflict[i] != AxiomReasonId) { - d_conflict.push_back(getReasonNode(conflict[i])); - } - } - if (Debug.isOn("bv-inequality")) { - Debug("bv-inequality") << "InequalityGraph::setConflict \n"; - for (unsigned i = 0; i < d_conflict.size(); ++i) { - Debug("bv-inequality") << " " << d_conflict[i] <<"\n"; - } - } -} - -void InequalityGraph::getConflict(std::vector<TNode>& conflict) { - for (unsigned i = 0; i < d_conflict.size(); ++i) { - conflict.push_back(d_conflict[i]); - } -} - -void InequalityGraph::setModelValue(TermId term, const ModelValue& mv) { - d_modelValues[term] = mv; -} - -InequalityGraph::ModelValue InequalityGraph::getModelValue(TermId term) const { - Assert(d_modelValues.find(term) != d_modelValues.end()); - return (*(d_modelValues.find(term))).second; -} - -bool InequalityGraph::hasModelValue(TermId id) const { - return d_modelValues.find(id) != d_modelValues.end(); -} - -BitVector InequalityGraph::getValue(TermId id) const { - Assert(hasModelValue(id)); - return (*(d_modelValues.find(id))).second.value; -} - -bool InequalityGraph::hasReason(TermId id) const { - const ModelValue& mv = getModelValue(id); - return mv.reason != UndefinedReasonId; -} - -bool InequalityGraph::addDisequality(TNode a, TNode b, TNode reason) { - Debug("bv-inequality") << "InequalityGraph::addDisequality " << reason << "\n"; - d_disequalities.push_back(reason); - - if (!isRegistered(a) || !isRegistered(b)) { - //splitDisequality(reason); - return true; - } - TermId id_a = getTermId(a); - TermId id_b = getTermId(b); - if (!hasModelValue(id_a)) { - initializeModelValue(a); - } - if (!hasModelValue(id_b)) { - initializeModelValue(b); - } - const BitVector val_a = getValue(id_a); - const BitVector val_b = getValue(id_b); - if (val_a == val_b) { - if (a.getKind() == kind::CONST_BITVECTOR) { - // then we know b cannot be smaller than the assigned value so we try to make it larger - std::vector<ReasonId> explanation_ids; - computeExplanation(UndefinedTermId, id_b, explanation_ids); - std::vector<TNode> explanation_nodes; - explanation_nodes.push_back(reason); - for (unsigned i = 0; i < explanation_ids.size(); ++i) { - explanation_nodes.push_back(getReasonNode(explanation_ids[i])); - } - Node explanation = utils::mkAnd(explanation_nodes); - d_reasonSet.insert(explanation); - return addInequality(a, b, true, explanation); - } - if (b.getKind() == kind::CONST_BITVECTOR) { - // then we know b cannot be smaller than the assigned value so we try to make it larger - std::vector<ReasonId> explanation_ids; - computeExplanation(UndefinedTermId, id_a, explanation_ids); - std::vector<TNode> explanation_nodes; - explanation_nodes.push_back(reason); - for (unsigned i = 0; i < explanation_ids.size(); ++i) { - explanation_nodes.push_back(getReasonNode(explanation_ids[i])); - } - Node explanation = utils::mkAnd(explanation_nodes); - d_reasonSet.insert(explanation); - return addInequality(b, a, true, explanation); - } - // if none of the terms are constants just add the lemma - //splitDisequality(reason); - } else { - Debug("bv-inequality-internal") << "Disequal: " << a << " => " << val_a.toString(10) << "\n" - << " " << b << " => " << val_b.toString(10) << "\n"; - } - return true; -} - -// void InequalityGraph::splitDisequality(TNode diseq) { -// Debug("bv-inequality-internal")<<"InequalityGraph::splitDisequality " << -// diseq <<"\n"; Assert (diseq.getKind() == kind::NOT && -// diseq[0].getKind() == kind::EQUAL); if -// (d_disequalitiesAlreadySplit.find(diseq) == -// d_disequalitiesAlreadySplit.end()) { -// d_disequalitiesToSplit.push_back(diseq); -// } -// } - -void InequalityGraph::backtrack() { - Debug("bv-inequality-internal") << "InequalityGraph::backtrack()\n"; - int size = d_undoStack.size(); - for (int i = size - 1; i >= (int)d_undoStackIndex.get(); --i) { - Assert(!d_undoStack.empty()); - TermId id = d_undoStack.back().first; - InequalityEdge edge = d_undoStack.back().second; - d_undoStack.pop_back(); - - Debug("bv-inequality-internal") << " remove edge " << getTermNode(id) << " => " - << getTermNode(edge.next) <<"\n"; - Edges& edges = getEdges(id); - for (Edges::const_iterator it = edges.begin(); it!= edges.end(); ++it) { - Debug("bv-inequality-internal") << getTermNode(it->next) <<" " << it->strict << "\n"; - } - Assert(!edges.empty()); - Assert(edges.back() == edge); - edges.pop_back(); - } -} - -Node InequalityGraph::makeDiseqSplitLemma(TNode diseq) -{ - Assert(diseq.getKind() == kind::NOT && diseq[0].getKind() == kind::EQUAL); - NodeManager* nm = NodeManager::currentNM(); - TNode a = diseq[0][0]; - TNode b = diseq[0][1]; - Node a_lt_b = nm->mkNode(kind::BITVECTOR_ULT, a, b); - Node b_lt_a = nm->mkNode(kind::BITVECTOR_ULT, b, a); - Node eq = diseq[0]; - Node lemma = nm->mkNode(kind::OR, a_lt_b, b_lt_a, eq); - return lemma; -} - -void InequalityGraph::checkDisequalities(std::vector<Node>& lemmas) { - for (CDQueue<TNode>::const_iterator it = d_disequalities.begin(); it != d_disequalities.end(); ++it) { - if (d_disequalitiesAlreadySplit.find(*it) == d_disequalitiesAlreadySplit.end()) { - // if we haven't already split on this disequality - TNode diseq = *it; - TermId a_id = registerTerm(diseq[0][0]); - TermId b_id = registerTerm(diseq[0][1]); - if (getValue(a_id) == getValue(b_id)) { - lemmas.push_back(makeDiseqSplitLemma(diseq)); - d_disequalitiesAlreadySplit.insert(diseq); - } - } - } -} - -bool InequalityGraph::isLessThan(TNode a, TNode b) { - Assert(isRegistered(a) && isRegistered(b)); - Unimplemented(); -} - -bool InequalityGraph::hasValueInModel(TNode node) const { - if (isRegistered(node)) { - TermId id = getTermId(node); - return hasModelValue(id); - } - return false; -} - -BitVector InequalityGraph::getValueInModel(TNode node) const { - TermId id = getTermId(node); - Assert(hasModelValue(id)); - return getValue(id); -} - -void InequalityGraph::getAllValuesInModel(std::vector<Node>& assignments) -{ - NodeManager* nm = NodeManager::currentNM(); - for (ModelValues::const_iterator it = d_modelValues.begin(); - it != d_modelValues.end(); - ++it) - { - TermId id = (*it).first; - BitVector value = (*it).second.value; - TNode var = getTermNode(id); - Node constant = utils::mkConst(value); - Node assignment = nm->mkNode(kind::EQUAL, var, constant); - assignments.push_back(assignment); - Debug("bitvector-model") << " " << var << " => " << constant << "\n"; - } -} diff --git a/src/theory/bv/bv_inequality_graph.h b/src/theory/bv/bv_inequality_graph.h deleted file mode 100644 index ba545e48b..000000000 --- a/src/theory/bv/bv_inequality_graph.h +++ /dev/null @@ -1,297 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Liana Hadarean, Mathias Preiner, Tim King - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * Algebraic solver. - */ - -#include "cvc5_private.h" - -#ifndef CVC5__THEORY__BV__BV_INEQUALITY__GRAPH_H -#define CVC5__THEORY__BV__BV_INEQUALITY__GRAPH_H - -#include <queue> -#include <unordered_map> -#include <unordered_set> - -#include "context/cdhashmap.h" -#include "context/cdhashset.h" -#include "context/cdo.h" -#include "context/cdqueue.h" -#include "context/context.h" -#include "util/bitvector.h" - -namespace cvc5 { -namespace theory { -namespace bv { - -typedef unsigned TermId; -typedef unsigned ReasonId; -extern const TermId UndefinedTermId; -extern const ReasonId UndefinedReasonId; -extern const ReasonId AxiomReasonId; - -class InequalityGraph : public context::ContextNotifyObj{ - - struct InequalityEdge { - TermId next; - ReasonId reason; - bool strict; - InequalityEdge(TermId n, bool s, ReasonId r) - : next(n), - reason(r), - strict(s) - {} - bool operator==(const InequalityEdge& other) const { - return next == other.next && reason == other.reason && strict == other.strict; - } - }; - - class InequalityNode { - TermId d_id; - unsigned d_bitwidth; - bool d_isConstant; - public: - InequalityNode(TermId id, unsigned bitwidth, bool isConst) - : d_id(id), - d_bitwidth(bitwidth), - d_isConstant(isConst) - {} - TermId getId() const { return d_id; } - unsigned getBitwidth() const { return d_bitwidth; } - bool isConstant() const { return d_isConstant; } - }; - - struct ModelValue { - TermId parent; - ReasonId reason; - BitVector value; - ModelValue() - : parent(UndefinedTermId), - reason(UndefinedReasonId), - value(0, 0u) - {} - - ModelValue(const BitVector& val, TermId p, ReasonId r) - : parent(p), - reason(r), - value(val) - {} - }; - - typedef context::CDHashMap<TermId, ModelValue> ModelValues; - - struct QueueComparator { - const ModelValues* d_model; - QueueComparator(const ModelValues* model) - : d_model(model) - {} - bool operator() (TermId left, TermId right) const { - Assert(d_model->find(left) != d_model->end() - && d_model->find(right) != d_model->end()); - - return (*(d_model->find(left))).second.value < (*(d_model->find(right))).second.value; - } - }; - - typedef std::unordered_map<TNode, ReasonId> ReasonToIdMap; - typedef std::unordered_map<TNode, TermId> TermNodeToIdMap; - - typedef std::vector<InequalityEdge> Edges; - typedef std::unordered_set<TermId> TermIdSet; - - typedef std::priority_queue<TermId, std::vector<TermId>, QueueComparator> - BFSQueue; - typedef std::unordered_set<TNode> TNodeSet; - typedef std::unordered_set<Node> NodeSet; - - std::vector<InequalityNode> d_ineqNodes; - std::vector< Edges > d_ineqEdges; - - // to keep the explanation nodes alive - NodeSet d_reasonSet; - std::vector<TNode> d_reasonNodes; - ReasonToIdMap d_reasonToIdMap; - - std::vector<Node> d_termNodes; - TermNodeToIdMap d_termNodeToIdMap; - - context::CDO<bool> d_inConflict; - std::vector<TNode> d_conflict; - - ModelValues d_modelValues; - void initializeModelValue(TNode node); - void setModelValue(TermId term, const ModelValue& mv); - ModelValue getModelValue(TermId term) const; - bool hasModelValue(TermId id) const; - bool hasReason(TermId id) const; - - /** - * Registers the term by creating its corresponding InequalityNode - * and adding the min <= term <= max default edges. - * - * @param term - * - * @return - */ - TermId registerTerm(TNode term); - TNode getTermNode(TermId id) const; - TermId getTermId(TNode node) const; - bool isRegistered(TNode term) const; - - ReasonId registerReason(TNode reason); - TNode getReasonNode(ReasonId id) const; - - Edges& getEdges(TermId id) - { - Assert(id < d_ineqEdges.size()); - return d_ineqEdges[id]; - } - InequalityNode& getInequalityNode(TermId id) - { - Assert(id < d_ineqNodes.size()); - return d_ineqNodes[id]; - } - const InequalityNode& getInequalityNode(TermId id) const - { - Assert(id < d_ineqNodes.size()); - return d_ineqNodes[id]; - } - unsigned getBitwidth(TermId id) const { return getInequalityNode(id).getBitwidth(); } - bool isConst(TermId id) const { return getInequalityNode(id).isConstant(); } - - BitVector getValue(TermId id) const; - - void addEdge(TermId a, TermId b, bool strict, TermId reason); - - void setConflict(const std::vector<ReasonId>& conflict); - /** - * If necessary update the value in the model of the current queue element. - * - * @param id current queue element we are updating - * @param start node we started with, to detect cycles - * - * @return - */ - bool updateValue(TermId id, ModelValue new_mv, TermId start, bool& changed); - /** - * Update the current model starting with the start term. - * - * @param queue - * @param start - * - * @return - */ - bool processQueue(BFSQueue& queue, TermId start); - /** - * Return the reasons why from <= to. If from is undefined we just - * explain the current value of to. - * - * @param from - * @param to - * @param explanation - */ - void computeExplanation(TermId from, TermId to, std::vector<ReasonId>& explanation); - // void splitDisequality(TNode diseq); - - /** - Disequality reasoning - */ - - /*** The currently asserted disequalities */ - context::CDQueue<TNode> d_disequalities; - typedef context::CDHashSet<Node> CDNodeSet; - CDNodeSet d_disequalitiesAlreadySplit; - Node makeDiseqSplitLemma(TNode diseq); - /** Backtracking mechanisms **/ - std::vector<std::pair<TermId, InequalityEdge> > d_undoStack; - context::CDO<unsigned> d_undoStackIndex; - - void contextNotifyPop() override { backtrack(); } - - void backtrack(); - -public: - - InequalityGraph(context::Context* c, context::Context* u, bool s = false) - : ContextNotifyObj(c), - d_ineqNodes(), - d_ineqEdges(), - d_inConflict(c, false), - d_conflict(), - d_modelValues(c), - d_disequalities(c), - d_disequalitiesAlreadySplit(u), - d_undoStack(), - d_undoStackIndex(c) - {} - /** - * Add a new inequality to the graph - * - * @param a - * @param b - * @param strict - * @param reason - * - * @return - */ - bool addInequality(TNode a, TNode b, bool strict, TNode reason); - /** - * Add a new disequality to the graph. This may lead in a lemma. - * - * @param a - * @param b - * @param reason - * - * @return - */ - bool addDisequality(TNode a, TNode b, TNode reason); - void getConflict(std::vector<TNode>& conflict); - virtual ~InequalityGraph() {} - /** - * Check that the currently asserted disequalities that have not been split on - * are still true in the current model. - */ - void checkDisequalities(std::vector<Node>& lemmas); - /** - * Return true if a < b is entailed by the current set of assertions. - * - * @param a - * @param b - * - * @return - */ - bool isLessThan(TNode a, TNode b); - /** - * Returns true if the term has a value in the model (i.e. if we have seen it) - * - * @param a - * - * @return - */ - bool hasValueInModel(TNode a) const; - /** - * Return the value of a in the current model. - * - * @param a - * - * @return - */ - BitVector getValueInModel(TNode a) const; - - void getAllValuesInModel(std::vector<Node>& assignments); -}; - -} -} -} // namespace cvc5 - -#endif /* CVC5__THEORY__BV__BV_INEQUALITY__GRAPH_H */ diff --git a/src/theory/bv/bv_quick_check.cpp b/src/theory/bv/bv_quick_check.cpp deleted file mode 100644 index dd9c1849d..000000000 --- a/src/theory/bv/bv_quick_check.cpp +++ /dev/null @@ -1,373 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Liana Hadarean, Tim King, Mathias Preiner - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * Wrapper around the SAT solver used for bitblasting. - */ - -#include "theory/bv/bv_quick_check.h" - -#include "smt/smt_statistics_registry.h" -#include "theory/bv/bitblast/lazy_bitblaster.h" -#include "theory/bv/bv_solver_layered.h" -#include "theory/bv/theory_bv_utils.h" - -using namespace cvc5::prop; - -namespace cvc5 { -namespace theory { -namespace bv { - -BVQuickCheck::BVQuickCheck(const std::string& name, - theory::bv::BVSolverLayered* bv) - : d_ctx(), - d_bitblaster(new TLazyBitblaster(&d_ctx, bv, name, true)), - d_conflict(), - d_inConflict(&d_ctx, false) -{} - - -bool BVQuickCheck::inConflict() { return d_inConflict.get(); } - -uint64_t BVQuickCheck::computeAtomWeight(TNode node, NodeSet& seen) { - return d_bitblaster->computeAtomWeight(node, seen); -} - -void BVQuickCheck::setConflict() -{ - Assert(!inConflict()); - std::vector<TNode> conflict; - d_bitblaster->getConflict(conflict); - Node confl = utils::mkAnd(conflict); - d_inConflict = true; - d_conflict = confl; -} - -prop::SatValue BVQuickCheck::checkSat(std::vector<Node>& assumptions, unsigned long budget) { - Node conflict; - - for (unsigned i = 0; i < assumptions.size(); ++i) { - TNode a = assumptions[i]; - Assert(a.getType().isBoolean()); - d_bitblaster->bbAtom(a); - bool ok = d_bitblaster->assertToSat(a, false); - if (!ok) { - setConflict(); - return SAT_VALUE_FALSE; - } - } - - if (budget == 0) { - bool ok = d_bitblaster->propagate(); - if (!ok) { - setConflict(); - return SAT_VALUE_FALSE; - } - return SAT_VALUE_UNKNOWN; // could check if assignment is full and return SAT_VALUE_TRUE - } - - prop::SatValue res = d_bitblaster->solveWithBudget(budget); - if (res == SAT_VALUE_FALSE) { - setConflict(); - return res; - } - // could be unknown or could be sat - return res; -} - -prop::SatValue BVQuickCheck::checkSat(unsigned long budget) { - prop::SatValue res = d_bitblaster->solveWithBudget(budget); - if (res == SAT_VALUE_FALSE) { - setConflict(); - } - return res; -} - -bool BVQuickCheck::addAssertion(TNode assertion) { - Assert(assertion.getType().isBoolean()); - d_bitblaster->bbAtom(assertion); - // assert to sat solver and run bcp to detect easy conflicts - bool ok = d_bitblaster->assertToSat(assertion, true); - if (!ok) { - setConflict(); - } - return ok; -} - - -void BVQuickCheck::push() { - d_ctx.push(); -} - -void BVQuickCheck::pop() { - d_ctx.pop(); -} - -BVQuickCheck::vars_iterator BVQuickCheck::beginVars() { - return d_bitblaster->beginVars(); -} -BVQuickCheck::vars_iterator BVQuickCheck::endVars() { - return d_bitblaster->endVars(); -} - -Node BVQuickCheck::getVarValue(TNode var, bool fullModel) { - return d_bitblaster->getTermModel(var, fullModel); -} - - -/** - * Constructs a new sat solver which requires throwing out the atomBBCache - * but keeps all the termBBCache - * - */ -void BVQuickCheck::clearSolver() { - popToZero(); - d_bitblaster->clearSolver(); -} - -void BVQuickCheck::popToZero() { - while (d_ctx.getLevel() > 0) { - d_ctx.pop(); - } -} - -bool BVQuickCheck::collectModelValues(theory::TheoryModel* model, - const std::set<Node>& termSet) -{ - return d_bitblaster->collectModelValues(model, termSet); -} - -BVQuickCheck::~BVQuickCheck() { - clearSolver(); -} - -QuickXPlain::QuickXPlain(const std::string& name, BVQuickCheck* solver, unsigned long budget) - : d_solver(solver) - , d_budget(budget) - , d_numCalled(0) - , d_minRatioSum(0) - , d_numConflicts(0) - // , d_period(20) - // , d_thresh(0.7) - // , d_hardThresh(0.9) - , d_statistics(name) -{} -QuickXPlain::~QuickXPlain() {} - -unsigned QuickXPlain::selectUnsatCore(unsigned low, unsigned high, - std::vector<TNode>& conflict) { - Assert(!d_solver->getConflict().isNull() && d_solver->inConflict()); - Node query_confl = d_solver->getConflict(); - - // conflict wasn't actually minimized - if (query_confl.getNumChildren() == high - low + 1) { - return high; - } - - TNodeSet nodes; - for (unsigned i = low; i <= high; i++) { - nodes.insert(conflict[i]); - } - - unsigned write = low; - for (unsigned i = 0; i < query_confl.getNumChildren(); ++i) { - TNode current = query_confl[i]; - // the conflict can have nodes in lower decision levels - if (nodes.find(current) != nodes.end()) { - conflict[write++] = current; - nodes.erase(nodes.find(current)); - } - } - // if all of the nodes in the conflict were on a lower level - if (write == low) { - return low; - } - Assert(write != 0); - unsigned new_high = write - 1; - - for (TNodeSet::const_iterator it = nodes.begin(); it != nodes.end(); ++it) { - conflict[write++] = *it; - } - Assert(write - 1 == high); - Assert(new_high <= high); - - return new_high; -} - -void QuickXPlain::minimizeConflictInternal(unsigned low, unsigned high, - std::vector<TNode>& conflict, - std::vector<TNode>& new_conflict) { - Assert(low <= high && high < conflict.size()); - - if (low == high) { - new_conflict.push_back(conflict[low]); - return; - } - - // check if top half is unsat - unsigned new_low = (high - low + 1)/ 2 + low; - d_solver->push(); - - for (unsigned i = new_low; i <=high; ++i) { - bool ok = d_solver->addAssertion(conflict[i]); - if (!ok) { - unsigned top = selectUnsatCore(new_low, i, conflict); - d_solver->pop(); - minimizeConflictInternal(new_low, top, conflict, new_conflict); - return; - } - } - - SatValue res = d_solver->checkSat(d_budget); - - if (res == SAT_VALUE_UNKNOWN) { - ++(d_statistics.d_numUnknown); - } else { - ++(d_statistics.d_numSolved); - } - - if (res == SAT_VALUE_FALSE) { - unsigned top = selectUnsatCore(new_low, high, conflict); - d_solver->pop(); - minimizeConflictInternal(new_low, top, conflict, new_conflict); - return; - } - - d_solver->pop(); - unsigned new_high = new_low - 1; - d_solver->push(); - - // check bottom half - for (unsigned i = low; i <= new_high; ++i) { - bool ok = d_solver->addAssertion(conflict[i]); - if (!ok) { - unsigned top = selectUnsatCore(low, i, conflict); - d_solver->pop(); - minimizeConflictInternal(low, top, conflict, new_conflict); - return; - } - } - - res = d_solver->checkSat(d_budget); - - if (res == SAT_VALUE_UNKNOWN) { - ++(d_statistics.d_numUnknown); - } else { - ++(d_statistics.d_numSolved); - } - - if (res == SAT_VALUE_FALSE) { - unsigned top = selectUnsatCore(low, new_high, conflict); - d_solver->pop(); - minimizeConflictInternal(low, top, conflict, new_conflict); - return; - } - - // conflict (probably) contains literals in both halves - // keep bottom half in context (no pop) - minimizeConflictInternal(new_low, high, conflict, new_conflict); - d_solver->pop(); - d_solver->push(); - for (unsigned i = 0; i < new_conflict.size(); ++i) { - bool ok = d_solver->addAssertion(new_conflict[i]); - if (!ok) { - ++(d_statistics.d_numUnknownWasUnsat); - d_solver->pop(); - return; - } - } - minimizeConflictInternal(low, new_high, conflict, new_conflict); - d_solver->pop(); -} - - -bool QuickXPlain::useHeuristic() { - return true; - // d_statistics.d_finalPeriod.setData(d_period); - // // try to minimize conflict periodically - // if (d_numConflicts % d_period == 0) - // return true; - - // if (d_numCalled == 0) { - // return true; - // } - - // if (d_minRatioSum / d_numCalled >= d_thresh && - // d_numCalled <= 20 ) { - // return false; - // } - - // if (d_minRatioSum / d_numCalled >= d_hardThresh) { - // return false; - // } - - // return true; -} - -Node QuickXPlain::minimizeConflict(TNode confl) { - ++d_numConflicts; - - if (!useHeuristic()) { - return confl; - } - - ++d_numCalled; - ++(d_statistics.d_numConflictsMinimized); - TimerStat::CodeTimer xplainTimer(d_statistics.d_xplainTime); - Assert(confl.getNumChildren() > 2); - std::vector<TNode> conflict; - for (unsigned i = 0; i < confl.getNumChildren(); ++i) { - conflict.push_back(confl[i]); - } - d_solver->popToZero(); - std::vector<TNode> minimized; - minimizeConflictInternal(0, conflict.size() - 1, conflict, minimized); - - double minimization_ratio = ((double) minimized.size())/confl.getNumChildren(); - d_minRatioSum+= minimization_ratio; - - - // if (minimization_ratio >= d_hardThresh) { - // d_period = d_period * 5; - // } - - // if (minimization_ratio <= d_thresh && d_period >= 40) { - // d_period = d_period *0.5; - // } - - // if (1.5* d_statistics.d_numUnknown.getData() > d_statistics.d_numSolved.getData()) { - // d_period = d_period * 2; - // } - d_statistics.d_avgMinimizationRatio << minimization_ratio; - return utils::mkAnd(minimized); -} - -QuickXPlain::Statistics::Statistics(const std::string& name) - : d_xplainTime( - smtStatisticsRegistry().registerTimer(name + "QuickXplain::Time")), - d_numSolved( - smtStatisticsRegistry().registerInt(name + "QuickXplain::NumSolved")), - d_numUnknown(smtStatisticsRegistry().registerInt( - name + "QuickXplain::NumUnknown")), - d_numUnknownWasUnsat(smtStatisticsRegistry().registerInt( - name + "QuickXplain::NumUnknownWasUnsat")), - d_numConflictsMinimized(smtStatisticsRegistry().registerInt( - name + "QuickXplain::NumConflictsMinimized")), - d_finalPeriod(smtStatisticsRegistry().registerInt( - name + "QuickXplain::FinalPeriod")), - d_avgMinimizationRatio(smtStatisticsRegistry().registerAverage( - name + "QuickXplain::AvgMinRatio")) -{ -} - -} // namespace bv -} // namespace theory -} // namespace cvc5 diff --git a/src/theory/bv/bv_quick_check.h b/src/theory/bv/bv_quick_check.h deleted file mode 100644 index b8274ce80..000000000 --- a/src/theory/bv/bv_quick_check.h +++ /dev/null @@ -1,182 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Liana Hadarean, Mathias Preiner, Morgan Deters - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * Sandboxed SAT solver for bv quickchecks. - */ - -#include "cvc5_private.h" - -#ifndef CVC5__BV_QUICK_CHECK_H -#define CVC5__BV_QUICK_CHECK_H - -#include <unordered_set> -#include <vector> - -#include "context/cdo.h" -#include "expr/node.h" -#include "prop/sat_solver_types.h" -#include "theory/bv/theory_bv_utils.h" -#include "util/statistics_stats.h" - -namespace cvc5 { -namespace theory { - -class TheoryModel; - -namespace bv { - -class TLazyBitblaster; -class BVSolverLayered; - -class BVQuickCheck -{ - context::Context d_ctx; - std::unique_ptr<TLazyBitblaster> d_bitblaster; - Node d_conflict; - context::CDO<bool> d_inConflict; - void setConflict(); - - public: - BVQuickCheck(const std::string& name, theory::bv::BVSolverLayered* bv); - ~BVQuickCheck(); - bool inConflict(); - Node getConflict() { return d_conflict; } - /** - * Checks the satisfiability for a given set of assumptions. - * - * @param assumptions literals assumed true - * @param budget max number of conflicts - * - * @return - */ - prop::SatValue checkSat(std::vector<Node>& assumptions, unsigned long budget); - /** - * Checks the satisfiability of given assertions. - * - * @param budget max number of conflicts - * - * @return - */ - prop::SatValue checkSat(unsigned long budget); - - /** - * Convert to CNF and assert the given literal. - * - * @param assumption bv literal - * - * @return false if a conflict has been found via bcp. - */ - bool addAssertion(TNode assumption); - - void push(); - void pop(); - void popToZero(); - /** - * Deletes the SAT solver and CNF stream, but maintains the - * bit-blasting term cache. - * - */ - void clearSolver(); - - /** - * Computes the size of the circuit required to bit-blast - * atom, by not recounting the nodes in seen. - * - * @param node - * @param seen - * - * @return - */ - uint64_t computeAtomWeight(TNode atom, NodeSet& seen); - bool collectModelValues(theory::TheoryModel* model, - const std::set<Node>& termSet); - - typedef std::unordered_set<TNode>::const_iterator vars_iterator; - vars_iterator beginVars(); - vars_iterator endVars(); - - Node getVarValue(TNode var, bool fullModel); -}; - -class QuickXPlain -{ - struct Statistics - { - TimerStat d_xplainTime; - IntStat d_numSolved; - IntStat d_numUnknown; - IntStat d_numUnknownWasUnsat; - IntStat d_numConflictsMinimized; - IntStat d_finalPeriod; - AverageStat d_avgMinimizationRatio; - Statistics(const std::string& name); - }; - BVQuickCheck* d_solver; - unsigned long d_budget; - - // crazy heuristic variables - unsigned d_numCalled; // number of times called - double d_minRatioSum; // sum of minimization ratio for computing average min - // ratio - unsigned d_numConflicts; // number of conflicts (including when minimization - // not applied) - // unsigned d_period; // after how many conflicts to try minimizing again - - // double d_thresh; // if minimization ratio is less, increase period - // double d_hardThresh; // decrease period if minimization ratio is greater - // than this - - Statistics d_statistics; - /** - * Uses solve with assumptions unsat core feature to - * further minimize a conflict. The minimized conflict - * will be between low and the returned value in conflict. - * - * @param low - * @param high - * @param conflict - * - * @return - */ - unsigned selectUnsatCore(unsigned low, - unsigned high, - std::vector<TNode>& conflict); - /** - * Internal conflict minimization, attempts to minimize - * literals in conflict between low and high and adds the - * result in new_conflict. - * - * @param low - * @param high - * @param conflict - * @param new_conflict - */ - void minimizeConflictInternal(unsigned low, - unsigned high, - std::vector<TNode>& conflict, - std::vector<TNode>& new_conflict); - - bool useHeuristic(); - - public: - QuickXPlain(const std::string& name, - BVQuickCheck* solver, - unsigned long budged = 10000); - ~QuickXPlain(); - Node minimizeConflict(TNode conflict); -}; - -} // namespace bv -} // namespace theory -} // namespace cvc5 - -#endif /* CVC5__BV_QUICK_CHECK_H */ diff --git a/src/theory/bv/bv_solver.h b/src/theory/bv/bv_solver.h index 82d6a4a5d..535618270 100644 --- a/src/theory/bv/bv_solver.h +++ b/src/theory/bv/bv_solver.h @@ -111,15 +111,6 @@ class BVSolver : protected EnvObj */ virtual Node getValue(TNode node, bool initialize) { return Node::null(); } - /** Called by abstraction preprocessing pass. */ - virtual bool applyAbstraction(const std::vector<Node>& assertions, - std::vector<Node>& new_assertions) - { - new_assertions.insert( - new_assertions.end(), assertions.begin(), assertions.end()); - return false; - }; - protected: TheoryState& d_state; TheoryInferenceManager& d_im; diff --git a/src/theory/bv/bv_solver_bitblast_internal.cpp b/src/theory/bv/bv_solver_bitblast_internal.cpp index 0c43cddbf..1d864e72a 100644 --- a/src/theory/bv/bv_solver_bitblast_internal.cpp +++ b/src/theory/bv/bv_solver_bitblast_internal.cpp @@ -16,6 +16,7 @@ #include "theory/bv/bv_solver_bitblast_internal.h" +#include "options/bv_options.h" #include "proof/conv_proof_generator.h" #include "theory/bv/bitblast/bitblast_proof_generator.h" #include "theory/bv/theory_bv.h" @@ -103,6 +104,12 @@ void BVSolverBitblastInternal::addBBLemma(TNode fact) } } +bool BVSolverBitblastInternal::needsEqualityEngine(EeSetupInfo& esi) +{ + // Disable equality engine if --bitblast=eager is enabled. + return options().bv.bitblastMode != options::BitblastMode::EAGER; +} + bool BVSolverBitblastInternal::preNotifyFact( TNode atom, bool pol, TNode fact, bool isPrereg, bool isInternal) { @@ -141,7 +148,9 @@ bool BVSolverBitblastInternal::preNotifyFact( } } - return false; // Return false to enable equality engine reasoning in Theory. + // Disable the equality engine in --bitblast=eager mode. Otherwise return + // false to enable equality engine reasoning in Theory. + return options().bv.bitblastMode == options::BitblastMode::EAGER; } TrustNode BVSolverBitblastInternal::explain(TNode n) diff --git a/src/theory/bv/bv_solver_bitblast_internal.h b/src/theory/bv/bv_solver_bitblast_internal.h index 2c53b9056..08c618880 100644 --- a/src/theory/bv/bv_solver_bitblast_internal.h +++ b/src/theory/bv/bv_solver_bitblast_internal.h @@ -44,7 +44,7 @@ class BVSolverBitblastInternal : public BVSolver ProofNodeManager* pnm); ~BVSolverBitblastInternal() = default; - bool needsEqualityEngine(EeSetupInfo& esi) override { return true; } + bool needsEqualityEngine(EeSetupInfo& esi) override; void preRegisterTerm(TNode n) override {} diff --git a/src/theory/bv/bv_solver_layered.cpp b/src/theory/bv/bv_solver_layered.cpp deleted file mode 100644 index 8427c1a50..000000000 --- a/src/theory/bv/bv_solver_layered.cpp +++ /dev/null @@ -1,553 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Mathias Preiner, Liana Hadarean, Andrew Reynolds - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * Layered bit-vector solver. - */ - -#include "theory/bv/bv_solver_layered.h" - -#include "expr/node_algorithm.h" -#include "options/bv_options.h" -#include "options/smt_options.h" -#include "smt/smt_statistics_registry.h" -#include "theory/bv/abstraction.h" -#include "theory/bv/bv_eager_solver.h" -#include "theory/bv/bv_subtheory_algebraic.h" -#include "theory/bv/bv_subtheory_bitblast.h" -#include "theory/bv/bv_subtheory_core.h" -#include "theory/bv/bv_subtheory_inequality.h" -#include "theory/bv/theory_bv_rewrite_rules_normalization.h" -#include "theory/bv/theory_bv_rewrite_rules_simplification.h" -#include "theory/bv/theory_bv_rewriter.h" -#include "theory/bv/theory_bv_utils.h" -#include "theory/theory_model.h" - -using namespace cvc5::theory::bv::utils; - -namespace cvc5 { -namespace theory { -namespace bv { - -BVSolverLayered::BVSolverLayered(Env& env, - TheoryBV& bv, - context::Context* c, - context::UserContext* u, - ProofNodeManager* pnm, - std::string name) - : BVSolver(env, bv.d_state, bv.d_im), - d_bv(bv), - d_context(c), - d_alreadyPropagatedSet(c), - d_sharedTermsSet(c), - d_subtheories(), - d_subtheoryMap(), - d_statistics(), - d_lemmasAdded(c, false), - d_conflict(c, false), - d_invalidateModelCache(c, true), - d_literalsToPropagate(c), - d_literalsToPropagateIndex(c, 0), - d_propagatedBy(c), - d_eagerSolver(), - d_abstractionModule(new AbstractionModule(getStatsPrefix(THEORY_BV))), - d_calledPreregister(false) -{ - if (options().bv.bitblastMode == options::BitblastMode::EAGER) - { - d_eagerSolver.reset(new EagerBitblastSolver(c, this)); - return; - } - - if (options().bv.bitvectorEqualitySolver) - { - d_subtheories.emplace_back(new CoreSolver(c, this)); - d_subtheoryMap[SUB_CORE] = d_subtheories.back().get(); - } - - if (options().bv.bitvectorInequalitySolver) - { - d_subtheories.emplace_back(new InequalitySolver(c, u, this)); - d_subtheoryMap[SUB_INEQUALITY] = d_subtheories.back().get(); - } - - if (options().bv.bitvectorAlgebraicSolver) - { - d_subtheories.emplace_back(new AlgebraicSolver(c, this)); - d_subtheoryMap[SUB_ALGEBRAIC] = d_subtheories.back().get(); - } - - BitblastSolver* bb_solver = new BitblastSolver(c, this); - if (options().bv.bvAbstraction) - { - bb_solver->setAbstraction(d_abstractionModule.get()); - } - d_subtheories.emplace_back(bb_solver); - d_subtheoryMap[SUB_BITBLAST] = bb_solver; -} - -BVSolverLayered::~BVSolverLayered() {} - -bool BVSolverLayered::needsEqualityEngine(EeSetupInfo& esi) -{ - CoreSolver* core = (CoreSolver*)d_subtheoryMap[SUB_CORE]; - if (core) - { - return core->needsEqualityEngine(esi); - } - // otherwise we don't use an equality engine - return false; -} - -void BVSolverLayered::finishInit() -{ - CoreSolver* core = (CoreSolver*)d_subtheoryMap[SUB_CORE]; - if (core) - { - // must finish initialization in the core solver - core->finishInit(); - } -} - -void BVSolverLayered::spendResource(Resource r) { d_im.spendResource(r); } - -BVSolverLayered::Statistics::Statistics() - : d_avgConflictSize(smtStatisticsRegistry().registerAverage( - "theory::bv::lazy::AvgBVConflictSize")), - d_solveTimer(smtStatisticsRegistry().registerTimer( - "theory::bv::lazy::solveTimer")), - d_numCallsToCheckFullEffort(smtStatisticsRegistry().registerInt( - "theory::bv::lazy::NumFullCheckCalls")), - d_numCallsToCheckStandardEffort(smtStatisticsRegistry().registerInt( - "theory::bv::lazy::NumStandardCheckCalls")), - d_weightComputationTimer(smtStatisticsRegistry().registerTimer( - "theory::bv::lazy::weightComputationTimer")), - d_numMultSlice(smtStatisticsRegistry().registerInt( - "theory::bv::lazy::NumMultSliceApplied")) -{ -} - -void BVSolverLayered::preRegisterTerm(TNode node) -{ - d_calledPreregister = true; - Debug("bitvector-preregister") - << "BVSolverLayered::preRegister(" << node << ")" << std::endl; - - if (options().bv.bitblastMode == options::BitblastMode::EAGER) - { - // the aig bit-blaster option is set heuristically - // if bv abstraction is used - if (!d_eagerSolver->isInitialized()) - { - d_eagerSolver->initialize(); - } - - if (node.getKind() == kind::BITVECTOR_EAGER_ATOM) - { - Node formula = node[0]; - d_eagerSolver->assertFormula(formula); - } - return; - } - - for (unsigned i = 0; i < d_subtheories.size(); ++i) - { - d_subtheories[i]->preRegister(node); - } - - // AJR : equality solver currently registers all terms to ExtTheory, if we - // want a lazy reduction without the bv equality solver, need to call this - // d_bv.d_extTheory->registerTermRec( node ); -} - -void BVSolverLayered::sendConflict() -{ - Assert(d_conflict); - if (d_conflictNode.isNull()) - { - return; - } - else - { - Debug("bitvector") << indent() << "BVSolverLayered::check(): conflict " - << d_conflictNode << std::endl; - d_im.conflict(d_conflictNode, InferenceId::BV_LAYERED_CONFLICT); - d_statistics.d_avgConflictSize << d_conflictNode.getNumChildren(); - d_conflictNode = Node::null(); - } -} - -void BVSolverLayered::checkForLemma(TNode fact) -{ - if (fact.getKind() == kind::EQUAL) - { - NodeManager* nm = NodeManager::currentNM(); - if (fact[0].getKind() == kind::BITVECTOR_UREM) - { - TNode urem = fact[0]; - TNode result = fact[1]; - TNode divisor = urem[1]; - Node result_ult_div = nm->mkNode(kind::BITVECTOR_ULT, result, divisor); - Node divisor_eq_0 = - nm->mkNode(kind::EQUAL, divisor, mkZero(getSize(divisor))); - Node split = nm->mkNode( - kind::OR, divisor_eq_0, nm->mkNode(kind::NOT, fact), result_ult_div); - lemma(split); - } - if (fact[1].getKind() == kind::BITVECTOR_UREM) - { - TNode urem = fact[1]; - TNode result = fact[0]; - TNode divisor = urem[1]; - Node result_ult_div = nm->mkNode(kind::BITVECTOR_ULT, result, divisor); - Node divisor_eq_0 = - nm->mkNode(kind::EQUAL, divisor, mkZero(getSize(divisor))); - Node split = nm->mkNode( - kind::OR, divisor_eq_0, nm->mkNode(kind::NOT, fact), result_ult_div); - lemma(split); - } - } -} - -bool BVSolverLayered::preCheck(Theory::Effort e) -{ - check(e); - return true; -} - -void BVSolverLayered::check(Theory::Effort e) -{ - if (done() && e < Theory::EFFORT_FULL) - { - return; - } - - Debug("bitvector") << "BVSolverLayered::check(" << e << ")" << std::endl; - TimerStat::CodeTimer codeTimer(d_statistics.d_solveTimer); - // we may be getting new assertions so the model cache may not be sound - d_invalidateModelCache.set(true); - // if we are using the eager solver - if (options().bv.bitblastMode == options::BitblastMode::EAGER) - { - // this can only happen on an empty benchmark - if (!d_eagerSolver->isInitialized()) - { - d_eagerSolver->initialize(); - } - if (!Theory::fullEffort(e)) return; - - std::vector<TNode> assertions; - while (!done()) - { - TNode fact = get().d_assertion; - Assert(fact.getKind() == kind::BITVECTOR_EAGER_ATOM); - assertions.push_back(fact); - d_eagerSolver->assertFormula(fact[0]); - } - - bool ok = d_eagerSolver->checkSat(); - if (!ok) - { - if (assertions.size() == 1) - { - d_im.conflict(assertions[0], InferenceId::BV_LAYERED_CONFLICT); - return; - } - Node conflict = utils::mkAnd(assertions); - d_im.conflict(conflict, InferenceId::BV_LAYERED_CONFLICT); - return; - } - return; - } - - if (Theory::fullEffort(e)) - { - ++(d_statistics.d_numCallsToCheckFullEffort); - } - else - { - ++(d_statistics.d_numCallsToCheckStandardEffort); - } - // if we are already in conflict just return the conflict - if (inConflict()) - { - sendConflict(); - return; - } - - while (!done()) - { - TNode fact = get().d_assertion; - - checkForLemma(fact); - - for (unsigned i = 0; i < d_subtheories.size(); ++i) - { - d_subtheories[i]->assertFact(fact); - } - } - - bool ok = true; - bool complete = false; - for (unsigned i = 0; i < d_subtheories.size(); ++i) - { - Assert(!inConflict()); - ok = d_subtheories[i]->check(e); - complete = d_subtheories[i]->isComplete(); - - if (!ok) - { - // if we are in a conflict no need to check with other theories - Assert(inConflict()); - sendConflict(); - return; - } - if (complete) - { - // if the last subtheory was complete we stop - break; - } - } -} - -bool BVSolverLayered::collectModelValues(TheoryModel* m, - const std::set<Node>& termSet) -{ - Assert(!inConflict()); - if (options().bv.bitblastMode == options::BitblastMode::EAGER) - { - if (!d_eagerSolver->collectModelInfo(m, true)) - { - return false; - } - } - for (unsigned i = 0; i < d_subtheories.size(); ++i) - { - if (d_subtheories[i]->isComplete()) - { - return d_subtheories[i]->collectModelValues(m, termSet); - } - } - return true; -} - -Node BVSolverLayered::getModelValue(TNode var) -{ - Assert(!inConflict()); - for (unsigned i = 0; i < d_subtheories.size(); ++i) - { - if (d_subtheories[i]->isComplete()) - { - return d_subtheories[i]->getModelValue(var); - } - } - Unreachable(); -} - -void BVSolverLayered::propagate(Theory::Effort e) -{ - Debug("bitvector") << indent() << "BVSolverLayered::propagate()" << std::endl; - if (options().bv.bitblastMode == options::BitblastMode::EAGER) - { - return; - } - - if (inConflict()) - { - return; - } - - // go through stored propagations - bool ok = true; - for (; d_literalsToPropagateIndex < d_literalsToPropagate.size() && ok; - d_literalsToPropagateIndex = d_literalsToPropagateIndex + 1) - { - TNode literal = d_literalsToPropagate[d_literalsToPropagateIndex]; - // temporary fix for incremental bit-blasting - if (d_state.isSatLiteral(literal)) - { - Debug("bitvector::propagate") - << "BVSolverLayered:: propagating " << literal << "\n"; - ok = d_im.propagateLit(literal); - } - } - - if (!ok) - { - Debug("bitvector::propagate") - << indent() - << "BVSolverLayered::propagate(): conflict from theory engine" - << std::endl; - setConflict(); - } -} - -void BVSolverLayered::presolve() -{ - Debug("bitvector") << "BVSolverLayered::presolve" << std::endl; -} - -static int prop_count = 0; - -bool BVSolverLayered::storePropagation(TNode literal, SubTheory subtheory) -{ - Debug("bitvector::propagate") - << indent() << d_context->getLevel() << " " - << "BVSolverLayered::storePropagation(" << literal << ", " << subtheory - << ")" << std::endl; - prop_count++; - - // If already in conflict, no more propagation - if (d_conflict) - { - Debug("bitvector::propagate") - << indent() << "BVSolverLayered::storePropagation(" << literal << ", " - << subtheory << "): already in conflict" << std::endl; - return false; - } - - // If propagated already, just skip - PropagatedMap::const_iterator find = d_propagatedBy.find(literal); - if (find != d_propagatedBy.end()) - { - return true; - } - else - { - bool polarity = literal.getKind() != kind::NOT; - Node negatedLiteral = polarity ? literal.notNode() : (Node)literal[0]; - find = d_propagatedBy.find(negatedLiteral); - if (find != d_propagatedBy.end() && (*find).second != subtheory) - { - // Safe to ignore this one, subtheory should produce a conflict - return true; - } - - d_propagatedBy[literal] = subtheory; - } - - // Propagate differs depending on the subtheory - // * bitblaster needs to be left alone until it's done, otherwise it doesn't - // know how to explain - // * equality engine can propagate eagerly - // TODO(2348): Determine if ok should be set by propagate. If not, remove ok. - constexpr bool ok = true; - if (subtheory == SUB_CORE) - { - d_im.propagateLit(literal); - if (!ok) - { - setConflict(); - } - } - else - { - d_literalsToPropagate.push_back(literal); - } - return ok; - -} /* BVSolverLayered::propagate(TNode) */ - -void BVSolverLayered::explain(TNode literal, std::vector<TNode>& assumptions) -{ - Assert(wasPropagatedBySubtheory(literal)); - SubTheory sub = getPropagatingSubtheory(literal); - d_subtheoryMap[sub]->explain(literal, assumptions); -} - -TrustNode BVSolverLayered::explain(TNode node) -{ - Debug("bitvector::explain") - << "BVSolverLayered::explain(" << node << ")" << std::endl; - std::vector<TNode> assumptions; - - // Ask for the explanation - explain(node, assumptions); - // this means that it is something true at level 0 - Node explanation; - if (assumptions.size() == 0) - { - explanation = utils::mkTrue(); - } - else - { - // return the explanation - explanation = utils::mkAnd(assumptions); - } - Debug("bitvector::explain") << "BVSolverLayered::explain(" << node << ") => " - << explanation << std::endl; - Debug("bitvector::explain") << "BVSolverLayered::explain done. \n"; - return TrustNode::mkTrustPropExp(node, explanation, nullptr); -} - -void BVSolverLayered::notifySharedTerm(TNode t) -{ - Debug("bitvector::sharing") - << indent() << "BVSolverLayered::notifySharedTerm(" << t << ")" - << std::endl; - d_sharedTermsSet.insert(t); -} - -EqualityStatus BVSolverLayered::getEqualityStatus(TNode a, TNode b) -{ - if (options().bv.bitblastMode == options::BitblastMode::EAGER) - return EQUALITY_UNKNOWN; - Assert(options().bv.bitblastMode == options::BitblastMode::LAZY); - for (unsigned i = 0; i < d_subtheories.size(); ++i) - { - EqualityStatus status = d_subtheories[i]->getEqualityStatus(a, b); - if (status != EQUALITY_UNKNOWN) - { - return status; - } - } - return EQUALITY_UNKNOWN; - ; -} - -bool BVSolverLayered::applyAbstraction(const std::vector<Node>& assertions, - std::vector<Node>& new_assertions) -{ - bool changed = - d_abstractionModule->applyAbstraction(assertions, new_assertions); - if (changed && options().bv.bitblastMode == options::BitblastMode::EAGER - && options().bv.bitvectorAig) - { - // disable AIG mode - AlwaysAssert(!d_eagerSolver->isInitialized()); - d_eagerSolver->turnOffAig(); - d_eagerSolver->initialize(); - } - return changed; -} - -void BVSolverLayered::setConflict(Node conflict) -{ - if (options().bv.bvAbstraction) - { - NodeManager* const nm = NodeManager::currentNM(); - Node new_conflict = d_abstractionModule->simplifyConflict(conflict); - - std::vector<Node> lemmas; - lemmas.push_back(new_conflict); - d_abstractionModule->generalizeConflict(new_conflict, lemmas); - for (unsigned i = 0; i < lemmas.size(); ++i) - { - lemma(nm->mkNode(kind::NOT, lemmas[i])); - } - } - d_conflict = true; - d_conflictNode = conflict; -} - -} // namespace bv -} // namespace theory -} // namespace cvc5 diff --git a/src/theory/bv/bv_solver_layered.h b/src/theory/bv/bv_solver_layered.h deleted file mode 100644 index 3870bc078..000000000 --- a/src/theory/bv/bv_solver_layered.h +++ /dev/null @@ -1,228 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Mathias Preiner, Liana Hadarean, Andrew Reynolds - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * Layered bit-vector solver. - */ - -#include "cvc5_private.h" - -#ifndef CVC5__THEORY__BV__BV_SOLVER_LAYERED_H -#define CVC5__THEORY__BV__BV_SOLVER_LAYERED_H - -#include <unordered_map> -#include <unordered_set> - -#include "context/cdhashset.h" -#include "context/cdlist.h" -#include "context/context.h" -#include "smt/env_obj.h" -#include "theory/bv/bv_solver.h" -#include "theory/bv/bv_subtheory.h" -#include "theory/bv/theory_bv.h" -#include "util/hash.h" - -namespace cvc5 { -namespace theory { -namespace bv { - -class CoreSolver; -class InequalitySolver; -class AlgebraicSolver; -class BitblastSolver; -class EagerBitblastSolver; -class AbstractionModule; - -class BVSolverLayered : public BVSolver -{ - /** Back reference to TheoryBV */ - TheoryBV& d_bv; - - /** The context we are using */ - context::Context* d_context; - - /** Context dependent set of atoms we already propagated */ - context::CDHashSet<Node> d_alreadyPropagatedSet; - context::CDHashSet<Node> d_sharedTermsSet; - - std::vector<std::unique_ptr<SubtheorySolver>> d_subtheories; - std::unordered_map<SubTheory, SubtheorySolver*, std::hash<int>> - d_subtheoryMap; - - public: - BVSolverLayered(Env& env, - TheoryBV& bv, - context::Context* c, - context::UserContext* u, - ProofNodeManager* pnm = nullptr, - std::string name = ""); - - ~BVSolverLayered(); - - //--------------------------------- initialization - - /** - * Returns true if we need an equality engine. If so, we initialize the - * information regarding how it should be setup. For details, see the - * documentation in Theory::needsEqualityEngine. - */ - bool needsEqualityEngine(EeSetupInfo& esi) override; - - /** finish initialization */ - void finishInit() override; - //--------------------------------- end initialization - - void preRegisterTerm(TNode n) override; - - bool preCheck(Theory::Effort e) override; - - void propagate(Theory::Effort e) override; - - TrustNode explain(TNode n) override; - - bool collectModelValues(TheoryModel* m, - const std::set<Node>& termSet) override; - - std::string identify() const override - { - return std::string("BVSolverLayered"); - } - - void presolve() override; - - bool applyAbstraction(const std::vector<Node>& assertions, - std::vector<Node>& new_assertions) override; - - bool isLeaf(TNode node) { return d_bv.isLeaf(node); } - - private: - class Statistics - { - public: - AverageStat d_avgConflictSize; - TimerStat d_solveTimer; - IntStat d_numCallsToCheckFullEffort; - IntStat d_numCallsToCheckStandardEffort; - TimerStat d_weightComputationTimer; - IntStat d_numMultSlice; - Statistics(); - }; - - Statistics d_statistics; - - void check(Theory::Effort e); - void spendResource(Resource r); - - typedef std::unordered_set<TNode> TNodeSet; - typedef std::unordered_set<Node> NodeSet; - - typedef std::unordered_map<Node, Node> NodeToNode; - - context::CDO<bool> d_lemmasAdded; - - // Are we in conflict? - context::CDO<bool> d_conflict; - - // Invalidate the model cache if check was called - context::CDO<bool> d_invalidateModelCache; - - /** The conflict node */ - Node d_conflictNode; - - /** Literals to propagate */ - context::CDList<Node> d_literalsToPropagate; - - /** Index of the next literal to propagate */ - context::CDO<unsigned> d_literalsToPropagateIndex; - - /** - * Keeps a map from nodes to the subtheory that propagated it so that we can - * explain it properly. - */ - typedef context::CDHashMap<Node, SubTheory> PropagatedMap; - PropagatedMap d_propagatedBy; - - std::unique_ptr<EagerBitblastSolver> d_eagerSolver; - std::unique_ptr<AbstractionModule> d_abstractionModule; - bool d_calledPreregister; - - bool wasPropagatedBySubtheory(TNode literal) const - { - return d_propagatedBy.find(literal) != d_propagatedBy.end(); - } - - SubTheory getPropagatingSubtheory(TNode literal) const - { - Assert(wasPropagatedBySubtheory(literal)); - PropagatedMap::const_iterator find = d_propagatedBy.find(literal); - return (*find).second; - } - - /** Should be called to propagate the literal. */ - bool storePropagation(TNode literal, SubTheory subtheory); - - /** - * Explains why this literal (propagated by subtheory) is true by adding - * assumptions. - */ - void explain(TNode literal, std::vector<TNode>& assumptions); - - void notifySharedTerm(TNode t) override; - - bool isSharedTerm(TNode t) { return d_sharedTermsSet.contains(t); } - - EqualityStatus getEqualityStatus(TNode a, TNode b) override; - - Node getModelValue(TNode var); - - inline std::string indent() - { - std::string indentStr(d_context->getLevel(), ' '); - return indentStr; - } - - void setConflict(Node conflict = Node::null()); - - bool inConflict() { return d_conflict; } - - void sendConflict(); - - void lemma(TNode node) - { - d_im.lemma(node, InferenceId::BV_LAYERED_LEMMA); - d_lemmasAdded = true; - } - - void checkForLemma(TNode node); - - size_t numAssertions() { return d_bv.numAssertions(); } - - theory::Assertion get() { return d_bv.get(); } - - bool done() { return d_bv.done(); } - - friend class LazyBitblaster; - friend class TLazyBitblaster; - friend class EagerBitblaster; - friend class BitblastSolver; - friend class EqualitySolver; - friend class CoreSolver; - friend class InequalitySolver; - friend class AlgebraicSolver; - friend class EagerBitblastSolver; -}; /* class BVSolverLayered */ - -} // namespace bv -} // namespace theory - -} // namespace cvc5 - -#endif /* CVC5__THEORY__BV__BV_SOLVER_LAZY_H */ diff --git a/src/theory/bv/bv_subtheory.h b/src/theory/bv/bv_subtheory.h deleted file mode 100644 index 6c887424a..000000000 --- a/src/theory/bv/bv_subtheory.h +++ /dev/null @@ -1,111 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Liana Hadarean, Tim King, Dejan Jovanovic - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * Interface for bit-vectors sub-solvers. - */ - -#ifndef CVC5__THEORY__BV__BV_SUBTHEORY_H -#define CVC5__THEORY__BV__BV_SUBTHEORY_H - -#include "context/cdqueue.h" -#include "context/context.h" -#include "cvc5_private.h" -#include "theory/theory.h" -#include "theory/uf/equality_engine.h" - -namespace cvc5 { - -namespace theory { - -class TheoryModel; - -namespace bv { - -enum SubTheory { - SUB_CORE = 1, - SUB_BITBLAST = 2, - SUB_INEQUALITY = 3, - SUB_ALGEBRAIC = 4 -}; - -inline std::ostream& operator<<(std::ostream& out, SubTheory subtheory) { - switch (subtheory) { - case SUB_BITBLAST: - return out << "BITBLASTER"; - case SUB_CORE: - return out << "BV_CORE_SUBTHEORY"; - case SUB_INEQUALITY: - return out << "BV_INEQUALITY_SUBTHEORY"; - case SUB_ALGEBRAIC: - return out << "BV_ALGEBRAIC_SUBTHEORY"; - default: - break; - } - Unreachable(); -} - -// forward declaration -class BVSolverLayered; - -using AssertionQueue = context::CDQueue<Node>; - -/** - * Abstract base class for bit-vector subtheory solvers - * - */ -class SubtheorySolver { - public: - SubtheorySolver(context::Context* c, BVSolverLayered* bv) - : d_context(c), d_bv(bv), d_assertionQueue(c), d_assertionIndex(c, 0) - { - } - virtual ~SubtheorySolver() {} - virtual bool check(Theory::Effort e) = 0; - virtual void explain(TNode literal, std::vector<TNode>& assumptions) = 0; - virtual void preRegister(TNode node) {} - virtual void propagate(Theory::Effort e) {} - virtual bool collectModelValues(TheoryModel* m, - const std::set<Node>& termSet) = 0; - virtual Node getModelValue(TNode var) = 0; - virtual bool isComplete() = 0; - virtual EqualityStatus getEqualityStatus(TNode a, TNode b) = 0; - bool done() { return d_assertionQueue.size() == d_assertionIndex; } - TNode get() { - Assert(!done()); - TNode res = d_assertionQueue[d_assertionIndex]; - d_assertionIndex = d_assertionIndex + 1; - return res; - } - virtual void assertFact(TNode fact) { d_assertionQueue.push_back(fact); } - - AssertionQueue::const_iterator assertionsBegin() { - return d_assertionQueue.begin(); - } - AssertionQueue::const_iterator assertionsEnd() { - return d_assertionQueue.end(); - } - - protected: - /** The context we are using */ - context::Context* d_context; - - /** The bit-vector theory */ - BVSolverLayered* d_bv; - AssertionQueue d_assertionQueue; - context::CDO<uint32_t> d_assertionIndex; -}; /* class SubtheorySolver */ - -} // namespace bv -} // namespace theory -} // namespace cvc5 - -#endif /* CVC5__THEORY__BV__BV_SUBTHEORY_H */ diff --git a/src/theory/bv/bv_subtheory_algebraic.cpp b/src/theory/bv/bv_subtheory_algebraic.cpp deleted file mode 100644 index e607444c2..000000000 --- a/src/theory/bv/bv_subtheory_algebraic.cpp +++ /dev/null @@ -1,984 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Liana Hadarean, Aina Niemetz, Mathias Preiner - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * Algebraic solver. - */ -#include "theory/bv/bv_subtheory_algebraic.h" - -#include <unordered_set> - -#include "expr/node_algorithm.h" -#include "options/bv_options.h" -#include "printer/printer.h" -#include "smt/dump.h" -#include "smt/smt_statistics_registry.h" -#include "smt/solver_engine.h" -#include "smt/solver_engine_scope.h" -#include "smt_util/boolean_simplification.h" -#include "theory/bv/bv_quick_check.h" -#include "theory/bv/bv_solver_layered.h" -#include "theory/bv/theory_bv_utils.h" -#include "theory/rewriter.h" -#include "theory/theory_model.h" -#include "util/bitvector.h" - -using namespace cvc5::context; -using namespace cvc5::prop; -using namespace cvc5::theory::bv::utils; -using namespace std; - -namespace cvc5 { -namespace theory { -namespace bv { - -/* ------------------------------------------------------------------------- */ - -namespace { - -/* Collect all variables under a given a node. */ -void collectVariables(TNode node, utils::NodeSet& vars) -{ - std::vector<TNode> stack; - std::unordered_set<TNode> visited; - - stack.push_back(node); - while (!stack.empty()) - { - Node n = stack.back(); - stack.pop_back(); - - if (vars.find(n) != vars.end()) continue; - if (visited.find(n) != visited.end()) continue; - visited.insert(n); - - if (Theory::isLeafOf(n, THEORY_BV) && n.getKind() != kind::CONST_BITVECTOR) - { - vars.insert(n); - continue; - } - stack.insert(stack.end(), n.begin(), n.end()); - } -} - -}; - -/* ------------------------------------------------------------------------- */ - -bool hasExpensiveBVOperators(TNode fact); -Node mergeExplanations(const std::vector<Node>& expls); -Node mergeExplanations(TNode expl1, TNode expl2); - - -SubstitutionEx::SubstitutionEx(theory::SubstitutionMap* modelMap) - : d_substitutions() - , d_cache() - , d_cacheInvalid(true) - , d_modelMap(modelMap) -{} - -bool SubstitutionEx::addSubstitution(TNode from, TNode to, TNode reason) { - Debug("bv-substitution") << "SubstitutionEx::addSubstitution: "<< from - <<" => "<< to << "\n" << " reason "<<reason << "\n"; - Assert(from != to); - if (d_substitutions.find(from) != d_substitutions.end()) { - return false; - } - - d_modelMap->addSubstitution(from, to); - - d_cacheInvalid = true; - d_substitutions[from] = SubstitutionElement(to, reason); - return true; -} - -Node SubstitutionEx::apply(TNode node) { - Debug("bv-substitution") << "SubstitutionEx::apply("<< node <<")\n"; - if (d_cacheInvalid) { - d_cache.clear(); - d_cacheInvalid = false; - } - - SubstitutionsCache::iterator it = d_cache.find(node); - - if (it != d_cache.end()) { - Node res = it->second.to; - Debug("bv-substitution") << " =>"<< res <<"\n"; - return res; - } - - Node result = internalApply(node); - Debug("bv-substitution") << " =>"<< result <<"\n"; - return result; -} - -Node SubstitutionEx::internalApply(TNode node) { - if (d_substitutions.empty()) - return node; - - vector<SubstitutionStackElement> stack; - stack.push_back(SubstitutionStackElement(node)); - - while (!stack.empty()) { - SubstitutionStackElement head = stack.back(); - stack.pop_back(); - - TNode current = head.node; - - if (hasCache(current)) { - continue; - } - - // check if it has substitution - Substitutions::const_iterator it = d_substitutions.find(current); - if (it != d_substitutions.end()) { - vector<Node> reasons; - TNode to = it->second.to; - reasons.push_back(it->second.reason); - // check if the thing we subsituted to has substitutions - TNode res = internalApply(to); - // update reasons - reasons.push_back(getReason(to)); - Node reason = mergeExplanations(reasons); - storeCache(current, res, reason); - continue; - } - - // if no children then just continue - if(current.getNumChildren() == 0) { - storeCache(current, current, utils::mkTrue()); - continue; - } - - // children already processed - if (head.childrenAdded) { - NodeBuilder nb(current.getKind()); - std::vector<Node> reasons; - - if (current.getMetaKind() == kind::metakind::PARAMETERIZED) { - TNode op = current.getOperator(); - Assert(hasCache(op)); - nb << getCache(op); - reasons.push_back(getReason(op)); - } - for (unsigned i = 0; i < current.getNumChildren(); ++i) { - Assert(hasCache(current[i])); - nb << getCache(current[i]); - reasons.push_back(getReason(current[i])); - } - Node result = nb; - // if the node is new apply substitutions to it - Node subst_result = result; - if (result != current) { - subst_result = result!= current? internalApply(result) : result; - reasons.push_back(getReason(result)); - } - Node reason = mergeExplanations(reasons); - storeCache(current, subst_result, reason); - continue; - } else { - // add children to stack - stack.push_back(SubstitutionStackElement(current, true)); - if (current.getMetaKind() == kind::metakind::PARAMETERIZED) { - stack.push_back(SubstitutionStackElement(current.getOperator())); - } - for (unsigned i = 0; i < current.getNumChildren(); ++i) { - stack.push_back(SubstitutionStackElement(current[i])); - } - } - } - - Assert(hasCache(node)); - return getCache(node); -} - -Node SubstitutionEx::explain(TNode node) const { - if(!hasCache(node)) { - return utils::mkTrue(); - } - - Debug("bv-substitution") << "SubstitutionEx::explain("<< node <<")\n"; - Node res = getReason(node); - Debug("bv-substitution") << " with "<< res <<"\n"; - return res; -} - -Node SubstitutionEx::getReason(TNode node) const { - Assert(hasCache(node)); - SubstitutionsCache::const_iterator it = d_cache.find(node); - return it->second.reason; -} - -bool SubstitutionEx::hasCache(TNode node) const { - return d_cache.find(node) != d_cache.end(); -} - -Node SubstitutionEx::getCache(TNode node) const { - Assert(hasCache(node)); - return d_cache.find(node)->second.to; -} - -void SubstitutionEx::storeCache(TNode from, TNode to, Node reason) { - // Debug("bv-substitution") << "SubstitutionEx::storeCache(" << from <<", " << to <<", "<< reason<<")\n"; - Assert(!hasCache(from)); - d_cache[from] = SubstitutionElement(to, reason); -} - -AlgebraicSolver::AlgebraicSolver(context::Context* c, BVSolverLayered* bv) - : SubtheorySolver(c, bv), - d_modelMap(), - d_quickSolver(new BVQuickCheck("theory::bv::algebraic", bv)), - d_isComplete(c, false), - d_isDifficult(c, false), - d_budget(options::bitvectorAlgebraicBudget()), - d_explanations(), - d_inputAssertions(), - d_ids(), - d_numSolved(0), - d_numCalls(0), - d_quickXplain(), - d_statistics() -{ - if (options::bitvectorQuickXplain()) - { - d_quickXplain.reset( - new QuickXPlain("theory::bv::algebraic", d_quickSolver.get())); - } -} - -AlgebraicSolver::~AlgebraicSolver() {} - -bool AlgebraicSolver::check(Theory::Effort e) -{ - Assert(options::bitblastMode() == options::BitblastMode::LAZY); - - if (!Theory::fullEffort(e)) { return true; } - if (!useHeuristic()) { return true; } - - TimerStat::CodeTimer algebraicTimer(d_statistics.d_solveTime); - Debug("bv-subtheory-algebraic") << "AlgebraicSolver::check (" << e << ")\n"; - ++(d_numCalls); - ++(d_statistics.d_numCallstoCheck); - - d_explanations.clear(); - d_ids.clear(); - d_inputAssertions.clear(); - - std::vector<WorklistElement> worklist; - - uint64_t original_bb_cost = 0; - - NodeSet seen_assertions; - // Processing assertions from scratch - for (AssertionQueue::const_iterator it = assertionsBegin(); it != assertionsEnd(); ++it) { - Debug("bv-subtheory-algebraic") << " " << *it << "\n"; - TNode assertion = *it; - unsigned id = worklist.size(); - d_ids[assertion] = id; - worklist.push_back(WorklistElement(assertion, id)); - d_inputAssertions.insert(assertion); - storeExplanation(assertion); - - uint64_t assertion_size = d_quickSolver->computeAtomWeight(assertion, seen_assertions); - Assert(original_bb_cost <= original_bb_cost + assertion_size); - original_bb_cost+= assertion_size; - } - - for (unsigned i = 0; i < worklist.size(); ++i) { - d_ids[worklist[i].node] = worklist[i].id; - } - - Debug("bv-subtheory-algebraic") << "Assertions " << worklist.size() <<" : \n"; - - Assert(d_explanations.size() == worklist.size()); - - d_modelMap.reset(new SubstitutionMap(d_context)); - SubstitutionEx subst(d_modelMap.get()); - - // first round of substitutions - processAssertions(worklist, subst); - - if (!d_isDifficult.get()) { - // skolemize all possible extracts - ExtractSkolemizer skolemizer(d_modelMap.get()); - skolemizer.skolemize(worklist); - // second round of substitutions - processAssertions(worklist, subst); - } - - NodeSet subst_seen; - uint64_t subst_bb_cost = 0; - - unsigned r = 0; - unsigned w = 0; - - for (; r < worklist.size(); ++r) { - - TNode fact = worklist[r].node; - unsigned id = worklist[r].id; - - if (fact.isConst() && - fact.getConst<bool>() == true) { - continue; - } - - if (fact.isConst() && - fact.getConst<bool>() == false) { - // we have a conflict - Node conflict = BooleanSimplification::simplify(d_explanations[id]); - d_bv->setConflict(conflict); - d_isComplete.set(true); - Debug("bv-subtheory-algebraic") << " UNSAT: assertion simplfies to false with conflict: "<< conflict << "\n"; - - ++(d_statistics.d_numSimplifiesToFalse); - ++(d_numSolved); - return false; - } - - subst_bb_cost+= d_quickSolver->computeAtomWeight(fact, subst_seen); - worklist[w] = WorklistElement(fact, id); - Node expl = BooleanSimplification::simplify(d_explanations[id]); - storeExplanation(id, expl); - d_ids[fact] = id; - ++w; - } - - worklist.resize(w); - - - if(Debug.isOn("bv-subtheory-algebraic")) { - Debug("bv-subtheory-algebraic") << "Assertions post-substitutions " << worklist.size() << ":\n"; - for (unsigned i = 0; i < worklist.size(); ++i) { - Debug("bv-subtheory-algebraic") << " " << worklist[i].node << "\n"; - } - } - - - // all facts solved to true - if (worklist.empty()) { - Debug("bv-subtheory-algebraic") << " SAT: everything simplifies to true.\n"; - ++(d_statistics.d_numSimplifiesToTrue); - ++(d_numSolved); - return true; - } - - double ratio = ((double)subst_bb_cost)/original_bb_cost; - if (ratio > 0.5 || - !d_isDifficult.get()) { - // give up if problem not reduced enough - d_isComplete.set(false); - return true; - } - - d_quickSolver->clearSolver(); - - d_quickSolver->push(); - std::vector<Node> facts; - for (unsigned i = 0; i < worklist.size(); ++i) { - facts.push_back(worklist[i].node); - } - bool ok = quickCheck(facts); - - Debug("bv-subtheory-algebraic") << "AlgebraicSolver::check done " << ok << ".\n"; - return ok; -} - -bool AlgebraicSolver::quickCheck(std::vector<Node>& facts) { - SatValue res = d_quickSolver->checkSat(facts, d_budget); - - if (res == SAT_VALUE_UNKNOWN) { - d_isComplete.set(false); - Debug("bv-subtheory-algebraic") << " Unknown.\n"; - ++(d_statistics.d_numUnknown); - return true; - } - - if (res == SAT_VALUE_TRUE) { - Debug("bv-subtheory-algebraic") << " Sat.\n"; - ++(d_statistics.d_numSat); - ++(d_numSolved); - d_isComplete.set(true); - return true; - } - - Assert(res == SAT_VALUE_FALSE); - Assert(d_quickSolver->inConflict()); - d_isComplete.set(true); - Debug("bv-subtheory-algebraic") << " Unsat.\n"; - ++(d_numSolved); - ++(d_statistics.d_numUnsat); - - - Node conflict = d_quickSolver->getConflict(); - Debug("bv-subtheory-algebraic") << " Conflict: " << conflict << "\n"; - - // singleton conflict - if (conflict.getKind() != kind::AND) { - Assert(d_ids.find(conflict) != d_ids.end()); - unsigned id = d_ids[conflict]; - Assert(id < d_explanations.size()); - Node theory_confl = d_explanations[id]; - d_bv->setConflict(theory_confl); - return false; - } - - Assert(conflict.getKind() == kind::AND); - if (options::bitvectorQuickXplain()) { - d_quickSolver->popToZero(); - Debug("bv-quick-xplain") << "AlgebraicSolver::quickCheck original conflict size " << conflict.getNumChildren() << "\n"; - conflict = d_quickXplain->minimizeConflict(conflict); - Debug("bv-quick-xplain") << "AlgebraicSolver::quickCheck minimized conflict size " << conflict.getNumChildren() << "\n"; - } - - vector<TNode> theory_confl; - for (unsigned i = 0; i < conflict.getNumChildren(); ++i) { - TNode c = conflict[i]; - - Assert(d_ids.find(c) != d_ids.end()); - unsigned c_id = d_ids[c]; - Assert(c_id < d_explanations.size()); - TNode c_expl = d_explanations[c_id]; - theory_confl.push_back(c_expl); - } - - Node confl = BooleanSimplification::simplify(utils::mkAnd(theory_confl)); - - Debug("bv-subtheory-algebraic") << " Out Conflict: " << confl << "\n"; - setConflict(confl); - return false; -} - -void AlgebraicSolver::setConflict(TNode conflict) -{ - Node final_conflict = conflict; - if (options::bitvectorQuickXplain() && - conflict.getKind() == kind::AND && - conflict.getNumChildren() > 4) { - final_conflict = d_quickXplain->minimizeConflict(conflict); - } - d_bv->setConflict(final_conflict); -} - -bool AlgebraicSolver::solve(TNode fact, TNode reason, SubstitutionEx& subst) { - if (fact.getKind() != kind::EQUAL) return false; - - NodeManager* nm = NodeManager::currentNM(); - TNode left = fact[0]; - TNode right = fact[1]; - - if (left.isVar() && !expr::hasSubterm(right, left)) - { - bool changed = subst.addSubstitution(left, right, reason); - return changed; - } - if (right.isVar() && !expr::hasSubterm(left, right)) - { - bool changed = subst.addSubstitution(right, left, reason); - return changed; - } - - // xor simplification - if (right.getKind() == kind::BITVECTOR_XOR && - left.getKind() == kind::BITVECTOR_XOR) { - TNode var = left[0]; - if (var.getMetaKind() != kind::metakind::VARIABLE) - return false; - - // simplify xor with same variable on both sides - if (expr::hasSubterm(right, var)) - { - std::vector<Node> right_children; - for (unsigned i = 0; i < right.getNumChildren(); ++i) { - if (right[i] != var) - right_children.push_back(right[i]); - } - Assert(right_children.size()); - Node new_right = utils::mkNaryNode(kind::BITVECTOR_XOR, right_children); - std::vector<Node> left_children; - for (unsigned i = 1; i < left.getNumChildren(); ++i) { - left_children.push_back(left[i]); - } - Node new_left = utils::mkNaryNode(kind::BITVECTOR_XOR, left_children); - Node new_fact = nm->mkNode(kind::EQUAL, new_left, new_right); - bool changed = subst.addSubstitution(fact, new_fact, reason); - return changed; - } - - NodeBuilder nb(kind::BITVECTOR_XOR); - for (unsigned i = 1; i < left.getNumChildren(); ++i) { - nb << left[i]; - } - Node inverse = left.getNumChildren() == 2? (Node)left[1] : (Node)nb; - Node new_right = nm->mkNode(kind::BITVECTOR_XOR, right, inverse); - bool changed = subst.addSubstitution(var, new_right, reason); - - return changed; - } - - // (a xor t = a) <=> (t = 0) - if (left.getKind() == kind::BITVECTOR_XOR - && right.getMetaKind() == kind::metakind::VARIABLE - && expr::hasSubterm(left, right)) - { - TNode var = right; - Node new_left = nm->mkNode(kind::BITVECTOR_XOR, var, left); - Node zero = utils::mkConst(utils::getSize(var), 0u); - Node new_fact = nm->mkNode(kind::EQUAL, zero, new_left); - bool changed = subst.addSubstitution(fact, new_fact, reason); - return changed; - } - - if (right.getKind() == kind::BITVECTOR_XOR - && left.getMetaKind() == kind::metakind::VARIABLE - && expr::hasSubterm(right, left)) - { - TNode var = left; - Node new_right = nm->mkNode(kind::BITVECTOR_XOR, var, right); - Node zero = utils::mkConst(utils::getSize(var), 0u); - Node new_fact = nm->mkNode(kind::EQUAL, zero, new_right); - bool changed = subst.addSubstitution(fact, new_fact, reason); - return changed; - } - - // (a xor b = 0) <=> (a = b) - if (left.getKind() == kind::BITVECTOR_XOR && - left.getNumChildren() == 2 && - right.getKind() == kind::CONST_BITVECTOR && - right.getConst<BitVector>() == BitVector(utils::getSize(left), 0u)) { - Node new_fact = nm->mkNode(kind::EQUAL, left[0], left[1]); - bool changed = subst.addSubstitution(fact, new_fact, reason); - return changed; - } - - - return false; -} - -bool AlgebraicSolver::isSubstitutableIn(TNode node, TNode in) -{ - if (node.getMetaKind() == kind::metakind::VARIABLE - && !expr::hasSubterm(in, node)) - return true; - return false; -} - -void AlgebraicSolver::processAssertions(std::vector<WorklistElement>& worklist, SubstitutionEx& subst) { - NodeManager* nm = NodeManager::currentNM(); - bool changed = true; - while(changed) { - // d_bv->spendResource(); - changed = false; - for (unsigned i = 0; i < worklist.size(); ++i) { - // apply current substitutions - Node current = subst.apply(worklist[i].node); - unsigned current_id = worklist[i].id; - Node subst_expl = subst.explain(worklist[i].node); - worklist[i] = WorklistElement(Rewriter::rewrite(current), current_id); - // explanation for this assertion - Node old_expl = d_explanations[current_id]; - Node new_expl = mergeExplanations(subst_expl, old_expl); - storeExplanation(current_id, new_expl); - - // use the new substitution to solve - if(solve(worklist[i].node, new_expl, subst)) { - changed = true; - } - } - - // check for concat slicings - for (unsigned i = 0; i < worklist.size(); ++i) { - TNode fact = worklist[i].node; - unsigned current_id = worklist[i].id; - - if (fact.getKind() != kind::EQUAL) { - continue; - } - - TNode left = fact[0]; - TNode right = fact[1]; - if (left.getKind() != kind::BITVECTOR_CONCAT || - right.getKind() != kind::BITVECTOR_CONCAT || - left.getNumChildren() != right.getNumChildren()) { - continue; - } - - bool can_slice = true; - for (unsigned j = 0; j < left.getNumChildren(); ++j) { - if (utils::getSize(left[j]) != utils::getSize(right[j])) - can_slice = false; - } - - if (!can_slice) { - continue; - } - - for (unsigned j = 0; j < left.getNumChildren(); ++j) { - Node eq_j = nm->mkNode(kind::EQUAL, left[j], right[j]); - unsigned id = d_explanations.size(); - TNode expl = d_explanations[current_id]; - storeExplanation(expl); - worklist.push_back(WorklistElement(eq_j, id)); - d_ids[eq_j] = id; - } - worklist[i] = WorklistElement(utils::mkTrue(), worklist[i].id); - changed = true; - } - Assert(d_explanations.size() == worklist.size()); - } -} - -void AlgebraicSolver::storeExplanation(unsigned id, TNode explanation) { - Assert(checkExplanation(explanation)); - d_explanations[id] = explanation; -} - -void AlgebraicSolver::storeExplanation(TNode explanation) { - Assert(checkExplanation(explanation)); - d_explanations.push_back(explanation); -} - -bool AlgebraicSolver::checkExplanation(TNode explanation) { - Node simplified_explanation = explanation; //BooleanSimplification::simplify(explanation); - if (simplified_explanation.getKind() != kind::AND) { - return d_inputAssertions.find(simplified_explanation) != d_inputAssertions.end(); - } - for (unsigned i = 0; i < simplified_explanation.getNumChildren(); ++i) { - if (d_inputAssertions.find(simplified_explanation[i]) == d_inputAssertions.end()) { - return false; - } - } - return true; -} - - -bool AlgebraicSolver::isComplete() { - return d_isComplete.get(); -} - -bool AlgebraicSolver::useHeuristic() { - if (d_numCalls == 0) - return true; - - double success_rate = double(d_numSolved)/double(d_numCalls); - d_statistics.d_useHeuristic.set(success_rate); - return success_rate > 0.8; -} - - -void AlgebraicSolver::assertFact(TNode fact) { - d_assertionQueue.push_back(fact); - d_isComplete.set(false); - if (!d_isDifficult.get()) { - d_isDifficult.set(hasExpensiveBVOperators(fact)); - } -} - -EqualityStatus AlgebraicSolver::getEqualityStatus(TNode a, TNode b) { - return EQUALITY_UNKNOWN; -} - -bool AlgebraicSolver::collectModelValues(TheoryModel* model, - const std::set<Node>& termSet) -{ - Debug("bitvector-model") << "AlgebraicSolver::collectModelValues\n"; - AlwaysAssert(!d_quickSolver->inConflict()); - - // collect relevant terms that the bv theory abstracts to variables - // (variables and parametric terms such as select apply_uf) - std::vector<TNode> variables; - std::vector<Node> values; - for (set<Node>::const_iterator it = termSet.begin(); it != termSet.end(); ++it) { - TNode term = *it; - if (term.getType().isBitVector() && - (term.getMetaKind() == kind::metakind::VARIABLE || - Theory::theoryOf(term) != THEORY_BV)) { - variables.push_back(term); - values.push_back(term); - } - } - - NodeSet leaf_vars; - Debug("bitvector-model") << "Substitutions:\n"; - for (unsigned i = 0; i < variables.size(); ++i) { - TNode current = variables[i]; - TNode subst = Rewriter::rewrite(d_modelMap->apply(current)); - Debug("bitvector-model") << " " << current << " => " << subst << "\n"; - values[i] = subst; - collectVariables(subst, leaf_vars); - } - - Debug("bitvector-model") << "Model:\n"; - - for (NodeSet::const_iterator it = leaf_vars.begin(); it != leaf_vars.end(); ++it) { - TNode var = *it; - Node value = d_quickSolver->getVarValue(var, true); - Assert(!value.isNull()); - - // may be a shared term that did not appear in the current assertions - // AJR: need to check whether already in map for cases where collectModelInfo is called multiple times in the same context - if (!value.isNull() && !d_modelMap->hasSubstitution(var)) { - Debug("bitvector-model") << " " << var << " => " << value << "\n"; - Assert(value.getKind() == kind::CONST_BITVECTOR); - d_modelMap->addSubstitution(var, value); - } - } - - Debug("bitvector-model") << "Final Model:\n"; - for (unsigned i = 0; i < variables.size(); ++i) { - TNode current = values[i]; - TNode subst = Rewriter::rewrite(d_modelMap->apply(current)); - Debug("bitvector-model") << "AlgebraicSolver: " << variables[i] << " => " << subst << "\n"; - // Doesn't have to be constant as it may be irrelevant - Assert(subst.getKind() == kind::CONST_BITVECTOR); - if (!model->assertEquality(variables[i], subst, true)) - { - return false; - } - } - return true; - } - -Node AlgebraicSolver::getModelValue(TNode node) { - return Node::null(); -} - -AlgebraicSolver::Statistics::Statistics() - : d_numCallstoCheck(smtStatisticsRegistry().registerInt( - "theory::bv::algebraic::NumCallsToCheck")), - d_numSimplifiesToTrue(smtStatisticsRegistry().registerInt( - "theory::bv::algebraic::NumSimplifiesToTrue")), - d_numSimplifiesToFalse(smtStatisticsRegistry().registerInt( - "theory::bv::algebraic::NumSimplifiesToFalse")), - d_numUnsat(smtStatisticsRegistry().registerInt( - "theory::bv::algebraic::NumUnsat")), - d_numSat( - smtStatisticsRegistry().registerInt("theory::bv::algebraic::NumSat")), - d_numUnknown(smtStatisticsRegistry().registerInt( - "theory::bv::algebraic::NumUnknown")), - d_solveTime(smtStatisticsRegistry().registerTimer( - "theory::bv::algebraic::SolveTime")), - d_useHeuristic(smtStatisticsRegistry().registerValue<double>( - "theory::bv::algebraic::UseHeuristic", 0.2)) -{ -} - -bool hasExpensiveBVOperatorsRec(TNode fact, TNodeSet& seen) { - if (fact.getKind() == kind::BITVECTOR_MULT - || fact.getKind() == kind::BITVECTOR_UDIV - || fact.getKind() == kind::BITVECTOR_UREM) - { - return true; - } - - if (seen.find(fact) != seen.end()) { - return false; - } - - if (fact.getNumChildren() == 0) { - return false; - } - for (unsigned i = 0; i < fact.getNumChildren(); ++i) { - bool difficult = hasExpensiveBVOperatorsRec(fact[i], seen); - if (difficult) - return true; - } - seen.insert(fact); - return false; -} - -bool hasExpensiveBVOperators(TNode fact) { - TNodeSet seen; - return hasExpensiveBVOperatorsRec(fact, seen); -} - -void ExtractSkolemizer::skolemize(std::vector<WorklistElement>& facts) { - TNodeSet seen; - for (unsigned i = 0; i < facts.size(); ++i) { - TNode current = facts[i].node; - collectExtracts(current, seen); - } - - for (VarExtractMap::iterator it = d_varToExtract.begin(); it != d_varToExtract.end(); ++it) { - ExtractList& el = it->second; - TNode var = it->first; - Base& base = el.base; - - unsigned bw = utils::getSize(var); - // compute decomposition - std::vector<unsigned> cuts; - for (unsigned i = 1; i <= bw; ++i) { - if (base.isCutPoint(i)) { - cuts.push_back(i); - } - } - unsigned previous = 0; - unsigned current = 0; - std::vector<Node> skolems; - for (unsigned i = 0; i < cuts.size(); ++i) { - current = cuts[i]; - Assert(current > 0); - int size = current - previous; - Assert(size > 0); - Node sk = utils::mkVar(size); - skolems.push_back(sk); - previous = current; - } - if (current < bw -1) { - int size = bw - current; - Assert(size > 0); - Node sk = utils::mkVar(size); - skolems.push_back(sk); - } - NodeBuilder skolem_nb(kind::BITVECTOR_CONCAT); - - for (int i = skolems.size() - 1; i >= 0; --i) { - skolem_nb << skolems[i]; - } - - Node skolem_concat = skolems.size() == 1 ? (Node)skolems[0] : (Node) skolem_nb; - Assert(utils::getSize(skolem_concat) == utils::getSize(var)); - storeSkolem(var, skolem_concat); - - for (unsigned i = 0; i < el.extracts.size(); ++i) { - unsigned h = el.extracts[i].high; - unsigned l = el.extracts[i].low; - Node extract = utils::mkExtract(var, h, l); - Node skolem_extract = Rewriter::rewrite(utils::mkExtract(skolem_concat, h, l)); - Assert(skolem_extract.getMetaKind() == kind::metakind::VARIABLE - || skolem_extract.getKind() == kind::BITVECTOR_CONCAT); - storeSkolem(extract, skolem_extract); - } - } - - for (unsigned i = 0; i < facts.size(); ++i) { - facts[i] = WorklistElement(skolemize(facts[i].node), facts[i].id); - } -} - -Node ExtractSkolemizer::mkSkolem(Node node) { - Assert(node.getKind() == kind::BITVECTOR_EXTRACT - && node[0].getMetaKind() == kind::metakind::VARIABLE); - Assert(!d_skolemSubst.hasSubstitution(node)); - return utils::mkVar(utils::getSize(node)); -} - -void ExtractSkolemizer::unSkolemize(std::vector<WorklistElement>& facts) { - for (unsigned i = 0; i < facts.size(); ++i) { - facts[i] = WorklistElement(unSkolemize(facts[i].node), facts[i].id); - } -} - -void ExtractSkolemizer::storeSkolem(TNode node, TNode skolem) { - d_skolemSubst.addSubstitution(node, skolem); - d_modelMap->addSubstitution(node, skolem); - d_skolemSubstRev.addSubstitution(skolem, node); -} - -Node ExtractSkolemizer::unSkolemize(TNode node) { - return d_skolemSubstRev.apply(node); -} - -Node ExtractSkolemizer::skolemize(TNode node) { - return d_skolemSubst.apply(node); -} - -void ExtractSkolemizer::ExtractList::addExtract(Extract& e) { - extracts.push_back(e); - base.sliceAt(e.low); - base.sliceAt(e.high+1); -} - -void ExtractSkolemizer::storeExtract(TNode var, unsigned high, unsigned low) { - Assert(var.getMetaKind() == kind::metakind::VARIABLE); - if (d_varToExtract.find(var) == d_varToExtract.end()) { - d_varToExtract[var] = ExtractList(utils::getSize(var)); - } - VarExtractMap::iterator it = d_varToExtract.find(var); - ExtractList& el = it->second; - Extract e(high, low); - el.addExtract(e); -} - -void ExtractSkolemizer::collectExtracts(TNode node, TNodeSet& seen) { - if (seen.find(node) != seen.end()) { - return; - } - - if (node.getKind() == kind::BITVECTOR_EXTRACT && - node[0].getMetaKind() == kind::metakind::VARIABLE) { - unsigned high = utils::getExtractHigh(node); - unsigned low = utils::getExtractLow(node); - TNode var = node[0]; - storeExtract(var, high, low); - seen.insert(node); - return; - } - - if (node.getNumChildren() == 0) - return; - - for (unsigned i = 0; i < node.getNumChildren(); ++i) { - collectExtracts(node[i], seen); - } - seen.insert(node); -} - -ExtractSkolemizer::ExtractSkolemizer(theory::SubstitutionMap* modelMap) - : d_emptyContext() - , d_varToExtract() - , d_modelMap(modelMap) - , d_skolemSubst(&d_emptyContext) - , d_skolemSubstRev(&d_emptyContext) -{} - -ExtractSkolemizer::~ExtractSkolemizer() { -} - -Node mergeExplanations(const std::vector<Node>& expls) { - TNodeSet literals; - for (unsigned i = 0; i < expls.size(); ++i) { - TNode expl = expls[i]; - Assert(expl.getType().isBoolean()); - if (expl.getKind() == kind::AND) { - for (const TNode& child : expl) - { - if (child == utils::mkTrue()) continue; - literals.insert(child); - } - } else if (expl != utils::mkTrue()) { - literals.insert(expl); - } - } - - if (literals.size() == 0) { - return utils::mkTrue(); - }else if (literals.size() == 1) { - return *literals.begin(); - } - - NodeBuilder nb(kind::AND); - - for (TNodeSet::const_iterator it = literals.begin(); it!= literals.end(); ++it) { - nb << *it; - } - return nb; -} - -Node mergeExplanations(TNode expl1, TNode expl2) { - std::vector<Node> expls; - expls.push_back(expl1); - expls.push_back(expl2); - return mergeExplanations(expls); -} - -} // namespace bv -} // namespace theory -} // namespace cvc5 diff --git a/src/theory/bv/bv_subtheory_algebraic.h b/src/theory/bv/bv_subtheory_algebraic.h deleted file mode 100644 index 16cf3d53b..000000000 --- a/src/theory/bv/bv_subtheory_algebraic.h +++ /dev/null @@ -1,244 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Liana Hadarean, Mathias Preiner, Tim King - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * Algebraic solver. - */ - -#include "cvc5_private.h" - -#pragma once - -#include <unordered_map> -#include <unordered_set> - -#include "theory/bv/bv_subtheory.h" -#include "theory/bv/slicer.h" -#include "theory/substitutions.h" - -namespace cvc5 { -namespace theory { -namespace bv { - -class AlgebraicSolver; - -Node mergeExplanations(TNode expl1, TNode expl2); -Node mergeExplanations(const std::vector<Node>& expls); - -/** - * Non-context dependent substitution with explanations. - * - */ -class SubstitutionEx -{ - struct SubstitutionElement - { - Node to; - Node reason; - SubstitutionElement() : to(), reason() {} - - SubstitutionElement(TNode t, TNode r) : to(t), reason(r) {} - }; - - struct SubstitutionStackElement - { - TNode node; - bool childrenAdded; - SubstitutionStackElement(TNode n, bool ca = false) - : node(n), childrenAdded(ca) - { - } - }; - - typedef std::unordered_map<Node, SubstitutionElement> Substitutions; - typedef std::unordered_map<Node, SubstitutionElement> SubstitutionsCache; - - Substitutions d_substitutions; - SubstitutionsCache d_cache; - bool d_cacheInvalid; - theory::SubstitutionMap* d_modelMap; - - Node getReason(TNode node) const; - bool hasCache(TNode node) const; - Node getCache(TNode node) const; - void storeCache(TNode from, TNode to, Node rason); - Node internalApply(TNode node); - - public: - SubstitutionEx(theory::SubstitutionMap* modelMap); - /** - * Returnst true if the substitution map did not contain from. - * - * @param from - * @param to - * @param reason - * - * @return - */ - bool addSubstitution(TNode from, TNode to, TNode reason); - Node apply(TNode node); - Node explain(TNode node) const; -}; - -/** - * In-processing worklist element, id keeps track of - * original assertion. - * - */ -struct WorklistElement -{ - Node node; - unsigned id; - WorklistElement(Node n, unsigned i) : node(n), id(i) {} - WorklistElement() : node(), id(-1) {} -}; - -typedef std::unordered_map<Node, Node> NodeNodeMap; -typedef std::unordered_map<Node, unsigned> NodeIdMap; -typedef std::unordered_set<TNode> TNodeSet; - -class ExtractSkolemizer -{ - struct Extract - { - unsigned high; - unsigned low; - Extract(unsigned h, unsigned l) : high(h), low(l) {} - }; - - struct ExtractList - { - Base base; - std::vector<Extract> extracts; - ExtractList(unsigned bitwidth) : base(bitwidth), extracts() {} - ExtractList() : base(1), extracts() {} - void addExtract(Extract& e); - }; - typedef std::unordered_map<Node, ExtractList> VarExtractMap; - context::Context d_emptyContext; - VarExtractMap d_varToExtract; - theory::SubstitutionMap* d_modelMap; - theory::SubstitutionMap d_skolemSubst; - theory::SubstitutionMap d_skolemSubstRev; - - void storeSkolem(TNode node, TNode skolem); - void storeExtract(TNode var, unsigned high, unsigned low); - void collectExtracts(TNode node, TNodeSet& seen); - Node skolemize(TNode); - Node unSkolemize(TNode); - - Node mkSkolem(Node node); - - public: - ExtractSkolemizer(theory::SubstitutionMap* modelMap); - void skolemize(std::vector<WorklistElement>&); - void unSkolemize(std::vector<WorklistElement>&); - ~ExtractSkolemizer(); -}; - -class BVQuickCheck; -class QuickXPlain; - -/** - * AlgebraicSolver - */ -class AlgebraicSolver : public SubtheorySolver -{ - struct Statistics - { - IntStat d_numCallstoCheck; - IntStat d_numSimplifiesToTrue; - IntStat d_numSimplifiesToFalse; - IntStat d_numUnsat; - IntStat d_numSat; - IntStat d_numUnknown; - TimerStat d_solveTime; - ValueStat<double> d_useHeuristic; - Statistics(); - }; - - std::unique_ptr<SubstitutionMap> d_modelMap; - std::unique_ptr<BVQuickCheck> d_quickSolver; - context::CDO<bool> d_isComplete; - context::CDO<bool> - d_isDifficult; /**< flag to indicate whether the current assertions - contain expensive BV operators */ - - unsigned long d_budget; - std::vector<Node> d_explanations; /**< explanations for assertions indexed by - assertion id */ - TNodeSet d_inputAssertions; /**< assertions in current context (for debugging - purposes only) */ - NodeIdMap d_ids; /**< map from assertions to ids */ - uint64_t d_numSolved; - uint64_t d_numCalls; - - /** separate quickXplain module as it can reuse the current SAT solver */ - std::unique_ptr<QuickXPlain> d_quickXplain; - - Statistics d_statistics; - bool useHeuristic(); - void setConflict(TNode conflict); - bool isSubstitutableIn(TNode node, TNode in); - bool checkExplanation(TNode expl); - void storeExplanation(TNode expl); - void storeExplanation(unsigned id, TNode expl); - /** - * Apply substitutions and rewriting to the worklist assertions to a fixpoint. - * Subsitutions learned store in subst. - * - * @param worklist - * @param subst - */ - void processAssertions(std::vector<WorklistElement>& worklist, - SubstitutionEx& subst); - /** - * Attempt to solve the equation in fact, and if successful - * add a substitution to subst. - * - * @param fact equation we are trying to solve - * @param reason the reason in terms of original assertions - * @param subst substitution map - * - * @return true if added a substitution to subst - */ - bool solve(TNode fact, TNode reason, SubstitutionEx& subst); - /** - * Run a SAT solver on the given facts with the given budget. - * Sets the isComplete flag and conflict accordingly. - * - * @param facts - * - * @return true if no conflict was detected. - */ - bool quickCheck(std::vector<Node>& facts); - - public: - AlgebraicSolver(context::Context* c, BVSolverLayered* bv); - ~AlgebraicSolver(); - - void preRegister(TNode node) override {} - bool check(Theory::Effort e) override; - void explain(TNode literal, std::vector<TNode>& assumptions) override - { - Unreachable() << "AlgebraicSolver does not propagate.\n"; - } - EqualityStatus getEqualityStatus(TNode a, TNode b) override; - bool collectModelValues(TheoryModel* m, - const std::set<Node>& termSet) override; - Node getModelValue(TNode node) override; - bool isComplete() override; - void assertFact(TNode fact) override; -}; - -} // namespace bv -} // namespace theory -} // namespace cvc5 diff --git a/src/theory/bv/bv_subtheory_bitblast.cpp b/src/theory/bv/bv_subtheory_bitblast.cpp deleted file mode 100644 index cdc2fc143..000000000 --- a/src/theory/bv/bv_subtheory_bitblast.cpp +++ /dev/null @@ -1,276 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Liana Hadarean, Aina Niemetz, Dejan Jovanovic - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * Algebraic solver. - */ - -#include "theory/bv/bv_subtheory_bitblast.h" - -#include "decision/decision_attributes.h" -#include "options/bv_options.h" -#include "options/decision_options.h" -#include "smt/smt_statistics_registry.h" -#include "theory/bv/abstraction.h" -#include "theory/bv/bitblast/lazy_bitblaster.h" -#include "theory/bv/bv_quick_check.h" -#include "theory/bv/bv_solver_layered.h" -#include "theory/bv/theory_bv_utils.h" - -using namespace std; -using namespace cvc5::context; - -namespace cvc5 { -namespace theory { -namespace bv { - -BitblastSolver::BitblastSolver(context::Context* c, BVSolverLayered* bv) - : SubtheorySolver(c, bv), - d_bitblaster(new TLazyBitblaster(c, bv, "theory::bv::lazy")), - d_bitblastQueue(c), - d_statistics(), - d_validModelCache(c, true), - d_lemmaAtomsQueue(c), - d_useSatPropagation(options::bitvectorPropagate()), - d_abstractionModule(NULL), - d_quickCheck(), - d_quickXplain() -{ - if (options::bitvectorQuickXplain()) - { - d_quickCheck.reset(new BVQuickCheck("bb", bv)); - d_quickXplain.reset(new QuickXPlain("bb", d_quickCheck.get())); - } -} - -BitblastSolver::~BitblastSolver() {} - -BitblastSolver::Statistics::Statistics() - : d_numCallstoCheck(smtStatisticsRegistry().registerInt( - "theory::bv::BitblastSolver::NumCallsToCheck")), - d_numBBLemmas(smtStatisticsRegistry().registerInt( - "theory::bv::BitblastSolver::NumTimesLemmasBB")) -{ -} - -void BitblastSolver::setAbstraction(AbstractionModule* abs) { - d_abstractionModule = abs; - d_bitblaster->setAbstraction(abs); -} - -void BitblastSolver::preRegister(TNode node) { - if ((node.getKind() == kind::EQUAL || - node.getKind() == kind::BITVECTOR_ULT || - node.getKind() == kind::BITVECTOR_ULE || - node.getKind() == kind::BITVECTOR_SLT || - node.getKind() == kind::BITVECTOR_SLE) && - !d_bitblaster->hasBBAtom(node)) { - CodeTimer weightComputationTime(d_bv->d_statistics.d_weightComputationTimer); - d_bitblastQueue.push_back(node); - if ((options::decisionUseWeight() || options::decisionThreshold() != 0) && - !node.hasAttribute(decision::DecisionWeightAttr())) { - node.setAttribute(decision::DecisionWeightAttr(),computeAtomWeight(node)); - } - } -} - -uint64_t BitblastSolver::computeAtomWeight(TNode node) { - NodeSet seen; - return d_bitblaster->computeAtomWeight(node, seen); -} - -void BitblastSolver::explain(TNode literal, std::vector<TNode>& assumptions) { - d_bitblaster->explain(literal, assumptions); -} - -void BitblastSolver::bitblastQueue() { - while (!d_bitblastQueue.empty()) { - TNode atom = d_bitblastQueue.front(); - d_bitblastQueue.pop(); - Debug("bv-bitblast-queue") << "BitblastSolver::bitblastQueue (" << atom << ")\n"; - if (options::bvAbstraction() && - d_abstractionModule->isLemmaAtom(atom)) { - // don't bit-blast lemma atoms - continue; - } - if( !utils::isBitblastAtom(atom) ){ - continue; - } - Debug("bitblast-queue") << "Bitblasting atom " << atom <<"\n"; - { - TimerStat::CodeTimer codeTimer(d_bitblaster->d_statistics.d_bitblastTimer); - d_bitblaster->bbAtom(atom); - } - } -} - -bool BitblastSolver::check(Theory::Effort e) -{ - Debug("bv-bitblast") << "BitblastSolver::check (" << e << ")\n"; - Assert(options::bitblastMode() == options::BitblastMode::LAZY); - - ++(d_statistics.d_numCallstoCheck); - - Debug("bv-bitblast-debug") << "...process queue" << std::endl; - //// Lazy bit-blasting - // bit-blast enqueued nodes - bitblastQueue(); - - // Processing assertions - while (!done()) - { - TNode fact = get(); - d_validModelCache = false; - Debug("bv-bitblast") << " fact " << fact << ")\n"; - - if (options::bvAbstraction()) - { - // skip atoms that are the result of abstraction lemmas - if (d_abstractionModule->isLemmaAtom(fact)) - { - d_lemmaAtomsQueue.push_back(fact); - continue; - } - } - // skip facts involving integer equalities (from bv2nat) - if (!utils::isBitblastAtom(fact)) - { - continue; - } - - if (!d_bv->inConflict() - && (!d_bv->wasPropagatedBySubtheory(fact) - || d_bv->getPropagatingSubtheory(fact) != SUB_BITBLAST)) - { - // Some atoms have not been bit-blasted yet - d_bitblaster->bbAtom(fact); - // Assert to sat - bool ok = d_bitblaster->assertToSat(fact, d_useSatPropagation); - if (!ok) - { - std::vector<TNode> conflictAtoms; - d_bitblaster->getConflict(conflictAtoms); - setConflict(utils::mkAnd(conflictAtoms)); - return false; - } - } - } - - Debug("bv-bitblast-debug") << "...do propagation" << std::endl; - // We need to ensure we are fully propagated, so propagate now - if (d_useSatPropagation) - { - d_bv->spendResource(Resource::BvPropagationStep); - bool ok = d_bitblaster->propagate(); - if (!ok) - { - std::vector<TNode> conflictAtoms; - d_bitblaster->getConflict(conflictAtoms); - setConflict(utils::mkAnd(conflictAtoms)); - return false; - } - } - - // Solving - Debug("bv-bitblast-debug") << "...do solving" << std::endl; - if (e == Theory::EFFORT_FULL) - { - Assert(!d_bv->inConflict()); - Debug("bitvector::bitblaster") - << "BitblastSolver::addAssertions solving. \n"; - bool ok = d_bitblaster->solve(); - if (!ok) - { - std::vector<TNode> conflictAtoms; - d_bitblaster->getConflict(conflictAtoms); - Node conflict = utils::mkAnd(conflictAtoms); - setConflict(conflict); - return false; - } - } - - Debug("bv-bitblast-debug") << "...do abs bb" << std::endl; - if (options::bvAbstraction() && e == Theory::EFFORT_FULL - && d_lemmaAtomsQueue.size()) - { - // bit-blast lemma atoms - while (!d_lemmaAtomsQueue.empty()) - { - TNode lemma_atom = d_lemmaAtomsQueue.front(); - d_lemmaAtomsQueue.pop(); - if (!utils::isBitblastAtom(lemma_atom)) - { - continue; - } - d_bitblaster->bbAtom(lemma_atom); - // Assert to sat and check for conflicts - bool ok = d_bitblaster->assertToSat(lemma_atom, d_useSatPropagation); - if (!ok) - { - std::vector<TNode> conflictAtoms; - d_bitblaster->getConflict(conflictAtoms); - setConflict(utils::mkAnd(conflictAtoms)); - return false; - } - } - - Assert(!d_bv->inConflict()); - bool ok = d_bitblaster->solve(); - if (!ok) - { - std::vector<TNode> conflictAtoms; - d_bitblaster->getConflict(conflictAtoms); - Node conflict = utils::mkAnd(conflictAtoms); - setConflict(conflict); - ++(d_statistics.d_numBBLemmas); - return false; - } - } - - - return true; -} - -EqualityStatus BitblastSolver::getEqualityStatus(TNode a, TNode b) { - return d_bitblaster->getEqualityStatus(a, b); -} - -bool BitblastSolver::collectModelValues(TheoryModel* m, - const std::set<Node>& termSet) -{ - return d_bitblaster->collectModelValues(m, termSet); -} - -Node BitblastSolver::getModelValue(TNode node) -{ - if (d_bv->d_invalidateModelCache.get()) { - d_bitblaster->invalidateModelCache(); - } - d_bv->d_invalidateModelCache.set(false); - Node val = d_bitblaster->getTermModel(node, true); - return val; -} - -void BitblastSolver::setConflict(TNode conflict) -{ - Node final_conflict = conflict; - if (options::bitvectorQuickXplain() && - conflict.getKind() == kind::AND) { - // std::cout << "Original conflict " << conflict.getNumChildren() << "\n"; - final_conflict = d_quickXplain->minimizeConflict(conflict); - //std::cout << "Minimized conflict " << final_conflict.getNumChildren() << "\n"; - } - d_bv->setConflict(final_conflict); -} - -} // namespace bv -} // namespace theory -} // namespace cvc5 diff --git a/src/theory/bv/bv_subtheory_bitblast.h b/src/theory/bv/bv_subtheory_bitblast.h deleted file mode 100644 index 3ad707482..000000000 --- a/src/theory/bv/bv_subtheory_bitblast.h +++ /dev/null @@ -1,84 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Liana Hadarean, Mathias Preiner, Dejan Jovanovic - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * Algebraic solver. - */ - -#include "cvc5_private.h" - -#pragma once - -#include <unordered_map> - -#include "theory/bv/bv_subtheory.h" - -namespace cvc5 { - -namespace theory { -namespace bv { - -class TLazyBitblaster; -class AbstractionModule; -class BVQuickCheck; -class QuickXPlain; - -/** - * BitblastSolver - */ -class BitblastSolver : public SubtheorySolver -{ - struct Statistics - { - IntStat d_numCallstoCheck; - IntStat d_numBBLemmas; - Statistics(); - }; - /** Bitblaster */ - std::unique_ptr<TLazyBitblaster> d_bitblaster; - - /** Nodes that still need to be bit-blasted */ - context::CDQueue<TNode> d_bitblastQueue; - Statistics d_statistics; - - typedef std::unordered_map<Node, Node> NodeMap; - NodeMap d_modelCache; - context::CDO<bool> d_validModelCache; - - /** Queue for bit-blasting lemma atoms only in full check if we are sat */ - context::CDQueue<TNode> d_lemmaAtomsQueue; - bool d_useSatPropagation; - AbstractionModule* d_abstractionModule; - std::unique_ptr<BVQuickCheck> d_quickCheck; - std::unique_ptr<QuickXPlain> d_quickXplain; - // Node getModelValueRec(TNode node); - void setConflict(TNode conflict); - - public: - BitblastSolver(context::Context* c, BVSolverLayered* bv); - ~BitblastSolver(); - - void preRegister(TNode node) override; - bool check(Theory::Effort e) override; - void explain(TNode literal, std::vector<TNode>& assumptions) override; - EqualityStatus getEqualityStatus(TNode a, TNode b) override; - bool collectModelValues(TheoryModel* m, - const std::set<Node>& termSet) override; - Node getModelValue(TNode node) override; - bool isComplete() override { return true; } - void bitblastQueue(); - void setAbstraction(AbstractionModule* module); - uint64_t computeAtomWeight(TNode atom); -}; - -} // namespace bv -} // namespace theory -} // namespace cvc5 diff --git a/src/theory/bv/bv_subtheory_core.cpp b/src/theory/bv/bv_subtheory_core.cpp deleted file mode 100644 index 3f3384257..000000000 --- a/src/theory/bv/bv_subtheory_core.cpp +++ /dev/null @@ -1,418 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Andrew Reynolds, Liana Hadarean, Aina Niemetz - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * Algebraic solver. - */ - -#include "theory/bv/bv_subtheory_core.h" - -#include "expr/skolem_manager.h" -#include "options/bv_options.h" -#include "options/smt_options.h" -#include "smt/smt_statistics_registry.h" -#include "theory/bv/bv_solver_layered.h" -#include "theory/bv/theory_bv_utils.h" -#include "theory/ext_theory.h" -#include "theory/theory_model.h" -#include "util/rational.h" - -using namespace std; -using namespace cvc5; -using namespace cvc5::context; -using namespace cvc5::theory; -using namespace cvc5::theory::bv; -using namespace cvc5::theory::bv::utils; - -CoreSolver::CoreSolver(context::Context* c, BVSolverLayered* bv) - : SubtheorySolver(c, bv), - d_notify(*this), - d_isComplete(c, true), - d_lemmaThreshold(16), - d_preregisterCalled(false), - d_checkCalled(false), - d_bv(bv), - d_reasons(c) -{ -} - -CoreSolver::~CoreSolver() {} - -bool CoreSolver::needsEqualityEngine(EeSetupInfo& esi) -{ - esi.d_notify = &d_notify; - esi.d_name = "theory::bv::ee"; - return true; -} - -void CoreSolver::finishInit() -{ - // use the parent's equality engine, which may be the one we allocated above - d_equalityEngine = d_bv->d_bv.getEqualityEngine(); - - // The kinds we are treating as function application in congruence - d_equalityEngine->addFunctionKind(kind::BITVECTOR_CONCAT, true); - // d_equalityEngine->addFunctionKind(kind::BITVECTOR_AND); - // d_equalityEngine->addFunctionKind(kind::BITVECTOR_OR); - // d_equalityEngine->addFunctionKind(kind::BITVECTOR_XOR); - // d_equalityEngine->addFunctionKind(kind::BITVECTOR_NOT); - // d_equalityEngine->addFunctionKind(kind::BITVECTOR_NAND); - // d_equalityEngine->addFunctionKind(kind::BITVECTOR_NOR); - // d_equalityEngine->addFunctionKind(kind::BITVECTOR_XNOR); - // d_equalityEngine->addFunctionKind(kind::BITVECTOR_COMP); - d_equalityEngine->addFunctionKind(kind::BITVECTOR_MULT, true); - d_equalityEngine->addFunctionKind(kind::BITVECTOR_ADD, true); - d_equalityEngine->addFunctionKind(kind::BITVECTOR_EXTRACT, true); - // d_equalityEngine->addFunctionKind(kind::BITVECTOR_SUB); - // d_equalityEngine->addFunctionKind(kind::BITVECTOR_NEG); - // d_equalityEngine->addFunctionKind(kind::BITVECTOR_UDIV); - // d_equalityEngine->addFunctionKind(kind::BITVECTOR_UREM); - // d_equalityEngine->addFunctionKind(kind::BITVECTOR_SDIV); - // d_equalityEngine->addFunctionKind(kind::BITVECTOR_SREM); - // d_equalityEngine->addFunctionKind(kind::BITVECTOR_SMOD); - // d_equalityEngine->addFunctionKind(kind::BITVECTOR_SHL); - // d_equalityEngine->addFunctionKind(kind::BITVECTOR_LSHR); - // d_equalityEngine->addFunctionKind(kind::BITVECTOR_ASHR); - // d_equalityEngine->addFunctionKind(kind::BITVECTOR_ULT); - // d_equalityEngine->addFunctionKind(kind::BITVECTOR_ULE); - // d_equalityEngine->addFunctionKind(kind::BITVECTOR_UGT); - // d_equalityEngine->addFunctionKind(kind::BITVECTOR_UGE); - // d_equalityEngine->addFunctionKind(kind::BITVECTOR_SLT); - // d_equalityEngine->addFunctionKind(kind::BITVECTOR_SLE); - // d_equalityEngine->addFunctionKind(kind::BITVECTOR_SGT); - // d_equalityEngine->addFunctionKind(kind::BITVECTOR_SGE); - d_equalityEngine->addFunctionKind(kind::BITVECTOR_TO_NAT); - d_equalityEngine->addFunctionKind(kind::INT_TO_BITVECTOR); -} - -void CoreSolver::preRegister(TNode node) { - d_preregisterCalled = true; - if (node.getKind() == kind::EQUAL) { - d_equalityEngine->addTriggerPredicate(node); - } else { - d_equalityEngine->addTerm(node); - } -} - - -void CoreSolver::explain(TNode literal, std::vector<TNode>& assumptions) { - bool polarity = literal.getKind() != kind::NOT; - TNode atom = polarity ? literal : literal[0]; - if (atom.getKind() == kind::EQUAL) { - d_equalityEngine->explainEquality(atom[0], atom[1], polarity, assumptions); - } else { - d_equalityEngine->explainPredicate(atom, polarity, assumptions); - } -} - -bool CoreSolver::check(Theory::Effort e) { - Trace("bitvector::core") << "CoreSolver::check \n"; - - d_bv->d_im.spendResource(Resource::TheoryCheckStep); - - d_checkCalled = true; - Assert(!d_bv->inConflict()); - ++(d_statistics.d_numCallstoCheck); - bool ok = true; - std::vector<Node> core_eqs; - TNodeBoolMap seen; - while (! done()) { - TNode fact = get(); - if (d_isComplete && !isCompleteForTerm(fact, seen)) { - d_isComplete = false; - } - - // only reason about equalities - if (fact.getKind() == kind::EQUAL || (fact.getKind() == kind::NOT && fact[0].getKind() == kind::EQUAL)) { - ok = assertFactToEqualityEngine(fact, fact); - } else { - ok = assertFactToEqualityEngine(fact, fact); - } - if (!ok) - return false; - } - - if (Theory::fullEffort(e) && isComplete()) { - buildModel(); - } - - return true; -} - -void CoreSolver::buildModel() -{ - Debug("bv-core") << "CoreSolver::buildModel() \n"; - NodeManager* nm = NodeManager::currentNM(); - d_modelValues.clear(); - TNodeSet constants; - TNodeSet constants_in_eq_engine; - // collect constants in equality engine - eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(d_equalityEngine); - while (!eqcs_i.isFinished()) - { - TNode repr = *eqcs_i; - if (repr.getKind() == kind::CONST_BITVECTOR) - { - // must check if it's just the constant - eq::EqClassIterator it(repr, d_equalityEngine); - if (!(++it).isFinished() || true) - { - constants.insert(repr); - constants_in_eq_engine.insert(repr); - } - } - ++eqcs_i; - } - - // build repr to value map - - eqcs_i = eq::EqClassesIterator(d_equalityEngine); - while (!eqcs_i.isFinished()) - { - TNode repr = *eqcs_i; - ++eqcs_i; - - if (!repr.isVar() && repr.getKind() != kind::CONST_BITVECTOR - && !d_bv->isSharedTerm(repr)) - { - continue; - } - - TypeNode type = repr.getType(); - if (type.isBitVector() && repr.getKind() != kind::CONST_BITVECTOR) - { - Debug("bv-core-model") << " processing " << repr << "\n"; - // we need to assign a value for it - TypeEnumerator te(type); - Node val; - do - { - val = *te; - ++te; - // Debug("bv-core-model") << " trying value " << val << "\n"; - // Debug("bv-core-model") << " is in set? " << constants.count(val) << - // "\n"; Debug("bv-core-model") << " enumerator done? " << - // te.isFinished() << "\n"; - } while (constants.count(val) != 0 && !(te.isFinished())); - - if (te.isFinished() && constants.count(val) != 0) - { - // if we cannot enumerate anymore values we just return the lemma - // stating that at least two of the representatives are equal. - std::vector<TNode> representatives; - representatives.push_back(repr); - - for (TNodeSet::const_iterator it = constants_in_eq_engine.begin(); - it != constants_in_eq_engine.end(); - ++it) - { - TNode constant = *it; - if (utils::getSize(constant) == utils::getSize(repr)) - { - representatives.push_back(constant); - } - } - for (ModelValue::const_iterator it = d_modelValues.begin(); - it != d_modelValues.end(); - ++it) - { - representatives.push_back(it->first); - } - std::vector<Node> equalities; - for (unsigned i = 0; i < representatives.size(); ++i) - { - for (unsigned j = i + 1; j < representatives.size(); ++j) - { - TNode a = representatives[i]; - TNode b = representatives[j]; - if (a.getKind() == kind::CONST_BITVECTOR - && b.getKind() == kind::CONST_BITVECTOR) - { - Assert(a != b); - continue; - } - if (utils::getSize(a) == utils::getSize(b)) - { - equalities.push_back(nm->mkNode(kind::EQUAL, a, b)); - } - } - } - // better off letting the SAT solver split on values - if (equalities.size() > d_lemmaThreshold) - { - d_isComplete = false; - return; - } - - if (equalities.size() == 0) - { - Debug("bv-core") << " lemma: true (no equalities)" << std::endl; - } - else - { - Node lemma = utils::mkOr(equalities); - d_bv->lemma(lemma); - Debug("bv-core") << " lemma: " << lemma << std::endl; - } - return; - } - - Debug("bv-core-model") << " " << repr << " => " << val << "\n"; - constants.insert(val); - d_modelValues[repr] = val; - } - } -} - -bool CoreSolver::assertFactToEqualityEngine(TNode fact, TNode reason) { - // Notify the equality engine - if (!d_bv->inConflict() - && (!d_bv->wasPropagatedBySubtheory(fact) - || d_bv->getPropagatingSubtheory(fact) != SUB_CORE)) - { - Debug("bv-slicer-eq") << "CoreSolver::assertFactToEqualityEngine fact=" << fact << endl; - // Debug("bv-slicer-eq") << " reason=" << reason << endl; - bool negated = fact.getKind() == kind::NOT; - TNode predicate = negated ? fact[0] : fact; - if (predicate.getKind() == kind::EQUAL) { - if (negated) { - // dis-equality - d_equalityEngine->assertEquality(predicate, false, reason); - } else { - // equality - d_equalityEngine->assertEquality(predicate, true, reason); - } - } else { - // Adding predicate if the congruence over it is turned on - if (d_equalityEngine->isFunctionKind(predicate.getKind())) - { - d_equalityEngine->assertPredicate(predicate, !negated, reason); - } - } - } - - // checking for a conflict - if (d_bv->inConflict()) - { - return false; - } - return true; -} - -bool CoreSolver::NotifyClass::eqNotifyTriggerPredicate(TNode predicate, bool value) { - Debug("bitvector::core") << "NotifyClass::eqNotifyTriggerPredicate(" << predicate << ", " << (value ? "true" : "false" ) << ")" << std::endl; - if (value) { - return d_solver.storePropagation(predicate); - } - return d_solver.storePropagation(predicate.notNode()); -} - -bool CoreSolver::NotifyClass::eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value) { - Debug("bitvector::core") << "NotifyClass::eqNotifyTriggerTermMerge(" << t1 << ", " << t2 << ")" << std::endl; - if (value) { - return d_solver.storePropagation(t1.eqNode(t2)); - } else { - return d_solver.storePropagation(t1.eqNode(t2).notNode()); - } -} - -void CoreSolver::NotifyClass::eqNotifyConstantTermMerge(TNode t1, TNode t2) { - d_solver.conflict(t1, t2); -} - -bool CoreSolver::storePropagation(TNode literal) { - return d_bv->storePropagation(literal, SUB_CORE); -} - -void CoreSolver::conflict(TNode a, TNode b) { - std::vector<TNode> assumptions; - d_equalityEngine->explainEquality(a, b, true, assumptions); - Node conflict = flattenAnd(assumptions); - d_bv->setConflict(conflict); -} - -bool CoreSolver::isCompleteForTerm(TNode term, TNodeBoolMap& seen) { - return utils::isEqualityTerm(term, seen); -} - -bool CoreSolver::collectModelValues(TheoryModel* m, - const std::set<Node>& termSet) -{ - if (Debug.isOn("bitvector-model")) { - context::CDQueue<Node>::const_iterator it = d_assertionQueue.begin(); - for (; it!= d_assertionQueue.end(); ++it) { - Debug("bitvector-model") - << "CoreSolver::collectModelValues (assert " << *it << ")\n"; - } - } - if (isComplete()) { - Debug("bitvector-model") << "CoreSolver::collectModelValues complete."; - for (ModelValue::const_iterator it = d_modelValues.begin(); it != d_modelValues.end(); ++it) { - Node a = it->first; - Node b = it->second; - Debug("bitvector-model") << "CoreSolver::collectModelValues modelValues " - << a << " => " << b << ")\n"; - if (!m->assertEquality(a, b, true)) - { - return false; - } - } - } - return true; -} - -Node CoreSolver::getModelValue(TNode var) { - Debug("bitvector-model") << "CoreSolver::getModelValue (" << var <<")"; - Assert(isComplete()); - TNode repr = d_equalityEngine->getRepresentative(var); - Node result = Node(); - if (repr.getKind() == kind::CONST_BITVECTOR) { - result = repr; - } else if (d_modelValues.find(repr) == d_modelValues.end()) { - // it may be a shared term that never gets asserted - // result is just Null - Assert(d_bv->isSharedTerm(var)); - } else { - result = d_modelValues[repr]; - } - Debug("bitvector-model") << " => " << result <<"\n"; - return result; -} - -EqualityStatus CoreSolver::getEqualityStatus(TNode a, TNode b) -{ - if (d_equalityEngine->areEqual(a, b)) - { - // The terms are implied to be equal - return EQUALITY_TRUE; - } - if (d_equalityEngine->areDisequal(a, b, false)) - { - // The terms are implied to be dis-equal - return EQUALITY_FALSE; - } - return EQUALITY_UNKNOWN; -} - -bool CoreSolver::hasTerm(TNode node) const -{ - return d_equalityEngine->hasTerm(node); -} -void CoreSolver::addTermToEqualityEngine(TNode node) -{ - d_equalityEngine->addTerm(node); -} - -CoreSolver::Statistics::Statistics() - : d_numCallstoCheck(smtStatisticsRegistry().registerInt( - "theory::bv::CoreSolver::NumCallsToCheck")) -{ -} diff --git a/src/theory/bv/bv_subtheory_core.h b/src/theory/bv/bv_subtheory_core.h deleted file mode 100644 index 2e6312144..000000000 --- a/src/theory/bv/bv_subtheory_core.h +++ /dev/null @@ -1,108 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Andrew Reynolds, Liana Hadarean, Mathias Preiner - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * Algebraic solver. - */ - -#include "cvc5_private.h" - -#pragma once - -#include <unordered_map> -#include <unordered_set> - -#include "context/cdhashset.h" -#include "theory/bv/bv_subtheory.h" - -namespace cvc5 { -namespace theory { -namespace bv { - -/** - * Bitvector equality solver - */ -class CoreSolver : public SubtheorySolver { - typedef std::unordered_map<TNode, Node> ModelValue; - typedef std::unordered_map<TNode, bool> TNodeBoolMap; - typedef std::unordered_set<TNode> TNodeSet; - - struct Statistics { - IntStat d_numCallstoCheck; - Statistics(); - }; - - // NotifyClass: handles call-back from congruence closure module - class NotifyClass : public eq::EqualityEngineNotify { - CoreSolver& d_solver; - - public: - NotifyClass(CoreSolver& solver): d_solver(solver) {} - bool eqNotifyTriggerPredicate(TNode predicate, bool value) override; - bool eqNotifyTriggerTermEquality(TheoryId tag, - TNode t1, - TNode t2, - bool value) override; - void eqNotifyConstantTermMerge(TNode t1, TNode t2) override; - void eqNotifyNewClass(TNode t) override {} - void eqNotifyMerge(TNode t1, TNode t2) override {} - void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) override {} - }; - - - /** The notify class for d_equalityEngine */ - NotifyClass d_notify; - - /** Store a propagation to the bv solver */ - bool storePropagation(TNode literal); - - /** Store a conflict from merging two constants */ - void conflict(TNode a, TNode b); - - context::CDO<bool> d_isComplete; - unsigned d_lemmaThreshold; - - bool d_preregisterCalled; - bool d_checkCalled; - - /** Pointer to the parent theory solver that owns this */ - BVSolverLayered* d_bv; - /** Pointer to the equality engine of the parent */ - eq::EqualityEngine* d_equalityEngine; - - /** To make sure we keep the explanations */ - context::CDHashSet<Node> d_reasons; - ModelValue d_modelValues; - void buildModel(); - bool assertFactToEqualityEngine(TNode fact, TNode reason); - bool isCompleteForTerm(TNode term, TNodeBoolMap& seen); - Statistics d_statistics; - - public: - CoreSolver(context::Context* c, BVSolverLayered* bv); - ~CoreSolver(); - bool needsEqualityEngine(EeSetupInfo& esi); - void finishInit(); - bool isComplete() override { return d_isComplete; } - void preRegister(TNode node) override; - bool check(Theory::Effort e) override; - void explain(TNode literal, std::vector<TNode>& assumptions) override; - bool collectModelValues(TheoryModel* m, - const std::set<Node>& termSet) override; - Node getModelValue(TNode var) override; - EqualityStatus getEqualityStatus(TNode a, TNode b) override; - bool hasTerm(TNode node) const; - void addTermToEqualityEngine(TNode node); -}; - -} -} -} // namespace cvc5 diff --git a/src/theory/bv/bv_subtheory_inequality.cpp b/src/theory/bv/bv_subtheory_inequality.cpp deleted file mode 100644 index 3bd3e9c3e..000000000 --- a/src/theory/bv/bv_subtheory_inequality.cpp +++ /dev/null @@ -1,254 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Liana Hadarean, Aina Niemetz, Andrew Reynolds - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * Algebraic solver. - */ - -#include "theory/bv/bv_subtheory_inequality.h" - -#include "options/smt_options.h" -#include "smt/smt_statistics_registry.h" -#include "theory/bv/bv_solver_layered.h" -#include "theory/bv/theory_bv_utils.h" -#include "theory/rewriter.h" -#include "theory/theory_model.h" - -using namespace std; -using namespace cvc5; -using namespace cvc5::context; -using namespace cvc5::theory; -using namespace cvc5::theory::bv; -using namespace cvc5::theory::bv::utils; - -bool InequalitySolver::check(Theory::Effort e) { - Debug("bv-subtheory-inequality") << "InequalitySolveR::check("<< e <<")\n"; - TimerStat::CodeTimer inequalityTimer(d_statistics.d_solveTime); - ++(d_statistics.d_numCallstoCheck); - d_bv->spendResource(Resource::TheoryCheckStep); - - bool ok = true; - while (!done() && ok) { - TNode fact = get(); - Debug("bv-subtheory-inequality") << " "<< fact <<"\n"; - if (fact.getKind() == kind::EQUAL) { - TNode a = fact[0]; - if( a.getType().isBitVector() ){ - TNode b = fact[1]; - ok = addInequality(a, b, false, fact); - if (ok) - ok = addInequality(b, a, false, fact); - } - } else if (fact.getKind() == kind::NOT && fact[0].getKind() == kind::EQUAL) { - TNode a = fact[0][0]; - if( a.getType().isBitVector() ){ - TNode b = fact[0][1]; - ok = d_inequalityGraph.addDisequality(a, b, fact); - } - } - if (fact.getKind() == kind::NOT && fact[0].getKind() == kind::BITVECTOR_ULE) { - TNode a = fact[0][1]; - TNode b = fact[0][0]; - ok = addInequality(a, b, true, fact); - // propagate - // NodeManager *nm = NodeManager::currentNM(); - // if (d_bv->isSharedTerm(a) && d_bv->isSharedTerm(b)) { - // Node neq = nm->mkNode(kind::NOT, nm->mkNode(kind::EQUAL, a, b)); - // d_bv->storePropagation(neq, SUB_INEQUALITY); - // d_explanations[neq] = fact; - // } - } else if (fact.getKind() == kind::NOT && fact[0].getKind() == kind::BITVECTOR_ULT) { - TNode a = fact[0][1]; - TNode b = fact[0][0]; - ok = addInequality(a, b, false, fact); - } else if (fact.getKind() == kind::BITVECTOR_ULT) { - TNode a = fact[0]; - TNode b = fact[1]; - ok = addInequality(a, b, true, fact); - // propagate - // if (d_bv->isSharedTerm(a) && d_bv->isSharedTerm(b)) { - // Node neq = nm->mkNode(kind::NOT, nm->mkNode(kind::EQUAL, a, b)); - // d_bv->storePropagation(neq, SUB_INEQUALITY); - // d_explanations[neq] = fact; - // } - } else if (fact.getKind() == kind::BITVECTOR_ULE) { - TNode a = fact[0]; - TNode b = fact[1]; - ok = addInequality(a, b, false, fact); - } - } - - if (!ok) { - std::vector<TNode> conflict; - d_inequalityGraph.getConflict(conflict); - Node confl = utils::flattenAnd(conflict); - d_bv->setConflict(confl); - Debug("bv-subtheory-inequality") << "InequalitySolver::conflict: "<< confl <<"\n"; - return false; - } - - if (isComplete() && Theory::fullEffort(e)) { - // make sure all the disequalities we didn't split on are still satisifed - // and split on the ones that are not - std::vector<Node> lemmas; - d_inequalityGraph.checkDisequalities(lemmas); - for(unsigned i = 0; i < lemmas.size(); ++i) { - d_bv->lemma(lemmas[i]); - } - } - Debug("bv-subtheory-inequality") << "InequalitySolver done. "; - return true; -} - -EqualityStatus InequalitySolver::getEqualityStatus(TNode a, TNode b) -{ - if (!isComplete()) return EQUALITY_UNKNOWN; - - NodeManager* nm = NodeManager::currentNM(); - Node a_lt_b = nm->mkNode(kind::BITVECTOR_ULT, a, b); - Node b_lt_a = nm->mkNode(kind::BITVECTOR_ULT, b, a); - - // if an inequality containing the terms has been asserted then we know - // the equality is false - if (d_assertionSet.contains(a_lt_b) || d_assertionSet.contains(b_lt_a)) - { - return EQUALITY_FALSE; - } - - if (!d_inequalityGraph.hasValueInModel(a) - || !d_inequalityGraph.hasValueInModel(b)) - { - return EQUALITY_UNKNOWN; - } - - // TODO: check if this disequality is entailed by inequalities via - // transitivity - - BitVector a_val = d_inequalityGraph.getValueInModel(a); - BitVector b_val = d_inequalityGraph.getValueInModel(b); - - if (a_val == b_val) - { - return EQUALITY_TRUE_IN_MODEL; - } - else - { - return EQUALITY_FALSE_IN_MODEL; - } -} - -void InequalitySolver::assertFact(TNode fact) { - d_assertionQueue.push_back(fact); - d_assertionSet.insert(fact); - if (!isInequalityOnly(fact)) { - d_isComplete = false; - } -} - -bool InequalitySolver::isInequalityOnly(TNode node) { - if (node.getKind() == kind::NOT) { - node = node[0]; - } - - if (node.getAttribute(IneqOnlyComputedAttribute())) { - return node.getAttribute(IneqOnlyAttribute()); - } - - if (node.getKind() != kind::EQUAL && - node.getKind() != kind::BITVECTOR_ULT && - node.getKind() != kind::BITVECTOR_ULE && - node.getKind() != kind::CONST_BITVECTOR && - node.getKind() != kind::SELECT && - node.getKind() != kind::STORE && - node.getMetaKind() != kind::metakind::VARIABLE) { - // not worth caching - return false; - } - bool res = true; - for (unsigned i = 0; res && i < node.getNumChildren(); ++i) { - res = res && isInequalityOnly(node[i]); - } - node.setAttribute(IneqOnlyComputedAttribute(), true); - node.setAttribute(IneqOnlyAttribute(), res); - return res; -} - -void InequalitySolver::explain(TNode literal, std::vector<TNode>& assumptions) { - Assert(d_explanations.find(literal) != d_explanations.end()); - TNode explanation = d_explanations[literal]; - assumptions.push_back(explanation); - Debug("bv-inequality-explain") << "InequalitySolver::explain " << literal << " with " << explanation <<"\n"; -} - -void InequalitySolver::propagate(Theory::Effort e) { Assert(false); } -bool InequalitySolver::collectModelValues(TheoryModel* m, - const std::set<Node>& termSet) -{ - Debug("bitvector-model") << "InequalitySolver::collectModelValues \n"; - std::vector<Node> model; - d_inequalityGraph.getAllValuesInModel(model); - for (unsigned i = 0; i < model.size(); ++i) { - Assert(model[i].getKind() == kind::EQUAL); - if (!m->assertEquality(model[i][0], model[i][1], true)) - { - return false; - } - } - return true; -} - -Node InequalitySolver::getModelValue(TNode var) { - Assert(isInequalityOnly(var)); - Debug("bitvector-model") << "InequalitySolver::getModelValue (" << var <<")"; - Assert(isComplete()); - Node result = Node(); - if (!d_inequalityGraph.hasValueInModel(var)) { - Assert(d_bv->isSharedTerm(var)); - } else { - BitVector val = d_inequalityGraph.getValueInModel(var); - result = utils::mkConst(val); - } - Debug("bitvector-model") << " => " << result <<"\n"; - return result; -} - -void InequalitySolver::preRegister(TNode node) { - Kind kind = node.getKind(); - if (kind == kind::EQUAL || - kind == kind::BITVECTOR_ULE || - kind == kind::BITVECTOR_ULT) { - d_ineqTerms.insert(node[0]); - d_ineqTerms.insert(node[1]); - } -} - -bool InequalitySolver::addInequality(TNode a, TNode b, bool strict, TNode fact) -{ - bool ok = d_inequalityGraph.addInequality(a, b, strict, fact); - if (!ok || !strict) return ok; - - Node one = utils::mkConst(utils::getSize(a), 1); - Node a_plus_one = Rewriter::rewrite( - NodeManager::currentNM()->mkNode(kind::BITVECTOR_ADD, a, one)); - if (d_ineqTerms.find(a_plus_one) != d_ineqTerms.end()) - { - ok = d_inequalityGraph.addInequality(a_plus_one, b, false, fact); - } - return ok; -} - -InequalitySolver::Statistics::Statistics() - : d_numCallstoCheck(smtStatisticsRegistry().registerInt( - "theory::bv::inequality::NumCallsToCheck")), - d_solveTime(smtStatisticsRegistry().registerTimer( - "theory::bv::inequality::SolveTime")) -{ -} diff --git a/src/theory/bv/bv_subtheory_inequality.h b/src/theory/bv/bv_subtheory_inequality.h deleted file mode 100644 index 8a76a6bf1..000000000 --- a/src/theory/bv/bv_subtheory_inequality.h +++ /dev/null @@ -1,94 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Mathias Preiner, Liana Hadarean, Aina Niemetz - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * Algebraic solver. - */ - -#include "cvc5_private.h" - -#ifndef CVC5__THEORY__BV__BV_SUBTHEORY__INEQUALITY_H -#define CVC5__THEORY__BV__BV_SUBTHEORY__INEQUALITY_H - -#include <unordered_set> - -#include "context/cdhashset.h" -#include "expr/attribute.h" -#include "theory/bv/bv_inequality_graph.h" -#include "theory/bv/bv_subtheory.h" - -namespace cvc5 { -namespace theory { -namespace bv { - -/** Cache for InequalitySolver::isInequalityOnly() */ -struct IneqOnlyAttributeId -{ -}; -typedef expr::Attribute<IneqOnlyAttributeId, bool> IneqOnlyAttribute; - -/** Whether the above has been computed yet or not for an expr */ -struct IneqOnlyComputedAttributeId -{ -}; -typedef expr::Attribute<IneqOnlyComputedAttributeId, bool> - IneqOnlyComputedAttribute; - -class InequalitySolver : public SubtheorySolver -{ - struct Statistics - { - IntStat d_numCallstoCheck; - TimerStat d_solveTime; - Statistics(); - }; - - context::CDHashSet<Node> d_assertionSet; - InequalityGraph d_inequalityGraph; - context::CDHashMap<Node, TNode> d_explanations; - context::CDO<bool> d_isComplete; - typedef std::unordered_set<Node> NodeSet; - NodeSet d_ineqTerms; - bool isInequalityOnly(TNode node); - bool addInequality(TNode a, TNode b, bool strict, TNode fact); - Statistics d_statistics; - - public: - InequalitySolver(context::Context* c, - context::Context* u, - BVSolverLayered* bv) - : SubtheorySolver(c, bv), - d_assertionSet(c), - d_inequalityGraph(c, u), - d_explanations(c), - d_isComplete(c, true), - d_ineqTerms(), - d_statistics() - { - } - - bool check(Theory::Effort e) override; - void propagate(Theory::Effort e) override; - void explain(TNode literal, std::vector<TNode>& assumptions) override; - bool isComplete() override { return d_isComplete; } - bool collectModelValues(TheoryModel* m, - const std::set<Node>& termSet) override; - Node getModelValue(TNode var) override; - EqualityStatus getEqualityStatus(TNode a, TNode b) override; - void assertFact(TNode fact) override; - void preRegister(TNode node) override; -}; - -} // namespace bv -} // namespace theory -} // namespace cvc5 - -#endif /* CVC5__THEORY__BV__BV_SUBTHEORY__INEQUALITY_H */ diff --git a/src/theory/bv/slicer.cpp b/src/theory/bv/slicer.cpp deleted file mode 100644 index 8ea7e1a9c..000000000 --- a/src/theory/bv/slicer.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Liana Hadarean, Aina Niemetz - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * Bitvector theory. - */ -#include "theory/bv/slicer.h" - -#include <sstream> - -#include "theory/bv/theory_bv_utils.h" -#include "theory/rewriter.h" - -using namespace std; - -namespace cvc5 { -namespace theory { -namespace bv { - -/** - * Base - * - */ -Base::Base(uint32_t size) - : d_size(size), - d_repr(size/32 + (size % 32 == 0? 0 : 1), 0) -{ - Assert(d_size > 0); -} - -void Base::sliceAt(Index index) -{ - Index vector_index = index / 32; - if (vector_index == d_repr.size()) - return; - - Index int_index = index % 32; - uint32_t bit_mask = 1u << int_index; - d_repr[vector_index] = d_repr[vector_index] | bit_mask; -} - -bool Base::isCutPoint (Index index) const -{ - // there is an implicit cut point at the end and begining of the bv - if (index == d_size || index == 0) - return true; - - Index vector_index = index / 32; - Assert(vector_index < d_size); - Index int_index = index % 32; - uint32_t bit_mask = 1u << int_index; - - return (bit_mask & d_repr[vector_index]) != 0; -} - -std::string Base::debugPrint() const { - std::ostringstream os; - os << "["; - bool first = true; - for (int i = d_size - 1; i >= 0; --i) { - if (isCutPoint(i)) { - if (first) - first = false; - else - os <<"| "; - - os << i ; - } - } - os << "]"; - return os.str(); -} - - -} // namespace bv -} // namespace theory -} // namespace cvc5 diff --git a/src/theory/bv/slicer.h b/src/theory/bv/slicer.h deleted file mode 100644 index d90cc501a..000000000 --- a/src/theory/bv/slicer.h +++ /dev/null @@ -1,55 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Liana Hadarean, Mathias Preiner, Andrew Reynolds - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * Bitvector theory. - */ - -#include "cvc5_private.h" - -#ifndef CVC5__THEORY__BV__SLICER_BV_H -#define CVC5__THEORY__BV__SLICER_BV_H - -#include <string> -#include <vector> -#include "util/index.h" - -namespace cvc5 { -namespace theory { -namespace bv { - -/** - * Base - * - */ -class Base { - Index d_size; - std::vector<uint32_t> d_repr; -public: - Base(Index size); - void sliceAt(Index index); - bool isCutPoint(Index index) const; - std::string debugPrint() const; - bool operator==(const Base& other) const { - if (other.d_size != d_size) return false; - for (unsigned i = 0; i < d_repr.size(); ++i) { - if (d_repr[i] != other.d_repr[i]) - return false; - } - return true; - } -}; - -} // namespace bv -} // namespace theory -} // namespace cvc5 - -#endif /* CVC5__THEORY__BV__SLICER_BV_H */ diff --git a/src/theory/bv/theory_bv.cpp b/src/theory/bv/theory_bv.cpp index 8e9c2da5b..96b1815e6 100644 --- a/src/theory/bv/theory_bv.cpp +++ b/src/theory/bv/theory_bv.cpp @@ -21,12 +21,12 @@ #include "smt/smt_statistics_registry.h" #include "theory/bv/bv_solver_bitblast.h" #include "theory/bv/bv_solver_bitblast_internal.h" -#include "theory/bv/bv_solver_layered.h" #include "theory/bv/theory_bv_rewrite_rules_normalization.h" #include "theory/bv/theory_bv_rewrite_rules_simplification.h" #include "theory/bv/theory_bv_utils.h" #include "theory/ee_setup_info.h" #include "theory/trust_substitutions.h" +#include "theory/uf/equality_engine.h" namespace cvc5 { namespace theory { @@ -51,11 +51,6 @@ TheoryBV::TheoryBV(Env& env, d_internal.reset(new BVSolverBitblast(env, &d_state, d_im, d_pnm)); break; - case options::BVSolver::LAYERED: - d_internal.reset(new BVSolverLayered( - env, *this, context(), userContext(), d_pnm, name)); - break; - default: AlwaysAssert(options().bv.bvSolver == options::BVSolver::BITBLAST_INTERNAL); d_internal.reset( @@ -395,12 +390,6 @@ void TheoryBV::ppStaticLearn(TNode in, NodeBuilder& learned) d_internal->ppStaticLearn(in, learned); } -bool TheoryBV::applyAbstraction(const std::vector<Node>& assertions, - std::vector<Node>& new_assertions) -{ - return d_internal->applyAbstraction(assertions, new_assertions); -} - Node TheoryBV::getValue(TNode node) { if (d_invalidateModelCache.get()) diff --git a/src/theory/bv/theory_bv.h b/src/theory/bv/theory_bv.h index 0249fe890..3534a1d8f 100644 --- a/src/theory/bv/theory_bv.h +++ b/src/theory/bv/theory_bv.h @@ -99,10 +99,6 @@ class TheoryBV : public Theory EqualityStatus getEqualityStatus(TNode a, TNode b) override; - /** Called by abstraction preprocessing pass. */ - bool applyAbstraction(const std::vector<Node>& assertions, - std::vector<Node>& new_assertions); - private: void notifySharedTerm(TNode t) override; diff --git a/src/theory/bv/theory_bv_rewrite_rules_normalization.h b/src/theory/bv/theory_bv_rewrite_rules_normalization.h index 5ead8a215..d73497adf 100644 --- a/src/theory/bv/theory_bv_rewrite_rules_normalization.h +++ b/src/theory/bv/theory_bv_rewrite_rules_normalization.h @@ -844,15 +844,9 @@ inline Node RewriteRule<SolveEq>::apply(TNode node) if (newLeft < newRight) { - Assert((newRight == left && newLeft == right) - || Rewriter::rewrite(newRight) != left - || Rewriter::rewrite(newLeft) != right); return newRight.eqNode(newLeft); } - Assert((newLeft == left && newRight == right) - || Rewriter::rewrite(newLeft) != left - || Rewriter::rewrite(newRight) != right); return newLeft.eqNode(newRight); } diff --git a/src/theory/combination_engine.cpp b/src/theory/combination_engine.cpp index dfa6d5da4..16f43966e 100644 --- a/src/theory/combination_engine.cpp +++ b/src/theory/combination_engine.cpp @@ -44,7 +44,7 @@ CombinationEngine::CombinationEngine(Env& env, : nullptr) { // create the equality engine, model manager, and shared solver - if (options::eeMode() == options::EqEngineMode::DISTRIBUTED) + if (options().theory.eeMode == options::EqEngineMode::DISTRIBUTED) { // use the distributed shared solver d_sharedSolver.reset(new SharedSolverDistributed(env, d_te)); @@ -55,7 +55,7 @@ CombinationEngine::CombinationEngine(Env& env, d_mmanager.reset( new ModelManagerDistributed(env, d_te, *d_eemanager.get())); } - else if (options::eeMode() == options::EqEngineMode::CENTRAL) + else if (options().theory.eeMode == options::EqEngineMode::CENTRAL) { // for now, the shared solver is the same in both approaches; use the // distributed one for now @@ -70,7 +70,7 @@ CombinationEngine::CombinationEngine(Env& env, else { Unhandled() << "CombinationEngine::finishInit: equality engine mode " - << options::eeMode() << " not supported"; + << options().theory.eeMode << " not supported"; } } diff --git a/src/theory/datatypes/sygus_extension.cpp b/src/theory/datatypes/sygus_extension.cpp index d3e711c32..bacbf8c47 100644 --- a/src/theory/datatypes/sygus_extension.cpp +++ b/src/theory/datatypes/sygus_extension.cpp @@ -79,7 +79,8 @@ void SygusExtension::assertTester(int tindex, TNode n, Node exp) // check if parent is active bool do_add = true; - if( options::sygusSymBreakLazy() ){ + if (options().datatypes.sygusSymBreakLazy) + { if( n.getKind()==kind::APPLY_SELECTOR_TOTAL ){ NodeSet::const_iterator it = d_active_terms.find( n[0] ); if( it==d_active_terms.end() ){ @@ -120,7 +121,7 @@ void SygusExtension::assertFact(Node n, bool polarity) Node m = n[0]; Trace("sygus-fair") << "Have sygus bound : " << n << ", polarity=" << polarity << " on measure " << m << std::endl; registerMeasureTerm( m ); - if (options::sygusFair() == options::SygusFairMode::DT_SIZE) + if (options().datatypes.sygusFair == options::SygusFairMode::DT_SIZE) { std::map<Node, std::unique_ptr<SygusSizeDecisionStrategy>>::iterator its = d_szinfo.find(m); @@ -231,7 +232,7 @@ void SygusExtension::assertTesterInternal(int tindex, TNode n, Node exp) Assert(itsz != d_szinfo.end()); unsigned ssz = itsz->second->d_curr_search_size; - if (options::sygusFair() == options::SygusFairMode::DIRECT) + if (options().datatypes.sygusFair == options::SygusFairMode::DIRECT) { if( dt[tindex].getNumArgs()>0 ){ quantifiers::SygusTypeInfo& nti = d_tds->getTypeInfo(ntn); @@ -282,7 +283,8 @@ void SygusExtension::assertTesterInternal(int tindex, TNode n, Node exp) unsigned d = d_term_to_depth[n]; Trace("sygus-sb-fair-debug") << "Tester " << exp << " is for depth " << d << " term in search size " << ssz << std::endl; //Assert( d<=ssz ); - if( options::sygusSymBreakLazy() ){ + if (options().datatypes.sygusSymBreakLazy) + { // dynamic symmetry breaking addSymBreakLemmasFor(ntn, n, d); } @@ -361,7 +363,8 @@ void SygusExtension::assertTesterInternal(int tindex, TNode n, Node exp) // now activate the children those testers were previously asserted in this // context and are awaiting activation, if they exist. - if( options::sygusSymBreakLazy() ){ + if (options().datatypes.sygusSymBreakLazy) + { Trace("sygus-sb-debug") << "Do lazy symmetry breaking...\n"; for( unsigned j=0; j<dt[tindex].getNumArgs(); j++ ){ Node sel = nm->mkNode( @@ -379,7 +382,7 @@ void SygusExtension::assertTesterInternal(int tindex, TNode n, Node exp) } Node SygusExtension::getRelevancyCondition( Node n ) { - if (!options::sygusSymBreakRlv()) + if (!options().datatypes.sygusSymBreakRlv) { return Node::null(); } @@ -391,7 +394,8 @@ Node SygusExtension::getRelevancyCondition( Node n ) { TypeNode ntn = n[0].getType(); const DType& dt = ntn.getDType(); Node sel = n.getOperator(); - if( options::dtSharedSelectors() ){ + if (options().datatypes.dtSharedSelectors) + { std::vector< Node > disj; bool excl = false; for( unsigned i=0; i<dt.getNumConstructors(); i++ ){ @@ -410,7 +414,9 @@ Node SygusExtension::getRelevancyCondition( Node n ) { cond = disj.size() == 1 ? disj[0] : NodeManager::currentNM()->mkNode( kind::AND, disj); } - }else{ + } + else + { int sindex = utils::cindexOf(sel); Assert(sindex != -1); cond = utils::mkTester(n[0], sindex, dt).negate(); @@ -597,7 +603,7 @@ Node SygusExtension::getSimpleSymBreakPred(Node e, { Trace("sygus-sb-simple-debug") << " Size..." << std::endl; // fairness - if (options::sygusFair() == options::SygusFairMode::DT_SIZE + if (options().datatypes.sygusFair == options::SygusFairMode::DT_SIZE && !isAnyConstant) { Node szl = nm->mkNode(DT_SIZE, n); @@ -685,7 +691,7 @@ Node SygusExtension::getSimpleSymBreakPred(Node e, // if we are the "any constant" constructor, we do no symmetry breaking // only do simple symmetry breaking up to depth 2 - bool doSymBreak = options::sygusSymBreak(); + bool doSymBreak = options().datatypes.sygusSymBreak; if (isAnyConstant || depth > 2) { doSymBreak = false; @@ -961,7 +967,8 @@ void SygusExtension::registerSearchTerm(TypeNode tn, { Trace("sygus-sb-debug") << " register search term : " << n << " at depth " << d << ", type=" << tn << ", tl=" << topLevel << std::endl; sca.d_search_terms[tn][d].push_back(n); - if( !options::sygusSymBreakLazy() ){ + if (!options().datatypes.sygusSymBreakLazy) + { addSymBreakLemmasFor(tn, n, d); } } @@ -1060,7 +1067,7 @@ Node SygusExtension::registerSearchValue(Node a, { // Is it equivalent under examples? Node bvr_equiv; - if (aconj != nullptr && options::sygusSymBreakPbe()) + if (aconj != nullptr && options().datatypes.sygusSymBreakPbe) { // If the enumerator has examples, see if it is equivalent up to its // examples with a previous term. @@ -1097,7 +1104,7 @@ Node SygusExtension::registerSearchValue(Node a, } } - if (options::sygusRewVerify()) + if (options().quantifiers.sygusRewVerify) { if (bv != bvr) { @@ -1111,7 +1118,7 @@ Node SygusExtension::registerSearchValue(Node a, { smap[tn].reset(new quantifiers::SygusSampler(d_env)); smap[tn]->initializeSygus( - d_tds, nv, options::sygusSamples(), false); + d_tds, nv, options().quantifiers.sygusSamples, false); its = d_sampler[a].find(tn); } // check equivalent @@ -1220,7 +1227,7 @@ void SygusExtension::registerSymBreakLemma(TypeNode tn, { for (const Node& t : itt->second) { - if (!options::sygusSymBreakLazy() + if (!options().datatypes.sygusSymBreakLazy || d_active_terms.find(t) != d_active_terms.end()) { Node slem = lem.substitute(x, t); @@ -1360,11 +1367,11 @@ void SygusExtension::registerSizeTerm(Node e) d_szinfo[m]->d_anchors.push_back(e); d_anchor_to_measure_term[e] = m; NodeManager* nm = NodeManager::currentNM(); - if (options::sygusFair() == options::SygusFairMode::DT_SIZE) + if (options().datatypes.sygusFair == options::SygusFairMode::DT_SIZE) { // update constraints on the measure term Node slem; - if (options::sygusFairMax()) + if (options().datatypes.sygusFairMax) { Node ds = nm->mkNode(DT_SIZE, e); slem = nm->mkNode(LEQ, ds, d_szinfo[m]->getOrMkMeasureValue()); @@ -1490,7 +1497,7 @@ void SygusExtension::incrementCurrentSearchSize(TNode m) if( itt!=itc->second.d_search_terms[tn].end() ){ for (const Node& t : itt->second) { - if (!options::sygusSymBreakLazy() + if (!options().datatypes.sygusSymBreakLazy || (d_active_terms.find(t) != d_active_terms.end() && !s.second.empty())) { @@ -1598,7 +1605,7 @@ void SygusExtension::check() { isExc = false; //debugging : ensure fairness was properly handled - if (options::sygusFair() == options::SygusFairMode::DT_SIZE) + if (options().datatypes.sygusFair == options::SygusFairMode::DT_SIZE) { Node prog_sz = NodeManager::currentNM()->mkNode( kind::DT_SIZE, prog ); Node prog_szv = d_state.getValuation().getModel()->getValue(prog_sz); @@ -1617,7 +1624,7 @@ void SygusExtension::check() // register the search value ( prog -> progv ), this may invoke symmetry // breaking - if (!isExc && options::sygusSymBreakDynamic()) + if (!isExc && options().datatypes.sygusSymBreakDynamic) { bool isVarAgnostic = d_tds->isVariableAgnosticEnumerator(prog); // check that it is unique up to theory-specific rewriting and @@ -1793,15 +1800,15 @@ Node SygusExtension::SygusSizeDecisionStrategy::getOrMkActiveMeasureValue( Node SygusExtension::SygusSizeDecisionStrategy::mkLiteral(unsigned s) { - if (options::sygusFair() == options::SygusFairMode::NONE) + if (options().datatypes.sygusFair == options::SygusFairMode::NONE) { return Node::null(); } - if (options::sygusAbortSize() != -1 - && static_cast<int>(s) > options::sygusAbortSize()) + if (options().datatypes.sygusAbortSize != -1 + && static_cast<int>(s) > options().datatypes.sygusAbortSize) { std::stringstream ss; - ss << "Maximum term size (" << options::sygusAbortSize() + ss << "Maximum term size (" << options().datatypes.sygusAbortSize << ") for enumerative SyGuS exceeded."; throw LogicException(ss.str()); } diff --git a/src/theory/fp/fp_expand_defs.cpp b/src/theory/fp/fp_expand_defs.cpp index a499b9666..de86626af 100644 --- a/src/theory/fp/fp_expand_defs.cpp +++ b/src/theory/fp/fp_expand_defs.cpp @@ -50,11 +50,8 @@ Node FpExpandDefs::minUF(Node node) args[0] = t; args[1] = t; fun = sm->mkDummySkolem("floatingpoint_min_zero_case", - nm->mkFunctionType(args, - nm->mkBitVectorType(1U) - ), - "floatingpoint_min_zero_case", - NodeManager::SKOLEM_EXACT_NAME); + nm->mkFunctionType(args, nm->mkBitVectorType(1U)), + "floatingpoint_min_zero_case"); d_minMap.insert(t, fun); } else @@ -84,11 +81,8 @@ Node FpExpandDefs::maxUF(Node node) args[0] = t; args[1] = t; fun = sm->mkDummySkolem("floatingpoint_max_zero_case", - nm->mkFunctionType(args, - nm->mkBitVectorType(1U) - ), - "floatingpoint_max_zero_case", - NodeManager::SKOLEM_EXACT_NAME); + nm->mkFunctionType(args, nm->mkBitVectorType(1U)), + "floatingpoint_max_zero_case"); d_maxMap.insert(t, fun); } else @@ -121,8 +115,7 @@ Node FpExpandDefs::toUBVUF(Node node) args[1] = source; fun = sm->mkDummySkolem("floatingpoint_to_ubv_out_of_range_case", nm->mkFunctionType(args, target), - "floatingpoint_to_ubv_out_of_range_case", - NodeManager::SKOLEM_EXACT_NAME); + "floatingpoint_to_ubv_out_of_range_case"); d_toUBVMap.insert(p, fun); } else @@ -155,8 +148,7 @@ Node FpExpandDefs::toSBVUF(Node node) args[1] = source; fun = sm->mkDummySkolem("floatingpoint_to_sbv_out_of_range_case", nm->mkFunctionType(args, target), - "floatingpoint_to_sbv_out_of_range_case", - NodeManager::SKOLEM_EXACT_NAME); + "floatingpoint_to_sbv_out_of_range_case"); d_toSBVMap.insert(p, fun); } else @@ -183,8 +175,7 @@ Node FpExpandDefs::toRealUF(Node node) args[0] = t; fun = sm->mkDummySkolem("floatingpoint_to_real_infinity_and_NaN_case", nm->mkFunctionType(args, nm->realType()), - "floatingpoint_to_real_infinity_and_NaN_case", - NodeManager::SKOLEM_EXACT_NAME); + "floatingpoint_to_real_infinity_and_NaN_case"); d_toRealMap.insert(t, fun); } else diff --git a/src/theory/fp/theory_fp.cpp b/src/theory/fp/theory_fp.cpp index 8364aa81b..e588bc1a9 100644 --- a/src/theory/fp/theory_fp.cpp +++ b/src/theory/fp/theory_fp.cpp @@ -476,20 +476,13 @@ void TheoryFp::registerTerm(TNode node) { Trace("fp-registerTerm") << "TheoryFp::registerTerm(): " << node << std::endl; - if (isRegistered(node)) - { - return; - } - Kind k = node.getKind(); Assert(k != kind::FLOATINGPOINT_TO_FP_GENERIC && k != kind::FLOATINGPOINT_SUB && k != kind::FLOATINGPOINT_EQ && k != kind::FLOATINGPOINT_GEQ && k != kind::FLOATINGPOINT_GT); - CVC5_UNUSED bool success = d_registeredTerms.insert(node); - Assert(success); - - // Add to the equality engine + // Add to the equality engine, always. This is required to ensure + // getEqualityStatus works as expected when theory combination is enabled. if (k == kind::EQUAL) { d_equalityEngine->addTriggerPredicate(node); @@ -499,6 +492,15 @@ void TheoryFp::registerTerm(TNode node) d_equalityEngine->addTerm(node); } + // if not registered in this user context + if (isRegistered(node)) + { + return; + } + + CVC5_UNUSED bool success = d_registeredTerms.insert(node); + Assert(success); + // Give the expansion of classifications in terms of equalities // This should make equality reasoning slightly more powerful. if ((k == kind::FLOATINGPOINT_ISNAN) || (k == kind::FLOATINGPOINT_ISZ) diff --git a/src/theory/inference_id.cpp b/src/theory/inference_id.cpp index b50522834..594834226 100644 --- a/src/theory/inference_id.cpp +++ b/src/theory/inference_id.cpp @@ -104,6 +104,7 @@ const char* toString(InferenceId i) case InferenceId::ARRAYS_EQ_TAUTOLOGY: return "ARRAYS_EQ_TAUTOLOGY"; case InferenceId::BAGS_NON_NEGATIVE_COUNT: return "BAGS_NON_NEGATIVE_COUNT"; + case InferenceId::BAGS_MK_BAG_DIFFERENT_ELEMENT: return "BAGS_MK_BAG_DIFFERENT_ELEMENT"; case InferenceId::BAGS_MK_BAG_SAME_ELEMENT: return "BAGS_MK_BAG_SAME_ELEMENT"; case InferenceId::BAGS_MK_BAG: return "BAGS_MK_BAG"; case InferenceId::BAGS_EQUALITY: return "BAGS_EQUALITY"; @@ -341,8 +342,6 @@ const char* toString(InferenceId i) case InferenceId::SETS_RELS_JOIN_IMAGE_UP: return "SETS_RELS_JOIN_IMAGE_UP"; case InferenceId::SETS_RELS_JOIN_SPLIT_1: return "SETS_RELS_JOIN_SPLIT_1"; case InferenceId::SETS_RELS_JOIN_SPLIT_2: return "SETS_RELS_JOIN_SPLIT_2"; - case InferenceId::SETS_RELS_JOIN_ELEM_SPLIT: - return "SETS_RELS_JOIN_ELEM_SPLIT"; case InferenceId::SETS_RELS_PRODUCE_COMPOSE: return "SETS_RELS_PRODUCE_COMPOSE"; case InferenceId::SETS_RELS_PRODUCT_SPLIT: return "SETS_RELS_PRODUCT_SPLIT"; diff --git a/src/theory/inference_id.h b/src/theory/inference_id.h index 3c644e545..cebf02c9d 100644 --- a/src/theory/inference_id.h +++ b/src/theory/inference_id.h @@ -169,6 +169,7 @@ enum class InferenceId // ---------------------------------- bags theory BAGS_NON_NEGATIVE_COUNT, + BAGS_MK_BAG_DIFFERENT_ELEMENT, BAGS_MK_BAG_SAME_ELEMENT, BAGS_MK_BAG, BAGS_EQUALITY, @@ -491,7 +492,6 @@ enum class InferenceId SETS_RELS_JOIN_IMAGE_UP, SETS_RELS_JOIN_SPLIT_1, SETS_RELS_JOIN_SPLIT_2, - SETS_RELS_JOIN_ELEM_SPLIT, SETS_RELS_PRODUCE_COMPOSE, SETS_RELS_PRODUCT_SPLIT, SETS_RELS_TCLOSURE_FWD, diff --git a/src/theory/model_manager.cpp b/src/theory/model_manager.cpp index 23cd6430f..8c8d63231 100644 --- a/src/theory/model_manager.cpp +++ b/src/theory/model_manager.cpp @@ -34,7 +34,7 @@ ModelManager::ModelManager(Env& env, TheoryEngine& te, EqEngineManager& eem) d_modelEqualityEngine(nullptr), d_modelEqualityEngineAlloc(nullptr), d_model(new TheoryModel( - env, "DefaultModel", options::assignFunctionValues())), + env, "DefaultModel", options().theory.assignFunctionValues)), d_modelBuilder(nullptr), d_modelBuilt(false), d_modelBuiltSuccess(false) @@ -118,7 +118,7 @@ void ModelManager::postProcessModel(bool incomplete) Trace("model-builder") << "ModelManager: post-process model..." << std::endl; // model construction should always succeed unless lemmas were added AlwaysAssert(d_modelBuiltSuccess); - if (!options::produceModels()) + if (!options().smt.produceModels) { return; } diff --git a/src/theory/quantifiers/candidate_rewrite_filter.cpp b/src/theory/quantifiers/candidate_rewrite_filter.cpp index e856f1519..4f9a46181 100644 --- a/src/theory/quantifiers/candidate_rewrite_filter.cpp +++ b/src/theory/quantifiers/candidate_rewrite_filter.cpp @@ -73,15 +73,17 @@ bool CandidateRewriteFilter::filterPair(Node n, Node eq_n) bool keep = true; // ----- check redundancy based on variables - if (options::sygusRewSynthFilterOrder() - || options::sygusRewSynthFilterNonLinear()) + if (options().quantifiers.sygusRewSynthFilterOrder + || options().quantifiers.sygusRewSynthFilterNonLinear) { - bool nor = d_ss->checkVariables(bn, - options::sygusRewSynthFilterOrder(), - options::sygusRewSynthFilterNonLinear()); - bool eqor = d_ss->checkVariables(beq_n, - options::sygusRewSynthFilterOrder(), - options::sygusRewSynthFilterNonLinear()); + bool nor = d_ss->checkVariables( + bn, + options().quantifiers.sygusRewSynthFilterOrder, + options().quantifiers.sygusRewSynthFilterNonLinear); + bool eqor = d_ss->checkVariables( + beq_n, + options().quantifiers.sygusRewSynthFilterOrder, + options().quantifiers.sygusRewSynthFilterNonLinear); Trace("cr-filter-debug") << "Variables ok? : " << nor << " " << eqor << std::endl; if (eqor || nor) @@ -118,7 +120,7 @@ bool CandidateRewriteFilter::filterPair(Node n, Node eq_n) } // ----- check rewriting redundancy - if (keep && options::sygusRewSynthFilterCong()) + if (keep && options().quantifiers.sygusRewSynthFilterCong) { // When using sygus types, this filtering applies to the builtin versions // of n and eq_n. This means that we may filter out a rewrite rule for one @@ -135,7 +137,7 @@ bool CandidateRewriteFilter::filterPair(Node n, Node eq_n) } } - if (keep && options::sygusRewSynthFilterMatch()) + if (keep && options().quantifiers.sygusRewSynthFilterMatch) { // ----- check matchable // check whether the pair is matchable with a previous one @@ -186,13 +188,13 @@ void CandidateRewriteFilter::registerRelevantPair(Node n, Node eq_n) beq_n = d_tds->sygusToBuiltin(eq_n); } // ----- check rewriting redundancy - if (options::sygusRewSynthFilterCong()) + if (options().quantifiers.sygusRewSynthFilterCong) { Trace("cr-filter-debug") << "Add rewrite pair..." << std::endl; Assert(!d_drewrite->areEqual(bn, beq_n)); d_drewrite->addRewrite(bn, beq_n); } - if (options::sygusRewSynthFilterMatch()) + if (options().quantifiers.sygusRewSynthFilterMatch) { // cache based on the builtin type TypeNode tn = bn.getType(); @@ -258,7 +260,7 @@ bool CandidateRewriteFilter::notify(Node s, Node nrs = nr.substitute(vars.begin(), vars.end(), esubs.begin(), esubs.end()); bool areEqual = (nrs == d_curr_pair_rhs); - if (!areEqual && options::sygusRewSynthFilterCong()) + if (!areEqual && options().quantifiers.sygusRewSynthFilterCong) { // if dynamic rewriter is available, consult it areEqual = d_drewrite->areEqual(nrs, d_curr_pair_rhs); diff --git a/src/theory/quantifiers/cegqi/ceg_arith_instantiator.cpp b/src/theory/quantifiers/cegqi/ceg_arith_instantiator.cpp index 85e91fee3..163a49b8c 100644 --- a/src/theory/quantifiers/cegqi/ceg_arith_instantiator.cpp +++ b/src/theory/quantifiers/cegqi/ceg_arith_instantiator.cpp @@ -166,7 +166,7 @@ bool ArithInstantiator::processAssertion(CegInstantiator* ci, } // compute how many bounds we will consider unsigned rmax = 1; - if (atom.getKind() == EQUAL && (pol || !options::cegqiModel())) + if (atom.getKind() == EQUAL && (pol || !options().quantifiers.cegqiModel)) { rmax = 2; } @@ -205,7 +205,7 @@ bool ArithInstantiator::processAssertion(CegInstantiator* ci, { // disequalities are either strict upper or lower bounds bool is_upper; - if (options::cegqiModel()) + if (options().quantifiers.cegqiModel) { // disequality is a disjunction : only consider the bound in the // direction of the model @@ -272,7 +272,7 @@ bool ArithInstantiator::processAssertion(CegInstantiator* ci, // take into account delta if (uires == CEG_TT_UPPER_STRICT || uires == CEG_TT_LOWER_STRICT) { - if (options::cegqiModel()) + if (options().quantifiers.cegqiModel) { Node delta_coeff = nm->mkConst(Rational(isUpperBoundCTT(uires) ? 1 : -1)); @@ -294,7 +294,7 @@ bool ArithInstantiator::processAssertion(CegInstantiator* ci, uval = rewrite(uval); } } - if (options::cegqiModel()) + if (options().quantifiers.cegqiModel) { // just store bounds, will choose based on tighest bound unsigned index = isUpperBoundCTT(uires) ? 0 : 1; @@ -329,15 +329,15 @@ bool ArithInstantiator::processAssertions(CegInstantiator* ci, Node pv, CegInstEffort effort) { - if (!options::cegqiModel()) + if (!options().quantifiers.cegqiModel) { return false; } NodeManager* nm = NodeManager::currentNM(); - bool use_inf = - d_type.isInteger() ? options::cegqiUseInfInt() : options::cegqiUseInfReal(); + bool use_inf = d_type.isInteger() ? options().quantifiers.cegqiUseInfInt + : options().quantifiers.cegqiUseInfReal; bool upper_first = Random::getRandom().pickWithProb(0.5); - if (options::cegqiMinBounds()) + if (options().quantifiers.cegqiMinBounds) { upper_first = d_mbp_bounds[1].size() < d_mbp_bounds[0].size(); } @@ -369,7 +369,7 @@ bool ArithInstantiator::processAssertions(CegInstantiator* ci, { return true; } - else if (!options::cegqiMultiInst()) + else if (!options().quantifiers.cegqiMultiInst) { return false; } @@ -508,7 +508,7 @@ bool ArithInstantiator::processAssertions(CegInstantiator* ci, best_used[rr] = best; // if using cbqiMidpoint, only add the instance based on one bound if // the bound is non-strict - if (!options::cegqiMidpoint() || d_type.isInteger() + if (!options().quantifiers.cegqiMidpoint || d_type.isInteger() || d_mbp_vts_coeff[rr][1][best].isNull()) { Node val = d_mbp_bounds[rr][best]; @@ -531,7 +531,7 @@ bool ArithInstantiator::processAssertions(CegInstantiator* ci, { return true; } - else if (!options::cegqiMultiInst()) + else if (!options().quantifiers.cegqiMultiInst) { return false; } @@ -562,13 +562,13 @@ bool ArithInstantiator::processAssertions(CegInstantiator* ci, { return true; } - else if (!options::cegqiMultiInst()) + else if (!options().quantifiers.cegqiMultiInst) { return false; } } } - if (options::cegqiMidpoint() && !d_type.isInteger()) + if (options().quantifiers.cegqiMidpoint && !d_type.isInteger()) { Node vals[2]; bool bothBounds = true; @@ -633,7 +633,7 @@ bool ArithInstantiator::processAssertions(CegInstantiator* ci, { return true; } - else if (!options::cegqiMultiInst()) + else if (!options().quantifiers.cegqiMultiInst) { return false; } @@ -642,7 +642,7 @@ bool ArithInstantiator::processAssertions(CegInstantiator* ci, // generally should not make it to this point, unless we are using a // non-monotonic selection function - if (!options::cegqiNopt()) + if (!options().quantifiers.cegqiNopt) { // if not trying non-optimal bounds, return return false; @@ -655,7 +655,8 @@ bool ArithInstantiator::processAssertions(CegInstantiator* ci, for (unsigned j = 0, nbounds = d_mbp_bounds[rr].size(); j < nbounds; j++) { if ((int)j != best_used[rr] - && (!options::cegqiMidpoint() || d_mbp_vts_coeff[rr][1][j].isNull())) + && (!options().quantifiers.cegqiMidpoint + || d_mbp_vts_coeff[rr][1][j].isNull())) { Node val = getModelBasedProjectionValue(ci, pv, @@ -676,7 +677,7 @@ bool ArithInstantiator::processAssertions(CegInstantiator* ci, { return true; } - else if (!options::cegqiMultiInst()) + else if (!options().quantifiers.cegqiMultiInst) { return false; } @@ -748,7 +749,7 @@ bool ArithInstantiator::postProcessInstantiationForVariable( << "...bound type is : " << sf.d_props[index].d_type << std::endl; // intger division rounding up if from a lower bound if (sf.d_props[index].d_type == CEG_TT_UPPER - && options::cegqiRoundUpLowerLia()) + && options().quantifiers.cegqiRoundUpLowerLia) { sf.d_subs[index] = nm->mkNode( PLUS, diff --git a/src/theory/quantifiers/cegqi/ceg_instantiator.cpp b/src/theory/quantifiers/cegqi/ceg_instantiator.cpp index d61dd2bd2..9dc11955b 100644 --- a/src/theory/quantifiers/cegqi/ceg_instantiator.cpp +++ b/src/theory/quantifiers/cegqi/ceg_instantiator.cpp @@ -629,7 +629,7 @@ bool CegInstantiator::constructInstantiation(SolvedForm& sf, unsigned i) // - the instantiator uses model values at this effort or // if we are solving for a subfield of a datatype (is_sv), and // - the instantiator allows model values. - if ((options::cegqiMultiInst() || !hasTriedInstantiation(pv)) + if ((options().quantifiers.cegqiMultiInst || !hasTriedInstantiation(pv)) && (vinst->useModelValue(this, sf, pv, d_effort) || is_sv) && vinst->allowModelValue(this, sf, pv, d_effort)) { @@ -677,7 +677,7 @@ bool CegInstantiator::constructInstantiation(SolvedForm& sf, << "], rep=" << pvr << ", instantiator is " << vinst->identify() << std::endl; Node pv_value; - if (options::cegqiModel()) + if (options().quantifiers.cegqiModel) { pv_value = getModelValue(pv); Trace("cegqi-bound2") << "...M( " << pv << " ) = " << pv_value << std::endl; @@ -730,7 +730,8 @@ bool CegInstantiator::constructInstantiation(SolvedForm& sf, { return true; } - else if (!options::cegqiMultiInst() && hasTriedInstantiation(pv)) + else if (!options().quantifiers.cegqiMultiInst + && hasTriedInstantiation(pv)) { return false; } @@ -746,7 +747,8 @@ bool CegInstantiator::constructInstantiation(SolvedForm& sf, { return true; } - else if (!options::cegqiMultiInst() && hasTriedInstantiation(pv)) + else if (!options().quantifiers.cegqiMultiInst + && hasTriedInstantiation(pv)) { return false; } @@ -817,7 +819,8 @@ bool CegInstantiator::constructInstantiation(SolvedForm& sf, { return true; } - else if (!options::cegqiMultiInst() && hasTriedInstantiation(pv)) + else if (!options().quantifiers.cegqiMultiInst + && hasTriedInstantiation(pv)) { return false; } @@ -866,7 +869,7 @@ bool CegInstantiator::constructInstantiation(SolvedForm& sf, { lits.insert(lit); Node plit; - if (options::cegqiRepeatLit() || !isSolvedAssertion(lit)) + if (options().quantifiers.cegqiRepeatLit || !isSolvedAssertion(lit)) { plit = vinst->hasProcessAssertion(this, sf, pv, lit, d_effort); } @@ -892,7 +895,8 @@ bool CegInstantiator::constructInstantiation(SolvedForm& sf, { return true; } - else if (!options::cegqiMultiInst() && hasTriedInstantiation(pv)) + else if (!options().quantifiers.cegqiMultiInst + && hasTriedInstantiation(pv)) { return false; } @@ -1072,7 +1076,7 @@ bool CegInstantiator::doAddInstantiation(std::vector<Node>& vars, Node n = it->second; Trace("cegqi-inst-debug") << " " << d_input_vars[i] << " -> " << n << std::endl; - Assert(n.getType().isSubtypeOf(d_input_vars[i].getType())); + Assert(n.getType().isComparableTo(d_input_vars[i].getType())); subs.push_back( n ); } } @@ -1084,7 +1088,7 @@ bool CegInstantiator::doAddInstantiation(std::vector<Node>& vars, Node v = d_input_vars[i]; Trace("cegqi-inst") << i << " (" << d_curr_iphase[v] << ") : " << v << " -> " << subs[i] << std::endl; - Assert(subs[i].getType().isSubtypeOf(v.getType())); + Assert(subs[i].getType().isComparableTo(v.getType())); } } Trace("cegqi-inst-debug") << "Do the instantiation...." << std::endl; diff --git a/src/theory/quantifiers/cegqi/inst_strategy_cegqi.cpp b/src/theory/quantifiers/cegqi/inst_strategy_cegqi.cpp index 339524d94..6340e2a2a 100644 --- a/src/theory/quantifiers/cegqi/inst_strategy_cegqi.cpp +++ b/src/theory/quantifiers/cegqi/inst_strategy_cegqi.cpp @@ -63,12 +63,12 @@ InstStrategyCegqi::InstStrategyCegqi(Env& env, d_small_const(d_small_const_multiplier) { d_check_vts_lemma_lc = false; - if (options::cegqiBv()) + if (options().quantifiers.cegqiBv) { // if doing instantiation for BV, need the inverter class d_bv_invert.reset(new BvInverter); } - if (options::cegqiNestedQE()) + if (options().quantifiers.cegqiNestedQE) { d_nestedQe.reset(new NestedQe(d_env)); } @@ -225,7 +225,8 @@ void InstStrategyCegqi::reset_round(Theory::Effort effort) } //refinement: only consider innermost active quantified formulas - if( options::cegqiInnermost() ){ + if (options().quantifiers.cegqiInnermost) + { if( !d_children_quant.empty() && !d_active_quant.empty() ){ Trace("cegqi-debug") << "Find non-innermost quantifiers..." << std::endl; std::vector< Node > ninner; @@ -297,10 +298,14 @@ void InstStrategyCegqi::check(Theory::Effort e, QEffort quant_e) bool InstStrategyCegqi::checkComplete(IncompleteId& incId) { - if( ( !options::cegqiSat() && d_cbqi_set_quant_inactive ) || d_incomplete_check ){ + if ((!options().quantifiers.cegqiSat && d_cbqi_set_quant_inactive) + || d_incomplete_check) + { incId = IncompleteId::QUANTIFIERS_CEGQI; return false; - }else{ + } + else + { return true; } } diff --git a/src/theory/quantifiers/conjecture_generator.cpp b/src/theory/quantifiers/conjecture_generator.cpp index d778a679e..2c6419de1 100644 --- a/src/theory/quantifiers/conjecture_generator.cpp +++ b/src/theory/quantifiers/conjecture_generator.cpp @@ -279,7 +279,7 @@ Node ConjectureGenerator::getUniversalRepresentative(TNode n, bool add) Assert(eqt.getType() == tn); registerPattern(eqt, tn); if (isUniversalLessThan(eqt, t) - || (options::conjectureUeeIntro() + || (options().quantifiers.conjectureUeeIntro && d_pattern_fun_sum[t] >= d_pattern_fun_sum[eqt])) { setUniversalRelevant(eqt); @@ -344,12 +344,13 @@ bool ConjectureGenerator::needsCheck( Theory::Effort e ) { } bool ConjectureGenerator::hasEnumeratedUf( Node n ) { - if( options::conjectureGenGtEnum()>0 ){ + if (options().quantifiers.conjectureGenGtEnum > 0) + { std::map< Node, bool >::iterator it = d_uf_enum.find( n.getOperator() ); if( it==d_uf_enum.end() ){ d_uf_enum[n.getOperator()] = true; std::vector< Node > lem; - getEnumeratePredUfTerm( n, options::conjectureGenGtEnum(), lem ); + getEnumeratePredUfTerm(n, options().quantifiers.conjectureGenGtEnum, lem); if( !lem.empty() ){ for (const Node& l : lem) { @@ -665,7 +666,7 @@ void ConjectureGenerator::check(Theory::Effort e, QEffort quant_e) std::vector< TypeNode > rt_types; std::map< TypeNode, std::map< int, std::vector< Node > > > conj_lhs; unsigned addedLemmas = 0; - unsigned maxDepth = options::conjectureGenMaxDepth(); + unsigned maxDepth = options().quantifiers.conjectureGenMaxDepth; for( unsigned depth=1; depth<=maxDepth; depth++ ){ Trace("sg-proc") << "Generate relevant LHS at depth " << depth << "..." << std::endl; Trace("sg-rel-term") << "Relevant terms of depth " << depth << " : " << std::endl; @@ -676,7 +677,9 @@ void ConjectureGenerator::check(Theory::Effort e, QEffort quant_e) while( d_tge.getNextTerm() ){ //construct term Node nn = d_tge.getTerm(); - if( !options::conjectureFilterCanonical() || considerTermCanon( nn, true ) ){ + if (!options().quantifiers.conjectureFilterCanonical + || considerTermCanon(nn, true)) + { rel_term_count++; Trace("sg-rel-term") << "*** Relevant term : "; d_tge.debugPrint( "sg-rel-term", "sg-rel-term-debug2" ); @@ -771,7 +774,9 @@ void ConjectureGenerator::check(Theory::Effort e, QEffort quant_e) } } Trace("sg-gen-tg-debug") << "...done build substitutions for ground EQC" << std::endl; - }else{ + } + else + { Trace("sg-gen-tg-debug") << "> not canonical : " << nn << std::endl; } } @@ -827,7 +832,9 @@ void ConjectureGenerator::check(Theory::Effort e, QEffort quant_e) //consider against all LHS up to depth if( rdepth==depth ){ for( unsigned lhs_depth = 1; lhs_depth<=depth; lhs_depth++ ){ - if( (int)addedLemmas<options::conjectureGenPerRound() ){ + if ((int)addedLemmas + < options().quantifiers.conjectureGenPerRound) + { Trace("sg-proc") << "Consider conjectures at depth (" << lhs_depth << ", " << rdepth << ")..." << std::endl; for( std::map< TypeNode, std::vector< Node > >::iterator it = conj_rhs.begin(); it != conj_rhs.end(); ++it ){ for( unsigned j=0; j<it->second.size(); j++ ){ @@ -840,11 +847,13 @@ void ConjectureGenerator::check(Theory::Effort e, QEffort quant_e) } } } - if( (int)addedLemmas>=options::conjectureGenPerRound() ){ + if ((int)addedLemmas >= options().quantifiers.conjectureGenPerRound) + { break; } } - if( (int)addedLemmas>=options::conjectureGenPerRound() ){ + if ((int)addedLemmas >= options().quantifiers.conjectureGenPerRound) + { break; } } @@ -887,7 +896,8 @@ void ConjectureGenerator::check(Theory::Effort e, QEffort quant_e) unsigned ConjectureGenerator::flushWaitingConjectures( unsigned& addedLemmas, int ldepth, int rdepth ) { if( !d_waiting_conjectures_lhs.empty() ){ Trace("sg-proc") << "Generated " << d_waiting_conjectures_lhs.size() << " conjectures at depth " << ldepth << "/" << rdepth << "." << std::endl; - if( (int)addedLemmas<options::conjectureGenPerRound() ){ + if ((int)addedLemmas < options().quantifiers.conjectureGenPerRound) + { /* std::vector< unsigned > indices; for( unsigned i=0; i<d_waiting_conjectures_lhs.size(); i++ ){ @@ -908,9 +918,14 @@ unsigned ConjectureGenerator::flushWaitingConjectures( unsigned& addedLemmas, in //we have determined a relevant subgoal Node lhs = d_waiting_conjectures_lhs[i]; Node rhs = d_waiting_conjectures_rhs[i]; - if( options::conjectureFilterCanonical() && ( getUniversalRepresentative( lhs )!=lhs || getUniversalRepresentative( rhs )!=rhs ) ){ + if (options().quantifiers.conjectureFilterCanonical + && (getUniversalRepresentative(lhs) != lhs + || getUniversalRepresentative(rhs) != rhs)) + { //skip - }else{ + } + else + { Trace("sg-engine") << "*** Consider conjecture : " << lhs << " == " << rhs << std::endl; Trace("sg-engine-debug") << " score : " << d_waiting_conjectures_score[i] << std::endl; if( optStatsOnly() ){ @@ -942,7 +957,9 @@ unsigned ConjectureGenerator::flushWaitingConjectures( unsigned& addedLemmas, in InferenceId::QUANTIFIERS_CONJ_GEN_SPLIT); d_qim.addPendingPhaseRequirement(rsg, false); addedLemmas++; - if( (int)addedLemmas>=options::conjectureGenPerRound() ){ + if ((int)addedLemmas + >= options().quantifiers.conjectureGenPerRound) + { break; } } @@ -1304,10 +1321,12 @@ int ConjectureGenerator::considerCandidateConjecture( TNode lhs, TNode rhs ) { return -1; } } - //check if canonical representation (should be, but for efficiency this is not guarenteed) - //if( options::conjectureFilterCanonical() && ( getUniversalRepresentative( lhs )!=lhs || getUniversalRepresentative( rhs )!=rhs ) ){ - // Trace("sg-cconj") << " -> after processing, not canonical." << std::endl; - // return -1; + // check if canonical representation (should be, but for efficiency this is + // not guarenteed) if( options().quantifiers.conjectureFilterCanonical && ( + // getUniversalRepresentative( lhs )!=lhs || getUniversalRepresentative( rhs + // )!=rhs ) ){ + // Trace("sg-cconj") << " -> after processing, not canonical." << + // std::endl; return -1; //} int score; @@ -1315,7 +1334,8 @@ int ConjectureGenerator::considerCandidateConjecture( TNode lhs, TNode rhs ) { Trace("sg-cconj") << "Consider possible candidate conjecture : " << lhs << " == " << rhs << "?" << std::endl; //find witness for counterexample, if possible - if( options::conjectureFilterModel() ){ + if (options().quantifiers.conjectureFilterModel) + { Assert(d_rel_pattern_var_sum.find(lhs) != d_rel_pattern_var_sum.end()); Trace("sg-cconj-debug") << "Notify substitutions over " << d_rel_pattern_var_sum[lhs] << " variables." << std::endl; std::map< TNode, TNode > subs; @@ -1342,7 +1362,9 @@ int ConjectureGenerator::considerCandidateConjecture( TNode lhs, TNode rhs ) { for( std::map< TNode, std::vector< TNode > >::iterator it = d_subs_confirmWitnessDomain.begin(); it != d_subs_confirmWitnessDomain.end(); ++it ){ Trace("sg-cconj") << " #witnesses for " << it->first << " : " << it->second.size() << std::endl; } - }else{ + } + else + { score = 1; } diff --git a/src/theory/quantifiers/ematching/ho_trigger.cpp b/src/theory/quantifiers/ematching/ho_trigger.cpp index d2b0b0542..f6d245fd9 100644 --- a/src/theory/quantifiers/ematching/ho_trigger.cpp +++ b/src/theory/quantifiers/ematching/ho_trigger.cpp @@ -205,7 +205,7 @@ uint64_t HigherOrderTrigger::addInstantiations() bool HigherOrderTrigger::sendInstantiation(std::vector<Node>& m, InferenceId id) { - if (options::hoMatching()) + if (options().quantifiers.hoMatching) { // get substitution corresponding to m std::vector<TNode> vars; @@ -342,7 +342,7 @@ bool HigherOrderTrigger::sendInstantiation(std::vector<Node>& m, InferenceId id) // value at this argument position d_arg_vector[vnum][index].push_back(bv_at_index); d_arg_vector[vnum][index].push_back(itf->second); - if (!options::hoMatchingVarArgPriority()) + if (!options().quantifiers.hoMatchingVarArgPriority) { std::reverse(d_arg_vector[vnum][index].begin(), d_arg_vector[vnum][index].end()); diff --git a/src/theory/quantifiers/equality_query.cpp b/src/theory/quantifiers/equality_query.cpp index 30d223b2a..2c5dd73d1 100644 --- a/src/theory/quantifiers/equality_query.cpp +++ b/src/theory/quantifiers/equality_query.cpp @@ -51,7 +51,8 @@ Node EqualityQuery::getInternalRepresentative(Node a, Node q, size_t index) { Assert(q.isNull() || q.getKind() == FORALL); Node r = d_qstate.getRepresentative(a); - if( options::finiteModelFind() ){ + if (options().quantifiers.finiteModelFind) + { if( r.isConst() && quantifiers::TermUtil::containsUninterpretedConstant( r ) ){ //map back from values assigned by model, if any if (d_model != nullptr) @@ -72,7 +73,7 @@ Node EqualityQuery::getInternalRepresentative(Node a, Node q, size_t index) } } TypeNode v_tn = q.isNull() ? a.getType() : q[0][index].getType(); - if (options::quantRepMode() == options::QuantRepMode::EE) + if (options().quantifiers.quantRepMode == options::QuantRepMode::EE) { int32_t score = getRepScore(r, q, index, v_tn); if (score >= 0) @@ -166,23 +167,28 @@ Node EqualityQuery::getInstance(Node n, //-2 : invalid, -1 : undesired, otherwise : smaller the score, the better int32_t EqualityQuery::getRepScore(Node n, Node q, size_t index, TypeNode v_tn) { - if( options::cegqi() && quantifiers::TermUtil::hasInstConstAttr(n) ){ //reject + if (options().quantifiers.cegqi && quantifiers::TermUtil::hasInstConstAttr(n)) + { // reject return -2; - }else if( !n.getType().isSubtypeOf( v_tn ) ){ //reject if incorrect type + } + else if (!n.getType().isSubtypeOf(v_tn)) + { // reject if incorrect type return -2; - }else if( options::instMaxLevel()!=-1 ){ + } + else if (options().quantifiers.instMaxLevel != -1) + { //score prefer lowest instantiation level if( n.hasAttribute(InstLevelAttribute()) ){ return n.getAttribute(InstLevelAttribute()); } - return options::instLevelInputOnly() ? -1 : 0; + return options().quantifiers.instLevelInputOnly ? -1 : 0; } - else if (options::quantRepMode() == options::QuantRepMode::FIRST) + else if (options().quantifiers.quantRepMode == options::QuantRepMode::FIRST) { // score prefers earliest use of this term as a representative return d_rep_score.find(n) == d_rep_score.end() ? -1 : d_rep_score[n]; } - Assert(options::quantRepMode() == options::QuantRepMode::DEPTH); + Assert(options().quantifiers.quantRepMode == options::QuantRepMode::DEPTH); return quantifiers::TermUtil::getTermDepth(n); } diff --git a/src/theory/quantifiers/instantiate.cpp b/src/theory/quantifiers/instantiate.cpp index f47a71926..23f789f4e 100644 --- a/src/theory/quantifiers/instantiate.cpp +++ b/src/theory/quantifiers/instantiate.cpp @@ -152,7 +152,7 @@ bool Instantiate::addInstantiation(Node q, << std::endl; bad_inst = true; } - else if (options::cegqi()) + else if (options().quantifiers.cegqi) { Node icf = TermUtil::getInstConstAttr(terms[i]); if (!icf.isNull()) @@ -198,7 +198,7 @@ bool Instantiate::addInstantiation(Node q, // lead to very small gains). // check for positive entailment - if (options::instNoEntail()) + if (options().quantifiers.instNoEntail) { // should check consistency of equality engine // (if not aborting on utility's reset) @@ -216,7 +216,7 @@ bool Instantiate::addInstantiation(Node q, } // check based on instantiation level - if (options::instMaxLevel() != -1) + if (options().quantifiers.instMaxLevel != -1) { TermDb* tdb = d_treg.getTermDatabase(); for (Node& t : terms) @@ -362,7 +362,7 @@ bool Instantiate::addInstantiation(Node q, } } } - if (options::instMaxLevel() != -1) + if (options().quantifiers.instMaxLevel != -1) { if (doVts) { @@ -447,7 +447,7 @@ bool Instantiate::addInstantiationExpFail(Node q, // check whether we are still redundant bool success = false; // check entailment, only if option is set - if (options::instNoEntail()) + if (options().quantifiers.instNoEntail) { Trace("inst-exp-fail") << " check entailment" << std::endl; success = echeck->isEntailed(q[1], subs, false, true); @@ -505,7 +505,7 @@ bool Instantiate::existsInstantiation(Node q, const std::vector<Node>& terms, bool modEq) { - if (options::incrementalSolving()) + if (options().base.incrementalSolving) { std::map<Node, CDInstMatchTrie*>::iterator it = d_c_inst_match_trie.find(q); if (it != d_c_inst_match_trie.end()) @@ -593,7 +593,7 @@ Node Instantiate::getInstantiation(Node q, bool Instantiate::recordInstantiationInternal(Node q, const std::vector<Node>& terms) { - if (options::incrementalSolving()) + if (options().base.incrementalSolving) { Trace("inst-add-debug") << "Adding into context-dependent inst trie" << std::endl; @@ -612,7 +612,7 @@ bool Instantiate::recordInstantiationInternal(Node q, bool Instantiate::removeInstantiationInternal(Node q, const std::vector<Node>& terms) { - if (options::incrementalSolving()) + if (options().base.incrementalSolving) { std::map<Node, CDInstMatchTrie*>::iterator it = d_c_inst_match_trie.find(q); if (it != d_c_inst_match_trie.end()) @@ -637,8 +637,7 @@ void Instantiate::getInstantiatedQuantifiedFormulas(std::vector<Node>& qs) const void Instantiate::getInstantiationTermVectors( Node q, std::vector<std::vector<Node> >& tvecs) { - - if (options::incrementalSolving()) + if (options().base.incrementalSolving) { std::map<Node, CDInstMatchTrie*>::const_iterator it = d_c_inst_match_trie.find(q); @@ -661,7 +660,7 @@ void Instantiate::getInstantiationTermVectors( void Instantiate::getInstantiationTermVectors( std::map<Node, std::vector<std::vector<Node> > >& insts) { - if (options::incrementalSolving()) + if (options().base.incrementalSolving) { for (const auto& t : d_c_inst_match_trie) { @@ -709,7 +708,7 @@ void Instantiate::notifyEndRound() } if (d_env.isOutputOn(options::OutputTag::INST)) { - bool req = !options::printInstFull(); + bool req = !options().printer.printInstFull; for (std::pair<const Node, uint32_t>& i : d_instDebugTemp) { Node name; diff --git a/src/theory/quantifiers/sygus/sygus_interpol.cpp b/src/theory/quantifiers/sygus/sygus_interpol.cpp index 1a42ec337..3e1a5b34c 100644 --- a/src/theory/quantifiers/sygus/sygus_interpol.cpp +++ b/src/theory/quantifiers/sygus/sygus_interpol.cpp @@ -99,21 +99,22 @@ void SygusInterpol::getIncludeCons( std::map<TypeNode, std::unordered_set<Node>>& result) { NodeManager* nm = NodeManager::currentNM(); - Assert(options::produceInterpols() != options::ProduceInterpols::NONE); + Assert(options().smt.produceInterpols != options::ProduceInterpols::NONE); // ASSUMPTIONS - if (options::produceInterpols() == options::ProduceInterpols::ASSUMPTIONS) + if (options().smt.produceInterpols == options::ProduceInterpols::ASSUMPTIONS) { Node tmpAssumptions = (axioms.size() == 1 ? axioms[0] : nm->mkNode(kind::AND, axioms)); expr::getOperatorsMap(tmpAssumptions, result); } // CONJECTURE - else if (options::produceInterpols() == options::ProduceInterpols::CONJECTURE) + else if (options().smt.produceInterpols + == options::ProduceInterpols::CONJECTURE) { expr::getOperatorsMap(conj, result); } // SHARED - else if (options::produceInterpols() == options::ProduceInterpols::SHARED) + else if (options().smt.produceInterpols == options::ProduceInterpols::SHARED) { // Get operators from axioms std::map<TypeNode, std::unordered_set<Node>> include_cons_axioms; @@ -153,7 +154,7 @@ void SygusInterpol::getIncludeCons( } } // ALL - else if (options::produceInterpols() == options::ProduceInterpols::ALL) + else if (options().smt.produceInterpols == options::ProduceInterpols::ALL) { Node tmpAssumptions = (axioms.size() == 1 ? axioms[0] : nm->mkNode(kind::AND, axioms)); diff --git a/src/theory/quantifiers/sygus/sygus_unif_rl.cpp b/src/theory/quantifiers/sygus/sygus_unif_rl.cpp index 5af838354..b3033aedb 100644 --- a/src/theory/quantifiers/sygus/sygus_unif_rl.cpp +++ b/src/theory/quantifiers/sygus/sygus_unif_rl.cpp @@ -188,10 +188,8 @@ Node SygusUnifRl::purifyLemma(Node n, // Build purified head with fresh skolem and recreate node std::stringstream ss; ss << nb[0] << "_" << d_cand_to_hd_count[nb[0]]++; - Node new_f = sm->mkDummySkolem(ss.str(), - nb[0].getType(), - "head of unif evaluation point", - NodeManager::SKOLEM_EXACT_NAME); + Node new_f = sm->mkDummySkolem( + ss.str(), nb[0].getType(), "head of unif evaluation point"); // Adds new enumerator to map from candidate Trace("sygus-unif-rl-purify") << "...new enum " << new_f << " for candidate " << nb[0] << "\n"; diff --git a/src/theory/quantifiers/sygus/synth_conjecture.cpp b/src/theory/quantifiers/sygus/synth_conjecture.cpp index 805f19b34..6c3f5e70b 100644 --- a/src/theory/quantifiers/sygus/synth_conjecture.cpp +++ b/src/theory/quantifiers/sygus/synth_conjecture.cpp @@ -73,15 +73,16 @@ SynthConjecture::SynthConjecture(Env& env, d_repair_index(0), d_guarded_stream_exc(false) { - if (options::sygusSymBreakPbe() || options::sygusUnifPbe()) + if (options().datatypes.sygusSymBreakPbe + || options().quantifiers.sygusUnifPbe) { d_modules.push_back(d_ceg_pbe.get()); } - if (options::sygusUnifPi() != options::SygusUnifPiMode::NONE) + if (options().quantifiers.sygusUnifPi != options::SygusUnifPiMode::NONE) { d_modules.push_back(d_ceg_cegisUnif.get()); } - if (options::sygusCoreConnective()) + if (options().quantifiers.sygusCoreConnective) { d_modules.push_back(d_sygus_ccore.get()); } @@ -202,10 +203,10 @@ void SynthConjecture::assign(Node q) Trace("cegqi") << "Base instantiation is : " << d_base_inst << std::endl; // initialize the sygus constant repair utility - if (options::sygusRepairConst()) + if (options().quantifiers.sygusRepairConst) { d_sygus_rconst->initialize(d_base_inst.negate(), d_candidates); - if (options::sygusConstRepairAbort()) + if (options().quantifiers.sygusConstRepairAbort) { if (!d_sygus_rconst->isActive()) { @@ -337,7 +338,7 @@ bool SynthConjecture::doCheck() // sygusRepairConst is true, we use a default scheme for trying to repair // constants here. bool doRepairConst = - options::sygusRepairConst() && !d_master->usingRepairConst(); + options().quantifiers.sygusRepairConst && !d_master->usingRepairConst(); if (doRepairConst) { // have we tried to repair the previous solution? @@ -502,7 +503,7 @@ bool SynthConjecture::doCheck() } // if we trust the sampling we ran, we terminate now - if (options::cegisSample() == options::CegisSampleMode::TRUST) + if (options().quantifiers.cegisSample == options::CegisSampleMode::TRUST) { // we have that the current candidate passed a sample test // since we trust sampling in this mode, we assert there is no @@ -565,7 +566,7 @@ bool SynthConjecture::doCheck() // now mark that we have a solution d_hasSolution = true; - if (options::sygusStream()) + if (options().quantifiers.sygusStream) { // immediately print the current solution printAndContinueStream(terms, candidate_values); @@ -805,10 +806,10 @@ void SynthConjecture::printSynthSolutionInternal(std::ostream& out) bool is_unique_term = true; if (status != 0 - && (options::sygusRewSynth() + && (options().quantifiers.sygusRewSynth || options().quantifiers.sygusQueryGen != options::SygusQueryGenMode::NONE - || options::sygusFilterSolMode() + || options().quantifiers.sygusFilterSolMode != options::SygusFilterSolMode::NONE)) { Trace("cegqi-sol-debug") << "Run expression mining..." << std::endl; @@ -819,7 +820,7 @@ void SynthConjecture::printSynthSolutionInternal(std::ostream& out) d_exprm[prog].reset(new ExpressionMinerManager(d_env)); ExpressionMinerManager* emm = d_exprm[prog].get(); emm->initializeSygus( - d_tds, d_candidates[i], options::sygusSamples(), true); + d_tds, d_candidates[i], options().quantifiers.sygusSamples, true); emm->initializeMinersForOptions(); its = d_exprm.find(prog); } @@ -989,7 +990,7 @@ bool SynthConjecture::getSynthSolutionsInternal(std::vector<Node>& sols, Trace("cegqi-inv-debug") << sf << " used template : " << templ << std::endl; // if it was not embedded into the grammar - if (!options::sygusTemplEmbedGrammar()) + if (!options().quantifiers.sygusTemplEmbedGrammar) { TNode templa = d_templInfer->getTemplateArg(sf); // make the builtin version of the full solution diff --git a/src/theory/quantifiers/term_registry.cpp b/src/theory/quantifiers/term_registry.cpp index d11fb0b8d..5cefb4275 100644 --- a/src/theory/quantifiers/term_registry.cpp +++ b/src/theory/quantifiers/term_registry.cpp @@ -44,14 +44,15 @@ TermRegistry::TermRegistry(Env& env, d_sygusTdb(nullptr), d_qmodel(nullptr) { - if (options::sygus() || options::sygusInst()) + if (options().quantifiers.sygus || options().quantifiers.sygusInst) { // must be constructed here since it is required for datatypes finistInit d_sygusTdb.reset(new TermDbSygus(env, qs)); } Trace("quant-engine-debug") << "Initialize quantifiers engine." << std::endl; Trace("quant-engine-debug") - << "Initialize model, mbqi : " << options::mbqiMode() << std::endl; + << "Initialize model, mbqi : " << options().quantifiers.mbqiMode + << std::endl; } void TermRegistry::finishInit(FirstOrderModel* fm, @@ -69,7 +70,7 @@ void TermRegistry::presolve() { d_presolve = false; // add all terms to database - if (options::incrementalSolving() && !options::termDbCd()) + if (options().base.incrementalSolving && !options().quantifiers.termDbCd) { Trace("quant-engine-proc") << "Add presolve cache " << d_presolveCache.size() << std::endl; @@ -84,19 +85,20 @@ void TermRegistry::presolve() void TermRegistry::addTerm(Node n, bool withinQuant) { // don't add terms in quantifier bodies - if (withinQuant && !options::registerQuantBodyTerms()) + if (withinQuant && !options().quantifiers.registerQuantBodyTerms) { return; } - if (options::incrementalSolving() && !options::termDbCd()) + if (options().base.incrementalSolving && !options().quantifiers.termDbCd) { d_presolveCache.insert(n); } // only wait if we are doing incremental solving - if (!d_presolve || !options::incrementalSolving() || options::termDbCd()) + if (!d_presolve || !options().base.incrementalSolving + || options().quantifiers.termDbCd) { d_termDb->addTerm(n); - if (d_sygusTdb.get() && options::sygusEvalUnfold()) + if (d_sygusTdb.get() && options().quantifiers.sygusEvalUnfold) { d_sygusTdb->getEvalUnfold()->registerEvalTerm(n); } diff --git a/src/theory/quantifiers_engine.cpp b/src/theory/quantifiers_engine.cpp index e0863f953..1098cd9fe 100644 --- a/src/theory/quantifiers_engine.cpp +++ b/src/theory/quantifiers_engine.cpp @@ -64,15 +64,15 @@ QuantifiersEngine::QuantifiersEngine( d_numInstRoundsLemma(0) { Trace("quant-init-debug") - << "Initialize model engine, mbqi : " << options::mbqiMode() << " " - << options::fmfBound() << std::endl; + << "Initialize model engine, mbqi : " << options().quantifiers.mbqiMode + << " " << options().quantifiers.fmfBound << std::endl; // Finite model finding requires specialized ways of building the model. // We require constructing the model here, since it is required for // initializing the CombinationEngine and the rest of quantifiers engine. - if (options::fmfBound() || options::stringExp() - || (options::finiteModelFind() - && (options::mbqiMode() == options::MbqiMode::FMC - || options::mbqiMode() == options::MbqiMode::TRUST))) + if (options().quantifiers.fmfBound || options().strings.stringExp + || (options().quantifiers.finiteModelFind + && (options().quantifiers.mbqiMode == options::MbqiMode::FMC + || options().quantifiers.mbqiMode == options::MbqiMode::TRUST))) { Trace("quant-init-debug") << "...make fmc builder." << std::endl; d_builder.reset( @@ -168,14 +168,15 @@ void QuantifiersEngine::ppNotifyAssertions( Trace("quant-engine-proc") << "ppNotifyAssertions in QE, #assertions = " << assertions.size() << std::endl; - if (options::instLevelInputOnly() && options::instMaxLevel() != -1) + if (options().quantifiers.instLevelInputOnly + && options().quantifiers.instMaxLevel != -1) { for (const Node& a : assertions) { quantifiers::QuantAttributes::setInstantiationLevelAttr(a, 0); } } - if (options::sygus()) + if (options().quantifiers.sygus) { quantifiers::SynthEngine* sye = d_qmodules->d_synth_e.get(); for (const Node& a : assertions) @@ -186,7 +187,7 @@ void QuantifiersEngine::ppNotifyAssertions( /* The SyGuS instantiation module needs a global view of all available * assertions to collect global terms that get added to each grammar. */ - if (options::sygusInst()) + if (options().quantifiers.sygusInst) { quantifiers::SygusInst* si = d_qmodules->d_sygus_inst.get(); si->ppNotifyAssertions(assertions); @@ -250,8 +251,9 @@ void QuantifiersEngine::check( Theory::Effort e ){ d_qim.reset(); bool setIncomplete = false; IncompleteId setIncompleteId = IncompleteId::QUANTIFIERS; - if (options::instMaxRounds() >= 0 - && d_numInstRoundsLemma >= static_cast<uint32_t>(options::instMaxRounds())) + if (options().quantifiers.instMaxRounds >= 0 + && d_numInstRoundsLemma + >= static_cast<uint32_t>(options().quantifiers.instMaxRounds)) { needsCheck = false; setIncomplete = true; diff --git a/src/theory/sets/cardinality_extension.cpp b/src/theory/sets/cardinality_extension.cpp index 4e4ee78a8..d2d7a636a 100644 --- a/src/theory/sets/cardinality_extension.cpp +++ b/src/theory/sets/cardinality_extension.cpp @@ -162,7 +162,7 @@ void CardinalityExtension::checkCardinalityExtended(TypeNode& t) Node subset = nm->mkNode(kind::SUBSET, variable, proxy); // subset terms are rewritten as union terms: (subset A B) implies (= // (union A B) B) - subset = Rewriter::rewrite(subset); + subset = rewrite(subset); if (!d_state.isEntailed(subset, true)) { d_im.assertInference( @@ -242,7 +242,7 @@ void CardinalityExtension::checkRegister() // if setminus, do for intersection instead if (n.getKind() == SETMINUS) { - n = Rewriter::rewrite(nm->mkNode(INTERSECTION, n[0], n[1])); + n = rewrite(nm->mkNode(INTERSECTION, n[0], n[1])); } registerCardinalityTerm(n); } @@ -293,7 +293,7 @@ void CardinalityExtension::registerCardinalityTerm(Node n) if (nn != nk) { Node lem = nm->mkNode(EQUAL, nm->mkNode(CARD, nk), nm->mkNode(CARD, nn)); - lem = Rewriter::rewrite(lem); + lem = rewrite(lem); Trace("sets-card") << " " << k << " : " << lem << std::endl; d_im.assertInference(lem, InferenceId::SETS_CARD_EQUAL, d_emp_exp, 1); } @@ -393,21 +393,21 @@ void CardinalityExtension::checkCardCyclesRec(Node eqc, d_localBase[n] = n; for (unsigned e = 0; e < 2; e++) { - Node sm = Rewriter::rewrite(nm->mkNode(SETMINUS, n[e], n[1 - e])); + Node sm = rewrite(nm->mkNode(SETMINUS, n[e], n[1 - e])); sib.push_back(sm); } true_sib = 2; } else { - Node si = Rewriter::rewrite(nm->mkNode(INTERSECTION, n[0], n[1])); + Node si = rewrite(nm->mkNode(INTERSECTION, n[0], n[1])); sib.push_back(si); d_localBase[n] = si; - Node osm = Rewriter::rewrite(nm->mkNode(SETMINUS, n[1], n[0])); + Node osm = rewrite(nm->mkNode(SETMINUS, n[1], n[0])); sib.push_back(osm); true_sib = 1; } - Node u = Rewriter::rewrite(nm->mkNode(UNION, n[0], n[1])); + Node u = rewrite(nm->mkNode(UNION, n[0], n[1])); if (!d_state.hasTerm(u)) { u = Node::null(); @@ -837,8 +837,7 @@ void CardinalityExtension::checkNormalForm(Node eqc, Assert(o0 != o1); Node kca = d_treg.getProxy(o0); Node kcb = d_treg.getProxy(o1); - Node intro = - Rewriter::rewrite(nm->mkNode(INTERSECTION, kca, kcb)); + Node intro = rewrite(nm->mkNode(INTERSECTION, kca, kcb)); Trace("sets-nf") << " Intro split : " << o0 << " against " << o1 << ", term is " << intro << std::endl; intro_sets.push_back(intro); diff --git a/src/theory/sets/inference_manager.cpp b/src/theory/sets/inference_manager.cpp index 15c4fd405..96705c029 100644 --- a/src/theory/sets/inference_manager.cpp +++ b/src/theory/sets/inference_manager.cpp @@ -35,7 +35,7 @@ InferenceManager::InferenceManager(Env& env, Theory& t, SolverState& s) bool InferenceManager::assertFactRec(Node fact, InferenceId id, Node exp, int inferType) { // should we send this fact out as a lemma? - if ((options::setsInferAsLemmas() && inferType != -1) || inferType == 1) + if ((options().sets.setsInferAsLemmas && inferType != -1) || inferType == 1) { if (d_state.isEntailed(fact, true)) { @@ -172,7 +172,7 @@ void InferenceManager::assertInference(std::vector<Node>& conc, void InferenceManager::split(Node n, InferenceId id, int reqPol) { - n = Rewriter::rewrite(n); + n = rewrite(n); Node lem = NodeManager::currentNM()->mkNode(OR, n, n.negate()); // send the lemma lemma(lem, id); diff --git a/src/theory/sets/skolem_cache.cpp b/src/theory/sets/skolem_cache.cpp index f759c2a7b..646ae1662 100644 --- a/src/theory/sets/skolem_cache.cpp +++ b/src/theory/sets/skolem_cache.cpp @@ -24,14 +24,16 @@ namespace cvc5 { namespace theory { namespace sets { -SkolemCache::SkolemCache() {} +SkolemCache::SkolemCache(Rewriter* rr) : d_rewriter(rr) {} Node SkolemCache::mkTypedSkolemCached( TypeNode tn, Node a, Node b, SkolemId id, const char* c) { - a = a.isNull() ? a : Rewriter::rewrite(a); - b = b.isNull() ? b : Rewriter::rewrite(b); - + if (d_rewriter != nullptr) + { + a = a.isNull() ? a : d_rewriter->rewrite(a); + b = b.isNull() ? b : d_rewriter->rewrite(b); + } std::map<SkolemId, Node>::iterator it = d_skolemCache[a][b].find(id); if (it == d_skolemCache[a][b].end()) { diff --git a/src/theory/sets/skolem_cache.h b/src/theory/sets/skolem_cache.h index 62547a66e..a13c48f1e 100644 --- a/src/theory/sets/skolem_cache.h +++ b/src/theory/sets/skolem_cache.h @@ -25,6 +25,9 @@ namespace cvc5 { namespace theory { + +class Rewriter; + namespace sets { /** @@ -35,7 +38,7 @@ namespace sets { class SkolemCache { public: - SkolemCache(); + SkolemCache(Rewriter* rr); /** Identifiers for skolem types * * The comments below document the properties of each skolem introduced by @@ -75,6 +78,8 @@ class SkolemCache std::map<Node, std::map<Node, std::map<SkolemId, Node> > > d_skolemCache; /** the set of all skolems we have generated */ std::unordered_set<Node> d_allSkolems; + /** the optional rewriter */ + Rewriter* d_rewriter; }; } // namespace sets diff --git a/src/theory/sets/solver_state.cpp b/src/theory/sets/solver_state.cpp index 6f8976f4d..d9fb30735 100644 --- a/src/theory/sets/solver_state.cpp +++ b/src/theory/sets/solver_state.cpp @@ -113,7 +113,7 @@ void SolverState::registerTerm(Node r, TypeNode tnn, Node n) } else if (nk == UNIVERSE_SET) { - Assert(options::setsExt()); + Assert(options().sets.setsExt); d_eqc_univset[tnn] = r; } else diff --git a/src/theory/sets/theory_sets.cpp b/src/theory/sets/theory_sets.cpp index 2901703dd..3cb6c853c 100644 --- a/src/theory/sets/theory_sets.cpp +++ b/src/theory/sets/theory_sets.cpp @@ -29,7 +29,7 @@ namespace sets { TheorySets::TheorySets(Env& env, OutputChannel& out, Valuation valuation) : Theory(THEORY_SETS, env, out, valuation), - d_skCache(), + d_skCache(env.getRewriter()), d_state(env, valuation, d_skCache), d_im(env, *this, d_state), d_internal( @@ -136,7 +136,7 @@ TrustNode TheorySets::ppRewrite(TNode n, std::vector<SkolemLemma>& lems) if (nk == UNIVERSE_SET || nk == COMPLEMENT || nk == JOIN_IMAGE || nk == COMPREHENSION) { - if (!options::setsExt()) + if (!options().sets.setsExt) { std::stringstream ss; ss << "Extended set operators are not supported in default mode, try " @@ -173,7 +173,7 @@ Theory::PPAssertStatus TheorySets::ppAssert( // may appear when this option is enabled, and solving for such a set // impacts the semantics of universe set, see // regress0/sets/pre-proc-univ.smt2 - if (!in[0].getType().isSet() || !options::setsExt()) + if (!in[0].getType().isSet() || !options().sets.setsExt) { outSubstitutions.addSubstitutionSolved(in[0], in[1], tin); status = Theory::PP_ASSERT_STATUS_SOLVED; @@ -181,7 +181,7 @@ Theory::PPAssertStatus TheorySets::ppAssert( } else if (in[1].isVar() && isLegalElimination(in[1], in[0])) { - if (!in[0].getType().isSet() || !options::setsExt()) + if (!in[0].getType().isSet() || !options().sets.setsExt) { outSubstitutions.addSubstitutionSolved(in[1], in[0], tin); status = Theory::PP_ASSERT_STATUS_SOLVED; diff --git a/src/theory/sets/theory_sets_private.cpp b/src/theory/sets/theory_sets_private.cpp index 2164c26b0..a87466fab 100644 --- a/src/theory/sets/theory_sets_private.cpp +++ b/src/theory/sets/theory_sets_private.cpp @@ -454,11 +454,11 @@ void TheorySetsPrivate::checkDownwardsClosure() { Trace("sets-debug") << "Downwards closure based on " << mem << ", eq_set = " << eq_set << std::endl; - if (!options::setsProxyLemmas()) + if (!options().sets.setsProxyLemmas) { Node nmem = NodeManager::currentNM()->mkNode( kind::MEMBER, mem[0], eq_set); - nmem = Rewriter::rewrite(nmem); + nmem = rewrite(nmem); std::vector<Node> exp; exp.push_back(mem); exp.push_back(mem[1].eqNode(eq_set)); @@ -476,7 +476,7 @@ void TheorySetsPrivate::checkDownwardsClosure() NodeManager::currentNM()->mkNode(kind::MEMBER, mem[0], k); Node nmem = NodeManager::currentNM()->mkNode( kind::MEMBER, mem[0], eq_set); - nmem = Rewriter::rewrite(nmem); + nmem = rewrite(nmem); std::vector<Node> exp; if (d_state.areEqual(mem, pmem)) { @@ -635,7 +635,7 @@ void TheorySetsPrivate::checkUpwardsClosure() } if (!d_im.hasSent()) { - if (options::setsExt()) + if (options().sets.setsExt) { // universal sets Trace("sets-debug") << "Check universe sets..." << std::endl; @@ -737,7 +737,7 @@ void TheorySetsPrivate::checkDisequalities() Node mem1 = nm->mkNode(MEMBER, x, deq[0]); Node mem2 = nm->mkNode(MEMBER, x, deq[1]); Node lem = nm->mkNode(OR, deq, nm->mkNode(EQUAL, mem1, mem2).negate()); - lem = Rewriter::rewrite(lem); + lem = rewrite(lem); d_im.assertInference(lem, InferenceId::SETS_DEQ, d_true, 1); d_im.doPendingLemmas(); if (d_im.hasSent()) @@ -1152,7 +1152,7 @@ bool TheorySetsPrivate::collectModelValues(TheoryModel* m, } Node rep = NormalForm::mkBop(kind::UNION, els, eqc.getType()); - rep = Rewriter::rewrite(rep); + rep = rewrite(rep); Trace("sets-model") << "* Assign representative of " << eqc << " to " << rep << std::endl; mvals[eqc] = rep; @@ -1361,7 +1361,7 @@ TrustNode TheorySetsPrivate::expandIsSingletonOperator(const Node& node) // we call the rewriter here to handle the pattern // (is_singleton (singleton x)) because the rewriter is called after expansion - Node rewritten = Rewriter::rewrite(node); + Node rewritten = rewrite(node); if (rewritten.getKind() != IS_SINGLETON) { return TrustNode::mkTrustRewrite(node, rewritten, nullptr); @@ -1407,8 +1407,7 @@ Node TheorySetsPrivate::getChooseFunction(const TypeNode& setType) stringstream stream; stream << "chooseUf" << setType.getId(); string name = stream.str(); - Node chooseSkolem = sm->mkDummySkolem( - name, chooseUf, "choose function", NodeManager::SKOLEM_EXACT_NAME); + Node chooseSkolem = sm->mkDummySkolem(name, chooseUf, "choose function"); d_chooseFunctions[setType] = chooseSkolem; return chooseSkolem; } diff --git a/src/theory/sets/theory_sets_rels.cpp b/src/theory/sets/theory_sets_rels.cpp index a4028d8fb..57a70f80a 100644 --- a/src/theory/sets/theory_sets_rels.cpp +++ b/src/theory/sets/theory_sets_rels.cpp @@ -125,44 +125,61 @@ void TheorySetsRels::check(Theory::Effort level) TERM_IT t_it = d_terms_cache.begin(); while( t_it != d_terms_cache.end() ) { - if( d_rReps_memberReps_cache.find(t_it->first) == d_rReps_memberReps_cache.end() ) { - Trace("rels-debug") << "[sets-rels] A term does not have membership constraints: " << t_it->first << std::endl; - KIND_TERM_IT k_t_it = t_it->second.begin(); - - while( k_t_it != t_it->second.end() ) { - if( k_t_it->first == kind::JOIN || k_t_it->first == kind::PRODUCT ) { - std::vector<Node>::iterator term_it = k_t_it->second.begin(); - while(term_it != k_t_it->second.end()) { - computeMembersForBinOpRel( *term_it ); - ++term_it; - } - } else if( k_t_it->first == kind::TRANSPOSE ) { - std::vector<Node>::iterator term_it = k_t_it->second.begin(); - while( term_it != k_t_it->second.end() ) { - computeMembersForUnaryOpRel( *term_it ); - ++term_it; - } - } else if ( k_t_it->first == kind::TCLOSURE ) { - std::vector<Node>::iterator term_it = k_t_it->second.begin(); - while( term_it != k_t_it->second.end() ) { - buildTCGraphForRel( *term_it ); - ++term_it; - } - } else if( k_t_it->first == kind::JOIN_IMAGE ) { - std::vector<Node>::iterator term_it = k_t_it->second.begin(); - while( term_it != k_t_it->second.end() ) { - computeMembersForJoinImageTerm( *term_it ); - ++term_it; - } - } else if( k_t_it->first == kind::IDEN ) { - std::vector<Node>::iterator term_it = k_t_it->second.begin(); - while( term_it != k_t_it->second.end() ) { - computeMembersForIdenTerm( *term_it ); - ++term_it; - } + // check the terms in this equivalence class for e.g. upwards closure + // (computeMembersForBinOpRel / computeMembersForUnaryOpRel). This is + // done regardless of whether we have initialized + // d_rReps_memberReps_cache for this equivalence class. + Trace("rels-debug") + << "[sets-rels] Check equivalence class: " + << t_it->first << std::endl; + KIND_TERM_IT k_t_it = t_it->second.begin(); + + while (k_t_it != t_it->second.end()) + { + Trace("rels-debug") << "[sets-rels] Check " << k_t_it->second.size() + << " terms of kind " << k_t_it->first << std::endl; + std::vector<Node>::iterator term_it = k_t_it->second.begin(); + if (k_t_it->first == kind::JOIN || k_t_it->first == kind::PRODUCT) + { + while (term_it != k_t_it->second.end()) + { + computeMembersForBinOpRel(*term_it); + ++term_it; + } + } + else if (k_t_it->first == kind::TRANSPOSE) + { + while (term_it != k_t_it->second.end()) + { + computeMembersForUnaryOpRel(*term_it); + ++term_it; + } + } + else if (k_t_it->first == kind::TCLOSURE) + { + while (term_it != k_t_it->second.end()) + { + buildTCGraphForRel(*term_it); + ++term_it; } - ++k_t_it; } + else if (k_t_it->first == kind::JOIN_IMAGE) + { + while (term_it != k_t_it->second.end()) + { + computeMembersForJoinImageTerm(*term_it); + ++term_it; + } + } + else if (k_t_it->first == kind::IDEN) + { + while (term_it != k_t_it->second.end()) + { + computeMembersForIdenTerm(*term_it); + ++term_it; + } + } + ++k_t_it; } ++t_it; } @@ -229,24 +246,7 @@ void TheorySetsRels::check(Theory::Effort level) if( eqc_node.getKind() == kind::TRANSPOSE || eqc_node.getKind() == kind::JOIN || eqc_node.getKind() == kind::PRODUCT || eqc_node.getKind() == kind::TCLOSURE || eqc_node.getKind() == kind::JOIN_IMAGE || eqc_node.getKind() == kind::IDEN ) { - std::vector<Node> terms; - std::map< kind::Kind_t, std::vector<Node> > rel_terms; - TERM_IT terms_it = d_terms_cache.find(eqc_rep); - - if( terms_it == d_terms_cache.end() ) { - terms.push_back(eqc_node); - rel_terms[eqc_node.getKind()] = terms; - d_terms_cache[eqc_rep] = rel_terms; - } else { - KIND_TERM_IT kind_term_it = terms_it->second.find(eqc_node.getKind()); - - if( kind_term_it == terms_it->second.end() ) { - terms.push_back(eqc_node); - d_terms_cache[eqc_rep][eqc_node.getKind()] = terms; - } else { - kind_term_it->second.push_back(eqc_node); - } - } + d_terms_cache[eqc_rep][eqc_node.getKind()].push_back(eqc_node); } // need to add all tuple elements as shared terms } @@ -657,10 +657,11 @@ void TheorySetsRels::check(Theory::Effort level) Node rel_rep = getRepresentative( tc_rel[0] ); Node tc_rel_rep = getRepresentative( tc_rel ); - std::vector< Node > members = d_rReps_memberReps_cache[rel_rep]; - std::vector< Node > exps = d_rReps_memberReps_exp_cache[rel_rep]; + const std::vector<Node>& members = d_rReps_memberReps_cache[rel_rep]; + const std::vector<Node>& exps = d_rReps_memberReps_exp_cache[rel_rep]; - for( unsigned int i = 0; i < members.size(); i++ ) { + for (size_t i = 0, msize = members.size(); i < msize; i++) + { Node fst_element_rep = getRepresentative( RelsUtils::nthElementOfTuple( members[i], 0 )); Node snd_element_rep = getRepresentative( RelsUtils::nthElementOfTuple( members[i], 1 )); Node tuple_rep = RelsUtils::constructPair( rel_rep, fst_element_rep, snd_element_rep ); @@ -988,10 +989,6 @@ void TheorySetsRels::check(Theory::Effort level) default: break; } - if(d_rReps_memberReps_cache.find(getRepresentative(rel[0])) == d_rReps_memberReps_cache.end() || - d_rReps_memberReps_cache.find(getRepresentative(rel[1])) == d_rReps_memberReps_cache.end()) { - return; - } composeMembersForRels(rel); } @@ -1020,16 +1017,19 @@ void TheorySetsRels::check(Theory::Effort level) } NodeManager* nm = NodeManager::currentNM(); - std::vector<Node> members = d_rReps_memberReps_cache[rel0_rep]; - std::vector<Node> exps = d_rReps_memberReps_exp_cache[rel0_rep]; + const std::vector<Node>& members = d_rReps_memberReps_cache[rel0_rep]; + const std::vector<Node>& exps = d_rReps_memberReps_exp_cache[rel0_rep]; Assert(members.size() == exps.size()); - for(unsigned int i = 0; i < members.size(); i++) { - Node reason = exps[i]; - if( rel.getKind() == kind::TRANSPOSE) { + if (rel.getKind() == kind::TRANSPOSE) + { + for (size_t i = 0, msize = members.size(); i < msize; i++) + { + Node reason = exps[i]; if( rel[0] != exps[i][1] ) { - reason = NodeManager::currentNM()->mkNode(kind::AND, reason, NodeManager::currentNM()->mkNode(kind::EQUAL, rel[0], exps[i][1])); + reason = nm->mkNode( + kind::AND, reason, nm->mkNode(kind::EQUAL, rel[0], exps[i][1])); } sendInfer(nm->mkNode(MEMBER, RelsUtils::reverseTuple(exps[i][0]), rel), InferenceId::SETS_RELS_TRANSPOSE_REV, @@ -1043,9 +1043,9 @@ void TheorySetsRels::check(Theory::Effort level) * consider the case that (a, b) in r1, (c, d) in r2. * * For JOIN, we have three cases: - * b = c, we infer (a, d) in (join r1 r2) - * b != c, do nothing - * else, if neither holds, we add the splitting lemma (b=c or b!=c) + * if b = c, we infer (a, d) in (join r1 r2) + * else, we mark b and c as shared terms; their equality will be split in + * theory combination if necessary. * * For PRODUCT, we infer (a, b, c, d) in (product r1 r2). */ @@ -1079,6 +1079,11 @@ void TheorySetsRels::check(Theory::Effort level) Node r1_rmost = RelsUtils::nthElementOfTuple(r1_rep_exps[i][0], r1_tuple_len - 1); Node r2_lmost = RelsUtils::nthElementOfTuple(r2_rep_exps[j][0], 0); + // Since we require notification r1_rmost and r2_lmost are equal, + // they must be shared terms of theory of sets. Hence, we make the + // following calls to makeSharedTerm to ensure this is the case. + makeSharedTerm(r1_rmost, r1_rmost.getType()); + makeSharedTerm(r2_lmost, r2_lmost.getType()); Trace("rels-debug") << "[Theory::Rels] r1_rmost: " << r1_rmost << " of type " << r1_rmost.getType() << std::endl; @@ -1086,19 +1091,12 @@ void TheorySetsRels::check(Theory::Effort level) << " of type " << r2_lmost.getType() << std::endl; if (!areEqual(r1_rmost, r2_lmost)) { - if (!d_state.areDisequal(r1_rmost, r2_lmost)) - { - // If we have (a,b) in R1, (c,d) in R2, and we are considering - // join(R1, R2) must split on b=c if they are neither equal nor - // disequal. - Node eq = r1_rmost.eqNode(r2_lmost); - Node lem = nm->mkNode(kind::OR, eq, eq.negate()); - d_im.addPendingLemma(lem, InferenceId::SETS_RELS_JOIN_ELEM_SPLIT); - } + continue; } else if (r1_rmost != r2_lmost) { + Trace("rels-debug") << "...equal" << std::endl; reasons.push_back(nm->mkNode(kind::EQUAL, r1_rmost, r2_lmost)); } } @@ -1178,15 +1176,25 @@ void TheorySetsRels::check(Theory::Effort level) return true; } else if( hasTerm( a ) && hasTerm( b ) ){ return d_state.areEqual(a, b); - } else if(a.getType().isTuple()) { - bool equal = true; - for(unsigned int i = 0; i < a.getType().getTupleLength(); i++) { - equal = equal && areEqual(RelsUtils::nthElementOfTuple(a, i), RelsUtils::nthElementOfTuple(b, i)); + } + TypeNode atn = a.getType(); + if (atn.isTuple()) + { + size_t tlen = atn.getTupleLength(); + for (size_t i = 0; i < tlen; i++) + { + if (!areEqual(RelsUtils::nthElementOfTuple(a, i), + RelsUtils::nthElementOfTuple(b, i))) + { + return false; + } } - return equal; - } else if(!a.getType().isBoolean()){ + return true; + } + else if (!atn.isBoolean()) + { // TODO(project##230): Find a safe type for the singleton operator - makeSharedTerm(a, a.getType()); + makeSharedTerm(a, atn); makeSharedTerm(b, b.getType()); } return false; diff --git a/src/theory/sets/theory_sets_rels.h b/src/theory/sets/theory_sets_rels.h index 560f47482..a12a28fff 100644 --- a/src/theory/sets/theory_sets_rels.h +++ b/src/theory/sets/theory_sets_rels.h @@ -113,7 +113,7 @@ class TheorySetsRels : protected EnvObj std::map< Node, std::vector< Node > > d_rReps_memberReps_exp_cache; /** Mapping between a relation representative and its equivalent relations involving relational operators */ - std::map< Node, std::map<kind::Kind_t, std::vector<Node> > > d_terms_cache; + std::map<Node, std::map<Kind, std::vector<Node> > > d_terms_cache; /** Mapping between transitive closure relation TC(r) and its TC graph constructed based on the members of r*/ std::map<Node, std::map<Node, std::unordered_set<Node> > > d_rRep_tcGraph; diff --git a/src/theory/strings/core_solver.cpp b/src/theory/strings/core_solver.cpp index b5e15a129..0b7294f2c 100644 --- a/src/theory/strings/core_solver.cpp +++ b/src/theory/strings/core_solver.cpp @@ -2463,8 +2463,7 @@ void CoreSolver::processDeqExtensionality(Node n1, Node n2) NodeManager* nm = NodeManager::currentNM(); SkolemCache* sc = d_termReg.getSkolemCache(); TypeNode intType = nm->integerType(); - Node k = sc->mkTypedSkolemCached( - intType, n1, n2, SkolemCache::SK_DEQ_DIFF, "diff"); + Node k = sc->mkSkolemFun(SkolemFunId::STRINGS_DEQ_DIFF, intType, n1, n2); Node deq = eq.negate(); Node ss1, ss2; if (n1.getType().isString()) diff --git a/src/theory/strings/extf_solver.cpp b/src/theory/strings/extf_solver.cpp index 4b12d2673..2de9bda96 100644 --- a/src/theory/strings/extf_solver.cpp +++ b/src/theory/strings/extf_solver.cpp @@ -259,6 +259,7 @@ void ExtfSolver::checkExtfEval(int effort) { // Setup information about n, including if it is equal to a constant. ExtfInfoTmp& einfo = d_extfInfoTmp[n]; + Assert(einfo.d_exp.empty()); Node r = d_state.getRepresentative(n); einfo.d_const = d_bsolver.getConstantEqc(r); // Get the current values of the children of n. @@ -292,8 +293,8 @@ void ExtfSolver::checkExtfEval(int effort) Node sn = nm->mkNode(n.getKind(), schildren); Trace("strings-extf-debug") << "Check extf " << n << " == " << sn - << ", constant = " << einfo.d_const << ", effort=" << effort << "..." - << std::endl; + << ", constant = " << einfo.d_const << ", effort=" << effort + << ", exp " << exp << std::endl; einfo.d_exp.insert(einfo.d_exp.end(), exp.begin(), exp.end()); // inference is rewriting the substituted node Node nrc = Rewriter::rewrite(sn); @@ -490,8 +491,9 @@ void ExtfSolver::checkExtfInference(Node n, return; } NodeManager* nm = NodeManager::currentNM(); - Trace("strings-extf-infer") << "checkExtfInference: " << n << " : " << nr - << " == " << in.d_const << std::endl; + Trace("strings-extf-infer") + << "checkExtfInference: " << n << " : " << nr << " == " << in.d_const + << " with exp " << in.d_exp << std::endl; // add original to explanation if (n.getType().isBoolean()) @@ -662,8 +664,9 @@ void ExtfSolver::checkExtfInference(Node n, if (inferEqrr != inferEqr) { inferEqrr = Rewriter::rewrite(inferEqrr); - Trace("strings-extf-infer") << "checkExtfInference: " << inferEq - << " ...reduces to " << inferEqrr << std::endl; + Trace("strings-extf-infer") + << "checkExtfInference: " << inferEq << " ...reduces to " << inferEqrr + << " with explanation " << in.d_exp << std::endl; d_im.sendInternalInference(in.d_exp, inferEqrr, InferenceId::STRINGS_EXTF_EQ_REW); } } diff --git a/src/theory/strings/infer_proof_cons.cpp b/src/theory/strings/infer_proof_cons.cpp index 5eba8663a..5090b15cb 100644 --- a/src/theory/strings/infer_proof_cons.cpp +++ b/src/theory/strings/infer_proof_cons.cpp @@ -217,18 +217,35 @@ void InferProofCons::convert(InferenceId infer, Node src = ps.d_children[ps.d_children.size() - 1]; std::vector<Node> expe(ps.d_children.begin(), ps.d_children.end() - 1); // start with a default rewrite + Trace("strings-ipc-core") + << "Generate proof for STRINGS_EXTF_EQ_REW, starting with " << src + << std::endl; Node mainEqSRew = psb.applyPredElim(src, expe); + Trace("strings-ipc-core") + << "...after pred elim: " << mainEqSRew << std::endl; if (mainEqSRew == conc) { + Trace("strings-ipc-core") << "...success" << std::endl; useBuffer = true; break; } + else if (mainEqSRew.getKind() != EQUAL) + { + // Note this can happen in rare cases where substitution+rewriting + // is more powerful than congruence+rewriting. We fail to reconstruct + // the proof in this case. + Trace("strings-ipc-core") + << "...failed, not equality after rewriting" << std::endl; + break; + } // may need the "extended equality rewrite" Node mainEqSRew2 = psb.applyPredElim(mainEqSRew, {}, MethodId::SB_DEFAULT, MethodId::SBA_SEQUENTIAL, MethodId::RW_REWRITE_EQ_EXT); + Trace("strings-ipc-core") + << "...after extended equality rewrite: " << mainEqSRew2 << std::endl; if (mainEqSRew2 == conc) { useBuffer = true; diff --git a/src/theory/strings/skolem_cache.cpp b/src/theory/strings/skolem_cache.cpp index 0d2e9cacb..fc68ddfc4 100644 --- a/src/theory/strings/skolem_cache.cpp +++ b/src/theory/strings/skolem_cache.cpp @@ -109,8 +109,8 @@ Node SkolemCache::mkTypedSkolemCached( { // for sequences of Booleans, we may purify Boolean terms, in which case // they must be Boolean term variables. - int flags = a.getType().isBoolean() ? NodeManager::SKOLEM_BOOL_TERM_VAR - : NodeManager::SKOLEM_DEFAULT; + int flags = a.getType().isBoolean() ? SkolemManager::SKOLEM_BOOL_TERM_VAR + : SkolemManager::SKOLEM_DEFAULT; sk = sm->mkPurifySkolem(a, c, "string purify skolem", flags); } break; @@ -119,7 +119,6 @@ Node SkolemCache::mkTypedSkolemCached( case SK_ID_V_SPT_REV: case SK_ID_VC_SPT: case SK_ID_VC_SPT_REV: - case SK_FIRST_CTN_POST: case SK_ID_C_SPT: case SK_ID_C_SPT_REV: case SK_ID_DC_SPT: @@ -127,12 +126,11 @@ Node SkolemCache::mkTypedSkolemCached( case SK_ID_DEQ_X: case SK_ID_DEQ_Y: case SK_FIRST_CTN_PRE: + case SK_FIRST_CTN_POST: case SK_PREFIX: case SK_SUFFIX_REM: Unhandled() << "Expected to eliminate Skolem ID " << id << std::endl; break; - case SK_NUM_OCCUR: - case SK_OCCUR_INDEX: default: { Notice() << "Don't know how to handle Skolem ID " << id << std::endl; @@ -318,6 +316,25 @@ Node SkolemCache::mkLengthVar(Node t) return bvm->mkBoundVar<LengthVarAttribute>(t, intType); } +Node SkolemCache::mkSkolemFun(SkolemFunId id, TypeNode tn, Node a, Node b) +{ + std::vector<Node> cacheVals; + for (size_t i = 0; i < 2; i++) + { + Node n = i == 0 ? a : b; + if (!n.isNull()) + { + n = d_rr != nullptr ? d_rr->rewrite(n) : n; + cacheVals.push_back(n); + } + } + NodeManager* nm = NodeManager::currentNM(); + SkolemManager* sm = nm->getSkolemManager(); + Node k = sm->mkSkolemFunction(id, tn, cacheVals); + d_allSkolems.insert(k); + return k; +} + } // namespace strings } // namespace theory } // namespace cvc5 diff --git a/src/theory/strings/skolem_cache.h b/src/theory/strings/skolem_cache.h index 2b714781b..ff74e5c0d 100644 --- a/src/theory/strings/skolem_cache.h +++ b/src/theory/strings/skolem_cache.h @@ -58,6 +58,10 @@ class SkolemCache * preconditions below, e.g. where we are considering a' ++ a = b' ++ b. * * All skolems assume a and b are strings unless otherwise stated. + * + * Notice that these identifiers are each syntax sugar for constructing a + * purification skolem. It is required for the purposes of proof checking + * that this only results in calls to SkolemManager::mkPurifySkolem. */ enum SkolemId { @@ -107,21 +111,6 @@ class SkolemCache // of b in a as the witness for contains( a, b ). SK_FIRST_CTN_PRE, SK_FIRST_CTN_POST, - // For sequence a and regular expression b, - // in_re(a, re.++(_*, b, _*)) => - // exists k_pre, k_match, k_post. - // a = k_pre ++ k_match ++ k_post ^ - // len(k_pre) = indexof_re(x, y, 0) ^ - // (forall l. 0 < l < len(k_match) => - // ~in_re(substr(k_match, 0, l), r)) ^ - // in_re(k_match, b) - // - // k_pre is the prefix before the first, shortest match of b in a. k_match - // is the substring of a matched by b. It is either empty or there is no - // shorter string that matches b. - SK_FIRST_MATCH_PRE, - SK_FIRST_MATCH, - SK_FIRST_MATCH_POST, // For integer b, // len( a ) > b => // exists k. a = k ++ a' ^ len( k ) = b @@ -129,33 +118,7 @@ class SkolemCache // For integer b, // b > 0 => // exists k. a = a' ++ k ^ len( k ) = ite( len(a)>b, len(a)-b, 0 ) - SK_SUFFIX_REM, - // --------------- integer skolems - // exists k. ( b occurs k times in a ) - SK_NUM_OCCUR, - // --------------- function skolems - // For function k: Int -> Int - // exists k. - // forall 0 <= x <= n, - // k(x) is the end index of the x^th occurrence of b in a - // where n is the number of occurrences of b in a, and k(0)=0. - SK_OCCUR_INDEX, - // For function k: Int -> Int - // exists k. - // forall 0 <= x < n, - // k(x) is the length of the x^th occurrence of b in a (excluding - // matches of empty strings) - // where b is a regular expression, n is the number of occurrences of b - // in a, and k(0)=0. - SK_OCCUR_LEN, - // For function k: ((Seq U) x Int) -> U - // exists k. - // forall s, n. - // k(s, n) is some undefined value of sort U - SK_NTH, - // Diff index for disequalities - // a != b => substr(a,k,1) != substr(b,k,1) - SK_DEQ_DIFF + SK_SUFFIX_REM }; /** * Returns a skolem of type string that is cached for (a,b,id) and has @@ -201,6 +164,19 @@ class SkolemCache * that could be matched by r. */ static Node mkLengthVar(Node t); + /** + * Make skolem function, possibly normalizing based on the rewriter of this + * class. This method should be used whenever it is not possible to define + * a Skolem identifier that amounts to purification of a term. + * + * Notice that this method is not static or constant since it tracks the + * Skolem we construct (in d_allSkolems), which is used for finite model + * finding. + */ + Node mkSkolemFun(SkolemFunId id, + TypeNode tn, + Node a = Node::null(), + Node b = Node::null()); private: /** diff --git a/src/theory/strings/theory_strings.cpp b/src/theory/strings/theory_strings.cpp index 9a793e14f..e0f0a8dac 100644 --- a/src/theory/strings/theory_strings.cpp +++ b/src/theory/strings/theory_strings.cpp @@ -998,21 +998,20 @@ TrustNode TheoryStrings::ppRewrite(TNode atom, std::vector<SkolemLemma>& lems) } if (atom.getKind() == STRING_FROM_CODE) { - // str.from_code(t) ---> - // witness k. ite(0 <= t < |A|, t = str.to_code(k), k = "") + // str.from_code(t) ---> ite(0 <= t < |A|, t = str.to_code(k), k = "") NodeManager* nm = NodeManager::currentNM(); + SkolemCache* sc = d_termReg.getSkolemCache(); + Node k = sc->mkSkolemCached(atom, SkolemCache::SK_PURIFY, "kFromCode"); Node t = atom[0]; Node card = nm->mkConst(Rational(d_termReg.getAlphabetCardinality())); Node cond = nm->mkNode(AND, nm->mkNode(LEQ, d_zero, t), nm->mkNode(LT, t, card)); - Node v = nm->mkBoundVar(nm->stringType()); Node emp = Word::mkEmptyWord(atom.getType()); Node pred = nm->mkNode( - ITE, cond, t.eqNode(nm->mkNode(STRING_TO_CODE, v)), v.eqNode(emp)); - SkolemManager* sm = nm->getSkolemManager(); - Node ret = sm->mkSkolem(v, pred, "kFromCode"); - lems.push_back(SkolemLemma(ret, nullptr)); - return TrustNode::mkTrustRewrite(atom, ret, nullptr); + ITE, cond, t.eqNode(nm->mkNode(STRING_TO_CODE, k)), k.eqNode(emp)); + TrustNode tnk = TrustNode::mkTrustLemma(pred); + lems.push_back(SkolemLemma(tnk, k)); + return TrustNode::mkTrustRewrite(atom, k, nullptr); } TrustNode ret; Node atomRet = atom; diff --git a/src/theory/strings/theory_strings_preprocess.cpp b/src/theory/strings/theory_strings_preprocess.cpp index 550a9af8b..31f43d565 100644 --- a/src/theory/strings/theory_strings_preprocess.cpp +++ b/src/theory/strings/theory_strings_preprocess.cpp @@ -53,7 +53,6 @@ Node StringsPreprocess::reduce(Node t, << "StringsPreprocess::reduce: " << t << std::endl; Node retNode = t; NodeManager* nm = NodeManager::currentNM(); - SkolemManager* sm = nm->getSkolemManager(); Node zero = nm->mkConst(Rational(0)); Node one = nm->mkConst(Rational(1)); Node negOne = nm->mkConst(Rational(-1)); @@ -343,8 +342,8 @@ Node StringsPreprocess::reduce(Node t, std::vector<Node> conc; std::vector< TypeNode > argTypes; argTypes.push_back(nm->integerType()); - Node u = - sm->mkDummySkolem("U", nm->mkFunctionType(argTypes, nm->integerType())); + TypeNode itosResType = nm->mkFunctionType(argTypes, nm->integerType()); + Node u = sc->mkSkolemFun(SkolemFunId::STRINGS_ITOS_RESULT, itosResType, t); Node lem = nm->mkNode(GEQ, leni, one); conc.push_back(lem); @@ -423,7 +422,8 @@ Node StringsPreprocess::reduce(Node t, Node emp = Word::mkEmptyWord(s.getType()); Node sEmpty = s.eqNode(emp); - Node k = sm->mkDummySkolem("k", nm->integerType()); + Node k = sc->mkSkolemFun( + SkolemFunId::STRINGS_STOI_NON_DIGIT, nm->integerType(), t); Node kc1 = nm->mkNode(GEQ, k, zero); Node kc2 = nm->mkNode(LT, k, lens); Node c0 = nm->mkNode(STRING_TO_CODE, nm->mkConst(String("0"))); @@ -439,8 +439,9 @@ Node StringsPreprocess::reduce(Node t, std::vector<Node> conc2; std::vector< TypeNode > argTypes; argTypes.push_back(nm->integerType()); + TypeNode stoiResultType = nm->mkFunctionType(argTypes, nm->integerType()); Node u = - sm->mkDummySkolem("U", nm->mkFunctionType(argTypes, nm->integerType())); + sc->mkSkolemFun(SkolemFunId::STRINGS_STOI_RESULT, stoiResultType, t); lem = stoit.eqNode(nm->mkNode(APPLY_UF, u, lens)); conc2.push_back(lem); @@ -605,15 +606,15 @@ Node StringsPreprocess::reduce(Node t, Node z = t[2]; Node rpaw = sc->mkSkolemCached(t, SkolemCache::SK_PURIFY, "rpaw"); - Node numOcc = sc->mkTypedSkolemCached( - nm->integerType(), x, y, SkolemCache::SK_NUM_OCCUR, "numOcc"); + Node numOcc = sc->mkSkolemFun( + SkolemFunId::STRINGS_NUM_OCCUR, nm->integerType(), x, y); std::vector<TypeNode> argTypes; argTypes.push_back(nm->integerType()); - Node us = - sm->mkDummySkolem("Us", nm->mkFunctionType(argTypes, nm->stringType())); + TypeNode raResultType = nm->mkFunctionType(argTypes, t.getType()); + Node us = sc->mkSkolemFun( + SkolemFunId::STRINGS_REPLACE_ALL_RESULT, raResultType, t); TypeNode ufType = nm->mkFunctionType(argTypes, nm->integerType()); - Node uf = sc->mkTypedSkolemCached( - ufType, x, y, SkolemCache::SK_OCCUR_INDEX, "Uf"); + Node uf = sc->mkSkolemFun(SkolemFunId::STRINGS_OCCUR_INDEX, ufType, x, y); Node ufno = nm->mkNode(APPLY_UF, uf, numOcc); Node usno = nm->mkNode(APPLY_UF, us, numOcc); @@ -691,12 +692,10 @@ Node StringsPreprocess::reduce(Node t, // k = z ++ x Node res1 = k.eqNode(nm->mkNode(STRING_CONCAT, z, x)); - Node k1 = - sc->mkSkolemCached(x, y, SkolemCache::SK_FIRST_MATCH_PRE, "rre_pre"); - Node k2 = - sc->mkSkolemCached(x, y, SkolemCache::SK_FIRST_MATCH, "rre_match"); - Node k3 = - sc->mkSkolemCached(x, y, SkolemCache::SK_FIRST_MATCH_POST, "rre_post"); + TypeNode ktype = t.getType(); + Node k1 = sc->mkSkolemFun(SkolemFunId::SK_FIRST_MATCH_PRE, ktype, x, y); + Node k2 = sc->mkSkolemFun(SkolemFunId::SK_FIRST_MATCH, ktype, x, y); + Node k3 = sc->mkSkolemFun(SkolemFunId::SK_FIRST_MATCH_POST, ktype, x, y); Node k2Len = nm->mkNode(STRING_LENGTH, k2); // x = k1 ++ k2 ++ k3 Node split = x.eqNode(nm->mkNode(STRING_CONCAT, k1, k2, k3)); @@ -740,17 +739,16 @@ Node StringsPreprocess::reduce(Node t, Node z = t[2]; Node k = sc->mkSkolemCached(t, SkolemCache::SK_PURIFY, "k"); - Node numOcc = sc->mkTypedSkolemCached( - nm->integerType(), x, y, SkolemCache::SK_NUM_OCCUR, "numOcc"); + Node numOcc = sc->mkSkolemFun( + SkolemFunId::STRINGS_NUM_OCCUR, nm->integerType(), x, y); std::vector<TypeNode> argTypes; argTypes.push_back(nm->integerType()); - Node us = - sm->mkDummySkolem("Us", nm->mkFunctionType(argTypes, t.getType())); + TypeNode raResultType = nm->mkFunctionType(argTypes, t.getType()); + Node us = sc->mkSkolemFun( + SkolemFunId::STRINGS_REPLACE_ALL_RESULT, raResultType, t); TypeNode ufType = nm->mkFunctionType(argTypes, nm->integerType()); - Node uf = sc->mkTypedSkolemCached( - ufType, x, y, SkolemCache::SK_OCCUR_INDEX, "Uf"); - Node ul = - sc->mkTypedSkolemCached(ufType, x, y, SkolemCache::SK_OCCUR_LEN, "Ul"); + Node uf = sc->mkSkolemFun(SkolemFunId::STRINGS_OCCUR_INDEX, ufType, x, y); + Node ul = sc->mkSkolemFun(SkolemFunId::STRINGS_OCCUR_LEN, ufType, x, y); Node emp = Word::mkEmptyWord(t.getType()); diff --git a/src/theory/theory.cpp b/src/theory/theory.cpp index a5c2e0861..bec5c7416 100644 --- a/src/theory/theory.cpp +++ b/src/theory/theory.cpp @@ -339,7 +339,7 @@ bool Theory::isLegalElimination(TNode x, TNode val) { return false; } - if (!options::produceModels() && !logicInfo().isQuantified()) + if (!options().smt.produceModels && !logicInfo().isQuantified()) { // Don't care about the model and logic is not quantified, we can eliminate. return true; diff --git a/src/theory/theory_engine.cpp b/src/theory/theory_engine.cpp index a186c05a0..03880bfbb 100644 --- a/src/theory/theory_engine.cpp +++ b/src/theory/theory_engine.cpp @@ -145,17 +145,17 @@ void TheoryEngine::finishInit() CVC5_FOR_EACH_THEORY; // Initialize the theory combination architecture - if (options::tcMode() == options::TcMode::CARE_GRAPH) + if (options().theory.tcMode == options::TcMode::CARE_GRAPH) { d_tc.reset(new CombinationCareGraph(d_env, *this, paraTheories)); } else { Unimplemented() << "TheoryEngine::finishInit: theory combination mode " - << options::tcMode() << " not supported"; + << options().theory.tcMode << " not supported"; } // create the relevance filter if any option requires it - if (options::relevanceFilter() || options::produceDifficulty()) + if (options().theory.relevanceFilter || options().smt.produceDifficulty) { d_relManager.reset(new RelevanceManager(userContext(), Valuation(this))); } @@ -247,7 +247,7 @@ TheoryEngine::TheoryEngine(Env& env) d_theoryOut[theoryId] = NULL; } - if (options::sortInference()) + if (options().smt.sortInference) { d_sortInfer.reset(new SortInference(env)); } @@ -633,7 +633,7 @@ TheoryModel* TheoryEngine::getBuiltModel() Assert(d_tc != nullptr); // If this method was called, we should be in SAT mode, and produceModels // should be true. - AlwaysAssert(options::produceModels()); + AlwaysAssert(options().smt.produceModels); if (!d_inSatMode) { // not available, perhaps due to interuption. diff --git a/src/theory/theory_model.cpp b/src/theory/theory_model.cpp index a5ec0867a..599e192f8 100644 --- a/src/theory/theory_model.cpp +++ b/src/theory/theory_model.cpp @@ -143,7 +143,7 @@ Node TheoryModel::getValue(TNode n) const } else if (nn.getKind() == kind::LAMBDA) { - if (options::condenseFunctionValues()) + if (options().theory.condenseFunctionValues) { // normalize the body. Do not normalize the entire node, which // involves array normalization. diff --git a/src/theory/theory_model_builder.cpp b/src/theory/theory_model_builder.cpp index f50e7e0ee..71fe48de8 100644 --- a/src/theory/theory_model_builder.cpp +++ b/src/theory/theory_model_builder.cpp @@ -567,7 +567,7 @@ bool TheoryEngineModelBuilder::buildModel(TheoryModel* tm) // finished traversing the equality engine TypeNode eqct = eqc.getType(); // count the number of equivalence classes of sorts in finite model finding - if (options::finiteModelFind()) + if (options().quantifiers.finiteModelFind) { if (eqct.isSort()) { @@ -660,7 +660,7 @@ bool TheoryEngineModelBuilder::buildModel(TheoryModel* tm) // then the type enumerator for list of U should enumerate: // nil, (cons U1 nil), (cons U2 nil), (cons U1 (cons U1 nil)), ... // instead of enumerating (cons U3 nil). - if (options::finiteModelFind()) + if (options().quantifiers.finiteModelFind) { tep.d_fixed_usort_card = true; for (std::map<TypeNode, unsigned>::iterator it = eqc_usort_count.begin(); @@ -847,7 +847,7 @@ bool TheoryEngineModelBuilder::buildModel(TheoryModel* tm) } #ifdef CVC5_ASSERTIONS bool isUSortFiniteRestricted = false; - if (options::finiteModelFind()) + if (options().quantifiers.finiteModelFind) { isUSortFiniteRestricted = !t.isSort() && involvesUSort(t); } @@ -1080,7 +1080,7 @@ void TheoryEngineModelBuilder::postProcessModel(bool incomplete, TheoryModel* m) } Assert(m != nullptr); // debug-check the model if the checkModels() is enabled. - if (options::debugCheckModels()) + if (options().smt.debugCheckModels) { debugCheckModel(m); } @@ -1258,7 +1258,7 @@ void TheoryEngineModelBuilder::assignFunction(TheoryModel* m, Node f) default_v = (*te); } ufmt.setDefaultValue(m, default_v); - bool condenseFuncValues = options::condenseFunctionValues(); + bool condenseFuncValues = options().theory.condenseFunctionValues; if (condenseFuncValues) { ufmt.simplify(); @@ -1389,7 +1389,7 @@ struct sortTypeSize void TheoryEngineModelBuilder::assignFunctions(TheoryModel* m) { - if (!options::assignFunctionValues()) + if (!options().theory.assignFunctionValues) { return; } diff --git a/src/theory/uf/eq_proof.cpp b/src/theory/uf/eq_proof.cpp index 45a00a620..ab091cffd 100644 --- a/src/theory/uf/eq_proof.cpp +++ b/src/theory/uf/eq_proof.cpp @@ -91,8 +91,8 @@ void EqProof::cleanReflPremises(std::vector<Node>& premises) const if (newPremises.size() != size) { Trace("eqproof-conv") << "EqProof::cleanReflPremises: removed " - << (newPremises.size() >= size - ? newPremises.size() - size + << (size >= newPremises.size() + ? size - newPremises.size() : 0) << " refl premises from " << premises << "\n"; premises.clear(); @@ -138,6 +138,8 @@ bool EqProof::expandTransitivityForDisequalities( // if no equality of the searched form, nothing to do if (offending == size) { + Trace("eqproof-conv") + << "EqProof::expandTransitivityForDisequalities: no need.\n"; return false; } NodeManager* nm = NodeManager::currentNM(); @@ -967,6 +969,7 @@ Node EqProof::addToProof(CDProof* p, if (d_id == MERGED_THROUGH_REFLEXIVITY || (d_node.getKind() == kind::EQUAL && d_node[0] == d_node[1])) { + Trace("eqproof-conv") << "EqProof::addToProof: refl step\n"; Node conclusion = d_node.getKind() == kind::EQUAL ? d_node : d_node.eqNode(d_node); p->addStep(conclusion, PfRule::REFL, {}, {conclusion[0]}); @@ -1170,7 +1173,9 @@ Node EqProof::addToProof(CDProof* p, } } } - Assert(p->hasStep(conclusion)); + Assert(p->hasStep(conclusion) || assumptions.count(conclusion)) + << "Conclusion " << conclusion + << " does not have a step in the proof neither it's an assumption.\n"; visited[d_node] = conclusion; return conclusion; } diff --git a/src/theory/uf/ho_extension.cpp b/src/theory/uf/ho_extension.cpp index fd7cd467e..e23262746 100644 --- a/src/theory/uf/ho_extension.cpp +++ b/src/theory/uf/ho_extension.cpp @@ -200,7 +200,11 @@ Node HoExtension::getApplyUfForHoApply(Node node) unsigned HoExtension::checkExtensionality(TheoryModel* m) { - eq::EqualityEngine* ee = d_state.getEqualityEngine(); + // if we are in collect model info, we require looking at the model's + // equality engine, so that we only consider "relevant" (see + // Theory::computeRelevantTerms) function terms. + eq::EqualityEngine* ee = + m != nullptr ? m->getEqualityEngine() : d_state.getEqualityEngine(); NodeManager* nm = NodeManager::currentNM(); unsigned num_lemmas = 0; bool isCollectModel = (m != nullptr); @@ -247,8 +251,13 @@ unsigned HoExtension::checkExtensionality(TheoryModel* m) for (unsigned k = (j + 1), sizek = itf->second.size(); k < sizek; k++) { // if these equivalence classes are not explicitly disequal, do - // extensionality to ensure distinctness - if (!ee->areDisequal(itf->second[j], itf->second[k], false)) + // extensionality to ensure distinctness. Notice that we always use + // the (local) equality engine for this check via the state, since the + // model's equality engine does not store any disequalities. This is + // an optimization to introduce fewer equalities during model + // construction, since we know such disequalities have already been + // witness via assertions. + if (!d_state.areDisequal(itf->second[j], itf->second[k])) { Node deq = Rewriter::rewrite(itf->second[j].eqNode(itf->second[k]).negate()); @@ -450,6 +459,11 @@ bool HoExtension::collectModelInfoHo(TheoryModel* m, return false; } } + // We apply an explicit extensionality technique for asserting + // disequalities to the model to ensure that function values are distinct + // in the curried HO_APPLY version of model construction. This is a + // non-standard alternative to using a type enumerator over function + // values to assign unique values. int addedLemmas = checkExtensionality(m); return addedLemmas == 0; } diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index ad277cbb6..2ac529565 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -29,6 +29,8 @@ libcvc5_add_sources( cardinality_class.cpp cardinality_class.h dense_map.h + didyoumean.cpp + didyoumean.h divisible.cpp divisible.h floatingpoint.cpp diff --git a/src/options/didyoumean.cpp b/src/util/didyoumean.cpp index 06abd51b8..0f95722fd 100644 --- a/src/options/didyoumean.cpp +++ b/src/util/didyoumean.cpp @@ -18,91 +18,52 @@ * There are no dependencies on cvc5 (except namespace). */ -#include "options/didyoumean.h" +#include "util/didyoumean.h" -#include <iostream> -#include <set> +#include <algorithm> +#include <array> #include <sstream> #include <string> #include <vector> namespace cvc5 { -std::vector<std::string> DidYouMean::getMatch(const std::string& input) -{ - /** Magic numbers */ - const int similarityThreshold = 7; - const unsigned numMatchesThreshold = 10; - - typedef std::set<std::pair<int, std::string> > ScoreSet; - ScoreSet scores; - std::vector<std::string> ret; - for (Words::const_iterator it = d_words.begin(); it != d_words.end(); ++it) { - std::string s = (*it); - if (s == input) { - // if input matches AS-IS just return that - ret.push_back(s); - return ret; - } - int score; - if (s.compare(0, input.size(), input) == 0) { - score = 0; - } else { - score = editDistance(input, s) + 1; - } - scores.insert(make_pair(score, s)); - } - int min_score = scores.begin()->first; - for (ScoreSet::const_iterator i = scores.begin(); i != scores.end(); ++i) { - // add if score is overall not too big, and also not much close to - // the score of the best suggestion - if (i->first < similarityThreshold && i->first <= min_score + 1) { - ret.push_back(i->second); -#ifdef DIDYOUMEAN_DEBUG - cout << i->second << ": " << i->first << std::endl; -#endif - } - } - if (ret.size() > numMatchesThreshold) { - ret.resize(numMatchesThreshold); - } - return ret; -} +namespace { -int DidYouMean::editDistance(const std::string& a, const std::string& b) { +uint64_t editDistance(const std::string& a, const std::string& b) { // input string: a // desired string: b - const size_t swapCost = 0; - const size_t substituteCost = 2; - const size_t addCost = 1; - const size_t deleteCost = 3; - const size_t switchCaseCost = 0; + constexpr uint64_t swapCost = 0; + constexpr uint64_t substituteCost = 2; + constexpr uint64_t addCost = 1; + constexpr uint64_t deleteCost = 3; + constexpr uint64_t switchCaseCost = 0; - size_t len1 = a.size(); - size_t len2 = b.size(); + uint64_t len1 = a.size(); + uint64_t len2 = b.size(); - size_t* C[3]; - size_t ii; - for (ii = 0; ii < 3; ++ii) { - C[ii] = new size_t[len2 + 1]; + std::array<std::vector<uint64_t>, 3> C; + for (auto& c: C) + { + c.resize(len2 + 1); } // int C[3][len2+1]; // cost - for (size_t j = 0; j <= len2; ++j) + for (uint64_t j = 0; j <= len2; ++j) { C[0][j] = j * addCost; } - for (size_t i = 1; i <= len1; ++i) + for (uint64_t i = 1; i <= len1; ++i) { - size_t cur = i % 3; - size_t prv = (i + 2) % 3; - size_t pr2 = (i + 1) % 3; + uint64_t cur = i % 3; + uint64_t prv = (i + 2) % 3; + uint64_t pr2 = (i + 1) % 3; C[cur][0] = i * deleteCost; - for (size_t j = 1; j <= len2; ++j) + for (uint64_t j = 1; j <= len2; ++j) { C[cur][j] = 100000000; // INF @@ -127,29 +88,59 @@ int DidYouMean::editDistance(const std::string& a, const std::string& b) { // delete C[cur][j] = std::min(C[cur][j], C[prv][j] + deleteCost); + } + } + return C[len1 % 3][len2]; +} + +} + +std::vector<std::string> DidYouMean::getMatch(const std::string& input) +{ + { + std::sort(d_words.begin(), d_words.end()); + auto it = std::unique(d_words.begin(), d_words.end()); + d_words.erase(it, d_words.end()); + } + + /** Magic numbers */ + constexpr uint64_t similarityThreshold = 7; + constexpr uint64_t numMatchesThreshold = 10; -#ifdef DIDYOUMEAN_DEBUG1 - std::cout << "C[" << cur << "][" << 0 << "] = " << C[cur][0] << std::endl; -#endif + std::vector<std::pair<uint64_t,std::string>> scores; + std::vector<std::string> ret; + for (const auto& s: d_words) { + if (s == input) { + // if input matches AS-IS just return that + ret.emplace_back(s); + return ret; } + uint64_t score = 0; + if (s.compare(0, input.size(), input) != 0) { + score = editDistance(input, s) + 1; + } + scores.emplace_back(std::make_pair(score, s)); } - int result = C[len1 % 3][len2]; - for (ii = 0; ii < 3; ++ii) { - delete[] C[ii]; + std::sort(scores.begin(), scores.end()); + const uint64_t min_score = scores.begin()->first; + for (const auto& score: scores) { + // from here on, matches are not similar enough + if (score.first > similarityThreshold) break; + // from here on, matches are way worse than the best one + if (score.first > min_score + 2) break; + // we already have enough matches + if (ret.size() >= numMatchesThreshold) break; + ret.push_back(score.second); } - return result; + return ret; } -std::string DidYouMean::getMatchAsString(const std::string& input, - uint64_t prefixNewLines, - uint64_t suffixNewLines) +std::string DidYouMean::getMatchAsString(const std::string& input) { std::vector<std::string> matches = getMatch(input); std::ostringstream oss; if (matches.size() > 0) { - while (prefixNewLines-- > 0) { - oss << std::endl; - } + oss << std::endl << std::endl; if (matches.size() == 1) { oss << "Did you mean this?"; } else { @@ -159,9 +150,6 @@ std::string DidYouMean::getMatchAsString(const std::string& input, { oss << "\n " << matches[i]; } - while (suffixNewLines-- > 0) { - oss << std::endl; - } } return oss.str(); } diff --git a/src/options/didyoumean.h b/src/util/didyoumean.h index 0118f1484..26de80f66 100644 --- a/src/options/didyoumean.h +++ b/src/util/didyoumean.h @@ -22,7 +22,6 @@ #include "cvc5_export.h" -#include <set> #include <string> #include <vector> @@ -30,15 +29,10 @@ namespace cvc5 { class CVC5_EXPORT DidYouMean { public: - using Words = std::set<std::string>; - - DidYouMean() {} - ~DidYouMean() {} - - void addWord(std::string word) { d_words.insert(std::move(word)); } + void addWord(const std::string& word) { d_words.emplace_back(word); } void addWords(const std::vector<std::string>& words) { - d_words.insert(words.begin(), words.end()); + d_words.insert(d_words.end(), words.begin(), words.end()); } std::vector<std::string> getMatch(const std::string& input); @@ -47,13 +41,10 @@ class CVC5_EXPORT DidYouMean { * This is provided to make it easier to ensure consistency of * output. Returned string is empty if there are no matches. */ - std::string getMatchAsString(const std::string& input, - uint64_t prefixNewLines = 2, - uint64_t suffixNewLines = 0); + std::string getMatchAsString(const std::string& input); private: - int editDistance(const std::string& a, const std::string& b); - Words d_words; + std::vector<std::string> d_words; }; } // namespace cvc5 diff --git a/src/util/integer_cln_imp.cpp b/src/util/integer_cln_imp.cpp index a9e4f6f0a..e09708ae5 100644 --- a/src/util/integer_cln_imp.cpp +++ b/src/util/integer_cln_imp.cpp @@ -12,6 +12,12 @@ * * A multiprecision integer constant; wraps a CLN multiprecision integer. */ + +#include <cln/input.h> +#include <cln/integer_io.h> +#include <cln/modinteger.h> + +#include <iostream> #include <sstream> #include <string> diff --git a/src/util/integer_cln_imp.h b/src/util/integer_cln_imp.h index 80bc406ee..2120a4d5d 100644 --- a/src/util/integer_cln_imp.h +++ b/src/util/integer_cln_imp.h @@ -18,19 +18,20 @@ #ifndef CVC5__INTEGER_H #define CVC5__INTEGER_H -#include <cln/input.h> #include <cln/integer.h> -#include <cln/integer_io.h> -#include <cln/modinteger.h> -#include <iostream> +#include <iosfwd> #include <limits> -#include <sstream> #include <string> #include "base/exception.h" #include "cvc5_export.h" // remove when Cvc language support is removed +namespace cln +{ + struct cl_read_flags; +} + namespace cvc5 { class Rational; diff --git a/test/api/CMakeLists.txt b/test/api/CMakeLists.txt index f6c1cf8df..56adf73e7 100644 --- a/test/api/CMakeLists.txt +++ b/test/api/CMakeLists.txt @@ -53,6 +53,7 @@ cvc5_add_api_test(issue5074) cvc5_add_api_test(issue4889) cvc5_add_api_test(issue6111) cvc5_add_api_test(proj-issue306) +cvc5_add_api_test(proj-issue334) # if we've built using libedit, then we want the interactive shell tests if (USE_EDITLINE) diff --git a/test/api/proj-issue306.cpp b/test/api/proj-issue306.cpp index 664536a0b..35ecda567 100644 --- a/test/api/proj-issue306.cpp +++ b/test/api/proj-issue306.cpp @@ -1,3 +1,19 @@ +/****************************************************************************** + * Top contributors (to current version): + * Andrew Reynolds + * + * This file is part of the cvc5 project. + * + * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS + * in the top-level source directory and their institutional affiliations. + * All rights reserved. See the file COPYING in the top-level source + * directory for licensing information. + * **************************************************************************** + * + * Test for project issue #306 + * + */ + #include "api/cpp/cvc5.h" using namespace cvc5::api; diff --git a/test/api/proj-issue334.cpp b/test/api/proj-issue334.cpp new file mode 100644 index 000000000..bbb7f1a46 --- /dev/null +++ b/test/api/proj-issue334.cpp @@ -0,0 +1,36 @@ +/****************************************************************************** + * Top contributors (to current version): + * Andrew Reynolds + * + * This file is part of the cvc5 project. + * + * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS + * in the top-level source directory and their institutional affiliations. + * All rights reserved. See the file COPYING in the top-level source + * directory for licensing information. + * **************************************************************************** + * + * Test for project issue #334 + * + */ + +#include "api/cpp/cvc5.h" + +using namespace cvc5::api; + +int main(void) +{ + Solver slv; + slv.setOption("produce-unsat-cores", "true"); + Sort s1 = slv.mkBitVectorSort(1); + Sort s2 = slv.mkFloatingPointSort(8, 24); + Term val = slv.mkBitVector(32, "10000000110010111010111011000101", 2); + Term t1 = slv.mkFloatingPoint(8, 24, val); + Term t2 = slv.mkConst(s1); + Term t4 = slv.mkTerm(Kind::BITVECTOR_TO_NAT, t2); + Term t5 = slv.mkTerm(Kind::STRING_FROM_CODE, t4); + Term t6 = slv.simplify(t5); + Term t7 = slv.mkTerm(Kind::STRING_LEQ, t5, t6); + slv.assertFormula(t7); + slv.simplify(t1); +} diff --git a/test/api/sep_log_api.cpp b/test/api/sep_log_api.cpp index 5d0e6b828..5795de794 100644 --- a/test/api/sep_log_api.cpp +++ b/test/api/sep_log_api.cpp @@ -83,7 +83,7 @@ int validate_exception(void) /* test the heap expression */ try { - Term heap_expr = slv.getSeparationHeap(); + Term heap_expr = slv.getValueSepHeap(); } catch (const CVC5ApiException& e) { @@ -99,7 +99,7 @@ int validate_exception(void) /* test the nil expression */ try { - Term nil_expr = slv.getSeparationNilTerm(); + Term nil_expr = slv.getValueSepNil(); } catch (const CVC5ApiException& e) { @@ -138,7 +138,7 @@ int validate_getters(void) Sort integer = slv.getIntegerSort(); /** Declare the separation logic heap types */ - slv.declareSeparationHeap(integer, integer); + slv.declareSepHeap(integer, integer); /* A "random" constant */ Term random_constant = slv.mkInteger(0xDEADBEEF); @@ -188,8 +188,8 @@ int validate_getters(void) } /* Obtain our separation logic terms from the solver */ - Term heap_expr = slv.getSeparationHeap(); - Term nil_expr = slv.getSeparationNilTerm(); + Term heap_expr = slv.getValueSepHeap(); + Term nil_expr = slv.getValueSepNil(); /* If the heap is not a separating conjunction, bail-out */ if (heap_expr.getKind() != Kind::SEP_STAR) diff --git a/test/python/unit/api/test_solver.py b/test/python/unit/api/test_solver.py index 04a275741..c7398aa3b 100644 --- a/test/python/unit/api/test_solver.py +++ b/test/python/unit/api/test_solver.py @@ -950,42 +950,23 @@ def test_declare_sort(solver): def test_define_fun(solver): bvSort = solver.mkBitVectorSort(32) - funSort1 = solver.mkFunctionSort([bvSort, bvSort], bvSort) - funSort2 = solver.mkFunctionSort(solver.mkUninterpretedSort("u"),\ - solver.getIntegerSort()) + funSort = solver.mkFunctionSort(solver.mkUninterpretedSort("u"), + solver.getIntegerSort()) b1 = solver.mkVar(bvSort, "b1") - b11 = solver.mkVar(bvSort, "b1") b2 = solver.mkVar(solver.getIntegerSort(), "b2") - b3 = solver.mkVar(funSort2, "b3") + b3 = solver.mkVar(funSort, "b3") v1 = solver.mkConst(bvSort, "v1") - v2 = solver.mkConst(solver.getIntegerSort(), "v2") - v3 = solver.mkConst(funSort2, "v3") - f1 = solver.mkConst(funSort1, "f1") - f2 = solver.mkConst(funSort2, "f2") - f3 = solver.mkConst(bvSort, "f3") + v2 = solver.mkConst(funSort, "v2") solver.defineFun("f", [], bvSort, v1) solver.defineFun("ff", [b1, b2], bvSort, v1) - solver.defineFun(f1, [b1, b11], v1) with pytest.raises(RuntimeError): solver.defineFun("ff", [v1, b2], bvSort, v1) with pytest.raises(RuntimeError): - solver.defineFun("fff", [b1], bvSort, v3) + solver.defineFun("fff", [b1], bvSort, v2) with pytest.raises(RuntimeError): - solver.defineFun("ffff", [b1], funSort2, v3) + solver.defineFun("ffff", [b1], funSort, v2) # b3 has function sort, which is allowed as an argument solver.defineFun("fffff", [b1, b3], bvSort, v1) - with pytest.raises(RuntimeError): - solver.defineFun(f1, [v1, b11], v1) - with pytest.raises(RuntimeError): - solver.defineFun(f1, [b1], v1) - with pytest.raises(RuntimeError): - solver.defineFun(f1, [b1, b11], v2) - with pytest.raises(RuntimeError): - solver.defineFun(f1, [b1, b11], v3) - with pytest.raises(RuntimeError): - solver.defineFun(f2, [b1], v2) - with pytest.raises(RuntimeError): - solver.defineFun(f3, [b1], v1) slv = pycvc5.Solver() bvSort2 = slv.mkBitVectorSort(32) @@ -1281,10 +1262,10 @@ def test_get_value3(solver): def test_declare_separation_heap(solver): solver.setLogic("ALL") integer = solver.getIntegerSort() - solver.declareSeparationHeap(integer, integer) + solver.declareSepHeap(integer, integer) # cannot declare separation logic heap more than once with pytest.raises(RuntimeError): - solver.declareSeparationHeap(integer, integer) + solver.declareSepHeap(integer, integer) # Helper function for test_get_separation_{heap,nil}_termX. Asserts and checks @@ -1292,7 +1273,7 @@ def test_declare_separation_heap(solver): def checkSimpleSeparationConstraints(slv): integer = slv.getIntegerSort() # declare the separation heap - slv.declareSeparationHeap(integer, integer) + slv.declareSepHeap(integer, integer) x = slv.mkConst(integer, "x") p = slv.mkConst(integer, "p") heap = slv.mkTerm(kinds.SepPto, p, x) @@ -1309,7 +1290,7 @@ def test_get_separation_heap_term1(solver): t = solver.mkTrue() solver.assertFormula(t) with pytest.raises(RuntimeError): - solver.getSeparationHeap() + solver.getValueSepHeap() def test_get_separation_heap_term2(solver): @@ -1318,7 +1299,7 @@ def test_get_separation_heap_term2(solver): solver.setOption("produce-models", "false") checkSimpleSeparationConstraints(solver) with pytest.raises(RuntimeError): - solver.getSeparationHeap() + solver.getValueSepHeap() def test_get_separation_heap_term3(solver): @@ -1329,7 +1310,7 @@ def test_get_separation_heap_term3(solver): solver.assertFormula(t) solver.checkSat() with pytest.raises(RuntimeError): - solver.getSeparationHeap() + solver.getValueSepHeap() def test_get_separation_heap_term4(solver): @@ -1340,7 +1321,7 @@ def test_get_separation_heap_term4(solver): solver.assertFormula(t) solver.checkSat() with pytest.raises(RuntimeError): - solver.getSeparationHeap() + solver.getValueSepHeap() def test_get_separation_heap_term5(solver): @@ -1348,7 +1329,7 @@ def test_get_separation_heap_term5(solver): solver.setOption("incremental", "false") solver.setOption("produce-models", "true") checkSimpleSeparationConstraints(solver) - solver.getSeparationHeap() + solver.getValueSepHeap() def test_get_separation_nil_term1(solver): @@ -1358,7 +1339,7 @@ def test_get_separation_nil_term1(solver): t = solver.mkTrue() solver.assertFormula(t) with pytest.raises(RuntimeError): - solver.getSeparationNilTerm() + solver.getValueSepNil() def test_get_separation_nil_term2(solver): @@ -1367,7 +1348,7 @@ def test_get_separation_nil_term2(solver): solver.setOption("produce-models", "false") checkSimpleSeparationConstraints(solver) with pytest.raises(RuntimeError): - solver.getSeparationNilTerm() + solver.getValueSepNil() def test_get_separation_nil_term3(solver): @@ -1378,7 +1359,7 @@ def test_get_separation_nil_term3(solver): solver.assertFormula(t) solver.checkSat() with pytest.raises(RuntimeError): - solver.getSeparationNilTerm() + solver.getValueSepNil() def test_get_separation_nil_term4(solver): @@ -1389,7 +1370,7 @@ def test_get_separation_nil_term4(solver): solver.assertFormula(t) solver.checkSat() with pytest.raises(RuntimeError): - solver.getSeparationNilTerm() + solver.getValueSepNil() def test_get_separation_nil_term5(solver): @@ -1397,7 +1378,7 @@ def test_get_separation_nil_term5(solver): solver.setOption("incremental", "false") solver.setOption("produce-models", "true") checkSimpleSeparationConstraints(solver) - solver.getSeparationNilTerm() + solver.getValueSepNil() def test_push1(solver): diff --git a/test/regress/CMakeLists.txt b/test/regress/CMakeLists.txt index 2529a8622..da7c40bc2 100644 --- a/test/regress/CMakeLists.txt +++ b/test/regress/CMakeLists.txt @@ -237,7 +237,6 @@ set(regress_0_tests regress0/bv/bug440.smtv1.smt2 regress0/bv/bug733.smt2 regress0/bv/bug734.smt2 - regress0/bv/bv-abstr-bug.smt2 regress0/bv/bv-abstr-bug2.smt2 regress0/bv/bv-int-collapse1.smt2 regress0/bv/bv-int-collapse2.smt2 @@ -614,6 +613,7 @@ set(regress_0_tests regress0/fp/issue5734.smt2 regress0/fp/issue6164.smt2 regress0/fp/issue7002.smt2 + regress0/fp/proj-issue329-prereg-context.smt2 regress0/fp/rti_3_5_bug.smt2 regress0/fp/simple.smt2 regress0/fp/word-blast.smt2 @@ -661,6 +661,7 @@ set(regress_0_tests regress0/ho/match-middle.smt2 regress0/ho/modulo-func-equality.smt2 regress0/ho/qgu-fuzz-ho-1-dd.smt2 + regress0/ho/qgu-fuzz-ho-2-dd-no-ext.smt2 regress0/ho/shadowing-defs.smt2 regress0/ho/simple-matching-partial.smt2 regress0/ho/simple-matching.smt2 @@ -846,6 +847,7 @@ set(regress_0_tests regress0/preprocess/proj-issue305-circuit-prop-ite-c.smt2 regress0/preprocess/proj-issue305-circuit-prop-ite-d.smt2 regress0/preprocess/proj-issue309-circuit-prop-ite.smt2 + regress0/preprocess/proj-issue332-circuit-prop-xor.smt2 regress0/print_define_fun_internal.smt2 regress0/print_lambda.cvc.smt2 regress0/print_model.cvc.smt2 @@ -864,6 +866,8 @@ set(regress_0_tests regress0/proofs/open-pf-if-unordered-iff.smt2 regress0/proofs/open-pf-rederivation.smt2 regress0/proofs/project-issue317-inc-sat-conflictlit.smt2 + regress0/proofs/project-issue330-eqproof.smt2 + regress0/proofs/proj-issue326-nl-bounds-check.smt2 regress0/proofs/qgu-fuzz-1-bool-sat.smt2 regress0/proofs/qgu-fuzz-2-bool-chainres-checking.smt2 regress0/proofs/qgu-fuzz-3-chainres-checking.smt2 @@ -1033,7 +1037,6 @@ set(regress_0_tests regress0/rels/rel_tc_2_1.cvc.smt2 regress0/rels/rel_tc_3_1.cvc.smt2 regress0/rels/rel_tc_3.cvc.smt2 - regress0/rels/rel_tc_7.cvc.smt2 regress0/rels/rel_tc_8.cvc.smt2 regress0/rels/rel_tp_3_1.cvc.smt2 regress0/rels/rel_tp_join_0.cvc.smt2 @@ -1586,6 +1589,9 @@ set(regress_1_tests regress1/bags/emptybag1.smt2 regress1/bags/fuzzy1.smt2 regress1/bags/fuzzy2.smt2 + regress1/bags/fuzzy3.smt2 + regress1/bags/fuzzy4.smt2 + regress1/bags/fuzzy5.smt2 regress1/bags/intersection_min1.smt2 regress1/bags/intersection_min2.smt2 regress1/bags/issue5759.smt2 @@ -1618,7 +1624,6 @@ set(regress_1_tests regress1/bv/issue3776.smt2 regress1/bv/issue3958.smt2 regress1/bv/min-pp-rewrite-error.smt2 - regress1/bv/test-bv-abstraction.smt2 regress1/bv/unsound1.smt2 regress1/bvdiv2.smt2 regress1/cee-bug0909-dd-scope.smt2 @@ -1953,6 +1958,7 @@ set(regress_1_tests regress1/quantifiers/issue4433-nqe.smt2 regress1/quantifiers/issue4620-erq-witness-unsound.smt2 regress1/quantifiers/issue4685-wrewrite.smt2 + regress1/quantifiers/issue4813-qe-quant.smt2 regress1/quantifiers/issue4849-nqe.smt2 regress1/quantifiers/issue5019-cegqi-i.smt2 regress1/quantifiers/issue5279-nqe.smt2 @@ -1979,6 +1985,7 @@ set(regress_1_tests regress1/quantifiers/issue6775-vts-int.smt2 regress1/quantifiers/issue6845-nl-lemma-tc.smt2 regress1/quantifiers/issue7385-sygus-inst-i.smt2 + regress1/quantifiers/issue7537-cegqi-comp-types.smt2 regress1/quantifiers/issue993.smt2 regress1/quantifiers/javafe.ast.StmtVec.009.smt2 regress1/quantifiers/lia-witness-div-pp.smt2 @@ -2068,6 +2075,8 @@ set(regress_1_tests regress1/rels/joinImg_2_1.cvc.smt2 regress1/rels/prod-mod-eq.cvc.smt2 regress1/rels/prod-mod-eq2.cvc.smt2 + regress1/rels/qgu-fuzz-relations-2.smt2 + regress1/rels/qgu-fuzz-relations-3-upwards.smt2 regress1/rels/rel_complex_3.cvc.smt2 regress1/rels/rel_complex_4.cvc.smt2 regress1/rels/rel_complex_5.cvc.smt2 @@ -2312,6 +2321,7 @@ set(regress_1_tests regress1/strings/policy_variable.smt2 regress1/strings/pre_ctn_no_skolem_share.smt2 regress1/strings/proj254-re-elim-agg.smt2 + regress1/strings/proj-issue331.smt2 regress1/strings/query4674.smt2 regress1/strings/query8485.smt2 regress1/strings/re-all-char-hard.smt2 @@ -2768,6 +2778,8 @@ set(regression_disabled_tests regress0/auflia/fuzz01.smtv1.smt2 ### regress0/bv/test00.smtv1.smt2 + # timeout after fixing upwards closure for relations + regress0/rels/rel_tc_7.cvc.smt2 # timeout after changes to equality rewriting policy in strings regress0/strings/quad-028-2-2-unsat.smt2 # FIXME #1649 diff --git a/test/regress/regress0/bug522.smt2 b/test/regress/regress0/bug522.smt2 index 3a9ea0eaa..ad6e526a8 100644 --- a/test/regress/regress0/bug522.smt2 +++ b/test/regress/regress0/bug522.smt2 @@ -1,6 +1,6 @@ ; EXPECT: sat ; EXPECT: sat -(set-option :incremental "true") +(set-option :incremental true) (set-logic QF_UF) (push 1) diff --git a/test/regress/regress0/bv/bv-abstr-bug.smt2 b/test/regress/regress0/bv/bv-abstr-bug.smt2 deleted file mode 100644 index cc38075a9..000000000 --- a/test/regress/regress0/bv/bv-abstr-bug.smt2 +++ /dev/null @@ -1,16 +0,0 @@ -; COMMAND-LINE: --bv-abstraction --bitblast=eager -; -; BV-abstraction should not be applied -(set-logic QF_BV) -(set-info :status sat) -(declare-const a Bool) -(declare-const b Bool) -(declare-const c Bool) -(declare-const d Bool) -(assert - (or - (and a b) - (and c d) - ) -) -(check-sat) diff --git a/test/regress/regress0/bv/test-bv_intro_pow2.smt2 b/test/regress/regress0/bv/test-bv_intro_pow2.smt2 index e89dd4c50..65471a6b9 100644 --- a/test/regress/regress0/bv/test-bv_intro_pow2.smt2 +++ b/test/regress/regress0/bv/test-bv_intro_pow2.smt2 @@ -1,4 +1,4 @@ -; COMMAND-LINE: --bv-intro-pow2 --no-check-unsat-cores --bv-solver=layered +; COMMAND-LINE: --bv-intro-pow2 --no-check-unsat-cores (set-info :smt-lib-version 2.6) (set-logic QF_BV) (set-info :status unsat) diff --git a/test/regress/regress0/fmf/cruanes-no-minimal-unk.smt2 b/test/regress/regress0/fmf/cruanes-no-minimal-unk.smt2 index f38a3ce41..6ce1c41cd 100644 --- a/test/regress/regress0/fmf/cruanes-no-minimal-unk.smt2 +++ b/test/regress/regress0/fmf/cruanes-no-minimal-unk.smt2 @@ -4,7 +4,7 @@ ; generated by Nunchaku (declare-sort i_ 0) (declare-fun __nun_card_witness_0_ () i_) -(assert (fmf.card __nun_card_witness_0_ 2)) +(assert (_ fmf.card i_ 2)) (declare-fun i2_ () i_) (declare-fun i1_ () i_) (declare-fun i3_ () i_) diff --git a/test/regress/regress0/fmf/fc-simple.smt2 b/test/regress/regress0/fmf/fc-simple.smt2 index d1fd2301c..26c9b423f 100644 --- a/test/regress/regress0/fmf/fc-simple.smt2 +++ b/test/regress/regress0/fmf/fc-simple.smt2 @@ -6,7 +6,7 @@ (declare-fun a () U) (declare-fun c () U) -(assert (fmf.card c 2)) -(assert (not (fmf.card a 4))) +(assert (_ fmf.card U 2)) +(assert (not (_ fmf.card U 4))) (check-sat) diff --git a/test/regress/regress0/fmf/fc-unsat-pent.smt2 b/test/regress/regress0/fmf/fc-unsat-pent.smt2 index 2d4000e6e..b07c53077 100644 --- a/test/regress/regress0/fmf/fc-unsat-pent.smt2 +++ b/test/regress/regress0/fmf/fc-unsat-pent.smt2 @@ -15,6 +15,6 @@ (assert (not (= d e))) (assert (not (= e a))) -(assert (fmf.card c 2)) +(assert (_ fmf.card U 2)) -(check-sat)
\ No newline at end of file +(check-sat) diff --git a/test/regress/regress0/fmf/fc-unsat-tot-2.smt2 b/test/regress/regress0/fmf/fc-unsat-tot-2.smt2 index 0d438f718..404b3abea 100644 --- a/test/regress/regress0/fmf/fc-unsat-tot-2.smt2 +++ b/test/regress/regress0/fmf/fc-unsat-tot-2.smt2 @@ -7,8 +7,8 @@ (declare-fun b () U) (declare-fun c () U) -(assert (not (fmf.card a 2))) +(assert (not (_ fmf.card U 2))) (assert (forall ((x U)) (or (= x a) (= x b)))) -(check-sat)
\ No newline at end of file +(check-sat) diff --git a/test/regress/regress0/fmf/issue4850-force-card.smt2 b/test/regress/regress0/fmf/issue4850-force-card.smt2 index 5aa7fc894..465584a83 100644 --- a/test/regress/regress0/fmf/issue4850-force-card.smt2 +++ b/test/regress/regress0/fmf/issue4850-force-card.smt2 @@ -2,5 +2,5 @@ (set-info :status sat) (declare-sort a 0) (declare-fun b () a) -(assert (not (fmf.card b 1))) +(assert (not (_ fmf.card a 1))) (check-sat) diff --git a/test/regress/regress0/fmf/issue4872-qf_ufc.smt2 b/test/regress/regress0/fmf/issue4872-qf_ufc.smt2 index c46bc1e28..c265dddcd 100644 --- a/test/regress/regress0/fmf/issue4872-qf_ufc.smt2 +++ b/test/regress/regress0/fmf/issue4872-qf_ufc.smt2 @@ -2,6 +2,6 @@ (set-info :status sat) (declare-sort S0 0) (declare-const S0-0 S0) -(assert (fmf.card S0-0 1)) -(assert (fmf.card S0-0 4)) +(assert (_ fmf.card S0 1)) +(assert (_ fmf.card S0 4)) (check-sat) diff --git a/test/regress/regress0/fmf/issue5239-uf-ss-tot.smt2 b/test/regress/regress0/fmf/issue5239-uf-ss-tot.smt2 index a92f2f441..d032114ac 100644 --- a/test/regress/regress0/fmf/issue5239-uf-ss-tot.smt2 +++ b/test/regress/regress0/fmf/issue5239-uf-ss-tot.smt2 @@ -2,5 +2,5 @@ (set-info :status sat) (declare-sort a 0) (declare-fun b () a) -(assert (fmf.card b 2)) +(assert (_ fmf.card a 2)) (check-sat) diff --git a/test/regress/regress0/fp/proj-issue329-prereg-context.smt2 b/test/regress/regress0/fp/proj-issue329-prereg-context.smt2 new file mode 100644 index 000000000..f32a4ed33 --- /dev/null +++ b/test/regress/regress0/fp/proj-issue329-prereg-context.smt2 @@ -0,0 +1,7 @@ +; COMMAND-LINE: --fp-exp +; EXPECT: sat +(set-logic ALL) +(declare-const x Float128) +(declare-const _x String) +(declare-fun x5 (Bool Float128) Bool) +(check-sat-assuming ((x5 (exists ((x (Array String Bool))) (and (select x _x) (or (select x _x) (x5 (exists ((x Bool)) true) (_ -oo 15 113))))) x))) diff --git a/test/regress/regress0/ho/qgu-fuzz-ho-2-dd-no-ext.smt2 b/test/regress/regress0/ho/qgu-fuzz-ho-2-dd-no-ext.smt2 new file mode 100644 index 000000000..7dc3188f2 --- /dev/null +++ b/test/regress/regress0/ho/qgu-fuzz-ho-2-dd-no-ext.smt2 @@ -0,0 +1,10 @@ +(set-logic HO_ALL) +(set-info :status sat) +(declare-const x6 Bool) +(declare-const x Int) +(declare-const b (-> Int Int Int)) +(declare-const c (-> Int Int)) +(assert (> (b 1 0) 0)) +(assert (= (c 0) (b 0 1))) +(assert(= c (ite x6 (b 1) (b (+ 1 x))))) +(check-sat) diff --git a/test/regress/regress0/issue5550-num-children.smt2 b/test/regress/regress0/issue5550-num-children.smt2 index 75810699b..62d078b32 100644 --- a/test/regress/regress0/issue5550-num-children.smt2 +++ b/test/regress/regress0/issue5550-num-children.smt2 @@ -2,5 +2,5 @@ (set-logic UFC) (declare-sort a 0) (declare-fun b () a) -(assert (not (fmf.card b 1))) -(check-sat)
\ No newline at end of file +(assert (not (_ fmf.card a 1))) +(check-sat) diff --git a/test/regress/regress0/options/ast-and-sexpr.smt2 b/test/regress/regress0/options/ast-and-sexpr.smt2 index 2a464571c..41012f888 100644 --- a/test/regress/regress0/options/ast-and-sexpr.smt2 +++ b/test/regress/regress0/options/ast-and-sexpr.smt2 @@ -13,5 +13,6 @@ (get-option :command-verbosity) ; There is no SMT option to get the verbosity of a specific command -(set-info :source (0 1 True False x "")) +(set-info :source (true false (- 15) 15 15.0 #b00001111 #x0f x |x +"| "" """")) (get-info :status) diff --git a/test/regress/regress0/preprocess/issue5729-rewritten-assertions.smt2 b/test/regress/regress0/preprocess/issue5729-rewritten-assertions.smt2 index 56d8bc107..a4c3c29f6 100644 --- a/test/regress/regress0/preprocess/issue5729-rewritten-assertions.smt2 +++ b/test/regress/regress0/preprocess/issue5729-rewritten-assertions.smt2 @@ -1,6 +1,5 @@ -; COMMAND-LINE: --no-bv-eq-solver ; EXPECT: sat (set-logic QF_ALL) (declare-fun x () (_ BitVec 1)) (assert (= (_ bv0 1) ((_ int2bv 1) (bv2nat x)))) -(check-sat)
\ No newline at end of file +(check-sat) diff --git a/test/regress/regress0/preprocess/proj-issue332-circuit-prop-xor.smt2 b/test/regress/regress0/preprocess/proj-issue332-circuit-prop-xor.smt2 new file mode 100644 index 000000000..841e7392b --- /dev/null +++ b/test/regress/regress0/preprocess/proj-issue332-circuit-prop-xor.smt2 @@ -0,0 +1,9 @@ +; EXPECT: sat +(set-logic ALL) +(set-option :check-proofs true) +(declare-const x Real) +(declare-const x4 Real) +(declare-const x8 Bool) +(assert (<= x4 x)) +(assert (not (xor (> x4 x) x8))) +(check-sat) diff --git a/test/regress/regress0/proofs/proj-issue326-nl-bounds-check.smt2 b/test/regress/regress0/proofs/proj-issue326-nl-bounds-check.smt2 new file mode 100644 index 000000000..bc10e9cac --- /dev/null +++ b/test/regress/regress0/proofs/proj-issue326-nl-bounds-check.smt2 @@ -0,0 +1,13 @@ +; EXPECT: unknown +(set-logic ALL) +(set-option :check-proofs true) +(set-option :proof-check eager) +(declare-const x Real) +(assert + (and + (< 1.0 x) + (<= x (/ 0.0 0.0 x)) + (<= (/ 0.0 0.0 x) x) + ) +) +(check-sat) diff --git a/test/regress/regress0/proofs/project-issue330-eqproof.smt2 b/test/regress/regress0/proofs/project-issue330-eqproof.smt2 new file mode 100644 index 000000000..1da778205 --- /dev/null +++ b/test/regress/regress0/proofs/project-issue330-eqproof.smt2 @@ -0,0 +1,7 @@ +; EXPECT: sat +(set-logic QF_SLIA) +(declare-const x String) +(declare-const x1 Int) +(set-option :check-proofs true) +(declare-const _x String) +(check-sat-assuming ((>= 0 (ite (= x (str.++ (str.from_code 0) (str.replace_all x (str.from_code 0) (str.++ (str.from_code 0) (str.from_code 0))) _x) (ite false x (str.++ _x _x _x)) x) x1 0))))
\ No newline at end of file diff --git a/test/regress/regress0/push-pop/inc-define.smt2 b/test/regress/regress0/push-pop/inc-define.smt2 index 27261eff6..57f4d711c 100644 --- a/test/regress/regress0/push-pop/inc-define.smt2 +++ b/test/regress/regress0/push-pop/inc-define.smt2 @@ -4,6 +4,6 @@ (set-logic QF_LIA) (declare-fun x () Int) (check-sat) -(define t (not (= x 0))) +(define-const t Bool (not (= x 0))) (assert t) (check-sat) diff --git a/test/regress/regress0/smtlib/issue4552.smt2 b/test/regress/regress0/smtlib/issue4552.smt2 index af8e0b948..8fcfabd5e 100644 --- a/test/regress/regress0/smtlib/issue4552.smt2 +++ b/test/regress/regress0/smtlib/issue4552.smt2 @@ -6,8 +6,8 @@ (set-option :global-declarations true) (push) -(define a true) -(define (f (b Bool)) b) +(define-const a Bool true) +(define-fun f ((b Bool)) Bool b) (define-const a2 Bool true) (define-fun a3 () Bool true) diff --git a/test/regress/regress1/bags/fuzzy3.smt2 b/test/regress/regress1/bags/fuzzy3.smt2 new file mode 100644 index 000000000..dd6dd02dc --- /dev/null +++ b/test/regress/regress1/bags/fuzzy3.smt2 @@ -0,0 +1,13 @@ +(set-logic ALL) +(set-info :status sat) +(set-option :produce-models true) +(declare-fun A () (Bag (Tuple Int Int))) +(declare-fun B () (Bag (Tuple Int Int))) +(declare-fun c () Int) +(declare-fun d () (Tuple Int Int)) +(assert + (not + (= + (= A (difference_remove (bag d c) A)) + (= A (bag (tuple c c) c))))) +(check-sat) diff --git a/test/regress/regress1/bags/fuzzy4.smt2 b/test/regress/regress1/bags/fuzzy4.smt2 new file mode 100644 index 000000000..b733a4862 --- /dev/null +++ b/test/regress/regress1/bags/fuzzy4.smt2 @@ -0,0 +1,15 @@ +(set-logic ALL) +(set-option :produce-models true) +(set-info :status sat) +(declare-fun A () (Bag (Tuple Int Int))) +(declare-fun c () Int) +(declare-fun d () (Tuple Int Int)) +(assert + (not + (= + (= A (bag d (+ c (bag.count d (union_disjoint A A))))) + (= A (difference_remove (bag d c) A))))) +(assert (= A (bag (tuple 0 0) 5))) +(assert (= c (- 5))) +(assert (= d (tuple 0 0))) +(check-sat) diff --git a/test/regress/regress1/bags/fuzzy5.smt2 b/test/regress/regress1/bags/fuzzy5.smt2 new file mode 100644 index 000000000..2dea236a5 --- /dev/null +++ b/test/regress/regress1/bags/fuzzy5.smt2 @@ -0,0 +1,21 @@ +(set-logic ALL) +(set-option :produce-models true) +(set-info :status sat) +(declare-fun A () (Bag (Tuple Int Int))) +(declare-fun c () Int) +(declare-fun d () (Tuple Int Int)) + +(assert + (let ((c_plus_1 (+ c 1))) + (and + (not + (= (= A (bag (tuple 0 c) (+ c c))) + (= A (difference_remove (bag d c) A)))) + (not + (= (= A (bag (tuple 0 1) c_plus_1)) + (= A (bag (tuple c 1) c_plus_1))))))) + +;(assert (= A (bag (tuple 0 1) 2))) +;(assert (= c 1)) +;(assert (= d (tuple 0 1))) +(check-sat)
\ No newline at end of file diff --git a/test/regress/regress1/bv/test-bv-abstraction.smt2 b/test/regress/regress1/bv/test-bv-abstraction.smt2 deleted file mode 100644 index 7a926d4be..000000000 --- a/test/regress/regress1/bv/test-bv-abstraction.smt2 +++ /dev/null @@ -1,24 +0,0 @@ -; COMMAND-LINE: --bv-abstraction -(set-logic QF_BV) -(set-info :status sat) -(declare-fun x0 () (_ BitVec 8)) -(declare-fun x1 () (_ BitVec 8)) -(declare-fun y0 () (_ BitVec 8)) -(declare-fun y1 () (_ BitVec 8)) -(declare-fun y2 () (_ BitVec 8)) -(assert - (or - (= x0 (bvadd (bvmul (_ bv2 8) y0) y1)) - (= x0 (bvadd (bvmul (_ bv2 8) y1) y2)) - (= x0 (bvadd (bvmul (_ bv2 8) y2) y0)) - ) -) -(assert - (or - (= x1 (bvadd (bvadd (bvmul (_ bv3 8) y0) (bvmul (_ bv2 8) x0)) (_ bv5 8))) - (= x1 (bvadd (bvadd (bvmul (_ bv3 8) y1) (bvmul (_ bv2 8) x0)) (_ bv5 8))) - (= x1 (bvadd (bvadd (bvmul (_ bv3 8) x0) (bvmul (_ bv2 8) y2)) (_ bv5 8))) - ) -) -(check-sat) -(exit) diff --git a/test/regress/regress1/fmf/fc-pigeonhole19.smt2 b/test/regress/regress1/fmf/fc-pigeonhole19.smt2 index f145013d8..2945a8a24 100644 --- a/test/regress/regress1/fmf/fc-pigeonhole19.smt2 +++ b/test/regress/regress1/fmf/fc-pigeonhole19.smt2 @@ -8,13 +8,13 @@ (declare-fun h () H) ; pigeonhole using native cardinality constraints -(assert (fmf.card p 19)) -(assert (not (fmf.card p 18))) -(assert (fmf.card h 18)) -(assert (not (fmf.card h 17))) +(assert (_ fmf.card P 19)) +(assert (not (_ fmf.card P 18))) +(assert (_ fmf.card H 18)) +(assert (not (_ fmf.card H 17))) ; each pigeon has different holes (declare-fun f (P) H) (assert (forall ((p1 P) (p2 P)) (=> (not (= p1 p2)) (not (= (f p1) (f p2)))))) -(check-sat)
\ No newline at end of file +(check-sat) diff --git a/test/regress/regress1/quantifiers/bi-artm-s.smt2 b/test/regress/regress1/quantifiers/bi-artm-s.smt2 index af8ee945d..9c6b821b5 100644 --- a/test/regress/regress1/quantifiers/bi-artm-s.smt2 +++ b/test/regress/regress1/quantifiers/bi-artm-s.smt2 @@ -1,6 +1,6 @@ ; COMMAND-LINE: --fmf-bound-lazy ; EXPECT: unsat -(set-option :incremental "false") +(set-option :incremental false) (set-info :status unsat) (set-logic ALL) (declare-fun Y () String) diff --git a/test/regress/regress1/quantifiers/issue4813-qe-quant.smt2 b/test/regress/regress1/quantifiers/issue4813-qe-quant.smt2 new file mode 100644 index 000000000..d20f14a7c --- /dev/null +++ b/test/regress/regress1/quantifiers/issue4813-qe-quant.smt2 @@ -0,0 +1,6 @@ +; EXPECT: v24 +(set-logic LIA) +(declare-const v8 Bool) +(assert (not (exists ((q16 Bool)) (xor true q16 v8 q16)))) +(declare-const v24 Bool) +(get-qe (exists ((q17 Bool) (q18 Int) (q19 Int) (q20 Int) (q21 Int) (q22 Bool)) v24)) diff --git a/test/regress/regress1/quantifiers/issue7537-cegqi-comp-types.smt2 b/test/regress/regress1/quantifiers/issue7537-cegqi-comp-types.smt2 new file mode 100644 index 000000000..bc9691ece --- /dev/null +++ b/test/regress/regress1/quantifiers/issue7537-cegqi-comp-types.smt2 @@ -0,0 +1,6 @@ +(set-logic ALL) +(set-info :status sat) +(declare-fun r1 () Real) +(declare-fun r5 () Real) +(assert (forall ((q102 Int)) (or (= q102 (/ r1 r5)) (= (= 0.0 q102) (< 1.0 (/ r1 r5)))))) +(check-sat) diff --git a/test/regress/regress1/rels/qgu-fuzz-relations-2.smt2 b/test/regress/regress1/rels/qgu-fuzz-relations-2.smt2 new file mode 100644 index 000000000..185c06502 --- /dev/null +++ b/test/regress/regress1/rels/qgu-fuzz-relations-2.smt2 @@ -0,0 +1,8 @@ +(set-logic ALL) +(set-info :status sat) +(declare-fun a () (Set (Tuple Int Int))) +(declare-fun b () (Set (Tuple Int Int))) +(declare-fun c () Int) +(declare-fun d () (Tuple Int Int)) +(assert (and (= a (singleton (tuple (+ c 1) 1))) (= (tclosure b) (join a a)))) +(check-sat) diff --git a/test/regress/regress1/rels/qgu-fuzz-relations-3-upwards.smt2 b/test/regress/regress1/rels/qgu-fuzz-relations-3-upwards.smt2 new file mode 100644 index 000000000..1cb91e94c --- /dev/null +++ b/test/regress/regress1/rels/qgu-fuzz-relations-3-upwards.smt2 @@ -0,0 +1,11 @@ +(set-logic ALL) +(set-info :status sat) +(declare-fun b () (Set (Tuple Int Int))) +(assert +(= (join b (tclosure (join b b))) (as emptyset (Set (Tuple Int Int)))) +) +(assert +(distinct b (as emptyset (Set (Tuple Int Int)))) +) +(assert (= (join b b) (as emptyset (Set (Tuple Int Int))))) +(check-sat) diff --git a/test/regress/regress1/strings/proj-issue331.smt2 b/test/regress/regress1/strings/proj-issue331.smt2 new file mode 100644 index 000000000..e993419f1 --- /dev/null +++ b/test/regress/regress1/strings/proj-issue331.smt2 @@ -0,0 +1,7 @@ +; COMMAND-LINE: --strings-exp +; EXPECT: unsat +(set-logic ALL) +(set-option :check-proofs true) +(set-info :status unsat) +(declare-const x Int) +(check-sat-assuming ((str.< (str.++ (str.from_int x) (str.replace_re (str.from_int x) re.none (str.from_int 0)) (str.replace_re (str.from_int x) re.none (str.from_int 0))) (str.from_int x)))) diff --git a/test/regress/regress2/quantifiers/cee-event-wrong-sat.smt2 b/test/regress/regress2/quantifiers/cee-event-wrong-sat.smt2 index c0b3aac7c..4a132a39b 100644 --- a/test/regress/regress2/quantifiers/cee-event-wrong-sat.smt2 +++ b/test/regress/regress2/quantifiers/cee-event-wrong-sat.smt2 @@ -1,5 +1,5 @@ -; COMMAND-LINE: --full-saturate-quant --ee-mode=distributed -; COMMAND-LINE: --full-saturate-quant --ee-mode=central +; COMMAND-LINE: -q --full-saturate-quant --ee-mode=distributed +; COMMAND-LINE: -q --full-saturate-quant --ee-mode=central ; EXPECT: unsat (set-logic ALL) (set-info :status unsat) @@ -23,7 +23,7 @@ (declare-fun $Event_EventHandleGenerator_type_value () T@$TypeValue) (assert (= 0 (|l#R| $EmptyValueArray))) (assert (forall ((v1 T@$Value) (v2 T@$Value)) (= ($IsEqual_stratified v1 v2) (or (= v1 v2) (forall ((i Int)) (or (> 0 i) (>= i (|l#R| (|v#V| v1))) ($IsEqual_stratified (sel (|v#R| (|v#V| v1)) i) (sel (|v#R| (|v#V| v2)) i)))))))) -(assert (forall ((m@@0 T@M) (a@@0 T@$Value)) (! (or (not (is-D a@@0)) (and (is-I (sel (|v#R| (|v#V| (s (|contents#M| m@@0) (G $Event_EventHandleGenerator_type_value (|a#D| a@@0))))) $Event_EventHandleGenerator_counter)) (forall ((x@@10 Int)) (or (> x@@10 0) (= E (sel (|v#R| (|v#V| (s (|contents#M| m@@0) (G $LibraAccount_T_type_value (|a#D| a@@0))))) x@@10)))))) :qid :skolemid))) +(assert (forall ((m@@0 T@M) (a@@0 T@$Value)) (! (or (not (is-D a@@0)) (and (is-I (sel (|v#R| (|v#V| (s (|contents#M| m@@0) (G $Event_EventHandleGenerator_type_value (|a#D| a@@0))))) $Event_EventHandleGenerator_counter)) (forall ((x@@10 Int)) (or (> x@@10 0) (= E (sel (|v#R| (|v#V| (s (|contents#M| m@@0) (G $LibraAccount_T_type_value (|a#D| a@@0))))) x@@10)))))) :qid || :skolemid ||))) (declare-fun |Select_[$Location]$bool| (b T@$Location) Bool) (declare-fun $m@@0 () T@M) (declare-fun $abort_flag@2 () Bool) diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 2e15cff4b..bbfc2a74b 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -53,9 +53,11 @@ macro(cvc5_add_unit_test is_white name output_dir) if(${is_white}) target_compile_options(${name} PRIVATE -fno-access-control) endif() + # Disable the Wunused-comparison warnings for the unit tests. - check_cxx_compiler_flag("-Wno-unused-comparison" HAVE_FLAGWno_unused_comparison) - if(HAVE_FLAGWno_unused_comparison) + # We check for `-Wunused-comparison` and then add `-Wno-unused-comparison` + check_cxx_compiler_flag("-Wunused-comparison" HAVE_CXX_FLAGWunused_comparison) + if(HAVE_CXX_FLAGWunused_comparison) target_compile_options(${name} PRIVATE -Wno-unused-comparison) endif() add_dependencies(build-units ${name}) diff --git a/test/unit/api/java/DatatypeTest.java b/test/unit/api/java/DatatypeTest.java index cd9d7ee73..fb23ea515 100644 --- a/test/unit/api/java/DatatypeTest.java +++ b/test/unit/api/java/DatatypeTest.java @@ -33,6 +33,11 @@ class DatatypeTest d_solver = new Solver(); } + @AfterEach void tearDown() + { + d_solver.close(); + } + @Test void mkDatatypeSort() throws CVC5ApiException { DatatypeDecl dtypeSpec = d_solver.mkDatatypeDecl("list"); diff --git a/test/unit/api/java/GrammarTest.java b/test/unit/api/java/GrammarTest.java index e9b0d730c..37e1b5206 100644 --- a/test/unit/api/java/GrammarTest.java +++ b/test/unit/api/java/GrammarTest.java @@ -32,6 +32,11 @@ class GrammarTest d_solver = new Solver(); } + @AfterEach void tearDown() + { + d_solver.close(); + } + @Test void addRule() { Sort bool = d_solver.getBooleanSort(); diff --git a/test/unit/api/java/OpTest.java b/test/unit/api/java/OpTest.java index c63157155..9b4999211 100644 --- a/test/unit/api/java/OpTest.java +++ b/test/unit/api/java/OpTest.java @@ -32,6 +32,11 @@ class OpTest d_solver = new Solver(); } + @AfterEach void tearDown() + { + d_solver.close(); + } + @Test void getKind() throws CVC5ApiException { Op x; diff --git a/test/unit/api/java/ResultTest.java b/test/unit/api/java/ResultTest.java index 38e981888..59bd752ca 100644 --- a/test/unit/api/java/ResultTest.java +++ b/test/unit/api/java/ResultTest.java @@ -31,6 +31,11 @@ class ResultTest d_solver = new Solver(); } + @AfterEach void tearDown() + { + d_solver.close(); + } + @Test void isNull() { Result res_null = d_solver.getNullResult(); diff --git a/test/unit/api/java/SolverTest.java b/test/unit/api/java/SolverTest.java index 1f88add2d..4c9ec4c0d 100644 --- a/test/unit/api/java/SolverTest.java +++ b/test/unit/api/java/SolverTest.java @@ -35,6 +35,11 @@ class SolverTest d_solver = new Solver(); } + @AfterEach void tearDown() + { + d_solver.close(); + } + @Test void recoverableException() throws CVC5ApiException { d_solver.setOption("produce-models", "true"); @@ -102,6 +107,7 @@ class SolverTest Solver slv = new Solver(); assertThrows(CVC5ApiException.class, () -> slv.mkArraySort(boolSort, boolSort)); + slv.close(); } @Test void mkBitVectorSort() throws CVC5ApiException @@ -132,6 +138,7 @@ class SolverTest DatatypeDecl throwsDtypeSpec = d_solver.mkDatatypeDecl("list"); assertThrows(CVC5ApiException.class, () -> d_solver.mkDatatypeSort(throwsDtypeSpec)); + slv.close(); } @Test void mkDatatypeSorts() throws CVC5ApiException @@ -175,6 +182,7 @@ class SolverTest assertThrows( CVC5ApiException.class, () -> slv.mkDatatypeSorts(Arrays.asList(udecls), unresSorts)); + slv.close(); /* Note: More tests are in datatype_api_black. */ } @@ -227,6 +235,7 @@ class SolverTest assertThrows(CVC5ApiException.class, () -> slv.mkFunctionSort(sorts1, slv.getIntegerSort())); assertThrows( CVC5ApiException.class, () -> slv.mkFunctionSort(sorts2, d_solver.getIntegerSort())); + slv.close(); } @Test void mkParamSort() throws CVC5ApiException @@ -248,6 +257,7 @@ class SolverTest Solver slv = new Solver(); assertThrows( CVC5ApiException.class, () -> slv.mkPredicateSort(new Sort[] {d_solver.getIntegerSort()})); + slv.close(); } @Test void mkRecordSort() throws CVC5ApiException @@ -263,6 +273,7 @@ class SolverTest Solver slv = new Solver(); assertThrows(CVC5ApiException.class, () -> slv.mkRecordSort(fields)); + slv.close(); } @Test void mkSetSort() throws CVC5ApiException @@ -272,6 +283,7 @@ class SolverTest assertDoesNotThrow(() -> d_solver.mkSetSort(d_solver.mkBitVectorSort(4))); Solver slv = new Solver(); assertThrows(CVC5ApiException.class, () -> slv.mkSetSort(d_solver.mkBitVectorSort(4))); + slv.close(); } @Test void mkBagSort() throws CVC5ApiException @@ -281,6 +293,7 @@ class SolverTest assertDoesNotThrow(() -> d_solver.mkBagSort(d_solver.mkBitVectorSort(4))); Solver slv = new Solver(); assertThrows(CVC5ApiException.class, () -> slv.mkBagSort(d_solver.mkBitVectorSort(4))); + slv.close(); } @Test void mkSequenceSort() throws CVC5ApiException @@ -290,6 +303,7 @@ class SolverTest () -> d_solver.mkSequenceSort(d_solver.mkSequenceSort(d_solver.getIntegerSort()))); Solver slv = new Solver(); assertThrows(CVC5ApiException.class, () -> slv.mkSequenceSort(d_solver.getIntegerSort())); + slv.close(); } @Test void mkUninterpretedSort() throws CVC5ApiException @@ -316,6 +330,7 @@ class SolverTest Solver slv = new Solver(); assertThrows( CVC5ApiException.class, () -> slv.mkTupleSort(new Sort[] {d_solver.getIntegerSort()})); + slv.close(); } @Test void mkBitVector() throws CVC5ApiException @@ -374,6 +389,7 @@ class SolverTest assertThrows(CVC5ApiException.class, () -> d_solver.mkVar(d_solver.getNullSort(), "a")); Solver slv = new Solver(); assertThrows(CVC5ApiException.class, () -> slv.mkVar(boolSort, "x")); + slv.close(); } @Test void mkBoolean() throws CVC5ApiException @@ -422,6 +438,7 @@ class SolverTest Solver slv = new Solver(); assertThrows(CVC5ApiException.class, () -> slv.mkFloatingPoint(3, 5, t1)); + slv.close(); } @Test void mkCardinalityConstraint() throws CVC5ApiException @@ -429,13 +446,11 @@ class SolverTest Sort su = d_solver.mkUninterpretedSort("u"); Sort si = d_solver.getIntegerSort(); assertDoesNotThrow(() -> d_solver.mkCardinalityConstraint(su, 3)); - assertThrows( - CVC5ApiException.class, () -> d_solver.mkCardinalityConstraint(si, 3)); - assertThrows( - CVC5ApiException.class, () -> d_solver.mkCardinalityConstraint(su, 0)); + assertThrows(CVC5ApiException.class, () -> d_solver.mkCardinalityConstraint(si, 3)); + assertThrows(CVC5ApiException.class, () -> d_solver.mkCardinalityConstraint(su, 0)); Solver slv = new Solver(); - assertThrows( - CVC5ApiException.class, () -> slv.mkCardinalityConstraint(su, 3)); + assertThrows(CVC5ApiException.class, () -> slv.mkCardinalityConstraint(su, 3)); + slv.close(); } @Test void mkEmptySet() throws CVC5ApiException @@ -446,6 +461,7 @@ class SolverTest assertDoesNotThrow(() -> d_solver.mkEmptySet(s)); assertThrows(CVC5ApiException.class, () -> d_solver.mkEmptySet(d_solver.getBooleanSort())); assertThrows(CVC5ApiException.class, () -> slv.mkEmptySet(s)); + slv.close(); } @Test void mkEmptyBag() throws CVC5ApiException @@ -457,6 +473,7 @@ class SolverTest assertThrows(CVC5ApiException.class, () -> d_solver.mkEmptyBag(d_solver.getBooleanSort())); assertThrows(CVC5ApiException.class, () -> slv.mkEmptyBag(s)); + slv.close(); } @Test void mkEmptySequence() throws CVC5ApiException @@ -466,6 +483,7 @@ class SolverTest assertDoesNotThrow(() -> d_solver.mkEmptySequence(s)); assertDoesNotThrow(() -> d_solver.mkEmptySequence(d_solver.getBooleanSort())); assertThrows(CVC5ApiException.class, () -> slv.mkEmptySequence(s)); + slv.close(); } @Test void mkFalse() throws CVC5ApiException @@ -639,6 +657,7 @@ class SolverTest assertThrows(CVC5ApiException.class, () -> d_solver.mkSepNil(d_solver.getNullSort())); Solver slv = new Solver(); assertThrows(CVC5ApiException.class, () -> slv.mkSepNil(d_solver.getIntegerSort())); + slv.close(); } @Test void mkString() @@ -704,6 +723,7 @@ class SolverTest assertThrows(CVC5ApiException.class, () -> d_solver.mkTerm(EQUAL, v2)); assertThrows(CVC5ApiException.class, () -> d_solver.mkTerm(EQUAL, v3)); assertThrows(CVC5ApiException.class, () -> d_solver.mkTerm(DISTINCT, v6)); + slv.close(); } @Test void mkTermFromOp() throws CVC5ApiException @@ -804,6 +824,7 @@ class SolverTest assertThrows(CVC5ApiException.class, () -> d_solver.mkTerm(opterm2, v2)); assertThrows(CVC5ApiException.class, () -> d_solver.mkTerm(opterm2, v3)); assertThrows(CVC5ApiException.class, () -> slv.mkTerm(opterm2, v4)); + slv.close(); } @Test void mkTrue() @@ -844,6 +865,7 @@ class SolverTest () -> slv.mkTuple(new Sort[] {slv.mkBitVectorSort(3)}, new Term[] {d_solver.mkBitVector(3, "101", 2)})); + slv.close(); } @Test void mkUniverseSet() @@ -852,6 +874,7 @@ class SolverTest assertThrows(CVC5ApiException.class, () -> d_solver.mkUniverseSet(d_solver.getNullSort())); Solver slv = new Solver(); assertThrows(CVC5ApiException.class, () -> slv.mkUniverseSet(d_solver.getBooleanSort())); + slv.close(); } @Test void mkConst() @@ -870,6 +893,7 @@ class SolverTest Solver slv = new Solver(); assertThrows(CVC5ApiException.class, () -> slv.mkConst(boolSort)); + slv.close(); } @Test void mkConstArray() @@ -892,6 +916,7 @@ class SolverTest Sort arrSort2 = slv.mkArraySort(slv.getIntegerSort(), slv.getIntegerSort()); assertThrows(CVC5ApiException.class, () -> slv.mkConstArray(arrSort2, zero)); assertThrows(CVC5ApiException.class, () -> slv.mkConstArray(arrSort, zero2)); + slv.close(); } @Test void declareDatatype() @@ -914,6 +939,7 @@ class SolverTest Solver slv = new Solver(); assertThrows(CVC5ApiException.class, () -> slv.declareDatatype(("a"), ctors1)); + slv.close(); } @Test void declareFun() throws CVC5ApiException @@ -932,6 +958,7 @@ class SolverTest Solver slv = new Solver(); assertThrows(CVC5ApiException.class, () -> slv.declareFun("f1", new Sort[] {}, bvSort)); + slv.close(); } @Test void declareSort() @@ -959,38 +986,25 @@ class SolverTest @Test void defineFun() throws CVC5ApiException { Sort bvSort = d_solver.mkBitVectorSort(32); - Sort funSort1 = d_solver.mkFunctionSort(new Sort[] {bvSort, bvSort}, bvSort); - Sort funSort2 = + Sort funSort = d_solver.mkFunctionSort(d_solver.mkUninterpretedSort("u"), d_solver.getIntegerSort()); Term b1 = d_solver.mkVar(bvSort, "b1"); - Term b11 = d_solver.mkVar(bvSort, "b1"); Term b2 = d_solver.mkVar(d_solver.getIntegerSort(), "b2"); - Term b3 = d_solver.mkVar(funSort2, "b3"); + Term b3 = d_solver.mkVar(funSort, "b3"); Term v1 = d_solver.mkConst(bvSort, "v1"); - Term v2 = d_solver.mkConst(d_solver.getIntegerSort(), "v2"); - Term v3 = d_solver.mkConst(funSort2, "v3"); - Term f1 = d_solver.mkConst(funSort1, "f1"); - Term f2 = d_solver.mkConst(funSort2, "f2"); - Term f3 = d_solver.mkConst(bvSort, "f3"); + Term v2 = d_solver.mkConst(funSort, "v2"); assertDoesNotThrow(() -> d_solver.defineFun("f", new Term[] {}, bvSort, v1)); assertDoesNotThrow(() -> d_solver.defineFun("ff", new Term[] {b1, b2}, bvSort, v1)); - assertDoesNotThrow(() -> d_solver.defineFun(f1, new Term[] {b1, b11}, v1)); assertThrows( CVC5ApiException.class, () -> d_solver.defineFun("ff", new Term[] {v1, b2}, bvSort, v1)); assertThrows( - CVC5ApiException.class, () -> d_solver.defineFun("fff", new Term[] {b1}, bvSort, v3)); + CVC5ApiException.class, () -> d_solver.defineFun("fff", new Term[] {b1}, bvSort, v2)); assertThrows( - CVC5ApiException.class, () -> d_solver.defineFun("ffff", new Term[] {b1}, funSort2, v3)); + CVC5ApiException.class, () -> d_solver.defineFun("ffff", new Term[] {b1}, funSort, v2)); // b3 has function sort, which is allowed as an argument assertDoesNotThrow(() -> d_solver.defineFun("fffff", new Term[] {b1, b3}, bvSort, v1)); - assertThrows(CVC5ApiException.class, () -> d_solver.defineFun(f1, new Term[] {v1, b11}, v1)); - assertThrows(CVC5ApiException.class, () -> d_solver.defineFun(f1, new Term[] {b1}, v1)); - assertThrows(CVC5ApiException.class, () -> d_solver.defineFun(f1, new Term[] {b1, b11}, v2)); - assertThrows(CVC5ApiException.class, () -> d_solver.defineFun(f1, new Term[] {b1, b11}, v3)); - assertThrows(CVC5ApiException.class, () -> d_solver.defineFun(f2, new Term[] {b1}, v2)); - assertThrows(CVC5ApiException.class, () -> d_solver.defineFun(f3, new Term[] {b1}, v1)); Solver slv = new Solver(); Sort bvSort2 = slv.mkBitVectorSort(32); @@ -1007,20 +1021,19 @@ class SolverTest CVC5ApiException.class, () -> slv.defineFun("ff", new Term[] {b12, b22}, bvSort, v12)); assertThrows( CVC5ApiException.class, () -> slv.defineFun("ff", new Term[] {b12, b22}, bvSort2, v1)); + slv.close(); } @Test void defineFunGlobal() { Sort bSort = d_solver.getBooleanSort(); - Sort fSort = d_solver.mkFunctionSort(bSort, bSort); Term bTrue = d_solver.mkBoolean(true); // (define-fun f () Bool true) Term f = d_solver.defineFun("f", new Term[] {}, bSort, bTrue, true); Term b = d_solver.mkVar(bSort, "b"); - Term gSym = d_solver.mkConst(fSort, "g"); // (define-fun g (b Bool) Bool b) - Term g = d_solver.defineFun(gSym, new Term[] {b}, b, true); + Term g = d_solver.defineFun("g", new Term[] {b}, bSort, b, true); // (assert (or (not f) (not (g true)))) d_solver.assertFormula( @@ -1089,6 +1102,7 @@ class SolverTest assertThrows( CVC5ApiException.class, () -> slv.defineFunRec("ff", new Term[] {b12, b22}, bvSort2, v1)); + slv.close(); } @Test void defineFunRecWrongLogic() throws CVC5ApiException @@ -1216,6 +1230,7 @@ class SolverTest () -> slv.defineFunsRec( new Term[] {f12, f22}, new Term[][] {{b12, b112}, {b42}}, new Term[] {v12, v2})); + slv.close(); } @Test void defineFunsRecWrongLogic() throws CVC5ApiException @@ -1596,6 +1611,7 @@ class SolverTest Solver slv = new Solver(); assertThrows(CVC5ApiException.class, () -> slv.getValue(x)); + slv.close(); } @Test void getModelDomainElements() @@ -1695,10 +1711,12 @@ class SolverTest d_solver.mkTerm(OR, x, d_solver.mkTerm(NOT, x))); assertThrows( CVC5ApiException.class, () -> d_solver.getQuantifierElimination(d_solver.getNullTerm())); - assertThrows(CVC5ApiException.class, - () -> d_solver.getQuantifierElimination(new Solver().mkBoolean(false))); + Solver slv = new Solver(); + assertThrows( + CVC5ApiException.class, () -> d_solver.getQuantifierElimination(slv.mkBoolean(false))); assertDoesNotThrow(() -> d_solver.getQuantifierElimination(forall)); + slv.close(); } @Test void getQuantifierEliminationDisjunct() @@ -1710,19 +1728,21 @@ class SolverTest assertThrows(CVC5ApiException.class, () -> d_solver.getQuantifierEliminationDisjunct(d_solver.getNullTerm())); + Solver slv = new Solver(); assertThrows(CVC5ApiException.class, - () -> d_solver.getQuantifierEliminationDisjunct(new Solver().mkBoolean(false))); + () -> d_solver.getQuantifierEliminationDisjunct(slv.mkBoolean(false))); assertDoesNotThrow(() -> d_solver.getQuantifierEliminationDisjunct(forall)); + slv.close(); } - @Test void declareSeparationHeap() throws CVC5ApiException + @Test void declareSepHeap() throws CVC5ApiException { d_solver.setLogic("ALL"); Sort integer = d_solver.getIntegerSort(); - assertDoesNotThrow(() -> d_solver.declareSeparationHeap(integer, integer)); + assertDoesNotThrow(() -> d_solver.declareSepHeap(integer, integer)); // cannot declare separation logic heap more than once - assertThrows(CVC5ApiException.class, () -> d_solver.declareSeparationHeap(integer, integer)); + assertThrows(CVC5ApiException.class, () -> d_solver.declareSepHeap(integer, integer)); } /** @@ -1734,7 +1754,7 @@ class SolverTest { Sort integer = solver.getIntegerSort(); // declare the separation heap - solver.declareSeparationHeap(integer, integer); + solver.declareSepHeap(integer, integer); Term x = solver.mkConst(integer, "x"); Term p = solver.mkConst(integer, "p"); Term heap = solver.mkTerm(SEP_PTO, p, x); @@ -1744,26 +1764,26 @@ class SolverTest solver.checkSat(); } - @Test void getSeparationHeapTerm1() throws CVC5ApiException + @Test void getValueSepHeap1() throws CVC5ApiException { d_solver.setLogic("QF_BV"); d_solver.setOption("incremental", "false"); d_solver.setOption("produce-models", "true"); Term t = d_solver.mkTrue(); d_solver.assertFormula(t); - assertThrows(CVC5ApiException.class, () -> d_solver.getSeparationHeap()); + assertThrows(CVC5ApiException.class, () -> d_solver.getValueSepHeap()); } - @Test void getSeparationHeapTerm2() throws CVC5ApiException + @Test void getValueSepHeap2() throws CVC5ApiException { d_solver.setLogic("ALL"); d_solver.setOption("incremental", "false"); d_solver.setOption("produce-models", "false"); checkSimpleSeparationConstraints(d_solver); - assertThrows(CVC5ApiException.class, () -> d_solver.getSeparationHeap()); + assertThrows(CVC5ApiException.class, () -> d_solver.getValueSepHeap()); } - @Test void getSeparationHeapTerm3() throws CVC5ApiException + @Test void getValueSepHeap3() throws CVC5ApiException { d_solver.setLogic("ALL"); d_solver.setOption("incremental", "false"); @@ -1771,10 +1791,10 @@ class SolverTest Term t = d_solver.mkFalse(); d_solver.assertFormula(t); d_solver.checkSat(); - assertThrows(CVC5ApiException.class, () -> d_solver.getSeparationHeap()); + assertThrows(CVC5ApiException.class, () -> d_solver.getValueSepHeap()); } - @Test void getSeparationHeapTerm4() throws CVC5ApiException + @Test void getValueSepHeap4() throws CVC5ApiException { d_solver.setLogic("ALL"); d_solver.setOption("incremental", "false"); @@ -1782,38 +1802,38 @@ class SolverTest Term t = d_solver.mkTrue(); d_solver.assertFormula(t); d_solver.checkSat(); - assertThrows(CVC5ApiException.class, () -> d_solver.getSeparationHeap()); + assertThrows(CVC5ApiException.class, () -> d_solver.getValueSepHeap()); } - @Test void getSeparationHeapTerm5() throws CVC5ApiException + @Test void getValueSepHeap5() throws CVC5ApiException { d_solver.setLogic("ALL"); d_solver.setOption("incremental", "false"); d_solver.setOption("produce-models", "true"); checkSimpleSeparationConstraints(d_solver); - assertDoesNotThrow(() -> d_solver.getSeparationHeap()); + assertDoesNotThrow(() -> d_solver.getValueSepHeap()); } - @Test void getSeparationNilTerm1() throws CVC5ApiException + @Test void getValueSepNil1() throws CVC5ApiException { d_solver.setLogic("QF_BV"); d_solver.setOption("incremental", "false"); d_solver.setOption("produce-models", "true"); Term t = d_solver.mkTrue(); d_solver.assertFormula(t); - assertThrows(CVC5ApiException.class, () -> d_solver.getSeparationNilTerm()); + assertThrows(CVC5ApiException.class, () -> d_solver.getValueSepNil()); } - @Test void getSeparationNilTerm2() throws CVC5ApiException + @Test void getValueSepNil2() throws CVC5ApiException { d_solver.setLogic("ALL"); d_solver.setOption("incremental", "false"); d_solver.setOption("produce-models", "false"); checkSimpleSeparationConstraints(d_solver); - assertThrows(CVC5ApiException.class, () -> d_solver.getSeparationNilTerm()); + assertThrows(CVC5ApiException.class, () -> d_solver.getValueSepNil()); } - @Test void getSeparationNilTerm3() throws CVC5ApiException + @Test void getValueSepNil3() throws CVC5ApiException { d_solver.setLogic("ALL"); d_solver.setOption("incremental", "false"); @@ -1821,10 +1841,10 @@ class SolverTest Term t = d_solver.mkFalse(); d_solver.assertFormula(t); d_solver.checkSat(); - assertThrows(CVC5ApiException.class, () -> d_solver.getSeparationNilTerm()); + assertThrows(CVC5ApiException.class, () -> d_solver.getValueSepNil()); } - @Test void getSeparationNilTerm4() throws CVC5ApiException + @Test void getValueSepNil4() throws CVC5ApiException { d_solver.setLogic("ALL"); d_solver.setOption("incremental", "false"); @@ -1832,16 +1852,16 @@ class SolverTest Term t = d_solver.mkTrue(); d_solver.assertFormula(t); d_solver.checkSat(); - assertThrows(CVC5ApiException.class, () -> d_solver.getSeparationNilTerm()); + assertThrows(CVC5ApiException.class, () -> d_solver.getValueSepNil()); } - @Test void getSeparationNilTerm5() throws CVC5ApiException + @Test void getValueSepNil5() throws CVC5ApiException { d_solver.setLogic("ALL"); d_solver.setOption("incremental", "false"); d_solver.setOption("produce-models", "true"); checkSimpleSeparationConstraints(d_solver); - assertDoesNotThrow(() -> d_solver.getSeparationNilTerm()); + assertDoesNotThrow(() -> d_solver.getValueSepNil()); } @Test void push1() @@ -1925,8 +1945,10 @@ class SolverTest assertThrows(CVC5ApiException.class, () -> d_solver.blockModelValues(new Term[] {})); assertThrows(CVC5ApiException.class, () -> d_solver.blockModelValues(new Term[] {d_solver.getNullTerm()})); - assertThrows(CVC5ApiException.class, - () -> d_solver.blockModelValues(new Term[] {new Solver().mkBoolean(false)})); + Solver slv = new Solver(); + assertThrows( + CVC5ApiException.class, () -> d_solver.blockModelValues(new Term[] {slv.mkBoolean(false)})); + slv.close(); } @Test void blockModelValues2() throws CVC5ApiException @@ -2064,6 +2086,7 @@ class SolverTest d_solver.defineFunsRec(new Term[] {f1, f2}, new Term[][] {{b1, b2}, {b3}}, new Term[] {v1, v2}); assertDoesNotThrow(() -> d_solver.simplify(f1)); assertDoesNotThrow(() -> d_solver.simplify(f2)); + slv.close(); } @Test void assertFormula() @@ -2072,6 +2095,7 @@ class SolverTest assertThrows(CVC5ApiException.class, () -> d_solver.assertFormula(d_solver.getNullTerm())); Solver slv = new Solver(); assertThrows(CVC5ApiException.class, () -> slv.assertFormula(d_solver.mkTrue())); + slv.close(); } @Test void checkEntailed() @@ -2081,6 +2105,7 @@ class SolverTest assertThrows(CVC5ApiException.class, () -> d_solver.checkEntailed(d_solver.mkTrue())); Solver slv = new Solver(); assertThrows(CVC5ApiException.class, () -> slv.checkEntailed(d_solver.mkTrue())); + slv.close(); } @Test void checkEntailed1() @@ -2096,6 +2121,7 @@ class SolverTest assertDoesNotThrow(() -> d_solver.checkEntailed(z)); Solver slv = new Solver(); assertThrows(CVC5ApiException.class, () -> slv.checkEntailed(d_solver.mkTrue())); + slv.close(); } @Test void checkEntailed2() @@ -2146,6 +2172,7 @@ class SolverTest Solver slv = new Solver(); assertThrows(CVC5ApiException.class, () -> slv.checkEntailed(d_solver.mkTrue())); + slv.close(); } @Test void checkSat() throws CVC5ApiException @@ -2162,6 +2189,7 @@ class SolverTest assertThrows(CVC5ApiException.class, () -> d_solver.checkSatAssuming(d_solver.mkTrue())); Solver slv = new Solver(); assertThrows(CVC5ApiException.class, () -> slv.checkSatAssuming(d_solver.mkTrue())); + slv.close(); } @Test void checkSatAssuming1() throws CVC5ApiException @@ -2177,6 +2205,7 @@ class SolverTest assertDoesNotThrow(() -> d_solver.checkSatAssuming(z)); Solver slv = new Solver(); assertThrows(CVC5ApiException.class, () -> slv.checkSatAssuming(d_solver.mkTrue())); + slv.close(); } @Test void checkSatAssuming2() throws CVC5ApiException @@ -2227,6 +2256,7 @@ class SolverTest Solver slv = new Solver(); assertThrows(CVC5ApiException.class, () -> slv.checkSatAssuming(d_solver.mkTrue())); + slv.close(); } @Test void setLogic() throws CVC5ApiException @@ -2276,6 +2306,7 @@ class SolverTest Solver slv = new Solver(); assertThrows(CVC5ApiException.class, () -> slv.mkSygusVar(boolSort)); + slv.close(); } @Test void mkSygusGrammar() throws CVC5ApiException @@ -2306,6 +2337,7 @@ class SolverTest () -> slv.mkSygusGrammar(new Term[] {boolVar}, new Term[] {intVar2})); assertThrows(CVC5ApiException.class, () -> slv.mkSygusGrammar(new Term[] {boolVar2}, new Term[] {intVar})); + slv.close(); } @Test void synthFun() throws CVC5ApiException @@ -2343,6 +2375,7 @@ class SolverTest CVC5ApiException.class, () -> slv.synthFun("", new Term[] {}, d_solver.getBooleanSort())); assertThrows(CVC5ApiException.class, () -> slv.synthFun("f1", new Term[] {x}, d_solver.getBooleanSort())); + slv.close(); } @Test void synthInv() throws CVC5ApiException @@ -2382,6 +2415,7 @@ class SolverTest Solver slv = new Solver(); assertThrows(CVC5ApiException.class, () -> slv.addSygusConstraint(boolTerm)); + slv.close(); } @Test void addSygusAssume() @@ -2396,6 +2430,7 @@ class SolverTest Solver slv = new Solver(); assertThrows(CVC5ApiException.class, () -> slv.addSygusAssume(boolTerm)); + slv.close(); } @Test void addSygusInvConstraint() throws CVC5ApiException @@ -2460,6 +2495,7 @@ class SolverTest CVC5ApiException.class, () -> slv.addSygusInvConstraint(inv22, pre22, trans, post22)); assertThrows( CVC5ApiException.class, () -> slv.addSygusInvConstraint(inv22, pre22, trans22, post)); + slv.close(); } @Test void getSynthSolution() throws CVC5ApiException @@ -2483,6 +2519,7 @@ class SolverTest Solver slv = new Solver(); assertThrows(CVC5ApiException.class, () -> slv.getSynthSolution(f)); + slv.close(); } @Test void getSynthSolutions() throws CVC5ApiException @@ -2508,6 +2545,7 @@ class SolverTest Solver slv = new Solver(); assertThrows(CVC5ApiException.class, () -> slv.getSynthSolutions(new Term[] {x})); + slv.close(); } @Test void tupleProject() throws CVC5ApiException diff --git a/test/unit/api/java/SortTest.java b/test/unit/api/java/SortTest.java index 6649e5de0..977ba483e 100644 --- a/test/unit/api/java/SortTest.java +++ b/test/unit/api/java/SortTest.java @@ -36,6 +36,11 @@ class SortTest d_solver = new Solver(); } + @AfterEach void tearDown() + { + d_solver.close(); + } + Sort create_datatype_sort() throws CVC5ApiException { DatatypeDecl dtypeSpec = d_solver.mkDatatypeDecl("list"); diff --git a/test/unit/api/java/TermTest.java b/test/unit/api/java/TermTest.java index cb59849e0..94f35e97f 100644 --- a/test/unit/api/java/TermTest.java +++ b/test/unit/api/java/TermTest.java @@ -39,6 +39,11 @@ class TermTest d_solver = new Solver(); } + @AfterEach void tearDown() + { + d_solver.close(); + } + @Test void eq() { Sort uSort = d_solver.mkUninterpretedSort("u"); diff --git a/test/unit/api/solver_black.cpp b/test/unit/api/solver_black.cpp index 8dcb0fde6..062a2a59e 100644 --- a/test/unit/api/solver_black.cpp +++ b/test/unit/api/solver_black.cpp @@ -922,35 +922,21 @@ TEST_F(TestApiBlackSolver, defineSort) TEST_F(TestApiBlackSolver, defineFun) { Sort bvSort = d_solver.mkBitVectorSort(32); - Sort funSort1 = d_solver.mkFunctionSort({bvSort, bvSort}, bvSort); - Sort funSort2 = d_solver.mkFunctionSort(d_solver.mkUninterpretedSort("u"), - d_solver.getIntegerSort()); + Sort funSort = d_solver.mkFunctionSort(d_solver.mkUninterpretedSort("u"), + d_solver.getIntegerSort()); Term b1 = d_solver.mkVar(bvSort, "b1"); - Term b11 = d_solver.mkVar(bvSort, "b1"); Term b2 = d_solver.mkVar(d_solver.getIntegerSort(), "b2"); - Term b3 = d_solver.mkVar(funSort2, "b3"); + Term b3 = d_solver.mkVar(funSort, "b3"); Term v1 = d_solver.mkConst(bvSort, "v1"); - Term v2 = d_solver.mkConst(d_solver.getIntegerSort(), "v2"); - Term v3 = d_solver.mkConst(funSort2, "v3"); - Term f1 = d_solver.mkConst(funSort1, "f1"); - Term f2 = d_solver.mkConst(funSort2, "f2"); - Term f3 = d_solver.mkConst(bvSort, "f3"); + Term v2 = d_solver.mkConst(funSort, "v2"); ASSERT_NO_THROW(d_solver.defineFun("f", {}, bvSort, v1)); ASSERT_NO_THROW(d_solver.defineFun("ff", {b1, b2}, bvSort, v1)); - ASSERT_NO_THROW(d_solver.defineFun(f1, {b1, b11}, v1)); ASSERT_THROW(d_solver.defineFun("ff", {v1, b2}, bvSort, v1), CVC5ApiException); - ASSERT_THROW(d_solver.defineFun("fff", {b1}, bvSort, v3), CVC5ApiException); - ASSERT_THROW(d_solver.defineFun("ffff", {b1}, funSort2, v3), - CVC5ApiException); + ASSERT_THROW(d_solver.defineFun("fff", {b1}, bvSort, v2), CVC5ApiException); + ASSERT_THROW(d_solver.defineFun("ffff", {b1}, funSort, v2), CVC5ApiException); // b3 has function sort, which is allowed as an argument ASSERT_NO_THROW(d_solver.defineFun("fffff", {b1, b3}, bvSort, v1)); - ASSERT_THROW(d_solver.defineFun(f1, {v1, b11}, v1), CVC5ApiException); - ASSERT_THROW(d_solver.defineFun(f1, {b1}, v1), CVC5ApiException); - ASSERT_THROW(d_solver.defineFun(f1, {b1, b11}, v2), CVC5ApiException); - ASSERT_THROW(d_solver.defineFun(f1, {b1, b11}, v3), CVC5ApiException); - ASSERT_THROW(d_solver.defineFun(f2, {b1}, v2), CVC5ApiException); - ASSERT_THROW(d_solver.defineFun(f3, {b1}, v1), CVC5ApiException); Solver slv; Sort bvSort2 = slv.mkBitVectorSort(32); @@ -968,15 +954,13 @@ TEST_F(TestApiBlackSolver, defineFun) TEST_F(TestApiBlackSolver, defineFunGlobal) { Sort bSort = d_solver.getBooleanSort(); - Sort fSort = d_solver.mkFunctionSort(bSort, bSort); Term bTrue = d_solver.mkBoolean(true); // (define-fun f () Bool true) Term f = d_solver.defineFun("f", {}, bSort, bTrue, true); Term b = d_solver.mkVar(bSort, "b"); - Term gSym = d_solver.mkConst(fSort, "g"); // (define-fun g (b Bool) Bool b) - Term g = d_solver.defineFun(gSym, {b}, b, true); + Term g = d_solver.defineFun("g", {b}, bSort, b, true); // (assert (or (not f) (not (g true)))) d_solver.assertFormula(d_solver.mkTerm( @@ -1701,14 +1685,13 @@ TEST_F(TestApiBlackSolver, getQuantifierEliminationDisjunct) ASSERT_NO_THROW(d_solver.getQuantifierEliminationDisjunct(forall)); } -TEST_F(TestApiBlackSolver, declareSeparationHeap) +TEST_F(TestApiBlackSolver, declareSepHeap) { d_solver.setLogic("ALL"); Sort integer = d_solver.getIntegerSort(); - ASSERT_NO_THROW(d_solver.declareSeparationHeap(integer, integer)); + ASSERT_NO_THROW(d_solver.declareSepHeap(integer, integer)); // cannot declare separation logic heap more than once - ASSERT_THROW(d_solver.declareSeparationHeap(integer, integer), - CVC5ApiException); + ASSERT_THROW(d_solver.declareSepHeap(integer, integer), CVC5ApiException); } namespace { @@ -1720,7 +1703,7 @@ void checkSimpleSeparationConstraints(Solver* solver) { Sort integer = solver->getIntegerSort(); // declare the separation heap - solver->declareSeparationHeap(integer, integer); + solver->declareSepHeap(integer, integer); Term x = solver->mkConst(integer, "x"); Term p = solver->mkConst(integer, "p"); Term heap = solver->mkTerm(cvc5::api::Kind::SEP_PTO, p, x); @@ -1731,26 +1714,26 @@ void checkSimpleSeparationConstraints(Solver* solver) } } // namespace -TEST_F(TestApiBlackSolver, getSeparationHeapTerm1) +TEST_F(TestApiBlackSolver, getValueSepHeap1) { d_solver.setLogic("QF_BV"); d_solver.setOption("incremental", "false"); d_solver.setOption("produce-models", "true"); Term t = d_solver.mkTrue(); d_solver.assertFormula(t); - ASSERT_THROW(d_solver.getSeparationHeap(), CVC5ApiException); + ASSERT_THROW(d_solver.getValueSepHeap(), CVC5ApiException); } -TEST_F(TestApiBlackSolver, getSeparationHeapTerm2) +TEST_F(TestApiBlackSolver, getValueSepHeap2) { d_solver.setLogic("ALL"); d_solver.setOption("incremental", "false"); d_solver.setOption("produce-models", "false"); checkSimpleSeparationConstraints(&d_solver); - ASSERT_THROW(d_solver.getSeparationHeap(), CVC5ApiException); + ASSERT_THROW(d_solver.getValueSepHeap(), CVC5ApiException); } -TEST_F(TestApiBlackSolver, getSeparationHeapTerm3) +TEST_F(TestApiBlackSolver, getValueSepHeap3) { d_solver.setLogic("ALL"); d_solver.setOption("incremental", "false"); @@ -1758,10 +1741,10 @@ TEST_F(TestApiBlackSolver, getSeparationHeapTerm3) Term t = d_solver.mkFalse(); d_solver.assertFormula(t); d_solver.checkSat(); - ASSERT_THROW(d_solver.getSeparationHeap(), CVC5ApiException); + ASSERT_THROW(d_solver.getValueSepHeap(), CVC5ApiException); } -TEST_F(TestApiBlackSolver, getSeparationHeapTerm4) +TEST_F(TestApiBlackSolver, getValueSepHeap4) { d_solver.setLogic("ALL"); d_solver.setOption("incremental", "false"); @@ -1769,38 +1752,38 @@ TEST_F(TestApiBlackSolver, getSeparationHeapTerm4) Term t = d_solver.mkTrue(); d_solver.assertFormula(t); d_solver.checkSat(); - ASSERT_THROW(d_solver.getSeparationHeap(), CVC5ApiException); + ASSERT_THROW(d_solver.getValueSepHeap(), CVC5ApiException); } -TEST_F(TestApiBlackSolver, getSeparationHeapTerm5) +TEST_F(TestApiBlackSolver, getValueSepHeap5) { d_solver.setLogic("ALL"); d_solver.setOption("incremental", "false"); d_solver.setOption("produce-models", "true"); checkSimpleSeparationConstraints(&d_solver); - ASSERT_NO_THROW(d_solver.getSeparationHeap()); + ASSERT_NO_THROW(d_solver.getValueSepHeap()); } -TEST_F(TestApiBlackSolver, getSeparationNilTerm1) +TEST_F(TestApiBlackSolver, getValueSepNil1) { d_solver.setLogic("QF_BV"); d_solver.setOption("incremental", "false"); d_solver.setOption("produce-models", "true"); Term t = d_solver.mkTrue(); d_solver.assertFormula(t); - ASSERT_THROW(d_solver.getSeparationNilTerm(), CVC5ApiException); + ASSERT_THROW(d_solver.getValueSepNil(), CVC5ApiException); } -TEST_F(TestApiBlackSolver, getSeparationNilTerm2) +TEST_F(TestApiBlackSolver, getValueSepNil2) { d_solver.setLogic("ALL"); d_solver.setOption("incremental", "false"); d_solver.setOption("produce-models", "false"); checkSimpleSeparationConstraints(&d_solver); - ASSERT_THROW(d_solver.getSeparationNilTerm(), CVC5ApiException); + ASSERT_THROW(d_solver.getValueSepNil(), CVC5ApiException); } -TEST_F(TestApiBlackSolver, getSeparationNilTerm3) +TEST_F(TestApiBlackSolver, getValueSepNil3) { d_solver.setLogic("ALL"); d_solver.setOption("incremental", "false"); @@ -1808,10 +1791,10 @@ TEST_F(TestApiBlackSolver, getSeparationNilTerm3) Term t = d_solver.mkFalse(); d_solver.assertFormula(t); d_solver.checkSat(); - ASSERT_THROW(d_solver.getSeparationNilTerm(), CVC5ApiException); + ASSERT_THROW(d_solver.getValueSepNil(), CVC5ApiException); } -TEST_F(TestApiBlackSolver, getSeparationNilTerm4) +TEST_F(TestApiBlackSolver, getValueSepNil4) { d_solver.setLogic("ALL"); d_solver.setOption("incremental", "false"); @@ -1819,16 +1802,16 @@ TEST_F(TestApiBlackSolver, getSeparationNilTerm4) Term t = d_solver.mkTrue(); d_solver.assertFormula(t); d_solver.checkSat(); - ASSERT_THROW(d_solver.getSeparationNilTerm(), CVC5ApiException); + ASSERT_THROW(d_solver.getValueSepNil(), CVC5ApiException); } -TEST_F(TestApiBlackSolver, getSeparationNilTerm5) +TEST_F(TestApiBlackSolver, getValueSepNil5) { d_solver.setLogic("ALL"); d_solver.setOption("incremental", "false"); d_solver.setOption("produce-models", "true"); checkSimpleSeparationConstraints(&d_solver); - ASSERT_NO_THROW(d_solver.getSeparationNilTerm()); + ASSERT_NO_THROW(d_solver.getValueSepNil()); } TEST_F(TestApiBlackSolver, push1) @@ -2573,5 +2556,19 @@ TEST_F(TestApiBlackSolver, issue7000) ASSERT_THROW(d_solver.checkEntailed({t72, t74, t72, t72}), CVC5ApiException); } +TEST_F(TestApiBlackSolver, issue5893) +{ + Solver slv; + Sort bvsort4 = d_solver.mkBitVectorSort(4); + Sort bvsort8 = d_solver.mkBitVectorSort(8); + Sort arrsort = d_solver.mkArraySort(bvsort4, bvsort8); + Term arr = d_solver.mkConst(arrsort, "arr"); + Term idx = d_solver.mkConst(bvsort4, "idx"); + Term ten = d_solver.mkBitVector(8, "10", 10); + Term sel = d_solver.mkTerm(SELECT, arr, idx); + Term distinct = d_solver.mkTerm(DISTINCT, sel, ten); + ASSERT_NO_FATAL_FAILURE(distinct.getOp()); +} + } // namespace test } // namespace cvc5 diff --git a/test/unit/node/node_black.cpp b/test/unit/node/node_black.cpp index 5ad7010ed..b170ccbb6 100644 --- a/test/unit/node/node_black.cpp +++ b/test/unit/node/node_black.cpp @@ -532,13 +532,13 @@ TEST_F(TestNodeBlackNode, toString) TypeNode booleanType = d_nodeManager->booleanType(); Node w = d_skolemManager->mkDummySkolem( - "w", booleanType, "", NodeManager::SKOLEM_EXACT_NAME); + "w", booleanType, "", SkolemManager::SKOLEM_EXACT_NAME); Node x = d_skolemManager->mkDummySkolem( - "x", booleanType, "", NodeManager::SKOLEM_EXACT_NAME); + "x", booleanType, "", SkolemManager::SKOLEM_EXACT_NAME); Node y = d_skolemManager->mkDummySkolem( - "y", booleanType, "", NodeManager::SKOLEM_EXACT_NAME); + "y", booleanType, "", SkolemManager::SKOLEM_EXACT_NAME); Node z = d_skolemManager->mkDummySkolem( - "z", booleanType, "", NodeManager::SKOLEM_EXACT_NAME); + "z", booleanType, "", SkolemManager::SKOLEM_EXACT_NAME); Node m = NodeBuilder() << w << x << kind::OR; Node n = NodeBuilder() << m << y << z << kind::AND; @@ -550,13 +550,13 @@ TEST_F(TestNodeBlackNode, toStream) TypeNode booleanType = d_nodeManager->booleanType(); Node w = d_skolemManager->mkDummySkolem( - "w", booleanType, "", NodeManager::SKOLEM_EXACT_NAME); + "w", booleanType, "", SkolemManager::SKOLEM_EXACT_NAME); Node x = d_skolemManager->mkDummySkolem( - "x", booleanType, "", NodeManager::SKOLEM_EXACT_NAME); + "x", booleanType, "", SkolemManager::SKOLEM_EXACT_NAME); Node y = d_skolemManager->mkDummySkolem( - "y", booleanType, "", NodeManager::SKOLEM_EXACT_NAME); + "y", booleanType, "", SkolemManager::SKOLEM_EXACT_NAME); Node z = d_skolemManager->mkDummySkolem( - "z", booleanType, "", NodeManager::SKOLEM_EXACT_NAME); + "z", booleanType, "", SkolemManager::SKOLEM_EXACT_NAME); Node m = NodeBuilder() << x << y << kind::OR; Node n = NodeBuilder() << w << m << z << kind::AND; Node o = NodeBuilder() << n << n << kind::XOR; @@ -619,13 +619,13 @@ TEST_F(TestNodeBlackNode, dagifier) TypeNode fnType = d_nodeManager->mkFunctionType(intType, intType); Node x = d_skolemManager->mkDummySkolem( - "x", intType, "", NodeManager::SKOLEM_EXACT_NAME); + "x", intType, "", SkolemManager::SKOLEM_EXACT_NAME); Node y = d_skolemManager->mkDummySkolem( - "y", intType, "", NodeManager::SKOLEM_EXACT_NAME); + "y", intType, "", SkolemManager::SKOLEM_EXACT_NAME); Node f = d_skolemManager->mkDummySkolem( - "f", fnType, "", NodeManager::SKOLEM_EXACT_NAME); + "f", fnType, "", SkolemManager::SKOLEM_EXACT_NAME); Node g = d_skolemManager->mkDummySkolem( - "g", fnType, "", NodeManager::SKOLEM_EXACT_NAME); + "g", fnType, "", SkolemManager::SKOLEM_EXACT_NAME); Node fx = d_nodeManager->mkNode(APPLY_UF, f, x); Node fy = d_nodeManager->mkNode(APPLY_UF, f, y); Node gx = d_nodeManager->mkNode(APPLY_UF, g, x); diff --git a/test/unit/node/node_manager_black.cpp b/test/unit/node/node_manager_black.cpp index de0c76ce1..b02790cb5 100644 --- a/test/unit/node/node_manager_black.cpp +++ b/test/unit/node/node_manager_black.cpp @@ -122,7 +122,7 @@ TEST_F(TestNodeBlackNodeManager, mkNode_vector_of_tnode) TEST_F(TestNodeBlackNodeManager, mkSkolem_with_name) { Node x = d_skolemManager->mkDummySkolem( - "x", *d_boolTypeNode, "", NodeManager::SKOLEM_EXACT_NAME); + "x", *d_boolTypeNode, "", SkolemManager::SKOLEM_EXACT_NAME); ASSERT_EQ(x.getKind(), SKOLEM); ASSERT_EQ(x.getNumChildren(), 0u); ASSERT_EQ(x.getAttribute(VarNameAttr()), "x"); diff --git a/test/unit/theory/CMakeLists.txt b/test/unit/theory/CMakeLists.txt index 2af747fd5..15c5e8570 100644 --- a/test/unit/theory/CMakeLists.txt +++ b/test/unit/theory/CMakeLists.txt @@ -42,3 +42,4 @@ cvc5_add_unit_test_white(theory_strings_utils_white theory) cvc5_add_unit_test_white(theory_strings_word_white theory) cvc5_add_unit_test_white(theory_white theory) cvc5_add_unit_test_white(type_enumerator_white theory) +cvc5_add_unit_test_white(arith_poly_white theory) diff --git a/test/unit/theory/arith_poly_white.cpp b/test/unit/theory/arith_poly_white.cpp new file mode 100644 index 000000000..3e0bb6c17 --- /dev/null +++ b/test/unit/theory/arith_poly_white.cpp @@ -0,0 +1,132 @@ +/****************************************************************************** + * Top contributors (to current version): + * Andrew Reynolds + * + * This file is part of the cvc5 project. + * + * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS + * in the top-level source directory and their institutional affiliations. + * All rights reserved. See the file COPYING in the top-level source + * directory for licensing information. + * **************************************************************************** + * + * Unit tests for arithmetic polynomial normalization. + */ + +#include <iostream> +#include <memory> +#include <vector> + +#include "expr/node.h" +#include "expr/node_manager.h" +#include "test_smt.h" +#include "theory/arith/arith_poly_norm.h" +#include "util/rational.h" + +namespace cvc5 { + +using namespace theory; +using namespace theory::arith; +using namespace kind; + +namespace test { + +class TestTheoryWhiteArithPolyNorm : public TestSmt +{ + protected: + void SetUp() override { TestSmt::SetUp(); } +}; + +TEST_F(TestTheoryWhiteArithPolyNorm, check_poly_norm_int) +{ + TypeNode intType = d_nodeManager->integerType(); + Node zero = d_nodeManager->mkConst(Rational(0)); + Node one = d_nodeManager->mkConst(Rational(1)); + Node two = d_nodeManager->mkConst(Rational(2)); + Node x = d_nodeManager->mkVar("x", intType); + Node y = d_nodeManager->mkVar("y", intType); + Node z = d_nodeManager->mkVar("z", intType); + Node w = d_nodeManager->mkVar("w", intType); + + Node t1, t2; + + t1 = zero; + t2 = one; + ASSERT_FALSE(PolyNorm::isArithPolyNorm(t1, t2)); + + t1 = d_nodeManager->mkNode(PLUS, x, y); + t2 = d_nodeManager->mkNode(PLUS, y, d_nodeManager->mkNode(MULT, one, x)); + ASSERT_TRUE(PolyNorm::isArithPolyNorm(t1, t2)); + + t2 = d_nodeManager->mkNode(PLUS, x, x, y); + ASSERT_FALSE(PolyNorm::isArithPolyNorm(t1, t2)); + + t1 = d_nodeManager->mkNode(PLUS, x, d_nodeManager->mkNode(MULT, y, zero)); + t2 = x; + ASSERT_TRUE(PolyNorm::isArithPolyNorm(t1, t2)); + + t1 = d_nodeManager->mkNode(MULT, y, d_nodeManager->mkNode(PLUS, one, one)); + t2 = d_nodeManager->mkNode(PLUS, y, y); + ASSERT_TRUE(PolyNorm::isArithPolyNorm(t1, t2)); + + t1 = d_nodeManager->mkNode(MULT, + d_nodeManager->mkNode(PLUS, one, zero), + d_nodeManager->mkNode(PLUS, x, y)); + t2 = d_nodeManager->mkNode(PLUS, x, y); + ASSERT_TRUE(PolyNorm::isArithPolyNorm(t1, t2)); + + t1 = d_nodeManager->mkNode(PLUS, {x, y, z, w, y}); + t2 = d_nodeManager->mkNode(PLUS, {w, y, y, z, x}); + ASSERT_TRUE(PolyNorm::isArithPolyNorm(t1, t2)); + + t1 = d_nodeManager->mkNode(MINUS, t1, t2); + t2 = zero; + ASSERT_TRUE(PolyNorm::isArithPolyNorm(t1, t2)); + + t1 = d_nodeManager->mkNode(UMINUS, d_nodeManager->mkNode(PLUS, x, y)); + t2 = d_nodeManager->mkNode(MINUS, zero, d_nodeManager->mkNode(PLUS, y, x)); + ASSERT_TRUE(PolyNorm::isArithPolyNorm(t1, t2)); + + t1 = d_nodeManager->mkNode(MULT, d_nodeManager->mkNode(UMINUS, x), y); + t2 = d_nodeManager->mkNode(MULT, d_nodeManager->mkNode(UMINUS, y), x); + ASSERT_TRUE(PolyNorm::isArithPolyNorm(t1, t2)); + + t1 = d_nodeManager->mkNode(MULT, x, d_nodeManager->mkNode(PLUS, y, z)); + t2 = d_nodeManager->mkNode(PLUS, + d_nodeManager->mkNode(MULT, x, y), + d_nodeManager->mkNode(MULT, z, x)); + ASSERT_TRUE(PolyNorm::isArithPolyNorm(t1, t2)); +} + +TEST_F(TestTheoryWhiteArithPolyNorm, check_poly_norm_real) +{ + TypeNode realType = d_nodeManager->realType(); + Node zero = d_nodeManager->mkConst(Rational(0)); + Node one = d_nodeManager->mkConst(Rational(1)); + Node half = d_nodeManager->mkConst(Rational(1) / Rational(2)); + Node two = d_nodeManager->mkConst(Rational(2)); + Node x = d_nodeManager->mkVar("x", realType); + Node y = d_nodeManager->mkVar("y", realType); + + Node t1, t2; + + t1 = d_nodeManager->mkNode(PLUS, x, y, y); + t2 = d_nodeManager->mkNode(PLUS, y, x, y); + ASSERT_TRUE(PolyNorm::isArithPolyNorm(t1, t2)); + + t1 = one; + t2 = d_nodeManager->mkNode(MULT, two, half); + ASSERT_TRUE(PolyNorm::isArithPolyNorm(t1, t2)); + + t1 = d_nodeManager->mkNode(PLUS, y, x); + t2 = d_nodeManager->mkNode( + MULT, + d_nodeManager->mkNode(PLUS, + d_nodeManager->mkNode(MULT, half, x), + d_nodeManager->mkNode(MULT, half, y)), + two); + ASSERT_TRUE(PolyNorm::isArithPolyNorm(t1, t2)); +} + +} // namespace test +} // namespace cvc5 diff --git a/test/unit/theory/theory_arith_cad_white.cpp b/test/unit/theory/theory_arith_cad_white.cpp index 0a2bcb532..4d6bade95 100644 --- a/test/unit/theory/theory_arith_cad_white.cpp +++ b/test/unit/theory/theory_arith_cad_white.cpp @@ -90,13 +90,15 @@ Node operator*(const Node& a, const Node& b) Node operator!(const Node& a) { return nodeManager->mkNode(Kind::NOT, a); } Node make_real_variable(const std::string& s) { - return nodeManager->mkSkolem( - s, nodeManager->realType(), "", NodeManager::SKOLEM_EXACT_NAME); + SkolemManager* sm = nodeManager->getSkolemManager(); + return sm->mkDummySkolem( + s, nodeManager->realType(), "", SkolemManager::SKOLEM_EXACT_NAME); } Node make_int_variable(const std::string& s) { - return nodeManager->mkSkolem( - s, nodeManager->integerType(), "", NodeManager::SKOLEM_EXACT_NAME); + SkolemManager* sm = nodeManager->getSkolemManager(); + return sm->mkDummySkolem( + s, nodeManager->integerType(), "", SkolemManager::SKOLEM_EXACT_NAME); } TEST_F(TestTheoryWhiteArithCAD, test_univariate_isolation) diff --git a/test/unit/theory/theory_bags_rewriter_white.cpp b/test/unit/theory/theory_bags_rewriter_white.cpp index 025d5aec7..7250f581c 100644 --- a/test/unit/theory/theory_bags_rewriter_white.cpp +++ b/test/unit/theory/theory_bags_rewriter_white.cpp @@ -165,25 +165,29 @@ TEST_F(TestTheoryWhiteBagsRewriter, mkBag_variable_element) TEST_F(TestTheoryWhiteBagsRewriter, bag_count) { - int n = 3; + Node zero = d_nodeManager->mkConst(Rational(0)); + Node one = d_nodeManager->mkConst(Rational(1)); + Node three = d_nodeManager->mkConst(Rational(3)); Node skolem = d_skolemManager->mkDummySkolem("x", d_nodeManager->stringType()); Node emptyBag = d_nodeManager->mkConst( EmptyBag(d_nodeManager->mkBagType(skolem.getType()))); - Node bag = d_nodeManager->mkBag( - d_nodeManager->stringType(), skolem, d_nodeManager->mkConst(Rational(n))); // (bag.count x emptybag) = 0 Node n1 = d_nodeManager->mkNode(BAG_COUNT, skolem, emptyBag); RewriteResponse response1 = d_rewriter->postRewrite(n1); ASSERT_TRUE(response1.d_status == REWRITE_AGAIN_FULL - && response1.d_node == d_nodeManager->mkConst(Rational(0))); + && response1.d_node == zero); - // (bag.count x (mkBag x c) = c where c > 0 is a constant + // (bag.count x (mkBag x c) = (ite (>= c 1) c 0) + Node bag = d_nodeManager->mkBag(d_nodeManager->stringType(), skolem, three); Node n2 = d_nodeManager->mkNode(BAG_COUNT, skolem, bag); RewriteResponse response2 = d_rewriter->postRewrite(n2); + + Node geq = d_nodeManager->mkNode(GEQ, three, one); + Node ite = d_nodeManager->mkNode(ITE, geq, three, zero); ASSERT_TRUE(response2.d_status == REWRITE_AGAIN_FULL - && response2.d_node == d_nodeManager->mkConst(Rational(n))); + && response2.d_node == ite); } TEST_F(TestTheoryWhiteBagsRewriter, duplicate_removal) @@ -715,12 +719,10 @@ TEST_F(TestTheoryWhiteBagsRewriter, map) std::vector<Node> elements = getNStrings(2); Node a = d_nodeManager->mkConst(String("a")); Node b = d_nodeManager->mkConst(String("b")); - Node A = d_nodeManager->mkBag(d_nodeManager->stringType(), - a, - d_nodeManager->mkConst(Rational(3))); - Node B = d_nodeManager->mkBag(d_nodeManager->stringType(), - b, - d_nodeManager->mkConst(Rational(4))); + Node A = d_nodeManager->mkBag( + d_nodeManager->stringType(), a, d_nodeManager->mkConst(Rational(3))); + Node B = d_nodeManager->mkBag( + d_nodeManager->stringType(), b, d_nodeManager->mkConst(Rational(4))); Node unionDisjointAB = d_nodeManager->mkNode(UNION_DISJOINT, A, B); ASSERT_TRUE(unionDisjointAB.isConst()); @@ -729,7 +731,7 @@ TEST_F(TestTheoryWhiteBagsRewriter, map) // (bag "" 7)) Node n2 = d_nodeManager->mkNode(BAG_MAP, lambda, unionDisjointAB); - Node rewritten = Rewriter:: rewrite(n2); + Node rewritten = Rewriter::rewrite(n2); Node bag = d_nodeManager->mkBag( d_nodeManager->stringType(), empty, d_nodeManager->mkConst(Rational(7))); ASSERT_TRUE(rewritten == bag); diff --git a/test/unit/theory/theory_bv_white.cpp b/test/unit/theory/theory_bv_white.cpp index 244cad7ec..847ca9415 100644 --- a/test/unit/theory/theory_bv_white.cpp +++ b/test/unit/theory/theory_bv_white.cpp @@ -21,8 +21,7 @@ #include "context/context.h" #include "expr/node.h" #include "test_smt.h" -#include "theory/bv/bitblast/eager_bitblaster.h" -#include "theory/bv/bv_solver_layered.h" +#include "theory/bv/theory_bv_utils.h" #include "theory/theory.h" #include "theory/theory_engine.h" @@ -40,38 +39,6 @@ class TestTheoryWhiteBv : public TestSmtNoFinishInit { }; -TEST_F(TestTheoryWhiteBv, bitblaster_core) -{ - d_slvEngine->setLogic("QF_BV"); - - d_slvEngine->setOption("bitblast", "eager"); - d_slvEngine->setOption("bv-solver", "layered"); - d_slvEngine->setOption("incremental", "false"); - // Notice that this unit test uses the theory engine of a created SMT - // engine d_slvEngine. We must ensure that d_slvEngine is properly initialized - // via the following call, which constructs its underlying theory engine. - d_slvEngine->finishInit(); - TheoryBV* tbv = dynamic_cast<TheoryBV*>( - d_slvEngine->getTheoryEngine()->d_theoryTable[THEORY_BV]); - BVSolverLayered* bvsl = dynamic_cast<BVSolverLayered*>(tbv->d_internal.get()); - std::unique_ptr<EagerBitblaster> bb( - new EagerBitblaster(bvsl, d_slvEngine->getContext())); - - Node x = d_nodeManager->mkVar("x", d_nodeManager->mkBitVectorType(16)); - Node y = d_nodeManager->mkVar("y", d_nodeManager->mkBitVectorType(16)); - Node x_plus_y = d_nodeManager->mkNode(kind::BITVECTOR_ADD, x, y); - Node one = d_nodeManager->mkConst<BitVector>(BitVector(16, 1u)); - Node x_shl_one = d_nodeManager->mkNode(kind::BITVECTOR_SHL, x, one); - Node eq = d_nodeManager->mkNode(kind::EQUAL, x_plus_y, x_shl_one); - Node not_x_eq_y = d_nodeManager->mkNode( - kind::NOT, d_nodeManager->mkNode(kind::EQUAL, x, y)); - - bb->bbFormula(eq); - bb->bbFormula(not_x_eq_y); - - ASSERT_EQ(bb->solve(), false); -} - TEST_F(TestTheoryWhiteBv, mkUmulo) { d_slvEngine->setOption("incremental", "true"); diff --git a/test/unit/util/CMakeLists.txt b/test/unit/util/CMakeLists.txt index c1630a203..03348f6e1 100644 --- a/test/unit/util/CMakeLists.txt +++ b/test/unit/util/CMakeLists.txt @@ -23,6 +23,7 @@ cvc5_add_unit_test_black(cardinality_black util) cvc5_add_unit_test_white(check_white util) cvc5_add_unit_test_black(configuration_black util) cvc5_add_unit_test_black(datatype_black util) +cvc5_add_unit_test_white(didyoumean_black util) cvc5_add_unit_test_black(exception_black util) cvc5_add_unit_test_black(floatingpoint_black util) cvc5_add_unit_test_black(integer_black util) diff --git a/test/unit/util/didyoumean_black.cpp b/test/unit/util/didyoumean_black.cpp new file mode 100644 index 000000000..cc2fdf878 --- /dev/null +++ b/test/unit/util/didyoumean_black.cpp @@ -0,0 +1,75 @@ +/****************************************************************************** + * Top contributors (to current version): + * Aina Niemetz, Andres Noetzli, Gereon Kremer + * + * This file is part of the cvc5 project. + * + * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS + * in the top-level source directory and their institutional affiliations. + * All rights reserved. See the file COPYING in the top-level source + * directory for licensing information. + * **************************************************************************** + * + * Black box testing of cvc5::Stat and associated classes. + */ + +#include "test.h" + +#include "util/didyoumean.h" + +namespace cvc5::test { + +class TestUtilDidYouMean : public TestInternal +{ +}; + +TEST_F(TestUtilDidYouMean, getMatch) +{ + { + DidYouMean dym; + dym.addWords({"abfish", "cdfish", "whale"}); + { + auto expected = std::vector<std::string>{"abfish"}; + EXPECT_EQ(dym.getMatch("abfish"), expected); + } + { + auto expected = std::vector<std::string>{"whale"}; + EXPECT_EQ(dym.getMatch("wahl"), expected); + } + { + auto expected = std::vector<std::string>{"abfish", "cdfish"}; + EXPECT_EQ(dym.getMatch("fish"), expected); + } + { + auto expected = std::vector<std::string>{}; + EXPECT_EQ(dym.getMatch("elephant"), expected); + } + } +} + +TEST_F(TestUtilDidYouMean, getMatchAsString) +{ + DidYouMean dym; + dym.addWords({"abfish", "cdfish", "whale"}); + { + std::string expected = ""; + EXPECT_EQ(dym.getMatchAsString("elephant"), expected); + } + { + std::string expected = R"FOOBAR( + +Did you mean this? + whale)FOOBAR"; + EXPECT_EQ(dym.getMatchAsString("wahl"), expected); + } + { + std::string expected = R"FOOBAR( + +Did you mean any of these? + abfish + cdfish)FOOBAR"; + EXPECT_EQ(dym.getMatchAsString("fish"), expected); + } +} + +} // namespace cvc5::test |