LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory - theory_model_builder.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 567 608 93.3 %
Date: 2026-04-21 10:32:34 Functions: 21 21 100.0 %
Branches: 428 637 67.2 %

           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 theory model buidler class.
      11                 :            :  */
      12                 :            : #include "theory/theory_model_builder.h"
      13                 :            : 
      14                 :            : #include "expr/dtype.h"
      15                 :            : #include "expr/dtype_cons.h"
      16                 :            : #include "expr/skolem_manager.h"
      17                 :            : #include "expr/sort_to_term.h"
      18                 :            : #include "expr/sort_type_size.h"
      19                 :            : #include "options/quantifiers_options.h"
      20                 :            : #include "options/smt_options.h"
      21                 :            : #include "options/strings_options.h"
      22                 :            : #include "options/theory_options.h"
      23                 :            : #include "options/uf_options.h"
      24                 :            : #include "smt/env.h"
      25                 :            : #include "theory/rewriter.h"
      26                 :            : #include "theory/uf/function_const.h"
      27                 :            : #include "theory/uf/theory_uf_model.h"
      28                 :            : #include "util/uninterpreted_sort_value.h"
      29                 :            : 
      30                 :            : using namespace std;
      31                 :            : using namespace cvc5::internal::kind;
      32                 :            : using namespace cvc5::context;
      33                 :            : 
      34                 :            : namespace cvc5::internal {
      35                 :            : namespace theory {
      36                 :            : 
      37                 :      57768 : TheoryEngineModelBuilder::TheoryEngineModelBuilder(Env& env) : EnvObj(env) {}
      38                 :            : 
      39                 :         12 : void TheoryEngineModelBuilder::Assigner::initialize(
      40                 :            :     TypeNode tn, TypeEnumeratorProperties* tep, const std::vector<Node>& aes)
      41                 :            : {
      42                 :         12 :   d_te.reset(new TypeEnumerator(tn, tep));
      43                 :         12 :   d_assignExcSet.insert(d_assignExcSet.end(), aes.begin(), aes.end());
      44                 :         12 : }
      45                 :            : 
      46                 :         47 : Node TheoryEngineModelBuilder::Assigner::getNextAssignment()
      47                 :            : {
      48 [ -  + ][ -  + ]:         47 :   Assert(d_te != nullptr);
                 [ -  - ]
      49                 :         47 :   Node n;
      50                 :         47 :   bool success = false;
      51                 :         47 :   TypeEnumerator& te = *d_te;
      52                 :            :   // Check if we have run out of elements. This should never happen; if it
      53                 :            :   // does we assert false and return null.
      54         [ -  + ]:         47 :   if (te.isFinished())
      55                 :            :   {
      56                 :          0 :     DebugUnhandled();
      57                 :            :     return Node::null();
      58                 :            :   }
      59                 :            :   // must increment until we find one that is not in the assignment
      60                 :            :   // exclusion set
      61                 :            :   do
      62                 :            :   {
      63                 :         57 :     n = *te;
      64                 :         57 :     success = std::find(d_assignExcSet.begin(), d_assignExcSet.end(), n)
      65                 :        114 :               == d_assignExcSet.end();
      66                 :            :     // increment regardless of fail or succeed, to set up the next value
      67                 :         57 :     ++te;
      68         [ +  + ]:         57 :   } while (!success);
      69                 :         47 :   return n;
      70                 :         47 : }
      71                 :            : 
      72                 :     424922 : Node TheoryEngineModelBuilder::evaluateEqc(TheoryModel* m, TNode r)
      73                 :            : {
      74                 :     424922 :   eq::EqClassIterator eqc_i = eq::EqClassIterator(r, m->d_equalityEngine);
      75         [ +  + ]:     438908 :   for (; !eqc_i.isFinished(); ++eqc_i)
      76                 :            :   {
      77                 :     429523 :     Node n = *eqc_i;
      78         [ +  - ]:     429523 :     Trace("model-builder-debug") << "Look at term : " << n << std::endl;
      79         [ +  + ]:     429523 :     if (!isAssignable(n))
      80                 :            :     {
      81         [ +  - ]:     428304 :       Trace("model-builder-debug") << "...try to normalize" << std::endl;
      82                 :     428304 :       Node normalized = normalize(m, n, true);
      83         [ +  - ]:     856608 :       Trace("model-builder-debug")
      84                 :          0 :           << "...return " << normalized
      85 [ -  + ][ -  - ]:     428304 :           << ", isValue=" << m->isValue(normalized) << std::endl;
      86         [ +  + ]:     428304 :       if (m->isValue(normalized))
      87                 :            :       {
      88                 :     415537 :         return normalized;
      89                 :            :       }
      90         [ +  + ]:     428304 :     }
      91         [ +  + ]:     429523 :   }
      92                 :       9385 :   return Node::null();
      93                 :            : }
      94                 :            : 
      95                 :         47 : bool TheoryEngineModelBuilder::isAssignerActive(TheoryModel* tm, Assigner& a)
      96                 :            : {
      97         [ +  + ]:         47 :   if (a.d_isActive)
      98                 :            :   {
      99                 :         35 :     return true;
     100                 :            :   }
     101                 :         12 :   std::vector<Node>& eset = a.d_assignExcSet;
     102                 :         12 :   std::map<Node, Node>::iterator it;
     103         [ +  + ]:         34 :   for (unsigned i = 0, size = eset.size(); i < size; i++)
     104                 :            :   {
     105                 :            :     // Members of exclusion set must have values, otherwise we are not yet
     106                 :            :     // assignable.
     107                 :         22 :     Node er = eset[i];
     108         [ +  + ]:         22 :     if (tm->isValue(er))
     109                 :            :     {
     110                 :            :       // already processed
     111                 :         16 :       continue;
     112                 :            :     }
     113                 :            :     // Assignable members of assignment exclusion set should be representatives
     114                 :            :     // of their equivalence classes. This ensures we look up the constant
     115                 :            :     // representatives for assignable members of assignment exclusion sets.
     116 [ -  + ][ -  + ]:          6 :     Assert(er == tm->getRepresentative(er));
                 [ -  - ]
     117                 :          6 :     it = d_constantReps.find(er);
     118         [ -  + ]:          6 :     if (it == d_constantReps.end())
     119                 :            :     {
     120         [ -  - ]:          0 :       Trace("model-build-aes")
     121                 :          0 :           << "isAssignerActive: not active due to " << er << std::endl;
     122                 :          0 :       return false;
     123                 :            :     }
     124                 :            :     // update
     125                 :          6 :     eset[i] = it->second;
     126    [ +  + ][ - ]:         22 :   }
     127         [ +  - ]:         12 :   Trace("model-build-aes") << "isAssignerActive: active!" << std::endl;
     128                 :         12 :   a.d_isActive = true;
     129                 :         12 :   return true;
     130                 :            : }
     131                 :            : 
     132                 :    6039404 : bool TheoryEngineModelBuilder::isAssignable(TNode n)
     133                 :            : {
     134                 :    6039404 :   Kind k = n.getKind();
     135 [ +  + ][ +  + ]:    6039404 :   if (k == Kind::SELECT || k == Kind::APPLY_SELECTOR || k == Kind::SEQ_NTH)
                 [ +  + ]
     136                 :            :   {
     137                 :            :     // selectors are always assignable (where we guarantee that they are not
     138                 :            :     // evaluatable here)
     139         [ +  + ]:     489779 :     if (!logicInfo().isHigherOrder())
     140                 :            :     {
     141 [ -  + ][ -  + ]:     488009 :       Assert(!n.getType().isFunction());
                 [ -  - ]
     142                 :     488009 :       return true;
     143                 :            :     }
     144                 :            :     else
     145                 :            :     {
     146                 :            :       // might be a function field
     147                 :       1770 :       return !n.getType().isFunction();
     148                 :            :     }
     149                 :            :   }
     150 [ +  + ][ +  + ]:    5549625 :   else if (k == Kind::FLOATINGPOINT_COMPONENT_SIGN || k == Kind::SEP_NIL)
     151                 :            :   {
     152                 :            :     // - Extracting the sign of a floating-point number acts similar to a
     153                 :            :     // selector on a datatype, i.e. if `(sign x)` wasn't assigned a value, we
     154                 :            :     // can pick an arbitrary one. Note that the other components of a
     155                 :            :     // floating-point number should always be assigned a value.
     156                 :            :     // - sep.nil is a nullary constant that acts like a variable and thus is
     157                 :            :     // assignable.
     158                 :       3108 :     return true;
     159                 :            :   }
     160                 :            :   else
     161                 :            :   {
     162                 :            :     // non-function variables, and fully applied functions
     163         [ +  + ]:    5546517 :     if (!logicInfo().isHigherOrder())
     164                 :            :     {
     165                 :            :       // no functions exist, all functions are fully applied
     166 [ -  + ][ -  + ]:    4850324 :       Assert(k != Kind::HO_APPLY);
                 [ -  - ]
     167 [ -  + ][ -  + ]:    4850324 :       Assert(!n.getType().isFunction());
                 [ -  - ]
     168 [ +  + ][ +  + ]:    4850324 :       return n.isVar() || k == Kind::APPLY_UF;
     169                 :            :     }
     170                 :            :     else
     171                 :            :     {
     172 [ +  + ][ +  + ]:    1392386 :       return (n.isVar() && !n.getType().isFunction()) || k == Kind::APPLY_UF
                 [ -  - ]
     173                 :    1392386 :              || (k == Kind::HO_APPLY && n[0].getType().getNumChildren() == 2);
     174                 :            :     }
     175                 :            :   }
     176                 :            : }
     177                 :            : 
     178                 :    5751829 : void TheoryEngineModelBuilder::addAssignableSubterms(TNode n,
     179                 :            :                                                      TheoryModel* tm,
     180                 :            :                                                      NodeSet& cache)
     181                 :            : {
     182         [ +  + ]:    5751829 :   if (n.isClosure())
     183                 :            :   {
     184                 :      81847 :     return;
     185                 :            :   }
     186         [ +  + ]:    5669982 :   if (cache.find(n) != cache.end())
     187                 :            :   {
     188                 :    2664088 :     return;
     189                 :            :   }
     190         [ +  + ]:    3005894 :   if (isAssignable(n))
     191                 :            :   {
     192                 :    1274724 :     tm->d_equalityEngine->addTerm(n);
     193                 :            :   }
     194         [ +  + ]:    6153791 :   for (TNode::iterator child_it = n.begin(); child_it != n.end(); ++child_it)
     195                 :            :   {
     196                 :    3147897 :     addAssignableSubterms(*child_it, tm, cache);
     197                 :            :   }
     198                 :    3005894 :   cache.insert(n);
     199                 :            : }
     200                 :            : 
     201                 :    1237896 : void TheoryEngineModelBuilder::assignConstantRep(TheoryModel* tm,
     202                 :            :                                                  Node eqc,
     203                 :            :                                                  Node constRep)
     204                 :            : {
     205                 :    1237896 :   d_constantReps[eqc] = constRep;
     206         [ +  - ]:    2475792 :   Trace("model-builder") << "    Assign: Setting constant rep of " << eqc
     207                 :    1237896 :                          << " to " << constRep << endl;
     208                 :    1237896 :   tm->d_rep_set.setTermForRepresentative(constRep, eqc);
     209                 :    1237896 : }
     210                 :            : 
     211                 :         49 : bool TheoryEngineModelBuilder::isExcludedCdtValue(
     212                 :            :     Node val,
     213                 :            :     std::set<Node>* repSet,
     214                 :            :     std::map<Node, Node>& assertedReps,
     215                 :            :     Node eqc)
     216                 :            : {
     217         [ +  - ]:         98 :   Trace("model-builder-debug")
     218                 :          0 :       << "Is " << val << " and excluded codatatype value for " << eqc << "? "
     219                 :         49 :       << std::endl;
     220         [ +  + ]:        103 :   for (set<Node>::iterator i = repSet->begin(); i != repSet->end(); ++i)
     221                 :            :   {
     222 [ -  + ][ -  + ]:         72 :     Assert(assertedReps.find(*i) != assertedReps.end());
                 [ -  - ]
     223                 :         72 :     Node rep = assertedReps[*i];
     224         [ +  - ]:         72 :     Trace("model-builder-debug") << "  Rep : " << rep << std::endl;
     225                 :            :     // check whether it is possible that rep will be assigned the same value
     226                 :            :     // as val.
     227         [ +  + ]:         72 :     if (isCdtValueMatch(val, rep))
     228                 :            :     {
     229                 :         18 :       return true;
     230                 :            :     }
     231         [ +  + ]:         72 :   }
     232                 :         31 :   return false;
     233                 :            : }
     234                 :            : 
     235                 :        170 : bool TheoryEngineModelBuilder::isCdtValueMatch(Node v, Node r)
     236                 :            : {
     237         [ +  + ]:        170 :   if (r == v)
     238                 :            :   {
     239                 :            :     // values equal match trivially
     240                 :         40 :     return true;
     241                 :            :   }
     242 [ +  - ][ +  + ]:        130 :   else if (v.isConst() && r.isConst())
                 [ +  + ]
     243                 :            :   {
     244                 :            :     // distinct constant values do not match
     245                 :          8 :     return false;
     246                 :            :   }
     247         [ +  + ]:        122 :   else if (r.getKind() == Kind::APPLY_CONSTRUCTOR)
     248                 :            :   {
     249         [ -  + ]:         72 :     if (v.getKind() != Kind::APPLY_CONSTRUCTOR)
     250                 :            :     {
     251                 :          0 :       Assert(v.getKind() == Kind::CODATATYPE_BOUND_VARIABLE);
     252                 :            :       // v is the position of a loop. It may be possible to match, we return
     253                 :            :       // true, which is an over-approximation of when it is unsafe to use v.
     254                 :          0 :       return true;
     255                 :            :     }
     256         [ +  + ]:         72 :     if (v.getOperator() == r.getOperator())
     257                 :            :     {
     258         [ +  + ]:        116 :       for (size_t i = 0, nchild = v.getNumChildren(); i < nchild; i++)
     259                 :            :       {
     260         [ +  + ]:         98 :         if (!isCdtValueMatch(v[i], r[i]))
     261                 :            :         {
     262                 :            :           // if one child fails to match, we cannot match
     263                 :         40 :           return false;
     264                 :            :         }
     265                 :            :       }
     266                 :         18 :       return true;
     267                 :            :     }
     268                 :            :     // operators do not match
     269                 :         14 :     return false;
     270                 :            :   }
     271         [ +  + ]:         50 :   else if (v.getKind() == Kind::APPLY_CONSTRUCTOR)
     272                 :            :   {
     273                 :            :     // v has a constructor in a position that we have yet to fill in r.
     274                 :            :     // we are either a finite type in which case this subfield of r can be
     275                 :            :     // assigned a default value (or otherwise would have been split on).
     276                 :            :     // otherwise we are an infinite type and the subfield of r will be
     277                 :            :     // chosen not to clash with the subfield of v.
     278                 :         32 :     return false;
     279                 :            :   }
     280                 :         18 :   return true;
     281                 :            : }
     282                 :            : 
     283                 :       1203 : bool TheoryEngineModelBuilder::involvesUSort(TypeNode tn) const
     284                 :            : {
     285         [ +  + ]:       1203 :   if (tn.isUninterpretedSort())
     286                 :            :   {
     287                 :          4 :     return true;
     288                 :            :   }
     289         [ +  + ]:       1199 :   else if (tn.isArray())
     290                 :            :   {
     291         [ -  - ]:         20 :     return involvesUSort(tn.getArrayIndexType())
     292 [ +  - ][ -  + ]:         20 :            || involvesUSort(tn.getArrayConstituentType());
         [ +  - ][ +  - ]
                 [ -  - ]
     293                 :            :   }
     294         [ +  + ]:       1179 :   else if (tn.isSet())
     295                 :            :   {
     296                 :          4 :     return involvesUSort(tn.getSetElementType());
     297                 :            :   }
     298         [ +  + ]:       1175 :   else if (tn.isDatatype())
     299                 :            :   {
     300                 :       1071 :     const DType& dt = tn.getDType();
     301                 :       1071 :     return dt.involvesUninterpretedType();
     302                 :            :   }
     303                 :            :   else
     304                 :            :   {
     305                 :        104 :     return false;
     306                 :            :   }
     307                 :            : }
     308                 :            : 
     309                 :       3707 : bool TheoryEngineModelBuilder::isExcludedUSortValue(
     310                 :            :     std::map<TypeNode, unsigned>& eqc_usort_count,
     311                 :            :     Node v,
     312                 :            :     std::map<Node, bool>& visited)
     313                 :            : {
     314 [ -  + ][ -  + ]:       3707 :   Assert(v.isConst());
                 [ -  - ]
     315         [ +  + ]:       3707 :   if (visited.find(v) == visited.end())
     316                 :            :   {
     317                 :       3268 :     visited[v] = true;
     318                 :       3268 :     TypeNode tn = v.getType();
     319         [ +  + ]:       3268 :     if (tn.isUninterpretedSort())
     320                 :            :     {
     321         [ +  - ]:        266 :       Trace("model-builder-debug")
     322                 :        133 :           << "Is excluded usort value : " << v << " " << tn << std::endl;
     323                 :        133 :       unsigned card = eqc_usort_count[tn];
     324         [ +  - ]:        133 :       Trace("model-builder-debug") << "  Cardinality is " << card << std::endl;
     325                 :            :       unsigned index =
     326                 :        133 :           v.getConst<UninterpretedSortValue>().getIndex().toUnsignedInt();
     327         [ +  - ]:        133 :       Trace("model-builder-debug") << "  Index is " << index << std::endl;
     328 [ -  + ][ -  - ]:        133 :       return index > 0 && index >= card;
     329                 :            :     }
     330         [ +  + ]:       5929 :     for (unsigned i = 0; i < v.getNumChildren(); i++)
     331                 :            :     {
     332         [ -  + ]:       2794 :       if (isExcludedUSortValue(eqc_usort_count, v[i], visited))
     333                 :            :       {
     334                 :          0 :         return true;
     335                 :            :       }
     336                 :            :     }
     337         [ +  + ]:       3268 :   }
     338                 :       3574 :   return false;
     339                 :            : }
     340                 :            : 
     341                 :     923792 : void TheoryEngineModelBuilder::addToTypeList(
     342                 :            :     TypeNode tn,
     343                 :            :     std::vector<TypeNode>& type_list,
     344                 :            :     std::unordered_set<TypeNode>& visiting)
     345                 :            : {
     346         [ +  + ]:     923792 :   if (std::find(type_list.begin(), type_list.end(), tn) == type_list.end())
     347                 :            :   {
     348         [ +  + ]:     292742 :     if (visiting.find(tn) == visiting.end())
     349                 :            :     {
     350                 :      55771 :       visiting.insert(tn);
     351                 :            :       /* This must make a recursive call on all types that are subterms of
     352                 :            :        * values of the current type.
     353                 :            :        * Note that recursive traversal here is over enumerated expressions
     354                 :            :        * (very low expression depth). */
     355         [ +  + ]:      55771 :       if (tn.isArray())
     356                 :            :       {
     357                 :        570 :         addToTypeList(tn.getArrayIndexType(), type_list, visiting);
     358                 :        570 :         addToTypeList(tn.getArrayConstituentType(), type_list, visiting);
     359                 :            :       }
     360         [ +  + ]:      55201 :       else if (tn.isSet())
     361                 :            :       {
     362                 :       1422 :         addToTypeList(tn.getSetElementType(), type_list, visiting);
     363                 :            :       }
     364         [ +  + ]:      53779 :       else if (tn.isDatatype())
     365                 :            :       {
     366                 :      22694 :         const DType& dt = tn.getDType();
     367         [ +  + ]:     150668 :         for (unsigned i = 0; i < dt.getNumConstructors(); i++)
     368                 :            :         {
     369                 :            :           // Note that we may be a parameteric datatype, in which case the
     370                 :            :           // instantiated sorts need to be considered.
     371                 :     127974 :           TypeNode ctn = dt[i].getInstantiatedConstructorType(tn);
     372         [ +  + ]:     389728 :           for (const TypeNode& ctnc : ctn)
     373                 :            :           {
     374                 :     261754 :             addToTypeList(ctnc, type_list, visiting);
     375                 :     261754 :           }
     376                 :     127974 :         }
     377                 :            :       }
     378 [ -  + ][ -  + ]:      55771 :       Assert(std::find(type_list.begin(), type_list.end(), tn)
                 [ -  - ]
     379                 :            :              == type_list.end());
     380                 :      55771 :       type_list.push_back(tn);
     381                 :            :     }
     382                 :            :   }
     383                 :     923792 : }
     384                 :            : 
     385                 :      35585 : bool TheoryEngineModelBuilder::buildModel(TheoryModel* tm)
     386                 :            : {
     387         [ +  - ]:      35585 :   Trace("model-builder") << "TheoryEngineModelBuilder: buildModel" << std::endl;
     388                 :            : 
     389         [ +  - ]:      71170 :   Trace("model-builder")
     390                 :      35585 :       << "TheoryEngineModelBuilder: Preprocess build model..." << std::endl;
     391                 :            :   // model-builder specific initialization
     392         [ -  + ]:      35585 :   if (!preProcessBuildModel(tm))
     393                 :            :   {
     394         [ -  - ]:          0 :     Trace("model-builder")
     395                 :          0 :         << "TheoryEngineModelBuilder: fail preprocess build model."
     396                 :          0 :         << std::endl;
     397                 :          0 :     return false;
     398                 :            :   }
     399                 :            : 
     400         [ +  - ]:      71170 :   Trace("model-builder")
     401                 :            :       << "TheoryEngineModelBuilder: Add assignable subterms "
     402                 :          0 :          ", collect representatives and compute assignable information..."
     403                 :      35585 :       << std::endl;
     404                 :            : 
     405                 :            :   // type enumerator properties
     406                 :      35585 :   bool tepFixUSortCard = options().quantifiers.finiteModelFind;
     407                 :      35585 :   uint32_t tepStrAlphaCard = options().strings.stringsAlphaCard;
     408                 :      35585 :   TypeEnumeratorProperties tep(tepFixUSortCard, tepStrAlphaCard);
     409                 :            : 
     410                 :            :   // In the first step of model building, we do a traversal of the
     411                 :            :   // equality engine and record the information in the following:
     412                 :            : 
     413                 :            :   // The constant representatives, per equivalence class
     414                 :      35585 :   d_constantReps.clear();
     415                 :            :   // The representatives that have been asserted by theories. This includes
     416                 :            :   // non-constant "skeletons" that have been specified by parametric theories.
     417                 :      35585 :   std::map<Node, Node> assertedReps;
     418                 :            :   // A parition of the set of equivalence classes that have:
     419                 :            :   // (1) constant representatives,
     420                 :            :   // (2) an assigned representative specified by a theory in collectModelInfo,
     421                 :            :   // (3) no assigned representative.
     422                 :      35585 :   TypeSet typeConstSet, typeRepSet, typeNoRepSet;
     423                 :            :   // An ordered list of types, such that T1 comes before T2 if T1 is a
     424                 :            :   // "component type" of T2, e.g. U comes before (Set U). This is only strictly
     425                 :            :   // necessary for finite model finding + parametric types instantiated with
     426                 :            :   // uninterpreted sorts, but is probably a good idea to do in general since it
     427                 :            :   // leads to models with smaller term sizes. -AJR
     428                 :      35585 :   std::vector<TypeNode> type_list;
     429                 :            :   // The count of equivalence classes per sort (for finite model finding).
     430                 :      35585 :   std::map<TypeNode, unsigned> eqc_usort_count;
     431                 :            : 
     432                 :            :   // the set of equivalence classes that are "assignable", i.e. those that have
     433                 :            :   // an assignable expression in them (see isAssignable), and have not already
     434                 :            :   // been assigned a constant.
     435                 :      35585 :   std::unordered_set<Node> assignableEqc;
     436                 :            :   // The set of equivalence classes that are "evaluable", i.e. those that have
     437                 :            :   // an expression in them that is not assignable, and have not already been
     438                 :            :   // assigned a constant.
     439                 :      35585 :   std::unordered_set<Node> evaluableEqc;
     440                 :            :   // Assigner objects for relevant equivalence classes that require special
     441                 :            :   // ways of assigning values, e.g. those that take into account assignment
     442                 :            :   // exclusion sets.
     443                 :      35585 :   std::map<Node, Assigner> eqcToAssigner;
     444                 :            :   // A map from equivalence classes to the equivalence class that it shares an
     445                 :            :   // assigner object with (all elements in the range of this map are in the
     446                 :            :   // domain of eqcToAssigner).
     447                 :      35585 :   std::map<Node, Node> eqcToAssignerMaster;
     448                 :            : 
     449                 :            :   // Loop through equivalence classes of the equality engine of the model.
     450                 :      35585 :   eq::EqualityEngine* ee = tm->d_equalityEngine;
     451                 :      35585 :   NodeSet assignableCache;
     452                 :      35585 :   std::map<Node, Node>::iterator itm;
     453                 :      35585 :   eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(ee);
     454                 :            :   // should we compute assigner objects?
     455                 :      35585 :   bool computeAssigners = tm->hasAssignmentExclusionSets();
     456                 :            :   // the set of exclusion sets we have processed
     457                 :      35585 :   std::unordered_set<Node> processedExcSet;
     458         [ +  + ]:    1279228 :   for (; !eqcs_i.isFinished(); ++eqcs_i)
     459                 :            :   {
     460                 :    1243643 :     Node eqc = *eqcs_i;
     461         [ +  - ]:    1243643 :     Trace("model-builder") << "  Processing EQC " << eqc << std::endl;
     462                 :            :     // Information computed for each equivalence class
     463                 :            : 
     464                 :            :     // The assigned represenative and constant representative
     465                 :    1243643 :     Node rep, constRep;
     466                 :            :     // is constant rep a "base model value" (see TheoryModel::isBaseModelValue)
     467                 :    1243643 :     bool constRepBaseModelValue = false;
     468                 :            :     // A flag set to true if the current equivalence class is assignable (see
     469                 :            :     // assignableEqc).
     470                 :    1243643 :     bool assignable = false;
     471                 :            :     // Set to true if the current equivalence class is evaluatable (see
     472                 :            :     // evaluableEqc).
     473                 :    1243643 :     bool evaluable = false;
     474                 :            :     // Set to true if a term in the current equivalence class has been given an
     475                 :            :     // assignment exclusion set.
     476                 :    1243643 :     bool hasESet CVC5_UNUSED = false;
     477                 :            :     // Set to true if we found that a term in the current equivalence class has
     478                 :            :     // been given an assignment exclusion set, and we have not seen this term
     479                 :            :     // as part of a previous assignment exclusion group. In other words, when
     480                 :            :     // this flag is true we construct a new assigner object with the current
     481                 :            :     // equivalence class as its master.
     482                 :    1243643 :     bool foundESet = false;
     483                 :            :     // The assignment exclusion set for the current equivalence class.
     484                 :    1243643 :     std::vector<Node> eset;
     485                 :            :     // The group to which this equivalence class belongs when exclusion sets
     486                 :            :     // were assigned (see the argument group of
     487                 :            :     // TheoryModel::getAssignmentExclusionSet).
     488                 :    1243643 :     std::vector<Node> esetGroup;
     489                 :            : 
     490                 :            :     // Loop through terms in this EC
     491                 :    1243643 :     eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, ee);
     492         [ +  + ]:    3847575 :     for (; !eqc_i.isFinished(); ++eqc_i)
     493                 :            :     {
     494                 :    2603932 :       Node n = *eqc_i;
     495         [ +  - ]:    2603932 :       Trace("model-builder") << "    Processing Term: " << n << endl;
     496                 :            : 
     497                 :            :       // For each term n in this equivalence class, below we register its
     498                 :            :       // assignable subterms, compute whether it is a constant or assigned
     499                 :            :       // representative, then if we don't have a constant representative,
     500                 :            :       // compute information regarding how we will assign values.
     501                 :            : 
     502                 :            :       // (1) Add assignable subterms, which ensures that e.g. models for
     503                 :            :       // uninterpreted functions take into account all subterms in the
     504                 :            :       // equality engine of the model
     505                 :    2603932 :       addAssignableSubterms(n, tm, assignableCache);
     506                 :            :       // model-specific processing of the term
     507                 :    2603932 :       tm->addTermInternal(n);
     508                 :            : 
     509                 :            :       // compute whether n is assignable
     510         [ +  + ]:    2603932 :       if (!isAssignable(n))
     511                 :            :       {
     512                 :            :         // (2) Record constant representative or assign representative, if
     513                 :            :         // applicable. We check if n is a value here, e.g. a term for which
     514                 :            :         // isConst returns true, or a lambda. The latter is required only for
     515                 :            :         // higher-order.
     516         [ +  + ]:    1329208 :         if (tm->isValue(n))
     517                 :            :         {
     518                 :            :           // In some cases, there can be multiple terms in the same equivalence
     519                 :            :           // class are considered values, e.g., when real algebraic numbers did
     520                 :            :           // not simplify to rational values or real.pi was used as a model
     521                 :            :           // value. We distinguish three kinds of model values: constants,
     522                 :            :           // non-constant base values and non-base values, and we use them in
     523                 :            :           // this order of preference.
     524                 :            :           // We print a trace message if there is more than one model value in
     525                 :            :           // the same equivalence class. We throw a debug failure if there are
     526                 :            :           // at least two base model values in the same equivalence class that
     527                 :            :           // do not compare equal.
     528                 :     578874 :           bool assignConstRep = false;
     529                 :     578874 :           bool isBaseValue = tm->isBaseModelValue(n);
     530         [ +  + ]:     578874 :           if (constRep.isNull())
     531                 :            :           {
     532                 :     578866 :             assignConstRep = true;
     533                 :            :           }
     534                 :            :           else
     535                 :            :           {
     536                 :            :             // This is currently a trace message, as it often triggers for
     537                 :            :             // non-linear arithmetic before the model is refined enough to
     538                 :            :             // e.g. show transcendental function apps are not equal to rationals
     539         [ +  - ]:         16 :             Trace("model-warn") << "Model values in the same equivalence class "
     540                 :          8 :                                 << constRep << " " << n << std::endl;
     541         [ -  + ]:          8 :             if (!constRepBaseModelValue)
     542                 :            :             {
     543                 :          0 :               assignConstRep = isBaseValue;
     544                 :            :             }
     545         [ +  + ]:          8 :             else if (isBaseValue)
     546                 :            :             {
     547                 :          2 :               Node isEqual = rewrite(constRep.eqNode(n));
     548 [ +  - ][ +  - ]:          1 :               if (isEqual.isConst() && isEqual.getConst<bool>())
                 [ +  - ]
     549                 :            :               {
     550                 :          1 :                 assignConstRep = n.isConst();
     551                 :            :               }
     552                 :            :               else
     553                 :            :               {
     554                 :          0 :                 DebugUnhandled() << "Distinct base model values in the same "
     555                 :          0 :                                     "equivalence class "
     556                 :          0 :                                  << constRep << " " << n << std::endl;
     557                 :            :               }
     558                 :          1 :             }
     559                 :            :           }
     560         [ +  + ]:     578874 :           if (assignConstRep)
     561                 :            :           {
     562                 :     578866 :             constRep = n;
     563         [ +  - ]:    1157732 :             Trace("model-builder") << "    ..ConstRep( " << eqc
     564                 :     578866 :                                    << " ) = " << constRep << std::endl;
     565                 :     578866 :             constRepBaseModelValue = isBaseValue;
     566                 :            :           }
     567                 :            :           // if we have a constant representative, nothing else matters
     568                 :     578874 :           continue;
     569                 :     578874 :         }
     570                 :            : 
     571                 :            :         // If we don't have a constant rep, check if this is an assigned rep.
     572                 :     750334 :         itm = tm->d_reps.find(n);
     573         [ +  + ]:     750334 :         if (itm != tm->d_reps.end())
     574                 :            :         {
     575                 :            :           // Notice that this equivalence class may contain multiple terms that
     576                 :            :           // were specified as being a representative, since e.g. datatypes may
     577                 :            :           // assert representative for two constructor terms that are not in the
     578                 :            :           // care graph and are merged during collectModeInfo due to equality
     579                 :            :           // information from another theory. We overwrite the value of rep in
     580                 :            :           // these cases here.
     581                 :      72506 :           rep = itm->second;
     582         [ +  - ]:     145012 :           Trace("model-builder")
     583                 :      72506 :               << "    ..Rep( " << eqc << " ) = " << rep << std::endl;
     584                 :            :         }
     585                 :            : 
     586                 :            :         // (3) Finally, process assignable information
     587                 :            :         // We are evaluable typically if we are not assignable. However the
     588                 :            :         // one exception is that higher-order variables when in HOL should be
     589                 :            :         // considered neither assignable nor evaluable, which we check for here.
     590                 :     750334 :         evaluable = !n.isVar();
     591                 :            :         // expressions that are not assignable should not be given assignment
     592                 :            :         // exclusion sets
     593 [ -  + ][ -  + ]:     750334 :         Assert(!tm->getAssignmentExclusionSet(n, esetGroup, eset));
                 [ -  - ]
     594                 :     750334 :         continue;
     595                 :     750334 :       }
     596                 :    1274724 :       assignable = true;
     597         [ +  + ]:    1274724 :       if (!computeAssigners)
     598                 :            :       {
     599                 :            :         // we don't compute assigners, skip
     600                 :    1274477 :         continue;
     601                 :            :       }
     602                 :            :       // process the assignment exclusion set for term n
     603                 :            :       // was it processed based on a master exclusion group (see
     604                 :            :       // eqcToAssignerMaster)?
     605         [ +  + ]:        247 :       if (processedExcSet.find(n) != processedExcSet.end())
     606                 :            :       {
     607                 :            :         // Should not have two assignment exclusion sets for the same
     608                 :            :         // equivalence class
     609 [ -  + ][ -  + ]:         35 :         Assert(!hasESet);
                 [ -  - ]
     610 [ -  + ][ -  + ]:         35 :         Assert(eqcToAssignerMaster.find(eqc) != eqcToAssignerMaster.end());
                 [ -  - ]
     611                 :            :         // already processed as a slave term
     612                 :         35 :         hasESet = true;
     613                 :         35 :         continue;
     614                 :            :       }
     615                 :            :       // was it assigned one?
     616         [ +  + ]:        212 :       if (tm->getAssignmentExclusionSet(n, esetGroup, eset))
     617                 :            :       {
     618                 :            :         // Should not have two assignment exclusion sets for the same
     619                 :            :         // equivalence class
     620 [ -  + ][ -  + ]:         12 :         Assert(!hasESet);
                 [ -  - ]
     621                 :         12 :         foundESet = true;
     622                 :         12 :         hasESet = true;
     623                 :            :       }
     624         [ +  + ]:    2603932 :     }
     625                 :            : 
     626                 :            :     // finished traversing the equality engine
     627                 :    1243643 :     TypeNode eqct = eqc.getType();
     628                 :            :     // count the number of equivalence classes of sorts in finite model finding
     629         [ +  + ]:    1243643 :     if (options().quantifiers.finiteModelFind)
     630                 :            :     {
     631         [ +  + ]:      19551 :       if (eqct.isUninterpretedSort())
     632                 :            :       {
     633                 :            :         // we never assign uninterpreted sorts a priori.
     634 [ -  + ][ -  + ]:       5301 :         Assert(constRep.isNull());
                 [ -  - ]
     635                 :       5301 :         eqc_usort_count[eqct]++;
     636                 :            :         // For uninterpreted sorts when finite model finding is enabled,
     637                 :            :         // we preemptively assign the next value in the enumeration here.
     638                 :            :         // This is important because uninterpreted sorts are considered
     639                 :            :         // "INTERPRETED_FINITE" cardinality when finite model finding is
     640                 :            :         // enabled, and hence would otherwise be assigned using the finite
     641                 :            :         // case below (assigning them to the first value), which we do not
     642                 :            :         // want. Instead, all initial equivalence classes of uninterpreted
     643                 :            :         // sorts are assigned distinct values, and all further values
     644                 :            :         // (e.g. terms introduced as subfields of datatypes) are assign
     645                 :            :         // arbitrary values.
     646                 :       5301 :         constRep = typeConstSet.nextTypeEnum(eqct);
     647         [ +  - ]:      10602 :         Trace("model-value-enum") << "Enum fmf usort " << eqct << " "
     648                 :       5301 :                                   << constRep << " for " << eqc << std::endl;
     649                 :            :       }
     650                 :            :     }
     651                 :            :     // Assign representative for this equivalence class
     652         [ +  + ]:    1243643 :     if (!constRep.isNull())
     653                 :            :     {
     654                 :            :       // Theories should not specify a rep if there is already a constant in the
     655                 :            :       // equivalence class. However, it may be the case that the representative
     656                 :            :       // specified by a theory may be merged with a constant based on equality
     657                 :            :       // information from another class. Thus, rep may be non-null here.
     658                 :            :       // Regardless, we assign constRep as the representative here.
     659                 :     584167 :       assignConstantRep(tm, eqc, constRep);
     660                 :     584167 :       typeConstSet.add(eqct, constRep);
     661                 :     584167 :       continue;
     662                 :            :     }
     663         [ +  + ]:     659476 :     else if (!rep.isNull())
     664                 :            :     {
     665                 :      72325 :       assertedReps[eqc] = rep;
     666                 :      72325 :       typeRepSet.add(eqct, eqc);
     667                 :      72325 :       std::unordered_set<TypeNode> visiting;
     668                 :      72325 :       addToTypeList(eqct, type_list, visiting);
     669                 :      72325 :     }
     670                 :            :     else
     671                 :            :     {
     672                 :     587151 :       typeNoRepSet.add(eqct, eqc);
     673                 :     587151 :       std::unordered_set<TypeNode> visiting;
     674                 :     587151 :       addToTypeList(eqct, type_list, visiting);
     675                 :     587151 :     }
     676                 :            : 
     677         [ +  + ]:     659476 :     if (assignable)
     678                 :            :     {
     679                 :     238346 :       assignableEqc.insert(eqc);
     680                 :            :     }
     681         [ +  + ]:     659476 :     if (evaluable)
     682                 :            :     {
     683                 :     490722 :       evaluableEqc.insert(eqc);
     684                 :            :     }
     685                 :            :     // If we found an assignment exclusion set, we construct a new assigner
     686                 :            :     // object.
     687         [ +  + ]:     659476 :     if (foundESet)
     688                 :            :     {
     689                 :            :       // we don't accept assignment exclusion sets for evaluable eqc
     690 [ -  + ][ -  + ]:         12 :       Assert(!evaluable);
                 [ -  - ]
     691                 :            :       // construct the assigner
     692                 :         12 :       Assigner& a = eqcToAssigner[eqc];
     693                 :            :       // Take the representatives of each term in the assignment exclusion
     694                 :            :       // set, which ensures we can look up their value in d_constReps later.
     695                 :         12 :       std::vector<Node> aes;
     696         [ +  + ]:         34 :       for (const Node& e : eset)
     697                 :            :       {
     698                 :            :         // Should only supply terms that occur in the model or constants
     699                 :            :         // in assignment exclusion sets.
     700                 :         22 :         Assert(tm->hasTerm(e) || e.isConst());
     701 [ +  - ][ +  - ]:         44 :         Node er = tm->hasTerm(e) ? tm->getRepresentative(e) : e;
                 [ -  - ]
     702                 :         22 :         aes.push_back(er);
     703                 :         22 :       }
     704                 :            :       // initialize
     705                 :         12 :       a.initialize(eqc.getType(), &tep, aes);
     706                 :            :       // all others in the group are slaves of this
     707         [ +  + ]:         59 :       for (const Node& g : esetGroup)
     708                 :            :       {
     709 [ -  + ][ -  + ]:         47 :         Assert(isAssignable(g));
                 [ -  - ]
     710         [ -  + ]:         47 :         if (!tm->hasTerm(g))
     711                 :            :         {
     712                 :            :           // Ignore those that aren't in the model, in the case the user
     713                 :            :           // has supplied an assignment exclusion set to a variable not in
     714                 :            :           // the model.
     715                 :          0 :           continue;
     716                 :            :         }
     717                 :         47 :         Node gr = tm->getRepresentative(g);
     718         [ +  + ]:         47 :         if (gr != eqc)
     719                 :            :         {
     720                 :         35 :           eqcToAssignerMaster[gr] = eqc;
     721                 :            :           // remember that this term has been processed
     722                 :         35 :           processedExcSet.insert(g);
     723                 :            :         }
     724                 :         47 :       }
     725                 :         12 :     }
     726 [ +  + ][ +  + ]:    4164478 :   }
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
     727                 :            : 
     728                 :            :   // Now finished initialization
     729                 :            : 
     730                 :            :   // Compute type enumerator properties. This code ensures we do not
     731                 :            :   // enumerate terms that have uninterpreted constants that violate the
     732                 :            :   // bounds imposed by finite model finding. For example, if finite
     733                 :            :   // model finding insists that there are only 2 values { U1, U2 } of type U,
     734                 :            :   // then the type enumerator for list of U should enumerate:
     735                 :            :   //   nil, (cons U1 nil), (cons U2 nil), (cons U1 (cons U1 nil)), ...
     736                 :            :   // instead of enumerating (cons U3 nil).
     737         [ +  + ]:      35585 :   if (options().quantifiers.finiteModelFind)
     738                 :            :   {
     739                 :       1557 :     tep.d_fixed_usort_card = true;
     740                 :       1557 :     for (std::map<TypeNode, unsigned>::iterator it = eqc_usort_count.begin();
     741         [ +  + ]:       4465 :          it != eqc_usort_count.end();
     742                 :       2908 :          ++it)
     743                 :            :     {
     744         [ +  - ]:       5816 :       Trace("model-builder") << "Fixed bound (#eqc) for " << it->first << " : "
     745                 :       2908 :                              << it->second << std::endl;
     746                 :       2908 :       tep.d_fixed_card[it->first] = Integer(it->second);
     747                 :            :     }
     748                 :       1557 :     typeConstSet.setTypeEnumeratorProperties(&tep);
     749                 :            :   }
     750                 :            : 
     751                 :            :   // Need to ensure that each EC has a constant representative.
     752                 :            : 
     753         [ +  - ]:      35585 :   Trace("model-builder") << "Processing EC's..." << std::endl;
     754                 :            : 
     755                 :      35585 :   TypeSet::iterator it;
     756                 :      35585 :   vector<TypeNode>::iterator type_it;
     757                 :      35585 :   set<Node>::iterator i, i2;
     758                 :      35585 :   bool changed, unassignedAssignable, assignOne = false;
     759                 :      35585 :   set<TypeNode> evaluableSet;
     760                 :            : 
     761                 :            :   // Double-fixed-point loop
     762                 :            :   // Outer loop handles a special corner case (see code at end of loop for
     763                 :            :   // details)
     764                 :            :   for (;;)
     765                 :            :   {
     766                 :            :     // Inner fixed-point loop: we are trying to learn constant values for every
     767                 :            :     // EC.  Each time through this loop, we process all of the
     768                 :            :     // types by type and may learn some new EC values.  EC's in one type may
     769                 :            :     // depend on EC's in another type, so we need a fixed-point loop
     770                 :            :     // to ensure that we learn as many EC values as possible
     771         [ +  + ]:     217444 :     do
     772                 :            :     {
     773                 :     217444 :       changed = false;
     774                 :     217444 :       unassignedAssignable = false;
     775                 :     217444 :       evaluableSet.clear();
     776                 :            : 
     777                 :            :       // Iterate over all types we've seen
     778         [ +  + ]:     974748 :       for (type_it = type_list.begin(); type_it != type_list.end(); ++type_it)
     779                 :            :       {
     780                 :     757304 :         TypeNode t = *type_it;
     781                 :     757304 :         TypeNode tb = t;
     782                 :     757304 :         set<Node>* noRepSet = typeNoRepSet.getSet(t);
     783                 :            : 
     784                 :            :         // 1. Try to evaluate the EC's in this type
     785 [ +  + ][ +  + ]:     757304 :         if (noRepSet != nullptr && !noRepSet->empty())
                 [ +  + ]
     786                 :            :         {
     787         [ +  - ]:     567344 :           Trace("model-builder")
     788                 :     283672 :               << "  Eval phase, working on type: " << t << endl;
     789                 :            :           bool evaluable;
     790                 :     283672 :           d_normalizedCache.clear();
     791         [ +  + ]:    3056453 :           for (i = noRepSet->begin(); i != noRepSet->end();)
     792                 :            :           {
     793                 :    2772781 :             i2 = i;
     794                 :    2772781 :             ++i;
     795         [ +  - ]:    5545562 :             Trace("model-builder-debug")
     796                 :    2772781 :                 << "Look at eqc : " << (*i2) << std::endl;
     797                 :    2772781 :             Node normalized;
     798                 :            :             // only possible to normalize if we are evaluable
     799                 :    2772781 :             evaluable = evaluableEqc.find(*i2) != evaluableEqc.end();
     800         [ +  + ]:    2772781 :             if (evaluable)
     801                 :            :             {
     802                 :     424922 :               normalized = evaluateEqc(tm, *i2);
     803                 :            :             }
     804         [ +  + ]:    2772781 :             if (!normalized.isNull())
     805                 :            :             {
     806 [ -  + ][ -  + ]:     415537 :               Assert(tm->isValue(normalized));
                 [ -  - ]
     807                 :     415537 :               typeConstSet.add(tb, normalized);
     808                 :     415537 :               assignConstantRep(tm, *i2, normalized);
     809         [ +  - ]:     831074 :               Trace("model-builder") << "    Eval: Setting constant rep of "
     810                 :     415537 :                                      << (*i2) << " to " << normalized << endl;
     811                 :     415537 :               changed = true;
     812                 :     415537 :               noRepSet->erase(i2);
     813                 :            :             }
     814                 :            :             else
     815                 :            :             {
     816         [ +  + ]:    2357244 :               if (evaluable)
     817                 :            :               {
     818                 :       9385 :                 evaluableSet.insert(tb);
     819                 :            :               }
     820                 :            :               // If assignable, remember there is an equivalence class that is
     821                 :            :               // not assigned and assignable.
     822         [ +  + ]:    2357244 :               if (assignableEqc.find(*i2) != assignableEqc.end())
     823                 :            :               {
     824                 :    2342554 :                 unassignedAssignable = true;
     825                 :            :               }
     826                 :            :             }
     827                 :    2772781 :           }
     828                 :            :         }
     829                 :            : 
     830                 :            :         // 2. Normalize any non-const representative terms for this type
     831                 :     757304 :         set<Node>* repSet = typeRepSet.getSet(t);
     832 [ +  + ][ +  + ]:     757304 :         if (repSet != nullptr && !repSet->empty())
                 [ +  + ]
     833                 :            :         {
     834         [ +  - ]:     667190 :           Trace("model-builder")
     835                 :     333595 :               << "  Normalization phase, working on type: " << t << endl;
     836                 :     333595 :           d_normalizedCache.clear();
     837         [ +  + ]:    2291821 :           for (i = repSet->begin(); i != repSet->end();)
     838                 :            :           {
     839 [ -  + ][ -  + ]:    1958226 :             Assert(assertedReps.find(*i) != assertedReps.end());
                 [ -  - ]
     840                 :    1958226 :             Node rep = assertedReps[*i];
     841                 :    1958226 :             Node normalized = normalize(tm, rep, false);
     842         [ +  - ]:    3916452 :             Trace("model-builder")
     843                 :          0 :                 << "    Normalizing rep (" << rep << "), normalized to ("
     844                 :          0 :                 << normalized << ")"
     845 [ -  + ][ -  - ]:    1958226 :                 << ", isValue=" << tm->isValue(normalized) << std::endl;
     846         [ +  + ]:    1958226 :             if (tm->isValue(normalized))
     847                 :            :             {
     848                 :      72325 :               changed = true;
     849                 :      72325 :               typeConstSet.add(tb, normalized);
     850                 :      72325 :               assignConstantRep(tm, *i, normalized);
     851                 :      72325 :               assertedReps.erase(*i);
     852                 :      72325 :               i2 = i;
     853                 :      72325 :               ++i;
     854                 :      72325 :               repSet->erase(i2);
     855                 :            :             }
     856                 :            :             else
     857                 :            :             {
     858         [ +  + ]:    1885901 :               if (normalized != rep)
     859                 :            :               {
     860                 :      41638 :                 assertedReps[*i] = normalized;
     861                 :      41638 :                 changed = true;
     862                 :            :               }
     863                 :    1885901 :               ++i;
     864                 :            :             }
     865                 :    1958226 :           }
     866                 :            :         }
     867                 :     757304 :       }
     868                 :            :     } while (changed);
     869                 :            : 
     870         [ +  + ]:     138637 :     if (!unassignedAssignable)
     871                 :            :     {
     872                 :      35585 :       break;
     873                 :            :     }
     874                 :            : 
     875                 :            :     // 3. Assign unassigned assignable EC's using type enumeration - assign a
     876                 :            :     // value *different* from all other EC's if the type is infinite
     877                 :            :     // Assign first value from type enumerator otherwise - for finite types, we
     878                 :            :     // rely on polite framework to ensure that EC's that have to be
     879                 :            :     // different are different.
     880                 :            : 
     881                 :            :     // Only make assignments on a type if:
     882                 :            :     // 1. there are no terms that share the same base type with un-normalized
     883                 :            :     // representatives
     884                 :            :     // 2. there are no terms that share teh same base type that are unevaluated
     885                 :            :     // evaluable terms
     886                 :            :     // Alternatively, if 2 or 3 don't hold but we are in a special
     887                 :            :     // deadlock-breaking mode where assignOne is true, go ahead and make one
     888                 :            :     // assignment
     889                 :     103052 :     changed = false;
     890                 :            :     // must iterate over the ordered type list to ensure that we do not
     891                 :            :     // enumerate values with subterms
     892                 :            :     //  having types that we are currently enumerating (when possible)
     893                 :            :     //  for example, this ensures we enumerate uninterpreted sort U before (List
     894                 :            :     //  of U) and (Array U U)
     895                 :            :     //  however, it does not break cyclic type dependencies for mutually
     896                 :            :     //  recursive datatypes, but this is handled
     897                 :            :     //  by recording all subterms of enumerated values in TypeSet::addSubTerms.
     898         [ +  + ]:     509844 :     for (type_it = type_list.begin(); type_it != type_list.end(); ++type_it)
     899                 :            :     {
     900                 :     406792 :       TypeNode t = *type_it;
     901                 :            :       // continue if there are no more equivalence classes of this type to
     902                 :            :       // assign
     903                 :     406792 :       std::set<Node>* noRepSetPtr = typeNoRepSet.getSet(t);
     904         [ +  + ]:     406792 :       if (noRepSetPtr == nullptr)
     905                 :            :       {
     906                 :      38149 :         continue;
     907                 :            :       }
     908                 :     368643 :       set<Node>& noRepSet = *noRepSetPtr;
     909         [ +  + ]:     368643 :       if (noRepSet.empty())
     910                 :            :       {
     911                 :     205030 :         continue;
     912                 :            :       }
     913                 :            : 
     914                 :            :       // get properties of this type
     915                 :     163613 :       bool isCorecursive = false;
     916         [ +  + ]:     163613 :       if (t.isDatatype())
     917                 :            :       {
     918                 :     154323 :         const DType& dt = t.getDType();
     919                 :     154323 :         isCorecursive =
     920                 :     308646 :             dt.isCodatatype()
     921                 :     154323 :             && (!d_env.isFiniteType(t) || dt.isRecursiveSingleton(t));
     922                 :            :       }
     923                 :            : #ifdef CVC5_ASSERTIONS
     924                 :     163613 :       bool isUSortFiniteRestricted = false;
     925         [ +  + ]:     163613 :       if (options().quantifiers.finiteModelFind)
     926                 :            :       {
     927 [ +  - ][ +  + ]:       1159 :         isUSortFiniteRestricted = !t.isUninterpretedSort() && involvesUSort(t);
         [ +  - ][ -  - ]
     928                 :            :       }
     929                 :            : #endif
     930                 :            : 
     931                 :     163613 :       TypeNode tb = t;
     932         [ +  + ]:     163613 :       if (!assignOne)
     933                 :            :       {
     934                 :     115729 :         set<Node>* repSet = typeRepSet.getSet(tb);
     935 [ +  + ][ +  + ]:     115729 :         if (repSet != nullptr && !repSet->empty())
                 [ +  + ]
     936                 :            :         {
     937                 :     103844 :           continue;
     938                 :            :         }
     939         [ +  + ]:      11885 :         if (evaluableSet.find(tb) != evaluableSet.end())
     940                 :            :         {
     941                 :        945 :           continue;
     942                 :            :         }
     943                 :            :       }
     944         [ +  - ]:     117648 :       Trace("model-builder")
     945                 :      58824 :           << "  Assign phase, working on type: " << t << endl;
     946                 :            :       bool assignable, evaluable CVC5_UNUSED;
     947                 :      58824 :       std::map<Node, Assigner>::iterator itAssigner;
     948                 :      58824 :       std::map<Node, Node>::iterator itAssignerM;
     949                 :      58824 :       set<Node>* repSet = typeRepSet.getSet(t);
     950         [ +  + ]:     179098 :       for (i = noRepSet.begin(); i != noRepSet.end();)
     951                 :            :       {
     952                 :     168084 :         i2 = i;
     953                 :     168084 :         ++i;
     954         [ +  + ]:     168084 :         if (evaluableEqc.find(*i2) != evaluableEqc.end())
     955                 :            :         {
     956         [ +  - ]:        478 :           Trace("model-builder")
     957                 :        239 :               << "  ...do not assign to evaluatable eqc " << *i2 << std::endl;
     958                 :            :           // we never assign to evaluable equivalence classes
     959                 :        239 :           continue;
     960                 :            :         }
     961                 :            :         // check whether it has an assigner object
     962                 :     167845 :         itAssignerM = eqcToAssignerMaster.find(*i2);
     963         [ +  + ]:     167845 :         if (itAssignerM != eqcToAssignerMaster.end())
     964                 :            :         {
     965                 :            :           // Take the master's assigner. Notice we don't care which order
     966                 :            :           // equivalence classes are assigned. For instance, the master can
     967                 :            :           // be assigned after one of its slaves.
     968                 :         35 :           itAssigner = eqcToAssigner.find(itAssignerM->second);
     969                 :            :         }
     970                 :            :         else
     971                 :            :         {
     972                 :     167810 :           itAssigner = eqcToAssigner.find(*i2);
     973                 :            :         }
     974         [ +  + ]:     167845 :         if (itAssigner != eqcToAssigner.end())
     975                 :            :         {
     976                 :         47 :           assignable = isAssignerActive(tm, itAssigner->second);
     977                 :            :         }
     978                 :            :         else
     979                 :            :         {
     980                 :     167798 :           assignable = assignableEqc.find(*i2) != assignableEqc.end();
     981                 :            :         }
     982         [ +  - ]:     335690 :         Trace("model-builder-debug")
     983                 :          0 :             << "    eqc " << *i2 << " is assignable=" << assignable
     984                 :     167845 :             << std::endl;
     985         [ +  + ]:     167845 :         if (assignable)
     986                 :            :         {
     987                 :            :           // this assertion ensures that if we are assigning to a term of
     988                 :            :           // Boolean type, then the term must be assignable.
     989                 :            :           // Note we only assign to terms of Boolean type if the term occurs in
     990                 :            :           // a singleton equivalence class; otherwise the term would have been
     991                 :            :           // in the equivalence class of true or false and would not need
     992                 :            :           // assigning.
     993                 :     165867 :           Assert(!t.isBoolean() || isAssignable(*i2));
     994                 :     165867 :           Node n;
     995         [ +  + ]:     165867 :           if (itAssigner != eqcToAssigner.end())
     996                 :            :           {
     997         [ +  - ]:         94 :             Trace("model-builder-debug")
     998                 :         47 :                 << "Get value from assigner for finite type..." << std::endl;
     999                 :            :             // if it has an assigner, get the value from the assigner.
    1000                 :         47 :             n = itAssigner->second.getNextAssignment();
    1001 [ -  + ][ -  + ]:         47 :             Assert(!n.isNull());
                 [ -  - ]
    1002                 :            :           }
    1003         [ +  + ]:     165820 :           else if (!d_env.isFiniteType(t))
    1004                 :            :           {
    1005                 :            :             // If its infinite, we get a fresh value that does not occur in the
    1006                 :            :             // model. Note that uninterpreted sorts are handled in the finite
    1007                 :            :             // case below in the case that finite model finding is enabled.
    1008                 :            :             bool success;
    1009                 :            :             do
    1010                 :            :             {
    1011         [ +  - ]:     331306 :               Trace("model-builder-debug")
    1012                 :     165653 :                   << "Enumerate term of type " << t << std::endl;
    1013                 :     165653 :               n = typeConstSet.nextTypeEnum(t);
    1014                 :            :               //--- AJR: this code checks whether n is a legal value
    1015 [ -  + ][ -  + ]:     165653 :               Assert(!n.isNull());
                 [ -  - ]
    1016                 :     165653 :               success = true;
    1017         [ +  - ]:     331306 :               Trace("model-builder-debug")
    1018                 :     165653 :                   << "Check if excluded : " << n << std::endl;
    1019                 :            : #ifdef CVC5_ASSERTIONS
    1020         [ +  + ]:     165653 :               if (isUSortFiniteRestricted)
    1021                 :            :               {
    1022                 :            :                 // must not involve uninterpreted constants beyond cardinality
    1023                 :            :                 // bound (which assumed to coincide with #eqc)
    1024                 :            :                 // this is just an assertion now, since TypeEnumeratorProperties
    1025                 :            :                 // should ensure that only legal values are enumerated wrt this
    1026                 :            :                 // constraint.
    1027                 :        913 :                 std::map<Node, bool> visited;
    1028                 :        913 :                 success = !isExcludedUSortValue(eqc_usort_count, n, visited);
    1029         [ -  + ]:        913 :                 if (!success)
    1030                 :            :                 {
    1031         [ -  - ]:          0 :                   Trace("model-builder")
    1032                 :          0 :                       << "Excluded value for " << t << " : " << n
    1033                 :          0 :                       << " due to out of range uninterpreted constant."
    1034                 :          0 :                       << std::endl;
    1035                 :            :                 }
    1036 [ -  + ][ -  + ]:        913 :                 Assert(success);
                 [ -  - ]
    1037                 :        913 :               }
    1038                 :            : #endif
    1039 [ +  - ][ +  + ]:     165653 :               if (success && isCorecursive)
    1040                 :            :               {
    1041 [ +  - ][ +  + ]:         57 :                 if (repSet != nullptr && !repSet->empty())
                 [ +  + ]
    1042                 :            :                 {
    1043                 :            :                   // in the case of codatatypes, check if it is in the set of
    1044                 :            :                   // values that we cannot assign
    1045                 :         49 :                   success = !isExcludedCdtValue(n, repSet, assertedReps, *i2);
    1046         [ +  + ]:         49 :                   if (!success)
    1047                 :            :                   {
    1048         [ +  - ]:         36 :                     Trace("model-builder")
    1049                 :          0 :                         << "Excluded value : " << n
    1050                 :          0 :                         << " due to alpha-equivalent codatatype expression."
    1051                 :         18 :                         << std::endl;
    1052                 :            :                   }
    1053                 :            :                 }
    1054                 :            :               }
    1055                 :            :               //---
    1056         [ +  + ]:     165653 :             } while (!success);
    1057 [ -  + ][ -  + ]:     165635 :             Assert(!n.isNull());
                 [ -  - ]
    1058         [ +  - ]:     331270 :             Trace("model-value-enum") << "Enum infinite " << t << " " << n
    1059                 :     165635 :                                       << " for " << *i2 << std::endl;
    1060                 :            :           }
    1061                 :            :           else
    1062                 :            :           {
    1063                 :            :             // Otherwise, we get the first value from the type enumerator.
    1064                 :            :             // Note that uninterpreted sorts in finite model finding assign
    1065                 :            :             // an arbitrary constant when unassigned. This case is applied
    1066                 :            :             // e.g. for datatypes over uninterpreted sorts, where subfields
    1067                 :            :             // of the datatype may be introduced when assigning arbitrary
    1068                 :            :             // values.
    1069         [ +  - ]:        370 :             Trace("model-builder-debug")
    1070                 :        185 :                 << "Get first value from finite type..." << std::endl;
    1071                 :        185 :             TypeEnumerator te(t);
    1072                 :        185 :             n = *te;
    1073         [ +  - ]:        370 :             Trace("model-value-enum") << "Enum finite " << t << " " << n
    1074                 :        185 :                                       << " for " << *i2 << std::endl;
    1075                 :        185 :           }
    1076         [ +  - ]:     165867 :           Trace("model-builder-debug") << "...got " << n << std::endl;
    1077                 :     165867 :           assignConstantRep(tm, *i2, n);
    1078                 :     165867 :           changed = true;
    1079                 :     165867 :           noRepSet.erase(i2);
    1080         [ +  + ]:     165867 :           if (assignOne)
    1081                 :            :           {
    1082                 :      47810 :             assignOne = false;
    1083                 :      47810 :             break;
    1084                 :            :           }
    1085         [ +  + ]:     165867 :         }
    1086                 :            :       }
    1087 [ +  + ][ +  + ]:     511581 :     }
    1088                 :            : 
    1089                 :            :     // Corner case - I'm not sure this can even happen - but it's theoretically
    1090                 :            :     // possible to have a cyclical dependency
    1091                 :            :     // in EC assignment/evaluation, e.g. EC1 = {a, b + 1}; EC2 = {b, a - 1}.  In
    1092                 :            :     // this case, neither one will get assigned because we are waiting
    1093                 :            :     // to be able to evaluate.  But we will never be able to evaluate because
    1094                 :            :     // the variables that need to be assigned are in
    1095                 :            :     // these same EC's.  In this case, repeat the whole fixed-point computation
    1096                 :            :     // with the difference that the first EC
    1097                 :            :     // that has both assignable and evaluable expressions will get assigned.
    1098         [ +  + ]:     103052 :     if (!changed)
    1099                 :            :     {
    1100         [ +  - ]:      47810 :       Trace("model-builder-debug") << "...must assign one" << std::endl;
    1101                 :            :       // Avoid infinite loops: if we are in a deadlock, we abort model building
    1102                 :            :       // unsuccessfully here.
    1103         [ -  + ]:      47810 :       if (assignOne)
    1104                 :            :       {
    1105                 :          0 :         Assert(false) << "Reached a deadlock during model construction";
    1106                 :            :         Trace("model-builder-debug") << "...avoid loop, fail" << std::endl;
    1107                 :            :         return false;
    1108                 :            :       }
    1109                 :      47810 :       assignOne = true;
    1110                 :            :     }
    1111                 :     103052 :   }
    1112                 :            : 
    1113                 :            : #ifdef CVC5_ASSERTIONS
    1114                 :            :   // Assert that all representatives have been converted to constants
    1115         [ +  + ]:      55482 :   for (it = typeRepSet.begin(); it != typeRepSet.end(); ++it)
    1116                 :            :   {
    1117                 :      19897 :     std::set<Node>& repSet = TypeSet::getSet(it);
    1118         [ -  + ]:      19897 :     if (!repSet.empty())
    1119                 :            :     {
    1120         [ -  - ]:          0 :       Trace("model-builder") << "***Non-empty repSet, size = " << repSet.size()
    1121                 :          0 :                              << ", repSet = " << repSet << endl;
    1122                 :          0 :       Trace("model-builder-debug") << tm->getEqualityEngine()->debugPrintEqc();
    1123                 :          0 :       DebugUnhandled();
    1124                 :            :     }
    1125                 :            :   }
    1126                 :            : #endif /* CVC5_ASSERTIONS */
    1127                 :            : 
    1128         [ +  - ]:      35585 :   Trace("model-builder") << "Copy representatives to model..." << std::endl;
    1129                 :      35585 :   tm->d_reps.clear();
    1130                 :      35585 :   std::map<Node, Node>::iterator itMap;
    1131         [ +  + ]:    1273481 :   for (itMap = d_constantReps.begin(); itMap != d_constantReps.end(); ++itMap)
    1132                 :            :   {
    1133                 :            :     // The "constant" representative is a model value, which may be a lambda
    1134                 :            :     // if higher-order. We now can go back and normalize its subterms.
    1135                 :            :     // This is necessary if we assigned a lambda value whose body contains
    1136                 :            :     // a free constant symbol that was assigned in this method.
    1137                 :    1237896 :     Node normc = itMap->second;
    1138         [ +  + ]:    1237896 :     if (!normc.isConst())
    1139                 :            :     {
    1140                 :        581 :       normc = normalize(tm, normc, true);
    1141                 :            :     }
    1142                 :            :     // mark this as the final representative
    1143                 :    1237896 :     tm->assignRepresentative(itMap->first, normc, true);
    1144                 :    1237896 :   }
    1145                 :            : 
    1146         [ +  - ]:      35585 :   Trace("model-builder") << "Make sure ECs have reps..." << std::endl;
    1147                 :            :   // Make sure every EC has a rep
    1148         [ -  + ]:      35585 :   for (itMap = assertedReps.begin(); itMap != assertedReps.end(); ++itMap)
    1149                 :            :   {
    1150                 :          0 :     tm->assignRepresentative(itMap->first, itMap->second, false);
    1151                 :            :   }
    1152         [ +  + ]:      74553 :   for (it = typeNoRepSet.begin(); it != typeNoRepSet.end(); ++it)
    1153                 :            :   {
    1154                 :      38968 :     set<Node>& noRepSet = TypeSet::getSet(it);
    1155         [ +  + ]:      44715 :     for (const Node& node : noRepSet)
    1156                 :            :     {
    1157                 :       5747 :       tm->assignRepresentative(node, node, false);
    1158                 :            :     }
    1159                 :            :   }
    1160                 :            : 
    1161                 :            :   // modelBuilder-specific initialization
    1162         [ -  + ]:      35585 :   if (!processBuildModel(tm))
    1163                 :            :   {
    1164         [ -  - ]:          0 :     Trace("model-builder")
    1165                 :          0 :         << "TheoryEngineModelBuilder: fail process build model." << std::endl;
    1166                 :          0 :     return false;
    1167                 :            :   }
    1168         [ +  - ]:      35585 :   Trace("model-builder") << "TheoryEngineModelBuilder: success" << std::endl;
    1169                 :      35585 :   return true;
    1170                 :      35585 : }
    1171                 :            : 
    1172                 :       4421 : void TheoryEngineModelBuilder::postProcessModel(bool incomplete, TheoryModel* m)
    1173                 :            : {
    1174         [ +  - ]:       4421 :   Trace("model-builder") << "postProcessModel" << std::endl;
    1175                 :            :   // Note that we do not insist that functions are assigned here, they can
    1176                 :            :   // continue to be built on demand in the theory model.
    1177                 :            :   // if we are incomplete, there is no guarantee on the model.
    1178                 :            :   // thus, we do not check the model here.
    1179         [ +  + ]:       4421 :   if (incomplete)
    1180                 :            :   {
    1181                 :       1586 :     return;
    1182                 :            :   }
    1183 [ -  + ][ -  + ]:       2835 :   Assert(m != nullptr);
                 [ -  - ]
    1184                 :            :   // debug-check the model if the checkModels() is enabled.
    1185         [ +  + ]:       2835 :   if (options().smt.debugCheckModels)
    1186                 :            :   {
    1187                 :        548 :     debugCheckModel(m);
    1188                 :            :   }
    1189                 :            : }
    1190                 :            : 
    1191                 :        548 : void TheoryEngineModelBuilder::debugCheckModel(TheoryModel* tm)
    1192                 :            : {
    1193                 :        548 :   eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(tm->d_equalityEngine);
    1194                 :        548 :   std::map<Node, Node>::iterator itMap;
    1195                 :            :   // Check that every term evaluates to its representative in the model
    1196                 :        548 :   for (eqcs_i = eq::EqClassesIterator(tm->d_equalityEngine);
    1197         [ +  + ]:      10415 :        !eqcs_i.isFinished();
    1198                 :       9867 :        ++eqcs_i)
    1199                 :            :   {
    1200                 :            :     // eqc is the equivalence class representative
    1201                 :       9867 :     Node eqc = (*eqcs_i);
    1202                 :            :     // get the representative
    1203                 :       9867 :     Node rep = tm->getRepresentative(eqc);
    1204 [ +  + ][ -  + ]:       9867 :     if (!rep.isConst() && eqc.getType().isBoolean())
         [ +  + ][ -  + ]
                 [ -  - ]
    1205                 :            :     {
    1206                 :            :       // if Boolean, it does not necessarily have a constant representative, use
    1207                 :            :       // get value instead
    1208                 :          0 :       rep = tm->getValue(eqc);
    1209                 :          0 :       AlwaysAssert(rep.isConst());
    1210                 :            :     }
    1211                 :       9867 :     eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, tm->d_equalityEngine);
    1212         [ +  + ]:      45202 :     for (; !eqc_i.isFinished(); ++eqc_i)
    1213                 :            :     {
    1214                 :      35335 :       Node n = *eqc_i;
    1215 [ -  + ][ -  - ]:     106005 :       AlwaysAssert(CVC5_EQUAL(rep.getType(), n.getType()))
    1216                 :      35335 :           << "Representative " << rep << " of " << n
    1217 [ -  + ][ -  - ]:      35335 :           << " violates type constraints (" << rep.getType() << " and "
    1218 [ -  + ][ -  + ]:      35335 :           << n.getType() << ")";
                 [ -  - ]
    1219                 :      35335 :       Node val = tm->getValue(n);
    1220         [ +  + ]:      35335 :       if (val != rep)
    1221                 :            :       {
    1222                 :        587 :         std::stringstream err;
    1223                 :        587 :         err << "Failed representative check:" << std::endl
    1224                 :        587 :             << "n: " << n << std::endl
    1225                 :       1174 :             << "getValue(n): " << val << std::endl
    1226                 :        587 :             << "rep: " << rep << std::endl;
    1227 [ -  + ][ -  - ]:        587 :         if (val.isConst() && rep.isConst())
                 [ -  + ]
    1228                 :            :         {
    1229                 :          0 :           AlwaysAssert(val == rep) << err.str();
    1230                 :            :         }
    1231         [ +  + ]:       2935 :         else if (!CVC5_EQUAL(rewrite(val), rewrite(rep)))
    1232                 :            :         {
    1233                 :            :           // if it does not evaluate, it is just a warning, which may be the
    1234                 :            :           // case for non-constant values, e.g. lambdas. Furthermore we only
    1235                 :            :           // throw this warning if rewriting cannot show they are equal.
    1236                 :         37 :           warning() << err.str();
    1237                 :            :         }
    1238                 :        587 :       }
    1239                 :      35335 :     }
    1240                 :       9867 :   }
    1241                 :            : 
    1242                 :            :   // builder-specific debugging
    1243                 :        548 :   debugModel(tm);
    1244                 :        548 : }
    1245                 :            : 
    1246                 :    2525376 : Node TheoryEngineModelBuilder::normalize(TheoryModel* m, TNode r, bool evalOnly)
    1247                 :            : {
    1248                 :    2525376 :   std::map<Node, Node>::iterator itMap = d_constantReps.find(r);
    1249         [ +  + ]:    2525376 :   if (itMap != d_constantReps.end())
    1250                 :            :   {
    1251                 :         18 :     r = (*itMap).second;
    1252                 :            :     // if d_constantReps stores a constant, we are done, otherwise we process
    1253                 :            :     // it below.
    1254         [ -  + ]:         18 :     if (r.isConst())
    1255                 :            :     {
    1256                 :          0 :       return r;
    1257                 :            :     }
    1258                 :            :   }
    1259                 :    2525376 :   NodeMap::iterator it = d_normalizedCache.find(r);
    1260         [ +  + ]:    2525376 :   if (it != d_normalizedCache.end())
    1261                 :            :   {
    1262                 :      44312 :     return (*it).second;
    1263                 :            :   }
    1264         [ +  - ]:    2481064 :   Trace("model-builder-debug") << "do normalize on " << r << std::endl;
    1265                 :    2481064 :   Node retNode = r;
    1266         [ +  + ]:    2481064 :   if (r.getNumChildren() > 0)
    1267                 :            :   {
    1268                 :    2472117 :     std::vector<Node> children;
    1269         [ +  + ]:    2472117 :     if (r.getMetaKind() == kind::metakind::PARAMETERIZED)
    1270                 :            :     {
    1271                 :    1988493 :       children.push_back(r.getOperator());
    1272                 :            :     }
    1273         [ +  + ]:    7500194 :     for (size_t i = 0, nchild = r.getNumChildren(); i < nchild; ++i)
    1274                 :            :     {
    1275                 :    5028077 :       Node ri = r[i];
    1276                 :    5028077 :       bool recurse = true;
    1277         [ +  + ]:    5028077 :       if (!ri.isConst())
    1278                 :            :       {
    1279         [ +  + ]:    3755528 :         if (m->d_equalityEngine->hasTerm(ri))
    1280                 :            :         {
    1281                 :            :           itMap =
    1282                 :    3710499 :               d_constantReps.find(m->d_equalityEngine->getRepresentative(ri));
    1283         [ +  + ]:    3710499 :           if (itMap != d_constantReps.end())
    1284                 :            :           {
    1285                 :     750736 :             ri = (*itMap).second;
    1286         [ +  - ]:    1501472 :             Trace("model-builder-debug")
    1287                 :     750736 :                 << i << ": const child " << ri << std::endl;
    1288                 :            :             // need to recurse if d_constantReps stores a non-constant
    1289                 :     750736 :             recurse = !ri.isConst();
    1290                 :            :           }
    1291         [ +  + ]:    2959763 :           else if (!evalOnly)
    1292                 :            :           {
    1293                 :    2866666 :             recurse = false;
    1294         [ +  - ]:    2866666 :             Trace("model-builder-debug") << i << ": keep " << ri << std::endl;
    1295                 :            :           }
    1296                 :            :         }
    1297                 :            :         else
    1298                 :            :         {
    1299         [ +  - ]:      90058 :           Trace("model-builder-debug")
    1300                 :      45029 :               << i << ": no hasTerm " << ri << std::endl;
    1301                 :            :         }
    1302         [ +  + ]:    3755528 :         if (recurse)
    1303                 :            :         {
    1304                 :     138265 :           ri = normalize(m, ri, evalOnly);
    1305                 :            :         }
    1306                 :            :       }
    1307                 :    5028077 :       children.push_back(ri);
    1308                 :    5028077 :     }
    1309                 :    2472117 :     retNode = nodeManager()->mkNode(r.getKind(), children);
    1310                 :    2472117 :     retNode = rewrite(retNode);
    1311                 :    2472117 :   }
    1312                 :    2481064 :   d_normalizedCache[r] = retNode;
    1313                 :    2481064 :   return retNode;
    1314                 :    2481064 : }
    1315                 :            : 
    1316                 :       1609 : bool TheoryEngineModelBuilder::preProcessBuildModel(CVC5_UNUSED TheoryModel* m)
    1317                 :            : {
    1318                 :       1609 :   return true;
    1319                 :            : }
    1320                 :            : 
    1321                 :      35585 : bool TheoryEngineModelBuilder::processBuildModel(CVC5_UNUSED TheoryModel* m)
    1322                 :            : {
    1323                 :      35585 :   return true;
    1324                 :            : }
    1325                 :            : 
    1326                 :            : }  // namespace theory
    1327                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14