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: 647 702 92.2 %
Date: 2025-01-05 12:38:24 Functions: 22 22 100.0 %
Branches: 475 744 63.8 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * Top contributors (to current version):
       3                 :            :  *   Andrew Reynolds, Clark Barrett, Aina Niemetz
       4                 :            :  *
       5                 :            :  * This file is part of the cvc5 project.
       6                 :            :  *
       7                 :            :  * Copyright (c) 2009-2024 by the authors listed in the file AUTHORS
       8                 :            :  * in the top-level source directory and their institutional affiliations.
       9                 :            :  * All rights reserved.  See the file COPYING in the top-level source
      10                 :            :  * directory for licensing information.
      11                 :            :  * ****************************************************************************
      12                 :            :  *
      13                 :            :  * Implementation of theory model buidler class.
      14                 :            :  */
      15                 :            : #include "theory/theory_model_builder.h"
      16                 :            : 
      17                 :            : #include "expr/dtype.h"
      18                 :            : #include "expr/dtype_cons.h"
      19                 :            : #include "expr/skolem_manager.h"
      20                 :            : #include "expr/sort_to_term.h"
      21                 :            : #include "expr/sort_type_size.h"
      22                 :            : #include "options/quantifiers_options.h"
      23                 :            : #include "options/smt_options.h"
      24                 :            : #include "options/strings_options.h"
      25                 :            : #include "options/theory_options.h"
      26                 :            : #include "options/uf_options.h"
      27                 :            : #include "smt/env.h"
      28                 :            : #include "theory/rewriter.h"
      29                 :            : #include "theory/uf/function_const.h"
      30                 :            : #include "theory/uf/theory_uf_model.h"
      31                 :            : #include "util/uninterpreted_sort_value.h"
      32                 :            : 
      33                 :            : using namespace std;
      34                 :            : using namespace cvc5::internal::kind;
      35                 :            : using namespace cvc5::context;
      36                 :            : 
      37                 :            : namespace cvc5::internal {
      38                 :            : namespace theory {
      39                 :            : 
      40                 :      57151 : TheoryEngineModelBuilder::TheoryEngineModelBuilder(Env& env) : EnvObj(env) {}
      41                 :            : 
      42                 :         12 : void TheoryEngineModelBuilder::Assigner::initialize(
      43                 :            :     TypeNode tn, TypeEnumeratorProperties* tep, const std::vector<Node>& aes)
      44                 :            : {
      45                 :         12 :   d_te.reset(new TypeEnumerator(tn, tep));
      46                 :         12 :   d_assignExcSet.insert(d_assignExcSet.end(), aes.begin(), aes.end());
      47                 :         12 : }
      48                 :            : 
      49                 :         47 : Node TheoryEngineModelBuilder::Assigner::getNextAssignment()
      50                 :            : {
      51 [ -  + ][ -  + ]:         47 :   Assert(d_te != nullptr);
                 [ -  - ]
      52                 :         94 :   Node n;
      53                 :         47 :   bool success = false;
      54                 :         47 :   TypeEnumerator& te = *d_te;
      55                 :            :   // Check if we have run out of elements. This should never happen; if it
      56                 :            :   // does we assert false and return null.
      57         [ -  + ]:         47 :   if (te.isFinished())
      58                 :            :   {
      59                 :          0 :     Assert(false);
      60                 :            :     return Node::null();
      61                 :            :   }
      62                 :            :   // must increment until we find one that is not in the assignment
      63                 :            :   // exclusion set
      64                 :         10 :   do
      65                 :            :   {
      66                 :         57 :     n = *te;
      67                 :         57 :     success = std::find(d_assignExcSet.begin(), d_assignExcSet.end(), n)
      68                 :        114 :               == d_assignExcSet.end();
      69                 :            :     // increment regardless of fail or succeed, to set up the next value
      70                 :         57 :     ++te;
      71         [ +  + ]:         57 :   } while (!success);
      72                 :         47 :   return n;
      73                 :            : }
      74                 :            : 
      75                 :     411495 : Node TheoryEngineModelBuilder::evaluateEqc(TheoryModel* m, TNode r)
      76                 :            : {
      77                 :     411495 :   eq::EqClassIterator eqc_i = eq::EqClassIterator(r, m->d_equalityEngine);
      78         [ +  + ]:     427524 :   for (; !eqc_i.isFinished(); ++eqc_i)
      79                 :            :   {
      80                 :     414796 :     Node n = *eqc_i;
      81         [ +  - ]:     414796 :     Trace("model-builder-debug") << "Look at term : " << n << std::endl;
      82         [ +  + ]:     414796 :     if (!isAssignable(n))
      83                 :            :     {
      84         [ +  - ]:     413658 :       Trace("model-builder-debug") << "...try to normalize" << std::endl;
      85                 :     413658 :       Node normalized = normalize(m, n, true);
      86         [ +  - ]:     827316 :       Trace("model-builder-debug")
      87                 :          0 :           << "...return " << normalized
      88 [ -  + ][ -  - ]:     413658 :           << ", isValue=" << m->isValue(normalized) << std::endl;
      89         [ +  + ]:     413658 :       if (m->isValue(normalized))
      90                 :            :       {
      91                 :     398767 :         return normalized;
      92                 :            :       }
      93                 :            :     }
      94                 :            :   }
      95                 :      12728 :   return Node::null();
      96                 :            : }
      97                 :            : 
      98                 :         47 : bool TheoryEngineModelBuilder::isAssignerActive(TheoryModel* tm, Assigner& a)
      99                 :            : {
     100         [ +  + ]:         47 :   if (a.d_isActive)
     101                 :            :   {
     102                 :         35 :     return true;
     103                 :            :   }
     104                 :         12 :   std::vector<Node>& eset = a.d_assignExcSet;
     105                 :         12 :   std::map<Node, Node>::iterator it;
     106         [ +  + ]:         34 :   for (unsigned i = 0, size = eset.size(); i < size; i++)
     107                 :            :   {
     108                 :            :     // Members of exclusion set must have values, otherwise we are not yet
     109                 :            :     // assignable.
     110                 :         22 :     Node er = eset[i];
     111         [ +  + ]:         22 :     if (tm->isValue(er))
     112                 :            :     {
     113                 :            :       // already processed
     114                 :         16 :       continue;
     115                 :            :     }
     116                 :            :     // Assignable members of assignment exclusion set should be representatives
     117                 :            :     // of their equivalence classes. This ensures we look up the constant
     118                 :            :     // representatives for assignable members of assignment exclusion sets.
     119 [ -  + ][ -  + ]:          6 :     Assert(er == tm->getRepresentative(er));
                 [ -  - ]
     120                 :          6 :     it = d_constantReps.find(er);
     121         [ -  + ]:          6 :     if (it == d_constantReps.end())
     122                 :            :     {
     123         [ -  - ]:          0 :       Trace("model-build-aes")
     124                 :          0 :           << "isAssignerActive: not active due to " << er << std::endl;
     125                 :          0 :       return false;
     126                 :            :     }
     127                 :            :     // update
     128                 :          6 :     eset[i] = it->second;
     129                 :            :   }
     130         [ +  - ]:         12 :   Trace("model-build-aes") << "isAssignerActive: active!" << std::endl;
     131                 :         12 :   a.d_isActive = true;
     132                 :         12 :   return true;
     133                 :            : }
     134                 :            : 
     135                 :    5260420 : bool TheoryEngineModelBuilder::isAssignable(TNode n)
     136                 :            : {
     137                 :    5260420 :   Kind k = n.getKind();
     138 [ +  + ][ +  + ]:    5260420 :   if (k == Kind::SELECT || k == Kind::APPLY_SELECTOR
     139         [ +  + ]:    4790810 :       || k == Kind::SEQ_NTH)
     140                 :            :   {
     141                 :            :     // selectors are always assignable (where we guarantee that they are not
     142                 :            :     // evaluatable here)
     143         [ +  + ]:     470375 :     if (!logicInfo().isHigherOrder())
     144                 :            :     {
     145 [ -  + ][ -  + ]:     468841 :       Assert(!n.getType().isFunction());
                 [ -  - ]
     146                 :     468841 :       return true;
     147                 :            :     }
     148                 :            :     else
     149                 :            :     {
     150                 :            :       // might be a function field
     151                 :       1534 :       return !n.getType().isFunction();
     152                 :            :     }
     153                 :            :   }
     154 [ +  + ][ +  + ]:    4790050 :   else if (k == Kind::FLOATINGPOINT_COMPONENT_SIGN || k==Kind::SEP_NIL)
     155                 :            :   {
     156                 :            :     // - Extracting the sign of a floating-point number acts similar to a
     157                 :            :     // selector on a datatype, i.e. if `(sign x)` wasn't assigned a value, we
     158                 :            :     // can pick an arbitrary one. Note that the other components of a
     159                 :            :     // floating-point number should always be assigned a value.
     160                 :            :     // - sep.nil is a nullary constant that acts like a variable and thus is
     161                 :            :     // assignable.
     162                 :       2724 :     return true;
     163                 :            :   }
     164                 :            :   else
     165                 :            :   {
     166                 :            :     // non-function variables, and fully applied functions
     167         [ +  + ]:    4787320 :     if (!logicInfo().isHigherOrder())
     168                 :            :     {
     169                 :            :       // no functions exist, all functions are fully applied
     170 [ -  + ][ -  + ]:    4642830 :       Assert(k != Kind::HO_APPLY);
                 [ -  - ]
     171 [ -  + ][ -  + ]:    4642830 :       Assert(!n.getType().isFunction());
                 [ -  - ]
     172 [ +  + ][ +  + ]:    4642830 :       return n.isVar() || k == Kind::APPLY_UF;
     173                 :            :     }
     174                 :            :     else
     175                 :            :     {
     176 [ +  + ][ -  - ]:     182435 :       return (n.isVar() && !n.getType().isFunction())
     177         [ +  + ]:     114418 :              || k == Kind::APPLY_UF
     178 [ +  + ][ +  + ]:     330707 :              || (k == Kind::HO_APPLY
     179                 :     186217 :                  && n[0].getType().getNumChildren() == 2);
     180                 :            :     }
     181                 :            :   }
     182                 :            : }
     183                 :            : 
     184                 :    6623050 : void TheoryEngineModelBuilder::addAssignableSubterms(TNode n,
     185                 :            :                                                      TheoryModel* tm,
     186                 :            :                                                      NodeSet& cache)
     187                 :            : {
     188         [ +  + ]:    6623050 :   if (n.isClosure())
     189                 :            :   {
     190                 :      52608 :     return;
     191                 :            :   }
     192         [ +  + ]:    6570440 :   if (cache.find(n) != cache.end())
     193                 :            :   {
     194                 :    4141520 :     return;
     195                 :            :   }
     196         [ +  + ]:    2428910 :   if (isAssignable(n))
     197                 :            :   {
     198                 :     975846 :     tm->d_equalityEngine->addTerm(n);
     199                 :            :   }
     200         [ +  + ]:    6635300 :   for (TNode::iterator child_it = n.begin(); child_it != n.end(); ++child_it)
     201                 :            :   {
     202                 :    4206390 :     addAssignableSubterms(*child_it, tm, cache);
     203                 :            :   }
     204                 :    2428910 :   cache.insert(n);
     205                 :            : }
     206                 :            : 
     207                 :    1162660 : void TheoryEngineModelBuilder::assignConstantRep(TheoryModel* tm,
     208                 :            :                                                  Node eqc,
     209                 :            :                                                  Node constRep)
     210                 :            : {
     211                 :    1162660 :   d_constantReps[eqc] = constRep;
     212         [ +  - ]:    2325320 :   Trace("model-builder") << "    Assign: Setting constant rep of " << eqc
     213                 :    1162660 :                          << " to " << constRep << endl;
     214                 :    1162660 :   tm->d_rep_set.setTermForRepresentative(constRep, eqc);
     215                 :    1162660 : }
     216                 :            : 
     217                 :         48 : bool TheoryEngineModelBuilder::isExcludedCdtValue(
     218                 :            :     Node val,
     219                 :            :     std::set<Node>* repSet,
     220                 :            :     std::map<Node, Node>& assertedReps,
     221                 :            :     Node eqc)
     222                 :            : {
     223         [ +  - ]:         96 :   Trace("model-builder-debug")
     224                 :          0 :       << "Is " << val << " and excluded codatatype value for " << eqc << "? "
     225                 :         48 :       << std::endl;
     226         [ +  + ]:         98 :   for (set<Node>::iterator i = repSet->begin(); i != repSet->end(); ++i)
     227                 :            :   {
     228 [ -  + ][ -  + ]:         68 :     Assert(assertedReps.find(*i) != assertedReps.end());
                 [ -  - ]
     229                 :         68 :     Node rep = assertedReps[*i];
     230         [ +  - ]:         68 :     Trace("model-builder-debug") << "  Rep : " << rep << std::endl;
     231                 :            :     // check whether it is possible that rep will be assigned the same value
     232                 :            :     // as val.
     233         [ +  + ]:         68 :     if (isCdtValueMatch(val, rep))
     234                 :            :     {
     235                 :         18 :       return true;
     236                 :            :     }
     237                 :            :   }
     238                 :         30 :   return false;
     239                 :            : }
     240                 :            : 
     241                 :        173 : bool TheoryEngineModelBuilder::isCdtValueMatch(Node v, Node r)
     242                 :            : {
     243         [ +  + ]:        173 :   if (r == v)
     244                 :            :   {
     245                 :            :     // values equal match trivially
     246                 :         45 :     return true;
     247                 :            :   }
     248 [ +  - ][ +  + ]:        128 :   else if (v.isConst() && r.isConst())
                 [ +  + ]
     249                 :            :   {
     250                 :            :     // distinct constant values do not match
     251                 :         10 :     return false;
     252                 :            :   }
     253         [ +  + ]:        118 :   else if (r.getKind() == Kind::APPLY_CONSTRUCTOR)
     254                 :            :   {
     255         [ +  + ]:         69 :     if (v.getKind() != Kind::APPLY_CONSTRUCTOR)
     256                 :            :     {
     257 [ -  + ][ -  + ]:          1 :       Assert(v.getKind() == Kind::CODATATYPE_BOUND_VARIABLE);
                 [ -  - ]
     258                 :            :       // v is the position of a loop. It may be possible to match, we return
     259                 :            :       // true, which is an over-approximation of when it is unsafe to use v.
     260                 :          1 :       return true;
     261                 :            :     }
     262         [ +  + ]:         68 :     if (v.getOperator() == r.getOperator())
     263                 :            :     {
     264         [ +  + ]:        123 :       for (size_t i = 0, nchild = v.getNumChildren(); i < nchild; i++)
     265                 :            :       {
     266         [ +  + ]:        105 :         if (!isCdtValueMatch(v[i], r[i]))
     267                 :            :         {
     268                 :            :           // if one child fails to match, we cannot match
     269                 :         42 :           return false;
     270                 :            :         }
     271                 :            :       }
     272                 :         18 :       return true;
     273                 :            :     }
     274                 :            :     // operators do not match
     275                 :          8 :     return false;
     276                 :            :   }
     277         [ +  + ]:         49 :   else if (v.getKind() == Kind::APPLY_CONSTRUCTOR)
     278                 :            :   {
     279                 :            :     // v has a constructor in a position that we have yet to fill in r.
     280                 :            :     // we are either a finite type in which case this subfield of r can be
     281                 :            :     // assigned a default value (or otherwise would have been split on).
     282                 :            :     // otherwise we are an infinite type and the subfield of r will be
     283                 :            :     // chosen not to clash with the subfield of v.
     284                 :         32 :     return false;
     285                 :            :   }
     286                 :         17 :   return true;
     287                 :            : }
     288                 :            : 
     289                 :       7782 : bool TheoryEngineModelBuilder::involvesUSort(TypeNode tn) const
     290                 :            : {
     291         [ +  + ]:       7782 :   if (tn.isUninterpretedSort())
     292                 :            :   {
     293                 :          5 :     return true;
     294                 :            :   }
     295         [ +  + ]:       7777 :   else if (tn.isArray())
     296                 :            :   {
     297         [ -  - ]:         23 :     return involvesUSort(tn.getArrayIndexType())
     298 [ +  - ][ +  + ]:         23 :            || involvesUSort(tn.getArrayConstituentType());
         [ +  - ][ +  - ]
                 [ -  - ]
     299                 :            :   }
     300         [ +  + ]:       7754 :   else if (tn.isSet())
     301                 :            :   {
     302                 :          4 :     return involvesUSort(tn.getSetElementType());
     303                 :            :   }
     304         [ +  + ]:       7750 :   else if (tn.isDatatype())
     305                 :            :   {
     306                 :       7402 :     const DType& dt = tn.getDType();
     307                 :       7402 :     return dt.involvesUninterpretedType();
     308                 :            :   }
     309                 :            :   else
     310                 :            :   {
     311                 :        348 :     return false;
     312                 :            :   }
     313                 :            : }
     314                 :            : 
     315                 :      16498 : bool TheoryEngineModelBuilder::isExcludedUSortValue(
     316                 :            :     std::map<TypeNode, unsigned>& eqc_usort_count,
     317                 :            :     Node v,
     318                 :            :     std::map<Node, bool>& visited)
     319                 :            : {
     320 [ -  + ][ -  + ]:      16498 :   Assert(v.isConst());
                 [ -  - ]
     321         [ +  + ]:      16498 :   if (visited.find(v) == visited.end())
     322                 :            :   {
     323                 :      12805 :     visited[v] = true;
     324                 :      12805 :     TypeNode tn = v.getType();
     325         [ +  + ]:      12805 :     if (tn.isUninterpretedSort())
     326                 :            :     {
     327         [ +  - ]:        336 :       Trace("model-builder-debug") << "Is excluded usort value : " << v << " "
     328                 :        168 :                                    << tn << std::endl;
     329                 :        168 :       unsigned card = eqc_usort_count[tn];
     330         [ +  - ]:        168 :       Trace("model-builder-debug") << "  Cardinality is " << card << std::endl;
     331                 :            :       unsigned index =
     332                 :        168 :           v.getConst<UninterpretedSortValue>().getIndex().toUnsignedInt();
     333         [ +  - ]:        168 :       Trace("model-builder-debug") << "  Index is " << index << std::endl;
     334 [ -  + ][ -  - ]:        168 :       return index > 0 && index >= card;
     335                 :            :     }
     336         [ +  + ]:      25879 :     for (unsigned i = 0; i < v.getNumChildren(); i++)
     337                 :            :     {
     338         [ -  + ]:      13242 :       if (isExcludedUSortValue(eqc_usort_count, v[i], visited))
     339                 :            :       {
     340                 :          0 :         return true;
     341                 :            :       }
     342                 :            :     }
     343                 :            :   }
     344                 :      16330 :   return false;
     345                 :            : }
     346                 :            : 
     347                 :     700403 : void TheoryEngineModelBuilder::addToTypeList(
     348                 :            :     TypeNode tn,
     349                 :            :     std::vector<TypeNode>& type_list,
     350                 :            :     std::unordered_set<TypeNode>& visiting)
     351                 :            : {
     352         [ +  + ]:     700403 :   if (std::find(type_list.begin(), type_list.end(), tn) == type_list.end())
     353                 :            :   {
     354         [ +  + ]:     158787 :     if (visiting.find(tn) == visiting.end())
     355                 :            :     {
     356                 :      51852 :       visiting.insert(tn);
     357                 :            :       /* This must make a recursive call on all types that are subterms of
     358                 :            :        * values of the current type.
     359                 :            :        * Note that recursive traversal here is over enumerated expressions
     360                 :            :        * (very low expression depth). */
     361         [ +  + ]:      51852 :       if (tn.isArray())
     362                 :            :       {
     363                 :        461 :         addToTypeList(tn.getArrayIndexType(), type_list, visiting);
     364                 :        461 :         addToTypeList(tn.getArrayConstituentType(), type_list, visiting);
     365                 :            :       }
     366         [ +  + ]:      51391 :       else if (tn.isSet())
     367                 :            :       {
     368                 :       1335 :         addToTypeList(tn.getSetElementType(), type_list, visiting);
     369                 :            :       }
     370         [ +  + ]:      50056 :       else if (tn.isDatatype())
     371                 :            :       {
     372                 :      22633 :         const DType& dt = tn.getDType();
     373         [ +  + ]:     148116 :         for (unsigned i = 0; i < dt.getNumConstructors(); i++)
     374                 :            :         {
     375         [ +  + ]:     257543 :           for (unsigned j = 0; j < dt[i].getNumArgs(); j++)
     376                 :            :           {
     377                 :     132060 :             TypeNode ctn = dt[i][j].getRangeType();
     378                 :     132060 :             addToTypeList(ctn, type_list, visiting);
     379                 :            :           }
     380                 :            :         }
     381                 :            :       }
     382 [ -  + ][ -  + ]:      51852 :       Assert(std::find(type_list.begin(), type_list.end(), tn)
                 [ -  - ]
     383                 :            :              == type_list.end());
     384                 :      51852 :       type_list.push_back(tn);
     385                 :            :     }
     386                 :            :   }
     387                 :     700403 : }
     388                 :            : 
     389                 :      35036 : bool TheoryEngineModelBuilder::buildModel(TheoryModel* tm)
     390                 :            : {
     391         [ +  - ]:      35036 :   Trace("model-builder") << "TheoryEngineModelBuilder: buildModel" << std::endl;
     392                 :            : 
     393         [ +  - ]:      70072 :   Trace("model-builder")
     394                 :      35036 :       << "TheoryEngineModelBuilder: Preprocess build model..." << std::endl;
     395                 :            :   // model-builder specific initialization
     396         [ -  + ]:      35036 :   if (!preProcessBuildModel(tm))
     397                 :            :   {
     398         [ -  - ]:          0 :     Trace("model-builder")
     399                 :          0 :         << "TheoryEngineModelBuilder: fail preprocess build model."
     400                 :          0 :         << std::endl;
     401                 :          0 :     return false;
     402                 :            :   }
     403                 :            : 
     404         [ +  - ]:      70072 :   Trace("model-builder")
     405                 :            :       << "TheoryEngineModelBuilder: Add assignable subterms "
     406                 :          0 :          ", collect representatives and compute assignable information..."
     407                 :      35036 :       << std::endl;
     408                 :            : 
     409                 :            :   // type enumerator properties
     410                 :      35036 :   bool tepFixUSortCard = options().quantifiers.finiteModelFind;
     411                 :      35036 :   uint32_t tepStrAlphaCard = options().strings.stringsAlphaCard;
     412                 :      70072 :   TypeEnumeratorProperties tep(tepFixUSortCard, tepStrAlphaCard);
     413                 :            : 
     414                 :            :   // In the first step of model building, we do a traversal of the
     415                 :            :   // equality engine and record the information in the following:
     416                 :            : 
     417                 :            :   // The constant representatives, per equivalence class
     418                 :      35036 :   d_constantReps.clear();
     419                 :            :   // The representatives that have been asserted by theories. This includes
     420                 :            :   // non-constant "skeletons" that have been specified by parametric theories.
     421                 :      70072 :   std::map<Node, Node> assertedReps;
     422                 :            :   // A parition of the set of equivalence classes that have:
     423                 :            :   // (1) constant representatives,
     424                 :            :   // (2) an assigned representative specified by a theory in collectModelInfo,
     425                 :            :   // (3) no assigned representative.
     426                 :      70072 :   TypeSet typeConstSet, typeRepSet, typeNoRepSet;
     427                 :            :   // An ordered list of types, such that T1 comes before T2 if T1 is a
     428                 :            :   // "component type" of T2, e.g. U comes before (Set U). This is only strictly
     429                 :            :   // necessary for finite model finding + parametric types instantiated with
     430                 :            :   // uninterpreted sorts, but is probably a good idea to do in general since it
     431                 :            :   // leads to models with smaller term sizes. -AJR
     432                 :      70072 :   std::vector<TypeNode> type_list;
     433                 :            :   // The count of equivalence classes per sort (for finite model finding).
     434                 :      70072 :   std::map<TypeNode, unsigned> eqc_usort_count;
     435                 :            : 
     436                 :            :   // the set of equivalence classes that are "assignable", i.e. those that have
     437                 :            :   // an assignable expression in them (see isAssignable), and have not already
     438                 :            :   // been assigned a constant.
     439                 :      70072 :   std::unordered_set<Node> assignableEqc;
     440                 :            :   // The set of equivalence classes that are "evaluable", i.e. those that have
     441                 :            :   // an expression in them that is not assignable, and have not already been
     442                 :            :   // assigned a constant.
     443                 :      70072 :   std::unordered_set<Node> evaluableEqc;
     444                 :            :   // Assigner objects for relevant equivalence classes that require special
     445                 :            :   // ways of assigning values, e.g. those that take into account assignment
     446                 :            :   // exclusion sets.
     447                 :      70072 :   std::map<Node, Assigner> eqcToAssigner;
     448                 :            :   // A map from equivalence classes to the equivalence class that it shares an
     449                 :            :   // assigner object with (all elements in the range of this map are in the
     450                 :            :   // domain of eqcToAssigner).
     451                 :      70072 :   std::map<Node, Node> eqcToAssignerMaster;
     452                 :            : 
     453                 :            :   // Loop through equivalence classes of the equality engine of the model.
     454                 :      35036 :   eq::EqualityEngine* ee = tm->d_equalityEngine;
     455                 :      70072 :   NodeSet assignableCache;
     456                 :      35036 :   std::map<Node, Node>::iterator itm;
     457                 :      35036 :   eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(ee);
     458                 :            :   // should we compute assigner objects?
     459                 :      35036 :   bool computeAssigners = tm->hasAssignmentExclusionSets();
     460                 :            :   // the set of exclusion sets we have processed
     461                 :      70072 :   std::unordered_set<Node> processedExcSet;
     462         [ +  + ]:    1199990 :   for (; !eqcs_i.isFinished(); ++eqcs_i)
     463                 :            :   {
     464                 :    1164960 :     Node eqc = *eqcs_i;
     465         [ +  - ]:    1164960 :     Trace("model-builder") << "  Processing EQC " << eqc << std::endl;
     466                 :            :     // Information computed for each equivalence class
     467                 :            : 
     468                 :            :     // The assigned represenative and constant representative
     469                 :    1164960 :     Node rep, constRep;
     470                 :            :     // is constant rep a "base model value" (see TheoryModel::isBaseModelValue)
     471                 :    1164960 :     bool constRepBaseModelValue = false;
     472                 :            :     // A flag set to true if the current equivalence class is assignable (see
     473                 :            :     // assignableEqc).
     474                 :    1164960 :     bool assignable = false;
     475                 :            :     // Set to true if the current equivalence class is evaluatable (see
     476                 :            :     // evaluableEqc).
     477                 :    1164960 :     bool evaluable = false;
     478                 :            :     // Set to true if a term in the current equivalence class has been given an
     479                 :            :     // assignment exclusion set.
     480                 :    1164960 :     bool hasESet CVC5_UNUSED = false;
     481                 :            :     // Set to true if we found that a term in the current equivalence class has
     482                 :            :     // been given an assignment exclusion set, and we have not seen this term
     483                 :            :     // as part of a previous assignment exclusion group. In other words, when
     484                 :            :     // this flag is true we construct a new assigner object with the current
     485                 :            :     // equivalence class as its master.
     486                 :    1164960 :     bool foundESet = false;
     487                 :            :     // The assignment exclusion set for the current equivalence class.
     488                 :    1164960 :     std::vector<Node> eset;
     489                 :            :     // The group to which this equivalence class belongs when exclusion sets
     490                 :            :     // were assigned (see the argument group of
     491                 :            :     // TheoryModel::getAssignmentExclusionSet).
     492                 :    1164960 :     std::vector<Node> esetGroup;
     493                 :            : 
     494                 :            :     // Loop through terms in this EC
     495                 :    1164960 :     eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, ee);
     496         [ +  + ]:    3581610 :     for (; !eqc_i.isFinished(); ++eqc_i)
     497                 :            :     {
     498                 :    2416660 :       Node n = *eqc_i;
     499         [ +  - ]:    2416660 :       Trace("model-builder") << "    Processing Term: " << n << endl;
     500                 :            : 
     501                 :            :       // For each term n in this equivalence class, below we register its
     502                 :            :       // assignable subterms, compute whether it is a constant or assigned
     503                 :            :       // representative, then if we don't have a constant representative,
     504                 :            :       // compute information regarding how we will assign values.
     505                 :            : 
     506                 :            :       // (1) Add assignable subterms, which ensures that e.g. models for
     507                 :            :       // uninterpreted functions take into account all subterms in the
     508                 :            :       // equality engine of the model
     509                 :    2416660 :       addAssignableSubterms(n, tm, assignableCache);
     510                 :            :       // model-specific processing of the term
     511                 :    2416660 :       tm->addTermInternal(n);
     512                 :            : 
     513                 :            :       // compute whether n is assignable
     514         [ +  + ]:    2416660 :       if (!isAssignable(n))
     515                 :            :       {
     516                 :            :         // (2) Record constant representative or assign representative, if
     517                 :            :         // applicable. We check if n is a value here, e.g. a term for which
     518                 :            :         // isConst returns true, or a lambda. The latter is required only for
     519                 :            :         // higher-order.
     520         [ +  + ]:    1440810 :         if (tm->isValue(n))
     521                 :            :         {
     522                 :            :           // In some cases, there can be multiple terms in the same equivalence
     523                 :            :           // class are considered values, e.g., when real algebraic numbers did
     524                 :            :           // not simplify to rational values or real.pi was used as a model
     525                 :            :           // value. We distinguish three kinds of model values: constants,
     526                 :            :           // non-constant base values and non-base values, and we use them in
     527                 :            :           // this order of preference.
     528                 :            :           // We print a trace message if there is more than one model value in
     529                 :            :           // the same equivalence class. We throw a debug failure if there are
     530                 :            :           // at least two base model values in the same equivalence class that
     531                 :            :           // do not compare equal.
     532                 :     598880 :           bool assignConstRep = false;
     533                 :     598880 :           bool isBaseValue = tm->isBaseModelValue(n);
     534         [ +  + ]:     598880 :           if (constRep.isNull())
     535                 :            :           {
     536                 :     598871 :             assignConstRep = true;
     537                 :            :           }
     538                 :            :           else
     539                 :            :           {
     540                 :            :             // This is currently a trace message, as it often triggers for
     541                 :            :             // non-linear arithmetic before the model is refined enough to
     542                 :            :             // e.g. show transcendental function apps are not equal to rationals
     543         [ +  - ]:         18 :             Trace("model-warn") << "Model values in the same equivalence class "
     544                 :          9 :                                 << constRep << " " << n << std::endl;
     545         [ -  + ]:          9 :             if (!constRepBaseModelValue)
     546                 :            :             {
     547                 :          0 :               assignConstRep = isBaseValue;
     548                 :            :             }
     549         [ +  + ]:          9 :             else if (isBaseValue)
     550                 :            :             {
     551                 :          3 :               Node isEqual = rewrite(constRep.eqNode(n));
     552 [ +  - ][ +  - ]:          1 :               if (isEqual.isConst() && isEqual.getConst<bool>())
                 [ +  - ]
     553                 :            :               {
     554                 :          1 :                 assignConstRep = n.isConst();
     555                 :            :               }
     556                 :            :               else
     557                 :            :               {
     558                 :          0 :                 Assert(false) << "Distinct base model values in the same "
     559                 :          0 :                                  "equivalence class "
     560                 :          0 :                               << constRep << " " << n << std::endl;
     561                 :            :               }
     562                 :            :             }
     563                 :            :           }
     564         [ +  + ]:     598880 :           if (assignConstRep)
     565                 :            :           {
     566                 :     598871 :             constRep = n;
     567         [ +  - ]:    1197740 :             Trace("model-builder") << "    ..ConstRep( " << eqc
     568                 :     598871 :                                    << " ) = " << constRep << std::endl;
     569                 :     598871 :             constRepBaseModelValue = isBaseValue;
     570                 :            :           }
     571                 :            :           // if we have a constant representative, nothing else matters
     572                 :     598880 :           continue;
     573                 :            :         }
     574                 :            : 
     575                 :            :         // If we don't have a constant rep, check if this is an assigned rep.
     576                 :     841931 :         itm = tm->d_reps.find(n);
     577         [ +  + ]:     841931 :         if (itm != tm->d_reps.end())
     578                 :            :         {
     579                 :            :           // Notice that this equivalence class may contain multiple terms that
     580                 :            :           // were specified as being a representative, since e.g. datatypes may
     581                 :            :           // assert representative for two constructor terms that are not in the
     582                 :            :           // care graph and are merged during collectModeInfo due to equality
     583                 :            :           // information from another theory. We overwrite the value of rep in
     584                 :            :           // these cases here.
     585                 :      75007 :           rep = itm->second;
     586         [ +  - ]:     150014 :           Trace("model-builder")
     587                 :      75007 :               << "    ..Rep( " << eqc << " ) = " << rep << std::endl;
     588                 :            :         }
     589                 :            : 
     590                 :            :         // (3) Finally, process assignable information
     591                 :     841931 :         evaluable = true;
     592                 :            :         // expressions that are not assignable should not be given assignment
     593                 :            :         // exclusion sets
     594 [ -  + ][ -  + ]:     841931 :         Assert(!tm->getAssignmentExclusionSet(n, esetGroup, eset));
                 [ -  - ]
     595                 :     841931 :         continue;
     596                 :            :       }
     597                 :     975846 :       assignable = true;
     598         [ +  + ]:     975846 :       if (!computeAssigners)
     599                 :            :       {
     600                 :            :         // we don't compute assigners, skip
     601                 :     975599 :         continue;
     602                 :            :       }
     603                 :            :       // process the assignment exclusion set for term n
     604                 :            :       // was it processed based on a master exclusion group (see
     605                 :            :       // eqcToAssignerMaster)?
     606         [ +  + ]:        247 :       if (processedExcSet.find(n) != processedExcSet.end())
     607                 :            :       {
     608                 :            :         // Should not have two assignment exclusion sets for the same
     609                 :            :         // equivalence class
     610 [ -  + ][ -  + ]:         35 :         Assert(!hasESet);
                 [ -  - ]
     611 [ -  + ][ -  + ]:         35 :         Assert(eqcToAssignerMaster.find(eqc) != eqcToAssignerMaster.end());
                 [ -  - ]
     612                 :            :         // already processed as a slave term
     613                 :         35 :         hasESet = true;
     614                 :         35 :         continue;
     615                 :            :       }
     616                 :            :       // was it assigned one?
     617         [ +  + ]:        212 :       if (tm->getAssignmentExclusionSet(n, esetGroup, eset))
     618                 :            :       {
     619                 :            :         // Should not have two assignment exclusion sets for the same
     620                 :            :         // equivalence class
     621 [ -  + ][ -  + ]:         12 :         Assert(!hasESet);
                 [ -  - ]
     622                 :         12 :         foundESet = true;
     623                 :         12 :         hasESet = true;
     624                 :            :       }
     625                 :            :     }
     626                 :            : 
     627                 :            :     // finished traversing the equality engine
     628                 :    1164960 :     TypeNode eqct = eqc.getType();
     629                 :            :     // count the number of equivalence classes of sorts in finite model finding
     630         [ +  + ]:    1164960 :     if (options().quantifiers.finiteModelFind)
     631                 :            :     {
     632         [ +  + ]:      23206 :       if (eqct.isUninterpretedSort())
     633                 :            :       {
     634                 :       5149 :         eqc_usort_count[eqct]++;
     635                 :            :       }
     636                 :            :     }
     637                 :            :     // Assign representative for this equivalence class
     638         [ +  + ]:    1164960 :     if (!constRep.isNull())
     639                 :            :     {
     640                 :            :       // Theories should not specify a rep if there is already a constant in the
     641                 :            :       // equivalence class. However, it may be the case that the representative
     642                 :            :       // specified by a theory may be merged with a constant based on equality
     643                 :            :       // information from another class. Thus, rep may be non-null here.
     644                 :            :       // Regardless, we assign constRep as the representative here.
     645                 :     598871 :       assignConstantRep(tm, eqc, constRep);
     646                 :     598871 :       typeConstSet.add(eqct, constRep);
     647                 :     598871 :       continue;
     648                 :            :     }
     649         [ +  + ]:     566086 :     else if (!rep.isNull())
     650                 :            :     {
     651                 :      72343 :       assertedReps[eqc] = rep;
     652                 :      72343 :       typeRepSet.add(eqct, eqc);
     653                 :      72343 :       std::unordered_set<TypeNode> visiting;
     654                 :      72343 :       addToTypeList(eqct, type_list, visiting);
     655                 :            :     }
     656                 :            :     else
     657                 :            :     {
     658                 :     493743 :       typeNoRepSet.add(eqct, eqc);
     659                 :     493743 :       std::unordered_set<TypeNode> visiting;
     660                 :     493743 :       addToTypeList(eqct, type_list, visiting);
     661                 :            :     }
     662                 :            : 
     663         [ +  + ]:     566086 :     if (assignable)
     664                 :            :     {
     665                 :     163468 :       assignableEqc.insert(eqc);
     666                 :            :     }
     667         [ +  + ]:     566086 :     if (evaluable)
     668                 :            :     {
     669                 :     473406 :       evaluableEqc.insert(eqc);
     670                 :            :     }
     671                 :            :     // If we found an assignment exclusion set, we construct a new assigner
     672                 :            :     // object.
     673         [ +  + ]:     566086 :     if (foundESet)
     674                 :            :     {
     675                 :            :       // we don't accept assignment exclusion sets for evaluable eqc
     676 [ -  + ][ -  + ]:         12 :       Assert(!evaluable);
                 [ -  - ]
     677                 :            :       // construct the assigner
     678                 :         12 :       Assigner& a = eqcToAssigner[eqc];
     679                 :            :       // Take the representatives of each term in the assignment exclusion
     680                 :            :       // set, which ensures we can look up their value in d_constReps later.
     681                 :         24 :       std::vector<Node> aes;
     682         [ +  + ]:         34 :       for (const Node& e : eset)
     683                 :            :       {
     684                 :            :         // Should only supply terms that occur in the model or constants
     685                 :            :         // in assignment exclusion sets.
     686                 :         22 :         Assert(tm->hasTerm(e) || e.isConst());
     687 [ +  - ][ +  - ]:         66 :         Node er = tm->hasTerm(e) ? tm->getRepresentative(e) : e;
                 [ -  - ]
     688                 :         22 :         aes.push_back(er);
     689                 :            :       }
     690                 :            :       // initialize
     691                 :         12 :       a.initialize(eqc.getType(), &tep, aes);
     692                 :            :       // all others in the group are slaves of this
     693         [ +  + ]:         59 :       for (const Node& g : esetGroup)
     694                 :            :       {
     695 [ -  + ][ -  + ]:         47 :         Assert(isAssignable(g));
                 [ -  - ]
     696         [ -  + ]:         47 :         if (!tm->hasTerm(g))
     697                 :            :         {
     698                 :            :           // Ignore those that aren't in the model, in the case the user
     699                 :            :           // has supplied an assignment exclusion set to a variable not in
     700                 :            :           // the model.
     701                 :          0 :           continue;
     702                 :            :         }
     703                 :         94 :         Node gr = tm->getRepresentative(g);
     704         [ +  + ]:         47 :         if (gr != eqc)
     705                 :            :         {
     706                 :         35 :           eqcToAssignerMaster[gr] = eqc;
     707                 :            :           // remember that this term has been processed
     708                 :         35 :           processedExcSet.insert(g);
     709                 :            :         }
     710                 :            :       }
     711                 :            :     }
     712                 :            :   }
     713                 :            : 
     714                 :            :   // Now finished initialization
     715                 :            : 
     716                 :            :   // Compute type enumerator properties. This code ensures we do not
     717                 :            :   // enumerate terms that have uninterpreted constants that violate the
     718                 :            :   // bounds imposed by finite model finding. For example, if finite
     719                 :            :   // model finding insists that there are only 2 values { U1, U2 } of type U,
     720                 :            :   // then the type enumerator for list of U should enumerate:
     721                 :            :   //   nil, (cons U1 nil), (cons U2 nil), (cons U1 (cons U1 nil)), ...
     722                 :            :   // instead of enumerating (cons U3 nil).
     723         [ +  + ]:      35036 :   if (options().quantifiers.finiteModelFind)
     724                 :            :   {
     725                 :       1560 :     tep.d_fixed_usort_card = true;
     726                 :       4386 :     for (std::map<TypeNode, unsigned>::iterator it = eqc_usort_count.begin();
     727         [ +  + ]:       4386 :          it != eqc_usort_count.end();
     728                 :       2826 :          ++it)
     729                 :            :     {
     730         [ +  - ]:       5652 :       Trace("model-builder") << "Fixed bound (#eqc) for " << it->first << " : "
     731                 :       2826 :                              << it->second << std::endl;
     732                 :       2826 :       tep.d_fixed_card[it->first] = Integer(it->second);
     733                 :            :     }
     734                 :       1560 :     typeConstSet.setTypeEnumeratorProperties(&tep);
     735                 :            :   }
     736                 :            : 
     737                 :            :   // Need to ensure that each EC has a constant representative.
     738                 :            : 
     739         [ +  - ]:      35036 :   Trace("model-builder") << "Processing EC's..." << std::endl;
     740                 :            : 
     741                 :      35036 :   TypeSet::iterator it;
     742                 :      35036 :   vector<TypeNode>::iterator type_it;
     743                 :      35036 :   set<Node>::iterator i, i2;
     744                 :      35036 :   bool changed, unassignedAssignable, assignOne = false;
     745                 :      70072 :   set<TypeNode> evaluableSet;
     746                 :            : 
     747                 :            :   // Double-fixed-point loop
     748                 :            :   // Outer loop handles a special corner case (see code at end of loop for
     749                 :            :   // details)
     750                 :            :   for (;;)
     751                 :            :   {
     752                 :            :     // Inner fixed-point loop: we are trying to learn constant values for every
     753                 :            :     // EC.  Each time through this loop, we process all of the
     754                 :            :     // types by type and may learn some new EC values.  EC's in one type may
     755                 :            :     // depend on EC's in another type, so we need a fixed-point loop
     756                 :            :     // to ensure that we learn as many EC values as possible
     757         [ +  + ]:     220390 :     do
     758                 :            :     {
     759                 :     220390 :       changed = false;
     760                 :     220390 :       unassignedAssignable = false;
     761                 :     220390 :       evaluableSet.clear();
     762                 :            : 
     763                 :            :       // Iterate over all types we've seen
     764         [ +  + ]:    1007970 :       for (type_it = type_list.begin(); type_it != type_list.end(); ++type_it)
     765                 :            :       {
     766                 :    1575170 :         TypeNode t = *type_it;
     767                 :    1575170 :         TypeNode tb = t;
     768                 :     787583 :         set<Node>* noRepSet = typeNoRepSet.getSet(t);
     769                 :            : 
     770                 :            :         // 1. Try to evaluate the EC's in this type
     771 [ +  + ][ +  + ]:     787583 :         if (noRepSet != NULL && !noRepSet->empty())
                 [ +  + ]
     772                 :            :         {
     773         [ +  - ]:     579422 :           Trace("model-builder") << "  Eval phase, working on type: " << t
     774                 :     289711 :                                  << endl;
     775                 :            :           bool evaluable;
     776                 :     289711 :           d_normalizedCache.clear();
     777         [ +  + ]:    3410070 :           for (i = noRepSet->begin(); i != noRepSet->end();)
     778                 :            :           {
     779                 :    3120360 :             i2 = i;
     780                 :    3120360 :             ++i;
     781         [ +  - ]:    6240730 :             Trace("model-builder-debug") << "Look at eqc : " << (*i2)
     782                 :    3120360 :                                          << std::endl;
     783                 :    6240730 :             Node normalized;
     784                 :            :             // only possible to normalize if we are evaluable
     785                 :    3120360 :             evaluable = evaluableEqc.find(*i2) != evaluableEqc.end();
     786         [ +  + ]:    3120360 :             if (evaluable)
     787                 :            :             {
     788                 :     411495 :               normalized = evaluateEqc(tm, *i2);
     789                 :            :             }
     790         [ +  + ]:    3120360 :             if (!normalized.isNull())
     791                 :            :             {
     792 [ -  + ][ -  + ]:     398767 :               Assert(tm->isValue(normalized));
                 [ -  - ]
     793                 :     398767 :               typeConstSet.add(tb, normalized);
     794                 :     398767 :               assignConstantRep(tm, *i2, normalized);
     795         [ +  - ]:     797534 :               Trace("model-builder") << "    Eval: Setting constant rep of "
     796                 :     398767 :                                      << (*i2) << " to " << normalized << endl;
     797                 :     398767 :               changed = true;
     798                 :     398767 :               noRepSet->erase(i2);
     799                 :            :             }
     800                 :            :             else
     801                 :            :             {
     802         [ +  + ]:    2721600 :               if (evaluable)
     803                 :            :               {
     804                 :      12728 :                 evaluableSet.insert(tb);
     805                 :            :               }
     806                 :            :               // If assignable, remember there is an equivalence class that is
     807                 :            :               // not assigned and assignable.
     808         [ +  + ]:    2721600 :               if (assignableEqc.find(*i2) != assignableEqc.end())
     809                 :            :               {
     810                 :    2708980 :                 unassignedAssignable = true;
     811                 :            :               }
     812                 :            :             }
     813                 :            :           }
     814                 :            :         }
     815                 :            : 
     816                 :            :         // 2. Normalize any non-const representative terms for this type
     817                 :     787583 :         set<Node>* repSet = typeRepSet.getSet(t);
     818 [ +  + ][ +  + ]:     787583 :         if (repSet != NULL && !repSet->empty())
                 [ +  + ]
     819                 :            :         {
     820         [ +  - ]:     659194 :           Trace("model-builder")
     821                 :     329597 :               << "  Normalization phase, working on type: " << t << endl;
     822                 :     329597 :           d_normalizedCache.clear();
     823         [ +  + ]:    2738040 :           for (i = repSet->begin(); i != repSet->end();)
     824                 :            :           {
     825 [ -  + ][ -  + ]:    2408450 :             Assert(assertedReps.find(*i) != assertedReps.end());
                 [ -  - ]
     826                 :    4816890 :             Node rep = assertedReps[*i];
     827                 :    4816890 :             Node normalized = normalize(tm, rep, false);
     828         [ +  - ]:    4816890 :             Trace("model-builder")
     829                 :          0 :                 << "    Normalizing rep (" << rep << "), normalized to ("
     830                 :          0 :                 << normalized << ")"
     831 [ -  + ][ -  - ]:    2408450 :                 << ", isValue=" << tm->isValue(normalized) << std::endl;
     832         [ +  + ]:    2408450 :             if (tm->isValue(normalized))
     833                 :            :             {
     834                 :      72343 :               changed = true;
     835                 :      72343 :               typeConstSet.add(tb, normalized);
     836                 :      72343 :               assignConstantRep(tm, *i, normalized);
     837                 :      72343 :               assertedReps.erase(*i);
     838                 :      72343 :               i2 = i;
     839                 :      72343 :               ++i;
     840                 :      72343 :               repSet->erase(i2);
     841                 :            :             }
     842                 :            :             else
     843                 :            :             {
     844         [ +  + ]:    2336100 :               if (normalized != rep)
     845                 :            :               {
     846                 :      42396 :                 assertedReps[*i] = normalized;
     847                 :      42396 :                 changed = true;
     848                 :            :               }
     849                 :    2336100 :               ++i;
     850                 :            :             }
     851                 :            :           }
     852                 :            :         }
     853                 :            :       }
     854                 :            :     } while (changed);
     855                 :            : 
     856         [ +  + ]:     140442 :     if (!unassignedAssignable)
     857                 :            :     {
     858                 :      35036 :       break;
     859                 :            :     }
     860                 :            : 
     861                 :            :     // 3. Assign unassigned assignable EC's using type enumeration - assign a
     862                 :            :     // value *different* from all other EC's if the type is infinite
     863                 :            :     // Assign first value from type enumerator otherwise - for finite types, we
     864                 :            :     // rely on polite framework to ensure that EC's that have to be
     865                 :            :     // different are different.
     866                 :            : 
     867                 :            :     // Only make assignments on a type if:
     868                 :            :     // 1. there are no terms that share the same base type with un-normalized
     869                 :            :     // representatives
     870                 :            :     // 2. there are no terms that share teh same base type that are unevaluated
     871                 :            :     // evaluable terms
     872                 :            :     // Alternatively, if 2 or 3 don't hold but we are in a special
     873                 :            :     // deadlock-breaking mode where assignOne is true, go ahead and make one
     874                 :            :     // assignment
     875                 :     105406 :     changed = false;
     876                 :            :     // must iterate over the ordered type list to ensure that we do not
     877                 :            :     // enumerate values with subterms
     878                 :            :     //  having types that we are currently enumerating (when possible)
     879                 :            :     //  for example, this ensures we enumerate uninterpreted sort U before (List
     880                 :            :     //  of U) and (Array U U)
     881                 :            :     //  however, it does not break cyclic type dependencies for mutually
     882                 :            :     //  recursive datatypes, but this is handled
     883                 :            :     //  by recording all subterms of enumerated values in TypeSet::addSubTerms.
     884         [ +  + ]:     535255 :     for (type_it = type_list.begin(); type_it != type_list.end(); ++type_it)
     885                 :            :     {
     886                 :     429849 :       TypeNode t = *type_it;
     887                 :            :       // continue if there are no more equivalence classes of this type to
     888                 :            :       // assign
     889                 :     429849 :       std::set<Node>* noRepSetPtr = typeNoRepSet.getSet(t);
     890         [ +  + ]:     429849 :       if (noRepSetPtr == NULL)
     891                 :            :       {
     892                 :      37729 :         continue;
     893                 :            :       }
     894                 :     392120 :       set<Node>& noRepSet = *noRepSetPtr;
     895         [ +  + ]:     392120 :       if (noRepSet.empty())
     896                 :            :       {
     897                 :     223984 :         continue;
     898                 :            :       }
     899                 :            : 
     900                 :            :       // get properties of this type
     901                 :     168136 :       bool isCorecursive = false;
     902         [ +  + ]:     168136 :       if (t.isDatatype())
     903                 :            :       {
     904                 :     159517 :         const DType& dt = t.getDType();
     905                 :     159517 :         isCorecursive =
     906                 :     319034 :             dt.isCodatatype()
     907                 :     159517 :             && (!d_env.isFiniteType(t) || dt.isRecursiveSingleton(t));
     908                 :            :       }
     909                 :            : #ifdef CVC5_ASSERTIONS
     910                 :     168136 :       bool isUSortFiniteRestricted = false;
     911         [ +  + ]:     168136 :       if (options().quantifiers.finiteModelFind)
     912                 :            :       {
     913 [ +  + ][ +  + ]:      10558 :         isUSortFiniteRestricted = !t.isUninterpretedSort() && involvesUSort(t);
         [ +  + ][ -  - ]
     914                 :            :       }
     915                 :            : #endif
     916                 :            : 
     917                 :     168136 :       TypeNode tb = t;
     918         [ +  + ]:     168136 :       if (!assignOne)
     919                 :            :       {
     920                 :     117864 :         set<Node>* repSet = typeRepSet.getSet(tb);
     921 [ +  + ][ +  + ]:     117864 :         if (repSet != NULL && !repSet->empty())
                 [ +  + ]
     922                 :            :         {
     923                 :     107284 :           continue;
     924                 :            :         }
     925         [ +  + ]:      10580 :         if (evaluableSet.find(tb) != evaluableSet.end())
     926                 :            :         {
     927                 :       1646 :           continue;
     928                 :            :         }
     929                 :            :       }
     930         [ +  - ]:     118412 :       Trace("model-builder") << "  Assign phase, working on type: " << t
     931                 :      59206 :                              << endl;
     932                 :            :       bool assignable, evaluable CVC5_UNUSED;
     933                 :      59206 :       std::map<Node, Assigner>::iterator itAssigner;
     934                 :      59206 :       std::map<Node, Node>::iterator itAssignerM;
     935                 :      59206 :       set<Node>* repSet = typeRepSet.getSet(t);
     936         [ +  + ]:     104209 :       for (i = noRepSet.begin(); i != noRepSet.end();)
     937                 :            :       {
     938                 :      94503 :         i2 = i;
     939                 :      94503 :         ++i;
     940         [ +  + ]:      94503 :         if (evaluableEqc.find(*i2) != evaluableEqc.end())
     941                 :            :         {
     942                 :            :           // we never assign to evaluable equivalence classes
     943                 :       1823 :           continue;
     944                 :            :         }
     945                 :            :         // check whether it has an assigner object
     946                 :      92680 :         itAssignerM = eqcToAssignerMaster.find(*i2);
     947         [ +  + ]:      92680 :         if (itAssignerM != eqcToAssignerMaster.end())
     948                 :            :         {
     949                 :            :           // Take the master's assigner. Notice we don't care which order
     950                 :            :           // equivalence classes are assigned. For instance, the master can
     951                 :            :           // be assigned after one of its slaves.
     952                 :         35 :           itAssigner = eqcToAssigner.find(itAssignerM->second);
     953                 :            :         }
     954                 :            :         else
     955                 :            :         {
     956                 :      92645 :           itAssigner = eqcToAssigner.find(*i2);
     957                 :            :         }
     958         [ +  + ]:      92680 :         if (itAssigner != eqcToAssigner.end())
     959                 :            :         {
     960                 :         47 :           assignable = isAssignerActive(tm, itAssigner->second);
     961                 :            :         }
     962                 :            :         else
     963                 :            :         {
     964                 :      92633 :           assignable = assignableEqc.find(*i2) != assignableEqc.end();
     965                 :            :         }
     966         [ +  - ]:     185360 :         Trace("model-builder-debug")
     967                 :          0 :             << "    eqc " << *i2 << " is assignable=" << assignable
     968                 :      92680 :             << std::endl;
     969         [ +  - ]:      92680 :         if (assignable)
     970                 :            :         {
     971                 :            :           // this assertion ensures that if we are assigning to a term of
     972                 :            :           // Boolean type, then the term must be assignable.
     973                 :            :           // Note we only assign to terms of Boolean type if the term occurs in
     974                 :            :           // a singleton equivalence class; otherwise the term would have been
     975                 :            :           // in the equivalence class of true or false and would not need
     976                 :            :           // assigning.
     977                 :      92680 :           Assert(!t.isBoolean() || isAssignable(*i2));
     978                 :      92680 :           Node n;
     979         [ +  + ]:      92680 :           if (itAssigner != eqcToAssigner.end())
     980                 :            :           {
     981         [ +  - ]:         94 :             Trace("model-builder-debug")
     982                 :         47 :                 << "Get value from assigner for finite type..." << std::endl;
     983                 :            :             // if it has an assigner, get the value from the assigner.
     984                 :         47 :             n = itAssigner->second.getNextAssignment();
     985 [ -  + ][ -  + ]:         47 :             Assert(!n.isNull());
                 [ -  - ]
     986                 :            :           }
     987 [ +  + ][ +  + ]:      92633 :           else if (t.isUninterpretedSort() || !d_env.isFiniteType(t))
         [ +  + ][ +  + ]
                 [ -  - ]
     988                 :            :           {
     989                 :            :             // If its interpreted as infinite, we get a fresh value that does
     990                 :            :             // not occur in the model.
     991                 :            :             // Note we also consider uninterpreted sorts to be infinite here
     992                 :            :             // regardless of whether the cardinality class of t is
     993                 :            :             // CardinalityClass::INTERPRETED_FINITE.
     994                 :            :             // This is required because the UF solver does not explicitly
     995                 :            :             // assign uninterpreted constants to equivalence classes in its
     996                 :            :             // collectModelValues method. Doing so would have the same effect
     997                 :            :             // as running the code in this case.
     998                 :            :             bool success;
     999                 :         18 :             do
    1000                 :            :             {
    1001         [ +  - ]:     185028 :               Trace("model-builder-debug") << "Enumerate term of type " << t
    1002                 :      92514 :                                            << std::endl;
    1003                 :      92514 :               n = typeConstSet.nextTypeEnum(t);
    1004                 :            :               //--- AJR: this code checks whether n is a legal value
    1005 [ -  + ][ -  + ]:      92514 :               Assert(!n.isNull());
                 [ -  - ]
    1006                 :      92514 :               success = true;
    1007         [ +  - ]:     185028 :               Trace("model-builder-debug") << "Check if excluded : " << n
    1008                 :      92514 :                                            << std::endl;
    1009                 :            : #ifdef CVC5_ASSERTIONS
    1010         [ +  + ]:      92514 :               if (isUSortFiniteRestricted)
    1011                 :            :               {
    1012                 :            :                 // must not involve uninterpreted constants beyond cardinality
    1013                 :            :                 // bound (which assumed to coincide with #eqc)
    1014                 :            :                 // this is just an assertion now, since TypeEnumeratorProperties
    1015                 :            :                 // should ensure that only legal values are enumerated wrt this
    1016                 :            :                 // constraint.
    1017                 :       3256 :                 std::map<Node, bool> visited;
    1018                 :       3256 :                 success = !isExcludedUSortValue(eqc_usort_count, n, visited);
    1019         [ -  + ]:       3256 :                 if (!success)
    1020                 :            :                 {
    1021         [ -  - ]:          0 :                   Trace("model-builder")
    1022                 :          0 :                       << "Excluded value for " << t << " : " << n
    1023                 :          0 :                       << " due to out of range uninterpreted constant."
    1024                 :          0 :                       << std::endl;
    1025                 :            :                 }
    1026 [ -  + ][ -  + ]:       3256 :                 Assert(success);
                 [ -  - ]
    1027                 :            :               }
    1028                 :            : #endif
    1029 [ +  - ][ +  + ]:      92514 :               if (success && isCorecursive)
    1030                 :            :               {
    1031 [ +  + ][ +  + ]:         57 :                 if (repSet != NULL && !repSet->empty())
                 [ +  + ]
    1032                 :            :                 {
    1033                 :            :                   // in the case of codatatypes, check if it is in the set of
    1034                 :            :                   // values that we cannot assign
    1035                 :         48 :                   success = !isExcludedCdtValue(n, repSet, assertedReps, *i2);
    1036         [ +  + ]:         48 :                   if (!success)
    1037                 :            :                   {
    1038         [ +  - ]:         36 :                     Trace("model-builder")
    1039                 :          0 :                         << "Excluded value : " << n
    1040                 :          0 :                         << " due to alpha-equivalent codatatype expression."
    1041                 :         18 :                         << std::endl;
    1042                 :            :                   }
    1043                 :            :                 }
    1044                 :            :               }
    1045                 :            :               //---
    1046         [ +  + ]:      92514 :             } while (!success);
    1047 [ -  + ][ -  + ]:      92496 :             Assert(!n.isNull());
                 [ -  - ]
    1048                 :            :           }
    1049                 :            :           else
    1050                 :            :           {
    1051                 :            :             // Otherwise, we get the first value from the type enumerator.
    1052         [ +  - ]:        274 :             Trace("model-builder-debug")
    1053                 :        137 :                 << "Get first value from finite type..." << std::endl;
    1054                 :        137 :             TypeEnumerator te(t);
    1055                 :        137 :             n = *te;
    1056                 :            :           }
    1057         [ +  - ]:      92680 :           Trace("model-builder-debug") << "...got " << n << std::endl;
    1058                 :      92680 :           assignConstantRep(tm, *i2, n);
    1059                 :      92680 :           changed = true;
    1060                 :      92680 :           noRepSet.erase(i2);
    1061         [ +  + ]:      92680 :           if (assignOne)
    1062                 :            :           {
    1063                 :      49500 :             assignOne = false;
    1064                 :      49500 :             break;
    1065                 :            :           }
    1066                 :            :         }
    1067                 :            :       }
    1068                 :            :     }
    1069                 :            : 
    1070                 :            :     // Corner case - I'm not sure this can even happen - but it's theoretically
    1071                 :            :     // possible to have a cyclical dependency
    1072                 :            :     // in EC assignment/evaluation, e.g. EC1 = {a, b + 1}; EC2 = {b, a - 1}.  In
    1073                 :            :     // this case, neither one will get assigned because we are waiting
    1074                 :            :     // to be able to evaluate.  But we will never be able to evaluate because
    1075                 :            :     // the variables that need to be assigned are in
    1076                 :            :     // these same EC's.  In this case, repeat the whole fixed-point computation
    1077                 :            :     // with the difference that the first EC
    1078                 :            :     // that has both assignable and evaluable expressions will get assigned.
    1079         [ +  + ]:     105406 :     if (!changed)
    1080                 :            :     {
    1081         [ +  - ]:      49500 :       Trace("model-builder-debug") << "...must assign one" << std::endl;
    1082                 :            :       // Avoid infinite loops: if we are in a deadlock, we abort model building
    1083                 :            :       // unsuccessfully here.
    1084         [ -  + ]:      49500 :       if (assignOne)
    1085                 :            :       {
    1086                 :          0 :         Assert (false) << "Reached a deadlock during model construction";
    1087                 :            :         Trace("model-builder-debug") << "...avoid loop, fail" << std::endl;
    1088                 :            :         return false;
    1089                 :            :       }
    1090                 :      49500 :       assignOne = true;
    1091                 :            :     }
    1092                 :     105406 :   }
    1093                 :            : 
    1094                 :            : #ifdef CVC5_ASSERTIONS
    1095                 :            :   // Assert that all representatives have been converted to constants
    1096         [ +  + ]:      54663 :   for (it = typeRepSet.begin(); it != typeRepSet.end(); ++it)
    1097                 :            :   {
    1098                 :      19627 :     std::set<Node>& repSet = TypeSet::getSet(it);
    1099         [ -  + ]:      19627 :     if (!repSet.empty())
    1100                 :            :     {
    1101         [ -  - ]:          0 :       Trace("model-builder") << "***Non-empty repSet, size = " << repSet.size()
    1102                 :          0 :                              << ", repSet = " << repSet << endl;
    1103                 :          0 :       Trace("model-builder-debug") << tm->getEqualityEngine()->debugPrintEqc();
    1104                 :          0 :       Assert(false);
    1105                 :            :     }
    1106                 :            :   }
    1107                 :            : #endif /* CVC5_ASSERTIONS */
    1108                 :            : 
    1109         [ +  - ]:      35036 :   Trace("model-builder") << "Copy representatives to model..." << std::endl;
    1110                 :      35036 :   tm->d_reps.clear();
    1111                 :      35036 :   std::map<Node, Node>::iterator itMap;
    1112         [ +  + ]:    1197700 :   for (itMap = d_constantReps.begin(); itMap != d_constantReps.end(); ++itMap)
    1113                 :            :   {
    1114                 :            :     // The "constant" representative is a model value, which may be a lambda
    1115                 :            :     // if higher-order. We now can go back and normalize its subterms.
    1116                 :            :     // This is necessary if we assigned a lambda value whose body contains
    1117                 :            :     // a free constant symbol that was assigned in this method.
    1118                 :    2325320 :     Node normc = itMap->second;
    1119         [ +  + ]:    1162660 :     if (!normc.isConst())
    1120                 :            :     {
    1121                 :        470 :       normc = normalize(tm, normc, true);
    1122                 :            :     }
    1123                 :            :     // mark this as the final representative
    1124                 :    1162660 :     tm->assignRepresentative(itMap->first, normc, true);
    1125                 :            :   }
    1126                 :            : 
    1127         [ +  - ]:      35036 :   Trace("model-builder") << "Make sure ECs have reps..." << std::endl;
    1128                 :            :   // Make sure every EC has a rep
    1129         [ -  + ]:      35036 :   for (itMap = assertedReps.begin(); itMap != assertedReps.end(); ++itMap)
    1130                 :            :   {
    1131                 :          0 :     tm->assignRepresentative(itMap->first, itMap->second, false);
    1132                 :            :   }
    1133         [ +  + ]:      70697 :   for (it = typeNoRepSet.begin(); it != typeNoRepSet.end(); ++it)
    1134                 :            :   {
    1135                 :      35661 :     set<Node>& noRepSet = TypeSet::getSet(it);
    1136         [ +  + ]:      37957 :     for (const Node& node : noRepSet)
    1137                 :            :     {
    1138                 :       2296 :       tm->assignRepresentative(node, node, false);
    1139                 :            :     }
    1140                 :            :   }
    1141                 :            : 
    1142                 :            :   // modelBuilder-specific initialization
    1143         [ -  + ]:      35036 :   if (!processBuildModel(tm))
    1144                 :            :   {
    1145         [ -  - ]:          0 :     Trace("model-builder")
    1146                 :          0 :         << "TheoryEngineModelBuilder: fail process build model." << std::endl;
    1147                 :          0 :     return false;
    1148                 :            :   }
    1149         [ +  - ]:      35036 :   Trace("model-builder") << "TheoryEngineModelBuilder: success" << std::endl;
    1150                 :      35036 :   return true;
    1151                 :            : }
    1152                 :            : 
    1153                 :       4410 : void TheoryEngineModelBuilder::postProcessModel(bool incomplete, TheoryModel* m)
    1154                 :            : {
    1155                 :            :   // if we are incomplete, there is no guarantee on the model.
    1156                 :            :   // thus, we do not check the model here.
    1157         [ +  + ]:       4410 :   if (incomplete)
    1158                 :            :   {
    1159                 :       1861 :     return;
    1160                 :            :   }
    1161 [ -  + ][ -  + ]:       2549 :   Assert(m != nullptr);
                 [ -  - ]
    1162                 :            :   // debug-check the model if the checkModels() is enabled.
    1163         [ +  + ]:       2549 :   if (options().smt.debugCheckModels)
    1164                 :            :   {
    1165                 :        432 :     debugCheckModel(m);
    1166                 :            :   }
    1167                 :            : }
    1168                 :            : 
    1169                 :        432 : void TheoryEngineModelBuilder::debugCheckModel(TheoryModel* tm)
    1170                 :            : {
    1171                 :        432 :   eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(tm->d_equalityEngine);
    1172                 :        432 :   std::map<Node, Node>::iterator itMap;
    1173                 :            :   // Check that every term evaluates to its representative in the model
    1174                 :       8070 :   for (eqcs_i = eq::EqClassesIterator(tm->d_equalityEngine);
    1175         [ +  + ]:       8070 :        !eqcs_i.isFinished();
    1176                 :       7638 :        ++eqcs_i)
    1177                 :            :   {
    1178                 :            :     // eqc is the equivalence class representative
    1179                 :      15276 :     Node eqc = (*eqcs_i);
    1180                 :            :     // get the representative
    1181                 :      15276 :     Node rep = tm->getRepresentative(eqc);
    1182 [ +  + ][ -  + ]:       7638 :     if (!rep.isConst() && eqc.getType().isBoolean())
         [ +  + ][ -  + ]
                 [ -  - ]
    1183                 :            :     {
    1184                 :            :       // if Boolean, it does not necessarily have a constant representative, use
    1185                 :            :       // get value instead
    1186                 :          0 :       rep = tm->getValue(eqc);
    1187                 :          0 :       AlwaysAssert(rep.isConst());
    1188                 :            :     }
    1189                 :       7638 :     eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, tm->d_equalityEngine);
    1190         [ +  + ]:      37963 :     for (; !eqc_i.isFinished(); ++eqc_i)
    1191                 :            :     {
    1192                 :      60650 :       Node n = *eqc_i;
    1193 [ -  + ][ -  - ]:      60650 :       AlwaysAssert(rep.getType() == n.getType())
    1194                 :      30325 :           << "Representative " << rep << " of " << n
    1195 [ -  + ][ -  - ]:      30325 :           << " violates type constraints (" << rep.getType() << " and "
    1196 [ -  + ][ -  + ]:      30325 :           << n.getType() << ")";
                 [ -  - ]
    1197                 :      60650 :       Node val = tm->getValue(n);
    1198         [ +  + ]:      30325 :       if (val != rep)
    1199                 :            :       {
    1200                 :        432 :         std::stringstream err;
    1201                 :        216 :         err << "Failed representative check:" << std::endl
    1202                 :        216 :             << "n: " << n << std::endl
    1203                 :        432 :             << "getValue(n): " << val << std::endl
    1204                 :        216 :             << "rep: " << rep << std::endl;
    1205 [ -  + ][ -  - ]:        216 :         if (val.isConst() && rep.isConst())
                 [ -  + ]
    1206                 :            :         {
    1207                 :          0 :           AlwaysAssert(val == rep) << err.str();
    1208                 :            :         }
    1209         [ +  + ]:        216 :         else if (rewrite(val) != rewrite(rep))
    1210                 :            :         {
    1211                 :            :           // if it does not evaluate, it is just a warning, which may be the
    1212                 :            :           // case for non-constant values, e.g. lambdas. Furthermore we only
    1213                 :            :           // throw this warning if rewriting cannot show they are equal.
    1214                 :         37 :           warning() << err.str();
    1215                 :            :         }
    1216                 :            :       }
    1217                 :            :     }
    1218                 :            :   }
    1219                 :            : 
    1220                 :            :   // builder-specific debugging
    1221                 :        432 :   debugModel(tm);
    1222                 :        432 : }
    1223                 :            : 
    1224                 :    2928370 : Node TheoryEngineModelBuilder::normalize(TheoryModel* m, TNode r, bool evalOnly)
    1225                 :            : {
    1226                 :    2928370 :   std::map<Node, Node>::iterator itMap = d_constantReps.find(r);
    1227         [ +  + ]:    2928370 :   if (itMap != d_constantReps.end())
    1228                 :            :   {
    1229                 :         18 :     r = (*itMap).second;
    1230                 :            :     // if d_constantReps stores a constant, we are done, otherwise we process
    1231                 :            :     // it below.
    1232         [ -  + ]:         18 :     if (r.isConst())
    1233                 :            :     {
    1234                 :          0 :       return r;
    1235                 :            :     }
    1236                 :            :   }
    1237                 :    2928370 :   NodeMap::iterator it = d_normalizedCache.find(r);
    1238         [ +  + ]:    2928370 :   if (it != d_normalizedCache.end())
    1239                 :            :   {
    1240                 :      31820 :     return (*it).second;
    1241                 :            :   }
    1242         [ +  - ]:    2896550 :   Trace("model-builder-debug") << "do normalize on " << r << std::endl;
    1243                 :    5793110 :   Node retNode = r;
    1244         [ +  + ]:    2896550 :   if (r.getNumChildren() > 0)
    1245                 :            :   {
    1246                 :    2889040 :     std::vector<Node> children;
    1247         [ +  + ]:    2889040 :     if (r.getMetaKind() == kind::metakind::PARAMETERIZED)
    1248                 :            :     {
    1249                 :    2433610 :       children.push_back(r.getOperator());
    1250                 :            :     }
    1251         [ +  + ]:    8846790 :     for (size_t i = 0, nchild = r.getNumChildren(); i < nchild; ++i)
    1252                 :            :     {
    1253                 :   11915500 :       Node ri = r[i];
    1254                 :    5957740 :       bool recurse = true;
    1255         [ +  + ]:    5957740 :       if (!ri.isConst())
    1256                 :            :       {
    1257         [ +  + ]:    4443260 :         if (m->d_equalityEngine->hasTerm(ri))
    1258                 :            :         {
    1259                 :            :           itMap =
    1260                 :    4410140 :               d_constantReps.find(m->d_equalityEngine->getRepresentative(ri));
    1261         [ +  + ]:    4410140 :           if (itMap != d_constantReps.end())
    1262                 :            :           {
    1263                 :     791005 :             ri = (*itMap).second;
    1264         [ +  - ]:     791005 :             Trace("model-builder-debug") << i << ": const child " << ri << std::endl;
    1265                 :            :             // need to recurse if d_constantReps stores a non-constant
    1266                 :     791005 :             recurse = !ri.isConst();
    1267                 :            :           }
    1268         [ +  + ]:    3619130 :           else if (!evalOnly)
    1269                 :            :           {
    1270                 :    3546580 :             recurse = false;
    1271         [ +  - ]:    3546580 :             Trace("model-builder-debug") << i << ": keep " << ri << std::endl;
    1272                 :            :           }
    1273                 :            :         }
    1274                 :            :         else
    1275                 :            :         {
    1276         [ +  - ]:      33118 :           Trace("model-builder-debug") << i << ": no hasTerm " << ri << std::endl;
    1277                 :            :         }
    1278         [ +  + ]:    4443260 :         if (recurse)
    1279                 :            :         {
    1280                 :     105800 :           ri = normalize(m, ri, evalOnly);
    1281                 :            :         }
    1282                 :            :       }
    1283                 :    5957740 :       children.push_back(ri);
    1284                 :            :     }
    1285                 :    2889040 :     retNode = nodeManager()->mkNode(r.getKind(), children);
    1286                 :    2889040 :     retNode = rewrite(retNode);
    1287                 :            :   }
    1288                 :    2896550 :   d_normalizedCache[r] = retNode;
    1289                 :    2896550 :   return retNode;
    1290                 :            : }
    1291                 :            : 
    1292                 :       1566 : bool TheoryEngineModelBuilder::preProcessBuildModel(TheoryModel* m)
    1293                 :            : {
    1294                 :       1566 :   return true;
    1295                 :            : }
    1296                 :            : 
    1297                 :      34207 : bool TheoryEngineModelBuilder::processBuildModel(TheoryModel* m)
    1298                 :            : {
    1299         [ +  - ]:      34207 :   if (m->areFunctionValuesEnabled())
    1300                 :            :   {
    1301                 :      34207 :     assignFunctions(m);
    1302                 :            :   }
    1303                 :      34207 :   return true;
    1304                 :            : }
    1305                 :            : 
    1306                 :       2962 : void TheoryEngineModelBuilder::assignFunction(TheoryModel* m, Node f)
    1307                 :            : {
    1308 [ -  + ][ -  + ]:       2962 :   Assert(!logicInfo().isHigherOrder());
                 [ -  - ]
    1309                 :       5924 :   uf::UfModelTree ufmt(f);
    1310                 :            :   options::DefaultFunctionValueMode dfvm =
    1311                 :       2962 :       options().theory.defaultFunctionValueMode;
    1312                 :       5924 :   Node default_v;
    1313         [ +  + ]:      14459 :   for (size_t i = 0; i < m->d_uf_terms[f].size(); i++)
    1314                 :            :   {
    1315                 :      22994 :     Node un = m->d_uf_terms[f][i];
    1316                 :      22994 :     vector<TNode> children;
    1317                 :      11497 :     children.push_back(f);
    1318         [ +  - ]:      11497 :     Trace("model-builder-debug") << "  process term : " << un << std::endl;
    1319         [ +  + ]:      56133 :     for (size_t j = 0; j < un.getNumChildren(); ++j)
    1320                 :            :     {
    1321                 :      89272 :       Node rc = m->getRepresentative(un[j]);
    1322 [ +  - ][ -  + ]:      89272 :       Trace("model-builder-debug2") << "    get rep : " << un[j] << " returned "
                 [ -  - ]
    1323                 :      44636 :                                     << rc << std::endl;
    1324 [ -  + ][ -  + ]:      44636 :       Assert(rewrite(rc) == rc);
                 [ -  - ]
    1325                 :      44636 :       children.push_back(rc);
    1326                 :            :     }
    1327                 :      22994 :     Node simp = nodeManager()->mkNode(un.getKind(), children);
    1328                 :      22994 :     Node v = m->getRepresentative(un);
    1329         [ +  - ]:      22994 :     Trace("model-builder") << "  Setting (" << simp << ") to (" << v << ")"
    1330                 :      11497 :                            << endl;
    1331                 :      11497 :     ufmt.setValue(m, simp, v);
    1332         [ +  + ]:      11497 :     if (dfvm == options::DefaultFunctionValueMode::FIRST)
    1333                 :            :     {
    1334                 :      11491 :       default_v = v;
    1335                 :            :     }
    1336                 :            :   }
    1337                 :       5924 :   TypeNode rangeType = f.getType().getRangeType();
    1338         [ +  + ]:       2962 :   if (dfvm == options::DefaultFunctionValueMode::HOLE)
    1339                 :            :   {
    1340                 :          2 :     NodeManager* nm = nodeManager();
    1341                 :          2 :     SkolemManager* sm = nm->getSkolemManager();
    1342                 :          2 :     std::vector<Node> cacheVals;
    1343                 :          2 :     cacheVals.push_back(nm->mkConst(SortToTerm(rangeType)));
    1344                 :          2 :     default_v = sm->mkSkolemFunction(SkolemId::GROUND_TERM, cacheVals);
    1345                 :            :   }
    1346         [ +  + ]:       2960 :   else if (default_v.isNull())
    1347                 :            :   {
    1348                 :            :     // choose default value from model if none exists
    1349                 :          2 :     TypeEnumerator te(rangeType);
    1350                 :          2 :     default_v = (*te);
    1351                 :            :   }
    1352                 :       2962 :   ufmt.setDefaultValue(m, default_v);
    1353                 :       2962 :   bool condenseFuncValues = options().theory.condenseFunctionValues;
    1354         [ +  - ]:       2962 :   if (condenseFuncValues)
    1355                 :            :   {
    1356                 :       2962 :     ufmt.simplify();
    1357                 :            :   }
    1358                 :       5924 :   std::stringstream ss;
    1359                 :       2962 :   ss << "_arg_";
    1360         [ +  - ]:       2962 :   Rewriter* r = condenseFuncValues ? d_env.getRewriter() : nullptr;
    1361                 :       2962 :   Node val = ufmt.getFunctionValue(ss.str(), r);
    1362         [ +  - ]:       2962 :   Trace("model-builder-debug") << "...assign via function" << std::endl;
    1363                 :       2962 :   m->assignFunctionDefinition(f, val);
    1364                 :            :   // ufmt.debugPrint( std::cout, m );
    1365                 :       2962 : }
    1366                 :            : 
    1367                 :       2296 : void TheoryEngineModelBuilder::assignHoFunction(TheoryModel* m, Node f)
    1368                 :            : {
    1369 [ -  + ][ -  + ]:       2296 :   Assert(logicInfo().isHigherOrder());
                 [ -  - ]
    1370                 :       4592 :   TypeNode type = f.getType();
    1371                 :       4592 :   std::vector<TypeNode> argTypes = type.getArgTypes();
    1372                 :       4592 :   std::vector<Node> args;
    1373                 :       4592 :   std::vector<TNode> apply_args;
    1374                 :            :   options::DefaultFunctionValueMode dfvm =
    1375                 :       2296 :       options().theory.defaultFunctionValueMode;
    1376         [ +  + ]:       5024 :   for (unsigned i = 0; i < argTypes.size(); i++)
    1377                 :            :   {
    1378                 :       5456 :     Node v = nodeManager()->mkBoundVar(argTypes[i]);
    1379                 :       2728 :     args.push_back(v);
    1380         [ +  + ]:       2728 :     if (i > 0)
    1381                 :            :     {
    1382                 :        432 :       apply_args.push_back(v);
    1383                 :            :     }
    1384                 :            :   }
    1385                 :            :   // Depending on the default value mode, maybe set the current value (curr).
    1386                 :            :   // We also remember a default value (currPre) in case there are no terms
    1387                 :            :   // to assign below.
    1388                 :       4592 :   TypeNode rangeType = type.getRangeType();
    1389                 :       4592 :   Node curr, currPre;
    1390         [ -  + ]:       2296 :   if (dfvm == options::DefaultFunctionValueMode::HOLE)
    1391                 :            :   {
    1392                 :          0 :     NodeManager* nm = nodeManager();
    1393                 :          0 :     SkolemManager* sm = nm->getSkolemManager();
    1394                 :          0 :     std::vector<Node> cacheVals;
    1395                 :          0 :     cacheVals.push_back(nm->mkConst(SortToTerm(rangeType)));
    1396                 :          0 :     currPre = sm->mkSkolemFunction(SkolemId::GROUND_TERM, cacheVals);
    1397                 :          0 :     curr = currPre;
    1398                 :            :   }
    1399                 :            :   else
    1400                 :            :   {
    1401                 :       4592 :     TypeEnumerator te(rangeType);
    1402                 :       2296 :     currPre = (*te);
    1403         [ -  + ]:       2296 :     if (dfvm == options::DefaultFunctionValueMode::FIRST_ENUM)
    1404                 :            :     {
    1405                 :          0 :       curr = currPre;
    1406                 :            :     }
    1407                 :            :   }
    1408                 :       2296 :   curr = currPre;
    1409                 :       2296 :   std::map<Node, std::vector<Node> >::iterator itht = m->d_ho_uf_terms.find(f);
    1410         [ +  - ]:       2296 :   if (itht != m->d_ho_uf_terms.end())
    1411                 :            :   {
    1412         [ +  + ]:      21971 :     for (size_t i = 0; i < itht->second.size(); i++)
    1413                 :            :     {
    1414                 :      39350 :       Node hn = itht->second[i];
    1415         [ +  - ]:      19675 :       Trace("model-builder-debug") << "    process : " << hn << std::endl;
    1416 [ -  + ][ -  + ]:      19675 :       Assert(hn.getKind() == Kind::HO_APPLY);
                 [ -  - ]
    1417 [ -  + ][ -  + ]:      19675 :       Assert(m->areEqual(hn[0], f));
                 [ -  - ]
    1418                 :      59025 :       Node hni = m->getRepresentative(hn[1]);
    1419         [ +  - ]:      39350 :       Trace("model-builder-debug2")
    1420 [ -  + ][ -  - ]:      19675 :           << "      get rep : " << hn[1] << " returned " << hni << std::endl;
    1421 [ -  + ][ -  + ]:      19675 :       Assert(hni.getType() == args[0].getType());
                 [ -  - ]
    1422                 :      19675 :       hni = rewrite(args[0].eqNode(hni));
    1423                 :      39350 :       Node hnv = m->getRepresentative(hn);
    1424         [ +  - ]:      39350 :       Trace("model-builder-debug2") << "      get rep val : " << hn
    1425                 :      19675 :                                     << " returned " << hnv << std::endl;
    1426                 :            :       // hnv is expected to be constant but may not be the case if e.g. a non-trivial
    1427                 :            :       // lambda is given as argument to this function.
    1428         [ +  + ]:      19675 :       if (!apply_args.empty())
    1429                 :            :       {
    1430                 :            :         // Convert to lambda, which is necessary if hnv is a function array
    1431                 :            :         // constant.
    1432                 :       1244 :         hnv = uf::FunctionConst::toLambda(hnv);
    1433                 :       2488 :         Assert(!hnv.isNull() && hnv.getKind() == Kind::LAMBDA
    1434                 :            :                && hnv[0].getNumChildren() + 1 == args.size());
    1435                 :       1244 :         std::vector<TNode> largs;
    1436         [ +  + ]:       2531 :         for (unsigned j = 0; j < hnv[0].getNumChildren(); j++)
    1437                 :            :         {
    1438                 :       1287 :           largs.push_back(hnv[0][j]);
    1439                 :            :         }
    1440 [ -  + ][ -  + ]:       1244 :         Assert(largs.size() == apply_args.size());
                 [ -  - ]
    1441                 :       2488 :         hnv = hnv[1].substitute(
    1442                 :       1244 :             largs.begin(), largs.end(), apply_args.begin(), apply_args.end());
    1443                 :       1244 :         hnv = rewrite(hnv);
    1444                 :            :       }
    1445 [ -  + ][ -  + ]:      19675 :       Assert(hnv.getType() == curr.getType());
                 [ -  - ]
    1446         [ -  + ]:      19675 :       if (curr.isNull())
    1447                 :            :       {
    1448                 :          0 :         curr = hnv;
    1449                 :            :       }
    1450                 :            :       else
    1451                 :            :       {
    1452                 :      19675 :         curr = nodeManager()->mkNode(Kind::ITE, hni, hnv, curr);
    1453                 :            :       }
    1454                 :            :     }
    1455                 :            :   }
    1456                 :            :   // if curr was not set, we set it to currPre.
    1457         [ -  + ]:       2296 :   if (curr.isNull())
    1458                 :            :   {
    1459                 :          0 :     curr = currPre;
    1460                 :            :   }
    1461                 :       2296 :   Node val = nodeManager()->mkNode(
    1462                 :       4592 :       Kind::LAMBDA, nodeManager()->mkNode(Kind::BOUND_VAR_LIST, args), curr);
    1463         [ +  - ]:       2296 :   Trace("model-builder-debug") << "...assign via ho function" << std::endl;
    1464                 :       2296 :   m->assignFunctionDefinition(f, val);
    1465                 :       2296 : }
    1466                 :            : 
    1467                 :      35036 : void TheoryEngineModelBuilder::assignFunctions(TheoryModel* m)
    1468                 :            : {
    1469         [ -  + ]:      35036 :   if (!options().theory.assignFunctionValues)
    1470                 :            :   {
    1471                 :          0 :     return;
    1472                 :            :   }
    1473         [ +  - ]:      35036 :   Trace("model-builder") << "Assigning function values..." << std::endl;
    1474                 :      35036 :   std::vector<Node> funcs_to_assign = m->getFunctionsToAssign();
    1475                 :            : 
    1476         [ +  + ]:      35036 :   if (logicInfo().isHigherOrder())
    1477                 :            :   {
    1478                 :            :     // sort based on type size if higher-order
    1479         [ +  - ]:        858 :     Trace("model-builder") << "Sort functions by type..." << std::endl;
    1480                 :        858 :     SortTypeSize sts;
    1481                 :        858 :     std::sort(funcs_to_assign.begin(), funcs_to_assign.end(), sts);
    1482                 :            :   }
    1483                 :            : 
    1484         [ -  + ]:      35036 :   if (TraceIsOn("model-builder"))
    1485                 :            :   {
    1486         [ -  - ]:          0 :     Trace("model-builder") << "...have " << funcs_to_assign.size()
    1487                 :          0 :                            << " functions to assign:" << std::endl;
    1488         [ -  - ]:          0 :     for (unsigned k = 0; k < funcs_to_assign.size(); k++)
    1489                 :            :     {
    1490                 :          0 :       Node f = funcs_to_assign[k];
    1491         [ -  - ]:          0 :       Trace("model-builder") << "  [" << k << "] : " << f << " : "
    1492                 :          0 :                              << f.getType() << std::endl;
    1493                 :            :     }
    1494                 :            :   }
    1495                 :            : 
    1496                 :            :   // construct function values
    1497         [ +  + ]:      40294 :   for (unsigned k = 0; k < funcs_to_assign.size(); k++)
    1498                 :            :   {
    1499                 :      10516 :     Node f = funcs_to_assign[k];
    1500         [ +  - ]:       5258 :     Trace("model-builder") << "  Function #" << k << " is " << f << std::endl;
    1501         [ +  + ]:       5258 :     if (!logicInfo().isHigherOrder())
    1502                 :            :     {
    1503         [ +  - ]:       5924 :       Trace("model-builder") << "  Assign function value for " << f
    1504                 :       2962 :                              << " based on APPLY_UF" << std::endl;
    1505                 :       2962 :       assignFunction(m, f);
    1506                 :            :     }
    1507                 :            :     else
    1508                 :            :     {
    1509         [ +  - ]:       4592 :       Trace("model-builder") << "  Assign function value for " << f
    1510                 :       2296 :                              << " based on curried HO_APPLY" << std::endl;
    1511                 :       2296 :       assignHoFunction(m, f);
    1512                 :            :     }
    1513                 :            :   }
    1514         [ +  - ]:      35036 :   Trace("model-builder") << "Finished assigning function values." << std::endl;
    1515                 :            : }
    1516                 :            : 
    1517                 :            : }  // namespace theory
    1518                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14