LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory/uf - cardinality_extension.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 850 1060 80.2 %
Date: 2026-07-07 10:35:32 Functions: 54 67 80.6 %
Branches: 582 998 58.3 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * This file is part of the cvc5 project.
       3                 :            :  *
       4                 :            :  * Copyright (c) 2009-2026 by the authors listed in the file AUTHORS
       5                 :            :  * in the top-level source directory and their institutional affiliations.
       6                 :            :  * All rights reserved.  See the file COPYING in the top-level source
       7                 :            :  * directory for licensing information.
       8                 :            :  * ****************************************************************************
       9                 :            :  *
      10                 :            :  * Implementation of theory of UF with cardinality.
      11                 :            :  */
      12                 :            : 
      13                 :            : #include "theory/uf/cardinality_extension.h"
      14                 :            : 
      15                 :            : #include <sstream>
      16                 :            : 
      17                 :            : #include "expr/cardinality_constraint.h"
      18                 :            : #include "expr/skolem_manager.h"
      19                 :            : #include "options/smt_options.h"
      20                 :            : #include "options/uf_options.h"
      21                 :            : #include "smt/logic_exception.h"
      22                 :            : #include "theory/decision_manager.h"
      23                 :            : #include "theory/quantifiers/term_database.h"
      24                 :            : #include "theory/quantifiers_engine.h"
      25                 :            : #include "theory/theory_engine.h"
      26                 :            : #include "theory/theory_model.h"
      27                 :            : #include "theory/uf/equality_engine.h"
      28                 :            : #include "theory/uf/theory_uf.h"
      29                 :            : #include "util/rational.h"
      30                 :            : 
      31                 :            : using namespace std;
      32                 :            : using namespace cvc5::internal::kind;
      33                 :            : using namespace cvc5::context;
      34                 :            : 
      35                 :            : namespace cvc5::internal {
      36                 :            : namespace theory {
      37                 :            : namespace uf {
      38                 :            : 
      39                 :            : /* These are names are unambigious are we use abbreviations. */
      40                 :            : typedef CardinalityExtension::SortModel SortModel;
      41                 :            : typedef SortModel::Region Region;
      42                 :            : typedef Region::RegionNodeInfo RegionNodeInfo;
      43                 :            : typedef RegionNodeInfo::DiseqList DiseqList;
      44                 :            : 
      45                 :       3842 : Region::Region(SortModel* cf, context::Context* c)
      46                 :       3842 :     : d_cf(cf),
      47                 :          0 :       d_testCliqueSize(c, 0),
      48                 :       3842 :       d_splitsSize(c, 0),
      49                 :       3842 :       d_testClique(c),
      50                 :       3842 :       d_splits(c),
      51                 :       3842 :       d_reps_size(c, 0),
      52                 :       3842 :       d_total_diseq_external(c, 0),
      53                 :       3842 :       d_total_diseq_internal(c, 0),
      54                 :       7684 :       d_valid(c, true)
      55                 :            : {
      56                 :       3842 : }
      57                 :            : 
      58                 :       7676 : Region::~Region()
      59                 :            : {
      60         [ +  + ]:      18587 :   for (iterator i = begin(), iend = end(); i != iend; ++i)
      61                 :            :   {
      62                 :      14749 :     RegionNodeInfo* regionNodeInfo = (*i).second;
      63         [ +  - ]:      14749 :     delete regionNodeInfo;
      64                 :            :   }
      65                 :       3838 :   d_nodes.clear();
      66                 :       7676 : }
      67                 :            : 
      68                 :       7678 : void Region::addRep(Node n) { setRep(n, true); }
      69                 :            : 
      70                 :        983 : void Region::takeNode(Region* r, Node n)
      71                 :            : {
      72 [ -  + ][ -  + ]:        983 :   Assert(!hasRep(n));
                 [ -  - ]
      73 [ -  + ][ -  + ]:        983 :   Assert(r->hasRep(n));
                 [ -  - ]
      74                 :            :   // add representative
      75                 :        983 :   setRep(n, true);
      76                 :            :   // take disequalities from r
      77                 :        983 :   RegionNodeInfo* rni = r->d_nodes[n];
      78         [ +  + ]:       2949 :   for (int t = 0; t < 2; t++)
      79                 :            :   {
      80                 :       1966 :     DiseqList* del = rni->get(t);
      81         [ +  + ]:       5166 :     for (DiseqList::iterator it = del->begin(); it != del->end(); ++it)
      82                 :            :     {
      83         [ +  + ]:       3200 :       if ((*it).second)
      84                 :            :       {
      85                 :       2003 :         r->setDisequal(n, (*it).first, t, false);
      86         [ +  + ]:       2003 :         if (t == 0)
      87                 :            :         {
      88         [ +  + ]:        846 :           if (hasRep((*it).first))
      89                 :            :           {
      90                 :        725 :             setDisequal((*it).first, n, 0, false);
      91                 :        725 :             setDisequal((*it).first, n, 1, true);
      92                 :        725 :             setDisequal(n, (*it).first, 1, true);
      93                 :            :           }
      94                 :            :           else
      95                 :            :           {
      96                 :        121 :             setDisequal(n, (*it).first, 0, true);
      97                 :            :           }
      98                 :            :         }
      99                 :            :         else
     100                 :            :         {
     101                 :       1157 :           r->setDisequal((*it).first, n, 1, false);
     102                 :       1157 :           r->setDisequal((*it).first, n, 0, true);
     103                 :       1157 :           setDisequal(n, (*it).first, 0, true);
     104                 :            :         }
     105                 :            :       }
     106                 :            :     }
     107                 :            :   }
     108                 :            :   // remove representative
     109                 :        983 :   r->setRep(n, false);
     110                 :        983 : }
     111                 :            : 
     112                 :      61417 : void Region::combine(Region* r)
     113                 :            : {
     114                 :            :   // take all nodes from r
     115         [ +  + ]:     341008 :   for (Region::iterator it = r->d_nodes.begin(); it != r->d_nodes.end(); ++it)
     116                 :            :   {
     117         [ +  + ]:     279591 :     if (it->second->valid())
     118                 :            :     {
     119                 :      65240 :       setRep(it->first, true);
     120                 :            :     }
     121                 :            :   }
     122         [ +  + ]:     341008 :   for (Region::iterator it = r->d_nodes.begin(); it != r->d_nodes.end(); ++it)
     123                 :            :   {
     124         [ +  + ]:     279591 :     if (it->second->valid())
     125                 :            :     {
     126                 :            :       // take disequalities from r
     127                 :      65240 :       Node n = it->first;
     128                 :      65240 :       RegionNodeInfo* rni = it->second;
     129         [ +  + ]:     195720 :       for (int t = 0; t < 2; t++)
     130                 :            :       {
     131                 :     130480 :         RegionNodeInfo::DiseqList* del = rni->get(t);
     132                 :     260960 :         for (RegionNodeInfo::DiseqList::iterator it2 = del->begin(),
     133                 :     130480 :                                                  it2end = del->end();
     134         [ +  + ]:     320647 :              it2 != it2end;
     135                 :     190167 :              ++it2)
     136                 :            :         {
     137         [ +  + ]:     190167 :           if ((*it2).second)
     138                 :            :           {
     139 [ +  + ][ +  + ]:     176190 :             if (t == 0 && hasRep((*it2).first))
         [ +  + ][ +  + ]
                 [ -  - ]
     140                 :            :             {
     141                 :      84479 :               setDisequal((*it2).first, n, 0, false);
     142                 :      84479 :               setDisequal((*it2).first, n, 1, true);
     143                 :      84479 :               setDisequal(n, (*it2).first, 1, true);
     144                 :            :             }
     145                 :            :             else
     146                 :            :             {
     147                 :      91711 :               setDisequal(n, (*it2).first, t, true);
     148                 :            :             }
     149                 :            :           }
     150                 :            :         }
     151                 :            :       }
     152                 :      65240 :     }
     153                 :            :   }
     154                 :      61417 :   r->d_valid = false;
     155                 :      61417 : }
     156                 :            : 
     157                 :            : /** setEqual */
     158                 :      48920 : void Region::setEqual(Node a, Node b)
     159                 :            : {
     160                 :      48920 :   Assert(hasRep(a) && hasRep(b));
     161                 :            :   // move disequalities of b over to a
     162         [ +  + ]:     146760 :   for (int t = 0; t < 2; t++)
     163                 :            :   {
     164                 :      97840 :     DiseqList* del = d_nodes[b]->get(t);
     165         [ +  + ]:     200433 :     for (DiseqList::iterator it = del->begin(); it != del->end(); ++it)
     166                 :            :     {
     167         [ +  + ]:     102593 :       if ((*it).second)
     168                 :            :       {
     169                 :      69335 :         Node n = (*it).first;
     170                 :            :         // get the region that contains the endpoint of the disequality b != ...
     171                 :      69335 :         Region* nr = d_cf->d_regions[d_cf->d_regions_map[n]];
     172         [ +  + ]:      69335 :         if (!isDisequal(a, n, t))
     173                 :            :         {
     174                 :      31640 :           setDisequal(a, n, t, true);
     175                 :      31640 :           nr->setDisequal(n, a, t, true);
     176                 :            :         }
     177                 :      69335 :         setDisequal(b, n, t, false);
     178                 :      69335 :         nr->setDisequal(n, b, t, false);
     179                 :      69335 :       }
     180                 :            :     }
     181                 :            :   }
     182                 :            :   // remove b from representatives
     183                 :      48920 :   setRep(b, false);
     184                 :      48920 : }
     185                 :            : 
     186                 :     597840 : void Region::setDisequal(Node n1, Node n2, int type, bool valid)
     187                 :            : {
     188                 :            :   // Trace("uf-ss-region-debug") << "set disequal " << n1 << " " << n2 << " "
     189                 :            :   //                             << type << " " << valid << std::endl;
     190                 :            :   // debugPrint("uf-ss-region-debug");
     191                 :            :   // Assert( isDisequal( n1, n2, type )!=valid );
     192         [ +  + ]:     597840 :   if (isDisequal(n1, n2, type) != valid)
     193                 :            :   {  // DO_THIS: make assertion
     194                 :     596313 :     d_nodes[n1]->get(type)->setDisequal(n2, valid);
     195         [ +  + ]:     596313 :     if (type == 0)
     196                 :            :     {
     197         [ +  + ]:     249742 :       d_total_diseq_external = d_total_diseq_external + (valid ? 1 : -1);
     198                 :            :     }
     199                 :            :     else
     200                 :            :     {
     201         [ +  + ]:     346571 :       d_total_diseq_internal = d_total_diseq_internal + (valid ? 1 : -1);
     202         [ +  + ]:     346571 :       if (valid)
     203                 :            :       {
     204                 :            :         // if they are both a part of testClique, then remove split
     205         [ +  - ]:     231989 :         if (d_testClique.find(n1) != d_testClique.end() && d_testClique[n1]
     206 [ +  + ][ +  + ]:     231989 :             && d_testClique.find(n2) != d_testClique.end() && d_testClique[n2])
         [ +  - ][ +  + ]
     207                 :            :         {
     208                 :       4802 :           Node eq = NodeManager::mkNode(Kind::EQUAL, n1, n2);
     209 [ +  + ][ +  - ]:       2401 :           if (d_splits.find(eq) != d_splits.end() && d_splits[eq])
                 [ +  + ]
     210                 :            :           {
     211         [ +  - ]:       2370 :             Trace("uf-ss-debug")
     212                 :       1185 :                 << "removing split for " << n1 << " " << n2 << std::endl;
     213                 :       1185 :             d_splits[eq] = false;
     214                 :       1185 :             d_splitsSize = d_splitsSize - 1;
     215                 :            :           }
     216                 :       2401 :         }
     217                 :            :       }
     218                 :            :     }
     219                 :            :   }
     220                 :     597840 : }
     221                 :            : 
     222                 :     123804 : void Region::setRep(Node n, bool valid)
     223                 :            : {
     224 [ -  + ][ -  + ]:     123804 :   Assert(hasRep(n) != valid);
                 [ -  - ]
     225 [ +  + ][ +  + ]:     123804 :   if (valid && d_nodes.find(n) == d_nodes.end())
                 [ +  + ]
     226                 :            :   {
     227                 :      14755 :     d_nodes[n] = new RegionNodeInfo(d_cf->d_thss->context());
     228                 :            :   }
     229                 :     123804 :   d_nodes[n]->setValid(valid);
     230         [ +  + ]:     123804 :   d_reps_size = d_reps_size + (valid ? 1 : -1);
     231                 :            :   // removing a member of the test clique from this region
     232 [ +  + ][ +  - ]:     123804 :   if (d_testClique.find(n) != d_testClique.end() && d_testClique[n])
                 [ +  + ]
     233                 :            :   {
     234 [ -  + ][ -  + ]:       2358 :     Assert(!valid);
                 [ -  - ]
     235                 :       2358 :     d_testClique[n] = false;
     236                 :       2358 :     d_testCliqueSize = d_testCliqueSize - 1;
     237                 :            :     // remove all splits involving n
     238         [ +  + ]:      22547 :     for (split_iterator it = begin_splits(); it != end_splits(); ++it)
     239                 :            :     {
     240         [ +  + ]:      20189 :       if ((*it).second)
     241                 :            :       {
     242                 :       6284 :         if ((*it).first[0] == n || (*it).first[1] == n)
     243                 :            :         {
     244                 :       6230 :           d_splits[(*it).first] = false;
     245                 :       6230 :           d_splitsSize = d_splitsSize - 1;
     246                 :            :         }
     247                 :            :       }
     248                 :            :     }
     249                 :            :   }
     250                 :     123804 : }
     251                 :            : 
     252                 :     740042 : bool Region::isDisequal(Node n1, Node n2, int type)
     253                 :            : {
     254                 :     740042 :   RegionNodeInfo::DiseqList* del = d_nodes[n1]->get(type);
     255                 :     740042 :   return del->isSet(n2) && del->getDisequalityValue(n2);
     256                 :            : }
     257                 :            : 
     258                 :            : struct sortInternalDegree
     259                 :            : {
     260                 :            :   Region* r;
     261                 :      23748 :   bool operator()(Node i, Node j)
     262                 :            :   {
     263                 :      47496 :     return (r->getRegionInfo(i)->getNumInternalDisequalities()
     264                 :      47496 :             > r->getRegionInfo(j)->getNumInternalDisequalities());
     265                 :            :   }
     266                 :            : };
     267                 :            : 
     268                 :            : struct sortExternalDegree
     269                 :            : {
     270                 :            :   Region* r;
     271                 :            :   bool operator()(Node i, Node j)
     272                 :            :   {
     273                 :            :     return (r->getRegionInfo(i)->getNumExternalDisequalities()
     274                 :            :             > r->getRegionInfo(j)->getNumExternalDisequalities());
     275                 :            :   }
     276                 :            : };
     277                 :            : 
     278                 :            : int gmcCount = 0;
     279                 :            : 
     280                 :     147306 : bool Region::getMustCombine(int cardinality)
     281                 :            : {
     282         [ +  + ]:     147306 :   if (d_total_diseq_external >= static_cast<unsigned>(cardinality))
     283                 :            :   {
     284                 :            :     // The number of external disequalities is greater than or equal to
     285                 :            :     // cardinality.  Thus, a clique of size cardinality+1 may exist
     286                 :            :     // between nodes in d_regions[i] and other regions Check if this is
     287                 :            :     // actually the case: must have n nodes with outgoing degree
     288                 :            :     //(cardinality+1-n) for some n>0
     289                 :      24833 :     std::vector<int> degrees;
     290         [ +  + ]:     226831 :     for (Region::iterator it = begin(); it != end(); ++it)
     291                 :            :     {
     292                 :     216293 :       RegionNodeInfo* rni = it->second;
     293         [ +  + ]:     216293 :       if (rni->valid())
     294                 :            :       {
     295         [ +  + ]:     100506 :         if (rni->getNumDisequalities() >= cardinality)
     296                 :            :         {
     297                 :      75241 :           int outDeg = rni->getNumExternalDisequalities();
     298         [ +  + ]:      75241 :           if (outDeg >= cardinality)
     299                 :            :           {
     300                 :            :             // we have 1 node of degree greater than (cardinality)
     301                 :      14295 :             return true;
     302                 :            :           }
     303         [ +  + ]:      62314 :           else if (outDeg >= 1)
     304                 :            :           {
     305                 :      53956 :             degrees.push_back(outDeg);
     306         [ +  + ]:      53956 :             if ((int)degrees.size() >= cardinality)
     307                 :            :             {
     308                 :            :               // we have (cardinality) nodes of degree 1
     309                 :       1368 :               return true;
     310                 :            :             }
     311                 :            :           }
     312                 :            :         }
     313                 :            :       }
     314                 :            :     }
     315                 :      10538 :     gmcCount++;
     316         [ +  + ]:      10538 :     if (gmcCount % 100 == 0)
     317                 :            :     {
     318         [ +  - ]:        166 :       Trace("gmc-count") << gmcCount << " " << cardinality
     319                 :         83 :                          << " sample : " << degrees.size() << std::endl;
     320                 :            :     }
     321                 :            :     // this should happen relatively infrequently....
     322                 :      10538 :     std::sort(degrees.begin(), degrees.end());
     323         [ +  + ]:      54505 :     for (int i = 0; i < (int)degrees.size(); i++)
     324                 :            :     {
     325         [ +  + ]:      45408 :       if (degrees[i] >= cardinality + 1 - ((int)degrees.size() - i))
     326                 :            :       {
     327                 :       1441 :         return true;
     328                 :            :       }
     329                 :            :     }
     330         [ +  + ]:      24833 :   }
     331                 :     131570 :   return false;
     332                 :            : }
     333                 :            : 
     334                 :    1144478 : bool Region::check(Theory::Effort level,
     335                 :            :                    int cardinality,
     336                 :            :                    std::vector<Node>& clique)
     337                 :            : {
     338         [ +  + ]:    1144478 :   if (d_reps_size > unsigned(cardinality))
     339                 :            :   {
     340         [ +  + ]:     116033 :     if (d_total_diseq_internal == d_reps_size * (d_reps_size - 1))
     341                 :            :     {
     342         [ +  + ]:      68176 :       if (d_reps_size > 1)
     343                 :            :       {
     344                 :            :         // quick clique check, all reps form a clique
     345         [ +  + ]:      37128 :         for (iterator it = begin(); it != end(); ++it)
     346                 :            :         {
     347         [ +  + ]:      32622 :           if (it->second->valid())
     348                 :            :           {
     349                 :      22061 :             clique.push_back(it->first);
     350                 :            :           }
     351                 :            :         }
     352         [ +  - ]:       4506 :         Trace("quick-clique") << "Found quick clique" << std::endl;
     353                 :       4506 :         return true;
     354                 :            :       }
     355                 :            :       else
     356                 :            :       {
     357                 :      63670 :         return false;
     358                 :            :       }
     359                 :            :     }
     360         [ +  + ]:      47857 :     else if (level == Theory::EFFORT_FULL)
     361                 :            :     {
     362                 :            :       // build test clique, up to size cardinality+1
     363         [ +  + ]:       2985 :       if (d_testCliqueSize <= unsigned(cardinality))
     364                 :            :       {
     365                 :       2865 :         std::vector<Node> newClique;
     366         [ +  + ]:       2865 :         if (d_testCliqueSize < unsigned(cardinality))
     367                 :            :         {
     368         [ +  + ]:      22595 :           for (iterator it = begin(); it != end(); ++it)
     369                 :            :           {
     370                 :            :             // if not in the test clique, add it to the set of new members
     371                 :      20186 :             if (it->second->valid()
     372 [ +  + ][ +  + ]:      20188 :                 && (d_testClique.find(it->first) == d_testClique.end()
                 [ +  + ]
     373         [ -  + ]:          2 :                     || !d_testClique[it->first]))
     374                 :            :             {
     375                 :            :               // if( it->second->getNumInternalDisequalities()>cardinality ||
     376                 :            :               //     level==Theory::EFFORT_FULL ){
     377                 :      12770 :               newClique.push_back(it->first);
     378                 :            :               //}
     379                 :            :             }
     380                 :            :           }
     381                 :            :           // choose remaining nodes with the highest degrees
     382                 :            :           sortInternalDegree sidObj;
     383                 :       2409 :           sidObj.r = this;
     384                 :       2409 :           std::sort(newClique.begin(), newClique.end(), sidObj);
     385                 :       2409 :           int offset = (cardinality - d_testCliqueSize) + 1;
     386                 :       2409 :           newClique.erase(newClique.begin() + offset, newClique.end());
     387                 :            :         }
     388                 :            :         else
     389                 :            :         {
     390                 :            :           // scan for the highest degree
     391                 :        456 :           int maxDeg = -1;
     392                 :        456 :           Node maxNode;
     393                 :        456 :           for (std::map<Node, RegionNodeInfo*>::iterator it = d_nodes.begin();
     394         [ +  + ]:       5945 :                it != d_nodes.end();
     395                 :       5489 :                ++it)
     396                 :            :           {
     397                 :            :             // if not in the test clique, add it to the set of new members
     398                 :       5489 :             if (it->second->valid()
     399 [ +  + ][ +  + ]:       8278 :                 && (d_testClique.find(it->first) == d_testClique.end()
                 [ +  + ]
     400         [ -  + ]:       2789 :                     || !d_testClique[it->first]))
     401                 :            :             {
     402         [ +  + ]:        471 :               if (it->second->getNumInternalDisequalities() > maxDeg)
     403                 :            :               {
     404                 :        456 :                 maxDeg = it->second->getNumInternalDisequalities();
     405                 :        456 :                 maxNode = it->first;
     406                 :            :               }
     407                 :            :             }
     408                 :            :           }
     409 [ -  + ][ -  + ]:        456 :           Assert(maxNode != Node::null());
                 [ -  - ]
     410                 :        456 :           newClique.push_back(maxNode);
     411                 :        456 :         }
     412                 :            :         // check splits internal to new members
     413         [ +  + ]:      15958 :         for (int j = 0; j < (int)newClique.size(); j++)
     414                 :            :         {
     415         [ +  - ]:      26186 :           Trace("uf-ss-debug")
     416                 :      13093 :               << "Choose to add clique member " << newClique[j] << std::endl;
     417         [ +  + ]:      61681 :           for (int k = (j + 1); k < (int)newClique.size(); k++)
     418                 :            :           {
     419         [ +  + ]:      48588 :             if (!isDisequal(newClique[j], newClique[k], 1))
     420                 :            :             {
     421                 :       5921 :               Node at_j = newClique[j];
     422                 :       5921 :               Node at_k = newClique[k];
     423                 :      11842 :               Node j_eq_k = NodeManager::mkNode(Kind::EQUAL, at_j, at_k);
     424                 :       5921 :               d_splits[j_eq_k] = true;
     425                 :       5921 :               d_splitsSize = d_splitsSize + 1;
     426                 :       5921 :             }
     427                 :            :           }
     428                 :            :           // check disequalities with old members
     429                 :      13093 :           for (NodeBoolMap::iterator it = d_testClique.begin();
     430         [ +  + ]:      17321 :                it != d_testClique.end();
     431                 :       4228 :                ++it)
     432                 :            :           {
     433         [ +  + ]:       4228 :             if ((*it).second)
     434                 :            :             {
     435         [ +  + ]:       2793 :               if (!isDisequal((*it).first, newClique[j], 1))
     436                 :            :               {
     437                 :       1737 :                 Node at_it = (*it).first;
     438                 :       1737 :                 Node at_j = newClique[j];
     439                 :       1737 :                 Node it_eq_j = at_it.eqNode(at_j);
     440                 :       1737 :                 d_splits[it_eq_j] = true;
     441                 :       1737 :                 d_splitsSize = d_splitsSize + 1;
     442                 :       1737 :               }
     443                 :            :             }
     444                 :            :           }
     445                 :            :         }
     446                 :            :         // add new clique members to test clique
     447         [ +  + ]:      15958 :         for (int j = 0; j < (int)newClique.size(); j++)
     448                 :            :         {
     449                 :      13093 :           d_testClique[newClique[j]] = true;
     450                 :      13093 :           d_testCliqueSize = d_testCliqueSize + 1;
     451                 :            :         }
     452                 :       2865 :       }
     453                 :            :       // Check if test clique has larger size than cardinality, and
     454                 :            :       // forms a clique.
     455 [ +  - ][ +  + ]:       2985 :       if (d_testCliqueSize >= unsigned(cardinality + 1) && d_splitsSize == 0)
                 [ +  + ]
     456                 :            :       {
     457                 :            :         // test clique is a clique
     458                 :         35 :         for (NodeBoolMap::iterator it = d_testClique.begin();
     459         [ +  + ]:        123 :              it != d_testClique.end();
     460                 :         88 :              ++it)
     461                 :            :         {
     462         [ +  - ]:         88 :           if ((*it).second)
     463                 :            :           {
     464                 :         88 :             clique.push_back((*it).first);
     465                 :            :           }
     466                 :            :         }
     467                 :         35 :         return true;
     468                 :            :       }
     469                 :            :     }
     470                 :            :   }
     471                 :    1076267 :   return false;
     472                 :            : }
     473                 :            : 
     474                 :          0 : void Region::getNumExternalDisequalities(
     475                 :            :     std::map<Node, int>& num_ext_disequalities)
     476                 :            : {
     477         [ -  - ]:          0 :   for (Region::iterator it = begin(); it != end(); ++it)
     478                 :            :   {
     479                 :          0 :     RegionNodeInfo* rni = it->second;
     480         [ -  - ]:          0 :     if (rni->valid())
     481                 :            :     {
     482                 :          0 :       DiseqList* del = rni->get(0);
     483         [ -  - ]:          0 :       for (DiseqList::iterator it2 = del->begin(); it2 != del->end(); ++it2)
     484                 :            :       {
     485         [ -  - ]:          0 :         if ((*it2).second)
     486                 :            :         {
     487                 :          0 :           num_ext_disequalities[(*it2).first]++;
     488                 :            :         }
     489                 :            :       }
     490                 :            :     }
     491                 :            :   }
     492                 :          0 : }
     493                 :            : 
     494                 :       3836 : void Region::debugPrint(CVC5_UNUSED const char* c, bool incClique)
     495                 :            : {
     496         [ +  - ]:       3836 :   Trace(c) << "Num reps: " << d_reps_size << std::endl;
     497         [ +  + ]:      10991 :   for (Region::iterator it = begin(); it != end(); ++it)
     498                 :            :   {
     499                 :       7155 :     RegionNodeInfo* rni = it->second;
     500         [ -  + ]:       7155 :     if (rni->valid())
     501                 :            :     {
     502                 :          0 :       Node n = it->first;
     503         [ -  - ]:          0 :       Trace(c) << "   " << n << std::endl;
     504         [ -  - ]:          0 :       for (int i = 0; i < 2; i++)
     505                 :            :       {
     506                 :          0 :         Trace(c) << "      " << (i == 0 ? "Ext" : "Int") << " disequal:";
     507                 :          0 :         DiseqList* del = rni->get(i);
     508         [ -  - ]:          0 :         for (DiseqList::iterator it2 = del->begin(); it2 != del->end(); ++it2)
     509                 :            :         {
     510         [ -  - ]:          0 :           if ((*it2).second)
     511                 :            :           {
     512         [ -  - ]:          0 :             Trace(c) << " " << (*it2).first;
     513                 :            :           }
     514                 :            :         }
     515         [ -  - ]:          0 :         Trace(c) << ", total = " << del->size() << std::endl;
     516                 :            :       }
     517                 :          0 :     }
     518                 :            :   }
     519         [ +  - ]:       3836 :   Trace(c) << "Total disequal: " << d_total_diseq_external << " external,";
     520         [ +  - ]:       3836 :   Trace(c) << " " << d_total_diseq_internal << " internal." << std::endl;
     521                 :            : 
     522         [ +  - ]:       3836 :   if (incClique)
     523                 :            :   {
     524         [ -  + ]:       3836 :     if (!d_testClique.empty())
     525                 :            :     {
     526         [ -  - ]:          0 :       Trace(c) << "Candidate clique members: " << std::endl;
     527         [ -  - ]:          0 :       Trace(c) << "   ";
     528                 :          0 :       for (NodeBoolMap::iterator it = d_testClique.begin();
     529         [ -  - ]:          0 :            it != d_testClique.end();
     530                 :          0 :            ++it)
     531                 :            :       {
     532         [ -  - ]:          0 :         if ((*it).second)
     533                 :            :         {
     534         [ -  - ]:          0 :           Trace(c) << (*it).first << " ";
     535                 :            :         }
     536                 :            :       }
     537         [ -  - ]:          0 :       Trace(c) << ", size = " << d_testCliqueSize << std::endl;
     538                 :            :     }
     539         [ -  + ]:       3836 :     if (!d_splits.empty())
     540                 :            :     {
     541         [ -  - ]:          0 :       Trace(c) << "Required splits: " << std::endl;
     542         [ -  - ]:          0 :       Trace(c) << "   ";
     543         [ -  - ]:          0 :       for (NodeBoolMap::iterator it = d_splits.begin(); it != d_splits.end();
     544                 :          0 :            ++it)
     545                 :            :       {
     546         [ -  - ]:          0 :         if ((*it).second)
     547                 :            :         {
     548         [ -  - ]:          0 :           Trace(c) << (*it).first << " ";
     549                 :            :         }
     550                 :            :       }
     551         [ -  - ]:          0 :       Trace(c) << ", size = " << d_splitsSize << std::endl;
     552                 :            :     }
     553                 :            :   }
     554                 :       3836 : }
     555                 :            : 
     556                 :        722 : SortModel::CardinalityDecisionStrategy::CardinalityDecisionStrategy(
     557                 :        722 :     Env& env, TypeNode type, Valuation valuation)
     558                 :        722 :     : DecisionStrategyFmf(env, valuation), d_type(type)
     559                 :            : {
     560                 :        722 : }
     561                 :            : 
     562                 :       1688 : Node SortModel::CardinalityDecisionStrategy::mkLiteral(unsigned i)
     563                 :            : {
     564                 :       1688 :   NodeManager* nm = nodeManager();
     565                 :       3376 :   Node cco = nm->mkConst(CardinalityConstraint(d_type, Integer(i + 1)));
     566                 :       3376 :   return nm->mkNode(Kind::CARDINALITY_CONSTRAINT, cco);
     567                 :       1688 : }
     568                 :            : 
     569                 :          0 : std::string SortModel::CardinalityDecisionStrategy::identify() const
     570                 :            : {
     571                 :          0 :   return std::string("uf_card");
     572                 :            : }
     573                 :            : 
     574                 :        722 : SortModel::SortModel(Env& env,
     575                 :            :                      TypeNode tn,
     576                 :            :                      TheoryState& state,
     577                 :            :                      TheoryInferenceManager& im,
     578                 :        722 :                      CardinalityExtension* thss)
     579                 :            :     : EnvObj(env),
     580                 :        722 :       d_type(tn),
     581                 :        722 :       d_state(state),
     582                 :        722 :       d_im(im),
     583                 :        722 :       d_thss(thss),
     584                 :        722 :       d_regions_index(thss->context(), 0),
     585                 :        722 :       d_regions_map(thss->context()),
     586                 :        722 :       d_split_score(thss->context()),
     587                 :        722 :       d_disequalities_index(thss->context(), 0),
     588                 :        722 :       d_reps(thss->context(), 0),
     589                 :        722 :       d_cardinality(thss->context(), 1),
     590                 :        722 :       d_hasCard(thss->context(), false),
     591                 :        722 :       d_maxNegCard(thss->context(), 0),
     592                 :        722 :       d_initialized(thss->userContext(), false),
     593                 :       5054 :       d_c_dec_strat(nullptr)
     594                 :            : {
     595         [ +  - ]:        722 :   if (options().uf.ufssMode == options::UfssMode::FULL)
     596                 :            :   {
     597                 :            :     // Register the strategy with the decision manager of the theory.
     598                 :            :     // We are guaranteed that the decision manager is ready since we
     599                 :            :     // construct this module during TheoryUF::finishInit.
     600                 :        722 :     d_c_dec_strat.reset(new CardinalityDecisionStrategy(
     601                 :        722 :         thss->d_env, d_type, thss->getTheory()->getValuation()));
     602                 :            :   }
     603                 :        722 : }
     604                 :            : 
     605                 :       1440 : SortModel::~SortModel()
     606                 :            : {
     607                 :        720 :   for (std::vector<Region*>::iterator i = d_regions.begin();
     608         [ +  + ]:       4558 :        i != d_regions.end();
     609                 :       3838 :        ++i)
     610                 :            :   {
     611                 :       3838 :     Region* region = *i;
     612         [ +  - ]:       3838 :     delete region;
     613                 :            :   }
     614                 :        720 :   d_regions.clear();
     615                 :       1440 : }
     616                 :            : 
     617                 :            : /** initialize */
     618                 :      24535 : void SortModel::initialize()
     619                 :            : {
     620 [ +  - ][ +  + ]:      24535 :   if (d_c_dec_strat.get() != nullptr && !d_initialized)
                 [ +  + ]
     621                 :            :   {
     622                 :       1160 :     d_initialized = true;
     623                 :            :     // Strategy is user-context-dependent, since it is in sync with
     624                 :            :     // user-context-dependent flag d_initialized.
     625                 :       2320 :     d_im.getDecisionManager()->registerStrategy(DecisionManager::STRAT_UF_CARD,
     626                 :       1160 :                                                 d_c_dec_strat.get());
     627                 :            :   }
     628                 :      24535 : }
     629                 :            : 
     630                 :            : /** new node */
     631                 :       7678 : void SortModel::newEqClass(Node n)
     632                 :            : {
     633         [ +  - ]:       7678 :   if (!d_state.isInConflict())
     634                 :            :   {
     635         [ +  - ]:       7678 :     if (d_regions_map.find(n) == d_regions_map.end())
     636                 :            :     {
     637                 :       7678 :       d_regions_map[n] = d_regions_index;
     638         [ +  - ]:       7678 :       Trace("uf-ss") << "CardinalityExtension: New Eq Class " << n << std::endl;
     639         [ +  - ]:      15356 :       Trace("uf-ss-debug") << d_regions_index << " " << (int)d_regions.size()
     640                 :       7678 :                            << std::endl;
     641         [ +  + ]:       7678 :       if (d_regions_index < d_regions.size())
     642                 :            :       {
     643                 :       3836 :         d_regions[d_regions_index]->debugPrint("uf-ss-debug", true);
     644                 :       3836 :         d_regions[d_regions_index]->setValid(true);
     645 [ -  + ][ -  + ]:       3836 :         Assert(d_regions[d_regions_index]->getNumReps() == 0);
                 [ -  - ]
     646                 :            :       }
     647                 :            :       else
     648                 :            :       {
     649                 :       3842 :         d_regions.push_back(new Region(this, d_thss->context()));
     650                 :            :       }
     651                 :       7678 :       d_regions[d_regions_index]->addRep(n);
     652                 :       7678 :       d_regions_index = d_regions_index + 1;
     653                 :            : 
     654                 :       7678 :       d_reps = d_reps + 1;
     655                 :            :     }
     656                 :            :   }
     657                 :       7678 : }
     658                 :            : 
     659                 :            : /** merge */
     660                 :      48920 : void SortModel::merge(Node a, Node b)
     661                 :            : {
     662         [ -  + ]:      48920 :   if (d_state.isInConflict())
     663                 :            :   {
     664                 :          0 :     return;
     665                 :            :   }
     666         [ +  - ]:      97840 :   Trace("uf-ss") << "CardinalityExtension: Merging " << a << " = " << b << "..."
     667                 :      48920 :                  << std::endl;
     668         [ +  - ]:      48920 :   if (a != b)
     669                 :            :   {
     670 [ -  + ][ -  + ]:      48920 :     Assert(d_regions_map.find(a) != d_regions_map.end());
                 [ -  - ]
     671 [ -  + ][ -  + ]:      48920 :     Assert(d_regions_map.find(b) != d_regions_map.end());
                 [ -  - ]
     672                 :      48920 :     int ai = d_regions_map[a];
     673                 :      48920 :     int bi = d_regions_map[b];
     674         [ +  - ]:      48920 :     Trace("uf-ss") << "   regions: " << ai << " " << bi << std::endl;
     675         [ +  + ]:      48920 :     if (ai != bi)
     676                 :            :     {
     677         [ +  + ]:      42570 :       if (d_regions[ai]->getNumReps() == 1)
     678                 :            :       {
     679                 :      28374 :         int ri = combineRegions(bi, ai);
     680                 :      28374 :         d_regions[ri]->setEqual(a, b);
     681                 :      28374 :         checkRegion(ri);
     682                 :            :       }
     683         [ +  + ]:      14196 :       else if (d_regions[bi]->getNumReps() == 1)
     684                 :            :       {
     685                 :      13213 :         int ri = combineRegions(ai, bi);
     686                 :      13213 :         d_regions[ri]->setEqual(a, b);
     687                 :      13213 :         checkRegion(ri);
     688                 :            :       }
     689                 :            :       else
     690                 :            :       {
     691                 :            :         // Either move a to d_regions[bi], or b to d_regions[ai].
     692                 :        983 :         RegionNodeInfo* a_region_info = d_regions[ai]->getRegionInfo(a);
     693                 :        983 :         RegionNodeInfo* b_region_info = d_regions[bi]->getRegionInfo(b);
     694                 :        983 :         int aex = (a_region_info->getNumInternalDisequalities()
     695                 :        983 :                    - getNumDisequalitiesToRegion(a, bi));
     696                 :        983 :         int bex = (b_region_info->getNumInternalDisequalities()
     697                 :        983 :                    - getNumDisequalitiesToRegion(b, ai));
     698                 :            :         // Based on which would produce the fewest number of
     699                 :            :         // external disequalities.
     700         [ +  + ]:        983 :         if (aex < bex)
     701                 :            :         {
     702                 :        356 :           moveNode(a, bi);
     703                 :        356 :           d_regions[bi]->setEqual(a, b);
     704                 :            :         }
     705                 :            :         else
     706                 :            :         {
     707                 :        627 :           moveNode(b, ai);
     708                 :        627 :           d_regions[ai]->setEqual(a, b);
     709                 :            :         }
     710                 :        983 :         checkRegion(ai);
     711                 :        983 :         checkRegion(bi);
     712                 :            :       }
     713                 :            :     }
     714                 :            :     else
     715                 :            :     {
     716                 :       6350 :       d_regions[ai]->setEqual(a, b);
     717                 :       6350 :       checkRegion(ai);
     718                 :            :     }
     719                 :      48920 :     d_regions_map[b] = -1;
     720                 :            :   }
     721                 :      48920 :   d_reps = d_reps - 1;
     722                 :            : }
     723                 :            : 
     724                 :            : /** assert terms are disequal */
     725                 :      21486 : void SortModel::assertDisequal(Node a, Node b, Node reason)
     726                 :            : {
     727         [ -  + ]:      21486 :   if (d_state.isInConflict())
     728                 :            :   {
     729                 :          0 :     return;
     730                 :            :   }
     731                 :            :   // if they are not already disequal
     732                 :      21486 :   eq::EqualityEngine* ee = d_thss->getTheory()->getEqualityEngine();
     733                 :      21486 :   a = ee->getRepresentative(a);
     734                 :      21486 :   b = ee->getRepresentative(b);
     735                 :      21486 :   int ai = d_regions_map[a];
     736                 :      21486 :   int bi = d_regions_map[b];
     737         [ -  + ]:      21486 :   if (d_regions[ai]->isDisequal(a, b, ai == bi))
     738                 :            :   {
     739                 :            :     // already disequal
     740                 :          0 :     return;
     741                 :            :   }
     742         [ +  - ]:      42972 :   Trace("uf-ss") << "Assert disequal " << a << " != " << b << "..."
     743                 :      21486 :                  << std::endl;
     744         [ +  - ]:      42972 :   Trace("uf-ss-disequal") << "Assert disequal " << a << " != " << b << "..."
     745                 :      21486 :                           << std::endl;
     746                 :            :   // add to list of disequalities
     747         [ +  + ]:      21486 :   if (d_disequalities_index < d_disequalities.size())
     748                 :            :   {
     749                 :      16174 :     d_disequalities[d_disequalities_index] = reason;
     750                 :            :   }
     751                 :            :   else
     752                 :            :   {
     753                 :       5312 :     d_disequalities.push_back(reason);
     754                 :            :   }
     755                 :      21486 :   d_disequalities_index = d_disequalities_index + 1;
     756                 :            :   // now, add disequalities to regions
     757 [ -  + ][ -  + ]:      21486 :   Assert(d_regions_map.find(a) != d_regions_map.end());
                 [ -  - ]
     758 [ -  + ][ -  + ]:      21486 :   Assert(d_regions_map.find(b) != d_regions_map.end());
                 [ -  - ]
     759         [ +  - ]:      21486 :   Trace("uf-ss") << "   regions: " << ai << " " << bi << std::endl;
     760         [ +  + ]:      21486 :   if (ai == bi)
     761                 :            :   {
     762                 :            :     // internal disequality
     763                 :        761 :     d_regions[ai]->setDisequal(a, b, 1, true);
     764                 :        761 :     d_regions[ai]->setDisequal(b, a, 1, true);
     765                 :            :     // do not need to check if it needs to combine (no new ext. disequalities)
     766                 :        761 :     checkRegion(ai, false);
     767                 :            :   }
     768                 :            :   else
     769                 :            :   {
     770                 :            :     // external disequality
     771                 :      20725 :     d_regions[ai]->setDisequal(a, b, 0, true);
     772                 :      20725 :     d_regions[bi]->setDisequal(b, a, 0, true);
     773                 :      20725 :     checkRegion(ai);
     774                 :      20725 :     checkRegion(bi);
     775                 :            :   }
     776                 :            : }
     777                 :            : 
     778                 :          0 : bool SortModel::areDisequal(Node a, Node b)
     779                 :            : {
     780                 :          0 :   Assert(a == d_thss->getTheory()->getEqualityEngine()->getRepresentative(a));
     781                 :          0 :   Assert(b == d_thss->getTheory()->getEqualityEngine()->getRepresentative(b));
     782                 :          0 :   if (d_regions_map.find(a) != d_regions_map.end()
     783                 :          0 :       && d_regions_map.find(b) != d_regions_map.end())
     784                 :            :   {
     785                 :          0 :     int ai = d_regions_map[a];
     786                 :          0 :     int bi = d_regions_map[b];
     787         [ -  - ]:          0 :     return d_regions[ai]->isDisequal(a, b, ai == bi ? 1 : 0);
     788                 :            :   }
     789                 :            :   else
     790                 :            :   {
     791                 :          0 :     return false;
     792                 :            :   }
     793                 :            : }
     794                 :            : 
     795                 :     336065 : void SortModel::check(Theory::Effort level)
     796                 :            : {
     797 [ -  + ][ -  + ]:     336065 :   Assert(options().uf.ufssMode == options::UfssMode::FULL);
                 [ -  - ]
     798 [ +  + ][ -  + ]:     336065 :   if (!d_hasCard && d_state.isInConflict())
                 [ -  + ]
     799                 :            :   {
     800                 :            :     // not necessary to check
     801                 :          0 :     return;
     802                 :            :   }
     803         [ +  - ]:     672130 :   Trace("uf-ss") << "CardinalityExtension: Check " << level << " " << d_type
     804                 :     336065 :                  << std::endl;
     805         [ +  + ]:     336065 :   if (level == Theory::EFFORT_FULL)
     806                 :            :   {
     807         [ +  - ]:      14140 :     Trace("fmf-full-check") << std::endl;
     808         [ +  - ]:      28280 :     Trace("fmf-full-check")
     809                 :      14140 :         << "Full check for SortModel " << d_type << ", status : " << std::endl;
     810                 :      14140 :     debugPrint("fmf-full-check");
     811         [ +  - ]:      14140 :     Trace("fmf-full-check") << std::endl;
     812                 :            :   }
     813         [ +  + ]:     336065 :   if (d_reps <= (unsigned)d_cardinality)
     814                 :            :   {
     815         [ +  - ]:     241904 :     Trace("uf-ss-debug") << "We have " << d_reps << " representatives for type "
     816                 :     120952 :                          << d_type << ", <= " << d_cardinality << std::endl;
     817         [ +  + ]:     120952 :     if (level == Theory::EFFORT_FULL)
     818                 :            :     {
     819         [ +  - ]:      14106 :       Trace("uf-ss-sat") << "We have " << d_reps << " representatives for type "
     820                 :       7053 :                          << d_type << ", <= " << d_cardinality << std::endl;
     821                 :            :     }
     822                 :     120952 :     return;
     823                 :            :   }
     824                 :            :   // first check if we can generate a clique conflict
     825                 :            :   // do a check within each region
     826         [ +  + ]:    1999312 :   for (size_t i = 0; i < d_regions_index; i++)
     827                 :            :   {
     828         [ +  + ]:    1785814 :     if (d_regions[i]->valid())
     829                 :            :     {
     830                 :     996411 :       std::vector<Node> clique;
     831         [ +  + ]:     996411 :       if (d_regions[i]->check(level, d_cardinality, clique))
     832                 :            :       {
     833                 :            :         // add clique lemma
     834                 :       1615 :         addCliqueLemma(clique);
     835                 :       1615 :         return;
     836                 :            :       }
     837                 :            :       else
     838                 :            :       {
     839         [ +  - ]:     994796 :         Trace("uf-ss-debug") << "No clique in Region #" << i << std::endl;
     840                 :            :       }
     841         [ +  + ]:     996411 :     }
     842                 :            :   }
     843                 :            :   // do splitting on demand
     844                 :     213498 :   bool addedLemma = false;
     845         [ +  + ]:     213498 :   if (level == Theory::EFFORT_FULL)
     846                 :            :   {
     847         [ +  - ]:       7044 :     Trace("uf-ss-debug") << "Add splits?" << std::endl;
     848                 :            :     // see if we have any recommended splits from large regions
     849         [ +  + ]:      93029 :     for (size_t i = 0; i < d_regions_index; i++)
     850                 :            :     {
     851 [ +  + ][ +  + ]:      85985 :       if (d_regions[i]->valid() && d_regions[i]->getNumReps() > d_cardinality)
                 [ +  + ]
     852                 :            :       {
     853                 :       2950 :         int sp = addSplit(d_regions[i]);
     854         [ +  - ]:       2950 :         if (sp == 1)
     855                 :            :         {
     856                 :       2950 :           addedLemma = true;
     857                 :            :         }
     858         [ -  - ]:          0 :         else if (sp == -1)
     859                 :            :         {
     860                 :          0 :           check(level);
     861                 :          0 :           return;
     862                 :            :         }
     863                 :            :       }
     864                 :            :     }
     865                 :            :   }
     866                 :            :   // If no added lemmas, force continuation via combination of regions.
     867 [ +  + ][ +  + ]:     213498 :   if (level != Theory::EFFORT_FULL || addedLemma)
     868                 :            :   {
     869                 :     209404 :     return;
     870                 :            :   }
     871                 :            :   // check at full effort
     872         [ +  - ]:       4094 :   Trace("uf-ss-debug") << "No splits added. " << d_cardinality << std::endl;
     873         [ +  - ]:       4094 :   Trace("uf-ss-si") << "Must combine region" << std::endl;
     874                 :       4094 :   bool recheck = false;
     875                 :       4094 :   SortInference* si = d_state.getSortInference();
     876         [ +  + ]:       4094 :   if (si != nullptr)
     877                 :            :   {
     878                 :            :     // If sort inference is enabled, search for regions with same sort.
     879                 :        217 :     std::map<int, int> sortsFound;
     880         [ +  - ]:       1628 :     for (size_t i = 0; i < d_regions_index; i++)
     881                 :            :     {
     882         [ +  + ]:       1628 :       if (d_regions[i]->valid())
     883                 :            :       {
     884                 :        434 :         Node op = d_regions[i]->frontKey();
     885                 :        434 :         int sort_id = si->getSortId(op);
     886         [ +  + ]:        434 :         if (sortsFound.find(sort_id) != sortsFound.end())
     887                 :            :         {
     888         [ +  - ]:        434 :           Trace("fmf-full-check") << "Combined regions " << i << " "
     889                 :        217 :                                   << sortsFound[sort_id] << std::endl;
     890                 :        217 :           combineRegions(sortsFound[sort_id], i);
     891                 :        217 :           recheck = true;
     892                 :        217 :           break;
     893                 :            :         }
     894                 :            :         else
     895                 :            :         {
     896                 :        217 :           sortsFound[sort_id] = i;
     897                 :            :         }
     898         [ +  + ]:        434 :       }
     899                 :            :     }
     900                 :        217 :   }
     901         [ +  + ]:       4094 :   if (!recheck)
     902                 :            :   {
     903                 :            :     // naive strategy, force region combination involving the first
     904                 :            :     // valid region
     905         [ +  - ]:      12234 :     for (size_t i = 0; i < d_regions_index; i++)
     906                 :            :     {
     907         [ +  + ]:      12234 :       if (d_regions[i]->valid())
     908                 :            :       {
     909                 :       3877 :         int fcr = forceCombineRegion(i, false);
     910         [ +  - ]:       7754 :         Trace("fmf-full-check")
     911                 :       3877 :             << "Combined regions " << i << " " << fcr << std::endl;
     912         [ +  - ]:       7754 :         Trace("uf-ss-debug")
     913                 :       3877 :             << "Combined regions " << i << " " << fcr << std::endl;
     914                 :       3877 :         recheck = true;
     915                 :       3877 :         break;
     916                 :            :       }
     917                 :            :     }
     918                 :            :   }
     919         [ +  - ]:       4094 :   if (recheck)
     920                 :            :   {
     921         [ +  - ]:       4094 :     Trace("uf-ss-debug") << "Must recheck." << std::endl;
     922                 :       4094 :     check(level);
     923                 :            :   }
     924                 :            : }
     925                 :            : 
     926                 :        437 : void SortModel::presolve() { d_initialized = false; }
     927                 :            : 
     928                 :       1966 : int SortModel::getNumDisequalitiesToRegion(Node n, int ri)
     929                 :            : {
     930                 :       1966 :   int ni = d_regions_map[n];
     931                 :       1966 :   int counter = 0;
     932                 :       1966 :   DiseqList* del = d_regions[ni]->getRegionInfo(n)->get(0);
     933         [ +  + ]:       5409 :   for (DiseqList::iterator it = del->begin(); it != del->end(); ++it)
     934                 :            :   {
     935         [ +  + ]:       3443 :     if ((*it).second)
     936                 :            :     {
     937         [ +  + ]:       1227 :       if (d_regions_map[(*it).first] == ri)
     938                 :            :       {
     939                 :        974 :         counter++;
     940                 :            :       }
     941                 :            :     }
     942                 :            :   }
     943                 :       1966 :   return counter;
     944                 :            : }
     945                 :            : 
     946                 :      15736 : void SortModel::getDisequalitiesToRegions(int ri,
     947                 :            :                                           std::map<int, int>& regions_diseq)
     948                 :            : {
     949                 :      15736 :   Region* region = d_regions[ri];
     950         [ +  + ]:     202400 :   for (Region::iterator it = region->begin(); it != region->end(); ++it)
     951                 :            :   {
     952         [ +  + ]:     186664 :     if (it->second->valid())
     953                 :            :     {
     954                 :      46106 :       DiseqList* del = it->second->get(0);
     955         [ +  + ]:     344267 :       for (DiseqList::iterator it2 = del->begin(); it2 != del->end(); ++it2)
     956                 :            :       {
     957         [ +  + ]:     298161 :         if ((*it2).second)
     958                 :            :         {
     959 [ -  + ][ -  + ]:     190773 :           Assert(isValid(d_regions_map[(*it2).first]));
                 [ -  - ]
     960                 :     190773 :           regions_diseq[d_regions_map[(*it2).first]]++;
     961                 :            :         }
     962                 :            :       }
     963                 :            :     }
     964                 :            :   }
     965                 :      15736 : }
     966                 :            : 
     967                 :          0 : void SortModel::setSplitScore(Node n, int s)
     968                 :            : {
     969         [ -  - ]:          0 :   if (d_split_score.find(n) != d_split_score.end())
     970                 :            :   {
     971                 :          0 :     int ss = d_split_score[n];
     972         [ -  - ]:          0 :     d_split_score[n] = s > ss ? s : ss;
     973                 :            :   }
     974                 :            :   else
     975                 :            :   {
     976                 :          0 :     d_split_score[n] = s;
     977                 :            :   }
     978         [ -  - ]:          0 :   for (int i = 0; i < (int)n.getNumChildren(); i++)
     979                 :            :   {
     980                 :          0 :     setSplitScore(n[i], s + 1);
     981                 :            :   }
     982                 :          0 : }
     983                 :            : 
     984                 :      12950 : void SortModel::assertCardinality(uint32_t c, bool val)
     985                 :            : {
     986         [ +  - ]:      12950 :   if (!d_state.isInConflict())
     987                 :            :   {
     988         [ +  - ]:      25900 :     Trace("uf-ss-assert")
     989                 :          0 :         << "Assert cardinality " << d_type << " " << c << " " << val
     990                 :          0 :         << " level = "
     991                 :      12950 :         << d_thss->getTheory()->getValuation().getAssertionLevel() << std::endl;
     992 [ -  + ][ -  + ]:      12950 :     Assert(c > 0);
                 [ -  - ]
     993                 :      12950 :     Node cl = getCardinalityLiteral(c);
     994         [ +  + ]:      12950 :     if (val)
     995                 :            :     {
     996                 :      10695 :       bool doCheckRegions = !d_hasCard;
     997                 :      10695 :       bool prevHasCard = d_hasCard;
     998                 :      10695 :       d_hasCard = true;
     999 [ +  + ][ +  + ]:      10695 :       if (!prevHasCard || c < d_cardinality)
                 [ +  + ]
    1000                 :            :       {
    1001                 :      10687 :         d_cardinality = c;
    1002                 :      10687 :         simpleCheckCardinality();
    1003         [ +  + ]:      10687 :         if (d_state.isInConflict())
    1004                 :            :         {
    1005                 :        222 :           return;
    1006                 :            :         }
    1007                 :            :       }
    1008                 :            :       // should check all regions now
    1009         [ +  + ]:      10473 :       if (doCheckRegions)
    1010                 :            :       {
    1011         [ +  + ]:      68973 :         for (size_t i = 0; i < d_regions_index; i++)
    1012                 :            :         {
    1013         [ +  + ]:      58552 :           if (d_regions[i]->valid())
    1014                 :            :           {
    1015                 :      50144 :             checkRegion(i);
    1016         [ -  + ]:      50144 :             if (d_state.isInConflict())
    1017                 :            :             {
    1018                 :          0 :               return;
    1019                 :            :             }
    1020                 :            :           }
    1021                 :            :         }
    1022                 :            :       }
    1023                 :            :       // we assert it positively, if its beyond the bound, abort
    1024                 :      10473 :       if (options().uf.ufssAbortCardinality >= 0
    1025 [ -  + ][ -  - ]:      10473 :           && c >= static_cast<uint32_t>(options().uf.ufssAbortCardinality))
                 [ -  + ]
    1026                 :            :       {
    1027                 :          0 :         std::stringstream ss;
    1028                 :          0 :         ss << "Maximum cardinality (" << options().uf.ufssAbortCardinality
    1029                 :          0 :            << ")  for finite model finding exceeded." << std::endl;
    1030                 :          0 :         throw LogicException(ss.str());
    1031                 :          0 :       }
    1032                 :            :     }
    1033                 :            :     else
    1034                 :            :     {
    1035         [ +  + ]:       2255 :       if (c > d_maxNegCard.get())
    1036                 :            :       {
    1037         [ +  - ]:       3982 :         Trace("uf-ss-com-card-debug") << "Maximum negative cardinality for "
    1038                 :       1991 :                                       << d_type << " is now " << c << std::endl;
    1039                 :       1991 :         d_maxNegCard.set(c);
    1040                 :       1991 :         simpleCheckCardinality();
    1041                 :            :       }
    1042                 :            :     }
    1043         [ +  + ]:      12950 :   }
    1044                 :            : }
    1045                 :            : 
    1046                 :     157994 : void SortModel::checkRegion(int ri, bool checkCombine)
    1047                 :            : {
    1048 [ +  + ][ +  + ]:     157994 :   if (isValid(ri) && d_hasCard)
                 [ +  + ]
    1049                 :            :   {
    1050 [ -  + ][ -  + ]:     148067 :     Assert(d_cardinality > 0);
                 [ -  - ]
    1051 [ +  + ][ +  + ]:     148067 :     if (checkCombine && d_regions[ri]->getMustCombine(d_cardinality))
                 [ +  + ]
    1052                 :            :     {
    1053                 :      15736 :       int riNew = forceCombineRegion(ri, true);
    1054         [ +  - ]:      15736 :       if (riNew >= 0)
    1055                 :            :       {
    1056                 :      15736 :         checkRegion(riNew, checkCombine);
    1057                 :            :       }
    1058                 :            :     }
    1059                 :            :     // now check if region is in conflict
    1060                 :     148067 :     std::vector<Node> clique;
    1061         [ +  + ]:     148067 :     if (d_regions[ri]->check(Theory::EFFORT_STANDARD, d_cardinality, clique))
    1062                 :            :     {
    1063                 :            :       // explain clique
    1064                 :       2926 :       addCliqueLemma(clique);
    1065                 :            :     }
    1066                 :     148067 :   }
    1067                 :     157994 : }
    1068                 :            : 
    1069                 :      19613 : int SortModel::forceCombineRegion(int ri, bool useDensity)
    1070                 :            : {
    1071         [ +  + ]:      19613 :   if (!useDensity)
    1072                 :            :   {
    1073         [ +  - ]:      32190 :     for (int i = 0; i < (int)d_regions_index; i++)
    1074                 :            :     {
    1075 [ +  + ][ +  + ]:      32190 :       if (ri != i && d_regions[i]->valid())
                 [ +  + ]
    1076                 :            :       {
    1077                 :       3877 :         return combineRegions(ri, i);
    1078                 :            :       }
    1079                 :            :     }
    1080                 :          0 :     return -1;
    1081                 :            :   }
    1082                 :            :   else
    1083                 :            :   {
    1084                 :            :     // this region must merge with another
    1085         [ -  + ]:      15736 :     if (TraceIsOn("uf-ss-check-region"))
    1086                 :            :     {
    1087         [ -  - ]:          0 :       Trace("uf-ss-check-region")
    1088                 :          0 :           << "We must combine Region #" << ri << ". " << std::endl;
    1089                 :          0 :       d_regions[ri]->debugPrint("uf-ss-check-region");
    1090                 :            :     }
    1091                 :            :     // take region with maximum disequality density
    1092                 :      15736 :     double maxScore = 0;
    1093                 :      15736 :     int maxRegion = -1;
    1094                 :      15736 :     std::map<int, int> regions_diseq;
    1095                 :      15736 :     getDisequalitiesToRegions(ri, regions_diseq);
    1096                 :      15736 :     for (std::map<int, int>::iterator it = regions_diseq.begin();
    1097         [ +  + ]:      95364 :          it != regions_diseq.end();
    1098                 :      79628 :          ++it)
    1099                 :            :     {
    1100         [ +  - ]:     159256 :       Trace("uf-ss-check-region")
    1101                 :      79628 :           << it->first << " : " << it->second << std::endl;
    1102                 :            :     }
    1103                 :      15736 :     for (std::map<int, int>::iterator it = regions_diseq.begin();
    1104         [ +  + ]:      95364 :          it != regions_diseq.end();
    1105                 :      79628 :          ++it)
    1106                 :            :     {
    1107 [ -  + ][ -  + ]:      79628 :       Assert(it->first != ri);
                 [ -  - ]
    1108 [ -  + ][ -  + ]:      79628 :       Assert(isValid(it->first));
                 [ -  - ]
    1109 [ -  + ][ -  + ]:      79628 :       Assert(d_regions[it->first]->getNumReps() > 0);
                 [ -  - ]
    1110                 :            :       double tempScore =
    1111                 :      79628 :           double(it->second) / double(d_regions[it->first]->getNumReps());
    1112         [ +  + ]:      79628 :       if (tempScore > maxScore)
    1113                 :            :       {
    1114                 :      19077 :         maxRegion = it->first;
    1115                 :      19077 :         maxScore = tempScore;
    1116                 :            :       }
    1117                 :            :     }
    1118         [ +  - ]:      15736 :     if (maxRegion != -1)
    1119                 :            :     {
    1120         [ -  + ]:      15736 :       if (TraceIsOn("uf-ss-check-region"))
    1121                 :            :       {
    1122         [ -  - ]:          0 :         Trace("uf-ss-check-region")
    1123                 :          0 :             << "Combine with region #" << maxRegion << ":" << std::endl;
    1124                 :          0 :         d_regions[maxRegion]->debugPrint("uf-ss-check-region");
    1125                 :            :       }
    1126                 :      15736 :       return combineRegions(ri, maxRegion);
    1127                 :            :     }
    1128                 :          0 :     return -1;
    1129                 :      15736 :   }
    1130                 :            : }
    1131                 :            : 
    1132                 :      61417 : int SortModel::combineRegions(int ai, int bi)
    1133                 :            : {
    1134         [ +  - ]:     122834 :   Trace("uf-ss-region") << "uf-ss: Combine Region #" << bi << " with Region #"
    1135                 :      61417 :                         << ai << std::endl;
    1136 [ +  - ][ +  - ]:      61417 :   Assert(isValid(ai) && isValid(bi));
         [ -  + ][ -  + ]
                 [ -  - ]
    1137                 :      61417 :   Region* region_bi = d_regions[bi];
    1138         [ +  + ]:     341008 :   for (Region::iterator it = region_bi->begin(); it != region_bi->end(); ++it)
    1139                 :            :   {
    1140                 :     279591 :     Region::RegionNodeInfo* rni = it->second;
    1141         [ +  + ]:     279591 :     if (rni->valid())
    1142                 :            :     {
    1143                 :      65240 :       d_regions_map[it->first] = ai;
    1144                 :            :     }
    1145                 :            :   }
    1146                 :            :   // update regions disequal DO_THIS?
    1147                 :      61417 :   d_regions[ai]->combine(d_regions[bi]);
    1148                 :      61417 :   d_regions[bi]->setValid(false);
    1149                 :      61417 :   return ai;
    1150                 :            : }
    1151                 :            : 
    1152                 :        983 : void SortModel::moveNode(Node n, int ri)
    1153                 :            : {
    1154         [ +  - ]:       1966 :   Trace("uf-ss-region") << "uf-ss: Move node " << n << " to Region #" << ri
    1155                 :        983 :                         << std::endl;
    1156 [ -  + ][ -  + ]:        983 :   Assert(isValid(d_regions_map[n]));
                 [ -  - ]
    1157 [ -  + ][ -  + ]:        983 :   Assert(isValid(ri));
                 [ -  - ]
    1158                 :            :   // move node to region ri
    1159                 :        983 :   d_regions[ri]->takeNode(d_regions[d_regions_map[n]], n);
    1160                 :        983 :   d_regions_map[n] = ri;
    1161                 :        983 : }
    1162                 :            : 
    1163                 :       2950 : int SortModel::addSplit(Region* r)
    1164                 :            : {
    1165                 :       2950 :   Node s;
    1166         [ +  - ]:       2950 :   if (r->hasSplits())
    1167                 :            :   {
    1168                 :            :     // take the first split you find
    1169         [ +  - ]:      15877 :     for (Region::split_iterator it = r->begin_splits(); it != r->end_splits();
    1170                 :      12927 :          ++it)
    1171                 :            :     {
    1172         [ +  + ]:      15877 :       if ((*it).second)
    1173                 :            :       {
    1174                 :       2950 :         s = (*it).first;
    1175                 :       2950 :         break;
    1176                 :            :       }
    1177                 :            :     }
    1178 [ -  + ][ -  + ]:       2950 :     Assert(s != Node::null());
                 [ -  - ]
    1179                 :            :   }
    1180         [ +  - ]:       2950 :   if (!s.isNull())
    1181                 :            :   {
    1182                 :            :     // add lemma to output channel
    1183 [ -  + ][ -  + ]:       2950 :     Assert(s.getKind() == Kind::EQUAL);
                 [ -  - ]
    1184                 :       2950 :     Node ss = rewrite(s);
    1185         [ -  + ]:       2950 :     if (ss.getKind() != Kind::EQUAL)
    1186                 :            :     {
    1187                 :          0 :       Node b_t = nodeManager()->mkConst(true);
    1188                 :          0 :       Node b_f = nodeManager()->mkConst(false);
    1189         [ -  - ]:          0 :       if (ss == b_f)
    1190                 :            :       {
    1191                 :          0 :         Trace("uf-ss-lemma") << "....Assert disequal directly : " << s[0] << " "
    1192                 :          0 :                              << s[1] << std::endl;
    1193                 :          0 :         assertDisequal(s[0], s[1], b_t);
    1194                 :          0 :         return -1;
    1195                 :            :       }
    1196                 :            :       else
    1197                 :            :       {
    1198         [ -  - ]:          0 :         Trace("uf-ss-warn") << "Split on unknown literal : " << ss << std::endl;
    1199                 :            :       }
    1200         [ -  - ]:          0 :       if (ss == b_t)
    1201                 :            :       {
    1202                 :          0 :         AlwaysAssert(false) << "Bad split " << s << std::endl;
    1203                 :            :       }
    1204 [ -  - ][ -  - ]:          0 :     }
    1205         [ -  + ]:       2950 :     if (TraceIsOn("uf-ss-split-si"))
    1206                 :            :     {
    1207                 :          0 :       SortInference* si = d_state.getSortInference();
    1208         [ -  - ]:          0 :       if (si != nullptr)
    1209                 :            :       {
    1210         [ -  - ]:          0 :         for (size_t i = 0; i < 2; i++)
    1211                 :            :         {
    1212                 :          0 :           int sid = si->getSortId(ss[i]);
    1213         [ -  - ]:          0 :           Trace("uf-ss-split-si") << sid << " ";
    1214                 :            :         }
    1215         [ -  - ]:          0 :         Trace("uf-ss-split-si") << std::endl;
    1216                 :            :       }
    1217                 :            :     }
    1218                 :            :     // Trace("uf-ss-lemma") << d_th->getEqualityEngine()->areEqual( s[0], s[1] )
    1219                 :            :     // << " "; Trace("uf-ss-lemma") << d_th->getEqualityEngine()->areDisequal(
    1220                 :            :     // s[0], s[1] ) << std::endl; Trace("uf-ss-lemma") << s[0].getType() << " "
    1221                 :            :     // << s[1].getType() << std::endl; split on the equality s
    1222                 :       5900 :     Node lem = NodeManager::mkNode(Kind::OR, ss, ss.negate());
    1223                 :            :     // send lemma, with caching
    1224         [ +  - ]:       2950 :     if (d_im.lemma(lem, InferenceId::UF_CARD_SPLIT))
    1225                 :            :     {
    1226         [ +  - ]:       2950 :       Trace("uf-ss-lemma") << "*** Split on " << s << std::endl;
    1227                 :            :       // tell the sat solver to explore the equals branch first
    1228                 :       2950 :       d_im.preferPhase(ss, true);
    1229                 :       2950 :       ++(d_thss->d_statistics.d_split_lemmas);
    1230                 :            :     }
    1231                 :       2950 :     return 1;
    1232                 :       2950 :   }
    1233                 :            :   else
    1234                 :            :   {
    1235                 :          0 :     return 0;
    1236                 :            :   }
    1237                 :       2950 : }
    1238                 :            : 
    1239                 :       4541 : void SortModel::addCliqueLemma(std::vector<Node>& clique)
    1240                 :            : {
    1241 [ -  + ][ -  + ]:       4541 :   Assert(d_hasCard);
                 [ -  - ]
    1242 [ -  + ][ -  + ]:       4541 :   Assert(d_cardinality > 0);
                 [ -  - ]
    1243         [ +  + ]:       7191 :   while (clique.size() > d_cardinality + 1)
    1244                 :            :   {
    1245                 :       2650 :     clique.pop_back();
    1246                 :            :   }
    1247                 :            :   // add as lemma
    1248                 :       4541 :   std::vector<Node> eqs;
    1249         [ +  + ]:      24040 :   for (unsigned i = 0, size = clique.size(); i < size; i++)
    1250                 :            :   {
    1251         [ +  + ]:      76622 :     for (unsigned j = 0; j < i; j++)
    1252                 :            :     {
    1253                 :      57123 :       eqs.push_back(clique[i].eqNode(clique[j]));
    1254                 :            :     }
    1255                 :            :   }
    1256                 :       4541 :   eqs.push_back(d_cardinality_literal[d_cardinality].notNode());
    1257                 :       4541 :   Node lem = nodeManager()->mkNode(Kind::OR, eqs);
    1258                 :            :   // send lemma, with caching
    1259         [ +  - ]:       4541 :   if (d_im.lemma(lem, InferenceId::UF_CARD_CLIQUE))
    1260                 :            :   {
    1261         [ +  - ]:       4541 :     Trace("uf-ss-lemma") << "*** Add clique lemma " << lem << std::endl;
    1262                 :       4541 :     ++(d_thss->d_statistics.d_clique_lemmas);
    1263                 :            :   }
    1264                 :       4541 : }
    1265                 :            : 
    1266                 :      12678 : void SortModel::simpleCheckCardinality()
    1267                 :            : {
    1268         [ +  + ]:      20185 :   if (d_maxNegCard.get() != 0 && d_hasCard.get()
    1269 [ +  + ][ +  + ]:      20185 :       && d_cardinality.get() < d_maxNegCard.get())
                 [ +  + ]
    1270                 :            :   {
    1271                 :        687 :     Node lem = NodeManager::mkNode(
    1272                 :            :         Kind::AND,
    1273                 :        229 :         {getCardinalityLiteral(d_cardinality.get()),
    1274                 :        458 :          getCardinalityLiteral(d_maxNegCard.get()).negate()});
    1275         [ +  - ]:        458 :     Trace("uf-ss-lemma") << "*** Simple cardinality conflict : " << lem
    1276                 :        229 :                          << std::endl;
    1277                 :        229 :     d_im.conflict(lem, InferenceId::UF_CARD_SIMPLE_CONFLICT);
    1278                 :        229 :   }
    1279                 :      12678 : }
    1280                 :            : 
    1281                 :      14140 : void SortModel::debugPrint(const char* c)
    1282                 :            : {
    1283         [ -  + ]:      14140 :   if (TraceIsOn(c))
    1284                 :            :   {
    1285         [ -  - ]:          0 :     Trace(c) << "Number of reps = " << d_reps << std::endl;
    1286         [ -  - ]:          0 :     Trace(c) << "Cardinality req = " << d_cardinality << std::endl;
    1287                 :          0 :     unsigned debugReps = 0;
    1288         [ -  - ]:          0 :     for (unsigned i = 0; i < d_regions_index; i++)
    1289                 :            :     {
    1290                 :          0 :       Region* region = d_regions[i];
    1291         [ -  - ]:          0 :       if (region->valid())
    1292                 :            :       {
    1293         [ -  - ]:          0 :         Trace(c) << "Region #" << i << ": " << std::endl;
    1294                 :          0 :         region->debugPrint(c, true);
    1295         [ -  - ]:          0 :         Trace(c) << std::endl;
    1296         [ -  - ]:          0 :         for (Region::iterator it = region->begin(); it != region->end(); ++it)
    1297                 :            :         {
    1298         [ -  - ]:          0 :           if (it->second->valid())
    1299                 :            :           {
    1300         [ -  - ]:          0 :             if (d_regions_map[it->first] != (int)i)
    1301                 :            :             {
    1302         [ -  - ]:          0 :               Trace(c) << "***Bad regions map : " << it->first << " "
    1303                 :          0 :                        << d_regions_map[it->first].get() << std::endl;
    1304                 :            :             }
    1305                 :            :           }
    1306                 :            :         }
    1307                 :          0 :         debugReps += region->getNumReps();
    1308                 :            :       }
    1309                 :            :     }
    1310                 :            : 
    1311         [ -  - ]:          0 :     if (debugReps != d_reps)
    1312                 :            :     {
    1313         [ -  - ]:          0 :       Trace(c) << "***Bad reps: " << d_reps << ", "
    1314                 :          0 :                << "actual = " << debugReps << std::endl;
    1315                 :            :     }
    1316                 :            :   }
    1317                 :      14140 : }
    1318                 :            : 
    1319                 :       2040 : bool SortModel::checkLastCall()
    1320                 :            : {
    1321                 :       2040 :   TheoryModel* m = d_state.getModel();
    1322         [ -  + ]:       2040 :   if (TraceIsOn("uf-ss-warn"))
    1323                 :            :   {
    1324                 :          0 :     std::vector<Node> eqcs;
    1325                 :            :     eq::EqClassesIterator eqcs_i =
    1326                 :          0 :         eq::EqClassesIterator(m->getEqualityEngine());
    1327         [ -  - ]:          0 :     while (!eqcs_i.isFinished())
    1328                 :            :     {
    1329                 :          0 :       Node eqc = (*eqcs_i);
    1330         [ -  - ]:          0 :       if (eqc.getType() == d_type)
    1331                 :            :       {
    1332         [ -  - ]:          0 :         if (std::find(eqcs.begin(), eqcs.end(), eqc) == eqcs.end())
    1333                 :            :         {
    1334                 :          0 :           eqcs.push_back(eqc);
    1335                 :            :           // we must ensure that this equivalence class has been accounted for
    1336         [ -  - ]:          0 :           if (d_regions_map.find(eqc) == d_regions_map.end())
    1337                 :            :           {
    1338         [ -  - ]:          0 :             Trace("uf-ss-warn") << "WARNING : equivalence class " << eqc
    1339                 :          0 :                                 << " unaccounted for." << std::endl;
    1340         [ -  - ]:          0 :             Trace("uf-ss-warn") << "  type : " << d_type << std::endl;
    1341         [ -  - ]:          0 :             Trace("uf-ss-warn") << "  kind : " << eqc.getKind() << std::endl;
    1342                 :            :           }
    1343                 :            :         }
    1344                 :            :       }
    1345                 :          0 :       ++eqcs_i;
    1346                 :          0 :     }
    1347                 :          0 :   }
    1348                 :       2040 :   RepSet* rs = m->getRepSetPtr();
    1349                 :       2040 :   size_t nReps = rs->getNumRepresentatives(d_type);
    1350         [ +  + ]:       2040 :   if (nReps != d_maxNegCard + 1)
    1351                 :            :   {
    1352         [ +  - ]:         72 :     Trace("uf-ss-warn") << "WARNING : Model does not have same # "
    1353                 :          0 :                            "representatives as cardinality for "
    1354                 :         36 :                         << d_type << "." << std::endl;
    1355         [ +  - ]:         72 :     Trace("uf-ss-warn") << "   Max neg cardinality : " << d_maxNegCard
    1356                 :         36 :                         << std::endl;
    1357         [ +  - ]:         36 :     Trace("uf-ss-warn") << "   # Reps : " << nReps << std::endl;
    1358         [ +  - ]:         36 :     if (d_maxNegCard >= nReps)
    1359                 :            :     {
    1360         [ +  + ]:        324 :       while (d_fresh_aloc_reps.size() <= d_maxNegCard)
    1361                 :            :       {
    1362                 :        288 :         std::stringstream ss;
    1363                 :        288 :         ss << "r_" << d_type;
    1364                 :        288 :         Node nn = NodeManager::mkDummySkolem(ss.str(), d_type);
    1365                 :        288 :         d_fresh_aloc_reps.push_back(nn);
    1366                 :        288 :       }
    1367         [ +  + ]:         36 :       if (d_maxNegCard == 0)
    1368                 :            :       {
    1369                 :          6 :         rs->d_type_reps[d_type].push_back(d_fresh_aloc_reps[0]);
    1370                 :            :       }
    1371                 :            :       else
    1372                 :            :       {
    1373                 :            :         // must add lemma
    1374                 :         30 :         std::vector<Node> force_cl;
    1375         [ +  + ]:        312 :         for (size_t i = 0; i <= d_maxNegCard; i++)
    1376                 :            :         {
    1377         [ +  + ]:       2428 :           for (size_t j = (i + 1); j <= d_maxNegCard; j++)
    1378                 :            :           {
    1379                 :       2146 :             force_cl.push_back(
    1380                 :       4292 :                 d_fresh_aloc_reps[i].eqNode(d_fresh_aloc_reps[j]).negate());
    1381                 :            :           }
    1382                 :            :         }
    1383                 :         30 :         Node cl = getCardinalityLiteral(d_maxNegCard);
    1384                 :            :         Node lem =
    1385                 :         60 :             NodeManager::mkNode(Kind::OR, cl, nodeManager()->mkAnd(force_cl));
    1386         [ +  - ]:         60 :         Trace("uf-ss-lemma")
    1387                 :          0 :             << "*** Enforce negative cardinality constraint lemma : " << lem
    1388                 :         30 :             << std::endl;
    1389                 :         30 :         d_im.lemma(lem, InferenceId::UF_CARD_ENFORCE_NEGATIVE);
    1390                 :         30 :         return false;
    1391                 :         30 :       }
    1392                 :            :     }
    1393                 :            :   }
    1394                 :       2010 :   return true;
    1395                 :            : }
    1396                 :            : 
    1397                 :          0 : int SortModel::getNumRegions()
    1398                 :            : {
    1399                 :          0 :   int count = 0;
    1400         [ -  - ]:          0 :   for (int i = 0; i < (int)d_regions_index; i++)
    1401                 :            :   {
    1402         [ -  - ]:          0 :     if (d_regions[i]->valid())
    1403                 :            :     {
    1404                 :          0 :       count++;
    1405                 :            :     }
    1406                 :            :   }
    1407                 :          0 :   return count;
    1408                 :            : }
    1409                 :            : 
    1410                 :      15747 : Node SortModel::getCardinalityLiteral(uint32_t c)
    1411                 :            : {
    1412 [ -  + ][ -  + ]:      15747 :   Assert(c > 0);
                 [ -  - ]
    1413                 :      15747 :   std::map<uint32_t, Node>::iterator itcl = d_cardinality_literal.find(c);
    1414         [ +  + ]:      15747 :   if (itcl != d_cardinality_literal.end())
    1415                 :            :   {
    1416                 :      14179 :     return itcl->second;
    1417                 :            :   }
    1418                 :            :   // get the literal from the decision strategy
    1419                 :       1568 :   Node lit = d_c_dec_strat->getLiteral(c - 1);
    1420                 :       1568 :   d_cardinality_literal[c] = lit;
    1421                 :            : 
    1422                 :            :   // return the literal
    1423                 :       1568 :   return lit;
    1424                 :       1568 : }
    1425                 :            : 
    1426                 :        741 : CardinalityExtension::CardinalityExtension(Env& env,
    1427                 :            :                                            TheoryState& state,
    1428                 :            :                                            TheoryInferenceManager& im,
    1429                 :        741 :                                            TheoryUF* th)
    1430                 :            :     : EnvObj(env),
    1431                 :        741 :       d_statistics(statisticsRegistry()),
    1432                 :        741 :       d_state(state),
    1433                 :        741 :       d_im(im),
    1434                 :        741 :       d_th(th),
    1435                 :        741 :       d_rep_model(),
    1436                 :        741 :       d_min_pos_com_card(context(), 0),
    1437                 :        741 :       d_min_pos_com_card_set(context(), false),
    1438                 :        741 :       d_cc_dec_strat(nullptr),
    1439                 :        741 :       d_initializedCombinedCardinality(userContext(), false),
    1440                 :        741 :       d_card_assertions_eqv_lemma(userContext()),
    1441                 :        741 :       d_min_pos_tn_master_card(context(), 0),
    1442                 :        741 :       d_min_pos_tn_master_card_set(context(), false),
    1443                 :       1482 :       d_rel_eqc(context())
    1444                 :            : {
    1445                 :        741 :   if (options().uf.ufssMode == options::UfssMode::FULL
    1446 [ +  + ][ +  - ]:        741 :       && options().uf.ufssFairness)
                 [ +  + ]
    1447                 :            :   {
    1448                 :            :     // Register the strategy with the decision manager of the theory.
    1449                 :            :     // We are guaranteed that the decision manager is ready since we
    1450                 :            :     // construct this module during TheoryUF::finishInit.
    1451                 :        727 :     d_cc_dec_strat.reset(
    1452                 :        727 :         new CombinedCardinalityDecisionStrategy(env, th->getValuation()));
    1453                 :            :   }
    1454                 :        741 : }
    1455                 :            : 
    1456                 :       1478 : CardinalityExtension::~CardinalityExtension()
    1457                 :            : {
    1458                 :        739 :   for (std::map<TypeNode, SortModel*>::iterator it = d_rep_model.begin();
    1459         [ +  + ]:       1459 :        it != d_rep_model.end();
    1460                 :        720 :        ++it)
    1461                 :            :   {
    1462         [ +  - ]:        720 :     delete it->second;
    1463                 :            :   }
    1464                 :       1478 : }
    1465                 :            : 
    1466                 :            : /** ensure eqc */
    1467                 :          0 : void CardinalityExtension::ensureEqc(SortModel* c, Node a)
    1468                 :            : {
    1469         [ -  - ]:          0 :   if (!hasEqc(a))
    1470                 :            :   {
    1471                 :          0 :     d_rel_eqc[a] = true;
    1472         [ -  - ]:          0 :     Trace("uf-ss-solver") << "CardinalityExtension: New eq class " << a << " : "
    1473                 :          0 :                           << a.getType() << std::endl;
    1474                 :          0 :     c->newEqClass(a);
    1475         [ -  - ]:          0 :     Trace("uf-ss-solver") << "CardinalityExtension: Done New eq class."
    1476                 :          0 :                           << std::endl;
    1477                 :            :   }
    1478                 :          0 : }
    1479                 :            : 
    1480                 :          0 : void CardinalityExtension::ensureEqcRec(Node n)
    1481                 :            : {
    1482         [ -  - ]:          0 :   if (!hasEqc(n))
    1483                 :            :   {
    1484                 :          0 :     SortModel* c = getSortModel(n);
    1485         [ -  - ]:          0 :     if (c)
    1486                 :            :     {
    1487                 :          0 :       ensureEqc(c, n);
    1488                 :            :     }
    1489         [ -  - ]:          0 :     for (unsigned i = 0; i < n.getNumChildren(); i++)
    1490                 :            :     {
    1491                 :          0 :       ensureEqcRec(n[i]);
    1492                 :            :     }
    1493                 :            :   }
    1494                 :          0 : }
    1495                 :            : 
    1496                 :            : /** has eqc */
    1497                 :          0 : bool CardinalityExtension::hasEqc(Node a)
    1498                 :            : {
    1499                 :          0 :   NodeBoolMap::iterator it = d_rel_eqc.find(a);
    1500                 :          0 :   return it != d_rel_eqc.end() && (*it).second;
    1501                 :            : }
    1502                 :            : 
    1503                 :            : /** new node */
    1504                 :      54045 : void CardinalityExtension::newEqClass(Node a)
    1505                 :            : {
    1506                 :      54045 :   SortModel* c = getSortModel(a);
    1507         [ +  + ]:      54045 :   if (c)
    1508                 :            :   {
    1509         [ +  - ]:      15356 :     Trace("uf-ss-solver") << "CardinalityExtension: New eq class " << a << " : "
    1510 [ -  + ][ -  - ]:       7678 :                           << a.getType() << std::endl;
    1511                 :       7678 :     c->newEqClass(a);
    1512         [ +  - ]:      15356 :     Trace("uf-ss-solver") << "CardinalityExtension: Done New eq class."
    1513                 :       7678 :                           << std::endl;
    1514                 :            :   }
    1515                 :      54045 : }
    1516                 :            : 
    1517                 :            : /** merge */
    1518                 :     354431 : void CardinalityExtension::merge(Node a, Node b)
    1519                 :            : {
    1520                 :            :   // TODO: ensure they are relevant
    1521                 :     354431 :   SortModel* c = getSortModel(a);
    1522         [ +  + ]:     354431 :   if (c)
    1523                 :            :   {
    1524         [ +  - ]:      97840 :     Trace("uf-ss-solver") << "CardinalityExtension: Merge " << a << " " << b
    1525 [ -  + ][ -  - ]:      48920 :                           << " : " << a.getType() << std::endl;
    1526                 :      48920 :     c->merge(a, b);
    1527         [ +  - ]:      48920 :     Trace("uf-ss-solver") << "CardinalityExtension: Done Merge." << std::endl;
    1528                 :            :   }
    1529                 :     354431 : }
    1530                 :            : 
    1531                 :            : /** assert terms are disequal */
    1532                 :      40556 : void CardinalityExtension::assertDisequal(Node a, Node b, Node reason)
    1533                 :            : {
    1534                 :      40556 :   SortModel* c = getSortModel(a);
    1535         [ +  + ]:      40556 :   if (c)
    1536                 :            :   {
    1537         [ +  - ]:      42972 :     Trace("uf-ss-solver") << "CardinalityExtension: Assert disequal " << a
    1538 [ -  + ][ -  - ]:      21486 :                           << " " << b << " : " << a.getType() << std::endl;
    1539                 :      21486 :     c->assertDisequal(a, b, reason);
    1540         [ +  - ]:      42972 :     Trace("uf-ss-solver") << "CardinalityExtension: Done Assert disequal."
    1541                 :      21486 :                           << std::endl;
    1542                 :            :   }
    1543                 :      40556 : }
    1544                 :            : 
    1545                 :            : /** assert a node */
    1546                 :     254447 : void CardinalityExtension::assertNode(Node n, bool isDecision)
    1547                 :            : {
    1548         [ +  - ]:     254447 :   Trace("uf-ss") << "Assert " << n << " " << isDecision << std::endl;
    1549                 :     254447 :   bool polarity = n.getKind() != Kind::NOT;
    1550         [ +  + ]:     254447 :   TNode lit = polarity ? n : n[0];
    1551         [ +  + ]:     254447 :   if (options().uf.ufssMode == options::UfssMode::FULL)
    1552                 :            :   {
    1553         [ +  + ]:     187632 :     if (lit.getKind() == Kind::CARDINALITY_CONSTRAINT)
    1554                 :            :     {
    1555                 :            :       const CardinalityConstraint& cc =
    1556                 :      12950 :           lit.getOperator().getConst<CardinalityConstraint>();
    1557                 :      12950 :       TypeNode tn = cc.getType();
    1558 [ -  + ][ -  + ]:      12950 :       Assert(tn.isUninterpretedSort());
                 [ -  - ]
    1559 [ -  + ][ -  + ]:      12950 :       Assert(d_rep_model[tn]);
                 [ -  - ]
    1560                 :      12950 :       uint32_t nCard = cc.getUpperBound().getUnsignedInt();
    1561         [ +  - ]:      25900 :       Trace("uf-ss-debug") << "...check cardinality constraint : " << tn
    1562                 :      12950 :                            << std::endl;
    1563         [ +  - ]:      12950 :       Trace("uf-ss-com-card-debug") << "...assert cardinality" << std::endl;
    1564                 :      12950 :       d_rep_model[tn]->assertCardinality(nCard, polarity);
    1565                 :            :       // check if combined cardinality is violated
    1566                 :      12950 :       checkCombinedCardinality();
    1567                 :      12950 :     }
    1568         [ +  + ]:     174682 :     else if (lit.getKind() == Kind::COMBINED_CARDINALITY_CONSTRAINT)
    1569                 :            :     {
    1570         [ +  + ]:       7204 :       if (polarity)
    1571                 :            :       {
    1572                 :            :         // safe to assume int here
    1573                 :            :         const CombinedCardinalityConstraint& cc =
    1574                 :       5755 :             lit.getOperator().getConst<CombinedCardinalityConstraint>();
    1575                 :       5755 :         uint32_t nCard = cc.getUpperBound().getUnsignedInt();
    1576 [ -  + ][ -  - ]:       5755 :         if (!d_min_pos_com_card_set.get() || nCard < d_min_pos_com_card.get())
                 [ +  - ]
    1577                 :            :         {
    1578                 :       5755 :           d_min_pos_com_card_set.set(true);
    1579                 :       5755 :           d_min_pos_com_card.set(nCard);
    1580                 :       5755 :           checkCombinedCardinality();
    1581                 :            :         }
    1582                 :            :       }
    1583                 :            :     }
    1584                 :            :     else
    1585                 :            :     {
    1586         [ -  + ]:     167478 :       if (TraceIsOn("uf-ss-warn"))
    1587                 :            :       {
    1588                 :            :         ////FIXME: this is too strict: theory propagations are showing up as
    1589                 :            :         /// isDecision=true, but /       a theory propagation is not a decision.
    1590         [ -  - ]:          0 :         if (isDecision)
    1591                 :            :         {
    1592                 :          0 :           for (std::map<TypeNode, SortModel*>::iterator it =
    1593                 :          0 :                    d_rep_model.begin();
    1594         [ -  - ]:          0 :                it != d_rep_model.end();
    1595                 :          0 :                ++it)
    1596                 :            :           {
    1597         [ -  - ]:          0 :             if (!it->second->hasCardinalityAsserted())
    1598                 :            :             {
    1599         [ -  - ]:          0 :               Trace("uf-ss-warn") << "WARNING: Assert " << n
    1600                 :          0 :                                   << " as a decision before cardinality for "
    1601                 :          0 :                                   << it->first << "." << std::endl;
    1602                 :            :             }
    1603                 :            :           }
    1604                 :            :         }
    1605                 :            :       }
    1606                 :            :     }
    1607                 :            :   }
    1608                 :            :   else
    1609                 :            :   {
    1610                 :      66815 :     if (lit.getKind() == Kind::CARDINALITY_CONSTRAINT
    1611 [ +  + ][ -  + ]:      66815 :         || lit.getKind() == Kind::COMBINED_CARDINALITY_CONSTRAINT)
                 [ +  + ]
    1612                 :            :     {
    1613                 :            :       // cardinality constraint from user input, set incomplete
    1614         [ +  - ]:          4 :       Trace("uf-ss")
    1615                 :          0 :           << "Literal " << lit
    1616                 :          0 :           << " not handled when uf ss mode is not FULL, set incomplete."
    1617                 :          2 :           << std::endl;
    1618                 :          2 :       d_im.setModelUnsound(IncompleteId::UF_CARD_MODE);
    1619                 :            :     }
    1620                 :            :   }
    1621         [ +  - ]:     254447 :   Trace("uf-ss") << "Assert: done " << n << " " << isDecision << std::endl;
    1622                 :     254447 : }
    1623                 :            : 
    1624                 :          0 : bool CardinalityExtension::areDisequal(Node a, Node b)
    1625                 :            : {
    1626         [ -  - ]:          0 :   if (a == b)
    1627                 :            :   {
    1628                 :          0 :     return false;
    1629                 :            :   }
    1630                 :          0 :   eq::EqualityEngine* ee = d_th->getEqualityEngine();
    1631                 :          0 :   a = ee->getRepresentative(a);
    1632                 :          0 :   b = ee->getRepresentative(b);
    1633         [ -  - ]:          0 :   if (ee->areDisequal(a, b, false))
    1634                 :            :   {
    1635                 :          0 :     return true;
    1636                 :            :   }
    1637                 :          0 :   SortModel* c = getSortModel(a);
    1638         [ -  - ]:          0 :   if (c)
    1639                 :            :   {
    1640                 :          0 :     return c->areDisequal(a, b);
    1641                 :            :   }
    1642                 :          0 :   return false;
    1643                 :            : }
    1644                 :            : 
    1645                 :            : /** check */
    1646                 :     120648 : void CardinalityExtension::check(Theory::Effort level)
    1647                 :            : {
    1648         [ +  + ]:     120648 :   if (level == Theory::EFFORT_LAST_CALL)
    1649                 :            :   {
    1650                 :            :     // if last call, call last call check for each sort
    1651         [ +  + ]:       3641 :     for (std::pair<const TypeNode, SortModel*>& r : d_rep_model)
    1652                 :            :     {
    1653         [ +  + ]:       2040 :       if (!r.second->checkLastCall())
    1654                 :            :       {
    1655                 :         30 :         break;
    1656                 :            :       }
    1657                 :            :     }
    1658                 :       1631 :     return;
    1659                 :            :   }
    1660         [ +  - ]:     119017 :   if (!d_state.isInConflict())
    1661                 :            :   {
    1662         [ +  + ]:     119017 :     if (options().uf.ufssMode == options::UfssMode::FULL)
    1663                 :            :     {
    1664         [ +  - ]:     168746 :       Trace("uf-ss-solver")
    1665                 :      84373 :           << "CardinalityExtension: check " << level << std::endl;
    1666         [ +  + ]:      84373 :       if (level == Theory::EFFORT_FULL)
    1667                 :            :       {
    1668         [ -  + ]:       6916 :         if (TraceIsOn("uf-ss-debug"))
    1669                 :            :         {
    1670                 :          0 :           debugPrint("uf-ss-debug");
    1671                 :            :         }
    1672         [ -  + ]:       6916 :         if (TraceIsOn("uf-ss-state"))
    1673                 :            :         {
    1674         [ -  - ]:          0 :           Trace("uf-ss-state")
    1675                 :          0 :               << "CardinalityExtension::check " << level << std::endl;
    1676         [ -  - ]:          0 :           for (std::pair<const TypeNode, SortModel*>& rm : d_rep_model)
    1677                 :            :           {
    1678         [ -  - ]:          0 :             Trace("uf-ss-state") << "  " << rm.first << " has cardinality "
    1679                 :          0 :                                  << rm.second->getCardinality() << std::endl;
    1680                 :            :           }
    1681                 :            :         }
    1682                 :            :       }
    1683                 :      84373 :       for (std::map<TypeNode, SortModel*>::iterator it = d_rep_model.begin();
    1684         [ +  + ]:     416344 :            it != d_rep_model.end();
    1685                 :     331971 :            ++it)
    1686                 :            :       {
    1687                 :     331971 :         it->second->check(level);
    1688         [ -  + ]:     331971 :         if (d_state.isInConflict())
    1689                 :            :         {
    1690                 :          0 :           break;
    1691                 :            :         }
    1692                 :            :       }
    1693                 :            :     }
    1694         [ +  - ]:      34644 :     else if (options().uf.ufssMode == options::UfssMode::NO_MINIMAL)
    1695                 :            :     {
    1696         [ +  + ]:      34644 :       if (level == Theory::EFFORT_FULL)
    1697                 :            :       {
    1698                 :            :         // split on an equality between two equivalence classes (at most one per
    1699                 :            :         // type)
    1700                 :        918 :         std::map<TypeNode, std::vector<Node> > eqc_list;
    1701                 :        918 :         std::map<TypeNode, bool> type_proc;
    1702                 :        918 :         eq::EqClassesIterator eqcs_i(d_th->getEqualityEngine());
    1703         [ +  + ]:      78838 :         while (!eqcs_i.isFinished())
    1704                 :            :         {
    1705                 :      77920 :           Node a = *eqcs_i;
    1706                 :      77920 :           TypeNode tn = a.getType();
    1707         [ +  + ]:      77920 :           if (tn.isUninterpretedSort())
    1708                 :            :           {
    1709         [ +  + ]:      12032 :             if (type_proc.find(tn) == type_proc.end())
    1710                 :            :             {
    1711                 :            :               std::map<TypeNode, std::vector<Node> >::iterator itel =
    1712                 :       9898 :                   eqc_list.find(tn);
    1713         [ +  + ]:       9898 :               if (itel != eqc_list.end())
    1714                 :            :               {
    1715         [ +  + ]:      16873 :                 for (unsigned j = 0; j < itel->second.size(); j++)
    1716                 :            :                 {
    1717                 :      11547 :                   Node b = itel->second[j];
    1718         [ +  + ]:      11547 :                   if (!d_th->getEqualityEngine()->areDisequal(a, b, false))
    1719                 :            :                   {
    1720                 :       1862 :                     Node eq = rewrite(a.eqNode(b));
    1721                 :       1862 :                     Node lem = NodeManager::mkNode(Kind::OR, eq, eq.negate());
    1722         [ +  - ]:       1862 :                     Trace("uf-ss-lemma")
    1723                 :        931 :                         << "*** Split (no-minimal) : " << lem << std::endl;
    1724                 :        931 :                     d_im.lemma(lem, InferenceId::UF_CARD_SPLIT);
    1725                 :        931 :                     d_im.preferPhase(eq, true);
    1726                 :        931 :                     type_proc[tn] = true;
    1727                 :        931 :                     break;
    1728                 :        931 :                   }
    1729         [ +  + ]:      11547 :                 }
    1730                 :            :               }
    1731                 :       9898 :               eqc_list[tn].push_back(a);
    1732                 :            :             }
    1733                 :            :           }
    1734                 :      77920 :           ++eqcs_i;
    1735                 :      77920 :         }
    1736                 :        918 :       }
    1737                 :            :     }
    1738                 :            :     else
    1739                 :            :     {
    1740                 :            :       // unhandled uf ss mode
    1741                 :          0 :       DebugUnhandled();
    1742                 :            :     }
    1743         [ +  - ]:     238034 :     Trace("uf-ss-solver") << "Done CardinalityExtension: check " << level
    1744                 :     119017 :                           << std::endl;
    1745                 :            :   }
    1746                 :            : }
    1747                 :            : 
    1748                 :        740 : void CardinalityExtension::presolve()
    1749                 :            : {
    1750                 :        740 :   d_initializedCombinedCardinality = false;
    1751                 :        740 :   for (std::map<TypeNode, SortModel*>::iterator it = d_rep_model.begin();
    1752         [ +  + ]:       1177 :        it != d_rep_model.end();
    1753                 :        437 :        ++it)
    1754                 :            :   {
    1755                 :        437 :     it->second->presolve();
    1756                 :        437 :     it->second->initialize();
    1757                 :            :   }
    1758                 :        740 : }
    1759                 :            : 
    1760                 :        727 : CardinalityExtension::CombinedCardinalityDecisionStrategy::
    1761                 :        727 :     CombinedCardinalityDecisionStrategy(Env& env, Valuation valuation)
    1762                 :        727 :     : DecisionStrategyFmf(env, valuation)
    1763                 :            : {
    1764                 :        727 : }
    1765                 :       1273 : Node CardinalityExtension::CombinedCardinalityDecisionStrategy::mkLiteral(
    1766                 :            :     unsigned i)
    1767                 :            : {
    1768                 :       1273 :   NodeManager* nm = nodeManager();
    1769                 :       2546 :   Node cco = nm->mkConst(CombinedCardinalityConstraint(Integer(i)));
    1770                 :       2546 :   return nm->mkNode(Kind::COMBINED_CARDINALITY_CONSTRAINT, cco);
    1771                 :       1273 : }
    1772                 :            : 
    1773                 :            : std::string
    1774                 :          0 : CardinalityExtension::CombinedCardinalityDecisionStrategy::identify() const
    1775                 :            : {
    1776                 :          0 :   return std::string("uf_combined_card");
    1777                 :            : }
    1778                 :            : 
    1779                 :     431161 : void CardinalityExtension::preRegisterTerm(TNode n)
    1780                 :            : {
    1781         [ +  + ]:     431161 :   if (options().uf.ufssMode != options::UfssMode::FULL)
    1782                 :            :   {
    1783                 :     407063 :     return;
    1784                 :            :   }
    1785                 :            :   // initialize combined cardinality
    1786                 :     302367 :   initializeCombinedCardinality();
    1787                 :            : 
    1788         [ +  - ]:     302367 :   Trace("uf-ss-register") << "Preregister " << n << "." << std::endl;
    1789                 :            :   // shouldn't have to preregister this type (it may be that there are no
    1790                 :            :   // quantifiers over tn)
    1791                 :     302367 :   TypeNode tn;
    1792         [ +  + ]:     302367 :   if (n.getKind() == Kind::CARDINALITY_CONSTRAINT)
    1793                 :            :   {
    1794                 :            :     const CardinalityConstraint& cc =
    1795                 :      16680 :         n.getOperator().getConst<CardinalityConstraint>();
    1796                 :      16680 :     tn = cc.getType();
    1797                 :            :   }
    1798                 :            :   else
    1799                 :            :   {
    1800                 :     285687 :     tn = n.getType();
    1801                 :            :   }
    1802         [ +  + ]:     302367 :   if (!tn.isUninterpretedSort())
    1803                 :            :   {
    1804                 :     278269 :     return;
    1805                 :            :   }
    1806                 :      24098 :   std::map<TypeNode, SortModel*>::iterator it = d_rep_model.find(tn);
    1807         [ +  + ]:      24098 :   if (it == d_rep_model.end())
    1808                 :            :   {
    1809                 :        722 :     SortModel* rm = nullptr;
    1810         [ +  - ]:        722 :     if (tn.isUninterpretedSort())
    1811                 :            :     {
    1812         [ +  - ]:        722 :       Trace("uf-ss-register") << "Create sort model " << tn << "." << std::endl;
    1813                 :        722 :       rm = new SortModel(d_env, tn, d_state, d_im, this);
    1814                 :            :     }
    1815         [ +  - ]:        722 :     if (rm)
    1816                 :            :     {
    1817                 :        722 :       rm->initialize();
    1818                 :        722 :       d_rep_model[tn] = rm;
    1819                 :            :       // d_rep_model_init[tn] = true;
    1820                 :            :     }
    1821                 :            :   }
    1822                 :            :   else
    1823                 :            :   {
    1824                 :            :     // ensure sort model is initialized
    1825                 :      23376 :     it->second->initialize();
    1826                 :            :   }
    1827         [ +  + ]:     302367 : }
    1828                 :            : 
    1829                 :     449032 : SortModel* CardinalityExtension::getSortModel(Node n)
    1830                 :            : {
    1831                 :     449032 :   TypeNode tn = n.getType();
    1832                 :     449032 :   std::map<TypeNode, SortModel*>::iterator it = d_rep_model.find(tn);
    1833                 :            :   // pre-register the type if not done already
    1834         [ +  + ]:     449032 :   if (it == d_rep_model.end())
    1835                 :            :   {
    1836                 :     370948 :     preRegisterTerm(n);
    1837                 :     370948 :     it = d_rep_model.find(tn);
    1838                 :            :   }
    1839         [ +  + ]:     449032 :   if (it != d_rep_model.end())
    1840                 :            :   {
    1841                 :      78084 :     return it->second;
    1842                 :            :   }
    1843                 :            :   else
    1844                 :            :   {
    1845                 :     370948 :     return nullptr;
    1846                 :            :   }
    1847                 :     449032 : }
    1848                 :            : 
    1849                 :            : /** get cardinality for sort */
    1850                 :          0 : int CardinalityExtension::getCardinality(Node n)
    1851                 :            : {
    1852                 :          0 :   SortModel* c = getSortModel(n);
    1853         [ -  - ]:          0 :   if (c)
    1854                 :            :   {
    1855                 :          0 :     return c->getCardinality();
    1856                 :            :   }
    1857                 :            :   else
    1858                 :            :   {
    1859                 :          0 :     return -1;
    1860                 :            :   }
    1861                 :            : }
    1862                 :            : 
    1863                 :          0 : int CardinalityExtension::getCardinality(TypeNode tn)
    1864                 :            : {
    1865                 :          0 :   std::map<TypeNode, SortModel*>::iterator it = d_rep_model.find(tn);
    1866 [ -  - ][ -  - ]:          0 :   if (it != d_rep_model.end() && it->second)
                 [ -  - ]
    1867                 :            :   {
    1868                 :          0 :     return it->second->getCardinality();
    1869                 :            :   }
    1870                 :          0 :   return -1;
    1871                 :            : }
    1872                 :            : 
    1873                 :            : // print debug
    1874                 :          0 : void CardinalityExtension::debugPrint(const char* c)
    1875                 :            : {
    1876                 :          0 :   for (std::map<TypeNode, SortModel*>::iterator it = d_rep_model.begin();
    1877         [ -  - ]:          0 :        it != d_rep_model.end();
    1878                 :          0 :        ++it)
    1879                 :            :   {
    1880         [ -  - ]:          0 :     Trace(c) << "Conflict find structure for " << it->first << ": "
    1881                 :          0 :              << std::endl;
    1882                 :          0 :     it->second->debugPrint(c);
    1883         [ -  - ]:          0 :     Trace(c) << std::endl;
    1884                 :            :   }
    1885                 :          0 : }
    1886                 :            : 
    1887                 :            : /** initialize */
    1888                 :     302367 : void CardinalityExtension::initializeCombinedCardinality()
    1889                 :            : {
    1890                 :     302367 :   if (d_cc_dec_strat.get() != nullptr
    1891 [ +  - ][ +  + ]:     302367 :       && !d_initializedCombinedCardinality.get())
                 [ +  + ]
    1892                 :            :   {
    1893                 :        745 :     d_initializedCombinedCardinality = true;
    1894                 :       1490 :     d_im.getDecisionManager()->registerStrategy(
    1895                 :        745 :         DecisionManager::STRAT_UF_COMBINED_CARD, d_cc_dec_strat.get());
    1896                 :            :   }
    1897                 :     302367 : }
    1898                 :            : 
    1899                 :            : /** check */
    1900                 :      18705 : void CardinalityExtension::checkCombinedCardinality()
    1901                 :            : {
    1902 [ -  + ][ -  + ]:      18705 :   Assert(options().uf.ufssMode == options::UfssMode::FULL);
                 [ -  - ]
    1903         [ +  - ]:      18705 :   if (options().uf.ufssFairness)
    1904                 :            :   {
    1905         [ +  - ]:      37410 :     Trace("uf-ss-com-card-debug")
    1906                 :          0 :         << "Check combined cardinality, get maximum negative cardinalities..."
    1907                 :      18705 :         << std::endl;
    1908                 :      18705 :     uint32_t totalCombinedCard = 0;
    1909                 :      18705 :     TypeNode maxSlaveType;
    1910                 :      18705 :     for (std::map<TypeNode, SortModel*>::iterator it = d_rep_model.begin();
    1911         [ +  + ]:     105571 :          it != d_rep_model.end();
    1912                 :      86866 :          ++it)
    1913                 :            :     {
    1914                 :      86866 :       uint32_t max_neg = it->second->getMaximumNegativeCardinality();
    1915                 :      86866 :       totalCombinedCard += max_neg;
    1916                 :            :     }
    1917         [ +  - ]:      37410 :     Trace("uf-ss-com-card-debug")
    1918                 :          0 :         << "Check combined cardinality, total combined card : "
    1919                 :      18705 :         << totalCombinedCard << std::endl;
    1920                 :      18705 :     uint32_t cc = d_min_pos_com_card.get();
    1921 [ +  + ][ +  + ]:      18705 :     if (d_min_pos_com_card_set.get() && totalCombinedCard > cc)
                 [ +  + ]
    1922                 :            :     {
    1923                 :            :       // conflict
    1924                 :       1060 :       Node com_lit = d_cc_dec_strat->getLiteral(cc);
    1925                 :       1060 :       std::vector<Node> conf;
    1926                 :       1060 :       conf.push_back(com_lit);
    1927                 :       1060 :       uint32_t totalAdded = 0;
    1928                 :       1060 :       for (std::map<TypeNode, SortModel*>::iterator it = d_rep_model.begin();
    1929         [ +  - ]:       3185 :            it != d_rep_model.end();
    1930                 :       2125 :            ++it)
    1931                 :            :       {
    1932                 :       3185 :         uint32_t c = it->second->getMaximumNegativeCardinality();
    1933         [ +  + ]:       3185 :         if (c > 0)
    1934                 :            :         {
    1935                 :       2309 :           conf.push_back(it->second->getCardinalityLiteral(c).negate());
    1936                 :       2309 :           totalAdded += c;
    1937                 :            :         }
    1938         [ +  + ]:       3185 :         if (totalAdded > cc)
    1939                 :            :         {
    1940                 :       1060 :           break;
    1941                 :            :         }
    1942                 :            :       }
    1943                 :       1060 :       Node cf = nodeManager()->mkNode(Kind::AND, conf);
    1944         [ +  - ]:       2120 :       Trace("uf-ss-lemma") << "*** Combined cardinality conflict : " << cf
    1945                 :       1060 :                            << std::endl;
    1946         [ +  - ]:       2120 :       Trace("uf-ss-com-card")
    1947                 :       1060 :           << "*** Combined cardinality conflict : " << cf << std::endl;
    1948                 :       1060 :       d_im.conflict(cf, InferenceId::UF_CARD_COMBINED);
    1949                 :       1060 :     }
    1950                 :      18705 :   }
    1951                 :      18705 : }
    1952                 :            : 
    1953                 :        741 : CardinalityExtension::Statistics::Statistics(StatisticsRegistry& sr)
    1954                 :            :     : d_clique_conflicts(
    1955                 :        741 :           sr.registerInt("CardinalityExtension::Clique_Conflicts")),
    1956                 :        741 :       d_clique_lemmas(sr.registerInt("CardinalityExtension::Clique_Lemmas")),
    1957                 :        741 :       d_split_lemmas(sr.registerInt("CardinalityExtension::Split_Lemmas")),
    1958                 :        741 :       d_max_model_size(sr.registerInt("CardinalityExtension::Max_Model_Size"))
    1959                 :            : {
    1960                 :        741 :   d_max_model_size.maxAssign(1);
    1961                 :        741 : }
    1962                 :            : 
    1963                 :            : }  // namespace uf
    1964                 :            : }  // namespace theory
    1965                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14