GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/uf/cardinality_extension.cpp Lines: 813 1012 80.3 %
Date: 2021-11-07 Branches: 1661 4068 40.8 %

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