GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/uf/cardinality_extension.cpp Lines: 807 1005 80.3 %
Date: 2021-09-16 Branches: 1672 4094 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/skolem_manager.h"
21
#include "options/smt_options.h"
22
#include "options/uf_options.h"
23
#include "smt/logic_exception.h"
24
#include "theory/decision_manager.h"
25
#include "theory/quantifiers/term_database.h"
26
#include "theory/quantifiers_engine.h"
27
#include "theory/theory_engine.h"
28
#include "theory/theory_model.h"
29
#include "theory/uf/equality_engine.h"
30
#include "theory/uf/theory_uf.h"
31
#include "util/rational.h"
32
33
using namespace std;
34
using namespace cvc5::kind;
35
using namespace cvc5::context;
36
37
namespace cvc5 {
38
namespace theory {
39
namespace uf {
40
41
/* These are names are unambigious are we use abbreviations. */
42
typedef CardinalityExtension::SortModel SortModel;
43
typedef SortModel::Region Region;
44
typedef Region::RegionNodeInfo RegionNodeInfo;
45
typedef RegionNodeInfo::DiseqList DiseqList;
46
47
2543
Region::Region(SortModel* cf, context::Context* c)
48
  : d_cf( cf )
49
  , d_testCliqueSize( c, 0 )
50
  , d_splitsSize( c, 0 )
51
  , d_testClique( c )
52
  , d_splits( c )
53
  , d_reps_size( c, 0 )
54
  , d_total_diseq_external( c, 0 )
55
  , d_total_diseq_internal( c, 0 )
56
2543
  , d_valid( c, true ) {}
57
58
7629
Region::~Region() {
59
12197
  for(iterator i = begin(), iend = end(); i != iend; ++i) {
60
9654
    RegionNodeInfo* regionNodeInfo = (*i).second;
61
9654
    delete regionNodeInfo;
62
  }
63
2543
  d_nodes.clear();
64
5086
}
65
66
5196
void Region::addRep( Node n ) {
67
5196
  setRep( n, true );
68
5196
}
69
70
435
void Region::takeNode( Region* r, Node n ){
71
435
  Assert(!hasRep(n));
72
435
  Assert(r->hasRep(n));
73
  //add representative
74
435
  setRep( n, true );
75
  //take disequalities from r
76
435
  RegionNodeInfo* rni = r->d_nodes[n];
77
1305
  for( int t=0; t<2; t++ ){
78
870
    DiseqList* del = rni->get(t);
79
2470
    for(DiseqList::iterator it = del->begin(); it != del->end(); ++it ){
80
1600
      if( (*it).second ){
81
1027
        r->setDisequal( n, (*it).first, t, false );
82
1027
        if( t==0 ){
83
534
          if( hasRep( (*it).first ) ){
84
456
            setDisequal( (*it).first, n, 0, false );
85
456
            setDisequal( (*it).first, n, 1, true );
86
456
            setDisequal( n, (*it).first, 1, true );
87
          }else{
88
78
            setDisequal( n, (*it).first, 0, true );
89
          }
90
        }else{
91
493
          r->setDisequal( (*it).first, n, 1, false );
92
493
          r->setDisequal( (*it).first, n, 0, true );
93
493
          setDisequal( n, (*it).first, 0, true );
94
        }
95
      }
96
    }
97
  }
98
  //remove representative
99
435
  r->setRep( n, false );
100
435
}
101
102
40175
void Region::combine( Region* r ){
103
  //take all nodes from r
104
215842
  for(Region::iterator it = r->d_nodes.begin(); it != r->d_nodes.end(); ++it) {
105
175667
    if( it->second->valid() ){
106
43144
      setRep( it->first, true );
107
    }
108
  }
109
215842
  for(Region::iterator it = r->d_nodes.begin(); it != r->d_nodes.end(); ++it){
110
175667
    if( it->second->valid() ){
111
      //take disequalities from r
112
86288
      Node n = it->first;
113
43144
      RegionNodeInfo* rni = it->second;
114
129432
      for( int t=0; t<2; t++ ){
115
86288
        RegionNodeInfo::DiseqList* del = rni->get(t);
116
221313
        for( RegionNodeInfo::DiseqList::iterator it2 = del->begin(),
117
86288
               it2end = del->end(); it2 != it2end; ++it2 ){
118
135025
          if( (*it2).second ){
119
124023
            if( t==0 && hasRep( (*it2).first ) ){
120
52910
              setDisequal( (*it2).first, n, 0, false );
121
52910
              setDisequal( (*it2).first, n, 1, true );
122
52910
              setDisequal( n, (*it2).first, 1, true );
123
            }else{
124
71113
              setDisequal( n, (*it2).first, t, true );
125
            }
126
          }
127
        }
128
      }
129
    }
130
  }
131
40175
  r->d_valid = false;
132
40175
}
133
134
/** setEqual */
135
31695
void Region::setEqual( Node a, Node b ){
136
31695
  Assert(hasRep(a) && hasRep(b));
137
  //move disequalities of b over to a
138
95085
  for( int t=0; t<2; t++ ){
139
63390
    DiseqList* del = d_nodes[b]->get(t);
140
116892
    for( DiseqList::iterator it = del->begin(); it != del->end(); ++it ){
141
53502
      if( (*it).second ){
142
78640
        Node n = (*it).first;
143
        //get the region that contains the endpoint of the disequality b != ...
144
39320
        Region* nr = d_cf->d_regions[ d_cf->d_regions_map[ n ] ];
145
39320
        if( !isDisequal( a, n, t ) ){
146
18025
          setDisequal( a, n, t, true );
147
18025
          nr->setDisequal( n, a, t, true );
148
        }
149
39320
        setDisequal( b, n, t, false );
150
39320
        nr->setDisequal( n, b, t, false );
151
      }
152
    }
153
  }
154
  //remove b from representatives
155
31695
  setRep( b, false );
156
31695
}
157
158
373929
void Region::setDisequal( Node n1, Node n2, int type, bool valid ){
159
  //Debug("uf-ss-region-debug") << "set disequal " << n1 << " " << n2 << " "
160
  //                            << type << " " << valid << std::endl;
161
  //debugPrint("uf-ss-region-debug");
162
  //Assert( isDisequal( n1, n2, type )!=valid );
163
373929
  if( isDisequal( n1, n2, type )!=valid ){    //DO_THIS: make assertion
164
373151
    d_nodes[ n1 ]->get(type)->setDisequal( n2, valid );
165
373151
    if( type==0 ){
166
162933
      d_total_diseq_external = d_total_diseq_external + ( valid ? 1 : -1 );
167
    }else{
168
210218
      d_total_diseq_internal = d_total_diseq_internal + ( valid ? 1 : -1 );
169
210218
      if( valid ){
170
        //if they are both a part of testClique, then remove split
171
298076
        if( d_testClique.find( n1 )!=d_testClique.end() && d_testClique[n1] &&
172
150597
            d_testClique.find( n2 )!=d_testClique.end() && d_testClique[n2] ){
173
3118
          Node eq = NodeManager::currentNM()->mkNode( EQUAL, n1, n2 );
174
1559
          if( d_splits.find( eq )!=d_splits.end() && d_splits[ eq ] ){
175
1536
            Debug("uf-ss-debug") << "removing split for " << n1 << " " << n2
176
768
                                 << std::endl;
177
768
            d_splits[ eq ] = false;
178
768
            d_splitsSize = d_splitsSize - 1;
179
          }
180
        }
181
      }
182
    }
183
  }
184
373929
}
185
186
80905
void Region::setRep( Node n, bool valid ) {
187
80905
  Assert(hasRep(n) != valid);
188
80905
  if( valid && d_nodes.find( n )==d_nodes.end() ){
189
9654
    d_nodes[n] = new RegionNodeInfo(d_cf->d_thss->context());
190
  }
191
80905
  d_nodes[n]->setValid(valid);
192
80905
  d_reps_size = d_reps_size + ( valid ? 1 : -1 );
193
  //removing a member of the test clique from this region
194
80905
  if( d_testClique.find( n ) != d_testClique.end() && d_testClique[n] ){
195
1562
    Assert(!valid);
196
1562
    d_testClique[n] = false;
197
1562
    d_testCliqueSize = d_testCliqueSize - 1;
198
    //remove all splits involving n
199
13753
    for( split_iterator it = begin_splits(); it != end_splits(); ++it ){
200
12191
      if( (*it).second ){
201
3945
        if( (*it).first[0]==n || (*it).first[1]==n ){
202
3905
          d_splits[ (*it).first ] = false;
203
3905
          d_splitsSize = d_splitsSize - 1;
204
        }
205
      }
206
    }
207
  }
208
80905
}
209
210
457555
bool Region::isDisequal( Node n1, Node n2, int type ) {
211
457555
  RegionNodeInfo::DiseqList* del = d_nodes[ n1 ]->get(type);
212
457555
  return del->isSet(n2) && del->getDisequalityValue(n2);
213
}
214
215
struct sortInternalDegree {
216
  Region* r;
217
15218
  bool operator() (Node i, Node j) {
218
30436
    return (r->getRegionInfo(i)->getNumInternalDisequalities() >
219
30436
            r->getRegionInfo(j)->getNumInternalDisequalities());
220
  }
221
};
222
223
struct sortExternalDegree {
224
  Region* r;
225
  bool operator() (Node i,Node j) {
226
    return (r->getRegionInfo(i)->getNumExternalDisequalities() >
227
            r->getRegionInfo(j)->getNumExternalDisequalities());
228
  }
229
};
230
231
int gmcCount = 0;
232
233
95129
bool Region::getMustCombine( int cardinality ){
234
95129
  if (d_total_diseq_external >= static_cast<unsigned>(cardinality))
235
  {
236
    //The number of external disequalities is greater than or equal to
237
    //cardinality.  Thus, a clique of size cardinality+1 may exist
238
    //between nodes in d_regions[i] and other regions Check if this is
239
    //actually the case: must have n nodes with outgoing degree
240
    //(cardinality+1-n) for some n>0
241
20876
    std::vector< int > degrees;
242
140391
    for( Region::iterator it = begin(); it != end(); ++it ){
243
133382
      RegionNodeInfo* rni = it->second;
244
133382
      if( rni->valid() ){
245
60620
        if( rni->getNumDisequalities() >= cardinality ){
246
46846
          int outDeg = rni->getNumExternalDisequalities();
247
46846
          if( outDeg>=cardinality ){
248
            //we have 1 node of degree greater than (cardinality)
249
15296
            return true;
250
39555
          }else if( outDeg>=1 ){
251
38553
            degrees.push_back( outDeg );
252
38553
            if( (int)degrees.size()>=cardinality ){
253
              //we have (cardinality) nodes of degree 1
254
714
              return true;
255
            }
256
          }
257
        }
258
      }
259
    }
260
7009
    gmcCount++;
261
7009
    if( gmcCount%100==0 ){
262
118
      Trace("gmc-count") << gmcCount << " " << cardinality
263
59
                         << " sample : " << degrees.size() << std::endl;
264
    }
265
    //this should happen relatively infrequently....
266
7009
    std::sort( degrees.begin(), degrees.end() );
267
38356
    for( int i=0; i<(int)degrees.size(); i++ ){
268
32494
      if( degrees[i]>=cardinality+1-((int)degrees.size()-i) ){
269
1147
        return true;
270
      }
271
    }
272
  }
273
85977
  return false;
274
}
275
276
1699299
bool Region::check( Theory::Effort level, int cardinality,
277
                    std::vector< Node >& clique ) {
278
1699299
  if( d_reps_size>unsigned(cardinality) ){
279
77194
    if( d_total_diseq_internal==d_reps_size*( d_reps_size - 1 ) ){
280
56949
      if( d_reps_size>1 ){
281
        //quick clique check, all reps form a clique
282
30086
        for( iterator it = begin(); it != end(); ++it ){
283
26455
          if( it->second->valid() ){
284
19299
            clique.push_back( it->first );
285
          }
286
        }
287
3631
        Trace("quick-clique") << "Found quick clique" << std::endl;
288
3631
        return true;
289
      }else{
290
53318
        return false;
291
      }
292
    }
293
20245
    else if (level==Theory::EFFORT_FULL)
294
    {
295
      //build test clique, up to size cardinality+1
296
2052
      if( d_testCliqueSize<=unsigned(cardinality) ){
297
3964
        std::vector< Node > newClique;
298
1982
        if( d_testCliqueSize<unsigned(cardinality) ){
299
14915
          for( iterator it = begin(); it != end(); ++it ){
300
            //if not in the test clique, add it to the set of new members
301
43113
            if( it->second->valid() &&
302
21561
                ( d_testClique.find( it->first ) == d_testClique.end() ||
303
3
                  !d_testClique[ it->first ] ) ){
304
              //if( it->second->getNumInternalDisequalities()>cardinality ||
305
              //    level==Theory::EFFORT_FULL ){
306
8337
              newClique.push_back( it->first );
307
              //}
308
            }
309
          }
310
          //choose remaining nodes with the highest degrees
311
          sortInternalDegree sidObj;
312
1697
          sidObj.r = this;
313
1697
          std::sort( newClique.begin(), newClique.end(), sidObj );
314
1697
          int offset = ( cardinality - d_testCliqueSize ) + 1;
315
1697
          newClique.erase( newClique.begin() + offset, newClique.end() );
316
        }else{
317
          //scan for the highest degree
318
285
          int maxDeg = -1;
319
570
          Node maxNode;
320
3088
          for( std::map< Node, RegionNodeInfo* >::iterator
321
285
                 it = d_nodes.begin(); it != d_nodes.end(); ++it ){
322
            //if not in the test clique, add it to the set of new members
323
8275
            if( it->second->valid() &&
324
6383
                ( d_testClique.find( it->first )==d_testClique.end() ||
325
1497
                  !d_testClique[ it->first ] ) ){
326
301
              if( it->second->getNumInternalDisequalities()>maxDeg ){
327
287
                maxDeg = it->second->getNumInternalDisequalities();
328
287
                maxNode = it->first;
329
              }
330
            }
331
          }
332
285
          Assert(maxNode != Node::null());
333
285
          newClique.push_back( maxNode );
334
        }
335
        //check splits internal to new members
336
10523
        for( int j=0; j<(int)newClique.size(); j++ ){
337
17082
          Debug("uf-ss-debug") << "Choose to add clique member "
338
8541
                               << newClique[j] << std::endl;
339
38622
          for( int k=(j+1); k<(int)newClique.size(); k++ ){
340
30081
            if( !isDisequal( newClique[j], newClique[k], 1 ) ){
341
7824
              Node at_j = newClique[j];
342
7824
              Node at_k = newClique[k];
343
              Node j_eq_k =
344
7824
                NodeManager::currentNM()->mkNode( EQUAL, at_j, at_k );
345
3912
              d_splits[ j_eq_k ] = true;
346
3912
              d_splitsSize = d_splitsSize + 1;
347
            }
348
          }
349
          //check disequalities with old members
350
10922
          for( NodeBoolMap::iterator it = d_testClique.begin();
351
10922
               it != d_testClique.end(); ++it ){
352
2381
            if( (*it).second ){
353
1503
              if( !isDisequal( (*it).first, newClique[j], 1 ) ){
354
1956
                Node at_it = (*it).first;
355
1956
                Node at_j = newClique[j];
356
1956
                Node it_eq_j = at_it.eqNode(at_j);
357
978
                d_splits[ it_eq_j ] = true;
358
978
                d_splitsSize = d_splitsSize + 1;
359
              }
360
            }
361
          }
362
        }
363
        //add new clique members to test clique
364
10523
        for( int j=0; j<(int)newClique.size(); j++ ){
365
8541
          d_testClique[ newClique[j] ] = true;
366
8541
          d_testCliqueSize = d_testCliqueSize + 1;
367
        }
368
      }
369
      // Check if test clique has larger size than cardinality, and
370
      // forms a clique.
371
2052
      if( d_testCliqueSize >= unsigned(cardinality+1) && d_splitsSize==0 ){
372
        //test clique is a clique
373
136
        for( NodeBoolMap::iterator it = d_testClique.begin();
374
136
             it != d_testClique.end(); ++it ){
375
100
          if( (*it).second ){
376
98
            clique.push_back( (*it).first );
377
          }
378
        }
379
36
        return true;
380
      }
381
    }
382
  }
383
1642314
  return false;
384
}
385
386
void Region::getNumExternalDisequalities(
387
    std::map< Node, int >& num_ext_disequalities ){
388
  for( Region::iterator it = begin(); it != end(); ++it ){
389
    RegionNodeInfo* rni = it->second;
390
    if( rni->valid() ){
391
      DiseqList* del = rni->get(0);
392
      for( DiseqList::iterator it2 = del->begin(); it2 != del->end(); ++it2 ){
393
        if( (*it2).second ){
394
          num_ext_disequalities[ (*it2).first ]++;
395
        }
396
      }
397
    }
398
  }
399
}
400
401
2653
void Region::debugPrint( const char* c, bool incClique ) {
402
2653
  Debug( c ) << "Num reps: " << d_reps_size << std::endl;
403
7783
  for( Region::iterator it = begin(); it != end(); ++it ){
404
5130
    RegionNodeInfo* rni = it->second;
405
5130
    if( rni->valid() ){
406
      Node n = it->first;
407
      Debug( c ) << "   " << n << std::endl;
408
      for( int i=0; i<2; i++ ){
409
        Debug( c ) << "      " << ( i==0 ? "Ext" : "Int" ) << " disequal:";
410
        DiseqList* del = rni->get(i);
411
        for( DiseqList::iterator it2 = del->begin(); it2 != del->end(); ++it2 ){
412
          if( (*it2).second ){
413
            Debug( c ) << " " << (*it2).first;
414
          }
415
        }
416
        Debug( c ) << ", total = " << del->size() << std::endl;
417
      }
418
    }
419
  }
420
2653
  Debug( c ) << "Total disequal: " << d_total_diseq_external << " external,";
421
2653
  Debug( c ) << " " << d_total_diseq_internal << " internal." << std::endl;
422
423
2653
  if( incClique ){
424
2653
    if( !d_testClique.empty() ){
425
      Debug( c ) << "Candidate clique members: " << std::endl;
426
      Debug( c ) << "   ";
427
      for( NodeBoolMap::iterator it = d_testClique.begin();
428
           it != d_testClique.end(); ++ it ){
429
        if( (*it).second ){
430
          Debug( c ) << (*it).first << " ";
431
        }
432
      }
433
      Debug( c ) << ", size = " << d_testCliqueSize << std::endl;
434
    }
435
2653
    if( !d_splits.empty() ){
436
      Debug( c ) << "Required splits: " << std::endl;
437
      Debug( c ) << "   ";
438
      for( NodeBoolMap::iterator it = d_splits.begin(); it != d_splits.end();
439
           ++ it ){
440
        if( (*it).second ){
441
          Debug( c ) << (*it).first << " ";
442
        }
443
      }
444
      Debug( c ) << ", size = " << d_splitsSize << std::endl;
445
    }
446
  }
447
2653
}
448
449
460
SortModel::CardinalityDecisionStrategy::CardinalityDecisionStrategy(
450
460
    Env& env, Node t, Valuation valuation)
451
460
    : DecisionStrategyFmf(env, valuation), d_cardinality_term(t)
452
{
453
460
}
454
1090
Node SortModel::CardinalityDecisionStrategy::mkLiteral(unsigned i)
455
{
456
1090
  NodeManager* nm = NodeManager::currentNM();
457
  return nm->mkNode(
458
1090
      CARDINALITY_CONSTRAINT, d_cardinality_term, nm->mkConst(Rational(i + 1)));
459
}
460
481338
std::string SortModel::CardinalityDecisionStrategy::identify() const
461
{
462
481338
  return std::string("uf_card");
463
}
464
465
460
SortModel::SortModel(Node n,
466
                     TheoryState& state,
467
                     TheoryInferenceManager& im,
468
460
                     CardinalityExtension* thss)
469
    : d_type(n.getType()),
470
      d_state(state),
471
      d_im(im),
472
      d_thss(thss),
473
      d_regions_index(thss->context(), 0),
474
      d_regions_map(thss->context()),
475
      d_split_score(thss->context()),
476
      d_disequalities_index(thss->context(), 0),
477
      d_reps(thss->context(), 0),
478
      d_cardinality(thss->context(), 1),
479
      d_hasCard(thss->context(), false),
480
      d_maxNegCard(thss->context(), 0),
481
460
      d_initialized(thss->userContext(), false),
482
920
      d_c_dec_strat(nullptr)
483
{
484
460
  d_cardinality_term = n;
485
486
460
  if (options::ufssMode() == options::UfssMode::FULL)
487
  {
488
    // Register the strategy with the decision manager of the theory.
489
    // We are guaranteed that the decision manager is ready since we
490
    // construct this module during TheoryUF::finishInit.
491
1380
    d_c_dec_strat.reset(new CardinalityDecisionStrategy(
492
920
        thss->d_env, n, thss->getTheory()->getValuation()));
493
  }
494
460
}
495
496
1380
SortModel::~SortModel() {
497
3003
  for(std::vector<Region*>::iterator i = d_regions.begin();
498
3003
      i != d_regions.end(); ++i) {
499
2543
    Region* region = *i;
500
2543
    delete region;
501
  }
502
460
  d_regions.clear();
503
920
}
504
505
/** initialize */
506
5408
void SortModel::initialize()
507
{
508
5408
  if (d_c_dec_strat.get() != nullptr && !d_initialized)
509
  {
510
776
    d_initialized = true;
511
    // Strategy is user-context-dependent, since it is in sync with
512
    // user-context-dependent flag d_initialized.
513
1552
    d_im.getDecisionManager()->registerStrategy(DecisionManager::STRAT_UF_CARD,
514
776
                                                d_c_dec_strat.get());
515
  }
516
5408
}
517
518
/** new node */
519
5196
void SortModel::newEqClass( Node n ){
520
5196
  if (!d_state.isInConflict())
521
  {
522
5196
    if( d_regions_map.find( n )==d_regions_map.end() ){
523
5196
      d_regions_map[n] = d_regions_index;
524
5196
      Debug("uf-ss") << "CardinalityExtension: New Eq Class " << n << std::endl;
525
10392
      Debug("uf-ss-debug") << d_regions_index << " " << (int)d_regions.size()
526
5196
                           << std::endl;
527
5196
      if (d_regions_index < d_regions.size())
528
      {
529
2653
        d_regions[d_regions_index]->debugPrint("uf-ss-debug", true);
530
2653
        d_regions[d_regions_index]->setValid(true);
531
2653
        Assert(d_regions[d_regions_index]->getNumReps() == 0);
532
      }else{
533
2543
        d_regions.push_back(new Region(this, d_thss->context()));
534
      }
535
5196
      d_regions[d_regions_index]->addRep(n);
536
5196
      d_regions_index = d_regions_index + 1;
537
538
5196
      d_reps = d_reps + 1;
539
    }
540
  }
541
5196
}
542
543
/** merge */
544
31695
void SortModel::merge( Node a, Node b ){
545
31695
  if (d_state.isInConflict())
546
  {
547
    return;
548
  }
549
63390
  Debug("uf-ss") << "CardinalityExtension: Merging " << a << " = " << b << "..."
550
31695
                 << std::endl;
551
31695
  if (a != b)
552
  {
553
31695
    Assert(d_regions_map.find(a) != d_regions_map.end());
554
31695
    Assert(d_regions_map.find(b) != d_regions_map.end());
555
31695
    int ai = d_regions_map[a];
556
31695
    int bi = d_regions_map[b];
557
31695
    Debug("uf-ss") << "   regions: " << ai << " " << bi << std::endl;
558
31695
    if (ai != bi)
559
    {
560
28425
      if (d_regions[ai]->getNumReps() == 1)
561
      {
562
19800
        int ri = combineRegions(bi, ai);
563
19800
        d_regions[ri]->setEqual(a, b);
564
19800
        checkRegion(ri);
565
      }
566
8625
      else if (d_regions[bi]->getNumReps() == 1)
567
      {
568
8190
        int ri = combineRegions(ai, bi);
569
8190
        d_regions[ri]->setEqual(a, b);
570
8190
        checkRegion(ri);
571
      }
572
      else
573
      {
574
        // Either move a to d_regions[bi], or b to d_regions[ai].
575
435
        RegionNodeInfo* a_region_info = d_regions[ai]->getRegionInfo(a);
576
435
        RegionNodeInfo* b_region_info = d_regions[bi]->getRegionInfo(b);
577
435
        int aex = (a_region_info->getNumInternalDisequalities()
578
435
                   - getNumDisequalitiesToRegion(a, bi));
579
435
        int bex = (b_region_info->getNumInternalDisequalities()
580
435
                   - getNumDisequalitiesToRegion(b, ai));
581
        // Based on which would produce the fewest number of
582
        // external disequalities.
583
435
        if (aex < bex)
584
        {
585
139
          moveNode(a, bi);
586
139
          d_regions[bi]->setEqual(a, b);
587
        }else{
588
296
          moveNode(b, ai);
589
296
          d_regions[ai]->setEqual( a, b );
590
        }
591
435
        checkRegion(ai);
592
435
        checkRegion(bi);
593
      }
594
    }
595
    else
596
    {
597
3270
      d_regions[ai]->setEqual(a, b);
598
3270
      checkRegion(ai);
599
    }
600
31695
    d_regions_map[b] = -1;
601
  }
602
31695
  d_reps = d_reps - 1;
603
}
604
605
/** assert terms are disequal */
606
12722
void SortModel::assertDisequal( Node a, Node b, Node reason ){
607
12722
  if (d_state.isInConflict())
608
  {
609
    return;
610
  }
611
  // if they are not already disequal
612
12722
  eq::EqualityEngine* ee = d_thss->getTheory()->getEqualityEngine();
613
12722
  a = ee->getRepresentative(a);
614
12722
  b = ee->getRepresentative(b);
615
12722
  int ai = d_regions_map[a];
616
12722
  int bi = d_regions_map[b];
617
12722
  if (d_regions[ai]->isDisequal(a, b, ai == bi))
618
  {
619
    // already disequal
620
    return;
621
  }
622
25444
  Debug("uf-ss") << "Assert disequal " << a << " != " << b << "..."
623
12722
                 << std::endl;
624
25444
  Debug("uf-ss-disequal") << "Assert disequal " << a << " != " << b << "..."
625
12722
                          << std::endl;
626
  // add to list of disequalities
627
12722
  if (d_disequalities_index < d_disequalities.size())
628
  {
629
9607
    d_disequalities[d_disequalities_index] = reason;
630
  }
631
  else
632
  {
633
3115
    d_disequalities.push_back(reason);
634
  }
635
12722
  d_disequalities_index = d_disequalities_index + 1;
636
  // now, add disequalities to regions
637
12722
  Assert(d_regions_map.find(a) != d_regions_map.end());
638
12722
  Assert(d_regions_map.find(b) != d_regions_map.end());
639
12722
  Debug("uf-ss") << "   regions: " << ai << " " << bi << std::endl;
640
12722
  if (ai == bi)
641
  {
642
    // internal disequality
643
528
    d_regions[ai]->setDisequal(a, b, 1, true);
644
528
    d_regions[ai]->setDisequal(b, a, 1, true);
645
    // do not need to check if it needs to combine (no new ext. disequalities)
646
528
    checkRegion(ai, false);
647
  }
648
  else
649
  {
650
    // external disequality
651
12194
    d_regions[ai]->setDisequal(a, b, 0, true);
652
12194
    d_regions[bi]->setDisequal(b, a, 0, true);
653
12194
    checkRegion(ai);
654
12194
    checkRegion(bi);
655
  }
656
}
657
658
bool SortModel::areDisequal( Node a, Node b ) {
659
  Assert(a == d_thss->getTheory()->getEqualityEngine()->getRepresentative(a));
660
  Assert(b == d_thss->getTheory()->getEqualityEngine()->getRepresentative(b));
661
  if( d_regions_map.find( a )!=d_regions_map.end() &&
662
      d_regions_map.find( b )!=d_regions_map.end() ){
663
    int ai = d_regions_map[a];
664
    int bi = d_regions_map[b];
665
    return d_regions[ai]->isDisequal(a, b, ai==bi ? 1 : 0);
666
  }else{
667
    return false;
668
  }
669
}
670
671
252110
void SortModel::check(Theory::Effort level)
672
{
673
252110
  Assert(options::ufssMode() == options::UfssMode::FULL);
674
252110
  if (!d_hasCard && d_state.isInConflict())
675
  {
676
    // not necessary to check
677
    return;
678
  }
679
504220
  Debug("uf-ss") << "CardinalityExtension: Check " << level << " " << d_type
680
252110
                 << std::endl;
681
252110
  if (level == Theory::EFFORT_FULL)
682
  {
683
9808
    Debug("fmf-full-check") << std::endl;
684
19616
    Debug("fmf-full-check")
685
9808
        << "Full check for SortModel " << d_type << ", status : " << std::endl;
686
9808
    debugPrint("fmf-full-check");
687
9808
    Debug("fmf-full-check") << std::endl;
688
  }
689
252110
  if (d_reps <= (unsigned)d_cardinality)
690
  {
691
185990
    Debug("uf-ss-debug") << "We have " << d_reps << " representatives for type "
692
92995
                         << d_type << ", <= " << d_cardinality << std::endl;
693
92995
    if( level==Theory::EFFORT_FULL ){
694
9446
      Debug("uf-ss-sat") << "We have " << d_reps << " representatives for type "
695
4723
                         << d_type << ", <= " << d_cardinality << std::endl;
696
    }
697
92995
    return;
698
  }
699
  // first check if we can generate a clique conflict
700
  // do a check within each region
701
2648015
  for (size_t i = 0; i < d_regions_index; i++)
702
  {
703
2490277
    if (d_regions[i]->valid())
704
    {
705
3205907
      std::vector<Node> clique;
706
1603642
      if (d_regions[i]->check(level, d_cardinality, clique))
707
      {
708
        // add clique lemma
709
1377
        addCliqueLemma(clique);
710
1377
        return;
711
      }
712
      else
713
      {
714
1602265
        Trace("uf-ss-debug") << "No clique in Region #" << i << std::endl;
715
      }
716
    }
717
  }
718
  // do splitting on demand
719
157738
  bool addedLemma = false;
720
157738
  if (level == Theory::EFFORT_FULL)
721
  {
722
5049
    Trace("uf-ss-debug") << "Add splits?" << std::endl;
723
    // see if we have any recommended splits from large regions
724
82294
    for (size_t i = 0; i < d_regions_index; i++)
725
    {
726
77245
      if (d_regions[i]->valid() && d_regions[i]->getNumReps() > d_cardinality)
727
      {
728
2016
        int sp = addSplit(d_regions[i]);
729
2016
        if (sp == 1)
730
        {
731
2016
          addedLemma = true;
732
        }
733
        else if (sp == -1)
734
        {
735
          check(level);
736
          return;
737
        }
738
      }
739
    }
740
  }
741
  // If no added lemmas, force continuation via combination of regions.
742
157738
  if (level != Theory::EFFORT_FULL || addedLemma)
743
  {
744
154705
    return;
745
  }
746
  // check at full effort
747
3033
  Trace("uf-ss-debug") << "No splits added. " << d_cardinality << std::endl;
748
3033
  Trace("uf-ss-si") << "Must combine region" << std::endl;
749
3033
  bool recheck = false;
750
3033
  SortInference* si = d_state.getSortInference();
751
3033
  if (si != nullptr)
752
  {
753
    // If sort inference is enabled, search for regions with same sort.
754
108
    std::map<int, int> sortsFound;
755
502
    for (size_t i = 0; i < d_regions_index; i++)
756
    {
757
502
      if (d_regions[i]->valid())
758
      {
759
162
        Node op = d_regions[i]->frontKey();
760
108
        int sort_id = si->getSortId(op);
761
108
        if (sortsFound.find(sort_id) != sortsFound.end())
762
        {
763
108
          Debug("fmf-full-check") << "Combined regions " << i << " "
764
54
                                  << sortsFound[sort_id] << std::endl;
765
54
          combineRegions(sortsFound[sort_id], i);
766
54
          recheck = true;
767
54
          break;
768
        }
769
        else
770
        {
771
54
          sortsFound[sort_id] = i;
772
        }
773
      }
774
    }
775
  }
776
3033
  if (!recheck)
777
  {
778
    // naive strategy, force region combination involving the first
779
    // valid region
780
12084
    for (size_t i = 0; i < d_regions_index; i++)
781
    {
782
12084
      if (d_regions[i]->valid())
783
      {
784
2979
        int fcr = forceCombineRegion(i, false);
785
5958
        Debug("fmf-full-check")
786
2979
            << "Combined regions " << i << " " << fcr << std::endl;
787
5958
        Trace("uf-ss-debug")
788
2979
            << "Combined regions " << i << " " << fcr << std::endl;
789
2979
        recheck = true;
790
2979
        break;
791
      }
792
    }
793
  }
794
3033
  if (recheck)
795
  {
796
3033
    Trace("uf-ss-debug") << "Must recheck." << std::endl;
797
3033
    check(level);
798
  }
799
}
800
801
314
void SortModel::presolve() {
802
314
  d_initialized = false;
803
314
}
804
805
870
int SortModel::getNumDisequalitiesToRegion( Node n, int ri ){
806
870
  int ni = d_regions_map[n];
807
870
  int counter = 0;
808
870
  DiseqList* del = d_regions[ni]->getRegionInfo(n)->get(0);
809
2406
  for( DiseqList::iterator it = del->begin(); it != del->end(); ++it ){
810
1536
    if( (*it).second ){
811
697
      if( d_regions_map[ (*it).first ]==ri ){
812
574
        counter++;
813
      }
814
    }
815
  }
816
870
  return counter;
817
}
818
819
9152
void SortModel::getDisequalitiesToRegions(int ri,
820
                                          std::map< int, int >& regions_diseq)
821
{
822
9152
  Region* region = d_regions[ri];
823
105076
  for(Region::iterator it = region->begin(); it != region->end(); ++it ){
824
95924
    if( it->second->valid() ){
825
25116
      DiseqList* del = it->second->get(0);
826
201137
      for( DiseqList::iterator it2 = del->begin(); it2 != del->end(); ++it2 ){
827
176021
        if( (*it2).second ){
828
120895
          Assert(isValid(d_regions_map[(*it2).first]));
829
          //Notice() << "Found disequality with " << (*it2).first << ", region = " << d_regions_map[ (*it2).first ] << std::endl;
830
120895
          regions_diseq[ d_regions_map[ (*it2).first ] ]++;
831
        }
832
      }
833
    }
834
  }
835
9152
}
836
837
void SortModel::setSplitScore( Node n, int s ){
838
  if( d_split_score.find( n )!=d_split_score.end() ){
839
    int ss = d_split_score[ n ];
840
    d_split_score[ n ] = s>ss ? s : ss;
841
  }else{
842
    d_split_score[ n ] = s;
843
  }
844
  for( int i=0; i<(int)n.getNumChildren(); i++ ){
845
    setSplitScore( n[i], s+1 );
846
  }
847
}
848
849
9066
void SortModel::assertCardinality(uint32_t c, bool val)
850
{
851
9066
  if (!d_state.isInConflict())
852
  {
853
18132
    Trace("uf-ss-assert")
854
9066
        << "Assert cardinality " << d_type << " " << c << " " << val
855
9066
        << " level = "
856
9066
        << d_thss->getTheory()->getValuation().getAssertionLevel() << std::endl;
857
9066
    Assert(c > 0);
858
18012
    Node cl = getCardinalityLiteral( c );
859
9066
    if( val ){
860
7534
      bool doCheckRegions = !d_hasCard;
861
7534
      bool prevHasCard = d_hasCard;
862
7534
      d_hasCard = true;
863
7534
      if (!prevHasCard || c < d_cardinality)
864
      {
865
7524
        d_cardinality = c;
866
7524
        simpleCheckCardinality();
867
7524
        if (d_state.isInConflict())
868
        {
869
120
          return;
870
        }
871
      }
872
      //should check all regions now
873
7414
      if (doCheckRegions)
874
      {
875
49330
        for (size_t i = 0; i < d_regions_index; i++)
876
        {
877
41958
          if( d_regions[i]->valid() ){
878
35965
            checkRegion( i );
879
35965
            if (d_state.isInConflict())
880
            {
881
              return;
882
            }
883
          }
884
        }
885
      }
886
      // we assert it positively, if its beyond the bound, abort
887
14828
      if (options::ufssAbortCardinality() >= 0
888
7414
          && c >= static_cast<uint32_t>(options::ufssAbortCardinality()))
889
      {
890
        std::stringstream ss;
891
        ss << "Maximum cardinality (" << options::ufssAbortCardinality()
892
           << ")  for finite model finding exceeded." << std::endl;
893
        throw LogicException(ss.str());
894
      }
895
    }
896
    else
897
    {
898
1532
      if (c > d_maxNegCard.get())
899
      {
900
2724
        Trace("uf-ss-com-card-debug") << "Maximum negative cardinality for "
901
1362
                                      << d_type << " is now " << c << std::endl;
902
1362
        d_maxNegCard.set(c);
903
1362
        simpleCheckCardinality();
904
      }
905
    }
906
  }
907
}
908
909
102163
void SortModel::checkRegion( int ri, bool checkCombine ){
910
102163
  if( isValid(ri) && d_hasCard ){
911
95657
    Assert(d_cardinality > 0);
912
95657
    if( checkCombine && d_regions[ri]->getMustCombine( d_cardinality ) ){
913
9152
      int riNew = forceCombineRegion( ri, true );
914
9152
      if( riNew>=0 ){
915
9152
        checkRegion( riNew, checkCombine );
916
      }
917
    }
918
    //now check if region is in conflict
919
191314
    std::vector< Node > clique;
920
95657
    if( d_regions[ri]->check( Theory::EFFORT_STANDARD, d_cardinality, clique ) ){
921
      //explain clique
922
2290
      addCliqueLemma(clique);
923
    }
924
  }
925
102163
}
926
927
12131
int SortModel::forceCombineRegion( int ri, bool useDensity ){
928
12131
  if( !useDensity ){
929
29528
    for( int i=0; i<(int)d_regions_index; i++ ){
930
29528
      if( ri!=i && d_regions[i]->valid() ){
931
2979
        return combineRegions( ri, i );
932
      }
933
    }
934
    return -1;
935
  }else{
936
    //this region must merge with another
937
9152
    if( Debug.isOn("uf-ss-check-region") ){
938
      Debug("uf-ss-check-region") << "We must combine Region #" << ri << ". " << std::endl;
939
      d_regions[ri]->debugPrint("uf-ss-check-region");
940
    }
941
    //take region with maximum disequality density
942
9152
    double maxScore = 0;
943
9152
    int maxRegion = -1;
944
18304
    std::map< int, int > regions_diseq;
945
9152
    getDisequalitiesToRegions( ri, regions_diseq );
946
56486
    for( std::map< int, int >::iterator it = regions_diseq.begin(); it != regions_diseq.end(); ++it ){
947
47334
      Debug("uf-ss-check-region") << it->first << " : " << it->second << std::endl;
948
    }
949
56486
    for( std::map< int, int >::iterator it = regions_diseq.begin(); it != regions_diseq.end(); ++it ){
950
47334
      Assert(it->first != ri);
951
47334
      Assert(isValid(it->first));
952
47334
      Assert(d_regions[it->first]->getNumReps() > 0);
953
47334
      double tempScore = double(it->second)/double(d_regions[it->first]->getNumReps() );
954
47334
      if( tempScore>maxScore ){
955
10914
        maxRegion = it->first;
956
10914
        maxScore = tempScore;
957
      }
958
    }
959
9152
    if( maxRegion!=-1 ){
960
9152
      if( Debug.isOn("uf-ss-check-region") ){
961
        Debug("uf-ss-check-region") << "Combine with region #" << maxRegion << ":" << std::endl;
962
        d_regions[maxRegion]->debugPrint("uf-ss-check-region");
963
      }
964
9152
      return combineRegions( ri, maxRegion );
965
    }
966
    return -1;
967
  }
968
}
969
970
971
40175
int SortModel::combineRegions( int ai, int bi ){
972
40175
  Debug("uf-ss-region") << "uf-ss: Combine Region #" << bi << " with Region #" << ai << std::endl;
973
40175
  Assert(isValid(ai) && isValid(bi));
974
40175
  Region* region_bi = d_regions[bi];
975
215842
  for(Region::iterator it = region_bi->begin(); it != region_bi->end(); ++it){
976
175667
    Region::RegionNodeInfo* rni = it->second;
977
175667
    if( rni->valid() ){
978
43144
      d_regions_map[ it->first ] = ai;
979
    }
980
  }
981
  //update regions disequal DO_THIS?
982
40175
  d_regions[ai]->combine( d_regions[bi] );
983
40175
  d_regions[bi]->setValid( false );
984
40175
  return ai;
985
}
986
987
435
void SortModel::moveNode( Node n, int ri ){
988
435
  Debug("uf-ss-region") << "uf-ss: Move node " << n << " to Region #" << ri << std::endl;
989
435
  Assert(isValid(d_regions_map[n]));
990
435
  Assert(isValid(ri));
991
  //move node to region ri
992
435
  d_regions[ri]->takeNode( d_regions[ d_regions_map[n] ], n );
993
435
  d_regions_map[n] = ri;
994
435
}
995
996
2016
int SortModel::addSplit(Region* r)
997
{
998
4032
  Node s;
999
2016
  if( r->hasSplits() ){
1000
    //take the first split you find
1001
9620
    for( Region::split_iterator it = r->begin_splits();
1002
9620
         it != r->end_splits(); ++it ){
1003
9620
      if( (*it).second ){
1004
2016
        s = (*it).first;
1005
2016
        break;
1006
      }
1007
    }
1008
2016
    Assert(s != Node::null());
1009
  }
1010
2016
  if (!s.isNull() ){
1011
    //add lemma to output channel
1012
2016
    Assert(s.getKind() == EQUAL);
1013
4032
    Node ss = Rewriter::rewrite( s );
1014
2016
    if( ss.getKind()!=EQUAL ){
1015
      Node b_t = NodeManager::currentNM()->mkConst( true );
1016
      Node b_f = NodeManager::currentNM()->mkConst( false );
1017
      if( ss==b_f ){
1018
        Trace("uf-ss-lemma") << "....Assert disequal directly : "
1019
                             << s[0] << " " << s[1] << std::endl;
1020
        assertDisequal( s[0], s[1], b_t );
1021
        return -1;
1022
      }else{
1023
        Trace("uf-ss-warn") << "Split on unknown literal : " << ss << std::endl;
1024
      }
1025
      if (ss == b_t)
1026
      {
1027
        CVC5Message() << "Bad split " << s << std::endl;
1028
        AlwaysAssert(false);
1029
      }
1030
    }
1031
2016
    if (Trace.isOn("uf-ss-split-si"))
1032
    {
1033
      SortInference* si = d_state.getSortInference();
1034
      if (si != nullptr)
1035
      {
1036
        for (size_t i = 0; i < 2; i++)
1037
        {
1038
          int sid = si->getSortId(ss[i]);
1039
          Trace("uf-ss-split-si") << sid << " ";
1040
        }
1041
        Trace("uf-ss-split-si") << std::endl;
1042
      }
1043
    }
1044
    //Trace("uf-ss-lemma") << d_th->getEqualityEngine()->areEqual( s[0], s[1] ) << " ";
1045
    //Trace("uf-ss-lemma") << d_th->getEqualityEngine()->areDisequal( s[0], s[1] ) << std::endl;
1046
    //Trace("uf-ss-lemma") << s[0].getType() << " " << s[1].getType() << std::endl;
1047
    //Notice() << "*** Split on " << s << std::endl;
1048
    //split on the equality s
1049
4032
    Node lem = NodeManager::currentNM()->mkNode( kind::OR, ss, ss.negate() );
1050
    // send lemma, with caching
1051
2016
    if (d_im.lemma(lem, InferenceId::UF_CARD_SPLIT))
1052
    {
1053
2016
      Trace("uf-ss-lemma") << "*** Split on " << s << std::endl;
1054
      //tell the sat solver to explore the equals branch first
1055
2016
      d_im.requirePhase(ss, true);
1056
2016
      ++( d_thss->d_statistics.d_split_lemmas );
1057
    }
1058
2016
    return 1;
1059
  }else{
1060
    return 0;
1061
  }
1062
}
1063
1064
3667
void SortModel::addCliqueLemma(std::vector<Node>& clique)
1065
{
1066
3667
  Assert(d_hasCard);
1067
3667
  Assert(d_cardinality > 0);
1068
9819
  while (clique.size() > d_cardinality + 1)
1069
  {
1070
3076
    clique.pop_back();
1071
  }
1072
  // add as lemma
1073
7334
  std::vector<Node> eqs;
1074
19988
  for (unsigned i = 0, size = clique.size(); i < size; i++)
1075
  {
1076
69523
    for (unsigned j = 0; j < i; j++)
1077
    {
1078
53202
      eqs.push_back(clique[i].eqNode(clique[j]));
1079
    }
1080
  }
1081
3667
  eqs.push_back(d_cardinality_literal[d_cardinality].notNode());
1082
7334
  Node lem = NodeManager::currentNM()->mkNode(OR, eqs);
1083
  // send lemma, with caching
1084
3667
  if (d_im.lemma(lem, InferenceId::UF_CARD_CLIQUE))
1085
  {
1086
3667
    Trace("uf-ss-lemma") << "*** Add clique lemma " << lem << std::endl;
1087
3667
    ++(d_thss->d_statistics.d_clique_lemmas);
1088
  }
1089
3667
}
1090
1091
8886
void SortModel::simpleCheckCardinality() {
1092
8886
  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
8886
}
1099
1100
9808
void SortModel::debugPrint( const char* c ){
1101
9808
  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
9808
}
1129
1130
1504
bool SortModel::checkLastCall()
1131
{
1132
1504
  NodeManager* nm = NodeManager::currentNM();
1133
1504
  SkolemManager* sm = nm->getSkolemManager();
1134
1504
  TheoryModel* m = d_state.getModel();
1135
1504
  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
1504
  RepSet* rs = m->getRepSetPtr();
1156
1504
  size_t nReps = rs->getNumRepresentatives(d_type);
1157
1504
  if (nReps != d_maxNegCard + 1)
1158
  {
1159
30
    Trace("uf-ss-warn") << "WARNING : Model does not have same # "
1160
15
                           "representatives as cardinality for "
1161
15
                        << d_type << "." << std::endl;
1162
30
    Trace("uf-ss-warn") << "   Max neg cardinality : " << d_maxNegCard
1163
15
                        << std::endl;
1164
15
    Trace("uf-ss-warn") << "   # Reps : " << nReps << std::endl;
1165
15
    if (d_maxNegCard >= nReps)
1166
    {
1167
315
      while (d_fresh_aloc_reps.size() <= d_maxNegCard)
1168
      {
1169
300
        std::stringstream ss;
1170
150
        ss << "r_" << d_type << "_";
1171
        Node nn = sm->mkDummySkolem(
1172
300
            ss.str(), d_type, "enumeration to meet negative card constraint");
1173
150
        d_fresh_aloc_reps.push_back( nn );
1174
      }
1175
15
      if (d_maxNegCard == 0)
1176
      {
1177
        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
1489
  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
11581
Node SortModel::getCardinalityLiteral(uint32_t c)
1213
{
1214
11581
  Assert(c > 0);
1215
11581
  std::map<uint32_t, Node>::iterator itcl = d_cardinality_literal.find(c);
1216
11581
  if (itcl != d_cardinality_literal.end())
1217
  {
1218
10597
    return itcl->second;
1219
  }
1220
  // get the literal from the decision strategy
1221
1968
  Node lit = d_c_dec_strat->getLiteral(c - 1);
1222
984
  d_cardinality_literal[c] = lit;
1223
1224
  // return the literal
1225
984
  return lit;
1226
}
1227
1228
288
CardinalityExtension::CardinalityExtension(Env& env,
1229
                                           TheoryState& state,
1230
                                           TheoryInferenceManager& im,
1231
288
                                           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
288
      d_initializedCombinedCardinality(userContext(), false),
1241
288
      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
864
      d_rel_eqc(context())
1245
{
1246
288
  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
840
    d_cc_dec_strat.reset(
1252
560
        new CombinedCardinalityDecisionStrategy(env, th->getValuation()));
1253
  }
1254
288
}
1255
1256
864
CardinalityExtension::~CardinalityExtension()
1257
{
1258
748
  for (std::map<TypeNode, SortModel*>::iterator it = d_rep_model.begin();
1259
748
       it != d_rep_model.end(); ++it) {
1260
460
    delete it->second;
1261
  }
1262
576
}
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
52730
void CardinalityExtension::newEqClass(Node a)
1299
{
1300
52730
  SortModel* c = getSortModel( a );
1301
52730
  if( c ){
1302
10392
    Trace("uf-ss-solver") << "CardinalityExtension: New eq class " << a << " : "
1303
5196
                          << a.getType() << std::endl;
1304
5196
    c->newEqClass( a );
1305
10392
    Trace("uf-ss-solver") << "CardinalityExtension: Done New eq class."
1306
5196
                          << std::endl;
1307
  }
1308
52730
}
1309
1310
/** merge */
1311
274039
void CardinalityExtension::merge(Node a, Node b)
1312
{
1313
  //TODO: ensure they are relevant
1314
274039
  SortModel* c = getSortModel( a );
1315
274039
  if( c ){
1316
63390
    Trace("uf-ss-solver") << "CardinalityExtension: Merge " << a << " " << b
1317
31695
                          << " : " << a.getType() << std::endl;
1318
31695
    c->merge( a, b );
1319
31695
    Trace("uf-ss-solver") << "CardinalityExtension: Done Merge." << std::endl;
1320
  }
1321
274039
}
1322
1323
/** assert terms are disequal */
1324
20818
void CardinalityExtension::assertDisequal(Node a, Node b, Node reason)
1325
{
1326
20818
  SortModel* c = getSortModel( a );
1327
20818
  if( c ){
1328
25444
    Trace("uf-ss-solver") << "CardinalityExtension: Assert disequal " << a
1329
12722
                          << " " << b << " : " << a.getType() << std::endl;
1330
12722
    c->assertDisequal( a, b, reason );
1331
25444
    Trace("uf-ss-solver") << "CardinalityExtension: Done Assert disequal."
1332
12722
                          << std::endl;
1333
  }
1334
20818
}
1335
1336
/** assert a node */
1337
211920
void CardinalityExtension::assertNode(Node n, bool isDecision)
1338
{
1339
211920
  Trace("uf-ss") << "Assert " << n << " " << isDecision << std::endl;
1340
211920
  bool polarity = n.getKind() != kind::NOT;
1341
423840
  TNode lit = polarity ? n : n[0];
1342
211920
  if (options::ufssMode() == options::UfssMode::FULL)
1343
  {
1344
190325
    if( lit.getKind()==CARDINALITY_CONSTRAINT ){
1345
18164
      TypeNode tn = lit[0].getType();
1346
9082
      Assert(tn.isSort());
1347
9082
      Assert(d_rep_model[tn]);
1348
      uint32_t nCard =
1349
9082
          lit[1].getConst<Rational>().getNumerator().getUnsignedInt();
1350
18164
      Node ct = d_rep_model[tn]->getCardinalityTerm();
1351
9082
      Trace("uf-ss-debug") << "...check cardinality terms : " << lit[0] << " " << ct << std::endl;
1352
9082
      if( lit[0]==ct ){
1353
9066
        if( options::ufssFairnessMonotone() ){
1354
54
          SortInference* si = d_state.getSortInference();
1355
54
          Trace("uf-ss-com-card-debug") << "...set master/slave" << std::endl;
1356
54
          if( tn!=d_tn_mono_master ){
1357
42
            std::map< TypeNode, bool >::iterator it = d_tn_mono_slave.find( tn );
1358
42
            if( it==d_tn_mono_slave.end() ){
1359
              bool isMonotonic;
1360
10
              if (si != nullptr)
1361
              {
1362
                isMonotonic = si->isMonotonic(tn);
1363
              }else{
1364
                //if ground, everything is monotonic
1365
10
                isMonotonic = true;
1366
              }
1367
10
              if( isMonotonic ){
1368
10
                if( d_tn_mono_master.isNull() ){
1369
4
                  Trace("uf-ss-com-card-debug") << "uf-ss-fair-monotone: Set master : " << tn << std::endl;
1370
4
                  d_tn_mono_master = tn;
1371
                }else{
1372
6
                  Trace("uf-ss-com-card-debug") << "uf-ss-fair-monotone: Set slave : " << tn << std::endl;
1373
6
                  d_tn_mono_slave[tn] = true;
1374
                }
1375
              }else{
1376
                Trace("uf-ss-com-card-debug") << "uf-ss-fair-monotone: Set non-monotonic : " << tn << std::endl;
1377
                d_tn_mono_slave[tn] = false;
1378
              }
1379
            }
1380
          }
1381
          //set the minimum positive cardinality for master if necessary
1382
54
          if( polarity && tn==d_tn_mono_master ){
1383
16
            Trace("uf-ss-com-card-debug") << "...set min positive cardinality" << std::endl;
1384
32
            if (!d_min_pos_tn_master_card_set.get()
1385
16
                || nCard < d_min_pos_tn_master_card.get())
1386
            {
1387
16
              d_min_pos_tn_master_card_set.set(true);
1388
16
              d_min_pos_tn_master_card.set( nCard );
1389
            }
1390
          }
1391
        }
1392
9066
        Trace("uf-ss-com-card-debug") << "...assert cardinality" << std::endl;
1393
9066
        d_rep_model[tn]->assertCardinality(nCard, polarity);
1394
        //check if combined cardinality is violated
1395
9066
        checkCombinedCardinality();
1396
      }else{
1397
        //otherwise, make equal via lemma
1398
16
        if( d_card_assertions_eqv_lemma.find( lit )==d_card_assertions_eqv_lemma.end() ){
1399
16
          Node eqv_lit = NodeManager::currentNM()->mkNode( CARDINALITY_CONSTRAINT, ct, lit[1] );
1400
8
          eqv_lit = lit.eqNode( eqv_lit );
1401
8
          Trace("uf-ss-lemma") << "*** Cardinality equiv lemma : " << eqv_lit << std::endl;
1402
8
          d_im.lemma(eqv_lit, InferenceId::UF_CARD_EQUIV);
1403
8
          d_card_assertions_eqv_lemma[lit] = true;
1404
        }
1405
      }
1406
181243
    }else if( lit.getKind()==COMBINED_CARDINALITY_CONSTRAINT ){
1407
4610
      if( polarity ){
1408
        //safe to assume int here
1409
        uint32_t nCard =
1410
3588
            lit[0].getConst<Rational>().getNumerator().getUnsignedInt();
1411
3588
        if (!d_min_pos_com_card_set.get() || nCard < d_min_pos_com_card.get())
1412
        {
1413
3588
          d_min_pos_com_card_set.set(true);
1414
3588
          d_min_pos_com_card.set( nCard );
1415
3588
          checkCombinedCardinality();
1416
        }
1417
      }
1418
    }else{
1419
176633
      if( Trace.isOn("uf-ss-warn") ){
1420
        ////FIXME: this is too strict: theory propagations are showing up as isDecision=true, but
1421
        ////       a theory propagation is not a decision.
1422
        if( isDecision ){
1423
          for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
1424
            if( !it->second->hasCardinalityAsserted() ){
1425
              Trace("uf-ss-warn") << "WARNING: Assert " << n << " as a decision before cardinality for " << it->first << "." << std::endl;
1426
              // CVC5Message() << "Error: constraint asserted before cardinality
1427
              // for " << it->first << std::endl; Unimplemented();
1428
            }
1429
          }
1430
        }
1431
      }
1432
    }
1433
  }
1434
  else
1435
  {
1436
21595
    if( lit.getKind()==CARDINALITY_CONSTRAINT || lit.getKind()==COMBINED_CARDINALITY_CONSTRAINT ){
1437
      // cardinality constraint from user input, set incomplete
1438
2
      Trace("uf-ss") << "Literal " << lit << " not handled when uf ss mode is not FULL, set incomplete." << std::endl;
1439
2
      d_im.setIncomplete(IncompleteId::UF_CARD_MODE);
1440
    }
1441
  }
1442
211920
  Trace("uf-ss") << "Assert: done " << n << " " << isDecision << std::endl;
1443
211920
}
1444
1445
bool CardinalityExtension::areDisequal(Node a, Node b)
1446
{
1447
  if( a==b ){
1448
    return false;
1449
  }
1450
  eq::EqualityEngine* ee = d_th->getEqualityEngine();
1451
  a = ee->getRepresentative(a);
1452
  b = ee->getRepresentative(b);
1453
  if (ee->areDisequal(a, b, false))
1454
  {
1455
    return true;
1456
  }
1457
  SortModel* c = getSortModel(a);
1458
  if (c)
1459
  {
1460
    return c->areDisequal(a, b);
1461
  }
1462
  return false;
1463
}
1464
1465
/** check */
1466
87751
void CardinalityExtension::check(Theory::Effort level)
1467
{
1468
87751
  if (level == Theory::EFFORT_LAST_CALL)
1469
  {
1470
    // if last call, call last call check for each sort
1471
2425
    for (std::pair<const TypeNode, SortModel*>& r : d_rep_model)
1472
    {
1473
1504
      if (!r.second->checkLastCall())
1474
      {
1475
15
        break;
1476
      }
1477
    }
1478
936
    return;
1479
  }
1480
86815
  if (!d_state.isInConflict())
1481
  {
1482
86815
    if (options::ufssMode() == options::UfssMode::FULL)
1483
    {
1484
146394
      Trace("uf-ss-solver")
1485
73197
          << "CardinalityExtension: check " << level << std::endl;
1486
73197
      if (level == Theory::EFFORT_FULL)
1487
      {
1488
3789
        if (Debug.isOn("uf-ss-debug"))
1489
        {
1490
          debugPrint("uf-ss-debug");
1491
        }
1492
3789
        if (Trace.isOn("uf-ss-state"))
1493
        {
1494
          Trace("uf-ss-state")
1495
              << "CardinalityExtension::check " << level << std::endl;
1496
          for (std::pair<const TypeNode, SortModel*>& rm : d_rep_model)
1497
          {
1498
            Trace("uf-ss-state") << "  " << rm.first << " has cardinality "
1499
                                 << rm.second->getCardinality() << std::endl;
1500
          }
1501
        }
1502
      }
1503
322274
      for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
1504
249077
        it->second->check(level);
1505
249077
        if (d_state.isInConflict())
1506
        {
1507
          break;
1508
        }
1509
      }
1510
    }
1511
13618
    else if (options::ufssMode() == options::UfssMode::NO_MINIMAL)
1512
    {
1513
13618
      if( level==Theory::EFFORT_FULL ){
1514
        // split on an equality between two equivalence classes (at most one per type)
1515
580
        std::map< TypeNode, std::vector< Node > > eqc_list;
1516
580
        std::map< TypeNode, bool > type_proc;
1517
290
        eq::EqClassesIterator eqcs_i(d_th->getEqualityEngine());
1518
61286
        while( !eqcs_i.isFinished() ){
1519
60996
          Node a = *eqcs_i;
1520
60996
          TypeNode tn = a.getType();
1521
30498
          if( tn.isSort() ){
1522
3354
            if( type_proc.find( tn )==type_proc.end() ){
1523
2521
              std::map< TypeNode, std::vector< Node > >::iterator itel = eqc_list.find( tn );
1524
2521
              if( itel!=eqc_list.end() ){
1525
3804
                for( unsigned j=0; j<itel->second.size(); j++ ){
1526
4890
                  Node b = itel->second[j];
1527
2567
                  if( !d_th->getEqualityEngine()->areDisequal( a, b, false ) ){
1528
488
                    Node eq = Rewriter::rewrite( a.eqNode( b ) );
1529
488
                    Node lem = NodeManager::currentNM()->mkNode( kind::OR, eq, eq.negate() );
1530
244
                    Trace("uf-ss-lemma") << "*** Split (no-minimal) : " << lem << std::endl;
1531
244
                    d_im.lemma(lem, InferenceId::UF_CARD_SPLIT);
1532
244
                    d_im.requirePhase(eq, true);
1533
244
                    type_proc[tn] = true;
1534
244
                    break;
1535
                  }
1536
                }
1537
              }
1538
2521
              eqc_list[tn].push_back( a );
1539
            }
1540
          }
1541
30498
          ++eqcs_i;
1542
        }
1543
      }
1544
    }
1545
    else
1546
    {
1547
      // unhandled uf ss mode
1548
      Assert(false);
1549
    }
1550
173630
    Trace("uf-ss-solver") << "Done CardinalityExtension: check " << level
1551
86815
                          << std::endl;
1552
  }
1553
}
1554
1555
338
void CardinalityExtension::presolve()
1556
{
1557
338
  d_initializedCombinedCardinality = false;
1558
652
  for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
1559
314
    it->second->presolve();
1560
314
    it->second->initialize();
1561
  }
1562
338
}
1563
1564
280
CardinalityExtension::CombinedCardinalityDecisionStrategy::
1565
280
    CombinedCardinalityDecisionStrategy(Env& env, Valuation valuation)
1566
280
    : DecisionStrategyFmf(env, valuation)
1567
{
1568
280
}
1569
801
Node CardinalityExtension::CombinedCardinalityDecisionStrategy::mkLiteral(
1570
    unsigned i)
1571
{
1572
801
  NodeManager* nm = NodeManager::currentNM();
1573
801
  return nm->mkNode(COMBINED_CARDINALITY_CONSTRAINT, nm->mkConst(Rational(i)));
1574
}
1575
1576
std::string
1577
239719
CardinalityExtension::CombinedCardinalityDecisionStrategy::identify() const
1578
{
1579
239719
  return std::string("uf_combined_card");
1580
}
1581
1582
342662
void CardinalityExtension::preRegisterTerm(TNode n)
1583
{
1584
342662
  if (options::ufssMode() == options::UfssMode::FULL)
1585
  {
1586
    //initialize combined cardinality
1587
289523
    initializeCombinedCardinality();
1588
1589
289523
    Trace("uf-ss-register") << "Preregister " << n << "." << std::endl;
1590
    //shouldn't have to preregister this type (it may be that there are no quantifiers over tn)
1591
579046
    TypeNode tn = n.getType();
1592
289523
    std::map< TypeNode, SortModel* >::iterator it = d_rep_model.find( tn );
1593
289523
    if( it==d_rep_model.end() ){
1594
284889
      SortModel* rm = NULL;
1595
284889
      if( tn.isSort() ){
1596
460
        Trace("uf-ss-register") << "Create sort model " << tn << "." << std::endl;
1597
460
        rm = new SortModel(n, d_state, d_im, this);
1598
      }
1599
284889
      if( rm ){
1600
460
        rm->initialize();
1601
460
        d_rep_model[tn] = rm;
1602
        //d_rep_model_init[tn] = true;
1603
      }
1604
    }else{
1605
      //ensure sort model is initialized
1606
4634
      it->second->initialize();
1607
    }
1608
  }
1609
342662
}
1610
1611
347587
SortModel* CardinalityExtension::getSortModel(Node n)
1612
{
1613
695174
  TypeNode tn = n.getType();
1614
347587
  std::map< TypeNode, SortModel* >::iterator it = d_rep_model.find( tn );
1615
  //pre-register the type if not done already
1616
347587
  if( it==d_rep_model.end() ){
1617
297974
    preRegisterTerm( n );
1618
297974
    it = d_rep_model.find( tn );
1619
  }
1620
347587
  if( it!=d_rep_model.end() ){
1621
49613
    return it->second;
1622
  }else{
1623
297974
    return NULL;
1624
  }
1625
}
1626
1627
/** get cardinality for sort */
1628
int CardinalityExtension::getCardinality(Node n)
1629
{
1630
  SortModel* c = getSortModel( n );
1631
  if( c ){
1632
    return c->getCardinality();
1633
  }else{
1634
    return -1;
1635
  }
1636
}
1637
1638
int CardinalityExtension::getCardinality(TypeNode tn)
1639
{
1640
  std::map< TypeNode, SortModel* >::iterator it = d_rep_model.find( tn );
1641
  if( it!=d_rep_model.end() && it->second ){
1642
    return it->second->getCardinality();
1643
  }
1644
  return -1;
1645
}
1646
1647
//print debug
1648
void CardinalityExtension::debugPrint(const char* c)
1649
{
1650
  for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
1651
    Debug( c ) << "Conflict find structure for " << it->first << ": " << std::endl;
1652
    it->second->debugPrint( c );
1653
    Debug( c ) << std::endl;
1654
  }
1655
}
1656
1657
/** initialize */
1658
289523
void CardinalityExtension::initializeCombinedCardinality()
1659
{
1660
579046
  if (d_cc_dec_strat.get() != nullptr
1661
289523
      && !d_initializedCombinedCardinality.get())
1662
  {
1663
481
    d_initializedCombinedCardinality = true;
1664
962
    d_im.getDecisionManager()->registerStrategy(
1665
481
        DecisionManager::STRAT_UF_COMBINED_CARD, d_cc_dec_strat.get());
1666
  }
1667
289523
}
1668
1669
/** check */
1670
12654
void CardinalityExtension::checkCombinedCardinality()
1671
{
1672
12654
  Assert(options::ufssMode() == options::UfssMode::FULL);
1673
12654
  if( options::ufssFairness() ){
1674
12654
    Trace("uf-ss-com-card-debug") << "Check combined cardinality, get maximum negative cardinalities..." << std::endl;
1675
12654
    uint32_t totalCombinedCard = 0;
1676
12654
    uint32_t maxMonoSlave = 0;
1677
25308
    TypeNode maxSlaveType;
1678
74595
    for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
1679
61941
      uint32_t max_neg = it->second->getMaximumNegativeCardinality();
1680
61941
      if( !options::ufssFairnessMonotone() ){
1681
61771
        totalCombinedCard += max_neg;
1682
      }else{
1683
170
        std::map< TypeNode, bool >::iterator its = d_tn_mono_slave.find( it->first );
1684
170
        if( its==d_tn_mono_slave.end() || !its->second ){
1685
74
          totalCombinedCard += max_neg;
1686
        }else{
1687
96
          if( max_neg>maxMonoSlave ){
1688
8
            maxMonoSlave = max_neg;
1689
8
            maxSlaveType = it->first;
1690
          }
1691
        }
1692
      }
1693
    }
1694
12654
    Trace("uf-ss-com-card-debug") << "Check combined cardinality, total combined card : " << totalCombinedCard << std::endl;
1695
12654
    if( options::ufssFairnessMonotone() ){
1696
70
      Trace("uf-ss-com-card-debug") << "Max slave monotonic negated cardinality : " << maxMonoSlave << std::endl;
1697
140
      if (!d_min_pos_tn_master_card_set.get()
1698
70
          && maxMonoSlave > d_min_pos_tn_master_card.get())
1699
      {
1700
        uint32_t mc = d_min_pos_tn_master_card.get();
1701
        std::vector< Node > conf;
1702
        conf.push_back( d_rep_model[d_tn_mono_master]->getCardinalityLiteral( mc ) );
1703
        conf.push_back( d_rep_model[maxSlaveType]->getCardinalityLiteral( maxMonoSlave ).negate() );
1704
        Node cf = NodeManager::currentNM()->mkNode( AND, conf );
1705
        Trace("uf-ss-lemma") << "*** Combined monotone cardinality conflict"
1706
                             << " : " << cf << std::endl;
1707
        Trace("uf-ss-com-card") << "*** Combined monotone cardinality conflict"
1708
                                << " : " << cf << std::endl;
1709
        d_im.conflict(cf, InferenceId::UF_CARD_MONOTONE_COMBINED);
1710
        return;
1711
      }
1712
    }
1713
12654
    uint32_t cc = d_min_pos_com_card.get();
1714
12654
    if (d_min_pos_com_card_set.get() && totalCombinedCard > cc)
1715
    {
1716
      //conflict
1717
1968
      Node com_lit = d_cc_dec_strat->getLiteral(cc);
1718
1968
      std::vector< Node > conf;
1719
984
      conf.push_back( com_lit );
1720
984
      uint32_t totalAdded = 0;
1721
2890
      for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin();
1722
2890
           it != d_rep_model.end(); ++it ){
1723
2890
        bool doAdd = true;
1724
2890
        if( options::ufssFairnessMonotone() ){
1725
          std::map< TypeNode, bool >::iterator its =
1726
            d_tn_mono_slave.find( it->first );
1727
          if( its!=d_tn_mono_slave.end() && its->second ){
1728
            doAdd = false;
1729
          }
1730
        }
1731
2890
        if( doAdd ){
1732
2890
          uint32_t c = it->second->getMaximumNegativeCardinality();
1733
2890
          if( c>0 ){
1734
2252
            conf.push_back( it->second->getCardinalityLiteral( c ).negate() );
1735
2252
            totalAdded += c;
1736
          }
1737
2890
          if( totalAdded>cc ){
1738
984
            break;
1739
          }
1740
        }
1741
      }
1742
1968
      Node cf = NodeManager::currentNM()->mkNode( AND, conf );
1743
1968
      Trace("uf-ss-lemma") << "*** Combined cardinality conflict : " << cf
1744
984
                           << std::endl;
1745
1968
      Trace("uf-ss-com-card") << "*** Combined cardinality conflict : " << cf
1746
984
                              << std::endl;
1747
984
      d_im.conflict(cf, InferenceId::UF_CARD_COMBINED);
1748
    }
1749
  }
1750
}
1751
1752
288
CardinalityExtension::Statistics::Statistics()
1753
288
    : d_clique_conflicts(smtStatisticsRegistry().registerInt(
1754
576
        "CardinalityExtension::Clique_Conflicts")),
1755
288
      d_clique_lemmas(smtStatisticsRegistry().registerInt(
1756
576
          "CardinalityExtension::Clique_Lemmas")),
1757
288
      d_split_lemmas(smtStatisticsRegistry().registerInt(
1758
576
          "CardinalityExtension::Split_Lemmas")),
1759
288
      d_max_model_size(smtStatisticsRegistry().registerInt(
1760
1152
          "CardinalityExtension::Max_Model_Size"))
1761
{
1762
288
  d_max_model_size.maxAssign(1);
1763
288
}
1764
1765
}  // namespace uf
1766
}  // namespace theory
1767
29577
}  // namespace cvc5