Add support for datatype update (#6449)
authorAndrew Reynolds <andrew.j.reynolds@gmail.com>
Sat, 8 May 2021 00:25:27 +0000 (19:25 -0500)
committerGitHub <noreply@github.com>
Sat, 8 May 2021 00:25:27 +0000 (19:25 -0500)
This removes the special case of TUPLE_UPDATE and RECORD_UPDATE in favor of the more general datatype update.

Datatype update is handled analogously to APPLY_SELECTOR / APPLY_TESTER.

36 files changed:
src/api/cpp/cvc5.cpp
src/api/cpp/cvc5.h
src/api/cpp/cvc5_kind.h
src/api/python/cvc5.pxd
src/api/python/cvc5.pxi
src/expr/CMakeLists.txt
src/expr/dtype.cpp
src/expr/node_manager.cpp
src/expr/node_manager.h
src/expr/record.cpp [deleted file]
src/expr/record.h [deleted file]
src/expr/type_node.cpp
src/expr/type_node.h
src/parser/cvc/Cvc.g
src/parser/parse_op.cpp
src/parser/parser.cpp
src/parser/smt2/Smt2.g
src/parser/smt2/smt2.cpp
src/printer/cvc/cvc_printer.cpp
src/printer/smt2/smt2_printer.cpp
src/theory/datatypes/datatypes_rewriter.cpp
src/theory/datatypes/datatypes_rewriter.h
src/theory/datatypes/kinds
src/theory/datatypes/theory_datatypes_type_rules.cpp
src/theory/datatypes/theory_datatypes_type_rules.h
src/theory/datatypes/theory_datatypes_utils.cpp
src/util/CMakeLists.txt
src/util/tuple.h [deleted file]
test/regress/CMakeLists.txt
test/regress/regress0/datatypes/list-update-sat.smt2 [new file with mode: 0644]
test/regress/regress0/datatypes/list-update.smt2 [new file with mode: 0644]
test/unit/api/datatype_api_black.cpp
test/unit/api/op_black.cpp
test/unit/api/solver_black.cpp
test/unit/api/sort_black.cpp
test/unit/util/datatype_black.cpp

index 6ee1409d6fa7f393a1fc966a8384bb9ebee2089e..18db5d5ab1e9fb90175483cad6ea1757be03555e 100644 (file)
@@ -243,8 +243,7 @@ const static std::unordered_map<Kind, cvc5::Kind> s_kinds{
     {APPLY_SELECTOR, cvc5::Kind::APPLY_SELECTOR},
     {APPLY_CONSTRUCTOR, cvc5::Kind::APPLY_CONSTRUCTOR},
     {APPLY_TESTER, cvc5::Kind::APPLY_TESTER},
-    {TUPLE_UPDATE, cvc5::Kind::TUPLE_UPDATE},
-    {RECORD_UPDATE, cvc5::Kind::RECORD_UPDATE},
+    {APPLY_UPDATER, cvc5::Kind::APPLY_UPDATER},
     {DT_SIZE, cvc5::Kind::DT_SIZE},
     {TUPLE_PROJECT, cvc5::Kind::TUPLE_PROJECT},
     /* Separation Logic ---------------------------------------------------- */
@@ -550,10 +549,7 @@ const static std::unordered_map<cvc5::Kind, Kind, cvc5::kind::KindHashFunction>
         {cvc5::Kind::APPLY_CONSTRUCTOR, APPLY_CONSTRUCTOR},
         {cvc5::Kind::APPLY_SELECTOR_TOTAL, INTERNAL_KIND},
         {cvc5::Kind::APPLY_TESTER, APPLY_TESTER},
-        {cvc5::Kind::TUPLE_UPDATE_OP, TUPLE_UPDATE},
-        {cvc5::Kind::TUPLE_UPDATE, TUPLE_UPDATE},
-        {cvc5::Kind::RECORD_UPDATE_OP, RECORD_UPDATE},
-        {cvc5::Kind::RECORD_UPDATE, RECORD_UPDATE},
+        {cvc5::Kind::APPLY_UPDATER, APPLY_UPDATER},
         {cvc5::Kind::DT_SIZE, DT_SIZE},
         {cvc5::Kind::TUPLE_PROJECT, TUPLE_PROJECT},
         /* Separation Logic ------------------------------------------------ */
@@ -661,8 +657,7 @@ const static std::unordered_map<cvc5::Kind, Kind, cvc5::kind::KindHashFunction>
 
 /* Set of kinds for indexed operators */
 const static std::unordered_set<Kind> s_indexed_kinds(
-    {RECORD_UPDATE,
-     DIVISIBLE,
+    {DIVISIBLE,
      IAND,
      BITVECTOR_REPEAT,
      BITVECTOR_ZERO_EXTEND,
@@ -672,7 +667,6 @@ const static std::unordered_set<Kind> s_indexed_kinds(
      INT_TO_BITVECTOR,
      FLOATINGPOINT_TO_UBV,
      FLOATINGPOINT_TO_SBV,
-     TUPLE_UPDATE,
      BITVECTOR_EXTRACT,
      FLOATINGPOINT_TO_FP_IEEE_BITVECTOR,
      FLOATINGPOINT_TO_FP_FLOATINGPOINT,
@@ -718,7 +712,8 @@ bool isDefinedKind(Kind k) { return k > UNDEFINED_KIND && k < LAST_KIND; }
 bool isApplyKind(cvc5::Kind k)
 {
   return (k == cvc5::Kind::APPLY_UF || k == cvc5::Kind::APPLY_CONSTRUCTOR
-          || k == cvc5::Kind::APPLY_SELECTOR || k == cvc5::Kind::APPLY_TESTER);
+          || k == cvc5::Kind::APPLY_SELECTOR || k == cvc5::Kind::APPLY_TESTER
+          || k == cvc5::Kind::APPLY_UPDATER);
 }
 
 #ifdef CVC5_ASSERTIONS
@@ -1194,6 +1189,15 @@ bool Sort::isTester() const
   CVC5_API_TRY_CATCH_END;
 }
 
+bool Sort::isUpdater() const
+{
+  CVC5_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return d_type->isUpdater();
+  ////////
+  CVC5_API_TRY_CATCH_END;
+}
+
 bool Sort::isFunction() const
 {
   CVC5_API_TRY_CATCH_BEGIN;
@@ -1852,7 +1856,6 @@ size_t Op::getNumIndices() const
   switch (k)
   {
     case DIVISIBLE: size = 1; break;
-    case RECORD_UPDATE: size = 1; break;
     case BITVECTOR_REPEAT: size = 1; break;
     case BITVECTOR_ZERO_EXTEND: size = 1; break;
     case BITVECTOR_SIGN_EXTEND: size = 1; break;
@@ -1862,7 +1865,6 @@ size_t Op::getNumIndices() const
     case IAND: size = 1; break;
     case FLOATINGPOINT_TO_UBV: size = 1; break;
     case FLOATINGPOINT_TO_SBV: size = 1; break;
-    case TUPLE_UPDATE: size = 1; break;
     case REGEXP_REPEAT: size = 1; break;
     case BITVECTOR_EXTRACT: size = 2; break;
     case FLOATINGPOINT_TO_FP_IEEE_BITVECTOR: size = 2; break;
@@ -1892,12 +1894,10 @@ std::string Op::getIndices() const
   CVC5_API_CHECK(!d_node->isNull())
       << "Expecting a non-null internal expression. This Op is not indexed.";
   Kind k = intToExtKind(d_node->getKind());
-  CVC5_API_CHECK(k == DIVISIBLE || k == RECORD_UPDATE)
-      << "Can't get string index from"
-      << " kind " << kindToString(k);
+  CVC5_API_CHECK(k == DIVISIBLE) << "Can't get string index from"
+                                 << " kind " << kindToString(k);
   //////// all checks before this line
-  return k == DIVISIBLE ? d_node->getConst<Divisible>().k.toString()
-                        : d_node->getConst<RecordUpdate>().getField();
+  return d_node->getConst<Divisible>().k.toString();
   ////////
   CVC5_API_TRY_CATCH_END;
 }
@@ -1938,7 +1938,6 @@ uint32_t Op::getIndices() const
     case FLOATINGPOINT_TO_SBV:
       i = d_node->getConst<FloatingPointToSBV>().d_bv_size.d_size;
       break;
-    case TUPLE_UPDATE: i = d_node->getConst<TupleUpdate>().getIndex(); break;
     case REGEXP_REPEAT:
       i = d_node->getConst<RegExpRepeat>().d_repeatAmount;
       break;
@@ -3062,6 +3061,15 @@ Term DatatypeSelector::getSelectorTerm() const
   ////////
   CVC5_API_TRY_CATCH_END;
 }
+Term DatatypeSelector::getUpdaterTerm() const
+{
+  CVC5_API_TRY_CATCH_BEGIN;
+  CVC5_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return Term(d_solver, d_stor->getUpdater());
+  ////////
+  CVC5_API_TRY_CATCH_END;
+}
 
 Sort DatatypeSelector::getRangeSort() const
 {
@@ -3424,7 +3432,17 @@ Term Datatype::getConstructorTerm(const std::string& name) const
   CVC5_API_TRY_CATCH_BEGIN;
   CVC5_API_CHECK_NOT_NULL;
   //////// all checks before this line
-  return getConstructor(name).getConstructorTerm();
+  return getConstructorForName(name).getConstructorTerm();
+  ////////
+  CVC5_API_TRY_CATCH_END;
+}
+
+DatatypeSelector Datatype::getSelector(const std::string& name) const
+{
+  CVC5_API_TRY_CATCH_BEGIN;
+  CVC5_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return getSelectorForName(name);
   ////////
   CVC5_API_TRY_CATCH_END;
 }
@@ -3579,6 +3597,30 @@ DatatypeConstructor Datatype::getConstructorForName(
   return DatatypeConstructor(d_solver, (*d_dtype)[index]);
 }
 
+DatatypeSelector Datatype::getSelectorForName(const std::string& name) const
+{
+  bool foundSel = false;
+  size_t index = 0;
+  size_t sindex = 0;
+  for (size_t i = 0, ncons = getNumConstructors(); i < ncons; i++)
+  {
+    int si = (*d_dtype)[i].getSelectorIndexForName(name);
+    if (si >= 0)
+    {
+      sindex = static_cast<size_t>(si);
+      index = i;
+      foundSel = true;
+      break;
+    }
+  }
+  if (!foundSel)
+  {
+    CVC5_API_CHECK(foundSel)
+        << "No select " << name << " for datatype " << getName() << " exists";
+  }
+  return DatatypeSelector(d_solver, (*d_dtype)[index][sindex]);
+}
+
 Datatype::const_iterator::const_iterator(const Solver* slv,
                                          const cvc5::DType& dtype,
                                          bool begin)
@@ -5806,29 +5848,18 @@ Op Solver::mkOp(Kind kind, const std::string& arg) const
 {
   CVC5_API_TRY_CATCH_BEGIN;
   CVC5_API_KIND_CHECK(kind);
-  CVC5_API_KIND_CHECK_EXPECTED((kind == RECORD_UPDATE) || (kind == DIVISIBLE),
-                               kind)
-      << "RECORD_UPDATE or DIVISIBLE";
+  CVC5_API_KIND_CHECK_EXPECTED((kind == DIVISIBLE), kind) << "DIVISIBLE";
   //////// all checks before this line
   Op res;
-  if (kind == RECORD_UPDATE)
-  {
-    res = Op(this,
-             kind,
-             *mkValHelper<cvc5::RecordUpdate>(cvc5::RecordUpdate(arg)).d_node);
-  }
-  else
-  {
-    /* CLN and GMP handle this case differently, CLN interprets it as 0, GMP
-     * throws an std::invalid_argument exception. For consistency, we treat it
-     * as invalid. */
-    CVC5_API_ARG_CHECK_EXPECTED(arg != ".", arg)
-        << "a string representing an integer, real or rational value.";
-    res = Op(this,
-             kind,
-             *mkValHelper<cvc5::Divisible>(cvc5::Divisible(cvc5::Integer(arg)))
-                  .d_node);
-  }
+  /* CLN and GMP handle this case differently, CLN interprets it as 0, GMP
+   * throws an std::invalid_argument exception. For consistency, we treat it
+   * as invalid. */
+  CVC5_API_ARG_CHECK_EXPECTED(arg != ".", arg)
+      << "a string representing an integer, real or rational value.";
+  res = Op(this,
+           kind,
+           *mkValHelper<cvc5::Divisible>(cvc5::Divisible(cvc5::Integer(arg)))
+                .d_node);
   return res;
   ////////
   CVC5_API_TRY_CATCH_END;
@@ -5905,11 +5936,6 @@ Op Solver::mkOp(Kind kind, uint32_t arg) const
           *mkValHelper<cvc5::FloatingPointToSBV>(cvc5::FloatingPointToSBV(arg))
                .d_node);
       break;
-    case TUPLE_UPDATE:
-      res = Op(this,
-               kind,
-               *mkValHelper<cvc5::TupleUpdate>(cvc5::TupleUpdate(arg)).d_node);
-      break;
     case REGEXP_REPEAT:
       res =
           Op(this,
index 1e857085b53df17b8882e2d679b0e628f3081774..16f58ee80820b9a5843dda71909e74a41cb7a643 100644 (file)
@@ -398,6 +398,11 @@ class CVC5_EXPORT Sort
    * @return true if the sort is a tester sort
    */
   bool isTester() const;
+  /**
+   * Is this a datatype updater sort?
+   * @return true if the sort is a datatype updater sort
+   */
+  bool isUpdater() const;
   /**
    * Is this a function sort?
    * @return true if the sort is a function sort
@@ -1575,6 +1580,7 @@ class CVC5_EXPORT DatatypeDecl
  */
 class CVC5_EXPORT DatatypeSelector
 {
+  friend class Datatype;
   friend class DatatypeConstructor;
   friend class Solver;
 
@@ -1598,6 +1604,12 @@ class CVC5_EXPORT DatatypeSelector
    */
   Term getSelectorTerm() const;
 
+  /**
+   * Get the upater operator of this datatype selector.
+   * @return the updater term
+   */
+  Term getUpdaterTerm() const;
+
   /** @return the range sort of this argument. */
   Sort getRangeSort() const;
 
@@ -1908,6 +1920,15 @@ class CVC5_EXPORT Datatype
    */
   Term getConstructorTerm(const std::string& name) const;
 
+  /**
+   * Get the datatype constructor with the given name.
+   * This is a linear search through the constructors and their selectors, so
+   * in case of multiple, similarly-named selectors, the first is returned.
+   * @param name the name of the datatype selector
+   * @return the datatype selector with the given name
+   */
+  DatatypeSelector getSelector(const std::string& name) const;
+
   /** @return the name of this Datatype. */
   std::string getName() const;
 
@@ -2069,6 +2090,13 @@ class CVC5_EXPORT Datatype
    */
   DatatypeConstructor getConstructorForName(const std::string& name) const;
 
+  /**
+   * Return selector for name.
+   * @param name The name of selector to find
+   * @return the selector object for the name
+   */
+  DatatypeSelector getSelectorForName(const std::string& name) const;
+
   /**
    * Helper for isNull checks. This prevents calling an API function with
    * CVC5_API_CHECK_NOT_NULL
@@ -2890,7 +2918,6 @@ class CVC5_EXPORT Solver
 
   /**
    * Create operator of kind:
-   *   - RECORD_UPDATE
    *   - DIVISIBLE (to support arbitrary precision integers)
    * See enum Kind for a description of the parameters.
    * @param kind the kind of the operator
index f7658412cdc2ab416543614641e12811823cc38c..0375b5e606105ee5414b4dd411d88caddbce7d53 100644 (file)
@@ -1918,11 +1918,11 @@ enum CVC5_EXPORT Kind : int32_t
    */
   APPLY_CONSTRUCTOR,
   /**
-   * Datatype selector application.
+   * Datatype selector application, which is undefined if misapplied.
    *
    * Parameters:
    *   - 1: Selector (operator)
-   *   - 2: Datatype term (undefined if mis-applied)
+   *   - 2: Datatype term
    *
    * Create with:
    *   - `Solver::mkTerm(const Op& op, const Term& child) const`
@@ -1940,56 +1940,20 @@ enum CVC5_EXPORT Kind : int32_t
    *   - `Solver::mkTerm(Kind kind, const std::vector<Term>& children) const`
    */
   APPLY_TESTER,
-#if 0
-  /* Parametric datatype term.  */
-  PARAMETRIC_DATATYPE,
-  /* type ascription, for datatype constructor applications;
-   * first parameter is an ASCRIPTION_TYPE, second is the datatype constructor
-   * application being ascribed */
-  APPLY_TYPE_ASCRIPTION,
-#endif
-  /**
-   * Operator for a tuple update.
-   *
-   * Parameters:
-   *   - 1: Index of the tuple to be updated
-   *
-   * Create with:
-   *   - `Solver::mkOp(Kind kind, uint32_t param) const`
-   *
-   * Apply tuple update.
-   *
-   * Parameters:
-   *   - 1: Op of kind TUPLE_UPDATE (which references an index)
-   *   - 2: Tuple
-   *   - 3: Element to store in the tuple at the given index
-   *
-   * Create with:
-   *   - `Solver::mkTerm(const Op& op, const Term& child1, const Term& child2) const`
-   *   - `Solver::mkTerm(const Op& op, const std::vector<Term>& children) const`
-   */
-  TUPLE_UPDATE,
   /**
-   * Operator for a record update.
+   * Datatype update application, which does not change the argument if
+   * misapplied.
    *
    * Parameters:
-   *   - 1: Name of the field to be updated
-   *
-   * Create with:
-   *   - `Solver::mkOp(Kind kind, const std::string& param) const`
-   *
-   * Record update.
-   *
-   * Parameters:
-   *   - 1: Op of kind RECORD_UPDATE (which references a field)
-   *   - 2: Record term to update
-   *   - 3: Element to store in the record in the given field
+   *   - 1: Updater (operator)
+   *   - 2: Datatype term
+   *   - 3: Value to update a field of the datatype term with
    *
    * Create with:
-   *   - `Solver::mkTerm(const Op& op, const Term& child1, const Term& child2) const`
-   *   - `Solver::mkTerm(const Op& op,, const std::vector<Term>& children) const`
+   *   - `Solver::mkTerm(Kind kind, const Term& child1, const Term& child2) const`
+   *   - `Solver::mkTerm(Kind kind, const std::vector<Term>& children) const`
    */
-  RECORD_UPDATE,
+  APPLY_UPDATER,
   /**
    * Match expressions.
    * For example, the smt2 syntax match term
index 6302b7e4332e2a99e4a0da631ebbb8db95bd2625..e4c0eb9158e4933dc1dfe11a8558a46fa3879d3b 100644 (file)
@@ -32,6 +32,7 @@ cdef extern from "api/cpp/cvc5.h" namespace "cvc5::api":
         DatatypeConstructor operator[](const string& name) except +
         DatatypeConstructor getConstructor(const string& name) except +
         Term getConstructorTerm(const string& name) except +
+        DatatypeSelector getSelector(const string& name) except +
         size_t getNumConstructors() except +
         bint isParametric() except +
         bint isCodatatype() except +
@@ -89,6 +90,7 @@ cdef extern from "api/cpp/cvc5.h" namespace "cvc5::api":
         DatatypeSelector() except +
         string getName() except +
         Term getSelectorTerm() except +
+        Term getUpdaterTerm() except +
         Sort getRangeSort() except +
         string toString() except +
 
index 135eeb1651cb6f5dfd64a6405ce6c75f80b9b2ae..11742ca08f772578a5f1d0ceb37d221d87efd4e6 100644 (file)
@@ -109,6 +109,12 @@ cdef class Datatype:
         term.cterm = self.cd.getConstructorTerm(name.encode())
         return term
 
+    def getSelector(self, str name):
+        """Return a selector by name."""
+        cdef DatatypeSelector ds = DatatypeSelector(self.solver)
+        ds.cds = self.cd.getSelector(name.encode())
+        return ds
+
     def getNumConstructors(self):
         """:return: number of constructors."""
         return self.cd.getNumConstructors()
@@ -267,6 +273,11 @@ cdef class DatatypeSelector:
         term.cterm = self.cds.getSelectorTerm()
         return term
 
+    def getUpdaterTerm(self):
+        cdef Term term = Term(self.solver)
+        term.cterm = self.cds.getUpdaterTerm()
+        return term
+
     def getRangeSort(self):
         cdef Sort sort = Sort(self.solver)
         sort.csort = self.cds.getRangeSort()
index 28cf23f57c3a5c3b4376ef9e93dc928a3b5ece3a..9bf63dcfc3f6e9a6d20c9a8cc45c04f9275ddc34 100644 (file)
@@ -112,8 +112,6 @@ libcvc5_add_sources(
   dtype_cons.cpp
   dtype_selector.h
   dtype_selector.cpp
-  record.cpp
-  record.h
   sequence.cpp
   sequence.h
   subs.cpp
index 07b8aa5f152a101e06e370fb2ead8938605002c4..c1893d3f4baebc84c796d487904ede83688f6f22 100644 (file)
@@ -109,7 +109,7 @@ const DType& DType::datatypeOf(Node item)
 size_t DType::indexOf(Node item)
 {
   Assert(item.getType().isConstructor() || item.getType().isTester()
-         || item.getType().isSelector());
+         || item.getType().isSelector() || item.getType().isUpdater());
   return indexOfInternal(item);
 }
 
@@ -125,7 +125,7 @@ size_t DType::indexOfInternal(Node item)
 
 size_t DType::cindexOf(Node item)
 {
-  Assert(item.getType().isSelector());
+  Assert(item.getType().isSelector() || item.getType().isUpdater());
   return cindexOfInternal(item);
 }
 size_t DType::cindexOfInternal(Node item)
index 0a0781819a7272f045dff1b64f9b708414ad3769..780fda9abd3eb4bfc0a99d412afed1e98f985138 100644 (file)
@@ -724,7 +724,7 @@ TypeNode NodeManager::mkDatatypeUpdateType(TypeNode domain, TypeNode range)
       domain.isDatatype(), domain, "cannot create non-datatype upater type");
   // It is a function type domain x range -> domain, we store only the
   // arguments
-  return mkTypeNode(kind::DT_UPDATE_TYPE, domain, range);
+  return mkTypeNode(kind::UPDATER_TYPE, domain, range);
 }
 
 TypeNode NodeManager::TupleTypeCache::getTupleType( NodeManager * nm, std::vector< TypeNode >& types, unsigned index ) {
index 8b99f5743171e8290453cf70e971558334931e54..9952baf898dd049c29d8402c7bcaa1197356087a 100644 (file)
@@ -34,6 +34,8 @@
 
 namespace cvc5 {
 
+using Record = std::vector<std::pair<std::string, TypeNode>>;
+
 namespace api {
 class Solver;
 }
diff --git a/src/expr/record.cpp b/src/expr/record.cpp
deleted file mode 100644 (file)
index 0792de2..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/******************************************************************************
- * Top contributors (to current version):
- *   Tim King
- *
- * This file is part of the cvc5 project.
- *
- * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
- * in the top-level source directory and their institutional affiliations.
- * All rights reserved.  See the file COPYING in the top-level source
- * directory for licensing information.
- * ****************************************************************************
- *
- * A class representing a record definition.
- */
-
-#include "expr/record.h"
-
-#include "base/check.h"
-#include "base/output.h"
-
-namespace cvc5 {
-
-std::ostream& operator<<(std::ostream& out, const RecordUpdate& t) {
-  return out << "[" << t.getField() << "]";
-}
-
-}  // namespace cvc5
diff --git a/src/expr/record.h b/src/expr/record.h
deleted file mode 100644 (file)
index ecf6c8d..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/******************************************************************************
- * Top contributors (to current version):
- *   Tim King, Mathias Preiner, Morgan Deters
- *
- * This file is part of the cvc5 project.
- *
- * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
- * in the top-level source directory and their institutional affiliations.
- * All rights reserved.  See the file COPYING in the top-level source
- * directory for licensing information.
- * ****************************************************************************
- *
- * A class representing a Record definition.
- */
-
-#include "cvc5_public.h"
-
-#ifndef CVC5__RECORD_H
-#define CVC5__RECORD_H
-
-#include <iostream>
-#include <string>
-#include <vector>
-#include <utility>
-
-// Forward Declarations
-namespace cvc5 {
-// This forward delcartion is required to resolve a cicular dependency with
-// Record which is a referenced in a Kind file.
-class TypeNode;
-}  // namespace cvc5
-
-namespace cvc5 {
-
-// operators for record update
-class RecordUpdate
-{
-  std::string d_field;
-
- public:
-  RecordUpdate(const std::string& field) : d_field(field) {}
-  std::string getField() const { return d_field; }
-  bool operator==(const RecordUpdate& t) const { return d_field == t.d_field; }
-  bool operator!=(const RecordUpdate& t) const { return d_field != t.d_field; }
-}; /* class RecordUpdate */
-
-struct RecordUpdateHashFunction
-{
-  inline size_t operator()(const RecordUpdate& t) const {
-    return std::hash<std::string>()(t.getField());
-  }
-}; /* struct RecordUpdateHashFunction */
-
-std::ostream& operator<<(std::ostream& out, const RecordUpdate& t);
-
-using Record = std::vector<std::pair<std::string, TypeNode>>;
-
-}  // namespace cvc5
-
-#endif /* CVC5__RECORD_H */
index 483983e6eceded6c1041999beb33a961edc84bcf..bd435a3928771632e4c2a2d8e375c5246b64f716 100644 (file)
@@ -249,7 +249,7 @@ bool TypeNode::isClosedEnumerable()
 bool TypeNode::isFirstClass() const
 {
   return getKind() != kind::CONSTRUCTOR_TYPE && getKind() != kind::SELECTOR_TYPE
-         && getKind() != kind::TESTER_TYPE && getKind() != kind::DT_UPDATE_TYPE
+         && getKind() != kind::TESTER_TYPE && getKind() != kind::UPDATER_TYPE
          && (getKind() != kind::TYPE_CONSTANT
              || (getConst<TypeConstant>() != REGEXP_TYPE
                  && getConst<TypeConstant>() != SEXPR_TYPE));
@@ -633,10 +633,7 @@ bool TypeNode::isSelector() const { return getKind() == kind::SELECTOR_TYPE; }
 
 bool TypeNode::isTester() const { return getKind() == kind::TESTER_TYPE; }
 
-bool TypeNode::isDatatypeUpdater() const
-{
-  return getKind() == kind::DT_UPDATE_TYPE;
-}
+bool TypeNode::isUpdater() const { return getKind() == kind::UPDATER_TYPE; }
 
 bool TypeNode::isCodatatype() const
 {
index d73d64b431139c59d01d82cef7c6475e606ac7a0..0ab1d0217dbf02586d9eaceb90fd90a0e08b52ea 100644 (file)
@@ -652,7 +652,7 @@ public:
   bool isTester() const;
 
   /** Is this a datatype updater type */
-  bool isDatatypeUpdater() const;
+  bool isUpdater() const;
 
   /** Get the internal Datatype specification from a datatype type */
   const DType& getDType() const;
index 039eaf0ad8321aac02034843dbf475e6bc241032..6e3332651e1f863dbadf0ae9e84950b2e909b223 100644 (file)
@@ -1636,7 +1636,11 @@ tupleStore[cvc5::api::Term& f]
       | DOT ( tupleStore[f2]
             | recordStore[f2] ) )
     | ASSIGN_TOK term[f2] )
-    { f = SOLVER->mkTerm(SOLVER->mkOp(api::TUPLE_UPDATE,k), f, f2); }
+    {
+      const api::Datatype& dt = f.getSort().getDatatype();
+      f = SOLVER->mkTerm(
+         api::APPLY_UPDATER, dt[0][k].getUpdaterTerm(), f, f2);
+    }
   ;
 
 /**
@@ -1665,7 +1669,11 @@ recordStore[cvc5::api::Term& f]
       | DOT ( tupleStore[f2]
             | recordStore[f2] ) )
     | ASSIGN_TOK term[f2] )
-    { f = SOLVER->mkTerm(SOLVER->mkOp(api::RECORD_UPDATE,id), f, f2); }
+    {
+      const api::Datatype& dt = f.getSort().getDatatype();
+      f = SOLVER->mkTerm(
+         api::APPLY_UPDATER, dt[0][id].getUpdaterTerm(), f, f2);
+    }
   ;
 
 /** Parses a unary minus term. */
index 3f7df3794837c2c2c10189cf6bbd2d9b0132bd2e..772b73b1e29d1a0c6490339c896458708535da9d 100644 (file)
@@ -20,7 +20,7 @@ namespace cvc5 {
 std::ostream& operator<<(std::ostream& os, const ParseOp& p)
 {
   std::stringstream out;
-  out << "(ParseOp ";
+  out << "(ParseOp";
   if (!p.d_expr.isNull())
   {
     out << " :expr " << p.d_expr;
index 84c1e66f3083dd017842b38d551a01e150fa42ed..31f8517cd33d9100745c6fd3bb3880f6308b982e 100644 (file)
@@ -154,6 +154,10 @@ api::Kind Parser::getKindForFunction(api::Term fun)
   {
     return api::APPLY_TESTER;
   }
+  else if (t.isUpdater())
+  {
+    return api::APPLY_UPDATER;
+  }
   return api::UNDEFINED_KIND;
 }
 
index 4a612ce6f595c8dc0d7f56c1390297fa2eace364..dc9a324bb60b5b4aacb1595ae15ace781244efb3 100644 (file)
@@ -1643,6 +1643,22 @@ identifier[cvc5::ParseOp& p]
         api::DatatypeConstructor dc = d.getConstructor(f.toString());
         p.d_expr = dc.getTesterTerm();
       }
+    | UPDATE_TOK term[f, f2]
+      {
+        if (!f.getSort().isSelector())
+        {
+          PARSER_STATE->parseError(
+              "Bad syntax for test (_ update X), X must be a selector.");
+        }
+        std::string sname = f.toString();
+        // get the datatype that f belongs to
+        api::Sort sf = f.getSort().getSelectorDomainSort();
+        api::Datatype d = sf.getDatatype();
+        // find the selector
+        api::DatatypeSelector ds = d.getSelector(f.toString());
+        // get the updater term
+        p.d_expr = ds.getUpdaterTerm();
+      }
     | TUPLE_SEL_TOK m=INTEGER_LITERAL
       {
         // we adopt a special syntax (_ tupSel n)
@@ -2226,6 +2242,7 @@ DECLARE_CODATATYPES_TOK : { PARSER_STATE->v2_6() || PARSER_STATE->sygus() }?'dec
 PAR_TOK : { PARSER_STATE->v2_6() || PARSER_STATE->sygus() }?'par';
 COMPREHENSION_TOK : { PARSER_STATE->isTheoryEnabled(theory::THEORY_SETS) }?'comprehension';
 TESTER_TOK : { ( PARSER_STATE->v2_6() || PARSER_STATE->sygus() ) && PARSER_STATE->isTheoryEnabled(theory::THEORY_DATATYPES) }?'is';
+UPDATE_TOK : { ( PARSER_STATE->v2_6() || PARSER_STATE->sygus() ) && PARSER_STATE->isTheoryEnabled(theory::THEORY_DATATYPES) }?'update';
 MATCH_TOK : { ( PARSER_STATE->v2_6() || PARSER_STATE->sygus() ) && PARSER_STATE->isTheoryEnabled(theory::THEORY_DATATYPES) }?'match';
 GET_MODEL_TOK : 'get-model';
 BLOCK_MODEL_TOK : 'block-model';
index 9d4267dd2b847363e58aaf00cc882fee1d7132fd..2f19d16f0582d3f0cafb0390654be9baa7111f83 100644 (file)
@@ -135,6 +135,7 @@ void Smt2::addDatatypesOperators()
 
   if (!strictModeEnabled())
   {
+    Parser::addOperator(api::APPLY_UPDATER);
     addOperator(api::DT_SIZE, "dt.size");
   }
 }
index e6e227879f7f344de37f7442d285e18054859562..8f433256dc093b5561028705a11bb3d0671526a1 100644 (file)
@@ -487,18 +487,6 @@ void CvcPrinter::toStreamNode(std::ostream& out,
       out << " -> BOOLEAN";
       return;
       break;
-    case kind::TUPLE_UPDATE:
-      toStreamNode(out, n[0], depth, true, lbind);
-      out << " WITH ." << n.getOperator().getConst<TupleUpdate>().getIndex() << " := ";
-      toStreamNode(out, n[1], depth, true, lbind);
-      return;
-      break;
-    case kind::RECORD_UPDATE:
-      toStreamNode(out, n[0], depth, true, lbind);
-      out << " WITH ." << n.getOperator().getConst<RecordUpdate>().getField() << " := ";
-      toStreamNode(out, n[1], depth, true, lbind);
-      return;
-      break;
 
     // ARRAYS
     case kind::ARRAY_TYPE:
index ae8d377135f3a0c0d3b25bafbeb4b8c64adb8fee..eb80bd5a2bf09fad27df277954867002066a1be8 100644 (file)
@@ -918,7 +918,7 @@ void Smt2Printer::toStream(std::ostream& out,
   case kind::APPLY_TESTER:
   case kind::APPLY_SELECTOR:
   case kind::APPLY_SELECTOR_TOTAL:
-  case kind::APPLY_DT_UPDATE:
+  case kind::APPLY_UPDATER:
   case kind::PARAMETRIC_DATATYPE: break;
 
   // separation logic
index a6d3a45bc5dee3a8e41b9049f429af03becb6bd0..744160c8bca2cea3603ccacd61322103f5a983bd 100644 (file)
@@ -48,6 +48,10 @@ RewriteResponse DatatypesRewriter::postRewrite(TNode in)
   {
     return rewriteTester(in);
   }
+  else if (kind == APPLY_UPDATER)
+  {
+    return rewriteUpdater(in);
+  }
   else if (kind == kind::DT_SIZE)
   {
     if (in[0].getKind() == kind::APPLY_CONSTRUCTOR)
@@ -473,6 +477,28 @@ RewriteResponse DatatypesRewriter::rewriteTester(TNode in)
   return RewriteResponse(REWRITE_DONE, in);
 }
 
+RewriteResponse DatatypesRewriter::rewriteUpdater(TNode in)
+{
+  Assert (in.getKind()==APPLY_UPDATER);
+  if (in[0].getKind() == APPLY_CONSTRUCTOR)
+  {
+    Node op = in.getOperator();
+    size_t cindex = utils::indexOf(in[0].getOperator());
+    size_t cuindex = utils::cindexOf(op);
+    if (cindex==cuindex)
+    {
+      NodeManager * nm = NodeManager::currentNM();
+      size_t updateIndex = utils::indexOf(op);
+      std::vector<Node> children(in[0].begin(), in[0].end());
+      children[updateIndex] = in[1];
+      children.insert(children.begin(),in[0].getOperator());
+      return RewriteResponse(REWRITE_DONE, nm->mkNode(APPLY_CONSTRUCTOR, children));
+    }
+    return RewriteResponse(REWRITE_DONE, in[0]);
+  }
+  return RewriteResponse(REWRITE_DONE, in);
+}
+
 Node DatatypesRewriter::normalizeCodatatypeConstant(Node n)
 {
   Trace("dt-nconst") << "Normalize " << n << std::endl;
@@ -843,51 +869,40 @@ TrustNode DatatypesRewriter::expandDefinition(Node n)
       }
     }
     break;
-    case TUPLE_UPDATE:
-    case RECORD_UPDATE:
+    case APPLY_UPDATER:
     {
       Assert(tn.isDatatype());
       const DType& dt = tn.getDType();
+      Node op = n.getOperator();
+      size_t updateIndex = utils::indexOf(op);
+      size_t cindex = utils::cindexOf(op);
+      const DTypeConstructor& dc = dt[cindex];
       NodeBuilder b(APPLY_CONSTRUCTOR);
-      b << dt[0].getConstructor();
-      size_t size, updateIndex;
-      if (n.getKind() == TUPLE_UPDATE)
-      {
-        Assert(tn.isTuple());
-        size = tn.getTupleLength();
-        updateIndex = n.getOperator().getConst<TupleUpdate>().getIndex();
-      }
-      else
-      {
-        Assert(tn.isRecord());
-        const DTypeConstructor& recCons = dt[0];
-        size = recCons.getNumArgs();
-        // get the index for the name
-        updateIndex = recCons.getSelectorIndexForName(
-            n.getOperator().getConst<RecordUpdate>().getField());
-      }
-      Debug("tuprec") << "expr is " << n << std::endl;
-      Debug("tuprec") << "updateIndex is " << updateIndex << std::endl;
-      Debug("tuprec") << "t is " << tn << std::endl;
-      Debug("tuprec") << "t has arity " << size << std::endl;
-      for (size_t i = 0; i < size; ++i)
+      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;
+      Trace("dt-expand") << "t is " << tn << std::endl;
+      for (size_t i = 0, size = dc.getNumArgs(); i < size; ++i)
       {
         if (i == updateIndex)
         {
           b << n[1];
-          Debug("tuprec") << "arg " << i << " gets updated to " << n[1]
-                          << std::endl;
         }
         else
         {
           b << nm->mkNode(
-              APPLY_SELECTOR_TOTAL, dt[0].getSelectorInternal(tn, i), n[0]);
-          Debug("tuprec") << "arg " << i << " copies "
-                          << b[b.getNumChildren() - 1] << std::endl;
+              APPLY_SELECTOR_TOTAL, dc.getSelectorInternal(tn, i), n[0]);
         }
       }
       ret = b;
-      Debug("tuprec") << "return " << ret << std::endl;
+      if (dt.getNumConstructors() > 1)
+      {
+        // must be the right constructor to update
+        Node tester = nm->mkNode(APPLY_TESTER, dc.getTester(), n[0]);
+        ret = nm->mkNode(ITE, tester, ret, n[0]);
+      }
+      Trace("dt-expand") << "return " << ret << std::endl;
     }
     break;
     default: break;
index c9a40ff7bf46fd7fad203e42557bc03d98882467..89e1901fa41bb7af2d1cf75bbc9706b91825677c 100644 (file)
@@ -58,6 +58,8 @@ class DatatypesRewriter : public TheoryRewriter
   static RewriteResponse rewriteSelector(TNode in);
   /** rewrite tester term in */
   static RewriteResponse rewriteTester(TNode in);
+  /** rewrite updater term in */
+  static RewriteResponse rewriteUpdater(TNode in);
 
   /** collect references
    *
index 4cabddd96dc831be5714be134f1e97c56d0e7b24..1b7808a8b0ed5d298f5386406928ac3287690fe9 100644 (file)
@@ -32,9 +32,9 @@ cardinality TESTER_TYPE \
     "theory/builtin/theory_builtin_type_rules.h"
 
 # tester type has a constructor type
-operator DT_UPDATE_TYPE 2 "datatype update"
+operator UPDATER_TYPE 2 "datatype update"
 # can re-use function cardinality
-cardinality DT_UPDATE_TYPE \
+cardinality UPDATER_TYPE \
     "::cvc5::theory::builtin::FunctionProperties::computeCardinality(%TYPE%)" \
     "theory/builtin/theory_builtin_type_rules.h"
 
@@ -45,7 +45,7 @@ parameterized APPLY_SELECTOR_TOTAL [SELECTOR_TYPE] 1 "selector application; para
 
 parameterized APPLY_TESTER TESTER_TYPE 1 "tester application; first parameter is a tester, second is a datatype term"
 
-parameterized APPLY_DT_UPDATE DT_UPDATE_TYPE 2 "datatype update application; first parameter is an update, second is a datatype term to update, third is the value to update with"
+parameterized APPLY_UPDATER UPDATER_TYPE 2 "datatype updater application; first parameter is an update, second is a datatype term to update, third is the value to update with"
 
 constant DATATYPE_TYPE \
     ::cvc5::DatatypeIndexConstant \
@@ -89,30 +89,12 @@ typerule APPLY_CONSTRUCTOR ::cvc5::theory::datatypes::DatatypeConstructorTypeRul
 typerule APPLY_SELECTOR ::cvc5::theory::datatypes::DatatypeSelectorTypeRule
 typerule APPLY_SELECTOR_TOTAL ::cvc5::theory::datatypes::DatatypeSelectorTypeRule
 typerule APPLY_TESTER ::cvc5::theory::datatypes::DatatypeTesterTypeRule
-typerule APPLY_DT_UPDATE ::cvc5::theory::datatypes::DatatypeUpdateTypeRule
+typerule APPLY_UPDATER ::cvc5::theory::datatypes::DatatypeUpdateTypeRule
 typerule APPLY_TYPE_ASCRIPTION ::cvc5::theory::datatypes::DatatypeAscriptionTypeRule
 
 # constructor applications are constant if they are applied only to constants
 construle APPLY_CONSTRUCTOR ::cvc5::theory::datatypes::DatatypeConstructorTypeRule
 
-constant TUPLE_UPDATE_OP \
-        ::cvc5::TupleUpdate \
-        ::cvc5::TupleUpdateHashFunction \
-        "util/tuple.h" \
-        "operator for a tuple update; payload is an instance of the cvc5::TupleUpdate class"
-parameterized TUPLE_UPDATE TUPLE_UPDATE_OP 2 "tuple update; first parameter is a TUPLE_UPDATE_OP (which references an index), second is the tuple, third is the element to store in the tuple at the given index"
-typerule TUPLE_UPDATE_OP ::cvc5::theory::datatypes::TupleUpdateOpTypeRule
-typerule TUPLE_UPDATE ::cvc5::theory::datatypes::TupleUpdateTypeRule
-
-constant RECORD_UPDATE_OP \
-        ::cvc5::RecordUpdate \
-        ::cvc5::RecordUpdateHashFunction \
-        "expr/record.h" \
-        "operator for a record update; payload is an instance cvc5::RecordUpdate class"
-parameterized RECORD_UPDATE RECORD_UPDATE_OP 2 "record update; first parameter is a RECORD_UPDATE_OP (which references a field), second is a record term to update, third is the element to store in the record in the given field"
-typerule RECORD_UPDATE_OP ::cvc5::theory::datatypes::RecordUpdateOpTypeRule
-typerule RECORD_UPDATE ::cvc5::theory::datatypes::RecordUpdateTypeRule
-
 operator DT_SIZE 1 "datatypes size"
 typerule DT_SIZE ::cvc5::theory::datatypes::DtSizeTypeRule
 
index 63f48668cf49b1810624278cbc0ec9a39f60c306..c9bfd98dff51bd31ff65be202fb557a25e6712fb 100644 (file)
@@ -207,7 +207,7 @@ TypeNode DatatypeUpdateTypeRule::computeType(NodeManager* nodeManager,
                                              TNode n,
                                              bool check)
 {
-  Assert(n.getKind() == kind::APPLY_DT_UPDATE);
+  Assert(n.getKind() == kind::APPLY_UPDATER);
   TypeNode updType = n.getOperator().getType(check);
   Assert(updType.getNumChildren() == 2);
   if (check)
@@ -288,78 +288,6 @@ Cardinality ConstructorProperties::computeCardinality(TypeNode type)
   return c;
 }
 
-TypeNode TupleUpdateTypeRule::computeType(NodeManager* nodeManager,
-                                          TNode n,
-                                          bool check)
-{
-  Assert(n.getKind() == kind::TUPLE_UPDATE);
-  const TupleUpdate& tu = n.getOperator().getConst<TupleUpdate>();
-  TypeNode tupleType = n[0].getType(check);
-  TypeNode newValue = n[1].getType(check);
-  if (check)
-  {
-    if (!tupleType.isTuple())
-    {
-      throw TypeCheckingExceptionPrivate(
-          n, "Tuple-update expression formed over non-tuple");
-    }
-    if (tu.getIndex() >= tupleType.getTupleLength())
-    {
-      std::stringstream ss;
-      ss << "Tuple-update expression index `" << tu.getIndex()
-         << "' is not a valid index; tuple type only has "
-         << tupleType.getTupleLength() << " fields";
-      throw TypeCheckingExceptionPrivate(n, ss.str().c_str());
-    }
-  }
-  return tupleType;
-}
-
-TypeNode TupleUpdateOpTypeRule::computeType(NodeManager* nodeManager,
-                                            TNode n,
-                                            bool check)
-{
-  Assert(n.getKind() == kind::TUPLE_UPDATE_OP);
-  return nodeManager->builtinOperatorType();
-}
-
-TypeNode RecordUpdateTypeRule::computeType(NodeManager* nodeManager,
-                                           TNode n,
-                                           bool check)
-{
-  Assert(n.getKind() == kind::RECORD_UPDATE);
-  NodeManagerScope nms(nodeManager);
-  const RecordUpdate& ru = n.getOperator().getConst<RecordUpdate>();
-  TypeNode recordType = n[0].getType(check);
-  TypeNode newValue = n[1].getType(check);
-  if (check)
-  {
-    if (!recordType.isRecord())
-    {
-      throw TypeCheckingExceptionPrivate(
-          n, "Record-update expression formed over non-record");
-    }
-    const DType& dt = recordType.getDType();
-    const DTypeConstructor& recCons = dt[0];
-    if (recCons.getSelectorIndexForName(ru.getField()) == -1)
-    {
-      std::stringstream ss;
-      ss << "Record-update field `" << ru.getField()
-         << "' is not a valid field name for the record type";
-      throw TypeCheckingExceptionPrivate(n, ss.str().c_str());
-    }
-  }
-  return recordType;
-}
-
-TypeNode RecordUpdateOpTypeRule::computeType(NodeManager* nodeManager,
-                                             TNode n,
-                                             bool check)
-{
-  Assert(n.getKind() == kind::RECORD_UPDATE_OP);
-  return nodeManager->builtinOperatorType();
-}
-
 TypeNode DtSizeTypeRule::computeType(NodeManager* nodeManager,
                                      TNode n,
                                      bool check)
index 3bf4660e6f29aef78d7df7fd77f18328fbdec2d0..cf57a6c0d1f8fe96988b3bd8250268122a390608 100644 (file)
@@ -44,32 +44,14 @@ struct DatatypeUpdateTypeRule
   static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check);
 };
 
-struct DatatypeAscriptionTypeRule {
-  static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check);
-};
-
-struct ConstructorProperties {
-  static Cardinality computeCardinality(TypeNode type);
-};
-
-struct TupleUpdateTypeRule {
-  static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check);
-};
-
-class TupleUpdateOpTypeRule
+struct DatatypeAscriptionTypeRule
 {
- public:
-  static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check);
-};
-
-struct RecordUpdateTypeRule {
   static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check);
 };
 
-class RecordUpdateOpTypeRule
+struct ConstructorProperties
 {
- public:
-  static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check);
+  static Cardinality computeCardinality(TypeNode type);
 };
 
 class DtSizeTypeRule {
index f651d5f8466d2cca28c95ff0c6c951fe5e5aeb53..bf74347d0af1ab3846232d06a831f90b1959933a 100644 (file)
@@ -117,7 +117,7 @@ const DType& datatypeOf(Node n)
     case CONSTRUCTOR_TYPE: return t[t.getNumChildren() - 1].getDType();
     case SELECTOR_TYPE:
     case TESTER_TYPE:
-    case DT_UPDATE_TYPE: return t[0].getDType();
+    case UPDATER_TYPE: return t[0].getDType();
     default:
       Unhandled() << "arg must be a datatype constructor, selector, or tester";
   }
index 79a44f4265c0a74798465003dd099985ad0480ba..5fd0003bf451ea94f243f4d2ec35d985bcc56042 100644 (file)
@@ -77,7 +77,6 @@ libcvc5_add_sources(
   statistics_value.h
   string.cpp
   string.h
-  tuple.h
   unsafe_interrupt_exception.h
   utility.cpp
   utility.h
diff --git a/src/util/tuple.h b/src/util/tuple.h
deleted file mode 100644 (file)
index 733ecf1..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/******************************************************************************
- * Top contributors (to current version):
- *   Morgan Deters, Mathias Preiner, Tim King
- *
- * This file is part of the cvc5 project.
- *
- * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
- * in the top-level source directory and their institutional affiliations.
- * All rights reserved.  See the file COPYING in the top-level source
- * directory for licensing information.
- * ****************************************************************************
- *
- * Tuple operators.
- */
-
-#include "cvc5_public.h"
-
-#ifndef CVC5__TUPLE_H
-#define CVC5__TUPLE_H
-
-#include <iostream>
-#include <vector>
-#include <utility>
-
-namespace cvc5 {
-
-class TupleUpdate
-{
-  unsigned d_index;
-
- public:
-  TupleUpdate(unsigned index) : d_index(index) {}
-  unsigned getIndex() const { return d_index; }
-  bool operator==(const TupleUpdate& t) const { return d_index == t.d_index; }
-  bool operator!=(const TupleUpdate& t) const { return d_index != t.d_index; }
-}; /* class TupleUpdate */
-
-struct TupleUpdateHashFunction
-{
-  inline size_t operator()(const TupleUpdate& t) const {
-    return t.getIndex();
-  }
-}; /* struct TupleUpdateHashFunction */
-
-std::ostream& operator<<(std::ostream& out, const TupleUpdate& t);
-
-inline std::ostream& operator<<(std::ostream& out, const TupleUpdate& t) {
-  return out << "[" << t.getIndex() << "]";
-}
-
-}  // namespace cvc5
-
-#endif /* CVC5__TUPLE_H */
index 9bda5cff1d2b1d02f9acb1f96e667c3b9815c855..538868c6cd66427772075fb3a4bdfeddac4c74c9 100644 (file)
@@ -480,6 +480,8 @@ set(regress_0_tests
   regress0/datatypes/issue5280-no-nrec.smt2
   regress0/datatypes/jsat-2.6.smt2
   regress0/datatypes/list-bool.smt2
+  regress0/datatypes/list-update.smt2
+  regress0/datatypes/list-update-sat.smt2
   regress0/datatypes/model-subterms-min.smt2
   regress0/datatypes/mutually-recursive.cvc
   regress0/datatypes/pair-bool-bool.cvc
diff --git a/test/regress/regress0/datatypes/list-update-sat.smt2 b/test/regress/regress0/datatypes/list-update-sat.smt2
new file mode 100644 (file)
index 0000000..9f424e5
--- /dev/null
@@ -0,0 +1,8 @@
+(set-logic ALL)
+(set-info :status sat)
+(declare-datatypes ((list 0)) (
+((cons (head Int) (tail list)) (nil))
+))
+(declare-fun a () list)
+(assert (= ((_ update head) a 3) (cons 3 nil)))
+(check-sat)
diff --git a/test/regress/regress0/datatypes/list-update.smt2 b/test/regress/regress0/datatypes/list-update.smt2
new file mode 100644 (file)
index 0000000..178f1a0
--- /dev/null
@@ -0,0 +1,10 @@
+(set-logic ALL)
+(set-info :status unsat)
+(declare-datatypes ((list 0)) (
+((cons (head Int) (tail list)) (nil))
+))
+(declare-fun a () list)
+(declare-fun b () list)
+(assert ((_ is cons) a))
+(assert (= ((_ update head) a 3) ((_ update head) b 4)))
+(check-sat)
index 3fbdcc0b5f884ca153fc631e8cd9233f629bd0ab..f82e722d3c26cf7ccf9ab6949e2ebabc98ca7626 100644 (file)
@@ -214,6 +214,10 @@ TEST_F(TestApiBlackDatatype, datatypeNames)
   ASSERT_EQ(dselTail.getName(), std::string("tail"));
   ASSERT_EQ(dselTail.getRangeSort(), dtypeSort);
 
+  // get selector from datatype
+  ASSERT_NO_THROW(dt.getSelector("head"));
+  ASSERT_THROW(dt.getSelector("cons"), CVC5ApiException);
+
   // possible to construct null datatype declarations if not using solver
   ASSERT_THROW(DatatypeDecl().getName(), CVC5ApiException);
 }
index 7183fa7a7b06606bc18c4d0608375a3951e003f0..8c4e31c22303c1a6e09300ea71ca9d9f24bcd23b 100644 (file)
@@ -50,7 +50,6 @@ TEST_F(TestApiBlackOp, getNumIndices)
 {
   Op plus = d_solver.mkOp(PLUS);
   Op divisible = d_solver.mkOp(DIVISIBLE, 4);
-  Op record_update = d_solver.mkOp(RECORD_UPDATE, "test");
   Op bitvector_repeat = d_solver.mkOp(BITVECTOR_REPEAT, 5);
   Op bitvector_zero_extend = d_solver.mkOp(BITVECTOR_ZERO_EXTEND, 6);
   Op bitvector_sign_extend = d_solver.mkOp(BITVECTOR_SIGN_EXTEND, 7);
@@ -60,7 +59,6 @@ TEST_F(TestApiBlackOp, getNumIndices)
   Op iand = d_solver.mkOp(IAND, 3);
   Op floatingpoint_to_ubv = d_solver.mkOp(FLOATINGPOINT_TO_UBV, 11);
   Op floatingopint_to_sbv = d_solver.mkOp(FLOATINGPOINT_TO_SBV, 13);
-  Op tuple_update = d_solver.mkOp(TUPLE_UPDATE, 5);
   Op floatingpoint_to_fp_ieee_bitvector =
       d_solver.mkOp(FLOATINGPOINT_TO_FP_IEEE_BITVECTOR, 4, 25);
   Op floatingpoint_to_fp_floatingpoint =
@@ -76,7 +74,6 @@ TEST_F(TestApiBlackOp, getNumIndices)
 
   ASSERT_EQ(0, plus.getNumIndices());
   ASSERT_EQ(1, divisible.getNumIndices());
-  ASSERT_EQ(1, record_update.getNumIndices());
   ASSERT_EQ(1, bitvector_repeat.getNumIndices());
   ASSERT_EQ(1, bitvector_zero_extend.getNumIndices());
   ASSERT_EQ(1, bitvector_sign_extend.getNumIndices());
@@ -86,7 +83,6 @@ TEST_F(TestApiBlackOp, getNumIndices)
   ASSERT_EQ(1, iand.getNumIndices());
   ASSERT_EQ(1, floatingpoint_to_ubv.getNumIndices());
   ASSERT_EQ(1, floatingopint_to_sbv.getNumIndices());
-  ASSERT_EQ(1, tuple_update.getNumIndices());
   ASSERT_EQ(2, floatingpoint_to_fp_ieee_bitvector.getNumIndices());
   ASSERT_EQ(2, floatingpoint_to_fp_floatingpoint.getNumIndices());
   ASSERT_EQ(2, floatingpoint_to_fp_real.getNumIndices());
@@ -105,11 +101,6 @@ TEST_F(TestApiBlackOp, getIndicesString)
   ASSERT_TRUE(divisible_ot.isIndexed());
   std::string divisible_idx = divisible_ot.getIndices<std::string>();
   ASSERT_EQ(divisible_idx, "4");
-
-  Op record_update_ot = d_solver.mkOp(RECORD_UPDATE, "test");
-  std::string record_update_idx = record_update_ot.getIndices<std::string>();
-  ASSERT_EQ(record_update_idx, "test");
-  ASSERT_THROW(record_update_ot.getIndices<uint32_t>(), CVC5ApiException);
 }
 
 TEST_F(TestApiBlackOp, getIndicesUint)
@@ -155,11 +146,6 @@ TEST_F(TestApiBlackOp, getIndicesUint)
   uint32_t floatingpoint_to_sbv_idx =
       floatingpoint_to_sbv_ot.getIndices<uint32_t>();
   ASSERT_EQ(floatingpoint_to_sbv_idx, 13);
-
-  Op tuple_update_ot = d_solver.mkOp(TUPLE_UPDATE, 5);
-  uint32_t tuple_update_idx = tuple_update_ot.getIndices<uint32_t>();
-  ASSERT_EQ(tuple_update_idx, 5);
-  ASSERT_THROW(tuple_update_ot.getIndices<std::string>(), CVC5ApiException);
 }
 
 TEST_F(TestApiBlackOp, getIndicesPairUint)
index c0258be9ae8ae48661cdad181bd6dbda2263a139..f7e6a3783dbabcb1c9151bdc6b7a7b39f5ef9852 100644 (file)
@@ -544,7 +544,6 @@ TEST_F(TestApiBlackSolver, mkOp)
   ASSERT_THROW(d_solver.mkOp(BITVECTOR_EXTRACT, EQUAL), CVC5ApiException);
 
   // mkOp(Kind kind, const std::string& arg)
-  ASSERT_NO_THROW(d_solver.mkOp(RECORD_UPDATE, "asdf"));
   ASSERT_NO_THROW(d_solver.mkOp(DIVISIBLE, "2147483648"));
   ASSERT_THROW(d_solver.mkOp(BITVECTOR_EXTRACT, "asdf"), CVC5ApiException);
 
index c2b924bfa6931f257b2dca0c9389915e435c0b18..d1b096bda07c9552f1f83956dba2092d20e5274b 100644 (file)
@@ -153,11 +153,20 @@ TEST_F(TestApiBlackSort, isTester)
 {
   Sort dt_sort = create_datatype_sort();
   Datatype dt = dt_sort.getDatatype();
-  Sort cons_sort = dt[0].getTesterTerm().getSort();
-  ASSERT_TRUE(cons_sort.isTester());
+  Sort testerSort = dt[0].getTesterTerm().getSort();
+  ASSERT_TRUE(testerSort.isTester());
   ASSERT_NO_THROW(Sort().isTester());
 }
 
+TEST_F(TestApiBlackSort, isUpdater)
+{
+  Sort dt_sort = create_datatype_sort();
+  Datatype dt = dt_sort.getDatatype();
+  Sort updaterSort = dt[0][0].getUpdaterTerm().getSort();
+  ASSERT_TRUE(updaterSort.isUpdater());
+  ASSERT_NO_THROW(Sort().isUpdater());
+}
+
 TEST_F(TestApiBlackSort, isFunction)
 {
   Sort fun_sort = d_solver.mkFunctionSort(d_solver.getRealSort(),
index 5844868f1efb7583f94406170a49a5bf815cf401..a19ab31a1800108fbd497cace48b4d1f2e658476 100644 (file)
@@ -249,9 +249,9 @@ TEST_F(TestUtilBlackDatatype, listIntUpdate)
   Node zero = d_nodeManager->mkConst(Rational(0));
   Node truen = d_nodeManager->mkConst(true);
   // construct an update term
-  Node uterm = d_nodeManager->mkNode(kind::APPLY_DT_UPDATE, updater, gt, zero);
+  Node uterm = d_nodeManager->mkNode(kind::APPLY_UPDATER, updater, gt, zero);
   // construct a non well-formed update term
-  ASSERT_THROW(d_nodeManager->mkNode(kind::APPLY_DT_UPDATE, updater, gt, truen)
+  ASSERT_THROW(d_nodeManager->mkNode(kind::APPLY_UPDATER, updater, gt, truen)
                    .getType(true),
                TypeCheckingExceptionPrivate);
 }