GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/uf/cardinality_extension.cpp Lines: 815 1013 80.5 %
Date: 2021-08-16 Branches: 1673 4096 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
2552
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
2552
  , d_valid( c, true ) {}
57
58
7656
Region::~Region() {
59
12266
  for(iterator i = begin(), iend = end(); i != iend; ++i) {
60
9714
    RegionNodeInfo* regionNodeInfo = (*i).second;
61
9714
    delete regionNodeInfo;
62
  }
63
2552
  d_nodes.clear();
64
5104
}
65
66
5212
void Region::addRep( Node n ) {
67
5212
  setRep( n, true );
68
5212
}
69
70
433
void Region::takeNode( Region* r, Node n ){
71
433
  Assert(!hasRep(n));
72
433
  Assert(r->hasRep(n));
73
  //add representative
74
433
  setRep( n, true );
75
  //take disequalities from r
76
433
  RegionNodeInfo* rni = r->d_nodes[n];
77
1299
  for( int t=0; t<2; t++ ){
78
866
    DiseqList* del = rni->get(t);
79
2458
    for(DiseqList::iterator it = del->begin(); it != del->end(); ++it ){
80
1592
      if( (*it).second ){
81
1021
        r->setDisequal( n, (*it).first, t, false );
82
1021
        if( t==0 ){
83
530
          if( hasRep( (*it).first ) ){
84
452
            setDisequal( (*it).first, n, 0, false );
85
452
            setDisequal( (*it).first, n, 1, true );
86
452
            setDisequal( n, (*it).first, 1, true );
87
          }else{
88
78
            setDisequal( n, (*it).first, 0, true );
89
          }
90
        }else{
91
491
          r->setDisequal( (*it).first, n, 1, false );
92
491
          r->setDisequal( (*it).first, n, 0, true );
93
491
          setDisequal( n, (*it).first, 0, true );
94
        }
95
      }
96
    }
97
  }
98
  //remove representative
99
433
  r->setRep( n, false );
100
433
}
101
102
40803
void Region::combine( Region* r ){
103
  //take all nodes from r
104
220398
  for(Region::iterator it = r->d_nodes.begin(); it != r->d_nodes.end(); ++it) {
105
179595
    if( it->second->valid() ){
106
43776
      setRep( it->first, true );
107
    }
108
  }
109
220398
  for(Region::iterator it = r->d_nodes.begin(); it != r->d_nodes.end(); ++it){
110
179595
    if( it->second->valid() ){
111
      //take disequalities from r
112
87552
      Node n = it->first;
113
43776
      RegionNodeInfo* rni = it->second;
114
131328
      for( int t=0; t<2; t++ ){
115
87552
        RegionNodeInfo::DiseqList* del = rni->get(t);
116
222798
        for( RegionNodeInfo::DiseqList::iterator it2 = del->begin(),
117
87552
               it2end = del->end(); it2 != it2end; ++it2 ){
118
135246
          if( (*it2).second ){
119
124238
            if( t==0 && hasRep( (*it2).first ) ){
120
53045
              setDisequal( (*it2).first, n, 0, false );
121
53045
              setDisequal( (*it2).first, n, 1, true );
122
53045
              setDisequal( n, (*it2).first, 1, true );
123
            }else{
124
71193
              setDisequal( n, (*it2).first, t, true );
125
            }
126
          }
127
        }
128
      }
129
    }
130
  }
131
40803
  r->d_valid = false;
132
40803
}
133
134
/** setEqual */
135
32328
void Region::setEqual( Node a, Node b ){
136
32328
  Assert(hasRep(a) && hasRep(b));
137
  //move disequalities of b over to a
138
96984
  for( int t=0; t<2; t++ ){
139
64656
    DiseqList* del = d_nodes[b]->get(t);
140
118347
    for( DiseqList::iterator it = del->begin(); it != del->end(); ++it ){
141
53691
      if( (*it).second ){
142
78974
        Node n = (*it).first;
143
        //get the region that contains the endpoint of the disequality b != ...
144
39487
        Region* nr = d_cf->d_regions[ d_cf->d_regions_map[ n ] ];
145
39487
        if( !isDisequal( a, n, t ) ){
146
18051
          setDisequal( a, n, t, true );
147
18051
          nr->setDisequal( n, a, t, true );
148
        }
149
39487
        setDisequal( b, n, t, false );
150
39487
        nr->setDisequal( n, b, t, false );
151
      }
152
    }
153
  }
154
  //remove b from representatives
155
32328
  setRep( b, false );
156
32328
}
157
158
374996
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
374996
  if( isDisequal( n1, n2, type )!=valid ){    //DO_THIS: make assertion
164
374216
    d_nodes[ n1 ]->get(type)->setDisequal( n2, valid );
165
374216
    if( type==0 ){
166
163388
      d_total_diseq_external = d_total_diseq_external + ( valid ? 1 : -1 );
167
    }else{
168
210828
      d_total_diseq_internal = d_total_diseq_internal + ( valid ? 1 : -1 );
169
210828
      if( valid ){
170
        //if they are both a part of testClique, then remove split
171
298708
        if( d_testClique.find( n1 )!=d_testClique.end() && d_testClique[n1] &&
172
150921
            d_testClique.find( n2 )!=d_testClique.end() && d_testClique[n2] ){
173
3134
          Node eq = NodeManager::currentNM()->mkNode( EQUAL, n1, n2 );
174
1567
          if( d_splits.find( eq )!=d_splits.end() && d_splits[ eq ] ){
175
1544
            Debug("uf-ss-debug") << "removing split for " << n1 << " " << n2
176
772
                                 << std::endl;
177
772
            d_splits[ eq ] = false;
178
772
            d_splitsSize = d_splitsSize - 1;
179
          }
180
        }
181
      }
182
    }
183
  }
184
374996
}
185
186
82182
void Region::setRep( Node n, bool valid ) {
187
82182
  Assert(hasRep(n) != valid);
188
82182
  if( valid && d_nodes.find( n )==d_nodes.end() ){
189
9714
    d_nodes[n] = new RegionNodeInfo(d_cf->d_state.getSatContext());
190
  }
191
82182
  d_nodes[n]->setValid(valid);
192
82182
  d_reps_size = d_reps_size + ( valid ? 1 : -1 );
193
  //removing a member of the test clique from this region
194
82182
  if( d_testClique.find( n ) != d_testClique.end() && d_testClique[n] ){
195
1592
    Assert(!valid);
196
1592
    d_testClique[n] = false;
197
1592
    d_testCliqueSize = d_testCliqueSize - 1;
198
    //remove all splits involving n
199
13834
    for( split_iterator it = begin_splits(); it != end_splits(); ++it ){
200
12242
      if( (*it).second ){
201
3975
        if( (*it).first[0]==n || (*it).first[1]==n ){
202
3935
          d_splits[ (*it).first ] = false;
203
3935
          d_splitsSize = d_splitsSize - 1;
204
        }
205
      }
206
    }
207
  }
208
82182
}
209
210
458930
bool Region::isDisequal( Node n1, Node n2, int type ) {
211
458930
  RegionNodeInfo::DiseqList* del = d_nodes[ n1 ]->get(type);
212
458930
  return del->isSet(n2) && del->getDisequalityValue(n2);
213
}
214
215
struct sortInternalDegree {
216
  Region* r;
217
15242
  bool operator() (Node i, Node j) {
218
30484
    return (r->getRegionInfo(i)->getNumInternalDisequalities() >
219
30484
            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
96045
bool Region::getMustCombine( int cardinality ){
234
96045
  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
20940
    std::vector< int > degrees;
242
140561
    for( Region::iterator it = begin(); it != end(); ++it ){
243
133565
      RegionNodeInfo* rni = it->second;
244
133565
      if( rni->valid() ){
245
60675
        if( rni->getNumDisequalities() >= cardinality ){
246
46921
          int outDeg = rni->getNumExternalDisequalities();
247
46921
          if( outDeg>=cardinality ){
248
            //we have 1 node of degree greater than (cardinality)
249
15473
            return true;
250
39543
          }else if( outDeg>=1 ){
251
38541
            degrees.push_back( outDeg );
252
38541
            if( (int)degrees.size()>=cardinality ){
253
              //we have (cardinality) nodes of degree 1
254
717
              return true;
255
            }
256
          }
257
        }
258
      }
259
    }
260
6996
    gmcCount++;
261
6996
    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
6996
    std::sort( degrees.begin(), degrees.end() );
267
38325
    for( int i=0; i<(int)degrees.size(); i++ ){
268
32476
      if( degrees[i]>=cardinality+1-((int)degrees.size()-i) ){
269
1147
        return true;
270
      }
271
    }
272
  }
273
86803
  return false;
274
}
275
276
1709588
bool Region::check( Theory::Effort level, int cardinality,
277
                    std::vector< Node >& clique ) {
278
1709588
  if( d_reps_size>unsigned(cardinality) ){
279
75688
    if( d_total_diseq_internal==d_reps_size*( d_reps_size - 1 ) ){
280
54820
      if( d_reps_size>1 ){
281
        //quick clique check, all reps form a clique
282
30375
        for( iterator it = begin(); it != end(); ++it ){
283
26694
          if( it->second->valid() ){
284
19419
            clique.push_back( it->first );
285
          }
286
        }
287
3681
        Trace("quick-clique") << "Found quick clique" << std::endl;
288
3681
        return true;
289
      }else{
290
51139
        return false;
291
      }
292
    }
293
20868
    else if (level==Theory::EFFORT_FULL)
294
    {
295
      //build test clique, up to size cardinality+1
296
2065
      if( d_testCliqueSize<=unsigned(cardinality) ){
297
3990
        std::vector< Node > newClique;
298
1995
        if( d_testCliqueSize<unsigned(cardinality) ){
299
14986
          for( iterator it = begin(); it != end(); ++it ){
300
            //if not in the test clique, add it to the set of new members
301
43291
            if( it->second->valid() &&
302
21650
                ( 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
8359
              newClique.push_back( it->first );
307
              //}
308
            }
309
          }
310
          //choose remaining nodes with the highest degrees
311
          sortInternalDegree sidObj;
312
1701
          sidObj.r = this;
313
1701
          std::sort( newClique.begin(), newClique.end(), sidObj );
314
1701
          int offset = ( cardinality - d_testCliqueSize ) + 1;
315
1701
          newClique.erase( newClique.begin() + offset, newClique.end() );
316
        }else{
317
          //scan for the highest degree
318
294
          int maxDeg = -1;
319
588
          Node maxNode;
320
3138
          for( std::map< Node, RegionNodeInfo* >::iterator
321
294
                 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
8404
            if( it->second->valid() &&
324
6464
                ( d_testClique.find( it->first )==d_testClique.end() ||
325
1508
                  !d_testClique[ it->first ] ) ){
326
310
              if( it->second->getNumInternalDisequalities()>maxDeg ){
327
296
                maxDeg = it->second->getNumInternalDisequalities();
328
296
                maxNode = it->first;
329
              }
330
            }
331
          }
332
294
          Assert(maxNode != Node::null());
333
294
          newClique.push_back( maxNode );
334
        }
335
        //check splits internal to new members
336
10561
        for( int j=0; j<(int)newClique.size(); j++ ){
337
17132
          Debug("uf-ss-debug") << "Choose to add clique member "
338
8566
                               << newClique[j] << std::endl;
339
38667
          for( int k=(j+1); k<(int)newClique.size(); k++ ){
340
30101
            if( !isDisequal( newClique[j], newClique[k], 1 ) ){
341
7828
              Node at_j = newClique[j];
342
7828
              Node at_k = newClique[k];
343
              Node j_eq_k =
344
7828
                NodeManager::currentNM()->mkNode( EQUAL, at_j, at_k );
345
3914
              d_splits[ j_eq_k ] = true;
346
3914
              d_splitsSize = d_splitsSize + 1;
347
            }
348
          }
349
          //check disequalities with old members
350
10975
          for( NodeBoolMap::iterator it = d_testClique.begin();
351
10975
               it != d_testClique.end(); ++it ){
352
2409
            if( (*it).second ){
353
1514
              if( !isDisequal( (*it).first, newClique[j], 1 ) ){
354
1978
                Node at_it = (*it).first;
355
1978
                Node at_j = newClique[j];
356
1978
                Node it_eq_j = at_it.eqNode(at_j);
357
989
                d_splits[ it_eq_j ] = true;
358
989
                d_splitsSize = d_splitsSize + 1;
359
              }
360
            }
361
          }
362
        }
363
        //add new clique members to test clique
364
10561
        for( int j=0; j<(int)newClique.size(); j++ ){
365
8566
          d_testClique[ newClique[j] ] = true;
366
8566
          d_testCliqueSize = d_testCliqueSize + 1;
367
        }
368
      }
369
      // Check if test clique has larger size than cardinality, and
370
      // forms a clique.
371
2065
      if( d_testCliqueSize >= unsigned(cardinality+1) && d_splitsSize==0 ){
372
        //test clique is a clique
373
144
        for( NodeBoolMap::iterator it = d_testClique.begin();
374
144
             it != d_testClique.end(); ++it ){
375
106
          if( (*it).second ){
376
104
            clique.push_back( (*it).first );
377
          }
378
        }
379
38
        return true;
380
      }
381
    }
382
  }
383
1654730
  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
2660
void Region::debugPrint( const char* c, bool incClique ) {
402
2660
  Debug( c ) << "Num reps: " << d_reps_size << std::endl;
403
7798
  for( Region::iterator it = begin(); it != end(); ++it ){
404
5138
    RegionNodeInfo* rni = it->second;
405
5138
    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
2660
  Debug( c ) << "Total disequal: " << d_total_diseq_external << " external,";
421
2660
  Debug( c ) << " " << d_total_diseq_internal << " internal." << std::endl;
422
423
2660
  if( incClique ){
424
2660
    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
2660
    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
2660
}
448
449
460
SortModel::CardinalityDecisionStrategy::CardinalityDecisionStrategy(
450
460
    Node t, context::Context* satContext, Valuation valuation)
451
460
    : DecisionStrategyFmf(satContext, 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
492974
std::string SortModel::CardinalityDecisionStrategy::identify() const
461
{
462
492974
  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
460
      d_regions_index(d_state.getSatContext(), 0),
474
460
      d_regions_map(d_state.getSatContext()),
475
460
      d_split_score(d_state.getSatContext()),
476
460
      d_disequalities_index(d_state.getSatContext(), 0),
477
460
      d_reps(d_state.getSatContext(), 0),
478
460
      d_cardinality(d_state.getSatContext(), 1),
479
460
      d_hasCard(d_state.getSatContext(), false),
480
460
      d_maxNegCard(d_state.getSatContext(), 0),
481
460
      d_initialized(d_state.getUserContext(), false),
482
4600
      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
        n, d_state.getSatContext(), thss->getTheory()->getValuation()));
493
  }
494
460
}
495
496
1380
SortModel::~SortModel() {
497
3012
  for(std::vector<Region*>::iterator i = d_regions.begin();
498
3012
      i != d_regions.end(); ++i) {
499
2552
    Region* region = *i;
500
2552
    delete region;
501
  }
502
460
  d_regions.clear();
503
920
}
504
505
/** initialize */
506
5424
void SortModel::initialize()
507
{
508
5424
  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
5424
}
517
518
/** new node */
519
5212
void SortModel::newEqClass( Node n ){
520
5212
  if (!d_state.isInConflict())
521
  {
522
5212
    if( d_regions_map.find( n )==d_regions_map.end() ){
523
5212
      d_regions_map[n] = d_regions_index;
524
5212
      Debug("uf-ss") << "CardinalityExtension: New Eq Class " << n << std::endl;
525
10424
      Debug("uf-ss-debug") << d_regions_index << " " << (int)d_regions.size()
526
5212
                           << std::endl;
527
5212
      if (d_regions_index < d_regions.size())
528
      {
529
2660
        d_regions[d_regions_index]->debugPrint("uf-ss-debug", true);
530
2660
        d_regions[d_regions_index]->setValid(true);
531
2660
        Assert(d_regions[d_regions_index]->getNumReps() == 0);
532
      }else{
533
2552
        d_regions.push_back(new Region(this, d_state.getSatContext()));
534
      }
535
5212
      d_regions[d_regions_index]->addRep(n);
536
5212
      d_regions_index = d_regions_index + 1;
537
538
5212
      d_reps = d_reps + 1;
539
    }
540
  }
541
5212
}
542
543
/** merge */
544
32328
void SortModel::merge( Node a, Node b ){
545
32328
  if (d_state.isInConflict())
546
  {
547
    return;
548
  }
549
64656
  Debug("uf-ss") << "CardinalityExtension: Merging " << a << " = " << b << "..."
550
32328
                 << std::endl;
551
32328
  if (a != b)
552
  {
553
32328
    Assert(d_regions_map.find(a) != d_regions_map.end());
554
32328
    Assert(d_regions_map.find(b) != d_regions_map.end());
555
32328
    int ai = d_regions_map[a];
556
32328
    int bi = d_regions_map[b];
557
32328
    Debug("uf-ss") << "   regions: " << ai << " " << bi << std::endl;
558
32328
    if (ai != bi)
559
    {
560
28954
      if (d_regions[ai]->getNumReps() == 1)
561
      {
562
20046
        int ri = combineRegions(bi, ai);
563
20046
        d_regions[ri]->setEqual(a, b);
564
20046
        checkRegion(ri);
565
      }
566
8908
      else if (d_regions[bi]->getNumReps() == 1)
567
      {
568
8475
        int ri = combineRegions(ai, bi);
569
8475
        d_regions[ri]->setEqual(a, b);
570
8475
        checkRegion(ri);
571
      }
572
      else
573
      {
574
        // Either move a to d_regions[bi], or b to d_regions[ai].
575
433
        RegionNodeInfo* a_region_info = d_regions[ai]->getRegionInfo(a);
576
433
        RegionNodeInfo* b_region_info = d_regions[bi]->getRegionInfo(b);
577
433
        int aex = (a_region_info->getNumInternalDisequalities()
578
433
                   - getNumDisequalitiesToRegion(a, bi));
579
433
        int bex = (b_region_info->getNumInternalDisequalities()
580
433
                   - getNumDisequalitiesToRegion(b, ai));
581
        // Based on which would produce the fewest number of
582
        // external disequalities.
583
433
        if (aex < bex)
584
        {
585
137
          moveNode(a, bi);
586
137
          d_regions[bi]->setEqual(a, b);
587
        }else{
588
296
          moveNode(b, ai);
589
296
          d_regions[ai]->setEqual( a, b );
590
        }
591
433
        checkRegion(ai);
592
433
        checkRegion(bi);
593
      }
594
    }
595
    else
596
    {
597
3374
      d_regions[ai]->setEqual(a, b);
598
3374
      checkRegion(ai);
599
    }
600
32328
    d_regions_map[b] = -1;
601
  }
602
32328
  d_reps = d_reps - 1;
603
}
604
605
/** assert terms are disequal */
606
12832
void SortModel::assertDisequal( Node a, Node b, Node reason ){
607
12832
  if (d_state.isInConflict())
608
  {
609
    return;
610
  }
611
  // if they are not already disequal
612
12832
  eq::EqualityEngine* ee = d_thss->getTheory()->getEqualityEngine();
613
12832
  a = ee->getRepresentative(a);
614
12832
  b = ee->getRepresentative(b);
615
12832
  int ai = d_regions_map[a];
616
12832
  int bi = d_regions_map[b];
617
12832
  if (d_regions[ai]->isDisequal(a, b, ai == bi))
618
  {
619
    // already disequal
620
    return;
621
  }
622
25664
  Debug("uf-ss") << "Assert disequal " << a << " != " << b << "..."
623
12832
                 << std::endl;
624
25664
  Debug("uf-ss-disequal") << "Assert disequal " << a << " != " << b << "..."
625
12832
                          << std::endl;
626
  // add to list of disequalities
627
12832
  if (d_disequalities_index < d_disequalities.size())
628
  {
629
9715
    d_disequalities[d_disequalities_index] = reason;
630
  }
631
  else
632
  {
633
3117
    d_disequalities.push_back(reason);
634
  }
635
12832
  d_disequalities_index = d_disequalities_index + 1;
636
  // now, add disequalities to regions
637
12832
  Assert(d_regions_map.find(a) != d_regions_map.end());
638
12832
  Assert(d_regions_map.find(b) != d_regions_map.end());
639
12832
  Debug("uf-ss") << "   regions: " << ai << " " << bi << std::endl;
640
12832
  if (ai == bi)
641
  {
642
    // internal disequality
643
538
    d_regions[ai]->setDisequal(a, b, 1, true);
644
538
    d_regions[ai]->setDisequal(b, a, 1, true);
645
    // do not need to check if it needs to combine (no new ext. disequalities)
646
538
    checkRegion(ai, false);
647
  }
648
  else
649
  {
650
    // external disequality
651
12294
    d_regions[ai]->setDisequal(a, b, 0, true);
652
12294
    d_regions[bi]->setDisequal(b, a, 0, true);
653
12294
    checkRegion(ai);
654
12294
    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
256259
void SortModel::check(Theory::Effort level)
672
{
673
256259
  Assert(options::ufssMode() == options::UfssMode::FULL);
674
256259
  if (!d_hasCard && d_state.isInConflict())
675
  {
676
    // not necessary to check
677
    return;
678
  }
679
512518
  Debug("uf-ss") << "CardinalityExtension: Check " << level << " " << d_type
680
256259
                 << std::endl;
681
256259
  if (level == Theory::EFFORT_FULL)
682
  {
683
9835
    Debug("fmf-full-check") << std::endl;
684
19670
    Debug("fmf-full-check")
685
9835
        << "Full check for SortModel " << d_type << ", status : " << std::endl;
686
9835
    debugPrint("fmf-full-check");
687
9835
    Debug("fmf-full-check") << std::endl;
688
  }
689
256259
  if (d_reps <= (unsigned)d_cardinality)
690
  {
691
189958
    Debug("uf-ss-debug") << "We have " << d_reps << " representatives for type "
692
94979
                         << d_type << ", <= " << d_cardinality << std::endl;
693
94979
    if( level==Theory::EFFORT_FULL ){
694
9460
      Debug("uf-ss-sat") << "We have " << d_reps << " representatives for type "
695
4730
                         << d_type << ", <= " << d_cardinality << std::endl;
696
    }
697
94979
    return;
698
  }
699
  // first check if we can generate a clique conflict
700
  // do a check within each region
701
2672827
  for (size_t i = 0; i < d_regions_index; i++)
702
  {
703
2512944
    if (d_regions[i]->valid())
704
    {
705
3224613
      std::vector<Node> clique;
706
1613005
      if (d_regions[i]->check(level, d_cardinality, clique))
707
      {
708
        // add clique lemma
709
1397
        addCliqueLemma(clique);
710
1397
        return;
711
      }
712
      else
713
      {
714
1611608
        Trace("uf-ss-debug") << "No clique in Region #" << i << std::endl;
715
      }
716
    }
717
  }
718
  // do splitting on demand
719
159883
  bool addedLemma = false;
720
159883
  if (level == Theory::EFFORT_FULL)
721
  {
722
5067
    Trace("uf-ss-debug") << "Add splits?" << std::endl;
723
    // see if we have any recommended splits from large regions
724
82474
    for (size_t i = 0; i < d_regions_index; i++)
725
    {
726
77407
      if (d_regions[i]->valid() && d_regions[i]->getNumReps() > d_cardinality)
727
      {
728
2027
        int sp = addSplit(d_regions[i]);
729
2027
        if (sp == 1)
730
        {
731
2027
          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
159883
  if (level != Theory::EFFORT_FULL || addedLemma)
743
  {
744
156843
    return;
745
  }
746
  // check at full effort
747
3040
  Trace("uf-ss-debug") << "No splits added. " << d_cardinality << std::endl;
748
3040
  Trace("uf-ss-si") << "Must combine region" << std::endl;
749
3040
  bool recheck = false;
750
3040
  SortInference* si = d_state.getSortInference();
751
3040
  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
3040
  if (!recheck)
777
  {
778
    // naive strategy, force region combination involving the first
779
    // valid region
780
12090
    for (size_t i = 0; i < d_regions_index; i++)
781
    {
782
12090
      if (d_regions[i]->valid())
783
      {
784
2986
        int fcr = forceCombineRegion(i, false);
785
5972
        Debug("fmf-full-check")
786
2986
            << "Combined regions " << i << " " << fcr << std::endl;
787
5972
        Trace("uf-ss-debug")
788
2986
            << "Combined regions " << i << " " << fcr << std::endl;
789
2986
        recheck = true;
790
2986
        break;
791
      }
792
    }
793
  }
794
3040
  if (recheck)
795
  {
796
3040
    Trace("uf-ss-debug") << "Must recheck." << std::endl;
797
3040
    check(level);
798
  }
799
}
800
801
314
void SortModel::presolve() {
802
314
  d_initialized = false;
803
314
}
804
805
866
int SortModel::getNumDisequalitiesToRegion( Node n, int ri ){
806
866
  int ni = d_regions_map[n];
807
866
  int counter = 0;
808
866
  DiseqList* del = d_regions[ni]->getRegionInfo(n)->get(0);
809
2396
  for( DiseqList::iterator it = del->begin(); it != del->end(); ++it ){
810
1530
    if( (*it).second ){
811
693
      if( d_regions_map[ (*it).first ]==ri ){
812
570
        counter++;
813
      }
814
    }
815
  }
816
866
  return counter;
817
}
818
819
9242
void SortModel::getDisequalitiesToRegions(int ri,
820
                                          std::map< int, int >& regions_diseq)
821
{
822
9242
  Region* region = d_regions[ri];
823
105842
  for(Region::iterator it = region->begin(); it != region->end(); ++it ){
824
96600
    if( it->second->valid() ){
825
25277
      DiseqList* del = it->second->get(0);
826
201502
      for( DiseqList::iterator it2 = del->begin(); it2 != del->end(); ++it2 ){
827
176225
        if( (*it2).second ){
828
121032
          Assert(isValid(d_regions_map[(*it2).first]));
829
          //Notice() << "Found disequality with " << (*it2).first << ", region = " << d_regions_map[ (*it2).first ] << std::endl;
830
121032
          regions_diseq[ d_regions_map[ (*it2).first ] ]++;
831
        }
832
      }
833
    }
834
  }
835
9242
}
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
9024
void SortModel::assertCardinality(uint32_t c, bool val)
850
{
851
9024
  if (!d_state.isInConflict())
852
  {
853
18048
    Trace("uf-ss-assert")
854
9024
        << "Assert cardinality " << d_type << " " << c << " " << val
855
9024
        << " level = "
856
9024
        << d_thss->getTheory()->getValuation().getAssertionLevel() << std::endl;
857
9024
    Assert(c > 0);
858
17928
    Node cl = getCardinalityLiteral( c );
859
9024
    if( val ){
860
7497
      bool doCheckRegions = !d_hasCard;
861
7497
      bool prevHasCard = d_hasCard;
862
7497
      d_hasCard = true;
863
7497
      if (!prevHasCard || c < d_cardinality)
864
      {
865
7488
        d_cardinality = c;
866
7488
        simpleCheckCardinality();
867
7488
        if (d_state.isInConflict())
868
        {
869
120
          return;
870
        }
871
      }
872
      //should check all regions now
873
7377
      if (doCheckRegions)
874
      {
875
49265
        for (size_t i = 0; i < d_regions_index; i++)
876
        {
877
41929
          if( d_regions[i]->valid() ){
878
35932
            checkRegion( i );
879
35932
            if (d_state.isInConflict())
880
            {
881
              return;
882
            }
883
          }
884
        }
885
      }
886
      // we assert it positively, if its beyond the bound, abort
887
14754
      if (options::ufssAbortCardinality() >= 0
888
7377
          && 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
1527
      if (c > d_maxNegCard.get())
899
      {
900
2710
        Trace("uf-ss-com-card-debug") << "Maximum negative cardinality for "
901
1355
                                      << d_type << " is now " << c << std::endl;
902
1355
        d_maxNegCard.set(c);
903
1355
        simpleCheckCardinality();
904
      }
905
    }
906
  }
907
}
908
909
103061
void SortModel::checkRegion( int ri, bool checkCombine ){
910
103061
  if( isValid(ri) && d_hasCard ){
911
96583
    Assert(d_cardinality > 0);
912
96583
    if( checkCombine && d_regions[ri]->getMustCombine( d_cardinality ) ){
913
9242
      int riNew = forceCombineRegion( ri, true );
914
9242
      if( riNew>=0 ){
915
9242
        checkRegion( riNew, checkCombine );
916
      }
917
    }
918
    //now check if region is in conflict
919
193166
    std::vector< Node > clique;
920
96583
    if( d_regions[ri]->check( Theory::EFFORT_STANDARD, d_cardinality, clique ) ){
921
      //explain clique
922
2322
      addCliqueLemma(clique);
923
    }
924
  }
925
103061
}
926
927
12228
int SortModel::forceCombineRegion( int ri, bool useDensity ){
928
12228
  if( !useDensity ){
929
29570
    for( int i=0; i<(int)d_regions_index; i++ ){
930
29570
      if( ri!=i && d_regions[i]->valid() ){
931
2986
        return combineRegions( ri, i );
932
      }
933
    }
934
    return -1;
935
  }else{
936
    //this region must merge with another
937
9242
    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
9242
    double maxScore = 0;
943
9242
    int maxRegion = -1;
944
18484
    std::map< int, int > regions_diseq;
945
9242
    getDisequalitiesToRegions( ri, regions_diseq );
946
56724
    for( std::map< int, int >::iterator it = regions_diseq.begin(); it != regions_diseq.end(); ++it ){
947
47482
      Debug("uf-ss-check-region") << it->first << " : " << it->second << std::endl;
948
    }
949
56724
    for( std::map< int, int >::iterator it = regions_diseq.begin(); it != regions_diseq.end(); ++it ){
950
47482
      Assert(it->first != ri);
951
47482
      Assert(isValid(it->first));
952
47482
      Assert(d_regions[it->first]->getNumReps() > 0);
953
47482
      double tempScore = double(it->second)/double(d_regions[it->first]->getNumReps() );
954
47482
      if( tempScore>maxScore ){
955
11007
        maxRegion = it->first;
956
11007
        maxScore = tempScore;
957
      }
958
    }
959
9242
    if( maxRegion!=-1 ){
960
9242
      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
9242
      return combineRegions( ri, maxRegion );
965
    }
966
    return -1;
967
  }
968
}
969
970
971
40803
int SortModel::combineRegions( int ai, int bi ){
972
40803
  Debug("uf-ss-region") << "uf-ss: Combine Region #" << bi << " with Region #" << ai << std::endl;
973
40803
  Assert(isValid(ai) && isValid(bi));
974
40803
  Region* region_bi = d_regions[bi];
975
220398
  for(Region::iterator it = region_bi->begin(); it != region_bi->end(); ++it){
976
179595
    Region::RegionNodeInfo* rni = it->second;
977
179595
    if( rni->valid() ){
978
43776
      d_regions_map[ it->first ] = ai;
979
    }
980
  }
981
  //update regions disequal DO_THIS?
982
40803
  d_regions[ai]->combine( d_regions[bi] );
983
40803
  d_regions[bi]->setValid( false );
984
40803
  return ai;
985
}
986
987
433
void SortModel::moveNode( Node n, int ri ){
988
433
  Debug("uf-ss-region") << "uf-ss: Move node " << n << " to Region #" << ri << std::endl;
989
433
  Assert(isValid(d_regions_map[n]));
990
433
  Assert(isValid(ri));
991
  //move node to region ri
992
433
  d_regions[ri]->takeNode( d_regions[ d_regions_map[n] ], n );
993
433
  d_regions_map[n] = ri;
994
433
}
995
996
2027
int SortModel::addSplit(Region* r)
997
{
998
4054
  Node s;
999
2027
  if( r->hasSplits() ){
1000
    //take the first split you find
1001
9650
    for( Region::split_iterator it = r->begin_splits();
1002
9650
         it != r->end_splits(); ++it ){
1003
9650
      if( (*it).second ){
1004
2027
        s = (*it).first;
1005
2027
        break;
1006
      }
1007
    }
1008
2027
    Assert(s != Node::null());
1009
  }
1010
2027
  if (!s.isNull() ){
1011
    //add lemma to output channel
1012
2027
    Assert(s.getKind() == EQUAL);
1013
4054
    Node ss = Rewriter::rewrite( s );
1014
2027
    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
2027
    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
4054
    Node lem = NodeManager::currentNM()->mkNode( kind::OR, ss, ss.negate() );
1050
    // send lemma, with caching
1051
2027
    if (d_im.lemma(lem, InferenceId::UF_CARD_SPLIT))
1052
    {
1053
2027
      Trace("uf-ss-lemma") << "*** Split on " << s << std::endl;
1054
      //tell the sat solver to explore the equals branch first
1055
2027
      d_im.requirePhase(ss, true);
1056
2027
      ++( d_thss->d_statistics.d_split_lemmas );
1057
    }
1058
2027
    return 1;
1059
  }else{
1060
    return 0;
1061
  }
1062
}
1063
1064
3719
void SortModel::addCliqueLemma(std::vector<Node>& clique)
1065
{
1066
3719
  Assert(d_hasCard);
1067
3719
  Assert(d_cardinality > 0);
1068
9871
  while (clique.size() > d_cardinality + 1)
1069
  {
1070
3076
    clique.pop_back();
1071
  }
1072
  // add as lemma
1073
7438
  std::vector<Node> eqs;
1074
20166
  for (unsigned i = 0, size = clique.size(); i < size; i++)
1075
  {
1076
69745
    for (unsigned j = 0; j < i; j++)
1077
    {
1078
53298
      eqs.push_back(clique[i].eqNode(clique[j]));
1079
    }
1080
  }
1081
3719
  eqs.push_back(d_cardinality_literal[d_cardinality].notNode());
1082
7438
  Node lem = NodeManager::currentNM()->mkNode(OR, eqs);
1083
  // send lemma, with caching
1084
3719
  if (d_im.lemma(lem, InferenceId::UF_CARD_CLIQUE))
1085
  {
1086
3719
    Trace("uf-ss-lemma") << "*** Add clique lemma " << lem << std::endl;
1087
3719
    ++(d_thss->d_statistics.d_clique_lemmas);
1088
  }
1089
3719
}
1090
1091
8843
void SortModel::simpleCheckCardinality() {
1092
8843
  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
8843
}
1099
1100
9835
void SortModel::debugPrint( const char* c ){
1101
9835
  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
9835
}
1129
1130
1514
bool SortModel::checkLastCall()
1131
{
1132
1514
  NodeManager* nm = NodeManager::currentNM();
1133
1514
  SkolemManager* sm = nm->getSkolemManager();
1134
1514
  TheoryModel* m = d_state.getModel();
1135
1514
  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
1514
  RepSet* rs = m->getRepSetPtr();
1156
1514
  size_t nReps = rs->getNumRepresentatives(d_type);
1157
1514
  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
1499
  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
11553
Node SortModel::getCardinalityLiteral(uint32_t c)
1213
{
1214
11553
  Assert(c > 0);
1215
11553
  std::map<uint32_t, Node>::iterator itcl = d_cardinality_literal.find(c);
1216
11553
  if (itcl != d_cardinality_literal.end())
1217
  {
1218
10569
    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
286
CardinalityExtension::CardinalityExtension(TheoryState& state,
1229
                                           TheoryInferenceManager& im,
1230
286
                                           TheoryUF* th)
1231
    : d_state(state),
1232
      d_im(im),
1233
      d_th(th),
1234
      d_rep_model(),
1235
      d_min_pos_com_card(state.getSatContext(), 0),
1236
      d_min_pos_com_card_set(state.getSatContext(), false),
1237
      d_cc_dec_strat(nullptr),
1238
286
      d_initializedCombinedCardinality(state.getUserContext(), false),
1239
286
      d_card_assertions_eqv_lemma(state.getUserContext()),
1240
      d_min_pos_tn_master_card(state.getSatContext(), 0),
1241
      d_min_pos_tn_master_card_set(state.getSatContext(), false),
1242
858
      d_rel_eqc(state.getSatContext())
1243
{
1244
286
  if (options::ufssMode() == options::UfssMode::FULL && options::ufssFairness())
1245
  {
1246
    // Register the strategy with the decision manager of the theory.
1247
    // We are guaranteed that the decision manager is ready since we
1248
    // construct this module during TheoryUF::finishInit.
1249
834
    d_cc_dec_strat.reset(new CombinedCardinalityDecisionStrategy(
1250
556
        state.getSatContext(), th->getValuation()));
1251
  }
1252
286
}
1253
1254
572
CardinalityExtension::~CardinalityExtension()
1255
{
1256
746
  for (std::map<TypeNode, SortModel*>::iterator it = d_rep_model.begin();
1257
746
       it != d_rep_model.end(); ++it) {
1258
460
    delete it->second;
1259
  }
1260
286
}
1261
1262
/** ensure eqc */
1263
void CardinalityExtension::ensureEqc(SortModel* c, Node a)
1264
{
1265
  if( !hasEqc( a ) ){
1266
    d_rel_eqc[a] = true;
1267
    Trace("uf-ss-solver") << "CardinalityExtension: New eq class " << a << " : "
1268
                          << a.getType() << std::endl;
1269
    c->newEqClass( a );
1270
    Trace("uf-ss-solver") << "CardinalityExtension: Done New eq class."
1271
                          << std::endl;
1272
  }
1273
}
1274
1275
void CardinalityExtension::ensureEqcRec(Node n)
1276
{
1277
  if( !hasEqc( n ) ){
1278
    SortModel* c = getSortModel( n );
1279
    if( c ){
1280
      ensureEqc( c, n );
1281
    }
1282
    for( unsigned i=0; i<n.getNumChildren(); i++ ){
1283
      ensureEqcRec( n[i] );
1284
    }
1285
  }
1286
}
1287
1288
/** has eqc */
1289
bool CardinalityExtension::hasEqc(Node a)
1290
{
1291
  NodeBoolMap::iterator it = d_rel_eqc.find( a );
1292
  return it!=d_rel_eqc.end() && (*it).second;
1293
}
1294
1295
/** new node */
1296
52824
void CardinalityExtension::newEqClass(Node a)
1297
{
1298
52824
  SortModel* c = getSortModel( a );
1299
52824
  if( c ){
1300
10424
    Trace("uf-ss-solver") << "CardinalityExtension: New eq class " << a << " : "
1301
5212
                          << a.getType() << std::endl;
1302
5212
    c->newEqClass( a );
1303
10424
    Trace("uf-ss-solver") << "CardinalityExtension: Done New eq class."
1304
5212
                          << std::endl;
1305
  }
1306
52824
}
1307
1308
/** merge */
1309
282277
void CardinalityExtension::merge(Node a, Node b)
1310
{
1311
  //TODO: ensure they are relevant
1312
282277
  SortModel* c = getSortModel( a );
1313
282277
  if( c ){
1314
64656
    Trace("uf-ss-solver") << "CardinalityExtension: Merge " << a << " " << b
1315
32328
                          << " : " << a.getType() << std::endl;
1316
32328
    c->merge( a, b );
1317
32328
    Trace("uf-ss-solver") << "CardinalityExtension: Done Merge." << std::endl;
1318
  }
1319
282277
}
1320
1321
/** assert terms are disequal */
1322
21042
void CardinalityExtension::assertDisequal(Node a, Node b, Node reason)
1323
{
1324
21042
  SortModel* c = getSortModel( a );
1325
21042
  if( c ){
1326
25664
    Trace("uf-ss-solver") << "CardinalityExtension: Assert disequal " << a
1327
12832
                          << " " << b << " : " << a.getType() << std::endl;
1328
12832
    c->assertDisequal( a, b, reason );
1329
25664
    Trace("uf-ss-solver") << "CardinalityExtension: Done Assert disequal."
1330
12832
                          << std::endl;
1331
  }
1332
21042
}
1333
1334
/** assert a node */
1335
218462
void CardinalityExtension::assertNode(Node n, bool isDecision)
1336
{
1337
218462
  Trace("uf-ss") << "Assert " << n << " " << isDecision << std::endl;
1338
218462
  bool polarity = n.getKind() != kind::NOT;
1339
436924
  TNode lit = polarity ? n : n[0];
1340
218462
  if (options::ufssMode() == options::UfssMode::FULL)
1341
  {
1342
196867
    if( lit.getKind()==CARDINALITY_CONSTRAINT ){
1343
18080
      TypeNode tn = lit[0].getType();
1344
9040
      Assert(tn.isSort());
1345
9040
      Assert(d_rep_model[tn]);
1346
      uint32_t nCard =
1347
9040
          lit[1].getConst<Rational>().getNumerator().getUnsignedInt();
1348
18080
      Node ct = d_rep_model[tn]->getCardinalityTerm();
1349
9040
      Trace("uf-ss-debug") << "...check cardinality terms : " << lit[0] << " " << ct << std::endl;
1350
9040
      if( lit[0]==ct ){
1351
9024
        if( options::ufssFairnessMonotone() ){
1352
54
          SortInference* si = d_state.getSortInference();
1353
54
          Trace("uf-ss-com-card-debug") << "...set master/slave" << std::endl;
1354
54
          if( tn!=d_tn_mono_master ){
1355
42
            std::map< TypeNode, bool >::iterator it = d_tn_mono_slave.find( tn );
1356
42
            if( it==d_tn_mono_slave.end() ){
1357
              bool isMonotonic;
1358
10
              if (si != nullptr)
1359
              {
1360
                isMonotonic = si->isMonotonic(tn);
1361
              }else{
1362
                //if ground, everything is monotonic
1363
10
                isMonotonic = true;
1364
              }
1365
10
              if( isMonotonic ){
1366
10
                if( d_tn_mono_master.isNull() ){
1367
4
                  Trace("uf-ss-com-card-debug") << "uf-ss-fair-monotone: Set master : " << tn << std::endl;
1368
4
                  d_tn_mono_master = tn;
1369
                }else{
1370
6
                  Trace("uf-ss-com-card-debug") << "uf-ss-fair-monotone: Set slave : " << tn << std::endl;
1371
6
                  d_tn_mono_slave[tn] = true;
1372
                }
1373
              }else{
1374
                Trace("uf-ss-com-card-debug") << "uf-ss-fair-monotone: Set non-monotonic : " << tn << std::endl;
1375
                d_tn_mono_slave[tn] = false;
1376
              }
1377
            }
1378
          }
1379
          //set the minimum positive cardinality for master if necessary
1380
54
          if( polarity && tn==d_tn_mono_master ){
1381
16
            Trace("uf-ss-com-card-debug") << "...set min positive cardinality" << std::endl;
1382
32
            if (!d_min_pos_tn_master_card_set.get()
1383
16
                || nCard < d_min_pos_tn_master_card.get())
1384
            {
1385
16
              d_min_pos_tn_master_card_set.set(true);
1386
16
              d_min_pos_tn_master_card.set( nCard );
1387
            }
1388
          }
1389
        }
1390
9024
        Trace("uf-ss-com-card-debug") << "...assert cardinality" << std::endl;
1391
9024
        d_rep_model[tn]->assertCardinality(nCard, polarity);
1392
        //check if combined cardinality is violated
1393
9024
        checkCombinedCardinality();
1394
      }else{
1395
        //otherwise, make equal via lemma
1396
16
        if( d_card_assertions_eqv_lemma.find( lit )==d_card_assertions_eqv_lemma.end() ){
1397
16
          Node eqv_lit = NodeManager::currentNM()->mkNode( CARDINALITY_CONSTRAINT, ct, lit[1] );
1398
8
          eqv_lit = lit.eqNode( eqv_lit );
1399
8
          Trace("uf-ss-lemma") << "*** Cardinality equiv lemma : " << eqv_lit << std::endl;
1400
8
          d_im.lemma(eqv_lit, InferenceId::UF_CARD_EQUIV);
1401
8
          d_card_assertions_eqv_lemma[lit] = true;
1402
        }
1403
      }
1404
187827
    }else if( lit.getKind()==COMBINED_CARDINALITY_CONSTRAINT ){
1405
4613
      if( polarity ){
1406
        //safe to assume int here
1407
        uint32_t nCard =
1408
3598
            lit[0].getConst<Rational>().getNumerator().getUnsignedInt();
1409
3598
        if (!d_min_pos_com_card_set.get() || nCard < d_min_pos_com_card.get())
1410
        {
1411
3598
          d_min_pos_com_card_set.set(true);
1412
3598
          d_min_pos_com_card.set( nCard );
1413
3598
          checkCombinedCardinality();
1414
        }
1415
      }
1416
    }else{
1417
183214
      if( Trace.isOn("uf-ss-warn") ){
1418
        ////FIXME: this is too strict: theory propagations are showing up as isDecision=true, but
1419
        ////       a theory propagation is not a decision.
1420
        if( isDecision ){
1421
          for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
1422
            if( !it->second->hasCardinalityAsserted() ){
1423
              Trace("uf-ss-warn") << "WARNING: Assert " << n << " as a decision before cardinality for " << it->first << "." << std::endl;
1424
              // CVC5Message() << "Error: constraint asserted before cardinality
1425
              // for " << it->first << std::endl; Unimplemented();
1426
            }
1427
          }
1428
        }
1429
      }
1430
    }
1431
  }
1432
  else
1433
  {
1434
21595
    if( lit.getKind()==CARDINALITY_CONSTRAINT || lit.getKind()==COMBINED_CARDINALITY_CONSTRAINT ){
1435
      // cardinality constraint from user input, set incomplete
1436
2
      Trace("uf-ss") << "Literal " << lit << " not handled when uf ss mode is not FULL, set incomplete." << std::endl;
1437
2
      d_im.setIncomplete(IncompleteId::UF_CARD_MODE);
1438
    }
1439
  }
1440
218462
  Trace("uf-ss") << "Assert: done " << n << " " << isDecision << std::endl;
1441
218462
}
1442
1443
bool CardinalityExtension::areDisequal(Node a, Node b)
1444
{
1445
  if( a==b ){
1446
    return false;
1447
  }
1448
  eq::EqualityEngine* ee = d_th->getEqualityEngine();
1449
  a = ee->getRepresentative(a);
1450
  b = ee->getRepresentative(b);
1451
  if (ee->areDisequal(a, b, false))
1452
  {
1453
    return true;
1454
  }
1455
  SortModel* c = getSortModel(a);
1456
  if (c)
1457
  {
1458
    return c->areDisequal(a, b);
1459
  }
1460
  return false;
1461
}
1462
1463
/** check */
1464
88871
void CardinalityExtension::check(Theory::Effort level)
1465
{
1466
88871
  if (level == Theory::EFFORT_LAST_CALL)
1467
  {
1468
    // if last call, call last call check for each sort
1469
2437
    for (std::pair<const TypeNode, SortModel*>& r : d_rep_model)
1470
    {
1471
1514
      if (!r.second->checkLastCall())
1472
      {
1473
15
        break;
1474
      }
1475
    }
1476
938
    return;
1477
  }
1478
87933
  if (!d_state.isInConflict())
1479
  {
1480
87933
    if (options::ufssMode() == options::UfssMode::FULL)
1481
    {
1482
148630
      Trace("uf-ss-solver")
1483
74315
          << "CardinalityExtension: check " << level << std::endl;
1484
74315
      if (level == Theory::EFFORT_FULL)
1485
      {
1486
3803
        if (Debug.isOn("uf-ss-debug"))
1487
        {
1488
          debugPrint("uf-ss-debug");
1489
        }
1490
3803
        if (Trace.isOn("uf-ss-state"))
1491
        {
1492
          Trace("uf-ss-state")
1493
              << "CardinalityExtension::check " << level << std::endl;
1494
          for (std::pair<const TypeNode, SortModel*>& rm : d_rep_model)
1495
          {
1496
            Trace("uf-ss-state") << "  " << rm.first << " has cardinality "
1497
                                 << rm.second->getCardinality() << std::endl;
1498
          }
1499
        }
1500
      }
1501
327534
      for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
1502
253219
        it->second->check(level);
1503
253219
        if (d_state.isInConflict())
1504
        {
1505
          break;
1506
        }
1507
      }
1508
    }
1509
13618
    else if (options::ufssMode() == options::UfssMode::NO_MINIMAL)
1510
    {
1511
13618
      if( level==Theory::EFFORT_FULL ){
1512
        // split on an equality between two equivalence classes (at most one per type)
1513
580
        std::map< TypeNode, std::vector< Node > > eqc_list;
1514
580
        std::map< TypeNode, bool > type_proc;
1515
290
        eq::EqClassesIterator eqcs_i(d_th->getEqualityEngine());
1516
61286
        while( !eqcs_i.isFinished() ){
1517
60996
          Node a = *eqcs_i;
1518
60996
          TypeNode tn = a.getType();
1519
30498
          if( tn.isSort() ){
1520
3354
            if( type_proc.find( tn )==type_proc.end() ){
1521
2521
              std::map< TypeNode, std::vector< Node > >::iterator itel = eqc_list.find( tn );
1522
2521
              if( itel!=eqc_list.end() ){
1523
3804
                for( unsigned j=0; j<itel->second.size(); j++ ){
1524
4890
                  Node b = itel->second[j];
1525
2567
                  if( !d_th->getEqualityEngine()->areDisequal( a, b, false ) ){
1526
488
                    Node eq = Rewriter::rewrite( a.eqNode( b ) );
1527
488
                    Node lem = NodeManager::currentNM()->mkNode( kind::OR, eq, eq.negate() );
1528
244
                    Trace("uf-ss-lemma") << "*** Split (no-minimal) : " << lem << std::endl;
1529
244
                    d_im.lemma(lem, InferenceId::UF_CARD_SPLIT);
1530
244
                    d_im.requirePhase(eq, true);
1531
244
                    type_proc[tn] = true;
1532
244
                    break;
1533
                  }
1534
                }
1535
              }
1536
2521
              eqc_list[tn].push_back( a );
1537
            }
1538
          }
1539
30498
          ++eqcs_i;
1540
        }
1541
      }
1542
    }
1543
    else
1544
    {
1545
      // unhandled uf ss mode
1546
      Assert(false);
1547
    }
1548
175866
    Trace("uf-ss-solver") << "Done CardinalityExtension: check " << level
1549
87933
                          << std::endl;
1550
  }
1551
}
1552
1553
336
void CardinalityExtension::presolve()
1554
{
1555
336
  d_initializedCombinedCardinality = false;
1556
650
  for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
1557
314
    it->second->presolve();
1558
314
    it->second->initialize();
1559
  }
1560
336
}
1561
1562
278
CardinalityExtension::CombinedCardinalityDecisionStrategy::
1563
    CombinedCardinalityDecisionStrategy(context::Context* satContext,
1564
278
                                        Valuation valuation)
1565
278
    : DecisionStrategyFmf(satContext, valuation)
1566
{
1567
278
}
1568
801
Node CardinalityExtension::CombinedCardinalityDecisionStrategy::mkLiteral(
1569
    unsigned i)
1570
{
1571
801
  NodeManager* nm = NodeManager::currentNM();
1572
801
  return nm->mkNode(COMBINED_CARDINALITY_CONSTRAINT, nm->mkConst(Rational(i)));
1573
}
1574
1575
std::string
1576
244223
CardinalityExtension::CombinedCardinalityDecisionStrategy::identify() const
1577
{
1578
244223
  return std::string("uf_combined_card");
1579
}
1580
1581
350793
void CardinalityExtension::preRegisterTerm(TNode n)
1582
{
1583
350793
  if (options::ufssMode() == options::UfssMode::FULL)
1584
  {
1585
    //initialize combined cardinality
1586
297654
    initializeCombinedCardinality();
1587
1588
297654
    Trace("uf-ss-register") << "Preregister " << n << "." << std::endl;
1589
    //shouldn't have to preregister this type (it may be that there are no quantifiers over tn)
1590
595308
    TypeNode tn = n.getType();
1591
297654
    std::map< TypeNode, SortModel* >::iterator it = d_rep_model.find( tn );
1592
297654
    if( it==d_rep_model.end() ){
1593
293004
      SortModel* rm = NULL;
1594
293004
      if( tn.isSort() ){
1595
460
        Trace("uf-ss-register") << "Create sort model " << tn << "." << std::endl;
1596
460
        rm = new SortModel(n, d_state, d_im, this);
1597
      }
1598
293004
      if( rm ){
1599
460
        rm->initialize();
1600
460
        d_rep_model[tn] = rm;
1601
        //d_rep_model_init[tn] = true;
1602
      }
1603
    }else{
1604
      //ensure sort model is initialized
1605
4650
      it->second->initialize();
1606
    }
1607
  }
1608
350793
}
1609
1610
356143
SortModel* CardinalityExtension::getSortModel(Node n)
1611
{
1612
712286
  TypeNode tn = n.getType();
1613
356143
  std::map< TypeNode, SortModel* >::iterator it = d_rep_model.find( tn );
1614
  //pre-register the type if not done already
1615
356143
  if( it==d_rep_model.end() ){
1616
305771
    preRegisterTerm( n );
1617
305771
    it = d_rep_model.find( tn );
1618
  }
1619
356143
  if( it!=d_rep_model.end() ){
1620
50372
    return it->second;
1621
  }else{
1622
305771
    return NULL;
1623
  }
1624
}
1625
1626
/** get cardinality for sort */
1627
int CardinalityExtension::getCardinality(Node n)
1628
{
1629
  SortModel* c = getSortModel( n );
1630
  if( c ){
1631
    return c->getCardinality();
1632
  }else{
1633
    return -1;
1634
  }
1635
}
1636
1637
int CardinalityExtension::getCardinality(TypeNode tn)
1638
{
1639
  std::map< TypeNode, SortModel* >::iterator it = d_rep_model.find( tn );
1640
  if( it!=d_rep_model.end() && it->second ){
1641
    return it->second->getCardinality();
1642
  }
1643
  return -1;
1644
}
1645
1646
//print debug
1647
void CardinalityExtension::debugPrint(const char* c)
1648
{
1649
  for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
1650
    Debug( c ) << "Conflict find structure for " << it->first << ": " << std::endl;
1651
    it->second->debugPrint( c );
1652
    Debug( c ) << std::endl;
1653
  }
1654
}
1655
1656
/** initialize */
1657
297654
void CardinalityExtension::initializeCombinedCardinality()
1658
{
1659
595308
  if (d_cc_dec_strat.get() != nullptr
1660
297654
      && !d_initializedCombinedCardinality.get())
1661
  {
1662
481
    d_initializedCombinedCardinality = true;
1663
962
    d_im.getDecisionManager()->registerStrategy(
1664
481
        DecisionManager::STRAT_UF_COMBINED_CARD, d_cc_dec_strat.get());
1665
  }
1666
297654
}
1667
1668
/** check */
1669
12622
void CardinalityExtension::checkCombinedCardinality()
1670
{
1671
12622
  Assert(options::ufssMode() == options::UfssMode::FULL);
1672
12622
  if( options::ufssFairness() ){
1673
12622
    Trace("uf-ss-com-card-debug") << "Check combined cardinality, get maximum negative cardinalities..." << std::endl;
1674
12622
    uint32_t totalCombinedCard = 0;
1675
12622
    uint32_t maxMonoSlave = 0;
1676
25244
    TypeNode maxSlaveType;
1677
73969
    for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
1678
61347
      uint32_t max_neg = it->second->getMaximumNegativeCardinality();
1679
61347
      if( !options::ufssFairnessMonotone() ){
1680
61177
        totalCombinedCard += max_neg;
1681
      }else{
1682
170
        std::map< TypeNode, bool >::iterator its = d_tn_mono_slave.find( it->first );
1683
170
        if( its==d_tn_mono_slave.end() || !its->second ){
1684
74
          totalCombinedCard += max_neg;
1685
        }else{
1686
96
          if( max_neg>maxMonoSlave ){
1687
8
            maxMonoSlave = max_neg;
1688
8
            maxSlaveType = it->first;
1689
          }
1690
        }
1691
      }
1692
    }
1693
12622
    Trace("uf-ss-com-card-debug") << "Check combined cardinality, total combined card : " << totalCombinedCard << std::endl;
1694
12622
    if( options::ufssFairnessMonotone() ){
1695
70
      Trace("uf-ss-com-card-debug") << "Max slave monotonic negated cardinality : " << maxMonoSlave << std::endl;
1696
140
      if (!d_min_pos_tn_master_card_set.get()
1697
70
          && maxMonoSlave > d_min_pos_tn_master_card.get())
1698
      {
1699
        uint32_t mc = d_min_pos_tn_master_card.get();
1700
        std::vector< Node > conf;
1701
        conf.push_back( d_rep_model[d_tn_mono_master]->getCardinalityLiteral( mc ) );
1702
        conf.push_back( d_rep_model[maxSlaveType]->getCardinalityLiteral( maxMonoSlave ).negate() );
1703
        Node cf = NodeManager::currentNM()->mkNode( AND, conf );
1704
        Trace("uf-ss-lemma") << "*** Combined monotone cardinality conflict"
1705
                             << " : " << cf << std::endl;
1706
        Trace("uf-ss-com-card") << "*** Combined monotone cardinality conflict"
1707
                                << " : " << cf << std::endl;
1708
        d_im.conflict(cf, InferenceId::UF_CARD_MONOTONE_COMBINED);
1709
        return;
1710
      }
1711
    }
1712
12622
    uint32_t cc = d_min_pos_com_card.get();
1713
12622
    if (d_min_pos_com_card_set.get() && totalCombinedCard > cc)
1714
    {
1715
      //conflict
1716
1976
      Node com_lit = d_cc_dec_strat->getLiteral(cc);
1717
1976
      std::vector< Node > conf;
1718
988
      conf.push_back( com_lit );
1719
988
      uint32_t totalAdded = 0;
1720
2910
      for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin();
1721
2910
           it != d_rep_model.end(); ++it ){
1722
2910
        bool doAdd = true;
1723
2910
        if( options::ufssFairnessMonotone() ){
1724
          std::map< TypeNode, bool >::iterator its =
1725
            d_tn_mono_slave.find( it->first );
1726
          if( its!=d_tn_mono_slave.end() && its->second ){
1727
            doAdd = false;
1728
          }
1729
        }
1730
2910
        if( doAdd ){
1731
2910
          uint32_t c = it->second->getMaximumNegativeCardinality();
1732
2910
          if( c>0 ){
1733
2266
            conf.push_back( it->second->getCardinalityLiteral( c ).negate() );
1734
2266
            totalAdded += c;
1735
          }
1736
2910
          if( totalAdded>cc ){
1737
988
            break;
1738
          }
1739
        }
1740
      }
1741
1976
      Node cf = NodeManager::currentNM()->mkNode( AND, conf );
1742
1976
      Trace("uf-ss-lemma") << "*** Combined cardinality conflict : " << cf
1743
988
                           << std::endl;
1744
1976
      Trace("uf-ss-com-card") << "*** Combined cardinality conflict : " << cf
1745
988
                              << std::endl;
1746
988
      d_im.conflict(cf, InferenceId::UF_CARD_COMBINED);
1747
    }
1748
  }
1749
}
1750
1751
286
CardinalityExtension::Statistics::Statistics()
1752
286
    : d_clique_conflicts(smtStatisticsRegistry().registerInt(
1753
572
        "CardinalityExtension::Clique_Conflicts")),
1754
286
      d_clique_lemmas(smtStatisticsRegistry().registerInt(
1755
572
          "CardinalityExtension::Clique_Lemmas")),
1756
286
      d_split_lemmas(smtStatisticsRegistry().registerInt(
1757
572
          "CardinalityExtension::Split_Lemmas")),
1758
286
      d_max_model_size(smtStatisticsRegistry().registerInt(
1759
1144
          "CardinalityExtension::Max_Model_Size"))
1760
{
1761
286
  d_max_model_size.maxAssign(1);
1762
286
}
1763
1764
}  // namespace uf
1765
}  // namespace theory
1766
29340
}  // namespace cvc5