diff options
390 files changed, 6246 insertions, 4718 deletions
diff --git a/.github/workflows/docs_upload.yml b/.github/workflows/docs_upload.yml index 98eb24943..937496d0a 100644 --- a/.github/workflows/docs_upload.yml +++ b/.github/workflows/docs_upload.yml @@ -53,6 +53,12 @@ jobs: - name: Unpack artifact run: unzip download.zip -d docs-new/ + - name: Check for broken links + continue-on-error: true + run: | + python3 -m pip install linkchecker + linkchecker --check-extern docs-new/index.html + - name: Setup Context run: | HASH=${{ github.event.workflow_run.head_commit.id }} diff --git a/cmake/version-base.cmake b/cmake/version-base.cmake index c3cca6a08..811209a96 100644 --- a/cmake/version-base.cmake +++ b/cmake/version-base.cmake @@ -5,7 +5,6 @@ set(CVC5_IS_RELEASE "false") # These are used in other places in cmake # If possible, they are updated by version.cmake set(GIT_BUILD "false") -set(CVC5_IS_RELEASE "false") set(CVC5_VERSION "${CVC5_LAST_RELEASE}") set(CVC5_FULL_VERSION "${CVC5_LAST_RELEASE}") set(CVC5_GIT_INFO "") diff --git a/cmake/version-base.cmake.template b/cmake/version-base.cmake.template index e149ea380..ec31ccd69 100644 --- a/cmake/version-base.cmake.template +++ b/cmake/version-base.cmake.template @@ -5,7 +5,6 @@ set(CVC5_IS_RELEASE "{{IS_RELEASE}}") # These are used in other places in cmake # If possible, they are updated by version.cmake set(GIT_BUILD "false") -set(CVC5_IS_RELEASE "false") set(CVC5_VERSION "${CVC5_LAST_RELEASE}") set(CVC5_FULL_VERSION "${CVC5_LAST_RELEASE}") set(CVC5_GIT_INFO "") diff --git a/cmake/version.cmake b/cmake/version.cmake index e6edd528c..183fe213b 100644 --- a/cmake/version.cmake +++ b/cmake/version.cmake @@ -25,13 +25,20 @@ if(CMAKE_SCRIPT_MODE_FILE) else() # was run within the overall cmake project # add target to update versioninfo.cpp at build time - add_custom_target(gen-versioninfo - BYPRODUCTS + add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/src/base/versioninfo.cpp COMMAND ${CMAKE_COMMAND} -DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR} -DCMAKE_BINARY_DIR=${CMAKE_BINARY_DIR} - -P ${PROJECT_SOURCE_DIR}/cmake/version.cmake) + -P ${PROJECT_SOURCE_DIR}/cmake/version.cmake + DEPENDS + ${PROJECT_SOURCE_DIR}/cmake/version-base.cmake + ${PROJECT_SOURCE_DIR}/cmake/version.cmake + ) + add_custom_target(gen-versioninfo + DEPENDS ${CMAKE_BINARY_DIR}/src/base/versioninfo.cpp + ) endif() # include basic version information @@ -112,8 +119,13 @@ if(GIT_FOUND) list(LENGTH VERSION_LIST VERSION_LIST_LENGTH) endwhile() - set(CVC5_VERSION "${GIT_LAST_TAG}-dev") - set(CVC5_FULL_VERSION "${GIT_LAST_TAG}-dev.${GIT_COMMITS_SINCE_TAG}.${GIT_COMMIT}") + if(CVC5_IS_RELEASE) + set(CVC5_VERSION "${CVC5_VERSION}-modified") + set(CVC5_FULL_VERSION "${CVC5_FULL_VERSION}-modified") + else() + set(CVC5_VERSION "${GIT_LAST_TAG}-dev") + set(CVC5_FULL_VERSION "${GIT_LAST_TAG}-dev.${GIT_COMMITS_SINCE_TAG}.${GIT_COMMIT}") + endif() set(CVC5_GIT_INFO "git ${GIT_COMMIT} on branch ${GIT_BRANCH}${GIT_DIRTY_MSG}") endif() endif() diff --git a/docs/api/api.rst b/docs/api/api.rst index 727caea4d..3eff4bd1c 100644 --- a/docs/api/api.rst +++ b/docs/api/api.rst @@ -3,12 +3,12 @@ API Documentation In addition to using cvc5 :doc:`as a binary <../binary/binary>`, cvc5 features APIs for several different programming languages. -While the :doc:`C++ API <cpp/cpp>` is considered the primary interface to cvc5, both the :doc:`Java API <java/index>` and the :doc:`Python API <python/python>` implement a thin wrapper around it. -Additionally, a more pythonic Python API is availble at https://github.com/cvc5/cvc5_z3py_compat. +While the :doc:`C++ API <cpp/cpp>` is considered the primary interface to cvc5, both the :doc:`Java API <java/java>` and the :doc:`Python API <python/python>` implement a thin wrapper around it. +Additionally, a more pythonic Python API is available at https://github.com/cvc5/cvc5_z3py_compat. .. toctree:: :maxdepth: 1 - C++ API <cpp/cpp> - Java API <java/index> - Python API <python/python> + cpp/cpp + java/java + python/python diff --git a/docs/api/cpp/Doxyfile.in b/docs/api/cpp/Doxyfile.in index 75a732ceb..b55c4ec48 100644 --- a/docs/api/cpp/Doxyfile.in +++ b/docs/api/cpp/Doxyfile.in @@ -270,6 +270,8 @@ TAB_SIZE = 4 # a double escape (\\{ and \\}) ALIASES = +ALIASES += "rst=\verbatim embed:rst" +ALIASES += "endrst=\endverbatim" # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For diff --git a/docs/api/cpp/cpp.rst b/docs/api/cpp/cpp.rst index 96177e7d8..49548222a 100644 --- a/docs/api/cpp/cpp.rst +++ b/docs/api/cpp/cpp.rst @@ -1,4 +1,4 @@ -C++ API Documentation +C++ API ===================== The C++ API is the primary interface for cvc5 and exposes the full functionality of cvc5. @@ -9,7 +9,6 @@ For most applications, the :cpp:class:`Solver <cvc5::api::Solver>` class is the .. container:: hide-toctree .. toctree:: - :maxdepth: 0 quickstart exceptions diff --git a/docs/api/java/CMakeLists.txt b/docs/api/java/CMakeLists.txt index 8a728407f..2fcf74767 100644 --- a/docs/api/java/CMakeLists.txt +++ b/docs/api/java/CMakeLists.txt @@ -31,6 +31,7 @@ if(BUILD_BINDINGS_JAVA) -sourcepath ${CMAKE_SOURCE_DIR}/src/api/java/:${CMAKE_BINARY_DIR}/src/api/java/ -d ${JAVADOC_OUTPUT_DIR} -cp ${CVC5_JAR_FILE} + -tag "apiNote:a:Note:" -notimestamp COMMAND find ${JAVADOC_OUTPUT_DIR} -type f -exec sed -i'orig' 's/<!-- Generated by javadoc [^>]* -->//' {} "\;" COMMAND find ${SPHINX_GH_OUTPUT_DIR} -name '*orig' -delete diff --git a/docs/api/java/index.rst b/docs/api/java/index.rst index f805880cc..75d81a090 100644 --- a/docs/api/java/index.rst +++ b/docs/api/java/index.rst @@ -1,4 +1,4 @@ -Java API Documentation +Java API ====================== This documentation was built while Java bindings were disabled. This part of the documentation is empty. Please enable :code:`BUILD_BINDINGS_JAVA` in :code:`cmake` and build the documentation again. diff --git a/docs/api/java/java.rst b/docs/api/java/java.rst new file mode 100644 index 000000000..725e2bf7c --- /dev/null +++ b/docs/api/java/java.rst @@ -0,0 +1,83 @@ +Java API +====================== + +The Java API for cvc5 mostly mirrors the :doc:`C++ API <../cpp/cpp>` and supports operator +overloading, iterators, and exceptions. +There are a few differences from the C++ API, such as using arbitrary-precision integer pairs, +specifically, pairs of Java `BigInteger` objects, to represent rational numbers. +The :doc:`quickstart guide <quickstart>` gives a short introduction, +and more examples can be found `here <../../examples/examples.html>`_. + + +For most applications, the `Solver <io/github/cvc5/api/Solver.html>`_ class is the main entry point to cvc5. +The class hierarchy of `cvc5 package <io/github/cvc5/api/package-summary.html>`_ +provides more details on the individual classes. + +.. toctree:: + :hidden: + + quickstart + API documentation <index> + +Building cvc5 Java API +^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + $ git clone https://github.com/cvc5/cvc5 + $ cd cvc5 + $ ./configure.sh production --java-bindings --auto-download --prefix=build/install + $ cd build + $ make + $ make install + + $ ls install/lib + cmake libcvc5jni.so libcvc5parser.so libcvc5parser.so.1 libcvc5.so + libpicpoly.a libpicpolyxx.a libpoly.so libpoly.so.0 libpoly.so.0.1.9 + libpolyxx.so libpolyxx.so.0 libpolyxx.so.0.1.9 objects-Production + $ ls install/share/java/ + cvc5-0.0.5-dev.jar cvc5.jar + + # compile example QuickStart.java with cvc5 jar file + $ javac -cp "install/share/java/cvc5.jar" ../examples/api/java/QuickStart.java -d . + + # run example QuickStart with cvc5 jar file and cvc5 shared libraries + $ java -cp "install/share/java/cvc5.jar:." "-Djava.library.path=install/lib" QuickStart + expected: sat + result: sat + value for x: 1/6 + value for y: 1/6 + expected: unsat + result: unsat + unsat core size: 3 + unsat core: + (< 0 a) + (< 0 b) + (< (+ a b) 1) + +`Package io.github.cvc5.api <io/github/cvc5/api/package-summary.html>`_ +^^^^^^^^^^^^^^^ + + * class `Datatype <io/github/cvc5/api/Datatype.html>`_ + * class `DatatypeConstructor <io/github/cvc5/api/DatatypeConstructor.html>`_ + * class `DatatypeConstructorDecl <io/github/cvc5/api/DatatypeConstructorDecl.html>`_ + * class `DatatypeDecl <io/github/cvc5/api/DatatypeDecl.html>`_ + * class `DatatypeSelector <io/github/cvc5/api/DatatypeSelector.html>`_ + * class `Grammar <io/github/cvc5/api/Grammar.html>`_ + * class `Op <io/github/cvc5/api/Op.html>`_ + * class `OptionInfo <io/github/cvc5/api/OptionInfo.html>`_ + * class `Pair<K,V> <io/github/cvc5/api/Pair.html>`_ + * class `Result <io/github/cvc5/api/Result.html>`_ + * class `Solver <io/github/cvc5/api/Solver.html>`_ + * class `Sort <io/github/cvc5/api/Sort.html>`_ + * class `Stat <io/github/cvc5/api/Stat.html>`_ + * class `Statistics <io/github/cvc5/api/Statistics.html>`_ + * class `Term <io/github/cvc5/api/Term.html>`_ + * class `Triplet<A,B,C> <io/github/cvc5/api/Triplet.html>`_ + * class `Utils <io/github/cvc5/api/Utils.html>`_ + * enum `Kind <io/github/cvc5/api/Kind.html>`_ + * enum `Result.UnknownExplanation <io/github/cvc5/api/Result.UnknownExplanation.html>`_ + * enum `RoundingMode <io/github/cvc5/api/RoundingMode.html>`_ + * exception `CVC5ApiException <io/github/cvc5/api/CVC5ApiException.html>`_ + * exception `CVC5ApiOptionException <io/github/cvc5/api/CVC5ApiOptionException.html>`_ + * exception `CVC5ApiRecoverableException <io/github/cvc5/api/CVC5ApiRecoverableException.html>`_ diff --git a/docs/api/java/quickstart.rst b/docs/api/java/quickstart.rst new file mode 100644 index 000000000..2c986ab55 --- /dev/null +++ b/docs/api/java/quickstart.rst @@ -0,0 +1,191 @@ +Quickstart Guide +================ + +First, create a cvc5 `Solver <io/github/cvc5/api/Solver.html>`_ +instance using try with resources: + +.. code-block:: java + + try (Solver solver = new Solver()) + { + /** write your code here */ + } + +To produce models and unsat cores, we have to enable the following options. + +.. literalinclude:: ../../../examples/api/java/QuickStart.java + :language: java + :lines: 32-33 + :dedent: 6 + +Next we set the logic. +The simplest way to set a logic for the solver is to choose ``"ALL"``. +This enables all logics in the solver. +Alternatively, ``"QF_ALL"`` enables all logics without quantifiers. +To optimize the solver's behavior for a more specific logic, +use the logic name, e.g. ``"QF_BV"`` or ``"QF_AUFBV"``. + +.. literalinclude:: ../../../examples/api/java/QuickStart.java + :language: java + :lines: 42 + :dedent: 6 + +In the following, we will define real and integer constraints. +For this, we first query the solver for the corresponding sorts. + +.. literalinclude:: ../../../examples/api/java/QuickStart.java + :language: java + :lines: 46-47 + :dedent: 6 + +Now, we create two constants ``x`` and ``y`` of sort ``Real``, +and two constants ``a`` and ``b`` of sort ``Integer``. +Notice that these are *symbolic* constants, not actual values. + +.. literalinclude:: ../../../examples/api/java/QuickStart.java + :language: java + :lines: 52-55 + :dedent: 6 + +We define the following constraints regarding ``x`` and ``y``: + +.. math:: + + (0 < x) \wedge (0 < y) \wedge (x + y < 1) \wedge (x \leq y) + +We construct the required terms and assert them as follows: + +.. literalinclude:: ../../../examples/api/java/QuickStart.java + :language: java + :lines: 65-89 + :dedent: 6 + +Now we check if the asserted formula is satisfiable, that is, we check if +there exist values of sort ``Real`` for ``x`` and ``y`` that satisfy all +the constraints. + +.. literalinclude:: ../../../examples/api/java/QuickStart.java + :language: java + :lines: 93 + :dedent: 6 + +The result we get from this satisfiability check is either ``sat``, ``unsat`` +or ``unknown``. +It's status can be queried via +`Result.isSat <io/github/cvc5/api/Result.html#isSat()>`_, +`Result.isUnsat <io/github/cvc5/api/Result.html#isUnsat()>`_ and +`Result.isSatUnknown <io/github/cvc5/api/Result.html#isSatUnknown()>`_. +Alternatively, it can also be printed. + +.. literalinclude:: ../../../examples/api/java/QuickStart.java + :language: java + :lines: 97-98 + :dedent: 6 + +This will print: + +.. code:: text + + expected: sat + result: sat + +Now, we query the solver for the values for ``x`` and ``y`` that satisfy +the constraints. + +.. literalinclude:: ../../../examples/api/java/QuickStart.java + :language: java + :lines: 101-102 + :dedent: 6 + +It is also possible to get values for terms that do not appear in the original +formula. + +.. literalinclude:: ../../../examples/api/java/QuickStart.java + :language: java + :lines: 106-107 + :dedent: 6 + +We can convert these values to Java types. + +.. literalinclude:: ../../../examples/api/java/QuickStart.java + :language: java + :lines: 109-116 + :dedent: 6 + +Another way to independently compute the value of ``x - y`` would be to +perform the (rational) arithmetic manually. +However, for more complex terms, it is easier to let the solver do the +evaluation. + +.. literalinclude:: ../../../examples/api/java/QuickStart.java + :language: java + :lines: 122-134 + :dedent: 6 + +This will print: + +.. code:: text + + computed correctly + +Next, we will check satisfiability of the same formula, +only this time over integer variables ``a`` and ``b``. +For this, we first reset the assertions added to the solver. + +.. literalinclude:: ../../../examples/api/java/QuickStart.java + :language: java + :lines: 140 + :dedent: 6 + +Next, we assert the same assertions as above, but with integers. +This time, we inline the construction of terms +in the assertion command. + +.. literalinclude:: ../../../examples/api/java/QuickStart.java + :language: java + :lines: 145-149 + :dedent: 6 + +Now, we check whether the revised assertion is satisfiable. + +.. literalinclude:: ../../../examples/api/java/QuickStart.java + :language: java + :lines: 152-156 + :dedent: 6 + +This time the asserted formula is unsatisfiable: + +.. code:: text + + expected: unsat + result: unsat + +We can query the solver for an unsatisfiable core, that is, a subset +of the assertions that is already unsatisfiable. + +.. literalinclude:: ../../../examples/api/java/QuickStart.java + :language: java + :lines: 160-166 + :dedent: 6 + +This will print: + +.. code:: text + + unsat core size: 3 + unsat core: + (< 0 a) + (< 0 b) + (< (+ a b) 1) + +Example +------- + +| The SMT-LIB input for this example can be found at `examples/api/smtlib/quickstart.smt2 <https://github.com/cvc5/cvc5/blob/master/examples/api/smtlib/quickstart.smt2>`_. +| The source code for this example can be found at `examples/api/java/QuickStart.java <https://github.com/cvc5/cvc5/blob/master/examples/api/java/QuickStart.java>`_. + +.. api-examples:: + <examples>/api/java/QuickStart.java + <examples>/api/cpp/quickstart.cpp + <examples>/api/python/quickstart.py + <examples>/api/smtlib/quickstart.smt2 diff --git a/docs/api/python/python.rst b/docs/api/python/python.rst index 3697cf579..b3bd865be 100644 --- a/docs/api/python/python.rst +++ b/docs/api/python/python.rst @@ -1,13 +1,6 @@ -Python API Documentation +Python API ======================== -.. toctree:: - :maxdepth: 1 - :hidden: - - z3py compatibility API <z3compat/z3compat> - regular Python API <regular/python> - .. only:: not bindings_python .. warning:: @@ -16,7 +9,13 @@ Python API Documentation cvc5 offers two separate APIs for Python users. The :doc:`regular Python API <regular/python>` is an almost exact copy of the :doc:`C++ API <../cpp/cpp>`. -Alternatively, the :doc:`z3py compatibility API <z3compat/z3compat>` is a more pythonic API that aims to be fully compatible with `Z3s Python API <https://z3prover.github.io/api/html/namespacez3py.html>`_ while adding functionality that Z3 does not support. +Alternatively, the :doc:`z3py compatibility Python API <z3compat/z3compat>` is a more pythonic API that aims to be fully compatible with `Z3s Python API <https://z3prover.github.io/api/html/namespacez3py.html>`_ while adding functionality that Z3 does not support. + +.. toctree:: + :maxdepth: 1 + + z3compat/z3compat + regular/python Which Python API should I use? diff --git a/docs/api/python/regular/kind.rst b/docs/api/python/regular/kind.rst index f2dd8550b..b4be797e0 100644 --- a/docs/api/python/regular/kind.rst +++ b/docs/api/python/regular/kind.rst @@ -2,11 +2,11 @@ Kind ================ Every :py:class:`Term <pycvc5.Term>` has a kind which represents its type, for -example whether it is an equality (:py:obj:`Equal <pycvc5.kinds.Equal>`), a -conjunction (:py:obj:`And <pycvc5.kinds.And>`), or a bit-vector addtion -(:py:obj:`BVAdd <pycvc5.kinds.BVAdd>`). +example whether it is an equality (:py:obj:`Equal <pycvc5.Kind.Equal>`), a +conjunction (:py:obj:`And <pycvc5.Kind.And>`), or a bit-vector addtion +(:py:obj:`BVAdd <pycvc5.Kind.BVAdd>`). The kinds below directly correspond to the enum values of the C++ :cpp:enum:`Kind <cvc5::api::Kind>` enum. -.. autoclass:: pycvc5.kinds +.. autoclass:: pycvc5.Kind :members: :undoc-members: diff --git a/docs/api/python/regular/python.rst b/docs/api/python/regular/python.rst index b054cbe16..84593b17f 100644 --- a/docs/api/python/regular/python.rst +++ b/docs/api/python/regular/python.rst @@ -1,4 +1,4 @@ -Python API Documentation +Regular Python API ======================== .. only:: not bindings_python @@ -8,7 +8,7 @@ Python API Documentation This documentation was built while python bindings were disabled. This part of the documentation is likely either empty or outdated. Please enable :code:`BUILD_BINDINGS_PYTHON` in :code:`cmake` and build the documentation again. .. toctree:: - :maxdepth: 1 + :maxdepth: 2 quickstart datatype diff --git a/docs/api/python/regular/quickstart.rst b/docs/api/python/regular/quickstart.rst index 783bcfd1f..ba3360db8 100644 --- a/docs/api/python/regular/quickstart.rst +++ b/docs/api/python/regular/quickstart.rst @@ -166,7 +166,7 @@ Example ------- | The SMT-LIB input for this example can be found at `examples/api/smtlib/quickstart.smt2 <https://github.com/cvc5/cvc5/blob/master/examples/api/smtlib/quickstart.smt2>`_. -| The source code for this example can be found at `examples/api/python/quickstart.py <https://github.com/cvc5/cvc5/blob/master/examples/api/python/quickstart.cpp>`_. +| The source code for this example can be found at `examples/api/python/quickstart.py <https://github.com/cvc5/cvc5/blob/master/examples/api/python/quickstart.py>`_. .. api-examples:: <examples>/api/cpp/quickstart.cpp diff --git a/docs/api/python/z3compat/z3compat.rst b/docs/api/python/z3compat/z3compat.rst index ad7c8524b..d5a06195d 100644 --- a/docs/api/python/z3compat/z3compat.rst +++ b/docs/api/python/z3compat/z3compat.rst @@ -1,4 +1,4 @@ -z3py compatibility API +z3py compatibility Python API ========================================= .. only:: not bindings_python diff --git a/docs/conf.py.in b/docs/conf.py.in index 453a56aad..37f7adfe8 100644 --- a/docs/conf.py.in +++ b/docs/conf.py.in @@ -46,6 +46,7 @@ extensions = [ 'sphinxcontrib.bibtex', 'sphinxcontrib.programoutput', 'sphinx_tabs.tabs', + 'autoenum', 'examples', 'include_build_file', ] diff --git a/docs/examples/examples.rst b/docs/examples/examples.rst index accdd004f..b9303f1d9 100644 --- a/docs/examples/examples.rst +++ b/docs/examples/examples.rst @@ -8,7 +8,6 @@ input mechanisms. .. toctree:: - :maxdepth: 2 helloworld exceptions diff --git a/docs/ext/autoenum.py b/docs/ext/autoenum.py new file mode 100644 index 000000000..9066a6109 --- /dev/null +++ b/docs/ext/autoenum.py @@ -0,0 +1,41 @@ +import enum +from typing import Any, Optional + +from docutils.statemachine import StringList +from sphinx.application import Sphinx +from sphinx.ext.autodoc import ClassDocumenter, bool_option + + +class EnumDocumenter(ClassDocumenter): + """Adds a custom "documenter" for the autodoc extension. This particular + documenter is internally used for enum values of a ``enum.Enum`` base class. + + This documenter assumes that the enum class injects proper docstrings into + the ``__doc__`` property of every single enum value. + """ + + objtype = 'enum' + directivetype = 'class' + priority = 10 + ClassDocumenter.priority + option_spec = dict(ClassDocumenter.option_spec) + + @classmethod + def can_document_member(cls, member: Any, membername: str, isattr: bool, + parent: Any) -> bool: + """Document instances of (derived classes of) ``enum.Enum``.""" + return isinstance(member, enum.Enum) + + def add_content(self, + more_content: Optional[StringList], + no_docstring: bool = False) -> None: + """Add the docstring for this object.""" + + # overriding this flag prints __doc__ just as we want to. + self.doc_as_attr = False + super().add_content(more_content, no_docstring) + self.doc_as_attr = True + + +def setup(app: Sphinx) -> None: + app.setup_extension('sphinx.ext.autodoc') + app.add_autodocumenter(EnumDocumenter) diff --git a/docs/theories/separation-logic.rst b/docs/theories/separation-logic.rst index 86f802ef8..36d3a165f 100644 --- a/docs/theories/separation-logic.rst +++ b/docs/theories/separation-logic.rst @@ -121,7 +121,7 @@ formula ``(not (emp x 0))`` is satisfied by heaps ``U -> Int`` (the sorts of (check-sat) The following input on heaps ``Int -> Node`` is satisfiable, where ``Node`` -denotes a user-defined inductive `datatypes <datatypes>`__. +denotes a user-defined inductive :doc:`datatypes`. .. code:: smtlib diff --git a/docs/theories/sets-and-relations.rst b/docs/theories/sets-and-relations.rst index 2da6715e3..33c0d4cd0 100644 --- a/docs/theories/sets-and-relations.rst +++ b/docs/theories/sets-and-relations.rst @@ -9,6 +9,7 @@ The simplest way to get a sense of the syntax is to look at an example: .. api-examples:: <examples>/api/cpp/sets.cpp + <examples>/api/java/Sets.java <examples>/api/python/sets.py <examples>/api/smtlib/sets.smt2 @@ -16,7 +17,8 @@ The source code of these examples is available at: * `SMT-LIB 2 language example <https://github.com/cvc5/cvc5/blob/master/examples/api/smtlib/sets.smt2>`__ * `C++ API example <https://github.com/cvc5/cvc5/blob/master/examples/api/cpp/sets.cpp>`__ -* `Python API example <https://github.com/cvc5/cvc5/blob/master/examples/api/python/sets.cpp>`__ +* `Java API example <https://github.com/cvc5/cvc5/blob/master/examples/api/java/Sets.java>`__ +* `Python API example <https://github.com/cvc5/cvc5/blob/master/examples/api/python/sets.py>`__ Below is a short summary of the sorts, constants, functions and diff --git a/docs/theories/transcendentals.rst b/docs/theories/transcendentals.rst index 6d35e6cce..6b76e7b41 100644 --- a/docs/theories/transcendentals.rst +++ b/docs/theories/transcendentals.rst @@ -51,5 +51,6 @@ Examples .. api-examples:: <examples>/api/cpp/transcendentals.cpp + <examples>/api/java/Transcendentals.java <examples>/api/python/transcendentals.py <examples>/api/smtlib/transcendentals.smt2
\ No newline at end of file diff --git a/examples/api/java/QuickStart.java b/examples/api/java/QuickStart.java index a79263cbf..c815278cc 100644 --- a/examples/api/java/QuickStart.java +++ b/examples/api/java/QuickStart.java @@ -106,11 +106,32 @@ public class QuickStart Term xMinusY = solver.mkTerm(Kind.MINUS, x, y); Term xMinusYVal = solver.getValue(xMinusY); - // Further, we can convert the values to java types, - Pair<BigInteger, BigInteger> xRational = xVal.getRealValue(); - Pair<BigInteger, BigInteger> yRational = yVal.getRealValue(); - System.out.println("value for x: " + xRational.first + "/" + xRational.second); - System.out.println("value for y: " + yRational.first + "/" + yRational.second); + // Further, we can convert the values to java types + Pair<BigInteger, BigInteger> xPair = xVal.getRealValue(); + Pair<BigInteger, BigInteger> yPair = yVal.getRealValue(); + Pair<BigInteger, BigInteger> xMinusYPair = xMinusYVal.getRealValue(); + + System.out.println("value for x: " + xPair.first + "/" + xPair.second); + System.out.println("value for y: " + yPair.first + "/" + yPair.second); + System.out.println("value for x - y: " + xMinusYPair.first + "/" + xMinusYPair.second); + + // Another way to independently compute the value of x - y would be + // to perform the (rational) arithmetic manually. + // However, for more complex terms, + // it is easier to let the solver do the evaluation. + Pair<BigInteger, BigInteger> xMinusYComputed = + new Pair(xPair.first.multiply(yPair.second).subtract(xPair.second.multiply(yPair.first)), + xPair.second.multiply(yPair.second)); + BigInteger g = xMinusYComputed.first.gcd(xMinusYComputed.second); + xMinusYComputed = new Pair(xMinusYComputed.first.divide(g), xMinusYComputed.second.divide(g)); + if (xMinusYComputed.equals(xMinusYPair)) + { + System.out.println("computed correctly"); + } + else + { + System.out.println("computed incorrectly"); + } // Next, we will check satisfiability of the same formula, // only this time over integer variables a and b. diff --git a/examples/api/java/Relations.java b/examples/api/java/Relations.java index a3e2b2a7e..95aede591 100644 --- a/examples/api/java/Relations.java +++ b/examples/api/java/Relations.java @@ -152,10 +152,9 @@ public class Relations Term transpose = solver.mkTerm(RELATION_TRANSPOSE, descendant); Term ancestorFormula = solver.mkTerm(EQUAL, ancestor, transpose); - // (assert (forall ((x Person)) (not (set.member (mkTuple x x) ancestor)))) + // (assert (forall ((x Person)) (not (set.member (tuple x x) ancestor)))) Term x = solver.mkVar(personSort, "x"); - DatatypeConstructor constructor = tupleArity2.getDatatype().getConstructor(0); - Term xxTuple = solver.mkTerm(APPLY_CONSTRUCTOR, constructor.getConstructorTerm(), x, x); + Term xxTuple = solver.mkTuple(new Sort[]{personSort, personSort}, new Term[] {x, x}); Term member = solver.mkTerm(SET_MEMBER, xxTuple, ancestor); Term notMember = solver.mkTerm(NOT, member); diff --git a/examples/api/python/bitvectors.py b/examples/api/python/bitvectors.py index ff99bd785..e785fd790 100644 --- a/examples/api/python/bitvectors.py +++ b/examples/api/python/bitvectors.py @@ -17,7 +17,7 @@ ## import pycvc5 -from pycvc5 import kinds +from pycvc5 import Kind if __name__ == "__main__": slv = pycvc5.Solver() @@ -50,9 +50,9 @@ if __name__ == "__main__": b = slv.mkConst(bitvector32, "b") # First encode the assumption that x must be equal to a or b - x_eq_a = slv.mkTerm(kinds.Equal, x, a) - x_eq_b = slv.mkTerm(kinds.Equal, x, b) - assumption = slv.mkTerm(kinds.Or, x_eq_a, x_eq_b) + x_eq_a = slv.mkTerm(Kind.Equal, x, a) + x_eq_b = slv.mkTerm(Kind.Equal, x, b) + assumption = slv.mkTerm(Kind.Or, x_eq_a, x_eq_b) # Assert the assumption slv.assertFormula(assumption) @@ -65,8 +65,8 @@ if __name__ == "__main__": # Encoding code (0) # new_x = x == a ? b : a - ite = slv.mkTerm(kinds.Ite, x_eq_a, b, a) - assignment0 = slv.mkTerm(kinds.Equal, new_x, ite) + ite = slv.mkTerm(Kind.Ite, x_eq_a, b, a) + assignment0 = slv.mkTerm(Kind.Equal, new_x, ite) # Assert the encoding of code (0) print("Asserting {} to cvc5".format(assignment0)) @@ -76,13 +76,13 @@ if __name__ == "__main__": # Encoding code (1) # new_x_ = a xor b xor x - a_xor_b_xor_x = slv.mkTerm(kinds.BVXor, a, b, x) - assignment1 = slv.mkTerm(kinds.Equal, new_x_, a_xor_b_xor_x) + a_xor_b_xor_x = slv.mkTerm(Kind.BVXor, a, b, x) + assignment1 = slv.mkTerm(Kind.Equal, new_x_, a_xor_b_xor_x) # Assert encoding to cvc5 in current context print("Asserting {} to cvc5".format(assignment1)) slv.assertFormula(assignment1) - new_x_eq_new_x_ = slv.mkTerm(kinds.Equal, new_x, new_x_) + new_x_eq_new_x_ = slv.mkTerm(Kind.Equal, new_x, new_x_) print("Checking entailment assuming:", new_x_eq_new_x_) print("Expect ENTAILED.") @@ -92,9 +92,9 @@ if __name__ == "__main__": # Encoding code (2) # new_x_ = a + b - x - a_plus_b = slv.mkTerm(kinds.BVAdd, a, b) - a_plus_b_minus_x = slv.mkTerm(kinds.BVSub, a_plus_b, x) - assignment2 = slv.mkTerm(kinds.Equal, new_x_, a_plus_b_minus_x) + a_plus_b = slv.mkTerm(Kind.BVAdd, a, b) + a_plus_b_minus_x = slv.mkTerm(Kind.BVSub, a_plus_b, x) + assignment2 = slv.mkTerm(Kind.Equal, new_x_, a_plus_b_minus_x) # Assert encoding to cvc5 in current context print("Asserting {} to cvc5".format(assignment2)) @@ -105,17 +105,17 @@ if __name__ == "__main__": print("cvc5:", slv.checkEntailed(new_x_eq_new_x_)) - x_neq_x = slv.mkTerm(kinds.Equal, x, x).notTerm() + x_neq_x = slv.mkTerm(Kind.Equal, x, x).notTerm() v = [new_x_eq_new_x_, x_neq_x] print("Check entailment assuming: ", v) print("Expect NOT_ENTAILED.") print("cvc5:", slv.checkEntailed(v)) # Assert that a is odd - extract_op = slv.mkOp(kinds.BVExtract, 0, 0) + extract_op = slv.mkOp(Kind.BVExtract, 0, 0) lsb_of_a = slv.mkTerm(extract_op, a) print("Sort of {} is {}".format(lsb_of_a, lsb_of_a.getSort())) - a_odd = slv.mkTerm(kinds.Equal, lsb_of_a, slv.mkBitVector(1, 1)) + a_odd = slv.mkTerm(Kind.Equal, lsb_of_a, slv.mkBitVector(1, 1)) print("Assert", a_odd) print("Check satisifiability") slv.assertFormula(a_odd) diff --git a/examples/api/python/bitvectors_and_arrays.py b/examples/api/python/bitvectors_and_arrays.py index be38077ca..d3c8caf75 100644 --- a/examples/api/python/bitvectors_and_arrays.py +++ b/examples/api/python/bitvectors_and_arrays.py @@ -17,7 +17,7 @@ ## import pycvc5 -from pycvc5 import kinds +from pycvc5 import Kind import math @@ -58,29 +58,29 @@ if __name__ == "__main__": constarr0 = slv.mkConstArray(arraySort, slv.mkBitVector(32, 0)) # Asserting that current_array[0] > 0 - current_array0 = slv.mkTerm(kinds.Select, current_array, zero) - current_array0_gt_0 = slv.mkTerm(kinds.BVSgt, + current_array0 = slv.mkTerm(Kind.Select, current_array, zero) + current_array0_gt_0 = slv.mkTerm(Kind.BVSgt, current_array0, slv.mkBitVector(32, 0)) slv.assertFormula(current_array0_gt_0) # Building the assertions in the loop unrolling index = slv.mkBitVector(index_size, 0) - old_current = slv.mkTerm(kinds.Select, current_array, index) + old_current = slv.mkTerm(Kind.Select, current_array, index) two = slv.mkBitVector(32, 2) assertions = [] for i in range(1, k): index = slv.mkBitVector(index_size, i) - new_current = slv.mkTerm(kinds.BVMult, two, old_current) + new_current = slv.mkTerm(Kind.BVMult, two, old_current) # current[i] = 2*current[i-1] - current_array = slv.mkTerm(kinds.Store, current_array, index, new_current) + current_array = slv.mkTerm(Kind.Store, current_array, index, new_current) # current[i-1] < current[i] - current_slt_new_current = slv.mkTerm(kinds.BVSlt, old_current, new_current) + current_slt_new_current = slv.mkTerm(Kind.BVSlt, old_current, new_current) assertions.append(current_slt_new_current) - old_current = slv.mkTerm(kinds.Select, current_array, index) + old_current = slv.mkTerm(Kind.Select, current_array, index) - query = slv.mkTerm(kinds.Not, slv.mkTerm(kinds.And, assertions)) + query = slv.mkTerm(Kind.Not, slv.mkTerm(Kind.And, assertions)) print("Asserting {} to cvc5".format(query)) slv.assertFormula(query) diff --git a/examples/api/python/combination.py b/examples/api/python/combination.py index 990149434..bceb7e738 100644 --- a/examples/api/python/combination.py +++ b/examples/api/python/combination.py @@ -17,7 +17,7 @@ ## import pycvc5 -from pycvc5 import kinds +from pycvc5 import Kind def prefixPrintGetValue(slv, t, level=0): print("slv.getValue({}): {}".format(t, slv.getValue(t))) @@ -51,18 +51,18 @@ if __name__ == "__main__": one = slv.mkInteger(1) # Terms - f_x = slv.mkTerm(kinds.ApplyUf, f, x) - f_y = slv.mkTerm(kinds.ApplyUf, f, y) - sum_ = slv.mkTerm(kinds.Plus, f_x, f_y) - p_0 = slv.mkTerm(kinds.ApplyUf, p, zero) - p_f_y = slv.mkTerm(kinds.ApplyUf, p, f_y) + f_x = slv.mkTerm(Kind.ApplyUf, f, x) + f_y = slv.mkTerm(Kind.ApplyUf, f, y) + sum_ = slv.mkTerm(Kind.Plus, f_x, f_y) + p_0 = slv.mkTerm(Kind.ApplyUf, p, zero) + p_f_y = slv.mkTerm(Kind.ApplyUf, p, f_y) # Construct the assertions - assertions = slv.mkTerm(kinds.And, + assertions = slv.mkTerm(Kind.And, [ - slv.mkTerm(kinds.Leq, zero, f_x), # 0 <= f(x) - slv.mkTerm(kinds.Leq, zero, f_y), # 0 <= f(y) - slv.mkTerm(kinds.Leq, sum_, one), # f(x) + f(y) <= 1 + slv.mkTerm(Kind.Leq, zero, f_x), # 0 <= f(x) + slv.mkTerm(Kind.Leq, zero, f_y), # 0 <= f(y) + slv.mkTerm(Kind.Leq, sum_, one), # f(x) + f(y) <= 1 p_0.notTerm(), # not p(0) p_f_y # p(f(y)) ]) @@ -71,7 +71,7 @@ if __name__ == "__main__": print("Given the following assertions:", assertions, "\n") print("Prove x /= y is entailed.\ncvc5: ", - slv.checkEntailed(slv.mkTerm(kinds.Distinct, x, y)), "\n") + slv.checkEntailed(slv.mkTerm(Kind.Distinct, x, y)), "\n") print("Call checkSat to show that the assertions are satisfiable") print("cvc5:", slv.checkSat(), "\n") diff --git a/examples/api/python/datatypes.py b/examples/api/python/datatypes.py index 96116da08..cc4ca719a 100644 --- a/examples/api/python/datatypes.py +++ b/examples/api/python/datatypes.py @@ -17,7 +17,7 @@ ## import pycvc5 -from pycvc5 import kinds +from pycvc5 import Kind def test(slv, consListSort): # Now our old "consListSpec" is useless--the relevant information @@ -34,9 +34,9 @@ def test(slv, consListSort): # which is equivalent to consList["cons"].getConstructor(). Note that # "nil" is a constructor too - t = slv.mkTerm(kinds.ApplyConstructor, consList.getConstructorTerm("cons"), + t = slv.mkTerm(Kind.ApplyConstructor, consList.getConstructorTerm("cons"), slv.mkInteger(0), - slv.mkTerm(kinds.ApplyConstructor, consList.getConstructorTerm("nil"))) + slv.mkTerm(Kind.ApplyConstructor, consList.getConstructorTerm("nil"))) print("t is {}\nsort of cons is {}\n sort of nil is {}".format( t, @@ -49,7 +49,7 @@ def test(slv, consListSort): # consList["cons"]) in order to get the "head" selector symbol # to apply. - t2 = slv.mkTerm(kinds.ApplySelector, consList["cons"].getSelectorTerm("head"), t) + t2 = slv.mkTerm(Kind.ApplySelector, consList["cons"].getSelectorTerm("head"), t) print("t2 is {}\nsimplify(t2) is {}\n\n".format(t2, slv.simplify(t2))) @@ -63,16 +63,16 @@ def test(slv, consListSort): # You can also define a tester term for constructor 'cons': (_ is cons) t_is_cons = slv.mkTerm( - kinds.ApplyTester, consList["cons"].getTesterTerm(), t) + Kind.ApplyTester, consList["cons"].getTesterTerm(), t) print("t_is_cons is {}\n\n".format(t_is_cons)) slv.assertFormula(t_is_cons) # Updating t at 'head' with value 1 is defined as follows: - t_updated = slv.mkTerm(kinds.ApplyUpdater, + t_updated = slv.mkTerm(Kind.ApplyUpdater, consList["cons"]["head"].getUpdaterTerm(), t, slv.mkInteger(1)) print("t_updated is {}\n\n".format(t_updated)) - slv.assertFormula(slv.mkTerm(kinds.Distinct, t, t_updated)) + slv.assertFormula(slv.mkTerm(Kind.Distinct, t, t_updated)) # You can also define parameterized datatypes. # This example builds a simple parameterized list of sort T, with one @@ -93,11 +93,11 @@ def test(slv, consListSort): a = slv.mkConst(paramConsIntListSort, "a") print("term {} is of sort {}".format(a, a.getSort())) - head_a = slv.mkTerm(kinds.ApplySelector, paramConsList["cons"].getSelectorTerm("head"), a) + head_a = slv.mkTerm(Kind.ApplySelector, paramConsList["cons"].getSelectorTerm("head"), a) print("head_a is {} of sort {}".format(head_a, head_a.getSort())) print("sort of cons is", paramConsList.getConstructorTerm("cons").getSort()) - assertion = slv.mkTerm(kinds.Gt, head_a, slv.mkInteger(50)) + assertion = slv.mkTerm(Kind.Gt, head_a, slv.mkInteger(50)) print("Assert", assertion) slv.assertFormula(assertion) print("Expect sat.") diff --git a/examples/api/python/exceptions.py b/examples/api/python/exceptions.py index a4597d12b..dcfff09e4 100644 --- a/examples/api/python/exceptions.py +++ b/examples/api/python/exceptions.py @@ -17,7 +17,7 @@ ## import pycvc5 -from pycvc5 import kinds +from pycvc5 import Kind import sys diff --git a/examples/api/python/extract.py b/examples/api/python/extract.py index 4e7026e97..fa7350285 100644 --- a/examples/api/python/extract.py +++ b/examples/api/python/extract.py @@ -16,8 +16,7 @@ # extract-new.cpp. ## -from pycvc5 import Solver -from pycvc5.kinds import BVExtract, Equal +from pycvc5 import Solver, Kind if __name__ == "__main__": slv = Solver() @@ -27,26 +26,26 @@ if __name__ == "__main__": x = slv.mkConst(bitvector32, "a") - ext_31_1 = slv.mkOp(BVExtract, 31, 1) + ext_31_1 = slv.mkOp(Kind.BVExtract, 31, 1) x_31_1 = slv.mkTerm(ext_31_1, x) - ext_30_0 = slv.mkOp(BVExtract, 30, 0) + ext_30_0 = slv.mkOp(Kind.BVExtract, 30, 0) x_30_0 = slv.mkTerm(ext_30_0, x) - ext_31_31 = slv.mkOp(BVExtract, 31, 31) + ext_31_31 = slv.mkOp(Kind.BVExtract, 31, 31) x_31_31 = slv.mkTerm(ext_31_31, x) - ext_0_0 = slv.mkOp(BVExtract, 0, 0) + ext_0_0 = slv.mkOp(Kind.BVExtract, 0, 0) x_0_0 = slv.mkTerm(ext_0_0, x) # test getting indices assert ext_30_0.getIndices() == (30, 0) - eq = slv.mkTerm(Equal, x_31_1, x_30_0) + eq = slv.mkTerm(Kind.Equal, x_31_1, x_30_0) print("Asserting:", eq) slv.assertFormula(eq) - eq2 = slv.mkTerm(Equal, x_31_31, x_0_0) + eq2 = slv.mkTerm(Kind.Equal, x_31_31, x_0_0) print("Check entailment assuming:", eq2) print("Expect ENTAILED") print("cvc5:", slv.checkEntailed(eq2)) diff --git a/examples/api/python/floating_point.py b/examples/api/python/floating_point.py index d6ba8d754..29f0d16d7 100644 --- a/examples/api/python/floating_point.py +++ b/examples/api/python/floating_point.py @@ -17,7 +17,7 @@ ## import pycvc5 -from pycvc5 import kinds +from pycvc5 import Kind if __name__ == "__main__": slv = pycvc5.Solver() @@ -37,10 +37,10 @@ if __name__ == "__main__": z = slv.mkConst(fp32, 'z') # check floating-point arithmetic is commutative, i.e. x + y == y + x - commutative = slv.mkTerm(kinds.FPEq, slv.mkTerm(kinds.FPAdd, rm, x, y), slv.mkTerm(kinds.FPAdd, rm, y, x)) + commutative = slv.mkTerm(Kind.FPEq, slv.mkTerm(Kind.FPAdd, rm, x, y), slv.mkTerm(Kind.FPAdd, rm, y, x)) slv.push() - slv.assertFormula(slv.mkTerm(kinds.Not, commutative)) + slv.assertFormula(slv.mkTerm(Kind.Not, commutative)) print("Checking floating-point commutativity") print("Expect SAT (property does not hold for NaN and Infinities).") print("cvc5:", slv.checkSat()) @@ -48,10 +48,10 @@ if __name__ == "__main__": print("Model for y:", slv.getValue(y)) # disallow NaNs and Infinities - slv.assertFormula(slv.mkTerm(kinds.Not, slv.mkTerm(kinds.FPIsNan, x))) - slv.assertFormula(slv.mkTerm(kinds.Not, slv.mkTerm(kinds.FPIsInf, x))) - slv.assertFormula(slv.mkTerm(kinds.Not, slv.mkTerm(kinds.FPIsNan, y))) - slv.assertFormula(slv.mkTerm(kinds.Not, slv.mkTerm(kinds.FPIsInf, y))) + slv.assertFormula(slv.mkTerm(Kind.Not, slv.mkTerm(Kind.FPIsNan, x))) + slv.assertFormula(slv.mkTerm(Kind.Not, slv.mkTerm(Kind.FPIsInf, x))) + slv.assertFormula(slv.mkTerm(Kind.Not, slv.mkTerm(Kind.FPIsNan, y))) + slv.assertFormula(slv.mkTerm(Kind.Not, slv.mkTerm(Kind.FPIsInf, y))) print("Checking floating-point commutativity assuming x and y are not NaN or Infinity") print("Expect UNSAT.") @@ -70,15 +70,15 @@ if __name__ == "__main__": 24, slv.mkBitVector(32, "01000000010010001111010111000011", 2)) # 3.14 - bounds_x = slv.mkTerm(kinds.And, slv.mkTerm(kinds.FPLeq, a, x), slv.mkTerm(kinds.FPLeq, x, b)) - bounds_y = slv.mkTerm(kinds.And, slv.mkTerm(kinds.FPLeq, a, y), slv.mkTerm(kinds.FPLeq, y, b)) - bounds_z = slv.mkTerm(kinds.And, slv.mkTerm(kinds.FPLeq, a, z), slv.mkTerm(kinds.FPLeq, z, b)) - slv.assertFormula(slv.mkTerm(kinds.And, slv.mkTerm(kinds.And, bounds_x, bounds_y), bounds_z)) + bounds_x = slv.mkTerm(Kind.And, slv.mkTerm(Kind.FPLeq, a, x), slv.mkTerm(Kind.FPLeq, x, b)) + bounds_y = slv.mkTerm(Kind.And, slv.mkTerm(Kind.FPLeq, a, y), slv.mkTerm(Kind.FPLeq, y, b)) + bounds_z = slv.mkTerm(Kind.And, slv.mkTerm(Kind.FPLeq, a, z), slv.mkTerm(Kind.FPLeq, z, b)) + slv.assertFormula(slv.mkTerm(Kind.And, slv.mkTerm(Kind.And, bounds_x, bounds_y), bounds_z)) # (x + y) + z == x + (y + z) - lhs = slv.mkTerm(kinds.FPAdd, rm, slv.mkTerm(kinds.FPAdd, rm, x, y), z) - rhs = slv.mkTerm(kinds.FPAdd, rm, x, slv.mkTerm(kinds.FPAdd, rm, y, z)) - associative = slv.mkTerm(kinds.Not, slv.mkTerm(kinds.FPEq, lhs, rhs)) + lhs = slv.mkTerm(Kind.FPAdd, rm, slv.mkTerm(Kind.FPAdd, rm, x, y), z) + rhs = slv.mkTerm(Kind.FPAdd, rm, x, slv.mkTerm(Kind.FPAdd, rm, y, z)) + associative = slv.mkTerm(Kind.Not, slv.mkTerm(Kind.FPEq, lhs, rhs)) slv.assertFormula(associative) diff --git a/examples/api/python/helloworld.py b/examples/api/python/helloworld.py index 6e6ce32ab..b437efc86 100644 --- a/examples/api/python/helloworld.py +++ b/examples/api/python/helloworld.py @@ -15,7 +15,7 @@ ## import pycvc5 -from pycvc5 import kinds +from pycvc5 import Kind if __name__ == "__main__": slv = pycvc5.Solver() diff --git a/examples/api/python/id.py b/examples/api/python/id.py index fb3672dbc..c7a2ed0bc 100644 --- a/examples/api/python/id.py +++ b/examples/api/python/id.py @@ -16,7 +16,6 @@ ## import pycvc5 -from pycvc5 import kinds if __name__ == "__main__": slv = pycvc5.Solver() diff --git a/examples/api/python/linear_arith.py b/examples/api/python/linear_arith.py index f8dad6a71..a2f303a5d 100644 --- a/examples/api/python/linear_arith.py +++ b/examples/api/python/linear_arith.py @@ -17,7 +17,7 @@ ## import pycvc5 -from pycvc5 import kinds +from pycvc5 import Kind if __name__ == "__main__": slv = pycvc5.Solver() @@ -40,21 +40,21 @@ if __name__ == "__main__": two_thirds = slv.mkReal(2, 3) # Terms - three_y = slv.mkTerm(kinds.Mult, three, y) - diff = slv.mkTerm(kinds.Minus, y, x) + three_y = slv.mkTerm(Kind.Mult, three, y) + diff = slv.mkTerm(Kind.Minus, y, x) # Formulas - x_geq_3y = slv.mkTerm(kinds.Geq, x, three_y) - x_leq_y = slv.mkTerm(kinds.Leq, x ,y) - neg2_lt_x = slv.mkTerm(kinds.Lt, neg2, x) + x_geq_3y = slv.mkTerm(Kind.Geq, x, three_y) + x_leq_y = slv.mkTerm(Kind.Leq, x ,y) + neg2_lt_x = slv.mkTerm(Kind.Lt, neg2, x) - assertions = slv.mkTerm(kinds.And, x_geq_3y, x_leq_y, neg2_lt_x) + assertions = slv.mkTerm(Kind.And, x_geq_3y, x_leq_y, neg2_lt_x) print("Given the assertions", assertions) slv.assertFormula(assertions) slv.push() - diff_leq_two_thirds = slv.mkTerm(kinds.Leq, diff, two_thirds) + diff_leq_two_thirds = slv.mkTerm(Kind.Leq, diff, two_thirds) print("Prove that", diff_leq_two_thirds, "with cvc5") print("cvc5 should report ENTAILED") print("Result from cvc5 is:", @@ -64,7 +64,7 @@ if __name__ == "__main__": print() slv.push() - diff_is_two_thirds = slv.mkTerm(kinds.Equal, diff, two_thirds) + diff_is_two_thirds = slv.mkTerm(Kind.Equal, diff, two_thirds) slv.assertFormula(diff_is_two_thirds) print("Show that the assertions are consistent with\n", diff_is_two_thirds, "with cvc5") print("cvc5 should report SAT") diff --git a/examples/api/python/quickstart.py b/examples/api/python/quickstart.py index 389e08be1..8261b3d70 100644 --- a/examples/api/python/quickstart.py +++ b/examples/api/python/quickstart.py @@ -15,7 +15,7 @@ ## import pycvc5 -from pycvc5 import kinds +from pycvc5 import Kind if __name__ == "__main__": # Create a solver @@ -64,15 +64,15 @@ if __name__ == "__main__": one = solver.mkReal(1); # Next, we construct the term x + y - xPlusY = solver.mkTerm(kinds.Plus, x, y); + xPlusY = solver.mkTerm(Kind.Plus, x, y); # Now we can define the constraints. # They use the operators +, <=, and <. # In the API, these are denoted by Plus, Leq, and Lt. - constraint1 = solver.mkTerm(kinds.Lt, zero, x); - constraint2 = solver.mkTerm(kinds.Lt, zero, y); - constraint3 = solver.mkTerm(kinds.Lt, xPlusY, one); - constraint4 = solver.mkTerm(kinds.Leq, x, y); + constraint1 = solver.mkTerm(Kind.Lt, zero, x); + constraint2 = solver.mkTerm(Kind.Lt, zero, y); + constraint3 = solver.mkTerm(Kind.Lt, xPlusY, one); + constraint4 = solver.mkTerm(Kind.Leq, x, y); # Now we assert the constraints to the solver. solver.assertFormula(constraint1); @@ -95,7 +95,7 @@ if __name__ == "__main__": # It is also possible to get values for compound terms, # even if those did not appear in the original formula. - xMinusY = solver.mkTerm(kinds.Minus, x, y); + xMinusY = solver.mkTerm(Kind.Minus, x, y); xMinusYVal = solver.getValue(xMinusY); # We can now obtain the values as python values @@ -132,11 +132,11 @@ if __name__ == "__main__": # Next, we assert the same assertions above with integers. # This time, we inline the construction of terms # to the assertion command. - solver.assertFormula(solver.mkTerm(kinds.Lt, solver.mkInteger(0), a)); - solver.assertFormula(solver.mkTerm(kinds.Lt, solver.mkInteger(0), b)); + solver.assertFormula(solver.mkTerm(Kind.Lt, solver.mkInteger(0), a)); + solver.assertFormula(solver.mkTerm(Kind.Lt, solver.mkInteger(0), b)); solver.assertFormula( - solver.mkTerm(kinds.Lt, solver.mkTerm(kinds.Plus, a, b), solver.mkInteger(1))); - solver.assertFormula(solver.mkTerm(kinds.Leq, a, b)); + solver.mkTerm(Kind.Lt, solver.mkTerm(Kind.Plus, a, b), solver.mkInteger(1))); + solver.assertFormula(solver.mkTerm(Kind.Leq, a, b)); # We check whether the revised assertion is satisfiable. r2 = solver.checkSat(); diff --git a/examples/api/python/sequences.py b/examples/api/python/sequences.py index f9fd925fb..66a4c1353 100644 --- a/examples/api/python/sequences.py +++ b/examples/api/python/sequences.py @@ -16,7 +16,7 @@ ## import pycvc5 -from pycvc5 import kinds +from pycvc5 import Kind if __name__ == "__main__": slv = pycvc5.Solver() @@ -39,18 +39,18 @@ if __name__ == "__main__": # Empty sequence empty = slv.mkEmptySequence(slv.getIntegerSort()) # Sequence concatenation: x.y.empty - concat = slv.mkTerm(kinds.SeqConcat, x, y, empty) + concat = slv.mkTerm(Kind.SeqConcat, x, y, empty) # Sequence length: |x.y.empty| - concat_len = slv.mkTerm(kinds.SeqLength, concat) + concat_len = slv.mkTerm(Kind.SeqLength, concat) # |x.y.empty| > 1 - formula1 = slv.mkTerm(kinds.Gt, concat_len, slv.mkInteger(1)) + formula1 = slv.mkTerm(Kind.Gt, concat_len, slv.mkInteger(1)) # Sequence unit: seq(1) - unit = slv.mkTerm(kinds.SeqUnit, slv.mkInteger(1)) + unit = slv.mkTerm(Kind.SeqUnit, slv.mkInteger(1)) # x = seq(1) - formula2 = slv.mkTerm(kinds.Equal, x, unit) + formula2 = slv.mkTerm(Kind.Equal, x, unit) # Make a query - q = slv.mkTerm(kinds.And, formula1, formula2) + q = slv.mkTerm(Kind.And, formula1, formula2) # Check satisfiability result = slv.checkSatAssuming(q) diff --git a/examples/api/python/sets.py b/examples/api/python/sets.py index 31f20dfeb..4bd6c4029 100644 --- a/examples/api/python/sets.py +++ b/examples/api/python/sets.py @@ -16,7 +16,7 @@ ## import pycvc5 -from pycvc5 import kinds +from pycvc5 import Kind if __name__ == "__main__": slv = pycvc5.Solver() @@ -39,14 +39,14 @@ if __name__ == "__main__": B = slv.mkConst(set_, "B") C = slv.mkConst(set_, "C") - unionAB = slv.mkTerm(kinds.SetUnion, A, B) - lhs = slv.mkTerm(kinds.SetInter, unionAB, C) + unionAB = slv.mkTerm(Kind.SetUnion, A, B) + lhs = slv.mkTerm(Kind.SetInter, unionAB, C) - intersectionAC = slv.mkTerm(kinds.SetInter, A, C) - intersectionBC = slv.mkTerm(kinds.SetInter, B, C) - rhs = slv.mkTerm(kinds.SetUnion, intersectionAC, intersectionBC) + intersectionAC = slv.mkTerm(Kind.SetInter, A, C) + intersectionBC = slv.mkTerm(Kind.SetInter, B, C) + rhs = slv.mkTerm(Kind.SetUnion, intersectionAC, intersectionBC) - theorem = slv.mkTerm(kinds.Equal, lhs, rhs) + theorem = slv.mkTerm(Kind.Equal, lhs, rhs) print("cvc5 reports: {} is {}".format(theorem, slv.checkEntailed(theorem))) @@ -56,7 +56,7 @@ if __name__ == "__main__": A = slv.mkConst(set_, "A") emptyset = slv.mkEmptySet(set_) - theorem = slv.mkTerm(kinds.SetSubset, emptyset, A) + theorem = slv.mkTerm(Kind.SetSubset, emptyset, A) print("cvc5 reports: {} is {}".format(theorem, slv.checkEntailed(theorem))) @@ -67,16 +67,16 @@ if __name__ == "__main__": two = slv.mkInteger(2) three = slv.mkInteger(3) - singleton_one = slv.mkTerm(kinds.SetSingleton, one) - singleton_two = slv.mkTerm(kinds.SetSingleton, two) - singleton_three = slv.mkTerm(kinds.SetSingleton, three) - one_two = slv.mkTerm(kinds.SetUnion, singleton_one, singleton_two) - two_three = slv.mkTerm(kinds.SetUnion, singleton_two, singleton_three) - intersection = slv.mkTerm(kinds.SetInter, one_two, two_three) + singleton_one = slv.mkTerm(Kind.SetSingleton, one) + singleton_two = slv.mkTerm(Kind.SetSingleton, two) + singleton_three = slv.mkTerm(Kind.SetSingleton, three) + one_two = slv.mkTerm(Kind.SetUnion, singleton_one, singleton_two) + two_three = slv.mkTerm(Kind.SetUnion, singleton_two, singleton_three) + intersection = slv.mkTerm(Kind.SetInter, one_two, two_three) x = slv.mkConst(integer, "x") - e = slv.mkTerm(kinds.SetMember, x, intersection) + e = slv.mkTerm(Kind.SetMember, x, intersection) result = slv.checkSatAssuming(e) diff --git a/examples/api/python/strings.py b/examples/api/python/strings.py index 64ce06548..c1087eaac 100644 --- a/examples/api/python/strings.py +++ b/examples/api/python/strings.py @@ -16,7 +16,7 @@ ## import pycvc5 -from pycvc5 import kinds +from pycvc5 import Kind if __name__ == "__main__": slv = pycvc5.Solver() @@ -43,38 +43,38 @@ if __name__ == "__main__": z = slv.mkConst(string, "z") # String concatenation: x.ab.y - lhs = slv.mkTerm(kinds.StringConcat, x, ab, y) + lhs = slv.mkTerm(Kind.StringConcat, x, ab, y) # String concatenation: abc.z - rhs = slv.mkTerm(kinds.StringConcat, abc, z) + rhs = slv.mkTerm(Kind.StringConcat, abc, z) # x.ab.y = abc.z - formula1 = slv.mkTerm(kinds.Equal, lhs, rhs) + formula1 = slv.mkTerm(Kind.Equal, lhs, rhs) # Length of y: |y| - leny = slv.mkTerm(kinds.StringLength, y) + leny = slv.mkTerm(Kind.StringLength, y) # |y| >= 0 - formula2 = slv.mkTerm(kinds.Geq, leny, slv.mkInteger(0)) + formula2 = slv.mkTerm(Kind.Geq, leny, slv.mkInteger(0)) # Regular expression: (ab[c-e]*f)|g|h - r = slv.mkTerm(kinds.RegexpUnion, - slv.mkTerm(kinds.RegexpConcat, - slv.mkTerm(kinds.StringToRegexp, slv.mkString("ab")), - slv.mkTerm(kinds.RegexpStar, - slv.mkTerm(kinds.RegexpRange, slv.mkString("c"), slv.mkString("e"))), - slv.mkTerm(kinds.StringToRegexp, slv.mkString("f"))), - slv.mkTerm(kinds.StringToRegexp, slv.mkString("g")), - slv.mkTerm(kinds.StringToRegexp, slv.mkString("h"))) + r = slv.mkTerm(Kind.RegexpUnion, + slv.mkTerm(Kind.RegexpConcat, + slv.mkTerm(Kind.StringToRegexp, slv.mkString("ab")), + slv.mkTerm(Kind.RegexpStar, + slv.mkTerm(Kind.RegexpRange, slv.mkString("c"), slv.mkString("e"))), + slv.mkTerm(Kind.StringToRegexp, slv.mkString("f"))), + slv.mkTerm(Kind.StringToRegexp, slv.mkString("g")), + slv.mkTerm(Kind.StringToRegexp, slv.mkString("h"))) # String variables s1 = slv.mkConst(string, "s1") s2 = slv.mkConst(string, "s2") # String concatenation: s1.s2 - s = slv.mkTerm(kinds.StringConcat, s1, s2) + s = slv.mkTerm(Kind.StringConcat, s1, s2) # s1.s2 in (ab[c-e]*f)|g|h - formula3 = slv.mkTerm(kinds.StringInRegexp, s, r) + formula3 = slv.mkTerm(Kind.StringInRegexp, s, r) # Make a query - q = slv.mkTerm(kinds.And, + q = slv.mkTerm(Kind.And, formula1, formula2, formula3) diff --git a/examples/api/python/sygus-fun.py b/examples/api/python/sygus-fun.py index d2ad1feb4..3cacc33d2 100644 --- a/examples/api/python/sygus-fun.py +++ b/examples/api/python/sygus-fun.py @@ -18,7 +18,7 @@ import copy import pycvc5 import utils -from pycvc5 import kinds +from pycvc5 import Kind if __name__ == "__main__": slv = pycvc5.Solver() @@ -45,13 +45,13 @@ if __name__ == "__main__": zero = slv.mkInteger(0) one = slv.mkInteger(1) - plus = slv.mkTerm(kinds.Plus, start, start) - minus = slv.mkTerm(kinds.Minus, start, start) - ite = slv.mkTerm(kinds.Ite, start_bool, start, start) + plus = slv.mkTerm(Kind.Plus, start, start) + minus = slv.mkTerm(Kind.Minus, start, start) + ite = slv.mkTerm(Kind.Ite, start_bool, start, start) - And = slv.mkTerm(kinds.And, start_bool, start_bool) - Not = slv.mkTerm(kinds.Not, start_bool) - leq = slv.mkTerm(kinds.Leq, start, start) + And = slv.mkTerm(Kind.And, start_bool, start_bool) + Not = slv.mkTerm(Kind.Not, start_bool) + leq = slv.mkTerm(Kind.Leq, start, start) # create the grammar object g = slv.mkSygusGrammar([x, y], [start, start_bool]) @@ -69,25 +69,25 @@ if __name__ == "__main__": varX = slv.mkSygusVar(integer, "x") varY = slv.mkSygusVar(integer, "y") - max_x_y = slv.mkTerm(kinds.ApplyUf, max, varX, varY) - min_x_y = slv.mkTerm(kinds.ApplyUf, min, varX, varY) + max_x_y = slv.mkTerm(Kind.ApplyUf, max, varX, varY) + min_x_y = slv.mkTerm(Kind.ApplyUf, min, varX, varY) # add semantic constraints # (constraint (>= (max x y) x)) - slv.addSygusConstraint(slv.mkTerm(kinds.Geq, max_x_y, varX)) + slv.addSygusConstraint(slv.mkTerm(Kind.Geq, max_x_y, varX)) # (constraint (>= (max x y) y)) - slv.addSygusConstraint(slv.mkTerm(kinds.Geq, max_x_y, varY)) + slv.addSygusConstraint(slv.mkTerm(Kind.Geq, max_x_y, varY)) # (constraint (or (= x (max x y)) # (= y (max x y)))) slv.addSygusConstraint(slv.mkTerm( - kinds.Or, slv.mkTerm(kinds.Equal, max_x_y, varX), slv.mkTerm(kinds.Equal, max_x_y, varY))) + Kind.Or, slv.mkTerm(Kind.Equal, max_x_y, varX), slv.mkTerm(Kind.Equal, max_x_y, varY))) # (constraint (= (+ (max x y) (min x y)) # (+ x y))) slv.addSygusConstraint(slv.mkTerm( - kinds.Equal, slv.mkTerm(kinds.Plus, max_x_y, min_x_y), slv.mkTerm(kinds.Plus, varX, varY))) + Kind.Equal, slv.mkTerm(Kind.Plus, max_x_y, min_x_y), slv.mkTerm(Kind.Plus, varX, varY))) # print solutions if available if (slv.checkSynth().isUnsat()): diff --git a/examples/api/python/sygus-grammar.py b/examples/api/python/sygus-grammar.py index 02a7dff48..466e2cdd3 100644 --- a/examples/api/python/sygus-grammar.py +++ b/examples/api/python/sygus-grammar.py @@ -19,7 +19,7 @@ import copy import utils import pycvc5 -from pycvc5 import kinds +from pycvc5 import Kind if __name__ == "__main__": slv = pycvc5.Solver() @@ -42,8 +42,8 @@ if __name__ == "__main__": # define the rules zero = slv.mkInteger(0) - neg_x = slv.mkTerm(kinds.Uminus, x) - plus = slv.mkTerm(kinds.Plus, x, start) + neg_x = slv.mkTerm(Kind.Uminus, x) + plus = slv.mkTerm(Kind.Plus, x, start) # create the grammar object g1 = slv.mkSygusGrammar({x}, {start}) @@ -72,14 +72,14 @@ if __name__ == "__main__": # declare universal variables. varX = slv.mkSygusVar(integer, "x") - id1_x = slv.mkTerm(kinds.ApplyUf, id1, varX) - id2_x = slv.mkTerm(kinds.ApplyUf, id2, varX) - id3_x = slv.mkTerm(kinds.ApplyUf, id3, varX) - id4_x = slv.mkTerm(kinds.ApplyUf, id4, varX) + id1_x = slv.mkTerm(Kind.ApplyUf, id1, varX) + id2_x = slv.mkTerm(Kind.ApplyUf, id2, varX) + id3_x = slv.mkTerm(Kind.ApplyUf, id3, varX) + id4_x = slv.mkTerm(Kind.ApplyUf, id4, varX) # add semantic constraints # (constraint (= (id1 x) (id2 x) (id3 x) (id4 x) x)) - slv.addSygusConstraint(slv.mkTerm(kinds.And, [slv.mkTerm(kinds.Equal, id1_x, id2_x), slv.mkTerm(kinds.Equal, id1_x, id3_x), slv.mkTerm(kinds.Equal, id1_x, id4_x), slv.mkTerm(kinds.Equal, id1_x, varX)])) + slv.addSygusConstraint(slv.mkTerm(Kind.And, [slv.mkTerm(Kind.Equal, id1_x, id2_x), slv.mkTerm(Kind.Equal, id1_x, id3_x), slv.mkTerm(Kind.Equal, id1_x, id4_x), slv.mkTerm(Kind.Equal, id1_x, varX)])) # print solutions if available if (slv.checkSynth().isUnsat()): diff --git a/examples/api/python/sygus-inv.py b/examples/api/python/sygus-inv.py index 50fa3f04f..3af4ac5ec 100644 --- a/examples/api/python/sygus-inv.py +++ b/examples/api/python/sygus-inv.py @@ -18,7 +18,7 @@ import utils import pycvc5 -from pycvc5 import kinds +from pycvc5 import Kind if __name__ == "__main__": slv = pycvc5.Solver() @@ -42,15 +42,15 @@ if __name__ == "__main__": xp = slv.mkVar(integer, "xp") # (ite (< x 10) (= xp (+ x 1)) (= xp x)) - ite = slv.mkTerm(kinds.Ite, - slv.mkTerm(kinds.Lt, x, ten), - slv.mkTerm(kinds.Equal, xp, slv.mkTerm(kinds.Plus, x, one)), - slv.mkTerm(kinds.Equal, xp, x)) + ite = slv.mkTerm(Kind.Ite, + slv.mkTerm(Kind.Lt, x, ten), + slv.mkTerm(Kind.Equal, xp, slv.mkTerm(Kind.Plus, x, one)), + slv.mkTerm(Kind.Equal, xp, x)) # define the pre-conditions, transition relations, and post-conditions - pre_f = slv.defineFun("pre-f", [x], boolean, slv.mkTerm(kinds.Equal, x, zero)) + pre_f = slv.defineFun("pre-f", [x], boolean, slv.mkTerm(Kind.Equal, x, zero)) trans_f = slv.defineFun("trans-f", [x, xp], boolean, ite) - post_f = slv.defineFun("post-f", [x], boolean, slv.mkTerm(kinds.Leq, x, ten)) + post_f = slv.defineFun("post-f", [x], boolean, slv.mkTerm(Kind.Leq, x, ten)) # declare the invariant-to-synthesize inv_f = slv.synthInv("inv-f", {x}) diff --git a/examples/api/python/transcendentals.py b/examples/api/python/transcendentals.py index 39bb343c7..ffeb0c775 100644 --- a/examples/api/python/transcendentals.py +++ b/examples/api/python/transcendentals.py @@ -15,7 +15,7 @@ ## import pycvc5 -from pycvc5 import kinds +from pycvc5 import Kind if __name__ == "__main__": slv = pycvc5.Solver() @@ -30,14 +30,14 @@ if __name__ == "__main__": # Helper terms two = slv.mkReal(2) pi = slv.mkPi() - twopi = slv.mkTerm(kinds.Mult, two, pi) - ysq = slv.mkTerm(kinds.Mult, y, y) - sinx = slv.mkTerm(kinds.Sine, x) + twopi = slv.mkTerm(Kind.Mult, two, pi) + ysq = slv.mkTerm(Kind.Mult, y, y) + sinx = slv.mkTerm(Kind.Sine, x) # Formulas - x_gt_pi = slv.mkTerm(kinds.Gt, x, pi) - x_lt_tpi = slv.mkTerm(kinds.Lt, x, twopi) - ysq_lt_sinx = slv.mkTerm(kinds.Lt, ysq, sinx) + x_gt_pi = slv.mkTerm(Kind.Gt, x, pi) + x_lt_tpi = slv.mkTerm(Kind.Lt, x, twopi) + ysq_lt_sinx = slv.mkTerm(Kind.Lt, ysq, sinx) slv.assertFormula(x_gt_pi) slv.assertFormula(x_lt_tpi) diff --git a/examples/api/python/utils.py b/examples/api/python/utils.py index 6d42325b5..cf906bc7a 100644 --- a/examples/api/python/utils.py +++ b/examples/api/python/utils.py @@ -15,7 +15,7 @@ ## import pycvc5 -from pycvc5 import kinds +from pycvc5 import Kind # Get the string version of define-fun command. # @param f the function to print @@ -47,7 +47,7 @@ def print_synth_solutions(terms, sols): result = "" for i in range(0, len(terms)): params = [] - if sols[i].getKind() == kinds.Lambda: + if sols[i].getKind() == Kind.Lambda: params += sols[i][0] body = sols[i][1] result += " " + define_fun_to_string(terms[i], params, body) + "\n" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 96de9afeb..1d57dfeb4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -151,6 +151,8 @@ libcvc5_add_sources( printer/smt2/smt2_printer.h printer/tptp/tptp_printer.cpp printer/tptp/tptp_printer.h + proof/annotation_proof_generator.cpp + proof/annotation_proof_generator.h proof/assumption_proof_generator.cpp proof/assumption_proof_generator.h proof/buffered_proof_generator.cpp @@ -420,6 +422,8 @@ libcvc5_add_sources( theory/arith/nl/cad/proof_generator.h theory/arith/nl/cad/variable_ordering.cpp theory/arith/nl/cad/variable_ordering.h + theory/arith/nl/equality_substitution.cpp + theory/arith/nl/equality_substitution.h theory/arith/nl/ext/constraint.cpp theory/arith/nl/ext/constraint.h theory/arith/nl/ext/factoring_check.cpp @@ -681,6 +685,8 @@ libcvc5_add_sources( theory/incomplete_id.h theory/inference_id.cpp theory/inference_id.h + theory/inference_id_proof_annotator.cpp + theory/inference_id_proof_annotator.h theory/inference_manager_buffered.cpp theory/inference_manager_buffered.h theory/logic_info.cpp @@ -1013,6 +1019,8 @@ libcvc5_add_sources( theory/sort_inference.h theory/strings/array_solver.cpp theory/strings/array_solver.h + theory/strings/array_core_solver.cpp + theory/strings/array_core_solver.h theory/strings/arith_entail.cpp theory/strings/arith_entail.h theory/strings/base_solver.cpp diff --git a/src/api/cpp/cvc5.cpp b/src/api/cpp/cvc5.cpp index c62dde511..4202a7fab 100644 --- a/src/api/cpp/cvc5.cpp +++ b/src/api/cpp/cvc5.cpp @@ -1763,7 +1763,7 @@ size_t Sort::getDatatypeArity() const CVC5_API_CHECK_NOT_NULL; CVC5_API_CHECK(isDatatype()) << "Not a datatype sort."; //////// all checks before this line - return d_type->getNumChildren() - 1; + return d_type->isParametricDatatype() ? d_type->getNumChildren() - 1 : 0; //////// CVC5_API_TRY_CATCH_END; } @@ -2908,7 +2908,7 @@ std::int64_t Term::getInt64Value() const CVC5_API_ARG_CHECK_EXPECTED(detail::isInt64(*d_node), *d_node) << "Term to be a 64-bit integer value when calling getInt64Value()"; //////// all checks before this line - return detail::getInteger(*d_node).getLong(); + return detail::getInteger(*d_node).getSigned64(); //////// CVC5_API_TRY_CATCH_END; } @@ -2931,7 +2931,7 @@ std::uint64_t Term::getUInt64Value() const << "Term to be a unsigned 64-bit integer value when calling " "getUInt64Value()"; //////// all checks before this line - return detail::getInteger(*d_node).getUnsignedLong(); + return detail::getInteger(*d_node).getUnsigned64(); //////// CVC5_API_TRY_CATCH_END; } @@ -3029,8 +3029,8 @@ std::pair<std::int64_t, std::uint64_t> Term::getReal64Value() const << "Term to be a 64-bit rational value when calling getReal64Value()"; //////// all checks before this line const Rational& r = detail::getRational(*d_node); - return std::make_pair(r.getNumerator().getLong(), - r.getDenominator().getUnsignedLong()); + return std::make_pair(r.getNumerator().getSigned64(), + r.getDenominator().getUnsigned64()); //////// CVC5_API_TRY_CATCH_END; } @@ -3558,6 +3558,11 @@ std::ostream& operator<<(std::ostream& out, bool DatatypeConstructorDecl::isNullHelper() const { return d_ctor == nullptr; } +bool DatatypeConstructorDecl::isResolved() const +{ + return d_ctor == nullptr || d_ctor->isResolved(); +} + /* DatatypeDecl ------------------------------------------------------------- */ DatatypeDecl::DatatypeDecl() : d_solver(nullptr), d_dtype(nullptr) {} @@ -3799,7 +3804,7 @@ Term DatatypeConstructor::getConstructorTerm() const CVC5_API_TRY_CATCH_END; } -Term DatatypeConstructor::getSpecializedConstructorTerm( +Term DatatypeConstructor::getInstantiatedConstructorTerm( const Sort& retSort) const { CVC5_API_TRY_CATCH_BEGIN; @@ -3810,13 +3815,7 @@ Term DatatypeConstructor::getSpecializedConstructorTerm( << "Cannot get specialized constructor type for non-datatype type " << retSort; //////// all checks before this line - - NodeManager* nm = d_solver->getNodeManager(); - Node ret = - nm->mkNode(kind::APPLY_TYPE_ASCRIPTION, - nm->mkConst(AscriptionType( - d_ctor->getSpecializedConstructorType(*retSort.d_type))), - d_ctor->getConstructor()); + Node ret = d_ctor->getInstantiatedConstructor(*retSort.d_type); (void)ret.getType(true); /* kick off type checking */ // apply type ascription to the operator Term sctor = api::Term(d_solver, ret); @@ -4110,6 +4109,18 @@ size_t Datatype::getNumConstructors() const CVC5_API_TRY_CATCH_END; } +std::vector<Sort> Datatype::getParameters() const +{ + CVC5_API_TRY_CATCH_BEGIN; + CVC5_API_CHECK_NOT_NULL; + CVC5_API_CHECK(isParametric()) << "Expected parametric datatype"; + //////// all checks before this line + std::vector<cvc5::TypeNode> params = d_dtype->getParameters(); + return Sort::typeNodeVectorToSorts(d_solver, params); + //////// + CVC5_API_TRY_CATCH_END; +} + bool Datatype::isParametric() const { CVC5_API_TRY_CATCH_BEGIN; @@ -6737,6 +6748,11 @@ Sort Solver::declareDatatype( CVC5_API_ARG_CHECK_EXPECTED(ctors.size() > 0, ctors) << "a datatype declaration with at least one constructor"; CVC5_API_SOLVER_CHECK_DTCTORDECLS(ctors); + for (size_t i = 0, size = ctors.size(); i < size; i++) + { + CVC5_API_CHECK(!ctors[i].isResolved()) + << "cannot use a constructor for multiple datatypes"; + } //////// all checks before this line DatatypeDecl dtdecl(this, symbol); for (size_t i = 0, size = ctors.size(); i < size; i++) @@ -7296,6 +7312,9 @@ Term Solver::getValue(const Term& term) const CVC5_API_SOLVER_CHECK_TERM(term); CVC5_API_RECOVERABLE_CHECK(term.getSort().isFirstClass()) << "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."; //////// all checks before this line return getValueHelper(term); //////// @@ -7314,6 +7333,9 @@ std::vector<Term> Solver::getValue(const std::vector<Term>& terms) const { CVC5_API_RECOVERABLE_CHECK(t.getSort().isFirstClass()) << "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."; } CVC5_API_SOLVER_CHECK_TERMS(terms); //////// all checks before this line diff --git a/src/api/cpp/cvc5.h b/src/api/cpp/cvc5.h index cd448123a..e3f64349f 100644 --- a/src/api/cpp/cvc5.h +++ b/src/api/cpp/cvc5.h @@ -275,8 +275,9 @@ class CVC5_EXPORT Result /** * The interal result wrapped by this result. - * Note: This is a shared_ptr rather than a unique_ptr since cvc5::Result is - * not ref counted. + * + * @note This is a ``std::shared_ptr`` rather than a ``std::unique_ptr`` + * since ``cvc5::Result`` is not ref counted. */ std::shared_ptr<cvc5::Result> d_result; }; @@ -314,6 +315,7 @@ class CVC5_EXPORT Sort friend class DatatypeConstructorDecl; friend class DatatypeSelector; friend class DatatypeDecl; + friend class Datatype; friend class Op; friend class Solver; friend class Grammar; @@ -433,7 +435,11 @@ class CVC5_EXPORT Sort bool isDatatype() const; /** - * Is this a parametric datatype sort? + * Is this a parametric datatype sort? A parametric datatype sort is either + * one that is returned by a call to Solver::mkDatatypeSort() or + * Solver::mkDatatypeSorts() for a parametric datatype, or an instantiated + * datatype sort returned by Sort::instantiate() for parametric datatype + * sort `s`. * @return true if the sort is a parametric datatype sort */ bool isParametricDatatype() const; @@ -544,7 +550,7 @@ class CVC5_EXPORT Sort * or return value for any term that is function-like. * This is mainly to avoid higher order. * - * Note that arrays are explicitly not considered function-like here. + * @note Arrays are explicitly not considered function-like here. * * @return true if this is a function-like sort */ @@ -639,6 +645,9 @@ class CVC5_EXPORT Sort /** * @return the codomain sort of a tester sort, which is the Boolean sort + * + * @note We mainly need this for the symbol table, which doesn't have + * access to the solver object. */ Sort getTesterCodomainSort() const; @@ -743,7 +752,14 @@ class CVC5_EXPORT Sort /* Datatype sort ------------------------------------------------------- */ /** - * @return the parameter sorts of a datatype sort + * + * Return the parameters of a parametric datatype sort. If this sort is a + * non-instantiated parametric datatype, this returns the parameter sorts of + * the underlying datatype. If this sort is an instantiated parametric + * datatype, then this returns the sort parameters that were used to + * construct the sort via Sort::instantiate(). + * + * @return the parameter sorts of a parametric datatype sort. */ std::vector<Sort> getDatatypeParamSorts() const; @@ -798,9 +814,10 @@ class CVC5_EXPORT Sort /** * The internal type wrapped by this sort. - * Note: This is a shared_ptr rather than a unique_ptr to avoid overhead due - * to memory allocation (cvc5::Type is already ref counted, so this - * could be a unique_ptr instead). + * + * @note This is a ``std::shared_ptr`` rather than a ``std::unique_ptr`` to + * avoid overhead due to memory allocation (``cvc5::Type`` is already + * ref counted, so this could be a ``std::unique_ptr`` instead). */ std::shared_ptr<cvc5::TypeNode> d_type; }; @@ -947,9 +964,11 @@ class CVC5_EXPORT Op bool isNullHelper() const; /** - * Note: An indexed operator has a non-null internal node, d_node - * Note 2: We use a helper method to avoid having API functions call - * other API functions (we need to call this internally) + * @note An indexed operator has a non-null internal node (``d_node``). + * + * @note We use a helper method to avoid having API functions call other API + * functions (we need to call this internally). + * * @return true iff this Op is indexed */ bool isIndexedHelper() const; @@ -977,9 +996,10 @@ class CVC5_EXPORT Op /** * The internal node wrapped by this operator. - * Note: This is a shared_ptr rather than a unique_ptr to avoid overhead due - * to memory allocation (cvc5::Node is already ref counted, so this - * could be a unique_ptr instead). + * + * @note This is a ``std::shared_ptr`` rather than a ``std::unique_ptr`` to + * avoid overhead due to memory allocation (``cvc5::Node`` is already + * ref counted, so this could be a ``std::unique_ptr`` instead). */ std::shared_ptr<cvc5::Node> d_node; }; @@ -1123,8 +1143,9 @@ class CVC5_EXPORT Term bool hasOp() const; /** + * @note This is safe to call when hasOp() returns true. + * * @return the Op used to create this term - * Note: This is safe to call when hasOp() returns true. */ Op getOp() const; @@ -1200,9 +1221,9 @@ class CVC5_EXPORT Term /** * Iterator for the children of a Term. - * Note: This treats uninterpreted functions as Term just like any other term - * for example, the term f(x, y) will have Kind APPLY_UF and three - * children: f, x, and y + * @note This treats uninterpreted functions as Term just like any other term + * for example, the term ``f(x, y)`` will have Kind ``APPLY_UF`` and + * three children: ``f``, ``x``, and ``y`` */ class CVC5_EXPORT const_iterator { @@ -1236,7 +1257,7 @@ class CVC5_EXPORT Term /** * Constructor * @param slv the associated solver object - * @param e a shared pointer to the node that we're iterating over + * @param e a ``std::shared pointer`` to the node that we're iterating over * @param p the position of the iterator (e.g. which child it's on) */ const_iterator(const Solver* slv, @@ -1359,9 +1380,9 @@ class CVC5_EXPORT Term */ bool isStringValue() const; /** - * Note: This method is not to be confused with toString() which returns - * the term in some string representation, whatever data it may hold. Asserts - * isStringValue(). + * Asserts isStringValue(). + * @note This method is not to be confused with toString(), which returns + * some string representation of the term, whatever data it may hold. * @return the string term as a native string value. */ std::wstring getStringValue() const; @@ -1389,9 +1410,8 @@ class CVC5_EXPORT Term */ std::pair<int64_t, uint64_t> getReal64Value() const; /** + * @note A term of kind PI is not considered to be a real value. * @return true if the term is a rational value. - * - * Note that a term of kind PI is not considered to be a real value. */ bool isRealValue() const; /** @@ -1496,8 +1516,8 @@ class CVC5_EXPORT Term * where `c1 ... cn` are values ordered by id such that `c1 > ... > cn` (see * also @ref Term::operator>(const Term&) const). * - * Note that a universe set term (kind SET_UNIVERSE) is not considered to be - * a set value. + * @note A universe set term (kind SET_UNIVERSE) is not considered to be + * a set value. */ bool isSetValue() const; /** @@ -1512,9 +1532,9 @@ class CVC5_EXPORT Term bool isSequenceValue() const; /** * Asserts isSequenceValue(). - * Note that it is usually necessary for sequences to call - * `Solver::simplify()` to turn a sequence that is constructed by, e.g., - * concatenation of unit sequences, into a sequence value. + * @note It is usually necessary for sequences to call `Solver::simplify()` + * to turn a sequence that is constructed by, e.g., concatenation of + * unit sequences, into a sequence value. * @return the representation of a sequence value as a vector of terms. */ std::vector<Term> getSequenceValue() const; @@ -1582,9 +1602,9 @@ class CVC5_EXPORT Term bool isCastedReal() const; /** * The internal node wrapped by this term. - * Note: This is a shared_ptr rather than a unique_ptr to avoid overhead due - * to memory allocation (cvc5::Node is already ref counted, so this - * could be a unique_ptr instead). + * @note This is a ``std::shared_ptr`` rather than a ``std::unique_ptr`` to + * avoid overhead due to memory allocation (``cvc5::Node`` is already + * ref counted, so this could be a ``std::unique_ptr`` instead). */ std::shared_ptr<cvc5::Node> d_node; }; @@ -1726,6 +1746,12 @@ class CVC5_EXPORT DatatypeConstructorDecl bool isNullHelper() const; /** + * Is the underlying constructor resolved (i.e. has it been used to declare + * a datatype already)? + */ + bool isResolved() const; + + /** * The associated solver object. */ const Solver* d_solver; @@ -1733,8 +1759,8 @@ class CVC5_EXPORT DatatypeConstructorDecl /** * The internal (intermediate) datatype constructor wrapped by this * datatype constructor declaration. - * Note: This is a shared_ptr rather than a unique_ptr since - * cvc5::DTypeConstructor is not ref counted. + * @note This is a ``std::shared_ptr`` rather than a ``std::unique_ptr`` + * since ``cvc5::DTypeConstructor`` is not ref counted. */ std::shared_ptr<cvc5::DTypeConstructor> d_ctor; }; @@ -1839,8 +1865,8 @@ class CVC5_EXPORT DatatypeDecl /** * The internal (intermediate) datatype wrapped by this datatype * declaration. - * Note: This is a shared_ptr rather than a unique_ptr since cvc5::DType is - * not ref counted. + * @note This is a ``std::shared_ptr`` rather than a ``std::unique_ptr`` + * since ``cvc5::DType`` is not ref counted. */ std::shared_ptr<cvc5::DType> d_dtype; }; @@ -1915,8 +1941,8 @@ class CVC5_EXPORT DatatypeSelector /** * The internal datatype selector wrapped by this datatype selector. - * Note: This is a shared_ptr rather than a unique_ptr since cvc5::DType is - * not ref counted. + * @note This is a ``std::shared_ptr`` rather than a ``std::unique_ptr`` + * since ``cvc5::DType`` is not ref counted. */ std::shared_ptr<cvc5::DTypeSelector> d_stor; }; @@ -1965,14 +1991,14 @@ class CVC5_EXPORT DatatypeConstructor * DatatypeConstructor is the one corresponding to nil, and retSort is * (List Int). * - * Furthermore note that the returned constructor term t is an operator, - * while Solver::mkTerm(APPLY_CONSTRUCTOR, t) is used to construct the above - * (nullary) application of nil. + * @note the returned constructor term ``t`` is an operator, while + * ``Solver::mkTerm(APPLY_CONSTRUCTOR, t)`` is used to construct the + * above (nullary) application of nil. * * @param retSort the desired return sort of the constructor * @return the constructor term */ - Term getSpecializedConstructorTerm(const Sort& retSort) const; + Term getInstantiatedConstructorTerm(const Sort& retSort) const; /** * Get the tester operator of this datatype constructor. @@ -2160,8 +2186,8 @@ class CVC5_EXPORT DatatypeConstructor /** * The internal datatype constructor wrapped by this datatype constructor. - * Note: This is a shared_ptr rather than a unique_ptr since cvc5::DType is - * not ref counted. + * @note This is a ``std::shared_ptr`` rather than a ``std::unique_ptr`` + * since ``cvc5::DType`` is not ref counted. */ std::shared_ptr<cvc5::DTypeConstructor> d_ctor; }; @@ -2223,6 +2249,12 @@ class CVC5_EXPORT Datatype /** @return the number of constructors for this Datatype. */ size_t getNumConstructors() const; + /** + * @return the parameters of this datatype, if it is parametric. An exception + * is thrown if this datatype is not parametric. + */ + std::vector<Sort> getParameters() const; + /** @return true if this datatype is parametric */ bool isParametric() const; @@ -2417,8 +2449,8 @@ class CVC5_EXPORT Datatype /** * The internal datatype wrapped by this datatype. - * Note: This is a shared_ptr rather than a unique_ptr since cvc5::DType is - * not ref counted. + * @note This is a ``std::shared_ptr`` rather than a ``std::unique_ptr`` + * since ``cvc5::DType`` is not ref counted. */ std::shared_ptr<cvc5::DType> d_dtype; }; @@ -2557,6 +2589,8 @@ class CVC5_EXPORT Grammar * with bound variables via purifySygusGTerm, and binding these variables * via a lambda. * + * @note Create unresolved sorts with Solver::mkUninterpretedSort(). + * * @param dt the non-terminal's datatype to which a constructor is added * @param term the sygus operator of the constructor * @param ntsToUnres mapping from non-terminals to their unresolved sorts @@ -3120,6 +3154,8 @@ class CVC5_EXPORT Solver * When constructing datatypes, unresolved sorts are replaced by the datatype * sort constructed for the datatype declaration it is associated with. * + * @note Create unresolved sorts with Solver::mkUninterpretedSort(). + * * @param dtypedecls the datatype declarations from which the sort is created * @param unresolvedSorts the list of unresolved sorts * @return the datatype sorts @@ -3324,12 +3360,13 @@ class CVC5_EXPORT Solver /* .................................................................... */ /** - * Create an operator for a builtin Kind + * Create an operator for a builtin Kind. + * * The Kind may not be the Kind for an indexed operator - * (e.g. BITVECTOR_EXTRACT) - * Note: in this case, the Op simply wraps the Kind. - * The Kind can be used in mkTerm directly without - * creating an op first. + * (e.g. BITVECTOR_EXTRACT). + * + * @note In this case, the ``Op`` simply wraps the ``Kind``. The Kind can be + * used in ``Solver::mkTerm`` directly without creating an ``Op`` first. * @param kind the kind to wrap */ Op mkOp(Kind kind) const; @@ -3535,7 +3572,7 @@ class CVC5_EXPORT Solver /** * Create a bit-vector constant of given size and value. * - * Note: The given value must fit into a bit-vector of the given size. + * @note The given value must fit into a bit-vector of the given size. * * @param size the bit-width of the bit-vector sort * @param val the value of the constant @@ -3547,7 +3584,7 @@ class CVC5_EXPORT Solver * Create a bit-vector constant of a given bit-width from a given string of * base 2, 10 or 16. * - * Note: The given value must fit into a bit-vector of the given size. + * @note The given value must fit into a bit-vector of the given size. * * @param size the bit-width of the constant * @param s the string representation of the constant @@ -4312,9 +4349,10 @@ class CVC5_EXPORT Solver void setOption(const std::string& option, const std::string& value) const; /** - * If needed, convert this term to a given sort. Note that the sort of the - * term must be convertible into the target sort. Currently only Int to Real - * conversions are supported. + * If needed, convert this term to a given sort. + * + * @note The sort of the term must be convertible into the target sort. + * Currently only Int to Real conversions are supported. * @param t the term * @param s the target sort * @return the term wrapped into a sort conversion if needed diff --git a/src/api/cpp/cvc5_kind.h b/src/api/cpp/cvc5_kind.h index 73843f9b5..e465a8faa 100644 --- a/src/api/cpp/cvc5_kind.h +++ b/src/api/cpp/cvc5_kind.h @@ -2013,7 +2013,7 @@ enum Kind : int32_t * Operator for tuple projection indices * * Parameters: - * - 1: The tuple projection indices + * - 1: A vector of tuple projection indices. * * Create with: * - `Solver::mkOp(Kind TUPLE_PROJECT, std::vector<uint32_t> param) const` diff --git a/src/api/java/genkinds.py.in b/src/api/java/genkinds.py.in index d44ae3c0d..18ac5ec3c 100644 --- a/src/api/java/genkinds.py.in +++ b/src/api/java/genkinds.py.in @@ -21,7 +21,7 @@ import argparse import os import sys import re - +import textwrap # get access to cvc5/src/api/parsekinds.py @@ -110,11 +110,7 @@ CPP_JAVA_MAPPING = \ def format_comment(comment): for pattern, replacement in CPP_JAVA_MAPPING.items(): comment = re.sub(pattern, replacement, comment) - java_comment = "\n /**" - for line in comment.split("\n"): - java_comment += "\n * " + line - java_comment = " " + java_comment.strip() + "/" - return java_comment + return """ /**\n{}\n */""".format(textwrap.indent(comment, ' * ')) # Files generation diff --git a/src/api/java/io/github/cvc5/api/Datatype.java b/src/api/java/io/github/cvc5/api/Datatype.java index bc33ba10b..39ea2bb19 100644 --- a/src/api/java/io/github/cvc5/api/Datatype.java +++ b/src/api/java/io/github/cvc5/api/Datatype.java @@ -108,6 +108,18 @@ public class Datatype extends AbstractPointer implements Iterable<DatatypeConstr private native int getNumConstructors(long pointer); + /** + * @return the parameters of this datatype, if it is parametric. An exception + * is thrown if this datatype is not parametric. + */ + public Sort[] getParameters() { + long[] sortPointers = getParameters(pointer); + Sort[] sorts = Utils.getSorts(solver, sortPointers); + return sorts; + } + + private native long[] getParameters(long pointer); + /** @return true if this datatype is parametric */ public boolean isParametric() { diff --git a/src/api/java/io/github/cvc5/api/DatatypeConstructor.java b/src/api/java/io/github/cvc5/api/DatatypeConstructor.java index 5fd9d8407..4a041dd99 100644 --- a/src/api/java/io/github/cvc5/api/DatatypeConstructor.java +++ b/src/api/java/io/github/cvc5/api/DatatypeConstructor.java @@ -78,13 +78,14 @@ public class DatatypeConstructor extends AbstractPointer implements Iterable<Dat * @param retSort the desired return sort of the constructor * @return the constructor term */ - public Term getSpecializedConstructorTerm(Sort retSort) - { - long termPointer = getSpecializedConstructorTerm(pointer, retSort.getPointer()); + public Term getInstantiatedConstructorTerm(Sort retSort) { + long termPointer = + getInstantiatedConstructorTerm(pointer, retSort.getPointer()); return new Term(solver, termPointer); } - private native long getSpecializedConstructorTerm(long pointer, long retSortPointer); + private native long getInstantiatedConstructorTerm( + long pointer, long retSortPointer); /** * Get the tester operator of this datatype constructor. diff --git a/src/api/java/io/github/cvc5/api/Solver.java b/src/api/java/io/github/cvc5/api/Solver.java index 16220228c..6f86928ca 100644 --- a/src/api/java/io/github/cvc5/api/Solver.java +++ b/src/api/java/io/github/cvc5/api/Solver.java @@ -639,10 +639,9 @@ public class Solver implements IPointer, AutoCloseable /** * Create an operator for a builtin Kind * The Kind may not be the Kind for an indexed operator - * (e.g. BITVECTOR_EXTRACT) - * Note: in this case, the Op simply wraps the Kind. - * The Kind can be used in mkTerm directly without - * creating an op first. + * (e.g. BITVECTOR_EXTRACT). + * @apiNote In this case, the Op simply wraps the Kind. The Kind can be used + * in mkTerm directly without creating an op first. * @param kind the kind to wrap */ public Op mkOp(Kind kind) @@ -1017,7 +1016,7 @@ public class Solver implements IPointer, AutoCloseable /** * Create a bit-vector constant of given size and value. * - * Note: The given value must fit into a bit-vector of the given size. + * @apiNote The given value must fit into a bit-vector of the given size. * * @param size the bit-width of the bit-vector sort * @param val the value of the constant @@ -1037,7 +1036,7 @@ public class Solver implements IPointer, AutoCloseable * Create a bit-vector constant of a given bit-width from a given string of * base 2, 10 or 16. * - * Note: The given value must fit into a bit-vector of the given size. + * @apiNote The given value must fit into a bit-vector of the given size. * * @param size the bit-width of the constant * @param s the string representation of the constant @@ -2355,9 +2354,10 @@ public class Solver implements IPointer, AutoCloseable private native void setOption(long pointer, String option, String value); /** - * If needed, convert this term to a given sort. Note that the sort of the - * term must be convertible into the target sort. Currently only Int to Real - * conversions are supported. + * If needed, convert this term to a given sort. + * + * @apiNote The sort of the term must be convertible into the target sort. + * Currently only Int to Real conversions are supported. * @param t the term * @param s the target sort * @return the term wrapped into a sort conversion if needed diff --git a/src/api/java/io/github/cvc5/api/Sort.java b/src/api/java/io/github/cvc5/api/Sort.java index 440b1ba59..6bd87a9af 100644 --- a/src/api/java/io/github/cvc5/api/Sort.java +++ b/src/api/java/io/github/cvc5/api/Sort.java @@ -372,7 +372,7 @@ public class Sort extends AbstractPointer implements Comparable<Sort> * or return value for any term that is function-like. * This is mainly to avoid higher order. * - * Note that arrays are explicitly not considered function-like here. + * @apiNote Arrays are explicitly not considered function-like here. * * @return true if this is a function-like sort */ @@ -752,6 +752,12 @@ public class Sort extends AbstractPointer implements Comparable<Sort> /* Datatype sort ------------------------------------------------------- */ /** + * Return the parameters of a parametric datatype sort. If this sort is a + * non-instantiated parametric datatype, this returns the parameter sorts of + * the underlying datatype. If this sort is an instantiated parametric + * datatype, then this returns the sort parameters that were used to + * construct the sort via Sort.instantiate(). + * * @return the parameter sorts of a datatype sort */ public Sort[] getDatatypeParamSorts() diff --git a/src/api/java/io/github/cvc5/api/Term.java b/src/api/java/io/github/cvc5/api/Term.java index fc09767ed..db780f9bd 100644 --- a/src/api/java/io/github/cvc5/api/Term.java +++ b/src/api/java/io/github/cvc5/api/Term.java @@ -190,7 +190,7 @@ public class Term extends AbstractPointer implements Comparable<Term>, Iterable< /** * @return the Op used to create this term - * Note: This is safe to call when hasOp() returns true. + * @apiNote This is safe to call when hasOp() returns true. */ public Op getOp() { @@ -367,10 +367,11 @@ public class Term extends AbstractPointer implements Comparable<Term>, Iterable< /** * @return the stored string constant. - * <p> - * Note: This method is not to be confused with toString() which returns the - * term in some string representation, whatever data it may hold. + * * Asserts isString(). + * + * @apiNote This method is not to be confused with toString() which returns + * the term in some string representation, whatever data it may hold. */ public String getStringValue() { @@ -623,9 +624,9 @@ public class Term extends AbstractPointer implements Comparable<Term>, Iterable< /** * Asserts isSequenceValue(). - * Note that it is usually necessary for sequences to call - * `Solver::simplify()` to turn a sequence that is constructed by, e.g., - * concatenation of unit sequences, into a sequence value. + * @apiNote It is usually necessary for sequences to call + * `Solver::simplify()` to turn a sequence that is constructed by, + * e.g., concatenation of unit sequences, into a sequence value. * @return the representation of a sequence value as a vector of terms. */ public Term[] getSequenceValue() diff --git a/src/api/java/jni/datatype.cpp b/src/api/java/jni/datatype.cpp index 3f340c93c..6cc8ba58e 100644 --- a/src/api/java/jni/datatype.cpp +++ b/src/api/java/jni/datatype.cpp @@ -114,6 +114,28 @@ JNIEXPORT jint JNICALL Java_io_github_cvc5_api_Datatype_getNumConstructors( /* * Class: io_github_cvc5_api_Datatype + * Method: getParameters + * Signature: (J)[J + */ +JNIEXPORT jlongArray JNICALL Java_io_github_cvc5_api_Datatype_getParameters( + JNIEnv* env, jobject, jlong pointer) +{ + CVC5_JAVA_API_TRY_CATCH_BEGIN; + Datatype* current = (Datatype*)pointer; + std::vector<Sort> sorts = current->getParameters(); + std::vector<jlong> sortPointers(sorts.size()); + for (size_t i = 0; i < sorts.size(); i++) + { + sortPointers[i] = reinterpret_cast<jlong>(new Sort(sorts[i])); + } + jlongArray ret = env->NewLongArray(sorts.size()); + env->SetLongArrayRegion(ret, 0, sorts.size(), sortPointers.data()); + return ret; + CVC5_JAVA_API_TRY_CATCH_END_RETURN(env, nullptr); +} + +/* + * Class: io_github_cvc5_api_Datatype * Method: isParametric * Signature: (J)Z */ diff --git a/src/api/java/jni/datatype_constructor.cpp b/src/api/java/jni/datatype_constructor.cpp index 7fe5f21c6..de9e4fa4c 100644 --- a/src/api/java/jni/datatype_constructor.cpp +++ b/src/api/java/jni/datatype_constructor.cpp @@ -65,17 +65,17 @@ Java_io_github_cvc5_api_DatatypeConstructor_getConstructorTerm(JNIEnv* env, /* * Class: io_github_cvc5_api_DatatypeConstructor - * Method: getSpecializedConstructorTerm + * Method: getInstantiatedConstructorTerm * Signature: (JJ)J */ JNIEXPORT jlong JNICALL -Java_io_github_cvc5_api_DatatypeConstructor_getSpecializedConstructorTerm( +Java_io_github_cvc5_api_DatatypeConstructor_getInstantiatedConstructorTerm( JNIEnv* env, jobject, jlong pointer, jlong retSortPointer) { CVC5_JAVA_API_TRY_CATCH_BEGIN; DatatypeConstructor* current = (DatatypeConstructor*)pointer; Sort* sort = (Sort*)retSortPointer; - Term* retPointer = new Term(current->getSpecializedConstructorTerm(*sort)); + Term* retPointer = new Term(current->getInstantiatedConstructorTerm(*sort)); return (jlong)retPointer; CVC5_JAVA_API_TRY_CATCH_END_RETURN(env, 0); } diff --git a/src/api/parsekinds.py b/src/api/parsekinds.py index 14762c24c..db72b20c9 100644 --- a/src/api/parsekinds.py +++ b/src/api/parsekinds.py @@ -22,7 +22,7 @@ handle nested '#if 0' pairs. """ from collections import OrderedDict - +import textwrap ##################### Useful Constants ################ OCB = '{' @@ -120,19 +120,19 @@ class KindsParser: def format_comment(self, comment): ''' - Removes the C++ syntax for block comments and returns just the text + Removes the C++ syntax for block comments and returns just the text. ''' - assert comment[0] == '/', \ - "Expecting to start with / but got %s" % comment[0] - assert comment[-1] == '/', \ - "Expecting to end with / but got %s" % comment[-1] - res = "" - for line in comment.strip("/* \t").split("\n"): - line = line.strip("*") - if line: - res += line - res += "\n" - return res + assert comment[:2] == '/*', \ + "Expecting to start with /* but got \"{}\"".format(comment[:2]) + assert comment[-2:] == '*/', \ + "Expecting to end with */ but got \"{}\"".format(comment[-2:]) + comment = comment[2:-2].strip('*\n') # /** ... */ -> ... + comment = textwrap.dedent(comment) # remove indentation + comment = comment.replace('\n*', '\n') # remove leading "*"" + comment = textwrap.dedent(comment) # remove indentation + comment = comment.replace('\\rst', '').replace('\\endrst', '') + comment = comment.strip() # remove leading and trailing spaces + return comment def ignore_block(self, line): ''' diff --git a/src/api/python/CMakeLists.txt b/src/api/python/CMakeLists.txt index 32022effe..bcf5d3379 100644 --- a/src/api/python/CMakeLists.txt +++ b/src/api/python/CMakeLists.txt @@ -64,6 +64,7 @@ add_custom_command( --kinds-file-prefix "${CMAKE_CURRENT_BINARY_DIR}/cvc5kinds" DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/genkinds.py" + "${PROJECT_SOURCE_DIR}/src/api/parsekinds.py" "${PROJECT_SOURCE_DIR}/src/api/cpp/cvc5_kind.h" ) diff --git a/src/api/python/__init__.py.in b/src/api/python/__init__.py.in index 9116976c3..8ce03e26d 100644 --- a/src/api/python/__init__.py.in +++ b/src/api/python/__init__.py.in @@ -1,4 +1,2 @@ import sys from .pycvc5 import * -# fake a submodule for dotted imports, e.g. from pycvc5.kinds import * -sys.modules['%s.%s'%(__name__, kinds.__name__)] = kinds diff --git a/src/api/python/cvc5.pxd b/src/api/python/cvc5.pxd index f5dc2aca2..2baed575a 100644 --- a/src/api/python/cvc5.pxd +++ b/src/api/python/cvc5.pxd @@ -51,6 +51,7 @@ cdef extern from "api/cpp/cvc5.h" namespace "cvc5::api": DatatypeSelector getSelector(const string& name) except + string getName() except + size_t getNumConstructors() except + + vector[Sort] getParameters() except + bint isParametric() except + bint isCodatatype() except + bint isTuple() except + @@ -76,7 +77,7 @@ cdef extern from "api/cpp/cvc5.h" namespace "cvc5::api": DatatypeSelector operator[](const string& name) except + string getName() except + Term getConstructorTerm() except + - Term getSpecializedConstructorTerm(const Sort& retSort) except + + Term getInstantiatedConstructorTerm(const Sort& retSort) except + Term getTesterTerm() except + size_t getNumSelectors() except + DatatypeSelector getSelector(const string& name) except + diff --git a/src/api/python/cvc5.pxi b/src/api/python/cvc5.pxi index aa207cd40..5c75047ef 100644 --- a/src/api/python/cvc5.pxi +++ b/src/api/python/cvc5.pxi @@ -153,6 +153,18 @@ cdef class Datatype: """ return self.cd.getNumConstructors() + def getParameters(self): + """ + :return: the parameters of this datatype, if it is parametric. An + exception is thrown if this datatype is not parametric. + """ + param_sorts = [] + for s in self.cd.getParameters(): + sort = Sort(self.solver) + sort.csort = s + param_sorts.append(sort) + return param_sorts + def isParametric(self): """:return: True if this datatype is parametric.""" return self.cd.isParametric() @@ -233,15 +245,17 @@ cdef class DatatypeConstructor: term.cterm = self.cdc.getConstructorTerm() return term - def getSpecializedConstructorTerm(self, Sort retSort): + def getInstantiatedConstructorTerm(self, Sort retSort): """ - Specialized method for parametric datatypes (see :cpp:func:`DatatypeConstructor::getSpecializedConstructorTerm() <cvc5::api::DatatypeConstructor::getSpecializedConstructorTerm>`). + Specialized method for parametric datatypes (see + :cpp:func:`DatatypeConstructor::getInstantiatedConstructorTerm() + <cvc5::api::DatatypeConstructor::getInstantiatedConstructorTerm>`). :param retSort: the desired return sort of the constructor :return: the constructor operator as a term. """ cdef Term term = Term(self.solver) - term.cterm = self.cdc.getSpecializedConstructorTerm(retSort.csort) + term.cterm = self.cdc.getInstantiatedConstructorTerm(retSort.csort) return term def getTesterTerm(self): @@ -464,7 +478,7 @@ cdef class Op: """ :return: the kind of this operator. """ - return kind(<int> self.cop.getKind()) + return Kind(<int> self.cop.getKind()) def isIndexed(self): """ @@ -982,7 +996,7 @@ cdef class Solver: cdef vector[c_Term] v op = kind_or_op - if isinstance(kind_or_op, kind): + if isinstance(kind_or_op, Kind): op = self.mkOp(kind_or_op) if len(args) == 0: @@ -1012,7 +1026,7 @@ cdef class Solver: return result @expand_list_arg(num_req_args=0) - def mkOp(self, kind k, *args): + def mkOp(self, k, *args): """ Supports the following uses: @@ -1027,27 +1041,27 @@ cdef class Solver: cdef vector[uint32_t] v if len(args) == 0: - op.cop = self.csolver.mkOp(k.k) + op.cop = self.csolver.mkOp(<c_Kind> k.value) elif len(args) == 1: if isinstance(args[0], str): - op.cop = self.csolver.mkOp(k.k, + op.cop = self.csolver.mkOp(<c_Kind> k.value, <const string &> args[0].encode()) elif isinstance(args[0], int): - op.cop = self.csolver.mkOp(k.k, <int?> args[0]) + op.cop = self.csolver.mkOp(<c_Kind> k.value, <int?> args[0]) elif isinstance(args[0], list): for a in args[0]: if a < 0 or a >= 2 ** 31: raise ValueError("Argument {} must fit in a uint32_t".format(a)) v.push_back((<uint32_t?> a)) - op.cop = self.csolver.mkOp(k.k, <const vector[uint32_t]&> v) + op.cop = self.csolver.mkOp(<c_Kind> k.value, <const vector[uint32_t]&> v) else: raise ValueError("Unsupported signature" " mkOp: {}".format(" X ".join([str(k), str(args[0])]))) elif len(args) == 2: if isinstance(args[0], int) and isinstance(args[1], int): - op.cop = self.csolver.mkOp(k.k, <int> args[0], <int> args[1]) + op.cop = self.csolver.mkOp(<c_Kind> k.value, <int> args[0], <int> args[1]) else: raise ValueError("Unsupported signature" " mkOp: {}".format(" X ".join([k, args[0], args[1]]))) @@ -2439,16 +2453,16 @@ cdef class Sort: def isFunctionLike(self): """ - Is this a function-LIKE sort? + Is this a function-LIKE sort? - Anything function-like except arrays (e.g., datatype selectors) is - considered a function here. Function-like terms can not be the argument - or return value for any term that is function-like. - This is mainly to avoid higher order. + Anything function-like except arrays (e.g., datatype selectors) is + considered a function here. Function-like terms can not be the argument + or return value for any term that is function-like. + This is mainly to avoid higher order. - Note that arrays are explicitly not considered function-like here. + .. note:: Arrays are explicitly not considered function-like here. - :return: True if this is a function-like sort + :return: True if this is a function-like sort """ return self.csort.isFunctionLike() @@ -2706,7 +2720,14 @@ cdef class Sort: def getDatatypeParamSorts(self): """ - :return: the parameter sorts of a datatype sort + Return the parameters of a parametric datatype sort. If this sort + is a non-instantiated parametric datatype, this returns the + parameter sorts of the underlying datatype. If this sort is an + instantiated parametric datatype, then this returns the sort + parameters that were used to construct the sort via + :py:meth:`instantiate()`. + + :return: the parameter sorts of a parametric datatype sort """ param_sorts = [] for s in self.csort.getDatatypeParamSorts(): @@ -2801,7 +2822,7 @@ cdef class Term: def getKind(self): """:return: the :py:class:`pycvc5.Kind` of this term.""" - return kind(<int> self.cterm.getKind()) + return Kind(<int> self.cterm.getKind()) def getSort(self): """:return: the :py:class:`pycvc5.Sort` of this term.""" @@ -2848,10 +2869,10 @@ cdef class Term: def getOp(self): """ - Note: This is safe to call when :py:meth:`hasOp()` returns True. + .. note:: This is safe to call when :py:meth:`hasOp()` returns True. - :return: the :py:class:`pycvc5.Op` used to create this Term. - """ + :return: the :py:class:`pycvc5.Op` used to create this Term. + """ cdef Op op = Op(self.solver) op.cop = self.cterm.getOp() return op @@ -2981,13 +3002,15 @@ cdef class Term: def getStringValue(self): """ - Note: This method is not to be confused with :py:meth:`__str__()` which - returns the term in some string representation, whatever data it - may hold. - Asserts :py:meth:`isStringValue()`. + Asserts :py:meth:`isStringValue()`. - :return: the string term as a native string value. - """ + .. note:: + This method is not to be confused with :py:meth:`__str__()` which + returns the term in some string representation, whatever data it + may hold. + + :return: the string term as a native string value. + """ cdef Py_ssize_t size cdef c_wstring s = self.cterm.getStringValue() return PyUnicode_FromWideChar(s.data(), s.size()) @@ -3053,19 +3076,23 @@ cdef class Term: def isSetValue(self): """ - A term is a set value if it is considered to be a (canonical) constant set - value. A canonical set value is one whose AST is: - - (union (singleton c1) ... (union (singleton c_{n-1}) (singleton c_n)))) - - where ``c1 ... cn`` are values ordered by id such that ``c1 > ... > cn`` (see - also :cpp:func:`cvc5::api::Term::operator>()`). - - Note that a universe set term ``(kind SET_UNIVERSE)`` is not considered to be + A term is a set value if it is considered to be a (canonical) constant + set value. A canonical set value is one whose AST is: + + .. code:: + + (union + (singleton c1) ... (union (singleton c_{n-1}) (singleton c_n)))) + + where ``c1 ... cn`` are values ordered by id such that + ``c1 > ... > cn`` (see also :cpp:func:`cvc5::api::Term::operator>()`). + + .. note:: + A universe set term ``(kind SET_UNIVERSE)`` is not considered to be a set value. - :return: True if the term is a set value. - """ + :return: True if the term is a set value. + """ return self.cterm.isSetValue() def getSetValue(self): @@ -3087,14 +3114,15 @@ cdef class Term: def getSequenceValue(self): """ - Asserts :py:meth:`isSequenceValue()`. - - Note that it is usually necessary for sequences to call - :py:meth:`Solver.simplify()` to turn a sequence that is constructed by, e.g., - concatenation of unit sequences, into a sequence value. - - :return: the representation of a sequence value as a vector of terms. - """ + Asserts :py:meth:`isSequenceValue()`. + + .. note:: + It is usually necessary for sequences to call + :py:meth:`Solver.simplify()` to turn a sequence that is constructed + by, e.g., concatenation of unit sequences, into a sequence value. + + :return: the representation of a sequence value as a vector of terms. + """ elems = [] for e in self.cterm.getSequenceValue(): term = Term(self.solver) @@ -3137,7 +3165,7 @@ cdef class Term: def isRealValue(self): """ - Note that a term of kind PI is not considered to be a real value. + .. note:: A term of kind PI is not considered to be a real value. :return: True iff this term is a rational value. """ @@ -3199,13 +3227,13 @@ cdef class Term: # on a constant array while to_visit: t = to_visit.pop() - if t.getKind() == kinds.Store: + if t.getKind().value == c_Kind.STORE: # save the mappings keys.append(t[1].toPythonObj()) values.append(t[2].toPythonObj()) to_visit.append(t[0]) else: - assert t.getKind() == kinds.ConstArray + assert t.getKind().value == c_Kind.CONST_ARRAY base_value = t.getConstArrayBase().toPythonObj() assert len(keys) == len(values) diff --git a/src/api/python/genkinds.py.in b/src/api/python/genkinds.py.in index 8c8de35ac..4af1f526e 100644 --- a/src/api/python/genkinds.py.in +++ b/src/api/python/genkinds.py.in @@ -39,97 +39,49 @@ DEFAULT_PREFIX = 'kinds' ################ Comments and Macro Tokens ############ PYCOMMENT = '#' -####################### Code Blocks ################### -CDEF_KIND = " cdef Kind " - KINDS_PXD_TOP = \ r"""cdef extern from "api/cpp/cvc5_kind.h" namespace "cvc5::api": - cdef cppclass Kind: - pass - - -# Kind declarations: See cpp/cvc5_kind.h for additional information -cdef extern from "api/cpp/cvc5_kind.h" namespace "cvc5::api::Kind": + enum Kind: """ KINDS_PXI_TOP = \ -r"""# distutils: language = c++ +r'''# distutils: language = c++ # distutils: extra_compile_args = -std=c++11 -from cvc5kinds cimport * -import sys -from types import ModuleType - -from libcpp.string cimport string -from libcpp.unordered_map cimport unordered_map - -# these maps are used for creating a kind -# it is needed for dynamically making a kind -# e.g. for getKind() -cdef unordered_map[int, Kind] int2kind -cdef unordered_map[int, string] int2name - -cdef class kind: - cdef Kind k - cdef str name - def __cinit__(self, int kindint): - self.k = int2kind[kindint] - self.name = str(int2name[kindint]) - - def __eq__(self, kind other): - return (<int> self.k) == (<int> other.k) - - def __ne__(self, kind other): - return (<int> self.k) != (<int> other.k) +from cvc5kinds cimport Kind as c_Kind +from enum import Enum - def __hash__(self): - return hash((<int> self.k, self.name)) - - def __str__(self): - return self.name - - def __repr__(self): - return self.name - - def as_int(self): - return <int> self.k - -# create a kinds submodule -kinds = ModuleType('kinds') -kinds.__file__ = kinds.__name__ + ".py" -""" - -KINDS_ATTR_TEMPLATE = \ -r""" -int2kind[<int> {kind}] = {kind} -int2name[<int> {kind}] = b"{name}" -cdef kind {name} = kind(<int> {kind}) -setattr(kinds, "{name}", {name}) -""" +class Kind(Enum): + """The Kinds enum""" + def __new__(cls, value, doc): + self = object.__new__(cls) + self._value_ = value + self.__doc__ = doc + return self +''' +KINDS_ATTR_TEMPLATE = r''' {name}=c_Kind.{kind}, """{doc}""" +''' def gen_pxd(parser: KindsParser, filename): - f = open(filename, "w") - f.write(KINDS_PXD_TOP) - # include the format_name docstring in the generated file - # could be helpful for users to see the formatting rules - for line in parser.format_name.__doc__.split(NL): - f.write(PYCOMMENT) - if not line.isspace(): - f.write(line) - f.write(NL) - for kind in parser.kinds: - f.write(CDEF_KIND + kind + NL) - f.close() + with open(filename, "w") as f: + # include the format_name docstring in the generated file + # could be helpful for users to see the formatting rules + for line in parser.format_name.__doc__.split(NL): + f.write(PYCOMMENT) + if not line.isspace(): + f.write(line) + f.write(NL) + f.write(KINDS_PXD_TOP) + for kind in parser.kinds: + f.write(' {},\n'.format(kind)) def gen_pxi(parser : KindsParser, filename): - f = open(filename, "w") - pxi = KINDS_PXI_TOP - for kind, name in parser.kinds.items(): - pxi += KINDS_ATTR_TEMPLATE.format(name=name, kind=kind) - f.write(pxi) - f.close() - + with open(filename, "w") as f: + f.write(KINDS_PXI_TOP) + for kind, name in parser.kinds.items(): + doc = parser.kinds_doc.get(name, '') + f.write(KINDS_ATTR_TEMPLATE.format(name=name, kind=kind, doc=doc)) if __name__ == "__main__": parser = argparse.ArgumentParser('Read a kinds header file and generate a ' diff --git a/src/base/CMakeLists.txt b/src/base/CMakeLists.txt index d2c763159..8769ac323 100644 --- a/src/base/CMakeLists.txt +++ b/src/base/CMakeLists.txt @@ -48,7 +48,6 @@ file(GLOB_RECURSE source_files ${PROJECT_SOURCE_DIR}/src/*.cc ${PROJECT_SOURCE_DIR}/src/*.h ${PROJECT_SOURCE_DIR}/src/*.g) -string(REPLACE ";" " " source_files_list "${source_files}") add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Debug_tags.h diff --git a/src/base/output.h b/src/base/output.h index 7bfae7bca..9ae5ad8db 100644 --- a/src/base/output.h +++ b/src/base/output.h @@ -357,82 +357,6 @@ class __cvc5_true inline operator bool() { return true; } }; /* __cvc5_true */ -#if defined(CVC5_DEBUG) && defined(CVC5_TRACING) - -class ScopedDebug -{ - std::string d_tag; - bool d_oldSetting; - -public: - - ScopedDebug(std::string tag, bool newSetting = true) : - d_tag(tag) { - d_oldSetting = Debug.isOn(d_tag); - if(newSetting) { - Debug.on(d_tag); - } else { - Debug.off(d_tag); - } - } - - ~ScopedDebug() { - if(d_oldSetting) { - Debug.on(d_tag); - } else { - Debug.off(d_tag); - } - } -}; /* class ScopedDebug */ - -#else /* CVC5_DEBUG && CVC5_TRACING */ - -class ScopedDebug -{ - public: - ScopedDebug(std::string tag, bool newSetting = true) {} -}; /* class ScopedDebug */ - -#endif /* CVC5_DEBUG && CVC5_TRACING */ - -#ifdef CVC5_TRACING - -class ScopedTrace -{ - std::string d_tag; - bool d_oldSetting; - -public: - - ScopedTrace(std::string tag, bool newSetting = true) : - d_tag(tag) { - d_oldSetting = Trace.isOn(d_tag); - if(newSetting) { - Trace.on(d_tag); - } else { - Trace.off(d_tag); - } - } - - ~ScopedTrace() { - if(d_oldSetting) { - Trace.on(d_tag); - } else { - Trace.off(d_tag); - } - } -}; /* class ScopedTrace */ - -#else /* CVC5_TRACING */ - -class ScopedTrace -{ - public: - ScopedTrace(std::string tag, bool newSetting = true) {} -}; /* class ScopedTrace */ - -#endif /* CVC5_TRACING */ - /** * Pushes an indentation level on construction, pop on destruction. * Useful for tracing recursive functions especially, but also can be @@ -442,23 +366,11 @@ class ScopedTrace class IndentedScope { Cvc5ostream d_out; - public: - inline IndentedScope(Cvc5ostream out); - inline ~IndentedScope(); + inline IndentedScope(Cvc5ostream out) : d_out(out) { d_out << push; } + inline ~IndentedScope() { d_out << pop; } }; /* class IndentedScope */ -#if defined(CVC5_DEBUG) && defined(CVC5_TRACING) -inline IndentedScope::IndentedScope(Cvc5ostream out) : d_out(out) -{ - d_out << push; -} -inline IndentedScope::~IndentedScope() { d_out << pop; } -#else /* CVC5_DEBUG && CVC5_TRACING */ -inline IndentedScope::IndentedScope(Cvc5ostream out) {} -inline IndentedScope::~IndentedScope() {} -#endif /* CVC5_DEBUG && CVC5_TRACING */ - } // namespace cvc5 #endif /* CVC5__OUTPUT_H */ diff --git a/src/base/versioninfo.cpp.in b/src/base/versioninfo.cpp.in index 0e873d7b3..af4129f6d 100644 --- a/src/base/versioninfo.cpp.in +++ b/src/base/versioninfo.cpp.in @@ -19,4 +19,4 @@ const bool ::cvc5::Configuration::GIT_BUILD = @GIT_BUILD@; const bool ::cvc5::Configuration::CVC5_IS_RELEASE = @CVC5_IS_RELEASE@; const char* const ::cvc5::Configuration::CVC5_VERSION = "@CVC5_VERSION@"; const char* const ::cvc5::Configuration::CVC5_FULL_VERSION = "@CVC5_FULL_VERSION@"; -const char* const ::cvc5::Configuration::CVC5_GIT_INFO = "@CVC5_GIT_INFO@";
\ No newline at end of file +const char* const ::cvc5::Configuration::CVC5_GIT_INFO = "@CVC5_GIT_INFO@"; diff --git a/src/expr/bound_var_manager.cpp b/src/expr/bound_var_manager.cpp index 53c87fb97..450b2358f 100644 --- a/src/expr/bound_var_manager.cpp +++ b/src/expr/bound_var_manager.cpp @@ -53,7 +53,7 @@ Node BoundVarManager::getCacheValue(TNode cv1, TNode cv2, size_t i) Node BoundVarManager::getCacheValue(size_t i) { - return NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(i)); + return NodeManager::currentNM()->mkConstInt(Rational(i)); } Node BoundVarManager::getCacheValue(TNode cv, size_t i) diff --git a/src/expr/dtype.cpp b/src/expr/dtype.cpp index 5b2503454..4902b1562 100644 --- a/src/expr/dtype.cpp +++ b/src/expr/dtype.cpp @@ -867,7 +867,7 @@ Node DType::getSharedSelector(TypeNode dtt, TypeNode t, size_t index) const ss << "sel_" << index; SkolemManager* sm = nm->getSkolemManager(); TypeNode stype = nm->mkSelectorType(dtt, t); - Node nindex = nm->mkConst(CONST_RATIONAL, Rational(index)); + Node nindex = nm->mkConstInt(Rational(index)); s = sm->mkSkolemFunction(SkolemFunId::SHARED_SELECTOR, stype, nindex); d_sharedSel[dtt][t][index] = s; Trace("dt-shared-sel") << "Made " << s << " of type " << dtt << " -> " << t diff --git a/src/expr/dtype_cons.cpp b/src/expr/dtype_cons.cpp index 6ba3970c9..a054dffb8 100644 --- a/src/expr/dtype_cons.cpp +++ b/src/expr/dtype_cons.cpp @@ -83,6 +83,16 @@ Node DTypeConstructor::getConstructor() const return d_constructor; } +Node DTypeConstructor::getInstantiatedConstructor(TypeNode returnType) const +{ + Assert(isResolved()); + NodeManager* nm = NodeManager::currentNM(); + return nm->mkNode( + kind::APPLY_TYPE_ASCRIPTION, + nm->mkConst(AscriptionType(getInstantiatedConstructorType(returnType))), + d_constructor); +} + Node DTypeConstructor::getTester() const { Assert(isResolved()); @@ -116,12 +126,12 @@ unsigned DTypeConstructor::getWeight() const size_t DTypeConstructor::getNumArgs() const { return d_args.size(); } -TypeNode DTypeConstructor::getSpecializedConstructorType( +TypeNode DTypeConstructor::getInstantiatedConstructorType( TypeNode returnType) const { Assert(isResolved()); Assert(returnType.isDatatype()) - << "DTypeConstructor::getSpecializedConstructorType: expected datatype, " + << "DTypeConstructor::getInstantiatedConstructorType: expected datatype, " "got " << returnType; TypeNode ctn = d_constructor.getType(); @@ -439,7 +449,7 @@ Node DTypeConstructor::computeGroundTerm(TypeNode t, << ", ascribe to " << t << std::endl; groundTerms[0] = nm->mkNode( APPLY_TYPE_ASCRIPTION, - nm->mkConst(AscriptionType(getSpecializedConstructorType(t))), + nm->mkConst(AscriptionType(getInstantiatedConstructorType(t))), groundTerms[0]); groundTerm = nm->mkNode(APPLY_CONSTRUCTOR, groundTerms); } @@ -456,7 +466,7 @@ void DTypeConstructor::computeSharedSelectors(TypeNode domainType) const TypeNode ctype; if (domainType.isParametricDatatype()) { - ctype = getSpecializedConstructorType(domainType); + ctype = getInstantiatedConstructorType(domainType); } else { diff --git a/src/expr/dtype_cons.h b/src/expr/dtype_cons.h index a6268aad1..657f6b7b8 100644 --- a/src/expr/dtype_cons.h +++ b/src/expr/dtype_cons.h @@ -85,6 +85,12 @@ class DTypeConstructor * DType must be resolved. */ Node getConstructor() const; + /** + * Get the specialized constructor term of this constructor, which is + * the constructor wrapped in a APPLY_TYPE_ASCRIPTION. This is required + * for constructing applications of constructors for parametric datatypes. + */ + Node getInstantiatedConstructor(TypeNode returnType) const; /** * Get the tester operator of this constructor. The @@ -139,7 +145,7 @@ class DTypeConstructor * "cons" constructor type for lists of int---namely, * "int -> list[int] -> list[int]". */ - TypeNode getSpecializedConstructorType(TypeNode returnType) const; + TypeNode getInstantiatedConstructorType(TypeNode returnType) const; /** * Return the cardinality of this constructor (the product of the diff --git a/src/expr/nary_term_util.cpp b/src/expr/nary_term_util.cpp index a872c64c7..03ce637e4 100644 --- a/src/expr/nary_term_util.cpp +++ b/src/expr/nary_term_util.cpp @@ -119,10 +119,10 @@ Node getNullTerminator(Kind k, TypeNode tn) case OR: nullTerm = nm->mkConst(false); break; case AND: case SEP_STAR: nullTerm = nm->mkConst(true); break; - case PLUS: nullTerm = nm->mkConst(CONST_RATIONAL, Rational(0)); break; + case PLUS: nullTerm = nm->mkConstRealOrInt(tn, Rational(0)); break; case MULT: case NONLINEAR_MULT: - nullTerm = nm->mkConst(CONST_RATIONAL, Rational(1)); + nullTerm = nm->mkConstRealOrInt(tn, Rational(1)); break; case STRING_CONCAT: // handles strings and sequences diff --git a/src/expr/node_manager.h b/src/expr/node_manager.h index 6435c488a..b2682661e 100644 --- a/src/expr/node_manager.h +++ b/src/expr/node_manager.h @@ -579,6 +579,12 @@ class NodeManager */ Node mkConstInt(const Rational& r); + /** + * Make constant real or int, which calls one of the above methods based + * on the type tn. + */ + Node mkConstRealOrInt(const TypeNode& tn, const Rational& r); + /** Create a node with children. */ TypeNode mkTypeNode(Kind kind, TypeNode child1); TypeNode mkTypeNode(Kind kind, TypeNode child1, TypeNode child2); diff --git a/src/expr/node_manager_template.cpp b/src/expr/node_manager_template.cpp index b00d79322..4f235a53a 100644 --- a/src/expr/node_manager_template.cpp +++ b/src/expr/node_manager_template.cpp @@ -1298,4 +1298,15 @@ Node NodeManager::mkConstInt(const Rational& r) return mkConst(kind::CONST_RATIONAL, r); } +Node NodeManager::mkConstRealOrInt(const TypeNode& tn, const Rational& r) +{ + Assert(tn.isRealOrInt()) << "Expected real or int for mkConstRealOrInt, got " + << tn; + if (tn.isReal()) + { + return mkConstReal(r); + } + return mkConstInt(r); +} + } // namespace cvc5 diff --git a/src/expr/sequence.cpp b/src/expr/sequence.cpp index 6b15f33e0..82c83e0ea 100644 --- a/src/expr/sequence.cpp +++ b/src/expr/sequence.cpp @@ -371,13 +371,13 @@ std::ostream& operator<<(std::ostream& os, const Sequence& s) size_t SequenceHashFunction::operator()(const Sequence& s) const { - size_t ret = 0; + uint64_t ret = fnv1a::offsetBasis; const std::vector<Node>& vec = s.getVec(); for (const Node& n : vec) { ret = fnv1a::fnv1a_64(ret, std::hash<Node>()(n)); } - return ret; + return static_cast<size_t>(ret); } } // namespace cvc5 diff --git a/src/expr/skolem_manager.cpp b/src/expr/skolem_manager.cpp index 476517820..f08ffc5f4 100644 --- a/src/expr/skolem_manager.cpp +++ b/src/expr/skolem_manager.cpp @@ -67,6 +67,12 @@ const char* toString(SkolemFunId id) case SkolemFunId::SK_FIRST_MATCH: return "SK_FIRST_MATCH"; case SkolemFunId::SK_FIRST_MATCH_POST: return "SK_FIRST_MATCH_POST"; case SkolemFunId::RE_UNFOLD_POS_COMPONENT: return "RE_UNFOLD_POS_COMPONENT"; + case SkolemFunId::SEQ_MODEL_BASE_ELEMENT: return "SEQ_MODEL_BASE_ELEMENT"; + case SkolemFunId::BAGS_CARD_CARDINALITY: return "BAGS_CARD_CARDINALITY"; + case SkolemFunId::BAGS_CARD_ELEMENTS: return "BAGS_CARD_ELEMENTS"; + case SkolemFunId::BAGS_CARD_N: return "BAGS_CARD_N"; + case SkolemFunId::BAGS_CARD_UNION_DISJOINT: + return "BAGS_CARD_UNION_DISJOINT"; case SkolemFunId::BAGS_CHOOSE: return "BAGS_CHOOSE"; case SkolemFunId::BAGS_FOLD_CARD: return "BAGS_FOLD_CARD"; case SkolemFunId::BAGS_FOLD_COMBINE: return "BAGS_FOLD_COMBINE"; diff --git a/src/expr/skolem_manager.h b/src/expr/skolem_manager.h index 780413d17..cca28ccf0 100644 --- a/src/expr/skolem_manager.h +++ b/src/expr/skolem_manager.h @@ -112,6 +112,12 @@ enum class SkolemFunId * i = 0, ..., n. */ RE_UNFOLD_POS_COMPONENT, + /** Sequence model construction, element for base */ + SEQ_MODEL_BASE_ELEMENT, + BAGS_CARD_CARDINALITY, + BAGS_CARD_ELEMENTS, + BAGS_CARD_N, + BAGS_CARD_UNION_DISJOINT, BAGS_FOLD_CARD, BAGS_FOLD_COMBINE, BAGS_FOLD_ELEMENTS, diff --git a/src/expr/term_context.cpp b/src/expr/term_context.cpp index 7f8aa9eac..02ec8981b 100644 --- a/src/expr/term_context.cpp +++ b/src/expr/term_context.cpp @@ -131,7 +131,7 @@ uint32_t PolarityTermContext::getValue(bool hasPol, bool pol) void PolarityTermContext::getFlags(uint32_t val, bool& hasPol, bool& pol) { - hasPol = val == 0; + hasPol = val != 0; pol = val == 2; } diff --git a/src/expr/term_context_node.cpp b/src/expr/term_context_node.cpp index 3be9faad0..91e6dbfd3 100644 --- a/src/expr/term_context_node.cpp +++ b/src/expr/term_context_node.cpp @@ -54,7 +54,7 @@ Node TCtxNode::getNodeHash() const { return computeNodeHash(d_node, d_val); } Node TCtxNode::computeNodeHash(Node n, uint32_t val) { NodeManager* nm = NodeManager::currentNM(); - return nm->mkNode(kind::SEXPR, n, nm->mkConst(CONST_RATIONAL, Rational(val))); + return nm->mkNode(kind::SEXPR, n, nm->mkConstInt(Rational(val))); } Node TCtxNode::decomposeNodeHash(Node h, uint32_t& val) diff --git a/src/expr/term_context_node.h b/src/expr/term_context_node.h index ac89b0d71..9e4fe90de 100644 --- a/src/expr/term_context_node.h +++ b/src/expr/term_context_node.h @@ -54,7 +54,7 @@ class TCtxNode Node getNodeHash() const; /** * Get node hash, which is a unique node representation of the pair (n, val). - * In particular, this returns (SEXPR n (CONST_RATIONAL val)). + * In particular, this returns (SEXPR n (CONST_INTEGER val)). */ static Node computeNodeHash(Node n, uint32_t val); /** diff --git a/src/options/README.md b/src/options/README.md index 54d7d4878..c3e018215 100644 --- a/src/options/README.md +++ b/src/options/README.md @@ -64,7 +64,6 @@ Option types Though not enforced explicitly, option types are commonly expected to come from a rather restricted set of C++ types: -some options are merely used to have a handler function called and use `void`; Boolean options should use `bool`; numeric options should use one of `int64_t`, `uint64_t` and `double`, possibly using `minimum` and `maximum` to further restrict the options domain; @@ -81,10 +80,9 @@ Handler functions Custom handler functions are used to turn the option value from an `std::string` into the type specified by `type`. Standard handler functions are provided for basic types (`std::string`, `bool`, `int64_t`, `uint64_t`, and `double`) as -well as enums specified by `mode`. A custom handler function needs to be member -function of `options::OptionsHandler` with signature -`{type} {handler}(const std::string& flag, const std::string& optionvalue)`, or -alternatively `void {handler}(const std::string& flag)` if the `type` is `void`. +well as enums specified by `mode`. A custom handler function needs to be a +member function of `options::OptionsHandler` with signature +`{type} {handler}(const std::string& flag, const std::string& optionvalue)`. The parameter `flag` holds the actually used option name, which may be an alias name, and should only be used in user messages. @@ -92,16 +90,14 @@ name, and should only be used in user messages. Predicate functions ------------------- -Predicate functions are used to check whether an option value is valid after it -has been parsed by a (standard or custom) handler function. Like a handler -function, a predicate function needs to be a member function of -`options::OptionsHandler` with signature +Predicate functions are called after an option value has been parsed by a +(standard or custom) handler function. They usually either check whether the +parsed option value is valid, or to trigger some action (e.g. print some +message or set another option). Like a handler function, a predicate function +needs to be a member function of `options::OptionsHandler` with signature `void {predicate}(const std::string& flag, {type} value)`. -If the check fails, the predicate should raise an `OptionException`. - -Note that a predicate function may not only check the value, but may also -trigger some other action. Examples include enabling trace tags or enforcing -dependencies between several options. +A predicate function is expected to raise an `OptionException` if the option +value is not valid for some reason. Mode options @@ -144,15 +140,15 @@ Generated code The entire options setup heavily relies on generating a lot of code from the information retrieved from the `*_options.toml` files. After code generation, files related to options live either in `src/options/` (if not changed) or in -`build/src/options/` (if automatically generated). After all code has been -generated, the entire options setup consists of the following components: +`build/src/options/` (if automatically generated). Additionally, code that is +only needed when using cvc5 on the command line lives in `src/main/` and +`build/src/main`. After all code has been generated, the entire options setup +consists of the following components: -* `options.h`: core `Options` class -* `options_api.h`: utility methods used by the API (`parse()`, `set()`, `get()`, - ...) -* `options_public.h`: utility methods used to access options from outside of - libcvc5 -* `{module}_options.h`: specifics for one single options module +* `options/options.h`: core `Options` class +* `options/options_public.h`: utility methods used by the API (`getNames()`, `get()`, `set()` and `getInfo()`) +* `options/{module}_options.h`: specifics for one single options module +* `main/options.h`: utility methods used by the CLI (`parse()` and `printUsage()`) `Options` class @@ -172,20 +168,13 @@ Option modules -------------- Every option module declares an "option holder" class, which is a simple struct -that has two members for every option (that is not declared as `type = void`): +that has two members for every option (that specifies a `name`): the actual option value as `{option.type} {option.name}` and a Boolean flag -`bool {option.name}__setByUser` that indicates whether the option value was +`bool {option.name}WasSetByUser` that indicates whether the option value was explicitly set by the user. If any of the options of a module is a mode option, the option module also defines an enum class that corresponds to the mode, including `operator<<()` and `stringTo{mode type}`. -For convenience, the option modules also provide methods `void -{module.id}::setDefault{option.name}(Options& opts, {option.type} value)`. Each -such method sets the option value to the given value, if the option was not yet -set by the user, i.e., the `__setByUser` flag is false. Additionally, every -option module exports the `long` option name as `static constexpr const char* -{module.id}::{option.name}__name`. - Full Example ============ @@ -218,6 +207,5 @@ with `--decision-mode=justification`, and similarly from an SMT-LIB input with `(set-option :decision internal)` and `(set-option :decision-mode justification)`. The command-line help for this option looks as follows: - --output-lang=LANG | --output-language=LANG - force output language (default is "auto"; see - --output-lang help) + --decision=MODE | --decision-mode=MODE + choose decision mode, see --decision=help diff --git a/src/options/arith_options.toml b/src/options/arith_options.toml index e5f65684b..5e6796864 100644 --- a/src/options/arith_options.toml +++ b/src/options/arith_options.toml @@ -500,6 +500,14 @@ name = "Arithmetic Theory" help = "whether to use the cylindrical algebraic coverings solver for non-linear arithmetic" [[option]] + name = "nlCadVarElim" + category = "regular" + long = "nl-cad-var-elim" + type = "bool" + default = "false" + help = "whether to eliminate variables using equalities before going into the cylindrical algebraic coverings solver" + +[[option]] name = "nlCadPrune" category = "regular" long = "nl-cad-prune" diff --git a/src/options/base_options.toml b/src/options/base_options.toml index 8255da027..042fd6b8a 100644 --- a/src/options/base_options.toml +++ b/src/options/base_options.toml @@ -63,16 +63,18 @@ name = "Base" category = "common" short = "v" long = "verbose" - type = "void" - handler = "increaseVerbosity" + type = "bool" + alternate = false + predicates = ["increaseVerbosity"] help = "increase verbosity (may be repeated)" [[option]] category = "common" short = "q" long = "quiet" - type = "void" - handler = "decreaseVerbosity" + type = "bool" + alternate = false + predicates = ["decreaseVerbosity"] help = "decrease verbosity (may be repeated)" [[option]] @@ -136,24 +138,23 @@ name = "Base" short = "t" long = "trace=TAG" type = "std::string" - handler = "enableTraceTag" - help = "trace something (e.g. -t pushpop), can repeat" + predicates = ["enableTraceTag"] + help = "trace something (e.g. -t pushpop), can repeat and may contain wildcards like (e.g. -t theory::*)" [[option]] category = "regular" short = "d" long = "debug=TAG" type = "std::string" - handler = "enableDebugTag" + predicates = ["enableDebugTag"] help = "debug something (e.g. -d arith), can repeat" [[option]] - name = "outputTag" short = "o" long = "output=TAG" type = "OutputTag" default = "NONE" - handler = "enableOutputTag" + predicates = ["enableOutputTag"] category = "regular" help = "Enable output tag." help_mode = "Output tags." @@ -241,7 +242,7 @@ name = "Base" category = "expert" long = "rweight=VAL=N" type = "std::string" - handler = "setResourceWeight" + predicates = ["setResourceWeight"] help = "set a single resource weight" [[option]] diff --git a/src/options/managed_streams.cpp b/src/options/managed_streams.cpp index 90090df25..935b75a35 100644 --- a/src/options/managed_streams.cpp +++ b/src/options/managed_streams.cpp @@ -72,12 +72,11 @@ std::string cvc5_errno_failreason() namespace detail { -std::ostream* openOStream(const std::string& filename) +std::unique_ptr<std::ostream> openOStream(const std::string& filename) { errno = 0; - std::ostream* res; - res = new std::ofstream(filename); - if (res == nullptr || !*res) + std::unique_ptr<std::ostream> res = std::make_unique<std::ofstream>(filename); + if (!res || !*res) { std::stringstream ss; ss << "Cannot open file: `" << filename << "': " << cvc5_errno_failreason(); @@ -85,12 +84,11 @@ std::ostream* openOStream(const std::string& filename) } return res; } -std::istream* openIStream(const std::string& filename) +std::unique_ptr<std::istream> openIStream(const std::string& filename) { errno = 0; - std::istream* res; - res = new std::ifstream(filename); - if (res == nullptr || !*res) + std::unique_ptr<std::istream> res = std::make_unique<std::ifstream>(filename); + if (!res || !*res) { std::stringstream ss; ss << "Cannot open file: `" << filename << "': " << cvc5_errno_failreason(); diff --git a/src/options/managed_streams.h b/src/options/managed_streams.h index cf1820de6..830916b2f 100644 --- a/src/options/managed_streams.h +++ b/src/options/managed_streams.h @@ -31,12 +31,12 @@ namespace detail { * Open a file as an output stream and return it as a pointer. The caller * assumes the ownership of the returned pointer. */ -std::ostream* openOStream(const std::string& filename); +std::unique_ptr<std::ostream> openOStream(const std::string& filename); /* * Open a file as an input stream and return it as a pointer. The caller * assumes the ownership of the returned pointer. */ -std::istream* openIStream(const std::string& filename); +std::unique_ptr<std::istream> openIStream(const std::string& filename); } // namespace detail /** @@ -64,13 +64,13 @@ class ManagedStream if constexpr (std::is_same<Stream, std::ostream>::value) { d_nonowned = nullptr; - d_owned.reset(detail::openOStream(value)); + d_owned = detail::openOStream(value); d_description = value; } else if constexpr (std::is_same<Stream, std::istream>::value) { d_nonowned = nullptr; - d_owned.reset(detail::openIStream(value)); + d_owned = detail::openIStream(value); d_description = value; } } diff --git a/src/options/mkoptions.py b/src/options/mkoptions.py index 3022c5d4b..8a7dbf605 100644 --- a/src/options/mkoptions.py +++ b/src/options/mkoptions.py @@ -287,16 +287,13 @@ def generate_get_impl(modules): ret = '{{ std::stringstream s; s << options.{}.{}; return s.str(); }}'.format( module.id, option.name) res.append('if ({}) {}'.format(cond, ret)) - return '\n '.join(res) + return '\n '.join(res) def _set_handlers(option): """Render handler call for options::set().""" if option.handler: - if option.type == 'void': - return 'opts.handler().{}(name)'.format(option.handler) - else: - return 'opts.handler().{}(name, optionarg)'.format(option.handler) + return 'opts.handler().{}(name, optionarg)'.format(option.handler) elif option.mode: return 'stringTo{}(optionarg)'.format(option.type) return 'handlers::handleOption<{}>(name, optionarg)'.format(option.type) @@ -304,9 +301,6 @@ def _set_handlers(option): def _set_predicates(option): """Render predicate calls for options::set().""" - if option.type == 'void': - return [] - assert option.type != 'void' res = [] if option.minimum: res.append( @@ -317,20 +311,11 @@ def _set_predicates(option): 'opts.handler().checkMaximum(name, value, static_cast<{}>({}));' .format(option.type, option.maximum)) res += [ - 'opts.handler().{}(name, value);'.format(x) - for x in option.predicates + 'opts.handler().{}(name, value);'.format(x) for x in option.predicates ] return res -TPL_SET = ''' opts.{module}.{name} = {handler}; - opts.{module}.{name}WasSetByUser = true;''' -TPL_SET_PRED = ''' auto value = {handler}; - {predicates} - opts.{module}.{name} = value; - opts.{module}.{name}WasSetByUser = true;''' - - def generate_set_impl(modules): """Generates the implementation for options::set().""" res = [] @@ -338,31 +323,19 @@ def generate_set_impl(modules): if not option.long: continue cond = ' || '.join(['name == "{}"'.format(x) for x in option.names]) - predicates = _set_predicates(option) if res: - res.append(' }} else if ({}) {{'.format(cond)) + res.append('}} else if ({}) {{'.format(cond)) else: res.append('if ({}) {{'.format(cond)) - if option.name and not (option.handler and option.mode): - if predicates: - res.append( - TPL_SET_PRED.format(module=module.id, - name=option.name, - handler=_set_handlers(option), - predicates='\n '.join(predicates))) - else: - res.append( - TPL_SET.format(module=module.id, - name=option.name, - handler=_set_handlers(option))) - elif option.handler: - h = ' opts.handler().{handler}(name' - if option.type not in ['bool', 'void']: - h += ', optionarg' - h += ');' - res.append( - h.format(handler=option.handler, smtname=option.long_name)) - return '\n'.join(res) + res.append(' auto value = {};'.format(_set_handlers(option))) + for pred in _set_predicates(option): + res.append(' {}'.format(pred)) + if option.name: + res.append(' opts.{module}.{name} = value;'.format( + module=module.id, name=option.name)) + res.append(' opts.{module}.{name}WasSetByUser = true;'.format( + module=module.id, name=option.name)) + return '\n '.join(res) def generate_getinfo_impl(modules): @@ -431,7 +404,7 @@ def generate_module_mode_decl(module): """Generates the declarations of mode enums and utility functions.""" res = [] for option in module.options: - if option.name is None or not option.mode: + if not option.mode: continue values = list(option.mode.keys()) res.append( @@ -523,12 +496,12 @@ def generate_module_mode_impl(module): """Generates the declarations of mode enums and utility functions.""" res = [] for option in module.options: - if option.name is None or not option.mode: + if not option.mode: continue cases = [ 'case {type}::{enum}: return os << "{name}";'.format( type=option.type, enum=enum, name=info[0]['name']) - for enum,info in option.mode.items() + for enum, info in option.mode.items() ] res.append( TPL_MODE_STREAM_OPERATOR.format(type=option.type, @@ -566,7 +539,7 @@ def generate_module_mode_impl(module): def _add_cmdoption(option, name, opts, next_id): fmt = { 'name': name, - 'arg': 'no' if option.type in ['bool', 'void'] else 'required', + 'arg': 'no' if option.type == 'bool' else 'required', 'next_id': next_id } opts.append( @@ -590,7 +563,7 @@ def generate_parsing(modules): needs_impl = True code.append("case '{0}': // -{0}".format(option.short)) short += option.short - if option.type not in ['bool', 'void']: + if option.type != 'bool': short += ':' if option.long: # long option needs_impl = True @@ -609,9 +582,6 @@ def generate_parsing(modules): if option.type == 'bool': code.append(' solver.setOption("{}", "true"); break;'.format( option.long_name)) - elif option.type == 'void': - code.append(' solver.setOption("{}", ""); break;'.format( - option.long_name)) else: code.append( ' solver.setOption("{}", optionarg); break;'.format( @@ -824,14 +794,14 @@ def generate_sphinx_help(modules): def generate_sphinx_output_tags(modules, src_dir, build_dir): """Render help for the --output option for sphinx.""" base = next(filter(lambda m: m.id == 'base', modules)) - opt = next(filter(lambda o: o.name == 'outputTag', base.options)) + opt = next(filter(lambda o: o.long == 'output=TAG', base.options)) # The programoutput extension has weird semantics about the cwd: # https://sphinxcontrib-programoutput.readthedocs.io/en/latest/#usage cwd = '/' + os.path.relpath(build_dir, src_dir) res = [] - for name,info in opt.mode.items(): + for name, info in opt.mode.items(): info = info[0] if 'description' not in info: continue @@ -1002,9 +972,9 @@ class Checker: self.__check_option_long(o, o.long_name) if o.alternate: self.__check_option_long(o, 'no-' + o.long_name) - if o.type in ['bool', 'void'] and '=' in o.long: - self.perr('must not have an argument description', option=o) - if o.type not in ['bool', 'void'] and not '=' in o.long: + if o.type == 'bool' and '=' in o.long: + self.perr('bool options must not have an argument description', option=o) + if o.type != 'bool' and not '=' in o.long: self.perr("needs argument description ('{}=...')", o.long, option=o) diff --git a/src/options/module_template.h b/src/options/module_template.h index c613c1cba..00bf7c0ca 100644 --- a/src/options/module_template.h +++ b/src/options/module_template.h @@ -42,7 +42,7 @@ ${modes_decl}$ struct Holder${id_cap}$ { // clang-format off -${holder_decl}$ + ${holder_decl}$ // clang-format on }; diff --git a/src/options/options_handler.cpp b/src/options/options_handler.cpp index 7af82df42..132525e6d 100644 --- a/src/options/options_handler.cpp +++ b/src/options/options_handler.cpp @@ -18,6 +18,7 @@ #include <cerrno> #include <iostream> #include <ostream> +#include <regex> #include <string> #include "base/check.h" @@ -66,6 +67,40 @@ std::string suggestTags(const std::vector<std::string>& validTags, return didYouMean.getMatchAsString(inputTag); } +/** + * Select all tags from validTags that match the given (globbing) pattern. + * The pattern may contain `*` as wildcards. These are internally converted to + * `.*` and matched using std::regex. If no wildcards are present, regular + * string comparisons are used. + */ +std::vector<std::string> selectTags(const std::vector<std::string>& validTags, std::string pattern) +{ + bool isRegex = false; + size_t pos = 0; + while ((pos = pattern.find('*', pos)) != std::string::npos) + { + pattern.replace(pos, 1, ".*"); + pos += 2; + isRegex = true; + } + std::vector<std::string> results; + if (isRegex) + { + std::regex re(pattern); + std::copy_if(validTags.begin(), validTags.end(), std::back_inserter(results), + [&re](const auto& tag){ return std::regex_match(tag, re); } + ); + } + else + { + if (std::find(validTags.begin(), validTags.end(), pattern) != validTags.end()) + { + results.emplace_back(pattern); + } + } + return results; +} + } // namespace OptionsHandler::OptionsHandler(Options* options) : d_options(options) { } @@ -142,13 +177,13 @@ void OptionsHandler::setVerbosity(const std::string& flag, int value) } } -void OptionsHandler::decreaseVerbosity(const std::string& flag) +void OptionsHandler::decreaseVerbosity(const std::string& flag, bool value) { d_options->base.verbosity -= 1; setVerbosity(flag, d_options->base.verbosity); } -void OptionsHandler::increaseVerbosity(const std::string& flag) +void OptionsHandler::increaseVerbosity(const std::string& flag, bool value) { d_options->base.verbosity += 1; setVerbosity(flag, d_options->base.verbosity); @@ -199,7 +234,8 @@ void OptionsHandler::enableTraceTag(const std::string& flag, { throw OptionException("trace tags not available in non-tracing builds"); } - else if (!Configuration::isTraceTag(optarg)) + auto tags = selectTags(Configuration::getTraceTags(), optarg); + if (tags.empty()) { if (optarg == "help") { @@ -209,10 +245,13 @@ void OptionsHandler::enableTraceTag(const std::string& flag, } throw OptionException( - std::string("trace tag ") + optarg + std::string(" not available.") + std::string("no trace tag matching ") + optarg + std::string(" was found.") + suggestTags(Configuration::getTraceTags(), optarg, {})); } - Trace.on(optarg); + for (const auto& tag: tags) + { + Trace.on(tag); + } } void OptionsHandler::enableDebugTag(const std::string& flag, @@ -247,9 +286,9 @@ void OptionsHandler::enableDebugTag(const std::string& flag, } void OptionsHandler::enableOutputTag(const std::string& flag, - const std::string& optarg) + OutputTag optarg) { - size_t tagid = static_cast<size_t>(stringToOutputTag(optarg)); + size_t tagid = static_cast<size_t>(optarg); Assert(d_options->base.outputTagHolder.size() > tagid) << "Output tag is larger than the bitset that holds it."; d_options->base.outputTagHolder.set(tagid); diff --git a/src/options/options_handler.h b/src/options/options_handler.h index 6f5016c6c..a70a46a4a 100644 --- a/src/options/options_handler.h +++ b/src/options/options_handler.h @@ -22,6 +22,7 @@ #include <sstream> #include <string> +#include "options/base_options.h" #include "options/bv_options.h" #include "options/decision_options.h" #include "options/language.h" @@ -83,9 +84,9 @@ class OptionsHandler /** Apply verbosity to the different output channels */ void setVerbosity(const std::string& flag, int value); /** Decrease verbosity and call setVerbosity */ - void decreaseVerbosity(const std::string& flag); + void decreaseVerbosity(const std::string& flag, bool value); /** Increase verbosity and call setVerbosity */ - void increaseVerbosity(const std::string& flag); + void increaseVerbosity(const std::string& flag, bool value); /** If statistics are disabled, disable statistics sub-options */ void setStats(const std::string& flag, bool value); /** If statistics sub-option is disabled, enable statistics */ @@ -95,7 +96,7 @@ class OptionsHandler /** Enable a particular debug tag */ void enableDebugTag(const std::string& flag, const std::string& optarg); /** Enable a particular output tag */ - void enableOutputTag(const std::string& flag, const std::string& optarg); + void enableOutputTag(const std::string& flag, OutputTag optarg); /** Apply print success flag to the different output channels */ void setPrintSuccess(const std::string& flag, bool value); /** Pass the resource weight specification to the resource manager */ diff --git a/src/options/options_public_template.cpp b/src/options/options_public_template.cpp index a6ab6efde..952b4c7f8 100644 --- a/src/options/options_public_template.cpp +++ b/src/options/options_public_template.cpp @@ -206,7 +206,7 @@ namespace cvc5::options Trace("options") << "set option " << name << " = " << optionarg << std::endl; // clang-format off - ${set_impl}$ + ${set_impl}$ // clang-format on } else diff --git a/src/options/proof_options.toml b/src/options/proof_options.toml index 3eb32060e..8eb2fd783 100644 --- a/src/options/proof_options.toml +++ b/src/options/proof_options.toml @@ -92,6 +92,22 @@ name = "Proof" help = "Allow DSL rewrites and evaluation steps, expand macros, rewrite, substitution, and theory rewrite steps." [[option]] + name = "proofAnnotate" + category = "regular" + long = "proof-annotate" + type = "bool" + default = "false" + help = "add optional annotations to proofs, which enables statistics for inference ids for lemmas and conflicts appearing in final proof" + +[[option]] + name = "proofPruneInput" + category = "regular" + long = "proof-prune-input" + type = "bool" + default = "false" + help = "Prune unused input assumptions from final scope" + +[[option]] name = "proofAletheResPivots" category = "regular" long = "proof-alethe-res-pivots" diff --git a/src/options/smt_options.toml b/src/options/smt_options.toml index 2e2742e73..026c8f494 100644 --- a/src/options/smt_options.toml +++ b/src/options/smt_options.toml @@ -395,6 +395,9 @@ name = "SMT Layer" [[option.mode.BV]] name = "bv" help = "Translate bvand back to bit-vectors" +[[option.mode.BITWISE]] + name = "bitwise" + help = "Introduce a UF operator for bvand, and eagerly add bitwise lemmas" [[option]] name = "BVAndIntegerGranularity" diff --git a/src/options/strings_options.toml b/src/options/strings_options.toml index 46f53147b..74112b286 100644 --- a/src/options/strings_options.toml +++ b/src/options/strings_options.toml @@ -223,3 +223,21 @@ name = "Strings Theory" type = "bool" default = "true" help = "use regular expression inclusion" + +[[option]] + name = "seqArray" + category = "expert" + long = "seq-array=MODE" + type = "SeqArrayMode" + default = "NONE" + help = "use array-inspired solver for sequence updates in eager or lazy mode" + help_mode = "use array-inspired solver for sequence updates in eager or lazy mode" +[[option.mode.LAZY]] + name = "lazy" + help = "use array-inspired solver for sequence updates in lazy mode" +[[option.mode.EAGER]] + name = "eager" + help = "use array-inspired solver for sequence updates in eager mode" +[[option.mode.NONE]] + name = "none" + help = "do not use array-inspired solver for sequence updates" diff --git a/src/parser/parser.cpp b/src/parser/parser.cpp index c94e39748..1481d66fe 100644 --- a/src/parser/parser.cpp +++ b/src/parser/parser.cpp @@ -583,7 +583,7 @@ api::Term Parser::applyTypeAscription(api::Term t, api::Sort s) // lookup by name api::DatatypeConstructor dc = d.getConstructor(t.toString()); // ask the constructor for the specialized constructor term - t = dc.getSpecializedConstructorTerm(s); + t = dc.getInstantiatedConstructorTerm(s); } // the type of t does not match the sort s by design (constructor type // vs datatype type), thus we use an alternative check here. diff --git a/src/parser/smt2/Smt2.g b/src/parser/smt2/Smt2.g index 5924ecde6..41cd4869a 100644 --- a/src/parser/smt2/Smt2.g +++ b/src/parser/smt2/Smt2.g @@ -371,7 +371,8 @@ command [std::unique_ptr<cvc5::Command>* cmd] } | /* check-sat */ CHECK_SAT_TOK { PARSER_STATE->checkThatLogicIsSet(); } - { if (PARSER_STATE->sygus()) { + { + if (PARSER_STATE->sygus()) { PARSER_STATE->parseError("Sygus does not support check-sat command."); } cmd->reset(new CheckSatCommand()); @@ -405,10 +406,6 @@ command [std::unique_ptr<cvc5::Command>* cmd] { cmd->reset(new GetDifficultyCommand); } | /* push */ PUSH_TOK { PARSER_STATE->checkThatLogicIsSet(); } - { if( PARSER_STATE->sygus() ){ - PARSER_STATE->parseError("Sygus does not support push command."); - } - } ( k=INTEGER_LITERAL { unsigned num = AntlrInput::tokenToUnsigned(k); if(num == 0) { @@ -438,10 +435,6 @@ command [std::unique_ptr<cvc5::Command>* cmd] } } ) | POP_TOK { PARSER_STATE->checkThatLogicIsSet(); } - { if( PARSER_STATE->sygus() ){ - PARSER_STATE->parseError("Sygus does not support pop command."); - } - } ( k=INTEGER_LITERAL { unsigned num = AntlrInput::tokenToUnsigned(k); // we don't compare num to PARSER_STATE->scopeLevel() here, since @@ -1371,7 +1364,7 @@ termNonVariable[cvc5::api::Term& expr, cvc5::api::Term& expr2] { // lookup constructor by name api::DatatypeConstructor dc = dt.getConstructor(f.toString()); - api::Term scons = dc.getSpecializedConstructorTerm(expr.getSort()); + api::Term scons = dc.getInstantiatedConstructorTerm(expr.getSort()); // take the type of the specialized constructor instead type = scons.getSort(); } @@ -1801,8 +1794,10 @@ attribute[cvc5::api::Term& expr, cvc5::api::Term& retExpr] | ATTRIBUTE_NAMED_TOK symbol[s,CHECK_UNDECLARED,SYM_VARIABLE] { // notify that expression was given a name - PARSER_STATE->preemptCommand( - new DefineFunctionCommand(s, expr.getSort(), expr)); + DefineFunctionCommand* defFunCmd = + new DefineFunctionCommand(s, expr.getSort(), expr); + defFunCmd->setMuted(true); + PARSER_STATE->preemptCommand(defFunCmd); PARSER_STATE->notifyNamedExpression(expr, s); } ; diff --git a/src/preprocessing/passes/apply_substs.cpp b/src/preprocessing/passes/apply_substs.cpp index 99bded47a..82122fa7f 100644 --- a/src/preprocessing/passes/apply_substs.cpp +++ b/src/preprocessing/passes/apply_substs.cpp @@ -21,7 +21,7 @@ #include "context/cdo.h" #include "preprocessing/assertion_pipeline.h" #include "preprocessing/preprocessing_pass_context.h" -#include "theory/rewriter.h" +#include "smt/env.h" #include "theory/substitutions.h" namespace cvc5 { @@ -55,7 +55,8 @@ PreprocessingPassResult ApplySubsts::applyInternal( << std::endl; d_preprocContext->spendResource(Resource::PreprocessStep); assertionsToPreprocess->replaceTrusted( - i, tlsm.applyTrusted((*assertionsToPreprocess)[i])); + i, + tlsm.applyTrusted((*assertionsToPreprocess)[i], d_env.getRewriter())); Trace("apply-substs") << " got " << (*assertionsToPreprocess)[i] << std::endl; } diff --git a/src/preprocessing/passes/bv_to_int.cpp b/src/preprocessing/passes/bv_to_int.cpp index 33f3dd445..ac1edeb96 100644 --- a/src/preprocessing/passes/bv_to_int.cpp +++ b/src/preprocessing/passes/bv_to_int.cpp @@ -19,1054 +19,90 @@ #include "preprocessing/passes/bv_to_int.h" #include <cmath> -#include <sstream> #include <string> #include <unordered_map> #include <vector> #include "expr/node.h" #include "expr/node_traversal.h" -#include "expr/skolem_manager.h" #include "options/smt_options.h" #include "options/uf_options.h" -#include "preprocessing/assertion_pipeline.h" -#include "preprocessing/preprocessing_pass_context.h" #include "theory/bv/theory_bv_rewrite_rules_operator_elimination.h" +#include "preprocessing/assertion_pipeline.h" #include "theory/bv/theory_bv_rewrite_rules_simplification.h" #include "theory/rewriter.h" -#include "util/bitvector.h" -#include "util/iand.h" -#include "util/rational.h" namespace cvc5 { namespace preprocessing { namespace passes { using namespace std; -using namespace cvc5::kind; using namespace cvc5::theory; using namespace cvc5::theory::bv; -namespace { - -Rational intpow2(uint64_t b) -{ - return Rational(Integer(2).pow(b), Integer(1)); -} - -} //end empty namespace - -Node BVToInt::mkRangeConstraint(Node newVar, uint64_t k) -{ - Node lower = d_nm->mkNode(kind::LEQ, d_zero, newVar); - Node upper = d_nm->mkNode(kind::LT, newVar, pow2(k)); - Node result = d_nm->mkNode(kind::AND, lower, upper); - return rewrite(result); -} - -Node BVToInt::maxInt(uint64_t k) -{ - Assert(k > 0); - Rational max_value = intpow2(k) - 1; - return d_nm->mkConst(CONST_RATIONAL, max_value); -} - -Node BVToInt::pow2(uint64_t k) -{ - Assert(k >= 0); - return d_nm->mkConst(CONST_RATIONAL, Rational(intpow2(k))); -} - -Node BVToInt::modpow2(Node n, uint64_t exponent) -{ - Node p2 = d_nm->mkConst(CONST_RATIONAL, Rational(intpow2(exponent))); - return d_nm->mkNode(kind::INTS_MODULUS_TOTAL, n, p2); -} - -/** - * Binarizing n via post-order traversal. - */ -Node BVToInt::makeBinary(Node n) -{ - for (TNode current : NodeDfsIterable(n, - VisitOrder::POSTORDER, - // skip visited nodes - [this](TNode tn) { - return d_binarizeCache.find(tn) - != d_binarizeCache.end(); - })) - { - uint64_t numChildren = current.getNumChildren(); - /* - * We already visited the sub-dag rooted at the current node, - * and binarized all its children. - * Now we binarize the current node itself. - */ - kind::Kind_t k = current.getKind(); - if ((numChildren > 2) - && (k == kind::BITVECTOR_ADD || k == kind::BITVECTOR_MULT - || k == kind::BITVECTOR_AND || k == kind::BITVECTOR_OR - || k == kind::BITVECTOR_XOR || k == kind::BITVECTOR_CONCAT)) - { - // We only binarize bvadd, bvmul, bvand, bvor, bvxor, bvconcat - Assert(d_binarizeCache.find(current[0]) != d_binarizeCache.end()); - Node result = d_binarizeCache[current[0]]; - for (uint64_t i = 1; i < numChildren; i++) - { - Assert(d_binarizeCache.find(current[i]) != d_binarizeCache.end()); - Node child = d_binarizeCache[current[i]]; - result = d_nm->mkNode(current.getKind(), result, child); - } - d_binarizeCache[current] = result; - } - else if (numChildren > 0) - { - // current has children, but we do not binarize it - NodeBuilder builder(k); - if (current.getMetaKind() == kind::metakind::PARAMETERIZED) - { - builder << current.getOperator(); - } - for (Node child : current) - { - builder << d_binarizeCache[child].get(); - } - d_binarizeCache[current] = builder.constructNode(); - } - else - { - // current has no children - d_binarizeCache[current] = current; - } - } - return d_binarizeCache[n]; -} - -/** - * We traverse n and perform rewrites both on the way down and on the way up. - * On the way down we rewrite the node but not it's children. - * On the way up, we update the node's children to the rewritten ones. - * For each sub-node, we perform rewrites to eliminate operators. - * Then, the original children are added to toVisit stack so that we rewrite - * them as well. - */ -Node BVToInt::eliminationPass(Node n) -{ - std::vector<Node> toVisit; - toVisit.push_back(n); - Node current; - while (!toVisit.empty()) - { - current = toVisit.back(); - // assert that the node is binarized - // The following variable is only used in assertions - CVC5_UNUSED kind::Kind_t k = current.getKind(); - uint64_t numChildren = current.getNumChildren(); - Assert((numChildren == 2) - || !(k == kind::BITVECTOR_ADD || k == kind::BITVECTOR_MULT - || k == kind::BITVECTOR_AND || k == kind::BITVECTOR_OR - || k == kind::BITVECTOR_XOR || k == kind::BITVECTOR_CONCAT)); - toVisit.pop_back(); - bool inEliminationCache = - (d_eliminationCache.find(current) != d_eliminationCache.end()); - bool inRebuildCache = - (d_rebuildCache.find(current) != d_rebuildCache.end()); - if (!inEliminationCache) - { - // current is not the elimination of any previously-visited node - // current hasn't been eliminated yet. - // eliminate operators from it using rewrite rules - Node currentEliminated = - FixpointRewriteStrategy<RewriteRule<UdivZero>, - RewriteRule<SdivEliminateFewerBitwiseOps>, - RewriteRule<SremEliminateFewerBitwiseOps>, - RewriteRule<SmodEliminateFewerBitwiseOps>, - RewriteRule<XnorEliminate>, - RewriteRule<NandEliminate>, - RewriteRule<NorEliminate>, - RewriteRule<NegEliminate>, - RewriteRule<XorEliminate>, - RewriteRule<OrEliminate>, - RewriteRule<SubEliminate>, - RewriteRule<RepeatEliminate>, - RewriteRule<RotateRightEliminate>, - RewriteRule<RotateLeftEliminate>, - RewriteRule<CompEliminate>, - RewriteRule<SleEliminate>, - RewriteRule<SltEliminate>, - RewriteRule<SgtEliminate>, - RewriteRule<SgeEliminate>>::apply(current); - - // save in the cache - d_eliminationCache[current] = currentEliminated; - // also assign the eliminated now to itself to avoid revisiting. - d_eliminationCache[currentEliminated] = currentEliminated; - // put the eliminated node in the rebuild cache, but mark that it hasn't - // yet been rebuilt by assigning null. - d_rebuildCache[currentEliminated] = Node(); - // Push the eliminated node to the stack - toVisit.push_back(currentEliminated); - // Add the children to the stack for future processing. - toVisit.insert( - toVisit.end(), currentEliminated.begin(), currentEliminated.end()); - } - if (inRebuildCache) - { - // current was already added to the rebuild cache. - if (d_rebuildCache[current].get().isNull()) - { - // current wasn't rebuilt yet. - numChildren = current.getNumChildren(); - if (numChildren == 0) - { - // We only eliminate operators that are not nullary. - d_rebuildCache[current] = current; - } - else - { - // The main operator is replaced, and the children - // are replaced with their eliminated counterparts. - NodeBuilder builder(current.getKind()); - if (current.getMetaKind() == kind::metakind::PARAMETERIZED) - { - builder << current.getOperator(); - } - for (Node child : current) - { - Assert(d_eliminationCache.find(child) != d_eliminationCache.end()); - Node eliminatedChild = d_eliminationCache[child]; - Assert(d_rebuildCache.find(eliminatedChild) != d_eliminationCache.end()); - Assert(!d_rebuildCache[eliminatedChild].get().isNull()); - builder << d_rebuildCache[eliminatedChild].get(); - } - d_rebuildCache[current] = builder.constructNode(); - } - } - } - } - Assert(d_eliminationCache.find(n) != d_eliminationCache.end()); - Node eliminated = d_eliminationCache[n]; - Assert(d_rebuildCache.find(eliminated) != d_rebuildCache.end()); - Assert(!d_rebuildCache[eliminated].get().isNull()); - return d_rebuildCache[eliminated]; -} - -/** - * Translate n to Integers via post-order traversal. - */ -Node BVToInt::bvToInt(Node n) -{ - // make sure the node is re-written before processing it. - n = rewrite(n); - n = makeBinary(n); - n = eliminationPass(n); - // binarize again, in case the elimination pass introduced - // non-binary terms (as can happen by RepeatEliminate, for example). - n = makeBinary(n); - vector<Node> toVisit; - toVisit.push_back(n); - - while (!toVisit.empty()) - { - Node current = toVisit.back(); - uint64_t currentNumChildren = current.getNumChildren(); - if (d_bvToIntCache.find(current) == d_bvToIntCache.end()) - { - // This is the first time we visit this node and it is not in the cache. - // We mark this node as visited but not translated by assiging - // a null node to it. - d_bvToIntCache[current] = Node(); - // all the node's children are added to the stack to be visited - // before visiting this node again. - toVisit.insert(toVisit.end(), current.begin(), current.end()); - // If this is a UF applicatinon, we also add the function to - // toVisit. - if (current.getKind() == kind::APPLY_UF) - { - toVisit.push_back(current.getOperator()); - } - } - else - { - // We already visited and translated this node - if (!d_bvToIntCache[current].get().isNull()) - { - // We are done computing the translation for current - toVisit.pop_back(); - } - else - { - // We are now visiting current on the way back up. - // This is when we do the actual translation. - Node translation; - if (currentNumChildren == 0) - { - translation = translateNoChildren(current); - } - else - { - /** - * The current node has children. - * Since we are on the way back up, - * these children were already translated. - * We save their translation for easy access. - * If the node's kind is APPLY_UF, - * we also need to include the translated uninterpreted function in - * this list. - */ - vector<Node> translated_children; - if (current.getKind() == kind::APPLY_UF) - { - translated_children.push_back( - d_bvToIntCache[current.getOperator()]); - } - for (uint64_t i = 0; i < currentNumChildren; i++) - { - translated_children.push_back(d_bvToIntCache[current[i]]); - } - translation = translateWithChildren(current, translated_children); - } - // Map the current node to its translation in the cache. - d_bvToIntCache[current] = translation; - // Also map the translation to itself. - d_bvToIntCache[translation] = translation; - toVisit.pop_back(); - } - } - } - return d_bvToIntCache[n].get(); -} - -Node BVToInt::translateWithChildren(Node original, - const vector<Node>& translated_children) -{ - // The translation of the original node is determined by the kind of - // the node. - kind::Kind_t oldKind = original.getKind(); - // ultbv and sltbv were supposed to be eliminated before this point. - Assert(oldKind != kind::BITVECTOR_ULTBV); - Assert(oldKind != kind::BITVECTOR_SLTBV); - // The following variable will only be used in assertions. - CVC5_UNUSED uint64_t originalNumChildren = original.getNumChildren(); - Node returnNode; - switch (oldKind) - { - case kind::BITVECTOR_ADD: - { - Assert(originalNumChildren == 2); - uint64_t bvsize = original[0].getType().getBitVectorSize(); - Node plus = d_nm->mkNode(kind::PLUS, translated_children); - Node p2 = pow2(bvsize); - returnNode = d_nm->mkNode(kind::INTS_MODULUS_TOTAL, plus, p2); - break; - } - case kind::BITVECTOR_MULT: - { - Assert(originalNumChildren == 2); - uint64_t bvsize = original[0].getType().getBitVectorSize(); - Node mult = d_nm->mkNode(kind::MULT, translated_children); - Node p2 = pow2(bvsize); - returnNode = d_nm->mkNode(kind::INTS_MODULUS_TOTAL, mult, p2); - break; - } - case kind::BITVECTOR_UDIV: - { - uint64_t bvsize = original[0].getType().getBitVectorSize(); - // we use an ITE for the case where the second operand is 0. - Node pow2BvSize = pow2(bvsize); - Node divNode = - d_nm->mkNode(kind::INTS_DIVISION_TOTAL, translated_children); - returnNode = d_nm->mkNode( - kind::ITE, - d_nm->mkNode(kind::EQUAL, translated_children[1], d_zero), - d_nm->mkNode(kind::MINUS, pow2BvSize, d_one), - divNode); - break; - } - case kind::BITVECTOR_UREM: - { - // we use an ITE for the case where the second operand is 0. - Node modNode = - d_nm->mkNode(kind::INTS_MODULUS_TOTAL, translated_children); - returnNode = d_nm->mkNode( - kind::ITE, - d_nm->mkNode(kind::EQUAL, translated_children[1], d_zero), - translated_children[0], - modNode); - break; - } - case kind::BITVECTOR_NOT: - { - uint64_t bvsize = original[0].getType().getBitVectorSize(); - // we use a specified function to generate the node. - returnNode = createBVNotNode(translated_children[0], bvsize); - break; - } - case kind::BITVECTOR_TO_NAT: - { - // In this case, we already translated the child to integer. - // So the result is the translated child. - returnNode = translated_children[0]; - break; - } - case kind::INT_TO_BITVECTOR: - { - // ((_ int2bv n) t) ---> (mod t 2^n) - size_t sz = original.getOperator().getConst<IntToBitVector>().d_size; - returnNode = d_nm->mkNode( - kind::INTS_MODULUS_TOTAL, translated_children[0], pow2(sz)); - } - break; - case kind::BITVECTOR_AND: - { - // We support three configurations: - // 1. translating to IAND - // 2. translating back to BV (using BITVECTOR_TO_NAT and INT_TO_BV - // operators) - // 3. translating into a sum - uint64_t bvsize = original[0].getType().getBitVectorSize(); - if (options().smt.solveBVAsInt == options::SolveBVAsIntMode::IAND) - { - Node iAndOp = d_nm->mkConst(IntAnd(bvsize)); - returnNode = d_nm->mkNode( - kind::IAND, iAndOp, translated_children[0], translated_children[1]); - } - else if (options().smt.solveBVAsInt == options::SolveBVAsIntMode::BV) - { - // translate the children back to BV - Node intToBVOp = d_nm->mkConst<IntToBitVector>(IntToBitVector(bvsize)); - Node x = translated_children[0]; - Node y = translated_children[1]; - Node bvx = d_nm->mkNode(intToBVOp, x); - Node bvy = d_nm->mkNode(intToBVOp, y); - // perform bvand on the bit-vectors - Node bvand = d_nm->mkNode(kind::BITVECTOR_AND, bvx, bvy); - // translate the result to integers - returnNode = d_nm->mkNode(kind::BITVECTOR_TO_NAT, bvand); - } - else - { - Assert(options().smt.solveBVAsInt == options::SolveBVAsIntMode::SUM); - // Construct a sum of ites, based on granularity. - Assert(translated_children.size() == 2); - returnNode = - d_iandUtils.createSumNode(translated_children[0], - translated_children[1], - bvsize, - options().smt.BVAndIntegerGranularity); - } - break; - } - case kind::BITVECTOR_SHL: - { - /** - * a << b is a*2^b. - * The exponentiation is simulated by an ite. - * Only cases where b <= bit width are considered. - * Otherwise, the result is 0. - */ - uint64_t bvsize = original[0].getType().getBitVectorSize(); - returnNode = createShiftNode(translated_children, bvsize, true); - break; - } - case kind::BITVECTOR_LSHR: - { - /** - * a >> b is a div 2^b. - * The exponentiation is simulated by an ite. - * Only cases where b <= bit width are considered. - * Otherwise, the result is 0. - */ - uint64_t bvsize = original[0].getType().getBitVectorSize(); - returnNode = createShiftNode(translated_children, bvsize, false); - break; - } - case kind::BITVECTOR_ASHR: - { - /* From SMT-LIB2: - * (bvashr s t) abbreviates - * (ite (= ((_ extract |m-1| |m-1|) s) #b0) - * (bvlshr s t) - * (bvnot (bvlshr (bvnot s) t))) - * - * Equivalently: - * (bvashr s t) abbreviates - * (ite (bvult s 100000...) - * (bvlshr s t) - * (bvnot (bvlshr (bvnot s) t))) - * - */ - uint64_t bvsize = original[0].getType().getBitVectorSize(); - // signed_min is 100000... - Node signed_min = pow2(bvsize - 1); - Node condition = - d_nm->mkNode(kind::LT, translated_children[0], signed_min); - Node thenNode = createShiftNode(translated_children, bvsize, false); - vector<Node> children = {createBVNotNode(translated_children[0], bvsize), - translated_children[1]}; - Node elseNode = - createBVNotNode(createShiftNode(children, bvsize, false), bvsize); - returnNode = d_nm->mkNode(kind::ITE, condition, thenNode, elseNode); - break; - } - case kind::BITVECTOR_ITE: - { - // Lifted to a boolean ite. - Node cond = d_nm->mkNode(kind::EQUAL, translated_children[0], d_one); - returnNode = d_nm->mkNode( - kind::ITE, cond, translated_children[1], translated_children[2]); - break; - } - case kind::BITVECTOR_ZERO_EXTEND: - { - returnNode = translated_children[0]; - break; - } - case kind::BITVECTOR_SIGN_EXTEND: - { - uint64_t bvsize = original[0].getType().getBitVectorSize(); - Node arg = translated_children[0]; - if (arg.isConst()) - { - Rational c(arg.getConst<Rational>()); - Rational twoToKMinusOne(intpow2(bvsize - 1)); - uint64_t amount = bv::utils::getSignExtendAmount(original); - /* if the msb is 0, this is like zero_extend. - * msb is 0 <-> the value is less than 2^{bvsize-1} - */ - if (c < twoToKMinusOne || amount == 0) - { - returnNode = arg; - } - else - { - /* otherwise, we add the integer equivalent of - * 11....1 `amount` times - */ - Rational max_of_amount = intpow2(amount) - 1; - Rational mul = max_of_amount * intpow2(bvsize); - Rational sum = mul + c; - returnNode = d_nm->mkConst(CONST_RATIONAL, sum); - } - } - else - { - uint64_t amount = bv::utils::getSignExtendAmount(original); - if (amount == 0) - { - returnNode = translated_children[0]; - } - else - { - Rational twoToKMinusOne(intpow2(bvsize - 1)); - Node minSigned = d_nm->mkConst(CONST_RATIONAL, twoToKMinusOne); - /* condition checks whether the msb is 1. - * This holds when the integer value is smaller than - * 100...0, which is 2^{bvsize-1}. - */ - Node condition = d_nm->mkNode(kind::LT, arg, minSigned); - Node thenResult = arg; - Node left = maxInt(amount); - Node mul = d_nm->mkNode(kind::MULT, left, pow2(bvsize)); - Node sum = d_nm->mkNode(kind::PLUS, mul, arg); - Node elseResult = sum; - Node ite = d_nm->mkNode(kind::ITE, condition, thenResult, elseResult); - returnNode = ite; - } - } - break; - } - case kind::BITVECTOR_CONCAT: - { - // (concat a b) translates to a*2^k+b, k being the bitwidth of b. - uint64_t bvsizeRight = original[1].getType().getBitVectorSize(); - Node pow2BvSizeRight = pow2(bvsizeRight); - Node a = - d_nm->mkNode(kind::MULT, translated_children[0], pow2BvSizeRight); - Node b = translated_children[1]; - returnNode = d_nm->mkNode(kind::PLUS, a, b); - break; - } - case kind::BITVECTOR_EXTRACT: - { - // ((_ extract i j) a) is a / 2^j mod 2^{i-j+1} - // original = a[i:j] - uint64_t i = bv::utils::getExtractHigh(original); - uint64_t j = bv::utils::getExtractLow(original); - Assert(i >= j); - Node div = d_nm->mkNode( - kind::INTS_DIVISION_TOTAL, translated_children[0], pow2(j)); - returnNode = modpow2(div, i - j + 1); - break; - } - case kind::EQUAL: - { - returnNode = d_nm->mkNode(kind::EQUAL, translated_children); - break; - } - case kind::BITVECTOR_ULT: - { - returnNode = d_nm->mkNode(kind::LT, translated_children); - break; - } - case kind::BITVECTOR_ULE: - { - returnNode = d_nm->mkNode(kind::LEQ, translated_children); - break; - } - case kind::BITVECTOR_UGT: - { - returnNode = d_nm->mkNode(kind::GT, translated_children); - break; - } - case kind::BITVECTOR_UGE: - { - returnNode = d_nm->mkNode(kind::GEQ, translated_children); - break; - } - case kind::LT: - { - returnNode = d_nm->mkNode(kind::LT, translated_children); - break; - } - case kind::LEQ: - { - returnNode = d_nm->mkNode(kind::LEQ, translated_children); - break; - } - case kind::GT: - { - returnNode = d_nm->mkNode(kind::GT, translated_children); - break; - } - case kind::GEQ: - { - returnNode = d_nm->mkNode(kind::GEQ, translated_children); - break; - } - case kind::ITE: - { - returnNode = d_nm->mkNode(oldKind, translated_children); - break; - } - case kind::APPLY_UF: - { - /** - * higher order logic allows comparing between functions - * The translation does not support this, - * as the translated functions may be different outside - * of the bounds that were relevant for the original - * bit-vectors. - */ - if (childrenTypesChanged(original) && logicInfo().isHigherOrder()) - { - throw TypeCheckingExceptionPrivate( - original, - string("Cannot translate to Int: ") + original.toString()); - } - // Insert the translated application term to the cache - returnNode = d_nm->mkNode(kind::APPLY_UF, translated_children); - // Add range constraints if necessary. - // If the original range was a BV sort, the original application of - // the function Must be within the range determined by the - // bitwidth. - if (original.getType().isBitVector()) - { - d_rangeAssertions.insert(mkRangeConstraint( - returnNode, original.getType().getBitVectorSize())); - } - break; - } - case kind::BOUND_VAR_LIST: - { - returnNode = d_nm->mkNode(oldKind, translated_children); - break; - } - case kind::FORALL: - { - returnNode = translateQuantifiedFormula(original); - break; - } - default: - { - Assert(oldKind != kind::EXISTS); // Exists is eliminated by the rewriter. - // In the default case, we have reached an operator that we do not - // translate directly to integers. The children whose types have - // changed from bv to int should be adjusted back to bv and then - // this term is reconstructed. - TypeNode resultingType; - if (original.getType().isBitVector()) - { - resultingType = d_nm->integerType(); - } - else - { - resultingType = original.getType(); - } - Node reconstruction = - reconstructNode(original, resultingType, translated_children); - returnNode = reconstruction; - break; - } - } - Trace("bv-to-int-debug") << "original: " << original << endl; - Trace("bv-to-int-debug") << "returnNode: " << returnNode << endl; - return returnNode; -} - -Node BVToInt::translateNoChildren(Node original) -{ - SkolemManager* sm = d_nm->getSkolemManager(); - Node translation; - Assert(original.isVar() || original.isConst()); - if (original.isVar()) - { - if (original.getType().isBitVector()) - { - // For bit-vector variables, we create fresh integer variables. - if (original.getKind() == kind::BOUND_VARIABLE) - { - // Range constraints for the bound integer variables are not added now. - // they will be added once the quantifier itself is handled. - std::stringstream ss; - ss << original; - translation = d_nm->mkBoundVar(ss.str() + "_int", d_nm->integerType()); - } - else - { - // New integer variables that are not bound (symbolic constants) - // are added together with range constraints induced by the - // bit-width of the original bit-vector variables. - Node newVar = sm->mkDummySkolem("__bvToInt_var", - d_nm->integerType(), - "Variable introduced in bvToInt " - "pass instead of original variable " - + original.toString()); - uint64_t bvsize = original.getType().getBitVectorSize(); - translation = newVar; - d_rangeAssertions.insert(mkRangeConstraint(newVar, bvsize)); - defineBVUFAsIntUF(original, newVar); - } - } - else if (original.getType().isFunction()) - { - translation = translateFunctionSymbol(original); - } - else - { - // variables other than bit-vector variables and function symbols - // are left intact - translation = original; - } - } - else - { - // original is a const - if (original.getKind() == kind::CONST_BITVECTOR) - { - // Bit-vector constants are transformed into their integer value. - BitVector constant(original.getConst<BitVector>()); - Integer c = constant.toInteger(); - translation = d_nm->mkConst(CONST_RATIONAL, Rational(c)); - } - else - { - // Other constants stay the same. - translation = original; - } - } - return translation; -} - -Node BVToInt::translateFunctionSymbol(Node bvUF) -{ - // construct the new function symbol. - Node intUF; - TypeNode tn = bvUF.getType(); - TypeNode bvRange = tn.getRangeType(); - // The function symbol has not been converted yet - vector<TypeNode> bvDomain = tn.getArgTypes(); - vector<TypeNode> intDomain; - /** - * if the original range is a bit-vector sort, - * the new range should be an integer sort. - * Otherwise, we keep the original range. - * Similarly for the domains. - */ - TypeNode intRange = bvRange.isBitVector() ? d_nm->integerType() : bvRange; - for (TypeNode d : bvDomain) - { - intDomain.push_back(d.isBitVector() ? d_nm->integerType() : d); - } - SkolemManager* sm = d_nm->getSkolemManager(); - ostringstream os; - os << "__bvToInt_fun_" << bvUF << "_int"; - intUF = sm->mkDummySkolem( - os.str(), d_nm->mkFunctionType(intDomain, intRange), "bv2int function"); - // introduce a `define-fun` in the smt-engine to keep - // the correspondence between the original - // function symbol and the new one. - defineBVUFAsIntUF(bvUF, intUF); - return intUF; -} - -void BVToInt::defineBVUFAsIntUF(Node bvUF, Node intUF) -{ - // The resulting term - Node result; - // The type of the resulting term - TypeNode resultType; - // symbolic arguments of original function - vector<Node> args; - if (!bvUF.getType().isFunction()) { - // bvUF is a variable. - // in this case, the result is just the original term - // (it will be casted later if needed) - result = intUF; - resultType = bvUF.getType(); - } else { - // bvUF is a function with arguments - // The arguments need to be casted as well. - TypeNode tn = bvUF.getType(); - resultType = tn.getRangeType(); - vector<TypeNode> bvDomain = tn.getArgTypes(); - // children of the new symbolic application - vector<Node> achildren; - achildren.push_back(intUF); - int i = 0; - for (const TypeNode& d : bvDomain) - { - // Each bit-vector argument is casted to a natural number - // Other arguments are left intact. - Node fresh_bound_var = d_nm->mkBoundVar(d); - args.push_back(fresh_bound_var); - Node castedArg = args[i]; - if (d.isBitVector()) - { - castedArg = castToType(castedArg, d_nm->integerType()); - } - achildren.push_back(castedArg); - i++; - } - result = d_nm->mkNode(kind::APPLY_UF, achildren); - } - // If the result is BV, it needs to be casted back. - result = castToType(result, resultType); - // add the substitution to the preprocessing context, which ensures the - // model for bvUF is correct, as well as substituting it in the input - // assertions when necessary. - if (!args.empty()) - { - result = d_nm->mkNode( - kind::LAMBDA, d_nm->mkNode(kind::BOUND_VAR_LIST, args), result); - } - d_preprocContext->addSubstitution(bvUF, result); -} - -bool BVToInt::childrenTypesChanged(Node n) -{ - bool result = false; - for (const Node& child : n) - { - TypeNode originalType = child.getType(); - TypeNode newType = d_bvToIntCache[child].get().getType(); - if (!newType.isSubtypeOf(originalType)) - { - result = true; - break; - } - } - return result; -} - -Node BVToInt::castToType(Node n, TypeNode tn) -{ - // If there is no reason to cast, return the - // original node. - if (n.getType().isSubtypeOf(tn)) - { - return n; - } - // We only case int to bv or vice verse. - Assert((n.getType().isBitVector() && tn.isInteger()) - || (n.getType().isInteger() && tn.isBitVector())); - if (n.getType().isInteger()) - { - Assert(tn.isBitVector()); - unsigned bvsize = tn.getBitVectorSize(); - Node intToBVOp = d_nm->mkConst<IntToBitVector>(IntToBitVector(bvsize)); - return d_nm->mkNode(intToBVOp, n); - } - Assert(n.getType().isBitVector()); - Assert(tn.isInteger()); - return d_nm->mkNode(kind::BITVECTOR_TO_NAT, n); -} - -Node BVToInt::reconstructNode(Node originalNode, - TypeNode resultType, - const vector<Node>& translated_children) -{ - // first, we adjust the children of the node as needed. - // re-construct the term with the adjusted children. - kind::Kind_t oldKind = originalNode.getKind(); - NodeBuilder builder(oldKind); - if (originalNode.getMetaKind() == kind::metakind::PARAMETERIZED) - { - builder << originalNode.getOperator(); - } - for (size_t i = 0; i < originalNode.getNumChildren(); i++) - { - Node originalChild = originalNode[i]; - Node translatedChild = translated_children[i]; - Node adjustedChild = castToType(translatedChild, originalChild.getType()); - builder << adjustedChild; - } - Node reconstruction = builder.constructNode(); - // cast to tn in case the reconstruction is a bit-vector. - reconstruction = castToType(reconstruction, resultType); - return reconstruction; -} - BVToInt::BVToInt(PreprocessingPassContext* preprocContext) : PreprocessingPass(preprocContext, "bv-to-int"), - d_binarizeCache(userContext()), - d_eliminationCache(userContext()), - d_rebuildCache(userContext()), - d_bvToIntCache(userContext()), - d_rangeAssertions(userContext()) -{ - d_nm = NodeManager::currentNM(); - d_zero = d_nm->mkConst(CONST_RATIONAL, Rational(0)); - d_one = d_nm->mkConst(CONST_RATIONAL, Rational(1)); -}; + d_intBlaster(preprocContext->getEnv(), + options::solveBVAsInt(), + options::BVAndIntegerGranularity()) {} PreprocessingPassResult BVToInt::applyInternal( AssertionPipeline* assertionsToPreprocess) { + // vector of boolean nodes for additional constraints + // this will always contain range constraints + // and for options::SolveBVAsIntMode::BITWISE, it will + // also include bitwise assertion constraints + std::vector<Node> additionalConstraints; + std::map<Node, Node> skolems; for (uint64_t i = 0; i < assertionsToPreprocess->size(); ++i) { Node bvNode = (*assertionsToPreprocess)[i]; - Node intNode = bvToInt(bvNode); + Node intNode = + d_intBlaster.intBlast(bvNode, additionalConstraints, skolems); Node rwNode = rewrite(intNode); Trace("bv-to-int-debug") << "bv node: " << bvNode << std::endl; Trace("bv-to-int-debug") << "int node: " << intNode << std::endl; Trace("bv-to-int-debug") << "rw node: " << rwNode << std::endl; assertionsToPreprocess->replace(i, rwNode); } - addFinalizeRangeAssertions(assertionsToPreprocess); + addFinalizeAssertions(assertionsToPreprocess, additionalConstraints); + addSkolemDefinitions(skolems); return PreprocessingPassResult::NO_CONFLICT; } -void BVToInt::addFinalizeRangeAssertions( - AssertionPipeline* assertionsToPreprocess) -{ - // collect the range assertions from d_rangeAssertions - // (which is a context-dependent set) - // into a vector. - vector<Node> vec_range; - vec_range.assign(d_rangeAssertions.key_begin(), d_rangeAssertions.key_end()); - // conjoin all range assertions and add the conjunction - // as a new assertion - Node rangeAssertions = rewrite(d_nm->mkAnd(vec_range)); - assertionsToPreprocess->push_back(rangeAssertions); - Trace("bv-to-int-debug") << "range constraints: " - << rangeAssertions.toString() << std::endl; -} - -Node BVToInt::createShiftNode(vector<Node> children, - uint64_t bvsize, - bool isLeftShift) +void BVToInt::addSkolemDefinitions(const std::map<Node, Node>& skolems) { - /** - * from SMT-LIB: - * [[(bvshl s t)]] := nat2bv[m](bv2nat([[s]]) * 2^(bv2nat([[t]]))) - * [[(bvlshr s t)]] := nat2bv[m](bv2nat([[s]]) div 2^(bv2nat([[t]]))) - * Since we don't have exponentiation, we use an ite. - * Important note: below we use INTS_DIVISION_TOTAL, which is safe here - * because we divide by 2^... which is never 0. - */ - Node x = children[0]; - Node y = children[1]; - // shifting by const is eliminated by the theory rewriter - Assert(!y.isConst()); - Node ite = d_zero; - Node body; - for (uint64_t i = 0; i < bvsize; i++) + map<Node, Node>::const_iterator it; + for (it = skolems.begin(); it != skolems.end(); it++) { - if (isLeftShift) + Node originalSkolem = it->first; + Node definition = it->second; + std::vector<Node> args; + Node body; + if (definition.getType().isFunction()) { - body = d_nm->mkNode(kind::INTS_MODULUS_TOTAL, - d_nm->mkNode(kind::MULT, x, pow2(i)), - pow2(bvsize)); + args.insert(args.end(), definition[0].begin(), definition[0].end()); + body = definition[1]; } else { - body = d_nm->mkNode(kind::INTS_DIVISION_TOTAL, x, pow2(i)); + body = definition; } - ite = d_nm->mkNode( - kind::ITE, - d_nm->mkNode( - kind::EQUAL, y, d_nm->mkConst(CONST_RATIONAL, Rational(i))), - body, - ite); + Trace("bv-to-int-debug") << "adding substitution: " << "[" << originalSkolem << "] ----> [" << definition << "]" << std::endl; + d_preprocContext->addSubstitution(originalSkolem, definition); } - return ite; -} - -Node BVToInt::translateQuantifiedFormula(Node quantifiedNode) -{ - kind::Kind_t k = quantifiedNode.getKind(); - Node boundVarList = quantifiedNode[0]; - Assert(boundVarList.getKind() == kind::BOUND_VAR_LIST); - // Since bit-vector variables are being translated to - // integer variables, we need to substitute the new ones - // for the old ones. - vector<Node> oldBoundVars; - vector<Node> newBoundVars; - vector<Node> rangeConstraints; - for (Node bv : quantifiedNode[0]) - { - oldBoundVars.push_back(bv); - if (bv.getType().isBitVector()) - { - // bit-vector variables are replaced by integer ones. - // the new variables induce range constraints based on the - // original bit-width. - Node newBoundVar = d_bvToIntCache[bv]; - newBoundVars.push_back(newBoundVar); - rangeConstraints.push_back( - mkRangeConstraint(newBoundVar, bv.getType().getBitVectorSize())); - } - else - { - // variables that are not bit-vectors are not changed - newBoundVars.push_back(bv); - } - } - - // the body of the quantifier - Node matrix = d_bvToIntCache[quantifiedNode[1]]; - // make the substitution - matrix = matrix.substitute(oldBoundVars.begin(), - oldBoundVars.end(), - newBoundVars.begin(), - newBoundVars.end()); - // A node to represent all the range constraints. - Node ranges = d_nm->mkAnd(rangeConstraints); - // Add the range constraints to the body of the quantifier. - // For "exists", this is added conjunctively - // For "forall", this is added to the left side of an implication. - matrix = d_nm->mkNode( - k == kind::FORALL ? kind::IMPLIES : kind::AND, ranges, matrix); - // create the new quantified formula and return it. - Node newBoundVarsList = d_nm->mkNode(kind::BOUND_VAR_LIST, newBoundVars); - Node result = d_nm->mkNode(kind::FORALL, newBoundVarsList, matrix); - return result; } -Node BVToInt::createBVNotNode(Node n, uint64_t bvsize) +void BVToInt::addFinalizeAssertions( + AssertionPipeline* assertionsToPreprocess, + const std::vector<Node>& additionalConstraints) { - return d_nm->mkNode(kind::MINUS, maxInt(bvsize), n); + NodeManager* nm = NodeManager::currentNM(); + Node lemmas = nm->mkAnd(additionalConstraints); + assertionsToPreprocess->push_back(lemmas); + Trace("bv-to-int-debug") << "range constraints: " << lemmas.toString() + << std::endl; } } // namespace passes diff --git a/src/preprocessing/passes/bv_to_int.h b/src/preprocessing/passes/bv_to_int.h index d09f9e738..24fc185b5 100644 --- a/src/preprocessing/passes/bv_to_int.h +++ b/src/preprocessing/passes/bv_to_int.h @@ -1,6 +1,7 @@ + /****************************************************************************** * Top contributors (to current version): - * Yoni Zohar, Gereon Kremer, Makai Mann + * Yoni Zohar * * This file is part of the cvc5 project. * @@ -10,69 +11,18 @@ * directory for licensing information. * **************************************************************************** * - * The BVToInt preprocessing pass - * - * Converts bit-vector formulas to integer formulas. - * The conversion is implemented using a translation function Tr, - * roughly described as follows: - * - * Tr(x) = fresh_x for every bit-vector variable x, where fresh_x is a fresh - * integer variable. - * Tr(c) = the integer value of c, for any bit-vector constant c. - * Tr((bvadd s t)) = Tr(s) + Tr(t) mod 2^k, where k is the bit width of - * s and t. - * Similar transformations are done for bvmul, bvsub, bvudiv, bvurem, bvneg, - * bvnot, bvconcat, bvextract - * Tr((_ zero_extend m) x) = Tr(x) - * Tr((_ sign_extend m) x) = ite(msb(x)=0, x, 2^k*(2^m-1) + x)) - * explanation: if the msb is 0, this is the same as zero_extend, - * which does not change the integer value. - * If the msb is 1, then the result should correspond to - * concat(1...1, x), with m 1's. - * m 1's is 2^m-1, and multiplying it by x's width (k) moves it - * to the front. - * - * Tr((bvand s t)) depends on the granularity, which is provided by the user - * when enabling this preprocessing pass. - * We divide s and t to blocks. - * The size of each block is the granularity, and so the number of - * blocks is: - * bit width/granularity (rounded down). - * We create an ITE that represents an arbitrary block, - * and then create a sum by mutiplying each block by the - * appropriate power of two. - * More formally: - * Let g denote the granularity. - * Let k denote the bit width of s and t. - * Let b denote floor(k/g) if k >= g, or just k otherwise. - * Tr((bvand s t)) = - * Sigma_{i=0}^{b-1}(bvand s[(i+1)*g, i*g] t[(i+1)*g, i*g])*2^(i*g) - * - * Similar transformations are done for bvor, bvxor, bvxnor, bvnand, bvnor. - * - * Tr((bvshl a b)) = ite(Tr(b) >= k, 0, Tr(a)*ITE), where k is the bit width of - * a and b, and ITE represents exponentiation up to k, that is: - * ITE = ite(Tr(b)=0, 1, ite(Tr(b)=1), 2, ite(Tr(b)=2, 4, ...)) - * Similar transformations are done for bvlshr. - * - * Tr(a=b) = Tr(a)=Tr(b) - * Tr((bvult a b)) = Tr(a) < Tr(b) - * Similar transformations are done for bvule, bvugt, and bvuge. - * - * Bit-vector operators that are not listed above are either eliminated using - * the function eliminationPass, or are not supported. - * + * The bv-to-int preprocessing pass. */ -#include "cvc5_private.h" - #ifndef __CVC5__PREPROCESSING__PASSES__BV_TO_INT_H #define __CVC5__PREPROCESSING__PASSES__BV_TO_INT_H #include "context/cdhashmap.h" -#include "context/cdhashset.h" +#include "context/cdo.h" +#include "context/context.h" #include "preprocessing/preprocessing_pass.h" -#include "theory/arith/nl/iand_utils.h" +#include "preprocessing/preprocessing_pass_context.h" +#include "theory/bv/int_blaster.h" namespace cvc5 { namespace preprocessing { @@ -88,200 +38,15 @@ class BVToInt : public PreprocessingPass protected: PreprocessingPassResult applyInternal( AssertionPipeline* assertionsToPreprocess) override; - /** - * A generic function that creates a logical shift node (either left or - * right). a << b gets translated to a * 2^b mod 2^k, where k is the bit - * width. a >> b gets translated to a div 2^b mod 2^k, where k is the bit - * width. The exponentiation operation is translated to an ite for possible - * values of the exponent, from 0 to k-1. - * If the right operand of the shift is greater than k-1, - * the result is 0. - * @param children the two operands for the shift - * @param bvsize the original bit widths of the operands - * (before translation to integers) - * @param isLeftShift true iff the desired operation is a left shift. - * @return a node representing the shift. - * - */ - Node createShiftNode(std::vector<Node> children, - uint64_t bvsize, - bool isLeftShift); - - /** - * Returns a node that represents the bitwise negation of n. - */ - Node createBVNotNode(Node n, uint64_t bvsize); - - /** - * The result is an integer term and is computed - * according to the translation specified above. - * @param n is a bit-vector term or formula to be translated. - * @return integer node that corresponds to n. - */ - Node bvToInt(Node n); - - /** - * Whenever we introduce an integer variable that represents a bit-vector - * variable, we need to guard the range of the newly introduced variable. - * For bit width k, the constraint is 0 <= newVar < 2^k. - * @param newVar the newly introduced integer variable - * @param k the bit width of the original bit-vector variable. - * @return a node representing the range constraint. - */ - Node mkRangeConstraint(Node newVar, uint64_t k); - - /** - * In the translation to integers, it is convenient to assume that certain - * bit-vector operators do not occur in the original formula (e.g., repeat). - * This function eliminates all these operators. - */ - Node eliminationPass(Node n); - - /** - * Some bit-vector operators (e.g., bvadd, bvand) are binary, but allow more - * than two arguments as a syntactic sugar. - * For example, we can have a node for (bvand x y z), - * that represents (bvand (x (bvand y z))). - * This function makes all such operators strictly binary. - */ - Node makeBinary(Node n); - - /** - * @param k A non-negative integer - * @return A node that represents the constant 2^k - */ - Node pow2(uint64_t k); - - /** - * @param k A positive integer k - * @return A node that represent the constant 2^k-1 - * For example, if k is 4, the result is a node representing the - * constant 15. - */ - Node maxInt(uint64_t k); - - /** - * @param n A node representing an integer term - * @param exponent A non-negative integer - * @return A node representing (n mod (2^exponent)) - */ - Node modpow2(Node n, uint64_t exponent); - - bool childrenTypesChanged(Node n); - - /** - * Add the range assertions collected in d_rangeAssertions - * (using mkRangeConstraint) to the assertion pipeline. - * If there are no range constraints, do nothing. - * If there is a single range constraint, add it to the pipeline. - * Otherwise, add all of them as a single conjunction - */ - void addFinalizeRangeAssertions(AssertionPipeline* assertionsToPreprocess); - - /** - * @param quantifiedNode a node whose main operator is forall/exists. - * @return a node opbtained from quantifiedNode by: - * 1. Replacing all bound BV variables by new bound integer variables. - * 2. Add range constraints for the new variables, induced by the original - * bit-width. These range constraints are added with "AND" in case of exists - * and with "IMPLIES" in case of forall. - */ - Node translateQuantifiedFormula(Node quantifiedNode); - - /** - * Reconstructs a node whose main operator cannot be - * translated to integers. - * Reconstruction is done by casting to integers/bit-vectors - * as needed. - * For example, if node is (select A x) where A - * is a bit-vector array, we do not change A to be - * an integer array, even though x was translated - * to integers. - * In this case we cast x to (bv2nat x) during - * the reconstruction. - * - * @param originalNode the node that we are reconstructing - * @param resultType the desired type for the reconstruction - * @param translated_children the children of originalNode - * after their translation to integers. - * @return A node with originalNode's operator that has type resultType. - */ - Node reconstructNode(Node originalNode, - TypeNode resultType, - const std::vector<Node>& translated_children); - - /** - * A useful utility function. - * if n is an integer and tn is bit-vector, - * applies the IntToBitVector operator on n. - * if n is a vit-vector and tn is integer, - * applies BitVector_TO_NAT operator. - * Otherwise, keeps n intact. - */ - Node castToType(Node n, TypeNode tn); - - /** - * When a UF f is translated to a UF g, - * we add a define-fun command to the smt-engine - * to relate between f and g. - * We do the same when f and g are just variables. - * This is useful, for example, when asking - * for a model-value of a term that includes the - * original UF f. - * @param bvUF the original function or variable - * @param intUF the translated function or variable - */ - void defineBVUFAsIntUF(Node bvUF, Node intUF); - - /** - * @param bvUF is an uninterpreted function symbol from the original formula - * @return a fresh uninterpreted function symbol, obtained from bvUF - by replacing every argument of type BV to an argument of type Integer, - and the return type becomes integer in case it was BV. - */ - Node translateFunctionSymbol(Node bvUF); - - /** - * Performs the actual translation to integers for nodes - * that have children. - */ - Node translateWithChildren(Node original, - const std::vector<Node>& translated_children); - - /** - * Performs the actual translation to integers for nodes - * that don't have children (variables, constants, uninterpreted function - * symbols). - */ - Node translateNoChildren(Node original); - - /** - * Caches for the different functions - */ - CDNodeMap d_binarizeCache; - CDNodeMap d_eliminationCache; - CDNodeMap d_rebuildCache; - CDNodeMap d_bvToIntCache; - /** - * Node manager that is used throughout the pass - */ - NodeManager* d_nm; + // Add the lemmas in `additionalConstraints` to the assertions pipeline. + void addFinalizeAssertions(AssertionPipeline* assertionsToPreprocess, + const std::vector<Node>& additionalConstraints); - /** - * A set of constraints of the form 0 <= x < 2^k - * These are added for every new integer variable that we introduce. - */ - context::CDHashSet<Node> d_rangeAssertions; + // include the skolem map as substitutions + void addSkolemDefinitions(const std::map<Node, Node>& skolems); - /** - * Useful constants - */ - Node d_zero; - Node d_one; - - /** helper class for handeling bvand translation */ - theory::arith::nl::IAndUtils d_iandUtils; + IntBlaster d_intBlaster; }; } // namespace passes diff --git a/src/preprocessing/passes/int_to_bv.cpp b/src/preprocessing/passes/int_to_bv.cpp index e6b5a4bca..2ff45aef0 100644 --- a/src/preprocessing/passes/int_to_bv.cpp +++ b/src/preprocessing/passes/int_to_bv.cpp @@ -235,25 +235,19 @@ Node IntToBV::intToBV(TNode n, NodeMap& cache) } else if (current.isConst()) { - switch (current.getKind()) + if (current.getType().isInteger()) { - case kind::CONST_RATIONAL: + Rational constant = current.getConst<Rational>(); + Assert (constant.isIntegral()); + BitVector bv(size, constant.getNumerator()); + if (bv.toSignedInteger() != constant.getNumerator()) { - Rational constant = current.getConst<Rational>(); - if (constant.isIntegral()) { - BitVector bv(size, constant.getNumerator()); - if (bv.toSignedInteger() != constant.getNumerator()) - { - throw TypeCheckingExceptionPrivate( - current, - string("Not enough bits for constant in intToBV: ") - + current.toString()); - } - result = nm->mkConst(bv); - } - break; + throw TypeCheckingExceptionPrivate( + current, + string("Not enough bits for constant in intToBV: ") + + current.toString()); } - default: break; + result = nm->mkConst(bv); } } else diff --git a/src/preprocessing/passes/learned_rewrite.cpp b/src/preprocessing/passes/learned_rewrite.cpp index 642a63aa4..3922525f2 100644 --- a/src/preprocessing/passes/learned_rewrite.cpp +++ b/src/preprocessing/passes/learned_rewrite.cpp @@ -61,7 +61,7 @@ PreprocessingPassResult LearnedRewrite::applyInternal( AssertionPipeline* assertionsToPreprocess) { NodeManager* nm = NodeManager::currentNM(); - arith::BoundInference binfer; + arith::BoundInference binfer(d_env); std::vector<Node> learnedLits = d_preprocContext->getLearnedLiterals(); std::unordered_set<Node> llrw; std::unordered_map<TNode, Node> visited; diff --git a/src/preprocessing/passes/miplib_trick.cpp b/src/preprocessing/passes/miplib_trick.cpp index 66646b766..1be5ee81b 100644 --- a/src/preprocessing/passes/miplib_trick.cpp +++ b/src/preprocessing/passes/miplib_trick.cpp @@ -213,8 +213,7 @@ PreprocessingPassResult MipLibTrick::applyInternal( NodeManager* nm = NodeManager::currentNM(); SkolemManager* sm = nm->getSkolemManager(); - Node zero = nm->mkConst(CONST_RATIONAL, Rational(0)), - one = nm->mkConst(CONST_RATIONAL, Rational(1)); + Node zero = nm->mkConstInt(Rational(0)), one = nm->mkConstInt(Rational(1)); Node trueNode = nm->mkConst(true); unordered_map<TNode, Node> intVars; @@ -276,10 +275,8 @@ PreprocessingPassResult MipLibTrick::applyInternal( break; } if ((*j1)[1].getKind() != kind::EQUAL - || !(((*j1)[1][0].isVar() - && (*j1)[1][1].getKind() == kind::CONST_RATIONAL) - || ((*j1)[1][0].getKind() == kind::CONST_RATIONAL - && (*j1)[1][1].isVar()))) + || !(((*j1)[1][0].isVar() && (*j1)[1][1].isConst()) + || ((*j1)[1][0].isConst() && (*j1)[1][1].isVar()))) { eligible = false; Debug("miplib") << " -- INELIGIBLE -- (=> (and X X) X)" << endl; @@ -332,14 +329,11 @@ PreprocessingPassResult MipLibTrick::applyInternal( } sort(posv.begin(), posv.end()); const Node pos = NodeManager::currentNM()->mkNode(kind::AND, posv); - const TNode var = ((*j1)[1][0].getKind() == kind::CONST_RATIONAL) - ? (*j1)[1][1] - : (*j1)[1][0]; + const TNode var = ((*j1)[1][0].isConst()) ? (*j1)[1][1] : (*j1)[1][0]; const pair<Node, Node> pos_var(pos, var); - const Rational& constant = - ((*j1)[1][0].getKind() == kind::CONST_RATIONAL) - ? (*j1)[1][0].getConst<Rational>() - : (*j1)[1][1].getConst<Rational>(); + const Rational& constant = ((*j1)[1][0].isConst()) + ? (*j1)[1][0].getConst<Rational>() + : (*j1)[1][1].getConst<Rational>(); uint64_t mark = 0; unsigned countneg = 0, thepos = 0; for (unsigned ii = 0; ii < pos.getNumChildren(); ++ii) @@ -406,14 +400,11 @@ PreprocessingPassResult MipLibTrick::applyInternal( const bool xneg = (x.getKind() == kind::NOT); x = xneg ? x[0] : x; Debug("miplib") << " x:" << x << " " << xneg << endl; - const TNode var = ((*j1)[1][0].getKind() == kind::CONST_RATIONAL) - ? (*j1)[1][1] - : (*j1)[1][0]; + const TNode var = ((*j1)[1][0].isConst()) ? (*j1)[1][1] : (*j1)[1][0]; const pair<Node, Node> x_var(x, var); - const Rational& constant = - ((*j1)[1][0].getKind() == kind::CONST_RATIONAL) - ? (*j1)[1][0].getConst<Rational>() - : (*j1)[1][1].getConst<Rational>(); + const Rational& constant = ((*j1)[1][0].isConst()) + ? (*j1)[1][0].getConst<Rational>() + : (*j1)[1][1].getConst<Rational>(); unsigned mark = (xneg ? 0 : 1); if ((marks[x_var] & (1u << mark)) != 0) { @@ -573,17 +564,15 @@ PreprocessingPassResult MipLibTrick::applyInternal( NodeBuilder sumb(kind::PLUS); for (size_t jj = 0; jj < pos.getNumChildren(); ++jj) { - sumb << nm->mkNode(kind::MULT, - nm->mkConst(CONST_RATIONAL, coef[pos_var][jj]), - newVars[jj]); + sumb << nm->mkNode( + kind::MULT, nm->mkConstInt(coef[pos_var][jj]), newVars[jj]); } sum = sumb; } else { - sum = nm->mkNode(kind::MULT, - nm->mkConst(CONST_RATIONAL, coef[pos_var][0]), - newVars[0]); + sum = nm->mkNode( + kind::MULT, nm->mkConstInt(coef[pos_var][0]), newVars[0]); } Debug("miplib") << "vars[] " << var << endl << " eq " << rewrite(sum) << endl; diff --git a/src/preprocessing/passes/non_clausal_simp.cpp b/src/preprocessing/passes/non_clausal_simp.cpp index 4bf29157e..247a8b72e 100644 --- a/src/preprocessing/passes/non_clausal_simp.cpp +++ b/src/preprocessing/passes/non_clausal_simp.cpp @@ -120,6 +120,7 @@ PreprocessingPassResult NonClausalSimp::applyInternal( << " learned literals." << std::endl; // No conflict, go through the literals and solve them context::Context* u = userContext(); + Rewriter* rw = d_env.getRewriter(); TrustSubstitutionMap& ttls = d_preprocContext->getTopLevelSubstitutions(); CVC5_UNUSED SubstitutionMap& top_level_substs = ttls.get(); // constant propagations @@ -228,7 +229,7 @@ PreprocessingPassResult NonClausalSimp::applyInternal( c = learnedLiteral[1]; } Assert(!t.isConst()); - Assert(cps.apply(t, true) == t); + Assert(rewrite(cps.apply(t)) == t); Assert(top_level_substs.apply(t) == t); Assert(nss.apply(t) == t); // also add to learned literal @@ -293,7 +294,7 @@ PreprocessingPassResult NonClausalSimp::applyInternal( for (size_t i = 0, size = assertionsToPreprocess->size(); i < size; ++i) { Node assertion = (*assertionsToPreprocess)[i]; - TrustNode assertionNew = newSubstitutions->applyTrusted(assertion); + TrustNode assertionNew = newSubstitutions->applyTrusted(assertion, rw); Trace("non-clausal-simplify") << "assertion = " << assertion << std::endl; if (!assertionNew.isNull()) { @@ -305,7 +306,7 @@ PreprocessingPassResult NonClausalSimp::applyInternal( } for (;;) { - assertionNew = constantPropagations->applyTrusted(assertion); + assertionNew = constantPropagations->applyTrusted(assertion, rw); if (assertionNew.isNull()) { break; @@ -340,7 +341,7 @@ PreprocessingPassResult NonClausalSimp::applyInternal( if (d_preprocContext->getSymsInAssertions().contains(lhs)) { // if it has, the substitution becomes an assertion - TrustNode trhs = newSubstitutions->applyTrusted(lhs); + TrustNode trhs = newSubstitutions->applyTrusted(lhs, rw); Assert(!trhs.isNull()); Trace("non-clausal-simplify") << "substitute: will notify SAT layer of substitution: " @@ -446,10 +447,11 @@ Node NonClausalSimp::processLearnedLit(Node lit, theory::TrustSubstitutionMap* subs, theory::TrustSubstitutionMap* cp) { + Rewriter* rw = d_env.getRewriter(); TrustNode tlit; if (subs != nullptr) { - tlit = subs->applyTrusted(lit); + tlit = subs->applyTrusted(lit, rw); if (!tlit.isNull()) { lit = processRewrittenLearnedLit(tlit); @@ -462,7 +464,7 @@ Node NonClausalSimp::processLearnedLit(Node lit, { for (;;) { - tlit = cp->applyTrusted(lit); + tlit = cp->applyTrusted(lit, rw); if (tlit.isNull()) { break; diff --git a/src/preprocessing/passes/pseudo_boolean_processor.cpp b/src/preprocessing/passes/pseudo_boolean_processor.cpp index 6c93eba15..0e7ac9c79 100644 --- a/src/preprocessing/passes/pseudo_boolean_processor.cpp +++ b/src/preprocessing/passes/pseudo_boolean_processor.cpp @@ -66,7 +66,7 @@ bool PseudoBooleanProcessor::decomposeAssertion(Node assertion, bool negated) Node l = assertion[0]; Node r = assertion[1]; - if (r.getKind() != kind::CONST_RATIONAL) + if (!r.isConst()) { Debug("pbs::rewrites") << "not rhs constant" << assertion << std::endl; return false; @@ -216,7 +216,7 @@ void PseudoBooleanProcessor::learnRewrittenGeq(Node assertion, Node l = assertion[0]; Node r = assertion[1]; - if (r.getKind() == kind::CONST_RATIONAL) + if (r.isConst()) { const Rational& rc = r.getConst<Rational>(); if (isIntVar(l)) @@ -233,8 +233,7 @@ void PseudoBooleanProcessor::learnRewrittenGeq(Node assertion, else if (l.getKind() == kind::MULT && l.getNumChildren() == 2) { Node c = l[0], v = l[1]; - if (c.getKind() == kind::CONST_RATIONAL - && c.getConst<Rational>().isNegativeOne()) + if (c.isConst() && c.getConst<Rational>().isNegativeOne()) { if (isIntVar(v)) { diff --git a/src/preprocessing/passes/real_to_int.cpp b/src/preprocessing/passes/real_to_int.cpp index 5c4539808..d2cde7b46 100644 --- a/src/preprocessing/passes/real_to_int.cpp +++ b/src/preprocessing/passes/real_to_int.cpp @@ -78,8 +78,7 @@ Node RealToInt::realToIntInternal(TNode n, NodeMap& cache, std::vector<Node>& va if (!c.isNull()) { Assert(c.isConst()); - coeffs.push_back(NodeManager::currentNM()->mkConst( - CONST_RATIONAL, + coeffs.push_back(nm->mkConstInt( Rational(c.getConst<Rational>().getDenominator()))); } } @@ -134,15 +133,10 @@ Node RealToInt::realToIntInternal(TNode n, NodeMap& cache, std::vector<Node>& va } Node sumt = sum.empty() - ? NodeManager::currentNM()->mkConst(CONST_RATIONAL, - Rational(0)) - : (sum.size() == 1 - ? sum[0] - : NodeManager::currentNM()->mkNode(kind::PLUS, sum)); - ret = NodeManager::currentNM()->mkNode( - ret_lit.getKind(), - sumt, - NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(0))); + ? nm->mkConstInt(Rational(0)) + : (sum.size() == 1 ? sum[0] : nm->mkNode(kind::PLUS, sum)); + ret = nm->mkNode( + ret_lit.getKind(), sumt, nm->mkConstInt(Rational(0))); if (!ret_pol) { ret = ret.negate(); diff --git a/src/preprocessing/passes/sygus_inference.cpp b/src/preprocessing/passes/sygus_inference.cpp index 3da75beb2..cdbd6099e 100644 --- a/src/preprocessing/passes/sygus_inference.cpp +++ b/src/preprocessing/passes/sygus_inference.cpp @@ -301,14 +301,13 @@ bool SygusInference::solveSygus(const std::vector<Node>& assertions, Trace("sygus-infer") << "*** Check sat..." << std::endl; Result r = rrSygus->checkSat(); Trace("sygus-infer") << "...result : " << r << std::endl; - if (r.asSatisfiabilityResult().isSat() != Result::UNSAT) + // get the synthesis solutions + std::map<Node, Node> synth_sols; + if (!rrSygus->getSubsolverSynthSolutions(synth_sols)) { // failed, conjecture was infeasible return false; } - // get the synthesis solutions - std::map<Node, Node> synth_sols; - rrSygus->getSynthSolutions(synth_sols); std::vector<Node> final_ff; std::vector<Node> final_ff_sol; diff --git a/src/preprocessing/passes/unconstrained_simplifier.cpp b/src/preprocessing/passes/unconstrained_simplifier.cpp index ae05d6b87..027be232b 100644 --- a/src/preprocessing/passes/unconstrained_simplifier.cpp +++ b/src/preprocessing/passes/unconstrained_simplifier.cpp @@ -515,9 +515,9 @@ void UnconstrainedSimplifier::processUnconstrained() if (current.getType().isInteger()) { // div/mult by 1 should have been simplified - Assert(other != nm->mkConst(CONST_RATIONAL, Rational(1))); + Assert(other != nm->mkConstInt(Rational(1))); // div by -1 should have been simplified - if (other != nm->mkConst(CONST_RATIONAL, Rational(-1))) + if (other != nm->mkConstInt(Rational(-1))) { break; } diff --git a/src/proof/alethe/alethe_post_processor.cpp b/src/proof/alethe/alethe_post_processor.cpp index 2254c025f..af683ffc6 100644 --- a/src/proof/alethe/alethe_post_processor.cpp +++ b/src/proof/alethe/alethe_post_processor.cpp @@ -20,6 +20,7 @@ #include "proof/proof.h" #include "proof/proof_checker.h" #include "proof/proof_node_algorithm.h" +#include "proof/proof_node_manager.h" #include "theory/builtin/proof_checker.h" #include "util/rational.h" @@ -465,7 +466,7 @@ bool AletheProofPostprocessCallback::update(Node res, res, nm->mkNode(kind::SEXPR, d_cl, res), children, - {nm->mkConst(CONST_RATIONAL, Rational(1))}, + {nm->mkConstInt(Rational(1))}, *cdp); } default: @@ -1351,7 +1352,7 @@ bool AletheProofPostprocessCallback::update(Node res, { Node vp1 = nm->mkNode(kind::SEXPR, d_cl, children[0], res); std::vector<Node> new_children = {vp1, children[0]}; - new_args.push_back(nm->mkConst<Rational>(CONST_RATIONAL, 1)); + new_args.push_back(nm->mkConstInt(Rational(1))); return addAletheStep(AletheRule::LA_GENERIC, vp1, vp1, {}, new_args, *cdp) && addAletheStep(AletheRule::RESOLUTION, res, @@ -1374,7 +1375,7 @@ bool AletheProofPostprocessCallback::update(Node res, { Node vp1 = nm->mkNode(kind::SEXPR, d_cl, children[0], res); std::vector<Node> new_children = {vp1, children[0]}; - new_args.push_back(nm->mkConst<Rational>(CONST_RATIONAL, 1)); + new_args.push_back(nm->mkConstInt(Rational(1))); return addAletheStep(AletheRule::LA_GENERIC, vp1, vp1, {}, new_args, *cdp) && addAletheStep(AletheRule::RESOLUTION, res, @@ -1383,6 +1384,232 @@ bool AletheProofPostprocessCallback::update(Node res, {}, *cdp); } + // ======== Trichotomy of the reals + // See proof_rule.h for documentation on the ARITH_TRICHOTOMY rule. This + // comment uses variable names as introduced there. + // + // If C = (= x c) or C = (> x c) pre-processing has to transform (>= x c) + // into (<= c x) + // + // ------------------------------------------------------ LA_DISEQUALITY + // (VP1: (cl (or (= x c) (not (<= x c)) (not (<= c x))))) + // -------------------------------------------------------- OR + // (VP2: (cl (= x c) (not (<= x c)) (not (<= c x)))) + // + // If C = (> x c) or C = (< x c) post-processing has to be added. In these + // cases resolution on VP2 A B yields (not (<=x c)) or (not (<= c x)) and + // comp_simplify is used to transform it into C. Otherwise, + // + // VP2 A B + // ---------------- RESOLUTION + // (cl C)* + // + // * the corresponding proof node is C + case PfRule::ARITH_TRICHOTOMY: + { + bool success = true; + Node equal, lesser, greater; + + Kind k = res.getKind(); + if (k == kind::EQUAL) + { + equal = res; + if (children[0].getKind() == kind::LEQ) + { + greater = children[0]; + lesser = children[1]; + } + else + { + greater = children[1]; + lesser = children[0]; + } + } + // Add case where res is not = + else if (res.getKind() == kind::GT) + { + greater = res; + if (children[0].getKind() == kind::NOT) + { + equal = children[0]; + lesser = children[1]; + } + else + { + equal = children[1]; + lesser = children[0]; + } + } + else + { + lesser = res; + if (children[0].getKind() == kind::NOT) + { + equal = children[0]; + greater = children[1]; + } + else + { + equal = children[1]; + greater = children[0]; + } + } + + Node x, c; + if (equal.getKind() == kind::NOT) + { + x = equal[0][0]; + c = equal[0][1]; + } + else + { + x = equal[0]; + c = equal[1]; + } + Node vp_child1 = children[0], vp_child2 = children[1]; + + // Preprocessing + if (res == equal || res == greater) + { // C = (= x c) or C = (> x c) + // lesser = (>= x c) + Node vpc2 = nm->mkNode( + kind::SEXPR, + d_cl, + nm->mkNode(kind::GEQ, x, c).eqNode(nm->mkNode(kind::LEQ, c, x))); + // (cl (= (>= x c) (<= c x))) + Node vpc1 = nm->mkNode(kind::SEXPR, + {d_cl, + vpc2[1].notNode(), + nm->mkNode(kind::GEQ, x, c).notNode(), + nm->mkNode(kind::LEQ, c, x)}); + // (cl (not(= (>= x c) (<= c x))) (not (>= x c)) (<= c x)) + vp_child1 = nm->mkNode( + kind::SEXPR, d_cl, nm->mkNode(kind::LEQ, c, x)); // (cl (<= c x)) + + success &= + addAletheStep(AletheRule::EQUIV_POS2, vpc1, vpc1, {}, {}, *cdp) + && addAletheStep( + AletheRule::COMP_SIMPLIFY, vpc2, vpc2, {}, {}, *cdp) + && addAletheStep(AletheRule::RESOLUTION, + vp_child1, + vp_child1, + {vpc1, vpc2, lesser}, + {}, + *cdp); + // greater = (<= x c) or greater = (not (= x c)) -> no preprocessing + // necessary + vp_child2 = res == equal ? greater : equal; + } + + // Process + Node vp1 = nm->mkNode(kind::SEXPR, + d_cl, + nm->mkNode(kind::OR, + nm->mkNode(kind::EQUAL, x, c), + nm->mkNode(kind::LEQ, x, c).notNode(), + nm->mkNode(kind::LEQ, c, x).notNode())); + // (cl (or (= x c) (not (<= x c)) (not (<= c x)))) + Node vp2 = nm->mkNode(kind::SEXPR, + {d_cl, + nm->mkNode(kind::EQUAL, x, c), + nm->mkNode(kind::LEQ, x, c).notNode(), + nm->mkNode(kind::LEQ, c, x).notNode()}); + // (cl (= x c) (not (<= x c)) (not (<= c x))) + success &= + addAletheStep(AletheRule::LA_DISEQUALITY, vp1, vp1, {}, {}, *cdp) + && addAletheStep(AletheRule::OR, vp2, vp2, {vp1}, {}, *cdp); + + // Postprocessing + if (res == equal) + { // no postprocessing necessary + return success + && addAletheStep(AletheRule::RESOLUTION, + res, + nm->mkNode(kind::SEXPR, d_cl, res), + {vp2, vp_child1, vp_child2}, + {}, + *cdp); + } + if (res == greater) + { // have (not (<= x c)) but result should be (> x c) + Node vp3 = nm->mkNode( + kind::SEXPR, + d_cl, + nm->mkNode(kind::LEQ, x, c).notNode()); // (cl (not (<= x c))) + Node vp4 = nm->mkNode( + kind::SEXPR, + {d_cl, + nm->mkNode(kind::EQUAL, + nm->mkNode(kind::GT, x, c), + nm->mkNode(kind::LEQ, x, c).notNode()) + .notNode(), + nm->mkNode(kind::GT, x, c), + nm->mkNode(kind::LEQ, x, c) + .notNode() + .notNode()}); // (cl (not(= (> x c) (not (<= x c)))) (> x c) + // (not (not (<= x c)))) + Node vp5 = + nm->mkNode(kind::SEXPR, + d_cl, + nm->mkNode(kind::GT, x, c) + .eqNode(nm->mkNode(kind::LEQ, x, c).notNode())); + // (cl (= (> x c) (not (<= x c)))) + + return success + && addAletheStep(AletheRule::RESOLUTION, + vp3, + vp3, + {vp2, vp_child1, vp_child2}, + {}, + *cdp) + && addAletheStep(AletheRule::EQUIV_POS1, vp4, vp4, {}, {}, *cdp) + && addAletheStep( + AletheRule::COMP_SIMPLIFY, vp5, vp5, {}, {}, *cdp) + && addAletheStep(AletheRule::RESOLUTION, + res, + nm->mkNode(kind::SEXPR, d_cl, res), + {vp3, vp4, vp5}, + {}, + *cdp); + } + // have (not (<= c x)) but result should be (< x c) + Node vp3 = nm->mkNode( + kind::SEXPR, + d_cl, + nm->mkNode(kind::LEQ, c, x).notNode()); // (cl (not (<= c x))) + Node vp4 = + nm->mkNode(kind::SEXPR, + {d_cl, + nm->mkNode(kind::LT, x, c) + .eqNode(nm->mkNode(kind::LEQ, c, x).notNode()) + .notNode(), + nm->mkNode(kind::LT, x, c), + nm->mkNode(kind::LEQ, c, x) + .notNode() + .notNode()}); // (cl (not(= (< x c) (not (<= c x)))) + // (< x c) (not (not (<= c x)))) + Node vp5 = nm->mkNode( + kind::SEXPR, + d_cl, + nm->mkNode(kind::LT, x, c) + .eqNode(nm->mkNode(kind::LEQ, c, x) + .notNode())); // (cl (= (< x c) (not (<= c x)))) + return success + && addAletheStep(AletheRule::RESOLUTION, + vp3, + vp3, + {vp2, vp_child1, vp_child2}, + {}, + *cdp) + && addAletheStep(AletheRule::EQUIV_POS1, vp4, vp4, {}, {}, *cdp) + && addAletheStep(AletheRule::COMP_SIMPLIFY, vp5, vp5, {}, {}, *cdp) + && addAletheStep(AletheRule::RESOLUTION, + res, + nm->mkNode(kind::SEXPR, d_cl, res), + {vp3, vp4, vp5}, + {}, + *cdp); + } default: { return addAletheStep(AletheRule::UNDEFINED, @@ -1445,17 +1672,28 @@ bool AletheProofPostprocessCallback::finalize(Node res, { std::shared_ptr<ProofNode> childPf = cdp->getProofFor(children[0]); Node childConclusion = childPf->getArguments()[2]; + AletheRule childRule = getAletheRule(childPf->getArguments()[0]); // if child conclusion is of the form (sexpr cl (or ...)), then we need // to add an OR step, since this child must not be a singleton - if (childConclusion.getNumChildren() == 2 && childConclusion[0] == d_cl - && childConclusion[1].getKind() == kind::OR) + if ((childConclusion.getNumChildren() == 2 && childConclusion[0] == d_cl + && childConclusion[1].getKind() == kind::OR) + || (childRule == AletheRule::ASSUME + && childConclusion.getKind() == kind::OR)) { hasUpdated = true; // Add or step std::vector<Node> subterms{d_cl}; - subterms.insert(subterms.end(), - childConclusion[1].begin(), - childConclusion[1].end()); + if (childRule == AletheRule::ASSUME) + { + subterms.insert( + subterms.end(), childConclusion.begin(), childConclusion.end()); + } + else + { + subterms.insert(subterms.end(), + childConclusion[1].begin(), + childConclusion[1].end()); + } Node newConclusion = nm->mkNode(kind::SEXPR, subterms); addAletheStep(AletheRule::OR, newConclusion, @@ -1484,16 +1722,27 @@ bool AletheProofPostprocessCallback::finalize(Node res, { std::shared_ptr<ProofNode> childPf = cdp->getProofFor(children[i]); Node childConclusion = childPf->getArguments()[2]; + AletheRule childRule = getAletheRule(childPf->getArguments()[0]); // Add or step - if (childConclusion.getNumChildren() == 2 - && childConclusion[0] == d_cl - && childConclusion[1].getKind() == kind::OR) + if ((childConclusion.getNumChildren() == 2 + && childConclusion[0] == d_cl + && childConclusion[1].getKind() == kind::OR) + || (childRule == AletheRule::ASSUME + && childConclusion.getKind() == kind::OR)) { hasUpdated = true; std::vector<Node> lits{d_cl}; - lits.insert(lits.end(), - childConclusion[1].begin(), - childConclusion[1].end()); + if (childRule == AletheRule::ASSUME) + { + lits.insert( + lits.end(), childConclusion.begin(), childConclusion.end()); + } + else + { + lits.insert(lits.end(), + childConclusion[1].begin(), + childConclusion[1].end()); + } Node conclusion = nm->mkNode(kind::SEXPR, lits); addAletheStep(AletheRule::OR, conclusion, @@ -1547,14 +1796,25 @@ bool AletheProofPostprocessCallback::finalize(Node res, { std::shared_ptr<ProofNode> childPf = cdp->getProofFor(children[0]); Node childConclusion = childPf->getArguments()[2]; - if (childConclusion.getNumChildren() == 2 && childConclusion[0] == d_cl - && childConclusion[1].getKind() == kind::OR) + AletheRule childRule = getAletheRule(childPf->getArguments()[0]); + if ((childConclusion.getNumChildren() == 2 && childConclusion[0] == d_cl + && childConclusion[1].getKind() == kind::OR) + || (childRule == AletheRule::ASSUME + && childConclusion.getKind() == kind::OR)) { // Add or step for child std::vector<Node> subterms{d_cl}; - subterms.insert(subterms.end(), - childConclusion[1].begin(), - childConclusion[1].end()); + if (getAletheRule(childPf->getArguments()[0]) == AletheRule::ASSUME) + { + subterms.insert( + subterms.end(), childConclusion.begin(), childConclusion.end()); + } + else + { + subterms.insert(subterms.end(), + childConclusion[1].begin(), + childConclusion[1].end()); + } Node newChild = nm->mkNode(kind::SEXPR, subterms); addAletheStep( AletheRule::OR, newChild, newChild, {children[0]}, {}, *cdp); @@ -1614,10 +1874,7 @@ bool AletheProofPostprocessCallback::finalStep( if (id != PfRule::ALETHE_RULE) { std::vector<Node> sanitized_args{ - res, - res, - nm->mkConst<Rational>(CONST_RATIONAL, - static_cast<unsigned>(AletheRule::ASSUME))}; + res, res, nm->mkConstInt(static_cast<uint32_t>(AletheRule::ASSUME))}; for (const Node& arg : args) { sanitized_args.push_back(d_anc.convert(arg)); @@ -1680,8 +1937,8 @@ bool AletheProofPostprocessCallback::addAletheStep( } std::vector<Node> new_args = std::vector<Node>(); - new_args.push_back(NodeManager::currentNM()->mkConst( - CONST_RATIONAL, Rational(static_cast<unsigned>(rule)))); + new_args.push_back(NodeManager::currentNM()->mkConstInt( + Rational(static_cast<uint32_t>(rule)))); new_args.push_back(res); new_args.push_back(sanitized_conclusion); new_args.insert(new_args.end(), args.begin(), args.end()); @@ -1712,7 +1969,37 @@ AletheProofPostprocess::AletheProofPostprocess(ProofNodeManager* pnm, AletheProofPostprocess::~AletheProofPostprocess() {} -void AletheProofPostprocess::process(std::shared_ptr<ProofNode> pf) {} +void AletheProofPostprocess::process(std::shared_ptr<ProofNode> pf) { + // Translate proof node + ProofNodeUpdater updater(d_pnm, d_cb,true,false); + updater.process(pf->getChildren()[0]); + + // In the Alethe proof format the final step has to be (cl). However, after + // the translation it might be (cl false). In that case additional steps are + // required. + // The function has the additional purpose of sanitizing the attributes of the + // first SCOPE + CDProof cpf(d_pnm, nullptr, "ProofNodeUpdater::CDProof", true); + const std::vector<std::shared_ptr<ProofNode>>& cc = pf->getChildren(); + std::vector<Node> ccn; + for (const std::shared_ptr<ProofNode>& cp : cc) + { + Node cpres = cp->getResult(); + ccn.push_back(cpres); + // store in the proof + cpf.addProof(cp); + } + if (d_cb.finalStep( + pf->getResult(), pf->getRule(), ccn, pf->getArguments(), &cpf)) + { + std::shared_ptr<ProofNode> npn = cpf.getProofFor(pf->getResult()); + + // then, update the original proof node based on this one + Trace("pf-process-debug") << "Update node..." << std::endl; + d_pnm->updateNode(pf.get(), npn.get()); + Trace("pf-process-debug") << "...update node finished." << std::endl; + } +} } // namespace proof diff --git a/src/proof/annotation_proof_generator.cpp b/src/proof/annotation_proof_generator.cpp new file mode 100644 index 000000000..e9467276b --- /dev/null +++ b/src/proof/annotation_proof_generator.cpp @@ -0,0 +1,87 @@ +/****************************************************************************** + * Top contributors (to current version): + * Andrew Reynolds + * + * This file is part of the cvc5 project. + * + * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS + * in the top-level source directory and their institutional affiliations. + * All rights reserved. See the file COPYING in the top-level source + * directory for licensing information. + * **************************************************************************** + * + * Implementation of the annotation proof generator class. + */ + +#include "proof/annotation_proof_generator.h" + +#include "proof/proof.h" +#include "proof/proof_node.h" +#include "proof/proof_node_manager.h" + +namespace cvc5 { + +AnnotationProofGenerator::AnnotationProofGenerator(ProofNodeManager* pnm, + context::Context* c, + std::string name) + : d_pnm(pnm), + d_name(name), + d_exps(c == nullptr ? &d_context : c), + d_proofs(c == nullptr ? &d_context : c) +{ +} + +void AnnotationProofGenerator::setExplanationFor(Node f, + ProofGenerator* pg, + Annotator* a) +{ + Assert(pg != nullptr); + d_exps[f] = std::pair<ProofGenerator*, Annotator*>(pg, a); +} + +std::shared_ptr<ProofNode> AnnotationProofGenerator::getProofFor(Node f) +{ + // is the proof already cached? + NodeProofNodeMap::iterator it = d_proofs.find(f); + if (it != d_proofs.end()) + { + return (*it).second; + } + // make it into an actual proof now + NodeExpMap::iterator itx = d_exps.find(f); + if (itx == d_exps.end()) + { + return nullptr; + } + // get the proof from the proof generator + std::shared_ptr<ProofNode> pf = itx->second.first->getProofFor(f); + if (pf == nullptr) + { + d_proofs[f] = nullptr; + return nullptr; + } + // now anntoate it if an annotator was provided + std::shared_ptr<ProofNode> pfa = pf; + if (itx->second.second != nullptr) + { + pfa = itx->second.second->annotate(pf); + } + d_proofs[f] = pfa; + return pfa; +} + +TrustNode AnnotationProofGenerator::transform(const TrustNode& trn, + Annotator* a) +{ + setExplanationFor(trn.getProven(), trn.getGenerator(), a); + return TrustNode::mkReplaceGenTrustNode(trn, this); +} + +bool AnnotationProofGenerator::hasProofFor(Node f) +{ + return d_exps.find(f) != d_exps.end(); +} + +std::string AnnotationProofGenerator::identify() const { return d_name; } + +} // namespace cvc5 diff --git a/src/proof/annotation_proof_generator.h b/src/proof/annotation_proof_generator.h new file mode 100644 index 000000000..fb737dc44 --- /dev/null +++ b/src/proof/annotation_proof_generator.h @@ -0,0 +1,102 @@ +/****************************************************************************** + * Top contributors (to current version): + * Andrew Reynolds + * + * This file is part of the cvc5 project. + * + * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS + * in the top-level source directory and their institutional affiliations. + * All rights reserved. See the file COPYING in the top-level source + * directory for licensing information. + * **************************************************************************** + * + * The annotation proof generator class. + */ + +#include "cvc5_private.h" + +#ifndef CVC5__PROOF__ANNOTATION_PROOF_GENERATOR_H +#define CVC5__PROOF__ANNOTATION_PROOF_GENERATOR_H + +#include "context/cdhashmap.h" +#include "expr/node.h" +#include "proof/proof_generator.h" +#include "proof/trust_node.h" + +namespace cvc5 { + +class ProofNodeManager; + +/** + * Base class for annotators. An annotator is a utility that implements a + * simple transformation on proofs: `annotate` below. + */ +class Annotator +{ + public: + Annotator() {} + virtual ~Annotator() {} + /** + * Annotate the proof node. This must return a proof node that concludes the + * same thing as p. + */ + virtual std::shared_ptr<ProofNode> annotate(std::shared_ptr<ProofNode> p) = 0; +}; + +/** + * Annotation proof generator, used to "wrap" proofs of other proof generators + * via the annotate method above. + */ +class AnnotationProofGenerator : public ProofGenerator +{ + typedef context::CDHashMap<Node, std::pair<ProofGenerator*, Annotator*>> + NodeExpMap; + typedef context::CDHashMap<Node, std::shared_ptr<ProofNode>> NodeProofNodeMap; + + public: + AnnotationProofGenerator(ProofNodeManager* pnm, + context::Context* c = nullptr, + std::string name = "AnnotationProofGenerator"); + ~AnnotationProofGenerator() {} + /** Get the proof for formula f. */ + std::shared_ptr<ProofNode> getProofFor(Node f) override; + /** Can we give the proof for formula f? */ + bool hasProofFor(Node f) override; + /** + * Set explanation for fact f, called when pg has a proof for f. + * + * @param f The fact proven by pg, + * @param pg The proof generator that can prove f. + * @param a The annotator that will annotate the proof of f, if necessary. + */ + void setExplanationFor(Node f, ProofGenerator* pg, Annotator* a); + /** + * Transform trust node, will be annotated by the given annotator. + */ + TrustNode transform(const TrustNode& trn, Annotator* a); + /** identify */ + std::string identify() const override; + + protected: + /** The proof node manager */ + ProofNodeManager* d_pnm; + /** Name identifier */ + std::string d_name; + /** A dummy context used by this class if none is provided */ + context::Context d_context; + /** + * A context-dependent map from formulas to a generator + annotation + * pair, which will be used to generate the proof of formulas if asked. + * We use the context provided to this class or otherwise d_context above. + */ + NodeExpMap d_exps; + /** + * A context-dependent map from formulas to the proof nodes we have + * returned in calls to getProofFor. + */ + NodeProofNodeMap d_proofs; +}; + +} // namespace cvc5 + +#endif /* CVC5__PROOF__ANNOTATION_PROOF_GENERATOR_H */ diff --git a/src/proof/lazy_proof_chain.cpp b/src/proof/lazy_proof_chain.cpp index 0de5673ab..3280626ad 100644 --- a/src/proof/lazy_proof_chain.cpp +++ b/src/proof/lazy_proof_chain.cpp @@ -30,7 +30,8 @@ LazyCDProofChain::LazyCDProofChain(ProofNodeManager* pnm, ProofGenerator* defGen, bool defRec, const std::string& name) - : d_manager(pnm), + : CDProof(pnm, c, name, false), + d_manager(pnm), d_cyclic(cyclic), d_defRec(defRec), d_context(), @@ -85,21 +86,10 @@ std::shared_ptr<ProofNode> LazyCDProofChain::getProofFor(Node fact) Trace("lazy-cdproofchain") << "LazyCDProofChain::getProofFor: check " << cur << "\n"; Assert(toConnect.find(cur) == toConnect.end()); + // The current fact may be justified by concrete steps added to this + // proof, in which case we do not use the generators. bool rec = true; - ProofGenerator* pg = getGeneratorForInternal(cur, rec); - if (!pg) - { - Trace("lazy-cdproofchain") - << "LazyCDProofChain::getProofFor: nothing to do\n"; - // nothing to do for this fact, it'll be a leaf in the final proof - // node, don't post-traverse. - visited[cur] = true; - continue; - } - Trace("lazy-cdproofchain") - << "LazyCDProofChain::getProofFor: Call generator " << pg->identify() - << " for chain link " << cur << "\n"; - std::shared_ptr<ProofNode> curPfn = pg->getProofFor(cur); + std::shared_ptr<ProofNode> curPfn = getProofForInternal(cur, rec); if (curPfn == nullptr) { Trace("lazy-cdproofchain") @@ -107,7 +97,8 @@ std::shared_ptr<ProofNode> LazyCDProofChain::getProofFor(Node fact) visited[cur] = true; continue; } - // map node whose proof node must be expanded to the respective poof node + // map node whose proof node must be expanded to the respective poof + // node toConnect[cur] = curPfn; // We may not want to recursively connect this proof so we skip. if (!rec) @@ -368,6 +359,27 @@ ProofGenerator* LazyCDProofChain::getGeneratorForInternal(Node fact, bool& rec) return nullptr; } +std::shared_ptr<ProofNode> LazyCDProofChain::getProofForInternal(Node fact, + bool& rec) +{ + std::shared_ptr<ProofNode> pfn = CDProof::getProofFor(fact); + Assert(pfn != nullptr); + // If concrete proof, save it, otherwise try generators. + if (pfn->getRule() != PfRule::ASSUME) + { + return pfn; + } + ProofGenerator* pg = getGeneratorForInternal(fact, rec); + if (!pg) + { + return nullptr; + } + Trace("lazy-cdproofchain") + << "LazyCDProofChain::getProofFor: Call generator " << pg->identify() + << " for chain link " << fact << "\n"; + return pg->getProofFor(fact); +} + std::string LazyCDProofChain::identify() const { return d_name; } } // namespace cvc5 diff --git a/src/proof/lazy_proof_chain.h b/src/proof/lazy_proof_chain.h index d15b8f9e2..114e2310e 100644 --- a/src/proof/lazy_proof_chain.h +++ b/src/proof/lazy_proof_chain.h @@ -20,8 +20,7 @@ #include <vector> -#include "context/cdhashmap.h" -#include "proof/proof_generator.h" +#include "proof/proof.h" namespace cvc5 { @@ -36,7 +35,7 @@ class ProofNodeManager; * connecting, for the proof generated to one fact, assumptions to the proofs * generated for those assumptinos that are registered in the chain. */ -class LazyCDProofChain : public ProofGenerator +class LazyCDProofChain : public CDProof { public: /** Constructor @@ -92,6 +91,11 @@ class LazyCDProofChain : public ProofGenerator * it is required to do so. This mapping is maintained in the remainder of * the current context (according to the context c provided to this class). * + * It is important to note that pg is asked to provide a proof for expected + * only when no other call for the fact expected is provided via the addStep + * method of this class. In particular, pg is asked to prove expected when it + * appears as the conclusion of an ASSUME leaf within CDProof::getProofFor. + * * Moreover the lazy steps of this class are expected to fulfill the * requirement that pg.getProofFor(expected) generates a proof node closed * with relation to @@ -136,6 +140,14 @@ class LazyCDProofChain : public ProofGenerator * true if we should recurse on its proof. */ ProofGenerator* getGeneratorForInternal(Node fact, bool& rec); + /** + * Get internal proof for fact from the underlying CDProof, if any, otherwise + * via a call to the above method. + * + * Returns a nullptr when no internal proof stored. + */ + std::shared_ptr<ProofNode> getProofForInternal(Node fact, bool& rec); + /** The proof manager, used for allocating new ProofNode objects */ ProofNodeManager* d_manager; /** Whether this instance is robust to cycles in the chain. */ diff --git a/src/proof/lfsc/lfsc_node_converter.cpp b/src/proof/lfsc/lfsc_node_converter.cpp index 6eab9b036..5af1c2b7e 100644 --- a/src/proof/lfsc/lfsc_node_converter.cpp +++ b/src/proof/lfsc/lfsc_node_converter.cpp @@ -89,7 +89,7 @@ Node LfscNodeConverter::postConvert(Node n) } // bound variable v is (bvar x T) TypeNode intType = nm->integerType(); - Node x = nm->mkConst(CONST_RATIONAL, Rational(getOrAssignIndexForVar(n))); + Node x = nm->mkConstInt(Rational(getOrAssignIndexForVar(n))); Node tc = typeAsNode(convertType(tn)); TypeNode ftype = nm->mkFunctionType({intType, d_sortType}, tn); Node bvarOp = getSymbolInternal(k, ftype, "bvar"); @@ -136,8 +136,7 @@ Node LfscNodeConverter::postConvert(Node n) TypeNode intType = nm->integerType(); TypeNode varType = nm->mkFunctionType({intType, d_sortType}, tn); Node var = mkInternalSymbol("var", varType); - Node index = - nm->mkConst(CONST_RATIONAL, Rational(getOrAssignIndexForVar(n))); + Node index = nm->mkConstInt(Rational(getOrAssignIndexForVar(n))); Node tc = typeAsNode(convertType(tn)); return nm->mkNode(APPLY_UF, var, index, tc); } @@ -176,7 +175,7 @@ Node LfscNodeConverter::postConvert(Node n) Node hconstf = getSymbolInternal(k, tnh, "apply"); return nm->mkNode(APPLY_UF, hconstf, n[0], n[1]); } - else if (k == CONST_RATIONAL || k == CAST_TO_REAL) + else if (k == CONST_RATIONAL || k == CONST_INTEGER || k == CAST_TO_REAL) { if (k == CAST_TO_REAL) { @@ -184,8 +183,9 @@ Node LfscNodeConverter::postConvert(Node n) do { n = n[0]; - Assert(n.getKind() == APPLY_UF || n.getKind() == CONST_RATIONAL); - } while (n.getKind() != CONST_RATIONAL); + Assert(n.getKind() == APPLY_UF || n.getKind() == CONST_RATIONAL + || n.getKind() == CONST_INTEGER); + } while (n.getKind() != CONST_RATIONAL && n.getKind() != CONST_INTEGER); } TypeNode tnv = nm->mkFunctionType(tn, tn); Node rconstf; @@ -198,7 +198,7 @@ Node LfscNodeConverter::postConvert(Node n) { // use LFSC syntax for mpz negation Node mpzn = getSymbolInternal(k, nm->mkFunctionType(tn, tn), "~"); - arg = nm->mkNode(APPLY_UF, mpzn, nm->mkConst(CONST_RATIONAL, r.abs())); + arg = nm->mkNode(APPLY_UF, mpzn, nm->mkConstInt(r.abs())); } else { @@ -344,8 +344,8 @@ Node LfscNodeConverter::postConvert(Node n) Node rop = getSymbolInternal( k, relType, printer::smt2::Smt2Printer::smtKindString(k)); RegExpLoop op = n.getOperator().getConst<RegExpLoop>(); - Node n1 = nm->mkConst(CONST_RATIONAL, Rational(op.d_loopMinOcc)); - Node n2 = nm->mkConst(CONST_RATIONAL, Rational(op.d_loopMaxOcc)); + Node n1 = nm->mkConstInt(Rational(op.d_loopMinOcc)); + Node n2 = nm->mkConstInt(Rational(op.d_loopMaxOcc)); return nm->mkNode(APPLY_UF, nm->mkNode(APPLY_UF, rop, n1, n2), n[0]); } else if (k == MATCH) @@ -485,16 +485,14 @@ TypeNode LfscNodeConverter::postConvertType(TypeNode tn) else if (k == BITVECTOR_TYPE) { tnn = d_typeKindToNodeCons[k]; - Node w = nm->mkConst(CONST_RATIONAL, Rational(tn.getBitVectorSize())); + Node w = nm->mkConstInt(Rational(tn.getBitVectorSize())); tnn = nm->mkNode(APPLY_UF, tnn, w); } else if (k == FLOATINGPOINT_TYPE) { tnn = d_typeKindToNodeCons[k]; - Node e = nm->mkConst(CONST_RATIONAL, - Rational(tn.getFloatingPointExponentSize())); - Node s = nm->mkConst(CONST_RATIONAL, - Rational(tn.getFloatingPointSignificandSize())); + Node e = nm->mkConstInt(Rational(tn.getFloatingPointExponentSize())); + Node s = nm->mkConstInt(Rational(tn.getFloatingPointSignificandSize())); tnn = nm->mkNode(APPLY_UF, tnn, e, s); } else if (tn.getNumChildren() == 0) @@ -723,8 +721,7 @@ void LfscNodeConverter::getCharVectorInternal(Node c, std::vector<Node>& chars) Node aconstf = getSymbolInternal(CONST_STRING, tnc, "char"); for (unsigned i = 0, size = vec.size(); i < size; i++) { - Node cc = nm->mkNode( - APPLY_UF, aconstf, nm->mkConst(CONST_RATIONAL, Rational(vec[i]))); + Node cc = nm->mkNode(APPLY_UF, aconstf, nm->mkConstInt(Rational(vec[i]))); chars.push_back(cc); } } @@ -747,42 +744,36 @@ std::vector<Node> LfscNodeConverter::getOperatorIndices(Kind k, Node n) case BITVECTOR_EXTRACT: { BitVectorExtract p = n.getConst<BitVectorExtract>(); - indices.push_back(nm->mkConst(CONST_RATIONAL, Rational(p.d_high))); - indices.push_back(nm->mkConst(CONST_RATIONAL, Rational(p.d_low))); + indices.push_back(nm->mkConstInt(Rational(p.d_high))); + indices.push_back(nm->mkConstInt(Rational(p.d_low))); break; } case BITVECTOR_REPEAT: - indices.push_back( - nm->mkConst(CONST_RATIONAL, - Rational(n.getConst<BitVectorRepeat>().d_repeatAmount))); + indices.push_back(nm->mkConstInt( + Rational(n.getConst<BitVectorRepeat>().d_repeatAmount))); break; case BITVECTOR_ZERO_EXTEND: - indices.push_back(nm->mkConst( - CONST_RATIONAL, + indices.push_back(nm->mkConstInt( Rational(n.getConst<BitVectorZeroExtend>().d_zeroExtendAmount))); break; case BITVECTOR_SIGN_EXTEND: - indices.push_back(nm->mkConst( - CONST_RATIONAL, + indices.push_back(nm->mkConstInt( Rational(n.getConst<BitVectorSignExtend>().d_signExtendAmount))); break; case BITVECTOR_ROTATE_LEFT: - indices.push_back(nm->mkConst( - CONST_RATIONAL, + indices.push_back(nm->mkConstInt( Rational(n.getConst<BitVectorRotateLeft>().d_rotateLeftAmount))); break; case BITVECTOR_ROTATE_RIGHT: - indices.push_back(nm->mkConst( - CONST_RATIONAL, + indices.push_back(nm->mkConstInt( Rational(n.getConst<BitVectorRotateRight>().d_rotateRightAmount))); break; case INT_TO_BITVECTOR: - indices.push_back(nm->mkConst( - CONST_RATIONAL, Rational(n.getConst<IntToBitVector>().d_size))); + indices.push_back( + nm->mkConstInt(Rational(n.getConst<IntToBitVector>().d_size))); break; case IAND: - indices.push_back( - nm->mkConst(CONST_RATIONAL, Rational(n.getConst<IntAnd>().d_size))); + indices.push_back(nm->mkConstInt(Rational(n.getConst<IntAnd>().d_size))); break; case APPLY_TESTER: { @@ -1023,7 +1014,7 @@ Node LfscNodeConverter::getOperatorOfClosure(Node q, bool macroApply) Node LfscNodeConverter::getOperatorOfBoundVar(Node cop, Node v) { NodeManager* nm = NodeManager::currentNM(); - Node x = nm->mkConst(CONST_RATIONAL, Rational(getOrAssignIndexForVar(v))); + Node x = nm->mkConstInt(Rational(getOrAssignIndexForVar(v))); Node tc = typeAsNode(convertType(v.getType())); return nm->mkNode(APPLY_UF, cop, x, tc); } diff --git a/src/proof/lfsc/lfsc_util.cpp b/src/proof/lfsc/lfsc_util.cpp index 06bedb895..aca884ddc 100644 --- a/src/proof/lfsc/lfsc_util.cpp +++ b/src/proof/lfsc/lfsc_util.cpp @@ -68,8 +68,8 @@ LfscRule getLfscRule(Node n) Node mkLfscRuleNode(LfscRule r) { - return NodeManager::currentNM()->mkConst(CONST_RATIONAL, - Rational(static_cast<uint32_t>(r))); + return NodeManager::currentNM()->mkConstInt( + Rational(static_cast<uint32_t>(r))); } bool LfscProofLetifyTraverseCallback::shouldTraverse(const ProofNode* pn) diff --git a/src/proof/method_id.cpp b/src/proof/method_id.cpp index 9567590a8..042df92bb 100644 --- a/src/proof/method_id.cpp +++ b/src/proof/method_id.cpp @@ -51,8 +51,8 @@ std::ostream& operator<<(std::ostream& out, MethodId id) Node mkMethodId(MethodId id) { - return NodeManager::currentNM()->mkConst(CONST_RATIONAL, - Rational(static_cast<uint32_t>(id))); + return NodeManager::currentNM()->mkConstInt( + Rational(static_cast<uint32_t>(id))); } bool getMethodId(TNode n, MethodId& i) diff --git a/src/proof/proof_checker.cpp b/src/proof/proof_checker.cpp index 5289d77ff..b688a28f3 100644 --- a/src/proof/proof_checker.cpp +++ b/src/proof/proof_checker.cpp @@ -74,8 +74,8 @@ Node ProofRuleChecker::mkKindNode(Kind k) // UNDEFINED_KIND is negative, hence return null to avoid cast return Node::null(); } - return NodeManager::currentNM()->mkConst(CONST_RATIONAL, - Rational(static_cast<uint32_t>(k))); + return NodeManager::currentNM()->mkConstInt( + Rational(static_cast<uint32_t>(k))); } ProofCheckerStatistics::ProofCheckerStatistics() diff --git a/src/proof/proof_node_manager.cpp b/src/proof/proof_node_manager.cpp index e0a7f81c0..c832ac3fa 100644 --- a/src/proof/proof_node_manager.cpp +++ b/src/proof/proof_node_manager.cpp @@ -28,8 +28,10 @@ using namespace cvc5::kind; namespace cvc5 { -ProofNodeManager::ProofNodeManager(theory::Rewriter* rr, ProofChecker* pc) - : d_rewriter(rr), d_checker(pc) +ProofNodeManager::ProofNodeManager(const Options& opts, + theory::Rewriter* rr, + ProofChecker* pc) + : d_opts(opts), d_rewriter(rr), d_checker(pc) { d_true = NodeManager::currentNM()->mkConst(true); // we always allocate a proof checker, regardless of the proof checking mode @@ -329,8 +331,8 @@ Node ProofNodeManager::checkInternal( // a proof checking mode that does not eagerly check rule applications if (!expected.isNull()) { - if (options::proofCheck() == options::ProofCheckMode::LAZY - || options::proofCheck() == options::ProofCheckMode::NONE) + if (d_opts.proof.proofCheck == options::ProofCheckMode::LAZY + || d_opts.proof.proofCheck == options::ProofCheckMode::NONE) { return expected; } @@ -435,7 +437,7 @@ bool ProofNodeManager::updateNodeInternal( { Assert(pn != nullptr); // ---------------- check for cyclic - if (options::proofCheck() == options::ProofCheckMode::EAGER) + if (d_opts.proof.proofCheck == options::ProofCheckMode::EAGER) { std::unordered_set<const ProofNode*> visited; for (const std::shared_ptr<ProofNode>& cpc : children) diff --git a/src/proof/proof_node_manager.h b/src/proof/proof_node_manager.h index 533f6d173..5926a5f2e 100644 --- a/src/proof/proof_node_manager.h +++ b/src/proof/proof_node_manager.h @@ -27,6 +27,7 @@ namespace cvc5 { class ProofChecker; class ProofNode; +class Options; namespace theory { class Rewriter; @@ -58,7 +59,9 @@ class Rewriter; class ProofNodeManager { public: - ProofNodeManager(theory::Rewriter* rr, ProofChecker* pc = nullptr); + ProofNodeManager(const Options& opts, + theory::Rewriter* rr, + ProofChecker* pc = nullptr); ~ProofNodeManager() {} /** * This constructs a ProofNode with the given arguments. The expected @@ -188,6 +191,8 @@ class ProofNodeManager static ProofNode* cancelDoubleSymm(ProofNode* pn); private: + /** Reference to the options */ + const Options& d_opts; /** The rewriter */ theory::Rewriter* d_rewriter; /** The (optional) proof checker */ diff --git a/src/proof/proof_node_to_sexpr.cpp b/src/proof/proof_node_to_sexpr.cpp index e8871af34..910af3d90 100644 --- a/src/proof/proof_node_to_sexpr.cpp +++ b/src/proof/proof_node_to_sexpr.cpp @@ -297,6 +297,12 @@ ProofNodeToSExpr::ArgFormat ProofNodeToSExpr::getArgumentFormat( } } break; + case PfRule::ANNOTATION: + if (i == 0) + { + return ArgFormat::INFERENCE_ID; + } + break; default: break; } return ArgFormat::DEFAULT; diff --git a/src/proof/proof_rule.cpp b/src/proof/proof_rule.cpp index c82928dc5..9bd714161 100644 --- a/src/proof/proof_rule.cpp +++ b/src/proof/proof_rule.cpp @@ -33,6 +33,7 @@ const char* toString(PfRule id) case PfRule::MACRO_SR_PRED_INTRO: return "MACRO_SR_PRED_INTRO"; case PfRule::MACRO_SR_PRED_ELIM: return "MACRO_SR_PRED_ELIM"; case PfRule::MACRO_SR_PRED_TRANSFORM: return "MACRO_SR_PRED_TRANSFORM"; + case PfRule::ANNOTATION: return "ANNOTATION"; case PfRule::REMOVE_TERM_FORMULA_AXIOM: return "REMOVE_TERM_FORMULA_AXIOM"; //================================================= Trusted rules case PfRule::THEORY_LEMMA: return "THEORY_LEMMA"; diff --git a/src/proof/proof_rule.h b/src/proof/proof_rule.h index d9e92fa92..eaa92c02c 100644 --- a/src/proof/proof_rule.h +++ b/src/proof/proof_rule.h @@ -185,6 +185,14 @@ enum class PfRule : uint32_t // where F' and G' are the result of each side of the equation above. Here, // original forms are used in a similar manner to MACRO_SR_PRED_INTRO above. MACRO_SR_PRED_TRANSFORM, + // ======== Annotation + // Children: (P1:F) + // Arguments: (a1 ... an) + // ---------------------------------------- + // Conclusion: F + // The terms a1 ... an can be anything used to annotate the proof node, one + // example is where a1 is a theory::InferenceId. + ANNOTATION, //================================================= Processing rules // ======== Remove Term Formulas Axiom // Children: none diff --git a/src/proof/unsat_core.cpp b/src/proof/unsat_core.cpp index 68e0f9a85..419dda9e2 100644 --- a/src/proof/unsat_core.cpp +++ b/src/proof/unsat_core.cpp @@ -52,7 +52,8 @@ UnsatCore::const_iterator UnsatCore::end() const { void UnsatCore::toStream(std::ostream& out) const { options::ioutils::Scope scope(out); options::ioutils::applyDagThresh(out, 0); - Printer::getPrinter(options::outputLanguage())->toStream(out, *this); + auto language = options::ioutils::getOutputLang(out); + Printer::getPrinter(language)->toStream(out, *this); } std::ostream& operator<<(std::ostream& out, const UnsatCore& core) { diff --git a/src/prop/minisat/core/Solver.cc b/src/prop/minisat/core/Solver.cc index 36f31eba9..a82ab5e06 100644 --- a/src/prop/minisat/core/Solver.cc +++ b/src/prop/minisat/core/Solver.cc @@ -145,12 +145,14 @@ class ScopedBool //================================================================================================= // Constructor/Destructor: -Solver::Solver(cvc5::prop::TheoryProxy* proxy, +Solver::Solver(Env& env, + cvc5::prop::TheoryProxy* proxy, cvc5::context::Context* context, cvc5::context::UserContext* userContext, ProofNodeManager* pnm, bool enableIncremental) - : d_proxy(proxy), + : EnvObj(env), + d_proxy(proxy), d_context(context), assertionLevel(0), d_pfManager(nullptr), @@ -454,7 +456,7 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable, ClauseId& id) // If a literal is false at 0 level (both sat and user level) we also // ignore it, unless we are tracking the SAT solver's reasoning if (value(ps[i]) == l_False) { - if (!options::unsatCores() && !needProof() && level(var(ps[i])) == 0 + if (!options().smt.unsatCores && !needProof() && level(var(ps[i])) == 0 && user_level(var(ps[i])) == 0) { continue; @@ -489,7 +491,7 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable, ClauseId& id) // If all false, we're in conflict if (ps.size() == falseLiteralsCount) { - if (options::unsatCores() || needProof()) + if (options().smt.unsatCores || needProof()) { // Take care of false units here; otherwise, we need to // construct the clause below to give to the proof manager @@ -520,7 +522,7 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable, ClauseId& id) clauses_persistent.push(cr); attachClause(cr); - if (options::unsatCores() || needProof()) + if (options().smt.unsatCores || needProof()) { if (ps.size() == falseLiteralsCount) { @@ -2043,7 +2045,7 @@ CRef Solver::updateLemmas() { // If it's an empty lemma, we have a conflict at zero level if (lemma.size() == 0) { - Assert(!options::unsatCores() && !needProof()); + Assert(!options().smt.unsatCores && !needProof()); conflict = CRef_Lazy; backtrackLevel = 0; Debug("minisat::lemmas") << "Solver::updateLemmas(): found empty clause" << std::endl; @@ -2189,8 +2191,8 @@ bool Solver::isProofEnabled() const { return d_pfManager != nullptr; } bool Solver::needProof() const { return isProofEnabled() - && options::unsatCoresMode() != options::UnsatCoresMode::ASSUMPTIONS - && options::unsatCoresMode() != options::UnsatCoresMode::PP_ONLY; + && options().smt.unsatCoresMode != options::UnsatCoresMode::ASSUMPTIONS + && options().smt.unsatCoresMode != options::UnsatCoresMode::PP_ONLY; } } // namespace Minisat diff --git a/src/prop/minisat/core/Solver.h b/src/prop/minisat/core/Solver.h index d0f5006e1..c5dc807ac 100644 --- a/src/prop/minisat/core/Solver.h +++ b/src/prop/minisat/core/Solver.h @@ -35,6 +35,7 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA #include "prop/minisat/mtl/Vec.h" #include "prop/minisat/utils/Options.h" #include "prop/sat_proof_manager.h" +#include "smt/env_obj.h" #include "theory/theory.h" #include "util/resource_manager.h" @@ -52,7 +53,8 @@ namespace Minisat { //================================================================================================= // Solver -- the main class: -class Solver { +class Solver : protected EnvObj +{ /** The only two cvc5 entry points to the private solver data */ friend class cvc5::prop::PropEngine; friend class cvc5::prop::TheoryProxy; @@ -128,7 +130,8 @@ public: // Constructor/Destructor: // - Solver(cvc5::prop::TheoryProxy* proxy, + Solver(Env& env, + cvc5::prop::TheoryProxy* proxy, cvc5::context::Context* context, cvc5::context::UserContext* userContext, ProofNodeManager* pnm, @@ -549,11 +552,8 @@ public: // Returns a random integer 0 <= x < size. Seed must never be 0. static inline int irand(double& seed, int size) { return (int)(drand(seed) * size); } - }; - - //================================================================================================= // Implementation of inline methods: diff --git a/src/prop/minisat/minisat.cpp b/src/prop/minisat/minisat.cpp index a681aa4f1..a8da07753 100644 --- a/src/prop/minisat/minisat.cpp +++ b/src/prop/minisat/minisat.cpp @@ -121,7 +121,8 @@ void MinisatSatSolver::initialize(context::Context* context, // Create the solver d_minisat = - new Minisat::SimpSolver(theoryProxy, + new Minisat::SimpSolver(d_env, + theoryProxy, d_context, userContext, pnm, diff --git a/src/prop/minisat/simp/SimpSolver.cc b/src/prop/minisat/simp/SimpSolver.cc index 04db5e3cb..32b0b736f 100644 --- a/src/prop/minisat/simp/SimpSolver.cc +++ b/src/prop/minisat/simp/SimpSolver.cc @@ -48,25 +48,26 @@ static DoubleOption opt_simp_garbage_frac(_cat, "simp-gc-frac", "The fraction of //================================================================================================= // Constructor/Destructor: -SimpSolver::SimpSolver(cvc5::prop::TheoryProxy* proxy, +SimpSolver::SimpSolver(Env& env, + cvc5::prop::TheoryProxy* proxy, cvc5::context::Context* context, cvc5::context::UserContext* userContext, ProofNodeManager* pnm, bool enableIncremental) - : Solver(proxy, context, userContext, pnm, enableIncremental), + : Solver(env, proxy, context, userContext, pnm, enableIncremental), grow(opt_grow), clause_lim(opt_clause_lim), subsumption_lim(opt_subsumption_lim), simp_garbage_frac(opt_simp_garbage_frac), use_asymm(opt_use_asymm), // make sure this is not enabled if unsat cores or proofs are on - use_rcheck(opt_use_rcheck && !options::unsatCores() && !pnm), - use_elim(options::minisatUseElim() && !enableIncremental), + use_rcheck(opt_use_rcheck && !options().smt.unsatCores && !pnm), + use_elim(options().prop.minisatUseElim && !enableIncremental), merges(0), asymm_lits(0), eliminated_vars(0), elimorder(1), - use_simplification(!enableIncremental && !options::unsatCores() + use_simplification(!enableIncremental && !options().smt.unsatCores && !pnm) // TODO: turn off simplifications if // proofs are on initially , @@ -75,11 +76,12 @@ SimpSolver::SimpSolver(cvc5::prop::TheoryProxy* proxy, bwdsub_assigns(0), n_touched(0) { - if(options::minisatUseElim() && - Options::current().prop.minisatUseElimWasSetByUser && - enableIncremental) { - WarningOnce() << "Incremental mode incompatible with --minisat-elim" << std::endl; - } + if (options().prop.minisatUseElim && options().prop.minisatUseElimWasSetByUser + && enableIncremental) + { + WarningOnce() << "Incremental mode incompatible with --minisat-elim" + << std::endl; + } vec<Lit> dummy(1,lit_Undef); ca.extra_clause_field = true; // NOTE: must happen before allocating the dummy clause below. @@ -124,10 +126,11 @@ Var SimpSolver::newVar(bool sign, bool dvar, bool isTheoryAtom, bool preRegister lbool SimpSolver::solve_(bool do_simp, bool turn_off_simp) { - if (options::minisatDumpDimacs()) { - toDimacs(); - return l_Undef; - } + if (options().prop.minisatDumpDimacs) + { + toDimacs(); + return l_Undef; + } Assert(decisionLevel() == 0); vec<Var> extra_frozen; diff --git a/src/prop/minisat/simp/SimpSolver.h b/src/prop/minisat/simp/SimpSolver.h index 5e218419c..3d116d500 100644 --- a/src/prop/minisat/simp/SimpSolver.h +++ b/src/prop/minisat/simp/SimpSolver.h @@ -42,7 +42,8 @@ class SimpSolver : public Solver { public: // Constructor/Destructor: // - SimpSolver(cvc5::prop::TheoryProxy* proxy, + SimpSolver(Env& env, + cvc5::prop::TheoryProxy* proxy, cvc5::context::Context* context, cvc5::context::UserContext* userContext, ProofNodeManager* pnm, diff --git a/src/prop/proof_cnf_stream.cpp b/src/prop/proof_cnf_stream.cpp index 61a1a298c..b5542ab35 100644 --- a/src/prop/proof_cnf_stream.cpp +++ b/src/prop/proof_cnf_stream.cpp @@ -173,7 +173,7 @@ void ProofCnfStream::convertAndAssertAnd(TNode node, bool negated) for (unsigned i = 0, size = node.getNumChildren(); i < size; ++i) { // Create a proof step for each n_i - Node iNode = nm->mkConst<Rational>(CONST_RATIONAL, i); + Node iNode = nm->mkConstInt(i); d_proof.addStep(node[i], PfRule::AND_ELIM, {node}, {iNode}); Trace("cnf") << "ProofCnfStream::convertAndAssertAnd: AND_ELIM " << i << " added norm " << node[i] << "\n"; @@ -232,7 +232,7 @@ void ProofCnfStream::convertAndAssertOr(TNode node, bool negated) for (unsigned i = 0, size = node.getNumChildren(); i < size; ++i) { // Create a proof step for each (not n_i) - Node iNode = nm->mkConst<Rational>(CONST_RATIONAL, i); + Node iNode = nm->mkConstInt(i); d_proof.addStep( node[i].notNode(), PfRule::NOT_OR_ELIM, {node.notNode()}, {iNode}); Trace("cnf") << "ProofCnfStream::convertAndAssertOr: NOT_OR_ELIM " << i @@ -687,7 +687,7 @@ SatLiteral ProofCnfStream::handleAnd(TNode node) if (added) { Node clauseNode = nm->mkNode(kind::OR, node.notNode(), node[i]); - Node iNode = nm->mkConst<Rational>(CONST_RATIONAL, i); + Node iNode = nm->mkConstInt(i); d_proof.addStep(clauseNode, PfRule::CNF_AND_POS, {}, {node, iNode}); Trace("cnf") << "ProofCnfStream::handleAnd: CNF_AND_POS " << i << " added " << clauseNode << "\n"; @@ -747,7 +747,7 @@ SatLiteral ProofCnfStream::handleOr(TNode node) if (added) { Node clauseNode = nm->mkNode(kind::OR, node, node[i].notNode()); - Node iNode = nm->mkConst<Rational>(CONST_RATIONAL, i); + Node iNode = nm->mkConstInt(i); d_proof.addStep(clauseNode, PfRule::CNF_OR_NEG, {}, {node, iNode}); Trace("cnf") << "ProofCnfStream::handleOr: CNF_OR_NEG " << i << " added " << clauseNode << "\n"; diff --git a/src/prop/prop_engine.cpp b/src/prop/prop_engine.cpp index eeca414e2..df18f9a85 100644 --- a/src/prop/prop_engine.cpp +++ b/src/prop/prop_engine.cpp @@ -65,10 +65,10 @@ public: } }; -PropEngine::PropEngine(TheoryEngine* te, Env& env) - : d_inCheckSat(false), +PropEngine::PropEngine(Env& env, TheoryEngine* te) + : EnvObj(env), + d_inCheckSat(false), d_theoryEngine(te), - d_env(env), d_skdm(new SkolemDefManager(d_env.getContext(), d_env.getUserContext())), d_theoryProxy(nullptr), d_satSolver(nullptr), @@ -83,7 +83,7 @@ PropEngine::PropEngine(TheoryEngine* te, Env& env) ProofNodeManager* pnm = d_env.getProofNodeManager(); ResourceManager* rm = d_env.getResourceManager(); - options::DecisionMode dmode = options::decisionMode(); + options::DecisionMode dmode = options().decision.decisionMode; if (dmode == options::DecisionMode::JUSTIFICATION || dmode == options::DecisionMode::STOPONLY) { @@ -105,7 +105,7 @@ PropEngine::PropEngine(TheoryEngine* te, Env& env) // CNF stream and theory proxy required pointers to each other, make the // theory proxy first d_theoryProxy = new TheoryProxy( - this, d_theoryEngine, d_decisionEngine.get(), d_skdm.get(), d_env); + d_env, this, d_theoryEngine, d_decisionEngine.get(), d_skdm.get()); d_cnfStream = new CnfStream(d_satSolver, d_theoryProxy, userContext, @@ -214,7 +214,7 @@ void PropEngine::assertLemma(TrustNode tlemma, theory::LemmaProperty p) // do final checks on the lemmas we are about to send if (isProofEnabled() - && options::proofCheck() == options::ProofCheckMode::EAGER) + && options().proof.proofCheck == options::ProofCheckMode::EAGER) { Assert(tplemma.getGenerator() != nullptr); // ensure closed, make the proof node eagerly here to debug @@ -245,11 +245,8 @@ void PropEngine::assertTrustedLemmaInternal(TrustNode trn, bool removable) Node node = trn.getNode(); Debug("prop::lemmas") << "assertLemma(" << node << ")" << std::endl; bool negated = trn.getKind() == TrustNodeKind::CONFLICT; - Assert( - !isProofEnabled() || trn.getGenerator() != nullptr - || options::unsatCores() - || (options::unsatCores() - && options::unsatCoresMode() != options::UnsatCoresMode::FULL_PROOF)); + Assert(!isProofEnabled() || trn.getGenerator() != nullptr + || options().smt.unsatCores); assertInternal(trn.getNode(), negated, removable, false, trn.getGenerator()); } @@ -257,7 +254,7 @@ void PropEngine::assertInternal( TNode node, bool negated, bool removable, bool input, ProofGenerator* pg) { // Assert as (possibly) removable - if (options::unsatCoresMode() == options::UnsatCoresMode::ASSUMPTIONS) + if (options().smt.unsatCoresMode == options::UnsatCoresMode::ASSUMPTIONS) { if (input) { @@ -378,7 +375,8 @@ Result PropEngine::checkSat() { // Note this currently ignores conflicts (a dangerous practice). d_theoryProxy->presolve(); - if(options::preprocessOnly()) { + if (options().base.preprocessOnly) + { return Result(Result::SAT_UNKNOWN, Result::REQUIRES_FULL_CHECK); } @@ -673,7 +671,7 @@ bool PropEngine::isProofEnabled() const { return d_pfCnfStream != nullptr; } void PropEngine::getUnsatCore(std::vector<Node>& core) { - Assert(options::unsatCoresMode() == options::UnsatCoresMode::ASSUMPTIONS); + Assert(options().smt.unsatCoresMode == options::UnsatCoresMode::ASSUMPTIONS); std::vector<SatLiteral> unsat_assumptions; d_satSolver->getUnsatAssumptions(unsat_assumptions); for (const SatLiteral& lit : unsat_assumptions) @@ -684,7 +682,7 @@ void PropEngine::getUnsatCore(std::vector<Node>& core) std::shared_ptr<ProofNode> PropEngine::getRefutation() { - Assert(options::unsatCoresMode() == options::UnsatCoresMode::ASSUMPTIONS); + Assert(options().smt.unsatCoresMode == options::UnsatCoresMode::ASSUMPTIONS); std::vector<Node> core; getUnsatCore(core); CDProof cdp(d_env.getProofNodeManager()); diff --git a/src/prop/prop_engine.h b/src/prop/prop_engine.h index 2f569ba72..da6a50b9a 100644 --- a/src/prop/prop_engine.h +++ b/src/prop/prop_engine.h @@ -24,6 +24,7 @@ #include "expr/node.h" #include "proof/trust_node.h" #include "prop/skolem_def_manager.h" +#include "smt/env_obj.h" #include "theory/output_channel.h" #include "theory/skolem_lemma.h" #include "util/result.h" @@ -51,13 +52,13 @@ class TheoryProxy; * PropEngine is the abstraction of a Sat Solver, providing methods for * solving the SAT problem and conversion to CNF (via the CnfStream). */ -class PropEngine +class PropEngine : protected EnvObj { public: /** * Create a PropEngine with a particular decision and theory engine. */ - PropEngine(TheoryEngine* te, Env& env); + PropEngine(Env& env, TheoryEngine* te); /** * Destructor. @@ -348,9 +349,6 @@ class PropEngine /** The theory engine we will be using */ TheoryEngine* d_theoryEngine; - /** Reference to the environment */ - Env& d_env; - /** The decision engine we will be using */ std::unique_ptr<decision::DecisionEngine> d_decisionEngine; diff --git a/src/prop/theory_proxy.cpp b/src/prop/theory_proxy.cpp index ff00acc51..269921da2 100644 --- a/src/prop/theory_proxy.cpp +++ b/src/prop/theory_proxy.cpp @@ -33,20 +33,20 @@ namespace cvc5 { namespace prop { -TheoryProxy::TheoryProxy(PropEngine* propEngine, +TheoryProxy::TheoryProxy(Env& env, + PropEngine* propEngine, TheoryEngine* theoryEngine, decision::DecisionEngine* decisionEngine, - SkolemDefManager* skdm, - Env& env) - : d_propEngine(propEngine), + SkolemDefManager* skdm) + : EnvObj(env), + d_propEngine(propEngine), d_cnfStream(nullptr), d_decisionEngine(decisionEngine), d_dmNeedsActiveDefs(d_decisionEngine->needsActiveSkolemDefs()), d_theoryEngine(theoryEngine), d_queue(env.getContext()), d_tpp(env, *theoryEngine), - d_skdm(skdm), - d_env(env) + d_skdm(skdm) { } @@ -120,7 +120,7 @@ void TheoryProxy::explainPropagation(SatLiteral l, SatClause& explanation) { Node theoryExplanation = tte.getNode(); if (d_env.isSatProofProducing()) { - Assert(options::unsatCoresMode() != options::UnsatCoresMode::FULL_PROOF + Assert(options().smt.unsatCoresMode != options::UnsatCoresMode::FULL_PROOF || tte.getGenerator()); d_propEngine->getProofCnfStream()->convertPropagation(tte); } diff --git a/src/prop/theory_proxy.h b/src/prop/theory_proxy.h index d4f8fb3a2..8e998583d 100644 --- a/src/prop/theory_proxy.h +++ b/src/prop/theory_proxy.h @@ -25,6 +25,7 @@ #include "proof/trust_node.h" #include "prop/registrar.h" #include "prop/sat_solver_types.h" +#include "smt/env_obj.h" #include "theory/theory.h" #include "theory/theory_preprocessor.h" #include "util/resource_manager.h" @@ -47,14 +48,14 @@ class SkolemDefManager; /** * The proxy class that allows the SatSolver to communicate with the theories */ -class TheoryProxy : public Registrar +class TheoryProxy : protected EnvObj, public Registrar { public: - TheoryProxy(PropEngine* propEngine, + TheoryProxy(Env& env, + PropEngine* propEngine, TheoryEngine* theoryEngine, decision::DecisionEngine* decisionEngine, - SkolemDefManager* skdm, - Env& env); + SkolemDefManager* skdm); ~TheoryProxy(); @@ -167,9 +168,6 @@ class TheoryProxy : public Registrar /** The skolem definition manager */ SkolemDefManager* d_skdm; - - /** Reference to the environment */ - Env& d_env; }; /* class TheoryProxy */ } // namespace prop diff --git a/src/smt/abduction_solver.cpp b/src/smt/abduction_solver.cpp index ce11c5718..f17e768c9 100644 --- a/src/smt/abduction_solver.cpp +++ b/src/smt/abduction_solver.cpp @@ -50,6 +50,7 @@ bool AbductionSolver::getAbduct(const std::vector<Node>& axioms, std::vector<Node> asserts(axioms.begin(), axioms.end()); // must expand definitions Node conjn = d_env.getTopLevelSubstitutions().apply(goal); + conjn = rewrite(conjn); // now negate conjn = conjn.negate(); d_abdConj = conjn; @@ -93,11 +94,12 @@ bool AbductionSolver::getAbductInternal(const std::vector<Node>& axioms, Result r = d_subsolver->checkSat(); Trace("sygus-abduct") << " SolverEngine::getAbduct result: " << r << std::endl; - if (r.asSatisfiabilityResult().isSat() == Result::UNSAT) + // get the synthesis solution + std::map<Node, Node> sols; + // use the "getSubsolverSynthSolutions" interface, since we asserted the + // internal form of the SyGuS conjecture and used check-sat. + if (d_subsolver->getSubsolverSynthSolutions(sols)) { - // get the synthesis solution - std::map<Node, Node> sols; - d_subsolver->getSynthSolutions(sols); Assert(sols.size() == 1); std::map<Node, Node>::iterator its = sols.find(d_sssf); if (its != sols.end()) diff --git a/src/smt/abstract_values.h b/src/smt/abstract_values.h index 32cff9378..354b8691f 100644 --- a/src/smt/abstract_values.h +++ b/src/smt/abstract_values.h @@ -48,7 +48,7 @@ class AbstractValues /** * Make a new (or return an existing) abstract value for a node. - * Can only use this if options::abstractValues() is on. + * Can only use this if abstractValues option is on. */ Node mkAbstractValue(TNode n); @@ -63,7 +63,7 @@ class AbstractValues /** * A map of AbsractValues to their actual constants. Only used if - * options::abstractValues() is on. + * abstractValues option is on. */ theory::SubstitutionMap d_abstractValueMap; @@ -71,7 +71,7 @@ class AbstractValues * A mapping of all abstract values (actual value |-> abstract) that * we've handed out. This is necessary to ensure that we give the * same AbstractValues for the same real constants. Only used if - * options::abstractValues() is on. + * abstractValues option is on. */ NodeToNodeHashMap d_abstractValues; }; diff --git a/src/smt/check_models.cpp b/src/smt/check_models.cpp index 7d546eae7..f3393caae 100644 --- a/src/smt/check_models.cpp +++ b/src/smt/check_models.cpp @@ -71,7 +71,7 @@ void CheckModels::checkModel(TheoryModel* m, // evaluate e.g. divide-by-zero. This is intentional since the evaluation // is not trustworthy, since the UF introduced by expanding definitions may // not be properly constrained. - Node n = sm.apply(assertion, false); + Node n = sm.apply(assertion); verbose(1) << "SolverEngine::checkModel(): -- substitutes to " << n << std::endl; diff --git a/src/smt/difficulty_post_processor.cpp b/src/smt/difficulty_post_processor.cpp index 31797ba5e..6d1882a4e 100644 --- a/src/smt/difficulty_post_processor.cpp +++ b/src/smt/difficulty_post_processor.cpp @@ -69,7 +69,7 @@ void DifficultyPostprocessCallback::getDifficultyMap( NodeManager* nm = NodeManager::currentNM(); for (const std::pair<const Node, uint64_t>& d : d_accMap) { - dmap[d.first] = nm->mkConst(CONST_RATIONAL, Rational(d.second)); + dmap[d.first] = nm->mkConstInt(Rational(d.second)); } } diff --git a/src/smt/interpolation_solver.cpp b/src/smt/interpolation_solver.cpp index 36f8e2a8d..20be53e85 100644 --- a/src/smt/interpolation_solver.cpp +++ b/src/smt/interpolation_solver.cpp @@ -51,6 +51,7 @@ bool InterpolationSolver::getInterpol(const std::vector<Node>& axioms, << std::endl; // must expand definitions Node conjn = d_env.getTopLevelSubstitutions().apply(conj); + conjn = rewrite(conjn); std::string name("__internal_interpol"); quantifiers::SygusInterpol interpolSolver(d_env); diff --git a/src/smt/model.cpp b/src/smt/model.cpp index 5c427fa46..69dddded8 100644 --- a/src/smt/model.cpp +++ b/src/smt/model.cpp @@ -30,7 +30,8 @@ Model::Model(bool isKnownSat, const std::string& inputName) std::ostream& operator<<(std::ostream& out, const Model& m) { options::ioutils::Scope scope(out); options::ioutils::applyDagThresh(out, 0); - Printer::getPrinter(options::outputLanguage())->toStream(out, m); + auto language = options::ioutils::getOutputLang(out); + Printer::getPrinter(language)->toStream(out, m); return out; } diff --git a/src/smt/preprocessor.cpp b/src/smt/preprocessor.cpp index 41653b6ee..0fdb569c8 100644 --- a/src/smt/preprocessor.cpp +++ b/src/smt/preprocessor.cpp @@ -125,8 +125,8 @@ Node Preprocessor::expandDefinitions(const Node& node, // Ensure node is type-checked at this point. n.getType(true); } - // we apply substitutions here, before expanding definitions - n = d_env.getTopLevelSubstitutions().apply(n, false); + // apply substitutions here (without rewriting), before expanding definitions + n = d_env.getTopLevelSubstitutions().apply(n); // now call expand definitions n = d_exDefs.expandDefinitions(n, cache); return n; diff --git a/src/smt/proof_final_callback.cpp b/src/smt/proof_final_callback.cpp index 93b4cae19..484f0dd73 100644 --- a/src/smt/proof_final_callback.cpp +++ b/src/smt/proof_final_callback.cpp @@ -34,6 +34,9 @@ ProofFinalCallback::ProofFinalCallback(ProofNodeManager* pnm) d_instRuleIds( smtStatisticsRegistry().registerHistogram<theory::InferenceId>( "finalProof::instRuleId")), + d_annotationRuleIds( + smtStatisticsRegistry().registerHistogram<theory::InferenceId>( + "finalProof::annotationRuleId")), d_totalRuleCount( smtStatisticsRegistry().registerInt("finalProof::totalRuleCount")), d_minPedanticLevel( @@ -96,6 +99,33 @@ bool ProofFinalCallback::shouldUpdate(std::shared_ptr<ProofNode> pn, } } } + else if (r == PfRule::ANNOTATION) + { + // we currently assume the annotation is a single inference id + const std::vector<Node>& args = pn->getArguments(); + if (args.size() > 0) + { + InferenceId id; + if (getInferenceId(args[0], id)) + { + d_annotationRuleIds << id; + } + } + } + // print for debugging + if (Trace.isOn("final-pf-hole")) + { + // currently only track theory rewrites + if (r == PfRule::THEORY_REWRITE) + { + const std::vector<Node>& args = pn->getArguments(); + Node eq = args[0]; + TheoryId tid = THEORY_BUILTIN; + builtin::BuiltinProofRuleChecker::getTheoryId(args[1], tid); + Trace("final-pf-hole") << "hole " << r << " " << tid << " : " << eq[0] + << " ---> " << eq[1] << std::endl; + } + } return false; } diff --git a/src/smt/proof_final_callback.h b/src/smt/proof_final_callback.h index 88b8e20ef..a1e6b1f69 100644 --- a/src/smt/proof_final_callback.h +++ b/src/smt/proof_final_callback.h @@ -54,6 +54,11 @@ class ProofFinalCallback : public ProofNodeUpdaterCallback * marked with the given inference id. */ HistogramStat<theory::InferenceId> d_instRuleIds; + /** + * Counts number of postprocessed proof nodes of rule ANNOTATION that were + * marked with the given inference id. + */ + HistogramStat<theory::InferenceId> d_annotationRuleIds; /** Total number of postprocessed rule applications */ IntStat d_totalRuleCount; /** The minimum pedantic level of any rule encountered */ diff --git a/src/smt/proof_manager.cpp b/src/smt/proof_manager.cpp index 4cb9d5bf9..04f601680 100644 --- a/src/smt/proof_manager.cpp +++ b/src/smt/proof_manager.cpp @@ -41,7 +41,8 @@ PfManager::PfManager(Env& env) d_pchecker(new ProofChecker( options().proof.proofCheck == options::ProofCheckMode::EAGER, options().proof.proofPedantic)), - d_pnm(new ProofNodeManager(env.getRewriter(), d_pchecker.get())), + d_pnm(new ProofNodeManager( + env.getOptions(), env.getRewriter(), d_pchecker.get())), d_pppg(new PreprocessProofGenerator( d_pnm.get(), env.getUserContext(), "smt::PreprocessProofGenerator")), d_pfpp(nullptr), @@ -150,8 +151,10 @@ void PfManager::setFinalProof(std::shared_ptr<ProofNode> pfn, Assertions& as) Trace("smt-proof") << "SolverEngine::setFinalProof(): make scope...\n"; // Now make the final scope, which ensures that the only open leaves of the - // proof are the assertions. - d_finalProof = d_pnm->mkScope(pfn, assertions); + // proof are the assertions. If we are pruning the input, we will try to + // minimize the used assertions. + d_finalProof = + d_pnm->mkScope(pfn, assertions, true, options().proof.proofPruneInput); Trace("smt-proof") << "SolverEngine::setFinalProof(): finished.\n"; } @@ -227,20 +230,14 @@ void PfManager::translateDifficultyMap(std::map<Node, Node>& dmap, std::map<Node, Node> dmapp = dmap; dmap.clear(); std::vector<Node> ppAsserts; - std::vector<Node> asserts; - getAssertions(as, asserts); for (const std::pair<const Node, Node>& ppa : dmapp) { Trace("difficulty") << " preprocess difficulty: " << ppa.second << " for " << ppa.first << std::endl; - // Ensure that only input assertions are marked as having a difficulty. - // In some cases, a lemma may be marked as having a difficulty - // internally, e.g. for lemmas that require justification, which we should - // skip or otherwise we end up with an open proof below. - if (std::find(asserts.begin(), asserts.end(), ppa.first) != asserts.end()) - { - ppAsserts.push_back(ppa.first); - } + // The difficulty manager should only report difficulty for preprocessed + // assertions, or we will get an open proof below. This is ensured + // internally by the difficuly manager. + ppAsserts.push_back(ppa.first); } // assume a SAT refutation from all input assertions that were marked // as having a difficulty diff --git a/src/smt/proof_post_processor.cpp b/src/smt/proof_post_processor.cpp index a292fec8f..167a82e26 100644 --- a/src/smt/proof_post_processor.cpp +++ b/src/smt/proof_post_processor.cpp @@ -422,6 +422,7 @@ Node ProofPostprocessCallback::expandMacros(PfRule id, // not eliminated return Node::null(); } + Trace("smt-proof-pp-debug") << "Expand macro " << id << std::endl; // macro elimination if (id == PfRule::MACRO_SR_EQ_INTRO) { @@ -855,7 +856,7 @@ Node ProofPostprocessCallback::expandMacros(PfRule id, for (size_t j = 0, nchildi = children[i].getNumChildren(); j < nchildi; j++) { - Node nodej = nm->mkConst(CONST_RATIONAL, Rational(j)); + Node nodej = nm->mkConstInt(Rational(j)); cdp->addStep( children[i][j], PfRule::AND_ELIM, {children[i]}, {nodej}); } @@ -1086,8 +1087,10 @@ Node ProofPostprocessCallback::expandMacros(PfRule id, TNode child = children[i]; TNode scalar = args[i]; bool isPos = scalar.getConst<Rational>() > 0; - Node scalarCmp = nm->mkNode( - isPos ? GT : LT, scalar, nm->mkConst(CONST_RATIONAL, Rational(0))); + Node scalarCmp = + nm->mkNode(isPos ? GT : LT, + scalar, + nm->mkConstRealOrInt(scalar.getType(), Rational(0))); // (= scalarCmp true) Node scalarCmpOrTrue = steps.tryStep(PfRule::EVALUATE, {}, {scalarCmp}); Assert(!scalarCmpOrTrue.isNull()); diff --git a/src/smt/set_defaults.cpp b/src/smt/set_defaults.cpp index b2fe2b5d6..194290399 100644 --- a/src/smt/set_defaults.cpp +++ b/src/smt/set_defaults.cpp @@ -373,7 +373,7 @@ void SetDefaults::setDefaultsPost(const LogicInfo& logic, Options& opts) const || opts.smt.produceInterpols != options::ProduceInterpols::NONE || opts.smt.modelCoresMode != options::ModelCoresMode::NONE || opts.smt.blockModelsMode != options::BlockModelsMode::NONE - || opts.smt.produceProofs) + || opts.smt.produceProofs || isSygus(opts)) && !opts.smt.produceAssertions) { verbose(1) << "SolverEngine: turning on produce-assertions to support " @@ -807,6 +807,7 @@ void SetDefaults::setDefaultsPost(const LogicInfo& logic, Options& opts) const if (!opts.arith.nlCad && !opts.arith.nlCadWasSetByUser) { opts.arith.nlCad = true; + opts.arith.nlCadVarElim = true; if (!opts.arith.nlExtWasSetByUser) { opts.arith.nlExt = options::NlExtMode::LIGHT; @@ -823,6 +824,7 @@ void SetDefaults::setDefaultsPost(const LogicInfo& logic, Options& opts) const if (!opts.arith.nlCad && !opts.arith.nlCadWasSetByUser) { opts.arith.nlCad = true; + opts.arith.nlCadVarElim = true; if (!opts.arith.nlExtWasSetByUser) { opts.arith.nlExt = options::NlExtMode::LIGHT; @@ -1161,9 +1163,8 @@ bool SetDefaults::incompatibleWithUnsatCores(Options& opts, bool SetDefaults::safeUnsatCores(const Options& opts) const { // whether we want to force safe unsat cores, i.e., if we are in the default - // ASSUMPTIONS mode or PP_ONLY, since other ones are experimental - return opts.smt.unsatCoresMode == options::UnsatCoresMode::ASSUMPTIONS - || opts.smt.unsatCoresMode == options::UnsatCoresMode::PP_ONLY; + // ASSUMPTIONS mode, since other ones are experimental + return opts.smt.unsatCoresMode == options::UnsatCoresMode::ASSUMPTIONS; } bool SetDefaults::incompatibleWithQuantifiers(Options& opts, diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 4530df774..25c6f5f9f 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -71,7 +71,7 @@ void SmtSolver::finishInit() * are unregistered by the obsolete PropEngine object before registered * again by the new PropEngine object */ d_propEngine.reset(nullptr); - d_propEngine.reset(new prop::PropEngine(d_theoryEngine.get(), d_env)); + d_propEngine.reset(new prop::PropEngine(d_env, d_theoryEngine.get())); Trace("smt-debug") << "Setting up theory engine..." << std::endl; d_theoryEngine->setPropEngine(getPropEngine()); @@ -89,7 +89,7 @@ void SmtSolver::resetAssertions() * statistics are unregistered by the obsolete PropEngine object before * registered again by the new PropEngine object */ d_propEngine.reset(nullptr); - d_propEngine.reset(new prop::PropEngine(d_theoryEngine.get(), d_env)); + d_propEngine.reset(new prop::PropEngine(d_env, d_theoryEngine.get())); d_theoryEngine->setPropEngine(getPropEngine()); // Notice that we do not reset TheoryEngine, nor does it require calling // finishInit again. In particular, TheoryEngine::finishInit does not @@ -158,13 +158,15 @@ Result SmtSolver::checkSatisfiability(Assertions& as, d_env.verbose(2) << "solving..." << std::endl; Trace("smt") << "SmtSolver::check(): running check" << endl; Result result = d_propEngine->checkSat(); + Trace("smt") << "SmtSolver::check(): result " << result << std::endl; rm->endCall(); Trace("limit") << "SmtSolver::check(): cumulative millis " << rm->getTimeUsage() << ", resources " << rm->getResourceUsage() << endl; - if ((options::solveRealAsInt() || options::solveIntAsBV() > 0) + if ((d_env.getOptions().smt.solveRealAsInt + || d_env.getOptions().smt.solveIntAsBV > 0) && result.asSatisfiabilityResult().isSat() == Result::UNSAT) { result = Result(Result::SAT_UNKNOWN, Result::UNKNOWN_REASON); diff --git a/src/smt/solver_engine.cpp b/src/smt/solver_engine.cpp index 2cf4862a9..32838eccf 100644 --- a/src/smt/solver_engine.cpp +++ b/src/smt/solver_engine.cpp @@ -1193,6 +1193,8 @@ std::vector<Node> SolverEngine::getAssertionsInternal() return res; } +const Options& SolverEngine::options() const { return d_env->getOptions(); } + std::vector<Node> SolverEngine::getExpandedAssertions() { std::vector<Node> easserts = getAssertions(); @@ -1270,7 +1272,7 @@ UnsatCore SolverEngine::getUnsatCoreInternal() Assert(pe != nullptr); std::shared_ptr<ProofNode> pepf; - if (options::unsatCoresMode() == options::UnsatCoresMode::ASSUMPTIONS) + if (options().smt.unsatCoresMode == options::UnsatCoresMode::ASSUMPTIONS) { pepf = pe->getRefutation(); } @@ -1282,7 +1284,7 @@ UnsatCore SolverEngine::getUnsatCoreInternal() std::shared_ptr<ProofNode> pfn = d_pfManager->getFinalProof(pepf, *d_asserts); std::vector<Node> core; d_ucManager->getUnsatCore(pfn, *d_asserts, core); - if (options::minimalUnsatCores()) + if (options().smt.minimalUnsatCores) { core = reduceUnsatCore(core); } @@ -1291,7 +1293,7 @@ UnsatCore SolverEngine::getUnsatCoreInternal() std::vector<Node> SolverEngine::reduceUnsatCore(const std::vector<Node>& core) { - Assert(options::unsatCores()) + Assert(options().smt.unsatCores) << "cannot reduce unsat core if unsat cores are turned off"; d_env->verbose(1) << "SolverEngine::reduceUnsatCore(): reducing unsat core" @@ -1386,7 +1388,7 @@ void SolverEngine::checkUnsatCore() theory::TrustSubstitutionMap& tls = d_env->getTopLevelSubstitutions(); for (UnsatCore::iterator i = core.begin(); i != core.end(); ++i) { - Node assertionAfterExpansion = tls.apply(*i, false); + Node assertionAfterExpansion = tls.apply(*i); d_env->verbose(1) << "SolverEngine::checkUnsatCore(): pushing core member " << *i << ", expanded to " << assertionAfterExpansion << std::endl; @@ -1432,7 +1434,7 @@ void SolverEngine::checkModel(bool hardFailure) Assert(m != nullptr); // check the model with the theory engine for debugging - if (options::debugCheckModels()) + if (options().smt.debugCheckModels) { TheoryEngine* te = getTheoryEngine(); Assert(te != nullptr); @@ -1527,8 +1529,8 @@ void SolverEngine::printInstantiations(std::ostream& out) && getSmtMode() == SmtMode::UNSAT) { // minimize instantiations based on proof manager - getRelevantInstantiationTermVectors(rinsts, - options::dumpInstantiationsDebug()); + getRelevantInstantiationTermVectors( + rinsts, options().driver.dumpInstantiationsDebug); } else { @@ -1601,6 +1603,13 @@ bool SolverEngine::getSynthSolutions(std::map<Node, Node>& solMap) return d_sygusSolver->getSynthSolutions(solMap); } +bool SolverEngine::getSubsolverSynthSolutions(std::map<Node, Node>& solMap) +{ + SolverEngineScope smts(this); + finishInit(); + return d_sygusSolver->getSubsolverSynthSolutions(solMap); +} + Node SolverEngine::getQuantifierElimination(Node q, bool doFull, bool strict) { SolverEngineScope smts(this); diff --git a/src/smt/solver_engine.h b/src/smt/solver_engine.h index d7df78f08..95b31eab2 100644 --- a/src/smt/solver_engine.h +++ b/src/smt/solver_engine.h @@ -563,6 +563,16 @@ class CVC5_EXPORT SolverEngine * is a valid formula. */ bool getSynthSolutions(std::map<Node, Node>& solMap); + /** + * Same as above, but used for getting synthesis solutions from a "subsolver" + * that has been initialized to assert the synthesis conjecture as a + * normal assertion. + * + * This method returns true if we are in a state immediately preceded by + * a successful call to checkSat, where this SolverEngine has an asserted + * synthesis conjecture. + */ + bool getSubsolverSynthSolutions(std::map<Node, Node>& solMap); /** * Do quantifier elimination. @@ -1025,6 +1035,12 @@ class CVC5_EXPORT SolverEngine * changes. */ std::vector<Node> getAssertionsInternal(); + + /** + * Return a reference to options like for `EnvObj`. + */ + const Options& options() const; + /* Members -------------------------------------------------------------- */ /** Solver instance that owns this SolverEngine instance. */ diff --git a/src/smt/sygus_solver.cpp b/src/smt/sygus_solver.cpp index 4c8d3e5bd..70ad65644 100644 --- a/src/smt/sygus_solver.cpp +++ b/src/smt/sygus_solver.cpp @@ -42,7 +42,14 @@ namespace cvc5 { namespace smt { SygusSolver::SygusSolver(Env& env, SmtSolver& sms) - : EnvObj(env), d_smtSolver(sms), d_sygusConjectureStale(userContext(), true) + : EnvObj(env), + d_smtSolver(sms), + d_sygusVars(userContext()), + d_sygusConstraints(userContext()), + d_sygusAssumps(userContext()), + d_sygusFunSymbols(userContext()), + d_sygusConjectureStale(userContext(), true), + d_subsolverCd(userContext(), nullptr) { } @@ -84,7 +91,7 @@ void SygusSolver::declareSynthFun(Node fn, } // sygus conjecture is now stale - setSygusConjectureStale(); + d_sygusConjectureStale = true; } void SygusSolver::assertSygusConstraint(Node n, bool isAssume) @@ -101,7 +108,7 @@ void SygusSolver::assertSygusConstraint(Node n, bool isAssume) } // sygus conjecture is now stale - setSygusConjectureStale(); + d_sygusConjectureStale = true; } void SygusSolver::assertSygusInvConstraint(Node inv, @@ -173,44 +180,50 @@ void SygusSolver::assertSygusInvConstraint(Node inv, d_sygusConstraints.push_back(constraint); // sygus conjecture is now stale - setSygusConjectureStale(); + d_sygusConjectureStale = true; } Result SygusSolver::checkSynth(Assertions& as) { - if (options().base.incrementalSolving) + Trace("smt") << "SygusSolver::checkSynth" << std::endl; + // if applicable, check if the subsolver is the correct one + if (usingSygusSubsolver() && d_subsolverCd.get() != d_subsolver.get()) { - // TODO (project #7) - throw ModalException( - "Cannot make check-synth commands when incremental solving is enabled"); + // this can occur if we backtrack to a place where we were using a different + // subsolver than the current one. In this case, we should reconstruct + // the subsolver. + d_sygusConjectureStale = true; } - Trace("smt") << "SygusSolver::checkSynth" << std::endl; - std::vector<Node> query; + // TODO (project #7): we currently must always rebuild the synthesis + // conjecture + subsolver, since it answers unsat. When the subsolver is + // updated to treat "sat" as solution for synthesis conjecture, this line + // will be deleted. + d_sygusConjectureStale = true; if (d_sygusConjectureStale) { NodeManager* nm = NodeManager::currentNM(); // build synthesis conjecture from asserted constraints and declared // variables/functions Trace("smt") << "Sygus : Constructing sygus constraint...\n"; - Node body = nm->mkAnd(d_sygusConstraints); + Node body = nm->mkAnd(listToVector(d_sygusConstraints)); // note that if there are no constraints, then assumptions are irrelevant if (!d_sygusConstraints.empty() && !d_sygusAssumps.empty()) { - Node bodyAssump = nm->mkAnd(d_sygusAssumps); + Node bodyAssump = nm->mkAnd(listToVector(d_sygusAssumps)); body = nm->mkNode(IMPLIES, bodyAssump, body); } body = body.notNode(); Trace("smt") << "...constructed sygus constraint " << body << std::endl; if (!d_sygusVars.empty()) { - Node boundVars = nm->mkNode(BOUND_VAR_LIST, d_sygusVars); + Node boundVars = nm->mkNode(BOUND_VAR_LIST, listToVector(d_sygusVars)); body = nm->mkNode(EXISTS, boundVars, body); Trace("smt") << "...constructed exists " << body << std::endl; } if (!d_sygusFunSymbols.empty()) { - body = - quantifiers::SygusUtils::mkSygusConjecture(d_sygusFunSymbols, body); + body = quantifiers::SygusUtils::mkSygusConjecture( + listToVector(d_sygusFunSymbols), body); } Trace("smt") << "...constructed forall " << body << std::endl; @@ -218,59 +231,119 @@ Result SygusSolver::checkSynth(Assertions& as) d_sygusConjectureStale = false; - // TODO (project #7): if incremental, we should push a context and assert - query.push_back(body); - } + d_conj = body; + + // if we are using a subsolver, initialize it now + if (usingSygusSubsolver()) + { + // we generate a new solver engine to do the SyGuS query + initializeSygusSubsolver(d_subsolver, as); - Result r = d_smtSolver.checkSatisfiability(as, query, false); + // store the pointer (context-dependent) + d_subsolverCd = d_subsolver.get(); - // Check that synthesis solutions satisfy the conjecture - if (options().smt.checkSynthSol - && r.asSatisfiabilityResult().isSat() == Result::UNSAT) + // also assert the internal SyGuS conjecture + d_subsolver->assertFormula(d_conj); + } + } + else + { + Assert(d_subsolver != nullptr); + } + Result r; + if (usingSygusSubsolver()) + { + r = d_subsolver->checkSat(); + } + else + { + std::vector<Node> query; + query.push_back(d_conj); + r = d_smtSolver.checkSatisfiability(as, query, false); + } + // The result returned by the above call is typically "unknown", which may + // or may not correspond to a state in which we solved the conjecture + // successfully. Instead we call getSynthSolutions below. If this returns + // true, then we were successful. In this case, we set the result to "unsat", + // since the synthesis conjecture was negated when asserted to the subsolver. + // + // This behavior is done for 2 reasons: + // (1) if we do not negate the synthesis conjecture, the subsolver in some + // cases cannot answer "sat", e.g. in the presence of recursive function + // definitions. Instead the SyGuS language standard itself indicates that + // a correct solution for a conjecture is one where the synthesis conjecture + // is *T-valid* (in the presence of defined recursive functions). In other + // words, a SyGuS query asks to prove that the conjecture is valid when + // witnessed by the given solution. + // (2) we do not want the solver to explicitly answer "unsat" by giving an + // unsatisfiable set of formulas to the underlying PropEngine, or otherwise + // we will not be able to ask for further solutions. This is critical for + // incremental solving where multiple solutions are returned for the same + // set of constraints. Thus, the internal SyGuS solver will mark unknown + // with IncompleteId::QUANTIFIERS_SYGUS_SOLVED. Furthermore, this id may be + // overwritten by other means of incompleteness, so we cannot rely on this + // identifier being the final reason for unknown. + // + // Thus, we use getSynthSolutions as means of knowing the conjecture was + // solved. + std::map<Node, Node> sol_map; + if (getSynthSolutions(sol_map)) { - checkSynthSolution(as); + // if we have solutions, we return "unsat" by convention + r = Result(Result::UNSAT); + // Check that synthesis solutions satisfy the conjecture + if (options().smt.checkSynthSol) + { + checkSynthSolution(as, sol_map); + } + } + else + { + // otherwise, we return "unknown" + r = Result(Result::SAT_UNKNOWN, Result::UNKNOWN_REASON); } return r; } -bool SygusSolver::getSynthSolutions(std::map<Node, Node>& sol_map) +bool SygusSolver::getSynthSolutions(std::map<Node, Node>& solMap) { Trace("smt") << "SygusSolver::getSynthSolutions" << std::endl; - std::map<Node, std::map<Node, Node>> sol_mapn; + if (usingSygusSubsolver()) + { + // use the call to get the synth solutions from the subsolver + return d_subsolver->getSubsolverSynthSolutions(solMap); + } + return getSubsolverSynthSolutions(solMap); +} + +bool SygusSolver::getSubsolverSynthSolutions(std::map<Node, Node>& solMap) +{ + Trace("smt") << "SygusSolver::getSubsolverSynthSolutions" << std::endl; + std::map<Node, std::map<Node, Node>> solMapn; // fail if the theory engine does not have synthesis solutions QuantifiersEngine* qe = d_smtSolver.getQuantifiersEngine(); - if (qe == nullptr || !qe->getSynthSolutions(sol_mapn)) + if (qe == nullptr || !qe->getSynthSolutions(solMapn)) { return false; } - for (std::pair<const Node, std::map<Node, Node>>& cs : sol_mapn) + for (std::pair<const Node, std::map<Node, Node>>& cs : solMapn) { for (std::pair<const Node, Node>& s : cs.second) { - sol_map[s.first] = s.second; + solMap[s.first] = s.second; } } return true; } -void SygusSolver::checkSynthSolution(Assertions& as) +void SygusSolver::checkSynthSolution(Assertions& as, + const std::map<Node, Node>& sol_map) { - NodeManager* nm = NodeManager::currentNM(); - SkolemManager* sm = nm->getSkolemManager(); if (isVerboseOn(1)) { verbose(1) << "SyGuS::checkSynthSolution: checking synthesis solution" << std::endl; } - std::map<Node, std::map<Node, Node>> sol_map; - // Get solutions and build auxiliary vectors for substituting - QuantifiersEngine* qe = d_smtSolver.getQuantifiersEngine(); - if (qe == nullptr || !qe->getSynthSolutions(sol_map)) - { - InternalError() - << "SygusSolver::checkSynthSolution(): No solution to check!"; - return; - } if (sol_map.empty()) { InternalError() << "SygusSolver::checkSynthSolution(): Got empty solution!"; @@ -279,100 +352,39 @@ void SygusSolver::checkSynthSolution(Assertions& as) Trace("check-synth-sol") << "Got solution map:\n"; // the set of synthesis conjectures in our assertions std::unordered_set<Node> conjs; + conjs.insert(d_conj); // For each of the above conjectures, the functions-to-synthesis and their // solutions. This is used as a substitution below. - std::map<Node, std::vector<Node>> fvarMap; - std::map<Node, std::vector<Node>> fsolMap; - for (const std::pair<const Node, std::map<Node, Node>>& cmap : sol_map) + std::vector<Node> fvars; + std::vector<Node> fsols; + for (const std::pair<const Node, Node>& pair : sol_map) { - Trace("check-synth-sol") << "For conjecture " << cmap.first << ":\n"; - conjs.insert(cmap.first); - std::vector<Node>& fvars = fvarMap[cmap.first]; - std::vector<Node>& fsols = fsolMap[cmap.first]; - for (const std::pair<const Node, Node>& pair : cmap.second) - { - Trace("check-synth-sol") - << " " << pair.first << " --> " << pair.second << "\n"; - fvars.push_back(pair.first); - fsols.push_back(pair.second); - } + Trace("check-synth-sol") + << " " << pair.first << " --> " << pair.second << "\n"; + fvars.push_back(pair.first); + fsols.push_back(pair.second); } + Trace("check-synth-sol") << "Starting new SMT Engine\n"; Trace("check-synth-sol") << "Retrieving assertions\n"; // Build conjecture from original assertions - const context::CDList<Node>& alist = as.getAssertionList(); - Assert(options().smt.produceAssertions) - << "Expected produce assertions to be true when checking synthesis " - "solution"; - // auxiliary assertions - std::vector<Node> auxAssertions; - // expand definitions cache - std::unordered_map<Node, Node> cache; - for (const Node& assertion : alist) - { - if (isVerboseOn(1)) - { - verbose(1) << "SyGuS::checkSynthSolution: checking assertion " - << assertion << std::endl; - } - Trace("check-synth-sol") << "Retrieving assertion " << assertion << "\n"; - // Apply any define-funs from the problem. - Node n = d_smtSolver.getPreprocessor()->expandDefinitions(assertion, cache); - if (isVerboseOn(1)) - { - verbose(1) << "SyGuS::checkSynthSolution: -- expands to " << n - << std::endl; - } - Trace("check-synth-sol") << "Expanded assertion " << n << "\n"; - if (conjs.find(n) == conjs.end()) - { - Trace("check-synth-sol") << "It is an auxiliary assertion\n"; - auxAssertions.push_back(n); - } - else - { - Trace("check-synth-sol") << "It is a synthesis conjecture\n"; - } - } // check all conjectures - for (Node conj : conjs) + for (const Node& conj : conjs) { // Start new SMT engine to check solutions std::unique_ptr<SolverEngine> solChecker; - initializeSubsolver(solChecker, d_env); + initializeSygusSubsolver(solChecker, as); solChecker->getOptions().smt.checkSynthSol = false; solChecker->getOptions().quantifiers.sygusRecFun = false; - // get the solution for this conjecture - std::vector<Node>& fvars = fvarMap[conj]; - std::vector<Node>& fsols = fsolMap[conj]; + Assert(conj.getKind() == FORALL); + Node conjBody = conj[1]; + // we must expand definitions here, since define-fun may contain the + // function-to-synthesize, which needs to be substituted. + conjBody = d_smtSolver.getPreprocessor()->expandDefinitions(conjBody); // Apply solution map to conjecture body - Node conjBody; - /* Whether property is quantifier free */ - if (conj[1].getKind() != EXISTS) - { - conjBody = conj[1].substitute( - fvars.begin(), fvars.end(), fsols.begin(), fsols.end()); - } - else - { - conjBody = conj[1][1].substitute( - fvars.begin(), fvars.end(), fsols.begin(), fsols.end()); - - /* Skolemize property */ - std::vector<Node> vars, skos; - for (unsigned j = 0, size = conj[1][0].getNumChildren(); j < size; ++j) - { - vars.push_back(conj[1][0][j]); - std::stringstream ss; - ss << "sk_" << j; - skos.push_back(sm->mkDummySkolem(ss.str(), conj[1][0][j].getType())); - Trace("check-synth-sol") << "\tSkolemizing " << conj[1][0][j] << " to " - << skos.back() << "\n"; - } - conjBody = conjBody.substitute( - vars.begin(), vars.end(), skos.begin(), skos.end()); - } + conjBody = conjBody.substitute( + fvars.begin(), fvars.end(), fsols.begin(), fsols.end()); if (isVerboseOn(1)) { @@ -382,17 +394,6 @@ void SygusSolver::checkSynthSolution(Assertions& as) Trace("check-synth-sol") << "Substituted body of assertion to " << conjBody << "\n"; solChecker->assertFormula(conjBody); - // Assert all auxiliary assertions. This may include recursive function - // definitions that were added as assertions to the sygus problem. - for (Node a : auxAssertions) - { - // We require rewriting here, e.g. so that define-fun from the original - // problem are rewritten to true. If this is not the case, then the - // assertions module of the subsolver will complain about assertions - // with free variables. - Node ar = rewrite(a); - solChecker->assertFormula(ar); - } Result r = solChecker->checkSat(); if (isVerboseOn(1)) { @@ -414,15 +415,47 @@ void SygusSolver::checkSynthSolution(Assertions& as) } } -void SygusSolver::setSygusConjectureStale() +void SygusSolver::initializeSygusSubsolver(std::unique_ptr<SolverEngine>& se, + Assertions& as) { - if (d_sygusConjectureStale) + initializeSubsolver(se, d_env); + // carry the ordinary define-fun definitions + const context::CDList<Node>& alistDefs = as.getAssertionListDefinitions(); + std::unordered_set<Node> processed; + for (const Node& def : alistDefs) { - // already stale - return; + // only consider define-fun, represented as (= f (lambda ...)). + if (def.getKind() == EQUAL) + { + Assert(def[0].isVar()); + std::vector<Node> formals; + Node dbody = def[1]; + if (def[1].getKind() == LAMBDA) + { + formals.insert(formals.end(), def[1][0].begin(), def[1][0].end()); + dbody = dbody[1]; + } + se->defineFunction(def[0], formals, dbody); + processed.insert(def); + } } - d_sygusConjectureStale = true; - // TODO (project #7): if incremental, we should pop a context + // Also assert auxiliary assertions + const context::CDList<Node>& alist = as.getAssertionList(); + for (size_t i = 0, asize = alist.size(); i < asize; ++i) + { + Node a = alist[i]; + // ignore definitions here + if (processed.find(a) == processed.end()) + { + se->assertFormula(a); + } + } +} + +bool SygusSolver::usingSygusSubsolver() const +{ + // use SyGuS subsolver if in incremental mode + return options().base.incrementalSolving; } void SygusSolver::expandDefinitionsSygusDt(TypeNode tn) const @@ -467,5 +500,15 @@ void SygusSolver::expandDefinitionsSygusDt(TypeNode tn) const } } +std::vector<Node> SygusSolver::listToVector(const NodeList& list) +{ + std::vector<Node> vec; + for (const Node& n : list) + { + vec.push_back(n); + } + return vec; +} + } // namespace smt } // namespace cvc5 diff --git a/src/smt/sygus_solver.h b/src/smt/sygus_solver.h index 0c742fbd4..4e7a04364 100644 --- a/src/smt/sygus_solver.h +++ b/src/smt/sygus_solver.h @@ -18,6 +18,7 @@ #ifndef CVC5__SMT__SYGUS_SOLVER_H #define CVC5__SMT__SYGUS_SOLVER_H +#include "context/cdlist.h" #include "context/cdo.h" #include "expr/node.h" #include "expr/type_node.h" @@ -27,7 +28,7 @@ namespace cvc5 { -class OutputManager; +class SolverEngine; namespace smt { @@ -37,13 +38,28 @@ class SmtSolver; * A solver for sygus queries. * * This class is responsible for responding to check-synth commands. It calls - * check satisfiability using an underlying SmtSolver object. + * check satisfiability using a separate SolverEngine "subsolver". * - * It also maintains a reference to a preprocessor for implementing - * checkSynthSolution. + * This solver operates in two modes. + * + * If in incremental mode, then the "main" SolverEngine for SyGuS inputs only + * maintains a (user-context) dependent state of SyGuS assertions, as well as + * assertions corresponding to (recursive) function definitions. The subsolver + * that solves SyGuS conjectures may be called to checkSat multiple times, + * however, push/pop (which impact SyGuS constraints) impacts only the main + * solver. This means that the conjecture being handled by the subsolver is + * reconstructed when the SyGuS conjecture is updated. The key property that + * this enables is that the subsolver does *not* get calls to push/pop, + * although it may receive multiple check-sat if the sygus functions and + * constraints are not updated between check-sat calls. + * + * If not in incremental mode, then the internal SyGuS conjecture is asserted + * to the "main" SolverEngine. */ class SygusSolver : protected EnvObj { + using NodeList = context::CDList<Node>; + public: SygusSolver(Env& env, SmtSolver& sms); ~SygusSolver(); @@ -134,6 +150,16 @@ class SygusSolver : protected EnvObj * is a valid formula. */ bool getSynthSolutions(std::map<Node, Node>& sol_map); + /** + * Same as above, but used for getting synthesis solutions from a "subsolver" + * that has been initialized to assert the synthesis conjecture as a + * normal assertion. + * + * This method returns true if we are in a state immediately preceded by + * a successful call to checkSat, where this SolverEngine has an asserted + * synthesis conjecture. + */ + bool getSubsolverSynthSolutions(std::map<Node, Node>& solMap); private: /** @@ -143,21 +169,13 @@ class SygusSolver : protected EnvObj * conjecture in which the functions-to-synthesize have been replaced by the * synthesized solutions, which is a quantifier-free formula, is * unsatisfiable. If not, then the found solutions are wrong. - */ - void checkSynthSolution(Assertions& as); - /** - * Set sygus conjecture is stale. The sygus conjecture is stale if either: - * (1) no sygus conjecture has been added as an assertion to this SMT engine, - * (2) there is a sygus conjecture that has been added as an assertion - * internally to this SMT engine, and there have been further calls such that - * the asserted conjecture is no longer up-to-date. * - * This method should be called when new sygus constraints are asserted and - * when functions-to-synthesize are declared. This function pops a user - * context if we are in incremental mode and the sygus conjecture was - * previously not stale. + * @param as The background assertions, which may include define-fun and + * define-fun-rec, + * @param sol_map Map from functions-to-synthesize to their solution (of the + * same type) for the asserted synthesis conjecture. */ - void setSygusConjectureStale(); + void checkSynthSolution(Assertions& as, const std::map<Node, Node>& solMap); /** * Expand definitions in sygus datatype tn, which ensures that all * sygus constructors that are used to build values of sygus datatype @@ -170,7 +188,19 @@ class SygusSolver : protected EnvObj * expansion. */ void expandDefinitionsSygusDt(TypeNode tn) const; - /** The SMT solver, which is used during checkSynth. */ + /** List to vector helper */ + static std::vector<Node> listToVector(const NodeList& list); + /** + * Initialize SyGuS subsolver based on the assertions from the "main" solver. + * This is used for check-synth using a subsolver, and for check-synth-sol. + * This constructs a subsolver se, and makes calls to add all define-fun + * and auxilary assertions. + */ + void initializeSygusSubsolver(std::unique_ptr<SolverEngine>& se, + Assertions& as); + /** Are we using a subsolver for the SyGuS query? */ + bool usingSygusSubsolver() const; + /** The SMT solver. */ SmtSolver& d_smtSolver; /** * sygus variables declared (from "declare-var" and "declare-fun" commands) @@ -178,17 +208,41 @@ class SygusSolver : protected EnvObj * The SyGuS semantics for declared variables is that they are implicitly * universally quantified in the constraints. */ - std::vector<Node> d_sygusVars; + NodeList d_sygusVars; /** sygus constraints */ - std::vector<Node> d_sygusConstraints; + NodeList d_sygusConstraints; /** sygus assumptions */ - std::vector<Node> d_sygusAssumps; + NodeList d_sygusAssumps; /** functions-to-synthesize */ - std::vector<Node> d_sygusFunSymbols; + NodeList d_sygusFunSymbols; + /** The current sygus conjecture */ + Node d_conj; /** * Whether we need to reconstruct the sygus conjecture. + * + * The sygus conjecture is stale if either: + * (1) no sygus conjecture has been added as an assertion to this SMT engine, + * (2) there is a sygus conjecture that has been added as an assertion + * internally to this SMT engine, and there have been further calls such that + * the asserted conjecture is no longer up-to-date. + * + * This flag should be set to true when new sygus constraints are asserted and + * when functions-to-synthesize are declared. */ context::CDO<bool> d_sygusConjectureStale; + /** + * The (context-dependent) pointer to the subsolver we have constructed. + * This is used to verify if the current subsolver is current, in case + * user-context dependent pop has a occurred. If this pointer does not match + * d_subsolver, then d_subsolver must be reconstructed in this context. + */ + context::CDO<SolverEngine*> d_subsolverCd; + /** + * The subsolver we are using. This is a separate copy of the SolverEngine + * which has the asserted synthesis conjecture, i.e. a formula returned by + * quantifiers::SygusUtils::mkSygusConjecture. + */ + std::unique_ptr<SolverEngine> d_subsolver; }; } // namespace smt diff --git a/src/theory/arith/arith_msum.cpp b/src/theory/arith/arith_msum.cpp index a8edb0e79..0621c1391 100644 --- a/src/theory/arith/arith_msum.cpp +++ b/src/theory/arith/arith_msum.cpp @@ -81,7 +81,8 @@ bool ArithMSum::getMonomialSum(Node n, std::map<Node, Node>& msum) bool ArithMSum::getMonomialSumLit(Node lit, std::map<Node, Node>& msum) { - if (lit.getKind() == GEQ || lit.getKind() == EQUAL) + if (lit.getKind() == GEQ + || (lit.getKind() == EQUAL && lit[0].getType().isRealOrInt())) { if (getMonomialSum(lit[0], msum)) { @@ -96,6 +97,7 @@ bool ArithMSum::getMonomialSumLit(Node lit, std::map<Node, Node>& msum) NodeManager* nm = NodeManager::currentNM(); if (getMonomialSum(lit[1], msum2)) { + TypeNode tn = lit[0].getType(); for (std::map<Node, Node>::iterator it = msum2.begin(); it != msum2.end(); ++it) @@ -103,20 +105,20 @@ bool ArithMSum::getMonomialSumLit(Node lit, std::map<Node, Node>& msum) std::map<Node, Node>::iterator it2 = msum.find(it->first); if (it2 != msum.end()) { - Node r = nm->mkNode(MINUS, - it2->second.isNull() - ? nm->mkConst(CONST_RATIONAL, Rational(1)) - : it2->second, - it->second.isNull() - ? nm->mkConst(CONST_RATIONAL, Rational(1)) - : it->second); - msum[it->first] = Rewriter::rewrite(r); + Rational r1 = it2->second.isNull() + ? Rational(1) + : it2->second.getConst<Rational>(); + Rational r2 = it->second.isNull() + ? Rational(1) + : it->second.getConst<Rational>(); + msum[it->first] = nm->mkConstRealOrInt(tn, r1 - r2); } else { msum[it->first] = it->second.isNull() - ? nm->mkConst(CONST_RATIONAL, Rational(-1)) - : negate(it->second); + ? nm->mkConstRealOrInt(tn, Rational(-1)) + : nm->mkConstRealOrInt( + tn, -it->second.getConst<Rational>()); } } return true; @@ -127,7 +129,7 @@ bool ArithMSum::getMonomialSumLit(Node lit, std::map<Node, Node>& msum) return false; } -Node ArithMSum::mkNode(const std::map<Node, Node>& msum) +Node ArithMSum::mkNode(TypeNode tn, const std::map<Node, Node>& msum) { NodeManager* nm = NodeManager::currentNM(); std::vector<Node> children; @@ -146,10 +148,10 @@ Node ArithMSum::mkNode(const std::map<Node, Node>& msum) } children.push_back(m); } - return children.size() > 1 ? nm->mkNode(PLUS, children) - : (children.size() == 1 - ? children[0] - : nm->mkConst(CONST_RATIONAL, Rational(0))); + return children.size() > 1 + ? nm->mkNode(PLUS, children) + : (children.size() == 1 ? children[0] + : nm->mkConstRealOrInt(tn, Rational(0))); } int ArithMSum::isolate( @@ -159,11 +161,13 @@ int ArithMSum::isolate( std::map<Node, Node>::const_iterator itv = msum.find(v); if (itv != msum.end()) { + NodeManager* nm = NodeManager::currentNM(); std::vector<Node> children; Rational r = itv->second.isNull() ? Rational(1) : itv->second.getConst<Rational>(); if (r.sgn() != 0) { + TypeNode vtn = v.getType(); for (std::map<Node, Node>::const_iterator it = msum.begin(); it != msum.end(); ++it) @@ -182,27 +186,25 @@ int ArithMSum::isolate( children.push_back(m); } } - val = children.size() > 1 - ? NodeManager::currentNM()->mkNode(PLUS, children) - : (children.size() == 1 ? children[0] - : NodeManager::currentNM()->mkConst( - CONST_RATIONAL, Rational(0))); + val = + children.size() > 1 + ? nm->mkNode(PLUS, children) + : (children.size() == 1 ? children[0] + : nm->mkConstRealOrInt(vtn, Rational(0))); if (!r.isOne() && !r.isNegativeOne()) { - if (v.getType().isInteger()) + if (vtn.isInteger()) { - veq_c = NodeManager::currentNM()->mkConst(CONST_RATIONAL, r.abs()); + veq_c = nm->mkConstInt(r.abs()); } else { - val = NodeManager::currentNM()->mkNode( - MULT, - val, - NodeManager::currentNM()->mkConst(CONST_RATIONAL, - Rational(1) / r.abs())); + val = nm->mkNode(MULT, val, nm->mkConstReal(Rational(1) / r.abs())); } } - val = r.sgn() == 1 ? negate(val) : Rewriter::rewrite(val); + val = r.sgn() == 1 + ? nm->mkNode(MULT, nm->mkConstRealOrInt(vtn, Rational(-1)), val) + : val; return (r.sgn() == 1 || k == EQUAL) ? 1 : -1; } } @@ -284,29 +286,13 @@ bool ArithMSum::decompose(Node n, Node v, Node& coeff, Node& rem) { coeff = it->second; msum.erase(v); - rem = mkNode(msum); + rem = mkNode(n.getType(), msum); return true; } } return false; } -Node ArithMSum::negate(Node t) -{ - Node tt = NodeManager::currentNM()->mkNode( - MULT, NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(-1)), t); - tt = Rewriter::rewrite(tt); - return tt; -} - -Node ArithMSum::offset(Node t, int i) -{ - Node tt = NodeManager::currentNM()->mkNode( - PLUS, NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(i)), t); - tt = Rewriter::rewrite(tt); - return tt; -} - void ArithMSum::debugPrintMonomialSum(std::map<Node, Node>& msum, const char* c) { for (std::map<Node, Node>::iterator it = msum.begin(); it != msum.end(); ++it) diff --git a/src/theory/arith/arith_msum.h b/src/theory/arith/arith_msum.h index 87f56e64f..ae57ee1cb 100644 --- a/src/theory/arith/arith_msum.h +++ b/src/theory/arith/arith_msum.h @@ -103,8 +103,13 @@ class ArithMSum * * Make the Node corresponding to the interpretation of msum, [msum], where: * [msum] = sum_{( v, c ) \in msum } [c]*[v] + * + * @param tn The type of the node to return, which is used only if msum is + * empty + * @param msum The monomial sum + * @return The node corresponding to the monomial sum */ - static Node mkNode(const std::map<Node, Node>& msum); + static Node mkNode(TypeNode tn, const std::map<Node, Node>& msum); /** make coefficent term * @@ -173,12 +178,6 @@ class ArithMSum */ static bool decompose(Node n, Node v, Node& coeff, Node& rem); - /** return the rewritten form of (UMINUS t) */ - static Node negate(Node t); - - /** return the rewritten form of (PLUS t (CONST_RATIONAL i)) */ - static Node offset(Node t, int i); - /** debug print for a monmoial sum, prints to Trace(c) */ static void debugPrintMonomialSum(std::map<Node, Node>& msum, const char* c); }; diff --git a/src/theory/arith/arith_rewriter.cpp b/src/theory/arith/arith_rewriter.cpp index 8408f15bb..af6f23c1f 100644 --- a/src/theory/arith/arith_rewriter.cpp +++ b/src/theory/arith/arith_rewriter.cpp @@ -214,7 +214,7 @@ RewriteResponse ArithRewriter::postRewriteTerm(TNode t){ return RewriteResponse(REWRITE_DONE, t); case kind::TO_REAL: case kind::CAST_TO_REAL: return RewriteResponse(REWRITE_DONE, t[0]); - case kind::TO_INTEGER:return rewriteExtIntegerOp(t); + case kind::TO_INTEGER: return rewriteExtIntegerOp(t); case kind::POW: { if(t[1].getKind() == kind::CONST_RATIONAL){ @@ -402,11 +402,11 @@ RewriteResponse ArithRewriter::postRewritePow2(TNode t) RewriteResponse ArithRewriter::postRewriteIAnd(TNode t) { Assert(t.getKind() == kind::IAND); + size_t bsize = t.getOperator().getConst<IntAnd>().d_size; NodeManager* nm = NodeManager::currentNM(); // if constant, we eliminate if (t[0].isConst() && t[1].isConst()) { - size_t bsize = t.getOperator().getConst<IntAnd>().d_size; Node iToBvop = nm->mkConst(IntToBitVector(bsize)); Node arg1 = nm->mkNode(kind::INT_TO_BITVECTOR, iToBvop, t[0]); Node arg2 = nm->mkNode(kind::INT_TO_BITVECTOR, iToBvop, t[1]); @@ -437,6 +437,11 @@ RewriteResponse ArithRewriter::postRewriteIAnd(TNode t) // ((_ iand k) 0 y) ---> 0 return RewriteResponse(REWRITE_DONE, t[i]); } + if (t[i].getConst<Rational>().getNumerator() == Integer(2).pow(bsize) - 1) + { + // ((_ iand k) 111...1 y) ---> y + return RewriteResponse(REWRITE_DONE, t[i == 0 ? 1 : 0]); + } } return RewriteResponse(REWRITE_DONE, t); } @@ -511,7 +516,7 @@ RewriteResponse ArithRewriter::postRewriteTranscendental(TNode t) { msum.erase(pi); if (!msum.empty()) { - rem = ArithMSum::mkNode(msum); + rem = ArithMSum::mkNode(t[0].getType(), msum); } } } diff --git a/src/theory/arith/bound_inference.cpp b/src/theory/arith/bound_inference.cpp index cd688660a..4423cae61 100644 --- a/src/theory/arith/bound_inference.cpp +++ b/src/theory/arith/bound_inference.cpp @@ -15,6 +15,7 @@ #include "theory/arith/bound_inference.h" +#include "smt/env.h" #include "theory/arith/normal_form.h" #include "theory/rewriter.h" @@ -29,6 +30,8 @@ std::ostream& operator<<(std::ostream& os, const Bounds& b) { << b.upper_value << (b.upper_strict ? ')' : ']'); } +BoundInference::BoundInference(Env& env) : EnvObj(env) {} + void BoundInference::reset() { d_bounds.clear(); } Bounds& BoundInference::get_or_add(const Node& lhs) @@ -53,7 +56,7 @@ Bounds BoundInference::get(const Node& lhs) const const std::map<Node, Bounds>& BoundInference::get() const { return d_bounds; } bool BoundInference::add(const Node& n, bool onlyVariables) { - Node tmp = Rewriter::rewrite(n); + Node tmp = rewrite(n); if (tmp.getKind() == Kind::CONST_BOOLEAN) { return false; @@ -175,19 +178,19 @@ void BoundInference::update_lower_bound(const Node& origin, if (!b.lower_strict && !b.upper_strict && b.lower_value == b.upper_value) { b.lower_bound = b.upper_bound = - Rewriter::rewrite(nm->mkNode(Kind::EQUAL, lhs, value)); + rewrite(nm->mkNode(Kind::EQUAL, lhs, value)); } else { - b.lower_bound = Rewriter::rewrite( - nm->mkNode(strict ? Kind::GT : Kind::GEQ, lhs, value)); + b.lower_bound = + rewrite(nm->mkNode(strict ? Kind::GT : Kind::GEQ, lhs, value)); } } else if (strict && b.lower_value == value) { auto* nm = NodeManager::currentNM(); b.lower_strict = strict; - b.lower_bound = Rewriter::rewrite(nm->mkNode(Kind::GT, lhs, value)); + b.lower_bound = rewrite(nm->mkNode(Kind::GT, lhs, value)); b.lower_origin = origin; } } @@ -210,19 +213,19 @@ void BoundInference::update_upper_bound(const Node& origin, if (!b.lower_strict && !b.upper_strict && b.lower_value == b.upper_value) { b.lower_bound = b.upper_bound = - Rewriter::rewrite(nm->mkNode(Kind::EQUAL, lhs, value)); + rewrite(nm->mkNode(Kind::EQUAL, lhs, value)); } else { - b.upper_bound = Rewriter::rewrite( - nm->mkNode(strict ? Kind::LT : Kind::LEQ, lhs, value)); + b.upper_bound = + rewrite(nm->mkNode(strict ? Kind::LT : Kind::LEQ, lhs, value)); } } else if (strict && b.upper_value == value) { auto* nm = NodeManager::currentNM(); b.upper_strict = strict; - b.upper_bound = Rewriter::rewrite(nm->mkNode(Kind::LT, lhs, value)); + b.upper_bound = rewrite(nm->mkNode(Kind::LT, lhs, value)); b.upper_origin = origin; } } @@ -238,20 +241,6 @@ std::ostream& operator<<(std::ostream& os, const BoundInference& bi) return os; } -std::map<Node, std::pair<Node,Node>> getBounds(const std::vector<Node>& assertions) { - BoundInference bi; - for (const auto& a: assertions) { - bi.add(a); - } - std::map<Node, std::pair<Node,Node>> res; - for (const auto& b : bi.get()) - { - res.emplace(b.first, - std::make_pair(b.second.lower_value, b.second.upper_value)); - } - return res; -} - } // namespace arith } // namespace theory } // namespace cvc5 diff --git a/src/theory/arith/bound_inference.h b/src/theory/arith/bound_inference.h index e8d7a294f..a3043ee93 100644 --- a/src/theory/arith/bound_inference.h +++ b/src/theory/arith/bound_inference.h @@ -21,6 +21,7 @@ #include <vector> #include "expr/node.h" +#include "smt/env_obj.h" namespace cvc5 { namespace theory { @@ -53,9 +54,10 @@ namespace arith { * A utility class that extracts direct bounds on arithmetic terms from theory * atoms. */ - class BoundInference + class BoundInference : protected EnvObj { public: + BoundInference(Env& env); void reset(); /** @@ -110,8 +112,6 @@ namespace arith { /** Print the current variable bounds. */ std::ostream& operator<<(std::ostream& os, const BoundInference& bi); -std::map<Node, std::pair<Node,Node>> getBounds(const std::vector<Node>& assertions); - } // namespace arith } // namespace theory } // namespace cvc5 diff --git a/src/theory/arith/constraint.cpp b/src/theory/arith/constraint.cpp index cffacdc39..a9576e0cc 100644 --- a/src/theory/arith/constraint.cpp +++ b/src/theory/arith/constraint.cpp @@ -1551,9 +1551,6 @@ TrustNode Constraint::externalExplainForPropagation(TNode lit) const Node n = safeConstructNary(nb); if (d_database->isProofEnabled()) { - // Check that the literal we're explaining via this constraint actually - // matches the constraint's canonical literal. - Assert(Rewriter::rewrite(lit) == getLiteral()); std::vector<Node> assumptions; if (n.getKind() == Kind::AND) { diff --git a/src/theory/arith/infer_bounds.cpp b/src/theory/arith/infer_bounds.cpp index aae9bae62..21f698e45 100644 --- a/src/theory/arith/infer_bounds.cpp +++ b/src/theory/arith/infer_bounds.cpp @@ -163,9 +163,7 @@ Node InferBoundsResult::getLiteral() const{ Assert(getValue().infinitesimalSgn() >= 0); k = boundIsRational() ? kind::GEQ : kind::GT; } - Node atom = nm->mkNode(k, getTerm(), qnode); - Node lit = Rewriter::rewrite(atom); - return lit; + return nm->mkNode(k, getTerm(), qnode); } /* If there is a bound, this is a node that explains the bound. */ diff --git a/src/theory/arith/nl/cad/cdcac.cpp b/src/theory/arith/nl/cad/cdcac.cpp index 2fc77be1b..18ccf7aca 100644 --- a/src/theory/arith/nl/cad/cdcac.cpp +++ b/src/theory/arith/nl/cad/cdcac.cpp @@ -105,16 +105,7 @@ std::vector<CACInterval> CDCAC::getUnsatIntervals(std::size_t cur_variable) { std::vector<CACInterval> res; LazardEvaluation le; - if (options().arith.nlCadLifting - == options::NlCadLiftingMode::LAZARD) - { - for (size_t vid = 0; vid < cur_variable; ++vid) - { - const auto& val = d_assignment.get(d_variableOrdering[vid]); - le.add(d_variableOrdering[vid], val); - } - le.addFreeVariable(d_variableOrdering[cur_variable]); - } + prepareRootIsolation(le, cur_variable); for (const auto& c : d_constraints.getConstraints()) { const poly::Polynomial& p = std::get<0>(c); @@ -428,11 +419,17 @@ CACInterval CDCAC::intervalFromCharacterization( m.pushDownPolys(d, d_variableOrdering[cur_variable]); // Collect -oo, all roots, oo + + LazardEvaluation le; + prepareRootIsolation(le, cur_variable); std::vector<poly::Value> roots; roots.emplace_back(poly::Value::minus_infty()); for (const auto& p : m) { - auto tmp = isolate_real_roots(p, d_assignment); + Trace("cdcac") << "Isolating real roots of " << p << " over " + << d_assignment << std::endl; + + auto tmp = isolateRealRoots(le, p); roots.insert(roots.end(), tmp.begin(), tmp.end()); } roots.emplace_back(poly::Value::plus_infty()); @@ -464,6 +461,8 @@ CACInterval CDCAC::intervalFromCharacterization( d_assignment.set(d_variableOrdering[cur_variable], lower); for (const auto& p : m) { + Trace("cdcac") << "Evaluating " << p << " = 0 over " << d_assignment + << std::endl; if (evaluate_constraint(p, d_assignment, poly::SignCondition::EQ)) { l.add(p, true); @@ -477,6 +476,8 @@ CACInterval CDCAC::intervalFromCharacterization( d_assignment.set(d_variableOrdering[cur_variable], upper); for (const auto& p : m) { + Trace("cdcac") << "Evaluating " << p << " = 0 over " << d_assignment + << std::endl; if (evaluate_constraint(p, d_assignment, poly::SignCondition::EQ)) { u.add(p, true); @@ -570,8 +571,10 @@ std::vector<CACInterval> CDCAC::getUnsatCoverImpl(std::size_t curVariable, d_assignment.unset(d_variableOrdering[curVariable]); + Trace("cdcac") << "Building interval..." << std::endl; auto newInterval = intervalFromCharacterization(characterization, curVariable, sample); + Trace("cdcac") << "New interval: " << newInterval.d_interval << std::endl; newInterval.d_origins = collectConstraints(cov); intervals.emplace_back(newInterval); if (isProofEnabled()) @@ -730,6 +733,30 @@ void CDCAC::pruneRedundantIntervals(std::vector<CACInterval>& intervals) } } +void CDCAC::prepareRootIsolation(LazardEvaluation& le, + size_t cur_variable) const +{ + if (options().arith.nlCadLifting == options::NlCadLiftingMode::LAZARD) + { + for (size_t vid = 0; vid < cur_variable; ++vid) + { + const auto& val = d_assignment.get(d_variableOrdering[vid]); + le.add(d_variableOrdering[vid], val); + } + le.addFreeVariable(d_variableOrdering[cur_variable]); + } +} + +std::vector<poly::Value> CDCAC::isolateRealRoots( + LazardEvaluation& le, const poly::Polynomial& p) const +{ + if (options().arith.nlCadLifting == options::NlCadLiftingMode::LAZARD) + { + return le.isolateRealRoots(p); + } + return poly::isolate_real_roots(p, d_assignment); +} + } // namespace cad } // namespace nl } // namespace arith diff --git a/src/theory/arith/nl/cad/cdcac.h b/src/theory/arith/nl/cad/cdcac.h index 04b5cab24..8317c0813 100644 --- a/src/theory/arith/nl/cad/cdcac.h +++ b/src/theory/arith/nl/cad/cdcac.h @@ -29,6 +29,7 @@ #include "smt/env_obj.h" #include "theory/arith/nl/cad/cdcac_utils.h" #include "theory/arith/nl/cad/constraints.h" +#include "theory/arith/nl/cad/lazard_evaluation.h" #include "theory/arith/nl/cad/proof_generator.h" #include "theory/arith/nl/cad/variable_ordering.h" @@ -196,6 +197,20 @@ class CDCAC : protected EnvObj void pruneRedundantIntervals(std::vector<CACInterval>& intervals); /** + * Prepare the lazard evaluation object with the current assignment, if the + * lazard lifting is enabled. Otherwise, this function does nothing. + */ + void prepareRootIsolation(LazardEvaluation& le, size_t cur_variable) const; + + /** + * Isolates the real roots of the polynomial `p`. If the lazard lifting is + * enabled, this function uses `le.isolateRealRoots()`, otherwise uses the + * regular `poly::isolate_real_roots()`. + */ + std::vector<poly::Value> isolateRealRoots(LazardEvaluation& le, + const poly::Polynomial& p) const; + + /** * The current assignment. When the method terminates with SAT, it contains a * model for the input constraints. */ diff --git a/src/theory/arith/nl/cad/lazard_evaluation.cpp b/src/theory/arith/nl/cad/lazard_evaluation.cpp index aec0d46e3..032565d3d 100644 --- a/src/theory/arith/nl/cad/lazard_evaluation.cpp +++ b/src/theory/arith/nl/cad/lazard_evaluation.cpp @@ -821,22 +821,11 @@ std::vector<poly::Polynomial> LazardEvaluation::reducePolynomial( return {p}; } -/** - * Compute the infeasible regions of the given polynomial according to a sign - * condition. We first reduce the polynomial and isolate the real roots of every - * resulting polynomial. We store all roots (except for -infty, +infty and none) - * in a set. Then, we transform the set of roots into a list of infeasible - * regions by generating intervals between -infty and the first root, in between - * every two consecutive roots and between the last root and +infty. While doing - * this, we only keep those intervals that are actually infeasible for the - * original polynomial q over the partial assignment. Finally, we go over the - * intervals and aggregate consecutive intervals that connect. - */ -std::vector<poly::Interval> LazardEvaluation::infeasibleRegions( - const poly::Polynomial& q, poly::SignCondition sc) const +std::vector<poly::Value> LazardEvaluation::isolateRealRoots( + const poly::Polynomial& q) const { poly::Assignment a; - std::set<poly::Value> roots; + std::vector<poly::Value> roots; // reduce q to a set of reduced polynomials p for (const auto& p : reducePolynomial(q)) { @@ -849,9 +838,28 @@ std::vector<poly::Interval> LazardEvaluation::infeasibleRegions( if (poly::is_minus_infinity(r)) continue; if (poly::is_none(r)) continue; if (poly::is_plus_infinity(r)) continue; - roots.insert(r); + roots.emplace_back(r); } } + std::sort(roots.begin(), roots.end()); + return roots; +} + +/** + * Compute the infeasible regions of the given polynomial according to a sign + * condition. We first reduce the polynomial and isolate the real roots of every + * resulting polynomial. We store all roots (except for -infty, +infty and none) + * in a set. Then, we transform the set of roots into a list of infeasible + * regions by generating intervals between -infty and the first root, in between + * every two consecutive roots and between the last root and +infty. While doing + * this, we only keep those intervals that are actually infeasible for the + * original polynomial q over the partial assignment. Finally, we go over the + * intervals and aggregate consecutive intervals that connect. + */ +std::vector<poly::Interval> LazardEvaluation::infeasibleRegions( + const poly::Polynomial& q, poly::SignCondition sc) const +{ + std::vector<poly::Value> roots = isolateRealRoots(q); // generate all intervals // (-infty,root_0), [root_0], (root_0,root_1), ..., [root_m], (root_m,+infty) @@ -962,6 +970,16 @@ std::vector<poly::Polynomial> LazardEvaluation::reducePolynomial( { return {p}; } + +std::vector<poly::Value> LazardEvaluation::isolateRealRoots( + const poly::Polynomial& q) const +{ + WarningOnce() + << "CAD::LazardEvaluation is disabled because CoCoA is not available. " + "Falling back to regular real root isolation." + << std::endl; + return poly::isolate_real_roots(q, d_state->d_assignment); +} std::vector<poly::Interval> LazardEvaluation::infeasibleRegions( const poly::Polynomial& q, poly::SignCondition sc) const { diff --git a/src/theory/arith/nl/cad/lazard_evaluation.h b/src/theory/arith/nl/cad/lazard_evaluation.h index 3bb971c4c..2afccb462 100644 --- a/src/theory/arith/nl/cad/lazard_evaluation.h +++ b/src/theory/arith/nl/cad/lazard_evaluation.h @@ -94,6 +94,11 @@ class LazardEvaluation const poly::Polynomial& q) const; /** + * Isolates the real roots of the given polynomials. + */ + std::vector<poly::Value> isolateRealRoots(const poly::Polynomial& q) const; + + /** * Compute the infeasible regions of q under the given sign condition. * Uses reducePolynomial and then performs real root isolation on the * resulting polynomials to obtain the intervals. Mimics diff --git a/src/theory/arith/nl/cad_solver.cpp b/src/theory/arith/nl/cad_solver.cpp index 721308a3d..f4582ac20 100644 --- a/src/theory/arith/nl/cad_solver.cpp +++ b/src/theory/arith/nl/cad_solver.cpp @@ -16,12 +16,14 @@ #include "theory/arith/nl/cad_solver.h" #include "expr/skolem_manager.h" +#include "options/arith_options.h" #include "smt/env.h" #include "theory/arith/inference_manager.h" #include "theory/arith/nl/cad/cdcac.h" #include "theory/arith/nl/nl_model.h" #include "theory/arith/nl/poly_conversion.h" #include "theory/inference_id.h" +#include "theory/theory.h" namespace cvc5 { namespace theory { @@ -36,7 +38,8 @@ CadSolver::CadSolver(Env& env, InferenceManager& im, NlModel& model) #endif d_foundSatisfiability(false), d_im(im), - d_model(model) + d_model(model), + d_eqsubs(env) { NodeManager* nm = NodeManager::currentNM(); SkolemManager* sm = nm->getSkolemManager(); @@ -65,11 +68,41 @@ void CadSolver::initLastCall(const std::vector<Node>& assertions) Trace("nl-cad") << " " << a << std::endl; } } - // store or process assertions - d_CAC.reset(); - for (const Node& a : assertions) + if (options().arith.nlCadVarElim) { - d_CAC.getConstraints().addConstraint(a); + d_eqsubs.reset(); + std::vector<Node> processed = d_eqsubs.eliminateEqualities(assertions); + if (d_eqsubs.hasConflict()) + { + Node lem = NodeManager::currentNM()->mkAnd(d_eqsubs.getConflict()).negate(); + d_im.addPendingLemma(lem, InferenceId::ARITH_NL_CAD_CONFLICT, nullptr); + Trace("nl-cad") << "Found conflict: " << lem << std::endl; + return; + } + if (Trace.isOn("nl-cad")) + { + Trace("nl-cad") << "After simplifications" << std::endl; + Trace("nl-cad") << "* Assertions: " << std::endl; + for (const Node& a : processed) + { + Trace("nl-cad") << " " << a << std::endl; + } + } + d_CAC.reset(); + for (const Node& a : processed) + { + Assert(!a.isConst()); + d_CAC.getConstraints().addConstraint(a); + } + } + else + { + d_CAC.reset(); + for (const Node& a : assertions) + { + Assert(!a.isConst()); + d_CAC.getConstraints().addConstraint(a); + } } d_CAC.computeVariableOrdering(); d_CAC.retrieveInitialAssignment(d_model, d_ranVariable); @@ -84,6 +117,7 @@ void CadSolver::checkFull() { #ifdef CVC5_POLY_IMP if (d_CAC.getConstraints().getConstraints().empty()) { + d_foundSatisfiability = true; Trace("nl-cad") << "No constraints. Return." << std::endl; return; } @@ -101,6 +135,8 @@ void CadSolver::checkFull() Trace("nl-cad") << "Collected MIS: " << mis << std::endl; Assert(!mis.empty()) << "Infeasible subset can not be empty"; Trace("nl-cad") << "UNSAT with MIS: " << mis << std::endl; + d_eqsubs.postprocessConflict(mis); + Trace("nl-cad") << "After postprocessing: " << mis << std::endl; Node lem = NodeManager::currentNM()->mkAnd(mis).negate(); ProofGenerator* proof = d_CAC.closeProof(mis); d_im.addPendingLemma(lem, InferenceId::ARITH_NL_CAD_CONFLICT, proof); @@ -170,10 +206,15 @@ bool CadSolver::constructModelIfAvailable(std::vector<Node>& assertions) return false; } bool foundNonVariable = false; + for (const auto& sub: d_eqsubs.getSubstitutions()) + { + d_model.addSubstitution(sub.first, sub.second); + Trace("nl-cad") << "-> " << sub.first << " = " << sub.second << std::endl; + } for (const auto& v : d_CAC.getVariableOrdering()) { Node variable = d_CAC.getConstraints().varMapper()(v); - if (!variable.isVar()) + if (!Theory::isLeafOf(variable, TheoryId::THEORY_ARITH)) { Trace("nl-cad") << "Not a variable: " << variable << std::endl; foundNonVariable = true; diff --git a/src/theory/arith/nl/cad_solver.h b/src/theory/arith/nl/cad_solver.h index bedffcaa9..73d09378b 100644 --- a/src/theory/arith/nl/cad_solver.h +++ b/src/theory/arith/nl/cad_solver.h @@ -23,6 +23,7 @@ #include "smt/env_obj.h" #include "theory/arith/nl/cad/cdcac.h" #include "theory/arith/nl/cad/proof_checker.h" +#include "theory/arith/nl/equality_substitution.h" namespace cvc5 { @@ -104,6 +105,9 @@ class CadSolver: protected EnvObj InferenceManager& d_im; /** Reference to the non-linear model object */ NlModel& d_model; + /** Utility to eliminate variables from simple equalities before going into + * the actual coverings solver */ + EqualitySubstitution d_eqsubs; }; /* class CadSolver */ } // namespace nl diff --git a/src/theory/arith/nl/equality_substitution.cpp b/src/theory/arith/nl/equality_substitution.cpp new file mode 100644 index 000000000..9b3a79cd4 --- /dev/null +++ b/src/theory/arith/nl/equality_substitution.cpp @@ -0,0 +1,183 @@ +/****************************************************************************** + * Top contributors (to current version): + * Gereon Kremer, Andrew Reynolds, Andres Noetzli + * + * This file is part of the cvc5 project. + * + * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS + * in the top-level source directory and their institutional affiliations. + * All rights reserved. See the file COPYING in the top-level source + * directory for licensing information. + * **************************************************************************** + * + * Implementation of new non-linear solver. + */ + +#include "theory/arith/nl/equality_substitution.h" + +#include "smt/env.h" + +namespace cvc5 { +namespace theory { +namespace arith { +namespace nl { + +EqualitySubstitution::EqualitySubstitution(Env& env) + : EnvObj(env), d_substitutions(std::make_unique<SubstitutionMap>()) +{ +} +void EqualitySubstitution::reset() +{ + d_substitutions = std::make_unique<SubstitutionMap>(); + d_conflict.clear(); + d_conflictMap.clear(); + d_trackOrigin.clear(); +} + +std::vector<Node> EqualitySubstitution::eliminateEqualities( + const std::vector<Node>& assertions) +{ + Trace("nl-eqs") << "Input:" << std::endl; + for (const auto& a : assertions) + { + Trace("nl-eqs") << "\t" << a << std::endl; + } + std::set<TNode> tracker; + std::vector<Node> asserts = assertions; + std::vector<Node> next; + + size_t last_size = 0; + while (asserts.size() != last_size) + { + last_size = asserts.size(); + // collect all eliminations from original into d_substitutions + for (const auto& orig : asserts) + { + if (orig.getKind() != Kind::EQUAL) continue; + tracker.clear(); + d_substitutions->invalidateCache(); + Node o = d_substitutions->apply(orig, d_env.getRewriter(), &tracker); + Trace("nl-eqs") << "Simplified for subst " << orig << " -> " << o + << std::endl; + if (o.getKind() != Kind::EQUAL) continue; + Assert(o.getNumChildren() == 2); + for (size_t i = 0; i < 2; ++i) + { + const auto& l = o[i]; + const auto& r = o[1 - i]; + if (l.isConst()) continue; + if (!Theory::isLeafOf(l, TheoryId::THEORY_ARITH)) continue; + if (d_substitutions->hasSubstitution(l)) continue; + if (expr::hasSubterm(r, l, true)) continue; + Trace("nl-eqs") << "Found substitution " << l << " -> " << r + << std::endl + << " from " << o << " / " << orig << std::endl; + d_substitutions->addSubstitution(l, r); + d_trackOrigin.emplace(l, o); + if (o != orig) + { + addToConflictMap(o, orig, tracker); + } + break; + } + } + + // simplify with subs from original into next + next.clear(); + for (const auto& a : asserts) + { + tracker.clear(); + d_substitutions->invalidateCache(); + Node simp = d_substitutions->apply(a, d_env.getRewriter(), &tracker); + if (simp.isConst()) + { + if (simp.getConst<bool>()) + { + continue; + } + Trace("nl-eqs") << "Simplified " << a << " to " << simp << std::endl; + for (TNode t : tracker) + { + Trace("nl-eqs") << "Tracker has " << t << std::endl; + auto toit = d_trackOrigin.find(t); + Assert(toit != d_trackOrigin.end()); + d_conflict.emplace_back(toit->second); + } + d_conflict.emplace_back(a); + postprocessConflict(d_conflict); + Trace("nl-eqs") << "Direct conflict: " << d_conflict << std::endl; + Trace("nl-eqs") << std::endl + << d_conflict.size() << " vs " + << std::distance(d_substitutions->begin(), + d_substitutions->end()) + << std::endl + << std::endl; + return {}; + } + if (simp != a) + { + Trace("nl-eqs") << "Simplified " << a << " to " << simp << std::endl; + addToConflictMap(simp, a, tracker); + } + next.emplace_back(simp); + } + asserts = std::move(next); + } + d_conflict.clear(); + return asserts; +} +void EqualitySubstitution::postprocessConflict( + std::vector<Node>& conflict) const +{ + Trace("nl-eqs") << "Postprocessing " << conflict << std::endl; + std::set<Node> result; + for (const auto& c : conflict) + { + auto it = d_conflictMap.find(c); + if (it == d_conflictMap.end()) + { + result.insert(c); + } + else + { + Trace("nl-eqs") << "Origin of " << c << ": " << it->second << std::endl; + result.insert(it->second.begin(), it->second.end()); + } + } + conflict.clear(); + conflict.insert(conflict.end(), result.begin(), result.end()); + Trace("nl-eqs") << "-> " << conflict << std::endl; +} +void EqualitySubstitution::insertOrigins(std::set<Node>& dest, + const Node& n) const +{ + auto it = d_conflictMap.find(n); + if (it == d_conflictMap.end()) + { + dest.insert(n); + } + else + { + dest.insert(it->second.begin(), it->second.end()); + } +} +void EqualitySubstitution::addToConflictMap(const Node& n, + const Node& orig, + const std::set<TNode>& tracker) +{ + std::set<Node> origins; + insertOrigins(origins, orig); + for (const auto& t : tracker) + { + auto tit = d_trackOrigin.find(t); + Assert(tit != d_trackOrigin.end()); + insertOrigins(origins, tit->second); + } + Trace("nl-eqs") << "ConflictMap: " << n << " -> " << origins << std::endl; + d_conflictMap.emplace(n, std::vector<Node>(origins.begin(), origins.end())); +} + +} // namespace nl +} // namespace arith +} // namespace theory +} // namespace cvc5 diff --git a/src/theory/arith/nl/equality_substitution.h b/src/theory/arith/nl/equality_substitution.h new file mode 100644 index 000000000..b095af8df --- /dev/null +++ b/src/theory/arith/nl/equality_substitution.h @@ -0,0 +1,102 @@ +/****************************************************************************** + * Top contributors (to current version): + * Gereon Kremer + * + * This file is part of the cvc5 project. + * + * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS + * in the top-level source directory and their institutional affiliations. + * All rights reserved. See the file COPYING in the top-level source + * directory for licensing information. + * **************************************************************************** + * + * CAD-based solver based on https://arxiv.org/pdf/2003.05633.pdf. + */ + +#ifndef CVC5__THEORY__ARITH__NL__EQUALITY_SUBSTITUTION_H +#define CVC5__THEORY__ARITH__NL__EQUALITY_SUBSTITUTION_H + +#include <vector> + +#include "context/context.h" +#include "expr/node.h" +#include "expr/node_algorithm.h" +#include "smt/env_obj.h" +#include "theory/substitutions.h" +#include "theory/theory.h" + +namespace cvc5 { +namespace theory { +namespace arith { +namespace nl { + +/** + * This class is a general utility to eliminate variables from a set of + * assertions. + */ +class EqualitySubstitution : protected EnvObj +{ + public: + EqualitySubstitution(Env& env); + /** Reset this object */ + void reset(); + + /** + * Eliminate variables using equalities from the set of assertions. + * Returns a set of assertions where some variables may have been eliminated. + * Substitutions for the eliminated variables can be obtained from + * getSubstitutions(). + */ + std::vector<Node> eliminateEqualities(const std::vector<Node>& assertions); + /** + * Can be called after eliminateEqualities(). Returns the substitutions that + * were found and eliminated. + */ + const SubstitutionMap& getSubstitutions() const { return *d_substitutions; } + /** + * Can be called after eliminateEqualities(). Checks whether a direct conflict + * was found, that is an assertion simplified to false during + * eliminateEqualities(). + */ + bool hasConflict() const { return !d_conflict.empty(); } + /** + * Return the conflict found in eliminateEqualities() as a set of assertions + * that is a subset of the input assertions provided to eliminateEqualities(). + */ + const std::vector<Node>& getConflict() const { return d_conflict; } + /** + * Postprocess a conflict found in the result of eliminateEqualities. + * Replaces assertions within the conflict by their origins, i.e. the input + * assertions and the assertions that gave rise to the substitutions being + * used. + */ + void postprocessConflict(std::vector<Node>& conflict) const; + + private: + /** Utility method for addToConflictMap. Checks for n in d_conflictMap */ + void insertOrigins(std::set<Node>& dest, const Node& n) const; + /** Add n -> { orig, *tracker } to the conflict map. The tracked nodes are + * first resolved using d_trackOrigin, and everything is run through + * insertOrigins to make sure that all origins are input assertions. */ + void addToConflictMap(const Node& n, + const Node& orig, + const std::set<TNode>& tracker); + + // The SubstitutionMap + std::unique_ptr<SubstitutionMap> d_substitutions; + // conflicting assertions, if a conflict was found + std::vector<Node> d_conflict; + // Maps a simplified assertion to the original assertion + set of original + // assertions used for substitutions + std::map<Node, std::vector<Node>> d_conflictMap; + // Maps substituted terms (what will end up in the tracker) to the equality + // from which the substitution was derived. + std::map<Node, Node> d_trackOrigin; +}; + +} // namespace nl +} // namespace arith +} // namespace theory +} // namespace cvc5 + +#endif /* CVC5__THEORY__ARITH__NL__EQUALITY_SUBSTITUTION_H */ diff --git a/src/theory/arith/nl/ext/factoring_check.cpp b/src/theory/arith/nl/ext/factoring_check.cpp index 06d6aeaab..32b630fa8 100644 --- a/src/theory/arith/nl/ext/factoring_check.cpp +++ b/src/theory/arith/nl/ext/factoring_check.cpp @@ -35,7 +35,6 @@ namespace nl { FactoringCheck::FactoringCheck(Env& env, ExtState* data) : EnvObj(env), d_data(data) { - d_zero = NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(0)); d_one = NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(1)); } @@ -155,7 +154,8 @@ void FactoringCheck::check(const std::vector<Node>& asserts, poly.size() == 1 ? poly[0] : nm->mkNode(Kind::PLUS, poly); Trace("nl-ext-factor") << "...factored polynomial : " << polyn << std::endl; - Node conc_lit = nm->mkNode(atom.getKind(), polyn, d_zero); + Node zero = nm->mkConstRealOrInt(polyn.getType(), Rational(0)); + Node conc_lit = nm->mkNode(atom.getKind(), polyn, zero); conc_lit = rewrite(conc_lit); if (!polarity) { diff --git a/src/theory/arith/nl/ext/monomial.cpp b/src/theory/arith/nl/ext/monomial.cpp index 83d0ff71f..47beb6959 100644 --- a/src/theory/arith/nl/ext/monomial.cpp +++ b/src/theory/arith/nl/ext/monomial.cpp @@ -326,7 +326,6 @@ Node MonomialDb::mkMonomialRemFactor(Node n, children.insert(children.end(), inc, v); } Node ret = safeConstructNary(MULT, children); - ret = Rewriter::rewrite(ret); Trace("nl-ext-mono-factor") << "...return : " << ret << std::endl; return ret; } diff --git a/src/theory/arith/nl/iand_solver.cpp b/src/theory/arith/nl/iand_solver.cpp index 5d4862307..c661dab4b 100644 --- a/src/theory/arith/nl/iand_solver.cpp +++ b/src/theory/arith/nl/iand_solver.cpp @@ -47,9 +47,9 @@ IAndSolver::IAndSolver(Env& env, NodeManager* nm = NodeManager::currentNM(); d_false = nm->mkConst(false); d_true = nm->mkConst(true); - d_zero = nm->mkConst(CONST_RATIONAL, Rational(0)); - d_one = nm->mkConst(CONST_RATIONAL, Rational(1)); - d_two = nm->mkConst(CONST_RATIONAL, Rational(2)); + d_zero = nm->mkConstInt(Rational(0)); + d_one = nm->mkConstInt(Rational(1)); + d_two = nm->mkConstInt(Rational(2)); } IAndSolver::~IAndSolver() {} @@ -100,7 +100,7 @@ void IAndSolver::checkInitialRefine() // conj.push_back(i.eqNode(nm->mkNode(IAND, op, i[1], i[0]))); // 0 <= iand(x,y) < 2^k conj.push_back(nm->mkNode(LEQ, d_zero, i)); - conj.push_back(nm->mkNode(LT, i, d_iandUtils.twoToK(k))); + conj.push_back(nm->mkNode(LT, i, rewrite(d_iandUtils.twoToK(k)))); // iand(x,y)<=x conj.push_back(nm->mkNode(LEQ, i, i[0])); // iand(x,y)<=y @@ -280,8 +280,8 @@ Node IAndSolver::bitwiseLemma(Node i) // compare each bit to bvI Node cond; Node bitIAnd; - unsigned high_bit; - for (unsigned j = 0; j < bvsize; j += granularity) + uint64_t high_bit; + for (uint64_t j = 0; j < bvsize; j += granularity) { high_bit = j + granularity - 1; // don't let high_bit pass bvsize @@ -296,7 +296,9 @@ Node IAndSolver::bitwiseLemma(Node i) bitIAnd = d_iandUtils.createBitwiseIAndNode(x, y, high_bit, j); // enforce bitwise equality lem = nm->mkNode( - AND, lem, d_iandUtils.iextract(high_bit, j, i).eqNode(bitIAnd)); + AND, + lem, + rewrite(d_iandUtils.iextract(high_bit, j, i)).eqNode(bitIAnd)); } } return lem; diff --git a/src/theory/arith/nl/iand_solver.h b/src/theory/arith/nl/iand_solver.h index 0b6a1fac6..997112fee 100644 --- a/src/theory/arith/nl/iand_solver.h +++ b/src/theory/arith/nl/iand_solver.h @@ -103,7 +103,7 @@ class IAndSolver : protected EnvObj /** * convert integer value to bitvector value of bitwidth k, - * equivalent to Rewriter::rewrite( ((_ intToBv k) n) ). + * equivalent to rewrite( ((_ intToBv k) n) ). */ Node convertToBvK(unsigned k, Node n) const; /** make iand */ @@ -115,7 +115,7 @@ class IAndSolver : protected EnvObj /** * Value-based refinement lemma for i of the form ((_ iand k) x y). Returns: * x = M(x) ^ y = M(y) => - * ((_ iand k) x y) = Rewriter::rewrite(((_ iand k) M(x) M(y))) + * ((_ iand k) x y) = rewrite(((_ iand k) M(x) M(y))) */ Node valueBasedLemma(Node i); /** diff --git a/src/theory/arith/nl/iand_utils.cpp b/src/theory/arith/nl/iand_utils.cpp index 50e03bfa5..700eb6de9 100644 --- a/src/theory/arith/nl/iand_utils.cpp +++ b/src/theory/arith/nl/iand_utils.cpp @@ -38,7 +38,7 @@ Node pow2(uint64_t k) { Assert(k >= 0); NodeManager* nm = NodeManager::currentNM(); - return nm->mkConst(CONST_RATIONAL, Rational(intpow2(k))); + return nm->mkConstInt(Rational(intpow2(k))); } bool oneBitAnd(bool a, bool b) { return (a && b); } @@ -60,9 +60,9 @@ Node intExtract(Node x, uint64_t i, uint64_t size) IAndUtils::IAndUtils() { NodeManager* nm = NodeManager::currentNM(); - d_zero = nm->mkConst(CONST_RATIONAL, Rational(0)); - d_one = nm->mkConst(CONST_RATIONAL, Rational(1)); - d_two = nm->mkConst(CONST_RATIONAL, Rational(2)); + d_zero = nm->mkConstInt(Rational(0)); + d_one = nm->mkConstInt(Rational(1)); + d_two = nm->mkConstInt(Rational(2)); } Node IAndUtils::createITEFromTable( @@ -80,8 +80,7 @@ Node IAndUtils::createITEFromTable( Assert(table.size() == 1 + ((uint64_t)(num_of_values * num_of_values))); // start with the default, most common value. // this value is represented in the table by (-1, -1). - Node ite = - nm->mkConst(CONST_RATIONAL, Rational(table.at(std::make_pair(-1, -1)))); + Node ite = nm->mkConstInt(Rational(table.at(std::make_pair(-1, -1)))); for (uint64_t i = 0; i < num_of_values; i++) { for (uint64_t j = 0; j < num_of_values; j++) @@ -94,13 +93,10 @@ Node IAndUtils::createITEFromTable( // append the current value to the ite. ite = nm->mkNode( kind::ITE, - nm->mkNode( - kind::AND, - nm->mkNode( - kind::EQUAL, x, nm->mkConst(CONST_RATIONAL, Rational(i))), - nm->mkNode( - kind::EQUAL, y, nm->mkConst(CONST_RATIONAL, Rational(j)))), - nm->mkConst(CONST_RATIONAL, Rational(table.at(std::make_pair(i, j)))), + nm->mkNode(kind::AND, + nm->mkNode(kind::EQUAL, x, nm->mkConstInt(Rational(i))), + nm->mkNode(kind::EQUAL, y, nm->mkConstInt(Rational(j)))), + nm->mkConstInt(Rational(table.at(std::make_pair(i, j)))), ite); } } @@ -139,7 +135,7 @@ Node IAndUtils::createSumNode(Node x, // number of elements in the sum expression uint64_t sumSize = bvsize / granularity; // initialize the sum - Node sumNode = nm->mkConst(CONST_RATIONAL, Rational(0)); + Node sumNode = nm->mkConstInt(Rational(0)); // compute the table for the current granularity if needed if (d_bvandTable.find(granularity) == d_bvandTable.end()) { @@ -186,9 +182,7 @@ Node IAndUtils::iextract(unsigned i, unsigned j, Node n) const NodeManager* nm = NodeManager::currentNM(); // ((_ extract i j) n) is n / 2^j mod 2^{i-j+1} Node n2j = nm->mkNode(kind::INTS_DIVISION_TOTAL, n, twoToK(j)); - Node ret = nm->mkNode(kind::INTS_MODULUS_TOTAL, n2j, twoToK(i - j + 1)); - ret = Rewriter::rewrite(ret); - return ret; + return nm->mkNode(kind::INTS_MODULUS_TOTAL, n2j, twoToK(i - j + 1)); } void IAndUtils::computeAndTable(uint64_t granularity) @@ -266,19 +260,14 @@ Node IAndUtils::twoToK(unsigned k) const { // could be faster NodeManager* nm = NodeManager::currentNM(); - Node ret = - nm->mkNode(kind::POW, d_two, nm->mkConst(CONST_RATIONAL, Rational(k))); - ret = Rewriter::rewrite(ret); - return ret; + return nm->mkNode(kind::POW, d_two, nm->mkConstInt(Rational(k))); } Node IAndUtils::twoToKMinusOne(unsigned k) const { // could be faster NodeManager* nm = NodeManager::currentNM(); - Node ret = nm->mkNode(kind::MINUS, twoToK(k), d_one); - ret = Rewriter::rewrite(ret); - return ret; + return nm->mkNode(kind::MINUS, twoToK(k), d_one); } } // namespace nl diff --git a/src/theory/arith/nl/icp/icp_solver.cpp b/src/theory/arith/nl/icp/icp_solver.cpp index 92c7d3ddd..aab63325e 100644 --- a/src/theory/arith/nl/icp/icp_solver.cpp +++ b/src/theory/arith/nl/icp/icp_solver.cpp @@ -66,7 +66,7 @@ inline std::ostream& operator<<(std::ostream& os, const IAWrapper& iaw) } // namespace ICPSolver::ICPSolver(Env& env, InferenceManager& im) - : EnvObj(env), d_im(im), d_state(d_mapper) + : EnvObj(env), d_im(im), d_state(env, d_mapper) { } diff --git a/src/theory/arith/nl/icp/icp_solver.h b/src/theory/arith/nl/icp/icp_solver.h index 8b0fbf583..b849255cc 100644 --- a/src/theory/arith/nl/icp/icp_solver.h +++ b/src/theory/arith/nl/icp/icp_solver.h @@ -86,12 +86,12 @@ class ICPSolver : protected EnvObj std::vector<Node> d_conflict; /** Initialized the variable bounds with a variable mapper */ - ICPState(VariableMapper& vm) {} + ICPState(Env& env, VariableMapper& vm) : d_bounds(env) {} /** Reset this state */ void reset() { - d_bounds = BoundInference(); + d_bounds.reset(); d_candidates.clear(); d_assignment.clear(); d_origins = ContractionOriginManager(); diff --git a/src/theory/arith/nl/nl_model.cpp b/src/theory/arith/nl/nl_model.cpp index d23ddd53d..90138bf3e 100644 --- a/src/theory/arith/nl/nl_model.cpp +++ b/src/theory/arith/nl/nl_model.cpp @@ -32,7 +32,7 @@ namespace theory { namespace arith { namespace nl { -NlModel::NlModel() : d_used_approx(false) +NlModel::NlModel(Env& env) : EnvObj(env), d_used_approx(false) { d_true = NodeManager::currentNM()->mkConst(true); d_false = NodeManager::currentNM()->mkConst(false); @@ -122,7 +122,7 @@ Node NlModel::computeModelValue(TNode n, bool isConcrete) children.emplace_back(computeModelValue(n[i], isConcrete)); } ret = NodeManager::currentNM()->mkNode(n.getKind(), children); - ret = Rewriter::rewrite(ret); + ret = rewrite(ret); } } Trace("nl-ext-mv-debug") << "computed " << (isConcrete ? "M" : "M_A") << "[" @@ -246,7 +246,7 @@ bool NlModel::checkModel(const std::vector<Node>& assertions, // apply the substitution to a if (!d_substitutions.empty()) { - av = Rewriter::rewrite(arithSubstitute(av, d_substitutions)); + av = rewrite(arithSubstitute(av, d_substitutions)); } // simple check literal if (!simpleCheckModelLit(av)) @@ -307,7 +307,7 @@ bool NlModel::addSubstitution(TNode v, TNode s) Node ms = arithSubstitute(sub, tmp); if (ms != sub) { - sub = Rewriter::rewrite(ms); + sub = rewrite(ms); } } d_substitutions.add(v, s); @@ -376,7 +376,7 @@ bool NlModel::solveEqualitySimple(Node eq, if (!d_substitutions.empty()) { seq = arithSubstitute(eq, d_substitutions); - seq = Rewriter::rewrite(seq); + seq = rewrite(seq); if (seq.isConst()) { if (seq.getConst<bool>()) @@ -580,7 +580,7 @@ bool NlModel::simpleCheckModelLit(Node lit) { lit2 = lit2.negate(); } - lit2 = Rewriter::rewrite(lit2); + lit2 = rewrite(lit2); bool success = simpleCheckModelLit(lit2); if (success != pol) { @@ -669,7 +669,7 @@ bool NlModel::simpleCheckModelLit(Node lit) b = it->second; t = nm->mkNode(PLUS, t, nm->mkNode(MULT, b, v)); } - t = Rewriter::rewrite(t); + t = rewrite(t); Trace("nl-ext-cms-debug") << "Trying to find min/max for quadratic " << t << "..." << std::endl; Trace("nl-ext-cms-debug") << " a = " << a << std::endl; @@ -677,7 +677,7 @@ bool NlModel::simpleCheckModelLit(Node lit) // find maximal/minimal value on the interval Node apex = nm->mkNode( DIVISION, nm->mkNode(UMINUS, b), nm->mkNode(MULT, d_two, a)); - apex = Rewriter::rewrite(apex); + apex = rewrite(apex); Assert(apex.isConst()); // for lower, upper, whether we are greater than the apex bool cmp[2]; @@ -686,7 +686,7 @@ bool NlModel::simpleCheckModelLit(Node lit) { boundn[r] = r == 0 ? bit->second.first : bit->second.second; Node cmpn = nm->mkNode(GT, boundn[r], apex); - cmpn = Rewriter::rewrite(cmpn); + cmpn = rewrite(cmpn); Assert(cmpn.isConst()); cmp[r] = cmpn.getConst<bool>(); } @@ -717,12 +717,12 @@ bool NlModel::simpleCheckModelLit(Node lit) { qsub.d_subs.back() = boundn[r]; Node ts = arithSubstitute(t, qsub); - tcmpn[r] = Rewriter::rewrite(ts); + tcmpn[r] = rewrite(ts); } Node tcmp = nm->mkNode(LT, tcmpn[0], tcmpn[1]); Trace("nl-ext-cms-debug") << " ...both sides of apex, compare " << tcmp << std::endl; - tcmp = Rewriter::rewrite(tcmp); + tcmp = rewrite(tcmp); Assert(tcmp.isConst()); unsigned bindex_use = (tcmp.getConst<bool>() == pol) ? 1 : 0; Trace("nl-ext-cms-debug") @@ -756,7 +756,7 @@ bool NlModel::simpleCheckModelLit(Node lit) if (!qsub.empty()) { Node slit = arithSubstitute(lit, qsub); - slit = Rewriter::rewrite(slit); + slit = rewrite(slit); return simpleCheckModelLit(slit); } return false; @@ -1003,7 +1003,7 @@ bool NlModel::simpleCheckModelMsum(const std::map<Node, Node>& msum, bool pol) comp = comp.negate(); } Trace("nl-ext-cms") << " comparison is : " << comp << std::endl; - comp = Rewriter::rewrite(comp); + comp = rewrite(comp); Assert(comp.isConst()); Trace("nl-ext-cms") << " returned : " << comp << std::endl; return comp == d_true; @@ -1073,7 +1073,7 @@ void NlModel::getModelValueRepair( witness = nm->mkNode(MULT, nm->mkConst(CONST_RATIONAL, Rational(1, 2)), nm->mkNode(PLUS, l, u)); - witness = Rewriter::rewrite(witness); + witness = rewrite(witness); Trace("nl-model") << v << " witness is " << witness << std::endl; } approximations[v] = std::pair<Node, Node>(pred, witness); diff --git a/src/theory/arith/nl/nl_model.h b/src/theory/arith/nl/nl_model.h index 7dcd89a4a..e195aa9b2 100644 --- a/src/theory/arith/nl/nl_model.h +++ b/src/theory/arith/nl/nl_model.h @@ -23,6 +23,7 @@ #include "expr/kind.h" #include "expr/node.h" #include "expr/subs.h" +#include "smt/env_obj.h" namespace cvc5 { @@ -48,12 +49,12 @@ class NonlinearExtension; * model in the case it can determine that a model exists. These include * techniques based on solving (quadratic) equations and bound analysis. */ -class NlModel +class NlModel : protected EnvObj { friend class NonlinearExtension; public: - NlModel(); + NlModel(Env& env); ~NlModel(); /** * This method is called once at the beginning of a last call effort check, diff --git a/src/theory/arith/nl/nonlinear_extension.cpp b/src/theory/arith/nl/nonlinear_extension.cpp index e75741096..3f60f8596 100644 --- a/src/theory/arith/nl/nonlinear_extension.cpp +++ b/src/theory/arith/nl/nonlinear_extension.cpp @@ -48,7 +48,7 @@ NonlinearExtension::NonlinearExtension(Env& env, d_checkCounter(0), d_extTheoryCb(state.getEqualityEngine()), d_extTheory(env, d_extTheoryCb, d_im), - d_model(), + d_model(env), d_trSlv(d_env, d_im, d_model), d_extState(d_im, d_model, d_env), d_factoringSlv(d_env, &d_extState), @@ -122,7 +122,7 @@ void NonlinearExtension::getAssertions(std::vector<Node>& assertions) } Valuation v = d_containing.getValuation(); - BoundInference bounds; + BoundInference bounds(d_env); std::unordered_set<Node> init_assertions; @@ -353,45 +353,6 @@ Result::Sat NonlinearExtension::modelBasedRefinement(const std::set<Node>& termS } // compute whether shared terms have correct values - unsigned num_shared_wrong_value = 0; - std::vector<Node> shared_term_value_splits; - // must ensure that shared terms are equal to their concrete value - Trace("nl-ext-mv") << "Shared terms : " << std::endl; - for (context::CDList<TNode>::const_iterator its = - d_containing.shared_terms_begin(); - its != d_containing.shared_terms_end(); - ++its) - { - TNode shared_term = *its; - // compute its value in the model, and its evaluation in the model - Node stv0 = d_model.computeConcreteModelValue(shared_term); - Node stv1 = d_model.computeAbstractModelValue(shared_term); - d_model.printModelValue("nl-ext-mv", shared_term); - if (stv0 != stv1) - { - num_shared_wrong_value++; - Trace("nl-ext-mv") << "Bad shared term value : " << shared_term - << std::endl; - if (shared_term != stv0) - { - // split on the value, this is non-terminating in general, TODO : - // improve this - Node eq = shared_term.eqNode(stv0); - shared_term_value_splits.push_back(eq); - } - else - { - // this can happen for transcendental functions - // the problem is that we cannot evaluate transcendental functions - // (they don't have a rewriter that returns constants) - // thus, the actual value in their model can be themselves, hence we - // have no reference point to rule out the current model. In this - // case, we may set incomplete below. - } - } - } - Trace("nl-ext-debug") << " " << num_shared_wrong_value - << " shared terms with wrong model value." << std::endl; bool needsRecheck; do { @@ -402,9 +363,9 @@ Result::Sat NonlinearExtension::modelBasedRefinement(const std::set<Node>& termS int complete_status = 1; // We require a check either if an assertion is false or a shared term has // a wrong value - if (!false_asserts.empty() || num_shared_wrong_value > 0) + if (!false_asserts.empty()) { - complete_status = num_shared_wrong_value > 0 ? -1 : 0; + complete_status = 0; runStrategy(Theory::Effort::EFFORT_FULL, assertions, false_asserts, xts); if (d_im.hasSentLemma() || d_im.hasPendingLemma()) { @@ -446,40 +407,6 @@ Result::Sat NonlinearExtension::modelBasedRefinement(const std::set<Node>& termS << std::endl; return Result::Sat::UNSAT; } - // resort to splitting on shared terms with their model value - // if we did not add any lemmas - if (num_shared_wrong_value > 0) - { - complete_status = -1; - if (!shared_term_value_splits.empty()) - { - for (const Node& eq : shared_term_value_splits) - { - Node req = rewrite(eq); - Node literal = d_containing.getValuation().ensureLiteral(req); - d_containing.getOutputChannel().requirePhase(literal, true); - Trace("nl-ext-debug") << "Split on : " << literal << std::endl; - Node split = literal.orNode(literal.negate()); - d_im.addPendingLemma(split, - InferenceId::ARITH_NL_SHARED_TERM_VALUE_SPLIT, - nullptr, - true); - } - if (d_im.hasWaitingLemma()) - { - d_im.flushWaitingLemmas(); - Trace("nl-ext") << "...added " << d_im.numPendingLemmas() - << " shared term value split lemmas." << std::endl; - return Result::Sat::UNSAT; - } - } - else - { - // this can happen if we are trying to do theory combination with - // trancendental functions - // since their model value cannot even be computed exactly - } - } // we are incomplete if (options().arith.nlExt == options::NlExtMode::FULL diff --git a/src/theory/arith/nl/pow2_solver.cpp b/src/theory/arith/nl/pow2_solver.cpp index e3a26397e..59bf89151 100644 --- a/src/theory/arith/nl/pow2_solver.cpp +++ b/src/theory/arith/nl/pow2_solver.cpp @@ -42,9 +42,9 @@ Pow2Solver::Pow2Solver(Env& env, NodeManager* nm = NodeManager::currentNM(); d_false = nm->mkConst(false); d_true = nm->mkConst(true); - d_zero = nm->mkConst(CONST_RATIONAL, Rational(0)); - d_one = nm->mkConst(CONST_RATIONAL, Rational(1)); - d_two = nm->mkConst(CONST_RATIONAL, Rational(2)); + d_zero = nm->mkConstInt(Rational(0)); + d_one = nm->mkConstInt(Rational(1)); + d_two = nm->mkConstInt(Rational(2)); } Pow2Solver::~Pow2Solver() {} @@ -190,8 +190,7 @@ Node Pow2Solver::valueBasedLemma(Node i) Node valC = nm->mkNode(POW2, valX); valC = rewrite(valC); - Node lem = nm->mkNode(IMPLIES, x.eqNode(valX), i.eqNode(valC)); - return lem; + return nm->mkNode(IMPLIES, x.eqNode(valX), i.eqNode(valC)); } } // namespace nl diff --git a/src/theory/arith/nl/pow2_solver.h b/src/theory/arith/nl/pow2_solver.h index b4e12616c..42586f206 100644 --- a/src/theory/arith/nl/pow2_solver.h +++ b/src/theory/arith/nl/pow2_solver.h @@ -100,7 +100,7 @@ class Pow2Solver : protected EnvObj /** * Value-based refinement lemma for i of the form (pow2 x). Returns: * x = M(x) /\ x>= 0 ----> - * (pow2 x) = Rewriter::rewrite((pow2 M(x))) + * (pow2 x) = rewrite((pow2 M(x))) */ Node valueBasedLemma(Node i); }; /* class Pow2Solver */ diff --git a/src/theory/arith/nl/strategy.cpp b/src/theory/arith/nl/strategy.cpp index b33e45129..a14841f67 100644 --- a/src/theory/arith/nl/strategy.cpp +++ b/src/theory/arith/nl/strategy.cpp @@ -172,10 +172,7 @@ void Strategy::initializeStrategy(const Options& options) one << InferStep::POW2_FULL << InferStep::BREAK; if (options.arith.nlCad) { - one << InferStep::CAD_INIT; - } - if (options.arith.nlCad) - { + one << InferStep::CAD_INIT << InferStep::BREAK; one << InferStep::CAD_FULL << InferStep::BREAK; } diff --git a/src/theory/arith/nl/transcendental/exponential_solver.cpp b/src/theory/arith/nl/transcendental/exponential_solver.cpp index c4f7f6ca9..77e5f9f3f 100644 --- a/src/theory/arith/nl/transcendental/exponential_solver.cpp +++ b/src/theory/arith/nl/transcendental/exponential_solver.cpp @@ -230,7 +230,7 @@ void ExponentialSolver::doTangentLemma(TNode e, proof->addStep(lem, PfRule::ARITH_TRANS_EXP_APPROX_BELOW, {}, - {nm->mkConst(CONST_RATIONAL, Rational(d)), e[0]}); + {nm->mkConstInt(Rational(d)), e[0]}); } d_data->d_im.addPendingLemma( lem, InferenceId::ARITH_NL_T_TANGENT, proof, true); diff --git a/src/theory/arith/nl/transcendental/proof_checker.cpp b/src/theory/arith/nl/transcendental/proof_checker.cpp index ca1afb9f6..3bf1ace98 100644 --- a/src/theory/arith/nl/transcendental/proof_checker.cpp +++ b/src/theory/arith/nl/transcendental/proof_checker.cpp @@ -18,7 +18,7 @@ #include "expr/sequence.h" #include "theory/arith/arith_utilities.h" #include "theory/arith/nl/transcendental/taylor_generator.h" -#include "theory/rewriter.h" +#include "theory/evaluator.h" using namespace cvc5::kind; @@ -42,18 +42,18 @@ Node mkBounds(TNode t, TNode lb, TNode ub) /** * Helper method to construct a secant plane: - * ((evall - evalu) / (l - u)) * (t - l) + evall + * evall + ((evall - evalu) / (l - u)) * (t - l) */ Node mkSecant(TNode t, TNode l, TNode u, TNode evall, TNode evalu) { NodeManager* nm = NodeManager::currentNM(); return nm->mkNode(Kind::PLUS, + evall, nm->mkNode(Kind::MULT, nm->mkNode(Kind::DIVISION, nm->mkNode(Kind::MINUS, evall, evalu), nm->mkNode(Kind::MINUS, l, u)), - nm->mkNode(Kind::MINUS, t, l)), - evall); + nm->mkNode(Kind::MINUS, t, l))); } } // namespace @@ -83,11 +83,11 @@ Node TranscendentalProofRuleChecker::checkInternal( PfRule id, const std::vector<Node>& children, const std::vector<Node>& args) { NodeManager* nm = NodeManager::currentNM(); - auto zero = nm->mkConst<Rational>(CONST_RATIONAL, 0); - auto one = nm->mkConst<Rational>(CONST_RATIONAL, 1); - auto mone = nm->mkConst<Rational>(CONST_RATIONAL, -1); - auto pi = nm->mkNullaryOperator(nm->realType(), Kind::PI); - auto mpi = nm->mkNode(Kind::MULT, mone, pi); + Node zero = nm->mkConstReal(Rational(0)); + Node one = nm->mkConstReal(Rational(1)); + Node mone = nm->mkConstReal(Rational(-1)); + Node pi = nm->mkNullaryOperator(nm->realType(), Kind::PI); + Node mpi = nm->mkNode(Kind::MULT, mone, pi); Trace("nl-trans-checker") << "Checking " << id << std::endl; Trace("nl-trans-checker") << "Children:" << std::endl; for (const auto& c : children) @@ -141,11 +141,10 @@ Node TranscendentalProofRuleChecker::checkInternal( { Assert(children.empty()); Assert(args.size() == 4); - Assert(args[0].isConst() && args[0].getKind() == Kind::CONST_RATIONAL - && args[0].getConst<Rational>().isIntegral()); + Assert(args[0].isConst() && args[0].getType().isInteger()); Assert(args[1].getType().isReal()); - Assert(args[2].isConst() && args[2].getKind() == Kind::CONST_RATIONAL); - Assert(args[3].isConst() && args[3].getKind() == Kind::CONST_RATIONAL); + Assert(args[2].isConst() && args[2].getType().isRealOrInt()); + Assert(args[3].isConst() && args[3].getType().isRealOrInt()); std::uint64_t d = args[0].getConst<Rational>().getNumerator().toUnsignedInt(); Node t = args[1]; @@ -154,26 +153,24 @@ Node TranscendentalProofRuleChecker::checkInternal( TaylorGenerator tg; TaylorGenerator::ApproximationBounds bounds; tg.getPolynomialApproximationBounds(Kind::EXPONENTIAL, d / 2, bounds); - Node evall = Rewriter::rewrite( - bounds.d_upperPos.substitute(tg.getTaylorVariable(), l)); - Node evalu = Rewriter::rewrite( - bounds.d_upperPos.substitute(tg.getTaylorVariable(), u)); + Evaluator eval(nullptr); + Node evall = eval.eval(bounds.d_upperPos, {tg.getTaylorVariable()}, {l}); + Node evalu = eval.eval(bounds.d_upperPos, {tg.getTaylorVariable()}, {u}); Node evalsecant = mkSecant(t, l, u, evall, evalu); Node lem = nm->mkNode( Kind::IMPLIES, mkBounds(t, l, u), nm->mkNode(Kind::LEQ, nm->mkNode(Kind::EXPONENTIAL, t), evalsecant)); - return Rewriter::rewrite(lem); + return lem; } else if (id == PfRule::ARITH_TRANS_EXP_APPROX_ABOVE_NEG) { Assert(children.empty()); Assert(args.size() == 4); - Assert(args[0].isConst() && args[0].getKind() == Kind::CONST_RATIONAL - && args[0].getConst<Rational>().isIntegral()); + Assert(args[0].isConst() && args[0].getType().isInteger()); Assert(args[1].getType().isReal()); - Assert(args[2].isConst() && args[2].getKind() == Kind::CONST_RATIONAL); - Assert(args[3].isConst() && args[3].getKind() == Kind::CONST_RATIONAL); + Assert(args[2].isConst() && args[2].getType().isRealOrInt()); + Assert(args[3].isConst() && args[3].getType().isRealOrInt()); std::uint64_t d = args[0].getConst<Rational>().getNumerator().toUnsignedInt(); Node t = args[1]; @@ -182,23 +179,21 @@ Node TranscendentalProofRuleChecker::checkInternal( TaylorGenerator tg; TaylorGenerator::ApproximationBounds bounds; tg.getPolynomialApproximationBounds(Kind::EXPONENTIAL, d / 2, bounds); - Node evall = Rewriter::rewrite( - bounds.d_upperNeg.substitute(tg.getTaylorVariable(), l)); - Node evalu = Rewriter::rewrite( - bounds.d_upperNeg.substitute(tg.getTaylorVariable(), u)); + Evaluator eval(nullptr); + Node evall = eval.eval(bounds.d_upperNeg, {tg.getTaylorVariable()}, {l}); + Node evalu = eval.eval(bounds.d_upperNeg, {tg.getTaylorVariable()}, {u}); Node evalsecant = mkSecant(t, l, u, evall, evalu); Node lem = nm->mkNode( Kind::IMPLIES, mkBounds(t, l, u), nm->mkNode(Kind::LEQ, nm->mkNode(Kind::EXPONENTIAL, t), evalsecant)); - return Rewriter::rewrite(lem); + return lem; } else if (id == PfRule::ARITH_TRANS_EXP_APPROX_BELOW) { Assert(children.empty()); Assert(args.size() == 2); - Assert(args[0].isConst() && args[0].getKind() == Kind::CONST_RATIONAL - && args[0].getConst<Rational>().isIntegral()); + Assert(args[0].isConst() && args[0].getType().isInteger()); Assert(args[1].getType().isReal()); std::uint64_t d = args[0].getConst<Rational>().getNumerator().toUnsignedInt(); @@ -206,10 +201,10 @@ Node TranscendentalProofRuleChecker::checkInternal( TaylorGenerator tg; TaylorGenerator::ApproximationBounds bounds; tg.getPolynomialApproximationBounds(Kind::EXPONENTIAL, d, bounds); - Node eval = - Rewriter::rewrite(bounds.d_lower.substitute(tg.getTaylorVariable(), t)); + Evaluator eval(nullptr); + Node evalt = eval.eval(bounds.d_lower, {tg.getTaylorVariable()}, {t}); return nm->mkNode( - Kind::GEQ, std::vector<Node>{nm->mkNode(Kind::EXPONENTIAL, t), eval}); + Kind::GEQ, std::vector<Node>{nm->mkNode(Kind::EXPONENTIAL, t), evalt}); } else if (id == PfRule::ARITH_TRANS_SINE_BOUNDS) { @@ -240,10 +235,7 @@ Node TranscendentalProofRuleChecker::checkInternal( x.eqNode( nm->mkNode(Kind::PLUS, y, - nm->mkNode(Kind::MULT, - nm->mkConst<Rational>(CONST_RATIONAL, 2), - s, - pi)))), + nm->mkNode(Kind::MULT, nm->mkConstReal(2), s, pi)))), nm->mkNode(Kind::SINE, y).eqNode(nm->mkNode(Kind::SINE, x))}); } else if (id == PfRule::ARITH_TRANS_SINE_SYMMETRY) @@ -252,8 +244,7 @@ Node TranscendentalProofRuleChecker::checkInternal( Assert(args.size() == 1); Assert(args[0].getType().isReal()); Node s1 = nm->mkNode(Kind::SINE, args[0]); - Node s2 = nm->mkNode( - Kind::SINE, Rewriter::rewrite(nm->mkNode(Kind::MULT, mone, args[0]))); + Node s2 = nm->mkNode(Kind::SINE, nm->mkNode(Kind::MULT, mone, args[0])); return nm->mkNode(PLUS, s1, s2).eqNode(zero); } else if (id == PfRule::ARITH_TRANS_SINE_TANGENT_ZERO) @@ -289,13 +280,12 @@ Node TranscendentalProofRuleChecker::checkInternal( { Assert(children.empty()); Assert(args.size() == 6); - Assert(args[0].isConst() && args[0].getKind() == Kind::CONST_RATIONAL - && args[0].getConst<Rational>().isIntegral()); + Assert(args[0].isConst() && args[0].getType().isInteger()); Assert(args[1].getType().isReal()); Assert(args[2].getType().isReal()); Assert(args[3].getType().isReal()); - Assert(args[4].isConst() && args[4].getKind() == Kind::CONST_RATIONAL); - Assert(args[5].isConst() && args[5].getKind() == Kind::CONST_RATIONAL); + Assert(args[4].isConst() && args[4].getType().isRealOrInt()); + Assert(args[5].isConst() && args[5].getType().isRealOrInt()); std::uint64_t d = args[0].getConst<Rational>().getNumerator().toUnsignedInt(); Node t = args[1]; @@ -306,23 +296,21 @@ Node TranscendentalProofRuleChecker::checkInternal( TaylorGenerator tg; TaylorGenerator::ApproximationBounds bounds; tg.getPolynomialApproximationBounds(Kind::SINE, d / 2, bounds); - Node evall = Rewriter::rewrite( - bounds.d_upperNeg.substitute(tg.getTaylorVariable(), l)); - Node evalu = Rewriter::rewrite( - bounds.d_upperNeg.substitute(tg.getTaylorVariable(), u)); + Evaluator eval(nullptr); + Node evall = eval.eval(bounds.d_upperNeg, {tg.getTaylorVariable()}, {l}); + Node evalu = eval.eval(bounds.d_upperNeg, {tg.getTaylorVariable()}, {u}); Node lem = nm->mkNode( Kind::IMPLIES, mkBounds(t, lb, ub), nm->mkNode( Kind::LEQ, nm->mkNode(Kind::SINE, t), mkSecant(t, lb, ub, l, u))); - return Rewriter::rewrite(lem); + return lem; } else if (id == PfRule::ARITH_TRANS_SINE_APPROX_ABOVE_POS) { Assert(children.empty()); Assert(args.size() == 5); - Assert(args[0].isConst() && args[0].getKind() == Kind::CONST_RATIONAL - && args[0].getConst<Rational>().isIntegral()); + Assert(args[0].isConst() && args[0].getType().isInteger()); Assert(args[1].getType().isReal()); Assert(args[2].getType().isReal()); Assert(args[3].getType().isReal()); @@ -335,24 +323,22 @@ Node TranscendentalProofRuleChecker::checkInternal( TaylorGenerator tg; TaylorGenerator::ApproximationBounds bounds; tg.getPolynomialApproximationBounds(Kind::SINE, d / 2, bounds); - Node eval = Rewriter::rewrite( - bounds.d_upperPos.substitute(tg.getTaylorVariable(), c)); - return Rewriter::rewrite( - nm->mkNode(Kind::IMPLIES, - mkBounds(t, lb, ub), - nm->mkNode(Kind::LEQ, nm->mkNode(Kind::SINE, t), eval))); + Evaluator eval(nullptr); + Node evalc = eval.eval(bounds.d_upperPos, {tg.getTaylorVariable()}, {c}); + return nm->mkNode(Kind::IMPLIES, + mkBounds(t, lb, ub), + nm->mkNode(Kind::LEQ, nm->mkNode(Kind::SINE, t), evalc)); } else if (id == PfRule::ARITH_TRANS_SINE_APPROX_BELOW_POS) { Assert(children.empty()); Assert(args.size() == 6); - Assert(args[0].isConst() && args[0].getKind() == Kind::CONST_RATIONAL - && args[0].getConst<Rational>().isIntegral()); + Assert(args[0].isConst() && args[0].getType().isInteger()); Assert(args[1].getType().isReal()); Assert(args[2].getType().isReal()); Assert(args[3].getType().isReal()); - Assert(args[4].isConst() && args[4].getKind() == Kind::CONST_RATIONAL); - Assert(args[5].isConst() && args[5].getKind() == Kind::CONST_RATIONAL); + Assert(args[4].isConst() && args[4].getType().isRealOrInt()); + Assert(args[5].isConst() && args[5].getType().isRealOrInt()); std::uint64_t d = args[0].getConst<Rational>().getNumerator().toUnsignedInt(); Node t = args[1]; @@ -363,23 +349,21 @@ Node TranscendentalProofRuleChecker::checkInternal( TaylorGenerator tg; TaylorGenerator::ApproximationBounds bounds; tg.getPolynomialApproximationBounds(Kind::SINE, d / 2, bounds); - Node evall = - Rewriter::rewrite(bounds.d_lower.substitute(tg.getTaylorVariable(), l)); - Node evalu = - Rewriter::rewrite(bounds.d_lower.substitute(tg.getTaylorVariable(), u)); + Evaluator eval(nullptr); + Node evall = eval.eval(bounds.d_lower, {tg.getTaylorVariable()}, {l}); + Node evalu = eval.eval(bounds.d_lower, {tg.getTaylorVariable()}, {u}); Node lem = nm->mkNode( Kind::IMPLIES, mkBounds(t, lb, ub), nm->mkNode( Kind::GEQ, nm->mkNode(Kind::SINE, t), mkSecant(t, lb, ub, l, u))); - return Rewriter::rewrite(lem); + return lem; } else if (id == PfRule::ARITH_TRANS_SINE_APPROX_BELOW_NEG) { Assert(children.empty()); Assert(args.size() == 5); - Assert(args[0].isConst() && args[0].getKind() == Kind::CONST_RATIONAL - && args[0].getConst<Rational>().isIntegral()); + Assert(args[0].isConst() && args[0].getType().isInteger()); Assert(args[1].getType().isReal()); Assert(args[2].getType().isReal()); Assert(args[3].getType().isReal()); @@ -392,12 +376,11 @@ Node TranscendentalProofRuleChecker::checkInternal( TaylorGenerator tg; TaylorGenerator::ApproximationBounds bounds; tg.getPolynomialApproximationBounds(Kind::SINE, d / 2, bounds); - Node eval = - Rewriter::rewrite(bounds.d_lower.substitute(tg.getTaylorVariable(), c)); - return Rewriter::rewrite( - nm->mkNode(Kind::IMPLIES, - mkBounds(t, lb, ub), - nm->mkNode(Kind::GEQ, nm->mkNode(Kind::SINE, t), eval))); + Evaluator eval(nullptr); + Node evalc = eval.eval(bounds.d_lower, {tg.getTaylorVariable()}, {c}); + return nm->mkNode(Kind::IMPLIES, + mkBounds(t, lb, ub), + nm->mkNode(Kind::GEQ, nm->mkNode(Kind::SINE, t), evalc)); } return Node::null(); } diff --git a/src/theory/arith/nl/transcendental/sine_solver.cpp b/src/theory/arith/nl/transcendental/sine_solver.cpp index b6b5c92c1..6c1bec647 100644 --- a/src/theory/arith/nl/transcendental/sine_solver.cpp +++ b/src/theory/arith/nl/transcendental/sine_solver.cpp @@ -75,13 +75,12 @@ void SineSolver::doPhaseShift(TNode a, TNode new_a, TNode y) nm->mkNode(Kind::ITE, mkValidPhase(a[0], d_data->d_pi), a[0].eqNode(y), - a[0].eqNode(nm->mkNode( - Kind::PLUS, - y, - nm->mkNode(Kind::MULT, - nm->mkConst(CONST_RATIONAL, Rational(2)), - shift, - d_data->d_pi)))), + a[0].eqNode(nm->mkNode(Kind::PLUS, + y, + nm->mkNode(Kind::MULT, + nm->mkConstReal(Rational(2)), + shift, + d_data->d_pi)))), new_a.eqNode(a)); CDProof* proof = nullptr; if (d_data->isProofEnabled()) @@ -143,7 +142,17 @@ void SineSolver::checkInitialRefine() if (d_data->isProofEnabled()) { proof = d_data->getProof(); - proof->addStep(lem, PfRule::ARITH_TRANS_SINE_SYMMETRY, {}, {t[0]}); + Node tmplem = + nm->mkNode(Kind::PLUS, + t, + nm->mkNode( + Kind::SINE, + nm->mkNode(Kind::MULT, d_data->d_neg_one, t[0]))) + .eqNode(d_data->d_zero); + proof->addStep( + tmplem, PfRule::ARITH_TRANS_SINE_SYMMETRY, {}, {t[0]}); + proof->addStep( + lem, PfRule::MACRO_SR_PRED_TRANSFORM, {tmplem}, {lem}); } d_data->d_im.addPendingLemma( lem, InferenceId::ARITH_NL_T_INIT_REFINE, proof); @@ -385,9 +394,6 @@ void SineSolver::doTangentLemma( e, poly_approx)); - Trace("nl-ext-sine") << "*** Tangent plane lemma (pre-rewrite): " << lem - << std::endl; - lem = rewrite(lem); Trace("nl-ext-sine") << "*** Tangent plane lemma : " << lem << std::endl; Assert(d_data->d_model.computeAbstractModelValue(lem) == d_data->d_false); // Figure 3 : line 9 @@ -402,7 +408,7 @@ void SineSolver::doTangentLemma( proof->addStep(lem, PfRule::ARITH_TRANS_SINE_APPROX_BELOW_NEG, {}, - {nm->mkConst(CONST_RATIONAL, Rational(2 * d)), + {nm->mkConstInt(Rational(2 * d)), e[0], c, regionToLowerBound(region), @@ -413,7 +419,7 @@ void SineSolver::doTangentLemma( proof->addStep(lem, PfRule::ARITH_TRANS_SINE_APPROX_BELOW_NEG, {}, - {nm->mkConst(CONST_RATIONAL, Rational(2 * d)), + {nm->mkConstInt(Rational(2 * d)), e[0], c, c, @@ -427,7 +433,7 @@ void SineSolver::doTangentLemma( proof->addStep(lem, PfRule::ARITH_TRANS_SINE_APPROX_ABOVE_POS, {}, - {nm->mkConst(CONST_RATIONAL, Rational(2 * d)), + {nm->mkConstInt(Rational(2 * d)), e[0], c, regionToLowerBound(region), @@ -438,7 +444,7 @@ void SineSolver::doTangentLemma( proof->addStep(lem, PfRule::ARITH_TRANS_SINE_APPROX_ABOVE_POS, {}, - {nm->mkConst(CONST_RATIONAL, Rational(2 * d)), + {nm->mkConstInt(Rational(2 * d)), e[0], c, c, diff --git a/src/theory/arith/nl/transcendental/taylor_generator.cpp b/src/theory/arith/nl/transcendental/taylor_generator.cpp index 2a231bc2b..c9e0015e2 100644 --- a/src/theory/arith/nl/transcendental/taylor_generator.cpp +++ b/src/theory/arith/nl/transcendental/taylor_generator.cpp @@ -17,6 +17,7 @@ #include "theory/arith/arith_utilities.h" #include "theory/arith/nl/nl_model.h" +#include "theory/evaluator.h" #include "theory/rewriter.h" using namespace cvc5::kind; @@ -28,8 +29,8 @@ namespace nl { namespace transcendental { TaylorGenerator::TaylorGenerator() - : d_nm(NodeManager::currentNM()), - d_taylor_real_fv(d_nm->mkBoundVar("x", d_nm->realType())) + : d_taylor_real_fv(NodeManager::currentNM()->mkBoundVar( + "x", NodeManager::currentNM()->realType())) { } @@ -50,7 +51,7 @@ std::pair<Node, Node> TaylorGenerator::getTaylor(Kind k, std::uint64_t n) // the current factorial `counter!` Integer factorial = 1; // the current variable power `x^counter` - Node varpow = nm->mkConst(CONST_RATIONAL, Rational(1)); + Node varpow = nm->mkConstReal(Rational(1)); std::vector<Node> sum; for (std::uint64_t counter = 1; counter <= n; ++counter) { @@ -59,9 +60,7 @@ std::pair<Node, Node> TaylorGenerator::getTaylor(Kind k, std::uint64_t n) // Maclaurin series for exponential: // \sum_{n=0}^\infty x^n / n! sum.push_back( - nm->mkNode(Kind::DIVISION, - varpow, - nm->mkConst<Rational>(CONST_RATIONAL, factorial))); + nm->mkNode(Kind::DIVISION, varpow, nm->mkConstReal(factorial))); } else if (k == Kind::SINE) { @@ -70,24 +69,19 @@ std::pair<Node, Node> TaylorGenerator::getTaylor(Kind k, std::uint64_t n) if (counter % 2 == 0) { int sign = (counter % 4 == 0 ? -1 : 1); - sum.push_back(nm->mkNode( - Kind::MULT, - nm->mkNode(Kind::DIVISION, - nm->mkConst<Rational>(CONST_RATIONAL, sign), - nm->mkConst<Rational>(CONST_RATIONAL, factorial)), - varpow)); + sum.push_back(nm->mkNode(Kind::MULT, + nm->mkNode(Kind::DIVISION, + nm->mkConstReal(sign), + nm->mkConstReal(factorial)), + varpow)); } } factorial *= counter; - varpow = - Rewriter::rewrite(nm->mkNode(Kind::MULT, d_taylor_real_fv, varpow)); + varpow = nm->mkNode(Kind::MULT, d_taylor_real_fv, varpow); } - Node taylor_sum = - Rewriter::rewrite(sum.size() == 1 ? sum[0] : nm->mkNode(Kind::PLUS, sum)); - Node taylor_rem = Rewriter::rewrite( - nm->mkNode(Kind::DIVISION, - varpow, - nm->mkConst<Rational>(CONST_RATIONAL, factorial))); + Node taylor_sum = (sum.size() == 1 ? sum[0] : nm->mkNode(Kind::PLUS, sum)); + Node taylor_rem = + nm->mkNode(Kind::DIVISION, varpow, nm->mkConstReal(factorial)); auto res = std::make_pair(taylor_sum, taylor_rem); @@ -118,19 +112,17 @@ void TaylorGenerator::getPolynomialApproximationBounds( if (k == Kind::EXPONENTIAL) { pbounds.d_lower = taylor_sum; - pbounds.d_upperNeg = - Rewriter::rewrite(nm->mkNode(Kind::PLUS, taylor_sum, ru)); - pbounds.d_upperPos = Rewriter::rewrite(nm->mkNode( - Kind::MULT, - taylor_sum, - nm->mkNode( - Kind::PLUS, nm->mkConst(CONST_RATIONAL, Rational(1)), ru))); + pbounds.d_upperNeg = nm->mkNode(Kind::PLUS, taylor_sum, ru); + pbounds.d_upperPos = + nm->mkNode(Kind::MULT, + taylor_sum, + nm->mkNode(Kind::PLUS, nm->mkConstReal(Rational(1)), ru)); } else { Assert(k == Kind::SINE); - Node l = Rewriter::rewrite(nm->mkNode(Kind::MINUS, taylor_sum, ru)); - Node u = Rewriter::rewrite(nm->mkNode(Kind::PLUS, taylor_sum, ru)); + Node l = nm->mkNode(Kind::MINUS, taylor_sum, ru); + Node u = nm->mkNode(Kind::PLUS, taylor_sum, ru); pbounds.d_lower = l; pbounds.d_upperNeg = u; pbounds.d_upperPos = u; @@ -160,6 +152,7 @@ std::uint64_t TaylorGenerator::getPolynomialApproximationBoundForArg( std::uint64_t ds = d; TNode ttrf = getTaylorVariable(); TNode tc = c; + Evaluator eval(nullptr); do { success = true; @@ -167,8 +160,7 @@ std::uint64_t TaylorGenerator::getPolynomialApproximationBoundForArg( std::pair<Node, Node> taylor = getTaylor(k, n); // check that 1-c^{n+1}/(n+1)! > 0 Node ru = taylor.second; - Node rus = ru.substitute(ttrf, tc); - rus = Rewriter::rewrite(rus); + Node rus = eval.eval(ru, {ttrf}, {tc}); Assert(rus.isConst()); if (rus.getConst<Rational>() > 1) { @@ -206,11 +198,11 @@ std::pair<Node, Node> TaylorGenerator::getTfModelBounds(Node tf, // at zero, its trivial if (k == Kind::SINE) { - Node zero = nm->mkConst(CONST_RATIONAL, Rational(0)); + Node zero = nm->mkConstReal(Rational(0)); return std::pair<Node, Node>(zero, zero); } Assert(k == Kind::EXPONENTIAL); - Node one = nm->mkConst(CONST_RATIONAL, Rational(1)); + Node one = nm->mkConstReal(Rational(1)); return std::pair<Node, Node>(one, one); } bool isNeg = csign == -1; @@ -221,6 +213,7 @@ std::pair<Node, Node> TaylorGenerator::getTfModelBounds(Node tf, std::vector<Node> bounds; TNode tfv = getTaylorVariable(); TNode tfs = tf[0]; + Evaluator eval(nullptr); for (unsigned d2 = 0; d2 < 2; d2++) { Node pab = (d2 == 0 ? pbounds.d_lower @@ -235,8 +228,7 @@ std::pair<Node, Node> TaylorGenerator::getTfModelBounds(Node tf, // M_A( x*x { x -> t } ) = M_A( t*t ) // where M_A denotes the abstract model. Node mtfs = model.computeAbstractModelValue(tfs); - pab = pab.substitute(tfv, mtfs); - pab = Rewriter::rewrite(pab); + pab = eval.eval(pab, {tfv}, {mtfs}); Assert(pab.isConst()); bounds.push_back(pab); } diff --git a/src/theory/arith/nl/transcendental/taylor_generator.h b/src/theory/arith/nl/transcendental/taylor_generator.h index df4cb128c..ea082d87b 100644 --- a/src/theory/arith/nl/transcendental/taylor_generator.h +++ b/src/theory/arith/nl/transcendental/taylor_generator.h @@ -104,7 +104,6 @@ class TaylorGenerator NlModel& model); private: - NodeManager* d_nm; const Node d_taylor_real_fv; /** diff --git a/src/theory/arith/nl/transcendental/transcendental_solver.cpp b/src/theory/arith/nl/transcendental/transcendental_solver.cpp index 9e204f582..25a5a511f 100644 --- a/src/theory/arith/nl/transcendental/transcendental_solver.cpp +++ b/src/theory/arith/nl/transcendental/transcendental_solver.cpp @@ -41,11 +41,11 @@ TranscendentalSolver::TranscendentalSolver(Env& env, InferenceManager& im, NlModel& m) : EnvObj(env), - d_tstate(im, m, env), + d_tstate(env, im, m), d_expSlv(env, &d_tstate), d_sineSlv(env, &d_tstate) { - d_taylor_degree = d_tstate.d_env.getOptions().arith.nlExtTfTaylorDegree; + d_taylor_degree = options().arith.nlExtTfTaylorDegree; } TranscendentalSolver::~TranscendentalSolver() {} @@ -187,7 +187,7 @@ void TranscendentalSolver::processSideEffect(const NlLemma& se) auto it = secant_points.find(d); if (it == secant_points.end()) { - it = secant_points.emplace(d, d_tstate.d_env.getUserContext()).first; + it = secant_points.emplace(d, userContext()).first; } it->second.push_back(c); } diff --git a/src/theory/arith/nl/transcendental/transcendental_state.cpp b/src/theory/arith/nl/transcendental/transcendental_state.cpp index 870eddc86..e32f336ac 100644 --- a/src/theory/arith/nl/transcendental/transcendental_state.cpp +++ b/src/theory/arith/nl/transcendental/transcendental_state.cpp @@ -30,16 +30,16 @@ namespace arith { namespace nl { namespace transcendental { -TranscendentalState::TranscendentalState(InferenceManager& im, - NlModel& model, - Env& env) - : d_im(im), d_model(model), d_env(env) +TranscendentalState::TranscendentalState(Env& env, + InferenceManager& im, + NlModel& model) + : EnvObj(env), d_im(im), d_model(model) { d_true = NodeManager::currentNM()->mkConst(true); d_false = NodeManager::currentNM()->mkConst(false); - d_zero = NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(0)); - d_one = NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(1)); - d_neg_one = NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(-1)); + d_zero = NodeManager::currentNM()->mkConstReal(Rational(0)); + d_one = NodeManager::currentNM()->mkConstReal(Rational(1)); + d_neg_one = NodeManager::currentNM()->mkConstReal(Rational(-1)); if (d_env.isTheoryProofProducing()) { d_proof.reset(new CDProofSet<CDProof>( @@ -204,21 +204,15 @@ void TranscendentalState::mkPi() if (d_pi.isNull()) { d_pi = nm->mkNullaryOperator(nm->realType(), Kind::PI); - d_pi_2 = Rewriter::rewrite( - nm->mkNode(Kind::MULT, - d_pi, - nm->mkConst(CONST_RATIONAL, Rational(1) / Rational(2)))); - d_pi_neg_2 = Rewriter::rewrite( - nm->mkNode(Kind::MULT, - d_pi, - nm->mkConst(CONST_RATIONAL, Rational(-1) / Rational(2)))); - d_pi_neg = Rewriter::rewrite(nm->mkNode( - Kind::MULT, d_pi, nm->mkConst(CONST_RATIONAL, Rational(-1)))); + d_pi_2 = rewrite(nm->mkNode( + Kind::MULT, d_pi, nm->mkConstReal(Rational(1) / Rational(2)))); + d_pi_neg_2 = rewrite(nm->mkNode( + Kind::MULT, d_pi, nm->mkConstReal(Rational(-1) / Rational(2)))); + d_pi_neg = + rewrite(nm->mkNode(Kind::MULT, d_pi, nm->mkConstReal(Rational(-1)))); // initialize bounds - d_pi_bound[0] = - nm->mkConst(CONST_RATIONAL, Rational(103993) / Rational(33102)); - d_pi_bound[1] = - nm->mkConst(CONST_RATIONAL, Rational(104348) / Rational(33215)); + d_pi_bound[0] = nm->mkConstReal(Rational(103993) / Rational(33102)); + d_pi_bound[1] = nm->mkConstReal(Rational(104348) / Rational(33215)); } } @@ -274,7 +268,7 @@ Node TranscendentalState::mkSecantPlane( { NodeManager* nm = NodeManager::currentNM(); // Figure 3: S_l( x ), S_u( x ) for s = 0,1 - Node rcoeff_n = Rewriter::rewrite(nm->mkNode(Kind::MINUS, lower, upper)); + Node rcoeff_n = rewrite(nm->mkNode(Kind::MINUS, lower, upper)); Assert(rcoeff_n.isConst()); Rational rcoeff = rcoeff_n.getConst<Rational>(); Assert(rcoeff.sgn() != 0); @@ -291,7 +285,7 @@ Node TranscendentalState::mkSecantPlane( Trace("nl-trans") << "\tfrom ( " << lower << " ; " << lval << " ) to ( " << upper << " ; " << uval << " )" << std::endl; Trace("nl-trans") << "\t" << res << std::endl; - Trace("nl-trans") << "\trewritten: " << Rewriter::rewrite(res) << std::endl; + Trace("nl-trans") << "\trewritten: " << rewrite(res) << std::endl; return res; } @@ -331,9 +325,6 @@ NlLemma TranscendentalState::mkSecantLemma(TNode lower, antec_n, nm->mkNode( convexity == Convexity::CONVEX ? Kind::LEQ : Kind::GEQ, tf, splane)); - Trace("nl-trans-lemma") << "*** Secant plane lemma (pre-rewrite) : " << lem - << std::endl; - lem = Rewriter::rewrite(lem); Trace("nl-trans-lemma") << "*** Secant plane lemma : " << lem << std::endl; Assert(d_model.computeAbstractModelValue(lem) == d_false); CDProof* proof = nullptr; @@ -347,44 +338,34 @@ NlLemma TranscendentalState::mkSecantLemma(TNode lower, proof->addStep(lem, PfRule::ARITH_TRANS_EXP_APPROX_ABOVE_POS, {}, - {nm->mkConst<Rational>(CONST_RATIONAL, 2 * actual_d), - tf[0], - lower, - upper}); + {nm->mkConstInt(2 * actual_d), tf[0], lower, upper}); } else { proof->addStep(lem, PfRule::ARITH_TRANS_EXP_APPROX_ABOVE_NEG, {}, - {nm->mkConst<Rational>(CONST_RATIONAL, 2 * actual_d), - tf[0], - lower, - upper}); + {nm->mkConstInt(2 * actual_d), tf[0], lower, upper}); } } else if (tf.getKind() == Kind::SINE) { if (convexity == Convexity::CONCAVE) { - proof->addStep(lem, - PfRule::ARITH_TRANS_SINE_APPROX_BELOW_POS, - {}, - {nm->mkConst<Rational>(CONST_RATIONAL, 2 * actual_d), - tf[0], - lower, - upper, - lapprox, - uapprox + proof->addStep( + lem, + PfRule::ARITH_TRANS_SINE_APPROX_BELOW_POS, + {}, + {nm->mkConstInt(2 * actual_d), tf[0], lower, upper, lapprox, uapprox - }); + }); } else { proof->addStep(lem, PfRule::ARITH_TRANS_SINE_APPROX_ABOVE_NEG, {}, - {nm->mkConst<Rational>(CONST_RATIONAL, 2 * actual_d), + {nm->mkConstInt(2 * actual_d), tf[0], lower, upper, @@ -419,8 +400,8 @@ void TranscendentalState::doSecantLemmas(const std::pair<Node, Node>& bounds, if (lower != center) { // Figure 3 : P(l), P(u), for s = 0 - Node lval = Rewriter::rewrite( - poly_approx.substitute(d_taylor.getTaylorVariable(), lower)); + Node lval = + rewrite(poly_approx.substitute(d_taylor.getTaylorVariable(), lower)); Node splane = mkSecantPlane(tf[0], lower, center, lval, cval); NlLemma nlem = mkSecantLemma( lower, center, lval, cval, csign, convexity, tf, splane, actual_d); @@ -438,8 +419,8 @@ void TranscendentalState::doSecantLemmas(const std::pair<Node, Node>& bounds, if (center != upper) { // Figure 3 : P(l), P(u), for s = 1 - Node uval = Rewriter::rewrite( - poly_approx.substitute(d_taylor.getTaylorVariable(), upper)); + Node uval = + rewrite(poly_approx.substitute(d_taylor.getTaylorVariable(), upper)); Node splane = mkSecantPlane(tf[0], center, upper, cval, uval); NlLemma nlem = mkSecantLemma( center, upper, cval, uval, csign, convexity, tf, splane, actual_d); diff --git a/src/theory/arith/nl/transcendental/transcendental_state.h b/src/theory/arith/nl/transcendental/transcendental_state.h index 77fcf57fb..ede8079a4 100644 --- a/src/theory/arith/nl/transcendental/transcendental_state.h +++ b/src/theory/arith/nl/transcendental/transcendental_state.h @@ -60,9 +60,9 @@ inline std::ostream& operator<<(std::ostream& os, Convexity c) { * This includes common lookups and caches as well as generic utilities for * secant plane lemmas and taylor approximations. */ -struct TranscendentalState +struct TranscendentalState : protected EnvObj { - TranscendentalState(InferenceManager& im, NlModel& model, Env& env); + TranscendentalState(Env& env, InferenceManager& im, NlModel& model); /** * Checks whether proofs are enabled. @@ -168,8 +168,6 @@ struct TranscendentalState InferenceManager& d_im; /** Reference to the non-linear model object */ NlModel& d_model; - /** Reference to the environment */ - Env& d_env; /** Utility to compute taylor approximations */ TaylorGenerator d_taylor; /** diff --git a/src/theory/arith/operator_elim.cpp b/src/theory/arith/operator_elim.cpp index 17efa53a5..99f5621d6 100644 --- a/src/theory/arith/operator_elim.cpp +++ b/src/theory/arith/operator_elim.cpp @@ -173,22 +173,20 @@ Node OperatorElim::eliminateOperators(Node node, nm->mkNode( MULT, den, - nm->mkNode( - PLUS, v, nm->mkConst(CONST_RATIONAL, Rational(1)))))); + nm->mkNode(PLUS, v, nm->mkConstInt(Rational(1)))))); } else { lem = nm->mkNode( AND, leqNum, - nm->mkNode(LT, - num, - nm->mkNode(MULT, - den, - nm->mkNode(PLUS, - v, - nm->mkConst(CONST_RATIONAL, - Rational(-1)))))); + nm->mkNode( + LT, + num, + nm->mkNode( + MULT, + den, + nm->mkNode(PLUS, v, nm->mkConstInt(Rational(-1)))))); } } else @@ -198,34 +196,32 @@ Node OperatorElim::eliminateOperators(Node node, AND, nm->mkNode( IMPLIES, - nm->mkNode(GT, den, nm->mkConst(CONST_RATIONAL, Rational(0))), + nm->mkNode(GT, den, nm->mkConstInt(Rational(0))), nm->mkNode( AND, leqNum, nm->mkNode( LT, num, - nm->mkNode(MULT, - den, - nm->mkNode(PLUS, - v, - nm->mkConst(CONST_RATIONAL, - Rational(1))))))), + nm->mkNode( + MULT, + den, + nm->mkNode( + PLUS, v, nm->mkConstInt(Rational(1))))))), nm->mkNode( IMPLIES, - nm->mkNode(LT, den, nm->mkConst(CONST_RATIONAL, Rational(0))), + nm->mkNode(LT, den, nm->mkConstInt(Rational(0))), nm->mkNode( AND, leqNum, nm->mkNode( LT, num, - nm->mkNode(MULT, - den, - nm->mkNode(PLUS, - v, - nm->mkConst(CONST_RATIONAL, - Rational(-1)))))))); + nm->mkNode( + MULT, + den, + nm->mkNode( + PLUS, v, nm->mkConstInt(Rational(-1)))))))); } Node intVar = mkWitnessTerm( v, lem, "linearIntDiv", "the result of an intdiv-by-k term", lems); @@ -259,10 +255,9 @@ Node OperatorElim::eliminateOperators(Node node, checkNonLinearLogic(node); Node rw = nm->mkNode(k, num, den); Node v = bvm->mkBoundVar<ArithWitnessVarAttribute>(rw, nm->realType()); - Node lem = nm->mkNode( - IMPLIES, - den.eqNode(nm->mkConst(CONST_RATIONAL, Rational(0))).negate(), - nm->mkNode(MULT, den, v).eqNode(num)); + Node lem = nm->mkNode(IMPLIES, + den.eqNode(nm->mkConstReal(Rational(0))).negate(), + nm->mkNode(MULT, den, v).eqNode(num)); return mkWitnessTerm( v, lem, "nonlinearDiv", "the result of a non-linear div term", lems); break; @@ -276,8 +271,7 @@ Node OperatorElim::eliminateOperators(Node node, { checkNonLinearLogic(node); Node divByZeroNum = getArithSkolemApp(num, SkolemFunId::DIV_BY_ZERO); - Node denEq0 = - nm->mkNode(EQUAL, den, nm->mkConst(CONST_RATIONAL, Rational(0))); + Node denEq0 = nm->mkNode(EQUAL, den, nm->mkConstReal(Rational(0))); ret = nm->mkNode(ITE, denEq0, divByZeroNum, ret); } return ret; @@ -295,8 +289,7 @@ Node OperatorElim::eliminateOperators(Node node, checkNonLinearLogic(node); Node intDivByZeroNum = getArithSkolemApp(num, SkolemFunId::INT_DIV_BY_ZERO); - Node denEq0 = - nm->mkNode(EQUAL, den, nm->mkConst(CONST_RATIONAL, Rational(0))); + Node denEq0 = nm->mkNode(EQUAL, den, nm->mkConstInt(Rational(0))); ret = nm->mkNode(ITE, denEq0, intDivByZeroNum, ret); } return ret; @@ -313,8 +306,7 @@ Node OperatorElim::eliminateOperators(Node node, { checkNonLinearLogic(node); Node modZeroNum = getArithSkolemApp(num, SkolemFunId::MOD_BY_ZERO); - Node denEq0 = - nm->mkNode(EQUAL, den, nm->mkConst(CONST_RATIONAL, Rational(0))); + Node denEq0 = nm->mkNode(EQUAL, den, nm->mkConstInt(Rational(0))); ret = nm->mkNode(ITE, denEq0, modZeroNum, ret); } return ret; @@ -325,7 +317,9 @@ Node OperatorElim::eliminateOperators(Node node, { return nm->mkNode( ITE, - nm->mkNode(LT, node[0], nm->mkConst(CONST_RATIONAL, Rational(0))), + nm->mkNode(LT, + node[0], + nm->mkConstRealOrInt(node[0].getType(), Rational(0))), nm->mkNode(UMINUS, node[0]), node[0]); break; @@ -363,11 +357,10 @@ Node OperatorElim::eliminateOperators(Node node, // satisfiable. On the original formula, this would require that we // simultaneously interpret sqrt(1) as 1 and -1, which is not a valid // model. - lem = nm->mkNode( - ITE, - nm->mkNode(GEQ, node[0], nm->mkConst(CONST_RATIONAL, Rational(0))), - nonNeg, - uf); + lem = nm->mkNode(ITE, + nm->mkNode(GEQ, node[0], nm->mkConstReal(Rational(0))), + nonNeg, + uf); } else { @@ -377,10 +370,9 @@ Node OperatorElim::eliminateOperators(Node node, Node rlem; if (k == ARCSINE || k == ARCTANGENT || k == ARCCOSECANT) { - Node half = nm->mkConst(CONST_RATIONAL, Rational(1) / Rational(2)); + Node half = nm->mkConstReal(Rational(1) / Rational(2)); Node pi2 = nm->mkNode(MULT, half, pi); - Node npi2 = - nm->mkNode(MULT, nm->mkConst(CONST_RATIONAL, Rational(-1)), pi2); + Node npi2 = nm->mkNode(MULT, nm->mkConstReal(Rational(-1)), pi2); // -pi/2 < var <= pi/2 rlem = nm->mkNode( AND, nm->mkNode(LT, npi2, var), nm->mkNode(LEQ, var, pi2)); @@ -388,10 +380,9 @@ Node OperatorElim::eliminateOperators(Node node, else { // 0 <= var < pi - rlem = nm->mkNode( - AND, - nm->mkNode(LEQ, nm->mkConst(CONST_RATIONAL, Rational(0)), var), - nm->mkNode(LT, var, pi)); + rlem = nm->mkNode(AND, + nm->mkNode(LEQ, nm->mkConstReal(Rational(0)), var), + nm->mkNode(LT, var, pi)); } Kind rk = diff --git a/src/theory/arith/proof_checker.cpp b/src/theory/arith/proof_checker.cpp index 69fe98734..c05f6ae0a 100644 --- a/src/theory/arith/proof_checker.cpp +++ b/src/theory/arith/proof_checker.cpp @@ -49,7 +49,6 @@ Node ArithProofRuleChecker::checkInternal(PfRule id, const std::vector<Node>& args) { NodeManager* nm = NodeManager::currentNM(); - auto zero = nm->mkConst<Rational>(CONST_RATIONAL, 0); if (Debug.isOn("arith::pf::check")) { Debug("arith::pf::check") << "Arith PfRule:" << id << std::endl; @@ -76,6 +75,7 @@ Node ArithProofRuleChecker::checkInternal(PfRule id, || rel == Kind::LEQ || rel == Kind::GT || rel == Kind::GEQ); Node lhs = args[1][0]; Node rhs = args[1][1]; + Node zero = nm->mkConstRealOrInt(mult.getType(), Rational(0)); return nm->mkNode(Kind::IMPLIES, nm->mkAnd(std::vector<Node>{ nm->mkNode(Kind::GT, mult, zero), args[1]}), @@ -94,6 +94,7 @@ Node ArithProofRuleChecker::checkInternal(PfRule id, Kind rel_inv = (rel == Kind::DISTINCT ? rel : reverseRelationKind(rel)); Node lhs = args[1][0]; Node rhs = args[1][1]; + Node zero = nm->mkConstRealOrInt(mult.getType(), Rational(0)); return nm->mkNode(Kind::IMPLIES, nm->mkAnd(std::vector<Node>{ nm->mkNode(Kind::LT, mult, zero), args[1]}), @@ -243,12 +244,8 @@ Node ArithProofRuleChecker::checkInternal(PfRule id, << "Bad kind: " << children[i].getKind() << std::endl; } } - leftSum << nm->mkNode(Kind::MULT, - nm->mkConst<Rational>(CONST_RATIONAL, scalar), - children[i][0]); - rightSum << nm->mkNode(Kind::MULT, - nm->mkConst<Rational>(CONST_RATIONAL, scalar), - children[i][1]); + leftSum << nm->mkNode(Kind::MULT, args[i], children[i][0]); + rightSum << nm->mkNode(Kind::MULT, args[i], children[i][1]); } Node r = nm->mkNode(strict ? Kind::LT : Kind::LEQ, leftSum.constructNode(), @@ -265,8 +262,7 @@ Node ArithProofRuleChecker::checkInternal(PfRule id, if (children.size() != 1 || (children[0].getKind() != Kind::GT && children[0].getKind() != Kind::GEQ) - || !children[0][0].getType().isInteger() - || children[0][1].getKind() != Kind::CONST_RATIONAL) + || !children[0][0].getType().isInteger() || !children[0][1].isConst()) { Debug("arith::pf::check") << "Illformed input: " << children; return Node::null(); @@ -275,7 +271,7 @@ Node ArithProofRuleChecker::checkInternal(PfRule id, { Rational originalBound = children[0][1].getConst<Rational>(); Rational newBound = leastIntGreaterThan(originalBound); - Node rational = nm->mkConst<Rational>(CONST_RATIONAL, newBound); + Node rational = nm->mkConstInt(newBound); return nm->mkNode(kind::GEQ, children[0][0], rational); } } @@ -290,8 +286,7 @@ Node ArithProofRuleChecker::checkInternal(PfRule id, if (children.size() != 1 || (children[0].getKind() != Kind::LT && children[0].getKind() != Kind::LEQ) - || !children[0][0].getType().isInteger() - || children[0][1].getKind() != Kind::CONST_RATIONAL) + || !children[0][0].getType().isInteger() || !children[0][1].isConst()) { Debug("arith::pf::check") << "Illformed input: " << children; return Node::null(); @@ -300,7 +295,7 @@ Node ArithProofRuleChecker::checkInternal(PfRule id, { Rational originalBound = children[0][1].getConst<Rational>(); Rational newBound = greatestIntLessThan(originalBound); - Node rational = nm->mkConst<Rational>(CONST_RATIONAL, newBound); + Node rational = nm->mkConstInt(newBound); return nm->mkNode(kind::LEQ, children[0][0], rational); } } diff --git a/src/theory/arith/theory_arith_private.cpp b/src/theory/arith/theory_arith_private.cpp index 643ba9a28..bf8798485 100644 --- a/src/theory/arith/theory_arith_private.cpp +++ b/src/theory/arith/theory_arith_private.cpp @@ -4782,8 +4782,11 @@ std::pair<bool, Node> TheoryArithPrivate::entailmentCheck(TNode lit, const Arith return make_pair(false, Node::null()); } -bool TheoryArithPrivate::decomposeTerm(Node term, Rational& m, Node& p, Rational& c){ - Node t = Rewriter::rewrite(term); +bool TheoryArithPrivate::decomposeTerm(Node t, + Rational& m, + Node& p, + Rational& c) +{ if(!Polynomial::isMember(t)){ return false; } @@ -4879,12 +4882,13 @@ bool TheoryArithPrivate::decomposeLiteral(Node lit, Kind& k, int& dir, Rational& // left : lm*( lp ) + lc // right: rm*( rp ) + rc Rational lc, rc; - bool success = decomposeTerm(left, lm, lp, lc); + bool success = decomposeTerm(rewrite(left), lm, lp, lc); if(!success){ return false; } - success = decomposeTerm(right, rm, rp, rc); + success = decomposeTerm(rewrite(right), rm, rp, rc); if(!success){ return false; } - Node diff = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::MINUS, left, right)); + Node diff = + rewrite(NodeManager::currentNM()->mkNode(kind::MINUS, left, right)); Rational dc; success = decomposeTerm(diff, dm, dp, dc); Assert(success); diff --git a/src/theory/arith/theory_arith_private.h b/src/theory/arith/theory_arith_private.h index 918f73a53..7c90352d2 100644 --- a/src/theory/arith/theory_arith_private.h +++ b/src/theory/arith/theory_arith_private.h @@ -162,20 +162,26 @@ private: //std::pair<DeltaRational, Node> inferBound(TNode term, bool lb, int maxRounds = -1, const DeltaRational* threshold = NULL); private: - static bool decomposeTerm(Node term, Rational& m, Node& p, Rational& c); - static bool decomposeLiteral(Node lit, Kind& k, int& dir, Rational& lm, Node& lp, Rational& rm, Node& rp, Rational& dm, Node& dp, DeltaRational& sep); - static void setToMin(int sgn, std::pair<Node, DeltaRational>& min, const std::pair<Node, DeltaRational>& e); - - /** - * The map between arith variables to nodes. - */ - //ArithVarNodeMap d_arithvarNodeMap; - - typedef ArithVariables::var_iterator var_iterator; - var_iterator var_begin() const { return d_partialModel.var_begin(); } - var_iterator var_end() const { return d_partialModel.var_end(); } - - NodeSet d_setupNodes; + static bool decomposeTerm(Node t, Rational& m, Node& p, Rational& c); + bool decomposeLiteral(Node lit, + Kind& k, + int& dir, + Rational& lm, + Node& lp, + Rational& rm, + Node& rp, + Rational& dm, + Node& dp, + DeltaRational& sep); + static void setToMin(int sgn, + std::pair<Node, DeltaRational>& min, + const std::pair<Node, DeltaRational>& e); + + typedef ArithVariables::var_iterator var_iterator; + var_iterator var_begin() const { return d_partialModel.var_begin(); } + var_iterator var_end() const { return d_partialModel.var_end(); } + + NodeSet d_setupNodes; public: bool isSetup(Node n) const { return d_setupNodes.find(n) != d_setupNodes.end(); diff --git a/src/theory/bags/bag_reduction.cpp b/src/theory/bags/bag_reduction.cpp index 9203a1c45..3e6544882 100644 --- a/src/theory/bags/bag_reduction.cpp +++ b/src/theory/bags/bag_reduction.cpp @@ -34,13 +34,26 @@ BagReduction::~BagReduction() {} /** * A bound variable corresponding to the universally quantified integer - * variable used to range over the distinct elements in a bag, used + * variable used to range over (may be distinct) elements in a bag, used * for axiomatizing the behavior of some term. + * If there are multiple quantifiers, this variable should be the first one. */ -struct IndexVarAttributeId +struct FirstIndexVarAttributeId { }; -typedef expr::Attribute<IndexVarAttributeId, Node> IndexVarAttribute; +typedef expr::Attribute<FirstIndexVarAttributeId, Node> FirstIndexVarAttribute; + +/** + * A bound variable corresponding to the universally quantified integer + * variable used to range over (may be distinct) elements in a bag, used + * for axiomatizing the behavior of some term. + * This variable should be the second of multiple quantifiers. + */ +struct SecondIndexVarAttributeId +{ +}; +typedef expr::Attribute<SecondIndexVarAttributeId, Node> + SecondIndexVarAttribute; Node BagReduction::reduceFoldOperator(Node node, std::vector<Node>& asserts) { @@ -52,8 +65,8 @@ Node BagReduction::reduceFoldOperator(Node node, std::vector<Node>& asserts) Node f = node[0]; Node t = node[1]; Node A = node[2]; - Node zero = nm->mkConst(CONST_RATIONAL, Rational(0)); - Node one = nm->mkConst(CONST_RATIONAL, Rational(1)); + Node zero = nm->mkConstInt(Rational(0)); + Node one = nm->mkConstInt(Rational(1)); // types TypeNode bagType = A.getType(); TypeNode elementType = A.getType().getBagElementType(); @@ -71,7 +84,8 @@ Node BagReduction::reduceFoldOperator(Node node, std::vector<Node>& asserts) SkolemFunId::BAGS_FOLD_COMBINE, combineType, {f, t, A}); BoundVarManager* bvm = nm->getBoundVarManager(); - Node i = bvm->mkBoundVar<IndexVarAttribute>(node, "i", nm->integerType()); + Node i = + bvm->mkBoundVar<FirstIndexVarAttribute>(node, "i", nm->integerType()); Node iList = nm->mkNode(BOUND_VAR_LIST, i); Node iMinusOne = nm->mkNode(MINUS, i, one); Node uf_i = nm->mkNode(APPLY_UF, uf, i); @@ -114,6 +128,84 @@ Node BagReduction::reduceFoldOperator(Node node, std::vector<Node>& asserts) return Node::null(); } +Node BagReduction::reduceCardOperator(Node node, std::vector<Node>& asserts) +{ + Assert(node.getKind() == BAG_CARD); + NodeManager* nm = NodeManager::currentNM(); + SkolemManager* sm = nm->getSkolemManager(); + Node A = node[0]; + Node zero = nm->mkConst(CONST_RATIONAL, Rational(0)); + Node one = nm->mkConst(CONST_RATIONAL, Rational(1)); + // types + TypeNode bagType = A.getType(); + TypeNode elementType = A.getType().getBagElementType(); + TypeNode integerType = nm->integerType(); + TypeNode ufType = nm->mkFunctionType(integerType, elementType); + TypeNode cardinalityType = nm->mkFunctionType(integerType, integerType); + TypeNode unionDisjointType = nm->mkFunctionType(integerType, bagType); + // skolem functions + Node n = sm->mkSkolemFunction(SkolemFunId::BAGS_CARD_N, integerType, A); + Node uf = sm->mkSkolemFunction(SkolemFunId::BAGS_CARD_ELEMENTS, ufType, A); + Node unionDisjoint = sm->mkSkolemFunction( + SkolemFunId::BAGS_CARD_UNION_DISJOINT, unionDisjointType, A); + Node cardinality = sm->mkSkolemFunction( + SkolemFunId::BAGS_CARD_CARDINALITY, cardinalityType, A); + + BoundVarManager* bvm = nm->getBoundVarManager(); + Node i = + bvm->mkBoundVar<FirstIndexVarAttribute>(node, "i", nm->integerType()); + Node j = + bvm->mkBoundVar<SecondIndexVarAttribute>(node, "j", nm->integerType()); + Node iList = nm->mkNode(BOUND_VAR_LIST, i); + Node jList = nm->mkNode(BOUND_VAR_LIST, j); + Node iMinusOne = nm->mkNode(MINUS, i, one); + Node uf_i = nm->mkNode(APPLY_UF, uf, i); + Node uf_j = nm->mkNode(APPLY_UF, uf, j); + Node cardinality_0 = nm->mkNode(APPLY_UF, cardinality, zero); + Node cardinality_iMinusOne = nm->mkNode(APPLY_UF, cardinality, iMinusOne); + Node cardinality_i = nm->mkNode(APPLY_UF, cardinality, i); + Node cardinality_n = nm->mkNode(APPLY_UF, cardinality, n); + Node unionDisjoint_0 = nm->mkNode(APPLY_UF, unionDisjoint, zero); + Node unionDisjoint_iMinusOne = nm->mkNode(APPLY_UF, unionDisjoint, iMinusOne); + Node unionDisjoint_i = nm->mkNode(APPLY_UF, unionDisjoint, i); + Node unionDisjoint_n = nm->mkNode(APPLY_UF, unionDisjoint, n); + Node cardinality_0_equal = cardinality_0.eqNode(zero); + Node uf_i_multiplicity = nm->mkNode(BAG_COUNT, uf_i, A); + Node cardinality_i_equal = cardinality_i.eqNode( + nm->mkNode(PLUS, uf_i_multiplicity, cardinality_iMinusOne)); + Node unionDisjoint_0_equal = + unionDisjoint_0.eqNode(nm->mkConst(EmptyBag(bagType))); + Node bag = nm->mkBag(elementType, uf_i, uf_i_multiplicity); + + Node unionDisjoint_i_equal = unionDisjoint_i.eqNode( + nm->mkNode(BAG_UNION_DISJOINT, bag, unionDisjoint_iMinusOne)); + // 1 <= i <= n + Node interval_i = + nm->mkNode(AND, nm->mkNode(GEQ, i, one), nm->mkNode(LEQ, i, n)); + + // i < j <= n + Node interval_j = + nm->mkNode(AND, nm->mkNode(LT, i, j), nm->mkNode(LEQ, j, n)); + // uf(i) != uf(j) + Node uf_i_equals_uf_j = nm->mkNode(EQUAL, uf_i, uf_j); + Node notEqual = nm->mkNode(EQUAL, uf_i, uf_j).negate(); + Node body_j = nm->mkNode(OR, interval_j.negate(), notEqual); + Node forAll_j = quantifiers::BoundedIntegers::mkBoundedForall(jList, body_j); + Node body_i = nm->mkNode( + IMPLIES, + interval_i, + nm->mkNode(AND, cardinality_i_equal, unionDisjoint_i_equal, forAll_j)); + Node forAll_i = quantifiers::BoundedIntegers::mkBoundedForall(iList, body_i); + Node nonNegative = nm->mkNode(GEQ, n, zero); + Node unionDisjoint_n_equal = A.eqNode(unionDisjoint_n); + asserts.push_back(forAll_i); + asserts.push_back(cardinality_0_equal); + asserts.push_back(unionDisjoint_0_equal); + asserts.push_back(unionDisjoint_n_equal); + asserts.push_back(nonNegative); + return cardinality_n; +} + } // namespace bags } // namespace theory } // namespace cvc5 diff --git a/src/theory/bags/bag_reduction.h b/src/theory/bags/bag_reduction.h index 11f091f94..694379dfc 100644 --- a/src/theory/bags/bag_reduction.h +++ b/src/theory/bags/bag_reduction.h @@ -41,9 +41,8 @@ class BagReduction : EnvObj * t: T2 is the initial value * A: (Bag T1) is a bag * @param asserts a list of assertions generated by this reduction - * @return the reduction term (combine n) such that - * (and - * (forall ((i Int)) + * @return the reduction term (combine n) with asserts: + * - (forall ((i Int)) * (let ((iMinusOne (- i 1))) * (let ((uf_i (uf i))) * (=> @@ -55,18 +54,49 @@ class BagReduction : EnvObj * (bag.union_disjoint * (bag uf_i 1) * (unionDisjoint iMinusOne)))))))) - * (= (combine 0) t) - * (= (unionDisjoint 0) (as bag.empty (Bag T1))) - * (= A (unionDisjoint n)) - * (>= n 0)) - * where - * n: Int is the cardinality of bag A - * uf:Int -> T1 is an uninterpreted function that represents elements of A - * combine: Int -> T2 is an uninterpreted function - * unionDisjoint: Int -> (Bag T1) is an uninterpreted function + * - (= (combine 0) t) + * - (= (unionDisjoint 0) (as bag.empty (Bag T1))) + * - (= A (unionDisjoint n)) + * - (>= n 0)) + * where + * n: Int is the cardinality of bag A + * uf:Int -> T1 is an uninterpreted function that represents elements of A + * combine: Int -> T2 is an uninterpreted function + * unionDisjoint: Int -> (Bag T1) is an uninterpreted function */ Node reduceFoldOperator(Node node, std::vector<Node>& asserts); + /** + * @param node a term of the form (bag.card A) where A: (Bag T) is a bag + * @param asserts a list of assertions generated by this reduction + * @return the reduction term (cardinality n) with asserts: + * - (forall ((i Int)) + * (let ((uf_i (uf i))) + * (let ((count_uf_i (bag.count uf_i A))) + * (=> + * (and (>= i 1) (<= i n)) + * (and + * (= (cardinality i) (+ count_uf_i (cardinality (- i 1)))) + * (= + * (unionDisjoint i) + * (bag.union_disjoint (bag uf_i count_uf_i) (unionDisjoint (- i 1)))) + * (forall ((j Int)) + * (or (not (and (< i j) (<= j n))) + * (not (= (uf i) (uf j)))))))))) + * - (= (cardinality 0) 0) + * - (= (unionDisjoint 0) (as bag.empty (Bag String))) + * - (= A (unionDisjoint n)) + * - (>= n 0) + * + * where + * n: number of distinct elements in A + * uf:Int -> T is an uninterpreted function that represents distinct + * elements of A + * cardinality: Int -> Int is an uninterpreted function + * unionDisjoint: Int -> (Bag T1) is an uninterpreted function + */ + Node reduceCardOperator(Node node, std::vector<Node>& asserts); + private: }; diff --git a/src/theory/bags/bag_solver.cpp b/src/theory/bags/bag_solver.cpp index 444878574..80ccd6707 100644 --- a/src/theory/bags/bag_solver.cpp +++ b/src/theory/bags/bag_solver.cpp @@ -42,8 +42,8 @@ BagSolver::BagSolver(Env& env, d_termReg(tr), d_mapCache(userContext()) { - d_zero = NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(0)); - d_one = NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(1)); + d_zero = NodeManager::currentNM()->mkConstInt(Rational(0)); + d_one = NodeManager::currentNM()->mkConstInt(Rational(1)); d_true = NodeManager::currentNM()->mkConst(true); d_false = NodeManager::currentNM()->mkConst(false); } @@ -89,7 +89,7 @@ void BagSolver::postCheck() { for (const Node& e : d_state.getElements(n)) { - checkNonNegativeCountTerms(n, e); + checkNonNegativeCountTerms(n, d_state.getRepresentative(e)); } } } @@ -115,7 +115,7 @@ void BagSolver::checkEmpty(const Node& n) Assert(n.getKind() == BAG_EMPTY); for (const Node& e : d_state.getElements(n)) { - InferInfo i = d_ig.empty(n, e); + InferInfo i = d_ig.empty(n, d_state.getRepresentative(e)); d_im.lemmaTheoryInference(&i); } } @@ -126,7 +126,7 @@ void BagSolver::checkUnionDisjoint(const Node& n) std::set<Node> elements = getElementsForBinaryOperator(n); for (const Node& e : elements) { - InferInfo i = d_ig.unionDisjoint(n, e); + InferInfo i = d_ig.unionDisjoint(n, d_state.getRepresentative(e)); d_im.lemmaTheoryInference(&i); } } @@ -137,7 +137,7 @@ void BagSolver::checkUnionMax(const Node& n) std::set<Node> elements = getElementsForBinaryOperator(n); for (const Node& e : elements) { - InferInfo i = d_ig.unionMax(n, e); + InferInfo i = d_ig.unionMax(n, d_state.getRepresentative(e)); d_im.lemmaTheoryInference(&i); } } @@ -148,7 +148,7 @@ void BagSolver::checkIntersectionMin(const Node& n) std::set<Node> elements = getElementsForBinaryOperator(n); for (const Node& e : elements) { - InferInfo i = d_ig.intersection(n, e); + InferInfo i = d_ig.intersection(n, d_state.getRepresentative(e)); d_im.lemmaTheoryInference(&i); } } @@ -159,7 +159,7 @@ void BagSolver::checkDifferenceSubtract(const Node& n) std::set<Node> elements = getElementsForBinaryOperator(n); for (const Node& e : elements) { - InferInfo i = d_ig.differenceSubtract(n, e); + InferInfo i = d_ig.differenceSubtract(n, d_state.getRepresentative(e)); d_im.lemmaTheoryInference(&i); } } @@ -172,7 +172,7 @@ void BagSolver::checkBagMake(const Node& n) << " are: " << d_state.getElements(n) << std::endl; for (const Node& e : d_state.getElements(n)) { - InferInfo i = d_ig.bagMake(n, e); + InferInfo i = d_ig.bagMake(n, d_state.getRepresentative(e)); d_im.lemmaTheoryInference(&i); } } @@ -188,7 +188,7 @@ void BagSolver::checkDifferenceRemove(const Node& n) std::set<Node> elements = getElementsForBinaryOperator(n); for (const Node& e : elements) { - InferInfo i = d_ig.differenceRemove(n, e); + InferInfo i = d_ig.differenceRemove(n, d_state.getRepresentative(e)); d_im.lemmaTheoryInference(&i); } } @@ -205,7 +205,7 @@ void BagSolver::checkDuplicateRemoval(Node n) for (const Node& e : elements) { - InferInfo i = d_ig.duplicateRemoval(n, e); + InferInfo i = d_ig.duplicateRemoval(n, d_state.getRepresentative(e)); d_im.lemmaTheoryInference(&i); } } @@ -224,8 +224,9 @@ void BagSolver::checkMap(Node n) Assert(n.getKind() == BAG_MAP); const set<Node>& downwards = d_state.getElements(n); const set<Node>& upwards = d_state.getElements(n[1]); - for (const Node& y : downwards) + for (const Node& z : downwards) { + Node y = d_state.getRepresentative(z); if (d_mapCache.count(n) && d_mapCache[n].get()->contains(y)) { continue; diff --git a/src/theory/bags/bags_rewriter.cpp b/src/theory/bags/bags_rewriter.cpp index 766731806..a5fb206aa 100644 --- a/src/theory/bags/bags_rewriter.cpp +++ b/src/theory/bags/bags_rewriter.cpp @@ -45,8 +45,8 @@ BagsRewriter::BagsRewriter(HistogramStat<Rewrite>* statistics) : d_statistics(statistics) { d_nm = NodeManager::currentNM(); - d_zero = d_nm->mkConst(CONST_RATIONAL, Rational(0)); - d_one = d_nm->mkConst(CONST_RATIONAL, Rational(1)); + d_zero = d_nm->mkConstInt(Rational(0)); + d_one = d_nm->mkConstInt(Rational(1)); } RewriteResponse BagsRewriter::postRewrite(TNode n) diff --git a/src/theory/bags/inference_generator.cpp b/src/theory/bags/inference_generator.cpp index a433ceb2d..cb6a3ea70 100644 --- a/src/theory/bags/inference_generator.cpp +++ b/src/theory/bags/inference_generator.cpp @@ -36,8 +36,8 @@ InferenceGenerator::InferenceGenerator(SolverState* state, InferenceManager* im) d_nm = NodeManager::currentNM(); d_sm = d_nm->getSkolemManager(); d_true = d_nm->mkConst(true); - d_zero = d_nm->mkConst(CONST_RATIONAL, Rational(0)); - d_one = d_nm->mkConst(CONST_RATIONAL, Rational(1)); + d_zero = d_nm->mkConstInt(Rational(0)); + d_one = d_nm->mkConstInt(Rational(1)); } InferInfo InferenceGenerator::nonNegativeCount(Node n, Node e) diff --git a/src/theory/bags/normal_form.cpp b/src/theory/bags/normal_form.cpp index 9a510c6f5..6cf26d357 100644 --- a/src/theory/bags/normal_form.cpp +++ b/src/theory/bags/normal_form.cpp @@ -201,14 +201,10 @@ Node NormalForm::constructConstantBagFromElements( } TypeNode elementType = t.getBagElementType(); std::map<Node, Rational>::const_reverse_iterator it = elements.rbegin(); - Node bag = nm->mkBag(elementType, - it->first, - nm->mkConst<Rational>(CONST_RATIONAL, it->second)); + Node bag = nm->mkBag(elementType, it->first, nm->mkConstInt(it->second)); while (++it != elements.rend()) { - Node n = nm->mkBag(elementType, - it->first, - nm->mkConst<Rational>(CONST_RATIONAL, it->second)); + Node n = nm->mkBag(elementType, it->first, nm->mkConstInt(it->second)); bag = nm->mkNode(BAG_UNION_DISJOINT, n, bag); } return bag; @@ -261,10 +257,10 @@ Node NormalForm::evaluateBagCount(TNode n) NodeManager* nm = NodeManager::currentNM(); if (it != elements.end()) { - Node count = nm->mkConst(CONST_RATIONAL, it->second); + Node count = nm->mkConstInt(it->second); return count; } - return nm->mkConst(CONST_RATIONAL, Rational(0)); + return nm->mkConstInt(Rational(0)); } Node NormalForm::evaluateDuplicateRemoval(TNode n) @@ -592,7 +588,7 @@ Node NormalForm::evaluateCard(TNode n) } NodeManager* nm = NodeManager::currentNM(); - Node sumNode = nm->mkConst(CONST_RATIONAL, sum); + Node sumNode = nm->mkConstInt(sum); return sumNode; } diff --git a/src/theory/bags/solver_state.cpp b/src/theory/bags/solver_state.cpp index 5c7c1dd73..ad817062f 100644 --- a/src/theory/bags/solver_state.cpp +++ b/src/theory/bags/solver_state.cpp @@ -43,7 +43,7 @@ void SolverState::registerBag(TNode n) void SolverState::registerCountTerm(TNode n) { Assert(n.getKind() == BAG_COUNT); - Node element = getRepresentative(n[0]); + Node element = n[0]; Node bag = getRepresentative(n[1]); d_bagElements[bag].insert(element); } diff --git a/src/theory/bags/theory_bags.cpp b/src/theory/bags/theory_bags.cpp index 68bdb7b1b..0694c179b 100644 --- a/src/theory/bags/theory_bags.cpp +++ b/src/theory/bags/theory_bags.cpp @@ -88,7 +88,18 @@ TrustNode TheoryBags::ppRewrite(TNode atom, std::vector<SkolemLemma>& lems) switch (atom.getKind()) { case kind::BAG_CHOOSE: return expandChooseOperator(atom, lems); - case kind::BAG_CARD: return expandCardOperator(atom, lems); + case kind::BAG_CARD: + { + std::vector<Node> asserts; + Node ret = d_bagReduction.reduceCardOperator(atom, asserts); + NodeManager* nm = NodeManager::currentNM(); + Node andNode = nm->mkNode(AND, asserts); + Trace("bags::ppr") << "reduce(" << atom << ") = " << ret + << " such that:" << std::endl + << andNode << std::endl; + d_im.lemma(andNode, InferenceId::BAGS_CARD); + return TrustNode::mkTrustRewrite(atom, ret, nullptr); + } case kind::BAG_FOLD: { std::vector<Node> asserts; @@ -98,7 +109,7 @@ TrustNode TheoryBags::ppRewrite(TNode atom, std::vector<SkolemLemma>& lems) d_im.lemma(andNode, InferenceId::BAGS_FOLD); Trace("bags::ppr") << "reduce(" << atom << ") = " << ret << " such that:" << std::endl - << asserts << std::endl; + << andNode << std::endl; return TrustNode::mkTrustRewrite(atom, ret, nullptr); } default: return TrustNode::null(); @@ -134,7 +145,7 @@ TrustNode TheoryBags::expandChooseOperator(const Node& node, Node emptyBag = nm->mkConst(EmptyBag(bagType)); Node isEmpty = A.eqNode(emptyBag); Node count = nm->mkNode(BAG_COUNT, x, A); - Node one = nm->mkConst(CONST_RATIONAL, Rational(1)); + Node one = nm->mkConstInt(Rational(1)); Node geqOne = nm->mkNode(GEQ, count, one); Node geqOneAndEqual = geqOne.andNode(equal); Node ite = nm->mkNode(ITE, isEmpty, equal, geqOneAndEqual); @@ -145,27 +156,6 @@ TrustNode TheoryBags::expandChooseOperator(const Node& node, return TrustNode::mkTrustRewrite(node, ret, nullptr); } -TrustNode TheoryBags::expandCardOperator(TNode n, std::vector<SkolemLemma>&) -{ - Assert(n.getKind() == BAG_CARD); - if (d_env.getLogicInfo().isHigherOrder()) - { - // (bag.card A) = (bag.count 1 (bag.map (lambda ((x E)) 1) A)), - // where E is the type of elements of A - NodeManager* nm = NodeManager::currentNM(); - Node one = nm->mkConst(CONST_RATIONAL, Rational(1)); - TypeNode type = n[0].getType().getBagElementType(); - Node x = nm->mkBoundVar("x", type); - Node lambda = nm->mkNode(LAMBDA, nm->mkNode(BOUND_VAR_LIST, x), one); - Node map = nm->mkNode(kind::BAG_MAP, lambda, n[0]); - Node countOne = nm->mkNode(kind::BAG_COUNT, one, map); - Trace("TheoryBags::ppRewrite") - << "ppRewrite(" << n << ") = " << countOne << std::endl; - return TrustNode::mkTrustRewrite(n, countOne, nullptr); - } - return TrustNode::null(); -} - void TheoryBags::postCheck(Effort effort) { d_im.doPendingFacts(); @@ -270,7 +260,18 @@ bool TheoryBags::collectModelValues(TheoryModel* m, { Node key = d_state.getRepresentative(e); Node countTerm = NodeManager::currentNM()->mkNode(BAG_COUNT, e, r); - Node value = d_state.getRepresentative(countTerm); + context::CDList<TNode>::const_iterator shared_it = + std::find(d_sharedTerms.begin(), d_sharedTerms.end(), countTerm); + eq::EqClassIterator it = + eq::EqClassIterator(r, d_state.getEqualityEngine()); + while (!it.isFinished() && shared_it == d_sharedTerms.end()) + { + Node bag = *(++it); + countTerm = NodeManager::currentNM()->mkNode(BAG_COUNT, e, bag); + shared_it = + std::find(d_sharedTerms.begin(), d_sharedTerms.end(), countTerm); + } + Node value = d_valuation.getModelValue(countTerm); elementReps[key] = value; } Node rep = NormalForm::constructBagFromElements(tn, elementReps); diff --git a/src/theory/bags/theory_bags.h b/src/theory/bags/theory_bags.h index 1a8af780e..8d15947ef 100644 --- a/src/theory/bags/theory_bags.h +++ b/src/theory/bags/theory_bags.h @@ -93,8 +93,6 @@ class TheoryBags : public Theory /** expand the definition of the bag.choose operator */ TrustNode expandChooseOperator(const Node& node, std::vector<SkolemLemma>& lems); - /** expand the definition of bag.card operator */ - TrustNode expandCardOperator(TNode n, std::vector<SkolemLemma>& lems); /** The state of the bags solver at full effort */ SolverState d_state; diff --git a/src/theory/bags/theory_bags_type_enumerator.cpp b/src/theory/bags/theory_bags_type_enumerator.cpp index 58a1b3291..0bfef55d2 100644 --- a/src/theory/bags/theory_bags_type_enumerator.cpp +++ b/src/theory/bags/theory_bags_type_enumerator.cpp @@ -57,7 +57,7 @@ Node BagEnumerator::operator*() BagEnumerator& BagEnumerator::operator++() { // increase the multiplicity by one - Node one = d_nodeManager->mkConst(CONST_RATIONAL, Rational(1)); + Node one = d_nodeManager->mkConstInt(Rational(1)); TypeNode elementType = d_elementTypeEnumerator.getType(); Node singleton = d_nodeManager->mkBag(elementType, d_element, one); if (d_currentBag.getKind() == kind::BAG_EMPTY) diff --git a/src/theory/booleans/proof_circuit_propagator.cpp b/src/theory/booleans/proof_circuit_propagator.cpp index 9190f423f..60ded97b6 100644 --- a/src/theory/booleans/proof_circuit_propagator.cpp +++ b/src/theory/booleans/proof_circuit_propagator.cpp @@ -31,9 +31,9 @@ namespace { /** Shorthand to create a Node from a constant number */ template <typename T> -Node mkRat(T val) +Node mkInt(T val) { - return NodeManager::currentNM()->mkConst<Rational>(CONST_RATIONAL, val); + return NodeManager::currentNM()->mkConstInt(Rational(val)); } /** @@ -356,7 +356,7 @@ std::shared_ptr<ProofNode> ProofCircuitPropagatorBackward::andTrue( return nullptr; } return mkProof( - PfRule::AND_ELIM, {assume(d_parent)}, {mkRat(i - d_parent.begin())}); + PfRule::AND_ELIM, {assume(d_parent)}, {mkInt(i - d_parent.begin())}); } std::shared_ptr<ProofNode> ProofCircuitPropagatorBackward::orFalse( @@ -368,7 +368,7 @@ std::shared_ptr<ProofNode> ProofCircuitPropagatorBackward::orFalse( } return mkNot(mkProof(PfRule::NOT_OR_ELIM, {assume(d_parent.notNode())}, - {mkRat(i - d_parent.begin())})); + {mkInt(i - d_parent.begin())})); } std::shared_ptr<ProofNode> ProofCircuitPropagatorBackward::iteC(bool c) @@ -463,7 +463,7 @@ std::shared_ptr<ProofNode> ProofCircuitPropagatorForward::andOneFalse() auto it = std::find(d_parent.begin(), d_parent.end(), d_child); return mkResolution( mkProof( - PfRule::CNF_AND_POS, {}, {d_parent, mkRat(it - d_parent.begin())}), + PfRule::CNF_AND_POS, {}, {d_parent, mkInt(it - d_parent.begin())}), d_child, true); } @@ -476,7 +476,7 @@ std::shared_ptr<ProofNode> ProofCircuitPropagatorForward::orOneTrue() } auto it = std::find(d_parent.begin(), d_parent.end(), d_child); return mkNot(mkResolution( - mkProof(PfRule::CNF_OR_NEG, {}, {d_parent, mkRat(it - d_parent.begin())}), + mkProof(PfRule::CNF_OR_NEG, {}, {d_parent, mkInt(it - d_parent.begin())}), d_child, false)); } diff --git a/src/theory/builtin/proof_checker.cpp b/src/theory/builtin/proof_checker.cpp index 9c05407b7..1c714b856 100644 --- a/src/theory/builtin/proof_checker.cpp +++ b/src/theory/builtin/proof_checker.cpp @@ -43,6 +43,7 @@ void BuiltinProofRuleChecker::registerTo(ProofChecker* pc) pc->registerChecker(PfRule::MACRO_SR_PRED_ELIM, this); pc->registerChecker(PfRule::MACRO_SR_PRED_TRANSFORM, this); pc->registerChecker(PfRule::THEORY_REWRITE, this); + pc->registerChecker(PfRule::ANNOTATION, this); pc->registerChecker(PfRule::REMOVE_TERM_FORMULA_AXIOM, this); // trusted rules pc->registerTrustedChecker(PfRule::THEORY_LEMMA, this, 1); @@ -381,6 +382,11 @@ Node BuiltinProofRuleChecker::checkInternal(PfRule id, Assert(args[0].getType().isBoolean()); return args[0]; } + else if (id == PfRule::ANNOTATION) + { + Assert(children.size() == 1); + return children[0]; + } // no rule return Node::null(); @@ -399,8 +405,8 @@ bool BuiltinProofRuleChecker::getTheoryId(TNode n, TheoryId& tid) Node BuiltinProofRuleChecker::mkTheoryIdNode(TheoryId tid) { - return NodeManager::currentNM()->mkConst( - CONST_RATIONAL, Rational(static_cast<uint32_t>(tid))); + return NodeManager::currentNM()->mkConstInt( + Rational(static_cast<uint32_t>(tid))); } } // namespace builtin diff --git a/src/theory/bv/int_blaster.cpp b/src/theory/bv/int_blaster.cpp index 649be5aab..58c12ceff 100644 --- a/src/theory/bv/int_blaster.cpp +++ b/src/theory/bv/int_blaster.cpp @@ -48,8 +48,7 @@ Rational intpow2(uint64_t b) { return Rational(Integer(2).pow(b), Integer(1)); } IntBlaster::IntBlaster(Env& env, options::SolveBVAsIntMode mode, - uint64_t granularity, - bool introduceFreshIntVars) + uint64_t granularity) : EnvObj(env), d_binarizeCache(userContext()), d_intblastCache(userContext()), @@ -57,12 +56,11 @@ IntBlaster::IntBlaster(Env& env, d_bitwiseAssertions(userContext()), d_mode(mode), d_granularity(granularity), - d_context(userContext()), - d_introduceFreshIntVars(introduceFreshIntVars) + d_context(userContext()) { d_nm = NodeManager::currentNM(); - d_zero = d_nm->mkConst(CONST_RATIONAL, Rational(0)); - d_one = d_nm->mkConst(CONST_RATIONAL, Rational(1)); + d_zero = d_nm->mkConstInt(0); + d_one = d_nm->mkConstInt(1); }; IntBlaster::~IntBlaster() {} @@ -108,18 +106,18 @@ Node IntBlaster::maxInt(uint64_t k) { Assert(k > 0); Rational max_value = intpow2(k) - 1; - return d_nm->mkConst(CONST_RATIONAL, max_value); + return d_nm->mkConstInt(max_value); } Node IntBlaster::pow2(uint64_t k) { Assert(k >= 0); - return d_nm->mkConst(CONST_RATIONAL, intpow2(k)); + return d_nm->mkConstInt(intpow2(k)); } Node IntBlaster::modpow2(Node n, uint64_t exponent) { - Node p2 = d_nm->mkConst(CONST_RATIONAL, intpow2(exponent)); + Node p2 = d_nm->mkConstInt(intpow2(exponent)); return d_nm->mkNode(kind::INTS_MODULUS_TOTAL, n, p2); } @@ -547,6 +545,11 @@ Node IntBlaster::translateWithChildren( case kind::BOUND_VAR_LIST: { returnNode = d_nm->mkNode(oldKind, translated_children); + if (d_mode == options::SolveBVAsIntMode::BITWISE) + { + throw OptionException( + "--solve-bv-as-int=bitwise does not support quantifiers"); + } break; } case kind::FORALL: @@ -588,7 +591,7 @@ Node IntBlaster::uts(Node x, uint64_t bvsize) { Node powNode = pow2(bvsize - 1); Node modNode = d_nm->mkNode(kind::INTS_MODULUS_TOTAL, x, powNode); - Node two = d_nm->mkConst(CONST_RATIONAL, Rational(2)); + Node two = d_nm->mkConstInt(Rational(2)); Node twoTimesNode = d_nm->mkNode(kind::MULT, two, modNode); return d_nm->mkNode(kind::MINUS, twoTimesNode, x); } @@ -615,7 +618,7 @@ Node IntBlaster::createSignExtendNode(Node x, uint64_t bvsize, uint64_t amount) Rational max_of_amount = intpow2(amount) - 1; Rational mul = max_of_amount * intpow2(bvsize); Rational sum = mul + c; - returnNode = d_nm->mkConst(CONST_RATIONAL, sum); + returnNode = d_nm->mkConstInt(sum); } } else @@ -627,7 +630,7 @@ Node IntBlaster::createSignExtendNode(Node x, uint64_t bvsize, uint64_t amount) else { Rational twoToKMinusOne(intpow2(bvsize - 1)); - Node minSigned = d_nm->mkConst(CONST_RATIONAL, twoToKMinusOne); + Node minSigned = d_nm->mkConstInt(twoToKMinusOne); /* condition checks whether the msb is 1. * This holds when the integer value is smaller than * 100...0, which is 2^{bvsize-1}. @@ -673,38 +676,18 @@ Node IntBlaster::translateNoChildren(Node original, } else { - // original is a bit-vector variable (symbolic constant). - // Either we translate it to a fresh integer variable, - // or we translate it to (bv2nat original). - // In the former case, we must include range lemmas, while in the - // latter we don't. - // This is determined by the option bv-to-int-fresh-vars. - // The variables intCast and bvCast are used for models: - // even if we introduce a fresh variable, - // it is associated with intCast (which is (bv2nat original)). - // bvCast is either ( (_ nat2bv k) original) or just original. Node intCast = castToType(original, d_nm->integerType()); Node bvCast; - if (d_introduceFreshIntVars) - { - // we introduce a fresh variable, add range constraints, and save the - // connection between original and the new variable via intCast - translation = d_nm->getSkolemManager()->mkPurifySkolem( - intCast, - "__intblast__var", - "Variable introduced in intblasting for " + original.toString()); - uint64_t bvsize = original.getType().getBitVectorSize(); - addRangeConstraint(translation, bvsize, lemmas); - // put new definition of old variable in skolems - bvCast = castToType(translation, original.getType()); - } - else - { - // we just translate original to (bv2nat original) - translation = intCast; - // no need to do any casting back to bit-vector in this case. - bvCast = original; - } + // we introduce a fresh variable, add range constraints, and save the + // connection between original and the new variable via intCast + translation = d_nm->getSkolemManager()->mkPurifySkolem( + intCast, + "__intblast__var", + "Variable introduced in intblasting for " + original.toString()); + uint64_t bvsize = original.getType().getBitVectorSize(); + addRangeConstraint(translation, bvsize, lemmas); + // put new definition of old variable in skolems + bvCast = castToType(translation, original.getType()); // add bvCast to skolems if it is not already there. if (skolems.find(original) == skolems.end()) @@ -737,7 +720,7 @@ Node IntBlaster::translateNoChildren(Node original, BitVector constant(original.getConst<BitVector>()); Integer c = constant.toInteger(); Rational r = Rational(c, Integer(1)); - translation = d_nm->mkConst(CONST_RATIONAL, r); + translation = d_nm->mkConstInt(r); } else { @@ -916,9 +899,7 @@ Node IntBlaster::createShiftNode(std::vector<Node> children, ite = d_nm->mkNode( kind::ITE, d_nm->mkNode( - kind::EQUAL, - y, - d_nm->mkConst(CONST_RATIONAL, Rational(Integer(i), Integer(1)))), + kind::EQUAL, y, d_nm->mkConstInt(Rational(Integer(i), Integer(1)))), body, ite); } @@ -1008,6 +989,38 @@ Node IntBlaster::createBVAndNode(Node x, // Construct a sum of ites, based on granularity. returnNode = d_iandUtils.createSumNode(x, y, bvsize, d_granularity); } + else + { + Assert(d_mode == options::SolveBVAsIntMode::BITWISE); + // Enforce semantics over individual bits with iextract and ites + uint64_t granularity = options().smt.BVAndIntegerGranularity; + + Node iAndOp = d_nm->mkConst(IntAnd(bvsize)); + Node iAnd = d_nm->mkNode(kind::IAND, iAndOp, x, y); + // get a skolem so the IAND solver knows not to do work + returnNode = d_nm->getSkolemManager()->mkPurifySkolem( + iAnd, + "__intblast__iand", + "skolem for an IAND node in bitwise mode " + iAnd.toString()); + addRangeConstraint(returnNode, bvsize, lemmas); + + // eagerly add bitwise lemmas according to the provided granularity + uint64_t high_bit; + for (uint64_t j = 0; j < bvsize; j += granularity) + { + high_bit = j + granularity - 1; + // don't let high_bit pass bvsize + if (high_bit >= bvsize) + { + high_bit = bvsize - 1; + } + Node extractedReturnNode = d_iandUtils.iextract(high_bit, j, returnNode); + addBitwiseConstraint( + extractedReturnNode.eqNode( + d_iandUtils.createBitwiseIAndNode(x, y, high_bit, j)), + lemmas); + } + } return returnNode; } diff --git a/src/theory/bv/int_blaster.h b/src/theory/bv/int_blaster.h index ed8ed10c6..fb7291f6e 100644 --- a/src/theory/bv/int_blaster.h +++ b/src/theory/bv/int_blaster.h @@ -101,14 +101,12 @@ class IntBlaster : protected EnvObj * @param context user context * @param mode bv-to-int translation mode * @param granularity bv-to-int translation granularity - * @param introduceFreshIntVars determines whether bit-vector variables are * translated to integer variables, or are directly casted using `bv2nat` * operator. not purely bit-vector nodes. */ IntBlaster(Env& env, options::SolveBVAsIntMode mode, - uint64_t granluarity = 1, - bool introduceFreshIntVars = true); + uint64_t granluarity = 1); ~IntBlaster(); @@ -371,11 +369,6 @@ class IntBlaster : protected EnvObj /** an SolverEngine for context */ context::Context* d_context; - /** true iff the translator should introduce - * fresh integer variables for bit-vector variables. - * Otherwise, we introduce a nat2bv term. - */ - bool d_introduceFreshIntVars; }; } // namespace cvc5 diff --git a/src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h b/src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h index 496a625ee..a8ac27a81 100644 --- a/src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h +++ b/src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h @@ -29,84 +29,6 @@ namespace cvc5 { namespace theory { namespace bv { -/* - * This rewrite is not meant to be used by the BV rewriter. - * It is specifically designed for the bv-to-int preprocessing pass. - * Based on Hacker's Delight section 2-2 equation a: - * -x = ~x+1 - */ -template <> -inline bool RewriteRule<NegEliminate>::applies(TNode node) -{ - return (node.getKind() == kind::BITVECTOR_NEG); -} - -template <> -inline Node RewriteRule<NegEliminate>::apply(TNode node) -{ - Debug("bv-rewrite") << "RewriteRule<NegEliminate>(" << node << ")" - << std::endl; - NodeManager* nm = NodeManager::currentNM(); - TNode a = node[0]; - unsigned size = utils::getSize(a); - Node one = utils::mkOne(size); - Node nota = nm->mkNode(kind::BITVECTOR_NOT, a); - Node bvadd = nm->mkNode(kind::BITVECTOR_ADD, nota, one); - return bvadd; -} - -/* - * This rewrite is not meant to be used by the BV rewriter. - * It is specifically designed for the bv-to-int preprocessing pass. - * Based on Hacker's Delight section 2-2 equation h: - * x+y = x|y + x&y - */ -template <> -inline bool RewriteRule<OrEliminate>::applies(TNode node) -{ - return (node.getKind() == kind::BITVECTOR_OR); -} - -template <> -inline Node RewriteRule<OrEliminate>::apply(TNode node) -{ - Debug("bv-rewrite") << "RewriteRule<OrEliminate>(" << node << ")" - << std::endl; - NodeManager* nm = NodeManager::currentNM(); - TNode a = node[0]; - TNode b = node[1]; - Node bvadd = nm->mkNode(kind::BITVECTOR_ADD, a, b); - Node bvand = nm->mkNode(kind::BITVECTOR_AND, a, b); - Node result = - nm->mkNode(kind::BITVECTOR_SUB, bvadd, bvand); - return result; -} - -/* - * This rewrite is not meant to be used by the BV rewriter. - * It is specifically designed for the bv-to-int preprocessing pass. - * Based on Hacker's Delight section 2-2 equation n: - * x xor y = x|y - x&y - */ -template <> -inline bool RewriteRule<XorEliminate>::applies(TNode node) -{ - return (node.getKind() == kind::BITVECTOR_XOR); -} - -template <> -inline Node RewriteRule<XorEliminate>::apply(TNode node) -{ - Debug("bv-rewrite") << "RewriteRule<XorEliminate>(" << node << ")" - << std::endl; - NodeManager* nm = NodeManager::currentNM(); - TNode a = node[0]; - TNode b = node[1]; - Node bvor = nm->mkNode(kind::BITVECTOR_OR, a, b); - Node bvand = nm->mkNode(kind::BITVECTOR_AND, a, b); - Node result = nm->mkNode(kind::BITVECTOR_SUB, bvor, bvand); - return result; -} template <> inline bool RewriteRule<UgtEliminate>::applies(TNode node) diff --git a/src/theory/bv/theory_bv_utils.cpp b/src/theory/bv/theory_bv_utils.cpp index adb067045..fd300fe41 100644 --- a/src/theory/bv/theory_bv_utils.cpp +++ b/src/theory/bv/theory_bv_utils.cpp @@ -467,7 +467,7 @@ Node eliminateBv2Nat(TNode node) { const unsigned size = utils::getSize(node[0]); NodeManager* const nm = NodeManager::currentNM(); - const Node z = nm->mkConst(CONST_RATIONAL, Rational(0)); + const Node z = nm->mkConstInt(Rational(0)); const Node bvone = utils::mkOne(1); Integer i = 1; @@ -478,8 +478,8 @@ Node eliminateBv2Nat(TNode node) nm->mkNode(kind::EQUAL, nm->mkNode(nm->mkConst(BitVectorExtract(bit, bit)), node[0]), bvone); - children.push_back(nm->mkNode( - kind::ITE, cond, nm->mkConst(CONST_RATIONAL, Rational(i)), z)); + children.push_back( + nm->mkNode(kind::ITE, cond, nm->mkConstInt(Rational(i)), z)); } // avoid plus with one child return children.size() == 1 ? children[0] : nm->mkNode(kind::PLUS, children); @@ -496,11 +496,11 @@ Node eliminateInt2Bv(TNode node) Integer i = 2; while (v.size() < size) { - Node cond = nm->mkNode(kind::GEQ, - nm->mkNode(kind::INTS_MODULUS_TOTAL, - node[0], - nm->mkConst(CONST_RATIONAL, Rational(i))), - nm->mkConst(CONST_RATIONAL, Rational(i, 2))); + Node cond = nm->mkNode( + kind::GEQ, + nm->mkNode( + kind::INTS_MODULUS_TOTAL, node[0], nm->mkConstInt(Rational(i))), + nm->mkConstInt(Rational(i, 2))); v.push_back(nm->mkNode(kind::ITE, cond, bvone, bvzero)); i *= 2; } diff --git a/src/theory/datatypes/datatypes_rewriter.cpp b/src/theory/datatypes/datatypes_rewriter.cpp index 903a08bb4..196b4f01d 100644 --- a/src/theory/datatypes/datatypes_rewriter.cpp +++ b/src/theory/datatypes/datatypes_rewriter.cpp @@ -78,7 +78,7 @@ RewriteResponse DatatypesRewriter::postRewrite(TNode in) const DType& dt = utils::datatypeOf(constructor); const DTypeConstructor& c = dt[constructorIndex]; unsigned weight = c.getWeight(); - children.push_back(nm->mkConst(CONST_RATIONAL, Rational(weight))); + children.push_back(nm->mkConstInt(Rational(weight))); Node res = children.size() == 1 ? children[0] : nm->mkNode(kind::PLUS, children); Trace("datatypes-rewrite") @@ -104,9 +104,8 @@ RewriteResponse DatatypesRewriter::postRewrite(TNode in) res = nm->mkConst(false); break; } - children.push_back(nm->mkNode(kind::DT_HEIGHT_BOUND, - in[0][i], - nm->mkConst(CONST_RATIONAL, rmo))); + children.push_back( + nm->mkNode(kind::DT_HEIGHT_BOUND, in[0][i], nm->mkConstInt(rmo))); } } if (res.isNull()) @@ -329,10 +328,7 @@ RewriteResponse DatatypesRewriter::preRewrite(TNode in) // get the constructor object const DTypeConstructor& dtc = utils::datatypeOf(op)[utils::indexOf(op)]; // create ascribed constructor type - Node tc = NodeManager::currentNM()->mkConst( - AscriptionType(dtc.getSpecializedConstructorType(tn))); - Node op_new = NodeManager::currentNM()->mkNode( - kind::APPLY_TYPE_ASCRIPTION, tc, op); + Node op_new = dtc.getInstantiatedConstructor(tn); // make new node std::vector<Node> children; children.push_back(op_new); @@ -891,7 +887,14 @@ TrustNode DatatypesRewriter::expandDefinition(Node n) size_t cindex = utils::cindexOf(op); const DTypeConstructor& dc = dt[cindex]; NodeBuilder b(APPLY_CONSTRUCTOR); - b << dc.getConstructor(); + if (tn.isParametricDatatype()) + { + b << dc.getInstantiatedConstructor(n[0].getType()); + } + else + { + b << dc.getConstructor(); + } Trace("dt-expand") << "Expand updater " << n << std::endl; Trace("dt-expand") << "expr is " << n << std::endl; Trace("dt-expand") << "updateIndex is " << updateIndex << std::endl; diff --git a/src/theory/datatypes/infer_proof_cons.cpp b/src/theory/datatypes/infer_proof_cons.cpp index 7ca58905f..4ed6e3da9 100644 --- a/src/theory/datatypes/infer_proof_cons.cpp +++ b/src/theory/datatypes/infer_proof_cons.cpp @@ -108,7 +108,7 @@ void InferProofCons::convert(InferenceId infer, TNode conc, TNode exp, CDProof* } if (argSuccess) { - narg = nm->mkConst(CONST_RATIONAL, Rational(i)); + narg = nm->mkConstInt(Rational(i)); break; } } @@ -141,7 +141,7 @@ void InferProofCons::convert(InferenceId infer, TNode conc, TNode exp, CDProof* if (n >= 0) { Node t = exp[0]; - Node nn = nm->mkConst(CONST_RATIONAL, Rational(n)); + Node nn = nm->mkConstInt(Rational(n)); Node eq = exp.eqNode(conc); cdp->addStep(eq, PfRule::DT_INST, {}, {t, nn}); cdp->addStep(conc, PfRule::EQ_RESOLVE, {exp, eq}, {}); diff --git a/src/theory/datatypes/kinds b/src/theory/datatypes/kinds index 5324e1c79..ee42add6b 100644 --- a/src/theory/datatypes/kinds +++ b/src/theory/datatypes/kinds @@ -107,10 +107,10 @@ operator DT_SIZE_BOUND 2 "datatypes height bound" typerule DT_SIZE_BOUND ::cvc5::theory::datatypes::DtBoundTypeRule operator DT_SYGUS_BOUND 2 "datatypes sygus bound" -typerule DT_SYGUS_BOUND ::cvc5::theory::datatypes::DtSygusBoundTypeRule +typerule DT_SYGUS_BOUND ::cvc5::theory::datatypes::DtBoundTypeRule operator DT_SYGUS_EVAL 1: "datatypes sygus evaluation function" -typerule DT_SYGUS_EVAL ::cvc5::theory::datatypes::DtSyguEvalTypeRule +typerule DT_SYGUS_EVAL ::cvc5::theory::datatypes::DtSygusEvalTypeRule # Kinds for match terms. For example, the match term diff --git a/src/theory/datatypes/sygus_extension.cpp b/src/theory/datatypes/sygus_extension.cpp index 88a3e43d7..90511112c 100644 --- a/src/theory/datatypes/sygus_extension.cpp +++ b/src/theory/datatypes/sygus_extension.cpp @@ -57,7 +57,7 @@ SygusExtension::SygusExtension(Env& env, d_active_terms(context()), d_currTermSize(context()) { - d_zero = NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(0)); + d_zero = NodeManager::currentNM()->mkConstInt(Rational(0)); d_true = NodeManager::currentNM()->mkConst(true); } @@ -1772,8 +1772,8 @@ Node SygusExtension::SygusSizeDecisionStrategy::getOrMkMeasureValue() NodeManager* nm = NodeManager::currentNM(); SkolemManager* sm = nm->getSkolemManager(); d_measure_value = sm->mkDummySkolem("mt", nm->integerType()); - Node mtlem = nm->mkNode( - kind::GEQ, d_measure_value, nm->mkConst(CONST_RATIONAL, Rational(0))); + Node mtlem = + nm->mkNode(kind::GEQ, d_measure_value, nm->mkConstInt(Rational(0))); d_im.lemma(mtlem, InferenceId::DATATYPES_SYGUS_MT_POS); } return d_measure_value; @@ -1787,8 +1787,7 @@ Node SygusExtension::SygusSizeDecisionStrategy::getOrMkActiveMeasureValue( NodeManager* nm = NodeManager::currentNM(); SkolemManager* sm = nm->getSkolemManager(); Node new_mt = sm->mkDummySkolem("mt", nm->integerType()); - Node mtlem = - nm->mkNode(kind::GEQ, new_mt, nm->mkConst(CONST_RATIONAL, Rational(0))); + Node mtlem = nm->mkNode(kind::GEQ, new_mt, nm->mkConstInt(Rational(0))); d_measure_value_active = new_mt; d_im.lemma(mtlem, InferenceId::DATATYPES_SYGUS_MT_POS); } @@ -1817,8 +1816,7 @@ Node SygusExtension::SygusSizeDecisionStrategy::mkLiteral(unsigned s) NodeManager* nm = NodeManager::currentNM(); Trace("sygus-engine") << "******* Sygus : allocate size literal " << s << " for " << d_this << std::endl; - return nm->mkNode( - DT_SYGUS_BOUND, d_this, nm->mkConst(CONST_RATIONAL, Rational(s))); + return nm->mkNode(DT_SYGUS_BOUND, d_this, nm->mkConstInt(Rational(s))); } int SygusExtension::getGuardStatus( Node g ) { diff --git a/src/theory/datatypes/sygus_simple_sym.cpp b/src/theory/datatypes/sygus_simple_sym.cpp index 1b5e37bc3..4826e87bc 100644 --- a/src/theory/datatypes/sygus_simple_sym.cpp +++ b/src/theory/datatypes/sygus_simple_sym.cpp @@ -245,7 +245,7 @@ bool SygusSimpleSymBreak::considerArgKind( rt.d_children[0].d_req_kind = PLUS; rt.d_children[0].d_children[0].d_req_type = dt[c].getArgType(1); rt.d_children[0].d_children[1].d_req_const = - NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(1)); + NodeManager::currentNM()->mkConstInt(Rational(1)); rt.d_children[1].d_req_type = dt[c].getArgType(0); } else if (k == LT || k == GEQ) @@ -256,7 +256,7 @@ bool SygusSimpleSymBreak::considerArgKind( rt.d_children[1].d_req_kind = PLUS; rt.d_children[1].d_children[0].d_req_type = dt[c].getArgType(0); rt.d_children[1].d_children[1].d_req_const = - NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(1)); + NodeManager::currentNM()->mkConstInt(Rational(1)); } } else if (pk == BITVECTOR_NOT) diff --git a/src/theory/datatypes/theory_datatypes.cpp b/src/theory/datatypes/theory_datatypes.cpp index a9f0c3198..3f13886ed 100644 --- a/src/theory/datatypes/theory_datatypes.cpp +++ b/src/theory/datatypes/theory_datatypes.cpp @@ -68,7 +68,7 @@ TheoryDatatypes::TheoryDatatypes(Env& env, { d_true = NodeManager::currentNM()->mkConst( true ); - d_zero = NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(0)); + d_zero = NodeManager::currentNM()->mkConstInt(Rational(0)); d_dtfCounter = 0; // indicate we are using the default theory state object @@ -1244,7 +1244,7 @@ bool TheoryDatatypes::collectModelValues(TheoryModel* m, for( unsigned i=0; i<pcons.size(); i++ ){ // must try the infinite ones first bool cfinite = - d_env.isFiniteType(dt[i].getSpecializedConstructorType(tt)); + d_env.isFiniteType(dt[i].getInstantiatedConstructorType(tt)); if( pcons[i] && (r==1)==cfinite ){ neqc = utils::getInstCons(eqc, dt, i); break; diff --git a/src/theory/datatypes/theory_datatypes_type_rules.cpp b/src/theory/datatypes/theory_datatypes_type_rules.cpp index 86a11357b..422af1731 100644 --- a/src/theory/datatypes/theory_datatypes_type_rules.cpp +++ b/src/theory/datatypes/theory_datatypes_type_rules.cpp @@ -36,6 +36,10 @@ TypeNode DatatypeConstructorTypeRule::computeType(NodeManager* nodeManager, { Assert(n.getKind() == kind::APPLY_CONSTRUCTOR); TypeNode consType = n.getOperator().getType(check); + if (!consType.isConstructor()) + { + throw TypeCheckingExceptionPrivate(n, "expected constructor to apply"); + } TypeNode t = consType.getConstructorRangeType(); Assert(t.isDatatype()); TNode::iterator child_it = n.begin(); @@ -215,16 +219,17 @@ TypeNode DatatypeUpdateTypeRule::computeType(NodeManager* nodeManager, Assert(updType.getNumChildren() == 2); if (check) { + TypeNode t = updType[0]; for (size_t i = 0; i < 2; i++) { TypeNode childType = n[i].getType(check); - TypeNode t = updType[i]; + TypeNode targ = updType[i]; + Trace("typecheck-idt") << "typecheck update: " << n << "[" << i + << "]: " << targ << " " << childType << std::endl; if (t.isParametricDatatype()) { - Debug("typecheck-idt") - << "typecheck parameterized update: " << n << std::endl; TypeMatcher m(t); - if (!m.doMatching(t, childType)) + if (!m.doMatching(targ, childType)) { throw TypeCheckingExceptionPrivate( n, @@ -233,9 +238,7 @@ TypeNode DatatypeUpdateTypeRule::computeType(NodeManager* nodeManager, } else { - Debug("typecheck-idt") << "typecheck update: " << n << std::endl; - Debug("typecheck-idt") << "test type: " << updType << std::endl; - if (!t.isComparableTo(childType)) + if (!targ.isComparableTo(childType)) { throw TypeCheckingExceptionPrivate(n, "bad type for update argument"); } @@ -243,7 +246,7 @@ TypeNode DatatypeUpdateTypeRule::computeType(NodeManager* nodeManager, } } // type is the first argument - return updType[0]; + return n[0].getType(); } TypeNode DatatypeAscriptionTypeRule::computeType(NodeManager* nodeManager, @@ -319,10 +322,10 @@ TypeNode DtBoundTypeRule::computeType(NodeManager* nodeManager, throw TypeCheckingExceptionPrivate( n, "expecting datatype bound term to have datatype argument."); } - if (n[1].getKind() != kind::CONST_RATIONAL) + if (!n[1].isConst() || !n[1].getType().isInteger()) { - throw TypeCheckingExceptionPrivate(n, - "datatype bound must be a constant"); + throw TypeCheckingExceptionPrivate( + n, "datatype bound must be a constant integer"); } if (n[1].getConst<Rational>().getNumerator().sgn() == -1) { @@ -333,34 +336,9 @@ TypeNode DtBoundTypeRule::computeType(NodeManager* nodeManager, return nodeManager->booleanType(); } -TypeNode DtSygusBoundTypeRule::computeType(NodeManager* nodeManager, - TNode n, - bool check) -{ - if (check) - { - if (!n[0].getType().isDatatype()) - { - throw TypeCheckingExceptionPrivate( - n, "datatype sygus bound takes a datatype"); - } - if (n[1].getKind() != kind::CONST_RATIONAL) - { - throw TypeCheckingExceptionPrivate( - n, "datatype sygus bound must be a constant"); - } - if (n[1].getConst<Rational>().getNumerator().sgn() == -1) - { - throw TypeCheckingExceptionPrivate( - n, "datatype sygus bound must be non-negative"); - } - } - return nodeManager->booleanType(); -} - -TypeNode DtSyguEvalTypeRule::computeType(NodeManager* nodeManager, - TNode n, - bool check) +TypeNode DtSygusEvalTypeRule::computeType(NodeManager* nodeManager, + TNode n, + bool check) { TypeNode headType = n[0].getType(check); if (!headType.isDatatype()) diff --git a/src/theory/datatypes/theory_datatypes_type_rules.h b/src/theory/datatypes/theory_datatypes_type_rules.h index 7cf98aa74..3b1276221 100644 --- a/src/theory/datatypes/theory_datatypes_type_rules.h +++ b/src/theory/datatypes/theory_datatypes_type_rules.h @@ -64,12 +64,7 @@ class DtBoundTypeRule { static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check); }; -class DtSygusBoundTypeRule { - public: - static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check); -}; - -class DtSyguEvalTypeRule +class DtSygusEvalTypeRule { public: static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check); diff --git a/src/theory/datatypes/theory_datatypes_utils.cpp b/src/theory/datatypes/theory_datatypes_utils.cpp index 3b36ad2f2..a429f8333 100644 --- a/src/theory/datatypes/theory_datatypes_utils.cpp +++ b/src/theory/datatypes/theory_datatypes_utils.cpp @@ -63,12 +63,7 @@ Node mkApplyCons(TypeNode tn, // add type ascription for ambiguous constructor types Debug("datatypes-parametric") << "Constructor is " << dt[index] << std::endl; - TypeNode tspec = dt[index].getSpecializedConstructorType(tn); - Debug("datatypes-parametric") - << "Type specification is " << tspec << std::endl; - cchildren[0] = nm->mkNode(APPLY_TYPE_ASCRIPTION, - nm->mkConst(AscriptionType(tspec)), - cchildren[0]); + cchildren[0] = dt[index].getInstantiatedConstructor(tn); } return nm->mkNode(APPLY_CONSTRUCTOR, cchildren); } diff --git a/src/theory/datatypes/type_enumerator.cpp b/src/theory/datatypes/type_enumerator.cpp index 6528f1052..69ebc9c78 100644 --- a/src/theory/datatypes/type_enumerator.cpp +++ b/src/theory/datatypes/type_enumerator.cpp @@ -143,11 +143,7 @@ Node DatatypesEnumerator::getTermEnum( TypeNode tn, unsigned i ){ NodeBuilder b(kind::APPLY_CONSTRUCTOR); if (d_datatype.isParametric()) { - NodeManager* nm = NodeManager::currentNM(); - TypeNode typ = ctor.getSpecializedConstructorType(d_type); - b << nm->mkNode(kind::APPLY_TYPE_ASCRIPTION, - nm->mkConst(AscriptionType(typ)), - ctor.getConstructor()); + b << ctor.getInstantiatedConstructor(d_type); } else { @@ -245,7 +241,7 @@ Node DatatypesEnumerator::getTermEnum( TypeNode tn, unsigned i ){ TypeNode typ; if (d_datatype.isParametric()) { - typ = ctor.getSpecializedConstructorType(d_type); + typ = ctor.getInstantiatedConstructorType(d_type); } for (unsigned a = 0; a < ctor.getNumArgs(); ++a) { diff --git a/src/theory/difficulty_manager.cpp b/src/theory/difficulty_manager.cpp index 0a9eba60d..7714abfa9 100644 --- a/src/theory/difficulty_manager.cpp +++ b/src/theory/difficulty_manager.cpp @@ -26,20 +26,30 @@ namespace cvc5 { namespace theory { DifficultyManager::DifficultyManager(context::Context* c, Valuation val) - : d_val(val), d_dfmap(c) + : d_input(c), d_val(val), d_dfmap(c) { } +void DifficultyManager::notifyInputAssertions( + const std::vector<Node>& assertions) +{ + for (const Node& a : assertions) + { + d_input.insert(a); + } +} + void DifficultyManager::getDifficultyMap(std::map<Node, Node>& dmap) { NodeManager* nm = NodeManager::currentNM(); for (const std::pair<const Node, uint64_t> p : d_dfmap) { - dmap[p.first] = nm->mkConst(CONST_RATIONAL, Rational(p.second)); + dmap[p.first] = nm->mkConstInt(Rational(p.second)); } } -void DifficultyManager::notifyLemma(const std::map<TNode, TNode>& rse, Node n) +void DifficultyManager::notifyLemma(const context::CDHashMap<Node, Node>& rse, + Node n) { if (options::difficultyMode() != options::DifficultyMode::LEMMA_LITERAL) { @@ -63,7 +73,7 @@ void DifficultyManager::notifyLemma(const std::map<TNode, TNode>& rse, Node n) { litsToCheck.push_back(n); } - std::map<TNode, TNode>::const_iterator it; + context::CDHashMap<Node, Node>::const_iterator it; for (TNode nc : litsToCheck) { bool pol = nc.getKind() != kind::NOT; @@ -72,23 +82,23 @@ void DifficultyManager::notifyLemma(const std::map<TNode, TNode>& rse, Node n) Trace("diff-man-debug") << "Check literal: " << atom << ", has reason = " << (it != rse.end()) << std::endl; - if (it != rse.end()) + // must be an input assertion + if (it != rse.end() && d_input.find(it->second) != d_input.end()) { incrementDifficulty(it->second); } } } -void DifficultyManager::notifyCandidateModel(const NodeList& input, - TheoryModel* m) +void DifficultyManager::notifyCandidateModel(TheoryModel* m) { if (options::difficultyMode() != options::DifficultyMode::MODEL_CHECK) { return; } Trace("diff-man") << "DifficultyManager::notifyCandidateModel, #input=" - << input.size() << std::endl; - for (const Node& a : input) + << d_input.size() << std::endl; + for (const Node& a : d_input) { // should have miniscoped the assertions upstream Assert(a.getKind() != kind::AND); diff --git a/src/theory/difficulty_manager.h b/src/theory/difficulty_manager.h index 3030bcc9b..1437965fe 100644 --- a/src/theory/difficulty_manager.h +++ b/src/theory/difficulty_manager.h @@ -19,7 +19,7 @@ #define CVC5__THEORY__DIFFICULTY_MANAGER__H #include "context/cdhashmap.h" -#include "context/cdlist.h" +#include "context/cdhashset.h" #include "expr/node.h" #include "theory/valuation.h" @@ -34,11 +34,13 @@ class TheoryModel; */ class DifficultyManager { - typedef context::CDList<Node> NodeList; + typedef context::CDHashSet<Node> NodeSet; typedef context::CDHashMap<Node, uint64_t> NodeUIntMap; public: DifficultyManager(context::Context* c, Valuation val); + /** Notify input assertions */ + void notifyInputAssertions(const std::vector<Node>& assertions); /** * Get difficulty map, which populates dmap mapping preprocessed assertions * to a difficulty measure (a constant integer). @@ -56,19 +58,23 @@ class DifficultyManager * the reason why that literal was relevant in the current context * @param lem The lemma */ - void notifyLemma(const std::map<TNode, TNode>& rse, Node lem); + void notifyLemma(const context::CDHashMap<Node, Node>& rse, Node lem); /** * Notify that `m` is a (candidate) model. This increments the difficulty * of assertions that are not satisfied by that model. * - * @param input The list of preprocessed assertions * @param m The candidate model. */ - void notifyCandidateModel(const NodeList& input, TheoryModel* m); + void notifyCandidateModel(TheoryModel* m); private: /** Increment difficulty on assertion a */ void incrementDifficulty(TNode a, uint64_t amount = 1); + /** + * The input assertions, tracked to ensure we do not increment difficulty + * on lemmas. + */ + NodeSet d_input; /** The valuation object, used to query current value of theory literals */ Valuation d_val; /** diff --git a/src/theory/evaluator.cpp b/src/theory/evaluator.cpp index 27e67dd9f..9451f9995 100644 --- a/src/theory/evaluator.cpp +++ b/src/theory/evaluator.cpp @@ -458,6 +458,29 @@ EvalResult Evaluator::evalInternal( results[currNode] = EvalResult(res); break; } + case kind::DIVISION: + case kind::DIVISION_TOTAL: + { + Rational res = results[currNode[0]].d_rat; + bool divbyzero = false; + for (size_t i = 1, end = currNode.getNumChildren(); i < end; i++) + { + if (results[currNode[i]].d_rat.isZero()) + { + Trace("evaluator") + << "Division by zero not supported" << std::endl; + divbyzero = true; + results[currNode] = EvalResult(); + break; + } + res = res / results[currNode[i]].d_rat; + } + if (!divbyzero) + { + results[currNode] = EvalResult(res); + } + break; + } case kind::GEQ: { diff --git a/src/theory/ext_theory.h b/src/theory/ext_theory.h index 998dac146..ecd061e7c 100644 --- a/src/theory/ext_theory.h +++ b/src/theory/ext_theory.h @@ -77,6 +77,8 @@ enum class ExtReducedId STRINGS_REGEXP_INCLUDE, // subsumed due to RE inclusion reasoning for negative memberships STRINGS_REGEXP_INCLUDE_NEG, + // reduction for seq.nth over seq.rev + STRINGS_NTH_REV, }; /** * Converts an ext reduced identifier to a string. diff --git a/src/theory/fp/fp_word_blaster.h b/src/theory/fp/fp_word_blaster.h index f9ec4fd4e..f7c7f26be 100644 --- a/src/theory/fp/fp_word_blaster.h +++ b/src/theory/fp/fp_word_blaster.h @@ -34,15 +34,6 @@ #include "util/floatingpoint_size.h" #include "util/hash.h" -#ifdef CVC5_SYM_SYMBOLIC_EVAL -// This allows debugging of the cvc5 symbolic back-end. -// By enabling this and disabling constant folding in the rewriter, -// SMT files that have operations on constants will be evaluated -// during the encoding step, which means that the expressions -// generated by the symbolic back-end can be debugged with gdb. -#include "theory/rewriter.h" -#endif - namespace cvc5 { namespace theory { namespace fp { @@ -100,16 +91,7 @@ typedef traits::bwt bwt; class nodeWrapper : public Node { protected: -/* CVC5_SYM_SYMBOLIC_EVAL is for debugging cvc5 symbolic back-end issues. - * Enable this and disabling constant folding will mean that operations - * that are input with constant args are 'folded' using the symbolic encoding - * allowing them to be traced via GDB. - */ -#ifdef CVC5_SYM_SYMBOLIC_EVAL - nodeWrapper(const Node& n) : Node(theory::Rewriter::rewrite(n)) {} -#else nodeWrapper(const Node& n) : Node(n) {} -#endif }; class symbolicProposition : public nodeWrapper diff --git a/src/theory/incomplete_id.cpp b/src/theory/incomplete_id.cpp index c763fb9a0..b1071b5ae 100644 --- a/src/theory/incomplete_id.cpp +++ b/src/theory/incomplete_id.cpp @@ -35,6 +35,8 @@ const char* toString(IncompleteId i) return "QUANTIFIERS_RECORDED_INST"; case IncompleteId::QUANTIFIERS_MAX_INST_ROUNDS: return "QUANTIFIERS_MAX_INST_ROUNDS"; + case IncompleteId::QUANTIFIERS_SYGUS_SOLVED: + return "QUANTIFIERS_SYGUS_SOLVED"; case IncompleteId::SEP: return "SEP"; case IncompleteId::SETS_RELS_CARD: return "SETS_RELS_CARD"; case IncompleteId::STRINGS_LOOP_SKIP: return "STRINGS_LOOP_SKIP"; diff --git a/src/theory/incomplete_id.h b/src/theory/incomplete_id.h index aaa458d8e..1e8bf155a 100644 --- a/src/theory/incomplete_id.h +++ b/src/theory/incomplete_id.h @@ -44,6 +44,9 @@ enum class IncompleteId QUANTIFIERS_RECORDED_INST, // incomplete due to limited number of allowed instantiation rounds QUANTIFIERS_MAX_INST_ROUNDS, + // we solved a negated synthesis conjecture and will terminate as a subsolver + // with unknown + QUANTIFIERS_SYGUS_SOLVED, // incomplete due to separation logic SEP, // relations were used in combination with set cardinality constraints diff --git a/src/theory/inference_id.cpp b/src/theory/inference_id.cpp index 56d2f0500..ced885abb 100644 --- a/src/theory/inference_id.cpp +++ b/src/theory/inference_id.cpp @@ -119,6 +119,7 @@ const char* toString(InferenceId i) case InferenceId::BAGS_DUPLICATE_REMOVAL: return "BAGS_DUPLICATE_REMOVAL"; case InferenceId::BAGS_MAP: return "BAGS_MAP"; case InferenceId::BAGS_FOLD: return "BAGS_FOLD"; + case InferenceId::BAGS_CARD: return "BAGS_CARD"; case InferenceId::BV_BITBLAST_CONFLICT: return "BV_BITBLAST_CONFLICT"; case InferenceId::BV_BITBLAST_INTERNAL_EAGER_LEMMA: @@ -229,12 +230,6 @@ const char* toString(InferenceId i) return "QUANTIFIERS_SYGUS_EXCLUDE_CURRENT"; case InferenceId::QUANTIFIERS_SYGUS_STREAM_EXCLUDE_CURRENT: return "QUANTIFIERS_SYGUS_STREAM_EXCLUDE_CURRENT"; - case InferenceId::QUANTIFIERS_SYGUS_SI_SOLVED: - return "QUANTIFIERS_SYGUS_SI_SOLVED"; - case InferenceId::QUANTIFIERS_SYGUS_SAMPLE_TRUST_SOLVED: - return "QUANTIFIERS_SYGUS_SAMPLE_TRUST_SOLVED"; - case InferenceId::QUANTIFIERS_SYGUS_VERIFY_SOLVED: - return "QUANTIFIERS_SYGUS_VERIFY_SOLVED"; case InferenceId::QUANTIFIERS_SYGUS_EXAMPLE_INFER_CONTRA: return "QUANTIFIERS_SYGUS_EXAMPLE_INFER_CONTRA"; case InferenceId::QUANTIFIERS_SYGUS_UNIF_PI_INTER_ENUM_SB: @@ -412,6 +407,11 @@ const char* toString(InferenceId i) case InferenceId::STRINGS_ARRAY_NTH_UNIT: return "STRINGS_ARRAY_NTH_UNIT"; case InferenceId::STRINGS_ARRAY_NTH_CONCAT: return "STRINGS_ARRAY_NTH_CONCAT"; + case InferenceId::STRINGS_ARRAY_NTH_EXTRACT: + return "STRINGS_ARRAY_NTH_EXTRACT"; + case InferenceId::STRINGS_ARRAY_NTH_UPDATE: + return "STRINGS_ARRAY_NTH_UPDATE"; + case InferenceId::STRINGS_ARRAY_NTH_REV: return "STRINGS_ARRAY_NTH_REV"; case InferenceId::STRINGS_RE_NF_CONFLICT: return "STRINGS_RE_NF_CONFLICT"; case InferenceId::STRINGS_RE_UNFOLD_POS: return "STRINGS_RE_UNFOLD_POS"; case InferenceId::STRINGS_RE_UNFOLD_NEG: return "STRINGS_RE_UNFOLD_NEG"; @@ -470,8 +470,8 @@ std::ostream& operator<<(std::ostream& out, InferenceId i) Node mkInferenceIdNode(InferenceId i) { - return NodeManager::currentNM()->mkConst(CONST_RATIONAL, - Rational(static_cast<uint32_t>(i))); + return NodeManager::currentNM()->mkConstInt( + Rational(static_cast<uint32_t>(i))); } bool getInferenceId(TNode n, InferenceId& i) diff --git a/src/theory/inference_id.h b/src/theory/inference_id.h index d98d3ff25..f0c726f78 100644 --- a/src/theory/inference_id.h +++ b/src/theory/inference_id.h @@ -181,6 +181,7 @@ enum class InferenceId BAGS_DUPLICATE_REMOVAL, BAGS_MAP, BAGS_FOLD, + BAGS_CARD, // ---------------------------------- end bags theory // ---------------------------------- bitvector theory @@ -342,12 +343,6 @@ enum class InferenceId QUANTIFIERS_SYGUS_EXCLUDE_CURRENT, // manual exclusion of a current solution for sygus-stream QUANTIFIERS_SYGUS_STREAM_EXCLUDE_CURRENT, - // Q where Q was solved by a subcall to the single invocation module - QUANTIFIERS_SYGUS_SI_SOLVED, - // Q where Q was (trusted) solved by sampling - QUANTIFIERS_SYGUS_SAMPLE_TRUST_SOLVED, - // Q where Q was solved by a verification subcall - QUANTIFIERS_SYGUS_VERIFY_SOLVED, // ~Q where Q is a PBE conjecture with conflicting examples QUANTIFIERS_SYGUS_EXAMPLE_INFER_CONTRA, // unif+pi symmetry breaking between multiple enumerators @@ -693,6 +688,12 @@ enum class InferenceId STRINGS_ARRAY_NTH_UNIT, // nth over conatenation STRINGS_ARRAY_NTH_CONCAT, + // nth over extract + STRINGS_ARRAY_NTH_EXTRACT, + // nth over update + STRINGS_ARRAY_NTH_UPDATE, + // nth over reverse + STRINGS_ARRAY_NTH_REV, //-------------------- regexp solver // regular expression normal form conflict // ( x in R ^ x = y ^ rewrite((str.in_re y R)) = false ) => false diff --git a/src/theory/inference_id_proof_annotator.cpp b/src/theory/inference_id_proof_annotator.cpp new file mode 100644 index 000000000..5af98c4bf --- /dev/null +++ b/src/theory/inference_id_proof_annotator.cpp @@ -0,0 +1,55 @@ +/****************************************************************************** + * Top contributors (to current version): + * Andrew Reynolds + * + * This file is part of the cvc5 project. + * + * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS + * in the top-level source directory and their institutional affiliations. + * All rights reserved. See the file COPYING in the top-level source + * directory for licensing information. + * **************************************************************************** + * + * The inference id annotator class. + */ + +#include "theory/inference_id_proof_annotator.h" + +#include "proof/proof_node.h" +#include "proof/proof_node_manager.h" + +namespace cvc5 { +namespace theory { + +InferenceIdProofAnnotator::InferenceIdProofAnnotator(ProofNodeManager* pnm, + context::Context* c) + : d_pnm(pnm), d_ids(c), d_list(c) +{ +} +void InferenceIdProofAnnotator::setAnnotation(Node f, InferenceId id) +{ + d_ids[f] = id; +} + +std::shared_ptr<ProofNode> InferenceIdProofAnnotator::annotate( + std::shared_ptr<ProofNode> p) +{ + Node f = p->getResult(); + NodeInferenceIdMap::iterator it = d_ids.find(f); + if (it != d_ids.end()) + { + std::vector<Node> pfArgs; + pfArgs.push_back(mkInferenceIdNode(it->second)); + std::shared_ptr<ProofNode> pa = + d_pnm->mkNode(PfRule::ANNOTATION, {p}, pfArgs); + // for now, do a double annotation to make stats accurate + std::shared_ptr<ProofNode> paf = + d_pnm->mkNode(PfRule::ANNOTATION, {pa}, {}); + d_list.push_back(paf); + return paf; + } + return p; +} + +} // namespace theory +} // namespace cvc5 diff --git a/src/theory/inference_id_proof_annotator.h b/src/theory/inference_id_proof_annotator.h new file mode 100644 index 000000000..8346370f1 --- /dev/null +++ b/src/theory/inference_id_proof_annotator.h @@ -0,0 +1,64 @@ +/****************************************************************************** + * Top contributors (to current version): + * Andrew Reynolds + * + * This file is part of the cvc5 project. + * + * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS + * in the top-level source directory and their institutional affiliations. + * All rights reserved. See the file COPYING in the top-level source + * directory for licensing information. + * **************************************************************************** + * + * The inference id annotator class. + */ + +#include "cvc5_private.h" + +#ifndef CVC5__THEORY__INFERENCE_ID_PROOF_ANNOTATOR_H +#define CVC5__THEORY__INFERENCE_ID_PROOF_ANNOTATOR_H + +#include "context/cdhashmap.h" +#include "context/cdlist.h" +#include "expr/node.h" +#include "proof/annotation_proof_generator.h" +#include "theory/inference_id.h" + +namespace cvc5 { +namespace theory { + +/** A class that tracks formulas to inference id annotations */ +class InferenceIdProofAnnotator : public Annotator +{ + typedef context::CDHashMap<Node, InferenceId> NodeInferenceIdMap; + typedef context::CDList<std::shared_ptr<ProofNode>> ProofNodeList; + + public: + InferenceIdProofAnnotator(ProofNodeManager* pnm, context::Context* c); + /** Set annotation, that formula f should be annotated by id */ + void setAnnotation(Node f, InferenceId id); + /** + * Annotate the proof node with the appropriate inference ID. Given proof + * P proving F that was generated as a lemma with inference id `i`, this + * returns (ANNOTATION (ANNOTATION P : args i)). The outer ANNOTATION is + * used since commonly a proof node is "linked" into another, where its + * children and rule are copied into another. Using ANNOTATION (with no + * arguments) ensures the top-most ANNOTATION may be linked/copied + * multiple times; however its child (which counts `i`) will only appear + * once in the final proof. + */ + std::shared_ptr<ProofNode> annotate(std::shared_ptr<ProofNode> p) override; + + private: + /** The proof node manager of the theory */ + ProofNodeManager* d_pnm; + /** The inference id for each formula */ + NodeInferenceIdMap d_ids; + /** Ensure we keep proof nodes alive */ + ProofNodeList d_list; +}; + +} // namespace theory +} // namespace cvc5 + +#endif /* CVC5__THEORY__INFERENCE_ID_PROOF_ANNOTATOR_H */ diff --git a/src/theory/inference_manager_buffered.cpp b/src/theory/inference_manager_buffered.cpp index 8b4880feb..963e0b95c 100644 --- a/src/theory/inference_manager_buffered.cpp +++ b/src/theory/inference_manager_buffered.cpp @@ -161,14 +161,14 @@ std::size_t InferenceManagerBuffered::numPendingFacts() const return d_pendingFact.size(); } -void InferenceManagerBuffered::lemmaTheoryInference(TheoryInference* lem) +bool InferenceManagerBuffered::lemmaTheoryInference(TheoryInference* lem) { // process this lemma LemmaProperty p = LemmaProperty::NONE; TrustNode tlem = lem->processLemma(p); Assert(!tlem.isNull()); // send the lemma - trustedLemma(tlem, lem->getId(), p); + return trustedLemma(tlem, lem->getId(), p); } void InferenceManagerBuffered::assertInternalFactTheoryInference( diff --git a/src/theory/inference_manager_buffered.h b/src/theory/inference_manager_buffered.h index e93152f72..579b1ae87 100644 --- a/src/theory/inference_manager_buffered.h +++ b/src/theory/inference_manager_buffered.h @@ -149,9 +149,10 @@ class InferenceManagerBuffered : public TheoryInferenceManager /** * Send the given theory inference as a lemma on the output channel of this * inference manager. This calls TheoryInferenceManager::trustedLemma based - * on the provided theory inference. + * on the provided theory inference, and returns true if the lemma was + * successfully sent. */ - void lemmaTheoryInference(TheoryInference* lem); + bool lemmaTheoryInference(TheoryInference* lem); /** * Add the given theory inference as an internal fact. This calls * TheoryInferenceManager::assertInternalFact based on the provided theory diff --git a/src/theory/quantifiers/cegqi/ceg_arith_instantiator.cpp b/src/theory/quantifiers/cegqi/ceg_arith_instantiator.cpp index 2d483d502..56debbbac 100644 --- a/src/theory/quantifiers/cegqi/ceg_arith_instantiator.cpp +++ b/src/theory/quantifiers/cegqi/ceg_arith_instantiator.cpp @@ -818,7 +818,7 @@ CegTermType ArithInstantiator::solve_arith(CegInstantiator* ci, // multiply by the coefficient we will isolate for if (itv->second.isNull()) { - vts_coeff[t] = ArithMSum::negate(vts_coeff[t]); + vts_coeff[t] = negate(vts_coeff[t]); } else { @@ -833,7 +833,7 @@ CegTermType ArithInstantiator::solve_arith(CegInstantiator* ci, } else if (itv->second.getConst<Rational>().sgn() == 1) { - vts_coeff[t] = ArithMSum::negate(vts_coeff[t]); + vts_coeff[t] = negate(vts_coeff[t]); } } } @@ -1040,6 +1040,13 @@ Node ArithInstantiator::getModelBasedProjectionValue(CegInstantiator* ci, return val; } +Node ArithInstantiator::negate(const Node& t) const +{ + NodeManager* nm = NodeManager::currentNM(); + return rewrite( + nm->mkNode(MULT, nm->mkConstRealOrInt(t.getType(), Rational(-1)), t)); +} + } // namespace quantifiers } // namespace theory } // namespace cvc5 diff --git a/src/theory/quantifiers/cegqi/ceg_arith_instantiator.h b/src/theory/quantifiers/cegqi/ceg_arith_instantiator.h index e102b834e..d44ab4993 100644 --- a/src/theory/quantifiers/cegqi/ceg_arith_instantiator.h +++ b/src/theory/quantifiers/cegqi/ceg_arith_instantiator.h @@ -206,6 +206,8 @@ class ArithInstantiator : public Instantiator Node theta, Node inf_coeff, Node delta_coeff); + /** Return the rewritten form of the negation of t */ + Node negate(const Node& t) const; }; } // namespace quantifiers diff --git a/src/theory/quantifiers/cegqi/ceg_instantiator.cpp b/src/theory/quantifiers/cegqi/ceg_instantiator.cpp index 9556d3f9c..81ae18f4f 100644 --- a/src/theory/quantifiers/cegqi/ceg_instantiator.cpp +++ b/src/theory/quantifiers/cegqi/ceg_instantiator.cpp @@ -163,8 +163,8 @@ void SolvedForm::push_back(Node pv, Node n, TermProperties& pv_prop) } else { - Assert(new_theta.getKind() == CONST_RATIONAL); - Assert(pv_prop.d_coeff.getKind() == CONST_RATIONAL); + Assert(new_theta.isConst()); + Assert(pv_prop.d_coeff.isConst()); NodeManager* nm = NodeManager::currentNM(); new_theta = nm->mkConst(CONST_RATIONAL, Rational(new_theta.getConst<Rational>() @@ -357,7 +357,7 @@ CegHandledStatus CegInstantiator::isCbqiSort( if (dt.isParametric()) { // if parametric, must instantiate the argument types - consType = dt[i].getSpecializedConstructorType(tn); + consType = dt[i].getInstantiatedConstructorType(tn); } else { @@ -1165,8 +1165,7 @@ Node CegInstantiator::applySubstitution( TypeNode tn, Node n, std::vector< Node Node nn = NodeManager::currentNM()->mkNode( MULT, subs[i], - NodeManager::currentNM()->mkConst( - CONST_RATIONAL, + NodeManager::currentNM()->mkConstReal( Rational(1) / prop[i].d_coeff.getConst<Rational>())); nn = NodeManager::currentNM()->mkNode( kind::TO_INTEGER, nn ); nn = rewrite(nn); @@ -1214,10 +1213,9 @@ Node CegInstantiator::applySubstitution( TypeNode tn, Node n, std::vector< Node for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){ Node c_coeff; if( !msum_coeff[it->first].isNull() ){ - c_coeff = rewrite(NodeManager::currentNM()->mkConst( - CONST_RATIONAL, + c_coeff = rewrite(NodeManager::currentNM()->mkConstReal( pv_prop.d_coeff.getConst<Rational>() - / msum_coeff[it->first].getConst<Rational>())); + / msum_coeff[it->first].getConst<Rational>())); }else{ c_coeff = pv_prop.d_coeff; } @@ -1283,7 +1281,7 @@ Node CegInstantiator::applySubstitutionToLiteral( Node lit, std::vector< Node >& }else{ atom_lhs = nm->mkNode(MINUS, atom[0], atom[1]); atom_lhs = rewrite(atom_lhs); - atom_rhs = nm->mkConst(CONST_RATIONAL, Rational(0)); + atom_rhs = nm->mkConstRealOrInt(atom_lhs.getType(), Rational(0)); } //must be an eligible term if( isEligible( atom_lhs ) ){ diff --git a/src/theory/quantifiers/cegqi/inst_strategy_cegqi.cpp b/src/theory/quantifiers/cegqi/inst_strategy_cegqi.cpp index 65ad79e29..2555ff637 100644 --- a/src/theory/quantifiers/cegqi/inst_strategy_cegqi.cpp +++ b/src/theory/quantifiers/cegqi/inst_strategy_cegqi.cpp @@ -56,10 +56,10 @@ InstStrategyCegqi::InstStrategyCegqi(Env& env, d_cbqi_set_quant_inactive(false), d_incomplete_check(false), d_added_cbqi_lemma(userContext()), - d_vtsCache(new VtsTermCache(qim)), + d_vtsCache(new VtsTermCache(env, qim)), d_bv_invert(nullptr), - d_small_const_multiplier(NodeManager::currentNM()->mkConst( - CONST_RATIONAL, Rational(1) / Rational(1000000))), + d_small_const_multiplier(NodeManager::currentNM()->mkConstReal( + Rational(1) / Rational(1000000))), d_small_const(d_small_const_multiplier) { d_check_vts_lemma_lc = false; @@ -435,6 +435,7 @@ void InstStrategyCegqi::process( Node q, Theory::Effort effort, int e ) { } d_curr_quant = Node::null(); }else if( e==1 ){ + NodeManager* nm = NodeManager::currentNM(); //minimize the free delta heuristically on demand if( d_check_vts_lemma_lc ){ Trace("inst-alg") << "-> Minimize delta heuristic, for " << q << std::endl; @@ -453,12 +454,10 @@ void InstStrategyCegqi::process( Node q, Theory::Effort effort, int e ) { d_vtsCache->getVtsTerms(inf, true, false, false); for( unsigned i=0; i<inf.size(); i++ ){ Trace("quant-vts-debug") << "Infinity lemma for " << inf[i] << " " << d_small_const << std::endl; - Node inf_lem_lb = NodeManager::currentNM()->mkNode( + Node inf_lem_lb = nm->mkNode( GT, inf[i], - NodeManager::currentNM()->mkConst( - CONST_RATIONAL, - Rational(1) / d_small_const.getConst<Rational>())); + nm->mkConstReal(Rational(1) / d_small_const.getConst<Rational>())); d_qim.lemma(inf_lem_lb, InferenceId::QUANTIFIERS_CEGQI_VTS_LB_INF); } } diff --git a/src/theory/quantifiers/cegqi/vts_term_cache.cpp b/src/theory/quantifiers/cegqi/vts_term_cache.cpp index 37ded9b7f..058b6a8bf 100644 --- a/src/theory/quantifiers/cegqi/vts_term_cache.cpp +++ b/src/theory/quantifiers/cegqi/vts_term_cache.cpp @@ -28,9 +28,9 @@ namespace cvc5 { namespace theory { namespace quantifiers { -VtsTermCache::VtsTermCache(QuantifiersInferenceManager& qim) : d_qim(qim) +VtsTermCache::VtsTermCache(Env& env, QuantifiersInferenceManager& qim) + : EnvObj(env), d_qim(qim) { - d_zero = NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(0)); } void VtsTermCache::getVtsTerms(std::vector<Node>& t, @@ -70,7 +70,8 @@ Node VtsTermCache::getVtsDelta(bool isFree, bool create) sm->mkDummySkolem("delta_free", nm->realType(), "free delta for virtual term substitution"); - Node delta_lem = nm->mkNode(GT, d_vts_delta_free, d_zero); + Node zero = nm->mkConstReal(Rational(0)); + Node delta_lem = nm->mkNode(GT, d_vts_delta_free, zero); d_qim.lemma(delta_lem, InferenceId::QUANTIFIERS_CEGQI_VTS_LB_DELTA); } if (d_vts_delta.isNull()) @@ -155,7 +156,7 @@ Node VtsTermCache::rewriteVtsSymbols(Node n) subs_lhs.end(), subs_rhs.begin(), subs_rhs.end()); - n = Rewriter::rewrite(n); + n = rewrite(n); // may have cancelled if (!expr::hasSubterm(n, rew_vts_inf)) { @@ -215,13 +216,17 @@ Node VtsTermCache::rewriteVtsSymbols(Node n) { nlit = nm->mkConst(false); } - else if (res == 1) - { - nlit = nm->mkNode(GEQ, d_zero, slv); - } else { - nlit = nm->mkNode(GT, slv, d_zero); + Node zero = nm->mkConstRealOrInt(slv.getType(), Rational(0)); + if (res == 1) + { + nlit = nm->mkNode(GEQ, zero, slv); + } + else + { + nlit = nm->mkNode(GT, slv, zero); + } } } } diff --git a/src/theory/quantifiers/cegqi/vts_term_cache.h b/src/theory/quantifiers/cegqi/vts_term_cache.h index d3a6558cf..7ae16aec8 100644 --- a/src/theory/quantifiers/cegqi/vts_term_cache.h +++ b/src/theory/quantifiers/cegqi/vts_term_cache.h @@ -19,8 +19,10 @@ #define CVC5__THEORY__QUANTIFIERS__CEGQI__VTS_TERM_CACHE_H #include <map> + #include "expr/attribute.h" #include "expr/node.h" +#include "smt/env_obj.h" namespace cvc5 { namespace theory { @@ -68,10 +70,10 @@ class QuantifiersInferenceManager; * that combine instantiating quantified formulas with nested quantifiers * with terms containing virtual terms. */ -class VtsTermCache +class VtsTermCache : protected EnvObj { public: - VtsTermCache(QuantifiersInferenceManager& qim); + VtsTermCache(Env& env, QuantifiersInferenceManager& qim); ~VtsTermCache() {} /** * Get vts delta. The argument isFree indicates if we are getting the @@ -125,8 +127,6 @@ class VtsTermCache private: /** Reference to the quantifiers inference manager */ QuantifiersInferenceManager& d_qim; - /** constants */ - Node d_zero; /** The virtual term substitution delta */ Node d_vts_delta; /** The virtual term substitution "free delta" */ diff --git a/src/theory/quantifiers/ematching/pattern_term_selector.cpp b/src/theory/quantifiers/ematching/pattern_term_selector.cpp index 9933eb6c9..e4d7436c8 100644 --- a/src/theory/quantifiers/ematching/pattern_term_selector.cpp +++ b/src/theory/quantifiers/ematching/pattern_term_selector.cpp @@ -678,8 +678,7 @@ Node PatternTermSelector::getInversion(Node n, Node x) Assert(nc.isConst()); if (x.getType().isInteger()) { - Node coeff = - nm->mkConst(CONST_RATIONAL, nc.getConst<Rational>().abs()); + Node coeff = nm->mkConstInt(nc.getConst<Rational>().abs()); if (!nc.getConst<Rational>().abs().isOne()) { x = nm->mkNode(INTS_DIVISION_TOTAL, x, coeff); @@ -691,8 +690,7 @@ Node PatternTermSelector::getInversion(Node n, Node x) } else { - Node coeff = nm->mkConst(CONST_RATIONAL, - Rational(1) / nc.getConst<Rational>()); + Node coeff = nm->mkConstReal(Rational(1) / nc.getConst<Rational>()); x = nm->mkNode(MULT, x, coeff); } } diff --git a/src/theory/quantifiers/extended_rewrite.cpp b/src/theory/quantifiers/extended_rewrite.cpp index 4ed918b43..1152267e8 100644 --- a/src/theory/quantifiers/extended_rewrite.cpp +++ b/src/theory/quantifiers/extended_rewrite.cpp @@ -49,7 +49,7 @@ ExtendedRewriter::ExtendedRewriter(Rewriter& rew, bool aggr) { d_true = NodeManager::currentNM()->mkConst(true); d_false = NodeManager::currentNM()->mkConst(false); - d_zero = NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(0)); + d_intZero = NodeManager::currentNM()->mkConstInt(Rational(0)); } void ExtendedRewriter::setCache(Node n, Node ret) const @@ -1723,7 +1723,7 @@ Node ExtendedRewriter::extendedRewriteStrings(Node node) const strings::ArithEntail aent(&d_rew); // (str.substr s x y) --> "" if x < len(s) |= 0 >= y Node n1_lt_tot_len = d_rew.rewrite(nm->mkNode(LT, node[1], tot_len)); - if (aent.checkWithAssumption(n1_lt_tot_len, d_zero, node[2], false)) + if (aent.checkWithAssumption(n1_lt_tot_len, d_intZero, node[2], false)) { Node ret = strings::Word::mkEmptyWord(node.getType()); debugExtendedRewrite(node, ret, "SS_START_ENTAILS_ZERO_LEN"); @@ -1731,7 +1731,7 @@ Node ExtendedRewriter::extendedRewriteStrings(Node node) const } // (str.substr s x y) --> "" if 0 < y |= x >= str.len(s) - Node non_zero_len = d_rew.rewrite(nm->mkNode(LT, d_zero, node[2])); + Node non_zero_len = d_rew.rewrite(nm->mkNode(LT, d_intZero, node[2])); if (aent.checkWithAssumption(non_zero_len, node[1], tot_len, false)) { Node ret = strings::Word::mkEmptyWord(node.getType()); @@ -1739,8 +1739,8 @@ Node ExtendedRewriter::extendedRewriteStrings(Node node) const return ret; } // (str.substr s x y) --> "" if x >= 0 |= 0 >= str.len(s) - Node geq_zero_start = d_rew.rewrite(nm->mkNode(GEQ, node[1], d_zero)); - if (aent.checkWithAssumption(geq_zero_start, d_zero, tot_len, false)) + Node geq_zero_start = d_rew.rewrite(nm->mkNode(GEQ, node[1], d_intZero)); + if (aent.checkWithAssumption(geq_zero_start, d_intZero, tot_len, false)) { Node ret = strings::Word::mkEmptyWord(node.getType()); debugExtendedRewrite(node, ret, "SS_GEQ_ZERO_START_ENTAILS_EMP_S"); diff --git a/src/theory/quantifiers/extended_rewrite.h b/src/theory/quantifiers/extended_rewrite.h index 1b9d0dae4..bf5829e03 100644 --- a/src/theory/quantifiers/extended_rewrite.h +++ b/src/theory/quantifiers/extended_rewrite.h @@ -262,7 +262,7 @@ class ExtendedRewriter /** Common constant nodes */ Node d_true; Node d_false; - Node d_zero; + Node d_intZero; }; } // namespace quantifiers diff --git a/src/theory/quantifiers/fmf/bounded_integers.cpp b/src/theory/quantifiers/fmf/bounded_integers.cpp index b5b9e7d88..5c0283863 100644 --- a/src/theory/quantifiers/fmf/bounded_integers.cpp +++ b/src/theory/quantifiers/fmf/bounded_integers.cpp @@ -59,7 +59,7 @@ BoundedIntegers::IntRangeDecisionHeuristic::IntRangeDecisionHeuristic( Node BoundedIntegers::IntRangeDecisionHeuristic::mkLiteral(unsigned n) { NodeManager* nm = NodeManager::currentNM(); - Node cn = nm->mkConst(CONST_RATIONAL, Rational(n == 0 ? 0 : n - 1)); + Node cn = nm->mkConstInt(Rational(n == 0 ? 0 : n - 1)); return nm->mkNode(n == 0 ? LT : LEQ, d_proxy_range, cn); } @@ -84,10 +84,9 @@ Node BoundedIntegers::IntRangeDecisionHeuristic::proxyCurrentRangeLemma() Node lem = nm->mkNode( EQUAL, currLit, - nm->mkNode( - curr == 0 ? LT : LEQ, - d_range, - nm->mkConst(CONST_RATIONAL, Rational(curr == 0 ? 0 : curr - 1)))); + nm->mkNode(curr == 0 ? LT : LEQ, + d_range, + nm->mkConstInt(Rational(curr == 0 ? 0 : curr - 1)))); return lem; } @@ -224,6 +223,7 @@ void BoundedIntegers::process( Node q, Node n, bool pol, std::map< Node, Node > msum; if (ArithMSum::getMonomialSumLit(n, msum)) { + NodeManager* nm = NodeManager::currentNM(); Trace("bound-int-debug") << "literal (polarity = " << pol << ") " << n << " is monomial sum : " << std::endl; ArithMSum::debugPrintMonomialSum(msum, "bound-int-debug"); for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){ @@ -240,11 +240,11 @@ void BoundedIntegers::process( Node q, Node n, bool pol, n1 = veq[1]; n2 = veq[0]; if( n1.getKind()==BOUND_VARIABLE ){ - n2 = ArithMSum::offset(n2, 1); + n2 = nm->mkNode(PLUS, n2, nm->mkConstInt(Rational(1))); }else{ - n1 = ArithMSum::offset(n1, -1); + n1 = nm->mkNode(PLUS, n1, nm->mkConstInt(Rational(-1))); } - veq = NodeManager::currentNM()->mkNode( GEQ, n1, n2 ); + veq = nm->mkNode(GEQ, n1, n2); } Trace("bound-int-debug") << "Isolated for " << it->first << " : (" << n1 << " >= " << n2 << ")" << std::endl; Node t = n1==it->first ? n2 : n1; @@ -693,8 +693,7 @@ Node BoundedIntegers::getSetRangeValue( Node q, Node v, RepSetIterator * rsi ) { } choices.pop_back(); Node bvl = nm->mkNode(BOUND_VAR_LIST, choice_i); - Node cMinCard = - nm->mkNode(LEQ, srCardN, nm->mkConst(CONST_RATIONAL, Rational(i))); + Node cMinCard = nm->mkNode(LEQ, srCardN, nm->mkConstInt(Rational(i))); choice_i = nm->mkNode(WITNESS, bvl, nm->mkNode(OR, cMinCard, cBody)); d_setm_choice[sro].push_back(choice_i); } @@ -818,8 +817,8 @@ bool BoundedIntegers::getBoundElements( RepSetIterator * rsi, bool initial, Node Node range = rewrite(nm->mkNode(MINUS, u, l)); // 9999 is an arbitrary range past which we do not do exhaustive // bounded instantation, based on the check below. - Node ra = rewrite(nm->mkNode( - LEQ, range, nm->mkConst(CONST_RATIONAL, Rational(9999)))); + Node ra = + rewrite(nm->mkNode(LEQ, range, nm->mkConstInt(Rational(9999)))); Node tl = l; Node tu = u; getBounds( q, v, rsi, tl, tu ); @@ -830,8 +829,7 @@ bool BoundedIntegers::getBoundElements( RepSetIterator * rsi, bool initial, Node Trace("bound-int-rsi") << "Actual bound range is " << rr << std::endl; for (long k = 0; k < rr; k++) { - Node t = - nm->mkNode(PLUS, tl, nm->mkConst(CONST_RATIONAL, Rational(k))); + Node t = nm->mkNode(PLUS, tl, nm->mkConstInt(Rational(k))); t = rewrite(t); elements.push_back( t ); } diff --git a/src/theory/quantifiers/fmf/full_model_check.cpp b/src/theory/quantifiers/fmf/full_model_check.cpp index be69617c7..c9e08b7a8 100644 --- a/src/theory/quantifiers/fmf/full_model_check.cpp +++ b/src/theory/quantifiers/fmf/full_model_check.cpp @@ -67,8 +67,9 @@ bool EntryTrie::hasGeneralization( FirstOrderModelFmc * m, Node c, int index ) { } if( c[index].getType().isSort() ){ //for star: check if all children are defined and have generalizations - if( c[index]==st ){ ///options::fmfFmcCoverSimplify() - //check if all children exist and are complete + if (c[index] == st) + { /// option fmfFmcCoverSimplify + // check if all children exist and are complete unsigned num_child_def = d_child.size() - (d_child.find(st) != d_child.end() ? 1 : 0); if (num_child_def == m->getRepSet()->getNumRepresentatives(tn)) diff --git a/src/theory/quantifiers/instantiation_list.cpp b/src/theory/quantifiers/instantiation_list.cpp index f4b52619a..81ef84ae0 100644 --- a/src/theory/quantifiers/instantiation_list.cpp +++ b/src/theory/quantifiers/instantiation_list.cpp @@ -16,6 +16,7 @@ #include "theory/quantifiers/instantiation_list.h" #include "options/base_options.h" +#include "options/io_utils.h" #include "printer/printer.h" namespace cvc5 { @@ -30,13 +31,15 @@ InstantiationVec::InstantiationVec(const std::vector<Node>& vec, void InstantiationList::initialize(Node q) { d_quant = q; } std::ostream& operator<<(std::ostream& out, const InstantiationList& ilist) { - Printer::getPrinter(options::outputLanguage())->toStream(out, ilist); + auto language = options::ioutils::getOutputLang(out); + Printer::getPrinter(language)->toStream(out, ilist); return out; } std::ostream& operator<<(std::ostream& out, const SkolemList& skl) { - Printer::getPrinter(options::outputLanguage())->toStream(out, skl); + auto language = options::ioutils::getOutputLang(out); + Printer::getPrinter(language)->toStream(out, skl); return out; } diff --git a/src/theory/quantifiers/quant_bound_inference.cpp b/src/theory/quantifiers/quant_bound_inference.cpp index af72e2a7c..dfffe64cf 100644 --- a/src/theory/quantifiers/quant_bound_inference.cpp +++ b/src/theory/quantifiers/quant_bound_inference.cpp @@ -61,10 +61,9 @@ bool QuantifiersBoundInference::mayComplete(TypeNode tn, unsigned maxCard) if (!c.isLargeFinite()) { NodeManager* nm = NodeManager::currentNM(); - Node card = - nm->mkConst(CONST_RATIONAL, Rational(c.getFiniteCardinality())); + Node card = nm->mkConstInt(Rational(c.getFiniteCardinality())); // check if less than fixed upper bound - Node oth = nm->mkConst(CONST_RATIONAL, Rational(maxCard)); + Node oth = nm->mkConstInt(Rational(maxCard)); Node eq = nm->mkNode(LEQ, card, oth); eq = Rewriter::rewrite(eq); mc = eq.isConst() && eq.getConst<bool>(); diff --git a/src/theory/quantifiers/quant_conflict_find.cpp b/src/theory/quantifiers/quant_conflict_find.cpp index 9f7b270de..d39212ddc 100644 --- a/src/theory/quantifiers/quant_conflict_find.cpp +++ b/src/theory/quantifiers/quant_conflict_find.cpp @@ -721,7 +721,7 @@ bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assign break; } }else{ - Node z = p->getZero( k ); + Node z = p->getZero(d_vars[index].getType(), k); if( !z.isNull() ){ Trace("qcf-tconstraint-debug") << "...set " << d_vars[vn] << " = " << z << std::endl; assigned.push_back( vn ); @@ -744,7 +744,7 @@ bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assign if( slv_v!=-1 ){ Node lhs; if( children.empty() ){ - lhs = p->getZero( k ); + lhs = p->getZero(d_vars[index].getType(), k); }else if( children.size()==1 ){ lhs = children[0]; }else{ @@ -1918,13 +1918,17 @@ bool QuantConflictFind::areMatchDisequal( TNode n1, TNode n2 ) { bool QuantConflictFind::needsCheck( Theory::Effort level ) { bool performCheck = false; - if( options::quantConflictFind() && !d_conflict ){ + if (options().quantifiers.quantConflictFind && !d_conflict) + { if( level==Theory::EFFORT_LAST_CALL ){ - performCheck = options::qcfWhenMode() == options::QcfWhenMode::LAST_CALL; + performCheck = + options().quantifiers.qcfWhenMode == options::QcfWhenMode::LAST_CALL; }else if( level==Theory::EFFORT_FULL ){ - performCheck = options::qcfWhenMode() == options::QcfWhenMode::DEFAULT; + performCheck = + options().quantifiers.qcfWhenMode == options::QcfWhenMode::DEFAULT; }else if( level==Theory::EFFORT_STANDARD ){ - performCheck = options::qcfWhenMode() == options::QcfWhenMode::STD; + performCheck = + options().quantifiers.qcfWhenMode == options::QcfWhenMode::STD; } } return performCheck; @@ -1943,7 +1947,7 @@ void QuantConflictFind::reset_round( Theory::Effort level ) { if (tdb->hasTermCurrent(r)) { TypeNode rtn = r.getType(); - if (!options::cegqi() || !TermUtil::hasInstConstAttr(r)) + if (!options().quantifiers.cegqi || !TermUtil::hasInstConstAttr(r)) { d_eqcs[rtn].push_back(r); } @@ -2276,18 +2280,20 @@ QuantConflictFind::Statistics::Statistics() { } -TNode QuantConflictFind::getZero( Kind k ) { - std::map< Kind, Node >::iterator it = d_zero.find( k ); - if( it==d_zero.end() ){ +TNode QuantConflictFind::getZero(TypeNode tn, Kind k) +{ + std::pair<TypeNode, Kind> key(tn, k); + std::map<std::pair<TypeNode, Kind>, Node>::iterator it = d_zero.find(key); + if (it == d_zero.end()) + { Node nn; if( k==PLUS ){ - nn = NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(0)); + nn = NodeManager::currentNM()->mkConstRealOrInt(tn, Rational(0)); } - d_zero[k] = nn; + d_zero[key] = nn; return nn; - }else{ - return it->second; } + return it->second; } std::ostream& operator<<(std::ostream& os, const QuantConflictFind::Effort& e) { diff --git a/src/theory/quantifiers/quant_conflict_find.h b/src/theory/quantifiers/quant_conflict_find.h index d14e281fb..82a925d3b 100644 --- a/src/theory/quantifiers/quant_conflict_find.h +++ b/src/theory/quantifiers/quant_conflict_find.h @@ -195,7 +195,7 @@ class QuantConflictFind : public QuantifiersModule private: context::CDO< bool > d_conflict; - std::map< Kind, Node > d_zero; + std::map<std::pair<TypeNode, Kind>, Node> d_zero; //for storing nodes created during t-constraint solving (prevents memory leaks) std::vector< Node > d_tempCache; //optimization: list of quantifiers that depend on ground function applications @@ -209,8 +209,9 @@ private: public: //for ground terms Node d_true; Node d_false; - TNode getZero( Kind k ); -private: + TNode getZero(TypeNode tn, Kind k); + + private: std::map< Node, QuantInfo > d_qinfo; private: //for equivalence classes // type -> list(eqc) diff --git a/src/theory/quantifiers/quant_split.cpp b/src/theory/quantifiers/quant_split.cpp index 55fa2a1e5..e6cee778b 100644 --- a/src/theory/quantifiers/quant_split.cpp +++ b/src/theory/quantifiers/quant_split.cpp @@ -167,7 +167,7 @@ void QuantDSplit::check(Theory::Effort e, QEffort quant_e) for (unsigned j = 0, ncons = dt.getNumConstructors(); j < ncons; j++) { std::vector<Node> vars; - TypeNode dtjtn = dt[j].getSpecializedConstructorType(tn); + TypeNode dtjtn = dt[j].getInstantiatedConstructorType(tn); Assert(dtjtn.getNumChildren() == dt[j].getNumArgs() + 1); for (unsigned k = 0, nargs = dt[j].getNumArgs(); k < nargs; k++) { diff --git a/src/theory/quantifiers/quantifiers_rewriter.cpp b/src/theory/quantifiers/quantifiers_rewriter.cpp index c38d0aa91..c53809d6e 100644 --- a/src/theory/quantifiers/quantifiers_rewriter.cpp +++ b/src/theory/quantifiers/quantifiers_rewriter.cpp @@ -443,7 +443,7 @@ Node QuantifiersRewriter::computeProcessTerms(Node body, { Node r = computeProcessTerms2(fbody, cache, new_vars, new_conds); Assert(new_vars.size() == h.getNumChildren()); - return Rewriter::rewrite(NodeManager::currentNM()->mkNode(EQUAL, h, r)); + return NodeManager::currentNM()->mkNode(EQUAL, h, r); } // It can happen that we can't infer the shape of the function definition, // for example: forall xy. f( x, y ) = 1 + f( x, y ), this is rewritten to @@ -906,9 +906,9 @@ bool QuantifiersRewriter::getVarElimLit(Node body, // take into account if parametric if (dt.isParametric()) { - tspec = c.getSpecializedConstructorType(lit[0].getType()); - cons = nm->mkNode( - APPLY_TYPE_ASCRIPTION, nm->mkConst(AscriptionType(tspec)), cons); + TypeNode ltn = lit[0].getType(); + tspec = c.getInstantiatedConstructorType(ltn); + cons = c.getInstantiatedConstructor(ltn); } else { @@ -920,7 +920,7 @@ bool QuantifiersRewriter::getVarElimLit(Node body, for (size_t j = 0, nargs = c.getNumArgs(); j < nargs; j++) { TypeNode tn = tspec[j]; - Node rn = nm->mkConst(CONST_RATIONAL, Rational(j)); + Node rn = nm->mkConstInt(Rational(j)); Node cacheVal = BoundVarManager::getCacheValue(body, lit, rn); Node v = bvm->mkBoundVar<QRewDtExpandAttribute>(cacheVal, tn); newChildren.push_back(v); @@ -1028,12 +1028,11 @@ bool QuantifiersRewriter::getVarElimInternal(Node body, std::vector<Node>& subs) const { Kind nk = n.getKind(); - if (nk == NOT) + while (nk == NOT) { n = n[0]; pol = !pol; nk = n.getKind(); - Assert(nk != NOT); } if ((nk == AND && pol) || (nk == OR && !pol)) { @@ -1326,7 +1325,6 @@ Node QuantifiersRewriter::computeVarElimination(Node body, // remake with eliminated nodes body = body.substitute(vars.begin(), vars.end(), subs.begin(), subs.end()); - body = Rewriter::rewrite(body); if (!qa.d_ipl.isNull()) { qa.d_ipl = qa.d_ipl.substitute( diff --git a/src/theory/quantifiers/query_generator_unsat.cpp b/src/theory/quantifiers/query_generator_unsat.cpp index ae7288080..40131ffaa 100644 --- a/src/theory/quantifiers/query_generator_unsat.cpp +++ b/src/theory/quantifiers/query_generator_unsat.cpp @@ -66,18 +66,19 @@ bool QueryGeneratorUnsat::addTerm(Node n, std::ostream& out) size_t checkCount = 0; while (checkCount < 10) { - Assert(!activeTerms.empty()); // if we just successfully added a term, do a satisfiability check if (addSuccess) { + Assert(!activeTerms.empty()); checkCount++; // check the current for satisfiability currModel.clear(); // Shuffle active terms to maximize the different possible behaviors // in the subsolver. This is instead of making multiple queries with // the same assertion order for a subsequence. - std::shuffle(activeTerms.begin(), activeTerms.end(), Random::getRandom()); - Result r = checkCurrent(activeTerms, out, currModel); + std::vector<Node> aTermCurr = activeTerms; + std::shuffle(aTermCurr.begin(), aTermCurr.end(), Random::getRandom()); + Result r = checkCurrent(aTermCurr, out, currModel); if (r.asSatisfiabilityResult().isSat() == Result::UNSAT) { // exclude the last active term diff --git a/src/theory/quantifiers/relevant_domain.cpp b/src/theory/quantifiers/relevant_domain.cpp index 0f3699990..f0684f04a 100644 --- a/src/theory/quantifiers/relevant_domain.cpp +++ b/src/theory/quantifiers/relevant_domain.cpp @@ -24,6 +24,7 @@ #include "theory/quantifiers/term_database.h" #include "theory/quantifiers/term_registry.h" #include "theory/quantifiers/term_util.h" +#include "util/rational.h" using namespace cvc5::kind; @@ -301,6 +302,7 @@ void RelevantDomain::computeRelevantDomainOpCh( RDomain * rf, Node n ) { void RelevantDomain::computeRelevantDomainLit( Node q, bool hasPol, bool pol, Node n ) { if( d_rel_dom_lit[hasPol][pol].find( n )==d_rel_dom_lit[hasPol][pol].end() ){ + NodeManager* nm = NodeManager::currentNM(); RDomainLit& rdl = d_rel_dom_lit[hasPol][pol][n]; rdl.d_merge = false; int varCount = 0; @@ -405,10 +407,14 @@ void RelevantDomain::computeRelevantDomainLit( Node q, bool hasPol, bool pol, No if( ( !hasPol || pol ) && n[0].getType().isInteger() ){ if( n.getKind()==EQUAL ){ for( unsigned i=0; i<2; i++ ){ - rdl.d_val.push_back(ArithMSum::offset(r_add, i == 0 ? 1 : -1)); + Node roff = nm->mkNode( + PLUS, r_add, nm->mkConstInt(Rational(i == 0 ? 1 : -1))); + rdl.d_val.push_back(roff); } }else if( n.getKind()==GEQ ){ - rdl.d_val.push_back(ArithMSum::offset(r_add, varLhs ? 1 : -1)); + Node roff = nm->mkNode( + PLUS, r_add, nm->mkConstInt(Rational(varLhs ? 1 : -1))); + rdl.d_val.push_back(roff); } } } diff --git a/src/theory/quantifiers/single_inv_partition.cpp b/src/theory/quantifiers/single_inv_partition.cpp index 73bcad535..2725e1826 100644 --- a/src/theory/quantifiers/single_inv_partition.cpp +++ b/src/theory/quantifiers/single_inv_partition.cpp @@ -19,7 +19,6 @@ #include "expr/node_algorithm.h" #include "expr/skolem_manager.h" #include "theory/quantifiers/term_util.h" -#include "theory/rewriter.h" using namespace cvc5; using namespace cvc5::kind; @@ -336,7 +335,6 @@ bool SingleInvocationPartition::init(std::vector<Node>& funcs, cr = cr.substitute( termsNs.begin(), termsNs.end(), subsNs.begin(), subsNs.end()); } - cr = Rewriter::rewrite(cr); Trace("si-prt") << ".....got si=" << singleInvocation << ", result : " << cr << std::endl; d_conjuncts[2].push_back(cr); @@ -349,7 +347,6 @@ bool SingleInvocationPartition::init(std::vector<Node>& funcs, Assert(si_terms.size() == si_subs.size()); cr = cr.substitute( si_terms.begin(), si_terms.end(), si_subs.begin(), si_subs.end()); - cr = Rewriter::rewrite(cr); Trace("si-prt") << ".....si version=" << cr << std::endl; d_conjuncts[0].push_back(cr); } diff --git a/src/theory/quantifiers/skolemize.cpp b/src/theory/quantifiers/skolemize.cpp index 4dea0dc22..6399340aa 100644 --- a/src/theory/quantifiers/skolemize.cpp +++ b/src/theory/quantifiers/skolemize.cpp @@ -137,8 +137,8 @@ void Skolemize::getSelfSel(const DType& dt, TypeNode tspec; if (dt.isParametric()) { - tspec = dc.getSpecializedConstructorType(n.getType()); - Trace("sk-ind-debug") << "Specialized constructor type : " << tspec + tspec = dc.getInstantiatedConstructorType(n.getType()); + Trace("sk-ind-debug") << "Instantiated constructor type : " << tspec << std::endl; Assert(tspec.getNumChildren() == dc.getNumArgs()); } @@ -285,11 +285,10 @@ Node Skolemize::mkSkolemizedBody(Node f, } else if (options::intWfInduction() && tn.isInteger()) { - Node icond = nm->mkNode(GEQ, k, nm->mkConst(CONST_RATIONAL, Rational(0))); + Node icond = nm->mkNode(GEQ, k, nm->mkConstInt(Rational(0))); Node iret = - ret.substitute( - ind_vars[0], - nm->mkNode(MINUS, k, nm->mkConst(CONST_RATIONAL, Rational(1)))) + ret.substitute(ind_vars[0], + nm->mkNode(MINUS, k, nm->mkConstInt(Rational(1)))) .negate(); n_str_ind = nm->mkNode(OR, icond.negate(), iret); n_str_ind = nm->mkNode(AND, icond, n_str_ind); @@ -309,7 +308,6 @@ Node Skolemize::mkSkolemizedBody(Node f, { Node bvl = nm->mkNode(BOUND_VAR_LIST, rem_ind_vars); nret = nm->mkNode(FORALL, bvl, nret); - nret = Rewriter::rewrite(nret); sub = nret; sub_vars.insert( sub_vars.end(), ind_var_indicies.begin() + 1, ind_var_indicies.end()); diff --git a/src/theory/quantifiers/sygus/cegis_unif.cpp b/src/theory/quantifiers/sygus/cegis_unif.cpp index be80992ea..c9706b40f 100644 --- a/src/theory/quantifiers/sygus/cegis_unif.cpp +++ b/src/theory/quantifiers/sygus/cegis_unif.cpp @@ -480,7 +480,7 @@ Node CegisUnifEnumDecisionStrategy::mkLiteral(unsigned n) std::set<TypeNode> unresolvedTypes; unresolvedTypes.insert(u); std::vector<TypeNode> cargsEmpty; - Node cr = nm->mkConst(CONST_RATIONAL, Rational(1)); + Node cr = nm->mkConstInt(Rational(1)); sdt.addConstructor(cr, "1", cargsEmpty); std::vector<TypeNode> cargsPlus; cargsPlus.push_back(u); @@ -503,8 +503,8 @@ Node CegisUnifEnumDecisionStrategy::mkLiteral(unsigned n) if (pow_two > 0) { Node size_ve = nm->mkNode(DT_SIZE, d_virtual_enum); - Node fair_lemma = nm->mkNode( - GEQ, size_ve, nm->mkConst(CONST_RATIONAL, Rational(pow_two - 1))); + Node fair_lemma = + nm->mkNode(GEQ, size_ve, nm->mkConstInt(Rational(pow_two - 1))); fair_lemma = nm->mkNode(OR, newLit, fair_lemma); Trace("cegis-unif-enum-lemma") << "CegisUnifEnum::lemma, fairness size:" << fair_lemma << "\n"; diff --git a/src/theory/quantifiers/sygus/sygus_abduct.cpp b/src/theory/quantifiers/sygus/sygus_abduct.cpp index fc7e7a1b9..3da55ff50 100644 --- a/src/theory/quantifiers/sygus/sygus_abduct.cpp +++ b/src/theory/quantifiers/sygus/sygus_abduct.cpp @@ -28,7 +28,6 @@ #include "theory/quantifiers/sygus/sygus_grammar_cons.h" #include "theory/quantifiers/sygus/sygus_utils.h" #include "theory/quantifiers/term_util.h" -#include "theory/rewriter.h" using namespace std; using namespace cvc5::kind; @@ -184,8 +183,6 @@ Node SygusAbduct::mkAbductionConjecture(const std::string& name, res = SygusUtils::mkSygusConjecture({abd}, res, {instAttr}); Trace("sygus-abduct-debug") << "...finish" << std::endl; - res = theory::Rewriter::rewrite(res); - Trace("sygus-abduct") << "Generate: " << res << std::endl; return res; diff --git a/src/theory/quantifiers/sygus/sygus_enumerator.cpp b/src/theory/quantifiers/sygus/sygus_enumerator.cpp index 674183b20..711d390f8 100644 --- a/src/theory/quantifiers/sygus/sygus_enumerator.cpp +++ b/src/theory/quantifiers/sygus/sygus_enumerator.cpp @@ -257,7 +257,7 @@ void SygusEnumerator::TermCache::initialize(SygusStatistics* s, // more aggressive merging of constructor classes. On the negative side, // this adds another level of indirection to remember which argument // positions the argument types occur in, for each constructor. - Node n = nm->mkConst(CONST_RATIONAL, Rational(i)); + Node n = nm->mkConstInt(Rational(i)); nToC[n] = i; tnit.add(n, argTypes[i]); } diff --git a/src/theory/quantifiers/sygus/sygus_grammar_cons.cpp b/src/theory/quantifiers/sygus/sygus_grammar_cons.cpp index 438afbe82..7227b7184 100644 --- a/src/theory/quantifiers/sygus/sygus_grammar_cons.cpp +++ b/src/theory/quantifiers/sygus/sygus_grammar_cons.cpp @@ -85,11 +85,12 @@ void CegGrammarConstructor::collectTerms( Node c = cur; if (tn.isRealOrInt()) { - c = nm->mkConst(CONST_RATIONAL, c.getConst<Rational>().abs()); + c = nm->mkConstRealOrInt(tn, c.getConst<Rational>().abs()); } consts[tn].insert(c); if (tn.isInteger()) { + c = nm->mkConstReal(c.getConst<Rational>().abs()); TypeNode rtype = nm->realType(); consts[rtype].insert(c); } @@ -410,8 +411,8 @@ void CegGrammarConstructor::mkSygusConstantsForType(TypeNode type, NodeManager* nm = NodeManager::currentNM(); if (type.isRealOrInt()) { - ops.push_back(nm->mkConst(CONST_RATIONAL, Rational(0))); - ops.push_back(nm->mkConst(CONST_RATIONAL, Rational(1))); + ops.push_back(nm->mkConstRealOrInt(type, Rational(0))); + ops.push_back(nm->mkConstRealOrInt(type, Rational(1))); } else if (type.isBitVector()) { @@ -483,7 +484,7 @@ void CegGrammarConstructor::collectSygusGrammarTypesFor( { // get the specialized constructor type, which accounts for // parametric datatypes - TypeNode ctn = dt[i].getSpecializedConstructorType(range); + TypeNode ctn = dt[i].getInstantiatedConstructorType(range); std::vector<TypeNode> argTypes = ctn.getArgTypes(); for (size_t j = 0, nargs = argTypes.size(); j < nargs; ++j) { @@ -556,7 +557,7 @@ Node CegGrammarConstructor::createLambdaWithZeroArg( Assert(bArgType.isRealOrInt() || bArgType.isBitVector()); if (bArgType.isRealOrInt()) { - zarg = nm->mkConst(CONST_RATIONAL, Rational(0)); + zarg = nm->mkConstRealOrInt(bArgType, Rational(0)); } else { @@ -800,7 +801,7 @@ void CegGrammarConstructor::mkSygusDefaultGrammar( Trace("sygus-grammar-def") << "\t...add for 1 to Pos_Int\n"; std::vector<TypeNode> cargsEmpty; sdts.back().addConstructor( - nm->mkConst(CONST_RATIONAL, Rational(1)), "1", cargsEmpty); + nm->mkConstInt(Rational(1)), "1", cargsEmpty); /* Add operator PLUS */ Kind kind = PLUS; Trace("sygus-grammar-def") << "\t...add for PLUS to Pos_Int\n"; @@ -1010,12 +1011,11 @@ void CegGrammarConstructor::mkSygusDefaultGrammar( { Trace("sygus-grammar-def") << "...for " << dt[l].getName() << std::endl; Node cop = dt[l].getConstructor(); - TypeNode tspec = dt[l].getSpecializedConstructorType(types[i]); + TypeNode tspec = dt[l].getInstantiatedConstructorType(types[i]); // must specialize if a parametric datatype if (dt.isParametric()) { - cop = nm->mkNode( - APPLY_TYPE_ASCRIPTION, nm->mkConst(AscriptionType(tspec)), cop); + cop = dt[l].getInstantiatedConstructor(types[i]); } if (dt[l].getNumArgs() == 0) { @@ -1151,7 +1151,7 @@ void CegGrammarConstructor::mkSygusDefaultGrammar( { const SygusDatatypeConstructor& sdc = sdti.getConstructor(k); Node sop = sdc.d_op; - bool isBuiltinArithOp = (sop.getKind() == CONST_RATIONAL); + bool isBuiltinArithOp = (sop.getType().isRealOrInt() && sop.isConst()); bool hasExternalType = false; for (unsigned j = 0, nargs = sdc.d_argTypes.size(); j < nargs; j++) { diff --git a/src/theory/quantifiers/sygus/sygus_process_conj.cpp b/src/theory/quantifiers/sygus/sygus_process_conj.cpp index f5cadc607..a1f197596 100644 --- a/src/theory/quantifiers/sygus/sygus_process_conj.cpp +++ b/src/theory/quantifiers/sygus/sygus_process_conj.cpp @@ -30,6 +30,8 @@ namespace cvc5 { namespace theory { namespace quantifiers { +SynthConjectureProcessFun::SynthConjectureProcessFun(Env& env) : EnvObj(env) {} + void SynthConjectureProcessFun::init(Node f) { d_synth_fun = f; @@ -511,7 +513,7 @@ void SynthConjectureProcessFun::getIrrelevantArgs( } } -SynthConjectureProcess::SynthConjectureProcess() {} +SynthConjectureProcess::SynthConjectureProcess(Env& env) : EnvObj(env) {} SynthConjectureProcess::~SynthConjectureProcess() {} Node SynthConjectureProcess::preSimplify(Node q) { @@ -524,7 +526,7 @@ Node SynthConjectureProcess::postSimplify(Node q) Trace("sygus-process") << "Post-simplify conjecture : " << q << std::endl; Assert(q.getKind() == FORALL); - if (options::sygusArgRelevant()) + if (options().quantifiers.sygusArgRelevant) { // initialize the information about each function to synthesize for (unsigned i = 0, size = q[0].getNumChildren(); i < size; i++) @@ -532,7 +534,9 @@ Node SynthConjectureProcess::postSimplify(Node q) Node f = q[0][i]; if (f.getType().isFunction()) { - d_sf_info[f].init(f); + std::pair<std::map<Node, SynthConjectureProcessFun>::iterator, bool> + it = d_sf_info.emplace(f, d_env); + it.first->second.init(f); } } @@ -582,7 +586,7 @@ void SynthConjectureProcess::initialize(Node n, std::vector<Node>& candidates) bool SynthConjectureProcess::isArgRelevant(Node f, unsigned i) { - if (!options::sygusArgRelevant()) + if (!options().quantifiers.sygusArgRelevant) { return true; } diff --git a/src/theory/quantifiers/sygus/sygus_process_conj.h b/src/theory/quantifiers/sygus/sygus_process_conj.h index d751e4c9c..b0b87c65b 100644 --- a/src/theory/quantifiers/sygus/sygus_process_conj.h +++ b/src/theory/quantifiers/sygus/sygus_process_conj.h @@ -25,6 +25,7 @@ #include "expr/node.h" #include "expr/type_node.h" +#include "smt/env_obj.h" namespace cvc5 { namespace theory { @@ -119,10 +120,10 @@ class SynthConjectureProcessArg * It maintains information about each of the function to * synthesize's arguments. */ -struct SynthConjectureProcessFun +struct SynthConjectureProcessFun : protected EnvObj { public: - SynthConjectureProcessFun() {} + SynthConjectureProcessFun(Env& env); ~SynthConjectureProcessFun() {} /** initialize this class for function f */ void init(Node f); @@ -266,10 +267,10 @@ struct SynthConjectureProcessFun * sygus to SynthConjectureProcess::getSymmetryBreakingPredicate(...), which are * used for pruning search space based on conjecture-specific analysis. */ -class SynthConjectureProcess +class SynthConjectureProcess : protected EnvObj { public: - SynthConjectureProcess(); + SynthConjectureProcess(Env& env); ~SynthConjectureProcess(); /** simplify the synthesis conjecture q * Returns a formula that is equivalent to q. diff --git a/src/theory/quantifiers/sygus/synth_conjecture.cpp b/src/theory/quantifiers/sygus/synth_conjecture.cpp index e7d0ef58b..e5dfe408b 100644 --- a/src/theory/quantifiers/sygus/synth_conjecture.cpp +++ b/src/theory/quantifiers/sygus/synth_conjecture.cpp @@ -61,7 +61,7 @@ SynthConjecture::SynthConjecture(Env& env, d_hasSolution(false), d_ceg_si(new CegSingleInv(env, tr, s)), d_templInfer(new SygusTemplateInfer(env)), - d_ceg_proc(new SynthConjectureProcess), + d_ceg_proc(new SynthConjectureProcess(env)), d_ceg_gc(new CegGrammarConstructor(env, d_tds, this)), d_sygus_rconst(new SygusRepairConst(env, d_tds)), d_exampleInfer(new ExampleInfer(d_tds)), @@ -306,6 +306,10 @@ bool SynthConjecture::needsCheck() bool SynthConjecture::doCheck() { + if (d_hasSolution) + { + return true; + } if (isSingleInvocation()) { // We now try to solve with the single invocation solver, which may or may @@ -314,14 +318,12 @@ bool SynthConjecture::doCheck() if (d_ceg_si->solve()) { d_hasSolution = true; - // the conjecture has a solution, so its negation holds - Node qn = d_quant.negate(); - d_qim.addPendingLemma(qn, InferenceId::QUANTIFIERS_SYGUS_SI_SOLVED); + // the conjecture has a solution, we set incomplete + d_qim.setIncomplete(IncompleteId::QUANTIFIERS_SYGUS_SOLVED); } return true; } Assert(d_master != nullptr); - Assert(!d_hasSolution); // get the list of terms that the master strategy is interested in std::vector<Node> terms; @@ -506,11 +508,10 @@ bool SynthConjecture::doCheck() if (options().quantifiers.cegisSample == options::CegisSampleMode::TRUST) { // we have that the current candidate passed a sample test - // since we trust sampling in this mode, we assert there is no - // counterexample to the conjecture here. - Node qn = d_quant.negate(); - d_qim.addPendingLemma(qn, - InferenceId::QUANTIFIERS_SYGUS_SAMPLE_TRUST_SOLVED); + // since we trust sampling in this mode, we assume there is a solution here + // and set incomplete. + d_hasSolution = true; + d_qim.setIncomplete(IncompleteId::QUANTIFIERS_SYGUS_SOLVED); recordSolution(candidate_values); return true; } @@ -573,10 +574,8 @@ bool SynthConjecture::doCheck() d_hasSolution = false; return false; } - // Use lemma to terminate with "unsat", this is justified by the verification - // check above, which confirms the synthesis conjecture is solved. - Node qn = d_quant.negate(); - d_qim.addPendingLemma(qn, InferenceId::QUANTIFIERS_SYGUS_VERIFY_SOLVED); + // We set incomplete and terminate with unknown. + d_qim.setIncomplete(IncompleteId::QUANTIFIERS_SYGUS_SOLVED); return true; } diff --git a/src/theory/quantifiers/sygus/synth_verify.cpp b/src/theory/quantifiers/sygus/synth_verify.cpp index 5b26efef5..6b4796949 100644 --- a/src/theory/quantifiers/sygus/synth_verify.cpp +++ b/src/theory/quantifiers/sygus/synth_verify.cpp @@ -124,7 +124,7 @@ Result SynthVerify::verify(Node query, Trace("cegqi-debug") << "...squery : " << squery << std::endl; squery = rewrite(squery); Trace("cegqi-debug") << "...rewrites to : " << squery << std::endl; - Assert(options::sygusRecFun() + Assert(options().quantifiers.sygusRecFun || (squery.isConst() && squery.getConst<bool>())); } } diff --git a/src/theory/quantifiers/sygus/template_infer.cpp b/src/theory/quantifiers/sygus/template_infer.cpp index ab9d5f845..043e8f5ed 100644 --- a/src/theory/quantifiers/sygus/template_infer.cpp +++ b/src/theory/quantifiers/sygus/template_infer.cpp @@ -36,7 +36,7 @@ void SygusTemplateInfer::initialize(Node q) // We are processing without single invocation techniques, now check if // we should fix an invariant template (post-condition strengthening or // pre-condition weakening). - options::SygusInvTemplMode tmode = options::sygusInvTemplMode(); + options::SygusInvTemplMode tmode = options().quantifiers.sygusInvTemplMode; if (tmode != options::SygusInvTemplMode::NONE) { // currently only works for single predicate synthesis @@ -44,7 +44,7 @@ void SygusTemplateInfer::initialize(Node q) { tmode = options::SygusInvTemplMode::NONE; } - else if (!options::sygusInvTemplWhenSyntax()) + else if (!options().quantifiers.sygusInvTemplWhenSyntax) { // only use invariant templates if no syntactic restrictions if (CegGrammarConstructor::hasSyntaxRestrictions(q)) @@ -106,7 +106,7 @@ void SygusTemplateInfer::initialize(Node q) // construct template Node templ; - if (options::sygusInvAutoUnfold()) + if (options().quantifiers.sygusInvAutoUnfold) { if (d_ti.isComplete()) { diff --git a/src/theory/quantifiers/sygus_sampler.cpp b/src/theory/quantifiers/sygus_sampler.cpp index 89cee0145..1402c845c 100644 --- a/src/theory/quantifiers/sygus_sampler.cpp +++ b/src/theory/quantifiers/sygus_sampler.cpp @@ -589,14 +589,14 @@ Node SygusSampler::getRandomValue(TypeNode tn) std::vector<Node> sum; for (unsigned j = 0, size = vec.size(); j < size; j++) { - Node digit = nm->mkConst(CONST_RATIONAL, Rational(vec[j]) * curr); + Node digit = nm->mkConstInt(Rational(vec[j]) * curr); sum.push_back(digit); curr = curr * baser; } Node ret; if (sum.empty()) { - ret = nm->mkConst(CONST_RATIONAL, Rational(0)); + ret = nm->mkConstInt(Rational(0)); } else if (sum.size() == 1) { @@ -631,7 +631,7 @@ Node SygusSampler::getRandomValue(TypeNode tn) } else { - return nm->mkConst(CONST_RATIONAL, sr / rr); + return nm->mkConstReal(sr / rr); } } } diff --git a/src/theory/quantifiers/term_util.cpp b/src/theory/quantifiers/term_util.cpp index 1dfcc044e..18f9ec7e2 100644 --- a/src/theory/quantifiers/term_util.cpp +++ b/src/theory/quantifiers/term_util.cpp @@ -332,7 +332,7 @@ Node TermUtil::mkTypeValue(TypeNode tn, int32_t val) if (tn.isRealOrInt()) { Rational c(val); - n = NodeManager::currentNM()->mkConst(CONST_RATIONAL, c); + n = NodeManager::currentNM()->mkConstRealOrInt(tn, c); } else if (tn.isBitVector()) { diff --git a/src/theory/relevance_manager.cpp b/src/theory/relevance_manager.cpp index 972a2918c..9acf2dffc 100644 --- a/src/theory/relevance_manager.cpp +++ b/src/theory/relevance_manager.cpp @@ -17,6 +17,7 @@ #include <sstream> +#include "expr/term_context_stack.h" #include "options/smt_options.h" #include "smt/env.h" @@ -25,17 +26,21 @@ using namespace cvc5::kind; namespace cvc5 { namespace theory { -RelevanceManager::RelevanceManager(context::Context* lemContext, Valuation val) - : d_val(val), - d_input(lemContext), - d_computed(false), +RelevanceManager::RelevanceManager(Env& env, Valuation val) + : EnvObj(env), + d_val(val), + d_input(userContext()), + d_rset(context()), + d_inFullEffortCheck(false), d_success(false), d_trackRSetExp(false), - d_miniscopeTopLevel(true) + d_miniscopeTopLevel(true), + d_rsetExp(context()), + d_jcache(context()) { - if (options::produceDifficulty()) + if (options().smt.produceDifficulty) { - d_dman.reset(new DifficultyManager(lemContext, val)); + d_dman.reset(new DifficultyManager(userContext(), val)); d_trackRSetExp = true; // we cannot miniscope AND at the top level, since we need to // preserve the exact form of preprocessed assertions so the dependencies @@ -45,7 +50,7 @@ RelevanceManager::RelevanceManager(context::Context* lemContext, Valuation val) } void RelevanceManager::notifyPreprocessedAssertions( - const std::vector<Node>& assertions) + const std::vector<Node>& assertions, bool isInput) { // add to input list, which is user-context dependent std::vector<Node> toProcess; @@ -65,13 +70,18 @@ void RelevanceManager::notifyPreprocessedAssertions( } } addAssertionsInternal(toProcess); + // notify the difficulty manager if these are input assertions + if (isInput && d_dman != nullptr) + { + d_dman->notifyInputAssertions(assertions); + } } -void RelevanceManager::notifyPreprocessedAssertion(Node n) +void RelevanceManager::notifyPreprocessedAssertion(Node n, bool isInput) { std::vector<Node> toProcess; toProcess.push_back(n); - addAssertionsInternal(toProcess); + notifyPreprocessedAssertions(toProcess, isInput); } void RelevanceManager::addAssertionsInternal(std::vector<Node>& toProcess) @@ -100,47 +110,53 @@ void RelevanceManager::addAssertionsInternal(std::vector<Node>& toProcess) } } -void RelevanceManager::beginRound() -{ - d_computed = false; -} +void RelevanceManager::beginRound() { d_inFullEffortCheck = true; } + +void RelevanceManager::endRound() { d_inFullEffortCheck = false; } void RelevanceManager::computeRelevance() { - d_computed = true; - d_rset.clear(); - d_rsetExp.clear(); - Trace("rel-manager") << "RelevanceManager::computeRelevance..." << std::endl; - std::unordered_map<TNode, int> cache; - d_success = true; + // if not at full effort, should be tracking something else, e.g. explanation + // for why literals are relevant. + Assert(d_inFullEffortCheck || d_trackRSetExp); + Trace("rel-manager") << "RelevanceManager::computeRelevance, full effort = " + << d_inFullEffortCheck << "..." << std::endl; for (const Node& node: d_input) { TNode n = node; - int val = justify(n, cache); + int32_t val = justify(n); if (val != 1) { - if (Trace.isOn("rel-manager")) + // if we are in full effort check and fail to justify, then we should + // give a failure and set success to false, or otherwise calls to + // isRelevant cannot be trusted. + if (d_inFullEffortCheck) { std::stringstream serr; serr << "RelevanceManager::computeRelevance: WARNING: failed to justify " << n; Trace("rel-manager") << serr.str() << std::endl; + Assert(false) << serr.str(); + d_success = false; + return; } - d_success = false; - // If we fail to justify an assertion, we set success to false and - // continue to try to justify the remaining assertions. This is important - // for cases where the difficulty manager is measuring based on lemmas - // that are being sent at STANDARD effort, before all assertions are - // satisfied. } } - if (!d_success) + if (Trace.isOn("rel-manager")) { - d_rset.clear(); - return; + if (d_inFullEffortCheck) + { + Trace("rel-manager") << "...success (full), size = " << d_rset.size() + << std::endl; + } + else + { + Trace("rel-manager") << "...success, exp size = " << d_rsetExp.size() + << std::endl; + } } - Trace("rel-manager") << "...success, size = " << d_rset.size() << std::endl; + d_success = true; } bool RelevanceManager::isBooleanConnective(TNode cur) @@ -150,27 +166,27 @@ bool RelevanceManager::isBooleanConnective(TNode cur) || (k == EQUAL && cur[0].getType().isBoolean()); } -bool RelevanceManager::updateJustifyLastChild( - TNode cur, - std::vector<int>& childrenJustify, - std::unordered_map<TNode, int>& cache) +bool RelevanceManager::updateJustifyLastChild(const RlvPair& cur, + std::vector<int32_t>& childrenJustify) { // This method is run when we are informed that child index of cur // has justify status lastChildJustify. We return true if we would like to // compute the next child, in this case we push the status of the current // child to childrenJustify. - size_t nchildren = cur.getNumChildren(); - Assert(isBooleanConnective(cur)); + size_t nchildren = cur.first.getNumChildren(); + Assert(isBooleanConnective(cur.first)); size_t index = childrenJustify.size(); Assert(index < nchildren); - Assert(cache.find(cur[index]) != cache.end()); - Kind k = cur.getKind(); + Kind k = cur.first.getKind(); // Lookup the last child's value in the overall cache, we may choose to // add this to childrenJustify if we return true. - int lastChildJustify = cache[cur[index]]; + RlvPair cp(cur.first[index], + d_ptctx.computeValue(cur.first, cur.second, index)); + Assert(d_jcache.find(cp) != d_jcache.end()); + int32_t lastChildJustify = d_jcache[cp]; if (k == NOT) { - cache[cur] = -lastChildJustify; + d_jcache[cur] = -lastChildJustify; } else if (k == IMPLIES || k == AND || k == OR) { @@ -181,7 +197,7 @@ bool RelevanceManager::updateJustifyLastChild( if (lastChildJustify == ((k == AND || (k == IMPLIES && index == 0)) ? -1 : 1)) { - cache[cur] = k == AND ? -1 : 1; + d_jcache[cur] = k == AND ? -1 : 1; return false; } } @@ -197,7 +213,7 @@ bool RelevanceManager::updateJustifyLastChild( break; } } - cache[cur] = ret; + d_jcache[cur] = ret; } else { @@ -209,7 +225,7 @@ bool RelevanceManager::updateJustifyLastChild( else if (lastChildJustify == 0) { // all other cases, an unknown child implies we are unknown - cache[cur] = 0; + d_jcache[cur] = 0; } else if (k == ITE) { @@ -230,7 +246,7 @@ bool RelevanceManager::updateJustifyLastChild( // should be in proper branch Assert(childrenJustify[0] == (index == 1 ? 1 : -1)); // we are the value of the branch - cache[cur] = lastChildJustify; + d_jcache[cur] = lastChildJustify; } } else @@ -248,7 +264,7 @@ bool RelevanceManager::updateJustifyLastChild( { // both children known, compute value Assert(childrenJustify.size() == 1 && childrenJustify[0] != 0); - cache[cur] = + d_jcache[cur] = ((k == XOR ? -1 : 1) * lastChildJustify == childrenJustify[0]) ? 1 : -1; } @@ -256,85 +272,110 @@ bool RelevanceManager::updateJustifyLastChild( return false; } -int RelevanceManager::justify(TNode n, std::unordered_map<TNode, int>& cache) +int32_t RelevanceManager::justify(TNode n) { + // The set of nodes that we have computed currently have no value. Those + // that are marked as having no value in d_jcache must be recomputed, since + // the values for SAT literals may have changed. + std::unordered_set<RlvPair, RlvPairHashFunction> noJustify; // the vector of values of children - std::unordered_map<TNode, std::vector<int>> childJustify; - std::unordered_map<TNode, int>::iterator it; - std::unordered_map<TNode, std::vector<int>>::iterator itc; - std::vector<TNode> visit; - TNode cur; - visit.push_back(n); + std::unordered_map<RlvPair, std::vector<int32_t>, RlvPairHashFunction> + childJustify; + RlvPairIntMap::iterator it; + std::unordered_map<RlvPair, std::vector<int32_t>, RlvPairHashFunction>::iterator + itc; + RlvPair cur; + TCtxStack visit(&d_ptctx); + visit.pushInitial(n); do { - cur = visit.back(); + cur = visit.getCurrent(); // should always have Boolean type - Assert(cur.getType().isBoolean()); - it = cache.find(cur); - if (it != cache.end()) + Assert(cur.first.getType().isBoolean()); + it = d_jcache.find(cur); + if (it != d_jcache.end()) { - visit.pop_back(); - // already computed value - continue; + if (it->second != 0 || noJustify.find(cur) != noJustify.end()) + { + visit.pop(); + // already computed value + continue; + } } itc = childJustify.find(cur); // have we traversed to children yet? if (itc == childJustify.end()) { // are we not a Boolean connective (including NOT)? - if (isBooleanConnective(cur)) + if (isBooleanConnective(cur.first)) { // initialize its children justify vector as empty childJustify[cur].clear(); // start with the first child - visit.push_back(cur[0]); + visit.pushChild(cur.first, cur.second, 0); } else { - visit.pop_back(); + visit.pop(); // The atom case, lookup the value in the valuation class to // see its current value in the SAT solver, if it has one. int ret = 0; // otherwise we look up the value bool value; - if (d_val.hasSatValue(cur, value)) + if (d_val.hasSatValue(cur.first, value)) { ret = value ? 1 : -1; - d_rset.insert(cur); - if (d_trackRSetExp) + bool hasPol, pol; + PolarityTermContext::getFlags(cur.second, hasPol, pol); + // relevant if weakly matches polarity + if (!hasPol || pol == value) { - d_rsetExp[cur] = n; + d_rset.insert(cur.first); + if (d_trackRSetExp) + { + d_rsetExp[cur.first] = n; + Trace("rel-manager-exp") + << "Reason for " << cur.first << " is " << n + << ", polarity is " << hasPol << "/" << pol << std::endl; + } } } - cache[cur] = ret; + d_jcache[cur] = ret; + if (ret == 0) + { + noJustify.insert(cur); + } } } else { // this processes the impact of the current child on the value of cur, // and possibly requests that a new child is computed. - if (updateJustifyLastChild(cur, itc->second, cache)) + if (updateJustifyLastChild(cur, itc->second)) { - Assert(itc->second.size() < cur.getNumChildren()); - TNode nextChild = cur[itc->second.size()]; - visit.push_back(nextChild); + Assert(itc->second.size() < cur.first.getNumChildren()); + visit.pushChild(cur.first, cur.second, itc->second.size()); } else { - visit.pop_back(); + visit.pop(); + Assert(d_jcache.find(cur) != d_jcache.end()); + if (d_jcache[cur] == 0) + { + noJustify.insert(cur); + } } } } while (!visit.empty()); - Assert(cache.find(n) != cache.end()); - return cache[n]; + RlvPair ci(n, d_ptctx.initialValue()); + Assert(d_jcache.find(ci) != d_jcache.end()); + return d_jcache[ci]; } bool RelevanceManager::isRelevant(Node lit) { - if (!d_computed) - { - computeRelevance(); - } + Assert(d_inFullEffortCheck); + computeRelevance(); if (!d_success) { // always relevant if we failed to compute @@ -348,22 +389,25 @@ bool RelevanceManager::isRelevant(Node lit) return d_rset.find(lit) != d_rset.end(); } -const std::unordered_set<TNode>& RelevanceManager::getRelevantAssertions( - bool& success) +std::unordered_set<TNode> RelevanceManager::getRelevantAssertions(bool& success) { - if (!d_computed) - { - computeRelevance(); - } + computeRelevance(); // update success flag success = d_success; - return d_rset; + std::unordered_set<TNode> rset; + if (success) + { + for (const Node& a : d_rset) + { + rset.insert(a); + } + } + return rset; } void RelevanceManager::notifyLemma(Node n) { - // only consider lemmas that were sent at full effort, when we have a - // complete SAT assignment. + // notice that we may be in FULL or STANDARD effort here. if (d_dman != nullptr) { // ensure we know which literals are relevant, and why @@ -376,7 +420,7 @@ void RelevanceManager::notifyCandidateModel(TheoryModel* m) { if (d_dman != nullptr) { - d_dman->notifyCandidateModel(d_input, m); + d_dman->notifyCandidateModel(m); } } diff --git a/src/theory/relevance_manager.h b/src/theory/relevance_manager.h index fbc50801c..582a8a938 100644 --- a/src/theory/relevance_manager.h +++ b/src/theory/relevance_manager.h @@ -21,8 +21,12 @@ #include <unordered_map> #include <unordered_set> +#include "context/cdhashmap.h" +#include "context/cdhashset.h" #include "context/cdlist.h" #include "expr/node.h" +#include "expr/term_context.h" +#include "smt/env_obj.h" #include "theory/difficulty_manager.h" #include "theory/valuation.h" @@ -71,28 +75,42 @@ class TheoryModel; * selection is computed lazily, i.e. only when someone asks if a literal is * relevant, and only at most once per FULL effort check. */ -class RelevanceManager +class RelevanceManager : protected EnvObj { - typedef context::CDList<Node> NodeList; + using RlvPair = std::pair<Node, uint32_t>; + using RlvPairHashFunction = PairHashFunction<Node, uint32_t, std::hash<Node>>; + using NodeList = context::CDList<Node>; + using NodeMap = context::CDHashMap<Node, Node>; + using NodeSet = context::CDHashSet<Node>; + using RlvPairIntMap = + context::CDHashMap<RlvPair, int32_t, RlvPairHashFunction>; public: /** - * @param lemContext The context which lemmas live at + * @param env The environment * @param val The valuation class, for computing what is relevant. */ - RelevanceManager(context::Context* lemContext, Valuation val); + RelevanceManager(Env& env, Valuation val); /** * Notify (preprocessed) assertions. This is called for input formulas or * lemmas that need justification that have been fully processed, just before * adding them to the PropEngine. + * + * @param assertions The assertions + * @param isInput Whether the assertions are preprocessed input assertions; + * this flag is false for lemmas. */ - void notifyPreprocessedAssertions(const std::vector<Node>& assertions); + void notifyPreprocessedAssertions(const std::vector<Node>& assertions, + bool isInput); /** Singleton version of above */ - void notifyPreprocessedAssertion(Node n); + void notifyPreprocessedAssertion(Node n, bool isInput); /** - * Begin round, called at the beginning of a check in TheoryEngine. + * Begin round, called at the beginning of a full effort check in + * TheoryEngine. */ void beginRound(); + /** End round, called at the end of a full effort check in TheoryEngine. */ + void endRound(); /** * Is lit part of the current relevant selection? This computes the set of * relevant assertions if not already done so. This call is valid during a @@ -110,8 +128,11 @@ class RelevanceManager * the assertions we are notified of. This should never happen. * * The value of this return is only valid if success was not updated to false. + * + * Note that this returns a context-independent set to the user, which + * copies the assertions. */ - const std::unordered_set<TNode>& getRelevantAssertions(bool& success); + std::unordered_set<TNode> getRelevantAssertions(bool& success); /** Notify lemma, for difficulty measurements */ void notifyLemma(Node n); /** Notify that m is a (candidate) model, for difficulty measurements */ @@ -138,32 +159,32 @@ class RelevanceManager * This method returns 1 if we justified n to be true, -1 means * justified n to be false, 0 means n could not be justified. */ - int justify(TNode n, std::unordered_map<TNode, int>& cache); + int32_t justify(TNode n); /** Is the top symbol of cur a Boolean connective? */ - bool isBooleanConnective(TNode cur); + static bool isBooleanConnective(TNode cur); /** * Update justify last child. This method is a helper function for justify, * which is called at the moment that Boolean connective formula cur - * has a new child that has been computed in the justify cache. + * has a new child that has been computed in the justify cache maintained + * by this class. * * @param cur The Boolean connective formula * @param childrenJustify The values of the previous children (not including * the current one) - * @param cache The justify cache * @return True if we wish to visit the next child. If this is the case, then * the justify value of the current child is added to childrenJustify. */ - bool updateJustifyLastChild(TNode cur, - std::vector<int>& childrenJustify, - std::unordered_map<TNode, int>& cache); + bool updateJustifyLastChild(const RlvPair& cur, + std::vector<int32_t>& childrenJustify); /** The valuation object, used to query current value of theory literals */ Valuation d_val; /** The input assertions */ NodeList d_input; - /** The current relevant selection. */ - std::unordered_set<TNode> d_rset; - /** Have we computed the relevant selection this round? */ - bool d_computed; + /** + * The current relevant selection, SAT-context dependent, includes + * literals that are definitely relevant in this context. + */ + NodeSet d_rset; /** Are we in a full effort check? */ bool d_inFullEffortCheck; /** @@ -172,6 +193,8 @@ class RelevanceManager * assignment since this class found that the input formula was not satisfied * by the assignment. This should never happen, but if it does, this class * aborts and indicates that all literals are relevant. + * + * This flag is only valid at FULL effort. */ bool d_success; /** Are we tracking the sources of why a literal is relevant */ @@ -187,7 +210,19 @@ class RelevanceManager * Map from the domain of d_rset to the assertion in d_input that is the * reason why that literal is currently relevant. */ - std::map<TNode, TNode> d_rsetExp; + NodeMap d_rsetExp; + /** For computing polarity on terms */ + PolarityTermContext d_ptctx; + /** + * Set of nodes that we have justified (SAT context dependent). This is SAT + * context dependent to avoid repeated calls to justify for uses of + * the relevance manager at standard effort. Notice that we pair each node + * with its polarity. We take into account the polarity of the node when + * computing relevance, where a node is only relevant if it is asserted + * and either does not have a polarity in the overall formula, or if its + * asserted value matches its polarity. + */ + RlvPairIntMap d_jcache; /** Difficulty module */ std::unique_ptr<DifficultyManager> d_dman; }; diff --git a/src/theory/sets/cardinality_extension.cpp b/src/theory/sets/cardinality_extension.cpp index e2181b4c6..7bb752acd 100644 --- a/src/theory/sets/cardinality_extension.cpp +++ b/src/theory/sets/cardinality_extension.cpp @@ -47,7 +47,7 @@ CardinalityExtension::CardinalityExtension(Env& env, d_finite_type_constants_processed(false) { d_true = NodeManager::currentNM()->mkConst(true); - d_zero = NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(0)); + d_zero = NodeManager::currentNM()->mkConstInt(Rational(0)); } void CardinalityExtension::reset() @@ -134,7 +134,7 @@ void CardinalityExtension::checkCardinalityExtended(TypeNode& t) if (finiteType) { Node typeCardinality = - nm->mkConst(CONST_RATIONAL, Rational(card.getFiniteCardinality())); + nm->mkConstInt(Rational(card.getFiniteCardinality())); Node cardUniv = nm->mkNode(kind::SET_CARD, proxy); Node leq = nm->mkNode(kind::LEQ, cardUniv, typeCardinality); @@ -980,8 +980,8 @@ void CardinalityExtension::checkMinCard() } if (!members.empty()) { - Node conc = nm->mkNode( - GEQ, cardTerm, nm->mkConst(CONST_RATIONAL, Rational(members.size()))); + Node conc = + nm->mkNode(GEQ, cardTerm, nm->mkConstInt(Rational(members.size()))); Node expn = exp.size() == 1 ? exp[0] : nm->mkNode(AND, exp); d_im.assertInference(conc, InferenceId::SETS_CARD_MINIMAL, expn, 1); } diff --git a/src/theory/sets/theory_sets_private.cpp b/src/theory/sets/theory_sets_private.cpp index f06580292..a08c051f6 100644 --- a/src/theory/sets/theory_sets_private.cpp +++ b/src/theory/sets/theory_sets_private.cpp @@ -59,7 +59,7 @@ TheorySetsPrivate::TheorySetsPrivate(Env& env, { d_true = NodeManager::currentNM()->mkConst(true); d_false = NodeManager::currentNM()->mkConst(false); - d_zero = NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(0)); + d_zero = NodeManager::currentNM()->mkConstInt(Rational(0)); } TheorySetsPrivate::~TheorySetsPrivate() @@ -1289,7 +1289,7 @@ void TheorySetsPrivate::preRegisterTerm(TNode node) case kind::RELATION_JOIN_IMAGE: { // these are logic exceptions, not type checking exceptions - if (node[1].getKind() != kind::CONST_RATIONAL) + if (!node[1].isConst()) { throw LogicException( "JoinImage cardinality constraint must be a constant"); diff --git a/src/theory/sets/theory_sets_rewriter.cpp b/src/theory/sets/theory_sets_rewriter.cpp index d603946c4..cb9b26731 100644 --- a/src/theory/sets/theory_sets_rewriter.cpp +++ b/src/theory/sets/theory_sets_rewriter.cpp @@ -272,13 +272,12 @@ RewriteResponse TheorySetsRewriter::postRewrite(TNode node) { { if(node[0].isConst()) { std::set<Node> elements = NormalForm::getElementsFromNormalConstant(node[0]); - return RewriteResponse( - REWRITE_DONE, nm->mkConst(CONST_RATIONAL, Rational(elements.size()))); + return RewriteResponse(REWRITE_DONE, + nm->mkConstInt(Rational(elements.size()))); } else if (node[0].getKind() == kind::SET_SINGLETON) { - return RewriteResponse(REWRITE_DONE, - nm->mkConst(CONST_RATIONAL, Rational(1))); + return RewriteResponse(REWRITE_DONE, nm->mkConstInt(Rational(1))); } else if (node[0].getKind() == kind::SET_UNION) { diff --git a/src/theory/sort_inference.cpp b/src/theory/sort_inference.cpp index 83062ce48..d44492259 100644 --- a/src/theory/sort_inference.cpp +++ b/src/theory/sort_inference.cpp @@ -405,10 +405,10 @@ int SortInference::process( Node n, std::map< Node, Node >& var_bound, std::map< for( size_t i=0; i<n.getNumChildren(); i++ ){ bool processChild = true; if( n.getKind()==kind::FORALL || n.getKind()==kind::EXISTS ){ - processChild = - options::userPatternsQuant() == options::UserPatMode::IGNORE - ? i == 1 - : i >= 1; + processChild = options().quantifiers.userPatternsQuant + == options::UserPatMode::IGNORE + ? i == 1 + : i >= 1; } if( processChild ){ children.push_back( n[i] ); @@ -672,10 +672,10 @@ Node SortInference::simplifyNode( for( size_t i=0; i<n.getNumChildren(); i++ ){ bool processChild = true; if( n.getKind()==kind::FORALL || n.getKind()==kind::EXISTS ){ - processChild = - options::userPatternsQuant() == options::UserPatMode::IGNORE - ? i == 1 - : i >= 1; + processChild = options().quantifiers.userPatternsQuant + == options::UserPatMode::IGNORE + ? i == 1 + : i >= 1; } if( processChild ){ if (isHandledApplyUf(n.getKind())) diff --git a/src/theory/strings/arith_entail.cpp b/src/theory/strings/arith_entail.cpp index 8eaa50354..19f1bc97d 100644 --- a/src/theory/strings/arith_entail.cpp +++ b/src/theory/strings/arith_entail.cpp @@ -32,7 +32,7 @@ namespace strings { ArithEntail::ArithEntail(Rewriter* r) : d_rr(r) { - d_zero = NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(0)); + d_zero = NodeManager::currentNM()->mkConstInt(Rational(0)); } Node ArithEntail::rewrite(Node a) { return d_rr->rewrite(a); } @@ -76,11 +76,10 @@ bool ArithEntail::check(Node a, bool strict) return a.getConst<Rational>().sgn() >= (strict ? 1 : 0); } - Node ar = strict ? NodeManager::currentNM()->mkNode( - kind::MINUS, - a, - NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(1))) - : a; + Node ar = + strict ? NodeManager::currentNM()->mkNode( + kind::MINUS, a, NodeManager::currentNM()->mkConstInt(Rational(1))) + : a; ar = d_rr->rewrite(ar); if (ar.getAttribute(StrCheckEntailArithComputedAttr())) @@ -133,7 +132,7 @@ bool ArithEntail::checkApprox(Node ar) << "Get approximations " << v << "..." << std::endl; if (v.isNull()) { - Node mn = c.isNull() ? nm->mkConst(CONST_RATIONAL, Rational(1)) : c; + Node mn = c.isNull() ? nm->mkConstInt(Rational(1)) : c; aarSum.push_back(mn); } else @@ -496,8 +495,8 @@ void ArithEntail::getArithApproximations(Node a, { // x >= 0 implies // x+1 >= len( int.to.str( x ) ) - approx.push_back(nm->mkNode( - PLUS, nm->mkConst(CONST_RATIONAL, Rational(1)), a[0][0])); + approx.push_back( + nm->mkNode(PLUS, nm->mkConstInt(Rational(1)), a[0][0])); } } } @@ -507,7 +506,7 @@ void ArithEntail::getArithApproximations(Node a, { // x >= 0 implies // len( int.to.str( x ) ) >= 1 - approx.push_back(nm->mkConst(CONST_RATIONAL, Rational(1))); + approx.push_back(nm->mkConstInt(Rational(1))); } // other crazy things are possible here, e.g. // len( int.to.str( len( y ) + 10 ) ) >= 2 @@ -541,7 +540,7 @@ void ArithEntail::getArithApproximations(Node a, // ...hard to test, runs risk of non-termination // -1 <= indexof( x, y, n ) - approx.push_back(nm->mkConst(CONST_RATIONAL, Rational(-1))); + approx.push_back(nm->mkConstInt(Rational(-1))); } } else if (ak == STRING_STOI) @@ -556,7 +555,7 @@ void ArithEntail::getArithApproximations(Node a, else { // -1 <= str.to.int( x ) - approx.push_back(nm->mkConst(CONST_RATIONAL, Rational(-1))); + approx.push_back(nm->mkConstInt(Rational(-1))); } } Trace("strings-ent-approx-debug") << "Return " << approx.size() << std::endl; @@ -661,9 +660,8 @@ bool ArithEntail::checkWithAssumption(Node assumption, // (not (>= s t)) --> (>= (t - 1) s) Assert(assumption.getKind() == kind::NOT && assumption[0].getKind() == kind::GEQ); - x = nm->mkNode(kind::MINUS, - assumption[0][1], - nm->mkConst(CONST_RATIONAL, Rational(1))); + x = nm->mkNode( + kind::MINUS, assumption[0][1], nm->mkConstInt(Rational(1))); y = assumption[0][0]; } @@ -866,7 +864,7 @@ Node ArithEntail::getConstantBoundLength(TNode s, bool isLower) const if (s.isConst()) { size_t len = Word::getLength(s); - ret = nm->mkConst(CONST_RATIONAL, Rational(len)); + ret = nm->mkConstInt(Rational(len)); } else if (s.getKind() == STRING_CONCAT) { @@ -885,12 +883,12 @@ Node ArithEntail::getConstantBoundLength(TNode s, bool isLower) const success = false; break; } - Assert(b.getKind() == CONST_RATIONAL); + Assert(b.isConst()); sum = sum + b.getConst<Rational>(); } if (success && (!isLower || sum.sgn() != 0)) { - ret = nm->mkConst(CONST_RATIONAL, sum); + ret = nm->mkConstInt(sum); } } if (ret.isNull() && isLower) diff --git a/src/theory/strings/array_core_solver.cpp b/src/theory/strings/array_core_solver.cpp new file mode 100644 index 000000000..3b8fdeff4 --- /dev/null +++ b/src/theory/strings/array_core_solver.cpp @@ -0,0 +1,300 @@ +/****************************************************************************** + * Top contributors (to current version): + * Andres Noetzli + * + * This file is part of the cvc5 project. + * + * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS + * in the top-level source directory and their institutional affiliations. + * All rights reserved. See the file COPYING in the top-level source + * directory for licensing information. + * **************************************************************************** + * + * Sequences solver for seq.nth/seq.update. + */ + +#include "theory/strings/array_core_solver.h" + +#include "theory/strings/array_solver.h" +#include "theory/strings/theory_strings_utils.h" +#include "theory/strings/word.h" +#include "util/rational.h" + +using namespace cvc5::context; +using namespace cvc5::kind; + +namespace cvc5 { +namespace theory { +namespace strings { + +ArrayCoreSolver::ArrayCoreSolver(Env& env, + SolverState& s, + InferenceManager& im, + TermRegistry& tr, + CoreSolver& cs, + ExtfSolver& es, + ExtTheory& extt) + : EnvObj(env), + d_state(s), + d_im(im), + d_termReg(tr), + d_csolver(cs), + d_esolver(es), + d_extt(extt), + d_lem(context()) +{ +} + +ArrayCoreSolver::~ArrayCoreSolver() {} + +void ArrayCoreSolver::sendInference(const std::vector<Node>& exp, + const Node& lem, + const InferenceId iid) +{ + if (d_lem.find(lem) == d_lem.end()) + { + d_lem.insert(lem); + Trace("seq-update") << "- send lemma - " << lem << std::endl; + d_im.sendInference(exp, lem, iid); + } +} + +void ArrayCoreSolver::checkNth(const std::vector<Node>& nthTerms) +{ + NodeManager* nm = NodeManager::currentNM(); + std::vector<Node> extractTerms = d_esolver.getActive(STRING_SUBSTR); + for (const Node& n : extractTerms) + { + if (d_termReg.isHandledUpdate(n)) + { + // (seq.extract A i l) ^ (<= 0 i) ^ (< i (str.len A)) --> (seq.unit + // (seq.nth A i)) + std::vector<Node> exp; + Node cond1 = nm->mkNode(LEQ, nm->mkConstInt(Rational(0)), n[1]); + Node cond2 = nm->mkNode(LT, n[1], nm->mkNode(STRING_LENGTH, n[0])); + Node cond = nm->mkNode(AND, cond1, cond2); + Node body1 = nm->mkNode( + EQUAL, n, nm->mkNode(SEQ_UNIT, nm->mkNode(SEQ_NTH, n[0], n[1]))); + Node body2 = nm->mkNode(EQUAL, n, Word::mkEmptyWord(n.getType())); + Node lem = nm->mkNode(ITE, cond, body1, body2); + sendInference(exp, lem, InferenceId::STRINGS_ARRAY_NTH_EXTRACT); + } + } +} + +void ArrayCoreSolver::checkUpdate(const std::vector<Node>& updateTerms) +{ + NodeManager* nm = NodeManager::currentNM(); + + Trace("seq-array-debug") << "updateTerms number: " << updateTerms.size() + << std::endl; + for (const Node& n : updateTerms) + { + // current term (seq.update x i a) + + // inference rule is: + // (seq.update x i a) in TERMS + // (seq.nth t j) in TERMS + // t == (seq.update x i a) + // ---------------------------------------------------------------------- + // (seq.nth (seq.update x i a) j) = + // (ITE, j in range(i, i+len(a)), (seq.nth a (j - i)), (seq.nth x j)) + + // t == (seq.update x i a) => + // (seq.nth t j) = (ITE, j in range(i, i+len(a)), (seq.nth a (j - i)), + // (seq.nth x j)) + + // note that the term could rewrites to a skolem + // get proxy variable for the update term as t + Node termProxy = d_termReg.getProxyVariableFor(n); + Trace("seq-update") << "- " << termProxy << " = " << n << std::endl; + std::vector<Node> exp; + d_im.addToExplanation(termProxy, n, exp); + + // optimization: add a short cut t == (seq.update n[0] n[1] n[2]) => t[i] == + // n[2][0] + Node left = nm->mkNode(SEQ_NTH, termProxy, n[1]); + Node right = + nm->mkNode(SEQ_NTH, n[2], nm->mkConstInt(Rational(0))); // n[2][0] + right = Rewriter::rewrite(right); + Node lem = nm->mkNode(EQUAL, left, right); + Trace("seq-array-debug") << "enter" << std::endl; + sendInference(exp, lem, InferenceId::STRINGS_ARRAY_NTH_UPDATE); + + // enumerate possible index + for (auto nth : d_index_map) + { + Node seq = nth.first; + if (d_state.areEqual(seq, n) || d_state.areEqual(seq, n[0])) + { + std::set<Node> indexes = nth.second; + for (Node j : indexes) + { + // optimization: add a short cut for special case (seq.update n[0] + // n[1] (seq.unit e)) + if (n[2].getKind() == SEQ_UNIT) + { + left = nm->mkNode(DISTINCT, n[1], j); + Node nth1 = nm->mkNode(SEQ_NTH, termProxy, j); + Node nth2 = nm->mkNode(SEQ_NTH, n[0], j); + right = nm->mkNode(EQUAL, nth1, nth2); + lem = nm->mkNode(IMPLIES, left, right); + sendInference(exp, lem, InferenceId::STRINGS_ARRAY_NTH_UPDATE); + } + + // normal cases + left = nm->mkNode(SEQ_NTH, termProxy, j); + Node cond = nm->mkNode( + AND, + nm->mkNode(LEQ, n[1], j), + nm->mkNode( + LT, + j, + nm->mkNode(PLUS, n[1], nm->mkNode(STRING_LENGTH, n[2])))); + Node body1 = nm->mkNode(SEQ_NTH, n[2], nm->mkNode(MINUS, j, n[1])); + Node body2 = nm->mkNode(SEQ_NTH, n[0], j); + right = nm->mkNode(ITE, cond, body1, body2); + lem = nm->mkNode(EQUAL, left, right); + sendInference(exp, lem, InferenceId::STRINGS_ARRAY_NTH_UPDATE); + } + } + } + } +} + +void ArrayCoreSolver::check(const std::vector<Node>& nthTerms, + const std::vector<Node>& updateTerms) +{ + NodeManager* nm = NodeManager::currentNM(); + + Trace("seq-array-debug") << "NTH SIZE: " << nthTerms.size() << std::endl; + if (Trace.isOn("seq-array-terms")) + { + for (const Node& n : nthTerms) + { + Trace("seq-array-terms") << n << std::endl; + } + } + Trace("seq-array-debug") << "UPDATE SIZE: " << updateTerms.size() + << std::endl; + if (Trace.isOn("seq-array-terms")) + { + for (const Node& n : updateTerms) + { + Trace("seq-array-terms") << n << std::endl; + } + } + Trace("seq-update") << "SequencesArraySolver::check..." << std::endl; + d_writeModel.clear(); + d_index_map.clear(); + for (const Node& n : nthTerms) + { + // (seq.nth n[0] n[1]) + Node r = d_state.getRepresentative(n[0]); + Trace("seq-update") << "- " << r << ": " << n[1] << " -> " << n + << std::endl; + d_writeModel[r][n[1]] = n; + if (d_index_map.find(r) == d_index_map.end()) + { + std::set<Node> indexes; + indexes.insert(n[1]); + d_index_map[r] = indexes; + } + else + { + d_index_map[r].insert(n[1]); + } + + if (n[0].getKind() == STRING_REV) + { + Node s = n[0][0]; + Node i = n[1]; + Node sLen = nm->mkNode(STRING_LENGTH, s); + Node iRev = nm->mkNode( + MINUS, sLen, nm->mkNode(PLUS, i, nm->mkConstInt(Rational(1)))); + + std::vector<Node> nexp; + nexp.push_back(nm->mkNode(LEQ, nm->mkConstInt(Rational(0)), i)); + nexp.push_back(nm->mkNode(LT, i, sLen)); + + // 0 <= i ^ i < len(s) => seq.nth(seq.rev(s), i) = seq.nth(s, len(s) - i - + // 1) + Node ret = nm->mkNode(SEQ_NTH, s, iRev); + d_im.sendInference( + {}, nexp, n.eqNode(ret), InferenceId::STRINGS_ARRAY_NTH_REV); + d_extt.markReduced(n, ExtReducedId::STRINGS_NTH_REV); + } + } + checkNth(nthTerms); + checkUpdate(updateTerms); + // compute connected sequences + if (!d_im.hasSent()) + { + computeConnected(updateTerms); + } +} + +void ArrayCoreSolver::computeConnected(const std::vector<Node>& updateTerms) +{ + d_connectedSeq.clear(); + std::map<Node, Node> conTmp; + std::map<Node, Node>::iterator it; + for (const Node& n : updateTerms) + { + Node newRep; + for (size_t i = 0; i < 2; i++) + { + Node s = i == 0 ? n[0] : n; + TNode r = d_state.getRepresentative(s); + // get the find + it = conTmp.find(r); + while (it != conTmp.end()) + { + r = it->second; + it = conTmp.find(r); + } + if (i == 0) + { + newRep = r; + } + else if (newRep != r) + { + conTmp[newRep] = r; + } + } + } + // go back and normalize the find to representatives + for (std::pair<const Node, Node>& c : conTmp) + { + TNode r = c.first; + it = conTmp.find(r); + while (it != conTmp.end()) + { + r = it->second; + it = conTmp.find(r); + } + d_connectedSeq[c.first] = r; + } +} + +const std::map<Node, Node>& ArrayCoreSolver::getWriteModel(Node eqc) +{ + if (Trace.isOn("seq-write-model")) + { + Trace("seq-write-model") << "write model of " << eqc << ":" << std::endl; + for (auto& x : d_writeModel[eqc]) + { + Trace("seq-write-model") << x.first << ": " << x.second << std::endl; + } + } + return d_writeModel[eqc]; +} + +const std::map<Node, Node>& ArrayCoreSolver::getConnectedSequences() +{ + return d_connectedSeq; +} + +} // namespace strings +} // namespace theory +} // namespace cvc5 diff --git a/src/theory/strings/array_core_solver.h b/src/theory/strings/array_core_solver.h new file mode 100644 index 000000000..3873f6a69 --- /dev/null +++ b/src/theory/strings/array_core_solver.h @@ -0,0 +1,146 @@ +/****************************************************************************** + * Top contributors (to current version): + * Andres Noetzli + * + * This file is part of the cvc5 project. + * + * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS + * in the top-level source directory and their institutional affiliations. + * All rights reserved. See the file COPYING in the top-level source + * directory for licensing information. + * **************************************************************************** + * + * Sequences solver for seq.nth/seq.update. + */ + +#include "cvc5_private.h" + +#ifndef CVC5__THEORY__STRINGS__ARRAY_CORE_SOLVER_H +#define CVC5__THEORY__STRINGS__ARRAY_CORE_SOLVER_H + +#include "theory/strings/core_solver.h" +#include "theory/strings/extf_solver.h" +#include "theory/strings/inference_manager.h" +#include "theory/strings/solver_state.h" +#include "theory/strings/term_registry.h" + +namespace cvc5 { +namespace theory { +namespace strings { + +class ArrayCoreSolver : protected EnvObj +{ + public: + ArrayCoreSolver(Env& env, + SolverState& s, + InferenceManager& im, + TermRegistry& tr, + CoreSolver& cs, + ExtfSolver& es, + ExtTheory& extt); + ~ArrayCoreSolver(); + + /** + * Perform reasoning about seq.nth and seq.update operations. + * + * Can assume that seq.update / seq.nth terms only apply to concatenation-free + * equivalence classes. + */ + void check(const std::vector<Node>& nthTerms, + const std::vector<Node>& updateTerms); + + /** + * + * @param eqc The sequence equivalence class representative. We can assume + * the equivalence class of eqc contains no concatenation terms. + * @return the map corresponding to the model for eqc. The domain of + * the returned map should be in distinct integer equivalence classes of the + * equality engine of strings theory. The model assigned to eqc will be + * a skeleton constructed via seq.++ where the components take values from + * this map. + */ + const std::map<Node, Node>& getWriteModel(Node eqc); + + /** + * Get connected sequences, see documentation of computeConnected. + * @return a map M such that sequence equivalence class representatives x and + * y are connected if an only if M[x] = M[y]. + */ + const std::map<Node, Node>& getConnectedSequences(); + + private: + void sendInference(const std::vector<Node>& exp, + const Node& lem, + const InferenceId iid); + + /** + * Perform reasoning about seq.nth operation. + * It handled the reduction from seq.extract to seq.nth, following the rule + * below: (t = (seq.extract A i 1)) ^ (0 <= i) ^ (i < (str.len A)) + * ---------------------------------------------------------------------- + * t = (seq.unit (seq.nth A i)) + */ + void checkNth(const std::vector<Node>& nthTerms); + + /** + * Perform reasoning about seq.update operation. + * It handled the reduction from seq.update to seq.nth, following the rule + * below: (seq.update x i a) in TERMS (seq.nth t j) in TERMS t == (seq.update + * x i a) + * ---------------------------------------------------------------------- + * (seq.nth (seq.update x i a) j) = (ITE, j in range(i, i+len(a)), (seq.nth a + * (j - i)), (seq.nth x j)) + */ + void checkUpdate(const std::vector<Node>& updateTerms); + + /** + * Given the current set of update terms, this computes the connected + * sequences implied by the current equality information + this set of terms. + * Connected sequences is a reflexive transitive relation where additionally + * a and b are connected if there exists an update term (seq.update a n x) + * that is currently equal to b. + * + * This method runs a union find algorithm to compute all connected sequences. + * + * As a result of running this method, the map d_connectedSeq is populated + * with information regarding which sequences are connected. + */ + void computeConnected(const std::vector<Node>& updateTerms); + + /** The solver state object */ + SolverState& d_state; + /** The (custom) output channel of the theory of strings */ + InferenceManager& d_im; + /** Reference to the term registry of theory of strings */ + TermRegistry& d_termReg; + /** reference to the core solver, used for certain queries */ + CoreSolver& d_csolver; + /** reference to the extended solver, used for certain queries */ + ExtfSolver& d_esolver; + /** the extended theory object for the theory of strings */ + ExtTheory& d_extt; + /** The write model */ + std::map<Node, std::map<Node, Node>> d_writeModel; + /** + * Map from sequences to their "connected representative". Two sequences are + * connected (based on the definition described in computeConnected) iff they + * have the same connected representative. Sequences that do not occur in + * this map are assumed to be their own connected representative. + * + * This map is only valid after running computeConnected, and is valid + * only during model building. + */ + std::map<Node, Node> d_connectedSeq; + /** The set of lemmas been sent */ + context::CDHashSet<Node> d_lem; + + // ========= data structure ========= + /** Map sequence variable to indices that occurred in nth terms */ + std::map<Node, std::set<Node>> d_index_map; +}; + +} // namespace strings +} // namespace theory +} // namespace cvc5 + +#endif diff --git a/src/theory/strings/array_solver.cpp b/src/theory/strings/array_solver.cpp index 65ff4cde4..672ca8b76 100644 --- a/src/theory/strings/array_solver.cpp +++ b/src/theory/strings/array_solver.cpp @@ -41,10 +41,11 @@ ArraySolver::ArraySolver(Env& env, d_termReg(tr), d_csolver(cs), d_esolver(es), + d_coreSolver(env, s, im, tr, cs, es, extt), d_eqProc(context()) { NodeManager* nm = NodeManager::currentNM(); - d_zero = nm->mkConst(CONST_RATIONAL, Rational(0)); + d_zero = nm->mkConstInt(Rational(0)); } ArraySolver::~ArraySolver() {} @@ -63,6 +64,32 @@ void ArraySolver::checkArrayConcat() checkTerms(SEQ_NTH); } +void ArraySolver::checkArray() +{ + if (!d_termReg.hasSeqUpdate()) + { + Trace("seq-array") << "No seq.update/seq.nth terms, skipping check..." + << std::endl; + return; + } + Trace("seq-array") << "ArraySolver::checkArray..." << std::endl; + d_coreSolver.check(d_currTerms[SEQ_NTH], d_currTerms[STRING_UPDATE]); +} + +void ArraySolver::checkArrayEager() +{ + if (!d_termReg.hasSeqUpdate()) + { + Trace("seq-array") << "No seq.update/seq.nth terms, skipping check..." + << std::endl; + return; + } + Trace("seq-array") << "ArraySolver::checkArray..." << std::endl; + std::vector<Node> nthTerms = d_esolver.getActive(SEQ_NTH); + std::vector<Node> updateTerms = d_esolver.getActive(STRING_UPDATE); + d_coreSolver.check(nthTerms, updateTerms); +} + void ArraySolver::checkTerms(Kind k) { Assert(k == STRING_UPDATE || k == SEQ_NTH); @@ -271,6 +298,16 @@ void ArraySolver::checkTerms(Kind k) } } +const std::map<Node, Node>& ArraySolver::getWriteModel(Node eqc) +{ + return d_coreSolver.getWriteModel(eqc); +} + +const std::map<Node, Node>& ArraySolver::getConnectedSequences() +{ + return d_coreSolver.getConnectedSequences(); +} + } // namespace strings } // namespace theory } // namespace cvc5 diff --git a/src/theory/strings/array_solver.h b/src/theory/strings/array_solver.h index 941061e9e..23bacd118 100644 --- a/src/theory/strings/array_solver.h +++ b/src/theory/strings/array_solver.h @@ -19,6 +19,7 @@ #define CVC5__THEORY__STRINGS__ARRAY_SOLVER_H #include "context/cdhashset.h" +#include "theory/strings/array_core_solver.h" #include "theory/strings/core_solver.h" #include "theory/strings/extf_solver.h" #include "theory/strings/inference_manager.h" @@ -54,6 +55,32 @@ class ArraySolver : protected EnvObj * their application to concatenation terms. */ void checkArrayConcat(); + /** + * Perform reasoning about seq.nth and seq.update operations (lazily), which + * calls the core sequences-array solver for the set of nth/update terms over atomic + * equivalence classes. + */ + void checkArray(); + /** + * Same as `checkArray`, but called eagerly, and for all nth/update terms, not just + * those over atomic equivalence classes. + */ + void checkArrayEager(); + + /** + * @param eqc The sequence equivalence class representative. We can assume + * the equivalence class of eqc contains no concatenation terms. + * @return the map corresponding to the model for eqc. The domain of + * the returned map should be in distinct integer equivalence classes of the + * equality engine of strings theory. The model assigned to eqc will be + * a skeleton constructed via seq.++ where the components take values from + * this map. + */ + const std::map<Node, Node>& getWriteModel(Node eqc); + /** + * Get connected sequences from the core array solver. + */ + const std::map<Node, Node>& getConnectedSequences(); private: /** check terms of given kind */ @@ -72,6 +99,8 @@ class ArraySolver : protected EnvObj std::map<Kind, std::vector<Node> > d_currTerms; /** Common constants */ Node d_zero; + /** The core array solver */ + ArrayCoreSolver d_coreSolver; /** Equalities we have processed in the current context */ NodeSet d_eqProc; }; diff --git a/src/theory/strings/base_solver.cpp b/src/theory/strings/base_solver.cpp index 69d50a7d9..2d25a0d1e 100644 --- a/src/theory/strings/base_solver.cpp +++ b/src/theory/strings/base_solver.cpp @@ -604,8 +604,7 @@ void BaseSolver::checkCardinalityType(TypeNode tn, if (lr.isConst()) { // if constant, compare - Node cmp = - nm->mkNode(GEQ, lr, nm->mkConst(CONST_RATIONAL, Rational(card_need))); + Node cmp = nm->mkNode(GEQ, lr, nm->mkConstInt(Rational(card_need))); cmp = rewrite(cmp); needsSplit = !cmp.getConst<bool>(); } @@ -619,7 +618,7 @@ void BaseSolver::checkCardinalityType(TypeNode tn, bool success = true; while (r < card_need && success) { - Node rr = nm->mkConst(CONST_RATIONAL, Rational(r)); + Node rr = nm->mkConstInt(Rational(r)); if (d_state.areDisequal(rr, lr)) { r++; @@ -669,7 +668,7 @@ void BaseSolver::checkCardinalityType(TypeNode tn, << std::endl; if (int_k + 1 > ei->d_cardinalityLemK.get()) { - Node k_node = nm->mkConst(CONST_RATIONAL, Rational(int_k)); + Node k_node = nm->mkConstInt(Rational(int_k)); // add cardinality lemma Node dist = nm->mkNode(DISTINCT, cols[i]); std::vector<Node> expn; diff --git a/src/theory/strings/core_solver.cpp b/src/theory/strings/core_solver.cpp index 46f75bd10..ab214c9ce 100644 --- a/src/theory/strings/core_solver.cpp +++ b/src/theory/strings/core_solver.cpp @@ -50,9 +50,9 @@ CoreSolver::CoreSolver(Env& env, d_nfPairs(context()), d_extDeq(userContext()) { - d_zero = NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(0)); - d_one = NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(1)); - d_neg_one = NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(-1)); + d_zero = NodeManager::currentNM()->mkConstInt(Rational(0)); + d_one = NodeManager::currentNM()->mkConstInt(Rational(1)); + d_neg_one = NodeManager::currentNM()->mkConstInt(Rational(-1)); d_true = NodeManager::currentNM()->mkConst( true ); d_false = NodeManager::currentNM()->mkConst( false ); } @@ -776,12 +776,12 @@ Node CoreSolver::getConclusion(Node x, { // we can assume its length is greater than zero Node emp = Word::mkEmptyWord(sk1.getType()); - conc = nm->mkNode(AND, - conc, - sk1.eqNode(emp).negate(), - nm->mkNode(GT, - nm->mkNode(STRING_LENGTH, sk1), - nm->mkConst(CONST_RATIONAL, Rational(0)))); + conc = nm->mkNode( + AND, + conc, + sk1.eqNode(emp).negate(), + nm->mkNode( + GT, nm->mkNode(STRING_LENGTH, sk1), nm->mkConstInt(Rational(0)))); } } else if (rule == PfRule::CONCAT_CSPLIT) diff --git a/src/theory/strings/eager_solver.cpp b/src/theory/strings/eager_solver.cpp index ac8e815df..0e5c19658 100644 --- a/src/theory/strings/eager_solver.cpp +++ b/src/theory/strings/eager_solver.cpp @@ -227,7 +227,7 @@ bool EagerSolver::addArithmeticBound(EqcInfo* e, Node t, bool isLower) Assert(e != nullptr); Assert(!t.isNull()); Node tb = t.isConst() ? t : getBoundForLength(t, isLower); - Assert(!tb.isNull() && tb.getKind() == CONST_RATIONAL) + Assert(!tb.isNull() && tb.isConst() && tb.getType().isInteger()) << "Unexpected bound " << tb << " from " << t; Rational br = tb.getConst<Rational>(); Node prev = isLower ? e->d_firstBound : e->d_secondBound; @@ -236,7 +236,7 @@ bool EagerSolver::addArithmeticBound(EqcInfo* e, Node t, bool isLower) { // convert to bound Node prevb = prev.isConst() ? prev : getBoundForLength(prev, isLower); - Assert(!prevb.isNull() && prevb.getKind() == CONST_RATIONAL); + Assert(!prevb.isNull() && prevb.isConst() && prevb.getType().isInteger()); Rational prevbr = prevb.getConst<Rational>(); if (prevbr == br || (br < prevbr) == isLower) { @@ -251,7 +251,8 @@ bool EagerSolver::addArithmeticBound(EqcInfo* e, Node t, bool isLower) { // are we in conflict? Node prevob = prevo.isConst() ? prevo : getBoundForLength(prevo, !isLower); - Assert(!prevob.isNull() && prevob.getKind() == CONST_RATIONAL); + Assert(!prevob.isNull() && prevob.isConst() + && prevob.getType().isInteger()); Rational prevobr = prevob.getConst<Rational>(); if (prevobr != br && (prevobr < br) == isLower) { diff --git a/src/theory/strings/infer_proof_cons.cpp b/src/theory/strings/infer_proof_cons.cpp index edfb91c64..81da50062 100644 --- a/src/theory/strings/infer_proof_cons.cpp +++ b/src/theory/strings/infer_proof_cons.cpp @@ -499,7 +499,7 @@ void InferProofCons::convert(InferenceId infer, { // it should be the case that lenConstraint => lenReq lenReq = nm->mkNode(STRING_LENGTH, t0) - .eqNode(nm->mkConst(CONST_RATIONAL, Rational(0))) + .eqNode(nm->mkConstInt(Rational(0))) .notNode(); lenSuccess = convertLengthPf(lenReq, lenConstraint, psb); rule = PfRule::CONCAT_CSPLIT; @@ -530,7 +530,7 @@ void InferProofCons::convert(InferenceId infer, { // it should be the case that lenConstraint => lenReq lenReq = nm->mkNode(STRING_LENGTH, t0) - .eqNode(nm->mkConst(CONST_RATIONAL, Rational(0))) + .eqNode(nm->mkConstInt(Rational(0))) .notNode(); lenSuccess = convertLengthPf(lenReq, lenConstraint, psb); rule = PfRule::CONCAT_CPROP; @@ -837,7 +837,7 @@ void InferProofCons::convert(InferenceId infer, std::vector<Node> childrenAE; childrenAE.push_back(eunf); std::vector<Node> argsAE; - argsAE.push_back(nm->mkConst(CONST_RATIONAL, Rational(0))); + argsAE.push_back(nm->mkConstInt(Rational(0))); Node eunfAE = psb.tryStep(PfRule::AND_ELIM, childrenAE, argsAE); Trace("strings-ipc-prefix") << "--- and elim to " << eunfAE << std::endl; diff --git a/src/theory/strings/inference_manager.cpp b/src/theory/strings/inference_manager.cpp index 5247e222d..c7020869f 100644 --- a/src/theory/strings/inference_manager.cpp +++ b/src/theory/strings/inference_manager.cpp @@ -51,8 +51,8 @@ InferenceManager::InferenceManager(Env& env, : nullptr) { NodeManager* nm = NodeManager::currentNM(); - d_zero = nm->mkConst(CONST_RATIONAL, Rational(0)); - d_one = nm->mkConst(CONST_RATIONAL, Rational(1)); + d_zero = nm->mkConstInt(Rational(0)); + d_one = nm->mkConstInt(Rational(1)); d_true = nm->mkConst(true); d_false = nm->mkConst(false); } diff --git a/src/theory/strings/proof_checker.cpp b/src/theory/strings/proof_checker.cpp index edb38e702..dc01bb6d7 100644 --- a/src/theory/strings/proof_checker.cpp +++ b/src/theory/strings/proof_checker.cpp @@ -212,8 +212,8 @@ Node StringProofRuleChecker::checkInternal(PfRule id, else if (id == PfRule::CONCAT_CSPLIT) { Assert(children.size() == 2); - Node zero = nm->mkConst(CONST_RATIONAL, Rational(0)); - Node one = nm->mkConst(CONST_RATIONAL, Rational(1)); + Node zero = nm->mkConstInt(Rational(0)); + Node one = nm->mkConstInt(Rational(1)); if (children[1].getKind() != NOT || children[1][0].getKind() != EQUAL || children[1][0][0].getKind() != STRING_LENGTH || children[1][0][0][0] != t0 || children[1][0][1] != zero) @@ -240,7 +240,7 @@ Node StringProofRuleChecker::checkInternal(PfRule id, else if (id == PfRule::CONCAT_CPROP) { Assert(children.size() == 2); - Node zero = nm->mkConst(CONST_RATIONAL, Rational(0)); + Node zero = nm->mkConstInt(Rational(0)); Trace("pfcheck-strings-cprop") << "CONCAT_PROP, isRev=" << isRev << std::endl; @@ -352,7 +352,7 @@ Node StringProofRuleChecker::checkInternal(PfRule id, { return Node::null(); } - Node zero = nm->mkConst(CONST_RATIONAL, Rational(0)); + Node zero = nm->mkConstInt(Rational(0)); Node clen = nm->mkNode(STRING_LENGTH, nemp[0][0]); return clen.eqNode(zero).notNode(); } @@ -462,7 +462,7 @@ Node StringProofRuleChecker::checkInternal(PfRule id, && args[1].getType().isStringLike()); Node c1 = nm->mkNode(STRING_TO_CODE, args[0]); Node c2 = nm->mkNode(STRING_TO_CODE, args[1]); - Node eqNegOne = c1.eqNode(nm->mkConst(CONST_RATIONAL, Rational(-1))); + Node eqNegOne = c1.eqNode(nm->mkConstInt(Rational(-1))); Node deq = c1.eqNode(c2).negate(); Node eqn = args[0].eqNode(args[1]); return nm->mkNode(kind::OR, eqNegOne, deq, eqn); diff --git a/src/theory/strings/regexp_elim.cpp b/src/theory/strings/regexp_elim.cpp index 8a96e22d2..477533bee 100644 --- a/src/theory/strings/regexp_elim.cpp +++ b/src/theory/strings/regexp_elim.cpp @@ -98,7 +98,7 @@ Node RegExpElimination::eliminateConcat(Node atom, bool isAgg) Node x = atom[0]; Node lenx = nm->mkNode(STRING_LENGTH, x); Node re = atom[1]; - Node zero = nm->mkConst(CONST_RATIONAL, Rational(0)); + Node zero = nm->mkConstInt(Rational(0)); std::vector<Node> children; utils::getConcat(re, children); @@ -252,10 +252,8 @@ Node RegExpElimination::eliminateConcat(Node atom, bool isAgg) if (gap_minsize[i] > 0) { // the gap to this child is at least gap_minsize[i] - prev_end = - nm->mkNode(PLUS, - prev_end, - nm->mkConst(CONST_RATIONAL, Rational(gap_minsize[i]))); + prev_end = nm->mkNode( + PLUS, prev_end, nm->mkConstInt(Rational(gap_minsize[i]))); } prev_ends.push_back(prev_end); Node sc = sep_children[i]; @@ -280,8 +278,8 @@ Node RegExpElimination::eliminateConcat(Node atom, bool isAgg) } // if the gap after this one is strict, we need a non-greedy find // thus, we add a symbolic constant - Node cacheVal = BoundVarManager::getCacheValue( - atom, nm->mkConst(CONST_RATIONAL, Rational(i))); + Node cacheVal = + BoundVarManager::getCacheValue(atom, nm->mkConstInt(Rational(i))); TypeNode intType = nm->integerType(); Node k = bvm->mkBoundVar<ReElimConcatIndexAttribute>(cacheVal, intType); @@ -289,8 +287,7 @@ Node RegExpElimination::eliminateConcat(Node atom, bool isAgg) prev_end = nm->mkNode(PLUS, prev_end, k); } Node curr = nm->mkNode(STRING_INDEXOF, x, sc, prev_end); - Node idofFind = - curr.eqNode(nm->mkConst(CONST_RATIONAL, Rational(-1))).negate(); + Node idofFind = curr.eqNode(nm->mkConstInt(Rational(-1))).negate(); conj.push_back(idofFind); prev_end = nm->mkNode(PLUS, curr, lensc); } @@ -305,7 +302,7 @@ Node RegExpElimination::eliminateConcat(Node atom, bool isAgg) // then the last indexof/substr constraint entails the following // constraint, so it is not necessary to add. // Below, we may write "A" for (str.to.re "A") and _ for re.allchar: - Node cEnd = nm->mkConst(CONST_RATIONAL, Rational(gap_minsize_end)); + Node cEnd = nm->mkConstInt(Rational(gap_minsize_end)); if (gap_exact_end) { Assert(!sep_children.empty()); @@ -477,8 +474,8 @@ Node RegExpElimination::eliminateConcat(Node atom, bool isAgg) } else { - Node cacheVal = BoundVarManager::getCacheValue( - atom, nm->mkConst(CONST_RATIONAL, Rational(i))); + Node cacheVal = + BoundVarManager::getCacheValue(atom, nm->mkConstInt(Rational(i))); TypeNode intType = nm->integerType(); k = bvm->mkBoundVar<ReElimConcatIndexAttribute>(cacheVal, intType); Node bound = @@ -541,7 +538,7 @@ Node RegExpElimination::eliminateStar(Node atom, bool isAgg) Node x = atom[0]; Node lenx = nm->mkNode(STRING_LENGTH, x); Node re = atom[1]; - Node zero = nm->mkConst(CONST_RATIONAL, Rational(0)); + Node zero = nm->mkConstInt(Rational(0)); // for regular expression star, // if the period is a fixed constant, we can turn it into a bounded // quantifier @@ -561,8 +558,8 @@ Node RegExpElimination::eliminateStar(Node atom, bool isAgg) std::vector<Node> char_constraints; TypeNode intType = nm->integerType(); Node index = bvm->mkBoundVar<ReElimStarIndexAttribute>(atom, intType); - Node substr_ch = nm->mkNode( - STRING_SUBSTR, x, index, nm->mkConst(CONST_RATIONAL, Rational(1))); + Node substr_ch = + nm->mkNode(STRING_SUBSTR, x, index, nm->mkConstInt(Rational(1))); substr_ch = Rewriter::rewrite(substr_ch); // handle the case where it is purely characters for (const Node& r : disj) diff --git a/src/theory/strings/regexp_entail.cpp b/src/theory/strings/regexp_entail.cpp index 645dc05cd..aa69f9ecf 100644 --- a/src/theory/strings/regexp_entail.cpp +++ b/src/theory/strings/regexp_entail.cpp @@ -30,8 +30,8 @@ namespace strings { RegExpEntail::RegExpEntail(Rewriter* r) : d_rewriter(r), d_aent(r) { - d_zero = NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(0)); - d_one = NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(1)); + d_zero = NodeManager::currentNM()->mkConstInt(Rational(0)); + d_one = NodeManager::currentNM()->mkConstInt(Rational(1)); } Node RegExpEntail::simpleRegexpConsume(std::vector<Node>& mchildren, @@ -584,7 +584,7 @@ bool RegExpEntail::testConstStringInRegExp(cvc5::String& s, } else { - Node num2 = nm->mkConst(CONST_RATIONAL, cvc5::Rational(u - 1)); + Node num2 = nm->mkConstInt(cvc5::Rational(u - 1)); Node r2 = nm->mkNode(REGEXP_LOOP, r[0], r[1], num2); if (testConstStringInRegExp(s, index_start + len, r2)) { @@ -616,7 +616,7 @@ bool RegExpEntail::testConstStringInRegExp(cvc5::String& s, cvc5::String t = s.substr(index_start, len); if (testConstStringInRegExp(t, 0, r[0])) { - Node num2 = nm->mkConst(CONST_RATIONAL, cvc5::Rational(l - 1)); + Node num2 = nm->mkConstInt(cvc5::Rational(l - 1)); Node r2 = nm->mkNode(REGEXP_LOOP, r[0], num2, num2); if (testConstStringInRegExp(s, index_start + len, r2)) { @@ -668,7 +668,7 @@ Node RegExpEntail::getFixedLengthForRegexp(TNode n) } else if (k == REGEXP_ALLCHAR || k == REGEXP_RANGE) { - return nm->mkConst(CONST_RATIONAL, Rational(1)); + return nm->mkConstInt(Rational(1)); } else if (k == REGEXP_UNION || k == REGEXP_INTER) { @@ -749,7 +749,7 @@ Node RegExpEntail::getConstantBoundLengthForRegexp(TNode n, bool isLower) const continue; } } - Assert(bc.getKind() == CONST_RATIONAL); + Assert(bc.isConst() && bc.getType().isInteger()); Rational r = bc.getConst<Rational>(); if (k == REGEXP_CONCAT) { @@ -772,7 +772,7 @@ Node RegExpEntail::getConstantBoundLengthForRegexp(TNode n, bool isLower) const // if we were successful and didn't ignore all components if (success && !firstTime) { - ret = nm->mkConst(CONST_RATIONAL, rr); + ret = nm->mkConstInt(rr); } } if (ret.isNull() && isLower) diff --git a/src/theory/strings/regexp_operation.cpp b/src/theory/strings/regexp_operation.cpp index a7ba37b18..eb6d2d355 100644 --- a/src/theory/strings/regexp_operation.cpp +++ b/src/theory/strings/regexp_operation.cpp @@ -37,10 +37,8 @@ RegExpOpr::RegExpOpr(Env& env, SkolemCache* sc) d_false(NodeManager::currentNM()->mkConst(false)), d_emptyRegexp(NodeManager::currentNM()->mkNode(kind::REGEXP_NONE, std::vector<Node>{})), - d_zero(NodeManager::currentNM()->mkConst(CONST_RATIONAL, - ::cvc5::Rational(0))), - d_one(NodeManager::currentNM()->mkConst(CONST_RATIONAL, - ::cvc5::Rational(1))), + d_zero(NodeManager::currentNM()->mkConstInt(Rational(0))), + d_one(NodeManager::currentNM()->mkConstInt(Rational(1))), d_sigma(NodeManager::currentNM()->mkNode(kind::REGEXP_ALLCHAR, std::vector<Node>{})), d_sigma_star( @@ -911,7 +909,7 @@ Node RegExpOpr::reduceRegExpNeg(Node mem) Node r = mem[0][1]; NodeManager* nm = NodeManager::currentNM(); Kind k = r.getKind(); - Node zero = nm->mkConst(CONST_RATIONAL, Rational(0)); + Node zero = nm->mkConstInt(Rational(0)); Node conc; if (k == REGEXP_CONCAT) { @@ -955,7 +953,7 @@ Node RegExpOpr::reduceRegExpNegConcatFixed(Node mem, Node reLen, size_t index) Node r = mem[0][1]; NodeManager* nm = NodeManager::currentNM(); Assert(r.getKind() == REGEXP_CONCAT); - Node zero = nm->mkConst(CONST_RATIONAL, Rational(0)); + Node zero = nm->mkConstInt(Rational(0)); // The following simplification states that // ~( s in R1 ++ R2 ++... ++ Rn ) // is equivalent to @@ -1040,7 +1038,7 @@ Node RegExpOpr::reduceRegExpPos(Node mem, } else { - Node ivalue = nm->mkConst(CONST_RATIONAL, Rational(i)); + Node ivalue = nm->mkConstInt(Rational(i)); Node sk = sm->mkSkolemFunction(SkolemFunId::RE_UNFOLD_POS_COMPONENT, s.getType(), {mem[0], mem[1], ivalue}); @@ -1321,10 +1319,8 @@ Node RegExpOpr::intersectInternal( Node r1, Node r2, std::map< PairNodes, Node > rt = itr2->second; } else { std::map< PairNodes, Node > cache2(cache); - cache2[p] = NodeManager::currentNM()->mkNode( - kind::REGEXP_RV, - NodeManager::currentNM()->mkConst(CONST_RATIONAL, - cvc5::Rational(cnt))); + cache2[p] = + nm->mkNode(kind::REGEXP_RV, nm->mkConstInt(Rational(cnt))); rt = intersectInternal(r1l, r2l, cache2, cnt+1); cacheX[ pp ] = rt; } diff --git a/src/theory/strings/rewrites.cpp b/src/theory/strings/rewrites.cpp index 4da6e5600..bfe9021aa 100644 --- a/src/theory/strings/rewrites.cpp +++ b/src/theory/strings/rewrites.cpp @@ -154,6 +154,7 @@ const char* toString(Rewrite r) case Rewrite::UPD_CONST_INDEX_MAX_OOB: return "UPD_CONST_INDEX_MAX_OOB"; case Rewrite::UPD_CONST_INDEX_NEG: return "UPD_CONST_INDEX_NEG"; case Rewrite::UPD_CONST_INDEX_OOB: return "UPD_CONST_INDEX_OOB"; + case Rewrite::UPD_REV: return "UPD_REV"; case Rewrite::STOI_CONCAT_NONNUM: return "STOI_CONCAT_NONNUM"; case Rewrite::STOI_EVAL: return "STOI_EVAL"; case Rewrite::STR_CONV_CONST: return "STR_CONV_CONST"; @@ -223,6 +224,7 @@ const char* toString(Rewrite r) case Rewrite::SEQ_UNIT_EVAL: return "SEQ_UNIT_EVAL"; case Rewrite::SEQ_NTH_EVAL: return "SEQ_NTH_EVAL"; case Rewrite::SEQ_NTH_TOTAL_OOB: return "SEQ_NTH_TOTAL_OOB"; + case Rewrite::SEQ_NTH_UNIT: return "SEQ_NTH_UNIT"; default: return "?"; } } diff --git a/src/theory/strings/rewrites.h b/src/theory/strings/rewrites.h index c96dffcde..b57c5f276 100644 --- a/src/theory/strings/rewrites.h +++ b/src/theory/strings/rewrites.h @@ -155,6 +155,7 @@ enum class Rewrite : uint32_t UPD_CONST_INDEX_MAX_OOB, UPD_CONST_INDEX_NEG, UPD_CONST_INDEX_OOB, + UPD_REV, STOI_CONCAT_NONNUM, STOI_EVAL, STR_CONV_CONST, @@ -223,7 +224,8 @@ enum class Rewrite : uint32_t CHARAT_ELIM, SEQ_UNIT_EVAL, SEQ_NTH_EVAL, - SEQ_NTH_TOTAL_OOB + SEQ_NTH_TOTAL_OOB, + SEQ_NTH_UNIT }; /** diff --git a/src/theory/strings/sequences_rewriter.cpp b/src/theory/strings/sequences_rewriter.cpp index 1d82f9abd..1ccb67490 100644 --- a/src/theory/strings/sequences_rewriter.cpp +++ b/src/theory/strings/sequences_rewriter.cpp @@ -352,7 +352,7 @@ Node SequencesRewriter::rewriteStrEqualityExt(Node node) } else if (ne.getKind() == STRING_SUBSTR) { - Node zero = nm->mkConst(CONST_RATIONAL, Rational(0)); + Node zero = nm->mkConstInt(Rational(0)); if (d_arithEntail.check(ne[1], false) && d_arithEntail.check(ne[2], true)) @@ -586,8 +586,7 @@ Node SequencesRewriter::rewriteLength(Node node) Kind nk0 = node[0].getKind(); if (node[0].isConst()) { - Node retNode = - nm->mkConst(CONST_RATIONAL, Rational(Word::getLength(node[0]))); + Node retNode = nm->mkConstInt(Rational(Word::getLength(node[0]))); return returnRewrite(node, retNode, Rewrite::LEN_EVAL); } else if (nk0 == kind::STRING_CONCAT) @@ -600,8 +599,8 @@ Node SequencesRewriter::rewriteLength(Node node) { if (tmpNode[i].isConst()) { - node_vec.push_back(nm->mkConst( - CONST_RATIONAL, Rational(Word::getLength(tmpNode[i])))); + node_vec.push_back( + nm->mkConstInt(Rational(Word::getLength(tmpNode[i])))); } else { @@ -634,7 +633,7 @@ Node SequencesRewriter::rewriteLength(Node node) } else if (nk0 == SEQ_UNIT) { - Node retNode = nm->mkConst(CONST_RATIONAL, Rational(1)); + Node retNode = nm->mkConstInt(Rational(1)); return returnRewrite(node, retNode, Rewrite::LEN_SEQ_UNIT); } return node; @@ -1311,7 +1310,7 @@ Node SequencesRewriter::rewriteMembership(TNode node) } else if (r.getKind() == kind::REGEXP_ALLCHAR) { - Node one = nm->mkConst(CONST_RATIONAL, Rational(1)); + Node one = nm->mkConstInt(Rational(1)); Node retNode = one.eqNode(nm->mkNode(STRING_LENGTH, x)); return returnRewrite(node, retNode, Rewrite::RE_IN_SIGMA); } @@ -1344,7 +1343,7 @@ Node SequencesRewriter::rewriteMembership(TNode node) Node flr = RegExpEntail::getFixedLengthForRegexp(r[0]); if (!flr.isNull()) { - Node one = nm->mkConst(CONST_RATIONAL, Rational(1)); + Node one = nm->mkConstInt(Rational(1)); if (flr == one) { NodeBuilder nb(AND); @@ -1430,7 +1429,7 @@ Node SequencesRewriter::rewriteMembership(TNode node) if (constStr.isNull()) { // x in re.++(_*, _, _) ---> str.len(x) >= 2 - Node num = nm->mkConst(CONST_RATIONAL, Rational(allSigmaMinSize)); + Node num = nm->mkConstInt(Rational(allSigmaMinSize)); Node lenx = nm->mkNode(STRING_LENGTH, x); Node retNode = nm->mkNode(allSigmaStrict ? EQUAL : GEQ, lenx, num); return returnRewrite(node, retNode, Rewrite::RE_CONCAT_PURE_ALLCHAR); @@ -1722,10 +1721,9 @@ TrustNode SequencesRewriter::expandDefinition(Node node) Node s = node[0]; Node n = node[1]; // seq.nth(s, n) --> ite(0 <= n < len(s), seq.nth_total(s,n), Uf(s, n)) - Node cond = - nm->mkNode(AND, - nm->mkNode(LEQ, nm->mkConst(CONST_RATIONAL, Rational(0)), n), - nm->mkNode(LT, n, nm->mkNode(STRING_LENGTH, s))); + Node cond = nm->mkNode(AND, + nm->mkNode(LEQ, nm->mkConstInt(Rational(0)), n), + nm->mkNode(LT, n, nm->mkNode(STRING_LENGTH, s))); Node ss = nm->mkNode(SEQ_NTH_TOTAL, s, n); Node uf = SkolemCache::mkSkolemSeqNth(s.getType(), "Uf"); Node u = nm->mkNode(APPLY_UF, uf, s, n); @@ -1761,22 +1759,22 @@ Node SequencesRewriter::rewriteSeqNth(Node node) Node ret = nm->mkGroundValue(s.getType().getSequenceElementType()); return returnRewrite(node, ret, Rewrite::SEQ_NTH_TOTAL_OOB); } - else - { - return node; - } } - else + + if (s.getKind() == SEQ_UNIT && i.isConst() && i.getConst<Rational>().isZero()) { - return node; + Node ret = s[0]; + return returnRewrite(node, ret, Rewrite::SEQ_NTH_UNIT); } + + return node; } Node SequencesRewriter::rewriteCharAt(Node node) { Assert(node.getKind() == STRING_CHARAT); NodeManager* nm = NodeManager::currentNM(); - Node one = nm->mkConst(CONST_RATIONAL, Rational(1)); + Node one = nm->mkConstInt(Rational(1)); Node retNode = nm->mkNode(STRING_SUBSTR, node[0], node[1], one); return returnRewrite(node, retNode, Rewrite::CHARAT_ELIM); } @@ -1854,7 +1852,7 @@ Node SequencesRewriter::rewriteSubstr(Node node) } } } - Node zero = nm->mkConst(CONST_RATIONAL, cvc5::Rational(0)); + Node zero = nm->mkConstInt(cvc5::Rational(0)); // if entailed non-positive length or negative start point if (d_arithEntail.check(zero, node[1], true)) @@ -2047,6 +2045,8 @@ Node SequencesRewriter::rewriteUpdate(Node node) { Assert(node.getKind() == kind::STRING_UPDATE); Node s = node[0]; + Node i = node[1]; + Node x = node[2]; if (s.isConst()) { if (Word::isEmpty(s)) @@ -2084,6 +2084,16 @@ Node SequencesRewriter::rewriteUpdate(Node node) } } + if (s.getKind() == STRING_REV) + { + NodeManager* nm = NodeManager::currentNM(); + Node idx = nm->mkNode(MINUS, + nm->mkNode(STRING_LENGTH, s), + nm->mkNode(PLUS, i, nm->mkConst(Rational(1)))); + Node ret = nm->mkNode(STRING_REV, nm->mkNode(STRING_UPDATE, s, idx, x)); + return returnRewrite(node, ret, Rewrite::UPD_REV); + } + return node; } @@ -2453,7 +2463,7 @@ Node SequencesRewriter::rewriteIndexof(Node node) if (node[2].isConst() && node[2].getConst<Rational>().sgn() < 0) { // z<0 implies str.indexof( x, y, z ) --> -1 - Node negone = nm->mkConst(CONST_RATIONAL, Rational(-1)); + Node negone = nm->mkConstInt(Rational(-1)); return returnRewrite(node, negone, Rewrite::IDOF_NEG); } @@ -2471,7 +2481,7 @@ Node SequencesRewriter::rewriteIndexof(Node node) // We know that, due to limitations on the size of string constants // in our implementation, that accessing a position greater than // rMaxInt is guaranteed to be out of bounds. - Node negone = nm->mkConst(CONST_RATIONAL, Rational(-1)); + Node negone = nm->mkConstInt(Rational(-1)); return returnRewrite(node, negone, Rewrite::IDOF_MAX); } Assert(node[2].getConst<Rational>().sgn() >= 0); @@ -2482,13 +2492,12 @@ Node SequencesRewriter::rewriteIndexof(Node node) std::size_t ret = Word::find(s, t, start); if (ret != std::string::npos) { - Node retv = - nm->mkConst(CONST_RATIONAL, Rational(static_cast<unsigned>(ret))); + Node retv = nm->mkConstInt(Rational(static_cast<unsigned>(ret))); return returnRewrite(node, retv, Rewrite::IDOF_FIND); } else if (children0.size() == 1) { - Node negone = nm->mkConst(CONST_RATIONAL, Rational(-1)); + Node negone = nm->mkConstInt(Rational(-1)); return returnRewrite(node, negone, Rewrite::IDOF_NFIND); } } @@ -2500,14 +2509,14 @@ Node SequencesRewriter::rewriteIndexof(Node node) if (node[2].getConst<Rational>().sgn() == 0) { // indexof( x, x, 0 ) --> 0 - Node zero = nm->mkConst(CONST_RATIONAL, Rational(0)); + Node zero = nm->mkConstInt(Rational(0)); return returnRewrite(node, zero, Rewrite::IDOF_EQ_CST_START); } } if (d_arithEntail.check(node[2], true)) { // y>0 implies indexof( x, x, y ) --> -1 - Node negone = nm->mkConst(CONST_RATIONAL, Rational(-1)); + Node negone = nm->mkConstInt(Rational(-1)); return returnRewrite(node, negone, Rewrite::IDOF_EQ_NSTART); } Node emp = Word::mkEmptyWord(stype); @@ -2538,7 +2547,7 @@ Node SequencesRewriter::rewriteIndexof(Node node) if (d_arithEntail.check(len1, len0m2, true)) { // len(x)-z < len(y) implies indexof( x, y, z ) ----> -1 - Node negone = nm->mkConst(CONST_RATIONAL, Rational(-1)); + Node negone = nm->mkConstInt(Rational(-1)); return returnRewrite(node, negone, Rewrite::IDOF_LEN); } @@ -2620,7 +2629,7 @@ Node SequencesRewriter::rewriteIndexof(Node node) else { // str.contains( x, y ) --> false implies str.indexof(x,y,z) --> -1 - Node negone = nm->mkConst(CONST_RATIONAL, Rational(-1)); + Node negone = nm->mkConstInt(Rational(-1)); return returnRewrite(node, negone, Rewrite::IDOF_NCTN); } } @@ -2675,12 +2684,12 @@ Node SequencesRewriter::rewriteIndexofRe(Node node) Node s = node[0]; Node r = node[1]; Node n = node[2]; - Node zero = nm->mkConst(CONST_RATIONAL, Rational(0)); + Node zero = nm->mkConstInt(Rational(0)); Node slen = nm->mkNode(STRING_LENGTH, s); if (d_arithEntail.check(zero, n, true) || d_arithEntail.check(n, slen, true)) { - Node ret = nm->mkConst(CONST_RATIONAL, Rational(-1)); + Node ret = nm->mkConstInt(Rational(-1)); return returnRewrite(node, ret, Rewrite::INDEXOF_RE_INVALID_INDEX); } @@ -2695,15 +2704,14 @@ Node SequencesRewriter::rewriteIndexofRe(Node node) // We know that, due to limitations on the size of string constants // in our implementation, that accessing a position greater than // rMaxInt is guaranteed to be out of bounds. - Node negone = nm->mkConst(CONST_RATIONAL, Rational(-1)); + Node negone = nm->mkConstInt(Rational(-1)); return returnRewrite(node, negone, Rewrite::INDEXOF_RE_MAX_INDEX); } uint32_t start = nrat.getNumerator().toUnsignedInt(); Node rem = nm->mkConst(s.getConst<String>().substr(start)); std::pair<size_t, size_t> match = firstMatch(rem, r); - Node ret = nm->mkConst( - CONST_RATIONAL, + Node ret = nm->mkConstInt( Rational(match.first == string::npos ? -1 : static_cast<int64_t>(start + match.first))); @@ -2967,8 +2975,8 @@ Node SequencesRewriter::rewriteReplace(Node node) nm->mkNode(kind::STRING_LENGTH, utils::mkConcat(children1, stype)); Node maxLen1 = nm->mkNode(kind::PLUS, partLen1, lastChild1[2]); - Node zero = nm->mkConst(CONST_RATIONAL, Rational(0)); - Node one = nm->mkConst(CONST_RATIONAL, Rational(1)); + Node zero = nm->mkConstInt(Rational(0)); + Node one = nm->mkConstInt(Rational(1)); Node len0 = nm->mkNode(kind::STRING_LENGTH, node[0]); Node len0_1 = nm->mkNode(kind::PLUS, len0, one); // Check len(t) + j > len(x) + 1 @@ -3491,8 +3499,7 @@ Node SequencesRewriter::rewritePrefixSuffix(Node n) Node val; if (isPrefix) { - val = - NodeManager::currentNM()->mkConst(CONST_RATIONAL, ::cvc5::Rational(0)); + val = NodeManager::currentNM()->mkConstInt(::cvc5::Rational(0)); } else { @@ -3527,7 +3534,7 @@ Node SequencesRewriter::canonicalStrForSymbolicLength(Node len, TypeNode stype) NodeManager* nm = NodeManager::currentNM(); Node res; - if (len.getKind() == CONST_RATIONAL) + if (len.isConst()) { // c -> "A" repeated c times Rational ratLen = len.getConst<Rational>(); diff --git a/src/theory/strings/skolem_cache.cpp b/src/theory/strings/skolem_cache.cpp index eb09ff187..03c9f9375 100644 --- a/src/theory/strings/skolem_cache.cpp +++ b/src/theory/strings/skolem_cache.cpp @@ -54,7 +54,7 @@ SkolemCache::SkolemCache(Rewriter* rr) : d_rr(rr) { NodeManager* nm = NodeManager::currentNM(); d_strType = nm->stringType(); - d_zero = nm->mkConst(CONST_RATIONAL, Rational(0)); + d_zero = nm->mkConstInt(Rational(0)); } Node SkolemCache::mkSkolemCached(Node a, Node b, SkolemId id, const char* c) @@ -217,27 +217,26 @@ SkolemCache::normalizeStringSkolem(SkolemId id, Node a, Node b) { // SK_ID_VC_SPT(x, y) ---> SK_SUFFIX_REM(x, 1) id = SK_SUFFIX_REM; - b = nm->mkConst(CONST_RATIONAL, Rational(1)); + b = nm->mkConstInt(Rational(1)); } else if (id == SK_ID_VC_SPT_REV) { // SK_ID_VC_SPT_REV(x, y) ---> SK_PREFIX(x, (- (str.len x) 1)) id = SK_PREFIX; - b = nm->mkNode(MINUS, - nm->mkNode(STRING_LENGTH, a), - nm->mkConst(CONST_RATIONAL, Rational(1))); + b = nm->mkNode( + MINUS, nm->mkNode(STRING_LENGTH, a), nm->mkConstInt(Rational(1))); } else if (id == SK_ID_DC_SPT) { // SK_ID_DC_SPT(x, y) ---> SK_PREFIX(x, 1) id = SK_PREFIX; - b = nm->mkConst(CONST_RATIONAL, Rational(1)); + b = nm->mkConstInt(Rational(1)); } else if (id == SK_ID_DC_SPT_REM) { // SK_ID_DC_SPT_REM(x, y) ---> SK_SUFFIX_REM(x, 1) id = SK_SUFFIX_REM; - b = nm->mkConst(CONST_RATIONAL, Rational(1)); + b = nm->mkConstInt(Rational(1)); } else if (id == SK_ID_DEQ_X) { diff --git a/src/theory/strings/solver_state.cpp b/src/theory/strings/solver_state.cpp index 045347cbb..6b7fc699b 100644 --- a/src/theory/strings/solver_state.cpp +++ b/src/theory/strings/solver_state.cpp @@ -34,7 +34,7 @@ SolverState::SolverState(Env& env, Valuation& v) d_pendingConflictSet(env.getContext(), false), d_pendingConflict(InferenceId::UNKNOWN) { - d_zero = NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(0)); + d_zero = NodeManager::currentNM()->mkConstInt(Rational(0)); d_false = NodeManager::currentNM()->mkConst(false); } diff --git a/src/theory/strings/strategy.cpp b/src/theory/strings/strategy.cpp index 7338b99fd..921a676d7 100644 --- a/src/theory/strings/strategy.cpp +++ b/src/theory/strings/strategy.cpp @@ -43,7 +43,7 @@ std::ostream& operator<<(std::ostream& out, InferStep s) return out; } -Strategy::Strategy() : d_strategy_init(false) {} +Strategy::Strategy(Env& env) : EnvObj(env), d_strategy_init(false) {} Strategy::~Strategy() {} @@ -93,7 +93,7 @@ void Strategy::initializeStrategy() d_strategy_init = true; // beginning indices step_begin[Theory::EFFORT_FULL] = 0; - if (options::stringEager()) + if (options().strings.stringEager) { step_begin[Theory::EFFORT_STANDARD] = 0; } @@ -103,45 +103,45 @@ void Strategy::initializeStrategy() addStrategyStep(CHECK_EXTF_EVAL, 0); // we must check cycles before using flat forms addStrategyStep(CHECK_CYCLES); - if (options::stringFlatForms()) + if (options().strings.stringFlatForms) { addStrategyStep(CHECK_FLAT_FORMS); } addStrategyStep(CHECK_EXTF_REDUCTION, 1); - if (options::stringEager()) + if (options().strings.stringEager) { // do only the above inferences at standard effort, if applicable step_end[Theory::EFFORT_STANDARD] = d_infer_steps.size() - 1; } - if (!options::stringEagerLen()) + if (!options().strings.stringEagerLen) { addStrategyStep(CHECK_REGISTER_TERMS_PRE_NF); } addStrategyStep(CHECK_NORMAL_FORMS_EQ); addStrategyStep(CHECK_EXTF_EVAL, 1); - if (!options::stringEagerLen() && options::stringLenNorm()) + if (!options().strings.stringEagerLen && options().strings.stringLenNorm) { addStrategyStep(CHECK_LENGTH_EQC, 0, false); addStrategyStep(CHECK_REGISTER_TERMS_NF); } addStrategyStep(CHECK_NORMAL_FORMS_DEQ); addStrategyStep(CHECK_CODES); - if (options::stringEagerLen() && options::stringLenNorm()) + if (options().strings.stringEagerLen && options().strings.stringLenNorm) { addStrategyStep(CHECK_LENGTH_EQC); } - if (options::stringExp()) + if (options().strings.stringExp) { addStrategyStep(CHECK_EXTF_REDUCTION, 2); } addStrategyStep(CHECK_MEMBERSHIP); addStrategyStep(CHECK_CARDINALITY); step_end[Theory::EFFORT_FULL] = d_infer_steps.size() - 1; - if (options::stringModelBasedReduction()) + if (options().strings.stringModelBasedReduction) { step_begin[Theory::EFFORT_LAST_CALL] = d_infer_steps.size(); addStrategyStep(CHECK_EXTF_EVAL, 3); - if (options::stringExp()) + if (options().strings.stringExp) { addStrategyStep(CHECK_EXTF_REDUCTION, 3); } diff --git a/src/theory/strings/strategy.h b/src/theory/strings/strategy.h index c390c5594..48253c64a 100644 --- a/src/theory/strings/strategy.h +++ b/src/theory/strings/strategy.h @@ -74,10 +74,10 @@ std::ostream& operator<<(std::ostream& out, InferStep i); * This stores a sequence of the above enum that indicates the calls to * runInferStep to make on the theory of strings, given by parent. */ -class Strategy +class Strategy : protected EnvObj { public: - Strategy(); + Strategy(Env& env); ~Strategy(); /** is this strategy initialized? */ bool isStrategyInit() const; diff --git a/src/theory/strings/strings_entail.cpp b/src/theory/strings/strings_entail.cpp index 6e4ba25a5..952a1a36b 100644 --- a/src/theory/strings/strings_entail.cpp +++ b/src/theory/strings/strings_entail.cpp @@ -123,7 +123,7 @@ bool StringsEntail::stripSymbolicLength(std::vector<Node>& n1, Assert(dir == 1 || dir == -1); Assert(nr.empty()); NodeManager* nm = NodeManager::currentNM(); - Node zero = nm->mkConst(CONST_RATIONAL, cvc5::Rational(0)); + Node zero = nm->mkConstInt(cvc5::Rational(0)); bool ret = false; bool success = true; unsigned sindex = 0; @@ -145,7 +145,7 @@ bool StringsEntail::stripSymbolicLength(std::vector<Node>& n1, Assert(d_arithEntail.check(curr, true)); Node s = n1[sindex_use]; size_t slen = Word::getLength(s); - Node ncl = nm->mkConst(CONST_RATIONAL, cvc5::Rational(slen)); + Node ncl = nm->mkConstInt(cvc5::Rational(slen)); Node next_s = nm->mkNode(MINUS, lowerBound, ncl); next_s = d_rr->rewrite(next_s); Assert(next_s.isConst()); @@ -461,7 +461,7 @@ bool StringsEntail::componentContainsBase( { n1rb = nm->mkNode(STRING_SUBSTR, n2[0], - nm->mkConst(CONST_RATIONAL, Rational(0)), + nm->mkConstInt(Rational(0)), start_pos); } if (dir != 1) @@ -714,7 +714,7 @@ bool StringsEntail::checkNonEmpty(Node a) bool StringsEntail::checkLengthOne(Node s, bool strict) { NodeManager* nm = NodeManager::currentNM(); - Node one = nm->mkConst(CONST_RATIONAL, Rational(1)); + Node one = nm->mkConstInt(Rational(1)); Node len = nm->mkNode(STRING_LENGTH, s); len = d_rr->rewrite(len); return d_arithEntail.check(one, len) diff --git a/src/theory/strings/strings_fmf.cpp b/src/theory/strings/strings_fmf.cpp index 2951c86a2..a3ae03099 100644 --- a/src/theory/strings/strings_fmf.cpp +++ b/src/theory/strings/strings_fmf.cpp @@ -85,8 +85,7 @@ Node StringsFmf::StringSumLengthDecisionStrategy::mkLiteral(unsigned i) return Node::null(); } NodeManager* nm = NodeManager::currentNM(); - Node lit = nm->mkNode( - LEQ, d_inputVarLsum.get(), nm->mkConst(CONST_RATIONAL, Rational(i))); + Node lit = nm->mkNode(LEQ, d_inputVarLsum.get(), nm->mkConstInt(Rational(i))); Trace("strings-fmf") << "StringsFMF::mkLiteral: " << lit << std::endl; return lit; } diff --git a/src/theory/strings/strings_rewriter.cpp b/src/theory/strings/strings_rewriter.cpp index e4b91d4d8..2ff7598b5 100644 --- a/src/theory/strings/strings_rewriter.cpp +++ b/src/theory/strings/strings_rewriter.cpp @@ -100,11 +100,11 @@ Node StringsRewriter::rewriteStrToInt(Node node) String s = node[0].getConst<String>(); if (s.isNumber()) { - ret = nm->mkConst(CONST_RATIONAL, s.toNumber()); + ret = nm->mkConstInt(s.toNumber()); } else { - ret = nm->mkConst(CONST_RATIONAL, Rational(-1)); + ret = nm->mkConstInt(Rational(-1)); } return returnRewrite(node, ret, Rewrite::STOI_EVAL); } @@ -117,7 +117,7 @@ Node StringsRewriter::rewriteStrToInt(Node node) String t = nc.getConst<String>(); if (!t.isNumber()) { - Node ret = nm->mkConst(CONST_RATIONAL, Rational(-1)); + Node ret = nm->mkConstInt(Rational(-1)); return returnRewrite(node, ret, Rewrite::STOI_CONCAT_NONNUM); } } @@ -303,11 +303,11 @@ Node StringsRewriter::rewriteStringToCode(Node n) { std::vector<unsigned> vec = s.getVec(); Assert(vec.size() == 1); - ret = nm->mkConst(CONST_RATIONAL, Rational(vec[0])); + ret = nm->mkConstInt(Rational(vec[0])); } else { - ret = nm->mkConst(CONST_RATIONAL, Rational(-1)); + ret = nm->mkConstInt(Rational(-1)); } return returnRewrite(n, ret, Rewrite::TO_CODE_EVAL); } @@ -320,10 +320,9 @@ Node StringsRewriter::rewriteStringIsDigit(Node n) NodeManager* nm = NodeManager::currentNM(); // eliminate str.is_digit(s) ----> 48 <= str.to_code(s) <= 57 Node t = nm->mkNode(STRING_TO_CODE, n[0]); - Node retNode = - nm->mkNode(AND, - nm->mkNode(LEQ, nm->mkConst(CONST_RATIONAL, Rational(48)), t), - nm->mkNode(LEQ, t, nm->mkConst(CONST_RATIONAL, Rational(57)))); + Node retNode = nm->mkNode(AND, + nm->mkNode(LEQ, nm->mkConstInt(Rational(48)), t), + nm->mkNode(LEQ, t, nm->mkConstInt(Rational(57)))); return returnRewrite(n, retNode, Rewrite::IS_DIGIT_ELIM); } diff --git a/src/theory/strings/term_registry.cpp b/src/theory/strings/term_registry.cpp index 85027370e..d2d723276 100644 --- a/src/theory/strings/term_registry.cpp +++ b/src/theory/strings/term_registry.cpp @@ -60,9 +60,9 @@ TermRegistry::TermRegistry(Env& env, : nullptr) { NodeManager* nm = NodeManager::currentNM(); - d_zero = nm->mkConst(CONST_RATIONAL, Rational(0)); - d_one = nm->mkConst(CONST_RATIONAL, Rational(1)); - d_negOne = NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(-1)); + d_zero = nm->mkConstInt(Rational(0)); + d_one = nm->mkConstInt(Rational(1)); + d_negOne = NodeManager::currentNM()->mkConstInt(Rational(-1)); Assert(options().strings.stringsAlphaCard <= String::num_codes()); d_alphaCard = options().strings.stringsAlphaCard; } @@ -81,13 +81,12 @@ Node TermRegistry::eagerReduce(Node t, SkolemCache* sc, uint32_t alphaCard) if (tk == STRING_TO_CODE) { // ite( str.len(s)==1, 0 <= str.code(s) < |A|, str.code(s)=-1 ) - Node code_len = - utils::mkNLength(t[0]).eqNode(nm->mkConst(CONST_RATIONAL, Rational(1))); - Node code_eq_neg1 = t.eqNode(nm->mkConst(CONST_RATIONAL, Rational(-1))); - Node code_range = nm->mkNode( - AND, - nm->mkNode(GEQ, t, nm->mkConst(CONST_RATIONAL, Rational(0))), - nm->mkNode(LT, t, nm->mkConst(CONST_RATIONAL, Rational(alphaCard)))); + Node code_len = utils::mkNLength(t[0]).eqNode(nm->mkConstInt(Rational(1))); + Node code_eq_neg1 = t.eqNode(nm->mkConstInt(Rational(-1))); + Node code_range = + nm->mkNode(AND, + nm->mkNode(GEQ, t, nm->mkConstInt(Rational(0))), + nm->mkNode(LT, t, nm->mkConstInt(Rational(alphaCard)))); lemma = nm->mkNode(ITE, code_len, code_range, code_eq_neg1); } else if (tk == STRING_INDEXOF || tk == STRING_INDEXOF_RE) @@ -98,17 +97,16 @@ Node TermRegistry::eagerReduce(Node t, SkolemCache* sc, uint32_t alphaCard) // // where f in { str.indexof, str.indexof_re } Node l = nm->mkNode(STRING_LENGTH, t[0]); - lemma = nm->mkNode( - AND, - nm->mkNode(OR, - t.eqNode(nm->mkConst(CONST_RATIONAL, Rational(-1))), - nm->mkNode(GEQ, t, t[2])), - nm->mkNode(LEQ, t, l)); + lemma = nm->mkNode(AND, + nm->mkNode(OR, + t.eqNode(nm->mkConstInt(Rational(-1))), + nm->mkNode(GEQ, t, t[2])), + nm->mkNode(LEQ, t, l)); } else if (tk == STRING_STOI) { // (>= (str.to_int x) (- 1)) - lemma = nm->mkNode(GEQ, t, nm->mkConst(CONST_RATIONAL, Rational(-1))); + lemma = nm->mkNode(GEQ, t, nm->mkConstInt(Rational(-1))); } else if (tk == STRING_CONTAINS) { @@ -126,7 +124,7 @@ Node TermRegistry::eagerReduce(Node t, SkolemCache* sc, uint32_t alphaCard) Node TermRegistry::lengthPositive(Node t) { NodeManager* nm = NodeManager::currentNM(); - Node zero = nm->mkConst(CONST_RATIONAL, Rational(0)); + Node zero = nm->mkConstInt(Rational(0)); Node emp = Word::mkEmptyWord(t.getType()); Node tlen = nm->mkNode(STRING_LENGTH, t); Node tlenEqZero = tlen.eqNode(zero); @@ -416,7 +414,7 @@ TrustNode TermRegistry::getRegisterTermLemma(Node n) } else if (n.isConst()) { - lsum = nm->mkConst(CONST_RATIONAL, Rational(Word::getLength(n))); + lsum = nm->mkConstInt(Rational(Word::getLength(n))); } Assert(!lsum.isNull()); d_proxyVarToLength[sk] = lsum; @@ -486,7 +484,7 @@ bool TermRegistry::isHandledUpdate(Node n) { lenN = nm->mkNode(STRING_LENGTH, n[2]); } - Node one = nm->mkConst(CONST_RATIONAL, Rational(1)); + Node one = nm->mkConstInt(Rational(1)); return d_aent.checkEq(lenN, one); } diff --git a/src/theory/strings/theory_strings.cpp b/src/theory/strings/theory_strings.cpp index 557dd7783..25db8d190 100644 --- a/src/theory/strings/theory_strings.cpp +++ b/src/theory/strings/theory_strings.cpp @@ -81,13 +81,14 @@ TheoryStrings::TheoryStrings(Env& env, OutputChannel& out, Valuation valuation) d_rsolver( env, d_state, d_im, d_termReg, d_csolver, d_esolver, d_statistics), d_regexp_elim(options().strings.regExpElimAgg, d_pnm, userContext()), - d_stringsFmf(env, valuation, d_termReg) + d_stringsFmf(env, valuation, d_termReg), + d_strat(d_env) { d_termReg.finishInit(&d_im); - d_zero = NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(0)); - d_one = NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(1)); - d_neg_one = NodeManager::currentNM()->mkConst(CONST_RATIONAL, Rational(-1)); + d_zero = NodeManager::currentNM()->mkConstInt(Rational(0)); + d_one = NodeManager::currentNM()->mkConstInt(Rational(1)); + d_neg_one = NodeManager::currentNM()->mkConstInt(Rational(-1)); d_true = NodeManager::currentNM()->mkConst( true ); d_false = NodeManager::currentNM()->mkConst( false ); @@ -426,7 +427,7 @@ bool TheoryStrings::collectModelInfoType( lvalue++; } Trace("strings-model") << "*** Decide to make length of " << lvalue << std::endl; - lts_values[i] = nm->mkConst(CONST_RATIONAL, Rational(lvalue)); + lts_values[i] = nm->mkConstInt(Rational(lvalue)); values_used[lvalue] = Node::null(); } Trace("strings-model") << "Need to assign values of length " << lts_values[i] << " to equivalence classes "; @@ -1081,8 +1082,7 @@ TrustNode TheoryStrings::ppRewrite(TNode atom, std::vector<SkolemLemma>& lems) SkolemCache* sc = d_termReg.getSkolemCache(); Node k = sc->mkSkolemCached(atom, SkolemCache::SK_PURIFY, "kFromCode"); Node t = atom[0]; - Node card = nm->mkConst(CONST_RATIONAL, - Rational(d_termReg.getAlphabetCardinality())); + Node card = nm->mkConstInt(Rational(d_termReg.getAlphabetCardinality())); Node cond = nm->mkNode(AND, nm->mkNode(LEQ, d_zero, t), nm->mkNode(LT, t, card)); Node emp = Word::mkEmptyWord(atom.getType()); diff --git a/src/theory/strings/theory_strings_preprocess.cpp b/src/theory/strings/theory_strings_preprocess.cpp index 4f27371ff..4c2319b4e 100644 --- a/src/theory/strings/theory_strings_preprocess.cpp +++ b/src/theory/strings/theory_strings_preprocess.cpp @@ -53,9 +53,9 @@ Node StringsPreprocess::reduce(Node t, << "StringsPreprocess::reduce: " << t << std::endl; Node retNode = t; NodeManager* nm = NodeManager::currentNM(); - Node zero = nm->mkConst(CONST_RATIONAL, Rational(0)); - Node one = nm->mkConst(CONST_RATIONAL, Rational(1)); - Node negOne = nm->mkConst(CONST_RATIONAL, Rational(-1)); + Node zero = nm->mkConstInt(Rational(0)); + Node one = nm->mkConstInt(Rational(1)); + Node negOne = nm->mkConstInt(Rational(-1)); if( t.getKind() == kind::STRING_SUBSTR ) { // processing term: substr( s, n, m ) @@ -184,7 +184,7 @@ Node StringsPreprocess::reduce(Node t, Node skk = sc->mkTypedSkolemCached( nm->integerType(), t, SkolemCache::SK_PURIFY, "iok"); - Node negone = nm->mkConst(CONST_RATIONAL, Rational(-1)); + Node negone = nm->mkConstInt(Rational(-1)); // substr( x, n, len( x ) - n ) Node st = nm->mkNode(STRING_SUBSTR, @@ -364,7 +364,7 @@ Node StringsPreprocess::reduce(Node t, Node c0 = nm->mkNode(STRING_TO_CODE, nm->mkConst(String("0"))); Node c = nm->mkNode(MINUS, nm->mkNode(STRING_TO_CODE, sx), c0); - Node ten = nm->mkConst(CONST_RATIONAL, Rational(10)); + Node ten = nm->mkConstInt(Rational(10)); Node eq = ux1.eqNode(nm->mkNode(PLUS, c, nm->mkNode(MULT, ten, ux))); Node leadingZeroPos = nm->mkNode(AND, x.eqNode(zero), nm->mkNode(GT, leni, one)); @@ -431,7 +431,7 @@ Node StringsPreprocess::reduce(Node t, MINUS, nm->mkNode(STRING_TO_CODE, nm->mkNode(STRING_SUBSTR, s, k, one)), c0); - Node ten = nm->mkConst(CONST_RATIONAL, Rational(10)); + Node ten = nm->mkConstInt(Rational(10)); Node kc3 = nm->mkNode( OR, nm->mkNode(LT, codeSk, zero), nm->mkNode(GEQ, codeSk, ten)); conc1.push_back(nm->mkNode(OR, sEmpty, nm->mkNode(AND, kc1, kc2, kc3))); @@ -865,12 +865,11 @@ Node StringsPreprocess::reduce(Node t, Node ci = nm->mkNode(STRING_TO_CODE, nm->mkNode(STRING_SUBSTR, x, i, one)); Node ri = nm->mkNode(STRING_TO_CODE, nm->mkNode(STRING_SUBSTR, r, i, one)); - Node lb = nm->mkConst(CONST_RATIONAL, - Rational(t.getKind() == STRING_TOUPPER ? 97 : 65)); - Node ub = nm->mkConst(CONST_RATIONAL, - Rational(t.getKind() == STRING_TOUPPER ? 122 : 90)); - Node offset = nm->mkConst( - CONST_RATIONAL, Rational(t.getKind() == STRING_TOUPPER ? -32 : 32)); + Node lb = nm->mkConstInt(Rational(t.getKind() == STRING_TOUPPER ? 97 : 65)); + Node ub = + nm->mkConstInt(Rational(t.getKind() == STRING_TOUPPER ? 122 : 90)); + Node offset = + nm->mkConstInt(Rational(t.getKind() == STRING_TOUPPER ? -32 : 32)); Node res = nm->mkNode( ITE, diff --git a/src/theory/strings/theory_strings_utils.cpp b/src/theory/strings/theory_strings_utils.cpp index a133babba..0ee2e906d 100644 --- a/src/theory/strings/theory_strings_utils.cpp +++ b/src/theory/strings/theory_strings_utils.cpp @@ -165,8 +165,7 @@ Node mkNLength(Node t) Node mkPrefix(Node t, Node n) { NodeManager* nm = NodeManager::currentNM(); - return nm->mkNode( - STRING_SUBSTR, t, nm->mkConst(CONST_RATIONAL, Rational(0)), n); + return nm->mkNode(STRING_SUBSTR, t, nm->mkConstInt(Rational(0)), n); } Node mkSuffix(Node t, Node n) diff --git a/src/theory/substitutions.cpp b/src/theory/substitutions.cpp index 70e3deb63..e49563046 100644 --- a/src/theory/substitutions.cpp +++ b/src/theory/substitutions.cpp @@ -39,7 +39,7 @@ struct substitution_stack_element { } };/* struct substitution_stack_element */ -Node SubstitutionMap::internalSubstitute(TNode t, NodeCache& cache) { +Node SubstitutionMap::internalSubstitute(TNode t, NodeCache& cache, std::set<TNode>* tracker) { Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << t << ")" << endl; @@ -70,10 +70,17 @@ Node SubstitutionMap::internalSubstitute(TNode t, NodeCache& cache) { if (find2 != d_substitutions.end()) { Node rhs = (*find2).second; Assert(rhs != current); - internalSubstitute(rhs, cache); - d_substitutions[current] = cache[rhs]; + internalSubstitute(rhs, cache, tracker); + if (tracker == nullptr) + { + d_substitutions[current] = cache[rhs]; + } cache[current] = cache[rhs]; toVisit.pop_back(); + if (tracker != nullptr) + { + tracker->insert(current); + } continue; } @@ -101,10 +108,14 @@ Node SubstitutionMap::internalSubstitute(TNode t, NodeCache& cache) { if (find2 != d_substitutions.end()) { Node rhs = (*find2).second; Assert(rhs != result); - internalSubstitute(rhs, cache); + internalSubstitute(rhs, cache, tracker); d_substitutions[result] = cache[rhs]; cache[result] = cache[rhs]; result = cache[rhs]; + if (tracker != nullptr) + { + tracker->insert(result); + } } } } @@ -184,7 +195,7 @@ void SubstitutionMap::addSubstitutions(SubstitutionMap& subMap, bool invalidateC } } -Node SubstitutionMap::apply(TNode t, bool doRewrite) { +Node SubstitutionMap::apply(TNode t, Rewriter* r, std::set<TNode>* tracker) { Debug("substitution") << "SubstitutionMap::apply(" << t << ")" << endl; @@ -196,12 +207,12 @@ Node SubstitutionMap::apply(TNode t, bool doRewrite) { } // Perform the substitution - Node result = internalSubstitute(t, d_substitutionCache); + Node result = internalSubstitute(t, d_substitutionCache, tracker); Debug("substitution") << "SubstitutionMap::apply(" << t << ") => " << result << endl; - if (doRewrite) + if (r != nullptr) { - result = Rewriter::rewrite(result); + result = r->rewrite(result); } return result; diff --git a/src/theory/substitutions.h b/src/theory/substitutions.h index 1de636fb3..2154c7fd5 100644 --- a/src/theory/substitutions.h +++ b/src/theory/substitutions.h @@ -32,6 +32,8 @@ namespace cvc5 { namespace theory { +class Rewriter; + /** * The type for the Substitutions mapping output by * Theory::simplify(), TheoryEngine::simplify(), and @@ -63,7 +65,7 @@ class SubstitutionMap bool d_cacheInvalidated; /** Internal method that performs substitution */ - Node internalSubstitute(TNode t, NodeCache& cache); + Node internalSubstitute(TNode t, NodeCache& cache, std::set<TNode>* tracker); /** Helper class to invalidate cache on user pop */ class CacheInvalidator : public context::ContextNotifyObj @@ -125,16 +127,17 @@ class SubstitutionMap } /** - * Apply the substitutions to the node. + * Apply the substitutions to the node, optionally rewrite if a non-null + * Rewriter pointer is passed. */ - Node apply(TNode t, bool doRewrite = false); + Node apply(TNode t, Rewriter* r = nullptr, std::set<TNode>* tracker = nullptr); /** * Apply the substitutions to the node. */ - Node apply(TNode t, bool doRewrite = false) const + Node apply(TNode t, Rewriter* r = nullptr) const { - return const_cast<SubstitutionMap*>(this)->apply(t, doRewrite); + return const_cast<SubstitutionMap*>(this)->apply(t, r); } iterator begin() { return d_substitutions.begin(); } @@ -152,6 +155,10 @@ class SubstitutionMap */ void print(std::ostream& out) const; + void invalidateCache() { + d_cacheInvalidated = true; + } + }; /* class SubstitutionMap */ inline std::ostream& operator << (std::ostream& out, const SubstitutionMap& subst) { diff --git a/src/theory/theory_engine.cpp b/src/theory/theory_engine.cpp index 1b2ad3358..ae71ac484 100644 --- a/src/theory/theory_engine.cpp +++ b/src/theory/theory_engine.cpp @@ -155,7 +155,7 @@ void TheoryEngine::finishInit() // create the relevance filter if any option requires it if (options().theory.relevanceFilter || options().smt.produceDifficulty) { - d_relManager.reset(new RelevanceManager(userContext(), Valuation(this))); + d_relManager.reset(new RelevanceManager(d_env, Valuation(this))); } // initialize the quantifiers engine @@ -384,15 +384,15 @@ void TheoryEngine::check(Theory::Effort effort) { Debug("theory") << "TheoryEngine::check(" << effort << "): d_factsAsserted = " << (d_factsAsserted ? "true" : "false") << endl; - // Reset round for the relevance manager, which notice only sets a flag - // to indicate that its information must be recomputed. - if (d_relManager != nullptr) - { - d_relManager->beginRound(); - } // If in full effort, we have a fake new assertion just to jumpstart the checking if (Theory::fullEffort(effort)) { d_factsAsserted = true; + // Reset round for the relevance manager, which notice only sets a flag + // to indicate that its information must be recomputed. + if (d_relManager != nullptr) + { + d_relManager->beginRound(); + } d_tc->resetRound(); } @@ -488,6 +488,10 @@ void TheoryEngine::check(Theory::Effort effort) { if (Theory::fullEffort(effort)) { + if (d_relManager != nullptr) + { + d_relManager->endRound(); + } if (!d_inConflict && !needCheck()) { // Do post-processing of model from the theories (e.g. used for @@ -775,7 +779,7 @@ void TheoryEngine::notifyPreprocessedAssertions( } if (d_relManager != nullptr) { - d_relManager->notifyPreprocessedAssertions(assertions); + d_relManager->notifyPreprocessedAssertions(assertions, true); } } @@ -1075,14 +1079,14 @@ theory::EqualityStatus TheoryEngine::getEqualityStatus(TNode a, TNode b) { return d_sharedSolver->getEqualityStatus(a, b); } -const std::unordered_set<TNode>& TheoryEngine::getRelevantAssertions( - bool& success) +std::unordered_set<TNode> TheoryEngine::getRelevantAssertions(bool& success) { // if we are not in SAT mode, or there is no relevance manager, we fail if (!d_inSatMode || d_relManager == nullptr) { success = false; - return d_emptyRelevantSet; + // return empty set + return std::unordered_set<TNode>(); } return d_relManager->getRelevantAssertions(success); } @@ -1093,13 +1097,19 @@ void TheoryEngine::getDifficultyMap(std::map<Node, Node>& dmap) d_relManager->getDifficultyMap(dmap); } +theory::IncompleteId TheoryEngine::getIncompleteId() const +{ + return d_incompleteId.get(); +} + Node TheoryEngine::getModelValue(TNode var) { if (var.isConst()) { // the model value of a constant must be itself return var; } - Assert(d_sharedSolver->isShared(var)); + Assert(d_sharedSolver->isShared(var)) + << "node " << var << " is not shared" << std::endl; return theoryOf(Theory::theoryOf(var.getType()))->getModelValue(var); } @@ -1317,8 +1327,8 @@ void TheoryEngine::lemma(TrustNode tlemma, d_propEngine->getPreprocessedTerm(tlemma.getProven(), skAsserts, sks); if (options().theory.relevanceFilter && isLemmaPropertyNeedsJustify(p)) { - d_relManager->notifyPreprocessedAssertion(retLemma); - d_relManager->notifyPreprocessedAssertions(skAsserts); + d_relManager->notifyPreprocessedAssertion(retLemma, false); + d_relManager->notifyPreprocessedAssertions(skAsserts, false); } d_relManager->notifyLemma(retLemma); } diff --git a/src/theory/theory_engine.h b/src/theory/theory_engine.h index efde513a9..f1e178055 100644 --- a/src/theory/theory_engine.h +++ b/src/theory/theory_engine.h @@ -374,7 +374,7 @@ class TheoryEngine : protected EnvObj * relevance manager failed to compute relevant assertions due to an internal * error. */ - const std::unordered_set<TNode>& getRelevantAssertions(bool& success); + std::unordered_set<TNode> getRelevantAssertions(bool& success); /** * Get difficulty map, which populates dmap, mapping preprocessed assertions @@ -384,6 +384,9 @@ class TheoryEngine : protected EnvObj */ void getDifficultyMap(std::map<Node, Node>& dmap); + /** Get incomplete id, valid immediately after an `unknown` response. */ + theory::IncompleteId getIncompleteId() const; + /** * Forwards an entailment check according to the given theoryOfMode. * See theory.h for documentation on entailmentCheck(). @@ -544,11 +547,6 @@ class TheoryEngine : protected EnvObj std::unique_ptr<theory::DecisionManager> d_decManager; /** The relevance manager */ std::unique_ptr<theory::RelevanceManager> d_relManager; - /** - * An empty set of relevant assertions, which is returned as a dummy value for - * getRelevantAssertions when relevance is disabled. - */ - std::unordered_set<TNode> d_emptyRelevantSet; /** are we in eager model building mode? (see setEagerModelBuilding). */ bool d_eager_model_building; diff --git a/src/theory/theory_inference_manager.cpp b/src/theory/theory_inference_manager.cpp index 4ed01b618..fda6d0881 100644 --- a/src/theory/theory_inference_manager.cpp +++ b/src/theory/theory_inference_manager.cpp @@ -15,7 +15,13 @@ #include "theory/theory_inference_manager.h" +#include "options/proof_options.h" +#include "proof/annotation_proof_generator.h" +#include "proof/eager_proof_generator.h" #include "smt/smt_statistics_registry.h" +#include "smt/solver_engine_scope.h" +#include "theory/builtin/proof_checker.h" +#include "theory/inference_id_proof_annotator.h" #include "theory/output_channel.h" #include "theory/rewriter.h" #include "theory/theory.h" @@ -56,6 +62,20 @@ TheoryInferenceManager::TheoryInferenceManager(Env& env, // don't add true lemma Node truen = NodeManager::currentNM()->mkConst(true); d_lemmasSent.insert(truen); + + if (isProofEnabled()) + { + context::UserContext* u = userContext(); + ProofNodeManager* pnm = env.getProofNodeManager(); + d_defaultPg.reset( + new EagerProofGenerator(pnm, u, statsName + "EagerProofGenerator")); + if (options().proof.proofAnnotate) + { + d_iipa.reset(new InferenceIdProofAnnotator(pnm, u)); + d_apg.reset(new AnnotationProofGenerator( + pnm, u, statsName + "AnnotationProofGenerator")); + } + } } TheoryInferenceManager::~TheoryInferenceManager() @@ -127,6 +147,11 @@ void TheoryInferenceManager::trustedConflict(TrustNode tconf, InferenceId id) resourceManager()->spendResource(id); Trace("im") << "(conflict " << id << " " << tconf.getProven() << ")" << std::endl; + // annotate if the annotation proof generator is active + if (d_apg != nullptr) + { + tconf = annotateId(tconf, id); + } d_out.trustedConflict(tconf); ++d_numConflicts; } @@ -261,7 +286,16 @@ bool TheoryInferenceManager::trustedLemma(const TrustNode& tlem, // shouldn't send trivially true or false lemmas Assert(!rewrite(tlem.getProven()).isConst()); d_numCurrentLemmas++; - d_out.trustedLemma(tlem, p); + // annotate if the annotation proof generator is active + if (d_apg != nullptr) + { + TrustNode tlema = annotateId(tlem, id); + d_out.trustedLemma(tlema, p); + } + else + { + d_out.trustedLemma(tlem, p); + } return true; } @@ -544,6 +578,24 @@ bool TheoryInferenceManager::cacheLemma(TNode lem, LemmaProperty p) return true; } +TrustNode TheoryInferenceManager::annotateId(const TrustNode& trn, + InferenceId id) +{ + Assert(d_iipa != nullptr && d_apg != nullptr); + Node lemma = trn.getProven(); + TrustNode trna = trn; + // ensure we have a proof generator, make trusted theory lemma if not + if (trn.getGenerator() == nullptr) + { + Node tidn = + builtin::BuiltinProofRuleChecker::mkTheoryIdNode(d_theory.getId()); + trna = d_defaultPg->mkTrustNode( + lemma, PfRule::THEORY_LEMMA, {}, {lemma, tidn}); + } + d_iipa->setAnnotation(lemma, id); + return d_apg->transform(trna, d_iipa.get()); +} + DecisionManager* TheoryInferenceManager::getDecisionManager() { return d_decManager; diff --git a/src/theory/theory_inference_manager.h b/src/theory/theory_inference_manager.h index d7334d0e6..c626bbef9 100644 --- a/src/theory/theory_inference_manager.h +++ b/src/theory/theory_inference_manager.h @@ -32,12 +32,15 @@ namespace cvc5 { class ProofNodeManager; +class AnnotationProofGenerator; +class EagerProofGenerator; namespace theory { class Theory; class TheoryState; class DecisionManager; +class InferenceIdProofAnnotator; namespace eq { class EqualityEngine; class ProofEqEngine; @@ -426,6 +429,11 @@ class TheoryInferenceManager : protected EnvObj * override this method to take the lemma property into account as needed. */ virtual bool cacheLemma(TNode lem, LemmaProperty p); + /** + * Return the trust node that is equivalent to trn, but its proof (if asked + * for) will be wrapped in (ANNOTATE ... :args id). + */ + TrustNode annotateId(const TrustNode& trn, InferenceId id); /** The theory object */ Theory& d_theory; /** Reference to the state of theory */ @@ -440,6 +448,12 @@ class TheoryInferenceManager : protected EnvObj eq::ProofEqEngine* d_pfee; /** The proof equality engine we allocated */ std::unique_ptr<eq::ProofEqEngine> d_pfeeAlloc; + /** Proof generator for trusted THEORY_LEMMA steps */ + std::unique_ptr<EagerProofGenerator> d_defaultPg; + /** The inference id proof annotator */ + std::unique_ptr<InferenceIdProofAnnotator> d_iipa; + /** The annotation proof generator */ + std::unique_ptr<AnnotationProofGenerator> d_apg; /** Whether this manager caches lemmas */ bool d_cacheLemmas; /** diff --git a/src/theory/theory_model.cpp b/src/theory/theory_model.cpp index 079683116..33ec5b23b 100644 --- a/src/theory/theory_model.cpp +++ b/src/theory/theory_model.cpp @@ -135,6 +135,7 @@ Node TheoryModel::getValue(TNode n) const { //apply substitutions Node nn = d_env.getTopLevelSubstitutions().apply(n); + nn = rewrite(nn); Debug("model-getvalue-debug") << "[model-getvalue] getValue : substitute " << n << " to " << nn << std::endl; //get value in model nn = getModelValue(nn); diff --git a/src/theory/theory_model_builder.cpp b/src/theory/theory_model_builder.cpp index bc63aef97..a83527004 100644 --- a/src/theory/theory_model_builder.cpp +++ b/src/theory/theory_model_builder.cpp @@ -1034,7 +1034,7 @@ bool TheoryEngineModelBuilder::buildModel(TheoryModel* tm) if (!repSet.empty()) { Trace("model-builder") << "***Non-empty repSet, size = " << repSet.size() - << ", first = " << *(repSet.begin()) << endl; + << ", repSet = " << repSet << endl; Assert(false); } } @@ -1278,7 +1278,8 @@ void TheoryEngineModelBuilder::assignFunction(TheoryModel* m, Node f) } std::stringstream ss; ss << "_arg_"; - Node val = ufmt.getFunctionValue(ss.str().c_str(), condenseFuncValues); + Rewriter* r = condenseFuncValues ? d_env.getRewriter() : nullptr; + Node val = ufmt.getFunctionValue(ss.str(), r); m->assignFunctionDefinition(f, val); // ufmt.debugPrint( std::cout, m ); } diff --git a/src/theory/trust_substitutions.cpp b/src/theory/trust_substitutions.cpp index c73265095..ea87829a9 100644 --- a/src/theory/trust_substitutions.cpp +++ b/src/theory/trust_substitutions.cpp @@ -145,11 +145,11 @@ void TrustSubstitutionMap::addSubstitutions(TrustSubstitutionMap& t) } } -TrustNode TrustSubstitutionMap::applyTrusted(Node n, bool doRewrite) +TrustNode TrustSubstitutionMap::applyTrusted(Node n, Rewriter* r) { Trace("trust-subs") << "TrustSubstitutionMap::addSubstitution: apply " << n << std::endl; - Node ns = d_subs.apply(n, doRewrite); + Node ns = d_subs.apply(n, r); Trace("trust-subs") << "...subs " << ns << std::endl; if (n == ns) { @@ -172,9 +172,9 @@ TrustNode TrustSubstitutionMap::applyTrusted(Node n, bool doRewrite) return TrustNode::mkTrustRewrite(n, ns, this); } -Node TrustSubstitutionMap::apply(Node n, bool doRewrite) +Node TrustSubstitutionMap::apply(Node n, Rewriter* r) { - return d_subs.apply(n, doRewrite); + return d_subs.apply(n, r); } std::shared_ptr<ProofNode> TrustSubstitutionMap::getProofFor(Node eq) diff --git a/src/theory/trust_substitutions.h b/src/theory/trust_substitutions.h index cc08c870d..abcf039ba 100644 --- a/src/theory/trust_substitutions.h +++ b/src/theory/trust_substitutions.h @@ -87,11 +87,12 @@ class TrustSubstitutionMap : public ProofGenerator /** * Apply substitutions in this class to node n. Returns a trust node * proving n = n*sigma, where the proof generator is provided by this class - * (when proofs are enabled). + * (when proofs are enabled). If a non-null rewriter is provided, the result + * of the substitution is rewritten. */ - TrustNode applyTrusted(Node n, bool doRewrite = true); + TrustNode applyTrusted(Node n, Rewriter* r = nullptr); /** Same as above, without proofs */ - Node apply(Node n, bool doRewrite = true); + Node apply(Node n, Rewriter* r = nullptr); /** Get the proof for formula f */ std::shared_ptr<ProofNode> getProofFor(Node f) override; diff --git a/src/theory/uf/cardinality_extension.cpp b/src/theory/uf/cardinality_extension.cpp index f5f6ff565..2ebdf5a24 100644 --- a/src/theory/uf/cardinality_extension.cpp +++ b/src/theory/uf/cardinality_extension.cpp @@ -465,11 +465,13 @@ std::string SortModel::CardinalityDecisionStrategy::identify() const return std::string("uf_card"); } -SortModel::SortModel(TypeNode tn, +SortModel::SortModel(Env& env, + TypeNode tn, TheoryState& state, TheoryInferenceManager& im, CardinalityExtension* thss) - : d_type(tn), + : EnvObj(env), + d_type(tn), d_state(state), d_im(im), d_thss(thss), @@ -484,8 +486,7 @@ SortModel::SortModel(TypeNode tn, d_initialized(thss->userContext(), false), d_c_dec_strat(nullptr) { - - if (options::ufssMode() == options::UfssMode::FULL) + if (options().uf.ufssMode == options::UfssMode::FULL) { // Register the strategy with the decision manager of the theory. // We are guaranteed that the decision manager is ready since we @@ -672,7 +673,7 @@ bool SortModel::areDisequal( Node a, Node b ) { void SortModel::check(Theory::Effort level) { - Assert(options::ufssMode() == options::UfssMode::FULL); + Assert(options().uf.ufssMode == options::UfssMode::FULL); if (!d_hasCard && d_state.isInConflict()) { // not necessary to check @@ -885,11 +886,11 @@ void SortModel::assertCardinality(uint32_t c, bool val) } } // we assert it positively, if its beyond the bound, abort - if (options::ufssAbortCardinality() >= 0 - && c >= static_cast<uint32_t>(options::ufssAbortCardinality())) + if (options().uf.ufssAbortCardinality >= 0 + && c >= static_cast<uint32_t>(options().uf.ufssAbortCardinality)) { std::stringstream ss; - ss << "Maximum cardinality (" << options::ufssAbortCardinality() + ss << "Maximum cardinality (" << options().uf.ufssAbortCardinality << ") for finite model finding exceeded." << std::endl; throw LogicException(ss.str()); } @@ -1011,7 +1012,7 @@ int SortModel::addSplit(Region* r) if (!s.isNull() ){ //add lemma to output channel Assert(s.getKind() == EQUAL); - Node ss = Rewriter::rewrite( s ); + Node ss = rewrite(s); if( ss.getKind()!=EQUAL ){ Node b_t = NodeManager::currentNM()->mkConst( true ); Node b_f = NodeManager::currentNM()->mkConst( false ); @@ -1620,7 +1621,7 @@ void CardinalityExtension::preRegisterTerm(TNode n) if (tn.isSort()) { Trace("uf-ss-register") << "Create sort model " << tn << "." << std::endl; - rm = new SortModel(tn, d_state, d_im, this); + rm = new SortModel(d_env, tn, d_state, d_im, this); } if (rm) { diff --git a/src/theory/uf/cardinality_extension.h b/src/theory/uf/cardinality_extension.h index 7a6d44ee9..822f13f23 100644 --- a/src/theory/uf/cardinality_extension.h +++ b/src/theory/uf/cardinality_extension.h @@ -48,7 +48,7 @@ class CardinalityExtension : protected EnvObj * Information for incremental conflict/clique finding for a * particular sort. */ - class SortModel + class SortModel : protected EnvObj { private: std::map< Node, std::vector< int > > d_totality_lems; @@ -281,7 +281,8 @@ class CardinalityExtension : protected EnvObj void simpleCheckCardinality(); public: - SortModel(TypeNode tn, + SortModel(Env& env, + TypeNode tn, TheoryState& state, TheoryInferenceManager& im, CardinalityExtension* thss); diff --git a/src/theory/uf/proof_equality_engine.cpp b/src/theory/uf/proof_equality_engine.cpp index 71688fc15..856dce011 100644 --- a/src/theory/uf/proof_equality_engine.cpp +++ b/src/theory/uf/proof_equality_engine.cpp @@ -31,7 +31,8 @@ namespace theory { namespace eq { ProofEqEngine::ProofEqEngine(Env& env, EqualityEngine& ee) - : EagerProofGenerator(env.getProofNodeManager(), + : EnvObj(env), + EagerProofGenerator(env.getProofNodeManager(), env.getUserContext(), "pfee::" + ee.identify()), d_ee(ee), @@ -180,7 +181,7 @@ TrustNode ProofEqEngine::assertConflict(Node lit) // lit may not be equivalent to false, but should rewrite to false if (lit != d_false) { - Assert(Rewriter::rewrite(lit) == d_false) + Assert(rewrite(lit) == d_false) << "pfee::assertConflict: conflict literal is not rewritable to " "false"; std::vector<Node> exp; diff --git a/src/theory/uf/proof_equality_engine.h b/src/theory/uf/proof_equality_engine.h index fc8520dd1..47bb2fe0d 100644 --- a/src/theory/uf/proof_equality_engine.h +++ b/src/theory/uf/proof_equality_engine.h @@ -27,6 +27,7 @@ #include "proof/buffered_proof_generator.h" #include "proof/eager_proof_generator.h" #include "proof/lazy_proof.h" +#include "smt/env_obj.h" namespace cvc5 { @@ -80,7 +81,7 @@ class EqualityEngine; * - explain, for explaining why a literal is true in the current state. * Details on these methods can be found below. */ -class ProofEqEngine : public EagerProofGenerator +class ProofEqEngine : protected EnvObj, public EagerProofGenerator { typedef context::CDHashSet<Node> NodeSet; typedef context::CDHashMap<Node, std::shared_ptr<ProofNode>> NodeProofMap; diff --git a/src/theory/uf/theory_uf_model.cpp b/src/theory/uf/theory_uf_model.cpp index 861f12d64..6d8d421ba 100644 --- a/src/theory/uf/theory_uf_model.cpp +++ b/src/theory/uf/theory_uf_model.cpp @@ -57,7 +57,11 @@ void UfModelTreeNode::setValue( TheoryModel* m, Node n, Node v, std::vector< int } } -Node UfModelTreeNode::getFunctionValue(std::vector<Node>& args, int index, Node argDefaultValue, bool simplify) { +Node UfModelTreeNode::getFunctionValue(const std::vector<Node>& args, + int index, + Node argDefaultValue, + bool simplify) +{ if(!d_data.empty()) { Node defaultValue = argDefaultValue; if(d_data.find(Node::null()) != d_data.end()) { @@ -222,16 +226,19 @@ void UfModelTreeNode::debugPrint( std::ostream& out, TheoryModel* m, std::vector } } -Node UfModelTree::getFunctionValue( std::vector< Node >& args, bool simplify ){ - Node body = d_tree.getFunctionValue( args, 0, Node::null(), simplify ); - if(simplify) { - body = Rewriter::rewrite( body ); +Node UfModelTree::getFunctionValue(const std::vector<Node>& args, Rewriter* r) +{ + Node body = d_tree.getFunctionValue(args, 0, Node::null(), r != nullptr); + if (r != nullptr) + { + body = r->rewrite(body); } Node boundVarList = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, args); return NodeManager::currentNM()->mkNode(kind::LAMBDA, boundVarList, body); } -Node UfModelTree::getFunctionValue( const char* argPrefix, bool simplify ){ +Node UfModelTree::getFunctionValue(const std::string& argPrefix, Rewriter* r) +{ TypeNode type = d_op.getType(); std::vector< Node > vars; for( size_t i=0; i<type.getNumChildren()-1; i++ ){ @@ -239,7 +246,7 @@ Node UfModelTree::getFunctionValue( const char* argPrefix, bool simplify ){ ss << argPrefix << (i+1); vars.push_back( NodeManager::currentNM()->mkBoundVar( ss.str(), type[i] ) ); } - return getFunctionValue( vars, simplify ); + return getFunctionValue(vars, r); } } // namespace uf diff --git a/src/theory/uf/theory_uf_model.h b/src/theory/uf/theory_uf_model.h index f386c2f99..e4235623e 100644 --- a/src/theory/uf/theory_uf_model.h +++ b/src/theory/uf/theory_uf_model.h @@ -26,6 +26,7 @@ namespace cvc5 { namespace theory { class TheoryModel; +class Rewriter; namespace uf { @@ -45,7 +46,10 @@ public: /** setValue function */ void setValue( TheoryModel* m, Node n, Node v, std::vector< int >& indexOrder, bool ground, int argIndex ); /** getFunctionValue */ - Node getFunctionValue( std::vector< Node >& args, int index, Node argDefaultValue, bool simplify = true ); + Node getFunctionValue(const std::vector<Node>& args, + int index, + Node argDefaultValue, + bool simplify = true); /** update function */ void update( TheoryModel* m ); /** simplify function */ @@ -92,11 +96,12 @@ public: d_tree.setValue( m, Node::null(), v, d_index_order, false, 0 ); } /** getFunctionValue - * Returns a representation of this function. - */ - Node getFunctionValue( std::vector< Node >& args, bool simplify = true ); + * Returns a representation of this function. The body of the function is + * rewritten if r is non-null. + */ + Node getFunctionValue(const std::vector<Node>& args, Rewriter* r); /** getFunctionValue for args with set prefix */ - Node getFunctionValue( const char* argPrefix, bool simplify = true ); + Node getFunctionValue(const std::string& argPrefix, Rewriter* r); /** update * This will update all values in the tree to be representatives in m. */ diff --git a/src/util/didyoumean.cpp b/src/util/didyoumean.cpp index 0f95722fd..f4dbbbd36 100644 --- a/src/util/didyoumean.cpp +++ b/src/util/didyoumean.cpp @@ -37,7 +37,7 @@ uint64_t editDistance(const std::string& a, const std::string& b) { constexpr uint64_t swapCost = 0; constexpr uint64_t substituteCost = 2; constexpr uint64_t addCost = 1; - constexpr uint64_t deleteCost = 3; + constexpr uint64_t deleteCost = 2; constexpr uint64_t switchCaseCost = 0; uint64_t len1 = a.size(); @@ -104,7 +104,7 @@ std::vector<std::string> DidYouMean::getMatch(const std::string& input) } /** Magic numbers */ - constexpr uint64_t similarityThreshold = 7; + constexpr uint64_t similarityThreshold = 10; constexpr uint64_t numMatchesThreshold = 10; std::vector<std::pair<uint64_t,std::string>> scores; @@ -127,7 +127,7 @@ std::vector<std::string> DidYouMean::getMatch(const std::string& input) // from here on, matches are not similar enough if (score.first > similarityThreshold) break; // from here on, matches are way worse than the best one - if (score.first > min_score + 2) break; + if (score.first > min_score + 4) break; // we already have enough matches if (ret.size() >= numMatchesThreshold) break; ret.push_back(score.second); diff --git a/src/util/hash.h b/src/util/hash.h index db280984b..ef8bf4a2a 100644 --- a/src/util/hash.h +++ b/src/util/hash.h @@ -43,12 +43,15 @@ namespace cvc5 { namespace fnv1a { +constexpr uint64_t offsetBasis = 14695981039346656037U; + /** * FNV-1a hash algorithm for 64-bit numbers. * * More details here: http://www.isthe.com/chongo/tech/comp/fnv/index.html */ -inline uint64_t fnv1a_64(uint64_t v, uint64_t hash = 14695981039346656037U) { +inline uint64_t fnv1a_64(uint64_t v, uint64_t hash = offsetBasis) +{ hash ^= v; // Compute (hash * 1099511628211) return hash + (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + diff --git a/src/util/integer_cln_imp.cpp b/src/util/integer_cln_imp.cpp index e09708ae5..149e02edc 100644 --- a/src/util/integer_cln_imp.cpp +++ b/src/util/integer_cln_imp.cpp @@ -483,16 +483,6 @@ unsigned int Integer::getUnsignedInt() const return cln::cl_I_to_uint(d_value); } -bool Integer::fitsSignedLong() const -{ - return d_value <= s_signedLongMax && d_value >= s_signedLongMin; -} - -bool Integer::fitsUnsignedLong() const -{ - return sgn() >= 0 && d_value <= s_unsignedLongMax; -} - long Integer::getLong() const { // ensure there isn't overflow @@ -517,6 +507,53 @@ unsigned long Integer::getUnsignedLong() const return cln::cl_I_to_ulong(d_value); } +int64_t Integer::getSigned64() const +{ + if constexpr (sizeof(int64_t) == sizeof(signed long int)) + { + return getLong(); + } + else + { + if (std::numeric_limits<long>::min() <= d_value + && d_value <= std::numeric_limits<long>::max()) + { + return getLong(); + } + // ensure there isn't overflow + CheckArgument(d_value <= std::numeric_limits<int64_t>::max(), + this, + "Overflow detected in Integer::getSigned64()"); + CheckArgument(d_value >= std::numeric_limits<int64_t>::min(), + this, + "Overflow detected in Integer::getSigned64()"); + return std::stoll(toString()); + } +} +uint64_t Integer::getUnsigned64() const +{ + if constexpr (sizeof(uint64_t) == sizeof(unsigned long int)) + { + return getUnsignedLong(); + } + else + { + if (std::numeric_limits<unsigned long>::min() <= d_value + && d_value <= std::numeric_limits<unsigned long>::max()) + { + return getUnsignedLong(); + } + // ensure there isn't overflow + CheckArgument(d_value <= std::numeric_limits<uint64_t>::max(), + this, + "Overflow detected in Integer::getSigned64()"); + CheckArgument(d_value >= std::numeric_limits<uint64_t>::min(), + this, + "Overflow detected in Integer::getSigned64()"); + return std::stoull(toString()); + } +} + size_t Integer::hash() const { return equal_hashcode(d_value); } bool Integer::testBit(unsigned n) const { return cln::logbitp(n, d_value); } diff --git a/src/util/integer_cln_imp.h b/src/util/integer_cln_imp.h index 2120a4d5d..333d8f502 100644 --- a/src/util/integer_cln_imp.h +++ b/src/util/integer_cln_imp.h @@ -274,18 +274,18 @@ class CVC5_EXPORT Integer /** Return the unsigned int representation of this Integer. */ unsigned int getUnsignedInt() const; - /** Return true if this Integer fits into a signed long. */ - bool fitsSignedLong() const; - - /** Return true if this Integer fits into an unsigned long. */ - bool fitsUnsignedLong() const; - /** Return the signed long representation of this Integer. */ long getLong() const; /** Return the unsigned long representation of this Integer. */ unsigned long getUnsignedLong() const; + /** Return the int64_t representation of this Integer. */ + int64_t getSigned64() const; + + /** Return the uint64_t representation of this Integer. */ + uint64_t getUnsigned64() const; + /** * Computes the hash of the node from the first word of the * numerator, the denominator. diff --git a/src/util/integer_gmp_imp.cpp b/src/util/integer_gmp_imp.cpp index f33a90408..8d9f7d050 100644 --- a/src/util/integer_gmp_imp.cpp +++ b/src/util/integer_gmp_imp.cpp @@ -14,6 +14,7 @@ */ #include <cmath> +#include <limits> #include <sstream> #include <string> @@ -38,6 +39,33 @@ Integer::Integer(const std::string& s, unsigned base) : d_value(s, base) {} +#ifdef CVC5_NEED_INT64_T_OVERLOADS +Integer::Integer(int64_t z) +{ + if (std::numeric_limits<signed long int>::min() <= z + && z <= std::numeric_limits<signed long int>::max()) + { + d_value = static_cast<signed long int>(z); + } + else + { + d_value = std::to_string(z); + } +} +Integer::Integer(uint64_t z) +{ + if (std::numeric_limits<unsigned long int>::min() <= z + && z <= std::numeric_limits<unsigned long int>::max()) + { + d_value = static_cast<unsigned long int>(z); + } + else + { + d_value = std::to_string(z); + } +} +#endif /* CVC5_NEED_INT64_T_OVERLOADS */ + Integer& Integer::operator=(const Integer& x) { if (this == &x) return *this; @@ -402,28 +430,73 @@ unsigned int Integer::getUnsignedInt() const return (unsigned int)d_value.get_ui(); } -bool Integer::fitsSignedLong() const { return d_value.fits_slong_p(); } - -bool Integer::fitsUnsignedLong() const { return d_value.fits_ulong_p(); } - long Integer::getLong() const { - long si = d_value.get_si(); - // ensure there wasn't overflow - CheckArgument(mpz_cmp_si(d_value.get_mpz_t(), si) == 0, + // ensure there it fits + CheckArgument(mpz_fits_slong_p(d_value.get_mpz_t()) != 0, this, "Overflow detected in Integer::getLong()."); - return si; + return d_value.get_si(); } unsigned long Integer::getUnsignedLong() const { - unsigned long ui = d_value.get_ui(); - // ensure there wasn't overflow - CheckArgument(mpz_cmp_ui(d_value.get_mpz_t(), ui) == 0, + // ensure that it fits + CheckArgument(mpz_fits_ulong_p(d_value.get_mpz_t()) != 0, this, "Overflow detected in Integer::getUnsignedLong()."); - return ui; + return d_value.get_ui(); +} + +int64_t Integer::getSigned64() const +{ + if constexpr (sizeof(int64_t) == sizeof(signed long int)) + { + return getLong(); + } + else + { + if (mpz_fits_slong_p(d_value.get_mpz_t()) != 0) + { + return getLong(); + } + try + { + return std::stoll(toString()); + } + catch (const std::exception& e) + { + CheckArgument( + false, this, "Overflow detected in Integer::getSigned64()."); + } + } + return 0; +} +uint64_t Integer::getUnsigned64() const +{ + if constexpr (sizeof(uint64_t) == sizeof(unsigned long int)) + { + return getUnsignedLong(); + } + else + { + if (mpz_fits_ulong_p(d_value.get_mpz_t()) != 0) + { + return getUnsignedLong(); + } + try + { + CheckArgument( + sgn() >= 0, this, "Overflow detected in Integer::getUnsigned64()."); + return std::stoull(toString()); + } + catch (const std::exception& e) + { + CheckArgument( + false, this, "Overflow detected in Integer::getUnsigned64()."); + } + } + return 0; } size_t Integer::hash() const { return gmpz_hash(d_value.get_mpz_t()); } diff --git a/src/util/integer_gmp_imp.h b/src/util/integer_gmp_imp.h index ff2ea9815..397455f87 100644 --- a/src/util/integer_gmp_imp.h +++ b/src/util/integer_gmp_imp.h @@ -59,8 +59,8 @@ class CVC5_EXPORT Integer Integer(unsigned long int z) : d_value(z) {} #ifdef CVC5_NEED_INT64_T_OVERLOADS - Integer(int64_t z) : d_value(static_cast<long>(z)) {} - Integer(uint64_t z) : d_value(static_cast<unsigned long>(z)) {} + Integer(int64_t z); + Integer(uint64_t z); #endif /* CVC5_NEED_INT64_T_OVERLOADS */ /** Destructor. */ @@ -257,18 +257,18 @@ class CVC5_EXPORT Integer /** Return the unsigned int representation of this Integer. */ unsigned int getUnsignedInt() const; - /** Return true if this Integer fits into a signed long. */ - bool fitsSignedLong() const; - - /** Return true if this Integer fits into an unsigned long. */ - bool fitsUnsignedLong() const; - /** Return the signed long representation of this Integer. */ long getLong() const; /** Return the unsigned long representation of this Integer. */ unsigned long getUnsignedLong() const; + /** Return the int64_t representation of this Integer. */ + int64_t getSigned64() const; + + /** Return the uint64_t representation of this Integer. */ + uint64_t getUnsigned64() const; + /** * Computes the hash of the node from the first word of the * numerator, the denominator. diff --git a/src/util/string.cpp b/src/util/string.cpp index 50b0a7199..2235ac5ee 100644 --- a/src/util/string.cpp +++ b/src/util/string.cpp @@ -23,6 +23,7 @@ #include "base/check.h" #include "base/exception.h" +#include "util/hash.h" using namespace std; @@ -519,6 +520,20 @@ Rational String::toNumber() const return Rational(toString()); } +namespace strings { + +size_t StringHashFunction::operator()(const ::cvc5::String& s) const +{ + uint64_t ret = fnv1a::offsetBasis; + for (unsigned c : s.d_str) + { + ret = fnv1a::fnv1a_64(c, ret); + } + return static_cast<size_t>(ret); +} + +} // namespace strings + std::ostream &operator<<(std::ostream &os, const String &s) { return os << "\"" << s.toString() << "\""; } diff --git a/src/util/string.h b/src/util/string.h index 3f6384082..017c60fb8 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -26,6 +26,10 @@ namespace cvc5 { +namespace strings { +struct StringHashFunction; +} + /** The cvc5 string class * * This data structure is the domain of values for the string type. It can also @@ -33,6 +37,8 @@ namespace cvc5 { */ class String { + friend strings::StringHashFunction; + public: /** * This is the cardinality of the alphabet that is representable by this @@ -267,10 +273,7 @@ namespace strings { struct StringHashFunction { - size_t operator()(const ::cvc5::String& s) const - { - return std::hash<std::string>()(s.toString()); - } + size_t operator()(const ::cvc5::String& s) const; }; /* struct StringHashFunction */ } // namespace strings diff --git a/test/api/cpp/CMakeLists.txt b/test/api/cpp/CMakeLists.txt index eae57f3b9..929c5bef2 100644 --- a/test/api/cpp/CMakeLists.txt +++ b/test/api/cpp/CMakeLists.txt @@ -54,3 +54,5 @@ cvc5_add_api_test(issue4889) cvc5_add_api_test(issue6111) cvc5_add_api_test(proj-issue306) cvc5_add_api_test(proj-issue334) +cvc5_add_api_test(proj-issue344) +cvc5_add_api_test(proj-issue345) diff --git a/test/api/cpp/proj-issue344.cpp b/test/api/cpp/proj-issue344.cpp new file mode 100644 index 000000000..5f486706c --- /dev/null +++ b/test/api/cpp/proj-issue344.cpp @@ -0,0 +1,33 @@ +/****************************************************************************** + * Top contributors (to current version): + * Yoni Zohar + * + * This file is part of the cvc5 project. + * + * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS + * in the top-level source directory and their institutional affiliations. + * All rights reserved. See the file COPYING in the top-level source + * directory for licensing information. + * **************************************************************************** + * + * Test for project issue #345 + * + */ + + +#include "api/cpp/cvc5.h" +#include <cassert> + +using namespace cvc5::api; + +int main(void) +{ + Solver slv; + slv.setOption("solve-bv-as-int", "iand"); + Sort s12 = slv.getIntegerSort(); + Term t13 = slv.mkConst(s12, "_x11"); + Term t25 = slv.mkTerm(slv.mkOp(Kind::INT_TO_BITVECTOR, 4124876294), {t13}); + Term t66 = slv.mkTerm(Kind::BITVECTOR_ULTBV, {t25, t25}); + Term t154 = slv.mkTerm(Kind::BITVECTOR_SGT, {t66, t66}); + slv.checkEntailed({t154, t154, t154, t154}); +} diff --git a/test/api/cpp/proj-issue345.cpp b/test/api/cpp/proj-issue345.cpp new file mode 100644 index 000000000..c33e9e5b8 --- /dev/null +++ b/test/api/cpp/proj-issue345.cpp @@ -0,0 +1,34 @@ +/****************************************************************************** + * Top contributors (to current version): + * Yoni Zohar + * + * This file is part of the cvc5 project. + * + * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS + * in the top-level source directory and their institutional affiliations. + * All rights reserved. See the file COPYING in the top-level source + * directory for licensing information. + * **************************************************************************** + * + * Test for project issue #345 + * + */ + + +#include "api/cpp/cvc5.h" +#include <cassert> + +using namespace cvc5::api; + +int main(void) +{ + Solver slv; + slv.setOption("solve-bv-as-int", "iand"); + Sort s12 = slv.getIntegerSort(); + Term t13 = slv.mkConst(s12, "_x11"); + Term t25 = slv.mkTerm(slv.mkOp(Kind::INT_TO_BITVECTOR, 4124876294), {t13}); + Term t66 = slv.mkTerm(Kind::BITVECTOR_SLTBV, {t25, t25}); + Term t154 = slv.mkTerm(Kind::BITVECTOR_SGT, {t66, t66}); + slv.checkEntailed({t154, t154, t154, t154}); +} + diff --git a/test/api/cpp/sep_log_api.cpp b/test/api/cpp/sep_log_api.cpp index 5795de794..6a2fc9740 100644 --- a/test/api/cpp/sep_log_api.cpp +++ b/test/api/cpp/sep_log_api.cpp @@ -247,8 +247,7 @@ int validate_getters(void) * than the random constant -- if we get a value that is LTE, then * something has gone wrong! */ - if (std::stoll(value.toString()) - <= std::stoll(random_constant.toString())) + if (value.getInt64Value() <= random_constant.getInt64Value()) { return -1; } diff --git a/test/api/python/issue4889.py b/test/api/python/issue4889.py index 538c9f2ca..eae0ecad7 100644 --- a/test/api/python/issue4889.py +++ b/test/api/python/issue4889.py @@ -14,7 +14,7 @@ ## import pycvc5 -from pycvc5 import kinds +from pycvc5 import Kind slv = pycvc5.Solver() sort_int = slv.getIntegerSort() @@ -25,7 +25,7 @@ sort_bool = slv.getBooleanSort() const0 = slv.mkConst(sort_fp32, "_c0") const1 = slv.mkConst(sort_fp32, "_c2") const2 = slv.mkConst(sort_bool, "_c4") -ite = slv.mkTerm(kinds.Ite, const2, const1, const0) -rem = slv.mkTerm(kinds.FPRem, ite, const1) -isnan = slv.mkTerm(kinds.FPIsNan, rem) +ite = slv.mkTerm(Kind.Ite, const2, const1, const0) +rem = slv.mkTerm(Kind.FPRem, ite, const1) +isnan = slv.mkTerm(Kind.FPIsNan, rem) slv.checkSatAssuming(isnan) diff --git a/test/api/python/issue5074.py b/test/api/python/issue5074.py index 05fc84ad6..f07b5c8fa 100644 --- a/test/api/python/issue5074.py +++ b/test/api/python/issue5074.py @@ -14,12 +14,12 @@ ## import pycvc5 -from pycvc5 import kinds +from pycvc5 import Kind slv = pycvc5.Solver() c1 = slv.mkConst(slv.getIntegerSort()) -t6 = slv.mkTerm(kinds.StringFromCode, c1) -t12 = slv.mkTerm(kinds.StringToRegexp, t6) -t14 = slv.mkTerm(kinds.StringReplaceRe, [t6, t12, t6]) -t16 = slv.mkTerm(kinds.StringContains, [t14, t14]) +t6 = slv.mkTerm(Kind.StringFromCode, c1) +t12 = slv.mkTerm(Kind.StringToRegexp, t6) +t14 = slv.mkTerm(Kind.StringReplaceRe, [t6, t12, t6]) +t16 = slv.mkTerm(Kind.StringContains, [t14, t14]) slv.checkEntailed(t16) diff --git a/test/api/python/issue6111.py b/test/api/python/issue6111.py index 6a4ec3842..9bbda286c 100644 --- a/test/api/python/issue6111.py +++ b/test/api/python/issue6111.py @@ -14,7 +14,7 @@ ## import pycvc5 -from pycvc5 import kinds +from pycvc5 import Kind solver = pycvc5.Solver() solver.setLogic("QF_BV") @@ -25,7 +25,7 @@ zero = solver.mkBitVector(bvsort12979.getBitVectorSize(), "0", 10) args1 = [] args1.append(zero) args1.append(input2_1) -bvult_res = solver.mkTerm(kinds.BVUlt, args1) +bvult_res = solver.mkTerm(Kind.BVUlt, args1) solver.assertFormula(bvult_res) bvsort4 = solver.mkBitVectorSort(4) @@ -36,13 +36,13 @@ concat_result_43 = solver.mkConst(bvsort8, "concat_result_43") args2 = [] args2.append(concat_result_42) args2.append( - solver.mkTerm(solver.mkOp(kinds.BVExtract, 7, 4), [concat_result_43])) -solver.assertFormula(solver.mkTerm(kinds.Equal, args2)) + solver.mkTerm(solver.mkOp(Kind.BVExtract, 7, 4), [concat_result_43])) +solver.assertFormula(solver.mkTerm(Kind.Equal, args2)) args3 = [] args3.append(concat_result_42) args3.append( - solver.mkTerm(solver.mkOp(kinds.BVExtract, 3, 0), [concat_result_43])) -solver.assertFormula(solver.mkTerm(kinds.Equal, args3)) + solver.mkTerm(solver.mkOp(Kind.BVExtract, 3, 0), [concat_result_43])) +solver.assertFormula(solver.mkTerm(Kind.Equal, args3)) print(solver.checkSat()) diff --git a/test/api/python/proj-issue306.py b/test/api/python/proj-issue306.py index 5d84f65b6..7dbdd6b41 100644 --- a/test/api/python/proj-issue306.py +++ b/test/api/python/proj-issue306.py @@ -13,7 +13,7 @@ ## import pycvc5 -from pycvc5 import kinds +from pycvc5 import Kind slv = pycvc5.Solver() slv.setOption("check-proofs", "true") @@ -24,8 +24,8 @@ t1 = slv.mkConst(s3, "_x0") t3 = slv.mkConst(s1, "_x2") t11 = slv.mkString("") t14 = slv.mkConst(s3, "_x11") -t42 = slv.mkTerm(kinds.Ite, t3, t14, t1) -t58 = slv.mkTerm(kinds.StringLeq, t14, t11) -t95 = slv.mkTerm(kinds.Equal, t14, t42) +t42 = slv.mkTerm(Kind.Ite, t3, t14, t1) +t58 = slv.mkTerm(Kind.StringLeq, t14, t11) +t95 = slv.mkTerm(Kind.Equal, t14, t42) slv.assertFormula(t95) slv.checkSatAssuming([t58]) diff --git a/test/api/python/reset_assertions.py b/test/api/python/reset_assertions.py index 221f1c884..8c3a4e44c 100644 --- a/test/api/python/reset_assertions.py +++ b/test/api/python/reset_assertions.py @@ -19,7 +19,7 @@ ## import pycvc5 -from pycvc5 import kinds +from pycvc5 import Kind slv = pycvc5.Solver() slv.setOption("incremental", "true") @@ -27,7 +27,7 @@ slv.setOption("incremental", "true") real = slv.getRealSort() x = slv.mkConst(real, "x") four = slv.mkInteger(4) -xEqFour = slv.mkTerm(kinds.Equal, x, four) +xEqFour = slv.mkTerm(Kind.Equal, x, four) slv.assertFormula(xEqFour) print(slv.checkSat()) @@ -37,8 +37,8 @@ elementType = slv.getIntegerSort() indexType = slv.getIntegerSort() arrayType = slv.mkArraySort(indexType, elementType) array = slv.mkConst(arrayType, "array") -arrayAtFour = slv.mkTerm(kinds.Select, array, four) +arrayAtFour = slv.mkTerm(Kind.Select, array, four) ten = slv.mkInteger(10) -arrayAtFour_eq_ten = slv.mkTerm(kinds.Equal, arrayAtFour, ten) +arrayAtFour_eq_ten = slv.mkTerm(Kind.Equal, arrayAtFour, ten) slv.assertFormula(arrayAtFour_eq_ten) print(slv.checkSat()) diff --git a/test/api/python/sep_log_api.py b/test/api/python/sep_log_api.py index 4e2fbb750..8bbef42fa 100644 --- a/test/api/python/sep_log_api.py +++ b/test/api/python/sep_log_api.py @@ -20,7 +20,7 @@ ## import pycvc5 -from pycvc5 import kinds +from pycvc5 import Kind # Test function to validate that we *cannot* obtain the heap/nil expressions @@ -43,7 +43,7 @@ def validate_exception(): y = slv.mkConst(integer, "y") # y > x - y_gt_x = slv.mkTerm(kinds.Gt, y, x) + y_gt_x = slv.mkTerm(Kind.Gt, y, x) # assert it slv.assertFormula(y_gt_x) @@ -124,18 +124,18 @@ def validate_getters(): p2 = slv.mkConst(integer, "p2") # Constraints on x and y - x_equal_const = slv.mkTerm(kinds.Equal, x, random_constant) - y_gt_x = slv.mkTerm(kinds.Gt, y, x) + x_equal_const = slv.mkTerm(Kind.Equal, x, random_constant) + y_gt_x = slv.mkTerm(Kind.Gt, y, x) # Points-to expressions - p1_to_x = slv.mkTerm(kinds.SepPto, p1, x) - p2_to_y = slv.mkTerm(kinds.SepPto, p2, y) + p1_to_x = slv.mkTerm(Kind.SepPto, p1, x) + p2_to_y = slv.mkTerm(Kind.SepPto, p2, y) # Heap -- the points-to have to be "starred"! - heap = slv.mkTerm(kinds.SepStar, p1_to_x, p2_to_y) + heap = slv.mkTerm(Kind.SepStar, p1_to_x, p2_to_y) # Constain "nil" to be something random - fix_nil = slv.mkTerm(kinds.Equal, nil, expr_nil_val) + fix_nil = slv.mkTerm(Kind.Equal, nil, expr_nil_val) # Add it all to the solver! slv.assertFormula(x_equal_const) @@ -157,11 +157,11 @@ def validate_getters(): nil_expr = slv.getValueSepNil() # If the heap is not a separating conjunction, bail-out - if (heap_expr.getKind() != kinds.SepStar): + if (heap_expr.getKind() != Kind.SepStar): return False # If nil is not a direct equality, bail-out - if (nil_expr.getKind() != kinds.Equal): + if (nil_expr.getKind() != Kind.Equal): return False # Obtain the values for our "pointers" @@ -175,7 +175,7 @@ def validate_getters(): # Walk all the children for child in heap_expr: # If we don't have a PTO operator, bail-out - if (child.getKind() != kinds.SepPto): + if (child.getKind() != Kind.SepPto): return False # Find both sides of the PTO operator diff --git a/test/regress/CMakeLists.txt b/test/regress/CMakeLists.txt index 4169036ba..20722a1da 100644 --- a/test/regress/CMakeLists.txt +++ b/test/regress/CMakeLists.txt @@ -257,6 +257,7 @@ set(regress_0_tests regress0/bv/bv_to_int_bvuf_to_intuf.smt2 regress0/bv/bv_to_int_bvuf_to_intuf_sorts.smt2 regress0/bv/bv_to_int_elim_err.smt2 + regress0/bv/bv_to_int_int1.smt2 regress0/bv/bv_to_int_zext.smt2 regress0/bv/bvcomp.cvc.smt2 regress0/bv/bvmul-pow2-only.smt2 @@ -434,6 +435,7 @@ set(regress_0_tests regress0/bv/mult-pow2-negative.smt2 regress0/bv/pr4993-bvugt-bvurem-a.smt2 regress0/bv/pr4993-bvugt-bvurem-b.smt2 + regress0/bv/proj-issue343.smt2 regress0/bv/reset-assertions-assert-input.smt2 regress0/bv/sizecheck.cvc.smt2 regress0/bv/smtcompbug.smtv1.smt2 @@ -510,7 +512,9 @@ set(regress_0_tests regress0/datatypes/mutually-recursive.cvc.smt2 regress0/datatypes/pair-bool-bool.cvc.smt2 regress0/datatypes/pair-real-bool.smt2 + regress0/datatypes/par-updater-type-rule.smt2 regress0/datatypes/parametric-alt-list.cvc.smt2 + regress0/datatypes/proj-issue172.smt2 regress0/datatypes/rec1.cvc.smt2 regress0/datatypes/rec2.cvc.smt2 regress0/datatypes/rec4.cvc.smt2 @@ -557,6 +561,8 @@ set(regress_0_tests regress0/declare-fun-is-match.smt2 regress0/declare-funs.smt2 regress0/define-fun-model.smt2 + regress0/difficulty-simple.smt2 + regress0/difficulty-model-ex.smt2 regress0/distinct.smtv1.smt2 regress0/dump-unsat-core-full.smt2 regress0/echo.smt2 @@ -783,6 +789,7 @@ set(regress_0_tests regress0/options/didyoumean.smt2 regress0/options/help.smt2 regress0/options/interactive-mode.smt2 + regress0/options/named_muted.smt2 regress0/options/set-after-init.smt2 regress0/options/set-and-get-options.smt2 regress0/options/statistics.smt2 @@ -1303,6 +1310,7 @@ set(regress_0_tests regress0/sygus/General_plus10.sy regress0/sygus/hd-05-d1-prog-nogrammar.sy regress0/sygus/ho-occ-synth-fun.sy + regress0/sygus/incremental-modify-ex.sy regress0/sygus/inv-different-var-order.sy regress0/sygus/issue3356-syg-inf-usort.smt2 regress0/sygus/issue3624.sy @@ -1597,6 +1605,7 @@ set(regress_1_tests regress1/bug694-Unapply1.scala-0.smt2 regress1/bug800.smt2 regress1/bags/card1.smt2 + regress1/bags/card2.smt2 regress1/bags/choose1.smt2 regress1/bags/choose2.smt2 regress1/bags/choose3.smt2 @@ -1616,10 +1625,12 @@ set(regress_1_tests regress1/bags/intersection_min1.smt2 regress1/bags/intersection_min2.smt2 regress1/bags/issue5759.smt2 - regress1/bags/map-lazy-lam.smt2 regress1/bags/map1.smt2 regress1/bags/map2.smt2 regress1/bags/map3.smt2 + regress1/bags/map-lazy-lam.smt2 + regress1/bags/murxla1.smt2 + regress1/bags/murxla2.smt2 regress1/bags/subbag1.smt2 regress1/bags/subbag2.smt2 regress1/bags/union_disjoint.smt2 @@ -1679,6 +1690,7 @@ set(regress_1_tests regress1/decision/wishue149-2.smt2 regress1/decision/wishue149-3.smt2 regress1/decision/wishue160.smt2 + regress1/difficulty-polarity.smt2 regress1/errorcrash.smt2 regress1/fp/fp_to_real.smt2 regress1/fp/rti_3_5_bug_report.smt2 @@ -1845,6 +1857,7 @@ set(regress_1_tests regress1/nl/tan-rewrite2.smt2 regress1/nl/zero-subset.smt2 regress1/non-fatal-errors.smt2 + regress1/proj-issue175.smt2 regress1/proof00.smt2 regress1/proofs/issue6625-unsat-core-proofs.smt2 regress1/proofs/macro-res-exp-crowding-lit-inside-unit.smt2 @@ -2218,6 +2231,8 @@ set(regress_1_tests regress1/sets/issue5342_difference_version.smt2 regress1/sets/issue5942-witness.smt2 regress1/sets/lemmabug-ListElts317minimized.smt2 + regress1/sets/proj-issue164.smt2 + regress1/sets/proj-issue178.smt2 regress1/sets/remove_check_free_31_6.smt2 regress1/sets/sets-disequal.smt2 regress1/sets/sets-tuple-poly.cvc.smt2 @@ -2510,6 +2525,9 @@ set(regress_1_tests regress1/sygus/phone-1-long.sy regress1/sygus/planning-unif.sy regress1/sygus/process-10-vars.sy + regress1/sygus/proj-issue181.smt2 + regress1/sygus/proj-issue183.smt2 + regress1/sygus/proj-issue185.smt2 regress1/sygus/pLTL_5_trace.sy regress1/sygus/qe.sy regress1/sygus/qf_abv.smt2 @@ -2612,6 +2630,7 @@ set(regress_2_tests regress2/bv_to_int_mask_array_2.smt2 regress2/bv_to_int_mask_array_3.smt2 regress2/bv_to_int_shifts.smt2 + regress2/bv_to_int_quantifiers_bvand.smt2 regress2/error1.smtv1.smt2 regress2/fp/issue7056.smt2 regress2/fuzz_2.smtv1.smt2 @@ -2677,7 +2696,7 @@ set(regress_2_tests regress2/strings/replaceall-diffrange.smt2 regress2/strings/replaceall-len-c.smt2 regress2/strings/small-1.smt2 - regress2/strings/strings-alpha-card-129.smt2 + regress2/strings/strings-alpha-card-65.smt2 regress2/strings/update-ex3.smt2 regress2/strings/update-ex4-seq.smt2 regress2/sygus/MPwL_d1s3.sy diff --git a/test/regress/regress0/arith/issue5219-conflict-rewrite.smt2 b/test/regress/regress0/arith/issue5219-conflict-rewrite.smt2 index ccb50c55d..b49287c30 100644 --- a/test/regress/regress0/arith/issue5219-conflict-rewrite.smt2 +++ b/test/regress/regress0/arith/issue5219-conflict-rewrite.smt2 @@ -1,6 +1,6 @@ ; REQUIRES: poly ; COMMAND-LINE: --theoryof-mode=term --nl-icp -; EXPECT: unknown +; EXPECT: sat (set-logic QF_NRA) (set-option :check-proofs true) (declare-fun x () Real) diff --git a/test/regress/regress0/bv/bv_to_int1.smt2 b/test/regress/regress0/bv/bv_to_int1.smt2 index 3908cdb16..eb8e75803 100644 --- a/test/regress/regress0/bv/bv_to_int1.smt2 +++ b/test/regress/regress0/bv/bv_to_int1.smt2 @@ -1,4 +1,5 @@ ; COMMAND-LINE: --solve-bv-as-int=sum --bvand-integer-granularity=1 +; COMMAND-LINE: --solve-bv-as-int=bitwise --bvand-integer-granularity=1 ; EXPECT: unsat (set-logic QF_BV) (declare-fun x () (_ BitVec 4)) diff --git a/test/regress/regress0/bv/bv_to_int_bvmul2.smt2 b/test/regress/regress0/bv/bv_to_int_bvmul2.smt2 index 91e0c45fd..eced6e0e9 100644 --- a/test/regress/regress0/bv/bv_to_int_bvmul2.smt2 +++ b/test/regress/regress0/bv/bv_to_int_bvmul2.smt2 @@ -1,4 +1,5 @@ ; COMMAND-LINE: --solve-bv-as-int=sum --bvand-integer-granularity=1 --no-check-unsat-cores +; COMMAND-LINE: --solve-bv-as-int=bitwise --bvand-integer-granularity=1 --no-check-unsat-cores ; EXPECT: unsat (set-logic QF_BV) (declare-fun T4_180 () (_ BitVec 32)) diff --git a/test/regress/regress0/bv/bv_to_int_bvuf_to_intuf.smt2 b/test/regress/regress0/bv/bv_to_int_bvuf_to_intuf.smt2 index 3e545ef03..45d539f04 100644 --- a/test/regress/regress0/bv/bv_to_int_bvuf_to_intuf.smt2 +++ b/test/regress/regress0/bv/bv_to_int_bvuf_to_intuf.smt2 @@ -1,4 +1,5 @@ ; COMMAND-LINE: --solve-bv-as-int=sum --bvand-integer-granularity=1 +; COMMAND-LINE: --solve-bv-as-int=bitwise --bvand-integer-granularity=1 ; EXPECT: sat (set-logic QF_UFBV) (declare-fun a () (_ BitVec 4)) diff --git a/test/regress/regress0/bv/bv_to_int_bvuf_to_intuf_sorts.smt2 b/test/regress/regress0/bv/bv_to_int_bvuf_to_intuf_sorts.smt2 index 0a0ec7b20..ae77380dd 100644 --- a/test/regress/regress0/bv/bv_to_int_bvuf_to_intuf_sorts.smt2 +++ b/test/regress/regress0/bv/bv_to_int_bvuf_to_intuf_sorts.smt2 @@ -1,4 +1,5 @@ ; COMMAND-LINE: --solve-bv-as-int=sum --bvand-integer-granularity=1 +; COMMAND-LINE: --solve-bv-as-int=bitwise --bvand-integer-granularity=1 ; EXPECT: sat (set-logic QF_UFBV) (declare-sort S 0) diff --git a/test/regress/regress0/bv/bv_to_int_elim_err.smt2 b/test/regress/regress0/bv/bv_to_int_elim_err.smt2 index 01ee5dad8..cb7eefbb2 100644 --- a/test/regress/regress0/bv/bv_to_int_elim_err.smt2 +++ b/test/regress/regress0/bv/bv_to_int_elim_err.smt2 @@ -1,4 +1,5 @@ -; COMMAND-LINE: --solve-bv-as-int=sum --bvand-integer-granularity=1 +; COMMAND-LINE: --solve-bv-as-int=sum --bvand-integer-granularity=1 +; COMMAND-LINE: --solve-bv-as-int=bitwise --bvand-integer-granularity=1 ; EXPECT: sat (set-logic QF_BV) (declare-fun _substvar_183_ () (_ BitVec 32)) diff --git a/test/regress/regress0/bv/bv_to_int_int1.smt2 b/test/regress/regress0/bv/bv_to_int_int1.smt2 new file mode 100644 index 000000000..3295d3481 --- /dev/null +++ b/test/regress/regress0/bv/bv_to_int_int1.smt2 @@ -0,0 +1,11 @@ +; COMMAND-LINE: --solve-bv-as-int=sum --bvand-integer-granularity=1 +; EXPECT: sat +(set-logic QF_ALL) +(declare-fun x () (_ BitVec 4)) +(declare-fun y () (_ BitVec 4)) +(declare-fun z () Int) +(declare-fun w () Int) +(assert (= x (_ bv3 4))) +(assert (= y (_ bv3 4))) +(assert (> z w)) +(check-sat) diff --git a/test/regress/regress0/bv/bv_to_int_zext.smt2 b/test/regress/regress0/bv/bv_to_int_zext.smt2 index 8bf4a825d..4fd6109f4 100644 --- a/test/regress/regress0/bv/bv_to_int_zext.smt2 +++ b/test/regress/regress0/bv/bv_to_int_zext.smt2 @@ -1,4 +1,5 @@ ; COMMAND-LINE: --solve-bv-as-int=sum --bvand-integer-granularity=1 +; COMMAND-LINE: --solve-bv-as-int=bitwise --bvand-integer-granularity=1 ; EXPECT: unsat (set-logic QF_BV) (declare-fun T1_31078 () (_ BitVec 8)) diff --git a/test/regress/regress0/bv/proj-issue343.smt2 b/test/regress/regress0/bv/proj-issue343.smt2 new file mode 100644 index 000000000..6d2971ad8 --- /dev/null +++ b/test/regress/regress0/bv/proj-issue343.smt2 @@ -0,0 +1,7 @@ +; EXPECT: sat +; COMMAND-LINE: --no-check-models +(set-logic ALL) +(set-option :solve-bv-as-int bv) +(declare-const _x8 Real) +(assert (distinct real.pi _x8)) +(check-sat) diff --git a/test/regress/regress0/datatypes/par-updater-type-rule.smt2 b/test/regress/regress0/datatypes/par-updater-type-rule.smt2 new file mode 100644 index 000000000..0b4af0287 --- /dev/null +++ b/test/regress/regress0/datatypes/par-updater-type-rule.smt2 @@ -0,0 +1,11 @@ +(set-option :global-declarations true) +(set-logic ALL) +(set-info :status unsat) +(declare-datatype _x0 ( (_x6 (_x1 Bool)))) +(declare-datatype _x36 ( (_x42 (_x37 Bool)))) +(declare-const _x53 Bool) +(declare-const _x56 _x36) +(declare-const _x58 _x0) +(declare-datatype _x176 ( par ( _x178 ) ( (_x186 (_x185 _x178)) (_x184 (_x180 _x0)))) ) +(assert (let ((_let0 ((_ update _x185) (_x184 _x58) _x58)))(distinct _let0 _let0))) +(check-sat) diff --git a/test/regress/regress0/datatypes/proj-issue172.smt2 b/test/regress/regress0/datatypes/proj-issue172.smt2 new file mode 100644 index 000000000..f9f5a2ffc --- /dev/null +++ b/test/regress/regress0/datatypes/proj-issue172.smt2 @@ -0,0 +1,7 @@ +(set-logic ALL) +(set-info :status sat) +(declare-codatatypes ((a 0)) (((b (c Int) (d a))))) +(declare-fun e () a) +(declare-fun f () a) +(assert (= e f)) +(check-sat) diff --git a/test/regress/regress0/difficulty-model-ex.smt2 b/test/regress/regress0/difficulty-model-ex.smt2 new file mode 100644 index 000000000..0546b5118 --- /dev/null +++ b/test/regress/regress0/difficulty-model-ex.smt2 @@ -0,0 +1,22 @@ +; COMMAND-LINE: --produce-difficulty --difficulty-mode=model-check +; SCRUBBER: sed 's/.*//g' +; EXIT: 0 + +(set-logic ALL) +(set-option :produce-difficulty true) +(declare-fun P (Int) Bool) +(declare-fun x () Int) +(declare-fun y () Int) +(declare-fun z () Int) + +(assert (= z 78)) + +(assert (! (= (* x x) z) :named a1)) + +(assert (= y 0)) + +(assert (P y)) + +(check-sat) + +(get-difficulty) diff --git a/test/regress/regress0/difficulty-simple.smt2 b/test/regress/regress0/difficulty-simple.smt2 new file mode 100644 index 000000000..a82a96550 --- /dev/null +++ b/test/regress/regress0/difficulty-simple.smt2 @@ -0,0 +1,16 @@ +; COMMAND-LINE: --produce-difficulty +; SCRUBBER: sed 's/.*//g' +; EXIT: 0 + +(set-logic ALL) +(set-option :produce-difficulty true) +(declare-fun a () Int) +(declare-fun b () Int) +(declare-fun c () Int) + +(assert (or (> a 0) (> b 0) (> c 0))) + +(assert (< (ite (> a b) a b) 0)) + +(check-sat) +(get-difficulty) diff --git a/test/regress/regress0/options/didyoumean.smt2 b/test/regress/regress0/options/didyoumean.smt2 index d95c1bde9..100e1e6fb 100644 --- a/test/regress/regress0/options/didyoumean.smt2 +++ b/test/regress/regress0/options/didyoumean.smt2 @@ -1,3 +1,4 @@ +; REQUIRES: no-competition ; COMMAND-LINE: --input-agnuage ; ERROR-SCRUBBER: grep -o "--[a-zA-Z-]+" ; ERROR-EXPECT: --input-language diff --git a/test/regress/regress0/options/named_muted.smt2 b/test/regress/regress0/options/named_muted.smt2 new file mode 100644 index 000000000..7026298c6 --- /dev/null +++ b/test/regress/regress0/options/named_muted.smt2 @@ -0,0 +1,6 @@ +; COMMAND-LINE: --print-success +; EXPECT: success +; EXPECT: success + +(set-logic UF) +(assert (! true :named t)) diff --git a/test/regress/regress0/sygus/incremental-modify-ex.sy b/test/regress/regress0/sygus/incremental-modify-ex.sy new file mode 100644 index 000000000..f453964b0 --- /dev/null +++ b/test/regress/regress0/sygus/incremental-modify-ex.sy @@ -0,0 +1,26 @@ +; COMMAND-LINE: -i --sygus-out=status +;EXPECT: unsat +;EXPECT: unsat +(set-logic LIA) + +(synth-fun f ((x Int) (y Int)) Int + ((Start Int) (StartBool Bool)) + ((Start Int (0 1 x y + (+ Start Start) + (- Start Start) + (ite StartBool Start Start))) + (StartBool Bool ((and StartBool StartBool) + (not StartBool) + (<= Start Start))))) + + +(declare-var x Int) +(declare-var y Int) + +(push 1) +(constraint (>= (f x y) 0)) +(check-synth) +(pop 1) + +(constraint (< (f x y) 0)) +(check-synth) diff --git a/test/regress/regress1/bags/card1.smt2 b/test/regress/regress1/bags/card1.smt2 index 4ea5488d2..3b19fb2cf 100644 --- a/test/regress/regress1/bags/card1.smt2 +++ b/test/regress/regress1/bags/card1.smt2 @@ -1,7 +1,8 @@ -; COMMAND-LINE: --fmf-bound --uf-lazy-ll -; EXPECT: sat -(set-logic HO_ALL) -(define-fun f ((x String)) Int 1) +(set-logic ALL) +(set-option :fmf-bound true) +(set-option :produce-models true) +(set-info :status sat) (declare-fun A () (Bag String)) -(assert (= (bag.card A) 20)) +(assert (= (bag.card A) 10000000)) (check-sat) + diff --git a/test/regress/regress1/bags/card2.smt2 b/test/regress/regress1/bags/card2.smt2 new file mode 100644 index 000000000..260c6927f --- /dev/null +++ b/test/regress/regress1/bags/card2.smt2 @@ -0,0 +1,11 @@ +(set-logic ALL) +(set-option :fmf-bound true) +(set-option :produce-models true) +(set-info :status sat) +(declare-fun A () (Bag String)) +(declare-fun B () (Bag String)) +(declare-fun C () (Bag String)) +(assert (distinct A B C (as bag.empty (Bag String)))) +(assert (= C (bag.union_disjoint A B))) +(assert (= (bag.card C) 10000000)) +(check-sat) diff --git a/test/regress/regress1/bags/murxla1.smt2 b/test/regress/regress1/bags/murxla1.smt2 new file mode 100644 index 000000000..248f566f0 --- /dev/null +++ b/test/regress/regress1/bags/murxla1.smt2 @@ -0,0 +1,6 @@ +(set-logic ALL) +(set-option :produce-models true) +(set-info :status sat) +(declare-const A (Bag Bool)) +(declare-const B (Bag Bool)) +(check-sat-assuming ((distinct A B))) diff --git a/test/regress/regress1/bags/murxla2.smt2 b/test/regress/regress1/bags/murxla2.smt2 new file mode 100644 index 000000000..82ca2e90c --- /dev/null +++ b/test/regress/regress1/bags/murxla2.smt2 @@ -0,0 +1,6 @@ +(set-logic ALL) +(set-info :status sat) +(set-option :strings-exp true) +(declare-const x Int) +(assert (seq.contains (seq.at (seq.unit (bag false x)) x) (seq.unit (bag false x)))) +(check-sat) diff --git a/test/regress/regress1/difficulty-polarity.smt2 b/test/regress/regress1/difficulty-polarity.smt2 new file mode 100644 index 000000000..ce2388c54 --- /dev/null +++ b/test/regress/regress1/difficulty-polarity.smt2 @@ -0,0 +1,31 @@ +; COMMAND-LINE: --produce-difficulty +; SCRUBBER: sed 's/.*//g' +; EXIT: 0 + +(set-logic ALL) +(set-option :finite-model-find true) +(set-option :mbqi none) +(set-option :produce-difficulty true) + +(declare-sort U 0) +(declare-fun a () U) +(declare-fun b () U) +(declare-fun c () U) +(assert (distinct a b c)) +(declare-fun P (U U) Bool) +(declare-fun R (U) Bool) +(declare-fun S (U) Bool) + +(define-fun Q () Bool (forall ((x U) (y U)) (P x y))) + +(assert (or (not Q) (S a))) +(assert (R a)) +(assert (=> (R a) Q)) + +; This example will instantiate the quantified formula 9 times, hence the +; explanation for why it is relevant will be incremented by 9. +; The explanation for why Q is relevant should be (=> (R b) Q) and +; not (or (not Q) (S a)), since the former is the reason it is asserted true. + +(check-sat) +(get-difficulty) diff --git a/test/regress/regress1/nl/cos1-tc.smt2 b/test/regress/regress1/nl/cos1-tc.smt2 index bedc0209b..ba49f23fe 100644 --- a/test/regress/regress1/nl/cos1-tc.smt2 +++ b/test/regress/regress1/nl/cos1-tc.smt2 @@ -1,5 +1,5 @@ ; COMMAND-LINE: --nl-ext=full --no-nl-ext-tf-tplanes --no-nl-ext-inc-prec -; EXPECT: unknown +; EXPECT: sat (set-logic UFNRAT) (declare-fun f (Real) Real) diff --git a/test/regress/regress1/proj-issue175.smt2 b/test/regress/regress1/proj-issue175.smt2 new file mode 100644 index 000000000..2df1e21e6 --- /dev/null +++ b/test/regress/regress1/proj-issue175.smt2 @@ -0,0 +1,83 @@ +(set-logic QF_AUFNIA) +(set-info :status sat) +(declare-fun |#offset~STRUCT#?type~INT?length~UINT?off~UINT?data~$Pointer$?input~$Pointer$?comp~$Pointer$#~data| () Int) +(declare-fun |ssl3_accept_#t~mem38_491| () Int) +(declare-fun |#offset~STRUCT#?version~INT?type~INT?method~$Pointer$?rbio~$Pointer$?wbio~$Pointer$?bbio~$Pointer$?rwstate~INT?in_handshake~INT?handshake_func~$Pointer$?server~INT?new_session~INT?quiet_shutdown~INT?shutdown~INT?state~INT?rstate~INT?init_buf~$Pointer$?init_num~INT?init_off~INT?packet~$Pointer$?packet_length~UINT?s2~$Pointer$?s3~$Pointer$?read_ahead~INT?hit~INT?purpose~INT?trust~INT?cipher_list~$Pointer$?cipher_list_by_id~$Pointer$?enc_read_ctx~$Pointer$?read_hash~$Pointer$?expand~$Pointer$?enc_write_ctx~$Pointer$?write_hash~$Pointer$?compress~$Pointer$?cert~$Pointer$?sid_ctx_length~UINT?sid_ctx~ARRAY#_32_~UCHAR#?session~$Pointer$?verify_mode~INT?verify_depth~INT?verify_callback~$Pointer$?info_callback~$Pointer$?error~INT?error_code~INT?ctx~$Pointer$?debug~INT?verify_result~LONG?ex_data~~CRYPTO_EX_DATA?client_CA~$Pointer$?references~INT?options~ULONG?mode~ULONG?first_packet~INT?client_version~INT#~state| () Int) +(declare-fun ssl3_accept_~s.offset_12 () Int) +(declare-fun ssl3_accept_~s.base_12 () Int) +(declare-fun |#memory_int_136| () (Array Int (Array Int Int))) +(declare-fun |ssl3_accept_#t~mem35_173| () Int) +(declare-fun |ssl3_accept_#t~mem49_513| () Int) +(declare-fun |ssl3_accept_#t~mem29_161| () Int) +(declare-fun |#memory_int_53| () (Array Int (Array Int Int))) +(declare-fun |ssl3_accept_#t~mem24_68| () Int) +(declare-fun |#memory_int_601| () (Array Int (Array Int Int))) +(declare-fun |ssl3_accept_#t~mem31_631| () Int) +(declare-fun |#offset~STRUCT#?version~INT?type~INT?method~$Pointer$?rbio~$Pointer$?wbio~$Pointer$?bbio~$Pointer$?rwstate~INT?in_handshake~INT?handshake_func~$Pointer$?server~INT?new_session~INT?quiet_shutdown~INT?shutdown~INT?state~INT?rstate~INT?init_buf~$Pointer$?init_num~INT?init_off~INT?packet~$Pointer$?packet_length~UINT?s2~$Pointer$?s3~$Pointer$?read_ahead~INT?hit~INT?purpose~INT?trust~INT?cipher_list~$Pointer$?cipher_list_by_id~$Pointer$?enc_read_ctx~$Pointer$?read_hash~$Pointer$?expand~$Pointer$?enc_write_ctx~$Pointer$?write_hash~$Pointer$?compress~$Pointer$?cert~$Pointer$?sid_ctx_length~UINT?sid_ctx~ARRAY#_32_~UCHAR#?session~$Pointer$?verify_mode~INT?verify_depth~INT?verify_callback~$Pointer$?info_callback~$Pointer$?error~INT?error_code~INT?ctx~$Pointer$?debug~INT?verify_result~LONG?ex_data~~CRYPTO_EX_DATA?client_CA~$Pointer$?references~INT?options~ULONG?mode~ULONG?first_packet~INT?client_version~INT#~init_num| () Int) +(declare-fun |#memory_$Pointer$.base_53| () (Array Int (Array Int Int))) +(declare-fun |#memory_$Pointer$.base_52| () (Array Int (Array Int Int))) +(declare-fun |ssl3_accept_#t~nondet159_515| () Int) +(declare-fun ssl3_accept_~ret~10_753 () Int) +(declare-fun ssl3_accept_~ret~10_314 () Int) +(declare-fun |ssl3_accept_#t~mem22_459| () Int) +(declare-fun |#offset~STRUCT#?version~INT?type~INT?method~$Pointer$?rbio~$Pointer$?wbio~$Pointer$?bbio~$Pointer$?rwstate~INT?in_handshake~INT?handshake_func~$Pointer$?server~INT?new_session~INT?quiet_shutdown~INT?shutdown~INT?state~INT?rstate~INT?init_buf~$Pointer$?init_num~INT?init_off~INT?packet~$Pointer$?packet_length~UINT?s2~$Pointer$?s3~$Pointer$?read_ahead~INT?hit~INT?purpose~INT?trust~INT?cipher_list~$Pointer$?cipher_list_by_id~$Pointer$?enc_read_ctx~$Pointer$?read_hash~$Pointer$?expand~$Pointer$?enc_write_ctx~$Pointer$?write_hash~$Pointer$?compress~$Pointer$?cert~$Pointer$?sid_ctx_length~UINT?sid_ctx~ARRAY#_32_~UCHAR#?session~$Pointer$?verify_mode~INT?verify_depth~INT?verify_callback~$Pointer$?info_callback~$Pointer$?error~INT?error_code~INT?ctx~$Pointer$?debug~INT?verify_result~LONG?ex_data~~CRYPTO_EX_DATA?client_CA~$Pointer$?references~INT?options~ULONG?mode~ULONG?first_packet~INT?client_version~INT#~s3| () Int) +(declare-fun |#memory_$Pointer$.offset_521| () (Array Int (Array Int Int))) +(declare-fun |ssl3_accept_#t~mem165.offset_593| () Int) +(declare-fun |ssl3_accept_#t~mem23_461| () Int) +(declare-fun |#offset~STRUCT#?version~INT?type~INT?method~$Pointer$?rbio~$Pointer$?wbio~$Pointer$?bbio~$Pointer$?rwstate~INT?in_handshake~INT?handshake_func~$Pointer$?server~INT?new_session~INT?quiet_shutdown~INT?shutdown~INT?state~INT?rstate~INT?init_buf~$Pointer$?init_num~INT?init_off~INT?packet~$Pointer$?packet_length~UINT?s2~$Pointer$?s3~$Pointer$?read_ahead~INT?hit~INT?purpose~INT?trust~INT?cipher_list~$Pointer$?cipher_list_by_id~$Pointer$?enc_read_ctx~$Pointer$?read_hash~$Pointer$?expand~$Pointer$?enc_write_ctx~$Pointer$?write_hash~$Pointer$?compress~$Pointer$?cert~$Pointer$?sid_ctx_length~UINT?sid_ctx~ARRAY#_32_~UCHAR#?session~$Pointer$?verify_mode~INT?verify_depth~INT?verify_callback~$Pointer$?info_callback~$Pointer$?error~INT?error_code~INT?ctx~$Pointer$?debug~INT?verify_result~LONG?ex_data~~CRYPTO_EX_DATA?client_CA~$Pointer$?references~INT?options~ULONG?mode~ULONG?first_packet~INT?client_version~INT#~packet| () Int) +(assert + (let (($x220 (= |#offset~STRUCT#?type~INT?length~UINT?off~UINT?data~$Pointer$?input~$Pointer$?comp~$Pointer$#~data| 12))) + (let (($x2621 (= |ssl3_accept_#t~mem38_491| 8544))) + (let (($x2622 (not $x2621))) + (let (($x10875 (not $x2622))) + (let (($x23085 (and $x10875 $x220))) + (not $x23085))))))) +(assert + (let ((?x806 (+ ssl3_accept_~s.offset_12 |#offset~STRUCT#?version~INT?type~INT?method~$Pointer$?rbio~$Pointer$?wbio~$Pointer$?bbio~$Pointer$?rwstate~INT?in_handshake~INT?handshake_func~$Pointer$?server~INT?new_session~INT?quiet_shutdown~INT?shutdown~INT?state~INT?rstate~INT?init_buf~$Pointer$?init_num~INT?init_off~INT?packet~$Pointer$?packet_length~UINT?s2~$Pointer$?s3~$Pointer$?read_ahead~INT?hit~INT?purpose~INT?trust~INT?cipher_list~$Pointer$?cipher_list_by_id~$Pointer$?enc_read_ctx~$Pointer$?read_hash~$Pointer$?expand~$Pointer$?enc_write_ctx~$Pointer$?write_hash~$Pointer$?compress~$Pointer$?cert~$Pointer$?sid_ctx_length~UINT?sid_ctx~ARRAY#_32_~UCHAR#?session~$Pointer$?verify_mode~INT?verify_depth~INT?verify_callback~$Pointer$?info_callback~$Pointer$?error~INT?error_code~INT?ctx~$Pointer$?debug~INT?verify_result~LONG?ex_data~~CRYPTO_EX_DATA?client_CA~$Pointer$?references~INT?options~ULONG?mode~ULONG?first_packet~INT?client_version~INT#~state|))) + (let ((?x1399 (select |#memory_int_136| ssl3_accept_~s.base_12))) + (let ((?x1400 (select ?x1399 ?x806))) + (let (($x1478 (>= |ssl3_accept_#t~mem35_173| ?x1400))) + (not $x1478)))))) +(assert + (let (($x2678 (>= |ssl3_accept_#t~mem49_513| 8640))) + (not $x2678))) +(assert + (let ((?x806 (+ ssl3_accept_~s.offset_12 |#offset~STRUCT#?version~INT?type~INT?method~$Pointer$?rbio~$Pointer$?wbio~$Pointer$?bbio~$Pointer$?rwstate~INT?in_handshake~INT?handshake_func~$Pointer$?server~INT?new_session~INT?quiet_shutdown~INT?shutdown~INT?state~INT?rstate~INT?init_buf~$Pointer$?init_num~INT?init_off~INT?packet~$Pointer$?packet_length~UINT?s2~$Pointer$?s3~$Pointer$?read_ahead~INT?hit~INT?purpose~INT?trust~INT?cipher_list~$Pointer$?cipher_list_by_id~$Pointer$?enc_read_ctx~$Pointer$?read_hash~$Pointer$?expand~$Pointer$?enc_write_ctx~$Pointer$?write_hash~$Pointer$?compress~$Pointer$?cert~$Pointer$?sid_ctx_length~UINT?sid_ctx~ARRAY#_32_~UCHAR#?session~$Pointer$?verify_mode~INT?verify_depth~INT?verify_callback~$Pointer$?info_callback~$Pointer$?error~INT?error_code~INT?ctx~$Pointer$?debug~INT?verify_result~LONG?ex_data~~CRYPTO_EX_DATA?client_CA~$Pointer$?references~INT?options~ULONG?mode~ULONG?first_packet~INT?client_version~INT#~state|))) + (let ((?x1399 (select |#memory_int_136| ssl3_accept_~s.base_12))) + (let ((?x1400 (select ?x1399 ?x806))) + (let (($x1447 (<= |ssl3_accept_#t~mem29_161| ?x1400))) + (let ((?x1089 (select |#memory_int_53| ssl3_accept_~s.base_12))) + (let ((?x1090 (select ?x1089 ?x806))) + (let (($x1113 (>= |ssl3_accept_#t~mem24_68| ?x1090))) + (let (($x19982 (and $x1113 $x1447))) + (not $x19982)))))))))) +(assert + (let ((?x806 (+ ssl3_accept_~s.offset_12 |#offset~STRUCT#?version~INT?type~INT?method~$Pointer$?rbio~$Pointer$?wbio~$Pointer$?bbio~$Pointer$?rwstate~INT?in_handshake~INT?handshake_func~$Pointer$?server~INT?new_session~INT?quiet_shutdown~INT?shutdown~INT?state~INT?rstate~INT?init_buf~$Pointer$?init_num~INT?init_off~INT?packet~$Pointer$?packet_length~UINT?s2~$Pointer$?s3~$Pointer$?read_ahead~INT?hit~INT?purpose~INT?trust~INT?cipher_list~$Pointer$?cipher_list_by_id~$Pointer$?enc_read_ctx~$Pointer$?read_hash~$Pointer$?expand~$Pointer$?enc_write_ctx~$Pointer$?write_hash~$Pointer$?compress~$Pointer$?cert~$Pointer$?sid_ctx_length~UINT?sid_ctx~ARRAY#_32_~UCHAR#?session~$Pointer$?verify_mode~INT?verify_depth~INT?verify_callback~$Pointer$?info_callback~$Pointer$?error~INT?error_code~INT?ctx~$Pointer$?debug~INT?verify_result~LONG?ex_data~~CRYPTO_EX_DATA?client_CA~$Pointer$?references~INT?options~ULONG?mode~ULONG?first_packet~INT?client_version~INT#~state|))) + (let ((?x3029 (select |#memory_int_601| ssl3_accept_~s.base_12))) + (let ((?x3030 (select ?x3029 ?x806))) + (let (($x3088 (>= |ssl3_accept_#t~mem31_631| ?x3030))) + (let ((?x1050 (+ ssl3_accept_~s.offset_12 |#offset~STRUCT#?version~INT?type~INT?method~$Pointer$?rbio~$Pointer$?wbio~$Pointer$?bbio~$Pointer$?rwstate~INT?in_handshake~INT?handshake_func~$Pointer$?server~INT?new_session~INT?quiet_shutdown~INT?shutdown~INT?state~INT?rstate~INT?init_buf~$Pointer$?init_num~INT?init_off~INT?packet~$Pointer$?packet_length~UINT?s2~$Pointer$?s3~$Pointer$?read_ahead~INT?hit~INT?purpose~INT?trust~INT?cipher_list~$Pointer$?cipher_list_by_id~$Pointer$?enc_read_ctx~$Pointer$?read_hash~$Pointer$?expand~$Pointer$?enc_write_ctx~$Pointer$?write_hash~$Pointer$?compress~$Pointer$?cert~$Pointer$?sid_ctx_length~UINT?sid_ctx~ARRAY#_32_~UCHAR#?session~$Pointer$?verify_mode~INT?verify_depth~INT?verify_callback~$Pointer$?info_callback~$Pointer$?error~INT?error_code~INT?ctx~$Pointer$?debug~INT?verify_result~LONG?ex_data~~CRYPTO_EX_DATA?client_CA~$Pointer$?references~INT?options~ULONG?mode~ULONG?first_packet~INT?client_version~INT#~init_num|))) + (let ((?x1051 (select |#memory_$Pointer$.base_53| ssl3_accept_~s.base_12))) + (let ((?x1032 (select |#memory_$Pointer$.base_52| ssl3_accept_~s.base_12))) + (let ((?x1054 (store |#memory_$Pointer$.base_52| ssl3_accept_~s.base_12 (store ?x1032 ?x1050 (select ?x1051 ?x1050))))) + (let (($x1055 (= |#memory_$Pointer$.base_53| ?x1054))) + (let (($x11490 (and $x1055 $x3088))) + (not $x11490)))))))))))) +(assert + (let (($x3458 (>= ssl3_accept_~ret~10_753 |ssl3_accept_#t~nondet159_515|))) + (let (($x2065 (not (<= ssl3_accept_~ret~10_314 0)))) + (let (($x50182 (and $x2065 $x3458))) + (not $x50182))))) +(assert + (let (($x2542 (not (= |ssl3_accept_#t~mem22_459| 16384)))) + (let ((?x1068 (+ ssl3_accept_~s.offset_12 |#offset~STRUCT#?version~INT?type~INT?method~$Pointer$?rbio~$Pointer$?wbio~$Pointer$?bbio~$Pointer$?rwstate~INT?in_handshake~INT?handshake_func~$Pointer$?server~INT?new_session~INT?quiet_shutdown~INT?shutdown~INT?state~INT?rstate~INT?init_buf~$Pointer$?init_num~INT?init_off~INT?packet~$Pointer$?packet_length~UINT?s2~$Pointer$?s3~$Pointer$?read_ahead~INT?hit~INT?purpose~INT?trust~INT?cipher_list~$Pointer$?cipher_list_by_id~$Pointer$?enc_read_ctx~$Pointer$?read_hash~$Pointer$?expand~$Pointer$?enc_write_ctx~$Pointer$?write_hash~$Pointer$?compress~$Pointer$?cert~$Pointer$?sid_ctx_length~UINT?sid_ctx~ARRAY#_32_~UCHAR#?session~$Pointer$?verify_mode~INT?verify_depth~INT?verify_callback~$Pointer$?info_callback~$Pointer$?error~INT?error_code~INT?ctx~$Pointer$?debug~INT?verify_result~LONG?ex_data~~CRYPTO_EX_DATA?client_CA~$Pointer$?references~INT?options~ULONG?mode~ULONG?first_packet~INT?client_version~INT#~s3|))) + (let ((?x2719 (select |#memory_$Pointer$.offset_521| ssl3_accept_~s.base_12))) + (let ((?x2734 (select ?x2719 ?x1068))) + (let (($x2925 (<= |ssl3_accept_#t~mem165.offset_593| ?x2734))) + (and $x2925 $x2542))))))) +(assert + (let (($x2547 (not (= |ssl3_accept_#t~mem23_461| 8192)))) + (let (($x73 (= |#offset~STRUCT#?version~INT?type~INT?method~$Pointer$?rbio~$Pointer$?wbio~$Pointer$?bbio~$Pointer$?rwstate~INT?in_handshake~INT?handshake_func~$Pointer$?server~INT?new_session~INT?quiet_shutdown~INT?shutdown~INT?state~INT?rstate~INT?init_buf~$Pointer$?init_num~INT?init_off~INT?packet~$Pointer$?packet_length~UINT?s2~$Pointer$?s3~$Pointer$?read_ahead~INT?hit~INT?purpose~INT?trust~INT?cipher_list~$Pointer$?cipher_list_by_id~$Pointer$?enc_read_ctx~$Pointer$?read_hash~$Pointer$?expand~$Pointer$?enc_write_ctx~$Pointer$?write_hash~$Pointer$?compress~$Pointer$?cert~$Pointer$?sid_ctx_length~UINT?sid_ctx~ARRAY#_32_~UCHAR#?session~$Pointer$?verify_mode~INT?verify_depth~INT?verify_callback~$Pointer$?info_callback~$Pointer$?error~INT?error_code~INT?ctx~$Pointer$?debug~INT?verify_result~LONG?ex_data~~CRYPTO_EX_DATA?client_CA~$Pointer$?references~INT?options~ULONG?mode~ULONG?first_packet~INT?client_version~INT#~packet| 72))) + (let (($x11452 (and $x73 $x2547))) + (not $x11452))))) +(check-sat) diff --git a/test/regress/regress1/sets/proj-issue164.smt2 b/test/regress/regress1/sets/proj-issue164.smt2 new file mode 100644 index 000000000..5e343156e --- /dev/null +++ b/test/regress/regress1/sets/proj-issue164.smt2 @@ -0,0 +1,10 @@ +(set-logic ALL) +(set-info :status sat) +(declare-fun b () (Set String)) +(declare-fun c () (Set (Tuple Int Int))) +(declare-fun d () (Set (Tuple Int Int))) +(declare-fun e () Int) +(assert (distinct c (set.insert (tuple 0 0) (set.singleton (tuple 1 1))))) +(assert (distinct d (rel.tclosure c))) +(assert (distinct e (set.card b))) +(check-sat) diff --git a/test/regress/regress1/sets/proj-issue178.smt2 b/test/regress/regress1/sets/proj-issue178.smt2 new file mode 100644 index 000000000..2b95f43c9 --- /dev/null +++ b/test/regress/regress1/sets/proj-issue178.smt2 @@ -0,0 +1,10 @@ +(set-logic ALL) +(set-info :status sat) +(set-option :sygus-inference true) +(set-option :sets-infer-as-lemmas false) +(declare-fun a () (Set Int)) +(declare-fun b () (Set Int)) +(declare-fun c () (Set Int)) +(declare-fun d () Int) +(assert (> (set.card (set.minus a (set.inter (set.minus a b) (set.minus a c)))) d)) +(check-sat) diff --git a/test/regress/regress1/sygus/proj-issue181.smt2 b/test/regress/regress1/sygus/proj-issue181.smt2 new file mode 100644 index 000000000..656d1e757 --- /dev/null +++ b/test/regress/regress1/sygus/proj-issue181.smt2 @@ -0,0 +1,8 @@ +(set-logic ALL) +(set-option :sygus-inference true) +(set-info :status sat) +(declare-fun a (Int) Int) +(assert (exists ((b Int)) (distinct (a b) (- b 29)))) +(assert (distinct (a 0) (- 4))) +(assert (= (a (- 99)) (- 107))) +(check-sat) diff --git a/test/regress/regress1/sygus/proj-issue183.smt2 b/test/regress/regress1/sygus/proj-issue183.smt2 new file mode 100644 index 000000000..e50e035f3 --- /dev/null +++ b/test/regress/regress1/sygus/proj-issue183.smt2 @@ -0,0 +1,20 @@ +; COMMAND-LINE: --strings-exp +; EXPECT: sat +(set-logic ALL) +(set-option :sygus-inference true) +(set-info :status sat) +(declare-fun a () String) +(declare-fun b () String) +(declare-const c String) +(declare-const d String) +(declare-fun g () Bool) +(declare-fun e () Bool) +(declare-fun f () String) +(assert (str.in_re (str.substr a 0 (str.len (str.substr a 0 (str.len (str.substr a 0 (str.len c)))))) (re.* (re.++ (str.to_re "") (re.* (str.to_re "aa")))))) +(assert (str.in_re (str.substr b 0 (str.len d)) (re.* (re.++ (re.* (str.to_re "")) (str.to_re "bb"))))) +(assert (= 4 (str.len d))) +(assert (not (= (str.substr a 0 (str.len c)) d))) +(assert (= g (not (= "file" (str.substr a (str.len c) (str.len f)))))) +(assert (= e (not g))) +(assert e) +(check-sat) diff --git a/test/regress/regress1/sygus/proj-issue185.smt2 b/test/regress/regress1/sygus/proj-issue185.smt2 new file mode 100644 index 000000000..a3e4b8205 --- /dev/null +++ b/test/regress/regress1/sygus/proj-issue185.smt2 @@ -0,0 +1,12 @@ +; COMMAND-LINE: -q +; EXPECT: unsat +(set-logic ALL) +(set-option :sygus-inference true) +(set-info :status unsat) +(declare-codatatypes ((a 0)) (((b (c Int) (d a))))) +(declare-fun e () a) +(declare-fun f () a) +(assert (= e (b 0 (b 0 e)))) +(assert (distinct f (b 0 f))) +(assert (not (distinct e f))) +(check-sat) diff --git a/test/regress/regress2/bv_to_int2.smt2 b/test/regress/regress2/bv_to_int2.smt2 index 424e95b27..b9c27c6b8 100644 --- a/test/regress/regress2/bv_to_int2.smt2 +++ b/test/regress/regress2/bv_to_int2.smt2 @@ -1,4 +1,5 @@ ; COMMAND-LINE: --solve-bv-as-int=sum --bvand-integer-granularity=1 +; COMMAND-LINE: --solve-bv-as-int=bitwise --bvand-integer-granularity=1 ; EXPECT: sat (set-logic QF_BV) (declare-fun a () (_ BitVec 8)) diff --git a/test/regress/regress2/bv_to_int_ashr.smt2 b/test/regress/regress2/bv_to_int_ashr.smt2 index 0c6768546..1f5df2c31 100644 --- a/test/regress/regress2/bv_to_int_ashr.smt2 +++ b/test/regress/regress2/bv_to_int_ashr.smt2 @@ -1,4 +1,5 @@ ; COMMAND-LINE: --solve-bv-as-int=sum --bvand-integer-granularity=1 +; COMMAND-LINE: --solve-bv-as-int=bitwise --bvand-integer-granularity=1 ; EXPECT: unsat (set-logic QF_BV) (declare-fun a () (_ BitVec 8)) diff --git a/test/regress/regress2/bv_to_int_bitwise.smt2 b/test/regress/regress2/bv_to_int_bitwise.smt2 index 23624e12c..4dc37a94c 100644 --- a/test/regress/regress2/bv_to_int_bitwise.smt2 +++ b/test/regress/regress2/bv_to_int_bitwise.smt2 @@ -1,8 +1,10 @@ -; COMMAND-LINE: --solve-bv-as-int=sum --bvand-integer-granularity=1 -; COMMAND-LINE: --solve-bv-as-int=sum --bvand-integer-granularity=5 -; COMMAND-LINE: --solve-bv-as-int=iand --iand-mode=value -; COMMAND-LINE: --solve-bv-as-int=iand --iand-mode=sum -; COMMAND-LINE: --solve-bv-as-int=bv +; COMMAND-LINE: --solve-bv-as-int=sum --bvand-integer-granularity=1 --no-check-unsat-cores +; COMMAND-LINE: --solve-bv-as-int=bitwise --bvand-integer-granularity=1 --no-check-unsat-cores +; COMMAND-LINE: --solve-bv-as-int=sum --bvand-integer-granularity=5 --no-check-unsat-cores +; COMMAND-LINE: --solve-bv-as-int=bitwise --bvand-integer-granularity=5 --no-check-unsat-cores +; COMMAND-LINE: --solve-bv-as-int=iand --iand-mode=value --no-check-unsat-cores +; COMMAND-LINE: --solve-bv-as-int=iand --iand-mode=sum --no-check-unsat-cores +; COMMAND-LINE: --solve-bv-as-int=bv --no-check-unsat-cores ; EXPECT: unsat (set-logic QF_BV) (declare-fun s () (_ BitVec 4)) diff --git a/test/regress/regress2/bv_to_int_bvmul1.smt2 b/test/regress/regress2/bv_to_int_bvmul1.smt2 index 232959f33..bf6f2cfc4 100644 --- a/test/regress/regress2/bv_to_int_bvmul1.smt2 +++ b/test/regress/regress2/bv_to_int_bvmul1.smt2 @@ -1,4 +1,5 @@ ; COMMAND-LINE: --solve-bv-as-int=sum --bvand-integer-granularity=1 +; COMMAND-LINE: --solve-bv-as-int=bitwise --bvand-integer-granularity=1 ; EXPECT: sat (set-logic QF_BV) (declare-fun a () (_ BitVec 8)) diff --git a/test/regress/regress2/bv_to_int_bvuf_to_intuf_smtlib.smt2 b/test/regress/regress2/bv_to_int_bvuf_to_intuf_smtlib.smt2 index babf9af32..2ecd0fe6c 100644 --- a/test/regress/regress2/bv_to_int_bvuf_to_intuf_smtlib.smt2 +++ b/test/regress/regress2/bv_to_int_bvuf_to_intuf_smtlib.smt2 @@ -1,4 +1,5 @@ -;COMMAND-LINE: --solve-bv-as-int=sum --bvand-integer-granularity=1 --no-produce-unsat-cores +;COMMAND-LINE: --solve-bv-as-int=sum --bvand-integer-granularity=1 --no-check-unsat-cores +;COMMAND-LINE: --solve-bv-as-int=bitwise --bvand-integer-granularity=1 --no-check-unsat-cores ;EXPECT: unsat (set-logic QF_UFBV) (declare-fun z$n0s32 () (_ BitVec 32)) diff --git a/test/regress/regress2/bv_to_int_inc1.smt2 b/test/regress/regress2/bv_to_int_inc1.smt2 index 4b22c8ed8..28fb86f76 100644 --- a/test/regress/regress2/bv_to_int_inc1.smt2 +++ b/test/regress/regress2/bv_to_int_inc1.smt2 @@ -1,4 +1,5 @@ ; COMMAND-LINE: --incremental --solve-bv-as-int=sum +; COMMAND-LINE: --incremental --solve-bv-as-int=bitwise ; COMMAND-LINE: --incremental --solve-bv-as-int=iand ; COMMAND-LINE: --incremental --solve-bv-as-int=bv ; EXPECT sat diff --git a/test/regress/regress2/bv_to_int_mask_array_1.smt2 b/test/regress/regress2/bv_to_int_mask_array_1.smt2 index 3b55c035d..c12138091 100644 --- a/test/regress/regress2/bv_to_int_mask_array_1.smt2 +++ b/test/regress/regress2/bv_to_int_mask_array_1.smt2 @@ -1,5 +1,6 @@ -; COMMAND-LINE: --solve-bv-as-int=sum --bvand-integer-granularity=1 -; COMMAND-LINE: --solve-bv-as-int=iand --iand-mode=value +; COMMAND-LINE: --solve-bv-as-int=sum --bvand-integer-granularity=1 --no-check-unsat-cores +; COMMAND-LINE: --solve-bv-as-int=bitwise --bvand-integer-granularity=1 --no-check-unsat-cores +; COMMAND-LINE: --solve-bv-as-int=iand --iand-mode=value --no-check-unsat-cores ; COMMAND-LINE: --solve-bv-as-int=iand --iand-mode=sum --no-check-unsat-cores ; COMMAND-LINE: --solve-bv-as-int=bv --no-check-unsat-cores ; EXPECT: unsat diff --git a/test/regress/regress2/bv_to_int_mask_array_2.smt2 b/test/regress/regress2/bv_to_int_mask_array_2.smt2 index edcc14149..17a113f85 100644 --- a/test/regress/regress2/bv_to_int_mask_array_2.smt2 +++ b/test/regress/regress2/bv_to_int_mask_array_2.smt2 @@ -1,4 +1,5 @@ ; COMMAND-LINE: --solve-bv-as-int=sum --bvand-integer-granularity=1 +; COMMAND-LINE: --solve-bv-as-int=bitwise --bvand-integer-granularity=1 ; COMMAND-LINE: --solve-bv-as-int=iand --iand-mode=value ; COMMAND-LINE: --solve-bv-as-int=iand --iand-mode=sum ; COMMAND-LINE: --solve-bv-as-int=bv diff --git a/test/regress/regress2/bv_to_int_mask_array_3.smt2 b/test/regress/regress2/bv_to_int_mask_array_3.smt2 index 74e5ca95a..2b411209d 100644 --- a/test/regress/regress2/bv_to_int_mask_array_3.smt2 +++ b/test/regress/regress2/bv_to_int_mask_array_3.smt2 @@ -1,4 +1,5 @@ ; COMMAND-LINE: --solve-bv-as-int=sum --bvand-integer-granularity=1 +; COMMAND-LINE: --solve-bv-as-int=bitwise --bvand-integer-granularity=1 ; EXPECT: sat (set-logic ALL) (declare-fun A () (Array (_ BitVec 4) (_ BitVec 4))) diff --git a/test/regress/regress2/bv_to_int_quantifiers_bvand.smt2 b/test/regress/regress2/bv_to_int_quantifiers_bvand.smt2 new file mode 100644 index 000000000..d454ad630 --- /dev/null +++ b/test/regress/regress2/bv_to_int_quantifiers_bvand.smt2 @@ -0,0 +1,9 @@ +; COMMAND-LINE: --solve-bv-as-int=bitwise --bvand-integer-granularity=1 --no-check-unsat-cores +; EXPECT: (error "Error in option parsing: --solve-bv-as-int=bitwise does not support quantifiers") +; EXIT: 1 +(set-logic BV) +(declare-const x (_ BitVec 8)) +(assert (forall ((y (_ BitVec 8))) + (distinct #b00000000 + (bvand x y)))) +(check-sat) diff --git a/test/regress/regress2/bv_to_int_shifts.smt2 b/test/regress/regress2/bv_to_int_shifts.smt2 index bcc31c38c..173f1a552 100644 --- a/test/regress/regress2/bv_to_int_shifts.smt2 +++ b/test/regress/regress2/bv_to_int_shifts.smt2 @@ -1,4 +1,5 @@ ; COMMAND-LINE: --solve-bv-as-int=sum --bvand-integer-granularity=1 +; COMMAND-LINE: --solve-bv-as-int=bitwise --bvand-integer-granularity=1 ; EXPECT: sat (set-logic QF_BV) (declare-fun s () (_ BitVec 4)) diff --git a/test/regress/regress2/strings/strings-alpha-card-129.smt2 b/test/regress/regress2/strings/strings-alpha-card-129.smt2 deleted file mode 100644 index c0b4ae0a2..000000000 --- a/test/regress/regress2/strings/strings-alpha-card-129.smt2 +++ /dev/null @@ -1,393 +0,0 @@ -; COMMAND-LINE: --strings-alpha-card=128 --simplification=none -; EXPECT: unsat -(set-logic QF_SLIA) -(declare-fun s1 () String) -(assert (= (str.len s1) 1)) -(declare-fun s2 () String) -(assert (= (str.len s2) 1)) -(declare-fun s3 () String) -(assert (= (str.len s3) 1)) -(declare-fun s4 () String) -(assert (= (str.len s4) 1)) -(declare-fun s5 () String) -(assert (= (str.len s5) 1)) -(declare-fun s6 () String) -(assert (= (str.len s6) 1)) -(declare-fun s7 () String) -(assert (= (str.len s7) 1)) -(declare-fun s8 () String) -(assert (= (str.len s8) 1)) -(declare-fun s9 () String) -(assert (= (str.len s9) 1)) -(declare-fun s10 () String) -(assert (= (str.len s10) 1)) -(declare-fun s11 () String) -(assert (= (str.len s11) 1)) -(declare-fun s12 () String) -(assert (= (str.len s12) 1)) -(declare-fun s13 () String) -(assert (= (str.len s13) 1)) -(declare-fun s14 () String) -(assert (= (str.len s14) 1)) -(declare-fun s15 () String) -(assert (= (str.len s15) 1)) -(declare-fun s16 () String) -(assert (= (str.len s16) 1)) -(declare-fun s17 () String) -(assert (= (str.len s17) 1)) -(declare-fun s18 () String) -(assert (= (str.len s18) 1)) -(declare-fun s19 () String) -(assert (= (str.len s19) 1)) -(declare-fun s20 () String) -(assert (= (str.len s20) 1)) -(declare-fun s21 () String) -(assert (= (str.len s21) 1)) -(declare-fun s22 () String) -(assert (= (str.len s22) 1)) -(declare-fun s23 () String) -(assert (= (str.len s23) 1)) -(declare-fun s24 () String) -(assert (= (str.len s24) 1)) -(declare-fun s25 () String) -(assert (= (str.len s25) 1)) -(declare-fun s26 () String) -(assert (= (str.len s26) 1)) -(declare-fun s27 () String) -(assert (= (str.len s27) 1)) -(declare-fun s28 () String) -(assert (= (str.len s28) 1)) -(declare-fun s29 () String) -(assert (= (str.len s29) 1)) -(declare-fun s30 () String) -(assert (= (str.len s30) 1)) -(declare-fun s31 () String) -(assert (= (str.len s31) 1)) -(declare-fun s32 () String) -(assert (= (str.len s32) 1)) -(declare-fun s33 () String) -(assert (= (str.len s33) 1)) -(declare-fun s34 () String) -(assert (= (str.len s34) 1)) -(declare-fun s35 () String) -(assert (= (str.len s35) 1)) -(declare-fun s36 () String) -(assert (= (str.len s36) 1)) -(declare-fun s37 () String) -(assert (= (str.len s37) 1)) -(declare-fun s38 () String) -(assert (= (str.len s38) 1)) -(declare-fun s39 () String) -(assert (= (str.len s39) 1)) -(declare-fun s40 () String) -(assert (= (str.len s40) 1)) -(declare-fun s41 () String) -(assert (= (str.len s41) 1)) -(declare-fun s42 () String) -(assert (= (str.len s42) 1)) -(declare-fun s43 () String) -(assert (= (str.len s43) 1)) -(declare-fun s44 () String) -(assert (= (str.len s44) 1)) -(declare-fun s45 () String) -(assert (= (str.len s45) 1)) -(declare-fun s46 () String) -(assert (= (str.len s46) 1)) -(declare-fun s47 () String) -(assert (= (str.len s47) 1)) -(declare-fun s48 () String) -(assert (= (str.len s48) 1)) -(declare-fun s49 () String) -(assert (= (str.len s49) 1)) -(declare-fun s50 () String) -(assert (= (str.len s50) 1)) -(declare-fun s51 () String) -(assert (= (str.len s51) 1)) -(declare-fun s52 () String) -(assert (= (str.len s52) 1)) -(declare-fun s53 () String) -(assert (= (str.len s53) 1)) -(declare-fun s54 () String) -(assert (= (str.len s54) 1)) -(declare-fun s55 () String) -(assert (= (str.len s55) 1)) -(declare-fun s56 () String) -(assert (= (str.len s56) 1)) -(declare-fun s57 () String) -(assert (= (str.len s57) 1)) -(declare-fun s58 () String) -(assert (= (str.len s58) 1)) -(declare-fun s59 () String) -(assert (= (str.len s59) 1)) -(declare-fun s60 () String) -(assert (= (str.len s60) 1)) -(declare-fun s61 () String) -(assert (= (str.len s61) 1)) -(declare-fun s62 () String) -(assert (= (str.len s62) 1)) -(declare-fun s63 () String) -(assert (= (str.len s63) 1)) -(declare-fun s64 () String) -(assert (= (str.len s64) 1)) -(declare-fun s65 () String) -(assert (= (str.len s65) 1)) -(declare-fun s66 () String) -(assert (= (str.len s66) 1)) -(declare-fun s67 () String) -(assert (= (str.len s67) 1)) -(declare-fun s68 () String) -(assert (= (str.len s68) 1)) -(declare-fun s69 () String) -(assert (= (str.len s69) 1)) -(declare-fun s70 () String) -(assert (= (str.len s70) 1)) -(declare-fun s71 () String) -(assert (= (str.len s71) 1)) -(declare-fun s72 () String) -(assert (= (str.len s72) 1)) -(declare-fun s73 () String) -(assert (= (str.len s73) 1)) -(declare-fun s74 () String) -(assert (= (str.len s74) 1)) -(declare-fun s75 () String) -(assert (= (str.len s75) 1)) -(declare-fun s76 () String) -(assert (= (str.len s76) 1)) -(declare-fun s77 () String) -(assert (= (str.len s77) 1)) -(declare-fun s78 () String) -(assert (= (str.len s78) 1)) -(declare-fun s79 () String) -(assert (= (str.len s79) 1)) -(declare-fun s80 () String) -(assert (= (str.len s80) 1)) -(declare-fun s81 () String) -(assert (= (str.len s81) 1)) -(declare-fun s82 () String) -(assert (= (str.len s82) 1)) -(declare-fun s83 () String) -(assert (= (str.len s83) 1)) -(declare-fun s84 () String) -(assert (= (str.len s84) 1)) -(declare-fun s85 () String) -(assert (= (str.len s85) 1)) -(declare-fun s86 () String) -(assert (= (str.len s86) 1)) -(declare-fun s87 () String) -(assert (= (str.len s87) 1)) -(declare-fun s88 () String) -(assert (= (str.len s88) 1)) -(declare-fun s89 () String) -(assert (= (str.len s89) 1)) -(declare-fun s90 () String) -(assert (= (str.len s90) 1)) -(declare-fun s91 () String) -(assert (= (str.len s91) 1)) -(declare-fun s92 () String) -(assert (= (str.len s92) 1)) -(declare-fun s93 () String) -(assert (= (str.len s93) 1)) -(declare-fun s94 () String) -(assert (= (str.len s94) 1)) -(declare-fun s95 () String) -(assert (= (str.len s95) 1)) -(declare-fun s96 () String) -(assert (= (str.len s96) 1)) -(declare-fun s97 () String) -(assert (= (str.len s97) 1)) -(declare-fun s98 () String) -(assert (= (str.len s98) 1)) -(declare-fun s99 () String) -(assert (= (str.len s99) 1)) -(declare-fun s100 () String) -(assert (= (str.len s100) 1)) -(declare-fun s101 () String) -(assert (= (str.len s101) 1)) -(declare-fun s102 () String) -(assert (= (str.len s102) 1)) -(declare-fun s103 () String) -(assert (= (str.len s103) 1)) -(declare-fun s104 () String) -(assert (= (str.len s104) 1)) -(declare-fun s105 () String) -(assert (= (str.len s105) 1)) -(declare-fun s106 () String) -(assert (= (str.len s106) 1)) -(declare-fun s107 () String) -(assert (= (str.len s107) 1)) -(declare-fun s108 () String) -(assert (= (str.len s108) 1)) -(declare-fun s109 () String) -(assert (= (str.len s109) 1)) -(declare-fun s110 () String) -(assert (= (str.len s110) 1)) -(declare-fun s111 () String) -(assert (= (str.len s111) 1)) -(declare-fun s112 () String) -(assert (= (str.len s112) 1)) -(declare-fun s113 () String) -(assert (= (str.len s113) 1)) -(declare-fun s114 () String) -(assert (= (str.len s114) 1)) -(declare-fun s115 () String) -(assert (= (str.len s115) 1)) -(declare-fun s116 () String) -(assert (= (str.len s116) 1)) -(declare-fun s117 () String) -(assert (= (str.len s117) 1)) -(declare-fun s118 () String) -(assert (= (str.len s118) 1)) -(declare-fun s119 () String) -(assert (= (str.len s119) 1)) -(declare-fun s120 () String) -(assert (= (str.len s120) 1)) -(declare-fun s121 () String) -(assert (= (str.len s121) 1)) -(declare-fun s122 () String) -(assert (= (str.len s122) 1)) -(declare-fun s123 () String) -(assert (= (str.len s123) 1)) -(declare-fun s124 () String) -(assert (= (str.len s124) 1)) -(declare-fun s125 () String) -(assert (= (str.len s125) 1)) -(declare-fun s126 () String) -(assert (= (str.len s126) 1)) -(declare-fun s127 () String) -(assert (= (str.len s127) 1)) -(declare-fun s128 () String) -(assert (= (str.len s128) 1)) -(declare-fun s129 () String) -(assert (= (str.len s129) 1)) -(assert (distinct -s1 -s2 -s3 -s4 -s5 -s6 -s7 -s8 -s9 -s10 -s11 -s12 -s13 -s14 -s15 -s16 -s17 -s18 -s19 -s20 -s21 -s22 -s23 -s24 -s25 -s26 -s27 -s28 -s29 -s30 -s31 -s32 -s33 -s34 -s35 -s36 -s37 -s38 -s39 -s40 -s41 -s42 -s43 -s44 -s45 -s46 -s47 -s48 -s49 -s50 -s51 -s52 -s53 -s54 -s55 -s56 -s57 -s58 -s59 -s60 -s61 -s62 -s63 -s64 -s65 -s66 -s67 -s68 -s69 -s70 -s71 -s72 -s73 -s74 -s75 -s76 -s77 -s78 -s79 -s80 -s81 -s82 -s83 -s84 -s85 -s86 -s87 -s88 -s89 -s90 -s91 -s92 -s93 -s94 -s95 -s96 -s97 -s98 -s99 -s100 -s101 -s102 -s103 -s104 -s105 -s106 -s107 -s108 -s109 -s110 -s111 -s112 -s113 -s114 -s115 -s116 -s117 -s118 -s119 -s120 -s121 -s122 -s123 -s124 -s125 -s126 -s127 -s128 -s129 -)) -(check-sat) diff --git a/test/regress/regress2/strings/strings-alpha-card-65.smt2 b/test/regress/regress2/strings/strings-alpha-card-65.smt2 new file mode 100644 index 000000000..82ab06ea9 --- /dev/null +++ b/test/regress/regress2/strings/strings-alpha-card-65.smt2 @@ -0,0 +1,201 @@ +; COMMAND-LINE: --strings-alpha-card=64 --simplification=none +; EXPECT: unsat +(set-logic QF_SLIA) +(declare-fun s1 () String) +(assert (= (str.len s1) 1)) +(declare-fun s2 () String) +(assert (= (str.len s2) 1)) +(declare-fun s3 () String) +(assert (= (str.len s3) 1)) +(declare-fun s4 () String) +(assert (= (str.len s4) 1)) +(declare-fun s5 () String) +(assert (= (str.len s5) 1)) +(declare-fun s6 () String) +(assert (= (str.len s6) 1)) +(declare-fun s7 () String) +(assert (= (str.len s7) 1)) +(declare-fun s8 () String) +(assert (= (str.len s8) 1)) +(declare-fun s9 () String) +(assert (= (str.len s9) 1)) +(declare-fun s10 () String) +(assert (= (str.len s10) 1)) +(declare-fun s11 () String) +(assert (= (str.len s11) 1)) +(declare-fun s12 () String) +(assert (= (str.len s12) 1)) +(declare-fun s13 () String) +(assert (= (str.len s13) 1)) +(declare-fun s14 () String) +(assert (= (str.len s14) 1)) +(declare-fun s15 () String) +(assert (= (str.len s15) 1)) +(declare-fun s16 () String) +(assert (= (str.len s16) 1)) +(declare-fun s17 () String) +(assert (= (str.len s17) 1)) +(declare-fun s18 () String) +(assert (= (str.len s18) 1)) +(declare-fun s19 () String) +(assert (= (str.len s19) 1)) +(declare-fun s20 () String) +(assert (= (str.len s20) 1)) +(declare-fun s21 () String) +(assert (= (str.len s21) 1)) +(declare-fun s22 () String) +(assert (= (str.len s22) 1)) +(declare-fun s23 () String) +(assert (= (str.len s23) 1)) +(declare-fun s24 () String) +(assert (= (str.len s24) 1)) +(declare-fun s25 () String) +(assert (= (str.len s25) 1)) +(declare-fun s26 () String) +(assert (= (str.len s26) 1)) +(declare-fun s27 () String) +(assert (= (str.len s27) 1)) +(declare-fun s28 () String) +(assert (= (str.len s28) 1)) +(declare-fun s29 () String) +(assert (= (str.len s29) 1)) +(declare-fun s30 () String) +(assert (= (str.len s30) 1)) +(declare-fun s31 () String) +(assert (= (str.len s31) 1)) +(declare-fun s32 () String) +(assert (= (str.len s32) 1)) +(declare-fun s33 () String) +(assert (= (str.len s33) 1)) +(declare-fun s34 () String) +(assert (= (str.len s34) 1)) +(declare-fun s35 () String) +(assert (= (str.len s35) 1)) +(declare-fun s36 () String) +(assert (= (str.len s36) 1)) +(declare-fun s37 () String) +(assert (= (str.len s37) 1)) +(declare-fun s38 () String) +(assert (= (str.len s38) 1)) +(declare-fun s39 () String) +(assert (= (str.len s39) 1)) +(declare-fun s40 () String) +(assert (= (str.len s40) 1)) +(declare-fun s41 () String) +(assert (= (str.len s41) 1)) +(declare-fun s42 () String) +(assert (= (str.len s42) 1)) +(declare-fun s43 () String) +(assert (= (str.len s43) 1)) +(declare-fun s44 () String) +(assert (= (str.len s44) 1)) +(declare-fun s45 () String) +(assert (= (str.len s45) 1)) +(declare-fun s46 () String) +(assert (= (str.len s46) 1)) +(declare-fun s47 () String) +(assert (= (str.len s47) 1)) +(declare-fun s48 () String) +(assert (= (str.len s48) 1)) +(declare-fun s49 () String) +(assert (= (str.len s49) 1)) +(declare-fun s50 () String) +(assert (= (str.len s50) 1)) +(declare-fun s51 () String) +(assert (= (str.len s51) 1)) +(declare-fun s52 () String) +(assert (= (str.len s52) 1)) +(declare-fun s53 () String) +(assert (= (str.len s53) 1)) +(declare-fun s54 () String) +(assert (= (str.len s54) 1)) +(declare-fun s55 () String) +(assert (= (str.len s55) 1)) +(declare-fun s56 () String) +(assert (= (str.len s56) 1)) +(declare-fun s57 () String) +(assert (= (str.len s57) 1)) +(declare-fun s58 () String) +(assert (= (str.len s58) 1)) +(declare-fun s59 () String) +(assert (= (str.len s59) 1)) +(declare-fun s60 () String) +(assert (= (str.len s60) 1)) +(declare-fun s61 () String) +(assert (= (str.len s61) 1)) +(declare-fun s62 () String) +(assert (= (str.len s62) 1)) +(declare-fun s63 () String) +(assert (= (str.len s63) 1)) +(declare-fun s64 () String) +(assert (= (str.len s64) 1)) +(declare-fun s65 () String) +(assert (= (str.len s65) 1)) +(assert (distinct +s1 +s2 +s3 +s4 +s5 +s6 +s7 +s8 +s9 +s10 +s11 +s12 +s13 +s14 +s15 +s16 +s17 +s18 +s19 +s20 +s21 +s22 +s23 +s24 +s25 +s26 +s27 +s28 +s29 +s30 +s31 +s32 +s33 +s34 +s35 +s36 +s37 +s38 +s39 +s40 +s41 +s42 +s43 +s44 +s45 +s46 +s47 +s48 +s49 +s50 +s51 +s52 +s53 +s54 +s55 +s56 +s57 +s58 +s59 +s60 +s61 +s62 +s63 +s64 +s65 +)) +(check-sat) diff --git a/test/regress/regress2/sygus/multi-udiv.sy b/test/regress/regress2/sygus/multi-udiv.sy index d9deb28a3..65e5d428f 100644 --- a/test/regress/regress2/sygus/multi-udiv.sy +++ b/test/regress/regress2/sygus/multi-udiv.sy @@ -1,5 +1,5 @@ ; EXPECT: unsat -; COMMAND-LINE: --lang=sygus2 --sygus-out=status +; COMMAND-LINE: --lang=sygus2 --sygus-out=status --sygus-active-gen=enum (set-logic BV) (define-fun hd05 ((x (_ BitVec 32))) (_ BitVec 32) (bvor x (bvsub x #x00000001))) diff --git a/test/regress/regress2/sygus/sets-fun-test.sy b/test/regress/regress2/sygus/sets-fun-test.sy index 43a8b36a9..23abc5c7e 100644 --- a/test/regress/regress2/sygus/sets-fun-test.sy +++ b/test/regress/regress2/sygus/sets-fun-test.sy @@ -1,5 +1,5 @@ ; EXPECT: unsat -; COMMAND-LINE: --lang=sygus2 --sygus-out=status +; COMMAND-LINE: --lang=sygus2 --sygus-out=status --sygus-active-gen=enum (set-logic ALL) (synth-fun f ((x Int)) (Set Int)) diff --git a/test/regress/regress2/sygus/three.sy b/test/regress/regress2/sygus/three.sy index 239f7f498..9bed1e667 100644 --- a/test/regress/regress2/sygus/three.sy +++ b/test/regress/regress2/sygus/three.sy @@ -1,5 +1,5 @@ ; EXPECT: unsat -; COMMAND-LINE: --lang=sygus2 --sygus-out=status +; COMMAND-LINE: --lang=sygus2 --sygus-out=status --sygus-active-gen=enum (set-logic NIA) diff --git a/test/regress/regress3/bv_to_int_and_or.smt2 b/test/regress/regress3/bv_to_int_and_or.smt2 index 2c728417d..8ae10a04f 100644 --- a/test/regress/regress3/bv_to_int_and_or.smt2 +++ b/test/regress/regress3/bv_to_int_and_or.smt2 @@ -1,5 +1,7 @@ -; COMMAND-LINE: --solve-bv-as-int=sum --bvand-integer-granularity=1 -; COMMAND-LINE: --solve-bv-as-int=sum --bvand-integer-granularity=2 +; COMMAND-LINE: --solve-bv-as-int=sum --bvand-integer-granularity=1 --no-check-unsat-cores --no-check-proofs +; COMMAND-LINE: --solve-bv-as-int=bitwise --bvand-integer-granularity=1 --no-check-unsat-cores --no-check-proofs +; COMMAND-LINE: --solve-bv-as-int=sum --bvand-integer-granularity=2 --no-check-unsat-cores --no-check-proofs +; COMMAND-LINE: --solve-bv-as-int=bitwise --bvand-integer-granularity=2 --no-check-unsat-cores --no-check-proofs ; EXPECT: unsat (set-logic QF_BV) (declare-fun a () (_ BitVec 4)) diff --git a/test/regress/regress3/bv_to_int_bench_9839.smt2.minimized.smt2 b/test/regress/regress3/bv_to_int_bench_9839.smt2.minimized.smt2 index aeacda35e..3a0320119 100644 --- a/test/regress/regress3/bv_to_int_bench_9839.smt2.minimized.smt2 +++ b/test/regress/regress3/bv_to_int_bench_9839.smt2.minimized.smt2 @@ -1,5 +1,6 @@ -; COMMAND-LINE: --solve-bv-as-int=bv -; COMMAND-LINE: --bvand-integer-granularity=1 --solve-bv-as-int=sum +; COMMAND-LINE: --solve-bv-as-int=bv +; COMMAND-LINE: --bvand-integer-granularity=1 --solve-bv-as-int=sum +; COMMAND-LINE: --bvand-integer-granularity=1 --solve-bv-as-int=bitwise ; EXPECT: sat (set-logic QF_BV) (declare-fun _substvar_1171_ () (_ BitVec 32)) diff --git a/test/regress/regress3/bv_to_int_check_bvsgt_bvlshr0_4bit.smt2.minimized.smt2 b/test/regress/regress3/bv_to_int_check_bvsgt_bvlshr0_4bit.smt2.minimized.smt2 index c4988e3c6..3c50acc1c 100644 --- a/test/regress/regress3/bv_to_int_check_bvsgt_bvlshr0_4bit.smt2.minimized.smt2 +++ b/test/regress/regress3/bv_to_int_check_bvsgt_bvlshr0_4bit.smt2.minimized.smt2 @@ -1,6 +1,6 @@ -; COMMAND-LINE: --solve-bv-as-int=bv -; COMMAND-LINE: --solve-bv-as-int=sum -; COMMAND-LINE: --solve-bv-as-int=iand --iand-mode=sum +; COMMAND-LINE: --solve-bv-as-int=bv +; COMMAND-LINE: --solve-bv-as-int=sum +; COMMAND-LINE: --solve-bv-as-int=iand --iand-mode=sum ; COMMAND-LINE: --solve-bv-as-int=iand --iand-mode=bitwise ; COMMAND-LINE: --solve-bv-as-int=iand --iand-mode=value ; EXPECT: unsat diff --git a/test/regress/regress3/bv_to_int_input_mouser_detect.c.smt2.minimized.smt2 b/test/regress/regress3/bv_to_int_input_mouser_detect.c.smt2.minimized.smt2 index dd7e11a50..b37dc371d 100644 --- a/test/regress/regress3/bv_to_int_input_mouser_detect.c.smt2.minimized.smt2 +++ b/test/regress/regress3/bv_to_int_input_mouser_detect.c.smt2.minimized.smt2 @@ -1,5 +1,5 @@ ; COMMAND-LINE: --solve-bv-as-int=bv --no-check-models -; COMMAND-LINE: --bvand-integer-granularity=1 --solve-bv-as-int=sum --full-saturate-quant --cegqi-all --no-check-models +; COMMAND-LINE: --bvand-integer-granularity=1 --solve-bv-as-int=sum --full-saturate-quant --cegqi-all --no-check-models ;EXPECT: sat (set-logic BV) (assert (exists ((c__detect__main__1__i_36_C (_ BitVec 32))) (bvslt ((_ sign_extend 32) c__detect__main__1__i_36_C) (_ bv0 64)))) diff --git a/test/unit/api/cpp/datatype_api_black.cpp b/test/unit/api/cpp/datatype_api_black.cpp index 745abc17c..fecf228a5 100644 --- a/test/unit/api/cpp/datatype_api_black.cpp +++ b/test/unit/api/cpp/datatype_api_black.cpp @@ -231,6 +231,7 @@ TEST_F(TestApiBlackDatatype, datatypeNames) dtypeSpec.addConstructor(nil); Sort dtypeSort = d_solver.mkDatatypeSort(dtypeSpec); Datatype dt = dtypeSort.getDatatype(); + ASSERT_THROW(dt.getParameters(), CVC5ApiException); ASSERT_EQ(dt.getName(), std::string("list")); ASSERT_NO_THROW(dt.getConstructor("nil")); ASSERT_NO_THROW(dt["cons"]); @@ -274,6 +275,8 @@ TEST_F(TestApiBlackDatatype, parametricDatatype) Sort pairType = d_solver.mkDatatypeSort(pairSpec); ASSERT_TRUE(pairType.getDatatype().isParametric()); + std::vector<Sort> dparams = pairType.getDatatype().getParameters(); + ASSERT_TRUE(dparams[0] == t1 && dparams[1] == t2); v.clear(); v.push_back(d_solver.getIntegerSort()); @@ -576,12 +579,16 @@ TEST_F(TestApiBlackDatatype, datatypeSpecializedCons) iargs.push_back(isort); Sort listInt = dtsorts[0].instantiate(iargs); + std::vector<Sort> liparams = listInt.getDatatype().getParameters(); + // the parameter of the datatype is not instantiated + ASSERT_TRUE(liparams.size() == 1 && liparams[0] == x); + Term testConsTerm; // get the specialized constructor term for list[Int] - ASSERT_NO_THROW(testConsTerm = nilc.getSpecializedConstructorTerm(listInt)); + ASSERT_NO_THROW(testConsTerm = nilc.getInstantiatedConstructorTerm(listInt)); ASSERT_NE(testConsTerm, nilc.getConstructorTerm()); // error to get the specialized constructor term for Int - ASSERT_THROW(nilc.getSpecializedConstructorTerm(isort), CVC5ApiException); + ASSERT_THROW(nilc.getInstantiatedConstructorTerm(isort), CVC5ApiException); } } // namespace test } // namespace cvc5 diff --git a/test/unit/api/cpp/solver_black.cpp b/test/unit/api/cpp/solver_black.cpp index 36b669bca..b17054637 100644 --- a/test/unit/api/cpp/solver_black.cpp +++ b/test/unit/api/cpp/solver_black.cpp @@ -929,22 +929,35 @@ TEST_F(TestApiBlackSolver, mkConstArray) TEST_F(TestApiBlackSolver, declareDatatype) { + DatatypeConstructorDecl lin = d_solver.mkDatatypeConstructorDecl("lin"); + std::vector<DatatypeConstructorDecl> ctors0 = {lin}; + ASSERT_NO_THROW(d_solver.declareDatatype(std::string(""), ctors0)); + DatatypeConstructorDecl nil = d_solver.mkDatatypeConstructorDecl("nil"); std::vector<DatatypeConstructorDecl> ctors1 = {nil}; ASSERT_NO_THROW(d_solver.declareDatatype(std::string("a"), ctors1)); + DatatypeConstructorDecl cons = d_solver.mkDatatypeConstructorDecl("cons"); DatatypeConstructorDecl nil2 = d_solver.mkDatatypeConstructorDecl("nil"); std::vector<DatatypeConstructorDecl> ctors2 = {cons, nil2}; ASSERT_NO_THROW(d_solver.declareDatatype(std::string("b"), ctors2)); + DatatypeConstructorDecl cons2 = d_solver.mkDatatypeConstructorDecl("cons"); DatatypeConstructorDecl nil3 = d_solver.mkDatatypeConstructorDecl("nil"); std::vector<DatatypeConstructorDecl> ctors3 = {cons2, nil3}; ASSERT_NO_THROW(d_solver.declareDatatype(std::string(""), ctors3)); + + // must have at least one constructor std::vector<DatatypeConstructorDecl> ctors4; ASSERT_THROW(d_solver.declareDatatype(std::string("c"), ctors4), CVC5ApiException); - ASSERT_THROW(d_solver.declareDatatype(std::string(""), ctors4), + // constructors may not be reused + DatatypeConstructorDecl ctor1 = d_solver.mkDatatypeConstructorDecl("_x21"); + DatatypeConstructorDecl ctor2 = d_solver.mkDatatypeConstructorDecl("_x31"); + Sort s3 = d_solver.declareDatatype(std::string("_x17"), {ctor1, ctor2}); + ASSERT_THROW(d_solver.declareDatatype(std::string("_x86"), {ctor1, ctor2}), CVC5ApiException); + // constructor belongs to different solver instance Solver slv; ASSERT_THROW(slv.declareDatatype(std::string("a"), ctors1), CVC5ApiException); } @@ -1443,13 +1456,16 @@ TEST_F(TestApiBlackSolver, getOptionInfo) } { // mode option - api::OptionInfo info = d_solver.getOptionInfo("output"); - EXPECT_EQ("output", info.name); - EXPECT_EQ(std::vector<std::string>{}, info.aliases); + api::OptionInfo info = d_solver.getOptionInfo("simplification"); + EXPECT_EQ("simplification", info.name); + EXPECT_EQ(std::vector<std::string>{"simplification-mode"}, info.aliases); EXPECT_TRUE(std::holds_alternative<OptionInfo::ModeInfo>(info.valueInfo)); auto modeInfo = std::get<OptionInfo::ModeInfo>(info.valueInfo); - EXPECT_EQ("none", modeInfo.defaultValue); - EXPECT_EQ("none", modeInfo.currentValue); + EXPECT_EQ("batch", modeInfo.defaultValue); + EXPECT_EQ("batch", modeInfo.currentValue); + EXPECT_EQ(2, modeInfo.modes.size()); + EXPECT_TRUE(std::find(modeInfo.modes.begin(), modeInfo.modes.end(), "batch") + != modeInfo.modes.end()); EXPECT_TRUE(std::find(modeInfo.modes.begin(), modeInfo.modes.end(), "none") != modeInfo.modes.end()); } @@ -2639,5 +2655,152 @@ TEST_F(TestApiBlackSolver, issue5893) ASSERT_NO_FATAL_FAILURE(distinct.getOp()); } +TEST_F(TestApiBlackSolver, proj_issue373) +{ + Sort s1 = d_solver.getRealSort(); + + DatatypeConstructorDecl ctor13 = d_solver.mkDatatypeConstructorDecl("_x115"); + ctor13.addSelector("_x109", s1); + Sort s4 = d_solver.declareDatatype("_x86", {ctor13}); + + Term t452 = d_solver.mkVar(s1, "_x281"); + Term bvl = d_solver.mkTerm(d_solver.mkOp(VARIABLE_LIST), {t452}); + Term acons = + d_solver.mkTerm(d_solver.mkOp(APPLY_CONSTRUCTOR), + {s4.getDatatype().getConstructorTerm("_x115"), t452}); + // type exception + ASSERT_THROW( + d_solver.mkTerm(d_solver.mkOp(APPLY_CONSTRUCTOR), {bvl, acons, t452}), + CVC5ApiException); +} + +TEST_F(TestApiBlackSolver, proj_issue378) +{ + DatatypeDecl dtdecl; + DatatypeConstructorDecl cdecl; + + Sort s1 = d_solver.getBooleanSort(); + + dtdecl = d_solver.mkDatatypeDecl("_x0"); + cdecl = d_solver.mkDatatypeConstructorDecl("_x6"); + cdecl.addSelector("_x1", s1); + dtdecl.addConstructor(cdecl); + Sort s2 = d_solver.mkDatatypeSort(dtdecl); + + dtdecl = d_solver.mkDatatypeDecl("_x36"); + cdecl = d_solver.mkDatatypeConstructorDecl("_x42"); + cdecl.addSelector("_x37", s1); + dtdecl.addConstructor(cdecl); + Sort s4 = d_solver.mkDatatypeSort(dtdecl); + + Term t1 = d_solver.mkConst(s1, "_x53"); + Term t4 = d_solver.mkConst(s4, "_x56"); + Term t7 = d_solver.mkConst(s2, "_x58"); + + Sort sp = d_solver.mkParamSort("_x178"); + dtdecl = d_solver.mkDatatypeDecl("_x176", sp); + cdecl = d_solver.mkDatatypeConstructorDecl("_x184"); + cdecl.addSelector("_x180", s2); + dtdecl.addConstructor(cdecl); + cdecl = d_solver.mkDatatypeConstructorDecl("_x186"); + cdecl.addSelector("_x185", sp); + dtdecl.addConstructor(cdecl); + Sort s7 = d_solver.mkDatatypeSort(dtdecl); + Sort s9 = s7.instantiate({s2}); + Term t1507 = d_solver.mkTerm( + APPLY_CONSTRUCTOR, s9.getDatatype().getConstructorTerm("_x184"), t7); + ASSERT_NO_THROW(d_solver.mkTerm( + APPLY_UPDATER, + s9.getDatatype().getConstructor("_x186").getSelectorTerm("_x185"), + t1507, + t7)); +} + +TEST_F(TestApiBlackSolver, proj_issue379) +{ + Sort bsort = d_solver.getBooleanSort(); + Sort psort = d_solver.mkParamSort("_x1"); + DatatypeConstructorDecl cdecl; + DatatypeDecl dtdecl = d_solver.mkDatatypeDecl("x_0", psort); + cdecl = d_solver.mkDatatypeConstructorDecl("_x8"); + cdecl.addSelector("_x7", bsort); + dtdecl.addConstructor(cdecl); + cdecl = d_solver.mkDatatypeConstructorDecl("_x6"); + cdecl.addSelector("_x2", psort); + cdecl.addSelectorSelf("_x3"); + cdecl.addSelector("_x4", psort); + cdecl.addSelector("_x5", bsort); + Sort s2 = d_solver.mkDatatypeSort(dtdecl); + Sort s6 = s2.instantiate({bsort}); + Term t317 = d_solver.mkConst(bsort, "_x345"); + Term t843 = d_solver.mkConst(s6, "_x346"); + Term t879 = d_solver.mkTerm(APPLY_UPDATER, + t843.getSort() + .getDatatype() + .getConstructor("_x8") + .getSelector("_x7") + .getUpdaterTerm(), + t843, + t317); + ASSERT_EQ(t879.getSort(), s6); +} + +TEST_F(TestApiBlackSolver, getDatatypeArity) +{ + DatatypeConstructorDecl ctor1 = d_solver.mkDatatypeConstructorDecl("_x21"); + DatatypeConstructorDecl ctor2 = d_solver.mkDatatypeConstructorDecl("_x31"); + Sort s3 = d_solver.declareDatatype(std::string("_x17"), {ctor1, ctor2}); + ASSERT_EQ(s3.getDatatypeArity(), 0); +} + +TEST_F(TestApiBlackSolver, proj_issue381) +{ + Sort s1 = d_solver.getBooleanSort(); + + Sort psort = d_solver.mkParamSort("_x9"); + DatatypeDecl dtdecl = d_solver.mkDatatypeDecl("_x8", psort); + DatatypeConstructorDecl ctor = d_solver.mkDatatypeConstructorDecl("_x22"); + ctor.addSelector("_x19", s1); + dtdecl.addConstructor(ctor); + Sort s3 = d_solver.mkDatatypeSort(dtdecl); + Sort s6 = s3.instantiate({s1}); + Term t26 = d_solver.mkConst(s6, "_x63"); + Term t5 = d_solver.mkTrue(); + Term t187 = d_solver.mkTerm(APPLY_UPDATER, + t26.getSort() + .getDatatype() + .getConstructor("_x22") + .getSelector("_x19") + .getUpdaterTerm(), + t26, + t5); + ASSERT_NO_THROW(d_solver.simplify(t187)); +} + +TEST_F(TestApiBlackSolver, proj_issue383) +{ + d_solver.setOption("produce-models", "true"); + + Sort s1 = d_solver.getBooleanSort(); + + DatatypeConstructorDecl ctordecl = d_solver.mkDatatypeConstructorDecl("_x5"); + DatatypeDecl dtdecl = d_solver.mkDatatypeDecl("_x0"); + dtdecl.addConstructor(ctordecl); + Sort s2 = d_solver.mkDatatypeSort(dtdecl); + + ctordecl = d_solver.mkDatatypeConstructorDecl("_x23"); + ctordecl.addSelectorSelf("_x21"); + dtdecl = d_solver.mkDatatypeDecl("_x12"); + dtdecl.addConstructor(ctordecl); + Sort s4 = d_solver.mkDatatypeSort(dtdecl); + ASSERT_FALSE(s4.getDatatype().isWellFounded()); + + Term t3 = d_solver.mkConst(s4, "_x25"); + Term t13 = d_solver.mkConst(s1, "_x34"); + + d_solver.checkEntailed(t13); + ASSERT_THROW(d_solver.getValue(t3), CVC5ApiException); +} + } // namespace test } // namespace cvc5 diff --git a/test/unit/api/java/DatatypeTest.java b/test/unit/api/java/DatatypeTest.java index fb23ea515..e94785b08 100644 --- a/test/unit/api/java/DatatypeTest.java +++ b/test/unit/api/java/DatatypeTest.java @@ -248,6 +248,8 @@ class DatatypeTest Sort pairType = d_solver.mkDatatypeSort(pairSpec); assertTrue(pairType.getDatatype().isParametric()); + Sort[] dparams = pairType.getDatatype().getParameters(); + assertTrue(dparams[0].equals(t1) && dparams[1].equals(t2)); v.clear(); v.add(d_solver.getIntegerSort()); @@ -562,10 +564,12 @@ class DatatypeTest AtomicReference<Term> atomicTerm = new AtomicReference<>(); // get the specialized constructor term for list[Int] - assertDoesNotThrow(() -> atomicTerm.set(nilc.getSpecializedConstructorTerm(listInt))); + assertDoesNotThrow( + () -> atomicTerm.set(nilc.getInstantiatedConstructorTerm(listInt))); Term testConsTerm = atomicTerm.get(); assertNotEquals(testConsTerm, nilc.getConstructorTerm()); // error to get the specialized constructor term for Int - assertThrows(CVC5ApiException.class, () -> nilc.getSpecializedConstructorTerm(isort)); + assertThrows(CVC5ApiException.class, + () -> nilc.getInstantiatedConstructorTerm(isort)); } } diff --git a/test/unit/api/java/SolverTest.java b/test/unit/api/java/SolverTest.java index ed2f7491d..5d651e82a 100644 --- a/test/unit/api/java/SolverTest.java +++ b/test/unit/api/java/SolverTest.java @@ -1428,15 +1428,17 @@ class SolverTest } { // mode option - OptionInfo info = d_solver.getOptionInfo("output"); + OptionInfo info = d_solver.getOptionInfo("simplification"); assertions.clear(); - assertions.add(() -> assertEquals("output", info.getName())); + assertions.add(() -> assertEquals("simplification", info.getName())); assertions.add( - () -> assertEquals(Arrays.asList(new String[] {}), Arrays.asList(info.getAliases()))); + () -> assertEquals(Arrays.asList(new String[] {"simplification-mode"}), Arrays.asList(info.getAliases()))); assertions.add(() -> assertTrue(info.getBaseInfo().getClass() == OptionInfo.ModeInfo.class)); OptionInfo.ModeInfo modeInfo = (OptionInfo.ModeInfo) info.getBaseInfo(); - assertions.add(() -> assertEquals("none", modeInfo.getDefaultValue())); - assertions.add(() -> assertEquals("none", modeInfo.getCurrentValue())); + assertions.add(() -> assertEquals("batch", modeInfo.getDefaultValue())); + assertions.add(() -> assertEquals("batch", modeInfo.getCurrentValue())); + assertions.add(() -> assertEquals(2, modeInfo.getModes().length)); + assertions.add(() -> assertTrue(Arrays.asList(modeInfo.getModes()).contains("batch"))); assertions.add(() -> assertTrue(Arrays.asList(modeInfo.getModes()).contains("none"))); } assertAll(assertions); diff --git a/test/unit/api/python/test_datatype_api.py b/test/unit/api/python/test_datatype_api.py index d8a4c26f7..af34e098e 100644 --- a/test/unit/api/python/test_datatype_api.py +++ b/test/unit/api/python/test_datatype_api.py @@ -13,7 +13,6 @@ import pytest import pycvc5 -from pycvc5 import kinds from pycvc5 import Sort, Term from pycvc5 import DatatypeDecl from pycvc5 import Datatype @@ -156,6 +155,8 @@ def test_datatype_structs(solver): dtypeSpec.addConstructor(nil) dtypeSort = solver.mkDatatypeSort(dtypeSpec) dt = dtypeSort.getDatatype() + # not parametric datatype + with pytest.raises(RuntimeError): dt.getParameters() assert not dt.isCodatatype() assert not dt.isTuple() assert not dt.isRecord() @@ -263,7 +264,7 @@ def test_parametric_datatype(solver): v.append(t1) v.append(t2) pairSpec = solver.mkDatatypeDecl("pair", v) - + mkpair = solver.mkDatatypeConstructorDecl("mk-pair") mkpair.addSelector("first", t1) mkpair.addSelector("second", t2) @@ -272,6 +273,8 @@ def test_parametric_datatype(solver): pairType = solver.mkDatatypeSort(pairSpec) assert pairType.getDatatype().isParametric() + dparams = pairType.getDatatype().getParameters() + assert dparams[0]==t1 and dparams[1]==t2 v.clear() v.append(solver.getIntegerSort()) @@ -559,8 +562,8 @@ def test_datatype_specialized_cons(solver): testConsTerm = Term(solver) # get the specialized constructor term for list[Int] - testConsTerm = nilc.getSpecializedConstructorTerm(listInt) + testConsTerm = nilc.getInstantiatedConstructorTerm(listInt) assert testConsTerm != nilc.getConstructorTerm() # error to get the specialized constructor term for Int with pytest.raises(RuntimeError): - nilc.getSpecializedConstructorTerm(isort) + nilc.getInstantiatedConstructorTerm(isort) diff --git a/test/unit/api/python/test_grammar.py b/test/unit/api/python/test_grammar.py index db567a6ba..6225844e3 100644 --- a/test/unit/api/python/test_grammar.py +++ b/test/unit/api/python/test_grammar.py @@ -16,7 +16,7 @@ import pytest import pycvc5 -from pycvc5 import kinds, Term +from pycvc5 import Term @pytest.fixture diff --git a/test/unit/api/python/test_op.py b/test/unit/api/python/test_op.py index 5126a481d..a79fd0426 100644 --- a/test/unit/api/python/test_op.py +++ b/test/unit/api/python/test_op.py @@ -17,7 +17,7 @@ import pytest import pycvc5 -from pycvc5 import kinds +from pycvc5 import Kind from pycvc5 import Sort from pycvc5 import Op @@ -28,44 +28,44 @@ def solver(): def test_get_kind(solver): - x = solver.mkOp(kinds.BVExtract, 31, 1) + x = solver.mkOp(Kind.BVExtract, 31, 1) x.getKind() def test_is_null(solver): x = Op(solver) assert x.isNull() - x = solver.mkOp(kinds.BVExtract, 31, 1) + x = solver.mkOp(Kind.BVExtract, 31, 1) assert not x.isNull() def test_op_from_kind(solver): - solver.mkOp(kinds.Plus) + solver.mkOp(Kind.Plus) with pytest.raises(RuntimeError): - solver.mkOp(kinds.BVExtract) + solver.mkOp(Kind.BVExtract) def test_get_num_indices(solver): - plus = solver.mkOp(kinds.Plus) - divisible = solver.mkOp(kinds.Divisible, 4) - bitvector_repeat = solver.mkOp(kinds.BVRepeat, 5) - bitvector_zero_extend = solver.mkOp(kinds.BVZeroExtend, 6) - bitvector_sign_extend = solver.mkOp(kinds.BVSignExtend, 7) - bitvector_rotate_left = solver.mkOp(kinds.BVRotateLeft, 8) - bitvector_rotate_right = solver.mkOp(kinds.BVRotateRight, 9) - int_to_bitvector = solver.mkOp(kinds.IntToBV, 10) - iand = solver.mkOp(kinds.Iand, 3) - floatingpoint_to_ubv = solver.mkOp(kinds.FPToUbv, 11) - floatingopint_to_sbv = solver.mkOp(kinds.FPToSbv, 13) - floatingpoint_to_fp_ieee_bitvector = solver.mkOp(kinds.FPToFpIeeeBV, 4, 25) - floatingpoint_to_fp_floatingpoint = solver.mkOp(kinds.FPToFpFP, 4, 25) - floatingpoint_to_fp_real = solver.mkOp(kinds.FPToFpReal, 4, 25) - floatingpoint_to_fp_signed_bitvector = solver.mkOp(kinds.FPToFpSignedBV, 4, + plus = solver.mkOp(Kind.Plus) + divisible = solver.mkOp(Kind.Divisible, 4) + bitvector_repeat = solver.mkOp(Kind.BVRepeat, 5) + bitvector_zero_extend = solver.mkOp(Kind.BVZeroExtend, 6) + bitvector_sign_extend = solver.mkOp(Kind.BVSignExtend, 7) + bitvector_rotate_left = solver.mkOp(Kind.BVRotateLeft, 8) + bitvector_rotate_right = solver.mkOp(Kind.BVRotateRight, 9) + int_to_bitvector = solver.mkOp(Kind.IntToBV, 10) + iand = solver.mkOp(Kind.Iand, 3) + floatingpoint_to_ubv = solver.mkOp(Kind.FPToUbv, 11) + floatingopint_to_sbv = solver.mkOp(Kind.FPToSbv, 13) + floatingpoint_to_fp_ieee_bitvector = solver.mkOp(Kind.FPToFpIeeeBV, 4, 25) + floatingpoint_to_fp_floatingpoint = solver.mkOp(Kind.FPToFpFP, 4, 25) + floatingpoint_to_fp_real = solver.mkOp(Kind.FPToFpReal, 4, 25) + floatingpoint_to_fp_signed_bitvector = solver.mkOp(Kind.FPToFpSignedBV, 4, 25) floatingpoint_to_fp_unsigned_bitvector = solver.mkOp( - kinds.FPToFpUnsignedBV, 4, 25) - floatingpoint_to_fp_generic = solver.mkOp(kinds.FPToFpGeneric, 4, 25) - regexp_loop = solver.mkOp(kinds.RegexpLoop, 2, 3) + Kind.FPToFpUnsignedBV, 4, 25) + floatingpoint_to_fp_generic = solver.mkOp(Kind.FPToFpGeneric, 4, 25) + regexp_loop = solver.mkOp(Kind.RegexpLoop, 2, 3) assert 0 == plus.getNumIndices() assert 1 == divisible.getNumIndices() @@ -87,7 +87,7 @@ def test_get_num_indices(solver): assert 2 == regexp_loop.getNumIndices() def test_op_indices_list(solver): - with_list = solver.mkOp(kinds.TupleProject, [4, 25]) + with_list = solver.mkOp(Kind.TupleProject, [4, 25]) assert 2 == with_list.getNumIndices() def test_get_indices_string(solver): @@ -95,87 +95,87 @@ def test_get_indices_string(solver): with pytest.raises(RuntimeError): x.getIndices() - divisible_ot = solver.mkOp(kinds.Divisible, 4) + divisible_ot = solver.mkOp(Kind.Divisible, 4) assert divisible_ot.isIndexed() divisible_idx = divisible_ot.getIndices() assert divisible_idx == "4" def test_get_indices_uint(solver): - bitvector_repeat_ot = solver.mkOp(kinds.BVRepeat, 5) + bitvector_repeat_ot = solver.mkOp(Kind.BVRepeat, 5) assert bitvector_repeat_ot.isIndexed() bitvector_repeat_idx = bitvector_repeat_ot.getIndices() assert bitvector_repeat_idx == 5 - bitvector_zero_extend_ot = solver.mkOp(kinds.BVZeroExtend, 6) + bitvector_zero_extend_ot = solver.mkOp(Kind.BVZeroExtend, 6) bitvector_zero_extend_idx = bitvector_zero_extend_ot.getIndices() assert bitvector_zero_extend_idx == 6 - bitvector_sign_extend_ot = solver.mkOp(kinds.BVSignExtend, 7) + bitvector_sign_extend_ot = solver.mkOp(Kind.BVSignExtend, 7) bitvector_sign_extend_idx = bitvector_sign_extend_ot.getIndices() assert bitvector_sign_extend_idx == 7 - bitvector_rotate_left_ot = solver.mkOp(kinds.BVRotateLeft, 8) + bitvector_rotate_left_ot = solver.mkOp(Kind.BVRotateLeft, 8) bitvector_rotate_left_idx = bitvector_rotate_left_ot.getIndices() assert bitvector_rotate_left_idx == 8 - bitvector_rotate_right_ot = solver.mkOp(kinds.BVRotateRight, 9) + bitvector_rotate_right_ot = solver.mkOp(Kind.BVRotateRight, 9) bitvector_rotate_right_idx = bitvector_rotate_right_ot.getIndices() assert bitvector_rotate_right_idx == 9 - int_to_bitvector_ot = solver.mkOp(kinds.IntToBV, 10) + int_to_bitvector_ot = solver.mkOp(Kind.IntToBV, 10) int_to_bitvector_idx = int_to_bitvector_ot.getIndices() assert int_to_bitvector_idx == 10 - floatingpoint_to_ubv_ot = solver.mkOp(kinds.FPToUbv, 11) + floatingpoint_to_ubv_ot = solver.mkOp(Kind.FPToUbv, 11) floatingpoint_to_ubv_idx = floatingpoint_to_ubv_ot.getIndices() assert floatingpoint_to_ubv_idx == 11 - floatingpoint_to_sbv_ot = solver.mkOp(kinds.FPToSbv, 13) + floatingpoint_to_sbv_ot = solver.mkOp(Kind.FPToSbv, 13) floatingpoint_to_sbv_idx = floatingpoint_to_sbv_ot.getIndices() assert floatingpoint_to_sbv_idx == 13 def test_get_indices_pair_uint(solver): - bitvector_extract_ot = solver.mkOp(kinds.BVExtract, 4, 0) + bitvector_extract_ot = solver.mkOp(Kind.BVExtract, 4, 0) assert bitvector_extract_ot.isIndexed() bitvector_extract_indices = bitvector_extract_ot.getIndices() assert bitvector_extract_indices == (4, 0) floatingpoint_to_fp_ieee_bitvector_ot = solver.mkOp( - kinds.FPToFpIeeeBV, 4, 25) + Kind.FPToFpIeeeBV, 4, 25) floatingpoint_to_fp_ieee_bitvector_indices = floatingpoint_to_fp_ieee_bitvector_ot.getIndices( ) assert floatingpoint_to_fp_ieee_bitvector_indices == (4, 25) - floatingpoint_to_fp_floatingpoint_ot = solver.mkOp(kinds.FPToFpFP, 4, 25) + floatingpoint_to_fp_floatingpoint_ot = solver.mkOp(Kind.FPToFpFP, 4, 25) floatingpoint_to_fp_floatingpoint_indices = floatingpoint_to_fp_floatingpoint_ot.getIndices( ) assert floatingpoint_to_fp_floatingpoint_indices == (4, 25) - floatingpoint_to_fp_real_ot = solver.mkOp(kinds.FPToFpReal, 4, 25) + floatingpoint_to_fp_real_ot = solver.mkOp(Kind.FPToFpReal, 4, 25) floatingpoint_to_fp_real_indices = floatingpoint_to_fp_real_ot.getIndices() assert floatingpoint_to_fp_real_indices == (4, 25) floatingpoint_to_fp_signed_bitvector_ot = solver.mkOp( - kinds.FPToFpSignedBV, 4, 25) + Kind.FPToFpSignedBV, 4, 25) floatingpoint_to_fp_signed_bitvector_indices = floatingpoint_to_fp_signed_bitvector_ot.getIndices( ) assert floatingpoint_to_fp_signed_bitvector_indices == (4, 25) floatingpoint_to_fp_unsigned_bitvector_ot = solver.mkOp( - kinds.FPToFpUnsignedBV, 4, 25) + Kind.FPToFpUnsignedBV, 4, 25) floatingpoint_to_fp_unsigned_bitvector_indices = floatingpoint_to_fp_unsigned_bitvector_ot.getIndices( ) assert floatingpoint_to_fp_unsigned_bitvector_indices == (4, 25) - floatingpoint_to_fp_generic_ot = solver.mkOp(kinds.FPToFpGeneric, 4, 25) + floatingpoint_to_fp_generic_ot = solver.mkOp(Kind.FPToFpGeneric, 4, 25) floatingpoint_to_fp_generic_indices = floatingpoint_to_fp_generic_ot.getIndices( ) assert floatingpoint_to_fp_generic_indices == (4, 25) def test_op_scoping_to_string(solver): - bitvector_repeat_ot = solver.mkOp(kinds.BVRepeat, 5) + bitvector_repeat_ot = solver.mkOp(Kind.BVRepeat, 5) op_repr = str(bitvector_repeat_ot) assert str(bitvector_repeat_ot) == op_repr diff --git a/test/unit/api/python/test_result.py b/test/unit/api/python/test_result.py index bd97646f9..e6ca3cf1e 100644 --- a/test/unit/api/python/test_result.py +++ b/test/unit/api/python/test_result.py @@ -17,7 +17,6 @@ import pytest import pycvc5 -from pycvc5 import kinds from pycvc5 import Result from pycvc5 import UnknownExplanation diff --git a/test/unit/api/python/test_solver.py b/test/unit/api/python/test_solver.py index b6520e0d3..d9d6a6c36 100644 --- a/test/unit/api/python/test_solver.py +++ b/test/unit/api/python/test_solver.py @@ -15,7 +15,7 @@ import pytest import pycvc5 import sys -from pycvc5 import kinds +from pycvc5 import Kind @pytest.fixture @@ -495,24 +495,24 @@ def test_mk_pos_zero(solver): def test_mk_op(solver): with pytest.raises(ValueError): - solver.mkOp(kinds.BVExtract, kinds.Equal) + solver.mkOp(Kind.BVExtract, Kind.Equal) - solver.mkOp(kinds.Divisible, "2147483648") + solver.mkOp(Kind.Divisible, "2147483648") with pytest.raises(RuntimeError): - solver.mkOp(kinds.BVExtract, "asdf") + solver.mkOp(Kind.BVExtract, "asdf") - solver.mkOp(kinds.Divisible, 1) - solver.mkOp(kinds.BVRotateLeft, 1) - solver.mkOp(kinds.BVRotateRight, 1) + solver.mkOp(Kind.Divisible, 1) + solver.mkOp(Kind.BVRotateLeft, 1) + solver.mkOp(Kind.BVRotateRight, 1) with pytest.raises(RuntimeError): - solver.mkOp(kinds.BVExtract, 1) + solver.mkOp(Kind.BVExtract, 1) - solver.mkOp(kinds.BVExtract, 1, 1) + solver.mkOp(Kind.BVExtract, 1, 1) with pytest.raises(RuntimeError): - solver.mkOp(kinds.Divisible, 1, 2) + solver.mkOp(Kind.Divisible, 1, 2) args = [1, 2, 2] - solver.mkOp(kinds.TupleProject, args) + solver.mkOp(Kind.TupleProject, args) def test_mk_pi(solver): @@ -644,19 +644,19 @@ def test_mk_real(solver): def test_mk_regexp_none(solver): strSort = solver.getStringSort() s = solver.mkConst(strSort, "s") - solver.mkTerm(kinds.StringInRegexp, s, solver.mkRegexpNone()) + solver.mkTerm(Kind.StringInRegexp, s, solver.mkRegexpNone()) def test_mk_regexp_all(solver): strSort = solver.getStringSort() s = solver.mkConst(strSort, "s") - solver.mkTerm(kinds.StringInRegexp, s, solver.mkRegexpAll()) + solver.mkTerm(Kind.StringInRegexp, s, solver.mkRegexpAll()) def test_mk_regexp_allchar(solver): strSort = solver.getStringSort() s = solver.mkConst(strSort, "s") - solver.mkTerm(kinds.StringInRegexp, s, solver.mkRegexpAllchar()) + solver.mkTerm(Kind.StringInRegexp, s, solver.mkRegexpAllchar()) def test_mk_sep_emp(solver): @@ -694,100 +694,100 @@ def test_mk_term(solver): # mkTerm(Kind kind) const solver.mkPi() - solver.mkTerm(kinds.Pi) - solver.mkTerm(kinds.Pi, v6) - solver.mkTerm(solver.mkOp(kinds.Pi)) - solver.mkTerm(solver.mkOp(kinds.Pi), v6) - solver.mkTerm(kinds.RegexpNone) - solver.mkTerm(kinds.RegexpNone, v6) - solver.mkTerm(solver.mkOp(kinds.RegexpNone)) - solver.mkTerm(solver.mkOp(kinds.RegexpNone), v6) - solver.mkTerm(kinds.RegexpAllchar) - solver.mkTerm(kinds.RegexpAllchar, v6) - solver.mkTerm(solver.mkOp(kinds.RegexpAllchar)) - solver.mkTerm(solver.mkOp(kinds.RegexpAllchar), v6) - solver.mkTerm(kinds.SepEmp) - solver.mkTerm(kinds.SepEmp, v6) - solver.mkTerm(solver.mkOp(kinds.SepEmp)) - solver.mkTerm(solver.mkOp(kinds.SepEmp), v6) - with pytest.raises(RuntimeError): - solver.mkTerm(kinds.ConstBV) + solver.mkTerm(Kind.Pi) + solver.mkTerm(Kind.Pi, v6) + solver.mkTerm(solver.mkOp(Kind.Pi)) + solver.mkTerm(solver.mkOp(Kind.Pi), v6) + solver.mkTerm(Kind.RegexpNone) + solver.mkTerm(Kind.RegexpNone, v6) + solver.mkTerm(solver.mkOp(Kind.RegexpNone)) + solver.mkTerm(solver.mkOp(Kind.RegexpNone), v6) + solver.mkTerm(Kind.RegexpAllchar) + solver.mkTerm(Kind.RegexpAllchar, v6) + solver.mkTerm(solver.mkOp(Kind.RegexpAllchar)) + solver.mkTerm(solver.mkOp(Kind.RegexpAllchar), v6) + solver.mkTerm(Kind.SepEmp) + solver.mkTerm(Kind.SepEmp, v6) + solver.mkTerm(solver.mkOp(Kind.SepEmp)) + solver.mkTerm(solver.mkOp(Kind.SepEmp), v6) + with pytest.raises(RuntimeError): + solver.mkTerm(Kind.ConstBV) # mkTerm(Kind kind, Term child) const - solver.mkTerm(kinds.Not, solver.mkTrue()) + solver.mkTerm(Kind.Not, solver.mkTrue()) with pytest.raises(RuntimeError): - solver.mkTerm(kinds.Not, pycvc5.Term(solver)) + solver.mkTerm(Kind.Not, pycvc5.Term(solver)) with pytest.raises(RuntimeError): - solver.mkTerm(kinds.Not, a) + solver.mkTerm(Kind.Not, a) with pytest.raises(RuntimeError): - slv.mkTerm(kinds.Not, solver.mkTrue()) + slv.mkTerm(Kind.Not, solver.mkTrue()) # mkTerm(Kind kind, Term child1, Term child2) const - solver.mkTerm(kinds.Equal, a, b) + solver.mkTerm(Kind.Equal, a, b) with pytest.raises(RuntimeError): - solver.mkTerm(kinds.Equal, pycvc5.Term(solver), b) + solver.mkTerm(Kind.Equal, pycvc5.Term(solver), b) with pytest.raises(RuntimeError): - solver.mkTerm(kinds.Equal, a, pycvc5.Term(solver)) + solver.mkTerm(Kind.Equal, a, pycvc5.Term(solver)) with pytest.raises(RuntimeError): - solver.mkTerm(kinds.Equal, a, solver.mkTrue()) + solver.mkTerm(Kind.Equal, a, solver.mkTrue()) with pytest.raises(RuntimeError): - slv.mkTerm(kinds.Equal, a, b) + slv.mkTerm(Kind.Equal, a, b) # mkTerm(Kind kind, Term child1, Term child2, Term child3) const - solver.mkTerm(kinds.Ite, solver.mkTrue(), solver.mkTrue(), solver.mkTrue()) + solver.mkTerm(Kind.Ite, solver.mkTrue(), solver.mkTrue(), solver.mkTrue()) with pytest.raises(RuntimeError): - solver.mkTerm(kinds.Ite, pycvc5.Term(solver), solver.mkTrue(), + solver.mkTerm(Kind.Ite, pycvc5.Term(solver), solver.mkTrue(), solver.mkTrue()) with pytest.raises(RuntimeError): - solver.mkTerm(kinds.Ite, solver.mkTrue(), pycvc5.Term(solver), + solver.mkTerm(Kind.Ite, solver.mkTrue(), pycvc5.Term(solver), solver.mkTrue()) with pytest.raises(RuntimeError): - solver.mkTerm(kinds.Ite, solver.mkTrue(), solver.mkTrue(), + solver.mkTerm(Kind.Ite, solver.mkTrue(), solver.mkTrue(), pycvc5.Term(solver)) with pytest.raises(RuntimeError): - solver.mkTerm(kinds.Ite, solver.mkTrue(), solver.mkTrue(), b) + solver.mkTerm(Kind.Ite, solver.mkTrue(), solver.mkTrue(), b) with pytest.raises(RuntimeError): - slv.mkTerm(kinds.Ite, solver.mkTrue(), solver.mkTrue(), + slv.mkTerm(Kind.Ite, solver.mkTrue(), solver.mkTrue(), solver.mkTrue()) - solver.mkTerm(kinds.Equal, v1) + solver.mkTerm(Kind.Equal, v1) with pytest.raises(RuntimeError): - solver.mkTerm(kinds.Equal, v2) + solver.mkTerm(Kind.Equal, v2) with pytest.raises(RuntimeError): - solver.mkTerm(kinds.Equal, v3) + solver.mkTerm(Kind.Equal, v3) with pytest.raises(RuntimeError): - solver.mkTerm(kinds.Distinct, v6) + solver.mkTerm(Kind.Distinct, v6) # Test cases that are nary via the API but have arity = 2 internally s_bool = solver.getBooleanSort() t_bool = solver.mkConst(s_bool, "t_bool") - solver.mkTerm(kinds.Implies, [t_bool, t_bool, t_bool]) - solver.mkTerm(kinds.Xor, [t_bool, t_bool, t_bool]) - solver.mkTerm(solver.mkOp(kinds.Xor), [t_bool, t_bool, t_bool]) + solver.mkTerm(Kind.Implies, [t_bool, t_bool, t_bool]) + solver.mkTerm(Kind.Xor, [t_bool, t_bool, t_bool]) + solver.mkTerm(solver.mkOp(Kind.Xor), [t_bool, t_bool, t_bool]) t_int = solver.mkConst(solver.getIntegerSort(), "t_int") - solver.mkTerm(kinds.Division, [t_int, t_int, t_int]) - solver.mkTerm(solver.mkOp(kinds.Division), [t_int, t_int, t_int]) - solver.mkTerm(kinds.IntsDivision, [t_int, t_int, t_int]) - solver.mkTerm(solver.mkOp(kinds.IntsDivision), [t_int, t_int, t_int]) - solver.mkTerm(kinds.Minus, [t_int, t_int, t_int]) - solver.mkTerm(solver.mkOp(kinds.Minus), [t_int, t_int, t_int]) - solver.mkTerm(kinds.Equal, [t_int, t_int, t_int]) - solver.mkTerm(solver.mkOp(kinds.Equal), [t_int, t_int, t_int]) - solver.mkTerm(kinds.Lt, [t_int, t_int, t_int]) - solver.mkTerm(solver.mkOp(kinds.Lt), [t_int, t_int, t_int]) - solver.mkTerm(kinds.Gt, [t_int, t_int, t_int]) - solver.mkTerm(solver.mkOp(kinds.Gt), [t_int, t_int, t_int]) - solver.mkTerm(kinds.Leq, [t_int, t_int, t_int]) - solver.mkTerm(solver.mkOp(kinds.Leq), [t_int, t_int, t_int]) - solver.mkTerm(kinds.Geq, [t_int, t_int, t_int]) - solver.mkTerm(solver.mkOp(kinds.Geq), [t_int, t_int, t_int]) + solver.mkTerm(Kind.Division, [t_int, t_int, t_int]) + solver.mkTerm(solver.mkOp(Kind.Division), [t_int, t_int, t_int]) + solver.mkTerm(Kind.IntsDivision, [t_int, t_int, t_int]) + solver.mkTerm(solver.mkOp(Kind.IntsDivision), [t_int, t_int, t_int]) + solver.mkTerm(Kind.Minus, [t_int, t_int, t_int]) + solver.mkTerm(solver.mkOp(Kind.Minus), [t_int, t_int, t_int]) + solver.mkTerm(Kind.Equal, [t_int, t_int, t_int]) + solver.mkTerm(solver.mkOp(Kind.Equal), [t_int, t_int, t_int]) + solver.mkTerm(Kind.Lt, [t_int, t_int, t_int]) + solver.mkTerm(solver.mkOp(Kind.Lt), [t_int, t_int, t_int]) + solver.mkTerm(Kind.Gt, [t_int, t_int, t_int]) + solver.mkTerm(solver.mkOp(Kind.Gt), [t_int, t_int, t_int]) + solver.mkTerm(Kind.Leq, [t_int, t_int, t_int]) + solver.mkTerm(solver.mkOp(Kind.Leq), [t_int, t_int, t_int]) + solver.mkTerm(Kind.Geq, [t_int, t_int, t_int]) + solver.mkTerm(solver.mkOp(Kind.Geq), [t_int, t_int, t_int]) t_reg = solver.mkConst(solver.getRegExpSort(), "t_reg") - solver.mkTerm(kinds.RegexpDiff, [t_reg, t_reg, t_reg]) - solver.mkTerm(solver.mkOp(kinds.RegexpDiff), [t_reg, t_reg, t_reg]) + solver.mkTerm(Kind.RegexpDiff, [t_reg, t_reg, t_reg]) + solver.mkTerm(solver.mkOp(Kind.RegexpDiff), [t_reg, t_reg, t_reg]) t_fun = solver.mkConst(solver.mkFunctionSort( [s_bool, s_bool, s_bool], s_bool)) - solver.mkTerm(kinds.HoApply, [t_fun, t_bool, t_bool, t_bool]) - solver.mkTerm(solver.mkOp(kinds.HoApply), [t_fun, t_bool, t_bool, t_bool]) + solver.mkTerm(Kind.HoApply, [t_fun, t_bool, t_bool, t_bool]) + solver.mkTerm(solver.mkOp(Kind.HoApply), [t_fun, t_bool, t_bool, t_bool]) def test_mk_term_from_op(solver): bv32 = solver.mkBitVectorSort(32) @@ -800,8 +800,8 @@ def test_mk_term_from_op(solver): slv = pycvc5.Solver() # simple operator terms - opterm1 = solver.mkOp(kinds.BVExtract, 2, 1) - opterm2 = solver.mkOp(kinds.Divisible, 1) + opterm1 = solver.mkOp(Kind.BVExtract, 2, 1) + opterm2 = solver.mkOp(Kind.Divisible, 1) # list datatype sort = solver.mkParamSort("T") @@ -829,40 +829,40 @@ def test_mk_term_from_op(solver): tailTerm2 = lis["cons"]["tail"].getSelectorTerm() # mkTerm(Op op, Term term) const - solver.mkTerm(kinds.ApplyConstructor, nilTerm1) - solver.mkTerm(kinds.ApplyConstructor, nilTerm2) + solver.mkTerm(Kind.ApplyConstructor, nilTerm1) + solver.mkTerm(Kind.ApplyConstructor, nilTerm2) with pytest.raises(RuntimeError): - solver.mkTerm(kinds.ApplySelector, nilTerm1) + solver.mkTerm(Kind.ApplySelector, nilTerm1) with pytest.raises(RuntimeError): - solver.mkTerm(kinds.ApplySelector, consTerm1) + solver.mkTerm(Kind.ApplySelector, consTerm1) with pytest.raises(RuntimeError): - solver.mkTerm(kinds.ApplyConstructor, consTerm2) + solver.mkTerm(Kind.ApplyConstructor, consTerm2) with pytest.raises(RuntimeError): solver.mkTerm(opterm1) with pytest.raises(RuntimeError): - solver.mkTerm(kinds.ApplySelector, headTerm1) + solver.mkTerm(Kind.ApplySelector, headTerm1) with pytest.raises(RuntimeError): solver.mkTerm(opterm1) with pytest.raises(RuntimeError): - slv.mkTerm(kinds.ApplyConstructor, nilTerm1) + slv.mkTerm(Kind.ApplyConstructor, nilTerm1) # mkTerm(Op op, Term child) const solver.mkTerm(opterm1, a) solver.mkTerm(opterm2, solver.mkInteger(1)) - solver.mkTerm(kinds.ApplySelector, headTerm1, c) - solver.mkTerm(kinds.ApplySelector, tailTerm2, c) + solver.mkTerm(Kind.ApplySelector, headTerm1, c) + solver.mkTerm(Kind.ApplySelector, tailTerm2, c) with pytest.raises(RuntimeError): solver.mkTerm(opterm2, a) with pytest.raises(RuntimeError): solver.mkTerm(opterm1, pycvc5.Term(solver)) with pytest.raises(RuntimeError): - solver.mkTerm(kinds.ApplyConstructor, consTerm1, solver.mkInteger(0)) + solver.mkTerm(Kind.ApplyConstructor, consTerm1, solver.mkInteger(0)) with pytest.raises(RuntimeError): slv.mkTerm(opterm1, a) # mkTerm(Op op, Term child1, Term child2) const - solver.mkTerm(kinds.ApplyConstructor, consTerm1, solver.mkInteger(0), - solver.mkTerm(kinds.ApplyConstructor, nilTerm1)) + solver.mkTerm(Kind.ApplyConstructor, consTerm1, solver.mkInteger(0), + solver.mkTerm(Kind.ApplyConstructor, nilTerm1)) with pytest.raises(RuntimeError): solver.mkTerm(opterm2, solver.mkInteger(1), solver.mkInteger(2)) with pytest.raises(RuntimeError): @@ -872,10 +872,10 @@ def test_mk_term_from_op(solver): with pytest.raises(RuntimeError): solver.mkTerm(opterm2, pycvc5.Term(solver), solver.mkInteger(1)) with pytest.raises(RuntimeError): - slv.mkTerm(kinds.ApplyConstructor,\ + slv.mkTerm(Kind.ApplyConstructor,\ consTerm1,\ solver.mkInteger(0),\ - solver.mkTerm(kinds.ApplyConstructor, nilTerm1)) + solver.mkTerm(Kind.ApplyConstructor, nilTerm1)) # mkTerm(Op op, Term child1, Term child2, Term child3) const with pytest.raises(RuntimeError): @@ -1113,7 +1113,7 @@ def test_uf_iteration(solver): x = solver.mkConst(intSort, "x") y = solver.mkConst(intSort, "y") f = solver.mkConst(funSort, "f") - fxy = solver.mkTerm(kinds.ApplyUf, f, x, y) + fxy = solver.mkTerm(Kind.ApplyUf, f, x, y) # Expecting the uninterpreted function to be one of the children expected_children = [f, x, y] @@ -1133,7 +1133,7 @@ def test_get_info(solver): def test_get_op(solver): bv32 = solver.mkBitVectorSort(32) a = solver.mkConst(bv32, "a") - ext = solver.mkOp(kinds.BVExtract, 2, 1) + ext = solver.mkOp(Kind.BVExtract, 2, 1) exta = solver.mkTerm(ext, a) assert not a.hasOp() @@ -1157,10 +1157,10 @@ def test_get_op(solver): nilTerm = consList.getConstructorTerm("nil") headTerm = consList["cons"].getSelectorTerm("head") - listnil = solver.mkTerm(kinds.ApplyConstructor, nilTerm) - listcons1 = solver.mkTerm(kinds.ApplyConstructor, consTerm, + listnil = solver.mkTerm(Kind.ApplyConstructor, nilTerm) + listcons1 = solver.mkTerm(Kind.ApplyConstructor, consTerm, solver.mkInteger(1), listnil) - listhead = solver.mkTerm(kinds.ApplySelector, headTerm, listcons1) + listhead = solver.mkTerm(Kind.ApplySelector, headTerm, listcons1) assert listnil.hasOp() assert listcons1.hasOp() @@ -1231,14 +1231,14 @@ def test_get_unsat_core3(solver): p = solver.mkConst(intPredSort, "p") zero = solver.mkInteger(0) one = solver.mkInteger(1) - f_x = solver.mkTerm(kinds.ApplyUf, f, x) - f_y = solver.mkTerm(kinds.ApplyUf, f, y) - summ = solver.mkTerm(kinds.Plus, f_x, f_y) - p_0 = solver.mkTerm(kinds.ApplyUf, p, zero) - p_f_y = solver.mkTerm(kinds.ApplyUf, p, f_y) - solver.assertFormula(solver.mkTerm(kinds.Gt, zero, f_x)) - solver.assertFormula(solver.mkTerm(kinds.Gt, zero, f_y)) - solver.assertFormula(solver.mkTerm(kinds.Gt, summ, one)) + f_x = solver.mkTerm(Kind.ApplyUf, f, x) + f_y = solver.mkTerm(Kind.ApplyUf, f, y) + summ = solver.mkTerm(Kind.Plus, f_x, f_y) + p_0 = solver.mkTerm(Kind.ApplyUf, p, zero) + p_f_y = solver.mkTerm(Kind.ApplyUf, p, f_y) + solver.assertFormula(solver.mkTerm(Kind.Gt, zero, f_x)) + solver.assertFormula(solver.mkTerm(Kind.Gt, zero, f_y)) + solver.assertFormula(solver.mkTerm(Kind.Gt, summ, one)) solver.assertFormula(p_0) solver.assertFormula(p_f_y.notTerm()) assert solver.checkSat().isUnsat() @@ -1285,15 +1285,15 @@ def test_get_value3(solver): p = solver.mkConst(intPredSort, "p") zero = solver.mkInteger(0) one = solver.mkInteger(1) - f_x = solver.mkTerm(kinds.ApplyUf, f, x) - f_y = solver.mkTerm(kinds.ApplyUf, f, y) - summ = solver.mkTerm(kinds.Plus, f_x, f_y) - p_0 = solver.mkTerm(kinds.ApplyUf, p, zero) - p_f_y = solver.mkTerm(kinds.ApplyUf, p, f_y) - - solver.assertFormula(solver.mkTerm(kinds.Leq, zero, f_x)) - solver.assertFormula(solver.mkTerm(kinds.Leq, zero, f_y)) - solver.assertFormula(solver.mkTerm(kinds.Leq, summ, one)) + f_x = solver.mkTerm(Kind.ApplyUf, f, x) + f_y = solver.mkTerm(Kind.ApplyUf, f, y) + summ = solver.mkTerm(Kind.Plus, f_x, f_y) + p_0 = solver.mkTerm(Kind.ApplyUf, p, zero) + p_f_y = solver.mkTerm(Kind.ApplyUf, p, f_y) + + solver.assertFormula(solver.mkTerm(Kind.Leq, zero, f_x)) + solver.assertFormula(solver.mkTerm(Kind.Leq, zero, f_y)) + solver.assertFormula(solver.mkTerm(Kind.Leq, summ, one)) solver.assertFormula(p_0.notTerm()) solver.assertFormula(p_f_y) assert solver.checkSat().isSat() @@ -1325,7 +1325,7 @@ def checkSimpleSeparationConstraints(slv): slv.declareSepHeap(integer, integer) x = slv.mkConst(integer, "x") p = slv.mkConst(integer, "p") - heap = slv.mkTerm(kinds.SepPto, p, x) + heap = slv.mkTerm(Kind.SepPto, p, x) slv.assertFormula(heap) nil = slv.mkSepNil(integer) slv.assertFormula(nil.eqTerm(slv.mkReal(5))) @@ -1518,11 +1518,11 @@ def test_simplify(solver): solver.simplify(a) b = solver.mkConst(bvSort, "b") solver.simplify(b) - x_eq_x = solver.mkTerm(kinds.Equal, x, x) + x_eq_x = solver.mkTerm(Kind.Equal, x, x) solver.simplify(x_eq_x) assert solver.mkTrue() != x_eq_x assert solver.mkTrue() == solver.simplify(x_eq_x) - x_eq_b = solver.mkTerm(kinds.Equal, x, b) + x_eq_b = solver.mkTerm(Kind.Equal, x, b) solver.simplify(x_eq_b) assert solver.mkTrue() != x_eq_b assert solver.mkTrue() != solver.simplify(x_eq_b) @@ -1532,24 +1532,24 @@ def test_simplify(solver): i1 = solver.mkConst(solver.getIntegerSort(), "i1") solver.simplify(i1) - i2 = solver.mkTerm(kinds.Mult, i1, solver.mkInteger("23")) + i2 = solver.mkTerm(Kind.Mult, i1, solver.mkInteger("23")) solver.simplify(i2) assert i1 != i2 assert i1 != solver.simplify(i2) - i3 = solver.mkTerm(kinds.Plus, i1, solver.mkInteger(0)) + i3 = solver.mkTerm(Kind.Plus, i1, solver.mkInteger(0)) solver.simplify(i3) assert i1 != i3 assert i1 == solver.simplify(i3) consList = consListSort.getDatatype() dt1 = solver.mkTerm(\ - kinds.ApplyConstructor,\ + Kind.ApplyConstructor,\ consList.getConstructorTerm("cons"),\ solver.mkInteger(0),\ - solver.mkTerm(kinds.ApplyConstructor, consList.getConstructorTerm("nil"))) + solver.mkTerm(Kind.ApplyConstructor, consList.getConstructorTerm("nil"))) solver.simplify(dt1) dt2 = solver.mkTerm(\ - kinds.ApplySelector, consList["cons"].getSelectorTerm("head"), dt1) + Kind.ApplySelector, consList["cons"].getSelectorTerm("head"), dt1) solver.simplify(dt2) b1 = solver.mkVar(bvSort, "b1") @@ -1594,7 +1594,7 @@ def test_check_entailed1(solver): boolSort = solver.getBooleanSort() x = solver.mkConst(boolSort, "x") y = solver.mkConst(boolSort, "y") - z = solver.mkTerm(kinds.And, x, y) + z = solver.mkTerm(Kind.And, x, y) solver.setOption("incremental", "true") solver.checkEntailed(solver.mkTrue()) with pytest.raises(RuntimeError): @@ -1626,30 +1626,30 @@ def test_check_entailed2(solver): zero = solver.mkInteger(0) one = solver.mkInteger(1) # Terms - f_x = solver.mkTerm(kinds.ApplyUf, f, x) - f_y = solver.mkTerm(kinds.ApplyUf, f, y) - summ = solver.mkTerm(kinds.Plus, f_x, f_y) - p_0 = solver.mkTerm(kinds.ApplyUf, p, zero) - p_f_y = solver.mkTerm(kinds.ApplyUf, p, f_y) + f_x = solver.mkTerm(Kind.ApplyUf, f, x) + f_y = solver.mkTerm(Kind.ApplyUf, f, y) + summ = solver.mkTerm(Kind.Plus, f_x, f_y) + p_0 = solver.mkTerm(Kind.ApplyUf, p, zero) + p_f_y = solver.mkTerm(Kind.ApplyUf, p, f_y) # Assertions assertions =\ - solver.mkTerm(kinds.And,\ - [solver.mkTerm(kinds.Leq, zero, f_x), # 0 <= f(x) - solver.mkTerm(kinds.Leq, zero, f_y), # 0 <= f(y) - solver.mkTerm(kinds.Leq, summ, one), # f(x) + f(y) <= 1 + solver.mkTerm(Kind.And,\ + [solver.mkTerm(Kind.Leq, zero, f_x), # 0 <= f(x) + solver.mkTerm(Kind.Leq, zero, f_y), # 0 <= f(y) + solver.mkTerm(Kind.Leq, summ, one), # f(x) + f(y) <= 1 p_0.notTerm(), # not p(0) p_f_y # p(f(y)) ]) solver.checkEntailed(solver.mkTrue()) solver.assertFormula(assertions) - solver.checkEntailed(solver.mkTerm(kinds.Distinct, x, y)) + solver.checkEntailed(solver.mkTerm(Kind.Distinct, x, y)) solver.checkEntailed(\ - [solver.mkFalse(), solver.mkTerm(kinds.Distinct, x, y)]) + [solver.mkFalse(), solver.mkTerm(Kind.Distinct, x, y)]) with pytest.raises(RuntimeError): solver.checkEntailed(n) with pytest.raises(RuntimeError): - solver.checkEntailed([n, solver.mkTerm(kinds.Distinct, x, y)]) + solver.checkEntailed([n, solver.mkTerm(Kind.Distinct, x, y)]) slv = pycvc5.Solver() with pytest.raises(RuntimeError): slv.checkEntailed(solver.mkTrue()) @@ -1676,7 +1676,7 @@ def test_check_sat_assuming1(solver): boolSort = solver.getBooleanSort() x = solver.mkConst(boolSort, "x") y = solver.mkConst(boolSort, "y") - z = solver.mkTerm(kinds.And, x, y) + z = solver.mkTerm(Kind.And, x, y) solver.setOption("incremental", "true") solver.checkSatAssuming(solver.mkTrue()) with pytest.raises(RuntimeError): @@ -1708,31 +1708,31 @@ def test_check_sat_assuming2(solver): zero = solver.mkInteger(0) one = solver.mkInteger(1) # Terms - f_x = solver.mkTerm(kinds.ApplyUf, f, x) - f_y = solver.mkTerm(kinds.ApplyUf, f, y) - summ = solver.mkTerm(kinds.Plus, f_x, f_y) - p_0 = solver.mkTerm(kinds.ApplyUf, p, zero) - p_f_y = solver.mkTerm(kinds.ApplyUf, p, f_y) + f_x = solver.mkTerm(Kind.ApplyUf, f, x) + f_y = solver.mkTerm(Kind.ApplyUf, f, y) + summ = solver.mkTerm(Kind.Plus, f_x, f_y) + p_0 = solver.mkTerm(Kind.ApplyUf, p, zero) + p_f_y = solver.mkTerm(Kind.ApplyUf, p, f_y) # Assertions assertions =\ - solver.mkTerm(kinds.And,\ - [solver.mkTerm(kinds.Leq, zero, f_x), # 0 <= f(x) - solver.mkTerm(kinds.Leq, zero, f_y), # 0 <= f(y) - solver.mkTerm(kinds.Leq, summ, one), # f(x) + f(y) <= 1 + solver.mkTerm(Kind.And,\ + [solver.mkTerm(Kind.Leq, zero, f_x), # 0 <= f(x) + solver.mkTerm(Kind.Leq, zero, f_y), # 0 <= f(y) + solver.mkTerm(Kind.Leq, summ, one), # f(x) + f(y) <= 1 p_0.notTerm(), # not p(0) p_f_y # p(f(y)) ]) solver.checkSatAssuming(solver.mkTrue()) solver.assertFormula(assertions) - solver.checkSatAssuming(solver.mkTerm(kinds.Distinct, x, y)) + solver.checkSatAssuming(solver.mkTerm(Kind.Distinct, x, y)) solver.checkSatAssuming( [solver.mkFalse(), - solver.mkTerm(kinds.Distinct, x, y)]) + solver.mkTerm(Kind.Distinct, x, y)]) with pytest.raises(RuntimeError): solver.checkSatAssuming(n) with pytest.raises(RuntimeError): - solver.checkSatAssuming([n, solver.mkTerm(kinds.Distinct, x, y)]) + solver.checkSatAssuming([n, solver.mkTerm(Kind.Distinct, x, y)]) slv = pycvc5.Solver() with pytest.raises(RuntimeError): slv.checkSatAssuming(solver.mkTrue()) @@ -1762,10 +1762,10 @@ def test_reset_assertions(solver): bvSort = solver.mkBitVectorSort(4) one = solver.mkBitVector(4, 1) x = solver.mkConst(bvSort, "x") - ule = solver.mkTerm(kinds.BVUle, x, one) - srem = solver.mkTerm(kinds.BVSrem, one, x) + ule = solver.mkTerm(Kind.BVUle, x, one) + srem = solver.mkTerm(Kind.BVSrem, one, x) solver.push(4) - slt = solver.mkTerm(kinds.BVSlt, srem, one) + slt = solver.mkTerm(Kind.BVSlt, srem, one) solver.resetAssertions() solver.checkSatAssuming([slt, ule]) @@ -1970,14 +1970,14 @@ def test_define_fun_global(solver): # (assert (or (not f) (not (g true)))) solver.assertFormula( - solver.mkTerm(kinds.Or, f.notTerm(), - solver.mkTerm(kinds.ApplyUf, g, bTrue).notTerm())) + solver.mkTerm(Kind.Or, f.notTerm(), + solver.mkTerm(Kind.ApplyUf, g, bTrue).notTerm())) assert solver.checkSat().isUnsat() solver.resetAssertions() # (assert (or (not f) (not (g true)))) solver.assertFormula( - solver.mkTerm(kinds.Or, f.notTerm(), - solver.mkTerm(kinds.ApplyUf, g, bTrue).notTerm())) + solver.mkTerm(Kind.Or, f.notTerm(), + solver.mkTerm(Kind.ApplyUf, g, bTrue).notTerm())) assert solver.checkSat().isUnsat() @@ -2001,7 +2001,7 @@ def test_get_model_domain_elements(solver): x = solver.mkConst(uSort, "x") y = solver.mkConst(uSort, "y") z = solver.mkConst(uSort, "z") - f = solver.mkTerm(kinds.Distinct, x, y, z) + f = solver.mkTerm(Kind.Distinct, x, y, z) solver.assertFormula(f) solver.checkSat() solver.getModelDomainElements(uSort) @@ -2146,7 +2146,7 @@ def test_is_model_core_symbol(solver): y = solver.mkConst(uSort, "y") z = solver.mkConst(uSort, "z") zero = solver.mkInteger(0) - f = solver.mkTerm(kinds.Not, solver.mkTerm(kinds.Equal, x, y)) + f = solver.mkTerm(Kind.Not, solver.mkTerm(Kind.Equal, x, y)) solver.assertFormula(f) solver.checkSat() assert solver.isModelCoreSymbol(x) @@ -2164,8 +2164,8 @@ def test_issue5893(solver): arr = solver.mkConst(arrsort, "arr") idx = solver.mkConst(bvsort4, "idx") ten = solver.mkBitVector(8, "10", 10) - sel = solver.mkTerm(kinds.Select, arr, idx) - distinct = solver.mkTerm(kinds.Distinct, sel, ten) + sel = solver.mkTerm(Kind.Select, arr, idx) + distinct = solver.mkTerm(Kind.Distinct, sel, ten) distinct.getOp() @@ -2177,8 +2177,8 @@ def test_issue7000(solver): t7 = solver.mkConst(s3, "_x5") t37 = solver.mkConst(s2, "_x32") t59 = solver.mkConst(s2, "_x51") - t72 = solver.mkTerm(kinds.Equal, t37, t59) - t74 = solver.mkTerm(kinds.Gt, t4, t7) + t72 = solver.mkTerm(Kind.Equal, t37, t59) + t74 = solver.mkTerm(Kind.Gt, t4, t7) # throws logic exception since logic is not higher order by default with pytest.raises(RuntimeError): solver.checkEntailed(t72, t74, t72, t72) @@ -2247,7 +2247,7 @@ def test_tuple_project(solver): solver.mkBoolean(True), \ solver.mkInteger(3),\ solver.mkString("C"),\ - solver.mkTerm(kinds.SetSingleton, solver.mkString("Z"))] + solver.mkTerm(Kind.SetSingleton, solver.mkString("Z"))] tuple = solver.mkTuple(sorts, elements) @@ -2258,22 +2258,22 @@ def test_tuple_project(solver): indices5 = [4] indices6 = [0, 4] - solver.mkTerm(solver.mkOp(kinds.TupleProject, indices1), tuple) + solver.mkTerm(solver.mkOp(Kind.TupleProject, indices1), tuple) - solver.mkTerm(solver.mkOp(kinds.TupleProject, indices2), tuple) + solver.mkTerm(solver.mkOp(Kind.TupleProject, indices2), tuple) - solver.mkTerm(solver.mkOp(kinds.TupleProject, indices3), tuple) + solver.mkTerm(solver.mkOp(Kind.TupleProject, indices3), tuple) - solver.mkTerm(solver.mkOp(kinds.TupleProject, indices4), tuple) + solver.mkTerm(solver.mkOp(Kind.TupleProject, indices4), tuple) with pytest.raises(RuntimeError): - solver.mkTerm(solver.mkOp(kinds.TupleProject, indices5), tuple) + solver.mkTerm(solver.mkOp(Kind.TupleProject, indices5), tuple) with pytest.raises(RuntimeError): - solver.mkTerm(solver.mkOp(kinds.TupleProject, indices6), tuple) + solver.mkTerm(solver.mkOp(Kind.TupleProject, indices6), tuple) indices = [0, 3, 2, 0, 1, 2] - op = solver.mkOp(kinds.TupleProject, indices) + op = solver.mkOp(Kind.TupleProject, indices) projection = solver.mkTerm(op, tuple) datatype = tuple.getSort().getDatatype() @@ -2282,7 +2282,7 @@ def test_tuple_project(solver): for i in indices: selectorTerm = constructor[i].getSelectorTerm() - selectedTerm = solver.mkTerm(kinds.ApplySelector, selectorTerm, tuple) + selectedTerm = solver.mkTerm(Kind.ApplySelector, selectorTerm, tuple) simplifiedTerm = solver.simplify(selectedTerm) assert elements[i] == simplifiedTerm diff --git a/test/unit/api/python/test_sort.py b/test/unit/api/python/test_sort.py index 98cf76d76..9c9458792 100644 --- a/test/unit/api/python/test_sort.py +++ b/test/unit/api/python/test_sort.py @@ -17,7 +17,6 @@ import pytest import pycvc5 -from pycvc5 import kinds from pycvc5 import Sort diff --git a/test/unit/api/python/test_term.py b/test/unit/api/python/test_term.py index 49314638f..27702bd23 100644 --- a/test/unit/api/python/test_term.py +++ b/test/unit/api/python/test_term.py @@ -13,7 +13,7 @@ import pytest import pycvc5 -from pycvc5 import kinds +from pycvc5 import Kind from pycvc5 import Sort, Term from fractions import Fraction @@ -73,23 +73,23 @@ def test_get_kind(solver): zero = solver.mkInteger(0) zero.getKind() - f_x = solver.mkTerm(kinds.ApplyUf, f, x) + f_x = solver.mkTerm(Kind.ApplyUf, f, x) f_x.getKind() - f_y = solver.mkTerm(kinds.ApplyUf, f, y) + f_y = solver.mkTerm(Kind.ApplyUf, f, y) f_y.getKind() - sum = solver.mkTerm(kinds.Plus, f_x, f_y) + sum = solver.mkTerm(Kind.Plus, f_x, f_y) sum.getKind() - p_0 = solver.mkTerm(kinds.ApplyUf, p, zero) + p_0 = solver.mkTerm(Kind.ApplyUf, p, zero) p_0.getKind() - p_f_y = solver.mkTerm(kinds.ApplyUf, p, f_y) + p_f_y = solver.mkTerm(Kind.ApplyUf, p, f_y) p_f_y.getKind() # Sequence kinds do not exist internally, test that the API properly # converts them back. seqSort = solver.mkSequenceSort(intSort) s = solver.mkConst(seqSort, "s") - ss = solver.mkTerm(kinds.SeqConcat, s, s) - assert ss.getKind() == kinds.SeqConcat + ss = solver.mkTerm(Kind.SeqConcat, s, s) + assert ss.getKind() == Kind.SeqConcat def test_get_sort(solver): @@ -120,19 +120,19 @@ def test_get_sort(solver): zero.getSort() assert zero.getSort() == intSort - f_x = solver.mkTerm(kinds.ApplyUf, f, x) + f_x = solver.mkTerm(Kind.ApplyUf, f, x) f_x.getSort() assert f_x.getSort() == intSort - f_y = solver.mkTerm(kinds.ApplyUf, f, y) + f_y = solver.mkTerm(Kind.ApplyUf, f, y) f_y.getSort() assert f_y.getSort() == intSort - sum = solver.mkTerm(kinds.Plus, f_x, f_y) + sum = solver.mkTerm(Kind.Plus, f_x, f_y) sum.getSort() assert sum.getSort() == intSort - p_0 = solver.mkTerm(kinds.ApplyUf, p, zero) + p_0 = solver.mkTerm(Kind.ApplyUf, p, zero) p_0.getSort() assert p_0.getSort() == boolSort - p_f_y = solver.mkTerm(kinds.ApplyUf, p, f_y) + p_f_y = solver.mkTerm(Kind.ApplyUf, p, f_y) p_f_y.getSort() assert p_f_y.getSort() == boolSort @@ -151,8 +151,8 @@ def test_get_op(solver): with pytest.raises(RuntimeError): x.getOp() - ab = solver.mkTerm(kinds.Select, a, b) - ext = solver.mkOp(kinds.BVExtract, 4, 0) + ab = solver.mkTerm(Kind.Select, a, b) + ext = solver.mkOp(Kind.BVExtract, 4, 0) extb = solver.mkTerm(ext, b) assert ab.hasOp() @@ -163,7 +163,7 @@ def test_get_op(solver): assert extb.getOp() == ext f = solver.mkConst(funsort, "f") - fx = solver.mkTerm(kinds.ApplyUf, f, x) + fx = solver.mkTerm(Kind.ApplyUf, f, x) assert not f.hasOp() with pytest.raises(RuntimeError): @@ -192,11 +192,11 @@ def test_get_op(solver): headOpTerm = list1["cons"].getSelectorTerm("head") tailOpTerm = list1["cons"].getSelectorTerm("tail") - nilTerm = solver.mkTerm(kinds.ApplyConstructor, nilOpTerm) - consTerm = solver.mkTerm(kinds.ApplyConstructor, consOpTerm, + nilTerm = solver.mkTerm(Kind.ApplyConstructor, nilOpTerm) + consTerm = solver.mkTerm(Kind.ApplyConstructor, consOpTerm, solver.mkInteger(0), nilTerm) - headTerm = solver.mkTerm(kinds.ApplySelector, headOpTerm, consTerm) - tailTerm = solver.mkTerm(kinds.ApplySelector, tailOpTerm, consTerm) + headTerm = solver.mkTerm(Kind.ApplySelector, headOpTerm, consTerm) + tailTerm = solver.mkTerm(Kind.ApplySelector, tailOpTerm, consTerm) assert nilTerm.hasOp() assert consTerm.hasOp() @@ -255,15 +255,15 @@ def test_not_term(solver): zero = solver.mkInteger(0) with pytest.raises(RuntimeError): zero.notTerm() - f_x = solver.mkTerm(kinds.ApplyUf, f, x) + f_x = solver.mkTerm(Kind.ApplyUf, f, x) with pytest.raises(RuntimeError): f_x.notTerm() - sum = solver.mkTerm(kinds.Plus, f_x, f_x) + sum = solver.mkTerm(Kind.Plus, f_x, f_x) with pytest.raises(RuntimeError): sum.notTerm() - p_0 = solver.mkTerm(kinds.ApplyUf, p, zero) + p_0 = solver.mkTerm(Kind.ApplyUf, p, zero) p_0.notTerm() - p_f_x = solver.mkTerm(kinds.ApplyUf, p, f_x) + p_f_x = solver.mkTerm(Kind.ApplyUf, p, f_x) p_f_x.notTerm() @@ -312,7 +312,7 @@ def test_and_term(solver): zero.andTerm(p) with pytest.raises(RuntimeError): zero.andTerm(zero) - f_x = solver.mkTerm(kinds.ApplyUf, f, x) + f_x = solver.mkTerm(Kind.ApplyUf, f, x) with pytest.raises(RuntimeError): f_x.andTerm(b) with pytest.raises(RuntimeError): @@ -325,7 +325,7 @@ def test_and_term(solver): f_x.andTerm(zero) with pytest.raises(RuntimeError): f_x.andTerm(f_x) - sum = solver.mkTerm(kinds.Plus, f_x, f_x) + sum = solver.mkTerm(Kind.Plus, f_x, f_x) with pytest.raises(RuntimeError): sum.andTerm(b) with pytest.raises(RuntimeError): @@ -340,7 +340,7 @@ def test_and_term(solver): sum.andTerm(f_x) with pytest.raises(RuntimeError): sum.andTerm(sum) - p_0 = solver.mkTerm(kinds.ApplyUf, p, zero) + p_0 = solver.mkTerm(Kind.ApplyUf, p, zero) p_0.andTerm(b) with pytest.raises(RuntimeError): p_0.andTerm(x) @@ -355,7 +355,7 @@ def test_and_term(solver): with pytest.raises(RuntimeError): p_0.andTerm(sum) p_0.andTerm(p_0) - p_f_x = solver.mkTerm(kinds.ApplyUf, p, f_x) + p_f_x = solver.mkTerm(Kind.ApplyUf, p, f_x) p_f_x.andTerm(b) with pytest.raises(RuntimeError): p_f_x.andTerm(x) @@ -418,7 +418,7 @@ def test_or_term(solver): zero.orTerm(p) with pytest.raises(RuntimeError): zero.orTerm(zero) - f_x = solver.mkTerm(kinds.ApplyUf, f, x) + f_x = solver.mkTerm(Kind.ApplyUf, f, x) with pytest.raises(RuntimeError): f_x.orTerm(b) with pytest.raises(RuntimeError): @@ -431,7 +431,7 @@ def test_or_term(solver): f_x.orTerm(zero) with pytest.raises(RuntimeError): f_x.orTerm(f_x) - sum = solver.mkTerm(kinds.Plus, f_x, f_x) + sum = solver.mkTerm(Kind.Plus, f_x, f_x) with pytest.raises(RuntimeError): sum.orTerm(b) with pytest.raises(RuntimeError): @@ -446,7 +446,7 @@ def test_or_term(solver): sum.orTerm(f_x) with pytest.raises(RuntimeError): sum.orTerm(sum) - p_0 = solver.mkTerm(kinds.ApplyUf, p, zero) + p_0 = solver.mkTerm(Kind.ApplyUf, p, zero) p_0.orTerm(b) with pytest.raises(RuntimeError): p_0.orTerm(x) @@ -461,7 +461,7 @@ def test_or_term(solver): with pytest.raises(RuntimeError): p_0.orTerm(sum) p_0.orTerm(p_0) - p_f_x = solver.mkTerm(kinds.ApplyUf, p, f_x) + p_f_x = solver.mkTerm(Kind.ApplyUf, p, f_x) p_f_x.orTerm(b) with pytest.raises(RuntimeError): p_f_x.orTerm(x) @@ -524,7 +524,7 @@ def test_xor_term(solver): zero.xorTerm(p) with pytest.raises(RuntimeError): zero.xorTerm(zero) - f_x = solver.mkTerm(kinds.ApplyUf, f, x) + f_x = solver.mkTerm(Kind.ApplyUf, f, x) with pytest.raises(RuntimeError): f_x.xorTerm(b) with pytest.raises(RuntimeError): @@ -537,7 +537,7 @@ def test_xor_term(solver): f_x.xorTerm(zero) with pytest.raises(RuntimeError): f_x.xorTerm(f_x) - sum = solver.mkTerm(kinds.Plus, f_x, f_x) + sum = solver.mkTerm(Kind.Plus, f_x, f_x) with pytest.raises(RuntimeError): sum.xorTerm(b) with pytest.raises(RuntimeError): @@ -552,7 +552,7 @@ def test_xor_term(solver): sum.xorTerm(f_x) with pytest.raises(RuntimeError): sum.xorTerm(sum) - p_0 = solver.mkTerm(kinds.ApplyUf, p, zero) + p_0 = solver.mkTerm(Kind.ApplyUf, p, zero) p_0.xorTerm(b) with pytest.raises(RuntimeError): p_0.xorTerm(x) @@ -567,7 +567,7 @@ def test_xor_term(solver): with pytest.raises(RuntimeError): p_0.xorTerm(sum) p_0.xorTerm(p_0) - p_f_x = solver.mkTerm(kinds.ApplyUf, p, f_x) + p_f_x = solver.mkTerm(Kind.ApplyUf, p, f_x) p_f_x.xorTerm(b) with pytest.raises(RuntimeError): p_f_x.xorTerm(x) @@ -626,7 +626,7 @@ def test_eq_term(solver): with pytest.raises(RuntimeError): zero.eqTerm(p) zero.eqTerm(zero) - f_x = solver.mkTerm(kinds.ApplyUf, f, x) + f_x = solver.mkTerm(Kind.ApplyUf, f, x) with pytest.raises(RuntimeError): f_x.eqTerm(b) with pytest.raises(RuntimeError): @@ -637,7 +637,7 @@ def test_eq_term(solver): f_x.eqTerm(p) f_x.eqTerm(zero) f_x.eqTerm(f_x) - sum = solver.mkTerm(kinds.Plus, f_x, f_x) + sum = solver.mkTerm(Kind.Plus, f_x, f_x) with pytest.raises(RuntimeError): sum.eqTerm(b) with pytest.raises(RuntimeError): @@ -649,7 +649,7 @@ def test_eq_term(solver): sum.eqTerm(zero) sum.eqTerm(f_x) sum.eqTerm(sum) - p_0 = solver.mkTerm(kinds.ApplyUf, p, zero) + p_0 = solver.mkTerm(Kind.ApplyUf, p, zero) p_0.eqTerm(b) with pytest.raises(RuntimeError): p_0.eqTerm(x) @@ -664,7 +664,7 @@ def test_eq_term(solver): with pytest.raises(RuntimeError): p_0.eqTerm(sum) p_0.eqTerm(p_0) - p_f_x = solver.mkTerm(kinds.ApplyUf, p, f_x) + p_f_x = solver.mkTerm(Kind.ApplyUf, p, f_x) p_f_x.eqTerm(b) with pytest.raises(RuntimeError): p_f_x.eqTerm(x) @@ -727,7 +727,7 @@ def test_imp_term(solver): zero.impTerm(p) with pytest.raises(RuntimeError): zero.impTerm(zero) - f_x = solver.mkTerm(kinds.ApplyUf, f, x) + f_x = solver.mkTerm(Kind.ApplyUf, f, x) with pytest.raises(RuntimeError): f_x.impTerm(b) with pytest.raises(RuntimeError): @@ -740,7 +740,7 @@ def test_imp_term(solver): f_x.impTerm(zero) with pytest.raises(RuntimeError): f_x.impTerm(f_x) - sum = solver.mkTerm(kinds.Plus, f_x, f_x) + sum = solver.mkTerm(Kind.Plus, f_x, f_x) with pytest.raises(RuntimeError): sum.impTerm(b) with pytest.raises(RuntimeError): @@ -755,7 +755,7 @@ def test_imp_term(solver): sum.impTerm(f_x) with pytest.raises(RuntimeError): sum.impTerm(sum) - p_0 = solver.mkTerm(kinds.ApplyUf, p, zero) + p_0 = solver.mkTerm(Kind.ApplyUf, p, zero) p_0.impTerm(b) with pytest.raises(RuntimeError): p_0.impTerm(x) @@ -770,7 +770,7 @@ def test_imp_term(solver): with pytest.raises(RuntimeError): p_0.impTerm(sum) p_0.impTerm(p_0) - p_f_x = solver.mkTerm(kinds.ApplyUf, p, f_x) + p_f_x = solver.mkTerm(Kind.ApplyUf, p, f_x) p_f_x.impTerm(b) with pytest.raises(RuntimeError): p_f_x.impTerm(x) @@ -827,22 +827,22 @@ def test_ite_term(solver): zero.iteTerm(x, x) with pytest.raises(RuntimeError): zero.iteTerm(x, b) - f_x = solver.mkTerm(kinds.ApplyUf, f, x) + f_x = solver.mkTerm(Kind.ApplyUf, f, x) with pytest.raises(RuntimeError): f_x.iteTerm(b, b) with pytest.raises(RuntimeError): f_x.iteTerm(b, x) - sum = solver.mkTerm(kinds.Plus, f_x, f_x) + sum = solver.mkTerm(Kind.Plus, f_x, f_x) with pytest.raises(RuntimeError): sum.iteTerm(x, x) with pytest.raises(RuntimeError): sum.iteTerm(b, x) - p_0 = solver.mkTerm(kinds.ApplyUf, p, zero) + p_0 = solver.mkTerm(Kind.ApplyUf, p, zero) p_0.iteTerm(b, b) p_0.iteTerm(x, x) with pytest.raises(RuntimeError): p_0.iteTerm(x, b) - p_f_x = solver.mkTerm(kinds.ApplyUf, p, f_x) + p_f_x = solver.mkTerm(Kind.ApplyUf, p, f_x) p_f_x.iteTerm(b, b) p_f_x.iteTerm(x, x) with pytest.raises(RuntimeError): @@ -860,8 +860,8 @@ def test_substitute(solver): x = solver.mkConst(solver.getIntegerSort(), "x") one = solver.mkInteger(1) ttrue = solver.mkTrue() - xpx = solver.mkTerm(kinds.Plus, x, x) - onepone = solver.mkTerm(kinds.Plus, one, one) + xpx = solver.mkTerm(Kind.Plus, x, x) + onepone = solver.mkTerm(Kind.Plus, one, one) assert xpx.substitute(x, one) == onepone assert onepone.substitute(one, x) == xpx @@ -871,8 +871,8 @@ def test_substitute(solver): # simultaneous substitution y = solver.mkConst(solver.getIntegerSort(), "y") - xpy = solver.mkTerm(kinds.Plus, x, y) - xpone = solver.mkTerm(kinds.Plus, y, one) + xpy = solver.mkTerm(Kind.Plus, x, y) + xpone = solver.mkTerm(Kind.Plus, y, one) es = [] rs = [] es.append(x) @@ -917,8 +917,8 @@ def test_substitute(solver): def test_term_compare(solver): t1 = solver.mkInteger(1) - t2 = solver.mkTerm(kinds.Plus, solver.mkInteger(2), solver.mkInteger(2)) - t3 = solver.mkTerm(kinds.Plus, solver.mkInteger(2), solver.mkInteger(2)) + t2 = solver.mkTerm(Kind.Plus, solver.mkInteger(2), solver.mkInteger(2)) + t3 = solver.mkTerm(Kind.Plus, solver.mkInteger(2), solver.mkInteger(2)) assert t2 >= t3 assert t2 <= t3 assert (t1 > t2) != (t1 < t2) @@ -928,7 +928,7 @@ def test_term_compare(solver): def test_term_children(solver): # simple term 2+3 two = solver.mkInteger(2) - t1 = solver.mkTerm(kinds.Plus, two, solver.mkInteger(3)) + t1 = solver.mkTerm(Kind.Plus, two, solver.mkInteger(3)) assert t1[0] == two assert t1.getNumChildren() == 2 tnull = Term(solver) @@ -939,8 +939,8 @@ def test_term_children(solver): intSort = solver.getIntegerSort() fsort = solver.mkFunctionSort(intSort, intSort) f = solver.mkConst(fsort, "f") - t2 = solver.mkTerm(kinds.ApplyUf, f, two) - # due to our higher-order view of terms, we treat f as a child of kinds.ApplyUf + t2 = solver.mkTerm(Kind.ApplyUf, f, two) + # due to our higher-order view of terms, we treat f as a child of Kind.ApplyUf assert t2.getNumChildren() == 2 assert t2[0] == f assert t2[1] == two @@ -993,11 +993,11 @@ def test_get_set(solver): i2 = solver.mkInteger(7) s1 = solver.mkEmptySet(s) - s2 = solver.mkTerm(kinds.SetSingleton, i1) - s3 = solver.mkTerm(kinds.SetSingleton, i1) - s4 = solver.mkTerm(kinds.SetSingleton, i2) + s2 = solver.mkTerm(Kind.SetSingleton, i1) + s3 = solver.mkTerm(Kind.SetSingleton, i1) + s4 = solver.mkTerm(Kind.SetSingleton, i2) s5 = solver.mkTerm( - kinds.SetUnion, s2, solver.mkTerm(kinds.SetUnion, s3, s4)) + Kind.SetUnion, s2, solver.mkTerm(Kind.SetUnion, s3, s4)) assert s1.isSetValue() assert s2.isSetValue() @@ -1021,11 +1021,11 @@ def test_get_sequence(solver): i2 = solver.mkInteger(7) s1 = solver.mkEmptySequence(s) - s2 = solver.mkTerm(kinds.SeqUnit, i1) - s3 = solver.mkTerm(kinds.SeqUnit, i1) - s4 = solver.mkTerm(kinds.SeqUnit, i2) - s5 = solver.mkTerm(kinds.SeqConcat, s2, - solver.mkTerm(kinds.SeqConcat, s3, s4)) + s2 = solver.mkTerm(Kind.SeqUnit, i1) + s3 = solver.mkTerm(Kind.SeqUnit, i1) + s4 = solver.mkTerm(Kind.SeqUnit, i2) + s5 = solver.mkTerm(Kind.SeqConcat, s2, + solver.mkTerm(Kind.SeqConcat, s3, s4)) assert s1.isSequenceValue() assert not s2.isSequenceValue() @@ -1244,18 +1244,18 @@ def test_const_array(solver): one = solver.mkInteger(1) constarr = solver.mkConstArray(arrsort, one) - assert constarr.getKind() == kinds.ConstArray + assert constarr.getKind() == Kind.ConstArray assert constarr.getConstArrayBase() == one with pytest.raises(RuntimeError): a.getConstArrayBase() arrsort = solver.mkArraySort(solver.getRealSort(), solver.getRealSort()) zero_array = solver.mkConstArray(arrsort, solver.mkReal(0)) - stores = solver.mkTerm(kinds.Store, zero_array, solver.mkReal(1), + stores = solver.mkTerm(Kind.Store, zero_array, solver.mkReal(1), solver.mkReal(2)) - stores = solver.mkTerm(kinds.Store, stores, solver.mkReal(2), + stores = solver.mkTerm(Kind.Store, stores, solver.mkReal(2), solver.mkReal(3)) - stores = solver.mkTerm(kinds.Store, stores, solver.mkReal(4), + stores = solver.mkTerm(Kind.Store, stores, solver.mkReal(4), solver.mkReal(5)) @@ -1264,14 +1264,14 @@ def test_const_sequence_elements(solver): seqsort = solver.mkSequenceSort(realsort) s = solver.mkEmptySequence(seqsort) - assert s.getKind() == kinds.ConstSequence + assert s.getKind() == Kind.ConstSequence # empty sequence has zero elements cs = s.getSequenceValue() assert len(cs) == 0 # A seq.unit app is not a constant sequence (regardless of whether it is # applied to a constant). - su = solver.mkTerm(kinds.SeqUnit, solver.mkReal(1)) + su = solver.mkTerm(Kind.SeqUnit, solver.mkReal(1)) with pytest.raises(RuntimeError): su.getSequenceValue() diff --git a/test/unit/api/python/test_to_python_obj.py b/test/unit/api/python/test_to_python_obj.py index bb30fae8f..bef7e78c0 100644 --- a/test/unit/api/python/test_to_python_obj.py +++ b/test/unit/api/python/test_to_python_obj.py @@ -15,7 +15,7 @@ from fractions import Fraction import pytest import pycvc5 -from pycvc5 import kinds +from pycvc5 import Kind def testGetBool(): @@ -54,9 +54,9 @@ def testGetArray(): solver = pycvc5.Solver() arrsort = solver.mkArraySort(solver.getRealSort(), solver.getRealSort()) zero_array = solver.mkConstArray(arrsort, solver.mkInteger(0)) - stores = solver.mkTerm(kinds.Store, zero_array, solver.mkInteger(1), solver.mkInteger(2)) - stores = solver.mkTerm(kinds.Store, stores, solver.mkInteger(2), solver.mkInteger(3)) - stores = solver.mkTerm(kinds.Store, stores, solver.mkInteger(4), solver.mkInteger(5)) + stores = solver.mkTerm(Kind.Store, zero_array, solver.mkInteger(1), solver.mkInteger(2)) + stores = solver.mkTerm(Kind.Store, stores, solver.mkInteger(2), solver.mkInteger(3)) + stores = solver.mkTerm(Kind.Store, stores, solver.mkInteger(4), solver.mkInteger(5)) array_dict = stores.toPythonObj() @@ -90,7 +90,7 @@ def testGetValueInt(): intsort = solver.getIntegerSort() x = solver.mkConst(intsort, "x") - solver.assertFormula(solver.mkTerm(kinds.Equal, x, solver.mkInteger(6))) + solver.assertFormula(solver.mkTerm(Kind.Equal, x, solver.mkInteger(6))) r = solver.checkSat() assert r.isSat() @@ -106,8 +106,8 @@ def testGetValueReal(): realsort = solver.getRealSort() x = solver.mkConst(realsort, "x") y = solver.mkConst(realsort, "y") - solver.assertFormula(solver.mkTerm(kinds.Equal, x, solver.mkReal("6"))) - solver.assertFormula(solver.mkTerm(kinds.Equal, y, solver.mkReal("8.33"))) + solver.assertFormula(solver.mkTerm(Kind.Equal, x, solver.mkReal("6"))) + solver.assertFormula(solver.mkTerm(Kind.Equal, y, solver.mkReal("8.33"))) r = solver.checkSat() assert r.isSat() diff --git a/test/unit/context/cdlist_black.cpp b/test/unit/context/cdlist_black.cpp index a8d9f952b..6bc48f9d0 100644 --- a/test/unit/context/cdlist_black.cpp +++ b/test/unit/context/cdlist_black.cpp @@ -20,7 +20,6 @@ #include "base/exception.h" #include "context/cdlist.h" -#include "memory.h" #include "test_context.h" namespace cvc5 { @@ -135,25 +134,6 @@ TEST_F(TestContextBlackCDList, empty_iterator) list->deleteSelf(); } -TEST_F(TestContextBlackCDList, out_of_memory) -{ -#ifndef CVC5_MEMORY_LIMITING_DISABLED - CDList<uint32_t> list(d_context.get()); - test::WithLimitedMemory wlm(1); - - ASSERT_THROW( - { - // We cap it at UINT32_MAX, preferring to terminate with a - // failure than run indefinitely. - for (uint32_t i = 0; i < UINT32_MAX; ++i) - { - list.push_back(i); - } - }, - std::bad_alloc); -#endif -} - TEST_F(TestContextBlackCDList, pop_below_level_created) { d_context->push(); diff --git a/test/unit/memory.h b/test/unit/memory.h deleted file mode 100644 index 574488e21..000000000 --- a/test/unit/memory.h +++ /dev/null @@ -1,93 +0,0 @@ -/****************************************************************************** - * Top contributors (to current version): - * Tim King, Morgan Deters, Aina Niemetz - * - * This file is part of the cvc5 project. - * - * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS - * in the top-level source directory and their institutional affiliations. - * All rights reserved. See the file COPYING in the top-level source - * directory for licensing information. - * **************************************************************************** - * - * Utility class to help testing out-of-memory conditions. - * - * Use it like this (for example): - * - * cvc5::test::WithLimitedMemory wlm(amount); - * ASSERT_THROW( foo(), bad_alloc ); - * - * The WithLimitedMemory destructor will re-establish the previous limit. - * - * This class does not exist in CVC5_MEMORY_LIMITING_DISABLED is defined. - * This can be disabled for a variety of reasons. - */ - -#include "test.h" - -#ifndef __CVC5__TEST__UNIT__MEMORY_H -#define __CVC5__TEST__UNIT__MEMORY_H - -#include <string> -#include <sys/resource.h> -#include <sys/time.h> - -#include "base/check.h" -#include "base/configuration_private.h" - -// Conditionally define CVC5_MEMORY_LIMITING_DISABLED. -#ifdef __APPLE__ -#define CVC5_MEMORY_LIMITING_DISABLED 1 -#define CVC5_MEMORY_LIMITING_DISABLED_REASON "setrlimit() is broken on Mac." -#else /* __APPLE__ */ - -// Tests cannot expect bad_alloc to be thrown due to limit memory using -// setrlimit when ASAN is enable. ASAN instead aborts on mmap failures. -# if IS_ASAN_BUILD -#define CVC5_MEMORY_LIMITING_DISABLED 1 -#define CVC5_MEMORY_LIMITING_DISABLED_REASON "ASAN's mmap failures abort." -# endif -#endif - -namespace cvc5 { -namespace test { - -#ifndef CVC5_MEMORY_LIMITING_DISABLED -class WithLimitedMemory { - public: - WithLimitedMemory() { remember(); } - - WithLimitedMemory(rlim_t amount) { - remember(); - set(amount); - } - - ~WithLimitedMemory() { set(d_prevAmount); } - - void set(rlim_t amount) { - struct rlimit rlim; - rlim.rlim_cur = amount; - rlim.rlim_max = RLIM_INFINITY; - ASSERT_EQ(setrlimit(RLIMIT_AS, &rlim), 0); - } - - private: - void remember() { - struct rlimit rlim; - ASSERT_EQ(getrlimit(RLIMIT_AS, &rlim), 0); - d_prevAmount = rlim.rlim_cur; - } - - rlim_t d_prevAmount; -}; /* class WithLimitedMemory */ -#endif - -} // namespace test -} // namespace cvc5 - -// Remove CVC5_MEMORY_LIMITING_DISABLED_REASON if it is defined. -#ifdef CVC5_MEMORY_LIMITING_DISABLED_REASON -#undef CVC5_MEMORY_LIMITING_DISABLED_REASON -#endif /* CVC5_MEMORY_LIMITING_DISABLED_REASON */ - -#endif /* __CVC5__TEST__MEMORY_H */ diff --git a/test/unit/options/options_black.cpp b/test/unit/options/options_black.cpp index 1ab4bce23..0aa160677 100644 --- a/test/unit/options/options_black.cpp +++ b/test/unit/options/options_black.cpp @@ -92,11 +92,13 @@ TEST_F(TestBlackOptions, set) } EXPECT_NO_THROW(d_solver.setOption( name, std::to_string((range.first + range.second) / 2))); + EXPECT_THROW(d_solver.setOption(name, "0123abc"), CVC5ApiOptionException); }, [this, &name](const OptionInfo::NumberInfo<uint64_t>& v) { std::pair<uint64_t, uint64_t> range{ std::numeric_limits<uint64_t>::min(), std::numeric_limits<uint64_t>::max()}; + EXPECT_THROW(d_solver.setOption(name, "-1"), CVC5ApiOptionException); if (v.minimum) { EXPECT_THROW( @@ -117,6 +119,7 @@ TEST_F(TestBlackOptions, set) } EXPECT_NO_THROW(d_solver.setOption( name, std::to_string((range.first + range.second) / 2))); + EXPECT_THROW(d_solver.setOption(name, "0123abc"), CVC5ApiOptionException); }, [this, &name](const OptionInfo::NumberInfo<double>& v) { std::pair<double, double> range{ @@ -149,7 +152,9 @@ TEST_F(TestBlackOptions, set) for (const auto& m : v.modes) { d_solver.setOption(name, m); + EXPECT_EQ(d_solver.getOption(name), m); } + EXPECT_DEATH(d_solver.setOption(name, "help"), ""); }, }, info.valueInfo); diff --git a/test/unit/theory/theory_bv_int_blaster_white.cpp b/test/unit/theory/theory_bv_int_blaster_white.cpp index 2ad8695de..e8238ecbb 100644 --- a/test/unit/theory/theory_bv_int_blaster_white.cpp +++ b/test/unit/theory/theory_bv_int_blaster_white.cpp @@ -61,7 +61,7 @@ TEST_F(TestTheoryWhiteBvIntblaster, intblaster_constants) Env env(d_nodeManager, &opts); env.d_logic.setLogicString("QF_UFBV"); env.d_logic.lock(); - IntBlaster intBlaster(env, options::SolveBVAsIntMode::SUM, 1, false); + IntBlaster intBlaster(env, options::SolveBVAsIntMode::SUM, 1); Node result = intBlaster.translateNoChildren(bv7_4, lemmas, skolems); Node seven = d_nodeManager->mkConst(CONST_RATIONAL, Rational(7)); ASSERT_EQ(seven, result); @@ -86,7 +86,7 @@ TEST_F(TestTheoryWhiteBvIntblaster, intblaster_symbolic_constant) Env env(d_nodeManager, &opts); env.d_logic.setLogicString("QF_UFBV"); env.d_logic.lock(); - IntBlaster intBlaster(env, options::SolveBVAsIntMode::SUM, 1, true); + IntBlaster intBlaster(env, options::SolveBVAsIntMode::SUM, 1); Node result = intBlaster.translateNoChildren(bv, lemmas, skolems); ASSERT_TRUE(result.isVar() && result.getType().isInteger()); @@ -116,7 +116,7 @@ TEST_F(TestTheoryWhiteBvIntblaster, intblaster_uf) Env env(d_nodeManager, &opts); env.d_logic.setLogicString("QF_UFBV"); env.d_logic.lock(); - IntBlaster intBlaster(env, options::SolveBVAsIntMode::SUM, 1, true); + IntBlaster intBlaster(env, options::SolveBVAsIntMode::SUM, 1); Node result = intBlaster.translateNoChildren(f, lemmas, skolems); TypeNode resultType = result.getType(); std::vector<TypeNode> resultDomain = resultType.getArgTypes(); @@ -130,7 +130,7 @@ TEST_F(TestTheoryWhiteBvIntblaster, intblaster_uf) } /** Check all cases of the translation. - * This is a sanity check, that noly verifies + * This is a sanity check, that only verifies * the expected type, and that there were no * failures. */ @@ -143,7 +143,7 @@ TEST_F(TestTheoryWhiteBvIntblaster, intblaster_with_children) Env env(d_nodeManager, &opts); env.d_logic.setLogicString("QF_UFBV"); env.d_logic.lock(); - IntBlaster intBlaster(env, options::SolveBVAsIntMode::SUM, 1, true); + IntBlaster intBlaster(env, options::SolveBVAsIntMode::SUM, 1); // bit-vector variables TypeNode bvType = d_nodeManager->mkBitVectorType(4); @@ -280,5 +280,45 @@ TEST_F(TestTheoryWhiteBvIntblaster, intblaster_with_children) ASSERT_TRUE(result.getType().isInteger()); } +/** Check AND translation for bitwise option. + * This is a sanity check, that only verifies + * the expected kind, and that there were no + * failures. + */ +TEST_F(TestTheoryWhiteBvIntblaster, intblaster_bitwise) +{ + // place holders for lemmas and skolem + std::vector<Node> lemmas; + std::map<Node, Node> skolems; + Options opts; + Env env(d_nodeManager, &opts); + env.d_logic.setLogicString("QF_UFBV"); + env.d_logic.lock(); + IntBlaster intBlaster(env, options::SolveBVAsIntMode::BITWISE, 1); + + // bit-vector variables + TypeNode bvType = d_nodeManager->mkBitVectorType(4); + Node v1 = d_nodeManager->mkVar("v1", bvType); + Node v2 = d_nodeManager->mkVar("v2", bvType); + + // translated integer variables + Node i1 = intBlaster.translateNoChildren(v1, lemmas, skolems); + Node i2 = intBlaster.translateNoChildren(v2, lemmas, skolems); + + // if original is BV, result should be Int. + // Otherwise, they should have the same type. + Node original; + Node result; + + // bvand + original = d_nodeManager->mkNode(BITVECTOR_AND, v1, v2); + size_t orig_num_lemmas = lemmas.size(); + result = intBlaster.translateWithChildren(original, {i1, i2}, lemmas); + // should have kind skolem, would use bitwise comparisons to refine + ASSERT_TRUE(result.getKind() == kind::SKOLEM); + // check that a lemma was added + ASSERT_TRUE(lemmas.size() > orig_num_lemmas); +} + } // namespace test } // namespace cvc5 diff --git a/test/unit/util/integer_black.cpp b/test/unit/util/integer_black.cpp index 368f12222..2be2515eb 100644 --- a/test/unit/util/integer_black.cpp +++ b/test/unit/util/integer_black.cpp @@ -333,18 +333,69 @@ TEST_F(TestUtilBlackInteger, pow) ASSERT_EQ(Integer(-1000), Integer(-10).pow(3)); } -TEST_F(TestUtilBlackInteger, overly_long) +TEST_F(TestUtilBlackInteger, overly_long_signed) +{ + int64_t sl = std::numeric_limits<int64_t>::max(); + Integer i(sl); + if constexpr (sizeof(unsigned long) == sizeof(uint64_t)) + { + ASSERT_EQ(i.getLong(), sl); + } + ASSERT_NO_THROW(i.getSigned64()); + ASSERT_EQ(i.getSigned64(), sl); + i = i + 1; + ASSERT_THROW(i.getSigned64(), IllegalArgumentException); +} + +TEST_F(TestUtilBlackInteger, overly_long_unsigned) { uint64_t ul = std::numeric_limits<uint64_t>::max(); Integer i(ul); - ASSERT_EQ(i.getUnsignedLong(), ul); + if constexpr (sizeof(unsigned long) == sizeof(uint64_t)) + { + ASSERT_EQ(i.getUnsignedLong(), ul); + } ASSERT_THROW(i.getLong(), IllegalArgumentException); + ASSERT_NO_THROW(i.getUnsigned64()); + ASSERT_EQ(i.getUnsigned64(), ul); uint64_t ulplus1 = ul + 1; ASSERT_EQ(ulplus1, 0); i = i + 1; ASSERT_THROW(i.getUnsignedLong(), IllegalArgumentException); } +TEST_F(TestUtilBlackInteger, getSigned64) +{ + { + int64_t i = std::numeric_limits<int64_t>::max(); + Integer a(i); + EXPECT_EQ(a.getSigned64(), i); + EXPECT_THROW((a + 1).getSigned64(), IllegalArgumentException); + } + { + int64_t i = std::numeric_limits<int64_t>::min(); + Integer a(i); + EXPECT_EQ(a.getSigned64(), i); + EXPECT_THROW((a - 1).getSigned64(), IllegalArgumentException); + } +} + +TEST_F(TestUtilBlackInteger, getUnsigned64) +{ + { + uint64_t i = std::numeric_limits<uint64_t>::max(); + Integer a(i); + EXPECT_EQ(a.getUnsigned64(), i); + EXPECT_THROW((a + 1).getUnsigned64(), IllegalArgumentException); + } + { + uint64_t i = std::numeric_limits<uint64_t>::min(); + Integer a(i); + EXPECT_EQ(a.getUnsigned64(), i); + EXPECT_THROW((a - 1).getUnsigned64(), IllegalArgumentException); + } +} + TEST_F(TestUtilBlackInteger, testBit) { ASSERT_FALSE(Integer(0).testBit(6)); |