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: 802 1025 78.2 %
Date: 2024-10-02 12:19:03 Functions: 54 67 80.6 %
Branches: 609 1052 57.9 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * Top contributors (to current version):
       3                 :            :  *   Andrew Reynolds, Morgan Deters, Tim King
       4                 :            :  *
       5                 :            :  * This file is part of the cvc5 project.
       6                 :            :  *
       7                 :            :  * Copyright (c) 2009-2024 by the authors listed in the file AUTHORS
       8                 :            :  * in the top-level source directory and their institutional affiliations.
       9                 :            :  * All rights reserved.  See the file COPYING in the top-level source
      10                 :            :  * directory for licensing information.
      11                 :            :  * ****************************************************************************
      12                 :            :  *
      13                 :            :  * Implementation of theory of UF with cardinality.
      14                 :            :  */
      15                 :            : 
      16                 :            : #include "theory/uf/cardinality_extension.h"
      17                 :            : 
      18                 :            : #include <sstream>
      19                 :            : 
      20                 :            : #include "expr/cardinality_constraint.h"
      21                 :            : #include "expr/skolem_manager.h"
      22                 :            : #include "options/smt_options.h"
      23                 :            : #include "options/uf_options.h"
      24                 :            : #include "smt/logic_exception.h"
      25                 :            : #include "theory/decision_manager.h"
      26                 :            : #include "theory/quantifiers/term_database.h"
      27                 :            : #include "theory/quantifiers_engine.h"
      28                 :            : #include "theory/theory_engine.h"
      29                 :            : #include "theory/theory_model.h"
      30                 :            : #include "theory/uf/equality_engine.h"
      31                 :            : #include "theory/uf/theory_uf.h"
      32                 :            : #include "util/rational.h"
      33                 :            : 
      34                 :            : using namespace std;
      35                 :            : using namespace cvc5::internal::kind;
      36                 :            : using namespace cvc5::context;
      37                 :            : 
      38                 :            : namespace cvc5::internal {
      39                 :            : namespace theory {
      40                 :            : namespace uf {
      41                 :            : 
      42                 :            : /* These are names are unambigious are we use abbreviations. */
      43                 :            : typedef CardinalityExtension::SortModel SortModel;
      44                 :            : typedef SortModel::Region Region;
      45                 :            : typedef Region::RegionNodeInfo RegionNodeInfo;
      46                 :            : typedef RegionNodeInfo::DiseqList DiseqList;
      47                 :            : 
      48                 :       3858 : Region::Region(SortModel* cf, context::Context* c)
      49                 :            :     : d_cf(cf),
      50                 :          0 :       d_testCliqueSize(c, 0),
      51                 :          0 :       d_splitsSize(c, 0),
      52                 :            :       d_testClique(c),
      53                 :            :       d_splits(c),
      54                 :          0 :       d_reps_size(c, 0),
      55                 :          0 :       d_total_diseq_external(c, 0),
      56                 :          0 :       d_total_diseq_internal(c, 0),
      57                 :       3858 :       d_valid(c, true)
      58                 :            : {
      59                 :       3858 : }
      60                 :            : 
      61                 :       7716 : Region::~Region() {
      62         [ +  + ]:      18160 :   for(iterator i = begin(), iend = end(); i != iend; ++i) {
      63                 :      14302 :     RegionNodeInfo* regionNodeInfo = (*i).second;
      64         [ +  - ]:      14302 :     delete regionNodeInfo;
      65                 :            :   }
      66                 :       3858 :   d_nodes.clear();
      67                 :       7716 : }
      68                 :            : 
      69                 :       7603 : void Region::addRep( Node n ) {
      70                 :       7603 :   setRep( n, true );
      71                 :       7603 : }
      72                 :            : 
      73                 :        850 : void Region::takeNode( Region* r, Node n ){
      74 [ -  + ][ -  + ]:        850 :   Assert(!hasRep(n));
                 [ -  - ]
      75 [ -  + ][ -  + ]:        850 :   Assert(r->hasRep(n));
                 [ -  - ]
      76                 :            :   //add representative
      77                 :        850 :   setRep( n, true );
      78                 :            :   //take disequalities from r
      79                 :        850 :   RegionNodeInfo* rni = r->d_nodes[n];
      80         [ +  + ]:       2550 :   for( int t=0; t<2; t++ ){
      81                 :       1700 :     DiseqList* del = rni->get(t);
      82         [ +  + ]:       4550 :     for(DiseqList::iterator it = del->begin(); it != del->end(); ++it ){
      83         [ +  + ]:       2850 :       if( (*it).second ){
      84                 :       1689 :         r->setDisequal( n, (*it).first, t, false );
      85         [ +  + ]:       1689 :         if( t==0 ){
      86         [ +  + ]:        687 :           if( hasRep( (*it).first ) ){
      87                 :        573 :             setDisequal( (*it).first, n, 0, false );
      88                 :        573 :             setDisequal( (*it).first, n, 1, true );
      89                 :        573 :             setDisequal( n, (*it).first, 1, true );
      90                 :            :           }else{
      91                 :        114 :             setDisequal( n, (*it).first, 0, true );
      92                 :            :           }
      93                 :            :         }else{
      94                 :       1002 :           r->setDisequal( (*it).first, n, 1, false );
      95                 :       1002 :           r->setDisequal( (*it).first, n, 0, true );
      96                 :       1002 :           setDisequal( n, (*it).first, 0, true );
      97                 :            :         }
      98                 :            :       }
      99                 :            :     }
     100                 :            :   }
     101                 :            :   //remove representative
     102                 :        850 :   r->setRep( n, false );
     103                 :        850 : }
     104                 :            : 
     105                 :      56379 : void Region::combine( Region* r ){
     106                 :            :   //take all nodes from r
     107         [ +  + ]:     292037 :   for(Region::iterator it = r->d_nodes.begin(); it != r->d_nodes.end(); ++it) {
     108         [ +  + ]:     235658 :     if( it->second->valid() ){
     109                 :      59903 :       setRep( it->first, true );
     110                 :            :     }
     111                 :            :   }
     112         [ +  + ]:     292037 :   for(Region::iterator it = r->d_nodes.begin(); it != r->d_nodes.end(); ++it){
     113         [ +  + ]:     235658 :     if( it->second->valid() ){
     114                 :            :       //take disequalities from r
     115                 :     119806 :       Node n = it->first;
     116                 :      59903 :       RegionNodeInfo* rni = it->second;
     117         [ +  + ]:     179709 :       for( int t=0; t<2; t++ ){
     118                 :     119806 :         RegionNodeInfo::DiseqList* del = rni->get(t);
     119                 :     316845 :         for( RegionNodeInfo::DiseqList::iterator it2 = del->begin(),
     120         [ +  + ]:     513884 :                it2end = del->end(); it2 != it2end; ++it2 ){
     121         [ +  + ]:     197039 :           if( (*it2).second ){
     122 [ +  + ][ +  + ]:     184855 :             if( t==0 && hasRep( (*it2).first ) ){
         [ +  + ][ +  + ]
                 [ -  - ]
     123                 :      89687 :               setDisequal( (*it2).first, n, 0, false );
     124                 :      89687 :               setDisequal( (*it2).first, n, 1, true );
     125                 :      89687 :               setDisequal( n, (*it2).first, 1, true );
     126                 :            :             }else{
     127                 :      95168 :               setDisequal( n, (*it2).first, t, true );
     128                 :            :             }
     129                 :            :           }
     130                 :            :         }
     131                 :            :       }
     132                 :            :     }
     133                 :            :   }
     134                 :      56379 :   r->d_valid = false;
     135                 :      56379 : }
     136                 :            : 
     137                 :            : /** setEqual */
     138                 :      43654 : void Region::setEqual( Node a, Node b ){
     139                 :      87308 :   Assert(hasRep(a) && hasRep(b));
     140                 :            :   //move disequalities of b over to a
     141         [ +  + ]:     130962 :   for( int t=0; t<2; t++ ){
     142                 :      87308 :     DiseqList* del = d_nodes[b]->get(t);
     143         [ +  + ]:     195422 :     for( DiseqList::iterator it = del->begin(); it != del->end(); ++it ){
     144         [ +  + ]:     108114 :       if( (*it).second ){
     145                 :      72021 :         Node n = (*it).first;
     146                 :            :         //get the region that contains the endpoint of the disequality b != ...
     147                 :      72021 :         Region* nr = d_cf->d_regions[ d_cf->d_regions_map[ n ] ];
     148         [ +  + ]:      72021 :         if( !isDisequal( a, n, t ) ){
     149                 :      32411 :           setDisequal( a, n, t, true );
     150                 :      32411 :           nr->setDisequal( n, a, t, true );
     151                 :            :         }
     152                 :      72021 :         setDisequal( b, n, t, false );
     153                 :      72021 :         nr->setDisequal( n, b, t, false );
     154                 :            :       }
     155                 :            :     }
     156                 :            :   }
     157                 :            :   //remove b from representatives
     158                 :      43654 :   setRep( b, false );
     159                 :      43654 : }
     160                 :            : 
     161                 :     620799 : void Region::setDisequal( Node n1, Node n2, int type, bool valid ){
     162                 :            :   //Trace("uf-ss-region-debug") << "set disequal " << n1 << " " << n2 << " "
     163                 :            :   //                            << type << " " << valid << std::endl;
     164                 :            :   //debugPrint("uf-ss-region-debug");
     165                 :            :   //Assert( isDisequal( n1, n2, type )!=valid );
     166         [ +  + ]:     620799 :   if( isDisequal( n1, n2, type )!=valid ){    //DO_THIS: make assertion
     167                 :     619583 :     d_nodes[ n1 ]->get(type)->setDisequal( n2, valid );
     168         [ +  + ]:     619583 :     if( type==0 ){
     169         [ +  + ]:     251783 :       d_total_diseq_external = d_total_diseq_external + ( valid ? 1 : -1 );
     170                 :            :     }else{
     171         [ +  + ]:     367800 :       d_total_diseq_internal = d_total_diseq_internal + ( valid ? 1 : -1 );
     172         [ +  + ]:     367800 :       if( valid ){
     173                 :            :         //if they are both a part of testClique, then remove split
     174 [ +  - ][ +  + ]:     249720 :         if( d_testClique.find( n1 )!=d_testClique.end() && d_testClique[n1] &&
     175 [ +  + ][ +  - ]:     249720 :             d_testClique.find( n2 )!=d_testClique.end() && d_testClique[n2] ){
                 [ +  + ]
     176                 :       7926 :           Node eq = NodeManager::currentNM()->mkNode(Kind::EQUAL, n1, n2);
     177 [ +  + ][ +  - ]:       2642 :           if( d_splits.find( eq )!=d_splits.end() && d_splits[ eq ] ){
                 [ +  + ]
     178         [ +  - ]:       2616 :             Trace("uf-ss-debug") << "removing split for " << n1 << " " << n2
     179                 :       1308 :                                  << std::endl;
     180                 :       1308 :             d_splits[ eq ] = false;
     181                 :       1308 :             d_splitsSize = d_splitsSize - 1;
     182                 :            :           }
     183                 :            :         }
     184                 :            :       }
     185                 :            :     }
     186                 :            :   }
     187                 :     620799 : }
     188                 :            : 
     189                 :     112860 : void Region::setRep( Node n, bool valid ) {
     190 [ -  + ][ -  + ]:     112860 :   Assert(hasRep(n) != valid);
                 [ -  - ]
     191 [ +  + ][ +  + ]:     112860 :   if( valid && d_nodes.find( n )==d_nodes.end() ){
                 [ +  + ]
     192                 :      14302 :     d_nodes[n] = new RegionNodeInfo(d_cf->d_thss->context());
     193                 :            :   }
     194                 :     112860 :   d_nodes[n]->setValid(valid);
     195         [ +  + ]:     112860 :   d_reps_size = d_reps_size + ( valid ? 1 : -1 );
     196                 :            :   //removing a member of the test clique from this region
     197 [ +  + ][ +  - ]:     112860 :   if( d_testClique.find( n ) != d_testClique.end() && d_testClique[n] ){
                 [ +  + ]
     198 [ -  + ][ -  + ]:       2407 :     Assert(!valid);
                 [ -  - ]
     199                 :       2407 :     d_testClique[n] = false;
     200                 :       2407 :     d_testCliqueSize = d_testCliqueSize - 1;
     201                 :            :     //remove all splits involving n
     202         [ +  + ]:      25090 :     for( split_iterator it = begin_splits(); it != end_splits(); ++it ){
     203         [ +  + ]:      22683 :       if( (*it).second ){
     204                 :       6695 :         if( (*it).first[0]==n || (*it).first[1]==n ){
     205                 :       6639 :           d_splits[ (*it).first ] = false;
     206                 :       6639 :           d_splitsSize = d_splitsSize - 1;
     207                 :            :         }
     208                 :            :       }
     209                 :            :     }
     210                 :            :   }
     211                 :     112860 : }
     212                 :            : 
     213                 :     769759 : bool Region::isDisequal( Node n1, Node n2, int type ) {
     214                 :     769759 :   RegionNodeInfo::DiseqList* del = d_nodes[ n1 ]->get(type);
     215                 :     769759 :   return del->isSet(n2) && del->getDisequalityValue(n2);
     216                 :            : }
     217                 :            : 
     218                 :            : struct sortInternalDegree {
     219                 :            :   Region* r;
     220                 :      25414 :   bool operator() (Node i, Node j) {
     221                 :      50828 :     return (r->getRegionInfo(i)->getNumInternalDisequalities() >
     222                 :      50828 :             r->getRegionInfo(j)->getNumInternalDisequalities());
     223                 :            :   }
     224                 :            : };
     225                 :            : 
     226                 :            : struct sortExternalDegree {
     227                 :            :   Region* r;
     228                 :            :   bool operator() (Node i,Node j) {
     229                 :            :     return (r->getRegionInfo(i)->getNumExternalDisequalities() >
     230                 :            :             r->getRegionInfo(j)->getNumExternalDisequalities());
     231                 :            :   }
     232                 :            : };
     233                 :            : 
     234                 :            : int gmcCount = 0;
     235                 :            : 
     236                 :     139193 : bool Region::getMustCombine( int cardinality ){
     237         [ +  + ]:     139193 :   if (d_total_diseq_external >= static_cast<unsigned>(cardinality))
     238                 :            :   {
     239                 :            :     //The number of external disequalities is greater than or equal to
     240                 :            :     //cardinality.  Thus, a clique of size cardinality+1 may exist
     241                 :            :     //between nodes in d_regions[i] and other regions Check if this is
     242                 :            :     //actually the case: must have n nodes with outgoing degree
     243                 :            :     //(cardinality+1-n) for some n>0
     244                 :      24135 :     std::vector< int > degrees;
     245         [ +  + ]:     236933 :     for( Region::iterator it = begin(); it != end(); ++it ){
     246                 :     225716 :       RegionNodeInfo* rni = it->second;
     247         [ +  + ]:     225716 :       if( rni->valid() ){
     248         [ +  + ]:     107902 :         if( rni->getNumDisequalities() >= cardinality ){
     249                 :      81144 :           int outDeg = rni->getNumExternalDisequalities();
     250         [ +  + ]:      81144 :           if( outDeg>=cardinality ){
     251                 :            :             //we have 1 node of degree greater than (cardinality)
     252                 :      12918 :             return true;
     253         [ +  + ]:      69261 :           }else if( outDeg>=1 ){
     254                 :      59726 :             degrees.push_back( outDeg );
     255         [ +  + ]:      59726 :             if( (int)degrees.size()>=cardinality ){
     256                 :            :               //we have (cardinality) nodes of degree 1
     257                 :       1035 :               return true;
     258                 :            :             }
     259                 :            :           }
     260                 :            :         }
     261                 :            :       }
     262                 :            :     }
     263                 :      11217 :     gmcCount++;
     264         [ +  + ]:      11217 :     if( gmcCount%100==0 ){
     265         [ +  - ]:        180 :       Trace("gmc-count") << gmcCount << " " << cardinality
     266                 :         90 :                          << " sample : " << degrees.size() << std::endl;
     267                 :            :     }
     268                 :            :     //this should happen relatively infrequently....
     269                 :      11217 :     std::sort( degrees.begin(), degrees.end() );
     270         [ +  + ]:      61036 :     for( int i=0; i<(int)degrees.size(); i++ ){
     271         [ +  + ]:      51396 :       if( degrees[i]>=cardinality+1-((int)degrees.size()-i) ){
     272                 :       1577 :         return true;
     273                 :            :       }
     274                 :            :     }
     275                 :            :   }
     276                 :     124698 :   return false;
     277                 :            : }
     278                 :            : 
     279                 :    1109700 : bool Region::check( Theory::Effort level, int cardinality,
     280                 :            :                     std::vector< Node >& clique ) {
     281         [ +  + ]:    1109700 :   if( d_reps_size>unsigned(cardinality) ){
     282         [ +  + ]:     102317 :     if( d_total_diseq_internal==d_reps_size*( d_reps_size - 1 ) ){
     283         [ +  + ]:      64602 :       if( d_reps_size>1 ){
     284                 :            :         //quick clique check, all reps form a clique
     285         [ +  + ]:      31030 :         for( iterator it = begin(); it != end(); ++it ){
     286         [ +  + ]:      27067 :           if( it->second->valid() ){
     287                 :      20095 :             clique.push_back( it->first );
     288                 :            :           }
     289                 :            :         }
     290         [ +  - ]:       3963 :         Trace("quick-clique") << "Found quick clique" << std::endl;
     291                 :       3963 :         return true;
     292                 :            :       }else{
     293                 :      60639 :         return false;
     294                 :            :       }
     295                 :            :     }
     296         [ +  + ]:      37715 :     else if (level==Theory::EFFORT_FULL) 
     297                 :            :     {
     298                 :            :       //build test clique, up to size cardinality+1
     299         [ +  + ]:       3061 :       if( d_testCliqueSize<=unsigned(cardinality) ){
     300                 :       5884 :         std::vector< Node > newClique;
     301         [ +  + ]:       2942 :         if( d_testCliqueSize<unsigned(cardinality) ){
     302         [ +  + ]:      23601 :           for( iterator it = begin(); it != end(); ++it ){
     303                 :            :             //if not in the test clique, add it to the set of new members
     304 [ +  + ][ +  + ]:      34664 :             if( it->second->valid() &&
     305         [ +  + ]:      34660 :                 ( d_testClique.find( it->first ) == d_testClique.end() ||
     306         [ -  + ]:          4 :                   !d_testClique[ it->first ] ) ){
     307                 :            :               //if( it->second->getNumInternalDisequalities()>cardinality ||
     308                 :            :               //    level==Theory::EFFORT_FULL ){
     309                 :      13547 :               newClique.push_back( it->first );
     310                 :            :               //}
     311                 :            :             }
     312                 :            :           }
     313                 :            :           //choose remaining nodes with the highest degrees
     314                 :            :           sortInternalDegree sidObj;
     315                 :       2492 :           sidObj.r = this;
     316                 :       2492 :           std::sort( newClique.begin(), newClique.end(), sidObj );
     317                 :       2492 :           int offset = ( cardinality - d_testCliqueSize ) + 1;
     318                 :       2492 :           newClique.erase( newClique.begin() + offset, newClique.end() );
     319                 :            :         }else{
     320                 :            :           //scan for the highest degree
     321                 :        450 :           int maxDeg = -1;
     322                 :        900 :           Node maxNode;
     323                 :       5785 :           for( std::map< Node, RegionNodeInfo* >::iterator
     324         [ +  + ]:      12020 :                  it = d_nodes.begin(); it != d_nodes.end(); ++it ){
     325                 :            :             //if not in the test clique, add it to the set of new members
     326 [ +  + ][ +  + ]:      12415 :             if( it->second->valid() &&
     327         [ +  + ]:       9333 :                 ( d_testClique.find( it->first )==d_testClique.end() ||
     328         [ -  + ]:       3082 :                   !d_testClique[ it->first ] ) ){
     329         [ +  + ]:        466 :               if( it->second->getNumInternalDisequalities()>maxDeg ){
     330                 :        450 :                 maxDeg = it->second->getNumInternalDisequalities();
     331                 :        450 :                 maxNode = it->first;
     332                 :            :               }
     333                 :            :             }
     334                 :            :           }
     335 [ -  + ][ -  + ]:        450 :           Assert(maxNode != Node::null());
                 [ -  - ]
     336                 :        450 :           newClique.push_back( maxNode );
     337                 :            :         }
     338                 :            :         //check splits internal to new members
     339         [ +  + ]:      16816 :         for( int j=0; j<(int)newClique.size(); j++ ){
     340         [ +  - ]:      27748 :           Trace("uf-ss-debug") << "Choose to add clique member "
     341                 :      13874 :                                << newClique[j] << std::endl;
     342         [ +  + ]:      67134 :           for( int k=(j+1); k<(int)newClique.size(); k++ ){
     343         [ +  + ]:      53260 :             if( !isDisequal( newClique[j], newClique[k], 1 ) ){
     344                 :      12642 :               Node at_j = newClique[j];
     345                 :      12642 :               Node at_k = newClique[k];
     346                 :            :               Node j_eq_k =
     347                 :      12642 :                   NodeManager::currentNM()->mkNode(Kind::EQUAL, at_j, at_k);
     348                 :       6321 :               d_splits[ j_eq_k ] = true;
     349                 :       6321 :               d_splitsSize = d_splitsSize + 1;
     350                 :            :             }
     351                 :            :           }
     352                 :            :           //check disequalities with old members
     353                 :      18559 :           for( NodeBoolMap::iterator it = d_testClique.begin();
     354         [ +  + ]:      23244 :                it != d_testClique.end(); ++it ){
     355         [ +  + ]:       4685 :             if( (*it).second ){
     356         [ +  + ]:       3090 :               if( !isDisequal( (*it).first, newClique[j], 1 ) ){
     357                 :       3804 :                 Node at_it = (*it).first;
     358                 :       3804 :                 Node at_j = newClique[j];
     359                 :       1902 :                 Node it_eq_j = at_it.eqNode(at_j);
     360                 :       1902 :                 d_splits[ it_eq_j ] = true;
     361                 :       1902 :                 d_splitsSize = d_splitsSize + 1;
     362                 :            :               }
     363                 :            :             }
     364                 :            :           }
     365                 :            :         }
     366                 :            :         //add new clique members to test clique
     367         [ +  + ]:      16816 :         for( int j=0; j<(int)newClique.size(); j++ ){
     368                 :      13874 :           d_testClique[ newClique[j] ] = true;
     369                 :      13874 :           d_testCliqueSize = d_testCliqueSize + 1;
     370                 :            :         }
     371                 :            :       }
     372                 :            :       // Check if test clique has larger size than cardinality, and
     373                 :            :       // forms a clique.
     374 [ +  - ][ +  + ]:       3061 :       if( d_testCliqueSize >= unsigned(cardinality+1) && d_splitsSize==0 ){
                 [ +  + ]
     375                 :            :         //test clique is a clique
     376                 :        137 :         for( NodeBoolMap::iterator it = d_testClique.begin();
     377         [ +  + ]:        235 :              it != d_testClique.end(); ++it ){
     378         [ +  - ]:         98 :           if( (*it).second ){
     379                 :         98 :             clique.push_back( (*it).first );
     380                 :            :           }
     381                 :            :         }
     382                 :         39 :         return true;
     383                 :            :       }
     384                 :            :     }
     385                 :            :   }
     386                 :    1045050 :   return false;
     387                 :            : }
     388                 :            : 
     389                 :          0 : void Region::getNumExternalDisequalities(
     390                 :            :     std::map< Node, int >& num_ext_disequalities ){
     391         [ -  - ]:          0 :   for( Region::iterator it = begin(); it != end(); ++it ){
     392                 :          0 :     RegionNodeInfo* rni = it->second;
     393         [ -  - ]:          0 :     if( rni->valid() ){
     394                 :          0 :       DiseqList* del = rni->get(0);
     395         [ -  - ]:          0 :       for( DiseqList::iterator it2 = del->begin(); it2 != del->end(); ++it2 ){
     396         [ -  - ]:          0 :         if( (*it2).second ){
     397                 :          0 :           num_ext_disequalities[ (*it2).first ]++;
     398                 :            :         }
     399                 :            :       }
     400                 :            :     }
     401                 :            :   }
     402                 :          0 : }
     403                 :            : 
     404                 :       3745 : void Region::debugPrint( const char* c, bool incClique ) {
     405         [ +  - ]:       3745 :   Trace( c ) << "Num reps: " << d_reps_size << std::endl;
     406         [ +  + ]:      10773 :   for( Region::iterator it = begin(); it != end(); ++it ){
     407                 :       7028 :     RegionNodeInfo* rni = it->second;
     408         [ -  + ]:       7028 :     if( rni->valid() ){
     409                 :          0 :       Node n = it->first;
     410         [ -  - ]:          0 :       Trace( c ) << "   " << n << std::endl;
     411         [ -  - ]:          0 :       for( int i=0; i<2; i++ ){
     412                 :          0 :         Trace( c ) << "      " << ( i==0 ? "Ext" : "Int" ) << " disequal:";
     413                 :          0 :         DiseqList* del = rni->get(i);
     414         [ -  - ]:          0 :         for( DiseqList::iterator it2 = del->begin(); it2 != del->end(); ++it2 ){
     415         [ -  - ]:          0 :           if( (*it2).second ){
     416         [ -  - ]:          0 :             Trace( c ) << " " << (*it2).first;
     417                 :            :           }
     418                 :            :         }
     419         [ -  - ]:          0 :         Trace( c ) << ", total = " << del->size() << std::endl;
     420                 :            :       }
     421                 :            :     }
     422                 :            :   }
     423         [ +  - ]:       3745 :   Trace( c ) << "Total disequal: " << d_total_diseq_external << " external,";
     424         [ +  - ]:       3745 :   Trace( c ) << " " << d_total_diseq_internal << " internal." << std::endl;
     425                 :            : 
     426         [ +  - ]:       3745 :   if( incClique ){
     427         [ -  + ]:       3745 :     if( !d_testClique.empty() ){
     428         [ -  - ]:          0 :       Trace( c ) << "Candidate clique members: " << std::endl;
     429         [ -  - ]:          0 :       Trace( c ) << "   ";
     430                 :          0 :       for( NodeBoolMap::iterator it = d_testClique.begin();
     431         [ -  - ]:          0 :            it != d_testClique.end(); ++ it ){
     432         [ -  - ]:          0 :         if( (*it).second ){
     433         [ -  - ]:          0 :           Trace( c ) << (*it).first << " ";
     434                 :            :         }
     435                 :            :       }
     436         [ -  - ]:          0 :       Trace( c ) << ", size = " << d_testCliqueSize << std::endl;
     437                 :            :     }
     438         [ -  + ]:       3745 :     if( !d_splits.empty() ){
     439         [ -  - ]:          0 :       Trace( c ) << "Required splits: " << std::endl;
     440         [ -  - ]:          0 :       Trace( c ) << "   ";
     441         [ -  - ]:          0 :       for( NodeBoolMap::iterator it = d_splits.begin(); it != d_splits.end();
     442                 :          0 :            ++ it ){
     443         [ -  - ]:          0 :         if( (*it).second ){
     444         [ -  - ]:          0 :           Trace( c ) << (*it).first << " ";
     445                 :            :         }
     446                 :            :       }
     447         [ -  - ]:          0 :       Trace( c ) << ", size = " << d_splitsSize << std::endl;
     448                 :            :     }
     449                 :            :   }
     450                 :       3745 : }
     451                 :            : 
     452                 :        745 : SortModel::CardinalityDecisionStrategy::CardinalityDecisionStrategy(
     453                 :        745 :     Env& env, TypeNode type, Valuation valuation)
     454                 :        745 :     : DecisionStrategyFmf(env, valuation), d_type(type)
     455                 :            : {
     456                 :        745 : }
     457                 :            : 
     458                 :       1765 : Node SortModel::CardinalityDecisionStrategy::mkLiteral(unsigned i)
     459                 :            : {
     460                 :       1765 :   NodeManager* nm = NodeManager::currentNM();
     461                 :       3530 :   Node cco = nm->mkConst(CardinalityConstraint(d_type, Integer(i + 1)));
     462                 :       3530 :   return nm->mkNode(Kind::CARDINALITY_CONSTRAINT, cco);
     463                 :            : }
     464                 :            : 
     465                 :          0 : std::string SortModel::CardinalityDecisionStrategy::identify() const
     466                 :            : {
     467                 :          0 :   return std::string("uf_card");
     468                 :            : }
     469                 :            : 
     470                 :        745 : SortModel::SortModel(Env& env,
     471                 :            :                      TypeNode tn,
     472                 :            :                      TheoryState& state,
     473                 :            :                      TheoryInferenceManager& im,
     474                 :        745 :                      CardinalityExtension* thss)
     475                 :            :     : EnvObj(env),
     476                 :            :       d_type(tn),
     477                 :            :       d_state(state),
     478                 :            :       d_im(im),
     479                 :            :       d_thss(thss),
     480                 :          0 :       d_regions_index(thss->context(), 0),
     481                 :            :       d_regions_map(thss->context()),
     482                 :            :       d_split_score(thss->context()),
     483                 :          0 :       d_disequalities_index(thss->context(), 0),
     484                 :          0 :       d_reps(thss->context(), 0),
     485                 :          0 :       d_cardinality(thss->context(), 1),
     486                 :          0 :       d_hasCard(thss->context(), false),
     487                 :          0 :       d_maxNegCard(thss->context(), 0),
     488                 :          0 :       d_initialized(thss->userContext(), false),
     489                 :        745 :       d_c_dec_strat(nullptr)
     490                 :            : {
     491         [ +  - ]:        745 :   if (options().uf.ufssMode == options::UfssMode::FULL)
     492                 :            :   {
     493                 :            :     // Register the strategy with the decision manager of the theory.
     494                 :            :     // We are guaranteed that the decision manager is ready since we
     495                 :            :     // construct this module during TheoryUF::finishInit.
     496                 :        745 :     d_c_dec_strat.reset(new CardinalityDecisionStrategy(
     497                 :        745 :         thss->d_env, d_type, thss->getTheory()->getValuation()));
     498                 :            :   }
     499                 :        745 : }
     500                 :            : 
     501                 :       1490 : SortModel::~SortModel() {
     502                 :       4603 :   for(std::vector<Region*>::iterator i = d_regions.begin();
     503         [ +  + ]:       8461 :       i != d_regions.end(); ++i) {
     504                 :       3858 :     Region* region = *i;
     505         [ +  - ]:       3858 :     delete region;
     506                 :            :   }
     507                 :        745 :   d_regions.clear();
     508                 :       1490 : }
     509                 :            : 
     510                 :            : /** initialize */
     511                 :      25233 : void SortModel::initialize()
     512                 :            : {
     513 [ +  - ][ +  + ]:      25233 :   if (d_c_dec_strat.get() != nullptr && !d_initialized)
                 [ +  + ]
     514                 :            :   {
     515                 :       1203 :     d_initialized = true;
     516                 :            :     // Strategy is user-context-dependent, since it is in sync with
     517                 :            :     // user-context-dependent flag d_initialized.
     518                 :       2406 :     d_im.getDecisionManager()->registerStrategy(DecisionManager::STRAT_UF_CARD,
     519                 :       1203 :                                                 d_c_dec_strat.get());
     520                 :            :   }
     521                 :      25233 : }
     522                 :            : 
     523                 :            : /** new node */
     524                 :       7603 : void SortModel::newEqClass( Node n ){
     525         [ +  - ]:       7603 :   if (!d_state.isInConflict())
     526                 :            :   {
     527         [ +  - ]:       7603 :     if( d_regions_map.find( n )==d_regions_map.end() ){
     528                 :       7603 :       d_regions_map[n] = d_regions_index;
     529         [ +  - ]:       7603 :       Trace("uf-ss") << "CardinalityExtension: New Eq Class " << n << std::endl;
     530         [ +  - ]:      15206 :       Trace("uf-ss-debug") << d_regions_index << " " << (int)d_regions.size()
     531                 :       7603 :                            << std::endl;
     532         [ +  + ]:       7603 :       if (d_regions_index < d_regions.size())
     533                 :            :       {
     534                 :       3745 :         d_regions[d_regions_index]->debugPrint("uf-ss-debug", true);
     535                 :       3745 :         d_regions[d_regions_index]->setValid(true);
     536 [ -  + ][ -  + ]:       3745 :         Assert(d_regions[d_regions_index]->getNumReps() == 0);
                 [ -  - ]
     537                 :            :       }else{
     538                 :       3858 :         d_regions.push_back(new Region(this, d_thss->context()));
     539                 :            :       }
     540                 :       7603 :       d_regions[d_regions_index]->addRep(n);
     541                 :       7603 :       d_regions_index = d_regions_index + 1;
     542                 :            : 
     543                 :       7603 :       d_reps = d_reps + 1;
     544                 :            :     }
     545                 :            :   }
     546                 :       7603 : }
     547                 :            : 
     548                 :            : /** merge */
     549                 :      43654 : void SortModel::merge( Node a, Node b ){
     550         [ -  + ]:      43654 :   if (d_state.isInConflict())
     551                 :            :   {
     552                 :          0 :     return;
     553                 :            :   }
     554         [ +  - ]:      87308 :   Trace("uf-ss") << "CardinalityExtension: Merging " << a << " = " << b << "..."
     555                 :      43654 :                  << std::endl;
     556         [ +  - ]:      43654 :   if (a != b)
     557                 :            :   {
     558 [ -  + ][ -  + ]:      43654 :     Assert(d_regions_map.find(a) != d_regions_map.end());
                 [ -  - ]
     559 [ -  + ][ -  + ]:      43654 :     Assert(d_regions_map.find(b) != d_regions_map.end());
                 [ -  - ]
     560                 :      43654 :     int ai = d_regions_map[a];
     561                 :      43654 :     int bi = d_regions_map[b];
     562         [ +  - ]:      43654 :     Trace("uf-ss") << "   regions: " << ai << " " << bi << std::endl;
     563         [ +  + ]:      43654 :     if (ai != bi)
     564                 :            :     {
     565         [ +  + ]:      38550 :       if (d_regions[ai]->getNumReps() == 1)
     566                 :            :       {
     567                 :      25929 :         int ri = combineRegions(bi, ai);
     568                 :      25929 :         d_regions[ri]->setEqual(a, b);
     569                 :      25929 :         checkRegion(ri);
     570                 :            :       }
     571         [ +  + ]:      12621 :       else if (d_regions[bi]->getNumReps() == 1)
     572                 :            :       {
     573                 :      11771 :         int ri = combineRegions(ai, bi);
     574                 :      11771 :         d_regions[ri]->setEqual(a, b);
     575                 :      11771 :         checkRegion(ri);
     576                 :            :       }
     577                 :            :       else
     578                 :            :       {
     579                 :            :         // Either move a to d_regions[bi], or b to d_regions[ai].
     580                 :        850 :         RegionNodeInfo* a_region_info = d_regions[ai]->getRegionInfo(a);
     581                 :        850 :         RegionNodeInfo* b_region_info = d_regions[bi]->getRegionInfo(b);
     582                 :        850 :         int aex = (a_region_info->getNumInternalDisequalities()
     583                 :        850 :                    - getNumDisequalitiesToRegion(a, bi));
     584                 :        850 :         int bex = (b_region_info->getNumInternalDisequalities()
     585                 :        850 :                    - getNumDisequalitiesToRegion(b, ai));
     586                 :            :         // Based on which would produce the fewest number of
     587                 :            :         // external disequalities.
     588         [ +  + ]:        850 :         if (aex < bex)
     589                 :            :         {
     590                 :        304 :           moveNode(a, bi);
     591                 :        304 :           d_regions[bi]->setEqual(a, b);
     592                 :            :         }else{
     593                 :        546 :           moveNode(b, ai);
     594                 :        546 :           d_regions[ai]->setEqual( a, b );
     595                 :            :         }
     596                 :        850 :         checkRegion(ai);
     597                 :        850 :         checkRegion(bi);
     598                 :            :       }
     599                 :            :     }
     600                 :            :     else
     601                 :            :     {
     602                 :       5104 :       d_regions[ai]->setEqual(a, b);
     603                 :       5104 :       checkRegion(ai);
     604                 :            :     }
     605                 :      43654 :     d_regions_map[b] = -1;
     606                 :            :   }
     607                 :      43654 :   d_reps = d_reps - 1;
     608                 :            : }
     609                 :            : 
     610                 :            : /** assert terms are disequal */
     611                 :      20589 : void SortModel::assertDisequal( Node a, Node b, Node reason ){
     612         [ -  + ]:      20589 :   if (d_state.isInConflict())
     613                 :            :   {
     614                 :          0 :     return;
     615                 :            :   }
     616                 :            :   // if they are not already disequal
     617                 :      20589 :   eq::EqualityEngine* ee = d_thss->getTheory()->getEqualityEngine();
     618                 :      20589 :   a = ee->getRepresentative(a);
     619                 :      20589 :   b = ee->getRepresentative(b);
     620                 :      20589 :   int ai = d_regions_map[a];
     621                 :      20589 :   int bi = d_regions_map[b];
     622         [ -  + ]:      20589 :   if (d_regions[ai]->isDisequal(a, b, ai == bi))
     623                 :            :   {
     624                 :            :     // already disequal
     625                 :          0 :     return;
     626                 :            :   }
     627         [ +  - ]:      41178 :   Trace("uf-ss") << "Assert disequal " << a << " != " << b << "..."
     628                 :      20589 :                  << std::endl;
     629         [ +  - ]:      41178 :   Trace("uf-ss-disequal") << "Assert disequal " << a << " != " << b << "..."
     630                 :      20589 :                           << std::endl;
     631                 :            :   // add to list of disequalities
     632         [ +  + ]:      20589 :   if (d_disequalities_index < d_disequalities.size())
     633                 :            :   {
     634                 :      14761 :     d_disequalities[d_disequalities_index] = reason;
     635                 :            :   }
     636                 :            :   else
     637                 :            :   {
     638                 :       5828 :     d_disequalities.push_back(reason);
     639                 :            :   }
     640                 :      20589 :   d_disequalities_index = d_disequalities_index + 1;
     641                 :            :   // now, add disequalities to regions
     642 [ -  + ][ -  + ]:      20589 :   Assert(d_regions_map.find(a) != d_regions_map.end());
                 [ -  - ]
     643 [ -  + ][ -  + ]:      20589 :   Assert(d_regions_map.find(b) != d_regions_map.end());
                 [ -  - ]
     644         [ +  - ]:      20589 :   Trace("uf-ss") << "   regions: " << ai << " " << bi << std::endl;
     645         [ +  + ]:      20589 :   if (ai == bi)
     646                 :            :   {
     647                 :            :     // internal disequality
     648                 :        750 :     d_regions[ai]->setDisequal(a, b, 1, true);
     649                 :        750 :     d_regions[ai]->setDisequal(b, a, 1, true);
     650                 :            :     // do not need to check if it needs to combine (no new ext. disequalities)
     651                 :        750 :     checkRegion(ai, false);
     652                 :            :   }
     653                 :            :   else
     654                 :            :   {
     655                 :            :     // external disequality
     656                 :      19839 :     d_regions[ai]->setDisequal(a, b, 0, true);
     657                 :      19839 :     d_regions[bi]->setDisequal(b, a, 0, true);
     658                 :      19839 :     checkRegion(ai);
     659                 :      19839 :     checkRegion(bi);
     660                 :            :   }
     661                 :            : }
     662                 :            : 
     663                 :          0 : bool SortModel::areDisequal( Node a, Node b ) {
     664                 :          0 :   Assert(a == d_thss->getTheory()->getEqualityEngine()->getRepresentative(a));
     665                 :          0 :   Assert(b == d_thss->getTheory()->getEqualityEngine()->getRepresentative(b));
     666                 :          0 :   if( d_regions_map.find( a )!=d_regions_map.end() &&
     667         [ -  - ]:          0 :       d_regions_map.find( b )!=d_regions_map.end() ){
     668                 :          0 :     int ai = d_regions_map[a];
     669                 :          0 :     int bi = d_regions_map[b];
     670         [ -  - ]:          0 :     return d_regions[ai]->isDisequal(a, b, ai==bi ? 1 : 0);
     671                 :            :   }else{
     672                 :          0 :     return false;
     673                 :            :   }
     674                 :            : }
     675                 :            : 
     676                 :     338055 : void SortModel::check(Theory::Effort level)
     677                 :            : {
     678 [ -  + ][ -  + ]:     338055 :   Assert(options().uf.ufssMode == options::UfssMode::FULL);
                 [ -  - ]
     679 [ +  + ][ -  + ]:     338055 :   if (!d_hasCard && d_state.isInConflict())
                 [ -  + ]
     680                 :            :   {
     681                 :            :     // not necessary to check
     682                 :          0 :     return;
     683                 :            :   }
     684         [ +  - ]:     676110 :   Trace("uf-ss") << "CardinalityExtension: Check " << level << " " << d_type
     685                 :     338055 :                  << std::endl;
     686         [ +  + ]:     338055 :   if (level == Theory::EFFORT_FULL)
     687                 :            :   {
     688         [ +  - ]:      14232 :     Trace("fmf-full-check") << std::endl;
     689         [ +  - ]:      28464 :     Trace("fmf-full-check")
     690                 :      14232 :         << "Full check for SortModel " << d_type << ", status : " << std::endl;
     691                 :      14232 :     debugPrint("fmf-full-check");
     692         [ +  - ]:      14232 :     Trace("fmf-full-check") << std::endl;
     693                 :            :   }
     694         [ +  + ]:     338055 :   if (d_reps <= (unsigned)d_cardinality)
     695                 :            :   {
     696         [ +  - ]:     242126 :     Trace("uf-ss-debug") << "We have " << d_reps << " representatives for type "
     697                 :     121063 :                          << d_type << ", <= " << d_cardinality << std::endl;
     698         [ +  + ]:     121063 :     if( level==Theory::EFFORT_FULL ){
     699         [ +  - ]:      13974 :       Trace("uf-ss-sat") << "We have " << d_reps << " representatives for type "
     700                 :       6987 :                          << d_type << ", <= " << d_cardinality << std::endl;
     701                 :            :     }
     702                 :     121063 :     return;
     703                 :            :   }
     704                 :            :   // first check if we can generate a clique conflict
     705                 :            :   // do a check within each region
     706         [ +  + ]:    1856850 :   for (size_t i = 0; i < d_regions_index; i++)
     707                 :            :   {
     708         [ +  + ]:    1641040 :     if (d_regions[i]->valid())
     709                 :            :     {
     710                 :     969752 :       std::vector<Node> clique;
     711         [ +  + ]:     969752 :       if (d_regions[i]->check(level, d_cardinality, clique))
     712                 :            :       {
     713                 :            :         // add clique lemma
     714                 :       1184 :         addCliqueLemma(clique);
     715                 :       1184 :         return;
     716                 :            :       }
     717                 :            :       else
     718                 :            :       {
     719         [ +  - ]:     968568 :         Trace("uf-ss-debug") << "No clique in Region #" << i << std::endl;
     720                 :            :       }
     721                 :            :     }
     722                 :            :   }
     723                 :            :   // do splitting on demand
     724                 :     215808 :   bool addedLemma = false;
     725         [ +  + ]:     215808 :   if (level == Theory::EFFORT_FULL)
     726                 :            :   {
     727         [ +  - ]:       7206 :     Trace("uf-ss-debug") << "Add splits?" << std::endl;
     728                 :            :     // see if we have any recommended splits from large regions
     729         [ +  + ]:      96172 :     for (size_t i = 0; i < d_regions_index; i++)
     730                 :            :     {
     731 [ +  + ][ +  + ]:      88966 :       if (d_regions[i]->valid() && d_regions[i]->getNumReps() > d_cardinality)
                 [ +  + ]
     732                 :            :       {
     733                 :       3022 :         int sp = addSplit(d_regions[i]);
     734         [ +  - ]:       3022 :         if (sp == 1)
     735                 :            :         {
     736                 :       3022 :           addedLemma = true;
     737                 :            :         }
     738         [ -  - ]:          0 :         else if (sp == -1)
     739                 :            :         {
     740                 :          0 :           check(level);
     741                 :          0 :           return;
     742                 :            :         }
     743                 :            :       }
     744                 :            :     }
     745                 :            :   }
     746                 :            :   // If no added lemmas, force continuation via combination of regions.
     747 [ +  + ][ +  + ]:     215808 :   if (level != Theory::EFFORT_FULL || addedLemma)
     748                 :            :   {
     749                 :     211624 :     return;
     750                 :            :   }
     751                 :            :   // check at full effort
     752         [ +  - ]:       4184 :   Trace("uf-ss-debug") << "No splits added. " << d_cardinality << std::endl;
     753         [ +  - ]:       4184 :   Trace("uf-ss-si") << "Must combine region" << std::endl;
     754                 :       4184 :   bool recheck = false;
     755                 :       4184 :   SortInference* si = d_state.getSortInference();
     756         [ +  + ]:       4184 :   if (si != nullptr)
     757                 :            :   {
     758                 :            :     // If sort inference is enabled, search for regions with same sort.
     759                 :        112 :     std::map<int, int> sortsFound;
     760         [ +  - ]:        550 :     for (size_t i = 0; i < d_regions_index; i++)
     761                 :            :     {
     762         [ +  + ]:        550 :       if (d_regions[i]->valid())
     763                 :            :       {
     764                 :        112 :         Node op = d_regions[i]->frontKey();
     765                 :        112 :         int sort_id = si->getSortId(op);
     766         [ +  + ]:        112 :         if (sortsFound.find(sort_id) != sortsFound.end())
     767                 :            :         {
     768         [ +  - ]:        112 :           Trace("fmf-full-check") << "Combined regions " << i << " "
     769                 :         56 :                                   << sortsFound[sort_id] << std::endl;
     770                 :         56 :           combineRegions(sortsFound[sort_id], i);
     771                 :         56 :           recheck = true;
     772                 :         56 :           break;
     773                 :            :         }
     774                 :            :         else
     775                 :            :         {
     776                 :         56 :           sortsFound[sort_id] = i;
     777                 :            :         }
     778                 :            :       }
     779                 :            :     }
     780                 :            :   }
     781         [ +  + ]:       4184 :   if (!recheck)
     782                 :            :   {
     783                 :            :     // naive strategy, force region combination involving the first
     784                 :            :     // valid region
     785         [ +  - ]:      11935 :     for (size_t i = 0; i < d_regions_index; i++)
     786                 :            :     {
     787         [ +  + ]:      11935 :       if (d_regions[i]->valid())
     788                 :            :       {
     789                 :       4128 :         int fcr = forceCombineRegion(i, false);
     790         [ +  - ]:       8256 :         Trace("fmf-full-check")
     791                 :       4128 :             << "Combined regions " << i << " " << fcr << std::endl;
     792         [ +  - ]:       8256 :         Trace("uf-ss-debug")
     793                 :       4128 :             << "Combined regions " << i << " " << fcr << std::endl;
     794                 :       4128 :         recheck = true;
     795                 :       4128 :         break;
     796                 :            :       }
     797                 :            :     }
     798                 :            :   }
     799         [ +  - ]:       4184 :   if (recheck)
     800                 :            :   {
     801         [ +  - ]:       4184 :     Trace("uf-ss-debug") << "Must recheck." << std::endl;
     802                 :       4184 :     check(level);
     803                 :            :   }
     804                 :            : }
     805                 :            : 
     806                 :        457 : void SortModel::presolve() {
     807                 :        457 :   d_initialized = false;
     808                 :        457 : }
     809                 :            : 
     810                 :       1700 : int SortModel::getNumDisequalitiesToRegion( Node n, int ri ){
     811                 :       1700 :   int ni = d_regions_map[n];
     812                 :       1700 :   int counter = 0;
     813                 :       1700 :   DiseqList* del = d_regions[ni]->getRegionInfo(n)->get(0);
     814         [ +  + ]:       4675 :   for( DiseqList::iterator it = del->begin(); it != del->end(); ++it ){
     815         [ +  + ]:       2975 :     if( (*it).second ){
     816         [ +  + ]:        968 :       if( d_regions_map[ (*it).first ]==ri ){
     817                 :        760 :         counter++;
     818                 :            :       }
     819                 :            :     }
     820                 :            :   }
     821                 :       1700 :   return counter;
     822                 :            : }
     823                 :            : 
     824                 :      14495 : void SortModel::getDisequalitiesToRegions(int ri,
     825                 :            :                                           std::map< int, int >& regions_diseq)
     826                 :            : {
     827                 :      14495 :   Region* region = d_regions[ri];
     828         [ +  + ]:     176367 :   for(Region::iterator it = region->begin(); it != region->end(); ++it ){
     829         [ +  + ]:     161872 :     if( it->second->valid() ){
     830                 :      45245 :       DiseqList* del = it->second->get(0);
     831         [ +  + ]:     369287 :       for( DiseqList::iterator it2 = del->begin(); it2 != del->end(); ++it2 ){
     832         [ +  + ]:     324042 :         if( (*it2).second ){
     833 [ -  + ][ -  + ]:     207888 :           Assert(isValid(d_regions_map[(*it2).first]));
                 [ -  - ]
     834                 :     207888 :           regions_diseq[ d_regions_map[ (*it2).first ] ]++;
     835                 :            :         }
     836                 :            :       }
     837                 :            :     }
     838                 :            :   }
     839                 :      14495 : }
     840                 :            : 
     841                 :          0 : void SortModel::setSplitScore( Node n, int s ){
     842         [ -  - ]:          0 :   if( d_split_score.find( n )!=d_split_score.end() ){
     843                 :          0 :     int ss = d_split_score[ n ];
     844         [ -  - ]:          0 :     d_split_score[ n ] = s>ss ? s : ss;
     845                 :            :   }else{
     846                 :          0 :     d_split_score[ n ] = s;
     847                 :            :   }
     848         [ -  - ]:          0 :   for( int i=0; i<(int)n.getNumChildren(); i++ ){
     849                 :          0 :     setSplitScore( n[i], s+1 );
     850                 :            :   }
     851                 :          0 : }
     852                 :            : 
     853                 :      13595 : void SortModel::assertCardinality(uint32_t c, bool val)
     854                 :            : {
     855         [ +  - ]:      13595 :   if (!d_state.isInConflict())
     856                 :            :   {
     857         [ +  - ]:      27190 :     Trace("uf-ss-assert")
     858                 :          0 :         << "Assert cardinality " << d_type << " " << c << " " << val
     859                 :          0 :         << " level = "
     860                 :      13595 :         << d_thss->getTheory()->getValuation().getAssertionLevel() << std::endl;
     861 [ -  + ][ -  + ]:      13595 :     Assert(c > 0);
                 [ -  - ]
     862                 :      13595 :     Node cl = getCardinalityLiteral( c );
     863         [ +  + ]:      13595 :     if( val ){
     864                 :      11215 :       bool doCheckRegions = !d_hasCard;
     865                 :      11215 :       bool prevHasCard = d_hasCard;
     866                 :      11215 :       d_hasCard = true;
     867 [ +  + ][ +  + ]:      11215 :       if (!prevHasCard || c < d_cardinality)
                 [ +  + ]
     868                 :            :       {
     869                 :      11209 :         d_cardinality = c;
     870                 :      11209 :         simpleCheckCardinality();
     871         [ +  + ]:      11209 :         if (d_state.isInConflict())
     872                 :            :         {
     873                 :        256 :           return;
     874                 :            :         }
     875                 :            :       }
     876                 :            :       //should check all regions now
     877         [ +  + ]:      10959 :       if (doCheckRegions)
     878                 :            :       {
     879         [ +  + ]:      68972 :         for (size_t i = 0; i < d_regions_index; i++)
     880                 :            :         {
     881         [ +  + ]:      58048 :           if( d_regions[i]->valid() ){
     882                 :      49700 :             checkRegion( i );
     883         [ -  + ]:      49700 :             if (d_state.isInConflict())
     884                 :            :             {
     885                 :          0 :               return;
     886                 :            :             }
     887                 :            :           }
     888                 :            :         }
     889                 :            :       }
     890                 :            :       // we assert it positively, if its beyond the bound, abort
     891                 :      10959 :       if (options().uf.ufssAbortCardinality >= 0
     892 [ -  + ][ -  - ]:      10959 :           && c >= static_cast<uint32_t>(options().uf.ufssAbortCardinality))
                 [ -  + ]
     893                 :            :       {
     894                 :          0 :         std::stringstream ss;
     895                 :          0 :         ss << "Maximum cardinality (" << options().uf.ufssAbortCardinality
     896                 :          0 :            << ")  for finite model finding exceeded." << std::endl;
     897                 :          0 :         throw LogicException(ss.str());
     898                 :            :       }
     899                 :            :     }
     900                 :            :     else
     901                 :            :     {
     902         [ +  + ]:       2380 :       if (c > d_maxNegCard.get())
     903                 :            :       {
     904         [ +  - ]:       4136 :         Trace("uf-ss-com-card-debug") << "Maximum negative cardinality for "
     905                 :       2068 :                                       << d_type << " is now " << c << std::endl;
     906                 :       2068 :         d_maxNegCard.set(c);
     907                 :       2068 :         simpleCheckCardinality();
     908                 :            :       }
     909                 :            :     }
     910                 :            :   }
     911                 :            : }
     912                 :            : 
     913                 :     149127 : void SortModel::checkRegion( int ri, bool checkCombine ){
     914 [ +  + ][ +  + ]:     149127 :   if( isValid(ri) && d_hasCard ){
                 [ +  + ]
     915 [ -  + ][ -  + ]:     139943 :     Assert(d_cardinality > 0);
                 [ -  - ]
     916 [ +  + ][ +  + ]:     139943 :     if( checkCombine && d_regions[ri]->getMustCombine( d_cardinality ) ){
                 [ +  + ]
     917                 :      14495 :       int riNew = forceCombineRegion( ri, true );
     918         [ +  - ]:      14495 :       if( riNew>=0 ){
     919                 :      14495 :         checkRegion( riNew, checkCombine );
     920                 :            :       }
     921                 :            :     }
     922                 :            :     //now check if region is in conflict
     923                 :     279886 :     std::vector< Node > clique;
     924         [ +  + ]:     139943 :     if( d_regions[ri]->check( Theory::EFFORT_STANDARD, d_cardinality, clique ) ){
     925                 :            :       //explain clique
     926                 :       2818 :       addCliqueLemma(clique);
     927                 :            :     }
     928                 :            :   }
     929                 :     149127 : }
     930                 :            : 
     931                 :      18623 : int SortModel::forceCombineRegion( int ri, bool useDensity ){
     932         [ +  + ]:      18623 :   if( !useDensity ){
     933         [ +  - ]:      34274 :     for( int i=0; i<(int)d_regions_index; i++ ){
     934 [ +  + ][ +  + ]:      34274 :       if( ri!=i && d_regions[i]->valid() ){
                 [ +  + ]
     935                 :       4128 :         return combineRegions( ri, i );
     936                 :            :       }
     937                 :            :     }
     938                 :          0 :     return -1;
     939                 :            :   }else{
     940                 :            :     //this region must merge with another
     941         [ -  + ]:      14495 :     if( TraceIsOn("uf-ss-check-region") ){
     942         [ -  - ]:          0 :       Trace("uf-ss-check-region") << "We must combine Region #" << ri << ". " << std::endl;
     943                 :          0 :       d_regions[ri]->debugPrint("uf-ss-check-region");
     944                 :            :     }
     945                 :            :     //take region with maximum disequality density
     946                 :      14495 :     double maxScore = 0;
     947                 :      14495 :     int maxRegion = -1;
     948                 :      28990 :     std::map< int, int > regions_diseq;
     949                 :      14495 :     getDisequalitiesToRegions( ri, regions_diseq );
     950         [ +  + ]:      97184 :     for( std::map< int, int >::iterator it = regions_diseq.begin(); it != regions_diseq.end(); ++it ){
     951         [ +  - ]:      82689 :       Trace("uf-ss-check-region") << it->first << " : " << it->second << std::endl;
     952                 :            :     }
     953         [ +  + ]:      97184 :     for( std::map< int, int >::iterator it = regions_diseq.begin(); it != regions_diseq.end(); ++it ){
     954 [ -  + ][ -  + ]:      82689 :       Assert(it->first != ri);
                 [ -  - ]
     955 [ -  + ][ -  + ]:      82689 :       Assert(isValid(it->first));
                 [ -  - ]
     956 [ -  + ][ -  + ]:      82689 :       Assert(d_regions[it->first]->getNumReps() > 0);
                 [ -  - ]
     957                 :      82689 :       double tempScore = double(it->second)/double(d_regions[it->first]->getNumReps() );
     958         [ +  + ]:      82689 :       if( tempScore>maxScore ){
     959                 :      18025 :         maxRegion = it->first;
     960                 :      18025 :         maxScore = tempScore;
     961                 :            :       }
     962                 :            :     }
     963         [ +  - ]:      14495 :     if( maxRegion!=-1 ){
     964         [ -  + ]:      14495 :       if( TraceIsOn("uf-ss-check-region") ){
     965         [ -  - ]:          0 :         Trace("uf-ss-check-region") << "Combine with region #" << maxRegion << ":" << std::endl;
     966                 :          0 :         d_regions[maxRegion]->debugPrint("uf-ss-check-region");
     967                 :            :       }
     968                 :      14495 :       return combineRegions( ri, maxRegion );
     969                 :            :     }
     970                 :          0 :     return -1;
     971                 :            :   }
     972                 :            : }
     973                 :            : 
     974                 :            : 
     975                 :      56379 : int SortModel::combineRegions( int ai, int bi ){
     976         [ +  - ]:      56379 :   Trace("uf-ss-region") << "uf-ss: Combine Region #" << bi << " with Region #" << ai << std::endl;
     977 [ +  - ][ +  - ]:     112758 :   Assert(isValid(ai) && isValid(bi));
         [ -  + ][ -  - ]
     978                 :      56379 :   Region* region_bi = d_regions[bi];
     979         [ +  + ]:     292037 :   for(Region::iterator it = region_bi->begin(); it != region_bi->end(); ++it){
     980                 :     235658 :     Region::RegionNodeInfo* rni = it->second;
     981         [ +  + ]:     235658 :     if( rni->valid() ){
     982                 :      59903 :       d_regions_map[ it->first ] = ai;
     983                 :            :     }
     984                 :            :   }
     985                 :            :   //update regions disequal DO_THIS?
     986                 :      56379 :   d_regions[ai]->combine( d_regions[bi] );
     987                 :      56379 :   d_regions[bi]->setValid( false );
     988                 :      56379 :   return ai;
     989                 :            : }
     990                 :            : 
     991                 :        850 : void SortModel::moveNode( Node n, int ri ){
     992         [ +  - ]:        850 :   Trace("uf-ss-region") << "uf-ss: Move node " << n << " to Region #" << ri << std::endl;
     993 [ -  + ][ -  + ]:        850 :   Assert(isValid(d_regions_map[n]));
                 [ -  - ]
     994 [ -  + ][ -  + ]:        850 :   Assert(isValid(ri));
                 [ -  - ]
     995                 :            :   //move node to region ri
     996                 :        850 :   d_regions[ri]->takeNode( d_regions[ d_regions_map[n] ], n );
     997                 :        850 :   d_regions_map[n] = ri;
     998                 :        850 : }
     999                 :            : 
    1000                 :       3022 : int SortModel::addSplit(Region* r)
    1001                 :            : {
    1002                 :       6044 :   Node s;
    1003         [ +  - ]:       3022 :   if( r->hasSplits() ){
    1004                 :            :     //take the first split you find
    1005                 :      17903 :     for( Region::split_iterator it = r->begin_splits();
    1006         [ +  - ]:      32784 :          it != r->end_splits(); ++it ){
    1007         [ +  + ]:      17903 :       if( (*it).second ){
    1008                 :       3022 :         s = (*it).first;
    1009                 :       3022 :         break;
    1010                 :            :       }
    1011                 :            :     }
    1012 [ -  + ][ -  + ]:       3022 :     Assert(s != Node::null());
                 [ -  - ]
    1013                 :            :   }
    1014         [ +  - ]:       3022 :   if (!s.isNull() ){
    1015                 :            :     //add lemma to output channel
    1016 [ -  + ][ -  + ]:       3022 :     Assert(s.getKind() == Kind::EQUAL);
                 [ -  - ]
    1017                 :       6044 :     Node ss = rewrite(s);
    1018         [ -  + ]:       3022 :     if (ss.getKind() != Kind::EQUAL)
    1019                 :            :     {
    1020                 :          0 :       Node b_t = NodeManager::currentNM()->mkConst( true );
    1021                 :          0 :       Node b_f = NodeManager::currentNM()->mkConst( false );
    1022         [ -  - ]:          0 :       if( ss==b_f ){
    1023         [ -  - ]:          0 :         Trace("uf-ss-lemma") << "....Assert disequal directly : "
    1024                 :          0 :                              << s[0] << " " << s[1] << std::endl;
    1025                 :          0 :         assertDisequal( s[0], s[1], b_t );
    1026                 :          0 :         return -1;
    1027                 :            :       }else{
    1028         [ -  - ]:          0 :         Trace("uf-ss-warn") << "Split on unknown literal : " << ss << std::endl;
    1029                 :            :       }
    1030         [ -  - ]:          0 :       if (ss == b_t)
    1031                 :            :       {
    1032                 :          0 :         AlwaysAssert(false) << "Bad split " << s << std::endl;
    1033                 :            :       }
    1034                 :            :     }
    1035         [ -  + ]:       3022 :     if (TraceIsOn("uf-ss-split-si"))
    1036                 :            :     {
    1037                 :          0 :       SortInference* si = d_state.getSortInference();
    1038         [ -  - ]:          0 :       if (si != nullptr)
    1039                 :            :       {
    1040         [ -  - ]:          0 :         for (size_t i = 0; i < 2; i++)
    1041                 :            :         {
    1042                 :          0 :           int sid = si->getSortId(ss[i]);
    1043         [ -  - ]:          0 :           Trace("uf-ss-split-si") << sid << " ";
    1044                 :            :         }
    1045         [ -  - ]:          0 :         Trace("uf-ss-split-si") << std::endl;
    1046                 :            :       }
    1047                 :            :     }
    1048                 :            :     //Trace("uf-ss-lemma") << d_th->getEqualityEngine()->areEqual( s[0], s[1] ) << " ";
    1049                 :            :     //Trace("uf-ss-lemma") << d_th->getEqualityEngine()->areDisequal( s[0], s[1] ) << std::endl;
    1050                 :            :     //Trace("uf-ss-lemma") << s[0].getType() << " " << s[1].getType() << std::endl;
    1051                 :            :     //split on the equality s
    1052                 :       6044 :     Node lem = NodeManager::currentNM()->mkNode(Kind::OR, ss, ss.negate());
    1053                 :            :     // send lemma, with caching
    1054         [ +  - ]:       3022 :     if (d_im.lemma(lem, InferenceId::UF_CARD_SPLIT))
    1055                 :            :     {
    1056         [ +  - ]:       3022 :       Trace("uf-ss-lemma") << "*** Split on " << s << std::endl;
    1057                 :            :       //tell the sat solver to explore the equals branch first
    1058                 :       3022 :       d_im.preferPhase(ss, true);
    1059                 :       3022 :       ++( d_thss->d_statistics.d_split_lemmas );
    1060                 :            :     }
    1061                 :       3022 :     return 1;
    1062                 :            :   }else{
    1063                 :          0 :     return 0;
    1064                 :            :   }
    1065                 :            : }
    1066                 :            : 
    1067                 :       4002 : void SortModel::addCliqueLemma(std::vector<Node>& clique)
    1068                 :            : {
    1069 [ -  + ][ -  + ]:       4002 :   Assert(d_hasCard);
                 [ -  - ]
    1070 [ -  + ][ -  + ]:       4002 :   Assert(d_cardinality > 0);
                 [ -  - ]
    1071         [ +  + ]:       6656 :   while (clique.size() > d_cardinality + 1)
    1072                 :            :   {
    1073                 :       2654 :     clique.pop_back();
    1074                 :            :   }
    1075                 :            :   // add as lemma
    1076                 :       8004 :   std::vector<Node> eqs;
    1077         [ +  + ]:      21541 :   for (unsigned i = 0, size = clique.size(); i < size; i++)
    1078                 :            :   {
    1079         [ +  + ]:      72669 :     for (unsigned j = 0; j < i; j++)
    1080                 :            :     {
    1081                 :      55130 :       eqs.push_back(clique[i].eqNode(clique[j]));
    1082                 :            :     }
    1083                 :            :   }
    1084                 :       4002 :   eqs.push_back(d_cardinality_literal[d_cardinality].notNode());
    1085                 :       8004 :   Node lem = NodeManager::currentNM()->mkNode(Kind::OR, eqs);
    1086                 :            :   // send lemma, with caching
    1087         [ +  - ]:       4002 :   if (d_im.lemma(lem, InferenceId::UF_CARD_CLIQUE))
    1088                 :            :   {
    1089         [ +  - ]:       4002 :     Trace("uf-ss-lemma") << "*** Add clique lemma " << lem << std::endl;
    1090                 :       4002 :     ++(d_thss->d_statistics.d_clique_lemmas);
    1091                 :            :   }
    1092                 :       4002 : }
    1093                 :            : 
    1094                 :      13277 : void SortModel::simpleCheckCardinality() {
    1095 [ +  + ][ +  + ]:      13277 :   if( d_maxNegCard.get()!=0 && d_hasCard.get() && d_cardinality.get()<d_maxNegCard.get() ){
         [ +  + ][ +  + ]
    1096                 :            :     Node lem = NodeManager::currentNM()->mkNode(
    1097                 :            :         Kind::AND,
    1098                 :        528 :         getCardinalityLiteral(d_cardinality.get()),
    1099                 :       1056 :         getCardinalityLiteral(d_maxNegCard.get()).negate());
    1100         [ +  - ]:        264 :     Trace("uf-ss-lemma") << "*** Simple cardinality conflict : " << lem << std::endl;
    1101                 :        264 :     d_im.conflict(lem, InferenceId::UF_CARD_SIMPLE_CONFLICT);
    1102                 :            :   }
    1103                 :      13277 : }
    1104                 :            : 
    1105                 :      14232 : void SortModel::debugPrint( const char* c ){
    1106         [ -  + ]:      14232 :   if( TraceIsOn( c ) ){
    1107         [ -  - ]:          0 :     Trace( c ) << "Number of reps = " << d_reps << std::endl;
    1108         [ -  - ]:          0 :     Trace( c ) << "Cardinality req = " << d_cardinality << std::endl;
    1109                 :          0 :     unsigned debugReps = 0;
    1110         [ -  - ]:          0 :     for( unsigned i=0; i<d_regions_index; i++ ){
    1111                 :          0 :       Region* region = d_regions[i]; 
    1112         [ -  - ]:          0 :       if( region->valid() ){
    1113         [ -  - ]:          0 :         Trace( c ) << "Region #" << i << ": " << std::endl;
    1114                 :          0 :         region->debugPrint( c, true );
    1115         [ -  - ]:          0 :         Trace( c ) << std::endl;
    1116         [ -  - ]:          0 :         for( Region::iterator it = region->begin(); it != region->end(); ++it ){
    1117         [ -  - ]:          0 :           if( it->second->valid() ){
    1118         [ -  - ]:          0 :             if( d_regions_map[ it->first ]!=(int)i ){
    1119         [ -  - ]:          0 :               Trace( c ) << "***Bad regions map : " << it->first
    1120                 :          0 :                          << " " << d_regions_map[ it->first ].get() << std::endl;
    1121                 :            :             }
    1122                 :            :           }
    1123                 :            :         }
    1124                 :          0 :         debugReps += region->getNumReps();
    1125                 :            :       }
    1126                 :            :     }
    1127                 :            : 
    1128         [ -  - ]:          0 :     if( debugReps!=d_reps ){
    1129         [ -  - ]:          0 :       Trace( c ) << "***Bad reps: " << d_reps << ", "
    1130                 :          0 :                  << "actual = " << debugReps << std::endl;
    1131                 :            :     }
    1132                 :            :   }
    1133                 :      14232 : }
    1134                 :            : 
    1135                 :       2038 : bool SortModel::checkLastCall()
    1136                 :            : {
    1137                 :       2038 :   NodeManager* nm = NodeManager::currentNM();
    1138                 :       2038 :   SkolemManager* sm = nm->getSkolemManager();
    1139                 :       2038 :   TheoryModel* m = d_state.getModel();
    1140         [ -  + ]:       2038 :   if( TraceIsOn("uf-ss-warn") ){
    1141                 :          0 :     std::vector< Node > eqcs;
    1142                 :            :     eq::EqClassesIterator eqcs_i =
    1143                 :          0 :         eq::EqClassesIterator(m->getEqualityEngine());
    1144         [ -  - ]:          0 :     while( !eqcs_i.isFinished() ){
    1145                 :          0 :       Node eqc = (*eqcs_i);
    1146         [ -  - ]:          0 :       if( eqc.getType()==d_type ){
    1147         [ -  - ]:          0 :         if( std::find( eqcs.begin(), eqcs.end(), eqc )==eqcs.end() ){
    1148                 :          0 :           eqcs.push_back( eqc );
    1149                 :            :           //we must ensure that this equivalence class has been accounted for
    1150         [ -  - ]:          0 :           if( d_regions_map.find( eqc )==d_regions_map.end() ){
    1151         [ -  - ]:          0 :             Trace("uf-ss-warn") << "WARNING : equivalence class " << eqc << " unaccounted for." << std::endl;
    1152         [ -  - ]:          0 :             Trace("uf-ss-warn") << "  type : " << d_type << std::endl;
    1153         [ -  - ]:          0 :             Trace("uf-ss-warn") << "  kind : " << eqc.getKind() << std::endl;
    1154                 :            :           }
    1155                 :            :         }
    1156                 :            :       }
    1157                 :          0 :       ++eqcs_i;
    1158                 :            :     }
    1159                 :            :   }
    1160                 :       2038 :   RepSet* rs = m->getRepSetPtr();
    1161                 :       2038 :   size_t nReps = rs->getNumRepresentatives(d_type);
    1162         [ +  + ]:       2038 :   if (nReps != d_maxNegCard + 1)
    1163                 :            :   {
    1164         [ +  - ]:         62 :     Trace("uf-ss-warn") << "WARNING : Model does not have same # "
    1165                 :          0 :                            "representatives as cardinality for "
    1166                 :         31 :                         << d_type << "." << std::endl;
    1167         [ +  - ]:         62 :     Trace("uf-ss-warn") << "   Max neg cardinality : " << d_maxNegCard
    1168                 :         31 :                         << std::endl;
    1169         [ +  - ]:         31 :     Trace("uf-ss-warn") << "   # Reps : " << nReps << std::endl;
    1170         [ +  - ]:         31 :     if (d_maxNegCard >= nReps)
    1171                 :            :     {
    1172         [ +  + ]:        345 :       while (d_fresh_aloc_reps.size() <= d_maxNegCard)
    1173                 :            :       {
    1174                 :        628 :         std::stringstream ss;
    1175                 :        314 :         ss << "r_" << d_type << "_";
    1176                 :            :         Node nn = sm->mkDummySkolem(
    1177                 :        942 :             ss.str(), d_type, "enumeration to meet negative card constraint");
    1178                 :        314 :         d_fresh_aloc_reps.push_back( nn );
    1179                 :            :       }
    1180         [ +  + ]:         31 :       if (d_maxNegCard == 0)
    1181                 :            :       {
    1182                 :          4 :         rs->d_type_reps[d_type].push_back(d_fresh_aloc_reps[0]);
    1183                 :            :       }
    1184                 :            :       else
    1185                 :            :       {
    1186                 :            :         //must add lemma
    1187                 :         54 :         std::vector< Node > force_cl;
    1188         [ +  + ]:        337 :         for (size_t i = 0; i <= d_maxNegCard; i++)
    1189                 :            :         {
    1190         [ +  + ]:       2777 :           for (size_t j = (i + 1); j <= d_maxNegCard; j++)
    1191                 :            :           {
    1192                 :       2467 :             force_cl.push_back(
    1193                 :       4934 :                 d_fresh_aloc_reps[i].eqNode(d_fresh_aloc_reps[j]).negate());
    1194                 :            :           }
    1195                 :            :         }
    1196                 :         54 :         Node cl = getCardinalityLiteral( d_maxNegCard );
    1197                 :         54 :         Node lem = nm->mkNode(Kind::OR, cl, nm->mkAnd(force_cl));
    1198         [ +  - ]:         27 :         Trace("uf-ss-lemma") << "*** Enforce negative cardinality constraint lemma : " << lem << std::endl;
    1199                 :         27 :         d_im.lemma(lem, InferenceId::UF_CARD_ENFORCE_NEGATIVE);
    1200                 :         27 :         return false;
    1201                 :            :       }
    1202                 :            :     }
    1203                 :            :   }
    1204                 :       2011 :   return true;
    1205                 :            : }
    1206                 :            : 
    1207                 :          0 : int SortModel::getNumRegions(){
    1208                 :          0 :   int count = 0;
    1209         [ -  - ]:          0 :   for( int i=0; i<(int)d_regions_index; i++ ){
    1210         [ -  - ]:          0 :     if( d_regions[i]->valid() ){
    1211                 :          0 :       count++;
    1212                 :            :     }
    1213                 :            :   }
    1214                 :          0 :   return count;
    1215                 :            : }
    1216                 :            : 
    1217                 :      16690 : Node SortModel::getCardinalityLiteral(uint32_t c)
    1218                 :            : {
    1219 [ -  + ][ -  + ]:      16690 :   Assert(c > 0);
                 [ -  - ]
    1220                 :      16690 :   std::map<uint32_t, Node>::iterator itcl = d_cardinality_literal.find(c);
    1221         [ +  + ]:      16690 :   if (itcl != d_cardinality_literal.end())
    1222                 :            :   {
    1223                 :      15054 :     return itcl->second;
    1224                 :            :   }
    1225                 :            :   // get the literal from the decision strategy
    1226                 :       3272 :   Node lit = d_c_dec_strat->getLiteral(c - 1);
    1227                 :       1636 :   d_cardinality_literal[c] = lit;
    1228                 :            : 
    1229                 :            :   // return the literal
    1230                 :       1636 :   return lit;
    1231                 :            : }
    1232                 :            : 
    1233                 :        721 : CardinalityExtension::CardinalityExtension(Env& env,
    1234                 :            :                                            TheoryState& state,
    1235                 :            :                                            TheoryInferenceManager& im,
    1236                 :        721 :                                            TheoryUF* th)
    1237                 :            :     : EnvObj(env),
    1238                 :            :       d_statistics(statisticsRegistry()),
    1239                 :            :       d_state(state),
    1240                 :            :       d_im(im),
    1241                 :            :       d_th(th),
    1242                 :            :       d_rep_model(),
    1243                 :          0 :       d_min_pos_com_card(context(), 0),
    1244                 :          0 :       d_min_pos_com_card_set(context(), false),
    1245                 :            :       d_cc_dec_strat(nullptr),
    1246                 :          0 :       d_initializedCombinedCardinality(userContext(), false),
    1247                 :       1442 :       d_card_assertions_eqv_lemma(userContext()),
    1248                 :          0 :       d_min_pos_tn_master_card(context(), 0),
    1249                 :          0 :       d_min_pos_tn_master_card_set(context(), false),
    1250                 :        721 :       d_rel_eqc(context())
    1251                 :            : {
    1252                 :        721 :   if (options().uf.ufssMode == options::UfssMode::FULL
    1253 [ +  + ][ +  - ]:        721 :       && options().uf.ufssFairness)
                 [ +  + ]
    1254                 :            :   {
    1255                 :            :     // Register the strategy with the decision manager of the theory.
    1256                 :            :     // We are guaranteed that the decision manager is ready since we
    1257                 :            :     // construct this module during TheoryUF::finishInit.
    1258                 :        709 :     d_cc_dec_strat.reset(
    1259                 :        709 :         new CombinedCardinalityDecisionStrategy(env, th->getValuation()));
    1260                 :            :   }
    1261                 :        721 : }
    1262                 :            : 
    1263                 :       1442 : CardinalityExtension::~CardinalityExtension()
    1264                 :            : {
    1265                 :       1466 :   for (std::map<TypeNode, SortModel*>::iterator it = d_rep_model.begin();
    1266         [ +  + ]:       2211 :        it != d_rep_model.end(); ++it) {
    1267         [ +  - ]:        745 :     delete it->second;
    1268                 :            :   }
    1269                 :       1442 : }
    1270                 :            : 
    1271                 :            : /** ensure eqc */
    1272                 :          0 : void CardinalityExtension::ensureEqc(SortModel* c, Node a)
    1273                 :            : {
    1274         [ -  - ]:          0 :   if( !hasEqc( a ) ){
    1275                 :          0 :     d_rel_eqc[a] = true;
    1276         [ -  - ]:          0 :     Trace("uf-ss-solver") << "CardinalityExtension: New eq class " << a << " : "
    1277                 :          0 :                           << a.getType() << std::endl;
    1278                 :          0 :     c->newEqClass( a );
    1279         [ -  - ]:          0 :     Trace("uf-ss-solver") << "CardinalityExtension: Done New eq class."
    1280                 :          0 :                           << std::endl;
    1281                 :            :   }
    1282                 :          0 : }
    1283                 :            : 
    1284                 :          0 : void CardinalityExtension::ensureEqcRec(Node n)
    1285                 :            : {
    1286         [ -  - ]:          0 :   if( !hasEqc( n ) ){
    1287                 :          0 :     SortModel* c = getSortModel( n );
    1288         [ -  - ]:          0 :     if( c ){
    1289                 :          0 :       ensureEqc( c, n );
    1290                 :            :     }
    1291         [ -  - ]:          0 :     for( unsigned i=0; i<n.getNumChildren(); i++ ){
    1292                 :          0 :       ensureEqcRec( n[i] );
    1293                 :            :     }
    1294                 :            :   }
    1295                 :          0 : }
    1296                 :            : 
    1297                 :            : /** has eqc */
    1298                 :          0 : bool CardinalityExtension::hasEqc(Node a)
    1299                 :            : {
    1300                 :          0 :   NodeBoolMap::iterator it = d_rel_eqc.find( a );
    1301                 :          0 :   return it!=d_rel_eqc.end() && (*it).second;
    1302                 :            : }
    1303                 :            : 
    1304                 :            : /** new node */
    1305                 :      53408 : void CardinalityExtension::newEqClass(Node a)
    1306                 :            : {
    1307                 :      53408 :   SortModel* c = getSortModel( a );
    1308         [ +  + ]:      53408 :   if( c ){
    1309         [ +  - ]:      15206 :     Trace("uf-ss-solver") << "CardinalityExtension: New eq class " << a << " : "
    1310 [ -  + ][ -  - ]:       7603 :                           << a.getType() << std::endl;
    1311                 :       7603 :     c->newEqClass( a );
    1312         [ +  - ]:      15206 :     Trace("uf-ss-solver") << "CardinalityExtension: Done New eq class."
    1313                 :       7603 :                           << std::endl;
    1314                 :            :   }
    1315                 :      53408 : }
    1316                 :            : 
    1317                 :            : /** merge */
    1318                 :     308148 : void CardinalityExtension::merge(Node a, Node b)
    1319                 :            : {
    1320                 :            :   //TODO: ensure they are relevant
    1321                 :     308148 :   SortModel* c = getSortModel( a );
    1322         [ +  + ]:     308148 :   if( c ){
    1323         [ +  - ]:      87308 :     Trace("uf-ss-solver") << "CardinalityExtension: Merge " << a << " " << b
    1324 [ -  + ][ -  - ]:      43654 :                           << " : " << a.getType() << std::endl;
    1325                 :      43654 :     c->merge( a, b );
    1326         [ +  - ]:      43654 :     Trace("uf-ss-solver") << "CardinalityExtension: Done Merge." << std::endl;
    1327                 :            :   }
    1328                 :     308148 : }
    1329                 :            : 
    1330                 :            : /** assert terms are disequal */
    1331                 :      34052 : void CardinalityExtension::assertDisequal(Node a, Node b, Node reason)
    1332                 :            : {
    1333                 :      34052 :   SortModel* c = getSortModel( a );
    1334         [ +  + ]:      34052 :   if( c ){
    1335         [ +  - ]:      41178 :     Trace("uf-ss-solver") << "CardinalityExtension: Assert disequal " << a
    1336 [ -  + ][ -  - ]:      20589 :                           << " " << b << " : " << a.getType() << std::endl;
    1337                 :      20589 :     c->assertDisequal( a, b, reason );
    1338         [ +  - ]:      41178 :     Trace("uf-ss-solver") << "CardinalityExtension: Done Assert disequal."
    1339                 :      20589 :                           << std::endl;
    1340                 :            :   }
    1341                 :      34052 : }
    1342                 :            : 
    1343                 :            : /** assert a node */
    1344                 :     225296 : void CardinalityExtension::assertNode(Node n, bool isDecision)
    1345                 :            : {
    1346         [ +  - ]:     225296 :   Trace("uf-ss") << "Assert " << n << " " << isDecision << std::endl;
    1347                 :     225296 :   bool polarity = n.getKind() != Kind::NOT;
    1348         [ +  + ]:     225296 :   TNode lit = polarity ? n : n[0];
    1349         [ +  + ]:     225296 :   if (options().uf.ufssMode == options::UfssMode::FULL)
    1350                 :            :   {
    1351         [ +  + ]:     181875 :     if (lit.getKind() == Kind::CARDINALITY_CONSTRAINT)
    1352                 :            :     {
    1353                 :            :       const CardinalityConstraint& cc =
    1354                 :      13595 :           lit.getOperator().getConst<CardinalityConstraint>();
    1355                 :      27190 :       TypeNode tn = cc.getType();
    1356 [ -  + ][ -  + ]:      13595 :       Assert(tn.isUninterpretedSort());
                 [ -  - ]
    1357 [ -  + ][ -  + ]:      13595 :       Assert(d_rep_model[tn]);
                 [ -  - ]
    1358                 :      13595 :       uint32_t nCard = cc.getUpperBound().getUnsignedInt();
    1359         [ +  - ]:      27190 :       Trace("uf-ss-debug") << "...check cardinality constraint : " << tn
    1360                 :      13595 :                            << std::endl;
    1361         [ +  + ]:      13595 :       if (options().uf.ufssFairnessMonotone)
    1362                 :            :       {
    1363                 :         68 :         SortInference* si = d_state.getSortInference();
    1364         [ +  - ]:         68 :         Trace("uf-ss-com-card-debug") << "...set master/slave" << std::endl;
    1365         [ +  + ]:         68 :         if (tn != d_tn_mono_master)
    1366                 :            :         {
    1367                 :         52 :           std::map<TypeNode, bool>::iterator it = d_tn_mono_slave.find(tn);
    1368         [ +  + ]:         52 :           if (it == d_tn_mono_slave.end())
    1369                 :            :           {
    1370                 :            :             bool isMonotonic;
    1371         [ -  + ]:         10 :             if (si != nullptr)
    1372                 :            :             {
    1373                 :          0 :               isMonotonic = si->isMonotonic(tn);
    1374                 :            :             }
    1375                 :            :             else
    1376                 :            :             {
    1377                 :            :               // if ground, everything is monotonic
    1378                 :         10 :               isMonotonic = true;
    1379                 :            :             }
    1380         [ +  - ]:         10 :             if (isMonotonic)
    1381                 :            :             {
    1382         [ +  + ]:         10 :               if (d_tn_mono_master.isNull())
    1383                 :            :               {
    1384         [ +  - ]:          8 :                 Trace("uf-ss-com-card-debug")
    1385                 :          4 :                     << "uf-ss-fair-monotone: Set master : " << tn << std::endl;
    1386                 :          4 :                 d_tn_mono_master = tn;
    1387                 :            :               }
    1388                 :            :               else
    1389                 :            :               {
    1390         [ +  - ]:         12 :                 Trace("uf-ss-com-card-debug")
    1391                 :          6 :                     << "uf-ss-fair-monotone: Set slave : " << tn << std::endl;
    1392                 :          6 :                 d_tn_mono_slave[tn] = true;
    1393                 :            :               }
    1394                 :            :             }
    1395                 :            :             else
    1396                 :            :             {
    1397         [ -  - ]:          0 :               Trace("uf-ss-com-card-debug")
    1398                 :          0 :                   << "uf-ss-fair-monotone: Set non-monotonic : " << tn
    1399                 :          0 :                   << std::endl;
    1400                 :          0 :               d_tn_mono_slave[tn] = false;
    1401                 :            :             }
    1402                 :            :           }
    1403                 :            :         }
    1404                 :            :         // set the minimum positive cardinality for master if necessary
    1405 [ +  + ][ +  + ]:         68 :         if (polarity && tn == d_tn_mono_master)
                 [ +  + ]
    1406                 :            :         {
    1407         [ +  - ]:         40 :           Trace("uf-ss-com-card-debug")
    1408                 :         20 :               << "...set min positive cardinality" << std::endl;
    1409                 :         20 :           if (!d_min_pos_tn_master_card_set.get()
    1410 [ -  + ][ -  - ]:         20 :               || nCard < d_min_pos_tn_master_card.get())
                 [ +  - ]
    1411                 :            :           {
    1412                 :         20 :             d_min_pos_tn_master_card_set.set(true);
    1413                 :         20 :             d_min_pos_tn_master_card.set(nCard);
    1414                 :            :           }
    1415                 :            :         }
    1416                 :            :       }
    1417         [ +  - ]:      13595 :       Trace("uf-ss-com-card-debug") << "...assert cardinality" << std::endl;
    1418                 :      13595 :       d_rep_model[tn]->assertCardinality(nCard, polarity);
    1419                 :            :       // check if combined cardinality is violated
    1420                 :      13595 :       checkCombinedCardinality();
    1421                 :            :     }
    1422         [ +  + ]:     168280 :     else if (lit.getKind() == Kind::COMBINED_CARDINALITY_CONSTRAINT)
    1423                 :            :     {
    1424         [ +  + ]:       6997 :       if( polarity ){
    1425                 :            :         //safe to assume int here
    1426                 :            :         const CombinedCardinalityConstraint& cc =
    1427                 :       5504 :             lit.getOperator().getConst<CombinedCardinalityConstraint>();
    1428                 :       5504 :         uint32_t nCard = cc.getUpperBound().getUnsignedInt();
    1429 [ -  + ][ -  - ]:       5504 :         if (!d_min_pos_com_card_set.get() || nCard < d_min_pos_com_card.get())
                 [ +  - ]
    1430                 :            :         {
    1431                 :       5504 :           d_min_pos_com_card_set.set(true);
    1432                 :       5504 :           d_min_pos_com_card.set( nCard );
    1433                 :       5504 :           checkCombinedCardinality();
    1434                 :            :         }
    1435                 :            :       }
    1436                 :            :     }
    1437                 :            :     else
    1438                 :            :     {
    1439         [ -  + ]:     161283 :       if( TraceIsOn("uf-ss-warn") ){
    1440                 :            :         ////FIXME: this is too strict: theory propagations are showing up as isDecision=true, but
    1441                 :            :         ////       a theory propagation is not a decision.
    1442         [ -  - ]:          0 :         if( isDecision ){
    1443         [ -  - ]:          0 :           for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
    1444         [ -  - ]:          0 :             if( !it->second->hasCardinalityAsserted() ){
    1445         [ -  - ]:          0 :               Trace("uf-ss-warn") << "WARNING: Assert " << n << " as a decision before cardinality for " << it->first << "." << std::endl;
    1446                 :            :             }
    1447                 :            :           }
    1448                 :            :         }
    1449                 :            :       }
    1450                 :            :     }
    1451                 :            :   }
    1452                 :            :   else
    1453                 :            :   {
    1454                 :      43421 :     if (lit.getKind() == Kind::CARDINALITY_CONSTRAINT
    1455 [ +  + ][ -  + ]:      43421 :         || lit.getKind() == Kind::COMBINED_CARDINALITY_CONSTRAINT)
                 [ +  + ]
    1456                 :            :     {
    1457                 :            :       // cardinality constraint from user input, set incomplete   
    1458         [ +  - ]:          2 :       Trace("uf-ss") << "Literal " << lit << " not handled when uf ss mode is not FULL, set incomplete." << std::endl;
    1459                 :          2 :       d_im.setModelUnsound(IncompleteId::UF_CARD_MODE);
    1460                 :            :     }
    1461                 :            :   }
    1462         [ +  - ]:     225296 :   Trace("uf-ss") << "Assert: done " << n << " " << isDecision << std::endl;
    1463                 :     225296 : }
    1464                 :            : 
    1465                 :          0 : bool CardinalityExtension::areDisequal(Node a, Node b)
    1466                 :            : {
    1467         [ -  - ]:          0 :   if( a==b ){
    1468                 :          0 :     return false;
    1469                 :            :   }
    1470                 :          0 :   eq::EqualityEngine* ee = d_th->getEqualityEngine();
    1471                 :          0 :   a = ee->getRepresentative(a);
    1472                 :          0 :   b = ee->getRepresentative(b);
    1473         [ -  - ]:          0 :   if (ee->areDisequal(a, b, false))
    1474                 :            :   {
    1475                 :          0 :     return true;
    1476                 :            :   }
    1477                 :          0 :   SortModel* c = getSortModel(a);
    1478         [ -  - ]:          0 :   if (c)
    1479                 :            :   {
    1480                 :          0 :     return c->areDisequal(a, b);
    1481                 :            :   }
    1482                 :          0 :   return false;
    1483                 :            : }
    1484                 :            : 
    1485                 :            : /** check */
    1486                 :     106872 : void CardinalityExtension::check(Theory::Effort level)
    1487                 :            : {
    1488         [ +  + ]:     106872 :   if (level == Theory::EFFORT_LAST_CALL)
    1489                 :            :   {
    1490                 :            :     // if last call, call last call check for each sort
    1491         [ +  + ]:       3507 :     for (std::pair<const TypeNode, SortModel*>& r : d_rep_model)
    1492                 :            :     {
    1493         [ +  + ]:       2038 :       if (!r.second->checkLastCall())
    1494                 :            :       {
    1495                 :         27 :         break;
    1496                 :            :       }
    1497                 :            :     }
    1498                 :       1496 :     return;
    1499                 :            :   }
    1500         [ +  - ]:     105376 :   if (!d_state.isInConflict())
    1501                 :            :   {
    1502         [ +  + ]:     105376 :     if (options().uf.ufssMode == options::UfssMode::FULL)
    1503                 :            :     {
    1504         [ +  - ]:     163656 :       Trace("uf-ss-solver")
    1505                 :      81828 :           << "CardinalityExtension: check " << level << std::endl;
    1506         [ +  + ]:      81828 :       if (level == Theory::EFFORT_FULL)
    1507                 :            :       {
    1508         [ -  + ]:       6332 :         if (TraceIsOn("uf-ss-debug"))
    1509                 :            :         {
    1510                 :          0 :           debugPrint("uf-ss-debug");
    1511                 :            :         }
    1512         [ -  + ]:       6332 :         if (TraceIsOn("uf-ss-state"))
    1513                 :            :         {
    1514         [ -  - ]:          0 :           Trace("uf-ss-state")
    1515                 :          0 :               << "CardinalityExtension::check " << level << std::endl;
    1516         [ -  - ]:          0 :           for (std::pair<const TypeNode, SortModel*>& rm : d_rep_model)
    1517                 :            :           {
    1518         [ -  - ]:          0 :             Trace("uf-ss-state") << "  " << rm.first << " has cardinality "
    1519                 :          0 :                                  << rm.second->getCardinality() << std::endl;
    1520                 :            :           }
    1521                 :            :         }
    1522                 :            :       }
    1523         [ +  + ]:     415699 :       for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
    1524                 :     333871 :         it->second->check(level);
    1525         [ -  + ]:     333871 :         if (d_state.isInConflict())
    1526                 :            :         {
    1527                 :          0 :           break;
    1528                 :            :         }
    1529                 :            :       }
    1530                 :            :     }
    1531         [ +  - ]:      23548 :     else if (options().uf.ufssMode == options::UfssMode::NO_MINIMAL)
    1532                 :            :     {
    1533         [ +  + ]:      23548 :       if( level==Theory::EFFORT_FULL ){
    1534                 :            :         // split on an equality between two equivalence classes (at most one per type)
    1535                 :       1314 :         std::map< TypeNode, std::vector< Node > > eqc_list;
    1536                 :       1314 :         std::map< TypeNode, bool > type_proc;
    1537                 :        657 :         eq::EqClassesIterator eqcs_i(d_th->getEqualityEngine());
    1538         [ +  + ]:      60633 :         while( !eqcs_i.isFinished() ){
    1539                 :     119952 :           Node a = *eqcs_i;
    1540                 :     119952 :           TypeNode tn = a.getType();
    1541         [ +  + ]:      59976 :           if (tn.isUninterpretedSort())
    1542                 :            :           {
    1543         [ +  + ]:       8425 :             if( type_proc.find( tn )==type_proc.end() ){
    1544                 :       6366 :               std::map< TypeNode, std::vector< Node > >::iterator itel = eqc_list.find( tn );
    1545         [ +  + ]:       6366 :               if( itel!=eqc_list.end() ){
    1546         [ +  + ]:      10494 :                 for( unsigned j=0; j<itel->second.size(); j++ ){
    1547                 :       7239 :                   Node b = itel->second[j];
    1548         [ +  + ]:       7239 :                   if( !d_th->getEqualityEngine()->areDisequal( a, b, false ) ){
    1549                 :       2043 :                     Node eq = rewrite(a.eqNode(b));
    1550                 :            :                     Node lem = NodeManager::currentNM()->mkNode(
    1551                 :       2043 :                         Kind::OR, eq, eq.negate());
    1552         [ +  - ]:        681 :                     Trace("uf-ss-lemma") << "*** Split (no-minimal) : " << lem << std::endl;
    1553                 :        681 :                     d_im.lemma(lem, InferenceId::UF_CARD_SPLIT);
    1554                 :        681 :                     d_im.preferPhase(eq, true);
    1555                 :        681 :                     type_proc[tn] = true;
    1556                 :        681 :                     break;
    1557                 :            :                   }
    1558                 :            :                 }
    1559                 :            :               }
    1560                 :       6366 :               eqc_list[tn].push_back( a );
    1561                 :            :             }
    1562                 :            :           }
    1563                 :      59976 :           ++eqcs_i;
    1564                 :            :         }
    1565                 :            :       }
    1566                 :            :     }
    1567                 :            :     else
    1568                 :            :     {
    1569                 :            :       // unhandled uf ss mode
    1570                 :          0 :       Assert(false);
    1571                 :            :     }
    1572         [ +  - ]:     210752 :     Trace("uf-ss-solver") << "Done CardinalityExtension: check " << level
    1573                 :     105376 :                           << std::endl;
    1574                 :            :   }
    1575                 :            : }
    1576                 :            : 
    1577                 :        734 : void CardinalityExtension::presolve()
    1578                 :            : {
    1579                 :        734 :   d_initializedCombinedCardinality = false;
    1580         [ +  + ]:       1191 :   for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
    1581                 :        457 :     it->second->presolve();
    1582                 :        457 :     it->second->initialize();
    1583                 :            :   }
    1584                 :        734 : }
    1585                 :            : 
    1586                 :        709 : CardinalityExtension::CombinedCardinalityDecisionStrategy::
    1587                 :        709 :     CombinedCardinalityDecisionStrategy(Env& env, Valuation valuation)
    1588                 :        709 :     : DecisionStrategyFmf(env, valuation)
    1589                 :            : {
    1590                 :        709 : }
    1591                 :       1336 : Node CardinalityExtension::CombinedCardinalityDecisionStrategy::mkLiteral(
    1592                 :            :     unsigned i)
    1593                 :            : {
    1594                 :       1336 :   NodeManager* nm = NodeManager::currentNM();
    1595                 :       2672 :   Node cco = nm->mkConst(CombinedCardinalityConstraint(Integer(i)));
    1596                 :       2672 :   return nm->mkNode(Kind::COMBINED_CARDINALITY_CONSTRAINT, cco);
    1597                 :            : }
    1598                 :            : 
    1599                 :            : std::string
    1600                 :          0 : CardinalityExtension::CombinedCardinalityDecisionStrategy::identify() const
    1601                 :            : {
    1602                 :          0 :   return std::string("uf_combined_card");
    1603                 :            : }
    1604                 :            : 
    1605                 :     382601 : void CardinalityExtension::preRegisterTerm(TNode n)
    1606                 :            : {
    1607         [ +  + ]:     382601 :   if (options().uf.ufssMode != options::UfssMode::FULL)
    1608                 :            :   {
    1609                 :     357825 :     return;
    1610                 :            :   }
    1611                 :            :   // initialize combined cardinality
    1612                 :     296164 :   initializeCombinedCardinality();
    1613                 :            : 
    1614         [ +  - ]:     296164 :   Trace("uf-ss-register") << "Preregister " << n << "." << std::endl;
    1615                 :            :   // shouldn't have to preregister this type (it may be that there are no
    1616                 :            :   // quantifiers over tn)
    1617                 :     296164 :   TypeNode tn;
    1618         [ +  + ]:     296164 :   if (n.getKind() == Kind::CARDINALITY_CONSTRAINT)
    1619                 :            :   {
    1620                 :            :     const CardinalityConstraint& cc =
    1621                 :      17471 :         n.getOperator().getConst<CardinalityConstraint>();
    1622                 :      17471 :     tn = cc.getType();
    1623                 :            :   }
    1624                 :            :   else
    1625                 :            :   {
    1626                 :     278693 :     tn = n.getType();
    1627                 :            :   }
    1628         [ +  + ]:     296164 :   if (!tn.isUninterpretedSort())
    1629                 :            :   {
    1630                 :     271388 :     return;
    1631                 :            :   }
    1632                 :      24776 :   std::map<TypeNode, SortModel*>::iterator it = d_rep_model.find(tn);
    1633         [ +  + ]:      24776 :   if (it == d_rep_model.end())
    1634                 :            :   {
    1635                 :        745 :     SortModel* rm = nullptr;
    1636         [ +  - ]:        745 :     if (tn.isUninterpretedSort())
    1637                 :            :     {
    1638         [ +  - ]:        745 :       Trace("uf-ss-register") << "Create sort model " << tn << "." << std::endl;
    1639                 :        745 :       rm = new SortModel(d_env, tn, d_state, d_im, this);
    1640                 :            :     }
    1641         [ +  - ]:        745 :     if (rm)
    1642                 :            :     {
    1643                 :        745 :       rm->initialize();
    1644                 :        745 :       d_rep_model[tn] = rm;
    1645                 :            :       // d_rep_model_init[tn] = true;
    1646                 :            :     }
    1647                 :            :   }
    1648                 :            :   else
    1649                 :            :   {
    1650                 :            :     // ensure sort model is initialized
    1651                 :      24031 :     it->second->initialize();
    1652                 :            :   }
    1653                 :            : }
    1654                 :            : 
    1655                 :     395608 : SortModel* CardinalityExtension::getSortModel(Node n)
    1656                 :            : {
    1657                 :     791216 :   TypeNode tn = n.getType();
    1658                 :     395608 :   std::map< TypeNode, SortModel* >::iterator it = d_rep_model.find( tn );
    1659                 :            :   //pre-register the type if not done already
    1660         [ +  + ]:     395608 :   if( it==d_rep_model.end() ){
    1661                 :     323762 :     preRegisterTerm( n );
    1662                 :     323762 :     it = d_rep_model.find( tn );
    1663                 :            :   }
    1664         [ +  + ]:     395608 :   if( it!=d_rep_model.end() ){
    1665                 :      71846 :     return it->second;
    1666                 :            :   }else{
    1667                 :     323762 :     return NULL;
    1668                 :            :   }
    1669                 :            : }
    1670                 :            : 
    1671                 :            : /** get cardinality for sort */
    1672                 :          0 : int CardinalityExtension::getCardinality(Node n)
    1673                 :            : {
    1674                 :          0 :   SortModel* c = getSortModel( n );
    1675         [ -  - ]:          0 :   if( c ){
    1676                 :          0 :     return c->getCardinality();
    1677                 :            :   }else{
    1678                 :          0 :     return -1;
    1679                 :            :   }
    1680                 :            : }
    1681                 :            : 
    1682                 :          0 : int CardinalityExtension::getCardinality(TypeNode tn)
    1683                 :            : {
    1684                 :          0 :   std::map< TypeNode, SortModel* >::iterator it = d_rep_model.find( tn );
    1685 [ -  - ][ -  - ]:          0 :   if( it!=d_rep_model.end() && it->second ){
                 [ -  - ]
    1686                 :          0 :     return it->second->getCardinality();
    1687                 :            :   }
    1688                 :          0 :   return -1;
    1689                 :            : }
    1690                 :            : 
    1691                 :            : //print debug
    1692                 :          0 : void CardinalityExtension::debugPrint(const char* c)
    1693                 :            : {
    1694         [ -  - ]:          0 :   for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
    1695         [ -  - ]:          0 :     Trace( c ) << "Conflict find structure for " << it->first << ": " << std::endl;
    1696                 :          0 :     it->second->debugPrint( c );
    1697         [ -  - ]:          0 :     Trace( c ) << std::endl;
    1698                 :            :   }
    1699                 :          0 : }
    1700                 :            : 
    1701                 :            : /** initialize */
    1702                 :     296164 : void CardinalityExtension::initializeCombinedCardinality()
    1703                 :            : {
    1704                 :     296164 :   if (d_cc_dec_strat.get() != nullptr
    1705 [ +  - ][ +  + ]:     296164 :       && !d_initializedCombinedCardinality.get())
                 [ +  + ]
    1706                 :            :   {
    1707                 :        776 :     d_initializedCombinedCardinality = true;
    1708                 :       1552 :     d_im.getDecisionManager()->registerStrategy(
    1709                 :        776 :         DecisionManager::STRAT_UF_COMBINED_CARD, d_cc_dec_strat.get());
    1710                 :            :   }
    1711                 :     296164 : }
    1712                 :            : 
    1713                 :            : /** check */
    1714                 :      19099 : void CardinalityExtension::checkCombinedCardinality()
    1715                 :            : {
    1716 [ -  + ][ -  + ]:      19099 :   Assert(options().uf.ufssMode == options::UfssMode::FULL);
                 [ -  - ]
    1717         [ +  - ]:      19099 :   if (options().uf.ufssFairness)
    1718                 :            :   {
    1719         [ +  - ]:      19099 :     Trace("uf-ss-com-card-debug") << "Check combined cardinality, get maximum negative cardinalities..." << std::endl;
    1720                 :      19099 :     uint32_t totalCombinedCard = 0;
    1721                 :      19099 :     uint32_t maxMonoSlave = 0;
    1722                 :      19099 :     TypeNode maxSlaveType;
    1723         [ +  + ]:     111565 :     for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
    1724                 :      92466 :       uint32_t max_neg = it->second->getMaximumNegativeCardinality();
    1725         [ +  + ]:      92466 :       if (!options().uf.ufssFairnessMonotone)
    1726                 :            :       {
    1727                 :      92244 :         totalCombinedCard += max_neg;
    1728                 :            :       }
    1729                 :            :       else
    1730                 :            :       {
    1731                 :        222 :         std::map< TypeNode, bool >::iterator its = d_tn_mono_slave.find( it->first );
    1732 [ +  + ][ -  + ]:        222 :         if( its==d_tn_mono_slave.end() || !its->second ){
                 [ +  + ]
    1733                 :         92 :           totalCombinedCard += max_neg;
    1734                 :            :         }else{
    1735         [ +  + ]:        130 :           if( max_neg>maxMonoSlave ){
    1736                 :          8 :             maxMonoSlave = max_neg;
    1737                 :          8 :             maxSlaveType = it->first;
    1738                 :            :           }
    1739                 :            :         }
    1740                 :            :       }
    1741                 :            :     }
    1742         [ +  - ]:      19099 :     Trace("uf-ss-com-card-debug") << "Check combined cardinality, total combined card : " << totalCombinedCard << std::endl;
    1743         [ +  + ]:      19099 :     if (options().uf.ufssFairnessMonotone)
    1744                 :            :     {
    1745         [ +  - ]:         88 :       Trace("uf-ss-com-card-debug") << "Max slave monotonic negated cardinality : " << maxMonoSlave << std::endl;
    1746                 :         88 :       if (!d_min_pos_tn_master_card_set.get()
    1747 [ +  + ][ -  + ]:         88 :           && maxMonoSlave > d_min_pos_tn_master_card.get())
                 [ -  + ]
    1748                 :            :       {
    1749                 :          0 :         uint32_t mc = d_min_pos_tn_master_card.get();
    1750                 :          0 :         std::vector< Node > conf;
    1751                 :          0 :         conf.push_back( d_rep_model[d_tn_mono_master]->getCardinalityLiteral( mc ) );
    1752                 :          0 :         conf.push_back( d_rep_model[maxSlaveType]->getCardinalityLiteral( maxMonoSlave ).negate() );
    1753                 :          0 :         Node cf = NodeManager::currentNM()->mkNode(Kind::AND, conf);
    1754         [ -  - ]:          0 :         Trace("uf-ss-lemma") << "*** Combined monotone cardinality conflict"
    1755                 :          0 :                              << " : " << cf << std::endl;
    1756         [ -  - ]:          0 :         Trace("uf-ss-com-card") << "*** Combined monotone cardinality conflict"
    1757                 :          0 :                                 << " : " << cf << std::endl;
    1758                 :          0 :         d_im.conflict(cf, InferenceId::UF_CARD_MONOTONE_COMBINED);
    1759                 :          0 :         return;
    1760                 :            :       }
    1761                 :            :     }
    1762                 :      19099 :     uint32_t cc = d_min_pos_com_card.get();
    1763 [ +  + ][ +  + ]:      19099 :     if (d_min_pos_com_card_set.get() && totalCombinedCard > cc)
                 [ +  + ]
    1764                 :            :     {
    1765                 :            :       //conflict
    1766                 :       2280 :       Node com_lit = d_cc_dec_strat->getLiteral(cc);
    1767                 :       2280 :       std::vector< Node > conf;
    1768                 :       1140 :       conf.push_back( com_lit );
    1769                 :       1140 :       uint32_t totalAdded = 0;
    1770                 :       3516 :       for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); 
    1771         [ +  - ]:       5892 :            it != d_rep_model.end(); ++it ){
    1772                 :       3516 :         bool doAdd = true;
    1773         [ -  + ]:       3516 :         if (options().uf.ufssFairnessMonotone)
    1774                 :            :         {
    1775                 :            :           std::map< TypeNode, bool >::iterator its =
    1776                 :          0 :             d_tn_mono_slave.find( it->first );
    1777 [ -  - ][ -  - ]:          0 :           if( its!=d_tn_mono_slave.end() && its->second ){
                 [ -  - ]
    1778                 :          0 :             doAdd = false;
    1779                 :            :           }
    1780                 :            :         }
    1781         [ +  - ]:       3516 :         if( doAdd ){
    1782                 :       3516 :           uint32_t c = it->second->getMaximumNegativeCardinality();
    1783         [ +  + ]:       3516 :           if( c>0 ){
    1784                 :       2540 :             conf.push_back( it->second->getCardinalityLiteral( c ).negate() );
    1785                 :       2540 :             totalAdded += c;
    1786                 :            :           }
    1787         [ +  + ]:       3516 :           if( totalAdded>cc ){
    1788                 :       1140 :             break;
    1789                 :            :           }
    1790                 :            :         }
    1791                 :            :       }
    1792                 :       1140 :       Node cf = NodeManager::currentNM()->mkNode(Kind::AND, conf);
    1793         [ +  - ]:       2280 :       Trace("uf-ss-lemma") << "*** Combined cardinality conflict : " << cf
    1794                 :       1140 :                            << std::endl;
    1795         [ +  - ]:       2280 :       Trace("uf-ss-com-card") << "*** Combined cardinality conflict : " << cf
    1796                 :       1140 :                               << std::endl;
    1797                 :       1140 :       d_im.conflict(cf, InferenceId::UF_CARD_COMBINED);
    1798                 :            :     }
    1799                 :            :   }
    1800                 :            : }
    1801                 :            : 
    1802                 :        721 : CardinalityExtension::Statistics::Statistics(StatisticsRegistry& sr)
    1803                 :            :     : d_clique_conflicts(
    1804                 :        721 :         sr.registerInt("CardinalityExtension::Clique_Conflicts")),
    1805                 :        721 :       d_clique_lemmas(sr.registerInt("CardinalityExtension::Clique_Lemmas")),
    1806                 :        721 :       d_split_lemmas(sr.registerInt("CardinalityExtension::Split_Lemmas")),
    1807                 :        721 :       d_max_model_size(sr.registerInt("CardinalityExtension::Max_Model_Size"))
    1808                 :            : {
    1809                 :        721 :   d_max_model_size.maxAssign(1);
    1810                 :        721 : }
    1811                 :            : 
    1812                 :            : }  // namespace uf
    1813                 :            : }  // namespace theory
    1814                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14