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