diff --git a/.github/actions/add-package/action.yml b/.github/actions/add-package/action.yml index a25665f9990..16e0355d3c3 100644 --- a/.github/actions/add-package/action.yml +++ b/.github/actions/add-package/action.yml @@ -96,7 +96,7 @@ runs: for cnt,asset in enumerate(assets): delete = False # We generate 10 artifacts per build: - # {Linux, Linux-arm64, macOS, macOS-arm64, Windows} * {static, shared} + # {Linux-x86_64, Linux-arm64, macOS-x86_64, macOS-arm64, Win64-x86_64} * {static, shared} if cnt >= 20: # Keep at most 2 builds delete = True if asset.name.startswith(samedayprefix): diff --git a/.github/actions/install-dependencies/action.yml b/.github/actions/install-dependencies/action.yml index 2eb92d29c37..d98e6dbe346 100644 --- a/.github/actions/install-dependencies/action.yml +++ b/.github/actions/install-dependencies/action.yml @@ -109,6 +109,14 @@ runs: echo "$HOME/.venv/bin" >> $GITHUB_PATH echo "::endgroup::" + # Required for the installation of Python bindings + - name: Upgrade Python pip + shell: ${{ inputs.shell }} + run: | + echo "::group::Upgrade Python pip" + python3 -m pip install --upgrade pip + echo "::endgroup::" + - name: Install software for documentation if: inputs.with-documentation == 'true' shell: ${{ inputs.shell }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7190936a7af..96862bd7017 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: python-bindings: true build-documentation: true check-examples: true - package-name: cvc5-Linux + package-name: cvc5-Linux-x86_64 exclude_regress: 3-4 run_regression_args: --tester base --tester model --tester synth --tester abduct --tester dump @@ -37,7 +37,7 @@ jobs: strip-bin: strip python-bindings: true check-examples: true - package-name: cvc5-macOS + package-name: cvc5-macOS-x86_64 macos-target: 10.13 exclude_regress: 3-4 run_regression_args: --tester base --tester model --tester synth --tester abduct --tester dump @@ -69,7 +69,7 @@ jobs: windows-build: true shell: 'msys2 {0}' check-examples: true - package-name: cvc5-Win64 + package-name: cvc5-Win64-x86_64 exclude_regress: 1-4 run_regression_args: --tester base --tester model --tester synth --tester abduct --tester dump @@ -192,18 +192,3 @@ jobs: github-token-latest: ${{ secrets.GITHUB_TOKEN }} github-token-release: ${{ secrets.ACTION_USER_TOKEN }} shell: ${{ matrix.shell }} - - update-pr: - runs-on: ubuntu-latest - if: github.repository == 'cvc5/cvc5' && github.event_name == 'push' && github.ref == 'refs/heads/main' - concurrency: - group: update-pr - steps: - - name: Automatically update PR - uses: adRise/update-pr-branch@v0.7.2 - with: - token: ${{ secrets.ACTION_USER_TOKEN }} - base: 'main' - sort: 'created' - direction: 'asc' - required_approval_count: 1 diff --git a/CMakeLists.txt b/CMakeLists.txt index ccc7801246a..bee54ba5d66 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -232,6 +232,7 @@ add_check_cxx_flag("-Wsuggest-override") add_check_cxx_flag("-Wnon-virtual-dtor") add_check_c_cxx_flag("-Wimplicit-fallthrough") add_check_c_cxx_flag("-Wshadow") +add_check_c_cxx_flag("-fno-operator-names") # Assume no dynamic initialization of thread-local variables in non-defining # translation units. This option should result in better performance and works diff --git a/INSTALL.rst b/INSTALL.rst index 4eba0a51bab..d658c91a43c 100644 --- a/INSTALL.rst +++ b/INSTALL.rst @@ -267,10 +267,12 @@ Dependencies for Language Bindings - `JDK >= 1.8 `_ - Python - - `Cython `_ >= 3.0.0 + - `pip `_ >= 23.0 - `pytest `_ - - The source for the `pythonic API <(https://github.com/cvc5/cvc5_pythonic_api)>`. + - `repairwheel `_ >= 0.2.9 + - `setuptools `_ >= 66.1.0 + - The source for the `pythonic API `_ If ``--auto-download`` is given, the Python modules will be installed automatically in a virtual environment if they are missing. To install the modules globally and skip @@ -279,6 +281,9 @@ the creation of the virtual environment, configure cvc5 with ``./configure.sh -- If configured with ``--pythonic-path=PATH``, the build system will expect the Pythonic API's source to be at ``PATH``. Otherwise, if configured with ``--auto-download``, the build system will download it. +Installing the Python bindings after building from source requires a Python environment with +pip version 20.3 or higher. + If you're interested in helping to develop, maintain, and test a language binding, please contact the cvc5 team via `our issue tracker `_. diff --git a/cmake/FindGMP.cmake b/cmake/FindGMP.cmake index 19d61a50c96..6382831c379 100644 --- a/cmake/FindGMP.cmake +++ b/cmake/FindGMP.cmake @@ -164,4 +164,21 @@ if(GMP_FOUND_SYSTEM) else() message(STATUS "Building GMP ${GMP_VERSION}: ${GMP_LIBRARIES}") add_dependencies(GMP GMP-EP) + # Static builds install the GMP static libraries. + # These libraries are required to compile a program that + # uses the cvc5 static library. + # On Windows, this installs the import libraries (LIB) and + # the DLL libraries (BIN) + install( + DIRECTORY ${DEPS_BASE}/${CMAKE_INSTALL_LIBDIR}/ + TYPE LIB + FILES_MATCHING PATTERN libgmp* PATTERN gmp*.pc + ) + if(BUILD_SHARED_LIBS AND WIN32) + install( + DIRECTORY ${DEPS_BASE}/${CMAKE_INSTALL_BINDIR}/ + TYPE BIN + FILES_MATCHING PATTERN libgmp* + ) + endif() endif() diff --git a/cmake/FindPip.cmake b/cmake/FindPip.cmake new file mode 100644 index 00000000000..d5d1f886b57 --- /dev/null +++ b/cmake/FindPip.cmake @@ -0,0 +1,69 @@ +############################################################################### +# Top contributors (to current version): +# Daniel Larraz +# +# This file is part of the cvc5 project. +# +# Copyright (c) 2009-2024 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 Pip +# Pip_FOUND - found Python pip +# Pip_VERSION - Python pip version +## + +macro(get_pip_version) + execute_process( + COMMAND "${Python_EXECUTABLE}" -c "import pip; print(pip.__version__)" + RESULT_VARIABLE Pip_VERSION_CHECK_RESULT + OUTPUT_VARIABLE Pip_VERSION + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) +endmacro() + +get_pip_version() + +if (Pip_FIND_REQUIRED) + set(Pip_FIND_MODE FATAL_ERROR) +else() + set(Pip_FIND_MODE STATUS) +endif() + +if(Pip_VERSION_CHECK_RESULT EQUAL 0) + set(Pip_FOUND TRUE) + if(DEFINED Pip_FIND_VERSION) + if(Pip_VERSION VERSION_LESS ${Pip_FIND_VERSION}) + if(ENABLE_AUTO_DOWNLOAD) + execute_process ( + COMMAND "${Python_EXECUTABLE}" -m pip install -U pip + ) + get_pip_version() + else() + message(${Pip_FIND_MODE} + "Pip version >= ${Pip_FIND_VERSION} is required, " + "but found version ${Pip_VERSION}") + endif() + endif() + endif() +else() + set(Pip_FOUND FALSE) + if(ENABLE_AUTO_DOWNLOAD) + execute_process ( + COMMAND "${Python_EXECUTABLE}" -m ensurepip --upgrade + RESULT_VARIABLE ENSUREPIP_RESULT + ) + if (ENSUREPIP_RESULT EQUAL 0) + set(Pip_FOUND TRUE) + else() + message(${Pip_FIND_MODE} "Could NOT install pip for Python version " + "${Python_VERSION_MAJOR}.${Python_VERSION_MINOR}") + endif() + else() + message(${Pip_FIND_MODE} "Could NOT find pip for Python version " + "${Python_VERSION_MAJOR}.${Python_VERSION_MINOR}") + endif() +endif() \ No newline at end of file diff --git a/cmake/FindRepairwheel.cmake b/cmake/FindRepairwheel.cmake new file mode 100644 index 00000000000..1a496d5a1b4 --- /dev/null +++ b/cmake/FindRepairwheel.cmake @@ -0,0 +1,83 @@ +############################################################################### +# Top contributors (to current version): +# Daniel Larraz +# +# This file is part of the cvc5 project. +# +# Copyright (c) 2009-2024 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 Repairwheel +# Repairwheel_FOUND - system has the repairwheel executable +# Repairwheel_EXECUTABLE - path to the repairwheel executable +# Repairwheel_VERSION - repairwheel version +## + +set(Python_SCRIPTS_Paths "") + +macro(add_scripts_path python_bin scheme) + execute_process( + COMMAND "${python_bin}" -c + "import sysconfig; print(sysconfig.get_paths('${scheme}')['scripts'])" + RESULT_VARIABLE Python_SCRIPTS_RESULT + OUTPUT_VARIABLE Python_SCRIPTS + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if (NOT Python_SCRIPTS_RESULT AND Python_SCRIPTS) + list(APPEND Python_SCRIPTS_Paths ${Python_SCRIPTS}) + endif() +endmacro() + +# Look for repairwheel executable in Python "Scripts" directories +add_scripts_path("${Python_EXECUTABLE}" "posix_prefix") +add_scripts_path("${Python_BASE_EXECUTABLE}" "posix_user") +add_scripts_path("${Python_BASE_EXECUTABLE}" "posix_prefix") +if(WIN32) + add_scripts_path("${Python_EXECUTABLE}" "nt") + add_scripts_path("${Python_BASE_EXECUTABLE}" "nt_user") + add_scripts_path("${Python_BASE_EXECUTABLE}" "nt") +endif() + +if (Repairwheel_FIND_REQUIRED) + set(Repairwheel_FIND_MODE FATAL_ERROR) +else() + set(Repairwheel_FIND_MODE STATUS) +endif() + +macro(find_repairwheel) + find_program(Repairwheel_EXECUTABLE repairwheel ${Python_SCRIPTS_Paths}) + if(Repairwheel_EXECUTABLE) + execute_process( + COMMAND "${Repairwheel_EXECUTABLE}" --version + RESULT_VARIABLE Repairwheel_VERSION_CHECK_RESULT + OUTPUT_VARIABLE Repairwheel_VERSION + ) + # Check we can run repairwheel successfully. + # Otherwise, reset path to executable. + if(NOT(Repairwheel_VERSION_CHECK_RESULT EQUAL 0)) + set(Repairwheel_EXECUTABLE "") + endif() + endif() +endmacro() + +find_repairwheel() + +if(NOT Repairwheel_EXECUTABLE AND ENABLE_AUTO_DOWNLOAD) + message(STATUS "Installing repairwheel") + execute_process( + COMMAND ${Python_EXECUTABLE} -m pip install repairwheel + ) + find_repairwheel() +endif() + +if(Repairwheel_EXECUTABLE) + set(Repairwheel_FOUND TRUE) + message(STATUS "Found repairwheel: ${Repairwheel_EXECUTABLE}") +else() + set(Repairwheel_FOUND FALSE) + message(${Repairwheel_FIND_MODE} "Could NOT find repairwheel executable") +endif() diff --git a/contrib/get-alf-checker b/contrib/get-alf-checker index 0e525c4bd59..26146df61f3 100755 --- a/contrib/get-alf-checker +++ b/contrib/get-alf-checker @@ -24,7 +24,7 @@ ALFC_DIR="$BASE_DIR/alf-checker" mkdir -p $ALFC_DIR # download and unpack ALFC -ALF_VERSION="da1903230c1d7cc5adbacb65d4eee602dcba93a0" +ALF_VERSION="612c7ad99d3e3679c14f9f907d9ec490fea88914" download "https://github.com/cvc5/alfc/archive/$ALF_VERSION.tar.gz" $BASE_DIR/tmp/alfc.tgz tar --strip 1 -xzf $BASE_DIR/tmp/alfc.tgz -C $ALFC_DIR diff --git a/docs/examples/uf.rst b/docs/examples/uf.rst new file mode 100644 index 00000000000..c2ae768ca0c --- /dev/null +++ b/docs/examples/uf.rst @@ -0,0 +1,10 @@ +Theory of Uninterpreted Functions +================================== + + +.. api-examples:: + /api/cpp/uf.cpp + /api/java/Uf.java + /api/python/pythonic/uf.py + /api/python/uf.py + /api/smtlib/uf.smt2 diff --git a/examples/api/cpp/CMakeLists.txt b/examples/api/cpp/CMakeLists.txt index 55652d3e30e..a78441005bd 100644 --- a/examples/api/cpp/CMakeLists.txt +++ b/examples/api/cpp/CMakeLists.txt @@ -31,6 +31,7 @@ set(CVC5_EXAMPLES_API transcendentals parser parser_sym_manager + uf ) foreach(example ${CVC5_EXAMPLES_API}) diff --git a/examples/api/cpp/uf.cpp b/examples/api/cpp/uf.cpp new file mode 100644 index 00000000000..1336446ca70 --- /dev/null +++ b/examples/api/cpp/uf.cpp @@ -0,0 +1,62 @@ +/****************************************************************************** + * Top contributors (to current version): + * Yoni Zohar + * + * This file is part of the cvc5 project. + * + * Copyright (c) 2009-2024 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 simple demonstration of the capabilities of the cvc5 uf solver. + */ + +#include + +#include + +using namespace cvc5; + +int main() +{ + TermManager tm; + Solver slv(tm); + slv.setLogic("QF_UF"); + + // Sorts + Sort u = tm.mkUninterpretedSort("U"); + Sort boolean = tm.getBooleanSort(); + Sort uTou = tm.mkFunctionSort({u}, u); + Sort uPred = tm.mkFunctionSort({u}, boolean); + + // Variables + Term x = tm.mkConst(u, "x"); + Term y = tm.mkConst(u, "y"); + + // Functions + Term f = tm.mkConst(uTou, "f"); + Term p = tm.mkConst(uPred, "p"); + + // Terms + Term f_x = tm.mkTerm(Kind::APPLY_UF, {f, x}); + Term f_y = tm.mkTerm(Kind::APPLY_UF, {f, y}); + Term p_f_x = tm.mkTerm(Kind::APPLY_UF, {p, f_x}); + Term p_f_y = tm.mkTerm(Kind::APPLY_UF, {p, f_y}); + + // Construct the assertions + Term assertions = + tm.mkTerm(Kind::AND, + { + tm.mkTerm(Kind::EQUAL, {x, f_x}), + tm.mkTerm(Kind::EQUAL, {y, f_y}), + p_f_x.notTerm(), + p_f_y + }); + slv.assertFormula(assertions); + + std::cout << slv.checkSat() << std::endl; + + return 0; +} diff --git a/examples/api/java/CMakeLists.txt b/examples/api/java/CMakeLists.txt index 57f5fb1a980..d752e364a98 100644 --- a/examples/api/java/CMakeLists.txt +++ b/examples/api/java/CMakeLists.txt @@ -34,6 +34,7 @@ set(EXAMPLES_API_JAVA SygusInv Transcendentals UnsatCores + Uf ) function(add_java_example example) diff --git a/examples/api/java/Uf.java b/examples/api/java/Uf.java new file mode 100644 index 00000000000..b2cc79d5b6c --- /dev/null +++ b/examples/api/java/Uf.java @@ -0,0 +1,63 @@ +/****************************************************************************** + * Top contributors (to current version): + * Yoni Zohar + * + * This file is part of the cvc5 project. + * + * Copyright (c) 2009-2024 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 simple demonstration of the capabilities of the cvc5 uf solver. + */ + +import io.github.cvc5.*; +import java.util.Iterator; + +public class Uf +{ + public static void main(String[] args) throws CVC5ApiException + { + Solver slv = new Solver(); + { + slv.setLogic("QF_UF"); + + // Sorts + Sort u = slv.mkUninterpretedSort("U"); + Sort bool = slv.getBooleanSort(); + Sort uTou = slv.mkFunctionSort(u, u); + Sort uPred = slv.mkFunctionSort(u, bool); + + // Variables + Term x = slv.mkConst(u, "x"); + Term y = slv.mkConst(u, "y"); + + // Functions + Term f = slv.mkConst(uTou, "f"); + Term p = slv.mkConst(uPred, "p"); + + // Terms + Term f_x = slv.mkTerm(Kind.APPLY_UF, f, x); + Term f_y = slv.mkTerm(Kind.APPLY_UF, f, y); + Term p_f_x = slv.mkTerm(Kind.APPLY_UF, p, f_x); + 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.EQUAL, x, f_x), + slv.mkTerm(Kind.EQUAL, y, f_y), + p_f_x.notTerm(), + p_f_y + }); + slv.assertFormula(assertions); + + System.out.println("Call checkSat to show that the assertions are satisfiable. \n" + + "cvc5: " + slv.checkSat() + ".\n"); + + Context.deletePointers(); + } + } +} diff --git a/examples/api/python/CMakeLists.txt b/examples/api/python/CMakeLists.txt index 653667dc087..65f3523bbf9 100644 --- a/examples/api/python/CMakeLists.txt +++ b/examples/api/python/CMakeLists.txt @@ -35,6 +35,7 @@ set(EXAMPLES_API_PYTHON sygus-fun sygus-inv transcendentals + uf ) find_package(Python ${CVC5_BINDINGS_PYTHON_VERSION} EXACT REQUIRED) diff --git a/examples/api/python/pythonic/uf.py b/examples/api/python/pythonic/uf.py new file mode 100644 index 00000000000..a5a1fb30beb --- /dev/null +++ b/examples/api/python/pythonic/uf.py @@ -0,0 +1,29 @@ +############################################################################### +# Top contributors (to current version): +# Yoni Zohar +# +# This file is part of the cvc5 project. +# +# Copyright (c) 2009-2024 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 simple demonstration of the capabilities of the cvc5 uf solver. +## +from cvc5.pythonic import * + +if __name__ == "__main__": + + U = DeclareSort("U") + x, y = Consts("x y", U) + + f = Function("f", U, U) + p = Function("p", U, BoolSort()) + + assumptions = [f(x) == x, f(y) == y, Not(p(f(x))), p(f(y))] + + s = Solver() + s.add(assumptions) + assert sat == s.check() diff --git a/examples/api/python/uf.py b/examples/api/python/uf.py new file mode 100644 index 00000000000..6a6f78dbe80 --- /dev/null +++ b/examples/api/python/uf.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python +############################################################################### +# Top contributors (to current version): +# Yoni Zohar +# +# This file is part of the cvc5 project. +# +# Copyright (c) 2009-2024 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 simple demonstration of the solving capabilities of the cvc5 uf solver. +## + +import cvc5 +from cvc5 import Kind + +if __name__ == "__main__": + tm = cvc5.TermManager() + slv = cvc5.Solver(tm) + slv.setLogic("QF_UF") + + # Sorts + u = tm.mkUninterpretedSort("U") + integer = tm.getIntegerSort() + boolean = tm.getBooleanSort() + uTou = tm.mkFunctionSort(u, u) + uPred = tm.mkFunctionSort(u, boolean) + + # Variables + x = tm.mkConst(u, "x") + y = tm.mkConst(u, "y") + + # Functions + f = tm.mkConst(uTou, "f") + p = tm.mkConst(uPred, "p") + + + # Terms + f_x = tm.mkTerm(Kind.APPLY_UF, f, x) + f_y = tm.mkTerm(Kind.APPLY_UF, f, y) + p_f_x = tm.mkTerm(Kind.APPLY_UF, p, f_x) + p_f_y = tm.mkTerm(Kind.APPLY_UF, p, f_y) + + # Construct the assertions + assertions = tm.mkTerm(Kind.AND, + tm.mkTerm(Kind.EQUAL, x, f_x), + tm.mkTerm(Kind.EQUAL, y, f_y), + p_f_x.notTerm(), + p_f_y) + + slv.assertFormula(assertions) + assert(slv.checkSat().isSat()) + diff --git a/examples/api/smtlib/uf.smt2 b/examples/api/smtlib/uf.smt2 new file mode 100644 index 00000000000..91fd8f1ff41 --- /dev/null +++ b/examples/api/smtlib/uf.smt2 @@ -0,0 +1,17 @@ +(set-logic QF_UF) + +(declare-sort U 0) + +(declare-const x U) +(declare-const y U) + +(declare-fun f (U) U) +(declare-fun p (U) Bool) + +(assert (= x (f x))) +(assert (= y (f y))) +(assert (not (p (f x)))) +(assert (p (f y))) + +(check-sat) + diff --git a/include/cvc5/c/cvc5.h b/include/cvc5/c/cvc5.h index 9979f10a8d4..959c9dd70e8 100644 --- a/include/cvc5/c/cvc5.h +++ b/include/cvc5/c/cvc5.h @@ -247,6 +247,29 @@ const char* cvc5_synth_result_to_string(const Cvc5SynthResult* result); /* Cvc5Sort */ /* -------------------------------------------------------------------------- */ +/** + * Make copy of sort, increases reference counter of `sort`. + * + * @param sort The sort to copy. + * @return The same sort with its reference count increased by one. + * + * @note This step is optional and allows users to manage resources in a more + * fine-grained manner. + */ +Cvc5Sort cvc5_sort_copy(Cvc5Sort sort); + +/** + * Release copy of sort, decrements reference counter of `sort`. + * + * @param sort The sort to release. + * + * @note This step is optional and allows users to release resources in a more + * fine-grained manner. Further, any API function that returns a + * Cvc5Sort returns a copy that is owned by the callee of the function + * and thus, can be released. + */ +void cvc5_sort_release(Cvc5Sort sort); + /** * Compare two sorts for structural equality. * @param a The first sort. @@ -838,6 +861,28 @@ Cvc5Sort cvc5_sort_nullable_get_element_sort(Cvc5Sort sort); /* Cvc5Op */ /* -------------------------------------------------------------------------- */ +/** + * Make copy of operator, increases reference counter of `op`. + * + * @param op The op to copy. + * @return The same op with its reference count increased by one. + * + * @note This step is optional and allows users to manage resources in a more + * fine-grained manner. + */ +Cvc5Op cvc5_op_copy(Cvc5Op op); + +/** + * Release copy of operator, decrements reference counter of `op`. + * + * @param op The op to release. + * + * @note This step is optional and allows users to release resources in a more + * fine-grained manner. Further, any API function that returns a + * Cvc5Op returns a copy that is owned by the callee of the function + * and thus, can be released. + */ +void cvc5_op_release(Cvc5Op op); /** * Compare two operators for syntactic equality. * @@ -905,6 +950,29 @@ size_t cvc5_op_hash(Cvc5Op op); /* Cvc5Term */ /* -------------------------------------------------------------------------- */ +/** + * Make copy of term, increases reference counter of `term`. + * + * @param term The term to copy. + * @return The same term with its reference count increased by one. + * + * @note This step is optional and allows users to manage resources in a more + * fine-grained manner. + */ +Cvc5Term cvc5_term_copy(Cvc5Term term); + +/** + * Release copy of term, decrements reference counter of `term`. + * + * @param term The term to release. + * + * @note This step is optional and allows users to release resources in a more + * fine-grained manner. Further, any API function that returns a + * Cvc5Term returns a copy that is owned by the callee of the function + * and thus, can be released. + */ +void cvc5_term_release(Cvc5Term term); + /** * Compare two terms for syntactic equality. * @param a The first term. @@ -943,7 +1011,7 @@ size_t cvc5_term_get_num_children(Cvc5Term term); * @param index The index of the child. * @return The child term at the given index. */ -Cvc5Term cvc5_term_get_child(size_t index); +Cvc5Term cvc5_term_get_child(Cvc5Term term, size_t index); /** * Get the id of a given term. @@ -1082,7 +1150,7 @@ bool cvc5_term_is_int32_value(Cvc5Term term); * @param term The term. * @return The given term as `int32_t` value. */ -int32_t cvc5_get_int32_value(Cvc5Term term); +int32_t cvc5_term_get_int32_value(Cvc5Term term); /** * Determine if a given term is an uint32 value. * @note This will return true for integer constants and real constants that @@ -1136,7 +1204,7 @@ uint64_t cvc5_term_get_uint64_value(Cvc5Term term); * @return True if the term is an integer constant or a real constant that * has an integral value. */ -bool cvc5_term_isIntegerValue(Cvc5Term term); +bool cvc5_term_is_integer_value(Cvc5Term term); /** * Get a string representation of a given integral value. * @note Requires that the term is an integral value (see @@ -1247,7 +1315,7 @@ bool cvc5_term_is_boolean_value(Cvc5Term term); * @param term The term. * @return The representation of a Boolean value as a native Boolean value. */ -bool cvc5_get_boolean_value(Cvc5Term term); +bool cvc5_term_get_boolean_value(Cvc5Term term); /** * Determine if a given term is a bit-vector value. @@ -1488,7 +1556,7 @@ bool cvc5_term_is_cardinality_constraint(Cvc5Term term); */ void cvc5_term_get_cardinality_constraint(Cvc5Term term, Cvc5Sort* sort, - uint32_t upper); + uint32_t* upper); /** * Determine if a given term is a real algebraic number. @@ -1541,11 +1609,12 @@ Cvc5SkolemId cvc5_term_get_skolem_id(Cvc5Term term); * @note Asserts isSkolem(). * @warning This function is experimental and may change in future versions. * @param term The skolem. + * @param size The size of the resulting array. * @return The skolem indices of the term. This is list of terms that the - * skolem function is indexed by. For example, the array diff skolem - * `Cvc5SkolemId::ARRAY_DEQ_DIFF` is indexed by two arrays. + * skolem function is indexed by. For example, the array diff skolem + * `Cvc5SkolemId::ARRAY_DEQ_DIFF` is indexed by two arrays. */ -const Cvc5Term* cvc5_term_get_skolem_indices(Cvc5Term term); +const Cvc5Term* cvc5_term_get_skolem_indices(Cvc5Term term, size_t* size); /** * Compute the hash value of a term. @@ -1600,6 +1669,29 @@ const char* cvc5_dt_cons_decl_to_string(Cvc5DatatypeConstructorDecl decl); /* Cvc5DatatypeDecl */ /* -------------------------------------------------------------------------- */ +/** + * Make copy of datatype declaration, increases reference counter of `decl`. + * + * @param decl The datatype declaration to copy. + * @return The same datatype with its reference count increased by one. + * + * @note This step is optional and allows users to manage resources in a more + * fine-grained manner. + */ +Cvc5DatatypeDecl cvc5_dt_decl_copy(Cvc5DatatypeDecl decl); + +/** + * Release copy of datatype declaration, decrements reference counter of `dt`. + * + * @param decl The datatype declaration to release. + * + * @note This step is optional and allows users to release resources in a more + * fine-grained manner. Further, any API function that returns a + * Cvc5DatatypeDecl returns a copy that is owned by the callee of the + * function and thus, can be released. + */ +void cvc5_dt_decl_release(Cvc5DatatypeDecl decl); + /** * Add datatype constructor declaration. * @param decl The datatype declaration. @@ -1653,6 +1745,29 @@ const char* cvc5_dt_decl_get_name(Cvc5DatatypeDecl decl); /* Cvc5DatatypeSelector */ /* -------------------------------------------------------------------------- */ +/** + * Make copy of datatype selector, increases reference counter of `sel`. + * + * @param sel The datatype selector to copy. + * @return The same datatype selector with its reference count increased by one. + * + * @note This step is optional and allows users to manage resources in a more + * fine-grained manner. + */ +Cvc5DatatypeSelector cvc5_dt_sel_copy(Cvc5DatatypeSelector sel); + +/** + * Release copy of datatype selector, decrements reference counter of `sel`. + * + * @param sel The datatype selector to release. + * + * @note This step is optional and allows users to release resources in a more + * fine-grained manner. Further, any API function that returns a + * Cvc5DatatypeSelector returns a copy that is owned by the callee of the + * function and thus, can be released. + */ +void cvc5_dt_sel_release(Cvc5DatatypeSelector sel); + /** * Get the name of a given datatype selector. * @param sel The datatype selector. @@ -1706,6 +1821,30 @@ const char* cvc5_dt_sel_to_string(Cvc5DatatypeSelector sel); /* Cvc5DatatypeConstructor */ /* -------------------------------------------------------------------------- */ +/** + * Make copy of datatype constructor, increases reference counter of `cons`. + * + * @param cons The datatype constructor to copy. + * @return The same datatype constructor with its reference count increased by + * one. + * + * @note This step is optional and allows users to manage resources in a more + * fine-grained manner. + */ +Cvc5DatatypeConstructor cvc5_dt_cons_copy(Cvc5DatatypeConstructor cons); + +/** + * Release copy of datatype constructor, decrements reference counter of `cons`. + * + * @param cons The datatype constructor to release. + * + * @note This step is optional and allows users to release resources in a more + * fine-grained manner. Further, any API function that returns a + * Cvc5DatatypeConstructor returns a copy that is owned by the callee of + * the function and thus, can be released. + */ +void cvc5_dt_cons_release(Cvc5DatatypeConstructor cons); + /** * Get the name of a given datatype constructor. * @param cons The datatype constructor. @@ -1828,6 +1967,29 @@ const char* cvc5_dt_cons_to_string(Cvc5DatatypeConstructor cons); /* Cvc5Datatype */ /* -------------------------------------------------------------------------- */ +/** + * Make copy of datatype, increases reference counter of `dt`. + * + * @param dt The datatype to copy. + * @return The same datatype with its reference count increased by one. + * + * @note This step is optional and allows users to manage resources in a more + * fine-grained manner. + */ +Cvc5Datatype cvc5_dt_copy(Cvc5Datatype dt); + +/** + * Release copy of datatype, decrements reference counter of `dt`. + * + * @param dt The datatype to release. + * + * @note This step is optional and allows users to release resources in a more + * fine-grained manner. Further, any API function that returns a + * Cvc5Datatype returns a copy that is owned by the callee of the + * function and thus, can be released. + */ +void cvc5_dt_release(Cvc5Datatype dt); + /** * Get the datatype constructor of a given datatype at a given index. * @param dt The datatype. @@ -2317,6 +2479,7 @@ Cvc5Term cvc5_mk_tuple(Cvc5TermManager* tm, /** * Create a nullable some term. + * @param tm The term manager instance. * @param term The element value. * @return the Element value wrapped in some constructor. */ @@ -2324,29 +2487,33 @@ Cvc5Term cvc5_mk_nullable_some(Cvc5TermManager* tm, Cvc5Term term); /** * Create a selector for nullable term. + * @param tm The term manager instance. * @param term A nullable term. * @return The element value of the nullable term. */ -Cvc5Term cvc5_mk_nullable_val(Cvc5Term term); +Cvc5Term cvc5_mk_nullable_val(Cvc5TermManager* tm, Cvc5Term term); /** * Create a null tester for a nullable term. + * @param tm The term manager instance. * @param term A nullable term. * @return A tester whether term is null. */ -Cvc5Term cvc5_mk_nullable_is_null(Cvc5Term term); +Cvc5Term cvc5_mk_nullable_is_null(Cvc5TermManager* tm, Cvc5Term term); /** * Create a some tester for a nullable term. + * @param tm The term manager instance. * @param term A nullable term. * @return A tester whether term is some. */ -Cvc5Term cvc5_mk_nullable_is_some(Cvc5Term term); +Cvc5Term cvc5_mk_nullable_is_some(Cvc5TermManager* tm, Cvc5Term term); /** * Create a constant representing an null of the given sort. + * @param tm The term manager instance. * @param sort The sort of the Nullable element. * @return The null constant. */ -Cvc5Term cvc5_mk_nullable_null(Cvc5Sort sort); +Cvc5Term cvc5_mk_nullable_null(Cvc5TermManager* tm, Cvc5Sort sort); /** * Create a term that lifts kind to nullable terms. * @@ -2357,15 +2524,17 @@ Cvc5Term cvc5_mk_nullable_null(Cvc5Sort sort); * This function would return * (nullable.lift (lambda ((a Int) (b Int)) (+ a b)) x y) * + * @param tm The term manager instance. * @param kind The lifted operator. - * @param nargs The number of arguments of the lifted operator. + * @param size The number of arguments of the lifted operator. * @param args The arguments of the lifted operator. * @return A term of kind #CVC5_KIND_NULLABLE_LIFT where the first child * is a lambda expression, and the remaining children are * the original arguments. */ -Cvc5Term cvc5_mk_nullable_lift(Cvc5Kind kind, - size_t nargs, +Cvc5Term cvc5_mk_nullable_lift(Cvc5TermManager* tm, + Cvc5Kind kind, + size_t size, const Cvc5Term args[]); /* .................................................................... */ @@ -2491,7 +2660,7 @@ Cvc5Term cvc5_mk_real_int64(Cvc5TermManager* tm, int64_t val); * @param den The value of the denominator. * @return A constant of sort Real. */ -Cvc5Term cvc5_mk_real_num_den(int64_t num, int64_t den); +Cvc5Term cvc5_mk_real_num_den(Cvc5TermManager* tm, int64_t num, int64_t den); /** * Create a regular expression all (re.all) term. @@ -2505,7 +2674,7 @@ Cvc5Term cvc5_mk_regexp_all(Cvc5TermManager* tm); * @param tm The term manager instance. * @return The allchar term. */ -Cvc5Term cvc5_mk_regexp_all_char(Cvc5TermManager* tm); +Cvc5Term cvc5_mk_regexp_allchar(Cvc5TermManager* tm); /** * Create a regular expression none (re.none) term. @@ -2947,6 +3116,29 @@ const Cvc5Proof** cvc5_proof_get_children(Cvc5Proof* proof); */ const Cvc5Term* cvc5_proof_get_arguments(Cvc5Proof* proof); +/** + * Compare two proofs for referential equality. + * @param a The first proof. + * @param b The second proof. + * @return `true` if both proofs point to the same internal proof object. + */ +bool cvc5_proof_is_equal(Cvc5Proof* a, Cvc5Proof* b); + +/** + * Compare two proofs for referential disequality. + * @param a The first proof. + * @param b The second proof. + * @return `true` if the proofs point to different internal proof objects. + */ +bool cvc5_proof_is_disequal(Cvc5Proof* a, Cvc5Proof* b); + +/** + * Compute the hash value of a proof. + * @param proof The proof. + * @return The hash value of the proof. + */ +size_t cvc5_proof_hash(Cvc5Proof* proof); + /** * Prints a proof as a string in a selected proof format mode. * Other aspects of printing are taken from the solver options. diff --git a/include/cvc5/cvc5.h b/include/cvc5/cvc5.h index e4bca88e0f5..24b02f820a9 100644 --- a/include/cvc5/cvc5.h +++ b/include/cvc5/cvc5.h @@ -3516,7 +3516,7 @@ class CVC5_EXPORT Plugin public: Plugin(TermManager& tm); - virtual ~Plugin(); + virtual ~Plugin() = default; /** * Call to check, return vector of lemmas to add to the SAT solver. * This method is called periodically, roughly at every SAT decision. @@ -3561,6 +3561,7 @@ class CVC5_EXPORT Plugin class CVC5_EXPORT Proof { friend class Solver; + friend struct std::hash; public: /** @@ -3595,15 +3596,26 @@ class CVC5_EXPORT Proof */ const std::vector getArguments() const; + /** + * Operator overloading for referential equality of two proofs. + * @param p The proof to compare to for equality. + * @return `true` if both proofs point to the same internal proof object. + */ + bool operator==(const Proof& p) const; + + /** + * Referential disequality operator. + * @param p The proof to compare to for disequality. + * @return `true` if proofs point to different internal proof objects. + */ + bool operator!=(const Proof& p) const; + private: /** Construct a proof by wrapping a ProofNode. */ Proof(TermManager* tm, const std::shared_ptr p); - /** @return The internal proof node wrapped by this proof object. */ - const std::shared_ptr& getProofNode(void) const; - /** The internal proof node wrapped by this proof object. */ - std::shared_ptr d_proof_node; + std::shared_ptr d_proofNode; /** * The associated term manager. * @note This is only needed temporarily until deprecated term/sort handling @@ -3612,6 +3624,21 @@ class CVC5_EXPORT Proof TermManager* d_tm; }; +} // namespace cvc5 + +namespace std { +/** + * Hash function for proofs. + */ +template <> +struct CVC5_EXPORT hash +{ + size_t operator()(const cvc5::Proof& p) const; +}; +} // namespace std + +namespace cvc5 { + /* -------------------------------------------------------------------------- */ /* TermManager */ /* -------------------------------------------------------------------------- */ @@ -3734,6 +3761,19 @@ class CVC5_EXPORT TermManager * @return The function sort. */ Sort mkFunctionSort(const std::vector& sorts, const Sort& codomain); + /** + * Make a skolem. + * @param id The skolem identifier. + * @param indices The indices of the skolem. + * @return The skolem. + */ + Term mkSkolem(SkolemId id, const std::vector& indices); + /** + * Get the number of indices for a skolem id. + * @param id The skolem id. + * @return The number of indices for the skolem id. + */ + size_t getNumIndicesForSkolemId(SkolemId id); /** * Create a sort parameter. * diff --git a/include/cvc5/cvc5_proof_rule.h b/include/cvc5/cvc5_proof_rule.h index 3f91f31d412..e3b010f0831 100644 --- a/include/cvc5/cvc5_proof_rule.h +++ b/include/cvc5/cvc5_proof_rule.h @@ -1714,21 +1714,6 @@ enum ENUM(ProofRule) : uint32_t * \endverbatim */ EVALUE(RE_UNFOLD_NEG_CONCAT_FIXED), - /** - * \verbatim embed:rst:leading-asterisk - * **Strings -- Regular expressions -- Elimination** - * - * .. math:: - * - * \inferrule{-\mid F,b}{F = - * \texttt{strings::RegExpElimination::eliminate}(F, b)} - * - * where :math:`b` is a Boolean indicating whether we are using aggressive - * eliminations. Notice this rule concludes :math:`F = F` if no eliminations - * are performed for :math:`F`. - * \endverbatim - */ - EVALUE(RE_ELIM), /** * \verbatim embed:rst:leading-asterisk * **Strings -- Code points** @@ -1766,7 +1751,24 @@ enum ENUM(ProofRule) : uint32_t * \endverbatim */ EVALUE(MACRO_STRING_INFERENCE), - + /** + * \verbatim embed:rst:leading-asterisk + * **Strings -- Regular expressions -- Macro elimination** + * + * .. math:: + * + * \inferrule{-\mid F,b}{F = + * \texttt{strings::RegExpElimination::eliminate}(F, b)} + * + * where :math:`b` is a Boolean indicating whether we are using aggressive + * eliminations. Notice this rule concludes :math:`F = F` if no eliminations + * are performed for :math:`F`. + * + * \rst + * .. note:: We do not currently support elaboration of this macro. + * \endverbatim + */ + EVALUE(MACRO_RE_ELIM), /** * \verbatim embed:rst:leading-asterisk * **Arithmetic -- Adding inequalities** @@ -2181,66 +2183,6 @@ enum ENUM(ProofRule) : uint32_t * :math:`u`. \endverbatim */ EVALUE(ARITH_TRANS_SINE_APPROX_BELOW_POS), - - /** - * \verbatim embed:rst:leading-asterisk - * **Arithmetic -- Coverings -- Direct conflict** - * - * We use :math:`\texttt{IRP}_k(poly)` for an IndexedRootPredicate that is - * defined as the :math:`k`'th root of the polynomial :math:`poly`. Note that - * :math:`poly` may not be univariate; in this case, the value of - * :math:`\texttt{IRP}_k(poly)` can only be calculated with respect to a - * (partial) model for all but one variable of :math:`poly`. - * - * A formula :math:`\texttt{Interval}(x_i)` describes that a variable - * :math:`x_i` is within a particular interval whose bounds are given as IRPs. - * It is either an open interval or a point interval: - * - * .. math:: - * \texttt{IRP}_k(poly) < x_i < \texttt{IRP}_k(poly) - * - * x_i = \texttt{IRP}_k(poly) - * - * A formula :math:`\texttt{Cell}(x_1 \dots x_i)` describes a portion - * of the real space in the following form: - * - * .. math:: - * \texttt{Interval}(x_1) \land \dots \land \texttt{Interval}(x_i) - * - * A cell can also be empty (for :math:`i = 0`). - * - * A formula :math:`\texttt{Covering}(x_i)` is a set of intervals, implying - * that :math:`x_i` can be in neither of these intervals. To be a covering (of - * the real line), the union of these intervals should be the real numbers. - * - * .. math:: - * \inferrule{\texttt{Cell}, A \mid -}{\bot} - * - * A direct interval is generated from an assumption :math:`A` (in variables - * :math:`x_1 \dots x_i`) over a :math:`\texttt{Cell}(x_1 \dots x_i)`. It - * derives that :math:`A` evaluates to false over the cell. In the actual - * algorithm, it means that :math:`x_i` can not be in the topmost interval of - * the cell. \endverbatim - */ - EVALUE(ARITH_NL_COVERING_DIRECT), - /** - * \verbatim embed:rst:leading-asterisk - * **Arithmetic -- Coverings -- Recursive interval** - * - * See - * :cpp:enumerator:`ARITH_NL_COVERING_DIRECT ` - * for the necessary definitions. - * - * .. math:: - * \inferrule{\texttt{Cell}, \texttt{Covering} \mid -}{\bot} - * - * A recursive interval is generated from :math:`\texttt{Covering}(x_i)` over - * :math:`\texttt{Cell}(x_1 \dots x_{i-1})`. It generates the conclusion that - * no :math:`x_i` exists that extends the cell and satisfies all assumptions. - * \endverbatim - */ - EVALUE(ARITH_NL_COVERING_RECURSIVE), - /** * \verbatim embed:rst:leading-asterisk * **External -- LFSC** @@ -2525,6 +2467,54 @@ enum ENUM(ProofRewriteRule) : uint32_t * \endverbatim */ EVALUE(DT_CONS_EQ), + + /** + * \verbatim embed:rst:leading-asterisk + * **Bitvectors - Unsigned multiplication overflow detection elimination** + * + * See M.Gok, M.J. Schulte, P.I. Balzola, "Efficient integer multiplication + * overflow detection circuits", 2001. + * http://ieeexplore.ieee.org/document/987767 + * \endverbatim + */ + EVALUE(BV_UMULO_ELIMINATE), + /** + * \verbatim embed:rst:leading-asterisk + * **Bitvectors - Unsigned multiplication overflow detection elimination** + * + * See M.Gok, M.J. Schulte, P.I. Balzola, "Efficient integer multiplication + * overflow detection circuits", 2001. + * http://ieeexplore.ieee.org/document/987767 + * \endverbatim + */ + EVALUE(BV_SMULO_ELIMINATE), + /** + * \verbatim embed:rst:leading-asterisk + * **Bitvectors - Combine like terms during addition by counting terms** + * \endverbatim + */ + EVALUE(BV_ADD_COMBINE_LIKE_TERMS), + /** + * \verbatim embed:rst:leading-asterisk + * **Bitvectors - Extract negations from multiplicands** + * + * .. math:: + * (-a bvmul b bvmul c) \to -(a bvmul b c) + * + * \endverbatim + */ + EVALUE(BV_MULT_SIMPLIFY), + /** + * \verbatim embed:rst:leading-asterisk + * **Bitvectors - Extract continuous substrings of bitvectors** + * + * .. math:: + * (a bvand c) \to (concat (bvand a[i0:j0] c0) ... (bvand a[in:jn] cn)) + * + * where c0,..., cn are maximally continuous substrings of 0 or 1 in the constant c + * \endverbatim + */ + EVALUE(BV_BITWISE_SLICING), /** * \verbatim embed:rst:leading-asterisk * **Strings - regular expression loop elimination** @@ -2552,7 +2542,20 @@ enum ENUM(ProofRewriteRule) : uint32_t EVALUE(STR_IN_RE_EVAL), /** * \verbatim embed:rst:leading-asterisk - * **Strings - regular expression loop elimination** + * **Strings - regular expression membership consume** + * + * .. math:: + * \mathit{str.in_re}(s, R) = b + * + * where :math:`b` is either :math:`false` or the result of stripping + * entailed prefixes and suffixes off of :math:`s` and :math:`R`. + * + * \endverbatim + */ + EVALUE(STR_IN_RE_CONSUME), + /** + * \verbatim embed:rst:leading-asterisk + * **Strings - string in regular expression concatenation star character** * * .. math:: * \mathit{str.in\_re}(\mathit{str}.\text{++}(s_1, \ldots, s_n), \mathit{re}.\text{*}(R)) = diff --git a/proofs/alf/cvc5/Cvc5.smt3 b/proofs/alf/cvc5/Cvc5.smt3 index 5277f0924fb..e3014d7a526 100644 --- a/proofs/alf/cvc5/Cvc5.smt3 +++ b/proofs/alf/cvc5/Cvc5.smt3 @@ -33,11 +33,11 @@ ((run_evaluate (= x y)) (let ((ex (run_evaluate x))) (let ((ey (run_evaluate y))) (let ((res (alf.is_eq ex ey))) - (alf.ite (alf.and ($is_q_literal ex) ($is_q_literal ey)) res - (alf.ite (alf.and ($is_z_literal ex) ($is_z_literal ey)) res - (alf.ite (alf.and ($is_bin_literal ex) ($is_bin_literal ey)) res - (alf.ite (alf.and ($is_str_literal ex) ($is_str_literal ey)) res - (alf.ite (alf.and ($is_bool_literal ex) ($is_bool_literal ey)) res + (alf.ite (alf.and (alf.is_q ex) (alf.is_q ey)) res + (alf.ite (alf.and (alf.is_z ex) (alf.is_z ey)) res + (alf.ite (alf.and (alf.is_bin ex) (alf.is_bin ey)) res + (alf.ite (alf.and (alf.is_str ex) (alf.is_str ey)) res + (alf.ite (alf.and (alf.is_bool ex) (alf.is_bool ey)) res (= ex ey)))))))))) ((run_evaluate (not b)) (alf.not (run_evaluate b))) ((run_evaluate (ite b x y)) (alf.ite (run_evaluate b) (run_evaluate x) (run_evaluate y))) @@ -91,7 +91,7 @@ (alf.ite (alf.is_neg en) -1 (let ((ex (run_evaluate x))) (let ((exl (alf.len ex))) - (alf.ite ($compare_gt en exl) -1 + (alf.ite (alf.gt en exl) -1 (let ((exs (alf.extract ex n exl))) (let ((ey (run_evaluate y))) (let ((r (alf.find (alf.to_str exs) (alf.to_str ey)))) @@ -155,36 +155,51 @@ :conclusion (= a b) ) -(define get_aci_normal_form ((S Type :implicit) (t S)) +; define: $get_aci_normal_form +; args: +; - t S: The term to compute the normal form for. +; return: > +; The result of normalizing t for the proof rule aci_norm. In +; particular, if t is an application of a known operator that has the property +; of being either associative and commutative (resp. associative) we call +; the method $get_aci_norm (resp. $get_a_norm). +(define $get_aci_normal_form ((S Type :implicit) (t S)) (alf.match ((T Type) (U Type) (V Type) (x V) (x1 T) (x2 U :list) (m Int) (xb1 (BitVec m)) (xb2 (BitVec m) :list) (xf1 (FiniteField m)) (xf2 (FiniteField m) :list) (xs1 (Seq U)) (xs2 (Seq U) :list)) t ( - ((or x1 x2) (get_aci_norm t)) - ((and x1 x2) (get_aci_norm t)) - ((sep x1 x2) (get_aci_norm t)) - ((re.union x1 x2) (get_aci_norm t)) - ((re.inter x1 x2) (get_aci_norm t)) - ((bvor xb1 xb2) (get_aci_norm t)) - ((bvand xb1 xb2) (get_aci_norm t)) - ((ff.add xf1 xf2) (get_aci_norm t)) - ((ff.mul xf1 xf2) (get_aci_norm t)) - ((str.++ xs1 xs2) (get_a_norm t)) - ((re.++ x1 x2) (get_a_norm t)) + ((or x1 x2) ($get_aci_norm t)) + ((and x1 x2) ($get_aci_norm t)) + ((sep x1 x2) ($get_aci_norm t)) + ((re.union x1 x2) ($get_aci_norm t)) + ((re.inter x1 x2) ($get_aci_norm t)) + ((bvor xb1 xb2) ($get_aci_norm t)) + ((bvand xb1 xb2) ($get_aci_norm t)) + ((ff.add xf1 xf2) ($get_aci_norm t)) + ((ff.mul xf1 xf2) ($get_aci_norm t)) + ((str.++ xs1 xs2) ($get_a_norm t)) + ((re.++ x1 x2) ($get_a_norm t)) (x x) ) ) ) -; ProofRule::ACI_NORM -; Note that we need three checks. The first two handle the cases where one side -; is treated as a singleton child of the other side. The remaining case checks -; where both terms are not singletons. +; rule: aci_norm +; implements: ProofRule::ACI_NORM +; args: +; - eq Bool: The equality to be proven by this rule. +; requires: > +; That computing the normal forms via $get_aci_normal_form of the sides of the +; given equality between terms a and b suffices to show that a and b are +; equivalent. Note that we need three checks. The first two handle the cases +; where one side is treated as a singleton child of the other side. The +; remaining case checks where both terms are not singletons. +; conclusion: The given equality. (declare-rule aci_norm ((U Type) (a U) (b U)) :args ((= a b)) - :requires (((let ((an (get_aci_normal_form a)) (bn (get_aci_normal_form b))) + :requires (((let ((an ($get_aci_normal_form a)) (bn ($get_aci_normal_form b))) (alf.ite (alf.is_eq an b) true (alf.ite (alf.is_eq a bn) true (alf.is_eq an bn)))) true)) diff --git a/proofs/alf/cvc5/programs/Arith.smt3 b/proofs/alf/cvc5/programs/Arith.smt3 index 1b96b8ab306..d70e7776d9c 100644 --- a/proofs/alf/cvc5/programs/Arith.smt3 +++ b/proofs/alf/cvc5/programs/Arith.smt3 @@ -52,8 +52,8 @@ ;; =============== for ARITH_POLY_NORM ; Definitions of monomials and polynomials. -; A monomial is a list of terms that are ordered by `compare_var` and a rational coefficient. -; A polynomial is a list of monomials whose monomials are ordered by `compare_var`. +; A monomial is a list of terms that are ordered by `$compare_var` and a rational coefficient. +; A polynomial is a list of monomials whose monomials are ordered by `$compare_var`. (declare-sort @Monomial 0) (declare-const @mon (-> (! Type :var T :implicit) T Real @Monomial)) @@ -78,7 +78,7 @@ (let ((ca (alf.add c1 c2)) (pa (poly_add p1 p2))) ; check if cancels (alf.ite (alf.is_eq ca 0.0) pa (alf.cons @poly (@mon a1 ca) pa))) - (alf.ite (compare_var a1 a2) + (alf.ite ($compare_var a1 a2) (alf.cons @poly (@mon a1 c1) (poly_add p1 (@poly (@mon a2 c2) p2))) (alf.cons @poly (@mon a2 c2) (poly_add (@poly (@mon a1 c1) p1) p2))))) ((poly_add @poly.zero p) p) @@ -90,7 +90,7 @@ (program mvar_mul_mvar ((T Type) (U Type) (V Type) (W Type) (X Type) (Y Type) (Z Type) (a1 T) (a2 U :list) (b1 V) (b2 W :list)) (X Y) Z ( - ((mvar_mul_mvar (* a1 a2) (* b1 b2)) (alf.ite (compare_var a1 b1) + ((mvar_mul_mvar (* a1 a2) (* b1 b2)) (alf.ite ($compare_var a1 b1) (alf.cons * a1 (mvar_mul_mvar a2 (* b1 b2))) (alf.cons * b1 (mvar_mul_mvar (* a1 a2) b2)))) ((mvar_mul_mvar (* a1 a2) 1) (* a1 a2)) diff --git a/proofs/alf/cvc5/programs/Quantifiers.smt3 b/proofs/alf/cvc5/programs/Quantifiers.smt3 index 20dca42395b..ffd59b372df 100644 --- a/proofs/alf/cvc5/programs/Quantifiers.smt3 +++ b/proofs/alf/cvc5/programs/Quantifiers.smt3 @@ -18,3 +18,36 @@ ((substitute_list @list.nil @list.nil F) F) ) ) + + +; program: $substitute_simul +; args: +; - s S: The term to substitute into. +; - xs @List: The list of variables to substitute. +; - ss @List: The terms to substitute. +; return: the result of simultaneously substituting xs to ss in t. +(program $substitute_simul + ((T Type) (S Type) (x S) (f (-> T S)) (a T) (xs @List :list) (ss @List :list) (s S) (y S)) + (S @List @List) S + ( + (($substitute_simul (f a) xs ss) (_ ($substitute_simul f xs ss) ($substitute_simul a xs ss))) + (($substitute_simul x @list.nil @list.nil) x) + (($substitute_simul x (@list x xs) (@list s ss)) s) ; note that we do not substitute further since this is a simultaneous substitution. + (($substitute_simul x (@list y xs) (@list s ss)) ($substitute_simul x xs ss)) + ) +) + +; program: $beta_reduce +; args: +; - u U: > +; The term to beta reduce. This should be an application of a lambda +; whose arguments have been partially accumulated into ss. +; - ss @List: The accumulated list of arguments to pass to the lambda. +; return: the result of beta reduction. +(program $beta_reduce ((U Type) (T Type) (S Type) (f (-> T U)) (a T) (t S) (xs @List) (ss @List :list)) + (U @List) U + ( + (($beta_reduce (lambda xs t) ss) ($substitute_simul t xs ss)) + (($beta_reduce (f a) ss) ($beta_reduce f (@list a ss))) + ) +) diff --git a/proofs/alf/cvc5/programs/Strings.smt3 b/proofs/alf/cvc5/programs/Strings.smt3 index c0a33ec78a8..b9d172859b0 100644 --- a/proofs/alf/cvc5/programs/Strings.smt3 +++ b/proofs/alf/cvc5/programs/Strings.smt3 @@ -36,7 +36,7 @@ ; Return true if n is a valid code point [0, 196607]. (define $str_is_code_point ((n Int)) - (alf.ite ($is_z_literal n) + (alf.ite (alf.is_z n) (alf.ite ($compare_geq 196608 n) (alf.not (alf.is_neg n)) false) @@ -67,6 +67,12 @@ ) ) +; `$str_is_char_range s1 s2` returns true if (re.range s1 s2) is a character +; range (i.e. s1 and s2 are strings of length 1). +(define $str_is_char_range ((s1 String) (s2 String)) + (alf.and (alf.is_eq (alf.len s1) 1) (alf.is_eq (alf.len s2) 1)) +) + ;;-------------------- RE evaluation (declare-const @re.null RegLan) @@ -120,7 +126,7 @@ ; Returns true if s is in regular expression r. ; Does not evaluate if s is not a string literal. (define $str_eval_str_in_re ((s String) (r RegLan)) - (alf.ite ($is_str_literal s) + (alf.ite (alf.is_str s) ($str_eval_str_in_re_rec s 0 r @re.null) (str.in_re s r))) @@ -179,7 +185,7 @@ (define $str_rev ((U Type :implicit) (rev Bool) (t U)) (alf.ite rev (nary.reverse t) t)) -; Nary-intro, which ensures that the input t is a str.++ application. +; String nary-intro, which ensures that the input t is a str.++ application. ; In particular, if it is not a str.++ and not the empty string, then we return ; (str.++ t empty) where empty is the empty string for the type of t. (program $str_nary_intro @@ -192,9 +198,21 @@ ) ) -; Nary-elimination, which ensures that the input t is not a str.++ application. -; In particular, if t is of the form (str.++ t empty) where empty is the empty -; string for the type of t, we return t. +; Regular expression nary-intro, which ensures that the input t is a re.++ +; application. In particular, if it is not a re.++ and not the empty regular +; expression, then we return (re.++ t @re.empty). +(program $re_nary_intro ((t RegLan) (ss RegLan :list)) + (RegLan) RegLan + ( + (($re_nary_intro (re.++ t ss)) (re.++ t ss)) + (($re_nary_intro @re.empty) @re.empty) + (($re_nary_intro t) (alf.cons re.++ t @re.empty)) + ) +) + +; String nary-elimination, which ensures that the input t is not a str.++ +; application. In particular, if t is of the form (str.++ t1 empty) where empty +; is the empty string for the type of t, we return t1. (program $str_nary_elim ((T Type) (t (Seq T)) (ss (Seq T) :list)) ((Seq T)) (Seq T) @@ -205,6 +223,17 @@ ) ) +; Regular expression nary-elimination, which ensures that the input t is not a +; re.++ application. In particular, if t is of the form (re.++ t1 @re.empty), +; we return t1. +(program $re_nary_elim ((t RegLan) (ss RegLan :list)) + (RegLan) RegLan + ( + (($re_nary_elim (re.++ t ss)) (alf.ite (alf.is_eq ss @re.empty) t (re.++ t ss))) + (($re_nary_elim t) t) + ) +) + ;;-------------------- Reductions ; In the following, a "reduction predicate" refers to a formula that is used @@ -345,7 +374,7 @@ (program re_unfold_pos_concat_rec ((t String) (r1 RegLan) (r2 RegLan :list) (ro RegLan) (i Int)) (String RegLan RegLan Int) (@Pair String Bool) ( - ((re_unfold_pos_concat_rec t (str.to_re "") ro i) (@pair "" true)) + ((re_unfold_pos_concat_rec t @re.empty ro i) (@pair "" true)) ((re_unfold_pos_concat_rec t (re.++ r1 r2) ro i) ; match recursive call (alf.match ((c String :list) (M Bool :list)) @@ -562,9 +591,9 @@ ; where d>0. This is the regular expression: ; (re.union r^n ... r^{n+d}) ; where r^k is (re.++ r ... r), where r is repeated k times when k>1, or -; r if k=1 or (str.to_re "") if k=0. +; r if k=1 or @re.empty if k=0. (define $str_mk_re_loop_elim ((n Int) (d Int) (r RegLan)) - ($singleton_elim ($str_mk_re_loop_elim_rec n d r (str.to_re ""))) + ($singleton_elim ($str_mk_re_loop_elim_rec n d r @re.empty)) ) ; Helper for ProofRewriteRule::STR_IN_RE_CONCAT_STAR_CHAR. @@ -620,6 +649,29 @@ ($str_rev rev ($str_flatten ($str_nary_intro s))) ) +; `$re_str_to_flat_form rev r` convert the strings s occurring as direct +; children (str.to_re s) of regular expression concatenation r to their flat +; form, reversing if rev is true. +(program $re_str_to_flat_form ((r1 RegLan) (r2 RegLan :list) (s String) (rev Bool)) + (Bool RegLan) RegLan + ( + (($re_str_to_flat_form rev (re.++ (str.to_re s) r2)) (alf.cons re.++ (str.to_re (string_to_flat_form s rev)) ($re_str_to_flat_form rev r2))) + (($re_str_to_flat_form rev (re.++ r1 r2)) (alf.cons re.++ r1 ($re_str_to_flat_form rev r2))) + (($re_str_to_flat_form rev r1) r1) + ) +) + +; Converts a regular expression term to "flat form". This consists of the +; following steps: +; (1) convert r to n-ary form if it not already a re.++ application, +; (2) (optionally) reverse, +; (3) convert the strings s occurring as direct children (str.to_re s) of the +; result to their flat form. Note that other strings in r, i.e. those that +; occur benath other children remain unchanged. +(define $re_to_flat_form ((r RegLan) (rev Bool)) + ($re_str_to_flat_form rev ($str_rev rev ($re_nary_intro r))) +) + ; Converts a term in "flat form" to a term that is in a form that corresponds ; to one in cvc5 rewritten form. This is the dual method to ; string_to_flat_form. This consists of the following steps: @@ -630,3 +682,158 @@ ; reverse, collect, elim ($str_nary_elim (string_collect ($str_rev rev s))) ) + +; `$re_str_from_flat_form rev r` convert the strings s occurring as direct +; children (str.to_re s) of regular expression concatenation r from their flat +; form, reversing if rev is true. +(program $re_str_from_flat_form ((r1 RegLan) (r2 RegLan :list) (s String) (rev Bool)) + (Bool RegLan) RegLan + ( + (($re_str_from_flat_form rev (re.++ (str.to_re s) r2)) (alf.cons re.++ (str.to_re (string_from_flat_form s rev)) ($re_str_from_flat_form rev r2))) + (($re_str_from_flat_form rev (re.++ r1 r2)) (alf.cons re.++ r1 ($re_str_from_flat_form rev r2))) + (($re_str_from_flat_form rev r1) r1) + ) +) + +; Converts a regular expression term in "flat form" to a term that is in a form +; that corresponds to one in cvc5 rewritten form. This is the dual method to +; $re_to_flat_form. This consists of the following steps: +; (1) convert the strings s occurring as direct children (str.to_re s) from their flat form, +; (2) (optionally) reverse, +; (3) eliminate n-ary form to its element if the term is a singleton list. +(define $re_from_flat_form ((r RegLan) (rev Bool)) + ; (un?)flatten, reverse, elim + ($re_nary_elim ($str_rev rev ($re_str_from_flat_form rev r))) +) + +; program: $str_re_consume_rec +; args: +; - s String: The string argument of the membership to rewrite. +; - r RegLan: The regular expression argument of the membership to rewrite. +; - b Bool: > +; Stores temporary results when we are processing a union or intersection +; regular expression as argument r. Otherwise, this argument is @result.null. +; - rev Bool: > +; Indicates whether s and r were reversed, in which case their components must +; be reversed when we recurse on non-str.to_re children. +; return: > +; The result of implied consumption of string s in regular expression r. +(program $str_re_consume_rec ((s1 String) (s2 String :list) (s String) (r1 RegLan) (r2 RegLan :list) (b Bool) (rev Bool)) + (String RegLan Bool Bool) Bool + ( + (($str_re_consume_rec (str.++ s1 s2) (re.++ r1 r2) @result.null rev) + (alf.match ((s3 String) (s4 String :list) (s5 String) (r3 RegLan)) + r1 + ( + ((str.to_re (str.++ s3 s4)) (alf.ite (alf.is_eq s1 s3) + ($str_re_consume_rec s2 (re.++ (str.to_re s4) r2) @result.null rev) + (alf.ite (alf.and (string_check_length_one s1) (string_check_length_one s3)) + false ; conflicting characters + (str.in_re (str.++ s1 s2) (re.++ r1 r2))))) ; otherwise stuck + (@re.empty ($str_re_consume_rec (str.++ s1 s2) r2 @result.null rev)) ; finished current component + ((re.range s3 s5) (alf.ite (alf.and (string_check_length_one s1) ($str_is_char_range s3 s5)) + (alf.ite ($str_eval_str_in_re s1 (re.range s3 s5)) + ($str_re_consume_rec s2 r2 @result.null rev) + false) + (str.in_re (str.++ s1 s2) (re.++ r1 r2)))) + (re.allchar (alf.ite (string_check_length_one s1) + ($str_re_consume_rec s2 r2 @result.null rev) + (str.in_re (str.++ s1 s2) (re.++ r1 r2)))) + ((re.* r3) ; see what happens if we unroll once + (alf.match ((sr String) (rr RegLan)) + ($str_re_consume_rec (str.++ s1 s2) ($re_to_flat_form r3 rev) @result.null rev) + ( + ; We can't unroll even once, thus we must skip it. + (false ($str_re_consume_rec (str.++ s1 s2) r2 @result.null rev)) + ; If we fully consumed, now we go back and check if we get a conflict if we skip. + ((str.in_re sr @re.empty) (alf.match ((br Bool)) + ($str_re_consume_rec (str.++ s1 s2) r2 @result.null rev) + ( + ; Skipping would give a conflict. + (false (alf.ite (alf.is_eq (str.++ s1 s2) sr) + ; if we did not consume anything, we are stuck. + (str.in_re (str.++ s1 s2) (re.++ r1 r2)) + ; otherwise, we continue with the RE consumed once. + ($str_re_consume_rec sr (re.++ r1 r2) @result.null rev) + )) + ; Otherwise we are stuck. + (br (str.in_re (str.++ s1 s2) (re.++ r1 r2))) + ) + )) + ; Otherwise we are stuck. + ((str.in_re sr rr) (str.in_re (str.++ s1 s2) (re.++ r1 r2))) + ) + )) + (r3 ; likely intersection or union, process cases recursively + (alf.match ((sr String) (br Bool)) + ($str_re_consume_rec (str.++ s1 s2) r3 @result.null rev) + ( + ; conflict + (false false) + ; if all cases consumed the same, continue + ((str.in_re sr @re.empty) ($str_re_consume_rec sr r2 @result.null rev)) + ; otherwise we are stuck + (br (str.in_re (str.++ s1 s2) (re.++ r1 r2))) + ) + )) + ) + ) + ) + (($str_re_consume_rec s1 (re.++ @re.empty r2) @result.null rev) + ($str_re_consume_rec s1 r2 @result.null rev)) ; finished current component + ; Intersection reports conflicts eagerly, and otherwise combines the results + (($str_re_consume_rec s1 (re.inter r1 r2) b rev) (let ((r1r ($re_to_flat_form r1 rev))) + (alf.match ((bb Bool)) + ($str_re_consume_rec s1 r1r @result.null rev) + ( + (false false) + (bb ($str_re_consume_rec s1 r2 ($result_combine bb b) rev)) + ) + ))) + (($str_re_consume_rec s1 re.all @result.null rev) (str.in_re "" @re.empty)) ; only used if re.all appears in unexpected position + (($str_re_consume_rec s1 re.all b rev) b) ; end of re.inter + ; Union ignores conflicts, and otherwise combines the results. We report a conflict if all children give conflicts. + (($str_re_consume_rec s1 (re.union r1 r2) b rev) (let ((r1r ($re_to_flat_form r1 rev))) + (alf.match ((bb Bool)) + ($str_re_consume_rec s1 r1r @result.null rev) + ( + (false ($str_re_consume_rec s1 r2 b rev)) + (bb ($str_re_consume_rec s1 r2 ($result_combine bb b) rev)) + ) + ))) + (($str_re_consume_rec s1 re.none @result.null rev) false) ; end of re.union, conflict, also used if re.none appears in unexpected position + (($str_re_consume_rec s1 re.none b rev) b) ; end of re.union, no conflict + (($str_re_consume_rec s1 r1 @result.null rev) (str.in_re s1 r1)) + ) +) + +; `$str_re_consume +; args: +; - s String: The string argument of the membership to rewrite. +; - r RegLan: The regular expression argument of the membership to rewrite. +; returns: > +; false if `(str.in_re s r)` can be shown to be equivalent to false, or +; otherwise `(str.in_re sr rr)` where sr and rr are the result of "consuming" +; prefixes/suffixes from s and r. We consume from the end of s and r first by +; reversing them initially and converting them to flat forms. We then reverse +; them again and consume from the beginning of the remainder. Finally, we convert +; back from flat form when applicable. +(define $str_re_consume ((s String) (r RegLan)) + (let ((ss (string_to_flat_form s true))) + (let ((rr ($re_to_flat_form r true))) + (alf.match ((s1 String) (r1 RegLan)) + ($str_re_consume_rec ss rr @result.null true) + ( + (false false) + ((str.in_re s1 r1) (let ((s1r ($str_rev true s1)) (r1r ($re_to_flat_form r1 true))) + (alf.match ((s2 String) (r2 RegLan)) + ($str_re_consume_rec s1r r1r @result.null false) + ( + (false false) + ((str.in_re s2 r2) (str.in_re (string_from_flat_form s2 false) ($re_from_flat_form r2 false))) + ) + )) + ) + ) + ))) +) diff --git a/proofs/alf/cvc5/programs/Utils.smt3 b/proofs/alf/cvc5/programs/Utils.smt3 index e6d1ffff0fe..60c77678fee 100644 --- a/proofs/alf/cvc5/programs/Utils.smt3 +++ b/proofs/alf/cvc5/programs/Utils.smt3 @@ -1,33 +1,10 @@ - -; Returns true if x is a Boolean literal. -(define $is_bool_literal ((T Type :implicit) (x T)) - (alf.ite (alf.is_eq x true) true (alf.is_eq x false))) - -; Returns true if x is a rational literal. -(define $is_q_literal ((T Type :implicit) (x T)) - (alf.is_eq (alf.to_q x) x)) - -; Returns true if x is a numeral literal. -(define $is_z_literal ((T Type :implicit) (x T)) - (alf.is_eq (alf.to_z x) x)) - -; Returns true if x is a binary literal. -(define $is_bin_literal ((T Type :implicit) (x T)) - (alf.is_eq (alf.to_bin (alf.len x) x) x)) - -; Returns true if x is a string literal. -(define $is_str_literal ((T Type :implicit) (x T)) - (alf.is_eq (alf.to_str x) x)) - -; Compare arithmetic greater than. Assumes x and y are values. -; Returns true if x > y. -(define $compare_gt ((T Type :implicit) (x T) (y T)) - (alf.is_neg (alf.add (alf.neg x) y))) - -; Compare arithmetic greater than. Assumes x and y are values. -; Returns true if x >= y. +; define: $compare_geq +; args: +; - x T: The first term to compare. +; - y T: The second term to compare. +; return: true if x >= y, where x and y are assumed to be arithmetic values. (define $compare_geq ((T Type :implicit) (x T) (y T)) - (alf.not (alf.is_neg (alf.add (alf.neg y) x)))) + (alf.ite (alf.is_eq x y) true (alf.gt x y))) (declare-type @Pair (Type Type)) (declare-const @pair (-> (! Type :var U :implicit) (! Type :var T :implicit) U T (@Pair U T))) @@ -37,25 +14,38 @@ (declare-const @list.nil @List) (declare-const @list (-> (! Type :var T :implicit) T @List @List) :right-assoc-nil @list.nil) -; This is used to have a canonical ordering of variables. -; It could potentially be improved by having a builtin operator, e.g. alf.compare. -; The variable ordering always returns true for the variable with the lower -; hash. This leads to best case performance if sorting a term with distinct -; children, where if we ask for the hash of the children in order and prefer -; the ones where this compare returns true, then the term remains unchanged. -(define compare_var ((T Type :implicit) (U Type :implicit) (a T) (b U)) - (alf.is_neg (alf.add (alf.hash b) (alf.neg (alf.hash a))))) - -; Returns the tail of x, where x is expected to be a function application. +; define: $compare_var +; args: +; - a T: The first term to compare. +; - b U: The second term to compare. +; return: true if a should be considered before b in an ordering where a and b are considered to be atomic variables. +; note: > +; This method is used to have a canonical ordering of variables. +; It could potentially be improved by having a builtin operator, e.g. alf.compare. +; The variable ordering always returns true for the variable with the lower +; hash. This leads to best case performance if sorting a term with distinct +; children, where if we ask for the hash of the children in order and prefer +; the ones where this compare returns true, then the term remains unchanged. +(define $compare_var ((T Type :implicit) (U Type :implicit) (a T) (b U)) + (alf.cmp b a)) + +; define: $tail +; args: +; - x S: The term to inspect. +; return: the tail of x, where x is expected to be a function application. (define $tail ((S Type :implicit) (x S)) (alf.match ((T Type) (U Type) (S Type) (f (-> T U S)) (x1 T) (x2 T :list)) x (((f x1 x2) x2))) ) -; Eliminate singleton list. -; If the input term is of the form (f x1 x2) where x2 is the nil terminator of -; f, then we return x1. Otherwise, we return the input term unchanged. +; program: $singleton_elim +; args: +; - s S: The term to proces. +; return: > +; The result of applying singleton elimination for s. In particular, +; if s is of the form (f x1 x2) where x2 is the nil terminator of f, then we +; return x1. Otherwise, we return s unchanged. (program $singleton_elim ((T Type) (S Type) (U Type) (f (-> T U S)) (x S) (x1 T) (x2 T :list)) (S) S ( @@ -64,79 +54,126 @@ ) ) -; Eliminate singleton list, which takes: -; (1) a function f -; (2) the identity element of f -; (3) the term to process -(program singleton_elim ((T Type) (S Type) (U Type) (f (-> T U S)) (id S) (x S) (x1 T) (x2 U :list)) +; program: $singleton_elim_aci +; args: +; - f (-> T U S): The function we are considering. +; - id S: The nil terminator of f. +; - s S: The term to process. +; return: > +; The result of applying singleton elimination for s, where s should +; be an application of f. In particular, if s is of the form (f x1 x2) where +; x2 is the nil terminator of f, then we return x1. Otherwise, we return s +; unchanged. +; note: > +; This method is similar in purpose to $singleton_elim, but insists that +; the function and its nil terminator are provided explicitly. +(program $singleton_elim_aci ((T Type) (S Type) (U Type) (f (-> T U S)) (id S) (x S) (x1 T) (x2 U :list)) ((-> T U S) S S) S ( - ((singleton_elim f id (f x1 x2)) (alf.ite (alf.is_eq x2 id) x1 (f x1 x2))) - ((singleton_elim f id x) x) + (($singleton_elim_aci f id (f x1 x2)) (alf.ite (alf.is_eq x2 id) x1 (f x1 x2))) + (($singleton_elim_aci f id x) x) ) ) ;; =============== for ACI_NORM associative, commutative and idempotent -; Append the children of two applications of an ACI operator, which takes: -; (1) a function f -; (2) the identity element of f -; (3) the first f :list term to append -; (4) the second f :list term to append -(program ac_append ((T Type) (S Type) (U Type) (f (-> T U S)) (id S) (x S) (x1 T) (x2 U :list) (y1 T) (y2 U :list)) +; program: $ac_append +; args: +; - f (-> T U S): The function, which is assumed to be associative, commutative, idempotent and has the given identity. +; - id S: The nil terminator of f. +; - s1 S: The first term to process. +; - s2 S: The second term to process. +; return: the result of appending the children of two applications s1 and s2 of the ACI operator f. +(program $ac_append ((T Type) (S Type) (U Type) (f (-> T U S)) (id S) (x S) (x1 T) (x2 U :list) (y1 T) (y2 U :list)) ((-> T U S) S S S) S ( - ((ac_append f id (f x1 x2) (f y1 y2)) (alf.ite (alf.is_eq x1 y1) - (ac_append f id (f x1 x2) y2) - (alf.ite (compare_var x1 y1) - (alf.cons f x1 (ac_append f id x2 (f y1 y2))) - (alf.cons f y1 (ac_append f id (f x1 x2) y2))))) - ((ac_append f id (f x1 x2) id) (f x1 x2)) - ((ac_append f id id (f y1 y2)) (f y1 y2)) - ((ac_append f id id id) id) + (($ac_append f id (f x1 x2) (f y1 y2)) (alf.ite (alf.is_eq x1 y1) + ($ac_append f id (f x1 x2) y2) + (alf.ite ($compare_var x1 y1) + (alf.cons f x1 ($ac_append f id x2 (f y1 y2))) + (alf.cons f y1 ($ac_append f id (f x1 x2) y2))))) + (($ac_append f id (f x1 x2) id) (f x1 x2)) + (($ac_append f id id (f y1 y2)) (f y1 y2)) + (($ac_append f id id id) id) ) ) -; Helper to normalize an application of an ACI operator, which takes: -; (1) a function f -; (2) the identity element of f -; (3) the term to process -(program get_aci_norm_rec ((T Type) (S Type) (U Type) (f (-> T U S)) (id S) (x S) (x1 T) (x2 U :list)) +; program: $get_aci_norm_rec +; args: +; - f (-> T U S): The function, which is assumed to be associative, commutative, idempotent and has the given identity. +; - id S: The nil terminator of f. +; - s S: The term to process. +; return: the result of normalizing s based on ACI reasoning. +(program $get_aci_norm_rec ((T Type) (S Type) (U Type) (f (-> T U S)) (id S) (x S) (x1 T) (x2 U :list)) ((-> T U S) S S) S ( - ((get_aci_norm_rec f id (f id x2)) (get_aci_norm_rec f id x2)) - ((get_aci_norm_rec f id (f x1 x2)) (ac_append f id (get_aci_norm_rec f id x1) (get_aci_norm_rec f id x2))) - ((get_aci_norm_rec f id id) id) - ((get_aci_norm_rec f id x) (alf.cons f x id)) + (($get_aci_norm_rec f id (f id x2)) ($get_aci_norm_rec f id x2)) + (($get_aci_norm_rec f id (f x1 x2)) ($ac_append f id ($get_aci_norm_rec f id x1) ($get_aci_norm_rec f id x2))) + (($get_aci_norm_rec f id id) id) + (($get_aci_norm_rec f id x) (alf.cons f x id)) ) ) -; Normalize an application of an ACI operator. -(define get_aci_norm ((T Type :implicit) (t T)) +; define: $get_aci_norm +; args: +; - t T: The term to process. +; return: the result of normalizing s based on ACI reasoning. +(define $get_aci_norm ((T Type :implicit) (t T)) (alf.match ((S Type) (U Type) (V Type) (f (-> S U V)) (x S) (y U :list)) t - (((f x y) (let ((id (alf.nil f x y))) (singleton_elim f id (get_aci_norm_rec f id t)))))) + (((f x y) (let ((id (alf.nil f x y))) ($singleton_elim_aci f id ($get_aci_norm_rec f id t)))))) ) ;; =============== for ACI_NORM associative -; Helper to normalize an application of an associative operator, which takes: -; (1) a function f -; (2) the identity element of f -; (3) the term to process -(program get_a_norm_rec ((T Type) (S Type) (U Type) (f (-> T U S)) (id S) (x S) (x1 T) (x2 U :list)) +; program: $get_a_norm_rec +; args: +; - f (-> T U S): The function we are considering, which is assumed to be associative and has the given identity. +; - id S: The nil terminator of f. +; - s S: The term to process. +; return: the result of normalizing s based on associative+identity reasoning. +(program $get_a_norm_rec ((T Type) (S Type) (U Type) (f (-> T U S)) (id S) (x S) (x1 T) (x2 U :list)) ((-> T U S) S S) S ( - ((get_a_norm_rec f id (f id x2)) (get_a_norm_rec f id x2)) - ((get_a_norm_rec f id (f x1 x2)) (alf.list_concat f (get_a_norm_rec f id x1) (get_a_norm_rec f id x2))) - ((get_a_norm_rec f id id) id) - ((get_a_norm_rec f id x) (alf.cons f x id)) + (($get_a_norm_rec f id (f id x2)) ($get_a_norm_rec f id x2)) + (($get_a_norm_rec f id (f x1 x2)) (alf.list_concat f ($get_a_norm_rec f id x1) ($get_a_norm_rec f id x2))) + (($get_a_norm_rec f id id) id) + (($get_a_norm_rec f id x) (alf.cons f x id)) ) ) -; Normalize an application of an associative operator. -(define get_a_norm ((T Type :implicit) (t T)) +; define: $get_a_norm +; args: +; - t T: The term to process. +; return: the result of normalizing s based on associative+identity reasoning. +(define $get_a_norm ((T Type :implicit) (t T)) (alf.match ((S Type) (U Type) (V Type) (f (-> S U V)) (x S) (y U :list)) t - (((f x y) (let ((id (alf.nil f x y))) (singleton_elim f id (get_a_norm_rec f id t)))))) + (((f x y) (let ((id (alf.nil f x y))) ($singleton_elim_aci f id ($get_a_norm_rec f id t)))))) +) + + +;; =============== for results + +; Used for representing partial results of the method below. +(declare-const @result.null Bool) +(declare-const @result.invalid Bool) + +; program: $result_combine +; args: +; - b1 Bool: The first Boolean result to combine. +; - b2 Bool: The second Boolean result to combine. +; return: > +; The result of combining the two results if they agree, where @result.null +; is treated as no result and @result.invalid is treated as an invalid result. +; note: > +; In summary, ($result_combine b1 ... ($result_combine bn @result.null)) returns +; b1 if b1...bn are the same or @result.invalid otherwise. +(program $result_combine ((b1 Bool) (b2 Bool)) + (Bool Bool) Bool + ( + (($result_combine b1 @result.null) b1) + (($result_combine b1 b1) b1) + (($result_combine b1 b2) @result.invalid) + ) ) diff --git a/proofs/alf/cvc5/rules/Arith.smt3 b/proofs/alf/cvc5/rules/Arith.smt3 index 8085a30870b..4de8a3f54ad 100644 --- a/proofs/alf/cvc5/rules/Arith.smt3 +++ b/proofs/alf/cvc5/rules/Arith.smt3 @@ -1,157 +1,253 @@ -; depends: arith_programs.plf - (include "../theories/Builtin.smt3") (include "../theories/Reals.smt3") (include "../theories/Ints.smt3") (include "../programs/Arith.smt3") (include "../programs/Utils.smt3") -(program arith_rel_sum ((T Type) (U Type) (S Type) (r1 T) (r2 U)) +; program: $arith_rel_sum +; args: +; - r1 T : The first arithmetic relation. +; - r2 U : The second arithmetic relation. +; return: > +; the relation that is implied when applications of the relations r1 and +; r2 are added together for ProofRule::ARITH_SUM_UB. +(program $arith_rel_sum ((T Type) (U Type) (S Type) (r1 T) (r2 U)) (T U) S ( - ((arith_rel_sum < <) <) - ((arith_rel_sum < =) <) - ((arith_rel_sum < <=) <) - ((arith_rel_sum <= <) <) - ((arith_rel_sum <= =) <=) - ((arith_rel_sum <= <=) <=) - ((arith_rel_sum = <) <) - ((arith_rel_sum = =) <=) ; could be =, but internal proof checker does <= - ((arith_rel_sum = <=) <=) + (($arith_rel_sum < <) <) + (($arith_rel_sum < =) <) + (($arith_rel_sum < <=) <) + (($arith_rel_sum <= <) <) + (($arith_rel_sum <= =) <=) + (($arith_rel_sum <= <=) <=) + (($arith_rel_sum = <) <) + (($arith_rel_sum = =) <=) ; could be =, but internal proof checker does <= + (($arith_rel_sum = <=) <=) ) ) -(program arith_mk_zero ((T Type)) + +; program: $arith_mk_zero +; args: +; - u Type : The type of the zero, which should be Int or Real. +; return: the zero for the given type. +(program $arith_mk_zero ((T Type)) (Type) T ( - ((arith_mk_zero Real) 0.0) - ((arith_mk_zero Int) 0) + (($arith_mk_zero Real) 0.0) + (($arith_mk_zero Int) 0) ) ) -(program mk_arith_sum_ub ((T Type) (U Type) (r (-> T U Bool)) (a T) (b U) (tail Bool :list)) +; program: $mk_arith_sum_ub +; args: +; - F Bool: A conjunction of arithmetic relations. +; return: the arithmetic relation that is implied by adding each of the relations in F together. +(program $mk_arith_sum_ub ((T Type) (U Type) (r (-> T U Bool)) (a T) (b U) (tail Bool :list)) (Bool) Bool ( - ((mk_arith_sum_ub true) (= 0 0)) - ((mk_arith_sum_ub (and (r a b) tail)) + (($mk_arith_sum_ub true) (= 0 0)) + (($mk_arith_sum_ub (and (r a b) tail)) (alf.match ((S Type) (V Type) (r2 (-> S V Bool)) (a2 S :list) (b2 V :list)) - (mk_arith_sum_ub tail) - (((r2 a2 b2) (_ (arith_rel_sum r r2) (+ a a2) (+ b b2)))))) + ($mk_arith_sum_ub tail) + (((r2 a2 b2) (_ ($arith_rel_sum r r2) (+ a a2) (+ b b2)))))) ) ) +; rule: arith_sum_ub +; implements: ProofRule::ARITH_SUM_UB +; premises: +; - F Bool: A conjunction of arithmetic relations. +; conclusion: > +; The arithmetic relation that is implied by adding each of the +; relations in F together. (declare-rule arith_sum_ub ((F Bool)) :premise-list F and - :conclusion (mk_arith_sum_ub F) + :conclusion ($mk_arith_sum_ub F) ) -; Computes the conclusion of the ProofRule::ARITH_MULT_POS rule. -(program mk_arith_mult_pos ((T Type) (U Type) (S Type) (r (-> T U Bool)) (a T) (b U) (m S)) +; program: $mk_arith_mult_pos +; args: +; - m S: A real or integer term to multiply by. +; - F Bool: The arithmetic atom to multiply. +; return: > +; the result of multiply the atom by m. This is used to compute the +; conclusion of the ProofRule::ARITH_MULT_POS rule. +(program $mk_arith_mult_pos ((T Type) (U Type) (S Type) (r (-> T U Bool)) (a T) (b U) (m S)) (S Bool) Bool ( - ((mk_arith_mult_pos m (r a b)) (r (* m a) (* m b))) + (($mk_arith_mult_pos m (r a b)) (r (* m a) (* m b))) ) ) +; rule: arith_mult_pos +; implements: ProofRule::ARITH_MULT_POS +; args: +; - m T: A real or integer term to multiply by. +; - F Bool: The arithmetic atom to multiply. +; conclusion: > +; An implication stating that if m is positive and F is true, then +; the result of multiply m by F also holds. (declare-rule arith_mult_pos ((T Type) (m T) (F Bool)) :args (m F) - :conclusion (=> (and (> m (arith_mk_zero (alf.typeof m))) F) (mk_arith_mult_pos m F)) + :conclusion (=> (and (> m ($arith_mk_zero (alf.typeof m))) F) ($mk_arith_mult_pos m F)) ) -(program arith_rel_inv ((T Type) (U Type) (S Type)) +; program: $arith_rel_inv +; args: +; - r T: An arithmetic relation. +; return: > +; the relation that is obtained by flipping its side. This is used for +; determining the relation obtained when multiply both sides by a negative term. +(program $arith_rel_inv ((T Type) (U Type) (S Type)) (T) S ( - ((arith_rel_inv =) =) - ((arith_rel_inv <) >) - ((arith_rel_inv <=) >=) - ((arith_rel_inv >) <) - ((arith_rel_inv >=) <=) + (($arith_rel_inv =) =) + (($arith_rel_inv <) >) + (($arith_rel_inv <=) >=) + (($arith_rel_inv >) <) + (($arith_rel_inv >=) <=) ) ) -; Computes the conclusion of the ProofRule::ARITH_MULT_NEG rule. -(program mk_arith_mult_neg ((T Type) (U Type) (S Type) (r (-> T U Bool)) (a T) (b U) (m S)) +; program: $mk_arith_mult_neg +; args: +; - m S: A real or integer term to multiply by. +; - F Bool: The arithmetic atom to multiply. +; return: > +; the result of multiply the atom by m and invert its relation. +; This is used to compute the conclusion of the ProofRule::ARITH_MULT_NEG rule. +(program $mk_arith_mult_neg ((T Type) (U Type) (S Type) (r (-> T U Bool)) (a T) (b U) (m S)) (S Bool) Bool ( - ((mk_arith_mult_neg m (r a b)) (_ (arith_rel_inv r) (* m a) (* m b))) + (($mk_arith_mult_neg m (r a b)) (_ ($arith_rel_inv r) (* m a) (* m b))) ) ) +; rule: arith_mult_neg +; implements: ProofRule::ARITH_MULT_NEG +; args: +; - m T: A real or integer term to multiply by. +; - F Bool: The arithmetic atom to multiply. +; conclusion: > +; An implication stating that if m is negative and F is true, then +; the result of multiply m by F and inverting its relation also holds. (declare-rule arith_mult_neg ((T Type) (m T) (F Bool)) :args (m F) - :conclusion (=> (and (< m (arith_mk_zero (alf.typeof m))) F) (mk_arith_mult_neg m F)) + :conclusion (=> (and (< m ($arith_mk_zero (alf.typeof m))) F) ($mk_arith_mult_neg m F)) ) -(program arith_rel_trichotomy ((T Type) (U Type) (S Type)) +; program: $arith_rel_trichotomy +; args: +; - r1 T: The first arithmetic relation. +; - r2 U: The second arithmetic relation. +; return: > +; the relation that along with r1 and r2 form a trichotomy over +; arithmetic values. +(program $arith_rel_trichotomy ((T Type) (U Type) (S Type)) (T U) S ( - ((arith_rel_trichotomy = <) >) - ((arith_rel_trichotomy = >) <) - ((arith_rel_trichotomy > =) <) - ((arith_rel_trichotomy < =) >) - ((arith_rel_trichotomy > <) =) - ((arith_rel_trichotomy < >) =) + (($arith_rel_trichotomy = <) >) + (($arith_rel_trichotomy = >) <) + (($arith_rel_trichotomy > =) <) + (($arith_rel_trichotomy < =) >) + (($arith_rel_trichotomy > <) =) + (($arith_rel_trichotomy < >) =) ) ) -(program arith_rel_neg ((T Type) (U Type) (S Type)) +; program: $arith_rel_trichotomy +; args: +; - r T: The arithmetic relation. +; return: the relation corresponding to the negation of r. +(program $arith_rel_neg ((T Type) (U Type) (S Type)) (T) S ( - ((arith_rel_neg <) >=) - ((arith_rel_neg <=) >) - ((arith_rel_neg >) <=) - ((arith_rel_neg >=) <) + (($arith_rel_neg <) >=) + (($arith_rel_neg <=) >) + (($arith_rel_neg >) <=) + (($arith_rel_neg >=) <) ) ) -(program arith_normalize_lit ((T Type) (U Type) (r (-> T U Bool)) (a T) (b U)) +; program: $arith_normalize_lit +; args: +; - F Bool: An arithmetic literal, possibly negated or doubly negated. +; return: a literal equivalent to F that eliminates its negations, if any. +(program $arith_normalize_lit ((T Type) (U Type) (r (-> T U Bool)) (a T) (b U)) (Bool) Bool ( - ((arith_normalize_lit (not (not (r a b)))) (r a b)) - ((arith_normalize_lit (not (r a b))) (_ (arith_rel_neg r) a b)) - ((arith_normalize_lit (r a b)) (r a b)) + (($arith_normalize_lit (not (not (r a b)))) (r a b)) + (($arith_normalize_lit (not (r a b))) (_ ($arith_rel_neg r) a b)) + (($arith_normalize_lit (r a b)) (r a b)) ) ) -; Computes the conclusion of the ProofRule::ARITH_TRICHOTOMY rule. -(program mk_arith_trichotomy ((T Type) (U Type) (S Type) (r1 (-> T U Bool)) (r2 (-> T U Bool)) (a T) (b U) (m S)) - (Bool S) Bool +; program: $mk_arith_trichotomy +; premises: +; - F1: The first arithmetic atom, which is an application of a binary arithmetic relation. +; - F2: The first arithmetic atom, which is an application of a binary arithmetic relation over the same terms as F1. +; return: the relation that along with F1 and F2 forms a trichotomy. +(program $mk_arith_trichotomy ((T Type) (U Type) (S Type) (r1 (-> T U Bool)) (r2 (-> T U Bool)) (a T) (b U)) + (Bool Bool) Bool ( - ((mk_arith_trichotomy (r1 a b) (r2 a b)) (_ (arith_rel_trichotomy r1 r2) a b)) + (($mk_arith_trichotomy (r1 a b) (r2 a b)) (_ ($arith_rel_trichotomy r1 r2) a b)) ) ) +; rule: arith_trichotomy +; implements: ProofRule::ARITH_TRICHOTOMY +; premises: +; - F1: The first arithmetic atom, which is an application of a (possibly negated) binary arithmetic relation. +; - F2: The first arithmetic atom, which is an application of a (possibly negated) binary arithmetic relation over the same terms as F1. +; conclusion: > +; A third relation over the same terms that along with F1 and F2 +; forms a trichotomy. (declare-rule arith_trichotomy ((F1 Bool) (F2 Bool)) :premises (F1 F2) - :conclusion (mk_arith_trichotomy (arith_normalize_lit (not F1)) (arith_normalize_lit (not F2))) + :conclusion ($mk_arith_trichotomy ($arith_normalize_lit (not F1)) ($arith_normalize_lit (not F2))) ) -; Returns the greatest integer less than (integer or real) c. -(program greatestIntLessThan ((R Type) (c R)) +; program: $greatest_int_lt +; args: +; - c R: A rational or integer value. +; return: the greatest integer less than (integer or real) c. +(program $greatest_int_lt ((R Type) (c R)) (R) Int ( - ((greatestIntLessThan c) (let ((ci (alf.to_z c))) + (($greatest_int_lt c) (let ((ci (alf.to_z c))) (alf.ite (alf.is_eq (alf.to_q c) (alf.to_q ci)) (alf.add -1 ci) ci))) ) ) -; Implements ProofRule::INT_TIGHT_UB based on the above method. +; rule: int_tight_ub +; implements: ProofRule::INT_TIGHT_UB +; premises: +; - r: The relation we are considering, whose right hand side should be a rational or integer value. +; conclusion: The result of tightening the upper bound. (declare-rule int_tight_ub ((R Type) (s Int) (t R)) :premises ((< s t)) - :conclusion (<= s (greatestIntLessThan t)) + :conclusion (<= s ($greatest_int_lt t)) ) -; Returns the least integer greater than (integer or real) c. -(program leastIntGreaterThan ((R Type) (c R)) +; program: $least_int_gt +; args: +; - c R: A rational or integer value. +; return: the least integer greater than (integer or real) c. +(program $least_int_gt ((R Type) (c R)) (R) Int ( - ((leastIntGreaterThan c) (alf.add 1 (alf.to_z c))) + (($least_int_gt c) (alf.add 1 (alf.to_z c))) ) ) -; Implements ProofRule::INT_TIGHT_LB based on the above method. +; rule: int_tight_lb +; implements: ProofRule::INT_TIGHT_LB +; premises: +; - r: The relation we are considering, whose right hand side should be a rational or integer value. +; conclusion: The result of tightening the lower bound. (declare-rule int_tight_lb ((R Type) (s Int) (t R)) :premises ((> s t)) - :conclusion (>= s (leastIntGreaterThan t)) + :conclusion (>= s ($least_int_gt t)) ) diff --git a/proofs/alf/cvc5/rules/Quantifiers.smt3 b/proofs/alf/cvc5/rules/Quantifiers.smt3 index 4ea889c8158..8657b4cc8d3 100644 --- a/proofs/alf/cvc5/rules/Quantifiers.smt3 +++ b/proofs/alf/cvc5/rules/Quantifiers.smt3 @@ -27,17 +27,9 @@ )) ) -(declare-rule skolem_intro ((T Type) (t T)) - :args (t) - :conclusion - (alf.match ((T Type) (x T) (F Bool)) - t - ( - ; special case for witness - ((@quantifiers_skolemize (exists (@list x) F) x) (= t (witness (@list x) F))) - ((@purify x) (= t x)) - ) - ) +(declare-rule skolem_intro ((T Type) (x T)) + :args ((@purify x)) + :conclusion (= (@purify x) x) ) ; B is the formula to apply to @@ -47,3 +39,14 @@ :args (B vs ts) :conclusion (= B (substitute_list vs ts B)) ) + +; rule: beta_reduce implements ProofRewriteRule::BETA_REDUCE +; args: +; - eq : Bool. The equality to prove between terms a and b. +; requires: Showing that a beta-reduces to b. +; conclusion: The given equality. +(declare-rule beta-reduce ((T Type) (a T) (b T)) + :args ((= a b)) + :requires ((($beta_reduce a @list.nil) b)) + :conclusion (= a b) +) diff --git a/proofs/alf/cvc5/rules/Sets.smt3 b/proofs/alf/cvc5/rules/Sets.smt3 index 498f2628c21..537e5669f01 100644 --- a/proofs/alf/cvc5/rules/Sets.smt3 +++ b/proofs/alf/cvc5/rules/Sets.smt3 @@ -1,5 +1,11 @@ (include "../theories/Sets.smt3") +; define: $set_is_empty_eval +; args: +; - t (Set T): The set to check. +; return: > +; true if we can determine that t is the empty set, false if we can +; determine t is not empty. Otherwise this method returns an unevaluated term. (define $set_is_empty_eval ((T Type :implicit) (t (Set T))) (alf.match ((U Type) (x U) (s (Set U))) t @@ -11,6 +17,14 @@ ) ) +; rule: sets-is-empty-eval +; implements: ProofRewriteRule::SETS_IS_EMPTY_EVAL +; args: +; - eq Bool: The equality to prove, whose left hand side is an application of set.is_empty. +; requires: > +; showing that the set that set.is_empty is applied to is (or is not) the +; empty set, as denoted by the right hand side of eq. +; conclusion: The given equality. (declare-rule sets-is-empty-eval ((T Type) (t (Set T)) (b Bool)) :args ((= (set.is_empty t) b)) :requires ((($set_is_empty_eval t) b)) diff --git a/proofs/alf/cvc5/rules/Strings.smt3 b/proofs/alf/cvc5/rules/Strings.smt3 index 5c1147ae268..fc4494e6dab 100644 --- a/proofs/alf/cvc5/rules/Strings.smt3 +++ b/proofs/alf/cvc5/rules/Strings.smt3 @@ -283,6 +283,22 @@ :conclusion (= (str.in_re s r) b) ) +; rule: str-in-re-consume +; implements: ProofRewriteRule::STR_IN_RE_CONSUME +; args: +; - eq Bool: The equality to prove whose left hand side is a regular expression membership. +; requires: > +; Showing that consuming portions of the regular expression membership using the +; method $str_re_consume results in b, where b is either false or the result of +; stripping constant prefixes and suffixes from the arguments of the left hand side +; of the given equality. +; conclusion: The given equality. +(declare-rule str-in-re-consume ((s String) (r RegLan) (b Bool)) + :args ((= (str.in_re s r) b)) + :requires ((($str_re_consume s r) b)) + :conclusion (= (str.in_re s r) b) +) + (declare-rule re-loop-elim ((l Int) (u Int) (r1 RegLan) (r2 RegLan)) :args ((= (re.loop l u r1) r2)) :requires (((alf.is_neg (alf.add (alf.neg l) u)) false) diff --git a/proofs/alf/cvc5/theories/Reals.smt3 b/proofs/alf/cvc5/theories/Reals.smt3 index d7765378cb7..3be4c89a58e 100644 --- a/proofs/alf/cvc5/theories/Reals.smt3 +++ b/proofs/alf/cvc5/theories/Reals.smt3 @@ -12,7 +12,7 @@ (! Type :var U :implicit) T U (! Real :requires ((is_arith_type T) true) :requires ((is_arith_type U) true))) :left-assoc) -(declare-const INDEXED_ROOT_PREDICATE (-> Int Bool Real Bool)) +(declare-const @indexed_root_predicate (-> Int Bool Real Bool)) ; skolems (declare-const @div_by_zero (-> Real Real)) diff --git a/proofs/alf/cvc5/theories/SepLogic.smt3 b/proofs/alf/cvc5/theories/SepLogic.smt3 index c395e372f1e..49c26cc0ed4 100644 --- a/proofs/alf/cvc5/theories/SepLogic.smt3 +++ b/proofs/alf/cvc5/theories/SepLogic.smt3 @@ -17,4 +17,4 @@ (declare-const pto (-> (! Type :var U :implicit) (! Type :var T :implicit) U T Bool)) ; Internal functions. -(declare-const SEP_LABEL (-> (! Type :var U :implicit) (! Type :var T :implicit) U (Set T) Bool)) +(declare-const @sep_label (-> (! Type :var U :implicit) (! Type :var T :implicit) U (Set T) Bool)) diff --git a/proofs/alf/cvc5/theories/Strings.smt3 b/proofs/alf/cvc5/theories/Strings.smt3 index fdccec5cb8c..91c72f39393 100644 --- a/proofs/alf/cvc5/theories/Strings.smt3 +++ b/proofs/alf/cvc5/theories/Strings.smt3 @@ -81,7 +81,7 @@ (declare-const re.opt (-> RegLan RegLan)) (declare-const re.comp (-> RegLan RegLan)) (declare-const re.range (-> String String RegLan)) -(declare-const re.++ (-> RegLan RegLan RegLan) :right-assoc-nil (str.to_re "")) +(declare-const re.++ (-> RegLan RegLan RegLan) :right-assoc-nil @re.empty) (declare-const re.inter (-> RegLan RegLan RegLan) :right-assoc-nil re.all) (declare-const re.union (-> RegLan RegLan RegLan) :right-assoc-nil re.none) (declare-const re.diff (-> RegLan RegLan RegLan)) diff --git a/src/api/c/cvc5.cpp b/src/api/c/cvc5.cpp index 53ea131a1fd..eec299c2f2f 100644 --- a/src/api/c/cvc5.cpp +++ b/src/api/c/cvc5.cpp @@ -198,6 +198,23 @@ struct cvc5_term_t Cvc5TermManager* d_tm = nullptr; }; +/** Wrapper for cvc5 C++ operators. */ +struct cvc5_op_t +{ + /** + * Constructor. + * @param op The wrapped C++ operator. + * @param tm The associated term manager. + */ + cvc5_op_t(Cvc5TermManager* tm, const cvc5::Op& op) : d_op(op), d_tm(tm) {} + /** The wrapped C++ op. */ + cvc5::Op d_op; + /** External refs count. */ + uint32_t d_refs = 1; + /** The associated term manager. */ + Cvc5TermManager* d_tm = nullptr; +}; + /** Wrapper for cvc5 C++ sorts. */ struct cvc5_sort_t { @@ -335,6 +352,11 @@ struct Cvc5TermManager * @param term The term to export. */ Cvc5Term export_term(const cvc5::Term& term); + /** + * Export C++ operator to C API. + * @param op The operator to export. + */ + Cvc5Op export_op(const cvc5::Op& op); /** * Export C++ datatype to C API. * @param dt The datatype to export. @@ -366,7 +388,7 @@ struct Cvc5TermManager /** * Decrement the external ref count of a term. If the ref count reaches zero, - * the term is release (freed). + * the term is released (freed). * @param term The term to release. */ void release(cvc5_term_t* term); @@ -376,9 +398,21 @@ struct Cvc5TermManager * @return The copied term. */ cvc5_term_t* copy(cvc5_term_t* term); + /** + * Decrement the external ref count of an operator. If the ref count reaches + * zero, the operator is released (freed). + * @param op The operator to release. + */ + void release(cvc5_op_t* op); + /** + * Increment the external ref count of an operator. + * @param op The operator to copy. + * @return The copied operator. + */ + cvc5_op_t* copy(cvc5_op_t* term); /** * Decrement the external ref count of a sort. If the ref count reaches zero, - * the sort is release (freed). + * the sort is released (freed). * @param sort The sort to release. */ void release(cvc5_sort_t* sort); @@ -390,7 +424,7 @@ struct Cvc5TermManager cvc5_sort_t* copy(cvc5_sort_t* sort); /** * Decrement the external ref count of a datatype. If the ref count reaches - * zero, the datatype is release (freed). + * zero, the datatype is released (freed). * @param dt The datatype to release. */ void release(cvc5_dt_t* dt); @@ -402,7 +436,7 @@ struct Cvc5TermManager cvc5_dt_t* copy(cvc5_dt_t* dt); /** * Decrement the external ref count of a datatype constructor. If the ref - * count reaches zero, the datatype constructor is release (freed). + * count reaches zero, the datatype constructor is released (freed). * @param cons The datatype constructor to release. */ void release(cvc5_dt_cons_t* cons); @@ -414,7 +448,7 @@ struct Cvc5TermManager cvc5_dt_cons_t* copy(cvc5_dt_cons_t* cons); /** * Decrement the external ref count of a datatype selector. If the ref - * count reaches zero, the datatype selector is release (freed). + * count reaches zero, the datatype selector is released (freed). * @param cons The datatype selector to release. */ void release(cvc5_dt_sel_t* sel); @@ -426,7 +460,7 @@ struct Cvc5TermManager cvc5_dt_sel_t* copy(cvc5_dt_sel_t* sel); /** * Decrement the external ref count of a datatype declaration. If the ref - * count reaches zero, the datatype declaration is release (freed). + * count reaches zero, the datatype declaration is released (freed). * @param decl The datatype declaration to release. */ void release(cvc5_dt_decl_t* decl); @@ -461,6 +495,7 @@ struct Cvc5TermManager private: std::unordered_map d_alloc_sorts; std::unordered_map d_alloc_terms; + std::unordered_map d_alloc_ops; std::unordered_map d_alloc_dts; std::unordered_map d_alloc_dt_conss; @@ -492,6 +527,17 @@ Cvc5Term Cvc5TermManager::export_term(const cvc5::Term& term) return &it->second; } +Cvc5Op Cvc5TermManager::export_op(const cvc5::Op& op) +{ + Assert(!op.isNull()); + auto [it, inserted] = d_alloc_ops.try_emplace(op, this, op); + if (!inserted) + { + copy(&it->second); + } + return &it->second; +} + Cvc5Datatype Cvc5TermManager::export_dt(const cvc5::Datatype& dt) { Assert(!dt.isNull()); @@ -552,114 +598,178 @@ Cvc5DatatypeConstructorDecl Cvc5TermManager::export_dt_cons_decl( void Cvc5TermManager::release(cvc5_term_t* term) { - term->d_refs -= 1; - if (term->d_refs == 0) + if (term) { - Assert(d_alloc_terms.find(term->d_term) != d_alloc_terms.end()); - d_alloc_terms.erase(term->d_term); + term->d_refs -= 1; + if (term->d_refs == 0) + { + Assert(d_alloc_terms.find(term->d_term) != d_alloc_terms.end()); + d_alloc_terms.erase(term->d_term); + } } } cvc5_term_t* Cvc5TermManager::copy(cvc5_term_t* term) { - term->d_refs += 1; + if (term) + { + term->d_refs += 1; + } return term; } +void Cvc5TermManager::release(cvc5_op_t* op) +{ + if (op) + { + op->d_refs -= 1; + if (op->d_refs == 0) + { + Assert(d_alloc_ops.find(op->d_op) != d_alloc_ops.end()); + d_alloc_ops.erase(op->d_op); + } + } +} + +cvc5_op_t* Cvc5TermManager::copy(cvc5_op_t* op) +{ + if (op) + { + op->d_refs += 1; + } + return op; +} + void Cvc5TermManager::release(cvc5_sort_t* sort) { - sort->d_refs -= 1; - if (sort->d_refs == 0) + if (sort) { - Assert(d_alloc_sorts.find(sort->d_sort) != d_alloc_sorts.end()); - d_alloc_sorts.erase(sort->d_sort); + sort->d_refs -= 1; + if (sort->d_refs == 0) + { + Assert(d_alloc_sorts.find(sort->d_sort) != d_alloc_sorts.end()); + d_alloc_sorts.erase(sort->d_sort); + } } } cvc5_sort_t* Cvc5TermManager::copy(cvc5_sort_t* sort) { - sort->d_refs += 1; + if (sort) + { + sort->d_refs += 1; + } return sort; } void Cvc5TermManager::release(cvc5_dt_t* dt) { - dt->d_refs -= 1; - if (dt->d_refs == 0) + if (dt) { - Assert(d_alloc_dts.find(dt->d_dt) != d_alloc_dts.end()); - d_alloc_dts.erase(dt->d_dt); + dt->d_refs -= 1; + if (dt->d_refs == 0) + { + Assert(d_alloc_dts.find(dt->d_dt) != d_alloc_dts.end()); + d_alloc_dts.erase(dt->d_dt); + } } } cvc5_dt_t* Cvc5TermManager::copy(cvc5_dt_t* dt) { - dt->d_refs += 1; + if (dt) + { + dt->d_refs += 1; + } return dt; } void Cvc5TermManager::release(cvc5_dt_cons_t* cons) { - cons->d_refs -= 1; - if (cons->d_refs == 0) + if (cons) { - Assert(d_alloc_dt_conss.find(cons->d_dt_cons) != d_alloc_dt_conss.end()); - d_alloc_dt_conss.erase(cons->d_dt_cons); + cons->d_refs -= 1; + if (cons->d_refs == 0) + { + Assert(d_alloc_dt_conss.find(cons->d_dt_cons) != d_alloc_dt_conss.end()); + d_alloc_dt_conss.erase(cons->d_dt_cons); + } } } cvc5_dt_cons_t* Cvc5TermManager::copy(cvc5_dt_cons_t* cons) { - cons->d_refs += 1; + if (cons) + { + cons->d_refs += 1; + } return cons; } void Cvc5TermManager::release(cvc5_dt_sel_t* sel) { - sel->d_refs -= 1; - if (sel->d_refs == 0) + if (sel) { - Assert(d_alloc_dt_sels.find(sel->d_dt_sel) != d_alloc_dt_sels.end()); - d_alloc_dt_sels.erase(sel->d_dt_sel); + sel->d_refs -= 1; + if (sel->d_refs == 0) + { + Assert(d_alloc_dt_sels.find(sel->d_dt_sel) != d_alloc_dt_sels.end()); + d_alloc_dt_sels.erase(sel->d_dt_sel); + } } } cvc5_dt_sel_t* Cvc5TermManager::copy(cvc5_dt_sel_t* sel) { - sel->d_refs += 1; + if (sel) + { + sel->d_refs += 1; + } return sel; } void Cvc5TermManager::release(cvc5_dt_decl_t* decl) { - decl->d_refs -= 1; - if (decl->d_refs == 0) + if (decl) { - Assert(d_alloc_dt_decls.find(decl->d_decl) != d_alloc_dt_decls.end()); - d_alloc_dt_decls.erase(decl->d_decl); + decl->d_refs -= 1; + if (decl->d_refs == 0) + { + Assert(d_alloc_dt_decls.find(decl->d_decl) != d_alloc_dt_decls.end()); + d_alloc_dt_decls.erase(decl->d_decl); + } } } cvc5_dt_decl_t* Cvc5TermManager::copy(cvc5_dt_decl_t* decl) { - decl->d_refs += 1; + if (decl) + { + decl->d_refs += 1; + } return decl; } void Cvc5TermManager::release(cvc5_dt_cons_decl_t* decl) { - decl->d_refs -= 1; - if (decl->d_refs == 0) + if (decl) { - Assert(d_alloc_dt_cons_decls.find(decl->d_decl) - != d_alloc_dt_cons_decls.end()); - d_alloc_dt_cons_decls.erase(decl->d_decl); + decl->d_refs -= 1; + if (decl->d_refs == 0) + { + Assert(d_alloc_dt_cons_decls.find(decl->d_decl) + != d_alloc_dt_cons_decls.end()); + d_alloc_dt_cons_decls.erase(decl->d_decl); + } } } cvc5_dt_cons_decl_t* Cvc5TermManager::copy(cvc5_dt_cons_decl_t* decl) { - decl->d_refs += 1; + if (decl) + { + decl->d_refs += 1; + } return decl; } @@ -678,6 +788,24 @@ void Cvc5TermManager::release() /* Cvc5Sort */ /* -------------------------------------------------------------------------- */ +Cvc5Sort cvc5_sort_copy(Cvc5Sort sort) +{ + Cvc5Sort res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_SORT(sort); + res = sort->d_tm->copy(sort); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +void cvc5_sort_release(Cvc5Sort sort) +{ + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_SORT(sort); + sort->d_tm->release(sort); + CVC5_CAPI_TRY_CATCH_END; +} + bool cvc5_sort_is_equal(Cvc5Sort a, Cvc5Sort b) { bool res = false; @@ -1513,6 +1641,25 @@ Cvc5Sort cvc5_sort_nullable_get_element_sort(Cvc5Sort sort) /* Cvc5DatatypeConstructorDecl ----------------------------------------- */ +Cvc5DatatypeConstructorDecl cvc5_dt_cons_decl_copy( + Cvc5DatatypeConstructorDecl decl) +{ + Cvc5DatatypeConstructorDecl res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_DT_CONS_DECL(decl); + res = decl->d_tm->copy(decl); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +void cvc5_dt_decl_release(Cvc5DatatypeConstructorDecl decl) +{ + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_DT_CONS_DECL(decl); + decl->d_tm->release(decl); + CVC5_CAPI_TRY_CATCH_END; +} + void cvc5_dt_cons_decl_add_selector(Cvc5DatatypeConstructorDecl decl, const char* name, Cvc5Sort sort) @@ -1559,6 +1706,24 @@ const char* cvc5_dt_cons_decl_to_string(Cvc5DatatypeConstructorDecl decl) /* Cvc5DatatypeDecl ---------------------------------------------------- */ +Cvc5DatatypeDecl cvc5_dt_decl_copy(Cvc5DatatypeDecl decl) +{ + Cvc5DatatypeDecl res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_DT_DECL(decl); + res = decl->d_tm->copy(decl); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +void cvc5_dt_decl_release(Cvc5DatatypeDecl decl) +{ + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_DT_DECL(decl); + decl->d_tm->release(decl); + CVC5_CAPI_TRY_CATCH_END; +} + void cvc5_dt_decl_add_constructor(Cvc5DatatypeDecl decl, Cvc5DatatypeConstructorDecl cdecl) { @@ -1621,7 +1786,25 @@ const char* cvc5_dt_decl_get_name(Cvc5DatatypeDecl decl) /* Cvc5DatatypeSelector ------------------------------------------------ */ -const char* cvc5_dt_del_get_name(Cvc5DatatypeSelector sel) +Cvc5DatatypeSelector cvc5_dt_sel_copy(Cvc5DatatypeSelector sel) +{ + Cvc5DatatypeSelector res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_DT_SEL(sel); + res = sel->d_tm->copy(sel); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +void cvc5_dt_sel_release(Cvc5DatatypeSelector sel) +{ + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_DT_SEL(sel); + sel->d_tm->release(sel); + CVC5_CAPI_TRY_CATCH_END; +} + +const char* cvc5_dt_sel_get_name(Cvc5DatatypeSelector sel) { static thread_local std::string str; CVC5_CAPI_TRY_CATCH_BEGIN; @@ -1673,6 +1856,24 @@ const char* cvc5_dt_sel_to_string(Cvc5DatatypeSelector sel) /* Cvc5DatatypeConstructor --------------------------------------------- */ +Cvc5DatatypeConstructor cvc5_dt_cons_copy(Cvc5DatatypeConstructor cons) +{ + Cvc5DatatypeConstructor res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_DT_CONS(cons); + res = cons->d_tm->copy(cons); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +void cvc5_dt_cons_release(Cvc5DatatypeConstructor cons) +{ + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_DT_CONS(cons); + cons->d_tm->release(cons); + CVC5_CAPI_TRY_CATCH_END; +} + const char* cvc5_dt_cons_get_name(Cvc5DatatypeConstructor cons) { static thread_local std::string str; @@ -1761,6 +1962,24 @@ const char* cvc5_dt_cons_to_string(Cvc5DatatypeConstructor cons) /* Cvc5Datatype -------------------------------------------------------- */ +Cvc5Datatype cvc5_dt_copy(Cvc5Datatype dt) +{ + Cvc5Datatype res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_DT(dt); + res = dt->d_tm->copy(dt); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +void cvc5_dt_release(Cvc5Datatype dt) +{ + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_DT(dt); + dt->d_tm->release(dt); + CVC5_CAPI_TRY_CATCH_END; +} + Cvc5DatatypeConstructor cvc5_dt_get_constructor(Cvc5Datatype dt, size_t idx) { Cvc5DatatypeConstructor res = nullptr; @@ -1906,431 +2125,1891 @@ const char* cvc5_dt_to_string(Cvc5Datatype dt) /* Cvc5Term */ /* -------------------------------------------------------------------------- */ -Cvc5Sort cvc5_term_get_sort(Cvc5Term term) +Cvc5Term cvc5_term_copy(Cvc5Term term) { - Cvc5Sort res = nullptr; + Cvc5Term res = nullptr; CVC5_CAPI_TRY_CATCH_BEGIN; CVC5_CAPI_CHECK_TERM(term); - res = term->d_tm->export_sort(term->d_term.getSort()); + res = term->d_tm->copy(term); CVC5_CAPI_TRY_CATCH_END; return res; } -/* -------------------------------------------------------------------------- */ -/* Cvc5TermManager */ -/* -------------------------------------------------------------------------- */ - -Cvc5TermManager* cvc5_term_manager_new() +void cvc5_term_release(Cvc5Term term) { - Cvc5TermManager* res = nullptr; CVC5_CAPI_TRY_CATCH_BEGIN; - res = new Cvc5TermManager(); + CVC5_CAPI_CHECK_TERM(term); + term->d_tm->release(term); CVC5_CAPI_TRY_CATCH_END; - return res; } -void cvc5_term_manager_delete(Cvc5TermManager* tm) +bool cvc5_term_is_equal(Cvc5Term a, Cvc5Term b) { + bool res = false; CVC5_CAPI_TRY_CATCH_BEGIN; - delete tm; + if (a == nullptr || b == nullptr) + { + res = a == b; + } + else + { + res = a->d_term == b->d_term; + } CVC5_CAPI_TRY_CATCH_END; + return res; } -void cvc5_term_manager_release(Cvc5TermManager* tm) +bool cvc5_term_is_disequal(Cvc5Term a, Cvc5Term b) { + bool res = false; CVC5_CAPI_TRY_CATCH_BEGIN; - tm->release(); + if (a == nullptr || b == nullptr) + { + res = a != b; + } + else + { + res = a->d_term != b->d_term; + } CVC5_CAPI_TRY_CATCH_END; + return res; } -/* Sorts Handling ----------------------------------------------------------- */ - -Cvc5Sort cvc5_get_boolean_sort(Cvc5TermManager* tm) +int64_t cvc5_term_compare(Cvc5Term a, Cvc5Term b) { - Cvc5Sort res = nullptr; + int64_t res = false; CVC5_CAPI_TRY_CATCH_BEGIN; - CVC5_CAPI_CHECK_NOT_NULL(tm); - res = tm->export_sort(tm->d_tm.getBooleanSort()); + CVC5_CAPI_CHECK_TERM(a); + CVC5_CAPI_CHECK_TERM(b); + res = a->d_term < b->d_term ? -1 : (a->d_term > b->d_term ? 1 : 0); CVC5_CAPI_TRY_CATCH_END; return res; } -Cvc5Sort cvc5_get_integer_sort(Cvc5TermManager* tm) +size_t cvc5_term_get_num_children(Cvc5Term term) { - Cvc5Sort res = nullptr; + size_t res = 0; CVC5_CAPI_TRY_CATCH_BEGIN; - CVC5_CAPI_CHECK_NOT_NULL(tm); - res = tm->export_sort(tm->d_tm.getIntegerSort()); + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.getNumChildren(); CVC5_CAPI_TRY_CATCH_END; return res; } -Cvc5Sort cvc5_get_real_sort(Cvc5TermManager* tm) +Cvc5Term cvc5_term_get_child(Cvc5Term term, size_t index) { - Cvc5Sort res = nullptr; + Cvc5Term res = nullptr; CVC5_CAPI_TRY_CATCH_BEGIN; - CVC5_CAPI_CHECK_NOT_NULL(tm); - res = tm->export_sort(tm->d_tm.getRealSort()); + CVC5_CAPI_CHECK_TERM(term); + res = term->d_tm->export_term(term->d_term[index]); CVC5_CAPI_TRY_CATCH_END; return res; } -Cvc5Sort cvc5_get_regexp_sort(Cvc5TermManager* tm) +uint64_t cvc5_term_get_id(Cvc5Term term) { - Cvc5Sort res = nullptr; + uint64_t res = 0; CVC5_CAPI_TRY_CATCH_BEGIN; - CVC5_CAPI_CHECK_NOT_NULL(tm); - res = tm->export_sort(tm->d_tm.getRegExpSort()); + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.getId(); CVC5_CAPI_TRY_CATCH_END; return res; } -Cvc5Sort cvc5_get_rm_sort(Cvc5TermManager* tm) +Cvc5Kind cvc5_term_get_kind(Cvc5Term term) { - Cvc5Sort res = nullptr; + Cvc5Kind res = CVC5_KIND_INTERNAL_KIND; CVC5_CAPI_TRY_CATCH_BEGIN; - CVC5_CAPI_CHECK_NOT_NULL(tm); - res = tm->export_sort(tm->d_tm.getRoundingModeSort()); + CVC5_CAPI_CHECK_TERM(term); + res = static_cast(term->d_term.getKind()); CVC5_CAPI_TRY_CATCH_END; return res; } -Cvc5Sort cvc5_get_string_sort(Cvc5TermManager* tm) +Cvc5Sort cvc5_term_get_sort(Cvc5Term term) { Cvc5Sort res = nullptr; CVC5_CAPI_TRY_CATCH_BEGIN; - CVC5_CAPI_CHECK_NOT_NULL(tm); - res = tm->export_sort(tm->d_tm.getStringSort()); + CVC5_CAPI_CHECK_TERM(term); + res = term->d_tm->export_sort(term->d_term.getSort()); CVC5_CAPI_TRY_CATCH_END; return res; } -Cvc5Sort cvc5_mk_array_sort(Cvc5TermManager* tm, Cvc5Sort index, Cvc5Sort elem) +Cvc5Term cvc5_term_substitute_term(Cvc5Term term, + Cvc5Term t, + Cvc5Term replacement) { - Cvc5Sort res = nullptr; + Cvc5Term res = nullptr; CVC5_CAPI_TRY_CATCH_BEGIN; - CVC5_CAPI_CHECK_NOT_NULL(tm); - CVC5_CAPI_CHECK_SORT(index); - CVC5_CAPI_CHECK_SORT(elem); - res = tm->export_sort(tm->d_tm.mkArraySort(index->d_sort, elem->d_sort)); + CVC5_CAPI_CHECK_TERM(term); + CVC5_CAPI_CHECK_TERM(t); + CVC5_CAPI_CHECK_TERM(replacement); + res = term->d_tm->export_term( + term->d_term.substitute(t->d_term, replacement->d_term)); CVC5_CAPI_TRY_CATCH_END; return res; } -Cvc5Sort cvc5_mk_bv_sort(Cvc5TermManager* tm, uint32_t size) +Cvc5Term cvc5_term_substitute_terms(Cvc5Term term, + size_t size, + const Cvc5Term terms[], + const Cvc5Term replacements[]) { - Cvc5Sort res = nullptr; + Cvc5Term res = nullptr; CVC5_CAPI_TRY_CATCH_BEGIN; - CVC5_CAPI_CHECK_NOT_NULL(tm); - res = tm->export_sort(tm->d_tm.mkBitVectorSort(size)); + CVC5_CAPI_CHECK_TERM(term); + CVC5_CAPI_CHECK_NOT_NULL(terms); + CVC5_CAPI_CHECK_NOT_NULL(replacements); + std::vector cterms; + for (uint32_t i = 0; i < size; ++i) + { + CVC5_CAPI_CHECK_TERM_AT_IDX(terms, i); + cterms.push_back(terms[i]->d_term); + } + std::vector creplacements; + for (uint32_t i = 0; i < size; ++i) + { + CVC5_CAPI_CHECK_TERM_AT_IDX(replacements, i); + creplacements.push_back(replacements[i]->d_term); + } + res = term->d_tm->export_term(term->d_term.substitute(cterms, creplacements)); CVC5_CAPI_TRY_CATCH_END; return res; } -Cvc5Sort cvc5_mk_fp_sort(Cvc5TermManager* tm, uint32_t exp, uint32_t sig) +bool cvc5_term_has_op(Cvc5Term term) { - Cvc5Sort res = nullptr; + bool res = false; CVC5_CAPI_TRY_CATCH_BEGIN; - CVC5_CAPI_CHECK_NOT_NULL(tm); - res = tm->export_sort(tm->d_tm.mkFloatingPointSort(exp, sig)); + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.hasOp(); CVC5_CAPI_TRY_CATCH_END; return res; } -Cvc5Sort cvc5_mk_ff_sort(Cvc5TermManager* tm, const char* size, uint32_t base) +Cvc5Op cvc5_term_get_op(Cvc5Term term) { - Cvc5Sort res = nullptr; + Cvc5Op res = nullptr; CVC5_CAPI_TRY_CATCH_BEGIN; - CVC5_CAPI_CHECK_NOT_NULL(tm); - CVC5_CAPI_CHECK_NOT_NULL(size); - res = tm->export_sort(tm->d_tm.mkFiniteFieldSort(size, base)); + CVC5_CAPI_CHECK_TERM(term); + res = term->d_tm->export_op(term->d_term.getOp()); CVC5_CAPI_TRY_CATCH_END; return res; } -Cvc5Sort cvc5_mk_dt_sort(Cvc5TermManager* tm, Cvc5DatatypeDecl decl) +bool cvc5_term_has_symbol(Cvc5Term term) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.hasSymbol(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +const char* cvc5_term_get_symbol(Cvc5Term term) +{ + const char* res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + CVC5_API_CHECK(cvc5_term_has_symbol(term)) + << "cannot get symbol of term that has no symbol"; + static thread_local std::string str; + if (term->d_term.hasSymbol()) + { + str = term->d_term.getSymbol(); + res = str.c_str(); + } + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +const char* cvc5_term_to_string(Cvc5Term term) +{ + static thread_local std::string str; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + str = term->d_term.toString(); + CVC5_CAPI_TRY_CATCH_END; + return str.c_str(); +} + +int32_t cvc5_term_get_real_or_integer_value_sign(Cvc5Term term) +{ + int32_t res = 0; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.getRealOrIntegerValueSign(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +bool cvc5_term_is_int32_value(Cvc5Term term) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.isInt32Value(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +int32_t cvc5_term_get_int32_value(Cvc5Term term) +{ + int32_t res = 0; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.getInt32Value(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +bool cvc5_term_is_uint32_value(Cvc5Term term) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.isUInt32Value(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +uint32_t cvc5_term_get_uint32_value(Cvc5Term term) +{ + uint32_t res = 0; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.getUInt32Value(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +bool cvc5_term_is_int64_value(Cvc5Term term) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.isInt64Value(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +int64_t cvc5_term_get_int64_value(Cvc5Term term) +{ + int64_t res = 0; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.getInt64Value(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +bool cvc5_term_is_uint64_value(Cvc5Term term) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.isUInt64Value(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +uint64_t cvc5_term_get_uint64_value(Cvc5Term term) +{ + uint64_t res = 0; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.getUInt64Value(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +bool cvc5_term_is_integer_value(Cvc5Term term) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.isIntegerValue(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +const char* cvc5_term_get_integer_value(Cvc5Term term) +{ + static thread_local std::string res; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.getIntegerValue(); + CVC5_CAPI_TRY_CATCH_END; + return res.c_str(); +} + +bool cvc5_term_is_string_value(Cvc5Term term) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.isStringValue(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +const wchar_t* cvc5_term_get_string_value(Cvc5Term term) +{ + static thread_local std::wstring res; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.getStringValue(); + CVC5_CAPI_TRY_CATCH_END; + return res.c_str(); +} + +bool cvc5_term_is_real32_value(Cvc5Term term) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.isReal32Value(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +void cvc5_term_get_real32_value(Cvc5Term term, int32_t* num, uint32_t* den) +{ + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + CVC5_CAPI_CHECK_NOT_NULL(num); + CVC5_CAPI_CHECK_NOT_NULL(den); + std::tie(*num, *den) = term->d_term.getReal32Value(); + CVC5_CAPI_TRY_CATCH_END; +} + +bool cvc5_term_is_real64_value(Cvc5Term term) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.isReal64Value(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +void cvc5_term_get_real64_value(Cvc5Term term, int64_t* num, uint64_t* den) +{ + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + CVC5_CAPI_CHECK_NOT_NULL(num); + CVC5_CAPI_CHECK_NOT_NULL(den); + std::tie(*num, *den) = term->d_term.getReal64Value(); + CVC5_CAPI_TRY_CATCH_END; +} + +bool cvc5_term_is_real_value(Cvc5Term term) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.isRealValue(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +const char* cvc5_term_get_real_value(Cvc5Term term) +{ + static thread_local std::string res; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.getRealValue(); + CVC5_CAPI_TRY_CATCH_END; + return res.c_str(); +} + +bool cvc5_term_is_const_array(Cvc5Term term) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.isConstArray(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Term cvc5_term_get_const_array_base(Cvc5Term term) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_tm->export_term(term->d_term.getConstArrayBase()); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +bool cvc5_term_is_boolean_value(Cvc5Term term) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.isBooleanValue(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +bool cvc5_term_get_boolean_value(Cvc5Term term) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.getBooleanValue(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +bool cvc5_term_is_bv_value(Cvc5Term term) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.isBitVectorValue(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +const char* cvc5_term_get_bv_value(Cvc5Term term, uint32_t base) +{ + static thread_local std::string res; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.getBitVectorValue(base); + CVC5_CAPI_TRY_CATCH_END; + return res.c_str(); +} + +bool cvc5_term_is_ff_value(Cvc5Term term) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.isFiniteFieldValue(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +const char* cvc5_term_get_ff_value(Cvc5Term term) +{ + static thread_local std::string res; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.getFiniteFieldValue(); + CVC5_CAPI_TRY_CATCH_END; + return res.c_str(); +} + +bool cvc5_term_is_uninterpreted_sort_value(Cvc5Term term) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.isUninterpretedSortValue(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +const char* cvc5_term_get_uninterpreted_sort_value(Cvc5Term term) +{ + static thread_local std::string res; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.getUninterpretedSortValue(); + CVC5_CAPI_TRY_CATCH_END; + return res.c_str(); +} + +bool cvc5_term_is_tuple_value(Cvc5Term term) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.isTupleValue(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +const Cvc5Term* cvc5_term_get_tuple_value(Cvc5Term term, size_t* size) +{ + static thread_local std::vector res; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + CVC5_CAPI_CHECK_NOT_NULL(size); + res.clear(); + auto terms = term->d_term.getTupleValue(); + for (auto& t : terms) + { + res.push_back(term->d_tm->export_term(t)); + } + *size = res.size(); + CVC5_CAPI_TRY_CATCH_END; + return res.data(); +} + +bool cvc5_term_is_rm_value(Cvc5Term term) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.isRoundingModeValue(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5RoundingMode cvc5_term_get_rm_value(Cvc5Term term) +{ + Cvc5RoundingMode res = CVC5_RM_ROUND_NEAREST_TIES_TO_AWAY; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = static_cast(term->d_term.getRoundingModeValue()); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +bool cvc5_term_is_fp_pos_zero(Cvc5Term term) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.isFloatingPointPosZero(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +bool cvc5_term_is_fp_neg_zero(Cvc5Term term) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.isFloatingPointNegZero(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +bool cvc5_term_is_fp_pos_inf(Cvc5Term term) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.isFloatingPointPosInf(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +bool cvc5_term_is_fp_neg_inf(Cvc5Term term) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.isFloatingPointNegInf(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +bool cvc5_term_is_fp_nan(Cvc5Term term) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.isFloatingPointNaN(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +bool cvc5_term_is_fp_value(Cvc5Term term) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.isFloatingPointValue(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +void cvc5_term_get_fp_value(Cvc5Term term, + uint32_t* ew, + uint32_t* sw, + Cvc5Term* val) +{ + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + CVC5_CAPI_CHECK_NOT_NULL(ew); + CVC5_CAPI_CHECK_NOT_NULL(sw); + CVC5_CAPI_CHECK_NOT_NULL(val); + cvc5::Term res; + std::tie(*ew, *sw, res) = term->d_term.getFloatingPointValue(); + *val = term->d_tm->export_term(res); + CVC5_CAPI_TRY_CATCH_END; +} + +bool cvc5_term_is_set_value(Cvc5Term term) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.isSetValue(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +const Cvc5Term* cvc5_term_get_set_value(Cvc5Term term, size_t* size) +{ + static thread_local std::vector res; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + CVC5_CAPI_CHECK_NOT_NULL(size); + res.clear(); + auto terms = term->d_term.getSetValue(); + for (auto& t : terms) + { + res.push_back(term->d_tm->export_term(t)); + } + *size = res.size(); + CVC5_CAPI_TRY_CATCH_END; + return res.data(); +} + +bool cvc5_term_is_sequence_value(Cvc5Term term) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.isSequenceValue(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +const Cvc5Term* cvc5_term_get_sequence_value(Cvc5Term term, size_t* size) +{ + static thread_local std::vector res; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + CVC5_CAPI_CHECK_NOT_NULL(size); + res.clear(); + auto terms = term->d_term.getSequenceValue(); + for (auto& t : terms) + { + res.push_back(term->d_tm->export_term(t)); + } + *size = res.size(); + CVC5_CAPI_TRY_CATCH_END; + return res.data(); +} + +bool cvc5_term_is_cardinality_constraint(Cvc5Term term) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.isCardinalityConstraint(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +void cvc5_term_get_cardinality_constraint(Cvc5Term term, + Cvc5Sort* sort, + uint32_t* upper) +{ + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + CVC5_CAPI_CHECK_NOT_NULL(sort); + CVC5_CAPI_CHECK_NOT_NULL(upper); + cvc5::Sort res; + std::tie(res, *upper) = term->d_term.getCardinalityConstraint(); + *sort = term->d_tm->export_sort(res); + CVC5_CAPI_TRY_CATCH_END; +} + +bool cvc5_term_is_real_algebraic_number(Cvc5Term term) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.isRealAlgebraicNumber(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Term cvc5_term_get_real_algebraic_number_defining_polynomial(Cvc5Term term, + Cvc5Term v) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + CVC5_CAPI_CHECK_TERM(v); + res = term->d_tm->export_term( + term->d_term.getRealAlgebraicNumberDefiningPolynomial(v->d_term)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Term cvc5_term_get_real_algebraic_number_lower_bound(Cvc5Term term) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = + term->d_tm->export_term(term->d_term.getRealAlgebraicNumberLowerBound()); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Term cvc5_term_get_real_algebraic_number_upper_bound(Cvc5Term term) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = + term->d_tm->export_term(term->d_term.getRealAlgebraicNumberUpperBound()); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +bool cvc5_term_is_skolem(Cvc5Term term) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = term->d_term.isSkolem(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5SkolemId cvc5_term_get_skolem_id(Cvc5Term term) +{ + Cvc5SkolemId res = CVC5_SKOLEM_ID_NONE; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = static_cast(term->d_term.getSkolemId()); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +const Cvc5Term* cvc5_term_get_skolem_indices(Cvc5Term term, size_t* size) +{ + static thread_local std::vector res; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + CVC5_CAPI_CHECK_NOT_NULL(size); + res.clear(); + auto terms = term->d_term.getSkolemIndices(); + for (auto& t : terms) + { + res.push_back(term->d_tm->export_term(t)); + } + *size = res.size(); + CVC5_CAPI_TRY_CATCH_END; + return res.data(); +} + +size_t cvc5_term_hash(Cvc5Term term) +{ + size_t res = 0; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_TERM(term); + res = std::hash{}(term->d_term); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +/* -------------------------------------------------------------------------- */ +/* Cvc5Op */ +/* -------------------------------------------------------------------------- */ + +bool cvc5_op_is_equal(Cvc5Op a, Cvc5Op b) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + if (a == nullptr || b == nullptr) + { + res = a == b; + } + else + { + res = a->d_op == b->d_op; + } + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +bool cvc5_op_is_disequal(Cvc5Op a, Cvc5Op b) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + if (a == nullptr || b == nullptr) + { + res = a != b; + } + else + { + res = a->d_op != b->d_op; + } + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Kind cvc5_op_get_kind(Cvc5Op op) +{ + Cvc5Kind res = CVC5_KIND_INTERNAL_KIND; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_OP(op); + res = static_cast(op->d_op.getKind()); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +bool cvc5_op_is_indexed(Cvc5Op op) +{ + bool res = false; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_OP(op); + res = op->d_op.isIndexed(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +size_t cvc5_op_get_num_indices(Cvc5Op op) +{ + size_t res = 0; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_OP(op); + res = op->d_op.getNumIndices(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Term cvc5_op_get_index(Cvc5Op op, size_t i) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_OP(op); + res = op->d_tm->export_term(op->d_op[i]); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +const char* cvc5_op_to_string(Cvc5Op op) +{ + static thread_local std::string str; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_OP(op); + str = op->d_op.toString(); + CVC5_CAPI_TRY_CATCH_END; + return str.c_str(); +} + +size_t cvc5_op_hash(Cvc5Op op) +{ + size_t res = 0; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_OP(op); + res = std::hash{}(op->d_op); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +/* -------------------------------------------------------------------------- */ +/* Cvc5TermManager */ +/* -------------------------------------------------------------------------- */ + +Cvc5TermManager* cvc5_term_manager_new() +{ + Cvc5TermManager* res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + res = new Cvc5TermManager(); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +void cvc5_term_manager_delete(Cvc5TermManager* tm) +{ + CVC5_CAPI_TRY_CATCH_BEGIN; + delete tm; + CVC5_CAPI_TRY_CATCH_END; +} + +void cvc5_term_manager_release(Cvc5TermManager* tm) +{ + CVC5_CAPI_TRY_CATCH_BEGIN; + tm->release(); + CVC5_CAPI_TRY_CATCH_END; +} + +/* Sorts Handling ----------------------------------------------------------- */ + +Cvc5Sort cvc5_get_boolean_sort(Cvc5TermManager* tm) +{ + Cvc5Sort res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + res = tm->export_sort(tm->d_tm.getBooleanSort()); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Sort cvc5_get_integer_sort(Cvc5TermManager* tm) +{ + Cvc5Sort res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + res = tm->export_sort(tm->d_tm.getIntegerSort()); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Sort cvc5_get_real_sort(Cvc5TermManager* tm) +{ + Cvc5Sort res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + res = tm->export_sort(tm->d_tm.getRealSort()); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Sort cvc5_get_regexp_sort(Cvc5TermManager* tm) +{ + Cvc5Sort res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + res = tm->export_sort(tm->d_tm.getRegExpSort()); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Sort cvc5_get_rm_sort(Cvc5TermManager* tm) +{ + Cvc5Sort res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + res = tm->export_sort(tm->d_tm.getRoundingModeSort()); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Sort cvc5_get_string_sort(Cvc5TermManager* tm) +{ + Cvc5Sort res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + res = tm->export_sort(tm->d_tm.getStringSort()); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Sort cvc5_mk_array_sort(Cvc5TermManager* tm, Cvc5Sort index, Cvc5Sort elem) +{ + Cvc5Sort res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_SORT(index); + CVC5_CAPI_CHECK_SORT(elem); + res = tm->export_sort(tm->d_tm.mkArraySort(index->d_sort, elem->d_sort)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Sort cvc5_mk_bv_sort(Cvc5TermManager* tm, uint32_t size) +{ + Cvc5Sort res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + res = tm->export_sort(tm->d_tm.mkBitVectorSort(size)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Sort cvc5_mk_fp_sort(Cvc5TermManager* tm, uint32_t exp, uint32_t sig) +{ + Cvc5Sort res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + res = tm->export_sort(tm->d_tm.mkFloatingPointSort(exp, sig)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Sort cvc5_mk_ff_sort(Cvc5TermManager* tm, const char* size, uint32_t base) +{ + Cvc5Sort res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_NOT_NULL(size); + res = tm->export_sort(tm->d_tm.mkFiniteFieldSort(size, base)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Sort cvc5_mk_dt_sort(Cvc5TermManager* tm, Cvc5DatatypeDecl decl) +{ + Cvc5Sort res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + res = tm->export_sort(tm->d_tm.mkDatatypeSort(decl->d_decl)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +const Cvc5Sort* cvc5_mk_dt_sorts(Cvc5TermManager* tm, + size_t size, + const Cvc5DatatypeDecl decls[]) +{ + static thread_local std::vector res; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_NOT_NULL(decls); + res.clear(); + std::vector cdecls; + for (size_t i = 0; i < size; ++i) + { + CVC5_CAPI_CHECK_DT_DECL_AT_IDX(decls, i); + cdecls.push_back(decls[i]->d_decl); + } + auto sorts = tm->d_tm.mkDatatypeSorts(cdecls); + for (auto& s : sorts) + { + res.push_back(tm->export_sort(s)); + } + CVC5_CAPI_TRY_CATCH_END; + return res.data(); +} + +Cvc5Sort cvc5_mk_fun_sort(Cvc5TermManager* tm, + size_t size, + const Cvc5Sort sorts[], + Cvc5Sort codomain) +{ + Cvc5Sort res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_NOT_NULL(sorts); + std::vector csorts; + for (size_t i = 0; i < size; ++i) + { + CVC5_CAPI_CHECK_SORT_AT_IDX(sorts, i); + csorts.push_back(sorts[i]->d_sort); + } + res = tm->export_sort(tm->d_tm.mkFunctionSort(csorts, codomain->d_sort)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Sort cvc5_mk_param_sort(Cvc5TermManager* tm, const char* symbol) +{ + Cvc5Sort res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_NOT_NULL(symbol); + res = tm->export_sort(tm->d_tm.mkParamSort(symbol)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Sort cvc5_mk_predicate_sort(Cvc5TermManager* tm, + size_t size, + const Cvc5Sort sorts[]) +{ + Cvc5Sort res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_NOT_NULL(sorts); + std::vector csorts; + for (size_t i = 0; i < size; ++i) + { + CVC5_CAPI_CHECK_SORT_AT_IDX(sorts, i); + csorts.push_back(sorts[i]->d_sort); + } + res = tm->export_sort(tm->d_tm.mkPredicateSort(csorts)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Sort cvc5_mk_record_sort(Cvc5TermManager* tm, + size_t size, + const char* names[], + const Cvc5Sort sorts[]) +{ + Cvc5Sort res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + if (names != NULL) + { + CVC5_CAPI_CHECK_NOT_NULL(sorts); + std::vector> cfields; + for (size_t i = 0; i < size; ++i) + { + CVC5_CAPI_CHECK_NOT_NULL_AT_IDX(names, i); + CVC5_CAPI_CHECK_SORT_AT_IDX(sorts, i); + cfields.emplace_back(names[i], sorts[i]->d_sort); + } + res = tm->export_sort(tm->d_tm.mkRecordSort(cfields)); + } + else + { + res = tm->export_sort(tm->d_tm.mkRecordSort({})); + } + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Sort cvc5_mk_set_sort(Cvc5TermManager* tm, Cvc5Sort sort) +{ + Cvc5Sort res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_SORT(sort); + res = tm->export_sort(tm->d_tm.mkSetSort(sort->d_sort)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Sort cvc5_mk_bag_sort(Cvc5TermManager* tm, Cvc5Sort sort) +{ + Cvc5Sort res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_SORT(sort); + res = tm->export_sort(tm->d_tm.mkBagSort(sort->d_sort)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Sort cvc5_mk_sequence_sort(Cvc5TermManager* tm, Cvc5Sort sort) +{ + Cvc5Sort res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_SORT(sort); + res = tm->export_sort(tm->d_tm.mkSequenceSort(sort->d_sort)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Sort cvc5_mk_abstract_sort(Cvc5TermManager* tm, Cvc5SortKind k) +{ + Cvc5Sort res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + res = + tm->export_sort(tm->d_tm.mkAbstractSort(static_cast(k))); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Sort cvc5_mk_uninterpreted_sort(Cvc5TermManager* tm, const char* symbol) +{ + Cvc5Sort res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + if (symbol) + { + res = tm->export_sort(tm->d_tm.mkUninterpretedSort(symbol)); + } + else + { + res = tm->export_sort(tm->d_tm.mkUninterpretedSort()); + } + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Sort cvc5_mk_unresolved_dt_sort(Cvc5TermManager* tm, + const char* symbol, + size_t arity) +{ + Cvc5Sort res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_NOT_NULL(symbol); + res = tm->export_sort(tm->d_tm.mkUnresolvedDatatypeSort(symbol, arity)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Sort cvc5_mk_uninterpreted_sort_constructor_sort(Cvc5TermManager* tm, + size_t arity, + const char* symbol) +{ + Cvc5Sort res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + if (symbol) + { + res = tm->export_sort( + tm->d_tm.mkUninterpretedSortConstructorSort(arity, symbol)); + } + else + { + res = tm->export_sort(tm->d_tm.mkUninterpretedSortConstructorSort(arity)); + } + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Sort cvc5_mk_tuple_sort(Cvc5TermManager* tm, + size_t size, + const Cvc5Sort sorts[]) +{ + Cvc5Sort res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_NOT_NULL(sorts); + std::vector csorts; + for (size_t i = 0; i < size; ++i) + { + CVC5_CAPI_CHECK_SORT_AT_IDX(sorts, i); + csorts.push_back(sorts[i]->d_sort); + } + res = tm->export_sort(tm->d_tm.mkTupleSort(csorts)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Sort cvc5_mk_nullable_sort(Cvc5TermManager* tm, Cvc5Sort sort) { Cvc5Sort res = nullptr; CVC5_CAPI_TRY_CATCH_BEGIN; CVC5_CAPI_CHECK_NOT_NULL(tm); - res = tm->export_sort(tm->d_tm.mkDatatypeSort(decl->d_decl)); + CVC5_CAPI_CHECK_SORT(sort); + res = tm->export_sort(tm->d_tm.mkNullableSort(sort->d_sort)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +/* Datatype constructor declaration ------------------------------------ */ + +Cvc5DatatypeConstructorDecl cvc5_mk_dt_cons_decl(Cvc5TermManager* tm, + const char* name) +{ + Cvc5DatatypeConstructorDecl res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_NOT_NULL(name); + res = tm->export_dt_cons_decl(tm->d_tm.mkDatatypeConstructorDecl(name)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +/* Datatype declaration ------------------------------------------------ */ + +Cvc5DatatypeDecl cvc5_mk_dt_decl(Cvc5TermManager* tm, + const char* name, + bool is_codt) +{ + Cvc5DatatypeDecl res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_NOT_NULL(name); + res = tm->export_dt_decl(tm->d_tm.mkDatatypeDecl(name, is_codt)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5DatatypeDecl cvc5_mk_dt_decl_with_params(Cvc5TermManager* tm, + const char* name, + size_t size, + const Cvc5Sort* params, + bool is_codt) +{ + Cvc5DatatypeDecl res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_NOT_NULL(name); + CVC5_CAPI_CHECK_NOT_NULL(params); + std::vector cparams; + for (size_t i = 0; i < size; ++i) + { + CVC5_CAPI_CHECK_SORT_AT_IDX(params, i); + cparams.push_back(params[i]->d_sort); + } + res = tm->export_dt_decl(tm->d_tm.mkDatatypeDecl(name, cparams, is_codt)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +/* Create Terms --------------------------------------------------------- */ + +Cvc5Term cvc5_mk_term(Cvc5TermManager* tm, + Cvc5Kind kind, + size_t size, + const Cvc5Term children[]) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_KIND(kind); + CVC5_API_CHECK(children || size == 0) + << "unexpected NULL argument for 'children'"; + std::vector cchildren; + for (size_t i = 0; i < size; ++i) + { + CVC5_CAPI_CHECK_TERM_AT_IDX(children, i); + cchildren.push_back(children[i]->d_term); + } + res = tm->export_term( + tm->d_tm.mkTerm(static_cast(kind), cchildren)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Term cvc5_mk_term_from_op(Cvc5TermManager* tm, + Cvc5Op op, + size_t size, + const Cvc5Term children[]) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_NOT_NULL(op); + CVC5_API_CHECK(children || size == 0) + << "unexpected NULL argument for 'children'"; + std::vector cchildren; + for (size_t i = 0; i < size; ++i) + { + CVC5_CAPI_CHECK_TERM_AT_IDX(children, i); + cchildren.push_back(children[i]->d_term); + } + res = tm->export_term(tm->d_tm.mkTerm(op->d_op, cchildren)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Term cvc5_mk_tuple(Cvc5TermManager* tm, size_t size, const Cvc5Term terms[]) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_NOT_NULL(terms); + std::vector cterms; + for (size_t i = 0; i < size; ++i) + { + CVC5_CAPI_CHECK_TERM_AT_IDX(terms, i); + cterms.push_back(terms[i]->d_term); + } + res = tm->export_term(tm->d_tm.mkTuple(cterms)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Term cvc5_mk_nullable_some(Cvc5TermManager* tm, Cvc5Term term) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_TERM(term); + res = tm->export_term(tm->d_tm.mkNullableSome(term->d_term)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Term cvc5_mk_nullable_val(Cvc5TermManager* tm, Cvc5Term term) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_TERM(term); + res = tm->export_term(tm->d_tm.mkNullableVal(term->d_term)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Term cvc5_mk_nullable_is_null(Cvc5TermManager* tm, Cvc5Term term) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_TERM(term); + res = tm->export_term(tm->d_tm.mkNullableIsNull(term->d_term)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Term cvc5_mk_nullable_is_some(Cvc5TermManager* tm, Cvc5Term term) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_TERM(term); + res = tm->export_term(tm->d_tm.mkNullableIsSome(term->d_term)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Term cvc5_mk_nullable_null(Cvc5TermManager* tm, Cvc5Sort sort) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_SORT(sort); + res = tm->export_term(tm->d_tm.mkNullableNull(sort->d_sort)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Term cvc5_mk_nullable_lift(Cvc5TermManager* tm, + Cvc5Kind kind, + size_t size, + const Cvc5Term args[]) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_KIND(kind); + CVC5_CAPI_CHECK_NOT_NULL(args); + std::vector cargs; + for (size_t i = 0; i < size; ++i) + { + CVC5_CAPI_CHECK_TERM_AT_IDX(args, i); + cargs.push_back(args[i]->d_term); + } + res = tm->export_term( + tm->d_tm.mkNullableLift(static_cast(kind), cargs)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +/* Create Operators ---------------------------------------------------- */ + +Cvc5Op cvc5_mk_op(Cvc5TermManager* tm, + Cvc5Kind kind, + size_t size, + const uint32_t idxs[]) +{ + Cvc5Op res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_KIND(kind); + CVC5_API_CHECK(idxs || size == 0) << "unexpected NULL argument for 'idxs'"; + std::vector cidxs; + for (size_t i = 0; i < size; ++i) + { + cidxs.push_back(idxs[i]); + } + res = tm->export_op(tm->d_tm.mkOp(static_cast(kind), cidxs)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Op cvc5_mk_op_from_str(Cvc5TermManager* tm, Cvc5Kind kind, const char* arg) +{ + Cvc5Op res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_KIND(kind); + CVC5_CAPI_CHECK_NOT_NULL(arg); + res = tm->export_op(tm->d_tm.mkOp(static_cast(kind), arg)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +/* Create Constants ---------------------------------------------------- */ + +Cvc5Term cvc5_mk_true(Cvc5TermManager* tm) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + res = tm->export_term(tm->d_tm.mkTrue()); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Term cvc5_mk_false(Cvc5TermManager* tm) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + res = tm->export_term(tm->d_tm.mkFalse()); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Term cvc5_mk_boolean(Cvc5TermManager* tm, bool val) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + res = tm->export_term(tm->d_tm.mkBoolean(val)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Term cvc5_mk_pi(Cvc5TermManager* tm) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + res = tm->export_term(tm->d_tm.mkPi()); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Term cvc5_mk_integer(Cvc5TermManager* tm, const char* s) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_NOT_NULL(s); + res = tm->export_term(tm->d_tm.mkInteger(s)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Term cvc5_mk_integer_int64(Cvc5TermManager* tm, int64_t val) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + res = tm->export_term(tm->d_tm.mkInteger(val)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Term cvc5_mk_real(Cvc5TermManager* tm, const char* s) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_NOT_NULL(s); + res = tm->export_term(tm->d_tm.mkReal(s)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Term cvc5_mk_real_int64(Cvc5TermManager* tm, int64_t val) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + res = tm->export_term(tm->d_tm.mkReal(val)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Term cvc5_mk_real_num_den(Cvc5TermManager* tm, int64_t num, int64_t den) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + res = tm->export_term(tm->d_tm.mkReal(num, den)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Term cvc5_mk_regexp_all(Cvc5TermManager* tm) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + res = tm->export_term(tm->d_tm.mkRegexpAll()); CVC5_CAPI_TRY_CATCH_END; return res; } -const Cvc5Sort* cvc5_mk_dt_sorts(Cvc5TermManager* tm, - size_t size, - const Cvc5DatatypeDecl decls[]) +Cvc5Term cvc5_mk_regexp_allchar(Cvc5TermManager* tm) { - static thread_local std::vector res; + Cvc5Term res = nullptr; CVC5_CAPI_TRY_CATCH_BEGIN; CVC5_CAPI_CHECK_NOT_NULL(tm); - CVC5_CAPI_CHECK_NOT_NULL(decls); - res.clear(); - std::vector cdecls; - for (size_t i = 0; i < size; ++i) - { - CVC5_CAPI_CHECK_DT_DECL_AT_IDX(decls, i); - cdecls.push_back(decls[i]->d_decl); - } - auto sorts = tm->d_tm.mkDatatypeSorts(cdecls); - for (auto& s : sorts) - { - res.push_back(tm->export_sort(s)); - } + res = tm->export_term(tm->d_tm.mkRegexpAllchar()); CVC5_CAPI_TRY_CATCH_END; - return res.data(); + return res; } -Cvc5Sort cvc5_mk_fun_sort(Cvc5TermManager* tm, - size_t size, - const Cvc5Sort sorts[], - Cvc5Sort codomain) +Cvc5Term cvc5_mk_regexp_none(Cvc5TermManager* tm) { - Cvc5Sort res = nullptr; + Cvc5Term res = nullptr; CVC5_CAPI_TRY_CATCH_BEGIN; CVC5_CAPI_CHECK_NOT_NULL(tm); - CVC5_CAPI_CHECK_NOT_NULL(sorts); - std::vector csorts; - for (size_t i = 0; i < size; ++i) - { - CVC5_CAPI_CHECK_SORT_AT_IDX(sorts, i); - csorts.push_back(sorts[i]->d_sort); - } - res = tm->export_sort(tm->d_tm.mkFunctionSort(csorts, codomain->d_sort)); + res = tm->export_term(tm->d_tm.mkRegexpNone()); CVC5_CAPI_TRY_CATCH_END; return res; } -Cvc5Sort cvc5_mk_param_sort(Cvc5TermManager* tm, const char* symbol) +Cvc5Term cvc5_mk_empty_set(Cvc5TermManager* tm, Cvc5Sort sort) { - Cvc5Sort res = nullptr; + Cvc5Term res = nullptr; CVC5_CAPI_TRY_CATCH_BEGIN; CVC5_CAPI_CHECK_NOT_NULL(tm); - CVC5_CAPI_CHECK_NOT_NULL(symbol); - res = tm->export_sort(tm->d_tm.mkParamSort(symbol)); + CVC5_CAPI_CHECK_SORT(sort); + res = tm->export_term(tm->d_tm.mkEmptySet(sort->d_sort)); CVC5_CAPI_TRY_CATCH_END; return res; } -Cvc5Sort cvc5_mk_predicate_sort(Cvc5TermManager* tm, - size_t size, - const Cvc5Sort sorts[]) +Cvc5Term cvc5_mk_empty_bag(Cvc5TermManager* tm, Cvc5Sort sort) { - Cvc5Sort res = nullptr; + Cvc5Term res = nullptr; CVC5_CAPI_TRY_CATCH_BEGIN; CVC5_CAPI_CHECK_NOT_NULL(tm); - CVC5_CAPI_CHECK_NOT_NULL(sorts); - std::vector csorts; - for (size_t i = 0; i < size; ++i) - { - CVC5_CAPI_CHECK_SORT_AT_IDX(sorts, i); - csorts.push_back(sorts[i]->d_sort); - } - res = tm->export_sort(tm->d_tm.mkPredicateSort(csorts)); + CVC5_CAPI_CHECK_SORT(sort); + res = tm->export_term(tm->d_tm.mkEmptyBag(sort->d_sort)); CVC5_CAPI_TRY_CATCH_END; return res; } -Cvc5Sort cvc5_mk_record_sort(Cvc5TermManager* tm, - size_t size, - const char* names[], - const Cvc5Sort sorts[]) +Cvc5Term cvc5_mk_sep_emp(Cvc5TermManager* tm) { - Cvc5Sort res = nullptr; + Cvc5Term res = nullptr; CVC5_CAPI_TRY_CATCH_BEGIN; CVC5_CAPI_CHECK_NOT_NULL(tm); - if (names != NULL) - { - CVC5_CAPI_CHECK_NOT_NULL(sorts); - std::vector> cfields; - for (size_t i = 0; i < size; ++i) - { - CVC5_CAPI_CHECK_NOT_NULL_AT_IDX(names, i); - CVC5_CAPI_CHECK_SORT_AT_IDX(sorts, i); - cfields.emplace_back(names[i], sorts[i]->d_sort); - } - res = tm->export_sort(tm->d_tm.mkRecordSort(cfields)); - } - else - { - res = tm->export_sort(tm->d_tm.mkRecordSort({})); - } + res = tm->export_term(tm->d_tm.mkSepEmp()); CVC5_CAPI_TRY_CATCH_END; return res; } -Cvc5Sort cvc5_mk_set_sort(Cvc5TermManager* tm, Cvc5Sort sort) +Cvc5Term cvc5_mk_sep_nil(Cvc5TermManager* tm, Cvc5Sort sort) { - Cvc5Sort res = nullptr; + Cvc5Term res = nullptr; CVC5_CAPI_TRY_CATCH_BEGIN; CVC5_CAPI_CHECK_NOT_NULL(tm); CVC5_CAPI_CHECK_SORT(sort); - res = tm->export_sort(tm->d_tm.mkSetSort(sort->d_sort)); + res = tm->export_term(tm->d_tm.mkSepNil(sort->d_sort)); CVC5_CAPI_TRY_CATCH_END; return res; } -Cvc5Sort cvc5_mk_bag_sort(Cvc5TermManager* tm, Cvc5Sort sort) +Cvc5Term cvc5_mk_string(Cvc5TermManager* tm, const char* s, bool use_esc_seq) { - Cvc5Sort res = nullptr; + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_NOT_NULL(s); + res = tm->export_term(tm->d_tm.mkString(s, use_esc_seq)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Term cvc5_mk_string_from_wchar(Cvc5TermManager* tm, const wchar_t* s) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_NOT_NULL(s); + res = tm->export_term(tm->d_tm.mkString(s)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Term cvc5_mk_empty_sequence(Cvc5TermManager* tm, Cvc5Sort sort) +{ + Cvc5Term res = nullptr; CVC5_CAPI_TRY_CATCH_BEGIN; CVC5_CAPI_CHECK_NOT_NULL(tm); CVC5_CAPI_CHECK_SORT(sort); - res = tm->export_sort(tm->d_tm.mkBagSort(sort->d_sort)); + res = tm->export_term(tm->d_tm.mkEmptySequence(sort->d_sort)); CVC5_CAPI_TRY_CATCH_END; return res; } -Cvc5Sort cvc5_mk_sequence_sort(Cvc5TermManager* tm, Cvc5Sort sort) +Cvc5Term cvc5_mk_universe_set(Cvc5TermManager* tm, Cvc5Sort sort) { - Cvc5Sort res = nullptr; + Cvc5Term res = nullptr; CVC5_CAPI_TRY_CATCH_BEGIN; CVC5_CAPI_CHECK_NOT_NULL(tm); CVC5_CAPI_CHECK_SORT(sort); - res = tm->export_sort(tm->d_tm.mkSequenceSort(sort->d_sort)); + res = tm->export_term(tm->d_tm.mkUniverseSet(sort->d_sort)); CVC5_CAPI_TRY_CATCH_END; return res; } -Cvc5Sort cvc5_mk_abstract_sort(Cvc5TermManager* tm, Cvc5SortKind k) +Cvc5Term cvc5_mk_bv_uint64(Cvc5TermManager* tm, uint32_t size, uint64_t val) { - Cvc5Sort res = nullptr; + Cvc5Term res = nullptr; CVC5_CAPI_TRY_CATCH_BEGIN; CVC5_CAPI_CHECK_NOT_NULL(tm); - res = - tm->export_sort(tm->d_tm.mkAbstractSort(static_cast(k))); + res = tm->export_term(tm->d_tm.mkBitVector(size, val)); CVC5_CAPI_TRY_CATCH_END; return res; } -Cvc5Sort cvc5_mk_uninterpreted_sort(Cvc5TermManager* tm, const char* symbol) +Cvc5Term cvc5_mk_bv(Cvc5TermManager* tm, + uint32_t size, + const char* s, + uint32_t base) { - Cvc5Sort res = nullptr; + Cvc5Term res = nullptr; CVC5_CAPI_TRY_CATCH_BEGIN; CVC5_CAPI_CHECK_NOT_NULL(tm); - if (symbol) - { - res = tm->export_sort(tm->d_tm.mkUninterpretedSort(symbol)); - } - else - { - res = tm->export_sort(tm->d_tm.mkUninterpretedSort()); - } + CVC5_CAPI_CHECK_NOT_NULL(s); + res = tm->export_term(tm->d_tm.mkBitVector(size, s, base)); CVC5_CAPI_TRY_CATCH_END; return res; } -Cvc5Sort cvc5_mk_unresolved_dt_sort(Cvc5TermManager* tm, - const char* symbol, - size_t arity) +Cvc5Term cvc5_mk_ff_elem(Cvc5TermManager* tm, + const char* value, + Cvc5Sort sort, + uint32_t base) { - Cvc5Sort res = nullptr; + Cvc5Term res = nullptr; CVC5_CAPI_TRY_CATCH_BEGIN; CVC5_CAPI_CHECK_NOT_NULL(tm); - CVC5_CAPI_CHECK_NOT_NULL(symbol); - res = tm->export_sort(tm->d_tm.mkUnresolvedDatatypeSort(symbol, arity)); + CVC5_CAPI_CHECK_NOT_NULL(value); + CVC5_CAPI_CHECK_SORT(sort); + res = tm->export_term(tm->d_tm.mkFiniteFieldElem(value, sort->d_sort, base)); CVC5_CAPI_TRY_CATCH_END; return res; } -Cvc5Sort cvc5_mk_uninterpreted_sort_constructor_sort(Cvc5TermManager* tm, - size_t arity, - const char* symbol) +Cvc5Term cvc5_mk_const_array(Cvc5TermManager* tm, Cvc5Sort sort, Cvc5Term val) { - Cvc5Sort res = nullptr; + Cvc5Term res = nullptr; CVC5_CAPI_TRY_CATCH_BEGIN; CVC5_CAPI_CHECK_NOT_NULL(tm); - if (symbol) - { - res = tm->export_sort( - tm->d_tm.mkUninterpretedSortConstructorSort(arity, symbol)); - } - else - { - res = tm->export_sort(tm->d_tm.mkUninterpretedSortConstructorSort(arity)); - } + CVC5_CAPI_CHECK_SORT(sort); + CVC5_CAPI_CHECK_TERM(val); + res = tm->export_term(tm->d_tm.mkConstArray(sort->d_sort, val->d_term)); CVC5_CAPI_TRY_CATCH_END; return res; } -Cvc5Sort cvc5_mk_tuple_sort(Cvc5TermManager* tm, - size_t size, - const Cvc5Sort sorts[]) +Cvc5Term cvc5_mk_fp_pos_inf(Cvc5TermManager* tm, uint32_t exp, uint32_t sig) { - Cvc5Sort res = nullptr; + Cvc5Term res = nullptr; CVC5_CAPI_TRY_CATCH_BEGIN; CVC5_CAPI_CHECK_NOT_NULL(tm); - CVC5_CAPI_CHECK_NOT_NULL(sorts); - std::vector csorts; - for (size_t i = 0; i < size; ++i) - { - CVC5_CAPI_CHECK_SORT_AT_IDX(sorts, i); - csorts.push_back(sorts[i]->d_sort); - } - res = tm->export_sort(tm->d_tm.mkTupleSort(csorts)); + res = tm->export_term(tm->d_tm.mkFloatingPointPosInf(exp, sig)); CVC5_CAPI_TRY_CATCH_END; return res; } -Cvc5Sort cvc5_mk_nullable_sort(Cvc5TermManager* tm, Cvc5Sort sort) +Cvc5Term cvc5_mk_fp_neg_inf(Cvc5TermManager* tm, uint32_t exp, uint32_t sig) { - Cvc5Sort res = nullptr; + Cvc5Term res = nullptr; CVC5_CAPI_TRY_CATCH_BEGIN; CVC5_CAPI_CHECK_NOT_NULL(tm); - CVC5_CAPI_CHECK_SORT(sort); - res = tm->export_sort(tm->d_tm.mkNullableSort(sort->d_sort)); + res = tm->export_term(tm->d_tm.mkFloatingPointNegInf(exp, sig)); CVC5_CAPI_TRY_CATCH_END; return res; } -/* Datatype constructor declaration ------------------------------------ */ +Cvc5Term cvc5_mk_fp_nan(Cvc5TermManager* tm, uint32_t exp, uint32_t sig) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + res = tm->export_term(tm->d_tm.mkFloatingPointNaN(exp, sig)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} -Cvc5DatatypeConstructorDecl cvc5_mk_dt_cons_decl(Cvc5TermManager* tm, - const char* name) +Cvc5Term cvc5_mk_fp_pos_zero(Cvc5TermManager* tm, uint32_t exp, uint32_t sig) { - Cvc5DatatypeConstructorDecl res = nullptr; + Cvc5Term res = nullptr; CVC5_CAPI_TRY_CATCH_BEGIN; CVC5_CAPI_CHECK_NOT_NULL(tm); - CVC5_CAPI_CHECK_NOT_NULL(name); - res = tm->export_dt_cons_decl(tm->d_tm.mkDatatypeConstructorDecl(name)); + res = tm->export_term(tm->d_tm.mkFloatingPointPosZero(exp, sig)); CVC5_CAPI_TRY_CATCH_END; return res; } -/* Datatype declaration ------------------------------------------------ */ +Cvc5Term cvc5_mk_fp_neg_zero(Cvc5TermManager* tm, uint32_t exp, uint32_t sig) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + res = tm->export_term(tm->d_tm.mkFloatingPointNegZero(exp, sig)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} -Cvc5DatatypeDecl cvc5_mk_dt_decl(Cvc5TermManager* tm, - const char* name, - bool is_codt) +Cvc5Term cvc5_mk_rm(Cvc5TermManager* tm, Cvc5RoundingMode rm) { - Cvc5DatatypeDecl res = nullptr; + Cvc5Term res = nullptr; CVC5_CAPI_TRY_CATCH_BEGIN; CVC5_CAPI_CHECK_NOT_NULL(tm); - CVC5_CAPI_CHECK_NOT_NULL(name); - res = tm->export_dt_decl(tm->d_tm.mkDatatypeDecl(name, is_codt)); + res = tm->export_term( + tm->d_tm.mkRoundingMode(static_cast(rm))); CVC5_CAPI_TRY_CATCH_END; return res; } -Cvc5DatatypeDecl cvc5_mk_dt_decl_with_params(Cvc5TermManager* tm, - const char* name, - size_t size, - const Cvc5Sort* params, - bool is_codt) +Cvc5Term cvc5_mk_fp(Cvc5TermManager* tm, + uint32_t exp, + uint32_t sig, + Cvc5Term val) { - Cvc5DatatypeDecl res = nullptr; + Cvc5Term res = nullptr; CVC5_CAPI_TRY_CATCH_BEGIN; CVC5_CAPI_CHECK_NOT_NULL(tm); - CVC5_CAPI_CHECK_NOT_NULL(name); - CVC5_CAPI_CHECK_NOT_NULL(params); - std::vector cparams; - for (size_t i = 0; i < size; ++i) + CVC5_CAPI_CHECK_TERM(val); + res = tm->export_term(tm->d_tm.mkFloatingPoint(exp, sig, val->d_term)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Term cvc5_mk_fp_from_ieee(Cvc5TermManager* tm, + Cvc5Term sign, + Cvc5Term exp, + Cvc5Term sig) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_TERM(sign); + CVC5_CAPI_CHECK_TERM(exp); + CVC5_CAPI_CHECK_TERM(sig); + res = tm->export_term( + tm->d_tm.mkFloatingPoint(sign->d_term, exp->d_term, sig->d_term)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Term cvc5_mk_cardinality_constraint(Cvc5TermManager* tm, + Cvc5Sort sort, + uint32_t upperBound) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_SORT(sort); + res = tm->export_term( + tm->d_tm.mkCardinalityConstraint(sort->d_sort, upperBound)); + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +/* Create Variables ----------------------------------------------------- */ + +Cvc5Term cvc5_mk_const(Cvc5TermManager* tm, Cvc5Sort sort, const char* symbol) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_SORT(sort); + if (symbol) { - CVC5_CAPI_CHECK_SORT_AT_IDX(params, i); - cparams.push_back(params[i]->d_sort); + res = tm->export_term(tm->d_tm.mkConst(sort->d_sort, symbol)); + } + else + { + res = tm->export_term(tm->d_tm.mkConst(sort->d_sort)); + } + CVC5_CAPI_TRY_CATCH_END; + return res; +} + +Cvc5Term cvc5_mk_var(Cvc5TermManager* tm, Cvc5Sort sort, const char* symbol) +{ + Cvc5Term res = nullptr; + CVC5_CAPI_TRY_CATCH_BEGIN; + CVC5_CAPI_CHECK_NOT_NULL(tm); + CVC5_CAPI_CHECK_SORT(sort); + if (symbol) + { + res = tm->export_term(tm->d_tm.mkVar(sort->d_sort, symbol)); + } + else + { + res = tm->export_term(tm->d_tm.mkVar(sort->d_sort)); } - res = tm->export_dt_decl(tm->d_tm.mkDatatypeDecl(name, cparams, is_codt)); CVC5_CAPI_TRY_CATCH_END; return res; } diff --git a/src/api/c/cvc5_checks.h b/src/api/c/cvc5_checks.h index 508296b69ce..bc9646b6093 100644 --- a/src/api/c/cvc5_checks.h +++ b/src/api/c/cvc5_checks.h @@ -156,5 +156,13 @@ class Cvc5CApiAbortStream #define CVC5_CAPI_CHECK_TERM(term) \ CVC5_API_CHECK(term != nullptr) << "invalid term" +#define CVC5_CAPI_CHECK_TERM_AT_IDX(terms, i) \ + CVC5_API_CHECK(terms[i] != nullptr) << "invalid term at index " << i + +/* -------------------------------------------------------------------------- */ + +#define CVC5_CAPI_CHECK_OP(op) \ + CVC5_API_CHECK(op != nullptr) << "invalid operator term" + /* -------------------------------------------------------------------------- */ } diff --git a/src/api/cpp/cvc5.cpp b/src/api/cpp/cvc5.cpp index 0a30b5679a8..f9644e903db 100644 --- a/src/api/cpp/cvc5.cpp +++ b/src/api/cpp/cvc5.cpp @@ -1367,7 +1367,7 @@ std::string Sort::getSymbol() const CVC5_API_TRY_CATCH_BEGIN; CVC5_API_CHECK_NOT_NULL; CVC5_API_CHECK(d_type->hasName()) - << "Invalid call to '" << __PRETTY_FUNCTION__ + << "invalid call to '" << __PRETTY_FUNCTION__ << "', expected the sort to have a symbol."; //////// all checks before this line return d_type->getName(); @@ -2113,7 +2113,7 @@ bool Op::operator!=(const Op& t) const Kind Op::getKind() const { - CVC5_API_CHECK(d_kind != Kind::NULL_TERM) << "expecting a non-null Kind"; + CVC5_API_CHECK(d_kind != Kind::NULL_TERM) << "expected a non-null Kind"; //////// all checks before this line return d_kind; } @@ -2200,7 +2200,7 @@ Term Op::getIndexHelper(size_t index) CVC5_API_TRY_CATCH_BEGIN; CVC5_API_CHECK_NOT_NULL; CVC5_API_CHECK(!d_node->isNull()) - << "expecting a non-null internal expression. This Op is not indexed."; + << "expected a non-null internal expression. This Op is not indexed."; CVC5_API_CHECK(index < getNumIndicesHelper()) << "index out of bound"; Kind k = intToExtKind(d_node->getKind()); Term t; @@ -2386,7 +2386,7 @@ std::string Op::toString() const else { CVC5_API_CHECK(!d_node->isNull()) - << "expecting a non-null internal expression"; + << "expected a non-null internal expression"; Assert(isNull() || d_tm != nullptr); return d_node->toString(); } @@ -2565,7 +2565,7 @@ Term Term::substitute(const Term& term, const Term& replacement) const CVC5_API_CHECK_TERM(term); CVC5_API_CHECK_TERM(replacement); CVC5_API_CHECK(term.getSort() == replacement.getSort()) - << "expecting terms of the same sort in substitute"; + << "expected terms of the same sort in substitute"; //////// all checks before this line return Term(d_tm, d_node->substitute(internal::TNode(*term.d_node), @@ -2580,7 +2580,7 @@ Term Term::substitute(const std::vector& terms, CVC5_API_TRY_CATCH_BEGIN; CVC5_API_CHECK_NOT_NULL; CVC5_API_CHECK(terms.size() == replacements.size()) - << "expecting vectors of the same arity in substitute"; + << "expected vectors of the same arity in substitute"; CVC5_API_TERM_CHECK_TERMS_WITH_TERMS_SORT_EQUAL_TO(terms, replacements); //////// all checks before this line std::vector nodes = Term::termVectorToNodes(terms); @@ -2610,7 +2610,7 @@ Op Term::getOp() const CVC5_API_TRY_CATCH_BEGIN; CVC5_API_CHECK_NOT_NULL; CVC5_API_CHECK(d_node->hasOperator()) - << "expecting Term to have an Op when calling getOp()"; + << "expected Term to have an Op when calling getOp()"; //////// all checks before this line // special cases for parameterized operators that are not indexed operators @@ -2651,7 +2651,7 @@ std::string Term::getSymbol() const CVC5_API_TRY_CATCH_BEGIN; CVC5_API_CHECK_NOT_NULL; CVC5_API_CHECK(d_node->hasName()) - << "Invalid call to '" << __PRETTY_FUNCTION__ + << "invalid call to '" << __PRETTY_FUNCTION__ << "', expected the term to have a symbol."; //////// all checks before this line return d_node->getName(); @@ -4194,7 +4194,7 @@ Term DatatypeConstructor::getInstantiatedTerm(const Sort& retSort) const CVC5_API_CHECK(d_ctor->isResolved()) << "expected resolved datatype constructor"; CVC5_API_CHECK(retSort.isDatatype()) - << "Cannot get specialized constructor type for non-datatype type " + << "cannot get specialized constructor type for non-datatype type " << retSort; //////// all checks before this line internal::Node ret = d_ctor->getInstantiatedConstructor(*retSort.d_type); @@ -4539,7 +4539,7 @@ bool Datatype::isFinite() const CVC5_API_TRY_CATCH_BEGIN; CVC5_API_CHECK_NOT_NULL; CVC5_API_CHECK(!d_dtype->isParametric()) - << "Invalid call to 'isFinite()', expected non-parametric Datatype"; + << "invalid call to 'isFinite()', expected non-parametric Datatype"; //////// all checks before this line // we assume that finite model finding is disabled by passing false as the // second argument @@ -5071,7 +5071,7 @@ std::ostream& operator<<(std::ostream& out, const Statistics& stats) Proof::Proof() : d_tm(nullptr) {} Proof::Proof(TermManager* tm, const std::shared_ptr p) - : d_proof_node(p), d_tm(tm) + : d_proofNode(p), d_tm(tm) { } @@ -5081,9 +5081,9 @@ ProofRule Proof::getRule() const { CVC5_API_TRY_CATCH_BEGIN; //////// all checks before this line - if (d_proof_node != nullptr) + if (d_proofNode != nullptr) { - return this->getProofNode()->getRule(); + return d_proofNode->getRule(); } return ProofRule::UNKNOWN; //////// @@ -5093,18 +5093,17 @@ ProofRule Proof::getRule() const ProofRewriteRule Proof::getRewriteRule() const { CVC5_API_TRY_CATCH_BEGIN; - CVC5_API_CHECK(this->getProofNode()->getRule() == ProofRule::DSL_REWRITE - || this->getProofNode()->getRule() + CVC5_API_CHECK(d_proofNode->getRule() == ProofRule::DSL_REWRITE + || d_proofNode->getRule() == ProofRule::THEORY_REWRITE) << "expected `getRule()` to return `DSL_REWRITE` or `THEORY_REWRITE`, " "got " - << this->getProofNode()->getRule() << " instead."; + << d_proofNode->getRule() << " instead."; //////// all checks before this line - if (d_proof_node != nullptr) + if (d_proofNode != nullptr) { return static_cast( - detail::getInteger(this->d_proof_node->getArguments()[0]) - .getUnsignedInt()); + detail::getInteger(d_proofNode->getArguments()[0]).getUnsignedInt()); } return ProofRewriteRule::NONE; //////// @@ -5115,9 +5114,9 @@ Term Proof::getResult() const { CVC5_API_TRY_CATCH_BEGIN; //////// all checks before this line - if (d_proof_node != nullptr) + if (d_proofNode != nullptr) { - return Term(d_tm, this->getProofNode()->getResult()); + return Term(d_tm, d_proofNode->getResult()); } return Term(); //////// @@ -5128,14 +5127,14 @@ const std::vector Proof::getChildren() const { CVC5_API_TRY_CATCH_BEGIN; //////// all checks before this line - if (d_proof_node != nullptr) + if (d_proofNode != nullptr) { std::vector children; - std::vector> node_children = - d_proof_node->getChildren(); - for (size_t i = 0, psize = node_children.size(); i < psize; i++) + std::vector> nodeChildren = + d_proofNode->getChildren(); + for (size_t i = 0, psize = nodeChildren.size(); i < psize; i++) { - children.push_back(Proof(d_tm, node_children[i])); + children.push_back(Proof(d_tm, nodeChildren[i])); } return children; } @@ -5148,13 +5147,13 @@ const std::vector Proof::getArguments() const { CVC5_API_TRY_CATCH_BEGIN; //////// all checks before this line - if (d_proof_node != nullptr) + if (d_proofNode != nullptr) { std::vector args; - const std::vector node_args = d_proof_node->getArguments(); - for (size_t i = 0, asize = node_args.size(); i < asize; i++) + const std::vector nodeArgs = d_proofNode->getArguments(); + for (size_t i = 0, asize = nodeArgs.size(); i < asize; i++) { - args.push_back(Term(d_tm, node_args[i])); + args.push_back(Term(d_tm, nodeArgs[i])); } return args; } @@ -5163,9 +5162,22 @@ const std::vector Proof::getArguments() const CVC5_API_TRY_CATCH_END; } -const std::shared_ptr& Proof::getProofNode(void) const +bool Proof::operator==(const Proof& p) const { - return this->d_proof_node; + CVC5_API_TRY_CATCH_BEGIN; + //////// all checks before this line + return d_proofNode == p.d_proofNode; + //////// + CVC5_API_TRY_CATCH_END; +} + +bool Proof::operator!=(const Proof& p) const +{ + CVC5_API_TRY_CATCH_BEGIN; + //////// all checks before this line + return d_proofNode != p.d_proofNode; + //////// + CVC5_API_TRY_CATCH_END; } /* -------------------------------------------------------------------------- */ @@ -5176,7 +5188,6 @@ Plugin::Plugin(TermManager& tm) : d_pExtToInt(new PluginInternal(tm.d_nm, tm, *this)) { } -Plugin::~Plugin() {} std::vector Plugin::check() { @@ -5398,7 +5409,7 @@ Term TermManager::mkRealOrIntegerFromStrHelper(const std::string& s, bool isInt) /* Catch to throw with a more meaningful error message. To be caught in * enclosing CVC5_API_TRY_CATCH_* block to throw CVC5ApiException. */ std::stringstream message; - message << "Cannot construct Real or Int from string argument '" << s + message << "cannot construct Real or Int from string argument '" << s << "'"; throw std::invalid_argument(message.str()); } @@ -5426,13 +5437,13 @@ Term TermManager::mkBVFromStrHelper(uint32_t size, if (val.strictlyNegative()) { CVC5_API_CHECK(val >= -internal::Integer(2).pow(size - 1)) - << "Overflow in bitvector construction (specified bitvector size " + << "overflow in bit-vector construction (specified bit-vector size " << size << " too small to hold value " << s << ")"; } else { CVC5_API_CHECK(val.modByPow2(size) == val) - << "Overflow in bitvector construction (specified bitvector size " + << "overflow in bit-vector construction (specified bit-vector size " << size << " too small to hold value " << s << ")"; } return mkValHelper(internal::BitVector(size, val)); @@ -5719,6 +5730,28 @@ Sort TermManager::mkFunctionSort(const std::vector& sorts, CVC5_API_TRY_CATCH_END; } +Term TermManager::mkSkolem(SkolemId id, const std::vector& indices) +{ + CVC5_API_TRY_CATCH_BEGIN; + //////// all checks before this line + // iterate over indices and convert the Terms to Nodes + std::vector nodeIndices = Term::termVectorToNodes(indices); + internal::Node res = + d_nm->getSkolemManager()->mkSkolemFunction(id, nodeIndices); + return Term(this, res); + //////// + CVC5_API_TRY_CATCH_END; +} + +size_t TermManager::getNumIndicesForSkolemId(SkolemId id) +{ + CVC5_API_TRY_CATCH_BEGIN; + //////// all checks before this line + return d_nm->getSkolemManager()->getNumIndicesForSkolemId(id); + //////// + CVC5_API_TRY_CATCH_END; +} + Sort TermManager::mkParamSort(const std::optional& symbol) { CVC5_API_TRY_CATCH_BEGIN; @@ -5793,7 +5826,7 @@ Sort TermManager::mkAbstractSort(SortKind k) CVC5_API_TRY_CATCH_BEGIN; internal::Kind ik = extToIntSortKind(k); CVC5_API_CHECK(d_nm->isSortKindAbstractable(ik)) - << "Cannot construct abstract type for kind " << k; + << "cannot construct abstract type for kind " << k; //////// all checks before this line return Sort(this, d_nm->mkAbstractType(ik)); //////// @@ -6081,10 +6114,10 @@ Term TermManager::mkPi() Term TermManager::mkInteger(const std::string& s) { CVC5_API_TRY_CATCH_BEGIN; - CVC5_API_ARG_CHECK_EXPECTED(isValidInteger(s), s) << " an integer "; + CVC5_API_ARG_CHECK_EXPECTED(isValidInteger(s), s) << "an integer "; Term res = mkRealOrIntegerFromStrHelper(s); CVC5_API_ARG_CHECK_EXPECTED(res.getSort() == getIntegerSort(), s) - << " a string representing an integer"; + << "a string representing an integer"; //////// all checks before this line return res; //////// @@ -6128,6 +6161,7 @@ Term TermManager::mkReal(int64_t val) Term TermManager::mkReal(int64_t num, int64_t den) { CVC5_API_TRY_CATCH_BEGIN; + CVC5_API_CHECK(den != 0) << "invalid denominator '" << den << "'"; //////// all checks before this line return TermManager::mkRationalValHelper(internal::Rational(num, den), false); //////// @@ -6305,7 +6339,7 @@ Term TermManager::mkConstArray(const Sort& sort, const Term& val) CVC5_API_TM_CHECK_TERM(val); CVC5_API_ARG_CHECK_EXPECTED(sort.isArray(), sort) << "an array sort"; CVC5_API_CHECK(val.getSort() == sort.getArrayElementSort()) - << "Value does not match element sort"; + << "value does not match element sort"; internal::Node n = *val.d_node; CVC5_API_ARG_CHECK_EXPECTED(n.isConst(), val) << "a value"; //////// all checks before this line @@ -6696,7 +6730,7 @@ Term Solver::synthFunHelper(const std::string& symbol, if (grammar) { CVC5_API_CHECK(grammar->d_sg->getNtSyms()[0].getType() == *sort.d_type) - << "Invalid Start symbol for grammar, expected Start's sort to be " + << "invalid Start symbol for grammar, expected Start's sort to be " << *sort.d_type << " but found " << grammar->d_sg->getNtSyms()[0].getType(); } @@ -6707,7 +6741,7 @@ Term Solver::synthFunHelper(const std::string& symbol, for (const auto& sym : grammar->d_sg->getNtSyms()) { CVC5_API_CHECK(!grammar->d_sg->getRulesFor(sym).empty()) - << "Invalid grammar, must have at least one rule for each " + << "invalid grammar, must have at least one rule for each " "non-terminal symbol"; } } @@ -6739,7 +6773,7 @@ void Solver::ensureWellFormedTerm(const Term& t) const if (internal::expr::hasFreeOrShadowedVar(*t.d_node, wasShadow)) { std::stringstream se; - se << "Cannot process term " << *t.d_node << " with "; + se << "cannot process term " << *t.d_node << " with "; if (wasShadow) { se << "shadowed variables " << std::endl; @@ -7142,7 +7176,7 @@ Result Solver::checkSat(void) const CVC5_API_TRY_CATCH_BEGIN; CVC5_API_CHECK(!d_slv->isQueryMade() || d_slv->getOptions().base.incrementalSolving) - << "Cannot make multiple queries unless incremental solving is enabled " + << "cannot make multiple queries unless incremental solving is enabled " "(try --" << internal::options::base::longName::incrementalSolving << ")"; //////// all checks before this line @@ -7156,7 +7190,7 @@ Result Solver::checkSatAssuming(const Term& assumption) const CVC5_API_TRY_CATCH_BEGIN; CVC5_API_CHECK(!d_slv->isQueryMade() || d_slv->getOptions().base.incrementalSolving) - << "Cannot make multiple queries unless incremental solving is enabled " + << "cannot make multiple queries unless incremental solving is enabled " "(try --" << internal::options::base::longName::incrementalSolving << ")"; CVC5_API_SOLVER_CHECK_TERM_WITH_SORT(assumption, getBooleanSort()); @@ -7172,7 +7206,7 @@ Result Solver::checkSatAssuming(const std::vector& assumptions) const CVC5_API_TRY_CATCH_BEGIN; CVC5_API_CHECK(!d_slv->isQueryMade() || assumptions.size() == 0 || d_slv->getOptions().base.incrementalSolving) - << "Cannot make multiple queries unless incremental solving is enabled " + << "cannot make multiple queries unless incremental solving is enabled " "(try --" << internal::options::base::longName::incrementalSolving << ")"; CVC5_API_SOLVER_CHECK_TERMS_WITH_SORT(assumptions, getBooleanSort()); @@ -7262,7 +7296,7 @@ Term Solver::defineFun(const std::string& symbol, CVC5_API_SOLVER_CHECK_TERM(term); // the sort of the body must match the return sort CVC5_API_CHECK(term.d_node->getType() == *sort.d_type) - << "Invalid sort of function body '" << term << "', expected '" << sort + << "invalid sort of function body '" << term << "', expected '" << sort << "', found '" << term.getSort() << "'"; std::vector domain_sorts; @@ -7306,7 +7340,7 @@ Term Solver::defineFunRec(const std::string& symbol, CVC5_API_SOLVER_CHECK_TERM(term); CVC5_API_SOLVER_CHECK_CODOMAIN_SORT(sort); CVC5_API_CHECK(term.d_node->getType() == *sort.d_type) - << "Invalid sort of function body '" << term << "', expected '" << sort + << "invalid sort of function body '" << term << "', expected '" << sort << "'"; std::vector domain_sorts; @@ -7355,7 +7389,7 @@ Term Solver::defineFunRec(const Term& fun, CVC5_API_SOLVER_CHECK_BOUND_VARS_DEF_FUN(fun, bound_vars, domain_sorts); Sort codomain = fun.getSort().getFunctionCodomainSort(); CVC5_API_CHECK(*codomain.d_type == term.d_node->getType()) - << "Invalid sort of function body '" << term << "', expected '" + << "invalid sort of function body '" << term << "', expected '" << codomain << "'"; } else @@ -7706,11 +7740,11 @@ std::vector Solver::getUnsatAssumptions(void) const { CVC5_API_TRY_CATCH_BEGIN; CVC5_API_CHECK(d_slv->getOptions().smt.unsatAssumptions) - << "Cannot get unsat assumptions unless explicitly enabled " + << "cannot get unsat assumptions unless explicitly enabled " "(try --" << internal::options::smt::longName::unsatAssumptions << ")"; CVC5_API_CHECK(d_slv->getSmtMode() == internal::SmtMode::UNSAT) - << "Cannot get unsat assumptions unless in unsat mode."; + << "cannot get unsat assumptions unless in unsat mode."; //////// all checks before this line std::vector uassumptions = d_slv->getUnsatAssumptions(); @@ -7731,11 +7765,11 @@ std::vector Solver::getUnsatCore(void) const { CVC5_API_TRY_CATCH_BEGIN; CVC5_API_CHECK(d_slv->getOptions().smt.produceUnsatCores) - << "Cannot get unsat core unless explicitly enabled " + << "cannot get unsat core unless explicitly enabled " "(try --" << internal::options::smt::longName::produceUnsatCores << ")"; CVC5_API_RECOVERABLE_CHECK(d_slv->getSmtMode() == internal::SmtMode::UNSAT) - << "Cannot get unsat core unless in unsat mode."; + << "cannot get unsat core unless in unsat mode."; //////// all checks before this line internal::UnsatCore core = d_slv->getUnsatCore(); /* Can not use @@ -7755,14 +7789,14 @@ std::vector Solver::getUnsatCoreLemmas(void) const { CVC5_API_TRY_CATCH_BEGIN; CVC5_API_CHECK(d_slv->getOptions().smt.produceUnsatCores) - << "Cannot get unsat core lemmas unless explicitly enabled " + << "cannot get unsat core lemmas unless explicitly enabled " "(try --" << internal::options::smt::longName::produceUnsatCores << ")"; CVC5_API_CHECK(d_slv->getOptions().smt.unsatCoresMode == internal::options::UnsatCoresMode::SAT_PROOF) - << "Cannot get unsat core lemmas unless SAT proofs are enabled"; + << "cannot get unsat core lemmas unless SAT proofs are enabled"; CVC5_API_RECOVERABLE_CHECK(d_slv->getSmtMode() == internal::SmtMode::UNSAT) - << "Cannot get unsat core unless in unsat mode."; + << "cannot get unsat core unless in unsat mode."; //////// all checks before this line std::vector lemmas = d_slv->getUnsatCoreLemmas(); /* Can not use @@ -7780,7 +7814,7 @@ std::map Solver::getDifficulty() const || d_slv->getSmtMode() == internal::SmtMode::SAT || d_slv->getSmtMode() == internal::SmtMode::SAT_UNKNOWN) - << "Cannot get difficulty unless after a UNSAT, SAT or UNKNOWN response."; + << "cannot get difficulty unless after a UNSAT, SAT or UNKNOWN response."; //////// all checks before this line std::map res; std::map dmap; @@ -7798,7 +7832,7 @@ std::pair> Solver::getTimeoutCore() const { CVC5_API_TRY_CATCH_BEGIN; CVC5_API_CHECK(d_slv->getOptions().smt.produceUnsatCores) - << "Cannot get timeout core unless unsat cores are enabled " + << "cannot get timeout core unless unsat cores are enabled " "(try --" << internal::options::smt::longName::produceUnsatCores << ")"; //////// all checks before this line @@ -7812,9 +7846,9 @@ std::pair> Solver::getTimeoutCoreAssuming( { CVC5_API_TRY_CATCH_BEGIN; CVC5_API_CHECK(!assumptions.empty()) - << "Cannot get timeout core assuming an empty set of assumptions"; + << "cannot get timeout core assuming an empty set of assumptions"; CVC5_API_CHECK(d_slv->getOptions().smt.produceUnsatCores) - << "Cannot get timeout core unless unsat cores are enabled " + << "cannot get timeout core unless unsat cores are enabled " "(try --" << internal::options::smt::longName::produceUnsatCores << ")"; //////// all checks before this line @@ -7840,10 +7874,10 @@ std::vector Solver::getProof(modes::ProofComponent c) const { CVC5_API_TRY_CATCH_BEGIN; CVC5_API_CHECK(d_slv->getOptions().smt.produceProofs) - << "Cannot get proof unless proofs are enabled (try --" + << "cannot get proof unless proofs are enabled (try --" << internal::options::smt::longName::produceProofs << ")"; CVC5_API_RECOVERABLE_CHECK(d_slv->getSmtMode() == internal::SmtMode::UNSAT) - << "Cannot get proof unless in unsat mode."; + << "cannot get proof unless in unsat mode."; //////// all checks before this line std::vector> proof_nodes = d_slv->getProof(c); @@ -7871,7 +7905,7 @@ std::string Solver::proofToString( { nodeAssertionNames[p.first.getNode()] = p.second; } - this->d_slv->printProof(ss, proof.getProofNode(), format, nodeAssertionNames); + this->d_slv->printProof(ss, proof.d_proofNode, format, nodeAssertionNames); return ss.str(); //////// CVC5_API_TRY_CATCH_END; @@ -7881,14 +7915,14 @@ std::vector Solver::getLearnedLiterals(modes::LearnedLitType t) const { CVC5_API_TRY_CATCH_BEGIN; CVC5_API_CHECK(d_slv->getOptions().smt.produceLearnedLiterals) - << "Cannot get learned literals unless enabled (try " + << "cannot get learned literals unless enabled (try " "--" << internal::options::smt::longName::produceLearnedLiterals << ")"; CVC5_API_RECOVERABLE_CHECK(d_slv->getSmtMode() == internal::SmtMode::UNSAT || d_slv->getSmtMode() == internal::SmtMode::SAT || d_slv->getSmtMode() == internal::SmtMode::SAT_UNKNOWN) - << "Cannot get learned literals unless after a UNSAT, SAT or UNKNOWN " + << "cannot get learned literals unless after a UNSAT, SAT or UNKNOWN " "response."; //////// all checks before this line std::vector lits = d_slv->getLearnedLiterals(t); @@ -7904,7 +7938,7 @@ Term Solver::getValueHelper(const Term& term) const bool freeOrShadowedVar = internal::expr::hasFreeOrShadowedVar(term.getNode(), wasShadow); CVC5_API_RECOVERABLE_CHECK(!freeOrShadowedVar) - << "Cannot get value of term containing " + << "cannot get value of term containing " << (wasShadow ? "shadowed" : "free") << " variables"; //////// all checks before this line internal::Node value = d_slv->getValue(*term.d_node); @@ -7917,17 +7951,17 @@ Term Solver::getValue(const Term& term) const { CVC5_API_TRY_CATCH_BEGIN; CVC5_API_RECOVERABLE_CHECK(d_slv->getOptions().smt.produceModels) - << "Cannot get value unless model generation is enabled " + << "cannot get value unless model generation is enabled " "(try --" << internal::options::smt::longName::produceModels << ")"; CVC5_API_RECOVERABLE_CHECK(d_slv->isSmtModeSat()) - << "Cannot get value unless after a SAT or UNKNOWN response."; + << "cannot get value unless after a SAT or UNKNOWN response."; CVC5_API_SOLVER_CHECK_TERM(term); CVC5_API_RECOVERABLE_CHECK(term.getSort().getTypeNode().isFirstClass()) - << "Cannot get value of a term that is not first class."; + << "cannot get value of a term that is not first class."; CVC5_API_RECOVERABLE_CHECK(!term.getSort().isDatatype() || term.getSort().getDatatype().isWellFounded()) - << "Cannot get value of a term of non-well-founded datatype sort."; + << "cannot get value of a term of non-well-founded datatype sort."; ensureWellFormedTerm(term); //////// all checks before this line return getValueHelper(term); @@ -7939,18 +7973,18 @@ std::vector Solver::getValue(const std::vector& terms) const { CVC5_API_TRY_CATCH_BEGIN; CVC5_API_RECOVERABLE_CHECK(d_slv->getOptions().smt.produceModels) - << "Cannot get value unless model generation is enabled " + << "cannot get value unless model generation is enabled " "(try --" << internal::options::smt::longName::produceModels << ")"; CVC5_API_RECOVERABLE_CHECK(d_slv->isSmtModeSat()) - << "Cannot get value unless after a SAT or UNKNOWN response."; + << "cannot get value unless after a SAT or UNKNOWN response."; for (const Term& t : terms) { CVC5_API_RECOVERABLE_CHECK(t.getSort().getTypeNode().isFirstClass()) - << "Cannot get value of a term that is not first class."; + << "cannot get value of a term that is not first class."; CVC5_API_RECOVERABLE_CHECK(!t.getSort().isDatatype() || t.getSort().getDatatype().isWellFounded()) - << "Cannot get value of a term of non-well-founded datatype sort."; + << "cannot get value of a term of non-well-founded datatype sort."; } CVC5_API_SOLVER_CHECK_TERMS(terms); ensureWellFormedTerms(terms); @@ -7971,14 +8005,14 @@ std::vector Solver::getModelDomainElements(const Sort& s) const { CVC5_API_TRY_CATCH_BEGIN; CVC5_API_RECOVERABLE_CHECK(d_slv->getOptions().smt.produceModels) - << "Cannot get domain elements unless model generation is enabled " + << "cannot get domain elements unless model generation is enabled " "(try --" << internal::options::smt::longName::produceModels << ")"; CVC5_API_RECOVERABLE_CHECK(d_slv->isSmtModeSat()) - << "Cannot get domain elements unless after a SAT or UNKNOWN response."; + << "cannot get domain elements unless after a SAT or UNKNOWN response."; CVC5_API_SOLVER_CHECK_SORT(s); CVC5_API_RECOVERABLE_CHECK(s.isUninterpretedSort()) - << "expecting an uninterpreted sort as argument to " + << "expected an uninterpreted sort as argument to " "getModelDomainElements."; //////// all checks before this line std::vector res; @@ -7997,15 +8031,15 @@ bool Solver::isModelCoreSymbol(const Term& v) const { CVC5_API_TRY_CATCH_BEGIN; CVC5_API_RECOVERABLE_CHECK(d_slv->getOptions().smt.produceModels) - << "Cannot check if model core symbol unless model generation is enabled " + << "cannot check if model core symbol unless model generation is enabled " "(try --" << internal::options::smt::longName::produceModels << ")"; CVC5_API_RECOVERABLE_CHECK(d_slv->isSmtModeSat()) - << "Cannot check if model core symbol unless after a SAT or UNKNOWN " + << "cannot check if model core symbol unless after a SAT or UNKNOWN " "response."; CVC5_API_SOLVER_CHECK_TERM(v); CVC5_API_RECOVERABLE_CHECK(v.getKind() == Kind::CONSTANT) - << "expecting a free constant as argument to isModelCoreSymbol."; + << "expected a free constant as argument to isModelCoreSymbol."; //////// all checks before this line return d_slv->isModelCoreSymbol(v.getNode()); //////// @@ -8017,23 +8051,23 @@ std::string Solver::getModel(const std::vector& sorts, { CVC5_API_TRY_CATCH_BEGIN; CVC5_API_RECOVERABLE_CHECK(d_slv->getOptions().smt.produceModels) - << "Cannot get model unless model generation is enabled " + << "cannot get model unless model generation is enabled " "(try --" << internal::options::smt::longName::produceModels << ")"; CVC5_API_RECOVERABLE_CHECK(d_slv->isSmtModeSat()) - << "Cannot get model unless after a SAT or UNKNOWN response."; + << "cannot get model unless after a SAT or UNKNOWN response."; CVC5_API_SOLVER_CHECK_SORTS(sorts); for (const Sort& s : sorts) { CVC5_API_RECOVERABLE_CHECK(s.isUninterpretedSort()) - << "expecting an uninterpreted sort as argument to " + << "expected an uninterpreted sort as argument to " "getModel."; } CVC5_API_SOLVER_CHECK_TERMS(vars); for (const Term& v : vars) { CVC5_API_RECOVERABLE_CHECK(v.getKind() == Kind::CONSTANT) - << "expecting a free constant as argument to getModel."; + << "expected a free constant as argument to getModel."; } //////// all checks before this line return d_slv->getModel(Sort::sortVectorToTypeNodes(sorts), @@ -8068,10 +8102,10 @@ void Solver::declareSepHeap(const Sort& locSort, const Sort& dataSort) const CVC5_API_SOLVER_CHECK_SORT(locSort); CVC5_API_SOLVER_CHECK_SORT(dataSort); CVC5_API_CHECK(d_slv->isLogicSet()) - << "Cannot call 'declareSepHeap()' if logic is not set"; + << "cannot call 'declareSepHeap()' if logic is not set"; CVC5_API_CHECK( d_slv->getLogicInfo().isTheoryEnabled(internal::theory::THEORY_SEP)) - << "Cannot obtain separation logic expressions if not using the " + << "cannot obtain separation logic expressions if not using the " "separation logic theory."; //////// all checks before this line d_slv->declareSepHeap(locSort.getTypeNode(), dataSort.getTypeNode()); @@ -8084,10 +8118,10 @@ Term Solver::getValueSepHeap() const CVC5_API_TRY_CATCH_BEGIN; CVC5_API_CHECK( d_slv->getLogicInfo().isTheoryEnabled(internal::theory::THEORY_SEP)) - << "Cannot obtain separation logic expressions if not using the " + << "cannot obtain separation logic expressions if not using the " "separation logic theory."; CVC5_API_CHECK(d_slv->getOptions().smt.produceModels) - << "Cannot get separation heap term unless model generation is enabled " + << "cannot get separation heap term unless model generation is enabled " "(try --" << internal::options::smt::longName::produceModels << ")"; CVC5_API_RECOVERABLE_CHECK(d_slv->isSmtModeSat()) @@ -8103,10 +8137,10 @@ Term Solver::getValueSepNil() const CVC5_API_TRY_CATCH_BEGIN; CVC5_API_CHECK( d_slv->getLogicInfo().isTheoryEnabled(internal::theory::THEORY_SEP)) - << "Cannot obtain separation logic expressions if not using the " + << "cannot obtain separation logic expressions if not using the " "separation logic theory."; CVC5_API_CHECK(d_slv->getOptions().smt.produceModels) - << "Cannot get separation nil term unless model generation is enabled " + << "cannot get separation nil term unless model generation is enabled " "(try --" << internal::options::smt::longName::produceModels << ")"; CVC5_API_RECOVERABLE_CHECK(d_slv->isSmtModeSat()) @@ -8145,7 +8179,7 @@ Term Solver::declareOracleFun( CVC5_API_SOLVER_CHECK_DOMAIN_SORTS(sorts); CVC5_API_SOLVER_CHECK_CODOMAIN_SORT(sort); CVC5_API_CHECK(d_slv->getOptions().quantifiers.oracles) - << "Cannot call declareOracleFun unless oracles is enabled (use " + << "cannot call declareOracleFun unless oracles is enabled (use " "--" << internal::options::quantifiers::longName::oracles << ")"; //////// all checks before this line @@ -8181,10 +8215,10 @@ void Solver::pop(uint32_t nscopes) const { CVC5_API_TRY_CATCH_BEGIN; CVC5_API_CHECK(d_slv->getOptions().base.incrementalSolving) - << "Cannot pop when not solving incrementally (use --" + << "cannot pop when not solving incrementally (use --" << internal::options::base::longName::incrementalSolving << ")"; CVC5_API_CHECK(nscopes <= d_slv->getNumUserLevels()) - << "Cannot pop beyond first pushed context"; + << "cannot pop beyond first pushed context"; //////// all checks before this line for (uint32_t n = 0; n < nscopes; ++n) { @@ -8199,7 +8233,7 @@ Term Solver::getInterpolant(const Term& conj) const CVC5_API_TRY_CATCH_BEGIN; CVC5_API_SOLVER_CHECK_TERM(conj); CVC5_API_CHECK(d_slv->getOptions().smt.produceInterpolants) - << "Cannot get interpolant unless interpolants are enabled (try " + << "cannot get interpolant unless interpolants are enabled (try " "--" << internal::options::smt::longName::produceInterpolants << ")"; //////// all checks before this line @@ -8215,13 +8249,13 @@ Term Solver::getInterpolant(const Term& conj, Grammar& grammar) const CVC5_API_TRY_CATCH_BEGIN; CVC5_API_SOLVER_CHECK_TERM(conj); CVC5_API_CHECK(d_slv->getOptions().smt.produceInterpolants) - << "Cannot get interpolant unless interpolants are enabled (try " + << "cannot get interpolant unless interpolants are enabled (try " "--" << internal::options::smt::longName::produceInterpolants << ")"; for (const auto& sym : grammar.d_sg->getNtSyms()) { CVC5_API_CHECK(!grammar.d_sg->getRulesFor(sym).empty()) - << "Invalid grammar, must have at least one rule for each " + << "invalid grammar, must have at least one rule for each " "non-terminal symbol"; } //////// all checks before this line @@ -8236,11 +8270,11 @@ Term Solver::getInterpolantNext() const { CVC5_API_TRY_CATCH_BEGIN; CVC5_API_CHECK(d_slv->getOptions().smt.produceInterpolants) - << "Cannot get interpolant unless interpolants are enabled (try " + << "cannot get interpolant unless interpolants are enabled (try " "--" << internal::options::smt::longName::produceInterpolants << ")"; CVC5_API_CHECK(d_slv->getOptions().base.incrementalSolving) - << "Cannot get next interpolant when not solving incrementally (try " + << "cannot get next interpolant when not solving incrementally (try " "--" << internal::options::base::longName::incrementalSolving << ")"; //////// all checks before this line @@ -8255,7 +8289,7 @@ Term Solver::getAbduct(const Term& conj) const CVC5_API_TRY_CATCH_BEGIN; CVC5_API_SOLVER_CHECK_TERM(conj); CVC5_API_CHECK(d_slv->getOptions().smt.produceAbducts) - << "Cannot get abduct unless abducts are enabled (try --" + << "cannot get abduct unless abducts are enabled (try --" << internal::options::smt::longName::produceAbducts << ")"; //////// all checks before this line internal::TypeNode nullType; @@ -8270,12 +8304,12 @@ Term Solver::getAbduct(const Term& conj, Grammar& grammar) const CVC5_API_TRY_CATCH_BEGIN; CVC5_API_SOLVER_CHECK_TERM(conj); CVC5_API_CHECK(d_slv->getOptions().smt.produceAbducts) - << "Cannot get abduct unless abducts are enabled (try --" + << "cannot get abduct unless abducts are enabled (try --" << internal::options::smt::longName::produceAbducts << ")"; for (const auto& sym : grammar.d_sg->getNtSyms()) { CVC5_API_CHECK(!grammar.d_sg->getRulesFor(sym).empty()) - << "Invalid grammar, must have at least one rule for each " + << "invalid grammar, must have at least one rule for each " "non-terminal symbol"; } //////// all checks before this line @@ -8290,11 +8324,11 @@ Term Solver::getAbductNext() const { CVC5_API_TRY_CATCH_BEGIN; CVC5_API_CHECK(d_slv->getOptions().smt.produceAbducts) - << "Cannot get next abduct unless abducts are enabled (try " + << "cannot get next abduct unless abducts are enabled (try " "--" << internal::options::smt::longName::produceAbducts << ")"; CVC5_API_CHECK(d_slv->getOptions().base.incrementalSolving) - << "Cannot get next abduct when not solving incrementally (try " + << "cannot get next abduct when not solving incrementally (try " "--" << internal::options::base::longName::incrementalSolving << ")"; //////// all checks before this line @@ -8308,7 +8342,7 @@ void Solver::blockModel(modes::BlockModelsMode mode) const { CVC5_API_TRY_CATCH_BEGIN; CVC5_API_CHECK(d_slv->getOptions().smt.produceModels) - << "Cannot get value unless model generation is enabled " + << "cannot get value unless model generation is enabled " "(try --" << internal::options::smt::longName::produceModels << ")"; CVC5_API_RECOVERABLE_CHECK(d_slv->isSmtModeSat()) @@ -8323,7 +8357,7 @@ void Solver::blockModelValues(const std::vector& terms) const { CVC5_API_TRY_CATCH_BEGIN; CVC5_API_CHECK(d_slv->getOptions().smt.produceModels) - << "Cannot get value unless model generation is enabled " + << "cannot get value unless model generation is enabled " "(try --" << internal::options::smt::longName::produceModels << ")"; CVC5_API_RECOVERABLE_CHECK(d_slv->isSmtModeSat()) @@ -8345,7 +8379,7 @@ std::string Solver::getInstantiations() const || d_slv->getSmtMode() == internal::SmtMode::SAT || d_slv->getSmtMode() == internal::SmtMode::SAT_UNKNOWN) - << "Cannot get instantiations unless after a UNSAT, SAT or UNKNOWN " + << "cannot get instantiations unless after a UNSAT, SAT or UNKNOWN " "response."; //////// all checks before this line std::stringstream ss; @@ -8359,7 +8393,7 @@ void Solver::push(uint32_t nscopes) const { CVC5_API_TRY_CATCH_BEGIN; CVC5_API_CHECK(d_slv->getOptions().base.incrementalSolving) - << "Cannot push when not solving incrementally (use --" + << "cannot push when not solving incrementally (use --" << internal::options::base::longName::incrementalSolving << ")"; //////// all checks before this line for (uint32_t n = 0; n < nscopes; ++n) @@ -8415,9 +8449,9 @@ void Solver::setLogic(const std::string& logic) const { CVC5_API_TRY_CATCH_BEGIN; CVC5_API_CHECK(!d_slv->isLogicSet()) - << "Invalid call to 'setLogic', logic is already set"; + << "invalid call to 'setLogic', logic is already set"; CVC5_API_CHECK(!d_slv->isFullyInited()) - << "Invalid call to 'setLogic', solver is already fully initialized"; + << "invalid call to 'setLogic', solver is already fully initialized"; //////// all checks before this line internal::LogicInfo linfo(logic); d_slv->setLogic(linfo); @@ -8438,7 +8472,7 @@ std::string Solver::getLogic() const { CVC5_API_TRY_CATCH_BEGIN; CVC5_API_CHECK(d_slv->isLogicSet()) - << "Invalid call to 'getLogic', logic has not yet been set"; + << "invalid call to 'getLogic', logic has not yet been set"; //////// all checks before this line return d_slv->getUserLogicInfo().getLogicString(); //////// @@ -8467,7 +8501,7 @@ void Solver::setOption(const std::string& option, == mutableOpts.end()) { CVC5_API_CHECK(!d_slv->isFullyInited()) - << "Invalid call to 'setOption' for option '" << option + << "invalid call to 'setOption' for option '" << option << "', solver is already fully initialized"; } //////// all checks before this line @@ -8482,7 +8516,7 @@ Term Solver::declareSygusVar(const std::string& symbol, const Sort& sort) const CVC5_API_TRY_CATCH_BEGIN; CVC5_API_SOLVER_CHECK_SORT(sort); CVC5_API_CHECK(d_slv->getOptions().quantifiers.sygus) - << "Cannot call declareSygusVar unless sygus is enabled (use --" + << "cannot call declareSygusVar unless sygus is enabled (use --" << internal::options::quantifiers::longName::sygus << ")"; //////// all checks before this line internal::Node res = d_tm.mkVarHelper(*sort.d_type, symbol); @@ -8514,7 +8548,7 @@ Term Solver::synthFun(const std::string& symbol, CVC5_API_SOLVER_CHECK_BOUND_VARS(boundVars); CVC5_API_SOLVER_CHECK_SORT(sort); CVC5_API_CHECK(d_slv->getOptions().quantifiers.sygus) - << "Cannot call synthFun unless sygus is enabled (use --" + << "cannot call synthFun unless sygus is enabled (use --" << internal::options::quantifiers::longName::sygus << ")"; //////// all checks before this line return synthFunHelper(symbol, boundVars, sort); @@ -8531,7 +8565,7 @@ Term Solver::synthFun(const std::string& symbol, CVC5_API_SOLVER_CHECK_BOUND_VARS(boundVars); CVC5_API_SOLVER_CHECK_SORT(sort); CVC5_API_CHECK(d_slv->getOptions().quantifiers.sygus) - << "Cannot call synthFun unless sygus is enabled (use --" + << "cannot call synthFun unless sygus is enabled (use --" << internal::options::quantifiers::longName::sygus << ")"; //////// all checks before this line return synthFunHelper(symbol, boundVars, sort, false, &grammar); @@ -8547,7 +8581,7 @@ void Solver::addSygusConstraint(const Term& term) const term.d_node->getType() == d_tm.d_nm->booleanType(), term) << "boolean term"; CVC5_API_CHECK(d_slv->getOptions().quantifiers.sygus) - << "Cannot addSygusConstraint unless sygus is enabled (use --" + << "cannot addSygusConstraint unless sygus is enabled (use --" << internal::options::quantifiers::longName::sygus << ")"; //////// all checks before this line d_slv->assertSygusConstraint(*term.d_node, false); @@ -8573,7 +8607,7 @@ void Solver::addSygusAssume(const Term& term) const term.d_node->getType() == d_tm.d_nm->booleanType(), term) << "boolean term"; CVC5_API_CHECK(d_slv->getOptions().quantifiers.sygus) - << "Cannot addSygusAssume unless sygus is enabled (use --" + << "cannot addSygusAssume unless sygus is enabled (use --" << internal::options::quantifiers::longName::sygus << ")"; //////// all checks before this line d_slv->assertSygusConstraint(*term.d_node, true); @@ -8616,7 +8650,7 @@ void Solver::addSygusInvConstraint(const Term& inv, CVC5_API_CHECK(post.d_node->getType() == invType) << "expected inv and post to have the same sort"; CVC5_API_CHECK(d_slv->getOptions().quantifiers.sygus) - << "Cannot addSygusInvConstraint unless sygus is enabled (use --" + << "cannot addSygusInvConstraint unless sygus is enabled (use --" << internal::options::quantifiers::longName::sygus << ")"; //////// all checks before this line @@ -8648,11 +8682,11 @@ SynthResult Solver::checkSynth() const { CVC5_API_TRY_CATCH_BEGIN; CVC5_API_CHECK(d_slv->getOptions().quantifiers.sygus) - << "Cannot checkSynth unless sygus is enabled (use --" + << "cannot checkSynth unless sygus is enabled (use --" << internal::options::quantifiers::longName::sygus << ")"; CVC5_API_CHECK(!d_slv->isQueryMade() || d_slv->getOptions().base.incrementalSolving) - << "Cannot make multiple checkSynth calls unless incremental solving is " + << "cannot make multiple checkSynth calls unless incremental solving is " "enabled (try --" << internal::options::base::longName::incrementalSolving << ")"; //////// all checks before this line @@ -8665,10 +8699,10 @@ SynthResult Solver::checkSynthNext() const { CVC5_API_TRY_CATCH_BEGIN; CVC5_API_CHECK(d_slv->getOptions().quantifiers.sygus) - << "Cannot checkSynthNext unless sygus is enabled (use --" + << "cannot checkSynthNext unless sygus is enabled (use --" << internal::options::quantifiers::longName::sygus << ")"; CVC5_API_CHECK(d_slv->getOptions().base.incrementalSolving) - << "Cannot checkSynthNext when not solving incrementally (use " + << "cannot checkSynthNext when not solving incrementally (use " "--" << internal::options::base::longName::incrementalSolving << ")"; //////// all checks before this line @@ -8744,7 +8778,7 @@ Term Solver::findSynth(modes::FindSynthTarget fst, Grammar& grammar) const for (const auto& sym : grammar.d_sg->getNtSyms()) { CVC5_API_CHECK(!grammar.d_sg->getRulesFor(sym).empty()) - << "Invalid grammar, must have at least one rule for each " + << "invalid grammar, must have at least one rule for each " "non-terminal symbol"; } //////// all checks before this line @@ -8778,7 +8812,7 @@ bool Solver::isOutputOn(const std::string& tag) const } catch (const internal::Exception& e) { - throw CVC5ApiException("Invalid output tag " + tag); + throw CVC5ApiException("invalid output tag " + tag); } } @@ -8793,7 +8827,7 @@ std::ostream& Solver::getOutput(const std::string& tag) const } catch (const internal::Exception& e) { - throw CVC5ApiException("Invalid output tag " + tag); + throw CVC5ApiException("invalid output tag " + tag); } } @@ -8891,4 +8925,9 @@ size_t hash::operator()(const cvc5::Datatype& dt) const return std::hash()(*dt.d_dtype); } +size_t std::hash::operator()(const cvc5::Proof& p) const +{ + return cvc5::internal::ProofNodeHashFunction()(p.d_proofNode); +} + } // namespace std diff --git a/src/api/cpp/cvc5_checks.h b/src/api/cpp/cvc5_checks.h index 7694c0b7886..b318ec67d41 100644 --- a/src/api/cpp/cvc5_checks.h +++ b/src/api/cpp/cvc5_checks.h @@ -155,24 +155,24 @@ class CVC5ApiUnsupportedExceptionStream /** Check it 'this' is not a null object. */ #define CVC5_API_CHECK_NOT_NULL \ CVC5_API_CHECK(!isNullHelper()) \ - << "Invalid call to '" << __PRETTY_FUNCTION__ \ - << "', expected non-null object"; + << "invalid call to '" << __PRETTY_FUNCTION__ \ + << "', expected non-null object" /** Check if given argument is not a null object. */ #define CVC5_API_ARG_CHECK_NOT_NULL(arg) \ - CVC5_API_CHECK(!arg.isNull()) << "Invalid null argument for '" << #arg << "'"; + CVC5_API_CHECK(!arg.isNull()) << "invalid null argument for '" << #arg << "'"; /** Check if given argument is not a null pointer. */ #define CVC5_API_ARG_CHECK_NOT_NULLPTR(arg) \ CVC5_API_CHECK(arg != nullptr) \ - << "Invalid null argument for '" << #arg << "'"; + << "invalid null argument for '" << #arg << "'" /** * Check if given argument at given index in container 'args' is not a null * object. */ #define CVC5_API_ARG_AT_INDEX_CHECK_NOT_NULL(what, arg, args, idx) \ - CVC5_API_CHECK(!arg.isNull()) << "Invalid null " << (what) << " in '" \ - << #args << "' at index " << (idx); + CVC5_API_CHECK(!arg.isNull()) << "invalid null " << (what) << " in '" \ + << #args << "' at index " << (idx) /* -------------------------------------------------------------------------- */ /* Kind checks. */ @@ -181,7 +181,7 @@ class CVC5ApiUnsupportedExceptionStream /** Check if given kind is a valid kind. */ #define CVC5_API_KIND_CHECK(kind) \ CVC5_API_CHECK(isDefinedKind(kind)) \ - << "Invalid kind '" << std::to_string(kind) << "'"; + << "invalid kind '" << std::to_string(kind) << "'" /** * Check if given kind is a valid kind. @@ -193,7 +193,7 @@ class CVC5ApiUnsupportedExceptionStream ? (void)0 \ : cvc5::internal::OstreamVoider() \ & CVC5ApiExceptionStream().ostream() \ - << "Invalid kind '" << std::to_string(kind) << "', expected " + << "invalid kind '" << std::to_string(kind) << "', expected " /* -------------------------------------------------------------------------- */ /* Argument checks. */ @@ -209,7 +209,7 @@ class CVC5ApiUnsupportedExceptionStream ? (void)0 \ : cvc5::internal::OstreamVoider() \ & CVC5ApiExceptionStream().ostream() \ - << "Invalid argument '" << arg << "' for '" << #arg \ + << "invalid argument '" << arg << "' for '" << #arg \ << "', expected " /** @@ -222,7 +222,7 @@ class CVC5ApiUnsupportedExceptionStream ? (void)0 \ : cvc5::internal::OstreamVoider() \ & CVC5ApiRecoverableExceptionStream().ostream() \ - << "Invalid argument '" << arg << "' for '" << #arg \ + << "invalid argument '" << arg << "' for '" << #arg \ << "', expected " /** @@ -237,7 +237,7 @@ class CVC5ApiUnsupportedExceptionStream ? (void)0 \ : cvc5::internal::OstreamVoider() \ & CVC5ApiExceptionStream().ostream() \ - << "Invalid size of argument '" << #arg << "', expected " + << "invalid size of argument '" << #arg << "', expected " /** * Check condition 'cond' for the argument at given index in container 'args'. @@ -253,7 +253,7 @@ class CVC5ApiUnsupportedExceptionStream ? (void)0 \ : cvc5::internal::OstreamVoider() \ & CVC5ApiExceptionStream().ostream() \ - << "Invalid " << (what) << " in '" << #args << "' at index " \ + << "invalid " << (what) << " in '" << #args << "' at index " \ << (idx) << ", expected " /** @@ -267,7 +267,7 @@ class CVC5ApiUnsupportedExceptionStream ? (void)0 \ : cvc5::internal::OstreamVoider() \ & CVC5ApiExceptionStream().ostream() \ - << "Invalid value '" << args[index] << "' at index " << index \ + << "invalid value '" << args[index] << "' at index " << index \ << " for operator, expected " /* -------------------------------------------------------------------------- */ @@ -283,7 +283,7 @@ class CVC5ApiUnsupportedExceptionStream CVC5_API_CHECK(d_tm->d_nm == arg.d_tm->d_nm) \ << "Given " << (what) \ << " is not associated with the term manager this " \ - << "object is associated with"; + << "object is associated with" /* -------------------------------------------------------------------------- */ /* Sort checks. */ @@ -460,7 +460,7 @@ class CVC5ApiUnsupportedExceptionStream "associated " \ "with"; \ CVC5_API_CHECK(t1.getSort() == t2.getSort()) \ - << "Expecting terms of the same sort at index " << i; \ + << "expecting terms of the same sort at index " << i; \ i += 1; \ } \ } while (0) @@ -494,7 +494,7 @@ class CVC5ApiUnsupportedExceptionStream */ #define CVC5_API_ARG_TM_CHECK_TM(what, arg) \ CVC5_API_CHECK(d_nm == arg.d_tm->d_nm) \ - << "Given " << (what) << " is not associated with this term manager"; + << "Given " << (what) << " is not associated with this term manager" /** * Sort check for member functions of class TermManager. * Check if given sort is not null and associated with this term manager. @@ -927,7 +927,7 @@ class CVC5ApiUnsupportedExceptionStream */ #define CVC5_API_OP_CHECK_ARITY(nargs, expected, kind) \ CVC5_API_CHECK(nargs == expected) \ - << "Invalid number of indices for operator " << kind << ". Expected " \ + << "invalid number of indices for operator " << kind << ", expected " \ << expected << " but got " << nargs << "." } // namespace cvc5 diff --git a/src/api/cpp/cvc5_proof_rule_template.cpp b/src/api/cpp/cvc5_proof_rule_template.cpp index 66c31043c46..966764b2a04 100644 --- a/src/api/cpp/cvc5_proof_rule_template.cpp +++ b/src/api/cpp/cvc5_proof_rule_template.cpp @@ -151,10 +151,10 @@ const char* toString(ProofRule rule) case ProofRule::RE_UNFOLD_NEG: return "RE_UNFOLD_NEG"; case ProofRule::RE_UNFOLD_NEG_CONCAT_FIXED: return "RE_UNFOLD_NEG_CONCAT_FIXED"; - case ProofRule::RE_ELIM: return "RE_ELIM"; case ProofRule::STRING_CODE_INJ: return "STRING_CODE_INJ"; case ProofRule::STRING_SEQ_UNIT_INJ: return "STRING_SEQ_UNIT_INJ"; case ProofRule::MACRO_STRING_INFERENCE: return "MACRO_STRING_INFERENCE"; + case ProofRule::MACRO_RE_ELIM: return "MACRO_RE_ELIM"; //================================================= Arith rules case ProofRule::MACRO_ARITH_SCALE_SUM_UB: return "MACRO_ARITH_SCALE_SUM_UB"; case ProofRule::ARITH_SUM_UB: return "ARITH_SUM_UB"; @@ -196,9 +196,6 @@ const char* toString(ProofRule rule) return "ARITH_TRANS_SINE_APPROX_BELOW_NEG"; case ProofRule::ARITH_TRANS_SINE_APPROX_BELOW_POS: return "ARITH_TRANS_SINE_APPROX_BELOW_POS"; - case ProofRule::ARITH_NL_COVERING_DIRECT: return "ARITH_NL_COVERING_DIRECT"; - case ProofRule::ARITH_NL_COVERING_RECURSIVE: - return "ARITH_NL_COVERING_RECURSIVE"; //================================================= External rules case ProofRule::LFSC_RULE: return "LFSC_RULE"; case ProofRule::ALETHE_RULE: return "ALETHE_RULE"; @@ -243,9 +240,15 @@ const char* toString(cvc5::ProofRewriteRule rule) case ProofRewriteRule::DT_COLLAPSE_TESTER_SINGLETON: return "dt-collapse-tester-singleton"; case ProofRewriteRule::DT_CONS_EQ: return "dt-cons-eq"; + case ProofRewriteRule::BV_UMULO_ELIMINATE: return "bv-umulo-eliminate"; + case ProofRewriteRule::BV_SMULO_ELIMINATE: return "bv-smulo-eliminate"; + case ProofRewriteRule::BV_ADD_COMBINE_LIKE_TERMS: return "bv-add-combine-like-terms"; + case ProofRewriteRule::BV_MULT_SIMPLIFY: return "bv-mult-simplify"; + case ProofRewriteRule::BV_BITWISE_SLICING: return "bv-bitwise-slicing"; case ProofRewriteRule::RE_LOOP_ELIM: return "re-loop-elim"; case ProofRewriteRule::STR_IN_RE_EVAL: return "str-in-re-eval"; + case ProofRewriteRule::STR_IN_RE_CONSUME: return "str-in-re-consume"; case ProofRewriteRule::STR_IN_RE_CONCAT_STAR_CHAR: return "str-in-re-concat-star-char"; case ProofRewriteRule::STR_IN_RE_SIGMA: return "str-in-re-sigma"; diff --git a/src/api/java/io/github/cvc5/Proof.java b/src/api/java/io/github/cvc5/Proof.java index 347f485a6f3..a73db436290 100644 --- a/src/api/java/io/github/cvc5/Proof.java +++ b/src/api/java/io/github/cvc5/Proof.java @@ -22,6 +22,16 @@ */ public class Proof implements IPointer { + /** + * Null proof + */ + public Proof() + { + this(getNullProof()); + } + + private static native long getNullProof(); + Proof(long pointer) { this.pointer = pointer; @@ -99,4 +109,41 @@ public Term[] getArguments() } private native long[] getArguments(long pointer); + + /** + * Referential equality operator. + * Return `true` if both proofs point to the same internal proof object. + * + * @param p The proof to compare to for equality. + * @return `true` if the proofs are equal. + */ + @Override + public boolean equals(Object p) + { + if (this == p) + { + return true; + } + if (p == null || getClass() != p.getClass()) + { + return false; + } + Proof proof = (Proof) p; + if (pointer == proof.pointer) + { + return true; + } + return equals(pointer, proof.getPointer()); + } + + private native boolean equals(long pointer1, long pointer2); + + /** @return The hash value of the proof. */ + @Override + public int hashCode() + { + return hashCode(pointer); + } + + private native int hashCode(long pointer); } diff --git a/src/api/java/io/github/cvc5/TermManager.java b/src/api/java/io/github/cvc5/TermManager.java index fba0194c907..455dd68b083 100644 --- a/src/api/java/io/github/cvc5/TermManager.java +++ b/src/api/java/io/github/cvc5/TermManager.java @@ -317,6 +317,40 @@ public Sort mkParamSort() private native long mkParamSort(long pointer); + /** + * Create a skolem + * + * @api.note This method is experimental and may change in future versions. + * + * @param skolemId The id of the skolem. + * @param indices The indices of the skolem. + * @return The skolem. + */ + public Term mkSkolem(SkolemId skolemId, Term[] indices) + { + long skolemPointer = mkSkolem(pointer, skolemId.getValue(), Utils.getPointers(indices)); + return new Term(skolemPointer); + } + + private native long mkSkolem(long pointer, int skolemId, long[] indices); + + /** + * Get the number of indices for a given skolem id. + * + * @api.note This method is experimental and may change in future versions. + * + * @param id The skolem id. + * @return The number of indices for the given skolem id. + */ + + public int getNumIndicesForSkolemId(SkolemId id) + { + int numIndices = getNumIndicesForSkolemId(pointer, id.getValue()); + return numIndices; + } + + private native int getNumIndicesForSkolemId(long pointer, int skolemId); + /** * Create a predicate sort. * @param sorts The list of sorts of the predicate. diff --git a/src/api/java/jni/proof.cpp b/src/api/java/jni/proof.cpp index 3a67b9e591c..9f9be1da33c 100644 --- a/src/api/java/jni/proof.cpp +++ b/src/api/java/jni/proof.cpp @@ -22,6 +22,20 @@ using namespace cvc5; +/* + * Class: io_github_cvc5_Proof + * Method: getNullProof + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_io_github_cvc5_Proof_getNullProof(JNIEnv* env, + jclass) +{ + CVC5_JAVA_API_TRY_CATCH_BEGIN; + Proof* ret = new Proof(); + return reinterpret_cast(ret); + CVC5_JAVA_API_TRY_CATCH_END_RETURN(env, 0); +} + /* * Class: io_github_cvc5_Proof * Method: deletePointer @@ -111,3 +125,36 @@ Java_io_github_cvc5_Proof_getArguments(JNIEnv* env, jobject, jlong pointer) return ret; CVC5_JAVA_API_TRY_CATCH_END_RETURN(env, 0); } + +/* + * Class: io_github_cvc5_Proof + * Method: equals + * Signature: (JJ)Z + */ +JNIEXPORT jboolean JNICALL Java_io_github_cvc5_Proof_equals(JNIEnv* env, + jobject, + jlong pointer1, + jlong pointer2) +{ + CVC5_JAVA_API_TRY_CATCH_BEGIN; + Proof* proof1 = reinterpret_cast(pointer1); + Proof* proof2 = reinterpret_cast(pointer2); + // We compare the actual proofs, not their pointers. + return static_cast(*proof1 == *proof2); + CVC5_JAVA_API_TRY_CATCH_END_RETURN(env, static_cast(false)); +} + +/* + * Class: io_github_cvc5_Proof + * Method: hashCode + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_io_github_cvc5_Proof_hashCode(JNIEnv* env, + jobject, + jlong pointer) +{ + CVC5_JAVA_API_TRY_CATCH_BEGIN; + Proof* current = reinterpret_cast(pointer); + return static_cast(std::hash()(*current)); + CVC5_JAVA_API_TRY_CATCH_END_RETURN(env, 0); +} diff --git a/src/api/java/jni/term_manager.cpp b/src/api/java/jni/term_manager.cpp index 31f2303871b..29fe178ea1c 100644 --- a/src/api/java/jni/term_manager.cpp +++ b/src/api/java/jni/term_manager.cpp @@ -309,6 +309,41 @@ Java_io_github_cvc5_TermManager_mkParamSort__JLjava_lang_String_2( CVC5_JAVA_API_TRY_CATCH_END_RETURN(env, 0); } +/* + * Class: io_github_cvc5_TermManager + * Method: mkSkolem + * Signature: (JI[J)J + */ +JNIEXPORT jlong JNICALL Java_io_github_cvc5_TermManager_mkSkolem( + JNIEnv* env, jobject, jlong pointer, jint jSkolemId, jlongArray jIndices) +{ + CVC5_JAVA_API_TRY_CATCH_BEGIN; + TermManager* tm = reinterpret_cast(pointer); + SkolemId id = static_cast(jSkolemId); + std::vector indices = getObjectsFromPointers(env, jIndices); + Term* retPointer = new Term(tm->mkSkolem(id, indices)); + return reinterpret_cast(retPointer); + + CVC5_JAVA_API_TRY_CATCH_END_RETURN(env, 0); +} + +/* + * Class: io_github_cvc5_TermManager + * Method: getNumIndicesForSkolemId + * Signature: (JI)I + */ +JNIEXPORT jint JNICALL Java_io_github_cvc5_TermManager_getNumIndicesForSkolemId( + JNIEnv* env, jobject, jlong pointer, jint jSkolemId) +{ + CVC5_JAVA_API_TRY_CATCH_BEGIN; + TermManager* tm = reinterpret_cast(pointer); + SkolemId id = static_cast(jSkolemId); + int numIndices = tm->getNumIndicesForSkolemId(id); + return numIndices; + + CVC5_JAVA_API_TRY_CATCH_END_RETURN(env, 0); +} + /* * Class: io_github_cvc5_TermManager * Method: mkParamSort diff --git a/src/api/python/CMakeLists.txt b/src/api/python/CMakeLists.txt index c1118464626..7657cf15423 100644 --- a/src/api/python/CMakeLists.txt +++ b/src/api/python/CMakeLists.txt @@ -14,9 +14,16 @@ ## if(NOT ONLY_PYTHON_EXT_SRC) - # Python modules for building and installing + # Python modules for building: check_python_module("setuptools") find_package(Cython 3.0.0 REQUIRED) + # Python modules for installing: + find_package(Pip 23.0 REQUIRED) + # Repairwheel copies the required shared libraries to + # a directory within the Python wheel package so that + # the package is self-contained. It works on Linux, + # macOS, and Windows. + find_package(Repairwheel 0.2.9 REQUIRED) endif() configure_file(genenums.py.in genenums.py) @@ -110,6 +117,7 @@ if (WIN32) set(PYTHON_EXT "pyd") set(SETUP_INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/include;${CMAKE_BINARY_DIR}/include") set(SETUP_LIBRARY_DIRS "${CMAKE_BINARY_DIR}/src;${CMAKE_BINARY_DIR}/src/parser") + set(SETUP_COMPILER "[build]\ncompiler=mingw32") else() set(PYTHON_EXT "so") set(SETUP_INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/include:${CMAKE_BINARY_DIR}/include") @@ -224,8 +232,17 @@ else() ${LICENSE_FILES} ) + set(BUILD_WHEEL_CMD + "${Python_EXECUTABLE} -m pip wheel ${CMAKE_CURRENT_BINARY_DIR} " + "${BUILD_WHEEL_CMD} --wheel-dir=${CMAKE_BINARY_DIR}/unrepaired-wheel") + + set(REPAIR_WHEEL_CMD + "${Repairwheel_EXECUTABLE} -o ${CMAKE_BINARY_DIR}/repaired-wheel " + "-l ${CMAKE_BINARY_DIR}/src -l ${CMAKE_BINARY_DIR}/src/parser " + "-l ${DEPS_BASE}/bin") + set(INSTALL_CMD - "${Python_BASE_EXECUTABLE} -m pip install ${CMAKE_CURRENT_BINARY_DIR}") + "${Python_BASE_EXECUTABLE} -m pip install") # If the user does not set a prefix, install the Python bindings in # the default location designated by the Python interpreter used to @@ -234,9 +251,28 @@ else() set(INSTALL_CMD "${INSTALL_CMD} --prefix ${CMAKE_INSTALL_PREFIX}") endif() - message("Python bindings install command: ${INSTALL_CMD}") + set(UNREPAIRED_WHEEL_DIR ${CMAKE_BINARY_DIR}/unrepaired-wheel) + set(REPAIRED_WHEEL_DIR ${CMAKE_BINARY_DIR}/repaired-wheel) + + # Remove previous wheel directories + install(CODE "execute_process(COMMAND \${CMAKE_COMMAND} -E remove_directory + ${UNREPAIRED_WHEEL_DIR} ${REPAIRED_WHEEL_DIR})" + FILE_PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ) + + # Build wheel + install(CODE "execute_process(COMMAND ${BUILD_WHEEL_CMD})" + FILE_PERMISSIONS OWNER_WRITE OWNER_READ) + + # Repair wheel (include required libraries) + install(CODE + "file(GLOB WHL_FILE ${UNREPAIRED_WHEEL_DIR}/cvc5*.whl) + execute_process(COMMAND ${REPAIR_WHEEL_CMD} \${WHL_FILE})" + FILE_PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ) - install(CODE "execute_process(COMMAND ${INSTALL_CMD})" + # Install wheel + install(CODE + "file(GLOB WHL_FILE ${REPAIRED_WHEEL_DIR}/cvc5*.whl) + execute_process(COMMAND ${INSTALL_CMD} \${WHL_FILE})" FILE_PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ) endif() diff --git a/src/api/python/cvc5.pxd b/src/api/python/cvc5.pxd index d43f1cb9e1c..32b877d8637 100644 --- a/src/api/python/cvc5.pxd +++ b/src/api/python/cvc5.pxd @@ -232,6 +232,8 @@ cdef extern from "" namespace "cvc5": Sort mkFunctionSort(const vector[Sort]& sorts, Sort codomain) except + Sort mkParamSort() except + Sort mkParamSort(const string& symbol) except + + Term mkSkolem(SkolemId id, const vector[Term]& indices) except + + size_t getNumIndicesForSkolemId(SkolemId id) except + Sort mkPredicateSort(const vector[Sort]& sorts) except + Sort mkRecordSort(const vector[pair[string, Sort]]& fields) except + Sort mkSetSort(Sort elemSort) except + @@ -322,6 +324,8 @@ cdef extern from "" namespace "cvc5": Sort mkFunctionSort(const vector[Sort]& sorts, Sort codomain) except + Sort mkParamSort() except + Sort mkParamSort(const string& symbol) except + + Term mkSkolem(SkolemId id, const vector[Term]& indices) except + + size_t getNumIndicesForSkolemId(SkolemId id) except + Sort mkPredicateSort(const vector[Sort]& sorts) except + Sort mkRecordSort(const vector[pair[string, Sort]]& fields) except + Sort mkSetSort(Sort elemSort) except + @@ -670,12 +674,18 @@ cdef extern from "" namespace "cvc5": size_t operator()(const Term & t) except + cdef cppclass Proof: + bint operator==(const Proof&) except + + bint operator!=(const Proof&) except + ProofRule getRule() except + ProofRewriteRule getRewriteRule() except + Term getResult() except + vector[Proof] getChildren() except + vector[Term] getArguments() except + + cdef cppclass ProofHashFunction: + ProofHashFunction() except + + size_t operator()(const Proof&) except + + cdef extern from "" namespace "cvc5::parser": cdef cppclass SymbolManager: diff --git a/src/api/python/cvc5.pxi b/src/api/python/cvc5.pxi index 34e7ea6046d..099ea5ab8a9 100644 --- a/src/api/python/cvc5.pxi +++ b/src/api/python/cvc5.pxi @@ -158,6 +158,7 @@ cdef Proof _proof(tm: TermManager, proof: c_Proof): cdef c_hash[c_Op] cophash = c_hash[c_Op]() cdef c_hash[c_Sort] csorthash = c_hash[c_Sort]() cdef c_hash[c_Term] ctermhash = c_hash[c_Term]() +cdef c_hash[c_Proof] cproofhash = c_hash[c_Proof]() # ---------------------------------------------------------------------------- # SymbolManager @@ -1308,6 +1309,34 @@ cdef class TermManager: return _sort(self, self.ctm.mkParamSort()) return _sort(self, self.ctm.mkParamSort(symbolname.encode())) + def mkSkolem(self, id, *indices): + """ + Create a skolem. + + .. warning:: This function is experimental and may change in future + versions. + + :param id: The skolem id. + :param indices: The indices for the skolem. + :return: The skolem with the given id and indices. + """ + cdef vector[c_Term] v + for t in indices: + v.push_back(( t).cterm) + return _term(self, self.ctm.mkSkolem( id.value, v)) + + def getNumIndicesForSkolemId(self, id): + """ + Get the number of indices for a skolem id. + + .. warning:: This function is experimental and may change in future + versions. + + :param id: The skolem id. + :return: The number of indice for a skolem with the given id. + """ + return self.ctm.getNumIndicesForSkolemId( id.value) + def mkPredicateSort(self, *sorts): """ Create a predicate sort. @@ -2250,6 +2279,25 @@ cdef class Solver: """ return self.tm.mkParamSort(symbolname) + def mkSkolem(self, id, *indices): + """ + Create a skolem. + + :param id: The skolem id. + :param indices: The indices for the skolem. + :return: The skolem with the given id and indices. + """ + return self.tm.mkSkolem(id, indices) + + def getNumIndicesForSkolemId(self, id): + """ + Get the number of indices for a skolem id. + + :param id: The skolem id. + :return: The number of indice for a skolem with the given id. + """ + return self.tm.getNumIndicesForSkolemId(id) + def mkPredicateSort(self, *sorts): """ Create a predicate sort. @@ -5671,6 +5719,15 @@ cdef class Proof: cdef c_Proof cproof cdef TermManager tm + def __eq__(self, Proof other): + return self.cproof == other.cproof + + def __ne__(self, Proof other): + return self.cproof != other.cproof + + def __hash__(self): + return cproofhash(self.cproof) + def getRule(self): """ :return: The proof rule used by the root step of the proof. @@ -5709,4 +5766,3 @@ cdef class Proof: for a in self.cproof.getArguments(): args.append(_term(self.tm, a)) return args - diff --git a/src/api/python/setup.cfg.in b/src/api/python/setup.cfg.in index f79cb06d2f1..218e51eb571 100644 --- a/src/api/python/setup.cfg.in +++ b/src/api/python/setup.cfg.in @@ -1,4 +1,5 @@ [build_ext] include_dirs=${SETUP_INCLUDE_DIRS} library_dirs=${SETUP_LIBRARY_DIRS} -${SETUP_RPATH} \ No newline at end of file +${SETUP_RPATH} +${SETUP_COMPILER} diff --git a/src/expr/attribute.h b/src/expr/attribute.h index f2c37071695..5c74c1ee886 100644 --- a/src/expr/attribute.h +++ b/src/expr/attribute.h @@ -464,12 +464,7 @@ AttributeManager::setAttribute(NodeValue* nv, template inline void AttributeManager::deleteFromTable(AttrHash& table, NodeValue* nv) { - // This cannot use nv as anything other than a pointer! - const uint64_t last = attr::LastAttributeId::getId(); - for (uint64_t id = 0; id < last; ++id) - { - table.erase(std::make_pair(id, nv)); - } + table.eraseBy(nv); } /** Remove all attributes from the table. */ @@ -506,9 +501,7 @@ void AttributeManager::deleteAttributesFromTable(AttrHash& table, const std:: uint64_t id = (*it).first.first; if(std::binary_search(begin_ids, end_ids, id)){ - tmp = it; - ++it; - table.erase(tmp); + it = table.erase(it); }else{ ++it; } diff --git a/src/expr/attribute_internals.h b/src/expr/attribute_internals.h index 3546f8683ee..cce4f1e1047 100644 --- a/src/expr/attribute_internals.h +++ b/src/expr/attribute_internals.h @@ -13,6 +13,10 @@ * Node attributes' internals. */ +#include +#include +#include + #include "cvc5_private.h" #ifndef CVC5_ATTRIBUTE_H__INCLUDING__ATTRIBUTE_INTERNALS_H @@ -145,15 +149,387 @@ inline uint64_t GetBitSet(uint64_t bit) } /** - * An "AttrHash"---the hash table underlying - * attributes---is simply a mapping of pair - * to value_type using our specialized hash function for these pairs. + * An "AttrHash"---the hash table underlying + * attributes---is a mapping of pair + * to V using a two-level hash+flat_map structure. The top level + * uses NodeValue* as its key, allowing rapid deletion of matching + * collections of entries, while the second level, keyed on Ids + * and implemented with a sorted vector, optimizes for size and + * speed for small collections. */ -template -class AttrHash : - public std::unordered_map, - value_type, - AttrHashFunction> { +template +class AttrHash +{ + // Second level flat map uint64_t -> V + class IdMap + { + public: + using value_type = std::pair; + using Container = std::vector; + using iterator = typename Container::iterator; + using const_iterator = typename Container::const_iterator; + + // only the methods required by AttrHash: + + const_iterator begin() const { return d_contents.begin(); } + const_iterator end() const { return d_contents.end(); } + + iterator begin() { return d_contents.begin(); } + iterator end() { return d_contents.end(); } + + std::size_t size() const { return d_contents.size(); } + + bool empty() const { return d_contents.empty(); } + + void reserve(std::size_t sz) { d_contents.reserve(sz); } + + std::pair emplace(uint64_t k, V v) + { + value_type p = std::make_pair(k, std::move(v)); + auto range = + std::equal_range(d_contents.begin(), + d_contents.end(), + p, + [](const value_type& a, const value_type& b) { + return a.first < b.first; + }); + if (range.first != range.second) + { + // key already present, don't insert + return std::make_pair(iterator{}, false); + } + + return std::make_pair(d_contents.insert(range.first, std::move(p)), true); + } + + const_iterator find(uint64_t key) const + { + auto range = + std::equal_range(d_contents.begin(), + d_contents.end(), + std::make_pair(key, V{}), + [](const value_type& a, const value_type& b) { + return a.first < b.first; + }); + if (range.first == range.second) + { + // not in map + return d_contents.end(); + } + return range.first; + } + + iterator find(uint64_t key) + { + auto range = + std::equal_range(d_contents.begin(), + d_contents.end(), + std::make_pair(key, V{}), + [](const value_type& a, const value_type& b) { + return a.first < b.first; + }); + if (range.first == range.second) + { + return d_contents.end(); + } + return range.first; + } + + iterator erase(iterator pos) { return d_contents.erase(pos); } + + V& operator[](uint64_t key) + { + iterator it = + std::lower_bound(d_contents.begin(), + d_contents.end(), + std::make_pair(key, V{}), + [](const value_type& a, const value_type& b) { + return a.first < b.first; + }); + if ((it == d_contents.end()) || (it->first != key)) + { + // not in map + it = d_contents.insert(it, std::make_pair(key, V{})); + } + return (*it).second; + } + + // range insert + template + void insert(Iter beg, Iter end) + { + for (Iter it = beg; it != end; ++it) + { + iterator found_it = + std::lower_bound(d_contents.begin(), + d_contents.end(), + it->first, + [](const value_type& a, const value_type& b) { + return a.first < b.first; + }); + if ((found_it != d_contents.end()) && (it->first == found_it->first)) + { + // this key is already present in the map. replace it: + found_it->second = it->second; + } + else + { + d_contents.insert(found_it, *it); + } + } + } + + private: + Container d_contents; + }; + + // a composite iterator combining a top-level (std::unordered_map) + // iterator with a lower-level (IdMap) iterator to preserve the + // illusion of a single map. Together they identify a virtual + // element pair, V> expected by + // users of AttrHash. + template + class Iterator + { + // access for AttrHash to implement erase(Iterator) + using NonConstParent = typename std::remove_const_t; + using NonConstIterator = typename NonConstParent::iterator; + friend NonConstIterator Parent::erase(NonConstIterator); + + public: + // requirements for ForwardIterator + using iterator_category = std::forward_iterator_tag; + using value_type = std::pair, V>; + using reference = value_type; // we don't supply a true reference + using pointer = value_type*; + using difference_type = std::ptrdiff_t; + + // default constructor + Iterator() : d_atEnd{true} {} + + Iterator(Parent* parent) + : d_parent{parent}, d_l1It(parent->d_storage.begin()) + { + d_atEnd = (d_l1It == parent->d_storage.end()); + if (!d_atEnd) + { + d_l2It = d_l1It->second.begin(); + legalize(); // L2 map may be empty + } + } + + // prerequisite: l1_it and l2_it are valid iterators + Iterator(Parent* parent, L1It l1_it, L2It l2_it) + : d_atEnd(l1_it == parent->d_storage.end()), + d_parent(parent), + d_l1It(l1_it), + d_l2It(l2_it) + { + } + + // increment + Iterator& operator++() // pre + { + increment(); + return *this; + } + + Iterator operator++(int) // post + { + Iterator tmp = *this; + increment(); + return tmp; + } + + // dereference + value_type operator*() const + { + return std::make_pair(std::make_pair(d_l2It->first, d_l1It->first), + d_l2It->second); + } + + // comparison + bool operator==(Iterator const& other) const + { + return (d_atEnd && other.d_atEnd) + || (!d_atEnd && !other.d_atEnd && (d_l1It == other.d_l1It) + && (d_l2It == other.d_l2It)); + } + bool operator!=(Iterator const& other) const { return !(*this == other); } + + private: + void increment() + { + ++d_l2It; + + legalize(); // we may be at the end of the current L2 map + } + + // if necessary, adjust L1/L2 iterators so they point at a real element + // called whenever a change may cause the L2 iterator to point to the end + // of the current L2 map, e.g.: + // initialization: the first L2 map is empty + // increment: the L2 iterator was pointing at the last element + // erase: the L2 iterator was pointing at the erased element and there are no more + void legalize() + { + // move forward to next valid entry + while (d_l2It == d_l1It->second.end()) + { + ++d_l1It; + if (d_l1It == d_parent->d_storage.end()) + { + d_atEnd = true; + return; + } + d_l2It = d_l1It->second.begin(); + } + } + + /** Whether at the end of all entries (matches only other end sentinels) */ + bool d_atEnd; + + /** The AttrHash this iterator belongs to */ + Parent* d_parent; + + /** Iterator within the top-level std::unordered_map */ + L1It d_l1It; + + /** Iterator within the second level IdMap (sorted vector) */ + L2It d_l2It; + }; + + using Storage = std::unordered_map; + + public: + using iterator = Iterator, + typename Storage::iterator, + typename IdMap::iterator>; + using const_iterator = Iterator, + typename Storage::const_iterator, + typename IdMap::const_iterator>; + + std::size_t size() const + { + return std::accumulate( + d_storage.begin(), + d_storage.end(), + 0u, + [](std::size_t sum, const std::pair& l2) { + return sum + l2.second.size(); + }); + } + + iterator begin() { return iterator(this); } + iterator end() { return iterator(); } + + const_iterator begin() const + { + return const_iterator(const_cast*>(this)); + } + const_iterator end() const { return const_iterator(); } + + iterator erase(iterator it) + { + // reach inside the iterator to get L1/L2 positions + auto nextL2It = it.d_l1It->second.erase(it.d_l2It); + + iterator nextIt(this, it.d_l1It, nextL2It); + nextIt.legalize(); + + if (it.d_l1It->second.empty()) + { + // this erase has made the L2 map empty. delete it: + d_storage.erase(it.d_l1It); + } + + return nextIt; + } + + template + void insert(Iter beg, Iter end) + { + using Entry = typename std::iterator_traits::value_type; + using Entries = std::vector; + using EntryIt = typename Entries::iterator; + Entries entries(beg, end); + + // sort by second (NodeValue*) then first (uint64_t) + std::sort( + entries.begin(), entries.end(), [](const Entry& a, const Entry& b) { + return (a.first.second < b.first.second) + || ((a.first.second == b.first.second) + && (a.first.first < b.first.first)); + }); + + auto find_different_nv = [](NodeValue* nv, EntryIt first, EntryIt last) { + return std::find_if( + first, last, [nv](const Entry& a) { return a.first.second != nv; }); + }; + + // determine number of new L1 entries required (count unique NodeValue*s) + std::size_t l1_unique_count = 0; + auto last = entries.end(); + for (EntryIt it = entries.begin(); it != last; + it = find_different_nv(it->first.second, it, entries.end())) + { + ++l1_unique_count; + } + // pre-allocate enough space for the new L1 entries (for speed) + d_storage.reserve(d_storage.size() + l1_unique_count); + + // add new entries one (same NodeValue*) chunk at a time + for (EntryIt it = entries.begin(); it != last;) + { + // identify range of entries with the same NodeValue* (a "chunk") + EntryIt chunk_end = std::find_if(it, entries.end(), [it](const Entry& v) { + return v.first.second != it->first.second; + }); + // add to corresponding l2 map + auto& l2 = d_storage[it->first.second]; + l2.reserve(l2.size() + std::distance(it, chunk_end)); + for (; it != chunk_end; ++it) + { + l2.emplace(it->first.first, it->second); + } + } + } + + void swap(AttrHash& other) { std::swap(d_storage, other.d_storage); } + + V& operator[](std::pair p) + { + return d_storage[p.second][p.first]; + } + + void clear() { d_storage.clear(); } + + const_iterator find(std::pair p) const + { + typename Storage::const_iterator it1 = d_storage.find(p.second); + if (it1 == d_storage.end()) return const_iterator(); + + typename IdMap::const_iterator it2 = it1->second.find(p.first); + if (it2 == it1->second.end()) return const_iterator(); + + return const_iterator(this, it1, it2); + } + + iterator find(std::pair p) + { + typename Storage::iterator it1 = d_storage.find(p.second); + if (it1 == d_storage.end()) return iterator(); + + typename IdMap::iterator it2 = it1->second.find(p.first); + if (it2 == it1->second.end()) return iterator(); + + return iterator(this, it1, it2); + } + + void eraseBy(NodeValue* nv) { d_storage.erase(nv); } + + private: + Storage d_storage; };/* class AttrHash<> */ /** diff --git a/src/expr/elim_shadow_converter.cpp b/src/expr/elim_shadow_converter.cpp index 10b8aa9fcf2..68ef3b4c857 100644 --- a/src/expr/elim_shadow_converter.cpp +++ b/src/expr/elim_shadow_converter.cpp @@ -17,6 +17,7 @@ #include "expr/attribute.h" #include "expr/bound_var_manager.h" +#include "util/rational.h" using namespace cvc5::internal::kind; @@ -57,11 +58,12 @@ Node ElimShadowNodeConverter::postConvert(Node n) } std::vector oldVars; std::vector newVars; - for (const Node& v : n[0]) + for (size_t i = 0, nvars = n[0].getNumChildren(); i < nvars; i++) { + const Node& v = n[0][i]; if (std::find(d_vars.begin(), d_vars.end(), v) != d_vars.end()) { - Node nv = getElimShadowVar(d_closure, n, v); + Node nv = getElimShadowVar(d_closure, n, i); oldVars.push_back(v); newVars.push_back(nv); } @@ -76,12 +78,13 @@ Node ElimShadowNodeConverter::postConvert(Node n) Node ElimShadowNodeConverter::getElimShadowVar(const Node& q, const Node& n, - const Node& v) + size_t i) { NodeManager* nm = NodeManager::currentNM(); BoundVarManager* bvm = nm->getBoundVarManager(); - Node cacheVal = BoundVarManager::getCacheValue(q, n, v); - return bvm->mkBoundVar(cacheVal, v.getType()); + Node ii = nm->mkConstInt(Rational(i)); + Node cacheVal = BoundVarManager::getCacheValue(q, n, ii); + return bvm->mkBoundVar(cacheVal, n[0][i].getType()); } Node ElimShadowNodeConverter::eliminateShadow(const Node& q) @@ -91,7 +94,31 @@ Node ElimShadowNodeConverter::eliminateShadow(const Node& q) ElimShadowNodeConverter esnc(nm, q); // eliminate shadowing in all children std::vector children; - children.push_back(q[0]); + // drop duplicate variables + std::vector vars; + bool childChanged = false; + for (size_t i = 0, nvars = q[0].getNumChildren(); i < nvars; i++) + { + const Node& v = q[0][i]; + if (std::find(vars.begin(), vars.end(), v) == vars.end()) + { + vars.push_back(v); + } + else + { + Node vn = getElimShadowVar(q, q, i); + vars.push_back(vn); + childChanged = true; + } + } + if (childChanged) + { + children.push_back(nm->mkNode(Kind::BOUND_VAR_LIST, vars)); + } + else + { + children.push_back(q[0]); + } for (size_t i = 1, nchild = q.getNumChildren(); i < nchild; i++) { children.push_back(esnc.convert(q[i])); diff --git a/src/expr/elim_shadow_converter.h b/src/expr/elim_shadow_converter.h index e27d22527b7..dfb8e85569e 100644 --- a/src/expr/elim_shadow_converter.h +++ b/src/expr/elim_shadow_converter.h @@ -57,12 +57,17 @@ class ElimShadowNodeConverter : public NodeConverter */ Node postConvert(Node n) override; /** - * Get the bound variable used for eliminating shadowing of variable v + * Get the bound variable used for eliminating shadowing of the i^th variable * bound by closure n that occurs as a subterm of closure q. */ - static Node getElimShadowVar(const Node& q, const Node& n, const Node& v); + static Node getElimShadowVar(const Node& q, const Node& n, size_t i); - /** Eliminate shadowing in the closure q */ + /** + * Eliminate shadowing in the closure q. This includes eliminating duplicate + * variables in the quantifier prefix of q. + * @param q The term to process which should have a binder kind. + * @return The result of eliminating shadowing in q. + */ static Node eliminateShadow(const Node& q); private: diff --git a/src/expr/nary_term_util.cpp b/src/expr/nary_term_util.cpp index a9510479c1c..40bc9d4a3fd 100644 --- a/src/expr/nary_term_util.cpp +++ b/src/expr/nary_term_util.cpp @@ -16,6 +16,7 @@ #include "expr/nary_term_util.h" #include "expr/attribute.h" +#include "expr/node_algorithm.h" #include "expr/skolem_manager.h" #include "theory/bv/theory_bv_utils.h" #include "theory/strings/word.h" @@ -223,6 +224,12 @@ Node narySubstitute(Node src, it = visited.find(cur); if (it == visited.end()) { + if (!expr::hasBoundVar(cur)) + { + visited[cur] = cur; + visit.pop_back(); + continue; + } // if it is a non-list variable, do the replacement itv = std::find(vars.begin(), vars.end(), cur); if (itv != vars.end()) diff --git a/src/expr/plugin.cpp b/src/expr/plugin.cpp index bf2fe9b0d91..4bac58b6f9c 100644 --- a/src/expr/plugin.cpp +++ b/src/expr/plugin.cpp @@ -15,29 +15,10 @@ #include "expr/plugin.h" -#include "expr/node_algorithm.h" -#include "expr/skolem_manager.h" -#include "expr/subtype_elim_node_converter.h" - namespace cvc5::internal { Plugin::Plugin(NodeManager* nm) : d_nm(nm) {} Plugin::~Plugin() {} -Node Plugin::getSharableFormula(const Node& n) const -{ - Node on = SkolemManager::getOriginalForm(n); - if (expr::hasSubtermKinds({Kind::SKOLEM, Kind::INST_CONSTANT}, on)) - { - // We cannot share formulas with skolems currently. - // We should never share formulas with instantiation constants. - return Node::null(); - } - // also eliminate subtyping - SubtypeElimNodeConverter senc(d_nm); - on = senc.convert(on); - return on; -} - } // namespace cvc5::internal diff --git a/src/expr/plugin.h b/src/expr/plugin.h index b322c73064d..9a50b6dde92 100644 --- a/src/expr/plugin.h +++ b/src/expr/plugin.h @@ -62,18 +62,6 @@ class Plugin * @return the name of the plugin. */ virtual std::string getName() = 0; - /** - * Get sharable formula. This returns an equivalent version of the given - * lemma n that can be shared externally. In particular, we require that the - * returned formula does not have any internally generated symbols, i.e. - * skolems. If n cannot be converted to a suitable formula, we return the - * null node. - * - * @param n The candidate formula to share. - * @return A tranformed version of n that is its represenation in a sharable - * form. If n cannot be tranformed, this returns null. - */ - Node getSharableFormula(const Node& n) const; private: /** Pointer to node manager */ diff --git a/src/expr/skolem_manager.cpp b/src/expr/skolem_manager.cpp index 911928e7bd2..f57c78a8229 100644 --- a/src/expr/skolem_manager.cpp +++ b/src/expr/skolem_manager.cpp @@ -66,33 +66,10 @@ std::ostream& operator<<(std::ostream& out, InternalSkolemId id) SkolemManager::SkolemManager() : d_skolemCounter(0) {} -Node SkolemManager::mkPurifySkolem(Node t, - ProofGenerator* pg) +Node SkolemManager::mkPurifySkolem(Node t) { // We do not recursively compute the original form of t here - Node k; - if (t.getKind() == Kind::WITNESS) - { - // The purification skolem for (witness ((x T)) P) is the same as - // the skolem function (QUANTIFIERS_SKOLEMIZE (exists ((x T)) P) x). - NodeManager* nm = NodeManager::currentNM(); - Node exists = - nm->mkNode(Kind::EXISTS, std::vector(t.begin(), t.end())); - k = mkSkolemFunction(SkolemId::QUANTIFIERS_SKOLEMIZE, {exists, t[0][0]}); - // store the proof generator if it exists - if (pg != nullptr) - { - d_gens[exists] = pg; - } - UnpurifiedFormAttribute ufa; - k.setAttribute(ufa, t); - } - else - { - k = mkSkolemFunction(SkolemId::PURIFY, {t}); - // shouldn't provide proof generators for other terms - Assert(pg == nullptr); - } + Node k = mkSkolemFunction(SkolemId::PURIFY, {t}); Trace("sk-manager-skolem") << "skolem: " << k << " purify " << t << std::endl; return k; } @@ -273,16 +250,6 @@ Node SkolemManager::mkDummySkolem(const std::string& prefix, return mkSkolemNode(Kind::DUMMY_SKOLEM, prefix, type, flags); } -ProofGenerator* SkolemManager::getProofGenerator(Node t) const -{ - std::map::const_iterator it = d_gens.find(t); - if (it != d_gens.end()) - { - return it->second; - } - return nullptr; -} - bool SkolemManager::isAbstractValue(TNode n) const { return (getInternalId(n) == InternalSkolemId::ABSTRACT_VALUE); @@ -615,4 +582,76 @@ TypeNode SkolemManager::getTypeFor(SkolemId id, return TypeNode(); } +size_t SkolemManager::getNumIndicesForSkolemId(SkolemId id) const +{ + switch (id) + { + // Number of skolem indices: 0 + case SkolemId::BV_EMPTY: + case SkolemId::DIV_BY_ZERO: + case SkolemId::INT_DIV_BY_ZERO: + case SkolemId::MOD_BY_ZERO: return 0; + + // Number of skolem indices: 1 + case SkolemId::PURIFY: + case SkolemId::GROUND_TERM: + case SkolemId::TRANSCENDENTAL_PURIFY: + case SkolemId::TRANSCENDENTAL_PURIFY_ARG: + case SkolemId::STRINGS_REPLACE_ALL_RESULT: + case SkolemId::STRINGS_ITOS_RESULT: + case SkolemId::STRINGS_STOI_RESULT: + case SkolemId::STRINGS_STOI_NON_DIGIT: + case SkolemId::BAGS_CARD_COMBINE: + case SkolemId::BAGS_DISTINCT_ELEMENTS_UNION_DISJOINT: + case SkolemId::BAGS_FOLD_CARD: + case SkolemId::BAGS_FOLD_ELEMENTS: + case SkolemId::BAGS_FOLD_UNION_DISJOINT: + case SkolemId::BAGS_CHOOSE: + case SkolemId::BAGS_DISTINCT_ELEMENTS: + case SkolemId::BAGS_DISTINCT_ELEMENTS_SIZE: + case SkolemId::TABLES_GROUP_PART: + case SkolemId::RELATIONS_GROUP_PART: + case SkolemId::SETS_CHOOSE: + case SkolemId::SETS_FOLD_CARD: + case SkolemId::SETS_FOLD_ELEMENTS: + case SkolemId::SETS_FOLD_UNION: + case SkolemId::FP_MIN_ZERO: + case SkolemId::FP_MAX_ZERO: + case SkolemId::FP_TO_REAL: return 1; + + // Number of skolem indices: 2 + case SkolemId::ARRAY_DEQ_DIFF: + case SkolemId::QUANTIFIERS_SKOLEMIZE: + case SkolemId::STRINGS_NUM_OCCUR: + case SkolemId::STRINGS_OCCUR_INDEX: + case SkolemId::STRINGS_NUM_OCCUR_RE: + case SkolemId::STRINGS_OCCUR_INDEX_RE: + case SkolemId::STRINGS_OCCUR_LEN_RE: + case SkolemId::STRINGS_DEQ_DIFF: + case SkolemId::RE_FIRST_MATCH_PRE: + case SkolemId::RE_FIRST_MATCH: + case SkolemId::RE_FIRST_MATCH_POST: + case SkolemId::BAGS_DEQ_DIFF: + case SkolemId::TABLES_GROUP_PART_ELEMENT: + case SkolemId::RELATIONS_GROUP_PART_ELEMENT: + case SkolemId::SETS_DEQ_DIFF: + case SkolemId::SETS_MAP_DOWN_ELEMENT: + case SkolemId::FP_TO_SBV: + case SkolemId::FP_TO_UBV: return 2; + + // Number of skolem indices: 3 + case SkolemId::SHARED_SELECTOR: + case SkolemId::RE_UNFOLD_POS_COMPONENT: + case SkolemId::BAGS_FOLD_COMBINE: + case SkolemId::BAGS_MAP_PREIMAGE_INJECTIVE: + case SkolemId::BAGS_MAP_SUM: + case SkolemId::SETS_FOLD_COMBINE: return 3; + + // Number of skolem indices: 5 + case SkolemId::BAGS_MAP_INDEX: return 5; + + default: Unimplemented() << "Unknown skolem kind " << id; break; + } +} + } // namespace cvc5::internal diff --git a/src/expr/skolem_manager.h b/src/expr/skolem_manager.h index c2739ce39f7..ebcae49d4be 100644 --- a/src/expr/skolem_manager.h +++ b/src/expr/skolem_manager.h @@ -143,14 +143,9 @@ class SkolemManager * will return two different Skolems. * * @param t The term to purify - * @param pg The proof generator for the skolemization of t. This should - * only be provided if t is a witness term (witness ((x T)) P). If non-null, - * this proof generator must respond to a call to getProofFor on - * (exists ((x T)) P) during the lifetime of the current node manager. * @return The purification skolem for t */ - Node mkPurifySkolem(Node t, - ProofGenerator* pg = nullptr); + Node mkPurifySkolem(Node t); /** * Make skolem function. This method should be used for creating fixed * skolem functions of the forms described in SkolemId. The user of this @@ -231,11 +226,6 @@ class SkolemManager const TypeNode& type, const std::string& comment = "", int flags = SKOLEM_DEFAULT); - /** - * Get proof generator for existentially quantified formula q. This returns - * the proof generator that was provided in a call to `mkSkolemize` above. - */ - ProofGenerator* getProofGenerator(Node q) const; /** Returns true if n is a skolem that stands for an abstract value */ bool isAbstractValue(TNode n) const; /** @@ -257,16 +247,18 @@ class SkolemManager * @return the unpurified form of k. */ static Node getUnpurifiedForm(Node k); + /** + * Get the number of indices for a skolem id. + * @param id The skolem id. + * @return The number of indices for the skolem id. + */ + size_t getNumIndicesForSkolemId(SkolemId id) const; private: /** Cache of skolem functions for mkSkolemFunction above. */ std::map, Node> d_skolemFuns; /** Backwards mapping of above */ std::map> d_skolemFunMap; - /** - * Mapping from witness terms to proof generators. - */ - std::map d_gens; /** * A counter used to produce unique skolem names. diff --git a/src/options/base_options.toml b/src/options/base_options.toml index 70821815f32..22052107a6f 100644 --- a/src/options/base_options.toml +++ b/src/options/base_options.toml @@ -339,3 +339,19 @@ name = "Base" type = "bool" default = "false" help = "do not allow setting any option that is not common or regular" + +[[option]] + name = "pluginNotifySatClauseInSolve" + category = "expert" + long = "plugin-notify-sat-clause-in-solve" + type = "bool" + default = "true" + help = "only inform plugins of SAT clauses when we are in the main solving loop of the SAT solver" + +[[option]] + name = "pluginShareSkolems" + category = "expert" + long = "plugin-share-skolems" + type = "bool" + default = "true" + help = "true if we permit sharing theory lemmas and SAT clauses with skolems" diff --git a/src/options/parser_options.toml b/src/options/parser_options.toml index 01121195d63..c172801f784 100644 --- a/src/options/parser_options.toml +++ b/src/options/parser_options.toml @@ -60,3 +60,11 @@ name = "Parser" type = "std::string" default = '""' help = "set the logic, and override all further user attempts to change it" + +[[option]] + name = "parseSkolemDefinitions" + category = "expert" + long = "parse-skolem-definitions" + type = "bool" + default = "false" + help = "allows the parsing of skolems in the input file" \ No newline at end of file diff --git a/src/options/prop_options.toml b/src/options/prop_options.toml index 6785e0aa590..e59e25dff71 100644 --- a/src/options/prop_options.toml +++ b/src/options/prop_options.toml @@ -108,11 +108,3 @@ name = "SAT Layer" [[option.mode.LAZY]] name = "lazy" help = "Preregister literals when they are asserted by the SAT solver." - -[[option]] - name = "pluginNotifySatClauseInSolve" - category = "expert" - long = "plugin-notify-sat-clause-in-solve" - type = "bool" - default = "true" - help = "only inform plugins of SAT clauses when we are in the main solving loop of the SAT solver" diff --git a/src/options/sets_options.toml b/src/options/sets_options.toml index bc0f6c367ab..f602fc03a0c 100644 --- a/src/options/sets_options.toml +++ b/src/options/sets_options.toml @@ -9,14 +9,6 @@ name = "Sets Theory" default = "false" help = "introduce proxy variables eagerly to shorten lemmas" -[[option]] - name = "setsInferAsLemmas" - category = "expert" - long = "sets-infer-as-lemmas" - type = "bool" - default = "true" - help = "send inferences as lemmas" - [[option]] name = "setsExt" category = "regular" diff --git a/src/parser/smt2/smt2_cmd_parser.cpp b/src/parser/smt2/smt2_cmd_parser.cpp index 98bc98b9b53..d1e88592bf3 100644 --- a/src/parser/smt2/smt2_cmd_parser.cpp +++ b/src/parser/smt2/smt2_cmd_parser.cpp @@ -402,7 +402,10 @@ std::unique_ptr Smt2CmdParser::parseNextCommand() { d_state.pushScope(); } - std::vector terms = d_state.bindBoundVars(sortedVarNames); + // Must use fresh=false here to ensure that variables introduced by + // define-fun are accurate with respect to proofs, i.e. variables of + // the same name and type are indeed the same variable. + std::vector terms = d_state.bindBoundVars(sortedVarNames, false); Term expr = d_tparser.parseTerm(); if (!flattenVars.empty()) { diff --git a/src/parser/smt2/smt2_state.cpp b/src/parser/smt2/smt2_state.cpp index 6acc7f8a6d0..e3e0a70ba9d 100644 --- a/src/parser/smt2/smt2_state.cpp +++ b/src/parser/smt2/smt2_state.cpp @@ -313,6 +313,19 @@ void Smt2State::addCoreSymbols() addClosureKind(Kind::EXISTS, "exists"); } +void Smt2State::addSkolemSymbols() +{ + for (int32_t s = static_cast(SkolemId::INTERNAL); + s <= static_cast(SkolemId::NONE); + ++s) + { + auto skolem = static_cast(s); + std::stringstream ss; + ss << "@" << skolem; + addSkolemId(skolem, ss.str()); + } +} + void Smt2State::addOperator(Kind kind, const std::string& name) { Trace("parser") << "Smt2State::addOperator( " << kind << ", " << name << " )" @@ -334,6 +347,12 @@ void Smt2State::addClosureKind(Kind tKind, const std::string& name) d_closureKindMap[name] = tKind; } +void Smt2State::addSkolemId(SkolemId skolemID, const std::string& name) +{ + addOperator(Kind::SKOLEM, name); + d_skolemMap[name] = skolemID; +} + bool Smt2State::isIndexedOperatorEnabled(const std::string& name) const { return d_indexedOpKindMap.find(name) != d_indexedOpKindMap.end(); @@ -757,6 +776,12 @@ void Smt2State::setLogic(std::string name) // Core theory belongs to every logic addCoreSymbols(); + // add skolems + if (d_solver->getOption("parse-skolem-definitions") == "true") + { + addSkolemSymbols(); + } + if (d_logic.isTheoryEnabled(internal::theory::THEORY_UF)) { ParserState::addOperator(Kind::APPLY_UF); @@ -1560,6 +1585,28 @@ Term Smt2State::applyParseOp(const ParseOp& p, std::vector& args) return ret; } } + else if (kind == Kind::SKOLEM) + { + Term ret; + SkolemId skolemId = d_skolemMap[p.d_name]; + size_t numSkolemIndices = d_tm.getNumIndicesForSkolemId(skolemId); + if (numSkolemIndices == args.size()) + { + ret = d_tm.mkSkolem(skolemId, args); + } + else + { + std::vector skolemArgs(args.begin(), + args.begin() + numSkolemIndices); + Term skolem = d_tm.mkSkolem(skolemId, skolemArgs); + std::vector finalArgs = {skolem}; + finalArgs.insert( + finalArgs.end(), args.begin() + numSkolemIndices, args.end()); + ret = d_tm.mkTerm(Kind::APPLY_UF, finalArgs); + } + Trace("parser") << "applyParseOp: return skolem " << ret << std::endl; + return ret; + } Term ret = d_tm.mkTerm(kind, args); Trace("parser") << "applyParseOp: return default builtin " << ret << std::endl; diff --git a/src/parser/smt2/smt2_state.h b/src/parser/smt2/smt2_state.h index 5f7c8fabf5e..2f5e15a78b7 100644 --- a/src/parser/smt2/smt2_state.h +++ b/src/parser/smt2/smt2_state.h @@ -52,6 +52,10 @@ class Smt2State : public ParserState * Add core theory symbols to the parser state. */ void addCoreSymbols(); + /** + * Add skolem symbols to the parser state. + */ + void addSkolemSymbols(); void addOperator(Kind k, const std::string& name); @@ -73,6 +77,13 @@ class Smt2State : public ParserState * @param name The name of the symbol (e.g. "lambda") */ void addClosureKind(Kind tKind, const std::string& name); + /** + * Registers a skolem + * + * @param skolemID The is of the skolem + * @param name The name of the skolem, e.g. @array_deq_diff + */ + void addSkolemId(SkolemId skolemID, const std::string& name); /** * Checks whether an indexed operator is enabled. All indexed operators in * the current logic are considered to be enabled. This includes operators @@ -466,6 +477,8 @@ class Smt2State : public ParserState internal::LogicInfo d_logic; /** Maps strings to the operator it is bound to */ std::unordered_map d_operatorKindMap; + /** Maps strings to the skolem it is bound to */ + std::unordered_map d_skolemMap; /** * Maps indexed symbols to the kind of the operator (e.g. "extract" to * BITVECTOR_EXTRACT). diff --git a/src/preprocessing/passes/ackermann.cpp b/src/preprocessing/passes/ackermann.cpp index 85a473eb71e..df46d3ad5c6 100644 --- a/src/preprocessing/passes/ackermann.cpp +++ b/src/preprocessing/passes/ackermann.cpp @@ -263,7 +263,7 @@ void usortsToBitVectors(const LogicInfo& d_logic, if (toProcess.size() > 0) { /* the current version only supports BV for removing uninterpreted sorts */ - if (not d_logic.isTheoryEnabled(theory::THEORY_BV)) + if (!d_logic.isTheoryEnabled(theory::THEORY_BV)) { return; } diff --git a/src/printer/smt2/smt2_printer.cpp b/src/printer/smt2/smt2_printer.cpp index a486e3e3f6c..63e62c8f5e3 100644 --- a/src/printer/smt2/smt2_printer.cpp +++ b/src/printer/smt2/smt2_printer.cpp @@ -609,23 +609,7 @@ bool Smt2Printer::toStreamBase(std::ostream& out, } else if (options::ioutils::getPrintSkolemDefinitions(out)) { - if (!cacheVal.isNull()) - { - out << "("; - } - out << "@" << id; - if (cacheVal.getKind() == Kind::SEXPR) - { - for (const Node& cv : cacheVal) - { - out << " " << cv; - } - out << ")"; - } - else if (!cacheVal.isNull()) - { - out << " " << cacheVal << ")"; - } + toStreamSkolem(out, cacheVal, id, /*isApplied=*/false); printed = true; } } @@ -671,6 +655,24 @@ bool Smt2Printer::toStreamBase(std::ostream& out, toStream(out, hoa, lbind, toDepth); return true; } + else if (n.getOperator().getKind() == Kind::SKOLEM) + { + SkolemManager* sm = nm->getSkolemManager(); + SkolemId id; + Node cacheVal; + if (sm->isSkolemFunction(n.getOperator(), id, cacheVal)) + { + if (options::ioutils::getPrintSkolemDefinitions(out)) + { + if (n.getNumChildren() != 0) + { + out << '('; + } + toStreamSkolem(out, cacheVal, id, /*isApplied=*/true); + return false; + } + } + } } else if (k == Kind::CONSTRUCTOR_TYPE) { @@ -1170,12 +1172,12 @@ std::string Smt2Printer::smtKindString(Kind k) case Kind::LEQ: return "<="; case Kind::GT: return ">"; case Kind::GEQ: return ">="; - case Kind::DIVISION: - case Kind::DIVISION_TOTAL: return "/"; - case Kind::INTS_DIVISION_TOTAL: + case Kind::DIVISION: return "/"; + case Kind::DIVISION_TOTAL: return "/_total"; case Kind::INTS_DIVISION: return "div"; - case Kind::INTS_MODULUS_TOTAL: + case Kind::INTS_DIVISION_TOTAL: return "div_total"; case Kind::INTS_MODULUS: return "mod"; + case Kind::INTS_MODULUS_TOTAL: return "mod_total"; case Kind::INTS_LOG2: return "int.log2"; case Kind::INTS_ISPOW2: return "int.ispow2"; case Kind::ABS: return "abs"; @@ -1422,6 +1424,7 @@ std::string Smt2Printer::smtKindString(Kind k) case Kind::SEP_WAND: return "wand"; case Kind::SEP_EMP: return "sep.emp"; case Kind::SEP_NIL: return "sep.nil"; + case Kind::SEP_LABEL: return "@sep_label"; // quantifiers case Kind::FORALL: return "forall"; @@ -2082,6 +2085,36 @@ void Smt2Printer::toStreamCmdDeclareHeap(std::ostream& out, out << "(declare-heap (" << locType << " " << dataType << "))"; } +void Smt2Printer::toStreamSkolem(std::ostream& out, + Node cacheVal, + SkolemId id, + bool isApplied) const +{ + auto delim = isApplied ? " " : ")"; + + if (!isApplied && !cacheVal.isNull()) + { + out << "("; + } + out << "@" << id; + if (cacheVal.getKind() == Kind::SEXPR) + { + for (const Node& cv : cacheVal) + { + out << " " << cv; + } + out << delim; + } + else if (!cacheVal.isNull()) + { + out << " " << cacheVal << delim; + } + else + { + out << delim; + } +} + void Smt2Printer::toStreamCmdEmpty(std::ostream& out, const std::string& name) const { diff --git a/src/printer/smt2/smt2_printer.h b/src/printer/smt2/smt2_printer.h index ee8d637a22a..645fc68e051 100644 --- a/src/printer/smt2/smt2_printer.h +++ b/src/printer/smt2/smt2_printer.h @@ -18,6 +18,8 @@ #ifndef CVC5__PRINTER__SMT2_PRINTER_H #define CVC5__PRINTER__SMT2_PRINTER_H +#include + #include "printer/printer.h" namespace cvc5::internal { @@ -284,6 +286,17 @@ class Smt2Printer : public cvc5::internal::Printer TypeNode locType, TypeNode dataType) const override; + /** Print skolems. + * @param out The stream to print to + * @param cacheVal The cache value of the skolem + * @param id The skolem id + * @param isApplied Whether the skolem is applied as an APPLY_UF + */ + void toStreamSkolem(std::ostream& out, + Node cacheVal, + SkolemId id, + bool isApplied) const; + /** * Get the string for a kind k, which returns how the kind k is printed in * the SMT-LIB format. diff --git a/src/proof/alf/alf_node_converter.cpp b/src/proof/alf/alf_node_converter.cpp index 9fc19c752ae..9220c7c6bc3 100644 --- a/src/proof/alf/alf_node_converter.cpp +++ b/src/proof/alf/alf_node_converter.cpp @@ -56,6 +56,8 @@ AlfNodeConverter::AlfNodeConverter(NodeManager* nm) : BaseAlfNodeConverter(nm) d_sortType = nm->mkSort("sortType"); } +AlfNodeConverter::~AlfNodeConverter() {} + Node AlfNodeConverter::preConvert(Node n) { // match is not supported in ALF syntax, we eliminate it at pre-order @@ -243,7 +245,7 @@ Node AlfNodeConverter::postConvert(Node n) std::vector newArgs; newArgs.push_back(nm->mkConstInt(irp.d_index)); newArgs.insert(newArgs.end(), n.begin(), n.end()); - return mkInternalApp("INDEXED_ROOT_PREDICATE", newArgs, tn); + return mkInternalApp("@indexed_root_predicate", newArgs, tn); } else if (k == Kind::FLOATINGPOINT_COMPONENT_NAN || k == Kind::FLOATINGPOINT_COMPONENT_INF @@ -375,18 +377,11 @@ size_t AlfNodeConverter::getNumChildrenToProcessForClosure(Kind k) const return k == Kind::SET_COMPREHENSION ? 3 : 2; } -Node AlfNodeConverter::mkNil(TypeNode tn) -{ - return mkInternalSymbol("alf.nil", tn); -} Node AlfNodeConverter::mkList(const std::vector& args) { + Assert(!args.empty()); TypeNode tn = NodeManager::currentNM()->booleanType(); - if (args.empty()) - { - return mkNil(tn); - } // singleton lists are handled due to (@list x) ---> (@list x alf.nil) return mkInternalApp("@list", args, tn); } @@ -607,11 +602,6 @@ Node AlfNodeConverter::getOperatorOfTerm(Node n, bool reqCast) else { opName << printer::smt2::Smt2Printer::smtKindString(k); - if (k == Kind::DIVISION_TOTAL || k == Kind::INTS_DIVISION_TOTAL - || k == Kind::INTS_MODULUS_TOTAL) - { - opName << "_total"; - } } } std::vector args(n.begin(), n.end()); diff --git a/src/proof/alf/alf_node_converter.h b/src/proof/alf/alf_node_converter.h index ac729d4c8f4..3af389941f4 100644 --- a/src/proof/alf/alf_node_converter.h +++ b/src/proof/alf/alf_node_converter.h @@ -78,7 +78,7 @@ class AlfNodeConverter : public BaseAlfNodeConverter { public: AlfNodeConverter(NodeManager* nm); - ~AlfNodeConverter() {} + ~AlfNodeConverter(); /** Convert at pre-order traversal */ Node preConvert(Node n) override; /** Convert at post-order traversal */ @@ -127,8 +127,6 @@ class AlfNodeConverter : public BaseAlfNodeConverter size_t getNumChildrenToProcessForClosure(Kind k) const; private: - /** Make alf.nil for the given type. */ - Node mkNil(TypeNode tn); /** * Get the variable index for free variable fv, or assign a fresh index if it * is not yet assigned. diff --git a/src/proof/alf/alf_print_channel.cpp b/src/proof/alf/alf_print_channel.cpp index 6a73256e32b..96a6e939b08 100644 --- a/src/proof/alf/alf_print_channel.cpp +++ b/src/proof/alf/alf_print_channel.cpp @@ -24,6 +24,10 @@ namespace cvc5::internal { namespace proof { +AlfPrintChannel::AlfPrintChannel() {} + +AlfPrintChannel::~AlfPrintChannel() {} + AlfPrintChannelOut::AlfPrintChannelOut(std::ostream& out, const LetBinding* lbind, const std::string& tprefix) @@ -180,6 +184,11 @@ void AlfPrintChannelPre::printNode(TNode n) } } +void AlfPrintChannelPre::printTypeNode(TypeNode tn) +{ + // current do nothing +} + void AlfPrintChannelPre::printAssume(TNode n, size_t i, bool isPush) { processInternal(n); diff --git a/src/proof/alf/alf_print_channel.h b/src/proof/alf/alf_print_channel.h index 8fb30e82a9b..f54e9429ce5 100644 --- a/src/proof/alf/alf_print_channel.h +++ b/src/proof/alf/alf_print_channel.h @@ -37,14 +37,14 @@ namespace proof { class AlfPrintChannel { public: - AlfPrintChannel() {} - virtual ~AlfPrintChannel() {} + AlfPrintChannel(); + virtual ~AlfPrintChannel(); /** Print node n */ - virtual void printNode(TNode n) {} + virtual void printNode(TNode n) = 0; /** Print type node n */ - virtual void printTypeNode(TypeNode tn) {} + virtual void printTypeNode(TypeNode tn) = 0; /** Print assume */ - virtual void printAssume(TNode n, size_t i, bool isPush = false) {} + virtual void printAssume(TNode n, size_t i, bool isPush = false) = 0; /** * Print step * @param rname The rule name. @@ -59,18 +59,14 @@ class AlfPrintChannel size_t i, const std::vector& premises, const std::vector& args, - bool isPop = false) - { - } + bool isPop = false) = 0; /** Print trust step */ virtual void printTrustStep(ProofRule r, TNode n, size_t i, const std::vector& premises, const std::vector& args, - TNode conc) - { - } + TNode conc) = 0; }; /** Prints the proof to output stream d_out */ @@ -140,6 +136,7 @@ class AlfPrintChannelPre : public AlfPrintChannel public: AlfPrintChannelPre(LetBinding* lbind); void printNode(TNode n) override; + void printTypeNode(TypeNode tn) override; void printAssume(TNode n, size_t i, bool isPush) override; void printStep(const std::string& rname, TNode n, diff --git a/src/proof/alf/alf_printer.cpp b/src/proof/alf/alf_printer.cpp index 900a0eda568..828d5f679b3 100644 --- a/src/proof/alf/alf_printer.cpp +++ b/src/proof/alf/alf_printer.cpp @@ -203,11 +203,13 @@ bool AlfPrinter::isHandledTheoryRewrite(ProofRewriteRule id, switch (id) { case ProofRewriteRule::DISTINCT_ELIM: + case ProofRewriteRule::BETA_REDUCE: case ProofRewriteRule::RE_LOOP_ELIM: case ProofRewriteRule::SETS_IS_EMPTY_EVAL: case ProofRewriteRule::STR_IN_RE_CONCAT_STAR_CHAR: case ProofRewriteRule::STR_IN_RE_SIGMA: - case ProofRewriteRule::STR_IN_RE_SIGMA_STAR: return true; + case ProofRewriteRule::STR_IN_RE_SIGMA_STAR: + case ProofRewriteRule::STR_IN_RE_CONSUME: return true; default: break; } return false; @@ -228,6 +230,7 @@ bool AlfPrinter::canEvaluate(Node n) const visited.insert(cur); switch (cur.getKind()) { + case Kind::ITE: case Kind::NOT: case Kind::AND: case Kind::OR: @@ -286,13 +289,6 @@ bool AlfPrinter::canEvaluate(Node n) const case Kind::BITVECTOR_SIZE: // special case, evaluates no matter what is inside continue; - case Kind::STRING_IN_REGEXP: - if (!canEvaluateRegExp(cur[1])) - { - return false; - } - visit.push_back(cur[0]); - continue; default: Trace("alf-printer-debug") << "Cannot evaluate " << cur.getKind() << std::endl; diff --git a/src/proof/lazy_tree_proof_generator.cpp b/src/proof/lazy_tree_proof_generator.cpp index 028331b1f5a..4856119e3ee 100644 --- a/src/proof/lazy_tree_proof_generator.cpp +++ b/src/proof/lazy_tree_proof_generator.cpp @@ -66,6 +66,19 @@ void LazyTreeProofGenerator::setCurrent(size_t objectId, pn.d_args = args; pn.d_proven = proven; } + +void LazyTreeProofGenerator::setCurrentTrust(size_t objectId, + TrustId tid, + const std::vector& premise, + std::vector args, + Node proven) +{ + std::vector newArgs; + newArgs.push_back(mkTrustId(tid)); + newArgs.push_back(proven); + newArgs.insert(newArgs.end(), args.begin(), args.end()); + setCurrent(objectId, ProofRule::TRUST, premise, newArgs, proven); +} std::shared_ptr LazyTreeProofGenerator::getProof() const { // Check cache diff --git a/src/proof/lazy_tree_proof_generator.h b/src/proof/lazy_tree_proof_generator.h index 06aafcc1d9c..d09e635b4d1 100644 --- a/src/proof/lazy_tree_proof_generator.h +++ b/src/proof/lazy_tree_proof_generator.h @@ -155,6 +155,14 @@ class LazyTreeProofGenerator : protected EnvObj, public ProofGenerator const std::vector& premise, std::vector args, Node proven); + /** + * Same as above, but with a trusted proof step. + */ + void setCurrentTrust(size_t objectId, + TrustId tid, + const std::vector& premise, + std::vector args, + Node proven); /** Construct the proof as a ProofNode */ std::shared_ptr getProof() const; /** Return the constructed proof. Checks that we have proven f */ diff --git a/src/proof/lfsc/lfsc_node_converter.cpp b/src/proof/lfsc/lfsc_node_converter.cpp index 2acf25e77dc..4cef3b4c760 100644 --- a/src/proof/lfsc/lfsc_node_converter.cpp +++ b/src/proof/lfsc/lfsc_node_converter.cpp @@ -1109,11 +1109,6 @@ Node LfscNodeConverter::getOperatorOfTerm(Node n, bool macroApply) opName << "u"; } opName << printer::smt2::Smt2Printer::smtKindString(k); - if (k == Kind::DIVISION_TOTAL || k == Kind::INTS_DIVISION_TOTAL - || k == Kind::INTS_MODULUS_TOTAL) - { - opName << "_total"; - } return getSymbolInternal(k, ftype, opName.str()); } diff --git a/src/proof/trust_id.cpp b/src/proof/trust_id.cpp index d540c678bdb..d4b5e53079e 100644 --- a/src/proof/trust_id.cpp +++ b/src/proof/trust_id.cpp @@ -35,8 +35,10 @@ const char* toString(TrustId id) case TrustId::THEORY_PREPROCESS: return "THEORY_PREPROCESS"; case TrustId::THEORY_PREPROCESS_LEMMA: return "THEORY_PREPROCESS_LEMMA"; case TrustId::THEORY_EXPAND_DEF: return "THEORY_EXPAND_DEF"; + case TrustId::ARITH_NL_COVERING_DIRECT: return "ARITH_NL_COVERING_DIRECT"; + case TrustId::ARITH_NL_COVERING_RECURSIVE: + return "ARITH_NL_COVERING_RECURSIVE"; case TrustId::EXT_THEORY_REWRITE: return "EXT_THEORY_REWRITE"; - case TrustId::WITNESS_AXIOM: return "WITNESS_AXIOM"; case TrustId::REWRITE_NO_ELABORATE: return "REWRITE_NO_ELABORATE"; case TrustId::FLATTENING_REWRITE: return "FLATTENING_REWRITE"; case TrustId::SUBS_NO_ELABORATE: return "SUBS_NO_ELABORATE"; diff --git a/src/proof/trust_id.h b/src/proof/trust_id.h index 4c686ff53f0..50a63acbebb 100644 --- a/src/proof/trust_id.h +++ b/src/proof/trust_id.h @@ -45,10 +45,58 @@ enum class TrustId : uint32_t THEORY_PREPROCESS_LEMMA, /** A expanding of definitions of the input formula made without a proof */ THEORY_EXPAND_DEF, + + /** + * We use :math:`\texttt{IRP}_k(poly)` for an IndexedRootPredicate that is + * defined as the :math:`k`'th root of the polynomial :math:`poly`. Note that + * :math:`poly` may not be univariate; in this case, the value of + * :math:`\texttt{IRP}_k(poly)` can only be calculated with respect to a + * (partial) model for all but one variable of :math:`poly`. + * + * A formula :math:`\texttt{Interval}(x_i)` describes that a variable + * :math:`x_i` is within a particular interval whose bounds are given as IRPs. + * It is either an open interval or a point interval: + * + * .. math:: + * \texttt{IRP}_k(poly) < x_i < \texttt{IRP}_k(poly) + * + * x_i = \texttt{IRP}_k(poly) + * + * A formula :math:`\texttt{Cell}(x_1 \dots x_i)` describes a portion + * of the real space in the following form: + * + * .. math:: + * \texttt{Interval}(x_1) \land \dots \land \texttt{Interval}(x_i) + * + * A cell can also be empty (for :math:`i = 0`). + * + * A formula :math:`\texttt{Covering}(x_i)` is a set of intervals, implying + * that :math:`x_i` can be in neither of these intervals. To be a covering (of + * the real line), the union of these intervals should be the real numbers. + * + * .. math:: + * \inferrule{\texttt{Cell}, A \mid -}{\bot} + * + * A direct interval is generated from an assumption :math:`A` (in variables + * :math:`x_1 \dots x_i`) over a :math:`\texttt{Cell}(x_1 \dots x_i)`. It + * derives that :math:`A` evaluates to false over the cell. In the actual + * algorithm, it means that :math:`x_i` can not be in the topmost interval of + * the cell. + */ + ARITH_NL_COVERING_DIRECT, + /** + * See ARITH_NL_COVERING_DIRECT for the necessary definitions. + * + * .. math:: + * \inferrule{\texttt{Cell}, \texttt{Covering} \mid -}{\bot} + * + * A recursive interval is generated from :math:`\texttt{Covering}(x_i)` over + * :math:`\texttt{Cell}(x_1 \dots x_{i-1})`. It generates the conclusion that + * no :math:`x_i` exists that extends the cell and satisfies all assumptions. + */ + ARITH_NL_COVERING_RECURSIVE, /** An extended theory rewrite */ EXT_THEORY_REWRITE, - /** An axiom for an introduced witness term without a corresponding proof */ - WITNESS_AXIOM, /** A rewrite whose proof could not be elaborated */ REWRITE_NO_ELABORATE, /** A flattening rewrite in an equality engine proof */ diff --git a/src/prop/sat_solver_types.h b/src/prop/sat_solver_types.h index 48a08a2c857..8c563b2ccc2 100644 --- a/src/prop/sat_solver_types.h +++ b/src/prop/sat_solver_types.h @@ -10,15 +10,7 @@ * directory for licensing information. * **************************************************************************** * - * This class transforms a sequence of formulas into clauses. - * - * This class takes a sequence of formulas. - * It outputs a stream of clauses that is propositionally - * equi-satisfiable with the conjunction of the formulas. - * This stream is maintained in an online fashion. - * - * Unlike other parts of the system it is aware of the PropEngine's - * internals such as the representation and translation of [??? -Chris] + * SAT solver types and type operations. */ #pragma once diff --git a/src/prop/theory_proxy.cpp b/src/prop/theory_proxy.cpp index ab51fcc1de7..a59a7f3b1e1 100644 --- a/src/prop/theory_proxy.cpp +++ b/src/prop/theory_proxy.cpp @@ -336,7 +336,7 @@ void TheoryProxy::notifySatClause(const SatClause& clause) // nothing to do if no plugins return; } - if (!d_inSolve && options().prop.pluginNotifySatClauseInSolve) + if (!d_inSolve && options().base.pluginNotifySatClauseInSolve) { // We are not in solving mode. We do not inform plugins of SAT clauses // if pluginNotifySatClauseInSolve is true (default). @@ -349,8 +349,8 @@ void TheoryProxy::notifySatClause(const SatClause& clause) clauseNodes.push_back(d_cnfStream->getNode(l)); } Node cln = NodeManager::currentNM()->mkOr(clauseNodes); - // getSharableFormula is independent of specific plugin, just use first - Node clns = plugins[0]->getSharableFormula(cln); + // get the sharable form of cln + Node clns = d_env.getSharableFormula(cln); if (!clns.isNull()) { Trace("theory-proxy") diff --git a/src/rewriter/rewrite_db_proof_cons.cpp b/src/rewriter/rewrite_db_proof_cons.cpp index 2132028eb93..457f34fc196 100644 --- a/src/rewriter/rewrite_db_proof_cons.cpp +++ b/src/rewriter/rewrite_db_proof_cons.cpp @@ -1179,6 +1179,8 @@ void RewriteDbProofCons::cacheProofSubPlaceholder(TNode context, std::unordered_map parent; std::vector congs; parent[context] = TNode::null(); + std::unordered_map visitedSrc; + std::unordered_map visitedTgt; while (!toVisit.empty()) { TNode curr = toVisit.back(); @@ -1189,8 +1191,10 @@ void RewriteDbProofCons::cacheProofSubPlaceholder(TNode context, TNode currp; while ((currp = parent[curr]) != Node::null()) { - Node lhs = currp.substitute(placeholder, source); - Node rhs = currp.substitute(placeholder, target); + Node lhs = + expr::narySubstitute(currp, {placeholder}, {source}, visitedSrc); + Node rhs = + expr::narySubstitute(currp, {placeholder}, {target}, visitedTgt); congs.emplace_back(lhs.eqNode(rhs)); curr = currp; } diff --git a/src/smt/env.cpp b/src/smt/env.cpp index a1465ce1aa7..3e7e3ad737d 100644 --- a/src/smt/env.cpp +++ b/src/smt/env.cpp @@ -18,6 +18,9 @@ #include "context/context.h" #include "expr/node.h" +#include "expr/node_algorithm.h" +#include "expr/skolem_manager.h" +#include "expr/subtype_elim_node_converter.h" #include "options/base_options.h" #include "options/printer_options.h" #include "options/quantifiers_options.h" @@ -306,4 +309,29 @@ bool Env::isBooleanTermSkolem(const Node& k) const return d_boolTermSkolems.find(k) != d_boolTermSkolems.end(); } +Node Env::getSharableFormula(const Node& n) const +{ + Node on = n; + // these kinds are never sharable + std::unordered_set ks = {Kind::INST_CONSTANT, + Kind::DUMMY_SKOLEM}; + if (!d_options.base.pluginShareSkolems) + { + // note we only remove purify skolems if the above option is disabled + on = SkolemManager::getOriginalForm(n); + // SKOLEM is additionally unsharable if option is set. + ks.insert(Kind::SKOLEM); + } + if (expr::hasSubtermKinds(ks, on)) + { + // We cannot share formulas with skolems currently. + // We should never share formulas with instantiation constants. + return Node::null(); + } + // also eliminate subtyping + SubtypeElimNodeConverter senc(d_nm); + on = senc.convert(on); + return on; +} + } // namespace cvc5::internal diff --git a/src/smt/env.h b/src/smt/env.h index 16842e5c9b2..7799d241344 100644 --- a/src/smt/env.h +++ b/src/smt/env.h @@ -299,6 +299,20 @@ class Env * @return true if k is a Boolean term skolem. */ bool isBooleanTermSkolem(const Node& k) const; + /** + * Get sharable formula. This returns an equivalent version of the given + * lemma n that can be shared externally. In particular, if the option + * pluginShareSkolems is false, we require that the returned formula does not + * have any internally generated symbols, i.e. skolems. We additionally + * exclude terms that have internally generated symbols (e.g. DUMMY_SKOLEM + * or INST_CONSTANT). If n cannot be converted to a suitable formula, we + * return the null node. + * + * @param n The candidate formula to share. + * @return A tranformed version of n that is its represenation in a sharable + * form. If n cannot be tranformed, this returns null. + */ + Node getSharableFormula(const Node& n) const; private: /* Private initialization ------------------------------------------------- */ diff --git a/src/smt/set_defaults.cpp b/src/smt/set_defaults.cpp index 1bf1233da88..ba351d7325b 100644 --- a/src/smt/set_defaults.cpp +++ b/src/smt/set_defaults.cpp @@ -656,7 +656,7 @@ void SetDefaults::setDefaultsPost(const LogicInfo& logic, Options& opts) const // Turn off array eager index splitting for QF_AUFLIA if (!opts.arrays.arraysEagerIndexSplittingWasSetByUser) { - if (not logic.isQuantified() && logic.isTheoryEnabled(THEORY_ARRAYS) + if (!logic.isQuantified() && logic.isTheoryEnabled(THEORY_ARRAYS) && logic.isTheoryEnabled(THEORY_UF) && logic.isTheoryEnabled(THEORY_ARITH)) { @@ -1679,51 +1679,49 @@ void SetDefaults::setDefaultDecisionMode(const LogicInfo& logic, usesSygus(opts) ? options::DecisionMode::INTERNAL : // ALL or its supersets logic.hasEverything() - ? options::DecisionMode::JUSTIFICATION - : ( // QF_BV - (not logic.isQuantified() && logic.isPure(THEORY_BV)) || - // QF_AUFBV or QF_ABV or QF_UFBV - (not logic.isQuantified() - && (logic.isTheoryEnabled(THEORY_ARRAYS) - || logic.isTheoryEnabled(THEORY_UF)) - && logic.isTheoryEnabled(THEORY_BV)) - || - // QF_AUFLIA (and may be ends up enabling - // QF_AUFLRA?) - (not logic.isQuantified() - && logic.isTheoryEnabled(THEORY_ARRAYS) - && logic.isTheoryEnabled(THEORY_UF) - && logic.isTheoryEnabled(THEORY_ARITH)) - || - // QF_LRA - (not logic.isQuantified() - && logic.isPure(THEORY_ARITH) && logic.isLinear() - && !logic.isDifferenceLogic() - && !logic.areIntegersUsed()) - || - // Quantifiers - logic.isQuantified() || - // Strings - logic.isTheoryEnabled(THEORY_STRINGS) - ? options::DecisionMode::JUSTIFICATION - : options::DecisionMode::INTERNAL); + ? options::DecisionMode::JUSTIFICATION + : ( // QF_BV + (!logic.isQuantified() && logic.isPure(THEORY_BV)) || + // QF_AUFBV or QF_ABV or QF_UFBV + (!logic.isQuantified() + && (logic.isTheoryEnabled(THEORY_ARRAYS) + || logic.isTheoryEnabled(THEORY_UF)) + && logic.isTheoryEnabled(THEORY_BV)) + || + // QF_AUFLIA (and may be ends up enabling + // QF_AUFLRA?) + (!logic.isQuantified() + && logic.isTheoryEnabled(THEORY_ARRAYS) + && logic.isTheoryEnabled(THEORY_UF) + && logic.isTheoryEnabled(THEORY_ARITH)) + || + // QF_LRA + (!logic.isQuantified() && logic.isPure(THEORY_ARITH) + && logic.isLinear() && !logic.isDifferenceLogic() + && !logic.areIntegersUsed()) + || + // Quantifiers + logic.isQuantified() || + // Strings + logic.isTheoryEnabled(THEORY_STRINGS) + ? options::DecisionMode::JUSTIFICATION + : options::DecisionMode::INTERNAL); bool stoponly = // ALL or its supersets logic.hasEverything() || logic.isTheoryEnabled(THEORY_STRINGS) ? false : ( // QF_AUFLIA - (not logic.isQuantified() - && logic.isTheoryEnabled(THEORY_ARRAYS) - && logic.isTheoryEnabled(THEORY_UF) - && logic.isTheoryEnabled(THEORY_ARITH)) - || - // QF_LRA - (not logic.isQuantified() && logic.isPure(THEORY_ARITH) - && logic.isLinear() && !logic.isDifferenceLogic() - && !logic.areIntegersUsed()) - ? true - : false); + (!logic.isQuantified() && logic.isTheoryEnabled(THEORY_ARRAYS) + && logic.isTheoryEnabled(THEORY_UF) + && logic.isTheoryEnabled(THEORY_ARITH)) + || + // QF_LRA + (!logic.isQuantified() && logic.isPure(THEORY_ARITH) + && logic.isLinear() && !logic.isDifferenceLogic() + && !logic.areIntegersUsed()) + ? true + : false); if (stoponly) { diff --git a/src/smt/term_formula_removal.cpp b/src/smt/term_formula_removal.cpp index 0e3aef56983..1fcf45a6d23 100644 --- a/src/smt/term_formula_removal.cpp +++ b/src/smt/term_formula_removal.cpp @@ -270,6 +270,7 @@ Node RemoveTermFormulas::runCurrentInternal(TNode node, uint32_t cval, TConvProofGenerator* pg) { + AlwaysAssert (node.getKind()!=Kind::WITNESS) << "WITNESS should never appear in asserted terms"; NodeManager *nodeManager = NodeManager::currentNM(); SkolemManager* sm = nodeManager->getSkolemManager(); @@ -339,60 +340,6 @@ Node RemoveTermFormulas::runCurrentInternal(TNode node, } } } - else if (node.getKind() == Kind::WITNESS) - { - // If a witness choice - // For details on this operator, see - // http://planetmath.org/hilbertsvarepsilonoperator. - if (!expr::hasFreeVar(node)) - { - // NOTE: we can replace by t if body is of the form (and (= z t) ...) - skolem = getSkolemForNode(node); - if (skolem.isNull()) - { - Trace("rtf-proof-debug") - << "RemoveTermFormulas::run: make WITNESS skolem" << std::endl; - // Make the skolem to witness the choice, which notice is handled - // as a special case within SkolemManager::mkPurifySkolem. - skolem = sm->mkPurifySkolem(node); - d_skolem_cache.insert(node, skolem); - if (nodeType.isBoolean() && inTerm) - { - // must treat as a Boolean term skolem - d_env.registerBooleanTermSkolem(skolem); - } - - Assert(node[0].getNumChildren() == 1); - - // The new assertion is the assumption that the body - // of the witness operator holds for the Skolem - newAssertion = node[1].substitute(node[0][0], skolem); - - // Get the proof generator, if one exists, which was responsible for - // constructing this witness term. This may not exist, in which case - // the witness term was trivial to justify. This is the case e.g. for - // purification witness terms. - if (isProofEnabled()) - { - Node existsAssertion = - nodeManager->mkNode(Kind::EXISTS, node[0], node[1]); - // -------------------- from skolem manager - // (exists x. node[1]) - // -------------------- SKOLEMIZE - // node[1] * { x -> skolem } - ProofGenerator* expg = sm->getProofGenerator(existsAssertion); - d_lp->addLazyStep(existsAssertion, - expg, - TrustId::WITNESS_AXIOM, - true, - "RemoveTermFormulas::run:skolem_pf"); - d_lp->addStep( - newAssertion, ProofRule::SKOLEMIZE, {existsAssertion}, {}); - newAssertionPg = d_lp.get(); - } - } - } - } else if (nodeType.isBoolean() && inTerm && !d_env.isBooleanTermSkolem(node)) { // if a purification skolem already, just use itself diff --git a/src/theory/arith/linear/constraint.cpp b/src/theory/arith/linear/constraint.cpp index 2c60caa4c78..283dc114768 100644 --- a/src/theory/arith/linear/constraint.cpp +++ b/src/theory/arith/linear/constraint.cpp @@ -626,7 +626,7 @@ void Constraint::printProofTree(std::ostream& out, size_t depth) const bool first = true; for (const auto& coeff : *rule.d_farkasCoefficients) { - if (not first) + if (!first) { out << ", "; } diff --git a/src/theory/arith/nl/coverings/proof_checker.cpp b/src/theory/arith/nl/coverings/proof_checker.cpp index 320d859c09b..f24bf6ba388 100644 --- a/src/theory/arith/nl/coverings/proof_checker.cpp +++ b/src/theory/arith/nl/coverings/proof_checker.cpp @@ -33,30 +33,12 @@ CoveringsProofRuleChecker::CoveringsProofRuleChecker(NodeManager* nm) void CoveringsProofRuleChecker::registerTo(ProofChecker* pc) { - // trusted rules - pc->registerTrustedChecker(ProofRule::ARITH_NL_COVERING_DIRECT, this, 2); - pc->registerTrustedChecker(ProofRule::ARITH_NL_COVERING_RECURSIVE, this, 2); } Node CoveringsProofRuleChecker::checkInternal(ProofRule id, const std::vector& children, const std::vector& args) { - Trace("nl-cov-checker") << "Checking " << id << std::endl; - for (const auto& c : children) - { - Trace("nl-cov-checker") << "\t" << c << std::endl; - } - if (id == ProofRule::ARITH_NL_COVERING_DIRECT) - { - Assert(args.size() == 1); - return args[0]; - } - if (id == ProofRule::ARITH_NL_COVERING_RECURSIVE) - { - Assert(args.size() == 1); - return args[0]; - } return Node::null(); } diff --git a/src/theory/arith/nl/coverings/proof_generator.cpp b/src/theory/arith/nl/coverings/proof_generator.cpp index d233f868832..4b497c771ee 100644 --- a/src/theory/arith/nl/coverings/proof_generator.cpp +++ b/src/theory/arith/nl/coverings/proof_generator.cpp @@ -107,11 +107,8 @@ void CoveringsProofGenerator::startNewProof() void CoveringsProofGenerator::startRecursive() { d_current->openChild(); } void CoveringsProofGenerator::endRecursive(size_t intervalId) { - d_current->setCurrent(intervalId, - ProofRule::ARITH_NL_COVERING_RECURSIVE, - {}, - {d_false}, - d_false); + d_current->setCurrentTrust( + intervalId, TrustId::ARITH_NL_COVERING_RECURSIVE, {}, {d_false}, d_false); d_current->closeChild(); } void CoveringsProofGenerator::startScope() @@ -144,11 +141,11 @@ void CoveringsProofGenerator::addDirect(Node var, { // "Full conflict", constraint excludes (-inf,inf) d_current->openChild(); - d_current->setCurrent(intervalId, - ProofRule::ARITH_NL_COVERING_DIRECT, - {constraint}, - {d_false}, - d_false); + d_current->setCurrentTrust(intervalId, + TrustId::ARITH_NL_COVERING_DIRECT, + {constraint}, + {d_false}, + d_false); d_current->closeChild(); return; } @@ -185,11 +182,11 @@ void CoveringsProofGenerator::addDirect(Node var, // Add to proof manager startScope(); d_current->openChild(); - d_current->setCurrent(intervalId, - ProofRule::ARITH_NL_COVERING_DIRECT, - {constraint}, - {d_false}, - d_false); + d_current->setCurrentTrust(intervalId, + TrustId::ARITH_NL_COVERING_DIRECT, + {constraint}, + {d_false}, + d_false); d_current->closeChild(); endScope(res); } diff --git a/src/theory/bv/theory_bv_rewriter.cpp b/src/theory/bv/theory_bv_rewriter.cpp index 5f3c17509a0..51333b5418e 100644 --- a/src/theory/bv/theory_bv_rewriter.cpp +++ b/src/theory/bv/theory_bv_rewriter.cpp @@ -13,6 +13,8 @@ * Theory BV rewriter. */ +#include "theory/bv/theory_bv_rewriter.h" + #include "options/bv_options.h" #include "theory/bv/theory_bv_rewrite_rules.h" #include "theory/bv/theory_bv_rewrite_rules_constant_evaluation.h" @@ -20,7 +22,6 @@ #include "theory/bv/theory_bv_rewrite_rules_normalization.h" #include "theory/bv/theory_bv_rewrite_rules_operator_elimination.h" #include "theory/bv/theory_bv_rewrite_rules_simplification.h" -#include "theory/bv/theory_bv_rewriter.h" #include "theory/theory.h" using namespace cvc5::internal; @@ -30,6 +31,16 @@ using namespace cvc5::internal::theory::bv; TheoryBVRewriter::TheoryBVRewriter(NodeManager* nm) : TheoryRewriter(nm) { initializeRewrites(); + registerProofRewriteRule(ProofRewriteRule::BV_UMULO_ELIMINATE, + TheoryRewriteCtx::POST_DSL); + registerProofRewriteRule(ProofRewriteRule::BV_SMULO_ELIMINATE, + TheoryRewriteCtx::POST_DSL); + registerProofRewriteRule(ProofRewriteRule::BV_ADD_COMBINE_LIKE_TERMS, + TheoryRewriteCtx::POST_DSL); + registerProofRewriteRule(ProofRewriteRule::BV_MULT_SIMPLIFY, + TheoryRewriteCtx::POST_DSL); + registerProofRewriteRule(ProofRewriteRule::BV_BITWISE_SLICING, + TheoryRewriteCtx::POST_DSL); } RewriteResponse TheoryBVRewriter::preRewrite(TNode node) @@ -38,7 +49,8 @@ RewriteResponse TheoryBVRewriter::preRewrite(TNode node) d_rewriteTable[static_cast(node.getKind())](node, true); if (res.d_node != node) { - Trace("bitvector-rewrite") << "TheoryBV::preRewrite " << node << std::endl; + Trace("bitvector-rewrite") + << "TheoryBV::preRewrite " << node << std::endl; Trace("bitvector-rewrite") << "TheoryBV::preRewrite to " << res.d_node << std::endl; } @@ -51,12 +63,39 @@ RewriteResponse TheoryBVRewriter::postRewrite(TNode node) d_rewriteTable[static_cast(node.getKind())](node, false); if (res.d_node != node) { - Trace("bitvector-rewrite") << "TheoryBV::postRewrite " << node << std::endl; + Trace("bitvector-rewrite") + << "TheoryBV::postRewrite " << node << std::endl; Trace("bitvector-rewrite") << "TheoryBV::postRewrite to " << res.d_node << std::endl; } return res; } +Node TheoryBVRewriter::rewriteViaRule(ProofRewriteRule id, const Node& n) +{ + switch (id) + { +#define BV_PROOF_REWRITE_CASE(rule) \ + { \ + if (RewriteRule::applies(n)) \ + { \ + return LinearRewriteStrategy>::apply(n); \ + } \ + break; \ + } \ + /* end of macro */ + case ProofRewriteRule::BV_UMULO_ELIMINATE: + BV_PROOF_REWRITE_CASE(UmuloEliminate) + case ProofRewriteRule::BV_SMULO_ELIMINATE: + BV_PROOF_REWRITE_CASE(SmuloEliminate) + case ProofRewriteRule::BV_ADD_COMBINE_LIKE_TERMS: + BV_PROOF_REWRITE_CASE(AddCombineLikeTerms) + case ProofRewriteRule::BV_MULT_SIMPLIFY: BV_PROOF_REWRITE_CASE(MultSimplify) + case ProofRewriteRule::BV_BITWISE_SLICING: + BV_PROOF_REWRITE_CASE(BitwiseSlicing) + default: break; + } + return Node::null(); +} RewriteResponse TheoryBVRewriter::RewriteBitOf(TNode node, bool prerewrite) { @@ -64,7 +103,8 @@ RewriteResponse TheoryBVRewriter::RewriteBitOf(TNode node, bool prerewrite) return RewriteResponse(REWRITE_DONE, resultNode); } -RewriteResponse TheoryBVRewriter::RewriteUlt(TNode node, bool prerewrite) { +RewriteResponse TheoryBVRewriter::RewriteUlt(TNode node, bool prerewrite) +{ // reduce common subexpressions on both sides Node resultNode = LinearRewriteStrategy, // if both arguments are @@ -80,21 +120,19 @@ RewriteResponse TheoryBVRewriter::RewriteUlt(TNode node, bool prerewrite) { resultNode); } -RewriteResponse TheoryBVRewriter::RewriteUltBv(TNode node, bool prerewrite) { +RewriteResponse TheoryBVRewriter::RewriteUltBv(TNode node, bool prerewrite) +{ // reduce common subexpressions on both sides - Node resultNode = LinearRewriteStrategy - < RewriteRule - >::apply(node); + Node resultNode = LinearRewriteStrategy>::apply(node); return RewriteResponse(REWRITE_DONE, resultNode); } - -RewriteResponse TheoryBVRewriter::RewriteSlt(TNode node, bool prerewrite){ - Node resultNode = LinearRewriteStrategy - < RewriteRule, - RewriteRule - >::apply(node); +RewriteResponse TheoryBVRewriter::RewriteSlt(TNode node, bool prerewrite) +{ + Node resultNode = + LinearRewriteStrategy, + RewriteRule>::apply(node); return RewriteResponse(REWRITE_DONE, resultNode); @@ -106,15 +144,15 @@ RewriteResponse TheoryBVRewriter::RewriteSlt(TNode node, bool prerewrite){ // return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); } -RewriteResponse TheoryBVRewriter::RewriteSltBv(TNode node, bool prerewrite){ - Node resultNode = LinearRewriteStrategy - < RewriteRule < EvalSltBv > - >::apply(node); +RewriteResponse TheoryBVRewriter::RewriteSltBv(TNode node, bool prerewrite) +{ + Node resultNode = LinearRewriteStrategy>::apply(node); return RewriteResponse(REWRITE_DONE, resultNode); } -RewriteResponse TheoryBVRewriter::RewriteUle(TNode node, bool prerewrite){ +RewriteResponse TheoryBVRewriter::RewriteUle(TNode node, bool prerewrite) +{ Node resultNode = LinearRewriteStrategy, RewriteRule, @@ -127,7 +165,8 @@ RewriteResponse TheoryBVRewriter::RewriteUle(TNode node, bool prerewrite){ resultNode); } -RewriteResponse TheoryBVRewriter::RewriteSle(TNode node, bool prerewrite){ +RewriteResponse TheoryBVRewriter::RewriteSle(TNode node, bool prerewrite) +{ Node resultNode = LinearRewriteStrategy, RewriteRule>::apply(node); @@ -135,7 +174,8 @@ RewriteResponse TheoryBVRewriter::RewriteSle(TNode node, bool prerewrite){ resultNode); } -RewriteResponse TheoryBVRewriter::RewriteUgt(TNode node, bool prerewrite){ +RewriteResponse TheoryBVRewriter::RewriteUgt(TNode node, bool prerewrite) +{ Node resultNode = LinearRewriteStrategy, RewriteRule>::apply(node); @@ -143,28 +183,28 @@ RewriteResponse TheoryBVRewriter::RewriteUgt(TNode node, bool prerewrite){ return RewriteResponse(REWRITE_AGAIN, resultNode); } -RewriteResponse TheoryBVRewriter::RewriteSgt(TNode node, bool prerewrite){ - Node resultNode = LinearRewriteStrategy - < RewriteRule - //RewriteRule - >::apply(node); +RewriteResponse TheoryBVRewriter::RewriteSgt(TNode node, bool prerewrite) +{ + Node resultNode = LinearRewriteStrategy + // RewriteRule + >::apply(node); return RewriteResponse(REWRITE_AGAIN, resultNode); } -RewriteResponse TheoryBVRewriter::RewriteUge(TNode node, bool prerewrite){ - Node resultNode = LinearRewriteStrategy - < RewriteRule - >::apply(node); +RewriteResponse TheoryBVRewriter::RewriteUge(TNode node, bool prerewrite) +{ + Node resultNode = + LinearRewriteStrategy>::apply(node); return RewriteResponse(REWRITE_AGAIN, resultNode); } -RewriteResponse TheoryBVRewriter::RewriteSge(TNode node, bool prerewrite){ - Node resultNode = LinearRewriteStrategy - < RewriteRule - // RewriteRule - >::apply(node); +RewriteResponse TheoryBVRewriter::RewriteSge(TNode node, bool prerewrite) +{ + Node resultNode = LinearRewriteStrategy + // RewriteRule + >::apply(node); return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); } @@ -202,7 +242,8 @@ RewriteResponse TheoryBVRewriter::RewriteITEBv(TNode node, bool prerewrite) resultNode); } -RewriteResponse TheoryBVRewriter::RewriteNot(TNode node, bool prerewrite){ +RewriteResponse TheoryBVRewriter::RewriteNot(TNode node, bool prerewrite) +{ Node resultNode = node; resultNode = @@ -215,20 +256,24 @@ RewriteResponse TheoryBVRewriter::RewriteNot(TNode node, bool prerewrite){ return RewriteResponse(REWRITE_DONE, resultNode); } -RewriteResponse TheoryBVRewriter::RewriteExtract(TNode node, bool prerewrite) { +RewriteResponse TheoryBVRewriter::RewriteExtract(TNode node, bool prerewrite) +{ Node resultNode = node; - if (RewriteRule::applies(node)) { + if (RewriteRule::applies(node)) + { resultNode = RewriteRule::run(node); return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); } - if (RewriteRule::applies(node)) { + if (RewriteRule::applies(node)) + { resultNode = RewriteRule::run(node); return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); } - if (RewriteRule::applies(node)) { + if (RewriteRule::applies(node)) + { resultNode = RewriteRule::run(node); return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); } @@ -337,26 +382,26 @@ RewriteResponse TheoryBVRewriter::RewriteXor(TNode node, bool prerewrite) return RewriteResponse(REWRITE_DONE, resultNode); } -RewriteResponse TheoryBVRewriter::RewriteXnor(TNode node, bool prerewrite) { - Node resultNode = LinearRewriteStrategy - < RewriteRule - >::apply(node); +RewriteResponse TheoryBVRewriter::RewriteXnor(TNode node, bool prerewrite) +{ + Node resultNode = + LinearRewriteStrategy>::apply(node); // need to rewrite two levels in return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); } -RewriteResponse TheoryBVRewriter::RewriteNand(TNode node, bool prerewrite) { - Node resultNode = LinearRewriteStrategy - < RewriteRule - >::apply(node); +RewriteResponse TheoryBVRewriter::RewriteNand(TNode node, bool prerewrite) +{ + Node resultNode = + LinearRewriteStrategy>::apply(node); return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); } -RewriteResponse TheoryBVRewriter::RewriteNor(TNode node, bool prerewrite) { - Node resultNode = LinearRewriteStrategy - < RewriteRule - >::apply(node); +RewriteResponse TheoryBVRewriter::RewriteNor(TNode node, bool prerewrite) +{ + Node resultNode = + LinearRewriteStrategy>::apply(node); return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); } @@ -395,23 +440,26 @@ RewriteResponse TheoryBVRewriter::RewriteEagerAtom(TNode node, bool prerewrite) return RewriteResponse(REWRITE_DONE, resultNode); } -RewriteResponse TheoryBVRewriter::RewriteMult(TNode node, bool prerewrite) { +RewriteResponse TheoryBVRewriter::RewriteMult(TNode node, bool prerewrite) +{ Node resultNode = node; - resultNode = LinearRewriteStrategy - < RewriteRule, // flattens and sorts - RewriteRule, // multiplies constant part and checks for 0 - RewriteRule // replaces multiplication by a power of 2 by a shift - >::apply(resultNode); + resultNode = LinearRewriteStrategy< + RewriteRule, // flattens and sorts + RewriteRule, // multiplies constant part and checks for 0 + RewriteRule // replaces multiplication by a power of 2 by a + // shift + >::apply(resultNode); // only apply if every subterm was already rewritten - if (!prerewrite) { - resultNode = LinearRewriteStrategy - < RewriteRule - , RewriteRule - >::apply(resultNode); + if (!prerewrite) + { + resultNode = + LinearRewriteStrategy, + RewriteRule>::apply(resultNode); } - if(resultNode == node) { + if (resultNode == node) + { return RewriteResponse(REWRITE_DONE, resultNode); } return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); @@ -420,10 +468,10 @@ RewriteResponse TheoryBVRewriter::RewriteMult(TNode node, bool prerewrite) { RewriteResponse TheoryBVRewriter::RewriteAdd(TNode node, bool prerewrite) { Node resultNode = node; - if (prerewrite) { - resultNode = LinearRewriteStrategy - < RewriteRule - >::apply(node); + if (prerewrite) + { + resultNode = + LinearRewriteStrategy>::apply(node); return RewriteResponse(REWRITE_DONE, resultNode); } @@ -431,30 +479,30 @@ RewriteResponse TheoryBVRewriter::RewriteAdd(TNode node, bool prerewrite) LinearRewriteStrategy, RewriteRule>::apply(node); - if (node != resultNode) { + if (node != resultNode) + { return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); } return RewriteResponse(REWRITE_DONE, resultNode); } -RewriteResponse TheoryBVRewriter::RewriteSub(TNode node, bool prerewrite){ +RewriteResponse TheoryBVRewriter::RewriteSub(TNode node, bool prerewrite) +{ // return RewriteResponse(REWRITE_DONE, node); - Node resultNode = LinearRewriteStrategy - < RewriteRule - >::apply(node); + Node resultNode = + LinearRewriteStrategy>::apply(node); return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); } -RewriteResponse TheoryBVRewriter::RewriteNeg(TNode node, bool prerewrite) { +RewriteResponse TheoryBVRewriter::RewriteNeg(TNode node, bool prerewrite) +{ Node resultNode = node; - resultNode = LinearRewriteStrategy - < RewriteRule, - RewriteRule, - RewriteRule - >::apply(node); + resultNode = LinearRewriteStrategy, + RewriteRule, + RewriteRule>::apply(node); if (RewriteRule::applies(node)) { @@ -462,8 +510,10 @@ RewriteResponse TheoryBVRewriter::RewriteNeg(TNode node, bool prerewrite) { return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); } - if(!prerewrite) { - if (RewriteRule::applies(node)) { + if (!prerewrite) + { + if (RewriteRule::applies(node)) + { resultNode = RewriteRule::run(node); return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); } @@ -476,17 +526,19 @@ RewriteResponse TheoryBVRewriter::RewriteNeg(TNode node, bool prerewrite) { resultNode); } -RewriteResponse TheoryBVRewriter::RewriteUdiv(TNode node, bool prerewrite){ +RewriteResponse TheoryBVRewriter::RewriteUdiv(TNode node, bool prerewrite) +{ Node resultNode = node; - if(RewriteRule::applies(node)) { - resultNode = RewriteRule::run (node); + if (RewriteRule::applies(node)) + { + resultNode = RewriteRule::run(node); return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); } - resultNode = - LinearRewriteStrategy, RewriteRule, - RewriteRule >::apply(node); + resultNode = LinearRewriteStrategy, + RewriteRule, + RewriteRule>::apply(node); return RewriteResponse(REWRITE_DONE, resultNode); } @@ -495,46 +547,47 @@ RewriteResponse TheoryBVRewriter::RewriteUrem(TNode node, bool prerewrite) { Node resultNode = node; - if(RewriteRule::applies(node)) { - resultNode = RewriteRule::run (node); + if (RewriteRule::applies(node)) + { + resultNode = RewriteRule::run(node); return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); } - resultNode = LinearRewriteStrategy - < RewriteRule, - RewriteRule, - RewriteRule - >::apply(node); + resultNode = LinearRewriteStrategy, + RewriteRule, + RewriteRule>::apply(node); return RewriteResponse(REWRITE_DONE, resultNode); } -RewriteResponse TheoryBVRewriter::RewriteSmod(TNode node, bool prerewrite) { - Node resultNode = LinearRewriteStrategy - < RewriteRule - >::apply(node); +RewriteResponse TheoryBVRewriter::RewriteSmod(TNode node, bool prerewrite) +{ + Node resultNode = + LinearRewriteStrategy>::apply(node); return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); } -RewriteResponse TheoryBVRewriter::RewriteSdiv(TNode node, bool prerewrite) { - Node resultNode = LinearRewriteStrategy - < RewriteRule - >::apply(node); +RewriteResponse TheoryBVRewriter::RewriteSdiv(TNode node, bool prerewrite) +{ + Node resultNode = + LinearRewriteStrategy>::apply(node); return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); } -RewriteResponse TheoryBVRewriter::RewriteSrem(TNode node, bool prerewrite) { - Node resultNode = LinearRewriteStrategy - < RewriteRule - >::apply(node); +RewriteResponse TheoryBVRewriter::RewriteSrem(TNode node, bool prerewrite) +{ + Node resultNode = + LinearRewriteStrategy>::apply(node); return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); } -RewriteResponse TheoryBVRewriter::RewriteShl(TNode node, bool prerewrite) { +RewriteResponse TheoryBVRewriter::RewriteShl(TNode node, bool prerewrite) +{ Node resultNode = node; - if(RewriteRule::applies(node)) { - resultNode = RewriteRule::run (node); + if (RewriteRule::applies(node)) + { + resultNode = RewriteRule::run(node); return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); } @@ -544,10 +597,12 @@ RewriteResponse TheoryBVRewriter::RewriteShl(TNode node, bool prerewrite) { return RewriteResponse(REWRITE_DONE, resultNode); } -RewriteResponse TheoryBVRewriter::RewriteLshr(TNode node, bool prerewrite) { +RewriteResponse TheoryBVRewriter::RewriteLshr(TNode node, bool prerewrite) +{ Node resultNode = node; - if(RewriteRule::applies(node)) { - resultNode = RewriteRule::run (node); + if (RewriteRule::applies(node)) + { + resultNode = RewriteRule::run(node); return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); } @@ -557,63 +612,63 @@ RewriteResponse TheoryBVRewriter::RewriteLshr(TNode node, bool prerewrite) { return RewriteResponse(REWRITE_DONE, resultNode); } -RewriteResponse TheoryBVRewriter::RewriteAshr(TNode node, bool prerewrite) { +RewriteResponse TheoryBVRewriter::RewriteAshr(TNode node, bool prerewrite) +{ Node resultNode = node; - if(RewriteRule::applies(node)) { - resultNode = RewriteRule::run (node); + if (RewriteRule::applies(node)) + { + resultNode = RewriteRule::run(node); return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); } - resultNode = LinearRewriteStrategy - < RewriteRule, - RewriteRule - >::apply(node); + resultNode = LinearRewriteStrategy, + RewriteRule>::apply(node); return RewriteResponse(REWRITE_DONE, resultNode); } - -RewriteResponse TheoryBVRewriter::RewriteRepeat(TNode node, bool prerewrite) { - Node resultNode = LinearRewriteStrategy - < RewriteRule - >::apply(node); +RewriteResponse TheoryBVRewriter::RewriteRepeat(TNode node, bool prerewrite) +{ + Node resultNode = + LinearRewriteStrategy>::apply(node); return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); } -RewriteResponse TheoryBVRewriter::RewriteZeroExtend(TNode node, bool prerewrite){ - Node resultNode = LinearRewriteStrategy - < RewriteRule - >::apply(node); +RewriteResponse TheoryBVRewriter::RewriteZeroExtend(TNode node, bool prerewrite) +{ + Node resultNode = + LinearRewriteStrategy>::apply(node); return RewriteResponse(REWRITE_AGAIN, resultNode); } -RewriteResponse TheoryBVRewriter::RewriteSignExtend(TNode node, bool prerewrite) { - Node resultNode = LinearRewriteStrategy - < RewriteRule - , RewriteRule - >::apply(node); +RewriteResponse TheoryBVRewriter::RewriteSignExtend(TNode node, bool prerewrite) +{ + Node resultNode = + LinearRewriteStrategy, + RewriteRule>::apply(node); - if (resultNode != node) { + if (resultNode != node) + { return RewriteResponse(REWRITE_AGAIN, resultNode); } return RewriteResponse(REWRITE_DONE, resultNode); } - -RewriteResponse TheoryBVRewriter::RewriteRotateRight(TNode node, bool prerewrite) { - Node resultNode = LinearRewriteStrategy - < RewriteRule - >::apply(node); +RewriteResponse TheoryBVRewriter::RewriteRotateRight(TNode node, + bool prerewrite) +{ + Node resultNode = + LinearRewriteStrategy>::apply(node); return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); } -RewriteResponse TheoryBVRewriter::RewriteRotateLeft(TNode node, bool prerewrite){ - Node resultNode = LinearRewriteStrategy - < RewriteRule - >::apply(node); +RewriteResponse TheoryBVRewriter::RewriteRotateLeft(TNode node, bool prerewrite) +{ + Node resultNode = + LinearRewriteStrategy>::apply(node); return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); } @@ -634,21 +689,22 @@ RewriteResponse TheoryBVRewriter::RewriteRedand(TNode node, bool prerewrite) return RewriteResponse(REWRITE_AGAIN_FULL, resultNode); } -RewriteResponse TheoryBVRewriter::RewriteEqual(TNode node, bool prerewrite) { - if (prerewrite) { - Node resultNode = LinearRewriteStrategy - < RewriteRule, - RewriteRule, - RewriteRule - >::apply(node); +RewriteResponse TheoryBVRewriter::RewriteEqual(TNode node, bool prerewrite) +{ + if (prerewrite) + { + Node resultNode = + LinearRewriteStrategy, + RewriteRule, + RewriteRule>::apply(node); return RewriteResponse(REWRITE_DONE, resultNode); } - else { - Node resultNode = LinearRewriteStrategy - < RewriteRule, - RewriteRule, - RewriteRule - >::apply(node); + else + { + Node resultNode = + LinearRewriteStrategy, + RewriteRule, + RewriteRule>::apply(node); return RewriteResponse(REWRITE_DONE, resultNode); } @@ -718,11 +774,13 @@ RewriteResponse TheoryBVRewriter::RewriteSdivo(TNode node, bool prerewrite) return RewriteResponse(REWRITE_AGAIN, resultNode); } -RewriteResponse TheoryBVRewriter::IdentityRewrite(TNode node, bool prerewrite) { +RewriteResponse TheoryBVRewriter::IdentityRewrite(TNode node, bool prerewrite) +{ return RewriteResponse(REWRITE_DONE, node); } -RewriteResponse TheoryBVRewriter::UndefinedRewrite(TNode node, bool prerewrite) { +RewriteResponse TheoryBVRewriter::UndefinedRewrite(TNode node, bool prerewrite) +{ Trace("bv-rewrite") << "TheoryBV::UndefinedRewrite for" << node; Unimplemented(); } @@ -731,7 +789,7 @@ void TheoryBVRewriter::initializeRewrites() { for (unsigned i = 0; i < static_cast(Kind::LAST_KIND); ++i) { - d_rewriteTable[i] = IdentityRewrite; //UndefinedRewrite; + d_rewriteTable[i] = IdentityRewrite; // UndefinedRewrite; } d_rewriteTable[static_cast(Kind::EQUAL)] = RewriteEqual; diff --git a/src/theory/bv/theory_bv_rewriter.h b/src/theory/bv/theory_bv_rewriter.h index c3f9373c594..9cb6dfe2cd0 100644 --- a/src/theory/bv/theory_bv_rewriter.h +++ b/src/theory/bv/theory_bv_rewriter.h @@ -33,7 +33,14 @@ class TheoryBVRewriter : public TheoryRewriter RewriteResponse postRewrite(TNode node) override; RewriteResponse preRewrite(TNode node) override; - + /** + * Rewrite n based on the proof rewrite rule id. + * @param id The rewrite rule. + * @param n The node to rewrite. + * @return The rewritten version of n based on id, or Node::null() if n + * cannot be rewritten. + */ + Node rewriteViaRule(ProofRewriteRule id, const Node& n) override; private: static RewriteResponse IdentityRewrite(TNode node, bool prerewrite = false); static RewriteResponse UndefinedRewrite(TNode node, bool prerewrite = false); diff --git a/src/theory/plugin_module.cpp b/src/theory/plugin_module.cpp index 75a259c6c8f..9d26187664f 100644 --- a/src/theory/plugin_module.cpp +++ b/src/theory/plugin_module.cpp @@ -63,7 +63,7 @@ void PluginModule::notifyLemma(TNode n, void PluginModule::notifyLemmaInternal(const Node& n) { - Node ns = d_plugin->getSharableFormula(n); + Node ns = d_env.getSharableFormula(n); if (!ns.isNull()) { d_plugin->notifyTheoryLemma(ns); diff --git a/src/theory/quantifiers/quantifiers_rewriter.cpp b/src/theory/quantifiers/quantifiers_rewriter.cpp index 4c39eb5c8ae..72ca8eb3085 100644 --- a/src/theory/quantifiers/quantifiers_rewriter.cpp +++ b/src/theory/quantifiers/quantifiers_rewriter.cpp @@ -574,14 +574,15 @@ Node QuantifiersRewriter::computeProcessTerms2( // to be over the fresh variables instead. std::vector oldVars; std::vector newVars; - for (const Node& v : body[0]) + for (size_t i = 0, nvars = body[0].getNumChildren(); i < nvars; i++) { + const Node& v = body[0][i]; if (std::find(args.begin(), args.end(), v) != args.end()) { Trace("quantifiers-rewrite-unshadow") << "Found shadowed variable " << v << " in " << q << std::endl; oldVars.push_back(v); - Node nv = ElimShadowNodeConverter::getElimShadowVar(q, body, v); + Node nv = ElimShadowNodeConverter::getElimShadowVar(q, body, i); newVars.push_back(nv); } } diff --git a/src/theory/sets/inference_manager.cpp b/src/theory/sets/inference_manager.cpp index dafc0e5f883..cd7ed682337 100644 --- a/src/theory/sets/inference_manager.cpp +++ b/src/theory/sets/inference_manager.cpp @@ -44,7 +44,7 @@ InferenceManager::InferenceManager(Env& env, bool InferenceManager::assertFactRec(Node fact, InferenceId id, Node exp, int inferType) { // should we send this fact out as a lemma? - if ((options().sets.setsInferAsLemmas && inferType != -1) || inferType == 1) + if (inferType != -1) { if (d_state.isEntailed(fact, true)) { diff --git a/src/theory/strings/proof_checker.cpp b/src/theory/strings/proof_checker.cpp index 03acb956a70..40cb7bc4b90 100644 --- a/src/theory/strings/proof_checker.cpp +++ b/src/theory/strings/proof_checker.cpp @@ -58,7 +58,7 @@ void StringProofRuleChecker::registerTo(ProofChecker* pc) pc->registerChecker(ProofRule::RE_UNFOLD_POS, this); pc->registerChecker(ProofRule::RE_UNFOLD_NEG, this); pc->registerChecker(ProofRule::RE_UNFOLD_NEG_CONCAT_FIXED, this); - pc->registerChecker(ProofRule::RE_ELIM, this); + pc->registerChecker(ProofRule::MACRO_RE_ELIM, this); pc->registerChecker(ProofRule::STRING_CODE_INJ, this); pc->registerChecker(ProofRule::STRING_SEQ_UNIT_INJ, this); // trusted rule @@ -475,7 +475,7 @@ Node StringProofRuleChecker::checkInternal(ProofRule id, } return conc; } - else if (id == ProofRule::RE_ELIM) + else if (id == ProofRule::MACRO_RE_ELIM) { Assert(children.empty()); Assert(args.size() == 2); diff --git a/src/theory/strings/regexp_elim.cpp b/src/theory/strings/regexp_elim.cpp index 195ab6cf018..a0148eb91bc 100644 --- a/src/theory/strings/regexp_elim.cpp +++ b/src/theory/strings/regexp_elim.cpp @@ -83,7 +83,7 @@ TrustNode RegExpElimination::eliminateTrusted(Node atom) Node eq = atom.eqNode(eatom); Node aggn = NodeManager::currentNM()->mkConst(d_isAggressive); std::shared_ptr pn = - pnm->mkNode(ProofRule::RE_ELIM, {}, {atom, aggn}, eq); + pnm->mkNode(ProofRule::MACRO_RE_ELIM, {}, {atom, aggn}, eq); d_epg->setProofFor(eq, pn); return TrustNode::mkTrustRewrite(atom, eatom, d_epg.get()); } diff --git a/src/theory/strings/sequences_rewriter.cpp b/src/theory/strings/sequences_rewriter.cpp index 56dab563a97..5ce612e672d 100644 --- a/src/theory/strings/sequences_rewriter.cpp +++ b/src/theory/strings/sequences_rewriter.cpp @@ -53,6 +53,8 @@ SequencesRewriter::SequencesRewriter(NodeManager* nm, TheoryRewriteCtx::PRE_DSL); registerProofRewriteRule(ProofRewriteRule::STR_IN_RE_EVAL, TheoryRewriteCtx::DSL_SUBCALL); + registerProofRewriteRule(ProofRewriteRule::STR_IN_RE_CONSUME, + TheoryRewriteCtx::PRE_DSL); registerProofRewriteRule(ProofRewriteRule::STR_IN_RE_CONCAT_STAR_CHAR, TheoryRewriteCtx::PRE_DSL); registerProofRewriteRule(ProofRewriteRule::STR_IN_RE_SIGMA, @@ -68,6 +70,8 @@ Node SequencesRewriter::rewriteViaRule(ProofRewriteRule id, const Node& n) case ProofRewriteRule::RE_LOOP_ELIM: return rewriteViaReLoopElim(n); case ProofRewriteRule::STR_IN_RE_EVAL: return rewriteViaStrInReEval(n); + case ProofRewriteRule::STR_IN_RE_CONSUME: + return rewriteViaStrInReConsume(n); case ProofRewriteRule::STR_IN_RE_CONCAT_STAR_CHAR: return rewriteViaStrInReConcatStarChar(n); case ProofRewriteRule::STR_IN_RE_SIGMA: return rewriteViaStrInReSigma(n); @@ -1470,6 +1474,40 @@ Node SequencesRewriter::rewriteRangeRegExp(TNode node) return node; } +Node SequencesRewriter::rewriteViaStrInReConsume(const Node& node) +{ + if (node.getKind() != Kind::STRING_IN_REGEXP) + { + return Node::null(); + } + std::vector children; + utils::getConcat(node[1], children); + std::vector mchildren; + utils::getConcat(node[0], mchildren); + Node scn = RegExpEntail::simpleRegexpConsume(mchildren, children); + if (!scn.isNull()) + { + return scn; + } + else + { + // Given a membership (str.++ x1 ... xn) in (re.++ r1 ... rm), + // above, we strip components to construct an equivalent membership: + // (str.++ xi .. xj) in (re.++ rk ... rl). + Node xn = utils::mkConcat(mchildren, node[0].getType()); + // construct the updated regular expression + Node newMem = + nodeManager()->mkNode(Kind::STRING_IN_REGEXP, + xn, + utils::mkConcat(children, node[1].getType())); + if (newMem != node) + { + return newMem; + } + } + return Node::null(); +} + Node SequencesRewriter::rewriteMembership(TNode node) { NodeManager* nm = nodeManager(); diff --git a/src/theory/strings/sequences_rewriter.h b/src/theory/strings/sequences_rewriter.h index a22b1d0d82b..0e58e7d4379 100644 --- a/src/theory/strings/sequences_rewriter.h +++ b/src/theory/strings/sequences_rewriter.h @@ -144,6 +144,8 @@ class SequencesRewriter : public TheoryRewriter Node rewriteViaReLoopElim(const Node& n); /** Rewrite based on STR_IN_RE_EVAL */ Node rewriteViaStrInReEval(const Node& n); + /** Rewrite based on STR_IN_RE_CONSUME */ + Node rewriteViaStrInReConsume(const Node& n); /** Rewrite based on STR_IN_RE_CONCAT_STAR_CHAR */ Node rewriteViaStrInReConcatStarChar(const Node& n); /** Rewrite based on STR_IN_RE_SIGMA */ diff --git a/src/theory/uf/theory_uf.cpp b/src/theory/uf/theory_uf.cpp index 13c4c8be0cc..ec5f52bba9f 100644 --- a/src/theory/uf/theory_uf.cpp +++ b/src/theory/uf/theory_uf.cpp @@ -52,7 +52,7 @@ TheoryUF::TheoryUF(Env& env, d_ho(nullptr), d_functionsTerms(context()), d_symb(env, instanceName), - d_rewriter(nodeManager()), + d_rewriter(nodeManager(), env.getRewriter()), d_checker(nodeManager()), d_state(env, valuation), d_im(env, *this, d_state, "theory::uf::" + instanceName, false), diff --git a/src/theory/uf/theory_uf_rewriter.cpp b/src/theory/uf/theory_uf_rewriter.cpp index 190327c729f..e1f5719aab2 100644 --- a/src/theory/uf/theory_uf_rewriter.cpp +++ b/src/theory/uf/theory_uf_rewriter.cpp @@ -29,7 +29,8 @@ namespace cvc5::internal { namespace theory { namespace uf { -TheoryUfRewriter::TheoryUfRewriter(NodeManager* nm) : TheoryRewriter(nm) +TheoryUfRewriter::TheoryUfRewriter(NodeManager* nm, Rewriter* rr) + : TheoryRewriter(nm), d_rr(rr) { registerProofRewriteRule(ProofRewriteRule::BETA_REDUCE, TheoryRewriteCtx::PRE_DSL); @@ -60,6 +61,22 @@ RewriteResponse TheoryUfRewriter::postRewrite(TNode node) Node lambda = FunctionConst::toLambda(node.getOperator()); if (!lambda.isNull()) { + // Note that the rewriter does not rewrite inside of operators, so the + // lambda we receive here may not be in rewritten form, and thus may + // contain variable shadowing. We rewrite the operator explicitly here. + Node lambdaRew = d_rr->rewrite(lambda); + // We compare against the original operator, if it is different, then + // we rewrite again. + if (lambdaRew != node.getOperator()) + { + std::vector args; + args.push_back(lambdaRew); + args.insert(args.end(), node.begin(), node.end()); + NodeManager* nm = NodeManager::currentNM(); + Node ret = nm->mkNode(Kind::APPLY_UF, args); + Assert(ret != node); + return RewriteResponse(REWRITE_AGAIN_FULL, ret); + } Trace("uf-ho-beta") << "uf-ho-beta : beta-reducing all args of : " << lambda << " for " << node << "\n"; std::vector vars(lambda[0].begin(), lambda[0].end()); @@ -70,10 +87,18 @@ RewriteResponse TheoryUfRewriter::postRewrite(TNode node) expr::getFreeVariables(s, fvs); } Node new_body = lambda[1]; + Trace("uf-ho-beta") << "... body is " << new_body << std::endl; if (!fvs.empty()) { ElimShadowNodeConverter esnc(nodeManager(), node, fvs); new_body = esnc.convert(new_body); + Trace("uf-ho-beta") + << "... elim shadow body is " << new_body << std::endl; + } + else + { + Trace("uf-ho-beta") << "... no free vars in substitution for " << vars + << " -> " << subs << std::endl; } Node ret = new_body.substitute( vars.begin(), vars.end(), subs.begin(), subs.end()); @@ -175,6 +200,10 @@ Node TheoryUfRewriter::rewriteViaRule(ProofRewriteRule id, const Node& n) { return Node::null(); } + // Note that we do not check for variable shadowing in the lambda here. + // This rule will only be used to express valid instances of beta + // reduction. If a beta reduction had to eliminate shadowing, then it + // will not be inferred by this rule as is. Node ret = lambda[1].substitute( vars.begin(), vars.end(), subs.begin(), subs.end()); return ret; @@ -238,6 +267,13 @@ Node TheoryUfRewriter::rewriteLambda(Node node) // normalization on array constants, and then converting the array constant // back to a lambda. Trace("builtin-rewrite") << "Rewriting lambda " << node << "..." << std::endl; + // eliminate shadowing, prior to handling whether the lambda is constant + // below. + Node retElimShadow = ElimShadowNodeConverter::eliminateShadow(node); + if (retElimShadow != node) + { + return retElimShadow; + } Node anode = FunctionConst::toArrayConst(node); // Only rewrite constant array nodes, since these are the only cases // where we require canonicalization of lambdas. Moreover, applying the @@ -257,12 +293,6 @@ Node TheoryUfRewriter::rewriteLambda(Node node) } Trace("builtin-rewrite-debug") << "...failed to get array representation." << std::endl; - // eliminate shadowing - Node retElimShadow = ElimShadowNodeConverter::eliminateShadow(node); - if (retElimShadow != node) - { - return retElimShadow; - } // see if it can be eliminated, (lambda ((x T)) (f x)) ---> f if (node[1].getKind() == Kind::APPLY_UF) { diff --git a/src/theory/uf/theory_uf_rewriter.h b/src/theory/uf/theory_uf_rewriter.h index 981ef3e2143..60a36aa78fe 100644 --- a/src/theory/uf/theory_uf_rewriter.h +++ b/src/theory/uf/theory_uf_rewriter.h @@ -34,7 +34,7 @@ namespace uf { class TheoryUfRewriter : public TheoryRewriter { public: - TheoryUfRewriter(NodeManager* nm); + TheoryUfRewriter(NodeManager* nm, Rewriter* rr); /** post-rewrite */ RewriteResponse postRewrite(TNode node) override; /** pre-rewrite */ @@ -79,6 +79,12 @@ class TheoryUfRewriter : public TheoryRewriter static bool canUseAsApplyUfOperator(TNode n); private: + /** + * Pointer to the rewriter, required for rewriting lambdas that appear + * inside of operators that are not in rewritten form. NOTE this is a cyclic + * dependency, and should be removed. + */ + Rewriter* d_rr; /** Entry point for rewriting lambdas */ Node rewriteLambda(Node node); /** rewrite bv2nat */ diff --git a/src/util/gmp_util.h b/src/util/gmp_util.h index be702df2e81..e79e4794457 100644 --- a/src/util/gmp_util.h +++ b/src/util/gmp_util.h @@ -35,7 +35,7 @@ inline size_t gmpz_hash(const mpz_t toHash) { for (int i = 0, n = mpz_size(toHash); i < n; ++i){ mp_limb_t limb = mpz_getlimbn(toHash, i); hash = hash * 2; - hash = hash xor limb; + hash = hash ^ limb; } return hash; }/* gmpz_hash() */ diff --git a/src/util/rational_gmp_imp.h b/src/util/rational_gmp_imp.h index d55fba134a1..a28db66a59c 100644 --- a/src/util/rational_gmp_imp.h +++ b/src/util/rational_gmp_imp.h @@ -298,7 +298,7 @@ class Rational size_t numeratorHash = gmpz_hash(d_value.get_num_mpz_t()); size_t denominatorHash = gmpz_hash(d_value.get_den_mpz_t()); - return numeratorHash xor denominatorHash; + return numeratorHash ^ denominatorHash; } uint32_t complexity() const diff --git a/test/api/cpp/sep_log_api.cpp b/test/api/cpp/sep_log_api.cpp index 6d8dcdf0d6c..a81f7e640b8 100644 --- a/test/api/cpp/sep_log_api.cpp +++ b/test/api/cpp/sep_log_api.cpp @@ -78,7 +78,7 @@ int validate_exception(void) /* The exception message we expect to obtain */ std::string expected( - "Cannot obtain separation logic expressions if not using the separation " + "cannot obtain separation logic expressions if not using the separation " "logic theory."); /* test the heap expression */ diff --git a/test/api/python/sep_log_api.py b/test/api/python/sep_log_api.py index 87502b0b45c..01db8765b6a 100644 --- a/test/api/python/sep_log_api.py +++ b/test/api/python/sep_log_api.py @@ -64,7 +64,7 @@ def validate_exception(): # The exception message we expect to obtain expected = \ - "Cannot obtain separation logic expressions if not using the separation " \ + "cannot obtain separation logic expressions if not using the separation " \ "logic theory." # test the heap expression diff --git a/test/regress/cli/CMakeLists.txt b/test/regress/cli/CMakeLists.txt index 7aa584eddbb..d01cfcb5642 100644 --- a/test/regress/cli/CMakeLists.txt +++ b/test/regress/cli/CMakeLists.txt @@ -1293,6 +1293,9 @@ set(regress_0_tests regress0/proofs/bvrewrite-extract.smt2 regress0/proofs/bvrewrite-ite.smt2 regress0/proofs/bvrewrite-shlbyconst.smt2 + regress0/proofs/dd_bug787_beta_reduce.smt2 + regress0/proofs/dd_fv-bvl.smt2 + regress0/proofs/define-fun-shadow.smt2 regress0/proofs/dsl-cong-eval-cr.smt2 regress0/proofs/dsl-no-eval.smt2 regress0/proofs/dsl-rule-comp-types.smt2 @@ -1691,6 +1694,10 @@ set(regress_0_tests regress0/sets/proj-issue493-choose-det.smt2 regress0/sets/proj-issue501-choose-bool-term-var.smt2 regress0/sets/proj-issue583.smt2 + regress0/sets/proj-issue632.smt2 + regress0/sets/proj-issue703.smt2 + regress0/sets/proj-issue720.smt2 + regress0/sets/proj-issue727.smt2 regress0/sets/rec_copy_loop_check_heap_access_43_4.smt2 regress0/sets/set_is_empty.smt2 regress0/sets/setel-eq.smt2 @@ -2575,6 +2582,9 @@ set(regress_1_tests regress1/nl/transcedental_model_simple.smt2 regress1/nl/zero-subset.smt2 regress1/non-fatal-errors.smt2 + regress1/parse-skolem-test-array-deq.smt2 + regress1/parse-skolem-test-int-div-by-zero.smt2 + regress1/parse-skolem-test-strings-occur-index.smt2 regress1/print_timeout_core.smt2 regress1/proj-issue175.smt2 regress1/proj-issue406-diff-unsat-core.smt2 diff --git a/test/regress/cli/regress0/cvc-rerror-print.cvc.smt2 b/test/regress/cli/regress0/cvc-rerror-print.cvc.smt2 index d3ffb7a7ea7..0b008310567 100644 --- a/test/regress/cli/regress0/cvc-rerror-print.cvc.smt2 +++ b/test/regress/cli/regress0/cvc-rerror-print.cvc.smt2 @@ -1,5 +1,5 @@ ; EXPECT: unsat -; EXPECT: (error "Cannot get model unless after a SAT or UNKNOWN response.") +; EXPECT: (error "cannot get model unless after a SAT or UNKNOWN response.") (set-option :incremental false) (set-logic ALL) (set-option :produce-models true) diff --git a/test/regress/cli/regress0/options/set-after-init.smt2 b/test/regress/cli/regress0/options/set-after-init.smt2 index 51bb1e78efc..1a2fca79902 100644 --- a/test/regress/cli/regress0/options/set-after-init.smt2 +++ b/test/regress/cli/regress0/options/set-after-init.smt2 @@ -4,7 +4,7 @@ ; EXPECT: 2 ; EXPECT: sat ; EXPECT: 0 -; EXPECT: (error "Invalid call to 'setOption' for option 'sat-random-seed', solver is already fully initialized") +; EXPECT: (error "invalid call to 'setOption' for option 'sat-random-seed', solver is already fully initialized") ; EXIT: 1 (get-option :verbosity) diff --git a/test/regress/cli/regress0/parser/get-model-after-declare.smt2 b/test/regress/cli/regress0/parser/get-model-after-declare.smt2 index ebf3889ba92..3ae021efaa9 100644 --- a/test/regress/cli/regress0/parser/get-model-after-declare.smt2 +++ b/test/regress/cli/regress0/parser/get-model-after-declare.smt2 @@ -1,5 +1,5 @@ ; EXPECT: sat -; EXPECT: (error "Cannot get model unless after a SAT or UNKNOWN response.") +; EXPECT: (error "cannot get model unless after a SAT or UNKNOWN response.") (set-logic ALL) (set-option :produce-models true) (declare-fun x () Int) diff --git a/test/regress/cli/regress0/parser/issue10723-divisible0.smt2 b/test/regress/cli/regress0/parser/issue10723-divisible0.smt2 index 5b091367442..8d47872392f 100644 --- a/test/regress/cli/regress0/parser/issue10723-divisible0.smt2 +++ b/test/regress/cli/regress0/parser/issue10723-divisible0.smt2 @@ -1,7 +1,7 @@ ; DISABLE-TESTER: dump ; REQUIRES: no-competition -; SCRUBBER: grep -o "Invalid value '0' at index 0 for operator" -; EXPECT: Invalid value '0' at index 0 for operator +; SCRUBBER: grep -o "invalid value '0' at index 0 for operator" +; EXPECT: invalid value '0' at index 0 for operator ; EXIT: 1 (set-logic ALL) (assert (forall ((v Real)) ((_ divisible 0) v))) diff --git a/test/regress/cli/regress0/parser/issue10813-1.smt2 b/test/regress/cli/regress0/parser/issue10813-1.smt2 index af415225aa3..cacf9fa5d67 100644 --- a/test/regress/cli/regress0/parser/issue10813-1.smt2 +++ b/test/regress/cli/regress0/parser/issue10813-1.smt2 @@ -1,6 +1,6 @@ ; DISABLE-TESTER: dump -; SCRUBBER: grep -o 'Cannot construct Real or Int from string argument' -; EXPECT: Cannot construct Real or Int from string argument +; SCRUBBER: grep -o 'cannot construct Real or Int from string argument' +; EXPECT: cannot construct Real or Int from string argument ; EXIT: 1 (set-logic QF_LRA) (declare-const x Real) diff --git a/test/regress/cli/regress0/parser/issue9675.smt2 b/test/regress/cli/regress0/parser/issue9675.smt2 index 8d98528a099..9d67082ea51 100644 --- a/test/regress/cli/regress0/parser/issue9675.smt2 +++ b/test/regress/cli/regress0/parser/issue9675.smt2 @@ -1,6 +1,6 @@ ; DISABLE-TESTER: dump -; SCRUBBER: grep -o '(error "Parse Error: issue9675.smt2:6.46: Invalid argument' -; EXPECT: (error "Parse Error: issue9675.smt2:6.46: Invalid argument +; SCRUBBER: grep -o '(error "Parse Error: issue9675.smt2:6.46: invalid argument' +; EXPECT: (error "Parse Error: issue9675.smt2:6.46: invalid argument ; EXIT: 1 (set-logic ALL) (assert (= (fp (_ bv0 1) (_ bv0 1) (_ bv0 11)))) diff --git a/test/regress/cli/regress0/proofs/dd_bug787_beta_reduce.smt2 b/test/regress/cli/regress0/proofs/dd_bug787_beta_reduce.smt2 new file mode 100644 index 00000000000..172ec142f69 --- /dev/null +++ b/test/regress/cli/regress0/proofs/dd_bug787_beta_reduce.smt2 @@ -0,0 +1,16 @@ +; EXPECT: unsat +(set-logic ALL) +(declare-const _vp1-1 (_ BitVec 1)) +(declare-const _vp1-2 (_ BitVec 1)) +(declare-const _vp1-3 (_ BitVec 1)) +(declare-const x796__fresh Bool) +(declare-const x836__fresh Bool) +(declare-const x322__fresh Bool) +(define-fun bit-1 ((bv (_ BitVec 4))) (_ BitVec 4) (bvand bv (bvneg bv))) +(define-fun bit-2 ((bv (_ BitVec 4))) (_ BitVec 4) (bit-1 (bvand bv (bvsub bv (_ bv1 4))))) +(define-fun index-bit ((index (_ BitVec 4)) (bv (_ BitVec 4))) (_ BitVec 4) (ite x836__fresh (bit-1 bv) (bit-2 bv))) +(define-fun permute ((index (_ BitVec 4)) (obj-0 (_ BitVec 4)) (obj-1 (_ BitVec 4)) (obj-2 (_ BitVec 4)) (obj-3 (_ BitVec 4))) (_ BitVec 4) (ite x836__fresh (_ bv0 4) (_ bv0 4))) +(define-fun left-zeros ((index (_ BitVec 4))) (_ BitVec 8) (ite false (_ bv0 8) (_ bv0 8))) +(define-fun centered ((index (_ BitVec 4)) (bv (_ BitVec 4))) (_ BitVec 8) (bvshl ((_ zero_extend 4) bv) (left-zeros index))) +(assert (= (_ bv0 8) (bvxor (_ bv1 8) (bvand (centered (index-bit (_ bv0 4) ((_ zero_extend 3) _vp1-3)) ((_ zero_extend 3) _vp1-3)) (centered ((_ zero_extend 3) _vp1-3) (index-bit ((_ zero_extend 3) _vp1-3) (permute (_ bv1 4) (_ bv0 4) (_ bv0 4) (_ bv0 4) (_ bv0 4)))))))) +(check-sat) diff --git a/test/regress/cli/regress0/proofs/dd_fv-bvl.smt2 b/test/regress/cli/regress0/proofs/dd_fv-bvl.smt2 new file mode 100644 index 00000000000..57b69011f60 --- /dev/null +++ b/test/regress/cli/regress0/proofs/dd_fv-bvl.smt2 @@ -0,0 +1,6 @@ +; EXPECT: unsat +(set-logic ALL) +(define-fun b ((bv (_ BitVec 4))) (_ BitVec 4) bv) +(define-fun i ((index (_ BitVec 4)) (bv (_ BitVec 4))) (_ BitVec 4) (b bv)) +(assert (= (_ bv0 8) (bvxor (_ bv1 8) ((_ zero_extend 4) (i (_ bv0 4) (_ bv0 4)))))) +(check-sat) diff --git a/test/regress/cli/regress0/proofs/define-fun-shadow.smt2 b/test/regress/cli/regress0/proofs/define-fun-shadow.smt2 new file mode 100644 index 00000000000..436fa2def74 --- /dev/null +++ b/test/regress/cli/regress0/proofs/define-fun-shadow.smt2 @@ -0,0 +1,7 @@ +; EXPECT: unsat +(set-logic ALL) +(declare-const x2 Bool) +(define-fun s ((a Int) (b Int) (z Int) (z Int)) Bool (= 0 0)) +(define-fun p ((a Int) (b Int) (c Int)) Bool (exists ((x Int) (y Int)) (and false (s 0 0 b c) (forall ((z Int)) false)))) +(assert (p 0 0 0)) +(check-sat) diff --git a/test/regress/cli/regress0/reset-i.smt2 b/test/regress/cli/regress0/reset-i.smt2 index 691122c0d56..3ac2175243b 100644 --- a/test/regress/cli/regress0/reset-i.smt2 +++ b/test/regress/cli/regress0/reset-i.smt2 @@ -1,5 +1,5 @@ ; EXPECT: sat -; EXPECT: (error "Cannot make multiple queries unless incremental solving is enabled (try --incremental)") +; EXPECT: (error "cannot make multiple queries unless incremental solving is enabled (try --incremental)") ; EXIT: 1 (reset) (set-logic ALL) diff --git a/test/regress/cli/regress0/sets/proj-issue632.smt2 b/test/regress/cli/regress0/sets/proj-issue632.smt2 new file mode 100644 index 00000000000..f22146db6cb --- /dev/null +++ b/test/regress/cli/regress0/sets/proj-issue632.smt2 @@ -0,0 +1,5 @@ +; EXPECT: sat +(set-logic ALL) +(declare-const x (Set Bool)) +(declare-const x4 (Set Bool)) +(check-sat-assuming ((distinct set.empty (set.union x x4)))) diff --git a/test/regress/cli/regress0/sets/proj-issue703.smt2 b/test/regress/cli/regress0/sets/proj-issue703.smt2 new file mode 100644 index 00000000000..22159ca7821 --- /dev/null +++ b/test/regress/cli/regress0/sets/proj-issue703.smt2 @@ -0,0 +1,6 @@ +; COMMAND-LINE: -q +; EXPECT: sat +(set-logic ALL) +(set-option :debug-check-models true) +(declare-const x String) +(check-sat-assuming ((str.is_digit (set.choose (set.insert "" (set.singleton x)))))) diff --git a/test/regress/cli/regress0/sets/proj-issue720.smt2 b/test/regress/cli/regress0/sets/proj-issue720.smt2 new file mode 100644 index 00000000000..e4c453bc16b --- /dev/null +++ b/test/regress/cli/regress0/sets/proj-issue720.smt2 @@ -0,0 +1,9 @@ +; COMMAND-LINE: -q +; EXPECT: sat +(set-logic ALL) +(set-option :debug-check-models true) +(declare-sort _u0 0) +(declare-const _x13 _u0) +(declare-const _x24 _u0) +(assert (set.member (set.choose (set.insert _x24 (set.singleton _x13))) (set.singleton _x24))) +(check-sat) diff --git a/test/regress/cli/regress0/sets/proj-issue727.smt2 b/test/regress/cli/regress0/sets/proj-issue727.smt2 new file mode 100644 index 00000000000..7444fe2abdf --- /dev/null +++ b/test/regress/cli/regress0/sets/proj-issue727.smt2 @@ -0,0 +1,10 @@ +; EXPECT: unsat +(set-logic ALL) +(set-option :sets-ext true) +(set-option :debug-check-models true) +(declare-const x (Set Bool)) +(declare-const _x6 (Set Bool)) +(declare-const _x8 (Set Bool)) +(assert (set.is_singleton (set.complement (set.complement x)))) +(assert (set.subset (as set.universe (Set Bool)) (set.minus (set.minus _x6 _x8) (as set.universe (Set Bool))))) +(check-sat) diff --git a/test/regress/cli/regress0/smtlib/set-info-status.smt2 b/test/regress/cli/regress0/smtlib/set-info-status.smt2 index 399886e52e7..657bc2231a3 100644 --- a/test/regress/cli/regress0/smtlib/set-info-status.smt2 +++ b/test/regress/cli/regress0/smtlib/set-info-status.smt2 @@ -1,4 +1,4 @@ -; EXPECT: (error "Cannot get unsat core unless in unsat mode.") +; EXPECT: (error "cannot get unsat core unless in unsat mode.") ; EXPECT: sat ; EXPECT: sat ; EXPECT: unsat diff --git a/test/regress/cli/regress0/sygus/sygus-no-incremental-err.sy b/test/regress/cli/regress0/sygus/sygus-no-incremental-err.sy index 18902825c44..97cdf1ca5ac 100644 --- a/test/regress/cli/regress0/sygus/sygus-no-incremental-err.sy +++ b/test/regress/cli/regress0/sygus/sygus-no-incremental-err.sy @@ -2,7 +2,7 @@ ; REQUIRES: no-competition ; COMMAND-LINE: --sygus-out=status ; EXPECT: feasible -; EXPECT: (error "Cannot make multiple checkSynth calls unless incremental solving is enabled (try --incremental)") +; EXPECT: (error "cannot make multiple checkSynth calls unless incremental solving is enabled (try --incremental)") ; EXIT: 1 (set-logic LIA) (synth-fun f ((x Int)) Int) diff --git a/test/regress/cli/regress1/parse-skolem-test-array-deq.smt2 b/test/regress/cli/regress1/parse-skolem-test-array-deq.smt2 new file mode 100644 index 00000000000..3cad1447698 --- /dev/null +++ b/test/regress/cli/regress1/parse-skolem-test-array-deq.smt2 @@ -0,0 +1,10 @@ +; COMMAND-LINE: --parse-skolem-definitions --print-skolem-definitions +; EXPECT: unsat +(set-option :parse-skolem-definitions true) +(set-logic QF_AUFNIA) +(set-info :status unsat) +(declare-fun b () (Array Int Int)) +(declare-fun a () (Array Int Int)) +(assert (not (= a b))) +(assert (= (select a (@array_deq_diff a b)) (select b (@array_deq_diff a b)))) +(check-sat) \ No newline at end of file diff --git a/test/regress/cli/regress1/parse-skolem-test-int-div-by-zero.smt2 b/test/regress/cli/regress1/parse-skolem-test-int-div-by-zero.smt2 new file mode 100644 index 00000000000..66d9ef08f60 --- /dev/null +++ b/test/regress/cli/regress1/parse-skolem-test-int-div-by-zero.smt2 @@ -0,0 +1,12 @@ +; COMMAND-LINE: --parse-skolem-definitions --print-skolem-definitions +; EXPECT: sat +(set-option :parse-skolem-definitions true) +(set-logic QF_NIA) +(set-info :status sat) +(declare-fun b () Int) +(declare-fun a () Int) +(assert (not (= a b))) +(assert (not (<= a b))) +(assert (= b (div a 0))) +(assert (or (not (= a (@int_div_by_zero a))) (not (>= (+ a (* (- 1) (@int_div_by_zero a))) 1)))) +(check-sat) diff --git a/test/regress/cli/regress1/parse-skolem-test-strings-occur-index.smt2 b/test/regress/cli/regress1/parse-skolem-test-strings-occur-index.smt2 new file mode 100644 index 00000000000..605393d89bd --- /dev/null +++ b/test/regress/cli/regress1/parse-skolem-test-strings-occur-index.smt2 @@ -0,0 +1,8 @@ +; COMMAND-LINE: --parse-skolem-definitions --print-skolem-definitions +; EXPECT: sat +(set-option :parse-skolem-definitions true) +(set-logic QF_SLIA) +(set-info :status sat) +(declare-fun x () String) +(assert (not (>= (+ (str.indexof x "\u{0}" (@strings_occur_index x "\u{0}" (@strings_num_occur x "\u{0}"))) (* (- 1) (str.len x))) 1))) +(check-sat) diff --git a/test/regress/cli/regress1/proj-issue406-diff-unsat-core.smt2 b/test/regress/cli/regress1/proj-issue406-diff-unsat-core.smt2 index db234dc8d42..7c06565ac33 100644 --- a/test/regress/cli/regress1/proj-issue406-diff-unsat-core.smt2 +++ b/test/regress/cli/regress1/proj-issue406-diff-unsat-core.smt2 @@ -1,7 +1,7 @@ ; DISABLE-TESTER: unsat-core ; DISABLE-TESTER: proof ; EXPECT: unsat -; EXPECT: (error "Cannot get unsat core unless explicitly enabled (try --produce-unsat-cores)") +; EXPECT: (error "cannot get unsat core unless explicitly enabled (try --produce-unsat-cores)") ; EXIT: 1 (set-logic ALL) (set-option :global-declarations true) @@ -9,4 +9,4 @@ (declare-const _x0 String) (assert (let ((_let0 (str.suffixof _x0 _x0)))(and (and (not _let0) (= _let0 _let0)) _let0))) (check-sat) -(get-unsat-core) \ No newline at end of file +(get-unsat-core) diff --git a/test/regress/cli/regress1/sets/issue4124-need-check.smt2 b/test/regress/cli/regress1/sets/issue4124-need-check.smt2 index 22a238b56a3..bbc1bb23c08 100644 --- a/test/regress/cli/regress1/sets/issue4124-need-check.smt2 +++ b/test/regress/cli/regress1/sets/issue4124-need-check.smt2 @@ -1,4 +1,4 @@ -; COMMAND-LINE: --sets-infer-as-lemmas --simplification=none +; COMMAND-LINE: --simplification=none ; EXPECT: sat (set-logic ALL) (declare-fun b () (Relation String Int)) diff --git a/test/regress/cli/regress1/sets/proj-issue178.smt2 b/test/regress/cli/regress1/sets/proj-issue178.smt2 index 0b4be95fa37..689ecff2ba2 100644 --- a/test/regress/cli/regress1/sets/proj-issue178.smt2 +++ b/test/regress/cli/regress1/sets/proj-issue178.smt2 @@ -1,7 +1,6 @@ (set-logic ALL) (set-info :status sat) (set-option :sygus-inference try) -(set-option :sets-infer-as-lemmas false) (declare-fun a () (Set Int)) (declare-fun b () (Set Int)) (declare-fun c () (Set Int)) diff --git a/test/unit/api/c/CMakeLists.txt b/test/unit/api/c/CMakeLists.txt index fa4207c5757..568d31a65c5 100644 --- a/test/unit/api/c/CMakeLists.txt +++ b/test/unit/api/c/CMakeLists.txt @@ -15,7 +15,9 @@ # Generate and add unit test. cvc5_add_unit_test_black(capi_kind_black api/c) +cvc5_add_unit_test_black(capi_op_black api/c) cvc5_add_unit_test_black(capi_sort_black api/c) cvc5_add_unit_test_black(capi_sort_kind_black api/c) +cvc5_add_unit_test_black(capi_term_black api/c) cvc5_add_unit_test_black(capi_term_manager_black api/c) cvc5_add_unit_test_black(capi_types_black api/c) diff --git a/test/unit/api/c/capi_op_black.cpp b/test/unit/api/c/capi_op_black.cpp new file mode 100644 index 00000000000..37a7aa86007 --- /dev/null +++ b/test/unit/api/c/capi_op_black.cpp @@ -0,0 +1,315 @@ +/****************************************************************************** + * Top contributors (to current version): + * Aina Niemetz + * + * This file is part of the cvc5 project. + * + * Copyright (c) 2009-2024 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 the guards of the C API functions. + */ + +extern "C" { +#include +} + +#include "base/output.h" +#include "gtest/gtest.h" + +namespace cvc5::internal::test { + +class TestCApiBlackOp : public ::testing::Test +{ + protected: + void SetUp() override + { + d_tm = cvc5_term_manager_new(); + d_bool = cvc5_get_boolean_sort(d_tm); + d_int = cvc5_get_integer_sort(d_tm); + d_real = cvc5_get_real_sort(d_tm); + d_uninterpreted = cvc5_mk_uninterpreted_sort(d_tm, "u"); + } + void TearDown() override { cvc5_term_manager_delete(d_tm); } + + Cvc5TermManager* d_tm; + Cvc5Sort d_bool; + Cvc5Sort d_int; + Cvc5Sort d_real; + Cvc5Sort d_uninterpreted; +}; + +TEST_F(TestCApiBlackOp, hash) +{ + ASSERT_DEATH(cvc5_op_hash(nullptr), "invalid operator"); + std::vector idxs = {4, 0}; + (void)cvc5_op_hash( + cvc5_mk_op(d_tm, CVC5_KIND_BITVECTOR_EXTRACT, idxs.size(), idxs.data())); +} + +TEST_F(TestCApiBlackOp, get_kind) +{ + ASSERT_DEATH(cvc5_op_get_kind(nullptr), "invalid operator"); + std::vector idxs = {4, 0}; + ASSERT_EQ(cvc5_op_get_kind(cvc5_mk_op( + d_tm, CVC5_KIND_BITVECTOR_EXTRACT, idxs.size(), idxs.data())), + CVC5_KIND_BITVECTOR_EXTRACT); +} + +TEST_F(TestCApiBlackOp, mk_op) +{ + std::vector idxs = {4, 0}; + ASSERT_DEATH( + cvc5_mk_op( + nullptr, CVC5_KIND_BITVECTOR_EXTRACT, idxs.size(), idxs.data()), + "unexpected NULL argument"); + ASSERT_DEATH( + cvc5_mk_op(d_tm, CVC5_KIND_BITVECTOR_EXTRACT, idxs.size(), nullptr), + "unexpected NULL argument"); + (void)cvc5_mk_op(d_tm, CVC5_KIND_ADD, 0, nullptr); + idxs.push_back(2); + ASSERT_DEATH( + cvc5_mk_op(d_tm, CVC5_KIND_BITVECTOR_EXTRACT, idxs.size(), idxs.data()), + "invalid number of indices"); +} + +TEST_F(TestCApiBlackOp, get_num_indices) +{ + ASSERT_DEATH(cvc5_op_get_num_indices(nullptr), "invalid operator"); + + // Operators with 0 indices + Cvc5Op add = cvc5_mk_op(d_tm, CVC5_KIND_ADD, 0, nullptr); + ASSERT_EQ(cvc5_op_get_num_indices(add), 0); + + // Operators with 1 index + std::vector idxs = {4}; + Cvc5Op divisible = + cvc5_mk_op(d_tm, CVC5_KIND_DIVISIBLE, idxs.size(), idxs.data()); + idxs = {5}; + Cvc5Op bv_repeat = + cvc5_mk_op(d_tm, CVC5_KIND_BITVECTOR_REPEAT, idxs.size(), idxs.data()); + idxs = {6}; + Cvc5Op bv_zext = cvc5_mk_op( + d_tm, CVC5_KIND_BITVECTOR_ZERO_EXTEND, idxs.size(), idxs.data()); + idxs = {7}; + Cvc5Op bv_sext = cvc5_mk_op( + d_tm, CVC5_KIND_BITVECTOR_SIGN_EXTEND, idxs.size(), idxs.data()); + idxs = {8}; + Cvc5Op bv_rol = cvc5_mk_op( + d_tm, CVC5_KIND_BITVECTOR_ROTATE_LEFT, idxs.size(), idxs.data()); + idxs = {9}; + Cvc5Op bv_ror = cvc5_mk_op( + d_tm, CVC5_KIND_BITVECTOR_ROTATE_RIGHT, idxs.size(), idxs.data()); + idxs = {10}; + Cvc5Op int_to_bv = + cvc5_mk_op(d_tm, CVC5_KIND_INT_TO_BITVECTOR, idxs.size(), idxs.data()); + idxs = {12}; + Cvc5Op iand = cvc5_mk_op(d_tm, CVC5_KIND_IAND, idxs.size(), idxs.data()); + idxs = {12}; + Cvc5Op fp_to_ubv = cvc5_mk_op( + d_tm, CVC5_KIND_FLOATINGPOINT_TO_UBV, idxs.size(), idxs.data()); + idxs = {13}; + Cvc5Op fp_to_sbv = cvc5_mk_op( + d_tm, CVC5_KIND_FLOATINGPOINT_TO_SBV, idxs.size(), idxs.data()); + + ASSERT_EQ(1, cvc5_op_get_num_indices(divisible)); + ASSERT_EQ(1, cvc5_op_get_num_indices(bv_repeat)); + ASSERT_EQ(1, cvc5_op_get_num_indices(bv_zext)); + ASSERT_EQ(1, cvc5_op_get_num_indices(bv_sext)); + ASSERT_EQ(1, cvc5_op_get_num_indices(bv_ror)); + ASSERT_EQ(1, cvc5_op_get_num_indices(bv_rol)); + ASSERT_EQ(1, cvc5_op_get_num_indices(int_to_bv)); + ASSERT_EQ(1, cvc5_op_get_num_indices(iand)); + ASSERT_EQ(1, cvc5_op_get_num_indices(fp_to_ubv)); + ASSERT_EQ(1, cvc5_op_get_num_indices(fp_to_sbv)); + + // Operators with 2 indices + idxs = {1, 0}; + Cvc5Op bv_ext = + cvc5_mk_op(d_tm, CVC5_KIND_BITVECTOR_EXTRACT, idxs.size(), idxs.data()); + idxs = {3, 2}; + Cvc5Op to_fp_from_ieee = + cvc5_mk_op(d_tm, + CVC5_KIND_FLOATINGPOINT_TO_FP_FROM_IEEE_BV, + idxs.size(), + idxs.data()); + idxs = {5, 4}; + Cvc5Op to_fp_from_fp = cvc5_mk_op( + d_tm, CVC5_KIND_FLOATINGPOINT_TO_FP_FROM_FP, idxs.size(), idxs.data()); + idxs = {7, 6}; + Cvc5Op to_fp_from_real = cvc5_mk_op( + d_tm, CVC5_KIND_FLOATINGPOINT_TO_FP_FROM_REAL, idxs.size(), idxs.data()); + idxs = {9, 8}; + Cvc5Op to_fp_from_sbv = cvc5_mk_op( + d_tm, CVC5_KIND_FLOATINGPOINT_TO_FP_FROM_SBV, idxs.size(), idxs.data()); + idxs = {11, 10}; + Cvc5Op to_fp_from_ubv = cvc5_mk_op( + d_tm, CVC5_KIND_FLOATINGPOINT_TO_FP_FROM_UBV, idxs.size(), idxs.data()); + idxs = {15, 14}; + Cvc5Op regexp_loop = + cvc5_mk_op(d_tm, CVC5_KIND_REGEXP_LOOP, idxs.size(), idxs.data()); + + ASSERT_EQ(2, cvc5_op_get_num_indices(bv_ext)); + ASSERT_EQ(2, cvc5_op_get_num_indices(to_fp_from_ieee)); + ASSERT_EQ(2, cvc5_op_get_num_indices(to_fp_from_fp)); + ASSERT_EQ(2, cvc5_op_get_num_indices(to_fp_from_real)); + ASSERT_EQ(2, cvc5_op_get_num_indices(to_fp_from_sbv)); + ASSERT_EQ(2, cvc5_op_get_num_indices(to_fp_from_ubv)); + ASSERT_EQ(2, cvc5_op_get_num_indices(regexp_loop)); + + // Operators with n indices + idxs = {0, 3, 2, 0, 1, 2}; + Cvc5Op tuple_proj = + cvc5_mk_op(d_tm, CVC5_KIND_TUPLE_PROJECT, idxs.size(), idxs.data()); + ASSERT_EQ(idxs.size(), cvc5_op_get_num_indices(tuple_proj)); + + Cvc5Op rel_proj = + cvc5_mk_op(d_tm, CVC5_KIND_RELATION_PROJECT, idxs.size(), idxs.data()); + ASSERT_EQ(idxs.size(), cvc5_op_get_num_indices(rel_proj)); + + Cvc5Op table_proj = + cvc5_mk_op(d_tm, CVC5_KIND_TABLE_PROJECT, idxs.size(), idxs.data()); + ASSERT_EQ(idxs.size(), cvc5_op_get_num_indices(table_proj)); +} + +TEST_F(TestCApiBlackOp, subscript_operator) +{ + // Operators with 0 indices + Cvc5Op add = cvc5_mk_op(d_tm, CVC5_KIND_ADD, 0, nullptr); + ASSERT_DEATH(cvc5_op_get_index(nullptr, 0), "invalid operator"); + ASSERT_DEATH(cvc5_op_get_index(add, 0), "Op is not indexed"); + + // Operators with 1 index + std::vector idxs = {4}; + Cvc5Op divisible = + cvc5_mk_op(d_tm, CVC5_KIND_DIVISIBLE, idxs.size(), idxs.data()); + idxs = {5}; + Cvc5Op bv_repeat = + cvc5_mk_op(d_tm, CVC5_KIND_BITVECTOR_REPEAT, idxs.size(), idxs.data()); + idxs = {6}; + Cvc5Op bv_zext = cvc5_mk_op( + d_tm, CVC5_KIND_BITVECTOR_ZERO_EXTEND, idxs.size(), idxs.data()); + idxs = {7}; + Cvc5Op bv_sext = cvc5_mk_op( + d_tm, CVC5_KIND_BITVECTOR_SIGN_EXTEND, idxs.size(), idxs.data()); + idxs = {8}; + Cvc5Op bv_rol = cvc5_mk_op( + d_tm, CVC5_KIND_BITVECTOR_ROTATE_LEFT, idxs.size(), idxs.data()); + idxs = {9}; + Cvc5Op bv_ror = cvc5_mk_op( + d_tm, CVC5_KIND_BITVECTOR_ROTATE_RIGHT, idxs.size(), idxs.data()); + idxs = {10}; + Cvc5Op int_to_bv = + cvc5_mk_op(d_tm, CVC5_KIND_INT_TO_BITVECTOR, idxs.size(), idxs.data()); + idxs = {11}; + Cvc5Op iand = cvc5_mk_op(d_tm, CVC5_KIND_IAND, idxs.size(), idxs.data()); + idxs = {12}; + Cvc5Op fp_to_ubv = cvc5_mk_op( + d_tm, CVC5_KIND_FLOATINGPOINT_TO_UBV, idxs.size(), idxs.data()); + idxs = {13}; + Cvc5Op fp_to_sbv = cvc5_mk_op( + d_tm, CVC5_KIND_FLOATINGPOINT_TO_SBV, idxs.size(), idxs.data()); + idxs = {14}; + Cvc5Op regexp_repeat = + cvc5_mk_op(d_tm, CVC5_KIND_REGEXP_REPEAT, idxs.size(), idxs.data()); + + ASSERT_EQ(4, cvc5_term_get_uint32_value(cvc5_op_get_index(divisible, 0))); + ASSERT_EQ(5, cvc5_term_get_uint32_value(cvc5_op_get_index(bv_repeat, 0))); + ASSERT_EQ(6, cvc5_term_get_uint32_value(cvc5_op_get_index(bv_zext, 0))); + ASSERT_EQ(7, cvc5_term_get_uint32_value(cvc5_op_get_index(bv_sext, 0))); + ASSERT_EQ(8, cvc5_term_get_uint32_value(cvc5_op_get_index(bv_rol, 0))); + ASSERT_EQ(9, cvc5_term_get_uint32_value(cvc5_op_get_index(bv_ror, 0))); + ASSERT_EQ(10, cvc5_term_get_uint32_value(cvc5_op_get_index(int_to_bv, 0))); + ASSERT_EQ(11, cvc5_term_get_uint32_value(cvc5_op_get_index(iand, 0))); + ASSERT_EQ(12, cvc5_term_get_uint32_value(cvc5_op_get_index(fp_to_ubv, 0))); + ASSERT_EQ(13, cvc5_term_get_uint32_value(cvc5_op_get_index(fp_to_sbv, 0))); + ASSERT_EQ(14, + cvc5_term_get_uint32_value(cvc5_op_get_index(regexp_repeat, 0))); + + // Operators with 2 indices + idxs = {1, 0}; + Cvc5Op bv_ext = + cvc5_mk_op(d_tm, CVC5_KIND_BITVECTOR_EXTRACT, idxs.size(), idxs.data()); + idxs = {3, 2}; + Cvc5Op to_fp_from_ieee = + cvc5_mk_op(d_tm, + CVC5_KIND_FLOATINGPOINT_TO_FP_FROM_IEEE_BV, + idxs.size(), + idxs.data()); + idxs = {5, 4}; + Cvc5Op to_fp_from_fp = cvc5_mk_op( + d_tm, CVC5_KIND_FLOATINGPOINT_TO_FP_FROM_FP, idxs.size(), idxs.data()); + idxs = {7, 6}; + Cvc5Op to_fp_from_real = cvc5_mk_op( + d_tm, CVC5_KIND_FLOATINGPOINT_TO_FP_FROM_REAL, idxs.size(), idxs.data()); + idxs = {9, 8}; + Cvc5Op to_fp_from_sbv = cvc5_mk_op( + d_tm, CVC5_KIND_FLOATINGPOINT_TO_FP_FROM_SBV, idxs.size(), idxs.data()); + idxs = {11, 10}; + Cvc5Op to_fp_from_ubv = cvc5_mk_op( + d_tm, CVC5_KIND_FLOATINGPOINT_TO_FP_FROM_UBV, idxs.size(), idxs.data()); + idxs = {15, 14}; + Cvc5Op regexp_loop = + cvc5_mk_op(d_tm, CVC5_KIND_REGEXP_LOOP, idxs.size(), idxs.data()); + + ASSERT_EQ(1, cvc5_term_get_uint32_value(cvc5_op_get_index(bv_ext, 0))); + ASSERT_EQ(0, cvc5_term_get_uint32_value(cvc5_op_get_index(bv_ext, 1))); + ASSERT_EQ(3, + cvc5_term_get_uint32_value(cvc5_op_get_index(to_fp_from_ieee, 0))); + ASSERT_EQ(2, + cvc5_term_get_uint32_value(cvc5_op_get_index(to_fp_from_ieee, 1))); + ASSERT_EQ(5, cvc5_term_get_uint32_value(cvc5_op_get_index(to_fp_from_fp, 0))); + ASSERT_EQ(4, cvc5_term_get_uint32_value(cvc5_op_get_index(to_fp_from_fp, 1))); + ASSERT_EQ(7, + cvc5_term_get_uint32_value(cvc5_op_get_index(to_fp_from_real, 0))); + ASSERT_EQ(6, + cvc5_term_get_uint32_value(cvc5_op_get_index(to_fp_from_real, 1))); + ASSERT_EQ(9, + cvc5_term_get_uint32_value(cvc5_op_get_index(to_fp_from_sbv, 0))); + ASSERT_EQ(8, + cvc5_term_get_uint32_value(cvc5_op_get_index(to_fp_from_sbv, 1))); + ASSERT_EQ(11, + cvc5_term_get_uint32_value(cvc5_op_get_index(to_fp_from_ubv, 0))); + ASSERT_EQ(10, + cvc5_term_get_uint32_value(cvc5_op_get_index(to_fp_from_ubv, 1))); + ASSERT_EQ(15, cvc5_term_get_uint32_value(cvc5_op_get_index(regexp_loop, 0))); + ASSERT_EQ(14, cvc5_term_get_uint32_value(cvc5_op_get_index(regexp_loop, 1))); + + // Operators with n indices + idxs = {0, 3, 2, 0, 1, 2}; + Cvc5Op tuple_proj = + cvc5_mk_op(d_tm, CVC5_KIND_TUPLE_PROJECT, idxs.size(), idxs.data()); + for (size_t i = 0, size = cvc5_op_get_num_indices(tuple_proj); i < size; ++i) + { + ASSERT_EQ(idxs[i], + cvc5_term_get_uint32_value(cvc5_op_get_index(tuple_proj, i))); + } + + Cvc5Op rel_proj = + cvc5_mk_op(d_tm, CVC5_KIND_RELATION_PROJECT, idxs.size(), idxs.data()); + for (size_t i = 0, size = cvc5_op_get_num_indices(rel_proj); i < size; ++i) + { + ASSERT_EQ(idxs[i], + cvc5_term_get_uint32_value(cvc5_op_get_index(rel_proj, i))); + } + + Cvc5Op table_proj = + cvc5_mk_op(d_tm, CVC5_KIND_TABLE_PROJECT, idxs.size(), idxs.data()); + for (size_t i = 0, size = cvc5_op_get_num_indices(table_proj); i < size; ++i) + { + ASSERT_EQ(idxs[i], + cvc5_term_get_uint32_value(cvc5_op_get_index(table_proj, i))); + } +} + +TEST_F(TestCApiBlackOp, to_string) +{ + std::vector idxs = {5}; + Cvc5Op bv_repeat = + cvc5_mk_op(d_tm, CVC5_KIND_BITVECTOR_REPEAT, idxs.size(), idxs.data()); + ASSERT_EQ(cvc5_op_to_string(bv_repeat), cvc5_op_to_string(bv_repeat)); +} +} // namespace cvc5::internal::test diff --git a/test/unit/api/c/capi_term_black.cpp b/test/unit/api/c/capi_term_black.cpp new file mode 100644 index 00000000000..f2013cd08b5 --- /dev/null +++ b/test/unit/api/c/capi_term_black.cpp @@ -0,0 +1,1149 @@ +/****************************************************************************** + * Top contributors (to current version): + * Aina Niemetz + * + * This file is part of the cvc5 project. + * + * Copyright (c) 2009-2024 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 the guards of the C API functions. + */ + +extern "C" { +#include +} + +#include "base/output.h" +#include "gtest/gtest.h" + +namespace cvc5::internal::test { + +class TestCApiBlackTerm : public ::testing::Test +{ + protected: + void SetUp() override + { + d_tm = cvc5_term_manager_new(); + d_bool = cvc5_get_boolean_sort(d_tm); + d_int = cvc5_get_integer_sort(d_tm); + d_real = cvc5_get_real_sort(d_tm); + d_uninterpreted = cvc5_mk_uninterpreted_sort(d_tm, "u"); + } + void TearDown() override { cvc5_term_manager_delete(d_tm); } + + Cvc5TermManager* d_tm; + Cvc5Sort d_bool; + Cvc5Sort d_int; + Cvc5Sort d_real; + Cvc5Sort d_uninterpreted; +}; + +TEST_F(TestCApiBlackTerm, hash) +{ + ASSERT_DEATH(cvc5_term_hash(nullptr), "invalid term"); + (void)cvc5_term_hash(cvc5_mk_integer_int64(d_tm, 2)); +} + +TEST_F(TestCApiBlackTerm, compare) +{ + Cvc5Term x = cvc5_mk_var(d_tm, d_uninterpreted, "x"); + Cvc5Term y = cvc5_mk_var(d_tm, d_uninterpreted, "y"); + ASSERT_DEATH(cvc5_term_compare(x, nullptr), "invalid term"); + ASSERT_DEATH(cvc5_term_compare(nullptr, y), "invalid term"); + ASSERT_FALSE(cvc5_term_is_equal(x, nullptr)); + ASSERT_TRUE(cvc5_term_is_disequal(x, nullptr)); + ASSERT_EQ(cvc5_term_compare(x, x), 0); + ASSERT_NE(cvc5_term_compare(x, y), 0); +} + +TEST_F(TestCApiBlackTerm, get_id) +{ + ASSERT_DEATH(cvc5_term_get_id(nullptr), "invalid term"); + Cvc5Term x = cvc5_mk_var(d_tm, d_int, "x"); + Cvc5Term y = cvc5_term_copy(x); + Cvc5Term z = cvc5_mk_var(d_tm, d_int, "z"); + (void)cvc5_term_get_id(x); + ASSERT_EQ(cvc5_term_get_id(x), cvc5_term_get_id(y)); + ASSERT_NE(cvc5_term_get_id(x), cvc5_term_get_id(z)); + cvc5_term_release(y); +} + +TEST_F(TestCApiBlackTerm, get_kind) +{ + std::vector domain = {d_uninterpreted}; + Cvc5Sort fun_sort1 = + cvc5_mk_fun_sort(d_tm, domain.size(), domain.data(), d_int); + domain = {d_int}; + Cvc5Sort fun_sort2 = + cvc5_mk_fun_sort(d_tm, domain.size(), domain.data(), d_int); + + ASSERT_DEATH(cvc5_term_get_kind(nullptr), "invalid term"); + + Cvc5Term x = cvc5_mk_var(d_tm, d_uninterpreted, "x"); + ASSERT_EQ(cvc5_term_get_kind(x), CVC5_KIND_VARIABLE); + Cvc5Term y = cvc5_mk_var(d_tm, d_uninterpreted, "y"); + ASSERT_EQ(cvc5_term_get_kind(y), CVC5_KIND_VARIABLE); + + Cvc5Term f = cvc5_mk_var(d_tm, fun_sort1, "f"); + ASSERT_EQ(cvc5_term_get_kind(f), CVC5_KIND_VARIABLE); + Cvc5Term p = cvc5_mk_var(d_tm, fun_sort2, "p"); + ASSERT_EQ(cvc5_term_get_kind(p), CVC5_KIND_VARIABLE); + + Cvc5Term zero = cvc5_mk_integer_int64(d_tm, 0); + ASSERT_EQ(cvc5_term_get_kind(zero), CVC5_KIND_CONST_INTEGER); + + std::vector args = {f, x}; + Cvc5Term f_x = + cvc5_mk_term(d_tm, CVC5_KIND_APPLY_UF, args.size(), args.data()); + ASSERT_EQ(cvc5_term_get_kind(f_x), CVC5_KIND_APPLY_UF); + args = {f, y}; + Cvc5Term f_y = + cvc5_mk_term(d_tm, CVC5_KIND_APPLY_UF, args.size(), args.data()); + ASSERT_EQ(cvc5_term_get_kind(f_y), CVC5_KIND_APPLY_UF); + args = {f_x, f_y}; + Cvc5Term sum = cvc5_mk_term(d_tm, CVC5_KIND_ADD, args.size(), args.data()); + ASSERT_EQ(cvc5_term_get_kind(sum), CVC5_KIND_ADD); + args = {p, zero}; + Cvc5Term p_0 = + cvc5_mk_term(d_tm, CVC5_KIND_APPLY_UF, args.size(), args.data()); + ASSERT_EQ(cvc5_term_get_kind(p_0), CVC5_KIND_APPLY_UF); + args = {p, f_y}; + Cvc5Term p_f_y = + cvc5_mk_term(d_tm, CVC5_KIND_APPLY_UF, args.size(), args.data()); + ASSERT_EQ(cvc5_term_get_kind(p_f_y), CVC5_KIND_APPLY_UF); + + // Sequence kinds do not exist internally, test that the API properly + // converts them back. + Cvc5Sort seq_sort = cvc5_mk_sequence_sort(d_tm, d_int); + Cvc5Term s = cvc5_mk_const(d_tm, seq_sort, "s"); + args = {s, s}; + Cvc5Term ss = + cvc5_mk_term(d_tm, CVC5_KIND_SEQ_CONCAT, args.size(), args.data()); + ASSERT_EQ(cvc5_term_get_kind(ss), CVC5_KIND_SEQ_CONCAT); +} + +TEST_F(TestCApiBlackTerm, get_sort) +{ + Cvc5Sort bv_sort = cvc5_mk_bv_sort(d_tm, 8); + std::vector domain = {bv_sort}; + Cvc5Sort fun_sort1 = + cvc5_mk_fun_sort(d_tm, domain.size(), domain.data(), d_int); + domain = {d_int}; + Cvc5Sort fun_sort2 = + cvc5_mk_fun_sort(d_tm, domain.size(), domain.data(), d_bool); + + ASSERT_DEATH(cvc5_term_get_sort(nullptr), "invalid term"); + + Cvc5Term x = cvc5_mk_var(d_tm, bv_sort, "x"); + ASSERT_TRUE(cvc5_sort_is_equal(cvc5_term_get_sort(x), bv_sort)); + Cvc5Term y = cvc5_mk_var(d_tm, bv_sort, "y"); + ASSERT_TRUE(cvc5_sort_is_equal(cvc5_term_get_sort(x), cvc5_term_get_sort(y))); + + Cvc5Term f = cvc5_mk_var(d_tm, fun_sort1, "f"); + ASSERT_TRUE(cvc5_sort_is_equal(cvc5_term_get_sort(f), fun_sort1)); + Cvc5Term p = cvc5_mk_var(d_tm, fun_sort2, "p"); + ASSERT_TRUE(cvc5_sort_is_equal(cvc5_term_get_sort(p), fun_sort2)); + + Cvc5Term zero = cvc5_mk_integer_int64(d_tm, 0); + ASSERT_TRUE(cvc5_sort_is_equal(cvc5_term_get_sort(zero), d_int)); + + std::vector args = {f, x}; + Cvc5Term f_x = + cvc5_mk_term(d_tm, CVC5_KIND_APPLY_UF, args.size(), args.data()); + ASSERT_TRUE(cvc5_sort_is_equal(cvc5_term_get_sort(f_x), d_int)); + args = {f, y}; + Cvc5Term f_y = + cvc5_mk_term(d_tm, CVC5_KIND_APPLY_UF, args.size(), args.data()); + ASSERT_TRUE(cvc5_sort_is_equal(cvc5_term_get_sort(f_y), d_int)); + args = {f_x, f_y}; + Cvc5Term sum = cvc5_mk_term(d_tm, CVC5_KIND_ADD, args.size(), args.data()); + ASSERT_TRUE(cvc5_sort_is_equal(cvc5_term_get_sort(sum), d_int)); + args = {p, zero}; + Cvc5Term p_0 = + cvc5_mk_term(d_tm, CVC5_KIND_APPLY_UF, args.size(), args.data()); + ASSERT_TRUE(cvc5_sort_is_equal(cvc5_term_get_sort(p_0), d_bool)); + args = {p, f_y}; + Cvc5Term p_f_y = + cvc5_mk_term(d_tm, CVC5_KIND_APPLY_UF, args.size(), args.data()); + ASSERT_TRUE(cvc5_sort_is_equal(cvc5_term_get_sort(p_f_y), d_bool)); + ASSERT_EQ(cvc5_term_get_kind(p_f_y), CVC5_KIND_APPLY_UF); +} + +TEST_F(TestCApiBlackTerm, get_op) +{ + ASSERT_DEATH(cvc5_term_has_op(nullptr), "invalid term"); + ASSERT_DEATH(cvc5_term_get_op(nullptr), "invalid term"); + + Cvc5Sort bv_sort = cvc5_mk_bv_sort(d_tm, 8); + Cvc5Sort arr_sort = cvc5_mk_array_sort(d_tm, bv_sort, d_int); + std::vector domain = {d_int}; + Cvc5Sort fun_sort = + cvc5_mk_fun_sort(d_tm, domain.size(), domain.data(), bv_sort); + + Cvc5Term x = cvc5_mk_const(d_tm, d_int, "x"); + Cvc5Term a = cvc5_mk_const(d_tm, arr_sort, "a"); + Cvc5Term b = cvc5_mk_const(d_tm, bv_sort, "b"); + + ASSERT_FALSE(cvc5_term_has_op(x)); + ASSERT_DEATH(cvc5_term_get_op(x), "expected Term to have an Op"); + + std::vector args = {a, b}; + Cvc5Term ab = cvc5_mk_term(d_tm, CVC5_KIND_SELECT, args.size(), args.data()); + std::vector idxs = {4, 0}; + Cvc5Op ext = + cvc5_mk_op(d_tm, CVC5_KIND_BITVECTOR_EXTRACT, idxs.size(), idxs.data()); + args = {b}; + Cvc5Term extb = cvc5_mk_term_from_op(d_tm, ext, args.size(), args.data()); + + ASSERT_TRUE(cvc5_term_has_op(ab)); + ASSERT_FALSE(cvc5_op_is_indexed(cvc5_term_get_op(ab))); + // can compare directly to a Kind (will invoke Op constructor) + ASSERT_TRUE(cvc5_term_has_op(extb)); + ASSERT_TRUE(cvc5_op_is_indexed(cvc5_term_get_op(extb))); + ASSERT_TRUE(cvc5_op_is_equal(cvc5_term_get_op(extb), ext)); + + Cvc5Term f = cvc5_mk_const(d_tm, fun_sort, "f"); + args = {f, x}; + Cvc5Term fx = + cvc5_mk_term(d_tm, CVC5_KIND_APPLY_UF, args.size(), args.data()); + + ASSERT_FALSE(cvc5_term_has_op(f)); + ASSERT_DEATH(cvc5_term_get_op(f), "expected Term to have an Op"); + ASSERT_TRUE(cvc5_term_has_op(fx)); + + // testing rebuild from op and children + ASSERT_TRUE(cvc5_term_is_equal( + fx, + cvc5_mk_term_from_op( + d_tm, cvc5_term_get_op(fx), args.size(), args.data()))); + + // Test Datatypes Ops + Cvc5Sort sort = cvc5_mk_param_sort(d_tm, "T"); + std::vector sorts = {sort}; + Cvc5DatatypeDecl decl = cvc5_mk_dt_decl_with_params( + d_tm, "paramlist", sorts.size(), sorts.data(), false); + Cvc5DatatypeConstructorDecl cons = cvc5_mk_dt_cons_decl(d_tm, "cons"); + cvc5_dt_cons_decl_add_selector(cons, "head", sort); + cvc5_dt_cons_decl_add_selector_self(cons, "tail"); + cvc5_dt_decl_add_constructor(decl, cons); + Cvc5DatatypeConstructorDecl nil = cvc5_mk_dt_cons_decl(d_tm, "nil"); + cvc5_dt_decl_add_constructor(decl, nil); + Cvc5Sort list_sort = cvc5_mk_dt_sort(d_tm, decl); + sorts = {d_int}; + Cvc5Sort int_list_sort = + cvc5_sort_instantiate(list_sort, sorts.size(), sorts.data()); + + Cvc5Term c = cvc5_mk_const(d_tm, int_list_sort, "c"); + Cvc5Datatype list = cvc5_sort_get_datatype(list_sort); + // list datatype constructor and selector operator terms + Cvc5Term cons_term = + cvc5_dt_cons_get_term(cvc5_dt_get_constructor_by_name(list, "cons")); + Cvc5Term nil_term = + cvc5_dt_cons_get_term(cvc5_dt_get_constructor_by_name(list, "nil")); + Cvc5Term head_term = cvc5_dt_sel_get_term(cvc5_dt_get_selector(list, "head")); + Cvc5Term tail_term = cvc5_dt_sel_get_term(cvc5_dt_get_selector(list, "tail")); + + args = {nil_term}; + Cvc5Term apply_nil_term = + cvc5_mk_term(d_tm, CVC5_KIND_APPLY_CONSTRUCTOR, args.size(), args.data()); + args = {cons_term, cvc5_mk_integer_int64(d_tm, 0), apply_nil_term}; + Cvc5Term apply_cons_term = + cvc5_mk_term(d_tm, CVC5_KIND_APPLY_CONSTRUCTOR, args.size(), args.data()); + args = {head_term, apply_cons_term}; + Cvc5Term apply_head_term = + cvc5_mk_term(d_tm, CVC5_KIND_APPLY_SELECTOR, args.size(), args.data()); + args = {tail_term, apply_cons_term}; + Cvc5Term apply_tail_term = + cvc5_mk_term(d_tm, CVC5_KIND_APPLY_SELECTOR, args.size(), args.data()); + + ASSERT_FALSE(cvc5_term_has_op(c)); + ASSERT_TRUE(cvc5_term_has_op(apply_nil_term)); + ASSERT_TRUE(cvc5_term_has_op(apply_cons_term)); + ASSERT_TRUE(cvc5_term_has_op(apply_head_term)); + ASSERT_TRUE(cvc5_term_has_op(apply_tail_term)); + + // Test rebuilding + args.clear(); + for (size_t i = 0, n = cvc5_term_get_num_children(apply_head_term); i < n; + ++i) + { + args.push_back(cvc5_term_get_child(apply_head_term, i)); + } + ASSERT_TRUE(cvc5_term_is_equal( + apply_head_term, + cvc5_mk_term_from_op( + d_tm, cvc5_term_get_op(apply_head_term), args.size(), args.data()))); +} + +TEST_F(TestCApiBlackTerm, has_get_symbol) +{ + ASSERT_DEATH(cvc5_term_has_symbol(nullptr), "invalid term"); + ASSERT_DEATH(cvc5_term_get_symbol(nullptr), "invalid term"); + + Cvc5Term t = cvc5_mk_true(d_tm); + Cvc5Term c = cvc5_mk_const(d_tm, d_bool, "|\\|"); + + ASSERT_FALSE(cvc5_term_has_symbol(t)); + ASSERT_TRUE(cvc5_term_has_symbol(c)); + + ASSERT_DEATH(cvc5_term_get_symbol(t), "cannot get symbol"); + ASSERT_EQ(cvc5_term_get_symbol(c), std::string("|\\|")); +} + +TEST_F(TestCApiBlackTerm, assignment) +{ + Cvc5Term t1 = cvc5_mk_integer_int64(d_tm, 1); + Cvc5Term t2 = cvc5_term_copy(t1); + t2 = cvc5_mk_integer_int64(d_tm, 2); + ASSERT_TRUE(cvc5_term_is_equal(t1, cvc5_mk_integer_int64(d_tm, 1))); + ASSERT_TRUE(cvc5_term_is_equal(t2, cvc5_mk_integer_int64(d_tm, 2))); + ASSERT_FALSE(cvc5_term_is_equal(t1, t2)); + cvc5_term_release(t1); + ASSERT_TRUE(cvc5_term_is_equal(t1, cvc5_mk_integer_int64(d_tm, 1))); + ASSERT_TRUE(cvc5_term_is_equal(t2, cvc5_mk_integer_int64(d_tm, 2))); + ASSERT_FALSE(cvc5_term_is_equal(t1, t2)); +} + +TEST_F(TestCApiBlackTerm, children) +{ + ASSERT_DEATH(cvc5_term_get_num_children(nullptr), "invalid term"); + ASSERT_DEATH(cvc5_term_get_child(nullptr, 0), "invalid term"); + // simple term 2+3 + Cvc5Term two = cvc5_mk_integer_int64(d_tm, 2); + std::vector args = {two, cvc5_mk_integer_int64(d_tm, 3)}; + Cvc5Term t1 = cvc5_mk_term(d_tm, CVC5_KIND_ADD, args.size(), args.data()); + ASSERT_EQ(cvc5_term_get_num_children(t1), 2); + ASSERT_TRUE(cvc5_term_is_equal(cvc5_term_get_child(t1, 0), two)); + + for (size_t i = 0, n = cvc5_term_get_num_children(t1); i < n; ++i) + { + (void)cvc5_term_get_child(t1, i); + } + + // apply term f(2) + std::vector domain = {d_int}; + Cvc5Sort fun_sort = + cvc5_mk_fun_sort(d_tm, domain.size(), domain.data(), d_int); + Cvc5Term f = cvc5_mk_const(d_tm, fun_sort, "f"); + args = {f, two}; + Cvc5Term t2 = + cvc5_mk_term(d_tm, CVC5_KIND_APPLY_UF, args.size(), args.data()); + // due to our higher-order view of terms, we treat f as a child of APPLY_UF + ASSERT_EQ(cvc5_term_get_num_children(t2), 2); + ASSERT_TRUE(cvc5_term_is_equal(cvc5_term_get_child(t2, 0), f)); + ASSERT_TRUE(cvc5_term_is_equal(cvc5_term_get_child(t2, 1), two)); +} + +TEST_F(TestCApiBlackTerm, get_integer) +{ + ASSERT_DEATH(cvc5_mk_integer(nullptr, "2"), "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_integer(d_tm, nullptr), "unexpected NULL argument"); + + Cvc5Term int1 = cvc5_mk_integer(d_tm, "-18446744073709551616"); + Cvc5Term int2 = cvc5_mk_integer(d_tm, "-18446744073709551615"); + Cvc5Term int3 = cvc5_mk_integer(d_tm, "-4294967296"); + Cvc5Term int4 = cvc5_mk_integer(d_tm, "-4294967295"); + Cvc5Term int5 = cvc5_mk_integer(d_tm, "-10"); + Cvc5Term int6 = cvc5_mk_integer(d_tm, "0"); + Cvc5Term int7 = cvc5_mk_integer(d_tm, "10"); + Cvc5Term int8 = cvc5_mk_integer(d_tm, "4294967295"); + Cvc5Term int9 = cvc5_mk_integer(d_tm, "4294967296"); + Cvc5Term int10 = cvc5_mk_integer(d_tm, "18446744073709551615"); + Cvc5Term int11 = cvc5_mk_integer(d_tm, "18446744073709551616"); + Cvc5Term int12 = cvc5_mk_integer(d_tm, "-0"); + + ASSERT_DEATH(cvc5_mk_integer(d_tm, ""), "invalid argument"); + ASSERT_DEATH(cvc5_mk_integer(d_tm, "-"), "invalid argument"); + ASSERT_DEATH(cvc5_mk_integer(d_tm, "-1-"), "invalid argument"); + ASSERT_DEATH(cvc5_mk_integer(d_tm, "0.0"), "invalid argument"); + ASSERT_DEATH(cvc5_mk_integer(d_tm, "-0.1"), "invalid argument"); + ASSERT_DEATH(cvc5_mk_integer(d_tm, "012"), "invalid argument"); + ASSERT_DEATH(cvc5_mk_integer(d_tm, "0000"), "invalid argument"); + ASSERT_DEATH(cvc5_mk_integer(d_tm, "-01"), "invalid argument"); + ASSERT_DEATH(cvc5_mk_integer(d_tm, "-00"), "invalid argument"); + + ASSERT_DEATH(cvc5_term_is_int32_value(nullptr), "invalid term"); + ASSERT_DEATH(cvc5_term_is_uint32_value(nullptr), "invalid term"); + ASSERT_DEATH(cvc5_term_is_int64_value(nullptr), "invalid term"); + ASSERT_DEATH(cvc5_term_is_uint64_value(nullptr), "invalid term"); + ASSERT_DEATH(cvc5_term_is_integer_value(nullptr), "invalid term"); + ASSERT_DEATH(cvc5_term_get_integer_value(nullptr), "invalid term"); + ASSERT_DEATH(cvc5_term_get_int32_value(nullptr), "invalid term"); + ASSERT_DEATH(cvc5_term_get_int64_value(nullptr), "invalid term"); + ASSERT_DEATH(cvc5_term_get_uint32_value(nullptr), "invalid term"); + ASSERT_DEATH(cvc5_term_get_uint64_value(nullptr), "invalid term"); + ASSERT_DEATH(cvc5_term_get_real_or_integer_value_sign(nullptr), + "invalid term"); + + ASSERT_TRUE( + !cvc5_term_is_int32_value(int1) && !cvc5_term_is_uint32_value(int1) + && !cvc5_term_is_int64_value(int1) && !cvc5_term_is_uint64_value(int1) + && cvc5_term_is_integer_value(int1)); + ASSERT_EQ(cvc5_term_get_integer_value(int1), + std::string("-18446744073709551616")); + ASSERT_EQ(cvc5_term_get_real_or_integer_value_sign(int1), -1); + + ASSERT_TRUE( + !cvc5_term_is_int32_value(int2) && !cvc5_term_is_uint32_value(int2) + && !cvc5_term_is_int64_value(int2) && !cvc5_term_is_uint64_value(int2) + && cvc5_term_is_integer_value(int2)); + ASSERT_EQ(cvc5_term_get_integer_value(int2), + std::string("-18446744073709551615")); + ASSERT_EQ(cvc5_term_get_real_or_integer_value_sign(int2), -1); + + ASSERT_TRUE( + !cvc5_term_is_int32_value(int3) && !cvc5_term_is_uint32_value(int3) + && cvc5_term_is_int64_value(int3) && !cvc5_term_is_uint64_value(int3) + && cvc5_term_is_integer_value(int3)); + ASSERT_EQ(cvc5_term_get_integer_value(int3), std::string("-4294967296")); + ASSERT_EQ(cvc5_term_get_real_or_integer_value_sign(int3), -1); + ASSERT_EQ(cvc5_term_get_int64_value(int3), -4294967296); + + ASSERT_TRUE( + !cvc5_term_is_int32_value(int4) && !cvc5_term_is_uint32_value(int4) + && cvc5_term_is_int64_value(int4) && !cvc5_term_is_uint64_value(int4) + && cvc5_term_is_integer_value(int4)); + ASSERT_EQ(cvc5_term_get_integer_value(int4), std::string("-4294967295")); + ASSERT_EQ(cvc5_term_get_real_or_integer_value_sign(int4), -1); + ASSERT_EQ(cvc5_term_get_int64_value(int4), -4294967295); + + ASSERT_TRUE(cvc5_term_is_int32_value(int5) && !cvc5_term_is_uint32_value(int5) + && cvc5_term_is_int64_value(int5) + && !cvc5_term_is_uint64_value(int5) + && cvc5_term_is_integer_value(int5)); + ASSERT_EQ(cvc5_term_get_integer_value(int5), std::string("-10")); + ASSERT_EQ(cvc5_term_get_real_or_integer_value_sign(int5), -1); + ASSERT_EQ(cvc5_term_get_int32_value(int5), -10); + ASSERT_EQ(cvc5_term_get_int64_value(int5), -10); + + ASSERT_TRUE(cvc5_term_is_int32_value(int6) && cvc5_term_is_uint32_value(int6) + && cvc5_term_is_int64_value(int6) + && cvc5_term_is_uint64_value(int6) + && cvc5_term_is_integer_value(int6)); + ASSERT_EQ(cvc5_term_get_integer_value(int6), std::string("0")); + ASSERT_EQ(cvc5_term_get_real_or_integer_value_sign(int6), 0); + ASSERT_EQ(cvc5_term_get_int32_value(int6), 0); + ASSERT_EQ(cvc5_term_get_int64_value(int6), 0); + ASSERT_EQ(cvc5_term_get_uint32_value(int6), 0); + ASSERT_EQ(cvc5_term_get_uint64_value(int6), 0); + + ASSERT_TRUE(cvc5_term_is_int32_value(int7) && cvc5_term_is_uint32_value(int7) + && cvc5_term_is_int64_value(int7) + && cvc5_term_is_uint64_value(int7) + && cvc5_term_is_integer_value(int7)); + ASSERT_EQ(cvc5_term_get_integer_value(int7), std::string("10")); + ASSERT_EQ(cvc5_term_get_real_or_integer_value_sign(int7), 1); + ASSERT_EQ(cvc5_term_get_int32_value(int7), 10); + ASSERT_EQ(cvc5_term_get_int64_value(int7), 10); + ASSERT_EQ(cvc5_term_get_uint32_value(int7), 10); + ASSERT_EQ(cvc5_term_get_uint64_value(int7), 10); + + ASSERT_TRUE(!cvc5_term_is_int32_value(int8) && cvc5_term_is_uint32_value(int8) + && cvc5_term_is_int64_value(int8) + && cvc5_term_is_uint64_value(int8) + && cvc5_term_is_integer_value(int8)); + ASSERT_EQ(cvc5_term_get_integer_value(int8), std::string("4294967295")); + ASSERT_EQ(cvc5_term_get_real_or_integer_value_sign(int8), 1); + ASSERT_EQ(cvc5_term_get_int64_value(int8), 4294967295); + ASSERT_EQ(cvc5_term_get_uint32_value(int8), 4294967295); + ASSERT_EQ(cvc5_term_get_uint64_value(int8), 4294967295); + + ASSERT_TRUE( + !cvc5_term_is_int32_value(int9) && !cvc5_term_is_uint32_value(int9) + && cvc5_term_is_int64_value(int9) && cvc5_term_is_uint64_value(int9) + && cvc5_term_is_integer_value(int9)); + ASSERT_EQ(cvc5_term_get_integer_value(int9), std::string("4294967296")); + ASSERT_EQ(cvc5_term_get_real_or_integer_value_sign(int9), 1); + ASSERT_EQ(cvc5_term_get_int64_value(int9), 4294967296); + ASSERT_EQ(cvc5_term_get_uint64_value(int9), 4294967296); + + ASSERT_TRUE( + !cvc5_term_is_int32_value(int10) && !cvc5_term_is_uint32_value(int10) + && !cvc5_term_is_int64_value(int10) && cvc5_term_is_uint64_value(int10) + && cvc5_term_is_integer_value(int10)); + ASSERT_EQ(cvc5_term_get_integer_value(int10), + std::string("18446744073709551615")); + ASSERT_EQ(cvc5_term_get_real_or_integer_value_sign(int10), 1); + ASSERT_EQ(cvc5_term_get_uint64_value(int10), 18446744073709551615ull); + + ASSERT_TRUE( + !cvc5_term_is_int32_value(int11) && !cvc5_term_is_uint32_value(int11) + && !cvc5_term_is_int64_value(int11) && !cvc5_term_is_uint64_value(int11) + && cvc5_term_is_integer_value(int11)); + ASSERT_EQ(cvc5_term_get_integer_value(int11), + std::string("18446744073709551616")); + ASSERT_EQ(cvc5_term_get_real_or_integer_value_sign(int11), 1); + + ASSERT_TRUE( + cvc5_term_is_int32_value(int12) && cvc5_term_is_uint32_value(int12) + && cvc5_term_is_int64_value(int12) && cvc5_term_is_uint64_value(int12) + && cvc5_term_is_integer_value(int12)); + ASSERT_EQ(cvc5_term_get_integer_value(int12), std::string("0")); + ASSERT_EQ(cvc5_term_get_real_or_integer_value_sign(int12), 0); + ASSERT_EQ(cvc5_term_get_int32_value(int12), 0); + ASSERT_EQ(cvc5_term_get_int64_value(int12), 0); + ASSERT_EQ(cvc5_term_get_uint32_value(int12), 0); + ASSERT_EQ(cvc5_term_get_uint64_value(int12), 0); +} + +TEST_F(TestCApiBlackTerm, get_string) +{ + ASSERT_DEATH(cvc5_mk_string(nullptr, "abcde", false), + "unexpected NULL argument"); + ASSERT_DEATH(cvc5_term_is_string_value(nullptr), "invalid term"); + ASSERT_DEATH(cvc5_term_get_string_value(nullptr), "invalid term"); + ASSERT_DEATH(cvc5_mk_string(d_tm, nullptr, false), + "unexpected NULL argument"); + Cvc5Term s1 = cvc5_mk_string(d_tm, "abcde", false); + ASSERT_TRUE(cvc5_term_is_string_value(s1)); + ASSERT_EQ(cvc5_term_get_string_value(s1), std::wstring(L"abcde")); +} + +TEST_F(TestCApiBlackTerm, get_real) +{ + int32_t num32; + uint32_t den32; + int64_t num64; + uint64_t den64; + + ASSERT_DEATH(cvc5_mk_real(nullptr, "2"), "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_real(d_tm, nullptr), "unexpected NULL argument"); + + Cvc5Term real1 = cvc5_mk_real(d_tm, "0"); + Cvc5Term real2 = cvc5_mk_real(d_tm, ".0"); + Cvc5Term real3 = cvc5_mk_real(d_tm, "-17"); + Cvc5Term real4 = cvc5_mk_real(d_tm, "-3/5"); + Cvc5Term real5 = cvc5_mk_real(d_tm, "12.7"); + Cvc5Term real6 = cvc5_mk_real(d_tm, "1/4294967297"); + Cvc5Term real7 = cvc5_mk_real(d_tm, "4294967297"); + Cvc5Term real8 = cvc5_mk_real(d_tm, "1/18446744073709551617"); + Cvc5Term real9 = cvc5_mk_real(d_tm, "18446744073709551617"); + Cvc5Term real10 = cvc5_mk_real(d_tm, "2343.2343"); + + ASSERT_DEATH(cvc5_term_is_real32_value(nullptr), "invalid term"); + ASSERT_DEATH(cvc5_term_is_real64_value(nullptr), "invalid term"); + ASSERT_DEATH(cvc5_term_is_real_value(nullptr), "invalid term"); + ASSERT_DEATH(cvc5_term_get_real_value(nullptr), "invalid term"); + ASSERT_DEATH(cvc5_term_get_real32_value(nullptr, &num32, &den32), + "invalid term"); + ASSERT_DEATH(cvc5_term_get_real32_value(real1, nullptr, &den32), + "unexpected NULL argument"); + ASSERT_DEATH(cvc5_term_get_real32_value(real1, &num32, nullptr), + "unexpected NULL argument"); + ASSERT_DEATH(cvc5_term_get_real64_value(real1, nullptr, &den64), + "unexpected NULL argument"); + ASSERT_DEATH(cvc5_term_get_real64_value(real1, &num64, nullptr), + "unexpected NULL argument"); + ASSERT_DEATH(cvc5_term_get_real64_value(nullptr, &num64, &den64), + "invalid term"); + ASSERT_DEATH(cvc5_term_get_real_or_integer_value_sign(nullptr), + "invalid term"); + + ASSERT_TRUE(cvc5_term_is_real_value(real1) && cvc5_term_is_real64_value(real1) + && cvc5_term_is_real32_value(real1)); + ASSERT_TRUE(cvc5_term_is_real_value(real2) && cvc5_term_is_real64_value(real2) + && cvc5_term_is_real32_value(real2)); + ASSERT_TRUE(cvc5_term_is_real_value(real3) && cvc5_term_is_real64_value(real3) + && cvc5_term_is_real32_value(real3)); + ASSERT_TRUE(cvc5_term_is_real_value(real4) && cvc5_term_is_real64_value(real4) + && cvc5_term_is_real32_value(real4)); + ASSERT_TRUE(cvc5_term_is_real_value(real5) && cvc5_term_is_real64_value(real5) + && cvc5_term_is_real32_value(real5)); + ASSERT_TRUE(cvc5_term_is_real_value(real6) + && cvc5_term_is_real64_value(real6)); + ASSERT_TRUE(cvc5_term_is_real_value(real7) + && cvc5_term_is_real64_value(real7)); + ASSERT_TRUE(cvc5_term_is_real_value(real8)); + ASSERT_TRUE(cvc5_term_is_real_value(real9)); + ASSERT_TRUE(cvc5_term_is_real_value(real10)); + + cvc5_term_get_real32_value(real1, &num32, &den32); + ASSERT_EQ(num32, 0); + ASSERT_EQ(den32, 1); + cvc5_term_get_real64_value(real1, &num64, &den64); + ASSERT_EQ(num64, 0); + ASSERT_EQ(den64, 1); + ASSERT_EQ(cvc5_term_get_real_value(real1), std::string("0/1")); + + cvc5_term_get_real32_value(real2, &num32, &den32); + ASSERT_EQ(num32, 0); + ASSERT_EQ(den32, 1); + cvc5_term_get_real64_value(real2, &num64, &den64); + ASSERT_EQ(num64, 0); + ASSERT_EQ(den64, 1); + ASSERT_EQ(cvc5_term_get_real_value(real2), std::string("0/1")); + + cvc5_term_get_real32_value(real3, &num32, &den32); + ASSERT_EQ(num32, -17); + ASSERT_EQ(den32, 1); + cvc5_term_get_real64_value(real3, &num64, &den64); + ASSERT_EQ(num64, -17); + ASSERT_EQ(den64, 1); + ASSERT_EQ(cvc5_term_get_real_value(real3), std::string("-17/1")); + + cvc5_term_get_real32_value(real4, &num32, &den32); + ASSERT_EQ(num32, -3); + ASSERT_EQ(den32, 5); + cvc5_term_get_real64_value(real4, &num64, &den64); + ASSERT_EQ(num64, -3); + ASSERT_EQ(den64, 5); + ASSERT_EQ(cvc5_term_get_real_value(real4), std::string("-3/5")); + + cvc5_term_get_real32_value(real5, &num32, &den32); + ASSERT_EQ(num32, 127); + ASSERT_EQ(den32, 10); + cvc5_term_get_real64_value(real5, &num64, &den64); + ASSERT_EQ(num64, 127); + ASSERT_EQ(den64, 10); + ASSERT_EQ(cvc5_term_get_real_value(real5), std::string("127/10")); + + cvc5_term_get_real64_value(real6, &num64, &den64); + ASSERT_EQ(num64, 1); + ASSERT_EQ(den64, 4294967297); + ASSERT_EQ(cvc5_term_get_real_value(real6), std::string("1/4294967297")); + + cvc5_term_get_real64_value(real7, &num64, &den64); + ASSERT_EQ(num64, 4294967297); + ASSERT_EQ(den64, 1); + ASSERT_EQ(cvc5_term_get_real_value(real7), std::string("4294967297/1")); + + ASSERT_EQ(cvc5_term_get_real_value(real8), + std::string("1/18446744073709551617")); + + ASSERT_EQ(cvc5_term_get_real_value(real9), + std::string("18446744073709551617/1")); + + ASSERT_EQ(cvc5_term_get_real_value(real10), std::string("23432343/10000")); +} + +TEST_F(TestCApiBlackTerm, get_const_array_base) +{ + Cvc5Sort arr_sort = cvc5_mk_array_sort(d_tm, d_int, d_int); + Cvc5Term one = cvc5_mk_integer_int64(d_tm, 1); + Cvc5Term const_arr = cvc5_mk_const_array(d_tm, arr_sort, one); + + ASSERT_DEATH(cvc5_term_is_const_array(nullptr), "invalid term"); + ASSERT_DEATH(cvc5_term_get_const_array_base(nullptr), "invalid term"); + + ASSERT_TRUE(cvc5_term_is_const_array(const_arr)); + ASSERT_TRUE( + cvc5_term_is_equal(cvc5_term_get_const_array_base(const_arr), one)); + + Cvc5Term a = cvc5_mk_const(d_tm, arr_sort, "a"); + ASSERT_DEATH(cvc5_term_get_const_array_base(a), "invalid argument"); + ASSERT_DEATH(cvc5_term_get_const_array_base(one), "invalid argument"); +} + +TEST_F(TestCApiBlackTerm, get_boolean_value) +{ + Cvc5Term b1 = cvc5_mk_true(d_tm); + Cvc5Term b2 = cvc5_mk_false(d_tm); + + ASSERT_DEATH(cvc5_term_is_boolean_value(nullptr), "invalid term"); + ASSERT_DEATH(cvc5_term_get_boolean_value(nullptr), "invalid term"); + ASSERT_TRUE(cvc5_term_is_boolean_value(b1)); + ASSERT_TRUE(cvc5_term_is_boolean_value(b2)); + ASSERT_TRUE(cvc5_term_get_boolean_value(b1)); + ASSERT_FALSE(cvc5_term_get_boolean_value(b2)); +} + +TEST_F(TestCApiBlackTerm, get_bv_value) +{ + ASSERT_DEATH(cvc5_mk_bv_uint64(nullptr, 8, 15), "unexpected NULL argument"); + ASSERT_DEATH(cvc5_term_is_bv_value(nullptr), "invalid term"); + + Cvc5Term b1 = cvc5_mk_bv_uint64(d_tm, 8, 15); + Cvc5Term b2 = cvc5_mk_bv(d_tm, 8, "00001111", 2); + Cvc5Term b3 = cvc5_mk_bv(d_tm, 8, "15", 10); + Cvc5Term b4 = cvc5_mk_bv(d_tm, 8, "0f", 16); + Cvc5Term b5 = cvc5_mk_bv(d_tm, 9, "00001111", 2); + Cvc5Term b6 = cvc5_mk_bv(d_tm, 9, "15", 10); + Cvc5Term b7 = cvc5_mk_bv(d_tm, 9, "0f", 16); + + ASSERT_TRUE(cvc5_term_is_bv_value(b1)); + ASSERT_TRUE(cvc5_term_is_bv_value(b2)); + ASSERT_TRUE(cvc5_term_is_bv_value(b3)); + ASSERT_TRUE(cvc5_term_is_bv_value(b4)); + ASSERT_TRUE(cvc5_term_is_bv_value(b5)); + ASSERT_TRUE(cvc5_term_is_bv_value(b6)); + ASSERT_TRUE(cvc5_term_is_bv_value(b7)); + + ASSERT_EQ(std::string("00001111"), cvc5_term_get_bv_value(b1, 2)); + ASSERT_EQ(std::string("15"), cvc5_term_get_bv_value(b1, 10)); + ASSERT_EQ(std::string("f"), cvc5_term_get_bv_value(b1, 16)); + ASSERT_EQ(std::string("00001111"), cvc5_term_get_bv_value(b2, 2)); + ASSERT_EQ(std::string("15"), cvc5_term_get_bv_value(b2, 10)); + ASSERT_EQ(std::string("f"), cvc5_term_get_bv_value(b2, 16)); + ASSERT_EQ(std::string("00001111"), cvc5_term_get_bv_value(b3, 2)); + ASSERT_EQ(std::string("15"), cvc5_term_get_bv_value(b3, 10)); + ASSERT_EQ(std::string("f"), cvc5_term_get_bv_value(b3, 16)); + ASSERT_EQ(std::string("00001111"), cvc5_term_get_bv_value(b4, 2)); + ASSERT_EQ(std::string("15"), cvc5_term_get_bv_value(b4, 10)); + ASSERT_EQ(std::string("f"), cvc5_term_get_bv_value(b4, 16)); + ASSERT_EQ(std::string("000001111"), cvc5_term_get_bv_value(b5, 2)); + ASSERT_EQ(std::string("15"), cvc5_term_get_bv_value(b5, 10)); + ASSERT_EQ(std::string("f"), cvc5_term_get_bv_value(b5, 16)); + ASSERT_EQ(std::string("000001111"), cvc5_term_get_bv_value(b6, 2)); + ASSERT_EQ(std::string("15"), cvc5_term_get_bv_value(b6, 10)); + ASSERT_EQ(std::string("f"), cvc5_term_get_bv_value(b6, 16)); + ASSERT_EQ(std::string("000001111"), cvc5_term_get_bv_value(b7, 2)); + ASSERT_EQ(std::string("15"), cvc5_term_get_bv_value(b7, 10)); + ASSERT_EQ(std::string("f"), cvc5_term_get_bv_value(b7, 16)); +} + +TEST_F(TestCApiBlackTerm, is_ff_value) +{ + ASSERT_DEATH(cvc5_term_is_ff_value(nullptr), "invalid term"); + Cvc5Sort fs = cvc5_mk_ff_sort(d_tm, "7", 10); + Cvc5Term fv = cvc5_mk_ff_elem(d_tm, "1", fs, 10); + ASSERT_TRUE(cvc5_term_is_ff_value(fv)); + Cvc5Term b1 = cvc5_mk_bv_uint64(d_tm, 8, 15); + ASSERT_FALSE(cvc5_term_is_ff_value(b1)); +} + +TEST_F(TestCApiBlackTerm, get_ff_value) +{ + ASSERT_DEATH(cvc5_term_get_ff_value(nullptr), "invalid term"); + Cvc5Sort fs = cvc5_mk_ff_sort(d_tm, "7", 10); + Cvc5Term fv = cvc5_mk_ff_elem(d_tm, "1", fs, 10); + ASSERT_EQ(std::string("1"), cvc5_term_get_ff_value(fv)); + Cvc5Term b1 = cvc5_mk_bv_uint64(d_tm, 8, 15); + ASSERT_DEATH(cvc5_term_get_ff_value(b1), + "expected Term to be a finite field value"); +} + +TEST_F(TestCApiBlackTerm, get_uninterpreted_sort_value) +{ + ASSERT_DEATH(cvc5_term_get_uninterpreted_sort_value(nullptr), "invalid term"); + // cvc5_set_option(d_solver, "produce-models", "true"); + // Cvc5Term x = cvc5_mk_const(d_tm, d_uninterpreted, "x"); + // Cvc5Term y = cvc5_mk_const(d_tm, d_uninterpreted, "y"); + // std::vector args = {x, y}; + // cvc5_assert_formula( + // d_solver, cvc5_mk_term(d_tm, CVC5_KIND_EQUAL, args.size(), + // args.data())); + // Cvc5Result res = cvc5_check_sat(d_solver); + // ASSERT_TRUE(cvc5_result_is_sat(res)); + // Cvc5Term vx = cvc5_get_value(d_solver, x); + // Cvc5Term vy = cvc5_get_value(d_solver, y); + // ASSERT_TRUE(cvc5_term_is_uninterpreted_sort_value(vx)); + // ASSERT_TRUE(cvc5_term_is_uninterpreted_sort_value(vy)); + // ASSERT_TRUE(cvc5_term_is_equal(cvc5_term_get_uninterpreted_sort_value(vx), + // cvc5_term_get_uninterpreted_sort_value(vy))); +} + +TEST_F(TestCApiBlackTerm, is_rm_value) +{ + ASSERT_DEATH(cvc5_term_is_rm_value(nullptr), "invalid term"); + ASSERT_FALSE(cvc5_term_is_rm_value(cvc5_mk_integer_int64(d_tm, 15))); + ASSERT_TRUE(cvc5_term_is_rm_value( + cvc5_mk_rm(d_tm, CVC5_RM_ROUND_NEAREST_TIES_TO_EVEN))); + ASSERT_FALSE( + cvc5_term_is_rm_value(cvc5_mk_const(d_tm, cvc5_get_rm_sort(d_tm), ""))); +} + +TEST_F(TestCApiBlackTerm, get_rm_value) +{ + ASSERT_DEATH(cvc5_term_get_rm_value(nullptr), "invalid term"); + ASSERT_DEATH(cvc5_term_get_rm_value(cvc5_mk_integer_int64(d_tm, 15)), + "invalid argument"); + + ASSERT_EQ(cvc5_term_get_rm_value( + cvc5_mk_rm(d_tm, CVC5_RM_ROUND_NEAREST_TIES_TO_EVEN)), + CVC5_RM_ROUND_NEAREST_TIES_TO_EVEN); + ASSERT_EQ(cvc5_term_get_rm_value( + cvc5_mk_rm(d_tm, CVC5_RM_ROUND_NEAREST_TIES_TO_AWAY)), + CVC5_RM_ROUND_NEAREST_TIES_TO_AWAY); + ASSERT_EQ( + cvc5_term_get_rm_value(cvc5_mk_rm(d_tm, CVC5_RM_ROUND_TOWARD_POSITIVE)), + CVC5_RM_ROUND_TOWARD_POSITIVE); + ASSERT_EQ( + cvc5_term_get_rm_value(cvc5_mk_rm(d_tm, CVC5_RM_ROUND_TOWARD_NEGATIVE)), + CVC5_RM_ROUND_TOWARD_NEGATIVE); + ASSERT_EQ(cvc5_term_get_rm_value(cvc5_mk_rm(d_tm, CVC5_RM_ROUND_TOWARD_ZERO)), + CVC5_RM_ROUND_TOWARD_ZERO); +} + +TEST_F(TestCApiBlackTerm, get_tuple) +{ + Cvc5Term t1 = cvc5_mk_integer_int64(d_tm, 15); + Cvc5Term t2 = cvc5_mk_real_num_den(d_tm, 17, 25); + Cvc5Term t3 = cvc5_mk_string(d_tm, "abc", false); + std::vector args = {t1, t2, t3}; + Cvc5Term tup = cvc5_mk_tuple(d_tm, args.size(), args.data()); + + size_t size; + ASSERT_DEATH(cvc5_term_get_tuple_value(nullptr, &size), "invalid term"); + ASSERT_DEATH(cvc5_term_get_tuple_value(tup, nullptr), + "unexpected NULL argument"); + ASSERT_DEATH(cvc5_term_is_tuple_value(nullptr), "invalid term"); + + ASSERT_TRUE(cvc5_term_is_tuple_value(tup)); + const Cvc5Term* val = cvc5_term_get_tuple_value(tup, &size); + ASSERT_EQ(size, 3); + ASSERT_TRUE(cvc5_term_is_equal(val[0], t1)); + ASSERT_TRUE(cvc5_term_is_equal(val[1], t2)); + ASSERT_TRUE(cvc5_term_is_equal(val[2], t3)); +} + +TEST_F(TestCApiBlackTerm, get_fp_value) +{ + uint32_t ew, sw; + Cvc5Term res; + Cvc5Term bv_val = cvc5_mk_bv(d_tm, 16, "0000110000000011", 2); + Cvc5Term fp_val = cvc5_mk_fp(d_tm, 5, 11, bv_val); + + ASSERT_DEATH(cvc5_term_is_fp_value(nullptr), "invalid term"); + ASSERT_DEATH(cvc5_term_is_fp_pos_zero(nullptr), "invalid term"); + ASSERT_DEATH(cvc5_term_is_fp_neg_zero(nullptr), "invalid term"); + ASSERT_DEATH(cvc5_term_is_fp_pos_inf(nullptr), "invalid term"); + ASSERT_DEATH(cvc5_term_is_fp_neg_inf(nullptr), "invalid term"); + ASSERT_DEATH(cvc5_term_is_fp_nan(nullptr), "invalid term"); + ASSERT_DEATH(cvc5_term_get_fp_value(nullptr, &ew, &sw, &res), "invalid term"); + ASSERT_DEATH(cvc5_term_get_fp_value(fp_val, nullptr, &sw, &res), + "unexpected NULL argument"); + ASSERT_DEATH(cvc5_term_get_fp_value(fp_val, &ew, nullptr, &res), + "unexpected NULL argument"); + ASSERT_DEATH(cvc5_term_get_fp_value(fp_val, &ew, &sw, nullptr), + "unexpected NULL argument"); + + ASSERT_TRUE(cvc5_term_is_fp_value(fp_val)); + ASSERT_FALSE(cvc5_term_is_fp_pos_zero(fp_val)); + ASSERT_FALSE(cvc5_term_is_fp_neg_zero(fp_val)); + ASSERT_FALSE(cvc5_term_is_fp_pos_inf(fp_val)); + ASSERT_FALSE(cvc5_term_is_fp_neg_inf(fp_val)); + ASSERT_FALSE(cvc5_term_is_fp_nan(fp_val)); + + cvc5_term_get_fp_value(fp_val, &ew, &sw, &res); + ASSERT_EQ(ew, 5u); + ASSERT_EQ(sw, 11u); + ASSERT_TRUE(cvc5_term_is_equal(bv_val, res)); + + ASSERT_TRUE(cvc5_term_is_fp_pos_zero(cvc5_mk_fp_pos_zero(d_tm, 5, 11))); + ASSERT_TRUE(cvc5_term_is_fp_neg_zero(cvc5_mk_fp_neg_zero(d_tm, 5, 11))); + ASSERT_TRUE(cvc5_term_is_fp_pos_inf(cvc5_mk_fp_pos_inf(d_tm, 5, 11))); + ASSERT_TRUE(cvc5_term_is_fp_neg_inf(cvc5_mk_fp_neg_inf(d_tm, 5, 11))); + ASSERT_TRUE(cvc5_term_is_fp_nan(cvc5_mk_fp_nan(d_tm, 5, 11))); +} + +TEST_F(TestCApiBlackTerm, get_set_value) +{ + Cvc5Sort s = cvc5_mk_set_sort(d_tm, d_int); + + Cvc5Term i1 = cvc5_mk_integer_int64(d_tm, 5); + Cvc5Term i2 = cvc5_mk_integer_int64(d_tm, 7); + + Cvc5Term s1 = cvc5_mk_empty_set(d_tm, s); + std::vector args = {i1}; + Cvc5Term s2 = + cvc5_mk_term(d_tm, CVC5_KIND_SET_SINGLETON, args.size(), args.data()); + Cvc5Term s3 = + cvc5_mk_term(d_tm, CVC5_KIND_SET_SINGLETON, args.size(), args.data()); + args = {i2}; + Cvc5Term s4 = + cvc5_mk_term(d_tm, CVC5_KIND_SET_SINGLETON, args.size(), args.data()); + args = {s3, s4}; + args = {s2, + cvc5_mk_term(d_tm, CVC5_KIND_SET_UNION, args.size(), args.data())}; + Cvc5Term s5 = + cvc5_mk_term(d_tm, CVC5_KIND_SET_UNION, args.size(), args.data()); + + ASSERT_DEATH(cvc5_term_is_set_value(nullptr), "invalid term"); + ASSERT_TRUE(cvc5_term_is_set_value(s1)); + ASSERT_TRUE(cvc5_term_is_set_value(s2)); + ASSERT_TRUE(cvc5_term_is_set_value(s3)); + ASSERT_TRUE(cvc5_term_is_set_value(s4)); + ASSERT_FALSE(cvc5_term_is_set_value(s5)); + // s5 = cvc5_simplify(d_solver, s5); + // ASSERT_TRUE(cvc5_term_is_set_value(s5)); + + size_t size; + ASSERT_DEATH(cvc5_term_get_set_value(nullptr, &size), "invalid term"); + ASSERT_DEATH(cvc5_term_get_set_value(s1, nullptr), + "unexpected NULL argument"); + (void)cvc5_term_get_set_value(s1, &size); + ASSERT_EQ(size, 0); + const Cvc5Term* res2 = cvc5_term_get_set_value(s2, &size); + ASSERT_EQ(size, 1); + ASSERT_TRUE(cvc5_term_is_equal(res2[0], i1)); + const Cvc5Term* res3 = cvc5_term_get_set_value(s3, &size); + ASSERT_EQ(size, 1); + ASSERT_TRUE(cvc5_term_is_equal(res3[0], i1)); + const Cvc5Term* res4 = cvc5_term_get_set_value(s4, &size); + ASSERT_EQ(size, 1); + ASSERT_TRUE(cvc5_term_is_equal(res4[0], i2)); + // const Cvc5Term* res5 = cvc5_term_get_set_value(s5, &size); + // ASSERT_EQ(size, 2); + // ASSERT_TRUE(cvc5_term_is_equal(res5[0], i1)); + // ASSERT_TRUE(cvc5_term_is_equal(res5[1], i2)); +} + +TEST_F(TestCApiBlackTerm, get_sequence_value) +{ + Cvc5Sort seq_sort = cvc5_mk_sequence_sort(d_tm, d_int); + + Cvc5Term i1 = cvc5_mk_integer_int64(d_tm, 5); + Cvc5Term i2 = cvc5_mk_integer_int64(d_tm, 7); + + Cvc5Term s1 = cvc5_mk_empty_sequence(d_tm, seq_sort); + std::vector args = {i1}; + Cvc5Term s2 = + cvc5_mk_term(d_tm, CVC5_KIND_SEQ_UNIT, args.size(), args.data()); + Cvc5Term s3 = + cvc5_mk_term(d_tm, CVC5_KIND_SEQ_UNIT, args.size(), args.data()); + args = {i2}; + Cvc5Term s4 = + cvc5_mk_term(d_tm, CVC5_KIND_SEQ_UNIT, args.size(), args.data()); + args = {s3, s4}; + args = {s2, + cvc5_mk_term(d_tm, CVC5_KIND_SEQ_CONCAT, args.size(), args.data())}; + Cvc5Term s5 = + cvc5_mk_term(d_tm, CVC5_KIND_SEQ_CONCAT, args.size(), args.data()); + + ASSERT_DEATH(cvc5_mk_empty_sequence(nullptr, seq_sort), + "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_empty_sequence(d_tm, nullptr), "invalid sort"); + ASSERT_DEATH(cvc5_term_is_sequence_value(nullptr), "invalid term"); + + ASSERT_TRUE(cvc5_term_is_sequence_value(s1)); + ASSERT_FALSE(cvc5_term_is_sequence_value(s2)); + ASSERT_FALSE(cvc5_term_is_sequence_value(s3)); + ASSERT_FALSE(cvc5_term_is_sequence_value(s4)); + ASSERT_FALSE(cvc5_term_is_sequence_value(s5)); + // s2 = cvc5_simplify(d_solver, s2); + // ASSERT_TRUE(cvc5_term_is_sequence_value(s2)); + // s3 = cvc5_simplify(d_solver, s3); + // ASSERT_TRUE(cvc5_term_is_sequence_value(s3)); + // s4 = cvc5_simplify(d_solver, s4); + // ASSERT_TRUE(cvc5_term_is_sequence_value(s4)); + // s5 = cvc5_simplify(d_solver, s5); + // ASSERT_TRUE(cvc5_term_is_sequence_value(s5)); + + size_t size; + ASSERT_DEATH(cvc5_term_get_sequence_value(nullptr, &size), "invalid term"); + ASSERT_DEATH(cvc5_term_get_sequence_value(s1, nullptr), + "unexpected NULL argument"); + (void)cvc5_term_get_sequence_value(s1, &size); + ASSERT_EQ(size, 0); + // const Cvc5Term* res2 = cvc5_term_get_sequence_value(s2, &size); + // ASSERT_EQ(size, 1); + // ASSERT_TRUE(cvc5_term_is_equal(res2[0], i1)); + // const Cvc5Term* res3 = cvc5_term_get_sequence_value(s3, &size); + // ASSERT_EQ(size, 1); + // ASSERT_TRUE(cvc5_term_is_equal(res3[0], i1)); + // const Cvc5Term* res4 = cvc5_term_get_sequence_value(s4, &size); + // ASSERT_EQ(size, 1); + // ASSERT_TRUE(cvc5_term_is_equal(res4[0], i2)); + // const Cvc5Term* res5 = cvc5_term_get_sequence_value(s5, &size); + // ASSERT_EQ(size, 3); + // ASSERT_TRUE(cvc5_term_is_equal(res5[0], i1)); + // ASSERT_TRUE(cvc5_term_is_equal(res5[1], i1)); + // ASSERT_TRUE(cvc5_term_is_equal(res5[1], i2)); + + seq_sort = cvc5_mk_sequence_sort(d_tm, d_real); + // A seq.unit app is not a constant sequence (regardless of whether it is + // applied to a constant). + args = {cvc5_mk_real_int64(d_tm, 1)}; + Cvc5Term su = + cvc5_mk_term(d_tm, CVC5_KIND_SEQ_UNIT, args.size(), args.data()); + ASSERT_DEATH(cvc5_term_get_sequence_value(su, &size), "invalid argument"); +} + +TEST_F(TestCApiBlackTerm, substitute) +{ + Cvc5Term x = cvc5_mk_const(d_tm, d_int, "x"); + Cvc5Term one = cvc5_mk_integer_int64(d_tm, 1); + Cvc5Term ttrue = cvc5_mk_true(d_tm); + std::vector args = {x, x}; + Cvc5Term xpx = cvc5_mk_term(d_tm, CVC5_KIND_ADD, args.size(), args.data()); + args = {one, one}; + Cvc5Term onepone = + cvc5_mk_term(d_tm, CVC5_KIND_ADD, args.size(), args.data()); + + ASSERT_DEATH(cvc5_term_substitute_term(nullptr, x, one), "invalid term"); + ASSERT_DEATH(cvc5_term_substitute_term(xpx, nullptr, one), "invalid term"); + ASSERT_DEATH(cvc5_term_substitute_term(xpx, x, nullptr), "invalid term"); + + ASSERT_TRUE( + cvc5_term_is_equal(cvc5_term_substitute_term(xpx, x, one), onepone)); + // incorrect due to type + ASSERT_DEATH(cvc5_term_substitute_term(xpx, one, ttrue), + "expected terms of the same sort"); + + // simultaneous substitution + Cvc5Term y = cvc5_mk_const(d_tm, d_int, "y"); + args = {x, y}; + Cvc5Term xpy = cvc5_mk_term(d_tm, CVC5_KIND_ADD, args.size(), args.data()); + args = {y, one}; + Cvc5Term xpone = cvc5_mk_term(d_tm, CVC5_KIND_ADD, args.size(), args.data()); + std::vector es = {x, y}; + std::vector rs = {y, one}; + ASSERT_EQ(cvc5_term_substitute_terms(xpy, es.size(), es.data(), rs.data()), + xpone); + + // incorrect substitution due to types + rs[1] = ttrue; + ASSERT_DEATH(cvc5_term_substitute_terms(xpy, es.size(), es.data(), rs.data()), + "expecting terms of the same sort at index 1"); + + // null cannot substitute + es = {nullptr, y}; + rs = {y, one}; + ASSERT_DEATH(cvc5_term_substitute_terms(xpy, es.size(), es.data(), rs.data()), + "invalid term at index 0"); + es = {x, nullptr}; + ASSERT_DEATH(cvc5_term_substitute_terms(xpy, es.size(), es.data(), rs.data()), + "invalid term at index 1"); + es = {x, y}; + rs = {nullptr, one}; + ASSERT_DEATH(cvc5_term_substitute_terms(xpy, es.size(), es.data(), rs.data()), + "invalid term at index 0"); + rs = {y, nullptr}; + ASSERT_DEATH(cvc5_term_substitute_terms(xpy, es.size(), es.data(), rs.data()), + "invalid term at index 1"); +} + +TEST_F(TestCApiBlackTerm, const_array) +{ + Cvc5Sort arr_sort = cvc5_mk_array_sort(d_tm, d_int, d_int); + Cvc5Term a = cvc5_mk_const(d_tm, arr_sort, "a"); + Cvc5Term one = cvc5_mk_integer_int64(d_tm, 1); + Cvc5Term two = cvc5_mk_bv_uint64(d_tm, 2, 2); + Cvc5Term i = cvc5_mk_const(d_tm, d_int, "i"); + Cvc5Term const_arr = cvc5_mk_const_array(d_tm, arr_sort, one); + + ASSERT_DEATH(cvc5_mk_const_array(nullptr, arr_sort, one), + "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_const_array(d_tm, nullptr, one), "invalid sort"); + ASSERT_DEATH(cvc5_mk_const_array(d_tm, arr_sort, nullptr), "invalid term"); + ASSERT_DEATH(cvc5_mk_const_array(d_tm, arr_sort, two), + "value does not match element sort"); + ASSERT_DEATH(cvc5_mk_const_array(d_tm, arr_sort, i), "invalid argument"); + + ASSERT_DEATH(cvc5_term_get_const_array_base(nullptr), "invalid term"); + + ASSERT_EQ(cvc5_term_get_kind(const_arr), CVC5_KIND_CONST_ARRAY); + ASSERT_TRUE( + cvc5_term_is_equal(cvc5_term_get_const_array_base(const_arr), one)); + ASSERT_DEATH(cvc5_term_get_const_array_base(a), "invalid argument"); + + arr_sort = cvc5_mk_array_sort(d_tm, d_real, d_real); + Cvc5Term zero_array = + cvc5_mk_const_array(d_tm, arr_sort, cvc5_mk_real_int64(d_tm, 0)); + std::vector args = { + zero_array, cvc5_mk_real_int64(d_tm, 1), cvc5_mk_real_int64(d_tm, 2)}; + Cvc5Term stores = + cvc5_mk_term(d_tm, CVC5_KIND_STORE, args.size(), args.data()); + args = {stores, cvc5_mk_real_int64(d_tm, 2), cvc5_mk_real_int64(d_tm, 3)}; + stores = cvc5_mk_term(d_tm, CVC5_KIND_STORE, args.size(), args.data()); + args = {stores, cvc5_mk_real_int64(d_tm, 4), cvc5_mk_real_int64(d_tm, 5)}; + stores = cvc5_mk_term(d_tm, CVC5_KIND_STORE, args.size(), args.data()); +} + +TEST_F(TestCApiBlackTerm, get_cardinality_constraint) +{ + ASSERT_DEATH(cvc5_mk_cardinality_constraint(nullptr, d_uninterpreted, 3), + "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_cardinality_constraint(d_tm, nullptr, 3), + "invalid sort"); + ASSERT_DEATH(cvc5_term_is_cardinality_constraint(nullptr), "invalid term"); + + Cvc5Term t = cvc5_mk_cardinality_constraint(d_tm, d_uninterpreted, 3); + ASSERT_TRUE(cvc5_term_is_cardinality_constraint(t)); + + Cvc5Sort res; + uint32_t res_upper; + ASSERT_DEATH(cvc5_term_get_cardinality_constraint(nullptr, &res, &res_upper), + "invalid term"); + ASSERT_DEATH(cvc5_term_get_cardinality_constraint(t, nullptr, &res_upper), + "unexpected NULL argument"); + ASSERT_DEATH(cvc5_term_get_cardinality_constraint(t, &res, nullptr), + "unexpected NULL argument"); + + cvc5_term_get_cardinality_constraint(t, &res, &res_upper); + ASSERT_TRUE(cvc5_sort_is_equal(res, d_uninterpreted)); + ASSERT_EQ(res_upper, 3); + + Cvc5Term x = cvc5_mk_const(d_tm, d_int, "x"); + ASSERT_FALSE(cvc5_term_is_cardinality_constraint(x)); + ASSERT_DEATH(cvc5_term_get_cardinality_constraint(x, &res, &res_upper), + "invalid argument"); +} + +TEST_F(TestCApiBlackTerm, get_real_algebraic_number) +{ + // cvc5_set_option(d_solver, "produce-models", "true"); + // cvc5_set_logic(d_solver, "QF_NRA"); + Cvc5Term x = cvc5_mk_const(d_tm, d_real, "x"); + Cvc5Term y = cvc5_mk_var(d_tm, d_real, "y"); + std::vector args = {x, x}; + Cvc5Term x2 = cvc5_mk_term(d_tm, CVC5_KIND_MULT, args.size(), args.data()); + Cvc5Term two = cvc5_mk_real_num_den(d_tm, 2, 1); + args = {x2, two}; + // Cvc5Term eq = cvc5_mk_term(d_tm, CVC5_KIND_EQUAL, args.size(), + // args.data()); cvc5_assert_formula(d_solver, eq); + + ASSERT_DEATH(cvc5_term_is_real_algebraic_number(nullptr), "invalid term"); + ASSERT_DEATH( + cvc5_term_get_real_algebraic_number_defining_polynomial(nullptr, y), + "invalid term"); + ASSERT_DEATH( + cvc5_term_get_real_algebraic_number_defining_polynomial(x, nullptr), + "invalid term"); + ASSERT_DEATH(cvc5_term_get_real_algebraic_number_lower_bound(nullptr), + "invalid term"); + ASSERT_DEATH(cvc5_term_get_real_algebraic_number_upper_bound(nullptr), + "invalid term"); + + // Note that check-sat should only return "sat" if libpoly is enabled. + // Otherwise, we do not test the following functionality. + // if (cvc5_result_is_sat(cvc5_check_sat(d_solver))) + //{ + // // We find a model for (x*x = 2), where x should be a real algebraic + // number. + // // We assert that its defining polynomial is non-null and its lower and + // // upper bounds are real. + // Cvc5Term vx = cvc5_get_value(d_solver, x); + // ASSERT_TRUE(cvc5_term_is_real_algebraic_number(vx)); + // Cvc5Term poly = + // cvc5_term_get_real_algebraic_number_defining_polynomial(vx, y); + // ASSERT_NE(poly, nullptr); + + // Cvc5Term lb = cvc5_term_get_real_algebraic_number_lower_bound(vx); + // Cvc5Term ub = cvc5_term_get_real_algebraic_number_upper_bound(vx); + // ASSERT_TRUE(cvc5_term_is_real_value(lb)); + // ASSERT_TRUE(cvc5_term_is_real_value(ub)); + // // cannot call with non-variable + // Cvc5Term yc = cvc5_mk_const(d_tm, d_real, "y"); + // ASSERT_DEATH(cvc5_term_get_real_algebraic_number_defining_polynomial(vx, + // yc), "asdf"); + //} +} + +TEST_F(TestCApiBlackTerm, get_skolem) +{ + size_t size; + ASSERT_DEATH(cvc5_term_is_skolem(nullptr), "invalid term"); + ASSERT_DEATH(cvc5_term_get_skolem_id(nullptr), "invalid term"); + // ordinary variables are not skolems + Cvc5Term x = cvc5_mk_const(d_tm, d_int, "x"); + ASSERT_FALSE(cvc5_term_is_skolem(x)); + ASSERT_DEATH(cvc5_term_get_skolem_id(x), "invalid argument"); + ASSERT_DEATH(cvc5_term_get_skolem_indices(x, &size), "invalid argument"); + ASSERT_DEATH(cvc5_term_get_skolem_indices(nullptr, &size), "invalid term"); + ASSERT_DEATH(cvc5_term_get_skolem_indices(x, nullptr), + "unexpected NULL argument"); +} + +TEST_F(TestCApiBlackTerm, term_scoped_to_string) +{ + Cvc5Term x = cvc5_mk_const(d_tm, d_int, "x"); + ASSERT_EQ(cvc5_term_to_string(x), std::string("x")); + ASSERT_EQ(cvc5_term_to_string(x), std::string("x")); +} + +} // namespace cvc5::internal::test diff --git a/test/unit/api/c/capi_term_manager_black.cpp b/test/unit/api/c/capi_term_manager_black.cpp index df1a3b6bdd2..451baba2a31 100644 --- a/test/unit/api/c/capi_term_manager_black.cpp +++ b/test/unit/api/c/capi_term_manager_black.cpp @@ -28,16 +28,16 @@ class TestCApiBlackTermManager : public ::testing::Test void SetUp() override { d_tm = cvc5_term_manager_new(); - // d_bool = cvc5_get_boolean_sort(d_tm); - // d_int = cvc5_get_integer_sort(d_tm); - // d_real = cvc5_get_real_sort(d_tm); + d_bool = cvc5_get_boolean_sort(d_tm); + d_int = cvc5_get_integer_sort(d_tm); + d_real = cvc5_get_real_sort(d_tm); } void TearDown() override { cvc5_term_manager_delete(d_tm); } Cvc5TermManager* d_tm; - // Cvc5Sort d_bool; - // Cvc5Sort d_int; - // Cvc5Sort d_real; + Cvc5Sort d_bool; + Cvc5Sort d_int; + Cvc5Sort d_real; }; TEST_F(TestCApiBlackTermManager, new) {} @@ -80,16 +80,13 @@ TEST_F(TestCApiBlackTermManager, get_rm_sort) TEST_F(TestCApiBlackTermManager, mk_array_sort) { - Cvc5Sort bsort = cvc5_get_boolean_sort(d_tm); - Cvc5Sort isort = cvc5_get_integer_sort(d_tm); - Cvc5Sort rsort = cvc5_get_real_sort(d_tm); Cvc5Sort bvsort = cvc5_mk_bv_sort(d_tm, 32); - (void)cvc5_mk_array_sort(d_tm, bsort, bsort); - (void)cvc5_mk_array_sort(d_tm, isort, isort); - (void)cvc5_mk_array_sort(d_tm, rsort, rsort); + (void)cvc5_mk_array_sort(d_tm, d_bool, d_bool); + (void)cvc5_mk_array_sort(d_tm, d_int, d_int); + (void)cvc5_mk_array_sort(d_tm, d_real, d_real); (void)cvc5_mk_array_sort(d_tm, bvsort, bvsort); - (void)cvc5_mk_array_sort(d_tm, bsort, isort); - (void)cvc5_mk_array_sort(d_tm, rsort, bvsort); + (void)cvc5_mk_array_sort(d_tm, d_bool, d_int); + (void)cvc5_mk_array_sort(d_tm, d_real, bvsort); Cvc5Sort fpsort = cvc5_mk_fp_sort(d_tm, 3, 5); (void)cvc5_mk_array_sort(d_tm, fpsort, fpsort); @@ -154,7 +151,7 @@ TEST_F(TestCApiBlackTermManager, mk_dt_sort) { Cvc5DatatypeDecl decl = cvc5_mk_dt_decl(d_tm, "list", false); Cvc5DatatypeConstructorDecl cons = cvc5_mk_dt_cons_decl(d_tm, "cons"); - cvc5_dt_cons_decl_add_selector(cons, "head", cvc5_get_integer_sort(d_tm)); + cvc5_dt_cons_decl_add_selector(cons, "head", d_int); cvc5_dt_decl_add_constructor(decl, cons); Cvc5DatatypeConstructorDecl nil = cvc5_mk_dt_cons_decl(d_tm, "nil"); cvc5_dt_decl_add_constructor(decl, nil); @@ -188,13 +185,13 @@ TEST_F(TestCApiBlackTermManager, mk_dt_sorts) { Cvc5DatatypeDecl decl1 = cvc5_mk_dt_decl(d_tm, "list1", false); Cvc5DatatypeConstructorDecl cons1 = cvc5_mk_dt_cons_decl(d_tm, "cons1"); - cvc5_dt_cons_decl_add_selector(cons1, "head1", cvc5_get_integer_sort(d_tm)); + cvc5_dt_cons_decl_add_selector(cons1, "head1", d_int); cvc5_dt_decl_add_constructor(decl1, cons1); Cvc5DatatypeConstructorDecl nil1 = cvc5_mk_dt_cons_decl(d_tm, "nil1"); cvc5_dt_decl_add_constructor(decl1, nil1); Cvc5DatatypeDecl decl2 = cvc5_mk_dt_decl(d_tm, "list2", false); Cvc5DatatypeConstructorDecl cons2 = cvc5_mk_dt_cons_decl(d_tm, "cons2"); - cvc5_dt_cons_decl_add_selector(cons2, "head2", cvc5_get_integer_sort(d_tm)); + cvc5_dt_cons_decl_add_selector(cons2, "head2", d_int); cvc5_dt_decl_add_constructor(decl2, cons2); Cvc5DatatypeConstructorDecl nil2 = cvc5_mk_dt_cons_decl(d_tm, "nil2"); cvc5_dt_decl_add_constructor(decl2, nil2); @@ -241,8 +238,10 @@ TEST_F(TestCApiBlackTermManager, mk_dt_sorts) Cvc5Sort u1 = cvc5_mk_unresolved_dt_sort(d_tm, "dt1", 1); std::vector sorts0 = {p0}; std::vector sorts1 = {p1}; - Cvc5DatatypeDecl decl0 = cvc5_mk_dt_decl(d_tm, "dt0", sorts0.data()); - Cvc5DatatypeDecl decl1 = cvc5_mk_dt_decl(d_tm, "dt1", sorts1.data()); + Cvc5DatatypeDecl decl0 = + cvc5_mk_dt_decl_with_params(d_tm, "dt0", 1, sorts0.data(), false); + Cvc5DatatypeDecl decl1 = + cvc5_mk_dt_decl_with_params(d_tm, "dt1", 1, sorts1.data(), false); Cvc5DatatypeConstructorDecl cons0 = cvc5_mk_dt_cons_decl(d_tm, "c0"); cvc5_dt_cons_decl_add_selector( cons0, "s0", cvc5_sort_instantiate(u1, sorts0.size(), sorts0.data())); @@ -253,21 +252,22 @@ TEST_F(TestCApiBlackTermManager, mk_dt_sorts) cvc5_dt_decl_add_constructor(decl1, cons1); cvc5_dt_decl_add_constructor(decl1, cvc5_mk_dt_cons_decl(d_tm, "nil")); std::vector decls = {decl0, decl1}; - // const Cvc5Sort* dtsorts = - // cvc5_mk_dt_sorts(d_tm, decls.size(), decls.data()); - // std::vector iargs = {cvc5_get_boolean_sort(d_tm)}; - // Cvc5Sort isort = - // cvc5_sort_instantiate(dtsorts[1], iargs.size(), iargs.data()); - // Cvc5Term t1 = cvc5_mk_const(d_tm, isort, "t"); - // std::vector children = { - // cvc5_dt_sel_get_term(cvc5_dt_get_selector( - // cvc5_sort_get_datatype(cvc5_term_get_sort(t1)), "s1")), - // t1}; - // Cvc5Term t0 = cvc5_mk_term( - // CVC5_KIND_APPLY_SELECTOR, children.size(), children.data()); - // iargs = {cvc5_get_boolean_sort(d_tm)}; - // ASSERT_EQ(cvc5_sort_instantiate(dtsorts[0], iargs.size(), iargs.data()), - // cvc5_term_get_sort(t0)); + const Cvc5Sort* dtsorts = + cvc5_mk_dt_sorts(d_tm, decls.size(), decls.data()); + + std::vector iargs = {cvc5_get_boolean_sort(d_tm)}; + Cvc5Sort isort = + cvc5_sort_instantiate(dtsorts[1], iargs.size(), iargs.data()); + Cvc5Term t1 = cvc5_mk_const(d_tm, isort, "t"); + std::vector children = { + cvc5_dt_sel_get_term(cvc5_dt_get_selector( + cvc5_sort_get_datatype(cvc5_term_get_sort(t1)), "s1")), + t1}; + Cvc5Term t0 = cvc5_mk_term( + d_tm, CVC5_KIND_APPLY_SELECTOR, children.size(), children.data()); + iargs = {cvc5_get_boolean_sort(d_tm)}; + ASSERT_EQ(cvc5_sort_instantiate(dtsorts[0], iargs.size(), iargs.data()), + cvc5_term_get_sort(t0)); } { @@ -295,54 +295,53 @@ TEST_F(TestCApiBlackTermManager, mk_fun_sort) { Cvc5Sort unsort = cvc5_mk_uninterpreted_sort(d_tm, "u"); std::vector domain = {unsort}; - Cvc5Sort intsort = cvc5_get_integer_sort(d_tm); Cvc5Sort funsort = - cvc5_mk_fun_sort(d_tm, domain.size(), domain.data(), intsort); + cvc5_mk_fun_sort(d_tm, domain.size(), domain.data(), d_int); // function arguments are allowed domain = {funsort}; - (void)cvc5_mk_fun_sort(d_tm, domain.size(), domain.data(), intsort); - ASSERT_DEATH(cvc5_mk_fun_sort(nullptr, domain.size(), domain.data(), intsort), + (void)cvc5_mk_fun_sort(d_tm, domain.size(), domain.data(), d_int); + ASSERT_DEATH(cvc5_mk_fun_sort(nullptr, domain.size(), domain.data(), d_int), "unexpected NULL argument"); - ASSERT_DEATH(cvc5_mk_fun_sort(d_tm, domain.size(), nullptr, intsort), + ASSERT_DEATH(cvc5_mk_fun_sort(d_tm, domain.size(), nullptr, d_int), "unexpected NULL argument"); domain = {nullptr}; - ASSERT_DEATH(cvc5_mk_fun_sort(d_tm, domain.size(), domain.data(), intsort), + ASSERT_DEATH(cvc5_mk_fun_sort(d_tm, domain.size(), domain.data(), d_int), "invalid sort at index 0"); // non-first-class arguments are not allowed Cvc5Sort regexpsort = cvc5_get_regexp_sort(d_tm); domain = {regexpsort}; - ASSERT_DEATH(cvc5_mk_fun_sort(d_tm, domain.size(), domain.data(), intsort), + ASSERT_DEATH(cvc5_mk_fun_sort(d_tm, domain.size(), domain.data(), d_int), "expected first-class sort as domain sort"); - domain = {intsort}; + domain = {d_int}; ASSERT_DEATH(cvc5_mk_fun_sort(d_tm, domain.size(), domain.data(), funsort), "expected non-function sort as codomain sort"); - domain = {unsort, intsort}; - (void)cvc5_mk_fun_sort(d_tm, domain.size(), domain.data(), intsort); + domain = {unsort, d_int}; + (void)cvc5_mk_fun_sort(d_tm, domain.size(), domain.data(), d_int); domain = {unsort}; - funsort = cvc5_mk_fun_sort(d_tm, domain.size(), domain.data(), intsort); + funsort = cvc5_mk_fun_sort(d_tm, domain.size(), domain.data(), d_int); // function arguments are allowed domain = {funsort, unsort}; - (void)cvc5_mk_fun_sort(d_tm, domain.size(), domain.data(), intsort); + (void)cvc5_mk_fun_sort(d_tm, domain.size(), domain.data(), d_int); - domain = {intsort, unsort}; + domain = {d_int, unsort}; ASSERT_DEATH(cvc5_mk_fun_sort(d_tm, domain.size(), domain.data(), funsort), "expected non-function sort as codomain sort"); - domain = {cvc5_get_boolean_sort(d_tm), intsort, intsort}; - (void)cvc5_mk_fun_sort(d_tm, domain.size(), domain.data(), intsort); - domain = {cvc5_get_boolean_sort(d_tm), intsort}; - (void)cvc5_mk_fun_sort(d_tm, domain.size(), domain.data(), intsort); + domain = {d_bool, d_int, d_int}; + (void)cvc5_mk_fun_sort(d_tm, domain.size(), domain.data(), d_int); + domain = {d_bool, d_int}; + (void)cvc5_mk_fun_sort(d_tm, domain.size(), domain.data(), d_int); Cvc5TermManager* tm = cvc5_term_manager_new(); // this will throw when NodeManager is not a singleton anymore (void)cvc5_mk_fun_sort( tm, domain.size(), domain.data(), cvc5_get_integer_sort(tm)); domain = {cvc5_get_boolean_sort(tm), cvc5_get_integer_sort(tm)}; - (void)cvc5_mk_fun_sort(tm, domain.size(), domain.data(), intsort); + (void)cvc5_mk_fun_sort(tm, domain.size(), domain.data(), d_int); cvc5_term_manager_delete(tm); } @@ -356,8 +355,7 @@ TEST_F(TestCApiBlackTermManager, mk_param_sort) TEST_F(TestCApiBlackTermManager, mk_predicate_sort) { - Cvc5Sort intsort = cvc5_get_integer_sort(d_tm); - std::vector sorts = {intsort}; + std::vector sorts = {d_int}; (void)cvc5_mk_predicate_sort(d_tm, sorts.size(), sorts.data()); ASSERT_DEATH(cvc5_mk_predicate_sort(nullptr, sorts.size(), sorts.data()), "unexpected NULL argument"); @@ -375,16 +373,15 @@ TEST_F(TestCApiBlackTermManager, mk_predicate_sort) ASSERT_DEATH(cvc5_mk_predicate_sort(d_tm, sorts.size(), sorts.data()), "invalid sort at index 0"); - sorts = {cvc5_mk_uninterpreted_sort(d_tm, "u"), intsort}; - Cvc5Sort funsort = - cvc5_mk_fun_sort(d_tm, sorts.size(), sorts.data(), intsort); + sorts = {cvc5_mk_uninterpreted_sort(d_tm, "u"), d_int}; + Cvc5Sort funsort = cvc5_mk_fun_sort(d_tm, sorts.size(), sorts.data(), d_int); // functions as arguments are allowed - sorts = {funsort, intsort}; + sorts = {funsort, d_int}; (void)cvc5_mk_predicate_sort(d_tm, sorts.size(), sorts.data()); Cvc5TermManager* tm = cvc5_term_manager_new(); // this will throw when NodeManager is not a singleton anymore - sorts = {intsort}; + sorts = {d_int}; (void)cvc5_mk_predicate_sort(tm, sorts.size(), sorts.data()); cvc5_term_manager_delete(tm); } @@ -405,14 +402,12 @@ TEST_F(TestCApiBlackTermManager, mk_record_sort) names = {"b", "bv", "i"}; - sorts = {nullptr, cvc5_mk_bv_sort(d_tm, 8), cvc5_get_integer_sort(d_tm)}; + sorts = {nullptr, cvc5_mk_bv_sort(d_tm, 8), d_int}; ASSERT_DEATH( cvc5_mk_record_sort(d_tm, names.size(), names.data(), sorts.data()), "invalid sort at index 0"); - sorts = {cvc5_get_boolean_sort(d_tm), - cvc5_mk_bv_sort(d_tm, 8), - cvc5_get_integer_sort(d_tm)}; + sorts = {d_bool, cvc5_mk_bv_sort(d_tm, 8), d_int}; // Cvc5Sort recsort = cvc5_mk_record_sort(d_tm, names.size(), names.data(), sorts.data()); @@ -430,12 +425,11 @@ TEST_F(TestCApiBlackTermManager, mk_record_sort) TEST_F(TestCApiBlackTermManager, mk_set_sort) { - (void)cvc5_mk_set_sort(d_tm, cvc5_get_boolean_sort(d_tm)); - (void)cvc5_mk_set_sort(d_tm, cvc5_get_integer_sort(d_tm)); + (void)cvc5_mk_set_sort(d_tm, d_bool); + (void)cvc5_mk_set_sort(d_tm, d_int); (void)cvc5_mk_set_sort(d_tm, cvc5_mk_bv_sort(d_tm, 4)); (void)cvc5_mk_set_sort(d_tm, cvc5_mk_bv_sort(d_tm, 4)); - ASSERT_DEATH(cvc5_mk_set_sort(nullptr, cvc5_get_boolean_sort(d_tm)), - "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_set_sort(nullptr, d_bool), "unexpected NULL argument"); ASSERT_DEATH(cvc5_mk_set_sort(d_tm, nullptr), "invalid sort"); Cvc5TermManager* tm = cvc5_term_manager_new(); // this will throw when NodeManager is not a singleton anymore @@ -445,12 +439,11 @@ TEST_F(TestCApiBlackTermManager, mk_set_sort) TEST_F(TestCApiBlackTermManager, mk_bag_sort) { - (void)cvc5_mk_bag_sort(d_tm, cvc5_get_boolean_sort(d_tm)); - (void)cvc5_mk_bag_sort(d_tm, cvc5_get_integer_sort(d_tm)); + (void)cvc5_mk_bag_sort(d_tm, d_bool); + (void)cvc5_mk_bag_sort(d_tm, d_int); (void)cvc5_mk_bag_sort(d_tm, cvc5_mk_bv_sort(d_tm, 4)); (void)cvc5_mk_bag_sort(d_tm, cvc5_mk_bv_sort(d_tm, 4)); - ASSERT_DEATH(cvc5_mk_bag_sort(nullptr, cvc5_get_boolean_sort(d_tm)), - "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_bag_sort(nullptr, d_bool), "unexpected NULL argument"); ASSERT_DEATH(cvc5_mk_bag_sort(d_tm, nullptr), "invalid sort"); Cvc5TermManager* tm = cvc5_term_manager_new(); // this will throw when NodeManager is not a singleton anymore @@ -460,11 +453,11 @@ TEST_F(TestCApiBlackTermManager, mk_bag_sort) TEST_F(TestCApiBlackTermManager, mk_sequence_sort) { - (void)cvc5_mk_sequence_sort(d_tm, cvc5_get_boolean_sort(d_tm)); - (void)cvc5_mk_sequence_sort(d_tm, cvc5_get_integer_sort(d_tm)); + (void)cvc5_mk_sequence_sort(d_tm, d_bool); + (void)cvc5_mk_sequence_sort(d_tm, d_int); (void)cvc5_mk_sequence_sort(d_tm, cvc5_mk_bv_sort(d_tm, 4)); (void)cvc5_mk_sequence_sort(d_tm, cvc5_mk_bv_sort(d_tm, 4)); - ASSERT_DEATH(cvc5_mk_sequence_sort(nullptr, cvc5_get_boolean_sort(d_tm)), + ASSERT_DEATH(cvc5_mk_sequence_sort(nullptr, d_bool), "unexpected NULL argument"); ASSERT_DEATH(cvc5_mk_sequence_sort(d_tm, nullptr), "invalid sort"); Cvc5TermManager* tm = cvc5_term_manager_new(); @@ -482,9 +475,9 @@ TEST_F(TestCApiBlackTermManager, mk_abstract_sort) ASSERT_DEATH(cvc5_mk_abstract_sort(nullptr, CVC5_SORT_KIND_SET_SORT), "unexpected NULL argument"); ASSERT_DEATH(cvc5_mk_abstract_sort(d_tm, CVC5_SORT_KIND_BOOLEAN_SORT), - "Cannot construct abstract type"); + "cannot construct abstract type"); ASSERT_DEATH(cvc5_mk_abstract_sort(d_tm, static_cast(-1)), - "Cannot construct abstract type"); + "cannot construct abstract type"); } TEST_F(TestCApiBlackTermManager, mk_uninterpreted_sort) @@ -521,21 +514,20 @@ TEST_F(TestCApiBlackTermManager, mk_uninterpreted_sort_constructor_sort) TEST_F(TestCApiBlackTermManager, mk_tuple_sort) { - Cvc5Sort intsort = cvc5_get_integer_sort(d_tm); - std::vector sorts = {intsort}; + std::vector sorts = {d_int}; (void)cvc5_mk_tuple_sort(d_tm, sorts.size(), sorts.data()); ASSERT_DEATH(cvc5_mk_tuple_sort(nullptr, sorts.size(), sorts.data()), "unexpected NULL argument"); ASSERT_DEATH(cvc5_mk_tuple_sort(nullptr, sorts.size(), nullptr), "unexpected NULL argument"); - sorts = {intsort, nullptr}; + sorts = {d_int, nullptr}; ASSERT_DEATH(cvc5_mk_tuple_sort(d_tm, sorts.size(), sorts.data()), "invalid sort at index 1"); - sorts = {cvc5_mk_uninterpreted_sort(d_tm, "u"), intsort}; + sorts = {cvc5_mk_uninterpreted_sort(d_tm, "u"), d_int}; Cvc5Sort funsort = cvc5_mk_tuple_sort(d_tm, sorts.size(), sorts.data()); - sorts = {intsort, funsort}; + sorts = {d_int, funsort}; (void)cvc5_mk_tuple_sort(d_tm, sorts.size(), sorts.data()); - sorts = {intsort}; + sorts = {d_int}; (void)cvc5_mk_tuple_sort(d_tm, sorts.size(), sorts.data()); Cvc5TermManager* tm = cvc5_term_manager_new(); @@ -547,15 +539,968 @@ TEST_F(TestCApiBlackTermManager, mk_tuple_sort) TEST_F(TestCApiBlackTermManager, mk_nullable_sort) { - Cvc5Sort intsort = cvc5_get_integer_sort(d_tm); - (void)cvc5_mk_nullable_sort(d_tm, intsort); - (void)cvc5_mk_nullable_sort(d_tm, intsort); - ASSERT_DEATH(cvc5_mk_nullable_sort(nullptr, intsort), + (void)cvc5_mk_nullable_sort(d_tm, d_int); + (void)cvc5_mk_nullable_sort(d_tm, d_int); + + ASSERT_DEATH(cvc5_mk_nullable_sort(nullptr, d_int), "unexpected NULL argument"); ASSERT_DEATH(cvc5_mk_nullable_sort(d_tm, nullptr), "invalid sort"); Cvc5TermManager* tm = cvc5_term_manager_new(); // this will throw when NodeManager is not a singleton anymore - (void)cvc5_mk_nullable_sort(tm, intsort); + (void)cvc5_mk_nullable_sort(tm, d_int); + cvc5_term_manager_delete(tm); +} + +TEST_F(TestCApiBlackTermManager, mk_bv) +{ + (void)cvc5_mk_bv(d_tm, 8, "-1111111", 2); + (void)cvc5_mk_bv(d_tm, 8, "0101", 2); + (void)cvc5_mk_bv(d_tm, 8, "00000101", 2); + (void)cvc5_mk_bv(d_tm, 8, "-127", 10); + (void)cvc5_mk_bv(d_tm, 8, "255", 10); + (void)cvc5_mk_bv(d_tm, 8, "-7f", 16); + (void)cvc5_mk_bv(d_tm, 8, "a0", 16); + + ASSERT_DEATH(cvc5_mk_bv(nullptr, 8, "-1111111", 2), + "unexpected NULL argument"); + + ASSERT_DEATH(cvc5_mk_bv(d_tm, 0, "-127", 10), + "invalid argument '0' for 'size'"); + ASSERT_DEATH(cvc5_mk_bv(d_tm, 0, "a0", 16), + "invalid argument '0' for 'size'"); + + ASSERT_DEATH(cvc5_mk_bv(d_tm, 8, "", 2), "expected a non-empty string"); + + ASSERT_DEATH(cvc5_mk_bv(d_tm, 8, "101", 5), "expected base 2, 10, or 16"); + ASSERT_DEATH(cvc5_mk_bv(d_tm, 8, "128", 11), "expected base 2, 10, or 16"); + ASSERT_DEATH(cvc5_mk_bv(d_tm, 8, "a0", 21), "expected base 2, 10, or 16"); + + ASSERT_DEATH(cvc5_mk_bv(d_tm, 8, "-11111111", 2), + "overflow in bit-vector construction"); + ASSERT_DEATH(cvc5_mk_bv(d_tm, 8, "101010101", 2), + "overflow in bit-vector construction"); + ASSERT_DEATH(cvc5_mk_bv(d_tm, 8, "-256", 10), + "overflow in bit-vector construction"); + ASSERT_DEATH(cvc5_mk_bv(d_tm, 8, "257", 10), + "overflow in bit-vector construction"); + ASSERT_DEATH(cvc5_mk_bv(d_tm, 8, "-a0", 16), + "overflow in bit-vector construction"); + ASSERT_DEATH(cvc5_mk_bv(d_tm, 8, "fffff", 16), + "overflow in bit-vector construction"); + + ASSERT_DEATH(cvc5_mk_bv(d_tm, 8, "10201010", 2), ""); + ASSERT_DEATH(cvc5_mk_bv(d_tm, 8, "-25x", 10), ""); + ASSERT_DEATH(cvc5_mk_bv(d_tm, 8, "2x7", 10), ""); + ASSERT_DEATH(cvc5_mk_bv(d_tm, 8, "fzff", 16), ""); + + ASSERT_EQ(cvc5_mk_bv(d_tm, 8, "0101", 2), cvc5_mk_bv(d_tm, 8, "00000101", 2)); + ASSERT_EQ(cvc5_mk_bv(d_tm, 4, "-1", 2), cvc5_mk_bv(d_tm, 4, "1111", 2)); + ASSERT_EQ(cvc5_mk_bv(d_tm, 4, "-1", 16), cvc5_mk_bv(d_tm, 4, "1111", 2)); + ASSERT_EQ(cvc5_mk_bv(d_tm, 4, "-1", 10), cvc5_mk_bv(d_tm, 4, "1111", 2)); + ASSERT_EQ(cvc5_term_to_string(cvc5_mk_bv(d_tm, 8, "01010101", 2)), + std::string("#b01010101")); + ASSERT_EQ(cvc5_term_to_string(cvc5_mk_bv(d_tm, 8, "F", 16)), + std::string("#b00001111")); + ASSERT_EQ(cvc5_mk_bv(d_tm, 8, "-1", 10), cvc5_mk_bv(d_tm, 8, "FF", 16)); +} + +TEST_F(TestCApiBlackTermManager, mk_bv_uint64) +{ + (void)cvc5_mk_bv_uint64(d_tm, 8, 2); + (void)cvc5_mk_bv_uint64(d_tm, 32, 2); + ASSERT_DEATH(cvc5_mk_bv_uint64(nullptr, 0, 2), "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_bv_uint64(d_tm, 0, 2), + "invalid argument '0' for 'size'"); +} + +TEST_F(TestCApiBlackTermManager, mk_ff_elem) +{ + Cvc5Sort ff_sort = cvc5_mk_ff_sort(d_tm, "7", 10); + Cvc5Sort bv_sort = cvc5_mk_bv_sort(d_tm, 4); + + (void)cvc5_mk_ff_elem(d_tm, "0", ff_sort, 10); + (void)cvc5_mk_ff_elem(d_tm, "1", ff_sort, 10); + (void)cvc5_mk_ff_elem(d_tm, "6", ff_sort, 10); + (void)cvc5_mk_ff_elem(d_tm, "8", ff_sort, 10); + (void)cvc5_mk_ff_elem(d_tm, "-1", ff_sort, 10); + + ASSERT_DEATH(cvc5_mk_ff_elem(nullptr, "-1", ff_sort, 10), + "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_ff_elem(d_tm, "a", ff_sort, 10), ""); + ASSERT_DEATH(cvc5_mk_ff_elem(d_tm, "-1", bv_sort, 10), + "expected a finite field sort"); + + ASSERT_EQ(cvc5_mk_ff_elem(d_tm, "-1", ff_sort, 10), + cvc5_mk_ff_elem(d_tm, "6", ff_sort, 10)); + ASSERT_EQ(cvc5_mk_ff_elem(d_tm, "1", ff_sort, 10), + cvc5_mk_ff_elem(d_tm, "8", ff_sort, 10)); + + (void)cvc5_mk_ff_elem(d_tm, "0", ff_sort, 2); + (void)cvc5_mk_ff_elem(d_tm, "101", ff_sort, 3); + (void)cvc5_mk_ff_elem(d_tm, "-10", ff_sort, 7); + (void)cvc5_mk_ff_elem(d_tm, "abcde", ff_sort, 16); + + ASSERT_EQ(cvc5_mk_ff_elem(d_tm, "0", ff_sort, 2), + cvc5_mk_ff_elem(d_tm, "0", ff_sort, 3)); + ASSERT_EQ(cvc5_mk_ff_elem(d_tm, "11", ff_sort, 2), + cvc5_mk_ff_elem(d_tm, "10", ff_sort, 3)); + ASSERT_EQ(cvc5_mk_ff_elem(d_tm, "1010", ff_sort, 2), + cvc5_mk_ff_elem(d_tm, "A", ff_sort, 16)); + + ASSERT_EQ(cvc5_mk_ff_elem(d_tm, "-22", ff_sort, 3), + cvc5_mk_ff_elem(d_tm, "10", ff_sort, 6)); +} + +TEST_F(TestCApiBlackTermManager, mk_const_array) +{ + Cvc5Sort arr_sort = cvc5_mk_array_sort(d_tm, d_int, d_int); + Cvc5Term zero = cvc5_mk_integer_int64(d_tm, 0); + (void)cvc5_mk_const_array(d_tm, arr_sort, zero); + + ASSERT_DEATH(cvc5_mk_const_array(nullptr, arr_sort, zero), + "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_const_array(d_tm, nullptr, zero), "invalid sort"); + ASSERT_DEATH(cvc5_mk_const_array(d_tm, arr_sort, nullptr), "invalid term"); + ASSERT_DEATH( + cvc5_mk_const_array(d_tm, arr_sort, cvc5_mk_bv_uint64(d_tm, 1, 1)), + "value does not match element sort"); + ASSERT_DEATH(cvc5_mk_const_array(d_tm, d_int, zero), + "expected an array sort"); + + Cvc5Sort arr_sort2 = cvc5_mk_array_sort(d_tm, d_int, d_int); + Cvc5Term zero2 = cvc5_mk_integer_int64(d_tm, 0); + (void)cvc5_mk_const_array(d_tm, arr_sort2, zero); + (void)cvc5_mk_const_array(d_tm, arr_sort, zero2); + Cvc5TermManager* tm = cvc5_term_manager_new(); + // this will throw when NodeManager is not a singleton anymore + (void)cvc5_mk_const_array(tm, arr_sort, cvc5_mk_integer_int64(tm, 0)); + (void)cvc5_mk_const_array( + tm, + cvc5_mk_array_sort( + tm, cvc5_get_integer_sort(tm), cvc5_get_integer_sort(tm)), + zero); + cvc5_term_manager_delete(tm); +} + +TEST_F(TestCApiBlackTermManager, mk_var) +{ + std::vector domain = {d_int}; + Cvc5Sort fun_sort = cvc5_mk_fun_sort(d_tm, 1, domain.data(), d_bool); + + (void)cvc5_mk_var(d_tm, d_bool, nullptr); + (void)cvc5_mk_var(d_tm, fun_sort, nullptr); + (void)cvc5_mk_var(d_tm, d_bool, "b"); + (void)cvc5_mk_var(d_tm, fun_sort, ""); + + ASSERT_DEATH(cvc5_mk_var(nullptr, d_bool, ""), "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_var(d_tm, nullptr, ""), "invalid sort"); + Cvc5TermManager* tm = cvc5_term_manager_new(); + // this will throw when NodeManager is not a singleton anymore + (void)cvc5_mk_var(tm, d_bool, "b"); + cvc5_term_manager_delete(tm); +} + +TEST_F(TestCApiBlackTermManager, mk_boolean) +{ + (void)cvc5_mk_boolean(d_tm, true); + (void)cvc5_mk_boolean(d_tm, false); + ASSERT_DEATH(cvc5_mk_boolean(nullptr, true), "unexpected NULL argument"); +} + +TEST_F(TestCApiBlackTermManager, mk_rm) +{ + ASSERT_EQ( + cvc5_term_to_string(cvc5_mk_rm(d_tm, CVC5_RM_ROUND_NEAREST_TIES_TO_EVEN)), + std::string("roundNearestTiesToEven")); + ASSERT_EQ( + cvc5_term_to_string(cvc5_mk_rm(d_tm, CVC5_RM_ROUND_TOWARD_POSITIVE)), + std::string("roundTowardPositive")); + ASSERT_EQ( + cvc5_term_to_string(cvc5_mk_rm(d_tm, CVC5_RM_ROUND_TOWARD_NEGATIVE)), + std::string("roundTowardNegative")); + ASSERT_EQ(cvc5_term_to_string(cvc5_mk_rm(d_tm, CVC5_RM_ROUND_TOWARD_ZERO)), + std::string("roundTowardZero")); + ASSERT_EQ( + cvc5_term_to_string(cvc5_mk_rm(d_tm, CVC5_RM_ROUND_NEAREST_TIES_TO_AWAY)), + std::string("roundNearestTiesToAway")); + ASSERT_DEATH(cvc5_mk_rm(nullptr, CVC5_RM_ROUND_TOWARD_ZERO), + "unexpected NULL argument"); +} + +TEST_F(TestCApiBlackTermManager, mk_fp) +{ + Cvc5Term t1 = cvc5_mk_bv_uint64(d_tm, 8, 0); + Cvc5Term t2 = cvc5_mk_bv_uint64(d_tm, 4, 0); + + (void)cvc5_mk_fp(d_tm, 3, 5, t1); + ASSERT_DEATH(cvc5_mk_fp(nullptr, 3, 5, t1), "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_fp(d_tm, 3, 5, nullptr), "invalid term"); + ASSERT_DEATH(cvc5_mk_fp(d_tm, 0, 5, t1), "expected exponent size > 1"); + ASSERT_DEATH(cvc5_mk_fp(d_tm, 1, 5, t1), "expected exponent size > 1"); + ASSERT_DEATH(cvc5_mk_fp(d_tm, 3, 0, t1), "expected significand size > 1"); + ASSERT_DEATH(cvc5_mk_fp(d_tm, 3, 1, t1), "expected significand size > 1"); + ASSERT_DEATH(cvc5_mk_fp(d_tm, 3, 5, t2), + "expected a bit-vector value with bit-width '8'"); + + Cvc5Term sign = cvc5_mk_bv_uint64(d_tm, 1, 0); + Cvc5Term exp = cvc5_mk_bv_uint64(d_tm, 5, 0); + Cvc5Term sig = cvc5_mk_bv_uint64(d_tm, 10, 0); + ASSERT_EQ(cvc5_mk_fp_from_ieee(d_tm, sign, exp, sig), + cvc5_mk_fp(d_tm, 5, 11, cvc5_mk_bv_uint64(d_tm, 16, 0))); + + ASSERT_DEATH(cvc5_mk_fp_from_ieee(nullptr, sign, exp, sig), + "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_fp_from_ieee(d_tm, nullptr, exp, sig), "invalid term"); + ASSERT_DEATH(cvc5_mk_fp_from_ieee(d_tm, sign, nullptr, sig), "invalid term"); + ASSERT_DEATH(cvc5_mk_fp_from_ieee(d_tm, sign, exp, nullptr), "invalid term"); + ASSERT_DEATH( + cvc5_mk_fp_from_ieee( + d_tm, cvc5_mk_const(d_tm, cvc5_mk_bv_sort(d_tm, 1), ""), exp, sig), + "expected bit-vector value"); + ASSERT_DEATH( + cvc5_mk_fp_from_ieee( + d_tm, sign, cvc5_mk_const(d_tm, cvc5_mk_bv_sort(d_tm, 5), ""), sig), + "expected bit-vector value"); + ASSERT_DEATH( + cvc5_mk_fp_from_ieee( + d_tm, sign, exp, cvc5_mk_const(d_tm, cvc5_mk_bv_sort(d_tm, 10), "")), + "expected bit-vector value"); + ASSERT_DEATH( + cvc5_mk_fp_from_ieee(d_tm, cvc5_mk_bv_uint64(d_tm, 2, 0), exp, sig), + "expected a bit-vector value of size 1"); + + Cvc5TermManager* tm = cvc5_term_manager_new(); + // this will throw when NodeManager is not a singleton anymore + (void)cvc5_mk_fp(tm, 3, 5, t1); + (void)cvc5_mk_fp_from_ieee( + tm, sign, cvc5_mk_bv_uint64(tm, 5, 0), cvc5_mk_bv_uint64(tm, 10, 0)); + (void)cvc5_mk_fp_from_ieee( + tm, cvc5_mk_bv_uint64(tm, 1, 0), exp, cvc5_mk_bv_uint64(tm, 10, 0)); + (void)cvc5_mk_fp_from_ieee( + tm, cvc5_mk_bv_uint64(tm, 1, 0), cvc5_mk_bv_uint64(tm, 5, 0), sig); + cvc5_term_manager_delete(tm); +} + +TEST_F(TestCApiBlackTermManager, mk_cardinality_constraint) +{ + Cvc5Sort unsort = cvc5_mk_uninterpreted_sort(d_tm, "u"); + (void)cvc5_mk_cardinality_constraint(d_tm, unsort, 3); + ASSERT_DEATH(cvc5_mk_cardinality_constraint(nullptr, unsort, 3), + "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_cardinality_constraint(d_tm, nullptr, 3), + "invalid sort"); + ASSERT_DEATH(cvc5_mk_cardinality_constraint(d_tm, d_int, 3), + "expected an uninterpreted sort"); + ASSERT_DEATH(cvc5_mk_cardinality_constraint(d_tm, unsort, 0), + "expected a value > 0"); + + Cvc5TermManager* tm = cvc5_term_manager_new(); + // this will throw when NodeManager is not a singleton anymore + (void)cvc5_mk_cardinality_constraint(tm, unsort, 3); + cvc5_term_manager_delete(tm); +} + +TEST_F(TestCApiBlackTermManager, mk_empty_set) +{ + Cvc5Sort sort = cvc5_mk_set_sort(d_tm, d_bool); + (void)cvc5_mk_empty_set(d_tm, sort); + ASSERT_DEATH(cvc5_mk_empty_set(nullptr, sort), "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_empty_set(d_tm, nullptr), "invalid sort"); + ASSERT_DEATH(cvc5_mk_empty_set(d_tm, d_bool), + "expected null sort or set sort"); + + Cvc5TermManager* tm = cvc5_term_manager_new(); + // this will throw when NodeManager is not a singleton anymore + (void)cvc5_mk_empty_set(tm, sort); + cvc5_term_manager_delete(tm); +} + +TEST_F(TestCApiBlackTermManager, mk_empty_bag) +{ + Cvc5Sort sort = cvc5_mk_bag_sort(d_tm, d_bool); + (void)cvc5_mk_empty_bag(d_tm, sort); + ASSERT_DEATH(cvc5_mk_empty_bag(nullptr, sort), "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_empty_bag(d_tm, nullptr), "invalid sort"); + ASSERT_DEATH(cvc5_mk_empty_bag(d_tm, d_bool), + "expected null sort or bag sort"); + + Cvc5TermManager* tm = cvc5_term_manager_new(); + // this will throw when NodeManager is not a singleton anymore + (void)cvc5_mk_empty_bag(tm, sort); + cvc5_term_manager_delete(tm); +} + +TEST_F(TestCApiBlackTermManager, mk_empty_sequence) +{ + Cvc5Sort sort = cvc5_mk_sequence_sort(d_tm, d_bool); + (void)cvc5_mk_empty_sequence(d_tm, sort); + (void)cvc5_mk_empty_sequence(d_tm, d_bool); + ASSERT_DEATH(cvc5_mk_empty_sequence(nullptr, sort), + "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_empty_sequence(d_tm, nullptr), "invalid sort"); + + Cvc5TermManager* tm = cvc5_term_manager_new(); + // this will throw when NodeManager is not a singleton anymore + (void)cvc5_mk_empty_sequence(tm, sort); + cvc5_term_manager_delete(tm); +} + +TEST_F(TestCApiBlackTermManager, mk_false) { (void)cvc5_mk_false(d_tm); } + +TEST_F(TestCApiBlackTermManager, mk_fp_nan) +{ + (void)cvc5_mk_fp_nan(d_tm, 3, 5); + ASSERT_DEATH(cvc5_mk_fp_nan(nullptr, 3, 5), "unexpected NULL argument"); +} + +TEST_F(TestCApiBlackTermManager, mk_fp_neg_zero) +{ + (void)cvc5_mk_fp_neg_zero(d_tm, 3, 5); + ASSERT_DEATH(cvc5_mk_fp_neg_zero(nullptr, 3, 5), "unexpected NULL argument"); +} + +TEST_F(TestCApiBlackTermManager, mk_fp_pos_zero) +{ + (void)cvc5_mk_fp_pos_zero(d_tm, 3, 5); + ASSERT_DEATH(cvc5_mk_fp_pos_zero(nullptr, 3, 5), "unexpected NULL argument"); +} + +TEST_F(TestCApiBlackTermManager, mk_fp_neg_inf) +{ + (void)cvc5_mk_fp_neg_inf(d_tm, 3, 5); + ASSERT_DEATH(cvc5_mk_fp_neg_inf(nullptr, 3, 5), "unexpected NULL argument"); +} + +TEST_F(TestCApiBlackTermManager, mk_fp_pos_inf) +{ + (void)cvc5_mk_fp_pos_inf(d_tm, 3, 5); + ASSERT_DEATH(cvc5_mk_fp_pos_inf(nullptr, 3, 5), "unexpected NULL argument"); +} + +TEST_F(TestCApiBlackTermManager, mk_op) +{ + (void)cvc5_mk_op_from_str(d_tm, CVC5_KIND_DIVISIBLE, "2147483648"); + ASSERT_DEATH(cvc5_mk_op_from_str(nullptr, CVC5_KIND_DIVISIBLE, "2147483648"), + "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_op_from_str(d_tm, CVC5_KIND_DIVISIBLE, nullptr), + "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_op_from_str(d_tm, CVC5_KIND_BITVECTOR_EXTRACT, "1"), + "expected DIVISIBLE"); + + std::vector idxs = {1}; + (void)cvc5_mk_op(d_tm, CVC5_KIND_DIVISIBLE, 1, idxs.data()); + (void)cvc5_mk_op(d_tm, CVC5_KIND_BITVECTOR_ROTATE_LEFT, 1, idxs.data()); + (void)cvc5_mk_op(d_tm, CVC5_KIND_BITVECTOR_ROTATE_RIGHT, 1, idxs.data()); + ASSERT_DEATH( + cvc5_mk_op(nullptr, CVC5_KIND_BITVECTOR_ROTATE_RIGHT, 1, idxs.data()), + "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_op(d_tm, CVC5_KIND_BITVECTOR_ROTATE_RIGHT, 1, nullptr), + "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_op(d_tm, CVC5_KIND_BITVECTOR_EXTRACT, 1, idxs.data()), + "expected 2 but got 1"); + + idxs = {1, 1}; + (void)cvc5_mk_op(d_tm, CVC5_KIND_BITVECTOR_EXTRACT, 2, idxs.data()); + ASSERT_DEATH(cvc5_mk_op(d_tm, CVC5_KIND_DIVISIBLE, 2, idxs.data()), + "expected 1 but got 2"); + + idxs = {1, 2, 2}; + (void)cvc5_mk_op(d_tm, CVC5_KIND_TUPLE_PROJECT, 3, idxs.data()); +} + +TEST_F(TestCApiBlackTermManager, mk_pi) +{ + (void)(cvc5_mk_pi(d_tm)); + ASSERT_DEATH(cvc5_mk_pi(nullptr), "unexpected NULL argument"); +} + +TEST_F(TestCApiBlackTermManager, mk_integer) +{ + (void)cvc5_mk_integer(d_tm, "123"); + ASSERT_DEATH(cvc5_mk_integer(nullptr, "123"), "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_integer(d_tm, nullptr), "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_integer(d_tm, "1.23"), "expected an integer"); + ASSERT_DEATH(cvc5_mk_integer(d_tm, "1/23"), "expected an integer"); + ASSERT_DEATH(cvc5_mk_integer(d_tm, "12/3"), "expected an integer"); + ASSERT_DEATH(cvc5_mk_integer(d_tm, ".2"), "expected an integer"); + ASSERT_DEATH(cvc5_mk_integer(d_tm, "2."), "expected an integer"); + ASSERT_DEATH(cvc5_mk_integer(d_tm, ""), "expected an integer"); + ASSERT_DEATH(cvc5_mk_integer(d_tm, "asdf"), "expected an integer"); + ASSERT_DEATH(cvc5_mk_integer(d_tm, "1.2/3"), "expected an integer"); + ASSERT_DEATH(cvc5_mk_integer(d_tm, "."), "expected an integer"); + ASSERT_DEATH(cvc5_mk_integer(d_tm, "/"), "expected an integer"); + ASSERT_DEATH(cvc5_mk_integer(d_tm, "2/"), "expected an integer"); + ASSERT_DEATH(cvc5_mk_integer(d_tm, "/2"), "expected an integer"); + + (void)cvc5_mk_integer_int64(d_tm, 1); + (void)cvc5_mk_integer_int64(d_tm, -1); +} + +TEST_F(TestCApiBlackTermManager, mkReal) +{ + (void)cvc5_mk_real(d_tm, "123"); + (void)cvc5_mk_real(d_tm, "1.23"); + (void)cvc5_mk_real(d_tm, "1/23"); + (void)cvc5_mk_real(d_tm, "12/3"); + (void)cvc5_mk_real(d_tm, "2."); + (void)cvc5_mk_real(d_tm, ".2"); + (void)cvc5_mk_real(d_tm, "1/1"); + (void)cvc5_mk_real(d_tm, "-1/-1"); + (void)cvc5_mk_real(d_tm, "1/-1"); + (void)cvc5_mk_real(d_tm, "-1/1"); + ASSERT_DEATH(cvc5_mk_real(nullptr, "123"), "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_real(d_tm, nullptr), "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_real(d_tm, ""), "cannot construct Real"); + ASSERT_DEATH(cvc5_mk_real(d_tm, "asdf"), "cannot construct Real"); + ASSERT_DEATH(cvc5_mk_real(d_tm, "1.2/3"), "cannot construct Real"); + ASSERT_DEATH(cvc5_mk_real(d_tm, "."), "invalid argument '.'"); + ASSERT_DEATH(cvc5_mk_real(d_tm, "/"), "cannot construct Real"); + ASSERT_DEATH(cvc5_mk_real(d_tm, "2/"), "cannot construct Real"); + ASSERT_DEATH(cvc5_mk_real(d_tm, "/2"), "cannot construct Real"); + ASSERT_DEATH(cvc5_mk_real(d_tm, "/-5"), "cannot construct Real"); + + (void)cvc5_mk_real_int64(d_tm, 1); + (void)cvc5_mk_real_int64(d_tm, -1); + (void)cvc5_mk_real_int64(d_tm, 1); + ASSERT_DEATH(cvc5_mk_real_int64(nullptr, 1), "unexpected NULL argument"); + + (void)cvc5_mk_real_num_den(d_tm, 1, 1); + (void)cvc5_mk_real_num_den(d_tm, -1, -1); + (void)cvc5_mk_real_num_den(d_tm, 1, -1); + (void)cvc5_mk_real_num_den(d_tm, -1, 1); + (void)cvc5_mk_real_num_den(d_tm, 0, 1); + ASSERT_DEATH(cvc5_mk_real_num_den(nullptr, 1, 1), "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_real_num_den(d_tm, 1, 0), "invalid denominator '0'"); +} + +TEST_F(TestCApiBlackTermManager, mk_regexp_all) +{ + Cvc5Sort sort = cvc5_get_string_sort(d_tm); + Cvc5Term s = cvc5_mk_const(d_tm, sort, "s"); + std::vector args = {s, cvc5_mk_regexp_all(d_tm)}; + (void)cvc5_mk_term(d_tm, CVC5_KIND_STRING_IN_REGEXP, 2, args.data()); + ASSERT_DEATH(cvc5_mk_regexp_all(nullptr), "unexpected NULL argument"); +} + +TEST_F(TestCApiBlackTermManager, mk_regexp_allchar) +{ + Cvc5Sort sort = cvc5_get_string_sort(d_tm); + Cvc5Term s = cvc5_mk_const(d_tm, sort, "s"); + std::vector args = {s, cvc5_mk_regexp_allchar(d_tm)}; + (void)cvc5_mk_term(d_tm, CVC5_KIND_STRING_IN_REGEXP, 2, args.data()); + ASSERT_DEATH(cvc5_mk_regexp_allchar(nullptr), "unexpected NULL argument"); +} + +TEST_F(TestCApiBlackTermManager, mk_regexp_none) +{ + Cvc5Sort sort = cvc5_get_string_sort(d_tm); + Cvc5Term s = cvc5_mk_const(d_tm, sort, "s"); + std::vector args = {s, cvc5_mk_regexp_none(d_tm)}; + (void)cvc5_mk_term(d_tm, CVC5_KIND_STRING_IN_REGEXP, 2, args.data()); + ASSERT_DEATH(cvc5_mk_regexp_none(nullptr), "unexpected NULL argument"); +} + +TEST_F(TestCApiBlackTermManager, mk_sep_emp) +{ + (void)cvc5_mk_sep_emp(d_tm); + ASSERT_DEATH(cvc5_mk_sep_emp(nullptr), "unexpected NULL argument"); +} + +TEST_F(TestCApiBlackTermManager, mk_sep_nil) +{ + (void)cvc5_mk_sep_nil(d_tm, d_bool); + (void)cvc5_mk_sep_nil(d_tm, d_int); + ASSERT_DEATH(cvc5_mk_sep_nil(nullptr, d_bool), "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_sep_nil(d_tm, nullptr), "invalid sort"); + + Cvc5TermManager* tm = cvc5_term_manager_new(); + // this will throw when NodeManager is not a singleton anymore + (void)cvc5_mk_sep_nil(tm, d_bool); + cvc5_term_manager_delete(tm); +} + +TEST_F(TestCApiBlackTermManager, mk_string) +{ + (void)cvc5_mk_string(d_tm, "", false); + (void)cvc5_mk_string(d_tm, "asdfasdf", false); + + ASSERT_EQ(cvc5_term_to_string(cvc5_mk_string(d_tm, "asdf\\nasdf", false)), + std::string("\"asdf\\u{5c}nasdf\"")); + ASSERT_EQ( + cvc5_term_to_string(cvc5_mk_string(d_tm, "asdf\\u{005c}nasdf", true)), + std::string("\"asdf\\u{5c}nasdf\"")); + const wchar_t* s = L""; + ASSERT_EQ(cvc5_term_get_string_value(cvc5_mk_string_from_wchar(d_tm, s)), + std::wstring(s)); +} + +TEST_F(TestCApiBlackTermManager, mk_term) +{ + Cvc5Sort bvsort = cvc5_mk_bv_sort(d_tm, 32); + Cvc5Term a = cvc5_mk_const(d_tm, bvsort, "a"); + Cvc5Term b = cvc5_mk_const(d_tm, bvsort, "b"); + + std::vector args = {}; + std::vector idxs = {}; + (void)cvc5_mk_term(d_tm, CVC5_KIND_PI, 0, nullptr); + (void)cvc5_mk_term(d_tm, CVC5_KIND_PI, 0, {}); + (void)cvc5_mk_term(d_tm, CVC5_KIND_PI, 0, args.data()); + (void)cvc5_mk_term_from_op( + d_tm, cvc5_mk_op(d_tm, CVC5_KIND_PI, 0, nullptr), 0, args.data()); + (void)cvc5_mk_term_from_op( + d_tm, cvc5_mk_op(d_tm, CVC5_KIND_PI, 0, idxs.data()), 0, args.data()); + + (void)cvc5_mk_term(d_tm, CVC5_KIND_REGEXP_NONE, 0, args.data()); + (void)cvc5_mk_term_from_op( + d_tm, + cvc5_mk_op(d_tm, CVC5_KIND_REGEXP_NONE, 0, idxs.data()), + 0, + args.data()); + + (void)cvc5_mk_term(d_tm, CVC5_KIND_REGEXP_ALLCHAR, 0, args.data()); + (void)cvc5_mk_term_from_op( + d_tm, + cvc5_mk_op(d_tm, CVC5_KIND_REGEXP_ALLCHAR, 0, idxs.data()), + 0, + args.data()); + + (void)cvc5_mk_term(d_tm, CVC5_KIND_SEP_EMP, 0, args.data()); + (void)cvc5_mk_term_from_op( + d_tm, + cvc5_mk_op(d_tm, CVC5_KIND_SEP_EMP, 0, idxs.data()), + 0, + args.data()); + + ASSERT_DEATH(cvc5_mk_term(nullptr, CVC5_KIND_PI, 0, args.data()), + "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_term(d_tm, CVC5_KIND_PI, 1, nullptr), + "unexpected NULL argument for 'children'"); + ASSERT_DEATH(cvc5_mk_term(d_tm, CVC5_KIND_PI, 1, {}), + "unexpected NULL argument for 'children'"); + ASSERT_DEATH(cvc5_mk_term(d_tm, CVC5_KIND_PI, 1, args.data()), + "unexpected NULL argument for 'children'"); + ASSERT_DEATH(cvc5_mk_term(d_tm, CVC5_KIND_CONST_BITVECTOR, 0, args.data()), + "invalid kind"); + + args = {cvc5_mk_true(d_tm)}; + (void)cvc5_mk_term(d_tm, CVC5_KIND_NOT, 1, args.data()); + (void)cvc5_mk_term_from_op( + d_tm, cvc5_mk_op(d_tm, CVC5_KIND_NOT, 0, idxs.data()), 1, args.data()); + args = {cvc5_mk_true(d_tm), cvc5_mk_integer_int64(d_tm, 1)}; + (void)cvc5_mk_term(d_tm, CVC5_KIND_BAG_MAKE, 2, args.data()); + (void)cvc5_mk_term_from_op( + d_tm, + cvc5_mk_op(d_tm, CVC5_KIND_BAG_MAKE, 0, idxs.data()), + 2, + args.data()); + args = {nullptr}; + ASSERT_DEATH(cvc5_mk_term(d_tm, CVC5_KIND_NOT, 1, args.data()), + "invalid term at index 0"); + args = {a}; + ASSERT_DEATH(cvc5_mk_term(d_tm, CVC5_KIND_NOT, 1, args.data()), + "expecting a Boolean"); + + args = {a, b}; + (void)cvc5_mk_term(d_tm, CVC5_KIND_EQUAL, 2, args.data()); + (void)cvc5_mk_term_from_op( + d_tm, cvc5_mk_op(d_tm, CVC5_KIND_EQUAL, 0, idxs.data()), 2, args.data()); + args = {cvc5_mk_integer_int64(d_tm, 1), cvc5_mk_integer_int64(d_tm, 2)}; + (void)cvc5_mk_term(d_tm, CVC5_KIND_EQUAL, 2, args.data()); + (void)cvc5_mk_term_from_op( + d_tm, cvc5_mk_op(d_tm, CVC5_KIND_EQUAL, 0, idxs.data()), 2, args.data()); + + ASSERT_DEATH(cvc5_mk_term(nullptr, CVC5_KIND_EQUAL, 2, nullptr), + "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_term(nullptr, CVC5_KIND_EQUAL, 2, {}), + "unexpected NULL argument"); + args = {nullptr, b}; + ASSERT_DEATH(cvc5_mk_term(d_tm, CVC5_KIND_EQUAL, 2, args.data()), + "invalid term at index 0"); + args = {a, nullptr}; + ASSERT_DEATH(cvc5_mk_term(d_tm, CVC5_KIND_EQUAL, 2, args.data()), + "invalid term at index 1"); + args = {a, cvc5_mk_true(d_tm)}; + ASSERT_DEATH(cvc5_mk_term(d_tm, CVC5_KIND_EQUAL, 2, args.data()), + "Subexpressions must have the same type"); + + args = {cvc5_mk_true(d_tm), cvc5_mk_true(d_tm), cvc5_mk_true(d_tm)}; + (void)cvc5_mk_term(d_tm, CVC5_KIND_ITE, 3, args.data()); + (void)cvc5_mk_term_from_op( + d_tm, cvc5_mk_op(d_tm, CVC5_KIND_ITE, 0, idxs.data()), 3, args.data()); + args = {nullptr, cvc5_mk_true(d_tm), cvc5_mk_true(d_tm)}; + ASSERT_DEATH(cvc5_mk_term(d_tm, CVC5_KIND_ITE, 3, args.data()), + "invalid term at index 0"); + args = {cvc5_mk_true(d_tm), nullptr, cvc5_mk_true(d_tm)}; + ASSERT_DEATH(cvc5_mk_term(d_tm, CVC5_KIND_ITE, 3, args.data()), + "invalid term at index 1"); + args = {cvc5_mk_true(d_tm), cvc5_mk_true(d_tm), nullptr}; + ASSERT_DEATH(cvc5_mk_term(d_tm, CVC5_KIND_ITE, 3, args.data()), + "invalid term at index 2"); + args = {a, cvc5_mk_true(d_tm), cvc5_mk_true(d_tm)}; + ASSERT_DEATH(cvc5_mk_term(d_tm, CVC5_KIND_ITE, 3, args.data()), + "condition of ITE is not Boolean"); + args = {cvc5_mk_true(d_tm), cvc5_mk_true(d_tm), b}; + ASSERT_DEATH(cvc5_mk_term(d_tm, CVC5_KIND_ITE, 3, args.data()), + "Branches of the ITE must have comparable type"); + + // Test cases that are nary via the API but have arity = 2 internally + Cvc5Term t_bool = cvc5_mk_const(d_tm, d_bool, "t_bool"); + args = {t_bool, t_bool, t_bool}; + (void)cvc5_mk_term(d_tm, CVC5_KIND_IMPLIES, 3, args.data()); + (void)cvc5_mk_term_from_op( + d_tm, + cvc5_mk_op(d_tm, CVC5_KIND_IMPLIES, 0, idxs.data()), + 3, + args.data()); + (void)cvc5_mk_term(d_tm, CVC5_KIND_XOR, 3, args.data()); + (void)cvc5_mk_term_from_op( + d_tm, cvc5_mk_op(d_tm, CVC5_KIND_XOR, 0, idxs.data()), 3, args.data()); + + Cvc5Term t_int = cvc5_mk_const(d_tm, d_int, "t_int"); + args = {t_int, t_int, t_int}; + (void)cvc5_mk_term(d_tm, CVC5_KIND_DIVISION, 3, args.data()); + (void)cvc5_mk_term_from_op( + d_tm, + cvc5_mk_op(d_tm, CVC5_KIND_DIVISION, 0, idxs.data()), + 3, + args.data()); + (void)cvc5_mk_term(d_tm, CVC5_KIND_INTS_DIVISION, 3, args.data()); + (void)cvc5_mk_term_from_op( + d_tm, + cvc5_mk_op(d_tm, CVC5_KIND_INTS_DIVISION, 0, idxs.data()), + 3, + args.data()); + (void)cvc5_mk_term(d_tm, CVC5_KIND_SUB, 3, args.data()); + (void)cvc5_mk_term_from_op( + d_tm, cvc5_mk_op(d_tm, CVC5_KIND_SUB, 0, idxs.data()), 3, args.data()); + (void)cvc5_mk_term(d_tm, CVC5_KIND_EQUAL, 3, args.data()); + (void)cvc5_mk_term_from_op( + d_tm, cvc5_mk_op(d_tm, CVC5_KIND_EQUAL, 0, idxs.data()), 3, args.data()); + (void)cvc5_mk_term(d_tm, CVC5_KIND_LT, 3, args.data()); + (void)cvc5_mk_term_from_op( + d_tm, cvc5_mk_op(d_tm, CVC5_KIND_LT, 0, idxs.data()), 3, args.data()); + (void)cvc5_mk_term(d_tm, CVC5_KIND_GT, 3, args.data()); + (void)cvc5_mk_term_from_op( + d_tm, cvc5_mk_op(d_tm, CVC5_KIND_GT, 0, idxs.data()), 3, args.data()); + (void)cvc5_mk_term(d_tm, CVC5_KIND_LEQ, 3, args.data()); + (void)cvc5_mk_term_from_op( + d_tm, cvc5_mk_op(d_tm, CVC5_KIND_LEQ, 0, idxs.data()), 3, args.data()); + (void)cvc5_mk_term(d_tm, CVC5_KIND_GEQ, 3, args.data()); + (void)cvc5_mk_term_from_op( + d_tm, cvc5_mk_op(d_tm, CVC5_KIND_GEQ, 0, idxs.data()), 3, args.data()); + + Cvc5Term t_reg = cvc5_mk_const(d_tm, cvc5_get_regexp_sort(d_tm), "t_reg"); + args = {t_reg, t_reg, t_reg}; + (void)cvc5_mk_term(d_tm, CVC5_KIND_REGEXP_DIFF, 3, args.data()); + (void)cvc5_mk_term_from_op( + d_tm, + cvc5_mk_op(d_tm, CVC5_KIND_REGEXP_DIFF, 0, idxs.data()), + 3, + args.data()); + + std::vector domain = {d_bool, d_bool, d_bool}; + Cvc5Term t_fun = cvc5_mk_const( + d_tm, cvc5_mk_fun_sort(d_tm, 3, domain.data(), d_bool), "t_fun"); + args = {t_fun, t_bool, t_bool, t_bool}; + (void)cvc5_mk_term(d_tm, CVC5_KIND_HO_APPLY, 3, args.data()); + (void)cvc5_mk_term_from_op( + d_tm, + cvc5_mk_op(d_tm, CVC5_KIND_HO_APPLY, 0, idxs.data()), + 3, + args.data()); + + Cvc5TermManager* tm = cvc5_term_manager_new(); + // this will throw when NodeManager is not a singleton anymore + (void)cvc5_mk_sep_nil(tm, d_bool); + args = {t_bool, + cvc5_mk_const(tm, cvc5_get_boolean_sort(tm), ""), + cvc5_mk_const(tm, cvc5_get_boolean_sort(tm), "")}; + (void)cvc5_mk_term(tm, CVC5_KIND_IMPLIES, 3, args.data()); + args = {cvc5_mk_const(tm, cvc5_get_boolean_sort(tm), ""), + t_bool, + cvc5_mk_const(tm, cvc5_get_boolean_sort(tm), "")}; + (void)cvc5_mk_term(tm, CVC5_KIND_IMPLIES, 3, args.data()); + args = {cvc5_mk_const(tm, cvc5_get_boolean_sort(tm), ""), + cvc5_mk_const(tm, cvc5_get_boolean_sort(tm), ""), + t_bool}; + cvc5_term_manager_delete(tm); +} + +TEST_F(TestCApiBlackTermManager, mk_term_from_op) +{ + Cvc5Sort bvsort = cvc5_mk_bv_sort(d_tm, 32); + Cvc5Term a = cvc5_mk_const(d_tm, bvsort, "a"); + Cvc5Term b = cvc5_mk_const(d_tm, bvsort, "b"); + + (void)cvc5_mk_op(d_tm, CVC5_KIND_PI, 0, {}); + + // simple operator terms + std::vector idxs = {2, 1}; + Cvc5Op op1 = cvc5_mk_op(d_tm, CVC5_KIND_BITVECTOR_EXTRACT, 2, idxs.data()); + idxs = {1}; + Cvc5Op op2 = cvc5_mk_op(d_tm, CVC5_KIND_DIVISIBLE, 1, idxs.data()); + + ASSERT_DEATH(cvc5_mk_op(nullptr, CVC5_KIND_BITVECTOR_EXTRACT, 2, idxs.data()), + "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_op(nullptr, CVC5_KIND_BITVECTOR_EXTRACT, 2, {}), + "unexpected NULL argument"); + + // list datatype + Cvc5Sort sort = cvc5_mk_param_sort(d_tm, "T"); + std::vector params = {sort}; + Cvc5DatatypeDecl decl = + cvc5_mk_dt_decl_with_params(d_tm, "paramlist", 1, params.data(), false); + Cvc5DatatypeConstructorDecl cons_decl = cvc5_mk_dt_cons_decl(d_tm, "cons"); + Cvc5DatatypeConstructorDecl nil_decl = cvc5_mk_dt_cons_decl(d_tm, "nil"); + cvc5_dt_cons_decl_add_selector(cons_decl, "head", sort); + cvc5_dt_cons_decl_add_selector_self(cons_decl, "tail"); + cvc5_dt_decl_add_constructor(decl, cons_decl); + cvc5_dt_decl_add_constructor(decl, nil_decl); + Cvc5Sort dtsort = cvc5_mk_dt_sort(d_tm, decl); + std::vector pargs = {d_int}; + Cvc5Sort dtsort_int = cvc5_sort_instantiate(dtsort, 1, pargs.data()); + Cvc5Term c = cvc5_mk_const(d_tm, dtsort_int, "c"); + Cvc5Datatype list = cvc5_sort_get_datatype(dtsort); + + // list datatype constructor and selector operator terms + Cvc5DatatypeConstructor cons = cvc5_dt_get_constructor_by_name(list, "cons"); + Cvc5DatatypeConstructor nil = cvc5_dt_get_constructor_by_name(list, "nil"); + Cvc5Term cons_term = cvc5_dt_cons_get_term(cons); + Cvc5Term nil_term = cvc5_dt_cons_get_term(nil); + Cvc5Term head_term = + cvc5_dt_sel_get_term(cvc5_dt_cons_get_selector_by_name(cons, "head")); + Cvc5Term tail_term = + cvc5_dt_sel_get_term(cvc5_dt_cons_get_selector_by_name(cons, "tail")); + + // mk_term(_from_op) + std::vector args = {nil_term}; + (void)cvc5_mk_term(d_tm, CVC5_KIND_APPLY_CONSTRUCTOR, 1, args.data()); + ASSERT_DEATH(cvc5_mk_term(d_tm, CVC5_KIND_APPLY_SELECTOR, 1, args.data()), + ""); + args = {cons_term}; + ASSERT_DEATH(cvc5_mk_term(d_tm, CVC5_KIND_APPLY_SELECTOR, 1, args.data()), + ""); + ASSERT_DEATH(cvc5_mk_term(d_tm, CVC5_KIND_APPLY_CONSTRUCTOR, 1, args.data()), + ""); + + args = {head_term}; + ASSERT_DEATH(cvc5_mk_term(d_tm, CVC5_KIND_APPLY_SELECTOR, 1, args.data()), + ""); + + args = {head_term, c}; + (void)cvc5_mk_term(d_tm, CVC5_KIND_APPLY_SELECTOR, 2, args.data()); + + args = {tail_term, c}; + (void)cvc5_mk_term(d_tm, CVC5_KIND_APPLY_SELECTOR, 2, args.data()); + + ASSERT_DEATH(cvc5_mk_term_from_op(d_tm, op1, 0, {}), ""); + args = {a}; + (void)cvc5_mk_term_from_op(d_tm, op1, 1, args.data()); + ASSERT_DEATH(cvc5_mk_term_from_op(d_tm, op2, 1, args.data()), ""); + args = {cvc5_mk_integer_int64(d_tm, 1)}; + (void)cvc5_mk_term_from_op(d_tm, op2, 1, args.data()); + args = {nullptr}; + ASSERT_DEATH(cvc5_mk_term_from_op(d_tm, op1, 1, args.data()), ""); + + args = {cons_term, cvc5_mk_integer_int64(d_tm, 0)}; + ASSERT_DEATH(cvc5_mk_term(d_tm, CVC5_KIND_APPLY_CONSTRUCTOR, 2, args.data()), + ""); + args = {nil_term}; + args = {cons_term, + cvc5_mk_integer_int64(d_tm, 0), + cvc5_mk_term(d_tm, CVC5_KIND_APPLY_CONSTRUCTOR, 1, args.data())}; + (void)cvc5_mk_term(d_tm, CVC5_KIND_APPLY_CONSTRUCTOR, 3, args.data()); + + args = {cvc5_mk_integer_int64(d_tm, 1), cvc5_mk_integer_int64(d_tm, 2)}; + ASSERT_DEATH(cvc5_mk_term_from_op(d_tm, op2, 2, args.data()), ""); + args = {a, b}; + ASSERT_DEATH(cvc5_mk_term_from_op(d_tm, op1, 2, args.data()), ""); + args = {cvc5_mk_integer_int64(d_tm, 1), nullptr}; + ASSERT_DEATH(cvc5_mk_term_from_op(d_tm, op2, 2, args.data()), ""); + args = {nullptr, cvc5_mk_integer_int64(d_tm, 1)}; + ASSERT_DEATH(cvc5_mk_term_from_op(d_tm, op2, 2, args.data()), ""); + + args = {a, b, a}; + ASSERT_DEATH(cvc5_mk_term_from_op(d_tm, op1, 3, args.data()), ""); + args = { + cvc5_mk_integer_int64(d_tm, 1), cvc5_mk_integer_int64(d_tm, 1), nullptr}; + ASSERT_DEATH(cvc5_mk_term_from_op(d_tm, op2, 3, args.data()), ""); + + args = {cvc5_mk_integer_int64(d_tm, 5)}; + (void)cvc5_mk_term_from_op(d_tm, op2, 1, args.data()); + + Cvc5TermManager* tm = cvc5_term_manager_new(); + // this will throw when NodeManager is not a singleton anymore + args = {cvc5_mk_integer_int64(tm, 1)}; + (void)cvc5_mk_term_from_op(tm, op2, 1, args.data()); + idxs = {1}; + (void)cvc5_mk_term_from_op( + tm, cvc5_mk_op(tm, CVC5_KIND_DIVISIBLE, 1, idxs.data()), 1, args.data()); + cvc5_term_manager_delete(tm); +} + +TEST_F(TestCApiBlackTermManager, mk_true) +{ + (void)cvc5_mk_true(d_tm); + ASSERT_DEATH(cvc5_mk_true(nullptr), "unexpected NULL argument"); +} + +TEST_F(TestCApiBlackTermManager, mk_tuple) +{ + std::vector args = {cvc5_mk_bv(d_tm, 3, "101", 2)}; + (void)cvc5_mk_tuple(d_tm, 1, args.data()); + args = {cvc5_mk_integer(d_tm, "5")}; + (void)cvc5_mk_tuple(d_tm, 1, args.data()); + args = {cvc5_mk_real(d_tm, "5.3")}; + (void)cvc5_mk_tuple(d_tm, 1, args.data()); + ASSERT_DEATH(cvc5_mk_tuple(nullptr, 1, args.data()), + "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_tuple(nullptr, 0, {}), "unexpected NULL argument"); + Cvc5TermManager* tm = cvc5_term_manager_new(); + // this will throw when NodeManager is not a singleton anymore + args = {cvc5_mk_bv(d_tm, 3, "101", 2)}; + (void)cvc5_mk_tuple(tm, 1, args.data()); + cvc5_term_manager_delete(tm); +} + +TEST_F(TestCApiBlackTermManager, mk_nullable_some) +{ + (void)cvc5_mk_nullable_some(d_tm, cvc5_mk_bv(d_tm, 3, "101", 2)); + (void)cvc5_mk_nullable_some(d_tm, cvc5_mk_integer(d_tm, "5")); + (void)cvc5_mk_nullable_some(d_tm, cvc5_mk_real(d_tm, "5.3")); + ASSERT_DEATH(cvc5_mk_nullable_some(nullptr, cvc5_mk_real(d_tm, "5.3")), + "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_nullable_some(d_tm, nullptr), "invalid term"); + + Cvc5TermManager* tm = cvc5_term_manager_new(); + // this will throw when NodeManager is not a singleton anymore + (void)cvc5_mk_nullable_some(tm, cvc5_mk_bv(d_tm, 3, "101", 2)); + cvc5_term_manager_delete(tm); +} + +TEST_F(TestCApiBlackTermManager, mk_nullable_val) +{ + // Cvc5Term value = cvc5_mk_nullable_val( + // d_tm, cvc5_mk_nullable_some(d_tm, cvc5_mk_integer_int64(d_tm, 5))); + // value = cvc5_simplify(d_solver, value); + // ASSERT_EQ(5, cvc5_term_get_int64_value(value)); + ASSERT_DEATH( + cvc5_mk_nullable_val( + nullptr, cvc5_mk_nullable_some(d_tm, cvc5_mk_integer_int64(d_tm, 5))), + "unexpected NULL argument"); + + ASSERT_DEATH(cvc5_mk_nullable_val(d_tm, nullptr), "invalid term"); + Cvc5TermManager* tm = cvc5_term_manager_new(); + // this will throw when NodeManager is not a singleton anymore + (void)cvc5_mk_nullable_val( + tm, cvc5_mk_nullable_some(d_tm, cvc5_mk_integer_int64(d_tm, 5))); + cvc5_term_manager_delete(tm); +} + +TEST_F(TestCApiBlackTermManager, mk_nullable_is_null) +{ + // Cvc5Term value = cvc5_mk_nullable_is_null( + // d_tm, cvc5_mk_nullable_some(d_tm, cvc5_mk_integer_int64(d_tm, 5))); + // value = cvc5_simplify(d_solver, value); + // ASSERT_EQ(false, cvc5_term_get_boolean_value(value)); + ASSERT_DEATH( + cvc5_mk_nullable_is_null( + nullptr, cvc5_mk_nullable_some(d_tm, cvc5_mk_integer_int64(d_tm, 5))), + "unexpected NULL argument"); + + ASSERT_DEATH(cvc5_mk_nullable_is_null(d_tm, nullptr), "invalid term"); + Cvc5TermManager* tm = cvc5_term_manager_new(); + // this will throw when NodeManager is not a singleton anymore + (void)cvc5_mk_nullable_is_null( + tm, cvc5_mk_nullable_some(d_tm, cvc5_mk_integer_int64(d_tm, 5))); + cvc5_term_manager_delete(tm); +} + +TEST_F(TestCApiBlackTermManager, mk_nullable_is_some) +{ + // Cvc5Term value = cvc5_mk_nullable_is_some( + // d_tm, cvc5_mk_nullable_some(d_tm, cvc5_mk_integer_int64(d_tm, 5))); + // value = cvc5_simplify(d_solver, value); + // ASSERT_EQ(true, cvc5_term_get_boolean_value(value)); + ASSERT_DEATH( + cvc5_mk_nullable_is_some( + nullptr, cvc5_mk_nullable_some(d_tm, cvc5_mk_integer_int64(d_tm, 5))), + "unexpected NULL argument"); + + ASSERT_DEATH(cvc5_mk_nullable_is_some(d_tm, nullptr), "invalid term"); + Cvc5TermManager* tm = cvc5_term_manager_new(); + // this will throw when NodeManager is not a singleton anymore + (void)cvc5_mk_nullable_is_some( + tm, cvc5_mk_nullable_some(d_tm, cvc5_mk_integer_int64(d_tm, 5))); + cvc5_term_manager_delete(tm); +} + +TEST_F(TestCApiBlackTermManager, mk_nullable_null) +{ + Cvc5Sort sort = cvc5_mk_nullable_sort(d_tm, d_bool); + // Cvc5Term null = cvc5_mk_nullable_null(d_tm, sort); + // Cvc5Term value = cvc5_mk_nullable_is_null(d_tm, null); + // value = cvc5_simplify(d_solver, value); + // ASSERT_EQ(true, cvc5_term_get_boolean_value(value)); + ASSERT_DEATH(cvc5_mk_nullable_null(nullptr, sort), + "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_nullable_null(d_tm, nullptr), "invalid sort"); + + Cvc5TermManager* tm = cvc5_term_manager_new(); + // this will throw when NodeManager is not a singleton anymore + (void)cvc5_mk_nullable_null(tm, sort); + cvc5_term_manager_delete(tm); +} + +TEST_F(TestCApiBlackTermManager, mk_nullable_lift) +{ + Cvc5Term some1 = cvc5_mk_nullable_some(d_tm, cvc5_mk_integer_int64(d_tm, 1)); + Cvc5Term some2 = cvc5_mk_nullable_some(d_tm, cvc5_mk_integer_int64(d_tm, 2)); + std::vector args = {some1, some2}; + // Cvc5Term lift = + cvc5_mk_nullable_lift(d_tm, CVC5_KIND_ADD, 2, args.data()); + // Cvc5Term three = cvc5_simplify(d_solver, cvc5_mk_nullable_val(d_tm, lift)); + // ASSERT_EQ(3, cvc5_term_get_int64_value(three)); + ASSERT_DEATH(cvc5_mk_nullable_lift(nullptr, CVC5_KIND_ADD, 2, args.data()), + "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_nullable_lift(d_tm, CVC5_KIND_ADD, 0, {}), + "unexpected NULL argument"); + + Cvc5TermManager* tm = cvc5_term_manager_new(); + // this will throw when NodeManager is not a singleton anymore + (void)cvc5_mk_nullable_lift(tm, CVC5_KIND_ADD, 2, args.data()); + cvc5_term_manager_delete(tm); +} + +TEST_F(TestCApiBlackTermManager, mk_universe_set) +{ + (void)cvc5_mk_universe_set(d_tm, d_bool); + ASSERT_DEATH(cvc5_mk_universe_set(nullptr, d_bool), + "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_universe_set(d_tm, nullptr), "invalid sort"); + + Cvc5TermManager* tm = cvc5_term_manager_new(); + // this will throw when NodeManager is not a singleton anymore + (void)cvc5_mk_universe_set(tm, d_bool); + cvc5_term_manager_delete(tm); +} + +TEST_F(TestCApiBlackTermManager, mk_const) +{ + std::vector domain = {d_int}; + Cvc5Sort fun_sort = cvc5_mk_fun_sort(d_tm, 1, domain.data(), d_bool); + (void)cvc5_mk_const(d_tm, d_bool, nullptr); + (void)cvc5_mk_const(d_tm, fun_sort, nullptr); + (void)cvc5_mk_const(d_tm, d_bool, "b"); + (void)cvc5_mk_const(d_tm, d_int, "i"); + (void)cvc5_mk_const(d_tm, fun_sort, "f"); + (void)cvc5_mk_const(d_tm, fun_sort, ""); + ASSERT_DEATH(cvc5_mk_const(nullptr, d_bool, nullptr), + "unexpected NULL argument"); + ASSERT_DEATH(cvc5_mk_const(d_tm, nullptr, nullptr), "invalid sort"); + Cvc5TermManager* tm = cvc5_term_manager_new(); + // this will throw when NodeManager is not a singleton anymore + (void)cvc5_mk_const(tm, d_bool, nullptr); cvc5_term_manager_delete(tm); } diff --git a/test/unit/api/cpp/CMakeLists.txt b/test/unit/api/cpp/CMakeLists.txt index 0d7ca366a1e..b339e33e229 100644 --- a/test/unit/api/cpp/CMakeLists.txt +++ b/test/unit/api/cpp/CMakeLists.txt @@ -13,27 +13,27 @@ # The build system configuration. ## cvc5_add_unit_test_black(api_kind_black api/cpp) +cvc5_add_unit_test_black(api_op_black api/cpp) +cvc5_add_unit_test_white(api_op_white api/cpp) cvc5_add_unit_test_black(api_proof_rule_black api/cpp) cvc5_add_unit_test_black(api_skolem_id_black api/cpp) cvc5_add_unit_test_black(api_sort_black api/cpp) cvc5_add_unit_test_black(api_sort_kind_black api/cpp) +cvc5_add_unit_test_black(api_term_black api/cpp) cvc5_add_unit_test_black(api_term_manager_black api/cpp) +cvc5_add_unit_test_white(api_term_white api/cpp) cvc5_add_unit_test_black(api_types_black api/cpp) cvc5_add_unit_test_black(command_black api/cpp) cvc5_add_unit_test_black(datatype_api_black api/cpp) cvc5_add_unit_test_black(grammar_black api/cpp) cvc5_add_unit_test_black(input_parser_black api/cpp) -cvc5_add_unit_test_black(op_black api/cpp) cvc5_add_unit_test_black(parametric_datatype_black api/cpp) cvc5_add_unit_test_black(proof_black api/cpp) cvc5_add_unit_test_black(result_black api/cpp) cvc5_add_unit_test_black(solver_black api/cpp) cvc5_add_unit_test_black(symbol_manager_black api/cpp) cvc5_add_unit_test_black(synth_result_black api/cpp) -cvc5_add_unit_test_black(term_black api/cpp) -cvc5_add_unit_test_white(op_white api/cpp) cvc5_add_unit_test_white(solver_white api/cpp) -cvc5_add_unit_test_white(term_white api/cpp) # tests to cover deprecated functions for API coverage build in nightlies set_source_files_properties(api_deprecated_black.cpp diff --git a/test/unit/api/cpp/op_black.cpp b/test/unit/api/cpp/api_op_black.cpp similarity index 98% rename from test/unit/api/cpp/op_black.cpp rename to test/unit/api/cpp/api_op_black.cpp index 1fe62a433de..e9fa459c5a5 100644 --- a/test/unit/api/cpp/op_black.cpp +++ b/test/unit/api/cpp/api_op_black.cpp @@ -31,9 +31,8 @@ TEST_F(TestApiBlackOp, hash) TEST_F(TestApiBlackOp, getKind) { - Op x; - x = d_tm.mkOp(Kind::BITVECTOR_EXTRACT, {31, 1}); - ASSERT_NO_THROW(x.getKind()); + Op x = d_tm.mkOp(Kind::BITVECTOR_EXTRACT, {31, 1}); + ASSERT_EQ(x.getKind(), Kind::BITVECTOR_EXTRACT); } TEST_F(TestApiBlackOp, isNull) diff --git a/test/unit/api/cpp/op_white.cpp b/test/unit/api/cpp/api_op_white.cpp similarity index 100% rename from test/unit/api/cpp/op_white.cpp rename to test/unit/api/cpp/api_op_white.cpp diff --git a/test/unit/api/cpp/term_black.cpp b/test/unit/api/cpp/api_term_black.cpp similarity index 98% rename from test/unit/api/cpp/term_black.cpp rename to test/unit/api/cpp/api_term_black.cpp index f673ec9870d..71f528dd37a 100644 --- a/test/unit/api/cpp/term_black.cpp +++ b/test/unit/api/cpp/api_term_black.cpp @@ -199,6 +199,7 @@ TEST_F(TestApiBlackTerm, getOp) Term headTerm = d_tm.mkTerm(Kind::APPLY_SELECTOR, {headOpTerm, consTerm}); Term tailTerm = d_tm.mkTerm(Kind::APPLY_SELECTOR, {tailOpTerm, consTerm}); + ASSERT_FALSE(c.hasOp()); ASSERT_TRUE(nilTerm.hasOp()); ASSERT_TRUE(consTerm.hasOp()); ASSERT_TRUE(headTerm.hasOp()); @@ -1088,12 +1089,8 @@ TEST_F(TestApiBlackTerm, substitute) Term y = d_tm.mkConst(d_tm.getIntegerSort(), "y"); Term xpy = d_tm.mkTerm(Kind::ADD, {x, y}); Term xpone = d_tm.mkTerm(Kind::ADD, {y, one}); - std::vector es; - std::vector rs; - es.push_back(x); - rs.push_back(y); - es.push_back(y); - rs.push_back(one); + std::vector es = {x, y}; + std::vector rs = {y, one}; ASSERT_EQ(xpy.substitute(es, rs), xpone); // incorrect substitution due to arity @@ -1207,7 +1204,8 @@ TEST_F(TestApiBlackTerm, getRealAlgebraicNumber) ASSERT_TRUE(ub.isRealValue()); // cannot call with non-variable Term yc = d_tm.mkConst(realsort, "y"); - ASSERT_THROW(vx.getRealAlgebraicNumberDefiningPolynomial(yc), CVC5ApiException); + ASSERT_THROW(vx.getRealAlgebraicNumberDefiningPolynomial(yc), + CVC5ApiException); } } @@ -1220,6 +1218,30 @@ TEST_F(TestApiBlackTerm, getSkolem) ASSERT_THROW(x.getSkolemIndices(), CVC5ApiException); } +TEST_F(TestApiBlackTerm, mkSkolem) +{ + Sort integer = d_tm.getIntegerSort(); + Sort arraySort = d_tm.mkArraySort(integer, integer); + + Term a = d_tm.mkConst(arraySort, "a"); + Term b = d_tm.mkConst(arraySort, "b"); + + Term sk = d_tm.mkSkolem(SkolemId::ARRAY_DEQ_DIFF, {a, b}); + Term sk2 = d_tm.mkSkolem(SkolemId::ARRAY_DEQ_DIFF, {b, a}); + + ASSERT_TRUE(sk.isSkolem()); + ASSERT_EQ(sk.getSkolemId(), SkolemId::ARRAY_DEQ_DIFF); + ASSERT_EQ(sk.getSkolemIndices(), std::vector({a, b})); + // ARRAY_DEQ_DIFF is commutative, so the order of the indices is sorted. + ASSERT_EQ(sk2.getSkolemIndices(), std::vector({a, b})); +} + +TEST_F(TestApiBlackTerm, getNumIndicesForSkolemId) +{ + size_t numIndices = d_tm.getNumIndicesForSkolemId(SkolemId::BAGS_MAP_INDEX); + ASSERT_EQ(numIndices, 5); +} + TEST_F(TestApiBlackTerm, termScopedToString) { Sort intsort = d_tm.getIntegerSort(); @@ -1228,7 +1250,8 @@ TEST_F(TestApiBlackTerm, termScopedToString) ASSERT_EQ(x.toString(), "x"); } -TEST_F(TestApiBlackTerm, toString) { +TEST_F(TestApiBlackTerm, toString) +{ ASSERT_NO_THROW(Term().toString()); Sort intsort = d_tm.getIntegerSort(); diff --git a/test/unit/api/cpp/api_term_manager_black.cpp b/test/unit/api/cpp/api_term_manager_black.cpp index bffad2ecda1..958e57b0bbd 100644 --- a/test/unit/api/cpp/api_term_manager_black.cpp +++ b/test/unit/api/cpp/api_term_manager_black.cpp @@ -482,7 +482,6 @@ TEST_F(TestApiBlackTermManager, mkConstArray) Term zero = d_tm.mkInteger(0); Term constArr = d_tm.mkConstArray(arrSort, zero); - ASSERT_NO_THROW(d_tm.mkConstArray(arrSort, zero)); ASSERT_THROW(d_tm.mkConstArray(Sort(), zero), CVC5ApiException); ASSERT_THROW(d_tm.mkConstArray(arrSort, Term()), CVC5ApiException); ASSERT_THROW(d_tm.mkConstArray(arrSort, d_tm.mkBitVector(1, 1)), @@ -496,7 +495,8 @@ TEST_F(TestApiBlackTermManager, mkConstArray) TermManager tm; // this will throw when NodeManager is not a singleton anymore ASSERT_NO_THROW(tm.mkConstArray(arrSort, tm.mkInteger(0))); - ASSERT_NO_THROW(tm.mkConstArray(tm.mkArraySort(intSort, intSort), zero)); + ASSERT_NO_THROW(tm.mkConstArray( + tm.mkArraySort(tm.getIntegerSort(), tm.getIntegerSort()), zero)); } TEST_F(TestApiBlackTermManager, mkVar) @@ -542,12 +542,12 @@ TEST_F(TestApiBlackTermManager, mkFloatingPoint) { Term t1 = d_tm.mkBitVector(8); Term t2 = d_tm.mkBitVector(4); - Term t3 = d_tm.mkInteger(2); ASSERT_NO_THROW(d_tm.mkFloatingPoint(3, 5, t1)); ASSERT_THROW(d_tm.mkFloatingPoint(0, 5, Term()), CVC5ApiException); ASSERT_THROW(d_tm.mkFloatingPoint(0, 5, t1), CVC5ApiException); + ASSERT_THROW(d_tm.mkFloatingPoint(1, 5, t1), CVC5ApiException); ASSERT_THROW(d_tm.mkFloatingPoint(3, 0, t1), CVC5ApiException); - ASSERT_THROW(d_tm.mkFloatingPoint(3, 5, t2), CVC5ApiException); + ASSERT_THROW(d_tm.mkFloatingPoint(3, 1, t1), CVC5ApiException); ASSERT_THROW(d_tm.mkFloatingPoint(3, 5, t2), CVC5ApiException); ASSERT_EQ(d_tm.mkFloatingPoint( @@ -579,8 +579,6 @@ TEST_F(TestApiBlackTermManager, mkFloatingPoint) d_tm.mkBitVector(2), d_tm.mkBitVector(5), d_tm.mkBitVector(10)), CVC5ApiException); - ASSERT_NO_THROW(d_tm.mkFloatingPoint(3, 5, t1)); - TermManager tm; // this will throw when NodeManager is not a singleton anymore ASSERT_NO_THROW(tm.mkFloatingPoint(3, 5, t1)); @@ -707,29 +705,8 @@ TEST_F(TestApiBlackTermManager, mkInteger) ASSERT_THROW(d_tm.mkInteger("2/"), CVC5ApiException); ASSERT_THROW(d_tm.mkInteger("/2"), CVC5ApiException); - ASSERT_NO_THROW(d_tm.mkReal(std::string("123"))); - ASSERT_THROW(d_tm.mkInteger(std::string("1.23")), CVC5ApiException); - ASSERT_THROW(d_tm.mkInteger(std::string("1/23")), CVC5ApiException); - ASSERT_THROW(d_tm.mkInteger(std::string("12/3")), CVC5ApiException); - ASSERT_THROW(d_tm.mkInteger(std::string(".2")), CVC5ApiException); - ASSERT_THROW(d_tm.mkInteger(std::string("2.")), CVC5ApiException); - ASSERT_THROW(d_tm.mkInteger(std::string("")), CVC5ApiException); - ASSERT_THROW(d_tm.mkInteger(std::string("asdf")), CVC5ApiException); - ASSERT_THROW(d_tm.mkInteger(std::string("1.2/3")), CVC5ApiException); - ASSERT_THROW(d_tm.mkInteger(std::string(".")), CVC5ApiException); - ASSERT_THROW(d_tm.mkInteger(std::string("/")), CVC5ApiException); - ASSERT_THROW(d_tm.mkInteger(std::string("2/")), CVC5ApiException); - ASSERT_THROW(d_tm.mkInteger(std::string("/2")), CVC5ApiException); - - int32_t val1 = 1; - int64_t val2 = -1; - uint32_t val3 = 1; - uint64_t val4 = -1; - ASSERT_NO_THROW(d_tm.mkInteger(val1)); - ASSERT_NO_THROW(d_tm.mkInteger(val2)); - ASSERT_NO_THROW(d_tm.mkInteger(val3)); - ASSERT_NO_THROW(d_tm.mkInteger(val4)); - ASSERT_NO_THROW(d_tm.mkInteger(val4)); + ASSERT_NO_THROW(d_tm.mkInteger(1)); + ASSERT_NO_THROW(d_tm.mkInteger(-1)); } TEST_F(TestApiBlackTermManager, mkReal) @@ -748,20 +725,6 @@ TEST_F(TestApiBlackTermManager, mkReal) ASSERT_THROW(d_tm.mkReal("2/"), CVC5ApiException); ASSERT_THROW(d_tm.mkReal("/2"), CVC5ApiException); - ASSERT_NO_THROW(d_tm.mkReal(std::string("123"))); - ASSERT_NO_THROW(d_tm.mkReal(std::string("1.23"))); - ASSERT_NO_THROW(d_tm.mkReal(std::string("1/23"))); - ASSERT_NO_THROW(d_tm.mkReal(std::string("12/3"))); - ASSERT_NO_THROW(d_tm.mkReal(std::string(".2"))); - ASSERT_NO_THROW(d_tm.mkReal(std::string("2."))); - ASSERT_THROW(d_tm.mkReal(std::string("")), CVC5ApiException); - ASSERT_THROW(d_tm.mkReal(std::string("asdf")), CVC5ApiException); - ASSERT_THROW(d_tm.mkReal(std::string("1.2/3")), CVC5ApiException); - ASSERT_THROW(d_tm.mkReal(std::string(".")), CVC5ApiException); - ASSERT_THROW(d_tm.mkReal(std::string("/")), CVC5ApiException); - ASSERT_THROW(d_tm.mkReal(std::string("2/")), CVC5ApiException); - ASSERT_THROW(d_tm.mkReal(std::string("/2")), CVC5ApiException); - int32_t val1 = 1; int64_t val2 = -1; uint32_t val3 = 1; @@ -780,6 +743,7 @@ TEST_F(TestApiBlackTermManager, mkReal) ASSERT_NO_THROW(d_tm.mkReal("-1/1")); ASSERT_NO_THROW(d_tm.mkReal("1/1")); ASSERT_THROW(d_tm.mkReal("/-5"), CVC5ApiException); + ASSERT_THROW(d_tm.mkReal(1, 0), CVC5ApiException); } TEST_F(TestApiBlackTermManager, mkRegexpAll) @@ -840,7 +804,6 @@ TEST_F(TestApiBlackTermManager, mkTerm) std::vector v5 = {d_tm.mkInteger(1), Term()}; std::vector v6 = {}; - // mkTerm(Kind kind) const ASSERT_NO_THROW(d_tm.mkTerm(Kind::PI)); ASSERT_NO_THROW(d_tm.mkTerm(Kind::PI, {v6})); ASSERT_NO_THROW(d_tm.mkTerm(d_tm.mkOp(Kind::PI))); @@ -859,7 +822,6 @@ TEST_F(TestApiBlackTermManager, mkTerm) ASSERT_NO_THROW(d_tm.mkTerm(d_tm.mkOp(Kind::SEP_EMP), {v6})); ASSERT_THROW(d_tm.mkTerm(Kind::CONST_BITVECTOR), CVC5ApiException); - // mkTerm(Kind kind, const std::vector& children) const ASSERT_NO_THROW(d_tm.mkTerm(Kind::NOT, {d_tm.mkTrue()})); ASSERT_NO_THROW( d_tm.mkTerm(Kind::BAG_MAKE, {d_tm.mkTrue(), d_tm.mkInteger(1)})); diff --git a/test/unit/api/cpp/term_white.cpp b/test/unit/api/cpp/api_term_white.cpp similarity index 100% rename from test/unit/api/cpp/term_white.cpp rename to test/unit/api/cpp/api_term_white.cpp diff --git a/test/unit/api/cpp/command_black.cpp b/test/unit/api/cpp/command_black.cpp index a4d396fdb09..4773efba02d 100644 --- a/test/unit/api/cpp/command_black.cpp +++ b/test/unit/api/cpp/command_black.cpp @@ -61,7 +61,7 @@ TEST_F(TestCommandBlack, invoke) cmd.invoke(d_solver.get(), d_symman.get(), out); std::string result = out.str(); ASSERT_EQ( - "(error \"Cannot get model unless model generation is enabled (try " + "(error \"cannot get model unless model generation is enabled (try " "--produce-models)\")\n", result); // logic already set diff --git a/test/unit/api/cpp/proof_black.cpp b/test/unit/api/cpp/proof_black.cpp index 760b1460d11..8481c9c3bcf 100644 --- a/test/unit/api/cpp/proof_black.cpp +++ b/test/unit/api/cpp/proof_black.cpp @@ -24,7 +24,7 @@ namespace test { class TestApiBlackProof : public TestApi { protected: - Proof create_proof() + Proof createProof() { d_solver->setOption("produce-proofs", "true"); @@ -74,7 +74,6 @@ TEST_F(TestApiBlackProof, nullProof) { Proof proof; ASSERT_EQ(proof.getRule(), ProofRule::UNKNOWN); - ASSERT_EQ(std::hash()(ProofRule::UNKNOWN), static_cast(ProofRule::UNKNOWN)); ASSERT_TRUE(proof.getResult().isNull()); @@ -84,7 +83,7 @@ TEST_F(TestApiBlackProof, nullProof) TEST_F(TestApiBlackProof, getRule) { - Proof proof = create_proof(); + Proof proof = createProof(); ASSERT_EQ(proof.getRule(), ProofRule::SCOPE); } @@ -108,13 +107,13 @@ TEST_F(TestApiBlackProof, getRewriteRule) TEST_F(TestApiBlackProof, getResult) { - Proof proof = create_proof(); + Proof proof = createProof(); ASSERT_NO_THROW(proof.getResult()); } TEST_F(TestApiBlackProof, getChildren) { - Proof proof = create_proof(); + Proof proof = createProof(); std::vector children; ASSERT_NO_THROW(children = proof.getChildren()); ASSERT_FALSE(children.empty()); @@ -122,9 +121,25 @@ TEST_F(TestApiBlackProof, getChildren) TEST_F(TestApiBlackProof, getArguments) { - Proof proof = create_proof(); + Proof proof = createProof(); ASSERT_NO_THROW(proof.getArguments()); } +TEST_F(TestApiBlackProof, eq) +{ + Proof x = createProof(); + Proof y = x.getChildren()[0]; + Proof z; + + ASSERT_TRUE(x == x); + ASSERT_FALSE(x != x); + ASSERT_FALSE(x == y); + ASSERT_TRUE(x != y); + ASSERT_FALSE(x == z); + ASSERT_TRUE(x != z); + + ASSERT_TRUE(std::hash()(x) == std::hash()(x)); +} + } // namespace test } // namespace cvc5::internal diff --git a/test/unit/api/cpp/solver_black.cpp b/test/unit/api/cpp/solver_black.cpp index e8a60a96429..b151fcb3b70 100644 --- a/test/unit/api/cpp/solver_black.cpp +++ b/test/unit/api/cpp/solver_black.cpp @@ -2554,10 +2554,15 @@ class PluginListen : public Plugin { } virtual ~PluginListen() {} - void notifySatClause(const Term& cl) override { d_hasSeenSatClause = true; } + void notifySatClause(const Term& cl) override + { + Plugin::notifySatClause(cl); // Cover default implementation + d_hasSeenSatClause = true; + } bool hasSeenSatClause() const { return d_hasSeenSatClause; } void notifyTheoryLemma(const Term& lem) override { + Plugin::notifyTheoryLemma(lem); // Cover default implementation d_hasSeenTheoryLemma = true; } bool hasSeenTheoryLemma() const { return d_hasSeenTheoryLemma; } diff --git a/test/unit/api/java/CommandTest.java b/test/unit/api/java/CommandTest.java index c793e55cdc1..11df0a7902c 100644 --- a/test/unit/api/java/CommandTest.java +++ b/test/unit/api/java/CommandTest.java @@ -46,7 +46,7 @@ void invoke() assertNotEquals(cmd.isNull(), true); String result = cmd.invoke(d_solver, d_symman); assertEquals( - "(error \"Cannot get model unless model generation is enabled (try --produce-models)\")\n", + "(error \"cannot get model unless model generation is enabled (try --produce-models)\")\n", result); // logic already set assertThrows(CVC5ParserException.class, () -> parseCommand("(set-logic QF_LRA)")); diff --git a/test/unit/api/java/ProofTest.java b/test/unit/api/java/ProofTest.java index d49d980ea21..02b260b57d4 100644 --- a/test/unit/api/java/ProofTest.java +++ b/test/unit/api/java/ProofTest.java @@ -47,7 +47,7 @@ void tearDown() Context.deletePointers(); } - Proof create_proof() throws CVC5ApiException + Proof createProof() throws CVC5ApiException { d_solver.setOption("produce-proofs", "true"); @@ -92,10 +92,21 @@ Proof createRewriteProof() throws CVC5ApiException return d_solver.getProof()[0]; } + @Test + void nullProof() throws CVC5ApiException + { + Proof proof = new Proof(); + assertEquals(proof.getRule(), ProofRule.UNKNOWN); + assertEquals(ProofRule.UNKNOWN.hashCode(), ProofRule.UNKNOWN.hashCode()); + assertTrue(proof.getResult().isNull()); + assertTrue(proof.getChildren().length == 0); + assertTrue(proof.getArguments().length == 0); + } + @Test void getRule() throws CVC5ApiException { - Proof proof = create_proof(); + Proof proof = createProof(); assertEquals(ProofRule.SCOPE, proof.getRule()); } @@ -123,14 +134,14 @@ void getRewriteRule() throws CVC5ApiException @Test void getResult() throws CVC5ApiException { - Proof proof = create_proof(); + Proof proof = createProof(); assertDoesNotThrow(() -> proof.getResult()); } @Test void getChildren() throws CVC5ApiException { - Proof proof = create_proof(); + Proof proof = createProof(); Proof[] children = proof.getChildren(); assertNotEquals(0, children.length); } @@ -138,8 +149,24 @@ void getChildren() throws CVC5ApiException @Test void getArguments() throws CVC5ApiException { - Proof proof = create_proof(); + Proof proof = createProof(); assertDoesNotThrow(() -> proof.getArguments()); } + @Test + void eq() throws CVC5ApiException + { + Proof x = createProof(); + Proof y = x.getChildren()[0]; + Proof z = new Proof(); + + assertTrue(x == x); + assertFalse(x != x); + assertFalse(x == y); + assertTrue(x != y); + assertFalse(x == z); + assertTrue(x != z); + + assertTrue(x.hashCode() == x.hashCode()); + } } diff --git a/test/unit/api/java/TermTest.java b/test/unit/api/java/TermTest.java index 19bfab7a601..7f5bfc3346a 100644 --- a/test/unit/api/java/TermTest.java +++ b/test/unit/api/java/TermTest.java @@ -1092,6 +1092,32 @@ void getSkolem() throws CVC5ApiException assertThrows(CVC5ApiException.class, () ->x.getSkolemIndices()); } + @Test + void testMkSkolem() throws CVC5ApiException + { + Sort integer = d_solver.getIntegerSort(); + Sort arraySort = d_solver.mkArraySort(integer, integer); + + Term a = d_solver.mkConst(arraySort, "a"); + Term b = d_solver.mkConst(arraySort, "b"); + + Term sk = d_tm.mkSkolem(SkolemId.ARRAY_DEQ_DIFF, new Term[] {a, b}); + Term sk2 = d_tm.mkSkolem(SkolemId.ARRAY_DEQ_DIFF, new Term[] {b, a}); + + assertTrue(sk.isSkolem()); + assertEquals(sk.getSkolemId(), SkolemId.ARRAY_DEQ_DIFF); + assertEquals(Arrays.asList(new Term[] {a, b}), Arrays.asList(sk.getSkolemIndices())); + // ARRAY_DEQ_DIFF is commutative, so the order of the indices is sorted. + assertEquals(Arrays.asList(new Term[] {a, b}), Arrays.asList(sk2.getSkolemIndices())); + } + + @Test + void testGetNumIndices() throws CVC5ApiException + { + int numIndices = d_tm.getNumIndicesForSkolemId(SkolemId.ARRAY_DEQ_DIFF); + assertEquals(numIndices, 2); + } + @Test void substitute() { diff --git a/test/unit/api/python/test_proof.py b/test/unit/api/python/test_proof.py index 9b50c102c90..180410e3dd7 100644 --- a/test/unit/api/python/test_proof.py +++ b/test/unit/api/python/test_proof.py @@ -29,7 +29,7 @@ def solver(tm): def create_proof(tm, solver): - solver.setOption("produce-proofs", "true"); + solver.setOption("produce-proofs", "true") uSort = tm.mkUninterpretedSort("u") intSort = tm.getIntegerSort() @@ -70,10 +70,19 @@ def create_rewrite_proof(tm, solver): return solver.getProof()[0] -def test_get_result(tm, solver): +def test_null_proof(solver): + proof = cvc5.Proof(solver) + assert proof.getRule() == ProofRule.UNKNOWN + assert hash(ProofRule.UNKNOWN) == hash(ProofRule.UNKNOWN) + assert proof.getResult().isNull() + assert len(proof.getChildren()) == 0 + assert len(proof.getArguments()) == 0 + + +def test_get_rule(tm, solver): proof = create_proof(tm, solver) rule = proof.getRule() - assert rule == "SCOPE" + assert rule == ProofRule.SCOPE def test_get_rewrite_rule(tm, solver): @@ -104,3 +113,18 @@ def test_get_children(tm, solver): def test_get_arguments(tm, solver): proof = create_proof(tm, solver) proof.getArguments() + + +def test_eq(tm, solver): + x = create_proof(tm, solver) + y = x.getChildren()[0] + z = cvc5.Proof(solver) + + assert x == x + assert not x != x + assert not x == y + assert x != y + assert not (x == z) + assert x != z + + assert hash(x) == hash(x) diff --git a/test/unit/api/python/test_term_manager.py b/test/unit/api/python/test_term_manager.py index a9422217747..69394379624 100644 --- a/test/unit/api/python/test_term_manager.py +++ b/test/unit/api/python/test_term_manager.py @@ -287,6 +287,26 @@ def test_mk_param_sort(tm): tm.mkParamSort("T") tm.mkParamSort("") +def test_mk_skolem(tm): + integer = tm.getIntegerSort() + arraySort = tm.mkArraySort(integer, integer) + a = tm.mkConst(arraySort, "a") + b = tm.mkConst(arraySort, "b") + + sk = tm.mkSkolem(cvc5.SkolemId.ARRAY_DEQ_DIFF, a, b) + sk2 = tm.mkSkolem(cvc5.SkolemId.ARRAY_DEQ_DIFF, b, a) + + assert sk.isSkolem() + assert sk2.isSkolem() + assert sk.getSkolemId() == cvc5.SkolemId.ARRAY_DEQ_DIFF + assert sk2.getSkolemId() == cvc5.SkolemId.ARRAY_DEQ_DIFF + assert sk.getSkolemIndices() == [a, b] + # ARRAY_DEQ_DIFF is commutative, so the order of the indices is sorted. + assert sk2.getSkolemIndices() == [a, b] + +def test_skolem_num_indices(tm): + num = tm.getNumIndicesForSkolemId(cvc5.SkolemId.ARRAY_DEQ_DIFF) + assert num == 2 def test_mk_predicate_sort(tm): tm.mkPredicateSort(tm.getIntegerSort()) diff --git a/test/unit/node/CMakeLists.txt b/test/unit/node/CMakeLists.txt index ad17aa3f1b0..2b4c9d4954b 100644 --- a/test/unit/node/CMakeLists.txt +++ b/test/unit/node/CMakeLists.txt @@ -16,6 +16,7 @@ # Add unit tests. cvc5_add_unit_test_black(attribute_black node) cvc5_add_unit_test_white(attribute_white node) +cvc5_add_unit_test_white(attrhash_white node) cvc5_add_unit_test_black(kind_black node) cvc5_add_unit_test_black(kind_map_black node) cvc5_add_unit_test_black(node_black node) diff --git a/test/unit/node/attrhash_white.cpp b/test/unit/node/attrhash_white.cpp new file mode 100644 index 00000000000..51adecc7ac8 --- /dev/null +++ b/test/unit/node/attrhash_white.cpp @@ -0,0 +1,250 @@ +/****************************************************************************** + * Top contributors (to current version): + * Jeff Trull + * + * This file is part of the cvc5 project. + * + * Copyright (c) 2009-2024 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. + * **************************************************************************** + * + * White box testing of cvc5::internal::expr::attr::AttrHash<> + */ + +#include "test_node.h" +#include "expr/attribute.h" +#include +#include +#include +#include + +namespace cvc5::internal { +namespace test { +// fixtures +class AttrHashFixture : public TestInternal +{ +public: + AttrHashFixture() : + d_nodeManager{NodeManager::currentNM()}, + d_booleanType{NodeManager::currentNM()->booleanType()} {} + +protected: + + template + using Hash = expr::attr::AttrHash; + + NodeManager* d_nodeManager; + TypeNode d_booleanType; + +}; + +TEST_F(AttrHashFixture, basic) +{ + Node nA = d_nodeManager->mkVar("A", d_booleanType); + Node nB = d_nodeManager->mkVar("B", d_booleanType); + Node nC = d_nodeManager->mkVar("C", d_booleanType); + Node nD = d_nodeManager->mkVar("D", d_booleanType); + + // a constant hash will always be empty (only default constructor) + const Hash emptyHash; + EXPECT_EQ(std::distance(emptyHash.begin(), emptyHash.end()), 0u); // const iterators + EXPECT_EQ(emptyHash.size(), 0u); + + // add elements using operator[] and varying NodeValue* + Hash hash1; + hash1[std::make_pair(0u, nA.d_nv)] = 0; + hash1[std::make_pair(0u, nB.d_nv)] = 1; + hash1[std::make_pair(0u, nC.d_nv)] = 2; + + EXPECT_EQ(hash1.size(), 3u); + EXPECT_EQ(std::distance(hash1.begin(), hash1.end()), 3u); // non-const + + // check const iterators on non-empty hash + auto const_size_of = [](Hash const & h){ return std::distance(h.begin(), h.end()); }; + EXPECT_EQ(const_size_of(hash1), 3u); + + // make sure the expected values are present + EXPECT_NE(hash1.find(std::make_pair(0u, nA.d_nv)), hash1.end()); + EXPECT_NE(hash1.find(std::make_pair(0u, nB.d_nv)), hash1.end()); + EXPECT_NE(hash1.find(std::make_pair(0u, nC.d_nv)), hash1.end()); + + // add elements using "insert", varying Id + Hash hash2; + std::array::iterator::value_type, 3> new_elements{ + std::make_pair(std::make_pair(uint64_t{42}, nA.d_nv), 1), + std::make_pair(std::make_pair(uint64_t{43}, nA.d_nv), 2), + std::make_pair(std::make_pair(uint64_t{44}, nA.d_nv), 3)}; + hash2.insert(new_elements.begin(), new_elements.end()); + EXPECT_EQ(hash2.size(), 3u); + EXPECT_EQ(std::distance(hash2.begin(), hash2.end()), 3u); + + // are they there? + EXPECT_NE(hash2.find(std::make_pair(uint64_t{42}, nA.d_nv)), hash2.end()); + EXPECT_NE(hash2.find(std::make_pair(uint64_t{43}, nA.d_nv)), hash2.end()); + EXPECT_NE(hash2.find(std::make_pair(uint64_t{44}, nA.d_nv)), hash2.end()); + + // erase by iterator + auto next_after_erase = hash2.erase(hash2.find(std::make_pair(uint64_t{43}, nA.d_nv))); + // entry is gone + EXPECT_EQ(hash2.find(std::make_pair(uint64_t{43}, nA.d_nv)), hash2.end()); + // the returned "next" iterator makes sense + EXPECT_TRUE((next_after_erase == hash2.end()) || + ((*next_after_erase) == std::make_pair(std::make_pair(uint64_t{42}, nA.d_nv), 1)) || + ((*next_after_erase) == std::make_pair(std::make_pair(uint64_t{44}, nA.d_nv), 3))); + + // erase by NodeValue* + hash1.eraseBy(nC.d_nv); + EXPECT_EQ(hash1.find(std::make_pair(0u, nC.d_nv)), hash1.end()); + EXPECT_EQ(hash1.size(), std::size_t{2}); + EXPECT_EQ(std::distance(hash1.begin(), hash1.end()), std::size_t{2}); + EXPECT_NE(hash1.find(std::make_pair(0u, nA.d_nv)), hash1.end()); + EXPECT_NE(hash1.find(std::make_pair(0u, nB.d_nv)), hash1.end()); + + // clear + hash1.clear(); + EXPECT_EQ(hash1.size(), 0ul); + + // swap + std::swap(hash1, hash2); + EXPECT_EQ(hash2.size(), 0ul); + EXPECT_EQ(hash1.size(), 2ul); + EXPECT_NE(hash1.find(std::make_pair(uint64_t{42}, nA.d_nv)), hash1.end()); + EXPECT_NE(hash1.find(std::make_pair(uint64_t{44}, nA.d_nv)), hash1.end()); + +} + +TEST_F(AttrHashFixture, empty_levels) +{ + // removing the last element from an L2 map + // (thus causing an empty L2) changes + // nothing about the operation of the hash overall + + Node nA = d_nodeManager->mkVar("A", d_booleanType); + Node nB = d_nodeManager->mkVar("B", d_booleanType); + Node nC = d_nodeManager->mkVar("C", d_booleanType); + Node nD = d_nodeManager->mkVar("D", d_booleanType); + + std::array::iterator::value_type, 2> new_elements{ + std::make_pair(std::make_pair(uint64_t{42}, nA.d_nv), 1), + std::make_pair(std::make_pair(uint64_t{43}, nA.d_nv), 2)}; + + Hash hash1; + hash1.insert(new_elements.begin(), new_elements.end()); + EXPECT_EQ(hash1.size(), std::size_t{2}); + auto it = hash1.erase(hash1.begin()); + EXPECT_TRUE((it == hash1.end()) || (it == hash1.begin())); + EXPECT_EQ(hash1.find((*hash1.begin()).first), hash1.begin()); + EXPECT_EQ(hash1.size(), std::size_t{1}); + + // delete the last element + hash1.erase(hash1.begin()); + EXPECT_EQ(hash1.size(), 0ul); + + // create several L2 maps in a fresh hash + std::array::iterator::value_type, 8> new_elements2{ + std::make_pair(std::make_pair(uint64_t{11}, nD.d_nv), 3), + std::make_pair(std::make_pair(uint64_t{12}, nA.d_nv), 3), + std::make_pair(std::make_pair(uint64_t{13}, nB.d_nv), 2), + std::make_pair(std::make_pair(uint64_t{14}, nA.d_nv), 4), + std::make_pair(std::make_pair(uint64_t{15}, nB.d_nv), 2), + std::make_pair(std::make_pair(uint64_t{16}, nC.d_nv), 5), + std::make_pair(std::make_pair(uint64_t{17}, nD.d_nv), 6), + std::make_pair(std::make_pair(uint64_t{18}, nC.d_nv), 7)}; + + Hash hash2; + hash2.insert(new_elements2.begin(), new_elements2.end()); + EXPECT_EQ(hash2.size(), std::size_t{8}); + + // remove the two node B attributes one at a time + hash2.erase(hash2.find(std::make_pair(uint64_t{13}, nB.d_nv))); + EXPECT_EQ(hash2.find(std::make_pair(uint64_t{13}, nB.d_nv)), hash2.end()); + EXPECT_NE(hash2.find(std::make_pair(uint64_t{15}, nB.d_nv)), hash2.end()); + EXPECT_EQ(hash2[std::make_pair(uint64_t{15}, nB.d_nv)], 2); + EXPECT_EQ(hash2.size(), std::size_t{7}); + EXPECT_EQ(std::distance(hash2.begin(), hash2.end()), std::size_t{7}); + + hash2.erase(hash2.find(std::make_pair(uint64_t{15}, nB.d_nv))); + EXPECT_EQ(hash2.find(std::make_pair(uint64_t{15}, nB.d_nv)), hash2.end()); + + // validate remaining entries + EXPECT_EQ(hash2.size(), std::size_t{6}); + EXPECT_EQ(std::distance(hash2.begin(), hash2.end()), std::size_t{6}); + EXPECT_NE(hash2.find(std::make_pair(uint64_t{11}, nD.d_nv)), hash2.end()); + EXPECT_NE(hash2.find(std::make_pair(uint64_t{12}, nA.d_nv)), hash2.end()); + EXPECT_NE(hash2.find(std::make_pair(uint64_t{14}, nA.d_nv)), hash2.end()); + EXPECT_NE(hash2.find(std::make_pair(uint64_t{16}, nC.d_nv)), hash2.end()); + EXPECT_NE(hash2.find(std::make_pair(uint64_t{17}, nD.d_nv)), hash2.end()); + EXPECT_NE(hash2.find(std::make_pair(uint64_t{18}, nC.d_nv)), hash2.end()); + EXPECT_EQ(hash2[std::make_pair(uint64_t{11}, nD.d_nv)], 3); + EXPECT_EQ(hash2[std::make_pair(uint64_t{12}, nA.d_nv)], 3); + EXPECT_EQ(hash2[std::make_pair(uint64_t{14}, nA.d_nv)], 4); + EXPECT_EQ(hash2[std::make_pair(uint64_t{16}, nC.d_nv)], 5); + EXPECT_EQ(hash2[std::make_pair(uint64_t{17}, nD.d_nv)], 6); + EXPECT_EQ(hash2[std::make_pair(uint64_t{18}, nC.d_nv)], 7); + + // now delete one full NodeValue*'s worth (one L2 map) and reverify + hash2.eraseBy(nA.d_nv); + EXPECT_EQ(hash2.size(), std::size_t{4}); + EXPECT_EQ(std::distance(hash2.begin(), hash2.end()), std::size_t{4}); + EXPECT_NE(hash2.find(std::make_pair(uint64_t{11}, nD.d_nv)), hash2.end()); + EXPECT_NE(hash2.find(std::make_pair(uint64_t{16}, nC.d_nv)), hash2.end()); + EXPECT_NE(hash2.find(std::make_pair(uint64_t{17}, nD.d_nv)), hash2.end()); + EXPECT_NE(hash2.find(std::make_pair(uint64_t{18}, nC.d_nv)), hash2.end()); + EXPECT_EQ(hash2[std::make_pair(uint64_t{11}, nD.d_nv)], 3); + EXPECT_EQ(hash2[std::make_pair(uint64_t{16}, nC.d_nv)], 5); + EXPECT_EQ(hash2[std::make_pair(uint64_t{17}, nD.d_nv)], 6); + EXPECT_EQ(hash2[std::make_pair(uint64_t{18}, nC.d_nv)], 7); + +} + +TEST_F(AttrHashFixture, repeated_inserts) +{ + // when we insert with an existing key, the value is not updated, + // but it is when we use operator[] + + Node nA = d_nodeManager->mkVar("A", d_booleanType); + Node nB = d_nodeManager->mkVar("B", d_booleanType); + Node nC = d_nodeManager->mkVar("C", d_booleanType); + + std::array::iterator::value_type, 5> initial_elements{ + std::make_pair(std::make_pair(uint64_t{42}, nA.d_nv), 2), + std::make_pair(std::make_pair(uint64_t{43}, nA.d_nv), 1), + std::make_pair(std::make_pair(uint64_t{42}, nB.d_nv), 4), + std::make_pair(std::make_pair(uint64_t{43}, nB.d_nv), 5), + std::make_pair(std::make_pair(uint64_t{42}, nC.d_nv), 2)}; + + Hash hash; + hash.insert(initial_elements.begin(), initial_elements.end()); + + // attempt to change two entries using insert + std::array::iterator::value_type, 2> new_elements{ + std::make_pair(std::make_pair(uint64_t{42}, nA.d_nv), 6), + std::make_pair(std::make_pair(uint64_t{42}, nC.d_nv), 8)}; + hash.insert(new_elements.begin(), new_elements.end()); + + // entries should be unchanged (insert doesn't alter existing entries) + EXPECT_EQ(hash.size(), std::size_t{5}); + EXPECT_EQ(hash[std::make_pair(uint64_t{42}, nA.d_nv)], 2); + EXPECT_EQ(hash[std::make_pair(uint64_t{42}, nC.d_nv)], 2); + EXPECT_EQ(*hash.find(std::make_pair(uint64_t{42}, nA.d_nv)), + std::make_pair(std::make_pair(uint64_t{42}, nA.d_nv), 2)); + EXPECT_EQ(*hash.find(std::make_pair(uint64_t{42}, nC.d_nv)), + std::make_pair(std::make_pair(uint64_t{42}, nC.d_nv), 2)); + + // change two entries using operator[] + hash[std::make_pair(uint64_t{42}, nB.d_nv)] = 10; + hash[std::make_pair(uint64_t{42}, nC.d_nv)] = 12; + + // entries should be changed this time + EXPECT_EQ(hash[std::make_pair(uint64_t{42}, nB.d_nv)], 10); + EXPECT_EQ(hash[std::make_pair(uint64_t{42}, nC.d_nv)], 12); + EXPECT_EQ(*hash.find(std::make_pair(uint64_t{42}, nB.d_nv)), + std::make_pair(std::make_pair(uint64_t{42}, nB.d_nv), 10)); + EXPECT_EQ(*hash.find(std::make_pair(uint64_t{42}, nC.d_nv)), + std::make_pair(std::make_pair(uint64_t{42}, nC.d_nv), 12)); +} + +} // namespace test +} // namespace cvc5::internal