LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/proof/eo - eo_node_converter.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 359 385 93.2 %
Date: 2026-07-26 10:35:54 Functions: 17 18 94.4 %
Branches: 222 282 78.7 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * This file is part of the cvc5 project.
       3                 :            :  *
       4                 :            :  * Copyright (c) 2009-2026 by the authors listed in the file AUTHORS
       5                 :            :  * in the top-level source directory and their institutional affiliations.
       6                 :            :  * All rights reserved.  See the file COPYING in the top-level source
       7                 :            :  * directory for licensing information.
       8                 :            :  * ****************************************************************************
       9                 :            :  *
      10                 :            :  * Implementation of Eunoia node conversion
      11                 :            :  */
      12                 :            : 
      13                 :            : #include "proof/eo/eo_node_converter.h"
      14                 :            : 
      15                 :            : #include <algorithm>
      16                 :            : #include <iomanip>
      17                 :            : #include <sstream>
      18                 :            : 
      19                 :            : #include "expr/aci_norm.h"
      20                 :            : #include "expr/array_store_all.h"
      21                 :            : #include "expr/cardinality_constraint.h"
      22                 :            : #include "expr/dtype.h"
      23                 :            : #include "expr/dtype_cons.h"
      24                 :            : #include "expr/sequence.h"
      25                 :            : #include "expr/sort_to_term.h"
      26                 :            : #include "printer/smt2/smt2_printer.h"
      27                 :            : #include "theory/builtin/generic_op.h"
      28                 :            : #include "theory/bv/theory_bv_utils.h"
      29                 :            : #include "theory/datatypes/datatypes_rewriter.h"
      30                 :            : #include "theory/strings/theory_strings_utils.h"
      31                 :            : #include "theory/strings/word.h"
      32                 :            : #include "theory/uf/function_const.h"
      33                 :            : #include "theory/uf/theory_uf_rewriter.h"
      34                 :            : #include "util/bitvector.h"
      35                 :            : #include "util/finite_field_value.h"
      36                 :            : #include "util/floatingpoint.h"
      37                 :            : #include "util/iand.h"
      38                 :            : #include "util/indexed_root_predicate.h"
      39                 :            : #include "util/rational.h"
      40                 :            : #include "util/regexp.h"
      41                 :            : #include "util/string.h"
      42                 :            : 
      43                 :            : using namespace cvc5::internal::kind;
      44                 :            : 
      45                 :            : namespace cvc5::internal {
      46                 :            : namespace proof {
      47                 :            : 
      48                 :       3526 : BaseEoNodeConverter::BaseEoNodeConverter(NodeManager* nm) : NodeConverter(nm) {}
      49                 :            : 
      50                 :       1792 : EoNodeConverter::EoNodeConverter(NodeManager* nm) : BaseEoNodeConverter(nm)
      51                 :            : {
      52                 :            :   // use builtin operator type as the type of sorts, which makes a difference
      53                 :            :   // e.g. for converting terms of kind SORT_TO_TERM.
      54                 :       1792 :   d_sortType = nm->builtinOperatorType();
      55                 :       1792 : }
      56                 :            : 
      57                 :       1792 : EoNodeConverter::~EoNodeConverter() {}
      58                 :            : 
      59                 :    2238283 : Node EoNodeConverter::preConvert(Node n)
      60                 :            : {
      61                 :            :   // match is not supported in Eunoia syntax, we eliminate it at pre-order
      62                 :            :   // traversal, which avoids type-checking errors during conversion, since e.g.
      63                 :            :   // match case nodes are required but cannot be preserved
      64         [ +  + ]:    2238283 :   if (n.getKind() == Kind::MATCH)
      65                 :            :   {
      66                 :         12 :     return theory::datatypes::DatatypesRewriter::expandMatch(n);
      67                 :            :   }
      68                 :    2238271 :   return n;
      69                 :            : }
      70                 :            : 
      71                 :    2234640 : Node EoNodeConverter::postConvert(Node n)
      72                 :            : {
      73                 :    2234640 :   Kind k = n.getKind();
      74                 :            :   // we eliminate MATCH at preConvert above
      75 [ -  + ][ -  + ]:    2234640 :   Assert(k != Kind::MATCH);
                 [ -  - ]
      76         [ +  - ]:    4469280 :   Trace("eo-term-process-debug")
      77                 :    2234640 :       << "postConvert " << n << " " << k << std::endl;
      78 [ +  + ][ -  + ]:    2234640 :   if (k == Kind::ASCRIPTION_TYPE || k == Kind::RAW_SYMBOL)
      79                 :            :   {
      80                 :            :     // dummy node, return it
      81                 :         13 :     return n;
      82                 :            :   }
      83                 :            :   // case for skolems, unhandled variables, and other unhandled terms
      84                 :            :   // These should print as @const, or otherwise be printed as a skolem,
      85                 :            :   // which may need further processing below. In the case of unhandled
      86                 :            :   // terms (e.g. DT_SYGUS_EVAL), we prefer printing them as @const instead
      87                 :            :   // of using their smt2 printer, which would lead to undeclared identifiers in
      88                 :            :   // the proof.
      89 [ +  + ][ +  + ]:    2234627 :   if (k == Kind::SKOLEM || k == Kind::DUMMY_SKOLEM || k == Kind::INST_CONSTANT
                 [ +  + ]
      90         [ -  + ]:    2227582 :       || k == Kind::DT_SYGUS_EVAL)
      91                 :            :   {
      92                 :       7045 :     TypeNode tn = n.getType();
      93                 :            :     // constructors/selectors are represented by skolems, which are defined
      94                 :            :     // symbols
      95         [ +  + ]:      13634 :     if (tn.isDatatypeConstructor() || tn.isDatatypeSelector()
      96 [ +  + ][ +  + ]:      13634 :         || tn.isDatatypeTester() || tn.isDatatypeUpdater())
         [ +  + ][ +  + ]
      97                 :            :     {
      98                 :            :       // note these are not converted to their user named (cvc.) symbols here,
      99                 :            :       // to avoid type errors when constructing terms for postConvert
     100                 :       1071 :       return n;
     101                 :            :     }
     102         [ +  + ]:       5974 :     if (k == Kind::SKOLEM)
     103                 :            :     {
     104                 :            :       // might be a skolem function
     105                 :       5771 :       Node ns = maybeMkSkolemFun(n);
     106         [ +  + ]:       5771 :       if (!ns.isNull())
     107                 :            :       {
     108                 :       5701 :         return ns;
     109                 :            :       }
     110         [ +  + ]:       5771 :     }
     111                 :            :     // Otherwise, it is an uncategorized skolem, must use a fresh variable.
     112                 :            :     // This case will only apply for terms originating from places with no
     113                 :            :     // proof support. Note it is not added as a declared variable, instead it
     114                 :            :     // is used as (var N T) throughout.
     115                 :        546 :     Node index = d_nm->mkConstInt(Rational(getOrAssignIndexForConst(n)));
     116                 :        273 :     Node tc = typeAsNode(tn);
     117 [ +  + ][ -  - ]:        819 :     return mkInternalApp("@const", {index, tc}, tn);
     118                 :       7045 :   }
     119         [ +  + ]:    2227582 :   else if (k == Kind::BOUND_VARIABLE)
     120                 :            :   {
     121                 :      10508 :     std::string sname;
     122         [ +  + ]:      10508 :     if (n.hasName())
     123                 :            :     {
     124                 :            :       // get its name if it has one
     125                 :       7618 :       sname = n.getName();
     126                 :            :     }
     127                 :            :     else
     128                 :            :     {
     129                 :            :       // otherwise invoke the printer to get its name
     130                 :       2890 :       std::stringstream ss;
     131                 :       2890 :       ss << n;
     132                 :       2890 :       sname = ss.str();
     133                 :       2890 :     }
     134                 :            :     // A variable x of type T can unambiguously referred to as (@var "x" T),
     135                 :            :     // which is a macro for (eo::var "x" T) in the cpc signature.
     136                 :            :     // We convert to this representation here, which will often be letified.
     137                 :      10508 :     TypeNode tn = n.getType();
     138                 :      10508 :     std::vector<Node> args;
     139                 :      10508 :     Node nn = d_nm->mkConst(String(sname));
     140                 :      10508 :     args.push_back(nn);
     141                 :      10508 :     Node tnn = typeAsNode(tn);
     142                 :      10508 :     args.push_back(tnn);
     143                 :      10508 :     return mkInternalApp("@var", args, tn);
     144                 :      10508 :   }
     145         [ +  + ]:    2217074 :   else if (k == Kind::VARIABLE)
     146                 :            :   {
     147                 :            :     // note that we do not handle overloading here
     148                 :      16990 :     return n;
     149                 :            :   }
     150         [ +  + ]:    2200084 :   else if (k == Kind::APPLY_UF)
     151                 :            :   {
     152                 :            :     // must ensure we print higher-order function applications with "_"
     153         [ +  + ]:      31500 :     if (!n.getOperator().isVar())
     154                 :            :     {
     155                 :        964 :       TypeNode tn = n.getType();
     156                 :        964 :       std::vector<Node> args;
     157                 :        964 :       args.push_back(n.getOperator());
     158                 :        964 :       args.insert(args.end(), n.begin(), n.end());
     159                 :        964 :       return mkInternalApp("_", args, tn);
     160                 :        964 :     }
     161                 :            :   }
     162         [ +  + ]:    2168584 :   else if (k == Kind::HO_APPLY)
     163                 :            :   {
     164                 :       4860 :     TypeNode tn = n.getType();
     165 [ +  + ][ -  - ]:      14580 :     return mkInternalApp("_", {n[0], n[1]}, tn);
     166                 :       4860 :   }
     167         [ +  + ]:    2163724 :   else if (n.isClosure())
     168                 :            :   {
     169                 :      22610 :     TypeNode tn = n.getType();
     170                 :      22610 :     Node vl = n[0];
     171                 :            :     // Notice that intentionally we drop annotations here.
     172                 :            :     // Additionally, it is important that we convert the closure to a
     173                 :            :     // non-closure operator here, since we will be traversing over it
     174                 :            :     // during letification.
     175                 :      22610 :     std::vector<Node> args;
     176                 :      22610 :     args.insert(args.end(),
     177                 :            :                 n.begin(),
     178                 :      22610 :                 n.begin() + getNumChildrenToProcessForClosure(k));
     179                 :      22610 :     return mkInternalApp(
     180                 :      45220 :         printer::smt2::Smt2Printer::smtKindString(k), args, tn);
     181                 :      22610 :   }
     182         [ +  + ]:    2141114 :   else if (k == Kind::SET_INSERT)
     183                 :            :   {
     184                 :          6 :     TypeNode tn = n.getType();
     185                 :          6 :     std::vector<Node> iargs(n.begin(), n.begin() + n.getNumChildren() - 1);
     186                 :          6 :     Node list = mkTypedList(iargs);
     187 [ +  + ][ -  - ]:         18 :     return mkInternalApp("set.insert", {list, n[n.getNumChildren() - 1]}, tn);
     188                 :          6 :   }
     189         [ +  + ]:    2141108 :   else if (k == Kind::CONST_SEQUENCE)
     190                 :            :   {
     191         [ +  + ]:         92 :     if (!n.getConst<Sequence>().empty())
     192                 :            :     {
     193                 :            :       // if non-empty, must convert to term representation and convert
     194                 :         69 :       Node cc = theory::strings::utils::mkConcatForConstSequence(n);
     195                 :         69 :       return convert(cc);
     196                 :         69 :     }
     197                 :            :   }
     198         [ +  + ]:    2141016 :   else if (k == Kind::CONST_FINITE_FIELD)
     199                 :            :   {
     200                 :         68 :     TypeNode tn = n.getType();
     201                 :         68 :     const FiniteFieldValue& ffv = n.getConst<FiniteFieldValue>();
     202                 :        136 :     Node v = convert(d_nm->mkConstInt(ffv.getValue()));
     203                 :        136 :     Node fs = convert(d_nm->mkConstInt(ffv.getFieldSize()));
     204 [ +  + ][ -  - ]:        204 :     return mkInternalApp("ff.value", {fs, v}, tn);
     205                 :         68 :   }
     206         [ +  + ]:    2140948 :   else if (k == Kind::FUNCTION_ARRAY_CONST)
     207                 :            :   {
     208                 :            :     // must convert to lambda and then run the conversion
     209                 :          7 :     Node lam = theory::uf::FunctionConst::toLambda(n);
     210 [ -  + ][ -  + ]:          7 :     Assert(!lam.isNull());
                 [ -  - ]
     211                 :          7 :     return convert(lam);
     212                 :          7 :   }
     213         [ +  + ]:    2140941 :   else if (k == Kind::APPLY_CONSTRUCTOR)
     214                 :            :   {
     215                 :       2732 :     Node opc = getOperatorOfTerm(n);
     216         [ +  + ]:       2732 :     if (n.getNumChildren() == 0)
     217                 :            :     {
     218                 :        157 :       return opc;
     219                 :            :     }
     220                 :       2575 :     std::vector<Node> newArgs;
     221                 :       2575 :     newArgs.push_back(opc);
     222                 :       2575 :     newArgs.insert(newArgs.end(), n.begin(), n.end());
     223                 :       2575 :     Node ret = d_nm->mkNode(Kind::APPLY_UF, newArgs);
     224                 :       2575 :     return convert(ret);
     225                 :       2732 :   }
     226 [ +  + ][ +  + ]:    2138209 :   else if (k == Kind::APPLY_TESTER || k == Kind::APPLY_UPDATER || k == Kind::NEG
                 [ +  + ]
     227 [ +  + ][ +  + ]:    2136750 :            || k == Kind::DIVISION_TOTAL || k == Kind::INTS_DIVISION_TOTAL
     228 [ +  + ][ +  + ]:    2136287 :            || k == Kind::INTS_MODULUS_TOTAL || k == Kind::APPLY_SELECTOR
     229         [ -  + ]:    2134099 :            || k == Kind::FLOATINGPOINT_TO_FP_FROM_IEEE_BV)
     230                 :            :   {
     231                 :            :     // kinds where the operator may be different
     232                 :       4110 :     Node opc = getOperatorOfTerm(n);
     233         [ -  + ]:       4110 :     if (n.getNumChildren() == 0)
     234                 :            :     {
     235                 :          0 :       return opc;
     236                 :            :     }
     237                 :       4110 :     std::vector<Node> newArgs;
     238         [ +  + ]:       4110 :     if (opc.getNumChildren() > 0)
     239                 :            :     {
     240                 :        900 :       TypeNode tn = n.getType();
     241                 :        900 :       newArgs.insert(newArgs.end(), opc.begin(), opc.end());
     242                 :        900 :       newArgs.insert(newArgs.end(), n.begin(), n.end());
     243                 :        900 :       opc = opc.getOperator();
     244                 :        900 :       std::stringstream ss;
     245                 :        900 :       ss << opc;
     246                 :       1800 :       return mkInternalApp(ss.str(), newArgs, tn);
     247                 :        900 :     }
     248                 :       3210 :     newArgs.push_back(opc);
     249                 :       3210 :     newArgs.insert(newArgs.end(), n.begin(), n.end());
     250                 :       3210 :     return d_nm->mkNode(Kind::APPLY_UF, newArgs);
     251                 :       4110 :   }
     252         [ +  + ]:    2134099 :   else if (k == Kind::INDEXED_ROOT_PREDICATE)
     253                 :            :   {
     254                 :         37 :     TypeNode tn = n.getType();
     255                 :            :     const IndexedRootPredicate& irp =
     256                 :         37 :         n.getOperator().getConst<IndexedRootPredicate>();
     257                 :         37 :     std::vector<Node> newArgs;
     258                 :         37 :     newArgs.push_back(d_nm->mkConstInt(irp.d_index));
     259                 :         37 :     newArgs.insert(newArgs.end(), n.begin(), n.end());
     260                 :         37 :     return mkInternalApp("@indexed_root_predicate", newArgs, tn);
     261                 :         37 :   }
     262         [ +  + ]:    2134062 :   else if (k == Kind::FLOATINGPOINT_COMPONENT_NAN
     263         [ +  + ]:    2134058 :            || k == Kind::FLOATINGPOINT_COMPONENT_INF
     264         [ +  + ]:    2134055 :            || k == Kind::FLOATINGPOINT_COMPONENT_ZERO
     265         [ +  + ]:    2134052 :            || k == Kind::FLOATINGPOINT_COMPONENT_SIGN
     266         [ +  + ]:    2134048 :            || k == Kind::FLOATINGPOINT_COMPONENT_EXPONENT
     267         [ +  + ]:    2134045 :            || k == Kind::FLOATINGPOINT_COMPONENT_SIGNIFICAND)
     268                 :            :   {
     269                 :         20 :     TypeNode tn = n.getType();
     270                 :            :     // dummy symbol, provide the return type
     271                 :         20 :     Node tnn = typeAsNode(tn);
     272                 :         20 :     std::stringstream ss;
     273                 :         20 :     ss << printer::smt2::Smt2Printer::smtKindString(k);
     274                 :         60 :     return mkInternalApp(ss.str(), {tnn}, tn);
     275                 :         20 :   }
     276 [ +  + ][ +  + ]:    2134042 :   else if (k == Kind::SEXPR || k == Kind::BOUND_VAR_LIST)
     277                 :            :   {
     278                 :      99499 :     TypeNode tn = n.getType();
     279                 :            :     // use generic list
     280                 :      99499 :     std::vector<Node> args;
     281                 :      99499 :     args.insert(args.end(), n.begin(), n.end());
     282                 :      99499 :     return mkInternalApp("@list", args, tn);
     283                 :      99499 :   }
     284         [ +  + ]:    2034543 :   else if (k == Kind::APPLY_INDEXED_SYMBOLIC)
     285                 :            :   {
     286                 :       2871 :     Kind okind = n.getOperator().getConst<GenericOp>().getKind();
     287         [ -  + ]:       2871 :     if (okind == Kind::FLOATINGPOINT_TO_FP_FROM_IEEE_BV)
     288                 :            :     {
     289                 :          0 :       TypeNode tn = n.getType();
     290                 :            :       // This does not take a rounding mode, we change the smt2 syntax
     291                 :            :       // to distinguish this case, similar to the case in getOperatorOfTerm
     292                 :            :       // where it is processed as an indexed operator.
     293                 :          0 :       std::vector<Node> children(n.begin(), n.end());
     294                 :          0 :       return mkInternalApp("to_fp_bv", children, tn);
     295                 :          0 :     }
     296                 :            :   }
     297         [ +  + ]:    2031672 :   else if (k == Kind::BITVECTOR_EAGER_ATOM)
     298                 :            :   {
     299                 :            :     // For now, we explicity remove the application.
     300                 :            :     // https://github.com/cvc5/cvc5-wishues/issues/156: if the smt2 printer
     301                 :            :     // is refactored to silently ignore this kind, this case can be deleted.
     302                 :          4 :     return n[0];
     303                 :            :   }
     304         [ +  + ]:    2031668 :   else if (k == Kind::SORT_TO_TERM)
     305                 :            :   {
     306                 :          1 :     return typeAsNode(n.getConst<SortToTerm>().getType());
     307                 :            :   }
     308         [ +  + ]:    2031667 :   else if (GenericOp::isIndexedOperatorKind(k))
     309                 :            :   {
     310                 :      15613 :     TypeNode tn = n.getType();
     311                 :            :     // return app of?
     312                 :            :     std::vector<Node> args =
     313                 :      15613 :         GenericOp::getIndicesForOperator(k, n.getOperator());
     314 [ +  + ][ +  + ]:      15613 :     if (k == Kind::RELATION_GROUP || k == Kind::TABLE_GROUP)
     315                 :            :     {
     316                 :          6 :       Node list = mkList(args);
     317                 :          6 :       std::vector<Node> children;
     318                 :          6 :       children.push_back(list);
     319                 :          6 :       children.insert(children.end(), n.begin(), n.end());
     320                 :          6 :       return mkInternalApp(
     321                 :         12 :           printer::smt2::Smt2Printer::smtKindString(k), children, tn);
     322                 :          6 :     }
     323                 :      15607 :     args.insert(args.end(), n.begin(), n.end());
     324                 :      15607 :     return mkInternalApp(
     325                 :      31214 :         printer::smt2::Smt2Printer::smtKindString(k), args, tn);
     326                 :      15613 :   }
     327                 :    2049484 :   return n;
     328                 :            : }
     329                 :            : 
     330                 :    2238271 : bool EoNodeConverter::shouldTraverse(Node n)
     331                 :            : {
     332                 :    2238271 :   Kind k = n.getKind();
     333                 :            :   // don't convert instantiation pattern list directly
     334         [ +  + ]:    2238271 :   if (k == Kind::INST_PATTERN_LIST)
     335                 :            :   {
     336                 :       1056 :     return false;
     337                 :            :   }
     338                 :            :   // should not traverse internal applications
     339         [ +  + ]:    2237215 :   if (k == Kind::APPLY_UF)
     340                 :            :   {
     341         [ +  + ]:      34075 :     if (d_symbols.find(n.getOperator()) != d_symbols.end())
     342                 :            :     {
     343                 :       2575 :       return false;
     344                 :            :     }
     345                 :            :   }
     346                 :    2234640 :   return true;
     347                 :            : }
     348                 :            : 
     349                 :       5771 : Node EoNodeConverter::maybeMkSkolemFun(Node k)
     350                 :            : {
     351                 :       5771 :   SkolemManager* sm = d_nm->getSkolemManager();
     352                 :       5771 :   SkolemId sfi = SkolemId::NONE;
     353                 :       5771 :   Node cacheVal;
     354                 :       5771 :   TypeNode tn = k.getType();
     355         [ +  - ]:       5771 :   if (sm->isSkolemFunction(k, sfi, cacheVal))
     356                 :            :   {
     357         [ +  + ]:       5771 :     if (isHandledSkolemId(sfi))
     358                 :            :     {
     359         [ +  + ]:       5701 :       if (!cacheVal.isNull())
     360                 :            :       {
     361                 :       5575 :         std::vector<Node> vals;
     362         [ +  + ]:       5575 :         if (cacheVal.getKind() == Kind::SEXPR)
     363                 :            :         {
     364                 :        687 :           vals.insert(vals.end(), cacheVal.begin(), cacheVal.end());
     365                 :            :         }
     366                 :            :         else
     367                 :            :         {
     368                 :       4888 :           vals.push_back(cacheVal);
     369                 :            :         }
     370                 :       5575 :         bool hasChanged = false;
     371         [ +  + ]:      11966 :         for (Node& v : vals)
     372                 :            :         {
     373                 :       6391 :           Node orig = v;
     374                 :       6391 :           v = convert(v);
     375 [ +  + ][ +  + ]:       6391 :           hasChanged = hasChanged || v != orig;
     376                 :       6391 :         }
     377                 :            :         // if an index term changed, we have to construct a new skolem
     378         [ +  + ]:       5575 :         if (hasChanged)
     379                 :            :         {
     380                 :            :           // construct an internal app instead
     381                 :       1780 :           std::stringstream ss;
     382                 :       1780 :           ss << "@" << sfi;
     383                 :       3560 :           return mkInternalApp(ss.str(), vals, k.getType());
     384                 :       1780 :         }
     385         [ +  + ]:       5575 :       }
     386                 :            :       // otherwise we return itself, this will be printed in its full
     387                 :            :       // definition since applyPrintSkolemDefinitions is set to true
     388                 :       3921 :       return k;
     389                 :            :     }
     390                 :            :   }
     391                 :         70 :   return Node::null();
     392                 :       5771 : }
     393                 :            : 
     394                 :      11334 : Node EoNodeConverter::typeAsNode(TypeNode tn)
     395                 :            : {
     396                 :            :   // should always exist in the cache, as we always run types through
     397                 :            :   // postConvertType before calling this method.
     398                 :      11334 :   std::map<TypeNode, Node>::const_iterator it = d_typeAsNode.find(tn);
     399         [ +  + ]:      11334 :   if (it != d_typeAsNode.end())
     400                 :            :   {
     401                 :       9902 :     return it->second;
     402                 :            :   }
     403                 :            :   // dummy symbol whose name is the type printed
     404                 :            :   // this suffices since Eunoia faithfully represents all types.
     405                 :            :   // note we cannot letify types (same as in SMT-LIB)
     406                 :       1432 :   std::stringstream ss;
     407                 :       1432 :   ss << tn;
     408                 :       2864 :   Node ret = mkInternalSymbol(ss.str(), d_sortType, true);
     409                 :       1432 :   d_typeAsNode[tn] = ret;
     410                 :       1432 :   return ret;
     411                 :       1432 : }
     412                 :            : 
     413                 :      22610 : size_t EoNodeConverter::getNumChildrenToProcessForClosure(Kind k) const
     414                 :            : {
     415         [ +  + ]:      22610 :   return k == Kind::SET_COMPREHENSION ? 3 : 2;
     416                 :            : }
     417                 :            : 
     418                 :          6 : Node EoNodeConverter::mkList(const std::vector<Node>& args)
     419                 :            : {
     420 [ -  + ][ -  + ]:          6 :   Assert(!args.empty());
                 [ -  - ]
     421                 :          6 :   TypeNode tn = d_nm->booleanType();
     422                 :            :   // singleton lists are handled due to (@list x) ---> (@list x eo::nil)
     423                 :         12 :   return mkInternalApp("@list", args, tn);
     424                 :          6 : }
     425                 :            : 
     426                 :          6 : Node EoNodeConverter::mkTypedList(const std::vector<Node>& args)
     427                 :            : {
     428 [ -  + ][ -  + ]:          6 :   Assert(!args.empty());
                 [ -  - ]
     429                 :          6 :   TypeNode tn = d_nm->booleanType();
     430                 :         12 :   return mkInternalApp("@tlist", args, tn);
     431                 :          6 : }
     432                 :            : 
     433                 :     173919 : Node EoNodeConverter::mkInternalSymbol(const std::string& name,
     434                 :            :                                        TypeNode tn,
     435                 :            :                                        bool useRawSym)
     436                 :            : {
     437                 :            :   // use raw symbol so that it is never quoted
     438                 :            :   Node sym = useRawSym ? NodeManager::mkRawSymbol(name, tn)
     439         [ +  - ]:     173919 :                        : NodeManager::mkBoundVar(name, tn);
     440                 :     173919 :   d_symbols.insert(sym);
     441                 :     173919 :   return sym;
     442                 :          0 : }
     443                 :            : 
     444                 :     172477 : Node EoNodeConverter::mkInternalApp(const std::string& name,
     445                 :            :                                     const std::vector<Node>& args,
     446                 :            :                                     TypeNode ret,
     447                 :            :                                     bool useRawSym)
     448                 :            : {
     449         [ +  + ]:     172477 :   if (!args.empty())
     450                 :            :   {
     451                 :     172320 :     std::vector<TypeNode> argTypes;
     452         [ +  + ]:    3318645 :     for (const Node& a : args)
     453                 :            :     {
     454 [ -  + ][ -  + ]:    3146325 :       Assert(!a.isNull());
                 [ -  - ]
     455                 :    3146325 :       argTypes.push_back(a.getType());
     456                 :            :     }
     457                 :     172320 :     TypeNode atype = d_nm->mkFunctionType(argTypes, ret);
     458                 :     172320 :     Node op = mkInternalSymbol(name, atype, useRawSym);
     459                 :     172320 :     std::vector<Node> aargs;
     460                 :     172320 :     aargs.push_back(op);
     461                 :     172320 :     aargs.insert(aargs.end(), args.begin(), args.end());
     462                 :     172320 :     return d_nm->mkNode(Kind::APPLY_UF, aargs);
     463                 :     172320 :   }
     464                 :        157 :   return mkInternalSymbol(name, ret, useRawSym);
     465                 :            : }
     466                 :            : 
     467                 :       6842 : Node EoNodeConverter::getOperatorOfTerm(Node n)
     468                 :            : {
     469 [ -  + ][ -  + ]:       6842 :   Assert(n.hasOperator());
                 [ -  - ]
     470                 :       6842 :   Kind k = n.getKind();
     471                 :       6842 :   std::stringstream opName;
     472         [ +  - ]:      13684 :   Trace("eo-term-process-debug2")
     473                 :          0 :       << "getOperatorOfTerm " << n << " " << k << " "
     474                 :          0 :       << (n.getMetaKind() == metakind::PARAMETERIZED) << " "
     475                 :       6842 :       << GenericOp::isIndexedOperatorKind(k) << std::endl;
     476                 :       6842 :   std::vector<Node> indices;
     477         [ +  + ]:       6842 :   if (n.getMetaKind() == metakind::PARAMETERIZED)
     478                 :            :   {
     479                 :       5434 :     Node op = n.getOperator();
     480                 :       5434 :     bool isIndexed = GenericOp::isIndexedOperatorKind(k);
     481         [ +  + ]:       5434 :     if (isIndexed)
     482                 :            :     {
     483                 :        817 :       indices = GenericOp::getIndicesForOperator(k, n.getOperator());
     484                 :            :     }
     485         [ -  + ]:       4617 :     else if (op.getType().isFunction())
     486                 :            :     {
     487                 :          0 :       return op;
     488                 :            :     }
     489                 :            :     // note other kinds of functions (e.g. selectors and testers)
     490                 :       5434 :     Node ret;
     491         [ +  + ]:       5434 :     if (isIndexed)
     492                 :            :     {
     493         [ +  + ]:        817 :       if (k == Kind::APPLY_TESTER)
     494                 :            :       {
     495                 :        802 :         indices.clear();
     496                 :        802 :         size_t cindex = DType::indexOf(op);
     497                 :        802 :         const DType& dt = DType::datatypeOf(op);
     498                 :        802 :         opName << "is";
     499         [ +  + ]:        802 :         if (dt.isTuple())
     500                 :            :         {
     501         [ +  + ]:         10 :           std::string tname = dt[0].getNumArgs() == 0 ? "tuple.unit" : "tuple";
     502                 :         20 :           Node tsym = mkInternalSymbol(tname, dt[0].getConstructor().getType());
     503                 :         10 :           indices.push_back(tsym);
     504                 :         10 :         }
     505                 :            :         else
     506                 :            :         {
     507                 :        792 :           indices.push_back(dt[cindex].getConstructor());
     508                 :            :         }
     509                 :            :       }
     510         [ +  - ]:         15 :       else if (k == Kind::APPLY_UPDATER)
     511                 :            :       {
     512                 :         15 :         indices.clear();
     513                 :         15 :         size_t index = DType::indexOf(op);
     514                 :         15 :         const DType& dt = DType::datatypeOf(op);
     515                 :         15 :         size_t cindex = DType::cindexOf(op);
     516         [ +  + ]:         15 :         if (dt.isTuple())
     517                 :            :         {
     518                 :          6 :           opName << "tuple.update";
     519                 :          6 :           indices.push_back(d_nm->mkConstInt(index));
     520                 :            :         }
     521                 :            :         else
     522                 :            :         {
     523                 :          9 :           opName << "update";
     524                 :          9 :           indices.push_back(dt[cindex][index].getSelector());
     525                 :            :         }
     526                 :            :       }
     527         [ -  - ]:          0 :       else if (k == Kind::FLOATINGPOINT_TO_FP_FROM_IEEE_BV)
     528                 :            :       {
     529                 :            :         // this does not take a rounding mode, we change the smt2 syntax
     530                 :            :         // to distinguish this case.
     531                 :          0 :         opName << "to_fp_bv";
     532                 :            :       }
     533                 :            :       else
     534                 :            :       {
     535                 :          0 :         opName << printer::smt2::Smt2Printer::smtKindString(k);
     536                 :            :       }
     537                 :            :     }
     538         [ +  + ]:       4617 :     else if (k == Kind::APPLY_CONSTRUCTOR)
     539                 :            :     {
     540                 :       2732 :       unsigned index = DType::indexOf(op);
     541                 :       2732 :       const DType& dt = DType::datatypeOf(op);
     542                 :            :       // get its variable name
     543         [ +  + ]:       2732 :       if (dt.isTuple())
     544                 :            :       {
     545         [ +  + ]:        452 :         if (n.getNumChildren() == 0)
     546                 :            :         {
     547                 :          1 :           opName << "tuple.unit";
     548                 :            :         }
     549                 :            :         else
     550                 :            :         {
     551                 :        451 :           opName << "tuple";
     552                 :            :         }
     553                 :            :       }
     554         [ +  + ]:          7 :       else if ((dt.isNullable() && index == 0)
     555 [ +  + ][ +  + ]:       2320 :                || (dt.isParametric()
     556 [ +  + ][ +  + ]:       2313 :                    && isAmbiguousDtConstructor(dt[index].getConstructor())))
         [ +  + ][ -  - ]
     557                 :            :       {
     558                 :            :         // ambiguous if nullable.null or a user provided ambiguous datatype
     559                 :            :         // constructor
     560                 :          6 :         opName << "as";
     561                 :          6 :         indices.push_back(dt[index].getConstructor());
     562                 :            :         // tn is the return type
     563                 :          6 :         TypeNode tn = n.getType();
     564                 :          6 :         indices.push_back(typeAsNode(tn));
     565                 :          6 :       }
     566                 :            :       else
     567                 :            :       {
     568                 :       2274 :         opName << dt[index].getConstructor();
     569                 :            :       }
     570                 :            :     }
     571         [ +  - ]:       1885 :     else if (k == Kind::APPLY_SELECTOR)
     572                 :            :     {
     573                 :            :       // maybe a shared selector
     574         [ -  + ]:       1885 :       if (op.getSkolemId() == SkolemId::SHARED_SELECTOR)
     575                 :            :       {
     576                 :          0 :         std::vector<Node> kindices = op.getSkolemIndices();
     577                 :          0 :         opName << "@shared_selector";
     578                 :          0 :         indices.push_back(
     579                 :          0 :             typeAsNode(kindices[0].getConst<SortToTerm>().getType()));
     580                 :          0 :         indices.push_back(
     581                 :          0 :             typeAsNode(kindices[1].getConst<SortToTerm>().getType()));
     582                 :          0 :         indices.push_back(kindices[2]);
     583                 :          0 :       }
     584                 :            :       else
     585                 :            :       {
     586                 :       1885 :         unsigned index = DType::indexOf(op);
     587                 :       1885 :         const DType& dt = DType::datatypeOf(op);
     588         [ +  + ]:       1885 :         if (dt.isTuple())
     589                 :            :         {
     590                 :         83 :           indices.push_back(d_nm->mkConstInt(index));
     591                 :         83 :           opName << "tuple.select";
     592                 :            :         }
     593                 :            :         else
     594                 :            :         {
     595                 :       1802 :           unsigned cindex = DType::cindexOf(op);
     596                 :       1802 :           opName << dt[cindex][index].getSelector();
     597                 :            :         }
     598                 :            :       }
     599                 :            :     }
     600                 :            :     else
     601                 :            :     {
     602                 :          0 :       opName << op;
     603                 :            :     }
     604         [ +  - ]:       5434 :   }
     605                 :            :   else
     606                 :            :   {
     607                 :       1408 :     opName << printer::smt2::Smt2Printer::smtKindString(k);
     608                 :            :   }
     609                 :       6842 :   std::vector<Node> args(n.begin(), n.end());
     610                 :      13684 :   Node app = mkInternalApp(opName.str(), args, n.getType());
     611                 :       6842 :   Node ret;
     612         [ +  + ]:       6842 :   if (!indices.empty())
     613                 :            :   {
     614         [ +  + ]:        906 :     Node op = args.empty() ? app : app.getOperator();
     615                 :        906 :     ret = mkInternalApp(opName.str(), indices, op.getType());
     616                 :        906 :   }
     617         [ -  + ]:       5936 :   else if (n.isClosure())
     618                 :            :   {
     619                 :            :     // The operator of a closure by convention includes its variable list.
     620                 :            :     // This is required for cong over binders. We do not convert the variable
     621                 :            :     // list here, for the same reason as why it is not converted in convert(..).
     622                 :          0 :     Node vl = n[0];
     623                 :            :     // the type of this term is irrelevant, just use vl's type
     624                 :          0 :     ret = mkInternalApp(
     625                 :          0 :         printer::smt2::Smt2Printer::smtKindString(k), {vl}, vl.getType());
     626                 :          0 :   }
     627                 :            :   else
     628                 :            :   {
     629         [ +  + ]:       5936 :     ret = args.empty() ? app : app.getOperator();
     630                 :            :   }
     631         [ +  - ]:       6842 :   Trace("eo-term-process-debug2") << "...return " << ret << std::endl;
     632                 :       6842 :   return ret;
     633                 :       6842 : }
     634                 :            : 
     635                 :        273 : size_t EoNodeConverter::getOrAssignIndexForConst(Node v)
     636                 :            : {
     637                 :        273 :   std::map<Node, size_t>::iterator it = d_constIndex.find(v);
     638         [ -  + ]:        273 :   if (it != d_constIndex.end())
     639                 :            :   {
     640                 :          0 :     return it->second;
     641                 :            :   }
     642                 :        273 :   size_t id = d_constIndex.size();
     643                 :        273 :   d_constIndex[v] = id;
     644                 :        273 :   return id;
     645                 :            : }
     646                 :            : 
     647                 :         33 : bool EoNodeConverter::isAmbiguousDtConstructor(const Node& op)
     648                 :            : {
     649                 :         33 :   std::map<Node, bool>::iterator it = d_ambDt.find(op);
     650         [ +  + ]:         33 :   if (it != d_ambDt.end())
     651                 :            :   {
     652                 :         22 :     return it->second;
     653                 :            :   }
     654                 :         11 :   bool ret = false;
     655                 :         11 :   TypeNode tn = op.getType();
     656         [ +  - ]:         22 :   Trace("eo-amb-dt") << "Ambiguous datatype constructor? " << op << " " << tn
     657                 :         11 :                      << std::endl;
     658                 :         11 :   size_t nchild = tn.getNumChildren();
     659 [ -  + ][ -  + ]:         11 :   Assert(nchild > 0);
                 [ -  - ]
     660                 :         11 :   std::unordered_set<TypeNode> atypes;
     661         [ +  + ]:         24 :   for (size_t i = 0; i < nchild - 1; i++)
     662                 :            :   {
     663                 :         13 :     expr::getComponentTypes(tn[i], atypes);
     664                 :            :   }
     665                 :         11 :   const DType& dt = DType::datatypeOf(op);
     666                 :         11 :   std::vector<TypeNode> params = dt.getParameters();
     667         [ +  + ]:         20 :   for (const TypeNode& p : params)
     668                 :            :   {
     669         [ +  + ]:         13 :     if (atypes.find(p) == atypes.end())
     670                 :            :     {
     671         [ +  - ]:          8 :       Trace("eo-amb-dt") << "...yes since " << p << " not contained"
     672                 :          4 :                          << std::endl;
     673                 :          4 :       ret = true;
     674                 :          4 :       break;
     675                 :            :     }
     676                 :            :   }
     677         [ +  - ]:         11 :   Trace("eo-amb-dt") << "...returns " << ret << std::endl;
     678                 :         11 :   d_ambDt[op] = ret;
     679                 :         11 :   return ret;
     680                 :         11 : }
     681                 :            : 
     682                 :       5771 : bool EoNodeConverter::isHandledSkolemId(SkolemId id)
     683                 :            : {
     684                 :            :   // Note we don't handle skolems that take types as arguments yet.
     685         [ +  + ]:       5771 :   switch (id)
     686                 :            :   {
     687                 :       5701 :     case SkolemId::PURIFY:
     688                 :            :     case SkolemId::ARRAY_DEQ_DIFF:
     689                 :            :     case SkolemId::BV_EMPTY:
     690                 :            :     case SkolemId::DIV_BY_ZERO:
     691                 :            :     case SkolemId::INT_DIV_BY_ZERO:
     692                 :            :     case SkolemId::MOD_BY_ZERO:
     693                 :            :     case SkolemId::TRANSCENDENTAL_PURIFY:
     694                 :            :     case SkolemId::TRANSCENDENTAL_PURIFY_ARG:
     695                 :            :     case SkolemId::ARITH_VTS_DELTA:
     696                 :            :     case SkolemId::ARITH_VTS_DELTA_FREE:
     697                 :            :     case SkolemId::QUANTIFIERS_SKOLEMIZE:
     698                 :            :     case SkolemId::SETS_DEQ_DIFF:
     699                 :            :     case SkolemId::STRINGS_NUM_OCCUR:
     700                 :            :     case SkolemId::STRINGS_NUM_OCCUR_RE:
     701                 :            :     case SkolemId::STRINGS_OCCUR_INDEX:
     702                 :            :     case SkolemId::STRINGS_OCCUR_INDEX_RE:
     703                 :            :     case SkolemId::STRINGS_DEQ_DIFF:
     704                 :            :     case SkolemId::STRINGS_REPLACE_ALL_RESULT:
     705                 :            :     case SkolemId::STRINGS_ITOS_RESULT:
     706                 :            :     case SkolemId::STRINGS_STOI_RESULT:
     707                 :            :     case SkolemId::STRINGS_STOI_NON_DIGIT:
     708                 :            :     case SkolemId::RE_UNFOLD_POS_COMPONENT:
     709                 :            :     case SkolemId::BAGS_DEQ_DIFF:
     710                 :            :     case SkolemId::BAGS_DISTINCT_ELEMENTS:
     711                 :            :     case SkolemId::BAGS_MAP_PREIMAGE_INJECTIVE:
     712                 :            :     case SkolemId::BAGS_DISTINCT_ELEMENTS_SIZE:
     713                 :            :     case SkolemId::BAGS_MAP_SUM:
     714                 :            :     case SkolemId::TABLES_GROUP_PART:
     715                 :            :     case SkolemId::TABLES_GROUP_PART_ELEMENT:
     716                 :       5701 :     case SkolemId::WITNESS_STRING_LENGTH: return true;
     717                 :         70 :     default: break;
     718                 :            :   }
     719                 :         70 :   return false;
     720                 :            : }
     721                 :            : 
     722                 :            : }  // namespace proof
     723                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14