GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/uf/cardinality_extension.cpp Lines: 815 1013 80.5 %
Date: 2021-05-22 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
2466
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
2466
  , d_valid( c, true ) {}
56
57
7398
Region::~Region() {
58
11772
  for(iterator i = begin(), iend = end(); i != iend; ++i) {
59
9306
    RegionNodeInfo* regionNodeInfo = (*i).second;
60
9306
    delete regionNodeInfo;
61
  }
62
2466
  d_nodes.clear();
63
4932
}
64
65
4897
void Region::addRep( Node n ) {
66
4897
  setRep( n, true );
67
4897
}
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
42828
void Region::combine( Region* r ){
102
  //take all nodes from r
103
231729
  for(Region::iterator it = r->d_nodes.begin(); it != r->d_nodes.end(); ++it) {
104
188901
    if( it->second->valid() ){
105
45743
      setRep( it->first, true );
106
    }
107
  }
108
231729
  for(Region::iterator it = r->d_nodes.begin(); it != r->d_nodes.end(); ++it){
109
188901
    if( it->second->valid() ){
110
      //take disequalities from r
111
91486
      Node n = it->first;
112
45743
      RegionNodeInfo* rni = it->second;
113
137229
      for( int t=0; t<2; t++ ){
114
91486
        RegionNodeInfo::DiseqList* del = rni->get(t);
115
231770
        for( RegionNodeInfo::DiseqList::iterator it2 = del->begin(),
116
91486
               it2end = del->end(); it2 != it2end; ++it2 ){
117
140284
          if( (*it2).second ){
118
129156
            if( t==0 && hasRep( (*it2).first ) ){
119
55259
              setDisequal( (*it2).first, n, 0, false );
120
55259
              setDisequal( (*it2).first, n, 1, true );
121
55259
              setDisequal( n, (*it2).first, 1, true );
122
            }else{
123
73897
              setDisequal( n, (*it2).first, t, true );
124
            }
125
          }
126
        }
127
      }
128
    }
129
  }
130
42828
  r->d_valid = false;
131
42828
}
132
133
/** setEqual */
134
33994
void Region::setEqual( Node a, Node b ){
135
33994
  Assert(hasRep(a) && hasRep(b));
136
  //move disequalities of b over to a
137
101982
  for( int t=0; t<2; t++ ){
138
67988
    DiseqList* del = d_nodes[b]->get(t);
139
122748
    for( DiseqList::iterator it = del->begin(); it != del->end(); ++it ){
140
54760
      if( (*it).second ){
141
81044
        Node n = (*it).first;
142
        //get the region that contains the endpoint of the disequality b != ...
143
40522
        Region* nr = d_cf->d_regions[ d_cf->d_regions_map[ n ] ];
144
40522
        if( !isDisequal( a, n, t ) ){
145
18184
          setDisequal( a, n, t, true );
146
18184
          nr->setDisequal( n, a, t, true );
147
        }
148
40522
        setDisequal( b, n, t, false );
149
40522
        nr->setDisequal( n, b, t, false );
150
      }
151
    }
152
  }
153
  //remove b from representatives
154
33994
  setRep( b, false );
155
33994
}
156
157
387850
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
387850
  if( isDisequal( n1, n2, type )!=valid ){    //DO_THIS: make assertion
163
387044
    d_nodes[ n1 ]->get(type)->setDisequal( n2, valid );
164
387044
    if( type==0 ){
165
170976
      d_total_diseq_external = d_total_diseq_external + ( valid ? 1 : -1 );
166
    }else{
167
216068
      d_total_diseq_internal = d_total_diseq_internal + ( valid ? 1 : -1 );
168
216068
      if( valid ){
169
        //if they are both a part of testClique, then remove split
170
306144
        if( d_testClique.find( n1 )!=d_testClique.end() && d_testClique[n1] &&
171
154599
            d_testClique.find( n2 )!=d_testClique.end() && d_testClique[n2] ){
172
3054
          Node eq = NodeManager::currentNM()->mkNode( EQUAL, n1, n2 );
173
1527
          if( d_splits.find( eq )!=d_splits.end() && d_splits[ eq ] ){
174
1498
            Debug("uf-ss-debug") << "removing split for " << n1 << " " << n2
175
749
                                 << std::endl;
176
749
            d_splits[ eq ] = false;
177
749
            d_splitsSize = d_splitsSize - 1;
178
          }
179
        }
180
      }
181
    }
182
  }
183
387850
}
184
185
85444
void Region::setRep( Node n, bool valid ) {
186
85444
  Assert(hasRep(n) != valid);
187
85444
  if( valid && d_nodes.find( n )==d_nodes.end() ){
188
9306
    d_nodes[n] = new RegionNodeInfo(d_cf->d_state.getSatContext());
189
  }
190
85444
  d_nodes[n]->setValid(valid);
191
85444
  d_reps_size = d_reps_size + ( valid ? 1 : -1 );
192
  //removing a member of the test clique from this region
193
85444
  if( d_testClique.find( n ) != d_testClique.end() && d_testClique[n] ){
194
1621
    Assert(!valid);
195
1621
    d_testClique[n] = false;
196
1621
    d_testCliqueSize = d_testCliqueSize - 1;
197
    //remove all splits involving n
198
14341
    for( split_iterator it = begin_splits(); it != end_splits(); ++it ){
199
12720
      if( (*it).second ){
200
4037
        if( (*it).first[0]==n || (*it).first[1]==n ){
201
3997
          d_splits[ (*it).first ] = false;
202
3997
          d_splitsSize = d_splitsSize - 1;
203
        }
204
      }
205
    }
206
  }
207
85444
}
208
209
474353
bool Region::isDisequal( Node n1, Node n2, int type ) {
210
474353
  RegionNodeInfo::DiseqList* del = d_nodes[ n1 ]->get(type);
211
474353
  return del->isSet(n2) && del->getDisequalityValue(n2);
212
}
213
214
struct sortInternalDegree {
215
  Region* r;
216
15279
  bool operator() (Node i, Node j) {
217
30558
    return (r->getRegionInfo(i)->getNumInternalDisequalities() >
218
30558
            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
98825
bool Region::getMustCombine( int cardinality ){
233
98825
  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
21601
    std::vector< int > degrees;
241
141726
    for( Region::iterator it = begin(); it != end(); ++it ){
242
134531
      RegionNodeInfo* rni = it->second;
243
134531
      if( rni->valid() ){
244
61100
        if( rni->getNumDisequalities() >= cardinality ){
245
47674
          int outDeg = rni->getNumExternalDisequalities();
246
47674
          if( outDeg>=cardinality ){
247
            //we have 1 node of degree greater than (cardinality)
248
16200
            return true;
249
39969
          }else if( outDeg>=1 ){
250
38863
            degrees.push_back( outDeg );
251
38863
            if( (int)degrees.size()>=cardinality ){
252
              //we have (cardinality) nodes of degree 1
253
790
              return true;
254
            }
255
          }
256
        }
257
      }
258
    }
259
7195
    gmcCount++;
260
7195
    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
7195
    std::sort( degrees.begin(), degrees.end() );
266
38280
    for( int i=0; i<(int)degrees.size(); i++ ){
267
32369
      if( degrees[i]>=cardinality+1-((int)degrees.size()-i) ){
268
1284
        return true;
269
      }
270
    }
271
  }
272
89046
  return false;
273
}
274
275
936438
bool Region::check( Theory::Effort level, int cardinality,
276
                    std::vector< Node >& clique ) {
277
936438
  if( d_reps_size>unsigned(cardinality) ){
278
79160
    if( d_total_diseq_internal==d_reps_size*( d_reps_size - 1 ) ){
279
56524
      if( d_reps_size>1 ){
280
        //quick clique check, all reps form a clique
281
24524
        for( iterator it = begin(); it != end(); ++it ){
282
21701
          if( it->second->valid() ){
283
17213
            clique.push_back( it->first );
284
          }
285
        }
286
2823
        Trace("quick-clique") << "Found quick clique" << std::endl;
287
2823
        return true;
288
      }else{
289
53701
        return false;
290
      }
291
    }
292
22636
    else if (level==Theory::EFFORT_FULL)
293
    {
294
      //build test clique, up to size cardinality+1
295
1965
      if( d_testCliqueSize<=unsigned(cardinality) ){
296
3818
        std::vector< Node > newClique;
297
1909
        if( d_testCliqueSize<unsigned(cardinality) ){
298
14232
          for( iterator it = begin(); it != end(); ++it ){
299
            //if not in the test clique, add it to the set of new members
300
41824
            if( it->second->valid() &&
301
20915
                ( 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
8228
              newClique.push_back( it->first );
306
              //}
307
            }
308
          }
309
          //choose remaining nodes with the highest degrees
310
          sortInternalDegree sidObj;
311
1549
          sidObj.r = this;
312
1549
          std::sort( newClique.begin(), newClique.end(), sidObj );
313
1549
          int offset = ( cardinality - d_testCliqueSize ) + 1;
314
1549
          newClique.erase( newClique.begin() + offset, newClique.end() );
315
        }else{
316
          //scan for the highest degree
317
360
          int maxDeg = -1;
318
720
          Node maxNode;
319
3780
          for( std::map< Node, RegionNodeInfo* >::iterator
320
360
                 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
9934
            if( it->second->valid() &&
323
7397
                ( d_testClique.find( it->first )==d_testClique.end() ||
324
1620
                  !d_testClique[ it->first ] ) ){
325
377
              if( it->second->getNumInternalDisequalities()>maxDeg ){
326
362
                maxDeg = it->second->getNumInternalDisequalities();
327
362
                maxNode = it->first;
328
              }
329
            }
330
          }
331
360
          Assert(maxNode != Node::null());
332
360
          newClique.push_back( maxNode );
333
        }
334
        //check splits internal to new members
335
10396
        for( int j=0; j<(int)newClique.size(); j++ ){
336
16974
          Debug("uf-ss-debug") << "Choose to add clique member "
337
8487
                               << newClique[j] << std::endl;
338
39454
          for( int k=(j+1); k<(int)newClique.size(); k++ ){
339
30967
            if( !isDisequal( newClique[j], newClique[k], 1 ) ){
340
7694
              Node at_j = newClique[j];
341
7694
              Node at_k = newClique[k];
342
              Node j_eq_k =
343
7694
                NodeManager::currentNM()->mkNode( EQUAL, at_j, at_k );
344
3847
              d_splits[ j_eq_k ] = true;
345
3847
              d_splitsSize = d_splitsSize + 1;
346
            }
347
          }
348
          //check disequalities with old members
349
11495
          for( NodeBoolMap::iterator it = d_testClique.begin();
350
11495
               it != d_testClique.end(); ++it ){
351
3008
            if( (*it).second ){
352
1624
              if( !isDisequal( (*it).first, newClique[j], 1 ) ){
353
2154
                Node at_it = (*it).first;
354
2154
                Node at_j = newClique[j];
355
2154
                Node it_eq_j = at_it.eqNode(at_j);
356
1077
                d_splits[ it_eq_j ] = true;
357
1077
                d_splitsSize = d_splitsSize + 1;
358
              }
359
            }
360
          }
361
        }
362
        //add new clique members to test clique
363
10396
        for( int j=0; j<(int)newClique.size(); j++ ){
364
8487
          d_testClique[ newClique[j] ] = true;
365
8487
          d_testCliqueSize = d_testCliqueSize + 1;
366
        }
367
      }
368
      // Check if test clique has larger size than cardinality, and
369
      // forms a clique.
370
1965
      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
879882
  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
2431
void Region::debugPrint( const char* c, bool incClique ) {
401
2431
  Debug( c ) << "Num reps: " << d_reps_size << std::endl;
402
7068
  for( Region::iterator it = begin(); it != end(); ++it ){
403
4637
    RegionNodeInfo* rni = it->second;
404
4637
    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
2431
  Debug( c ) << "Total disequal: " << d_total_diseq_external << " external,";
420
2431
  Debug( c ) << " " << d_total_diseq_internal << " internal." << std::endl;
421
422
2431
  if( incClique ){
423
2431
    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
2431
    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
2431
}
447
448
470
SortModel::CardinalityDecisionStrategy::CardinalityDecisionStrategy(
449
470
    Node t, context::Context* satContext, Valuation valuation)
450
470
    : DecisionStrategyFmf(satContext, valuation), d_cardinality_term(t)
451
{
452
470
}
453
1135
Node SortModel::CardinalityDecisionStrategy::mkLiteral(unsigned i)
454
{
455
1135
  NodeManager* nm = NodeManager::currentNM();
456
  return nm->mkNode(
457
1135
      CARDINALITY_CONSTRAINT, d_cardinality_term, nm->mkConst(Rational(i + 1)));
458
}
459
533136
std::string SortModel::CardinalityDecisionStrategy::identify() const
460
{
461
533136
  return std::string("uf_card");
462
}
463
464
470
SortModel::SortModel(Node n,
465
                     TheoryState& state,
466
                     TheoryInferenceManager& im,
467
470
                     CardinalityExtension* thss)
468
    : d_type(n.getType()),
469
      d_state(state),
470
      d_im(im),
471
      d_thss(thss),
472
470
      d_regions_index(d_state.getSatContext(), 0),
473
470
      d_regions_map(d_state.getSatContext()),
474
470
      d_split_score(d_state.getSatContext()),
475
470
      d_disequalities_index(d_state.getSatContext(), 0),
476
470
      d_reps(d_state.getSatContext(), 0),
477
470
      d_cardinality(d_state.getSatContext(), 1),
478
470
      d_hasCard(d_state.getSatContext(), false),
479
470
      d_maxNegCard(d_state.getSatContext(), 0),
480
470
      d_initialized(d_state.getUserContext(), false),
481
4700
      d_c_dec_strat(nullptr)
482
{
483
470
  d_cardinality_term = n;
484
485
1281435
  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
1410
    d_c_dec_strat.reset(new CardinalityDecisionStrategy(
491
940
        n, d_state.getSatContext(), thss->getTheory()->getValuation()));
492
  }
493
470
}
494
495
1410
SortModel::~SortModel() {
496
2936
  for(std::vector<Region*>::iterator i = d_regions.begin();
497
2936
      i != d_regions.end(); ++i) {
498
2466
    Region* region = *i;
499
2466
    delete region;
500
  }
501
470
  d_regions.clear();
502
940
}
503
504
/** initialize */
505
5145
void SortModel::initialize()
506
{
507
5145
  if (d_c_dec_strat.get() != nullptr && !d_initialized)
508
  {
509
818
    d_initialized = true;
510
    // Strategy is user-context-dependent, since it is in sync with
511
    // user-context-dependent flag d_initialized.
512
1636
    d_im.getDecisionManager()->registerStrategy(DecisionManager::STRAT_UF_CARD,
513
818
                                                d_c_dec_strat.get());
514
  }
515
5145
}
516
517
/** new node */
518
4897
void SortModel::newEqClass( Node n ){
519
4897
  if (!d_state.isInConflict())
520
  {
521
4897
    if( d_regions_map.find( n )==d_regions_map.end() ){
522
4897
      d_regions_map[n] = d_regions_index;
523
4897
      Debug("uf-ss") << "CardinalityExtension: New Eq Class " << n << std::endl;
524
9794
      Debug("uf-ss-debug") << d_regions_index << " " << (int)d_regions.size()
525
4897
                           << std::endl;
526
4897
      if (d_regions_index < d_regions.size())
527
      {
528
2431
        d_regions[d_regions_index]->debugPrint("uf-ss-debug", true);
529
2431
        d_regions[d_regions_index]->setValid(true);
530
2431
        Assert(d_regions[d_regions_index]->getNumReps() == 0);
531
      }else{
532
2466
        d_regions.push_back(new Region(this, d_state.getSatContext()));
533
      }
534
4897
      d_regions[d_regions_index]->addRep(n);
535
4897
      d_regions_index = d_regions_index + 1;
536
537
4897
      d_reps = d_reps + 1;
538
    }
539
  }
540
4897
}
541
542
/** merge */
543
33994
void SortModel::merge( Node a, Node b ){
544
33994
  if (d_state.isInConflict())
545
  {
546
    return;
547
  }
548
67988
  Debug("uf-ss") << "CardinalityExtension: Merging " << a << " = " << b << "..."
549
33994
                 << std::endl;
550
33994
  if (a != b)
551
  {
552
33994
    Assert(d_regions_map.find(a) != d_regions_map.end());
553
33994
    Assert(d_regions_map.find(b) != d_regions_map.end());
554
33994
    int ai = d_regions_map[a];
555
33994
    int bi = d_regions_map[b];
556
33994
    Debug("uf-ss") << "   regions: " << ai << " " << bi << std::endl;
557
33994
    if (ai != bi)
558
    {
559
30435
      if (d_regions[ai]->getNumReps() == 1)
560
      {
561
20660
        int ri = combineRegions(bi, ai);
562
20660
        d_regions[ri]->setEqual(a, b);
563
20660
        checkRegion(ri);
564
      }
565
9775
      else if (d_regions[bi]->getNumReps() == 1)
566
      {
567
9370
        int ri = combineRegions(ai, bi);
568
9370
        d_regions[ri]->setEqual(a, b);
569
9370
        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
3559
      d_regions[ai]->setEqual(a, b);
597
3559
      checkRegion(ai);
598
    }
599
33994
    d_regions_map[b] = -1;
600
  }
601
33994
  d_reps = d_reps - 1;
602
}
603
604
/** assert terms are disequal */
605
13390
void SortModel::assertDisequal( Node a, Node b, Node reason ){
606
13390
  if (d_state.isInConflict())
607
  {
608
    return;
609
  }
610
  // if they are not already disequal
611
13390
  eq::EqualityEngine* ee = d_thss->getTheory()->getEqualityEngine();
612
13390
  a = ee->getRepresentative(a);
613
13390
  b = ee->getRepresentative(b);
614
13390
  int ai = d_regions_map[a];
615
13390
  int bi = d_regions_map[b];
616
13390
  if (d_regions[ai]->isDisequal(a, b, ai == bi))
617
  {
618
    // already disequal
619
    return;
620
  }
621
26780
  Debug("uf-ss") << "Assert disequal " << a << " != " << b << "..."
622
13390
                 << std::endl;
623
26780
  Debug("uf-ss-disequal") << "Assert disequal " << a << " != " << b << "..."
624
13390
                          << std::endl;
625
  // add to list of disequalities
626
13390
  if (d_disequalities_index < d_disequalities.size())
627
  {
628
10244
    d_disequalities[d_disequalities_index] = reason;
629
  }
630
  else
631
  {
632
3146
    d_disequalities.push_back(reason);
633
  }
634
13390
  d_disequalities_index = d_disequalities_index + 1;
635
  // now, add disequalities to regions
636
13390
  Assert(d_regions_map.find(a) != d_regions_map.end());
637
13390
  Assert(d_regions_map.find(b) != d_regions_map.end());
638
13390
  Debug("uf-ss") << "   regions: " << ai << " " << bi << std::endl;
639
13390
  if (ai == bi)
640
  {
641
    // internal disequality
642
450
    d_regions[ai]->setDisequal(a, b, 1, true);
643
450
    d_regions[ai]->setDisequal(b, a, 1, true);
644
    // do not need to check if it needs to combine (no new ext. disequalities)
645
450
    checkRegion(ai, false);
646
  }
647
  else
648
  {
649
    // external disequality
650
12940
    d_regions[ai]->setDisequal(a, b, 0, true);
651
12940
    d_regions[bi]->setDisequal(b, a, 0, true);
652
12940
    checkRegion(ai);
653
12940
    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
285285
void SortModel::check(Theory::Effort level)
671
{
672
285285
  Assert(options::ufssMode() == options::UfssMode::FULL);
673
285285
  if (!d_hasCard && d_state.isInConflict())
674
  {
675
    // not necessary to check
676
    return;
677
  }
678
570570
  Debug("uf-ss") << "CardinalityExtension: Check " << level << " " << d_type
679
285285
                 << std::endl;
680
285285
  if (level == Theory::EFFORT_FULL)
681
  {
682
9762
    Debug("fmf-full-check") << std::endl;
683
19524
    Debug("fmf-full-check")
684
9762
        << "Full check for SortModel " << d_type << ", status : " << std::endl;
685
9762
    debugPrint("fmf-full-check");
686
9762
    Debug("fmf-full-check") << std::endl;
687
  }
688
285285
  if (d_reps <= (unsigned)d_cardinality)
689
  {
690
215642
    Debug("uf-ss-debug") << "We have " << d_reps << " representatives for type "
691
107821
                         << d_type << ", <= " << d_cardinality << std::endl;
692
107821
    if( level==Theory::EFFORT_FULL ){
693
9556
      Debug("uf-ss-sat") << "We have " << d_reps << " representatives for type "
694
4778
                         << d_type << ", <= " << d_cardinality << std::endl;
695
    }
696
107821
    return;
697
  }
698
  // first check if we can generate a clique conflict
699
  // do a check within each region
700
1630411
  for (size_t i = 0; i < d_regions_index; i++)
701
  {
702
1453729
    if (d_regions[i]->valid())
703
    {
704
1673544
      std::vector<Node> clique;
705
837163
      if (d_regions[i]->check(level, d_cardinality, clique))
706
      {
707
        // add clique lemma
708
782
        addCliqueLemma(clique);
709
782
        return;
710
      }
711
      else
712
      {
713
836381
        Trace("uf-ss-debug") << "No clique in Region #" << i << std::endl;
714
      }
715
    }
716
  }
717
  // do splitting on demand
718
176682
  bool addedLemma = false;
719
176682
  if (level == Theory::EFFORT_FULL)
720
  {
721
4952
    Trace("uf-ss-debug") << "Add splits?" << std::endl;
722
    // see if we have any recommended splits from large regions
723
64515
    for (size_t i = 0; i < d_regions_index; i++)
724
    {
725
59563
      if (d_regions[i]->valid() && d_regions[i]->getNumReps() > d_cardinality)
726
      {
727
1933
        int sp = addSplit(d_regions[i]);
728
1933
        if (sp == 1)
729
        {
730
1933
          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
176682
  if (level != Theory::EFFORT_FULL || addedLemma)
742
  {
743
173663
    return;
744
  }
745
  // check at full effort
746
3019
  Trace("uf-ss-debug") << "No splits added. " << d_cardinality << std::endl;
747
3019
  Trace("uf-ss-si") << "Must combine region" << std::endl;
748
3019
  bool recheck = false;
749
3019
  SortInference* si = d_state.getSortInference();
750
3019
  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
3019
  if (!recheck)
776
  {
777
    // naive strategy, force region combination involving the first
778
    // valid region
779
9068
    for (size_t i = 0; i < d_regions_index; i++)
780
    {
781
9068
      if (d_regions[i]->valid())
782
      {
783
2971
        int fcr = forceCombineRegion(i, false);
784
5942
        Debug("fmf-full-check")
785
2971
            << "Combined regions " << i << " " << fcr << std::endl;
786
5942
        Trace("uf-ss-debug")
787
2971
            << "Combined regions " << i << " " << fcr << std::endl;
788
2971
        recheck = true;
789
2971
        break;
790
      }
791
    }
792
  }
793
3019
  if (recheck)
794
  {
795
3019
    Trace("uf-ss-debug") << "Must recheck." << std::endl;
796
3019
    check(level);
797
  }
798
}
799
800
348
void SortModel::presolve() {
801
348
  d_initialized = false;
802
348
}
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
9779
void SortModel::getDisequalitiesToRegions(int ri,
819
                                          std::map< int, int >& regions_diseq)
820
{
821
9779
  Region* region = d_regions[ri];
822
111496
  for(Region::iterator it = region->begin(); it != region->end(); ++it ){
823
101717
    if( it->second->valid() ){
824
26558
      DiseqList* del = it->second->get(0);
825
208085
      for( DiseqList::iterator it2 = del->begin(); it2 != del->end(); ++it2 ){
826
181527
        if( (*it2).second ){
827
124931
          Assert(isValid(d_regions_map[(*it2).first]));
828
          //Notice() << "Found disequality with " << (*it2).first << ", region = " << d_regions_map[ (*it2).first ] << std::endl;
829
124931
          regions_diseq[ d_regions_map[ (*it2).first ] ]++;
830
        }
831
      }
832
    }
833
  }
834
9779
}
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
9242
void SortModel::assertCardinality(uint32_t c, bool val)
849
{
850
9242
  if (!d_state.isInConflict())
851
  {
852
18484
    Trace("uf-ss-assert")
853
9242
        << "Assert cardinality " << d_type << " " << c << " " << val
854
9242
        << " level = "
855
9242
        << d_thss->getTheory()->getValuation().getAssertionLevel() << std::endl;
856
9242
    Assert(c > 0);
857
18364
    Node cl = getCardinalityLiteral( c );
858
9242
    if( val ){
859
7781
      bool doCheckRegions = !d_hasCard;
860
7781
      bool prevHasCard = d_hasCard;
861
7781
      d_hasCard = true;
862
7781
      if (!prevHasCard || c < d_cardinality)
863
      {
864
7773
        d_cardinality = c;
865
7773
        simpleCheckCardinality();
866
7773
        if (d_state.isInConflict())
867
        {
868
120
          return;
869
        }
870
      }
871
      //should check all regions now
872
7661
      if (doCheckRegions)
873
      {
874
49807
        for (size_t i = 0; i < d_regions_index; i++)
875
        {
876
42187
          if( d_regions[i]->valid() ){
877
35435
            checkRegion( i );
878
35435
            if (d_state.isInConflict())
879
            {
880
              return;
881
            }
882
          }
883
        }
884
      }
885
      // we assert it positively, if its beyond the bound, abort
886
22983
      if (options::ufssAbortCardinality() >= 0
887
7661
          && 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
1461
      if (c > d_maxNegCard.get())
898
      {
899
2582
        Trace("uf-ss-com-card-debug") << "Maximum negative cardinality for "
900
1291
                                      << d_type << " is now " << c << std::endl;
901
1291
        d_maxNegCard.set(c);
902
1291
        simpleCheckCardinality();
903
      }
904
    }
905
  }
906
}
907
908
105943
void SortModel::checkRegion( int ri, bool checkCombine ){
909
105943
  if( isValid(ri) && d_hasCard ){
910
99275
    Assert(d_cardinality > 0);
911
99275
    if( checkCombine && d_regions[ri]->getMustCombine( d_cardinality ) ){
912
9779
      int riNew = forceCombineRegion( ri, true );
913
9779
      if( riNew>=0 ){
914
9779
        checkRegion( riNew, checkCombine );
915
      }
916
    }
917
    //now check if region is in conflict
918
198550
    std::vector< Node > clique;
919
99275
    if( d_regions[ri]->check( Theory::EFFORT_STANDARD, d_cardinality, clique ) ){
920
      //explain clique
921
2073
      addCliqueLemma(clique);
922
    }
923
  }
924
105943
}
925
926
12750
int SortModel::forceCombineRegion( int ri, bool useDensity ){
927
12750
  if( !useDensity ){
928
25519
    for( int i=0; i<(int)d_regions_index; i++ ){
929
25519
      if( ri!=i && d_regions[i]->valid() ){
930
2971
        return combineRegions( ri, i );
931
      }
932
    }
933
    return -1;
934
  }else{
935
    //this region must merge with another
936
9779
    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
9779
    double maxScore = 0;
942
9779
    int maxRegion = -1;
943
19558
    std::map< int, int > regions_diseq;
944
9779
    getDisequalitiesToRegions( ri, regions_diseq );
945
59447
    for( std::map< int, int >::iterator it = regions_diseq.begin(); it != regions_diseq.end(); ++it ){
946
49668
      Debug("uf-ss-check-region") << it->first << " : " << it->second << std::endl;
947
    }
948
59447
    for( std::map< int, int >::iterator it = regions_diseq.begin(); it != regions_diseq.end(); ++it ){
949
49668
      Assert(it->first != ri);
950
49668
      Assert(isValid(it->first));
951
49668
      Assert(d_regions[it->first]->getNumReps() > 0);
952
49668
      double tempScore = double(it->second)/double(d_regions[it->first]->getNumReps() );
953
49668
      if( tempScore>maxScore ){
954
11565
        maxRegion = it->first;
955
11565
        maxScore = tempScore;
956
      }
957
    }
958
9779
    if( maxRegion!=-1 ){
959
9779
      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
9779
      return combineRegions( ri, maxRegion );
964
    }
965
    return -1;
966
  }
967
}
968
969
970
42828
int SortModel::combineRegions( int ai, int bi ){
971
42828
  Debug("uf-ss-region") << "uf-ss: Combine Region #" << bi << " with Region #" << ai << std::endl;
972
42828
  Assert(isValid(ai) && isValid(bi));
973
42828
  Region* region_bi = d_regions[bi];
974
231729
  for(Region::iterator it = region_bi->begin(); it != region_bi->end(); ++it){
975
188901
    Region::RegionNodeInfo* rni = it->second;
976
188901
    if( rni->valid() ){
977
45743
      d_regions_map[ it->first ] = ai;
978
    }
979
  }
980
  //update regions disequal DO_THIS?
981
42828
  d_regions[ai]->combine( d_regions[bi] );
982
42828
  d_regions[bi]->setValid( false );
983
42828
  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
1933
int SortModel::addSplit(Region* r)
996
{
997
3866
  Node s;
998
1933
  if( r->hasSplits() ){
999
    //take the first split you find
1000
9968
    for( Region::split_iterator it = r->begin_splits();
1001
9968
         it != r->end_splits(); ++it ){
1002
9968
      if( (*it).second ){
1003
1933
        s = (*it).first;
1004
1933
        break;
1005
      }
1006
    }
1007
1933
    Assert(s != Node::null());
1008
  }
1009
1933
  if (!s.isNull() ){
1010
    //add lemma to output channel
1011
1933
    Assert(s.getKind() == EQUAL);
1012
3866
    Node ss = Rewriter::rewrite( s );
1013
1933
    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
1933
    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
3866
    Node lem = NodeManager::currentNM()->mkNode( kind::OR, ss, ss.negate() );
1049
    // send lemma, with caching
1050
1933
    if (d_im.lemma(lem, InferenceId::UF_CARD_SPLIT))
1051
    {
1052
1933
      Trace("uf-ss-lemma") << "*** Split on " << s << std::endl;
1053
      //tell the sat solver to explore the equals branch first
1054
1933
      d_im.requirePhase(ss, true);
1055
1933
      ++( d_thss->d_statistics.d_split_lemmas );
1056
    }
1057
1933
    return 1;
1058
  }else{
1059
    return 0;
1060
  }
1061
}
1062
1063
2855
void SortModel::addCliqueLemma(std::vector<Node>& clique)
1064
{
1065
2855
  Assert(d_hasCard);
1066
2855
  Assert(d_cardinality > 0);
1067
9011
  while (clique.size() > d_cardinality + 1)
1068
  {
1069
3078
    clique.pop_back();
1070
  }
1071
  // add as lemma
1072
5710
  std::vector<Node> eqs;
1073
17076
  for (unsigned i = 0, size = clique.size(); i < size; i++)
1074
  {
1075
66392
    for (unsigned j = 0; j < i; j++)
1076
    {
1077
52171
      eqs.push_back(clique[i].eqNode(clique[j]));
1078
    }
1079
  }
1080
2855
  eqs.push_back(d_cardinality_literal[d_cardinality].notNode());
1081
5710
  Node lem = NodeManager::currentNM()->mkNode(OR, eqs);
1082
  // send lemma, with caching
1083
2855
  if (d_im.lemma(lem, InferenceId::UF_CARD_CLIQUE))
1084
  {
1085
2855
    Trace("uf-ss-lemma") << "*** Add clique lemma " << lem << std::endl;
1086
2855
    ++(d_thss->d_statistics.d_clique_lemmas);
1087
  }
1088
2855
}
1089
1090
9064
void SortModel::simpleCheckCardinality() {
1091
9064
  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
9064
}
1098
1099
9762
void SortModel::debugPrint( const char* c ){
1100
9762
  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
9762
}
1128
1129
1725
bool SortModel::checkLastCall()
1130
{
1131
1725
  NodeManager* nm = NodeManager::currentNM();
1132
1725
  SkolemManager* sm = nm->getSkolemManager();
1133
1725
  TheoryModel* m = d_state.getModel();
1134
1725
  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
1725
  RepSet* rs = m->getRepSetPtr();
1155
1725
  size_t nReps = rs->getNumRepresentatives(d_type);
1156
1725
  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
1710
  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
11877
Node SortModel::getCardinalityLiteral(uint32_t c)
1212
{
1213
11877
  Assert(c > 0);
1214
11877
  std::map<uint32_t, Node>::iterator itcl = d_cardinality_literal.find(c);
1215
11877
  if (itcl != d_cardinality_literal.end())
1216
  {
1217
10884
    return itcl->second;
1218
  }
1219
  // get the literal from the decision strategy
1220
1986
  Node lit = d_c_dec_strat->getLiteral(c - 1);
1221
993
  d_cardinality_literal[c] = lit;
1222
1223
  // return the literal
1224
993
  return lit;
1225
}
1226
1227
282
CardinalityExtension::CardinalityExtension(TheoryState& state,
1228
                                           TheoryInferenceManager& im,
1229
282
                                           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
282
      d_initializedCombinedCardinality(state.getUserContext(), false),
1238
282
      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
846
      d_rel_eqc(state.getSatContext())
1242
{
1243
13456
  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
822
    d_cc_dec_strat.reset(new CombinedCardinalityDecisionStrategy(
1249
548
        state.getSatContext(), th->getValuation()));
1250
  }
1251
282
}
1252
1253
564
CardinalityExtension::~CardinalityExtension()
1254
{
1255
752
  for (std::map<TypeNode, SortModel*>::iterator it = d_rep_model.begin();
1256
752
       it != d_rep_model.end(); ++it) {
1257
470
    delete it->second;
1258
  }
1259
282
}
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
32038
void CardinalityExtension::newEqClass(Node a)
1296
{
1297
32038
  SortModel* c = getSortModel( a );
1298
32038
  if( c ){
1299
9794
    Trace("uf-ss-solver") << "CardinalityExtension: New eq class " << a << " : "
1300
4897
                          << a.getType() << std::endl;
1301
4897
    c->newEqClass( a );
1302
9794
    Trace("uf-ss-solver") << "CardinalityExtension: Done New eq class."
1303
4897
                          << std::endl;
1304
  }
1305
32038
}
1306
1307
/** merge */
1308
427827
void CardinalityExtension::merge(Node a, Node b)
1309
{
1310
  //TODO: ensure they are relevant
1311
427827
  SortModel* c = getSortModel( a );
1312
427827
  if( c ){
1313
67988
    Trace("uf-ss-solver") << "CardinalityExtension: Merge " << a << " " << b
1314
33994
                          << " : " << a.getType() << std::endl;
1315
33994
    c->merge( a, b );
1316
33994
    Trace("uf-ss-solver") << "CardinalityExtension: Done Merge." << std::endl;
1317
  }
1318
427827
}
1319
1320
/** assert terms are disequal */
1321
25723
void CardinalityExtension::assertDisequal(Node a, Node b, Node reason)
1322
{
1323
25723
  SortModel* c = getSortModel( a );
1324
25723
  if( c ){
1325
26780
    Trace("uf-ss-solver") << "CardinalityExtension: Assert disequal " << a
1326
13390
                          << " " << b << " : " << a.getType() << std::endl;
1327
13390
    c->assertDisequal( a, b, reason );
1328
26780
    Trace("uf-ss-solver") << "CardinalityExtension: Done Assert disequal."
1329
13390
                          << std::endl;
1330
  }
1331
25723
}
1332
1333
/** assert a node */
1334
293698
void CardinalityExtension::assertNode(Node n, bool isDecision)
1335
{
1336
293698
  Trace("uf-ss") << "Assert " << n << " " << isDecision << std::endl;
1337
293698
  bool polarity = n.getKind() != kind::NOT;
1338
587396
  TNode lit = polarity ? n : n[0];
1339
293698
  if (options::ufssMode() == options::UfssMode::FULL)
1340
  {
1341
158294
    if( lit.getKind()==CARDINALITY_CONSTRAINT ){
1342
18516
      TypeNode tn = lit[0].getType();
1343
9258
      Assert(tn.isSort());
1344
9258
      Assert(d_rep_model[tn]);
1345
      uint32_t nCard =
1346
9258
          lit[1].getConst<Rational>().getNumerator().getUnsignedInt();
1347
18516
      Node ct = d_rep_model[tn]->getCardinalityTerm();
1348
9258
      Trace("uf-ss-debug") << "...check cardinality terms : " << lit[0] << " " << ct << std::endl;
1349
9258
      if( lit[0]==ct ){
1350
9242
        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
9242
        Trace("uf-ss-com-card-debug") << "...assert cardinality" << std::endl;
1390
9242
        d_rep_model[tn]->assertCardinality(nCard, polarity);
1391
        //check if combined cardinality is violated
1392
9242
        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
149036
    }else if( lit.getKind()==COMBINED_CARDINALITY_CONSTRAINT ){
1404
4672
      if( polarity ){
1405
        //safe to assume int here
1406
        uint32_t nCard =
1407
3658
            lit[0].getConst<Rational>().getNumerator().getUnsignedInt();
1408
3658
        if (!d_min_pos_com_card_set.get() || nCard < d_min_pos_com_card.get())
1409
        {
1410
3658
          d_min_pos_com_card_set.set(true);
1411
3658
          d_min_pos_com_card.set( nCard );
1412
3658
          checkCombinedCardinality();
1413
        }
1414
      }
1415
    }else{
1416
144364
      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
293698
  Trace("uf-ss") << "Assert: done " << n << " " << isDecision << std::endl;
1440
293698
}
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
137479
void CardinalityExtension::check(Theory::Effort level)
1464
{
1465
137479
  if (level == Theory::EFFORT_LAST_CALL)
1466
  {
1467
    // if last call, call last call check for each sort
1468
2724
    for (std::pair<const TypeNode, SortModel*>& r : d_rep_model)
1469
    {
1470
1725
      if (!r.second->checkLastCall())
1471
      {
1472
15
        break;
1473
      }
1474
    }
1475
1014
    return;
1476
  }
1477
136465
  if (!d_state.isInConflict())
1478
  {
1479
136465
    if (options::ufssMode() == options::UfssMode::FULL)
1480
    {
1481
127192
      Trace("uf-ss-solver")
1482
63596
          << "CardinalityExtension: check " << level << std::endl;
1483
63596
      if (level == Theory::EFFORT_FULL)
1484
      {
1485
3569
        if (Debug.isOn("uf-ss-debug"))
1486
        {
1487
          debugPrint("uf-ss-debug");
1488
        }
1489
3569
        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
345862
      for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
1501
282266
        it->second->check(level);
1502
282266
        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
272930
    Trace("uf-ss-solver") << "Done CardinalityExtension: check " << level
1548
136465
                          << std::endl;
1549
  }
1550
}
1551
1552
332
void CardinalityExtension::presolve()
1553
{
1554
332
  d_initializedCombinedCardinality = false;
1555
680
  for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
1556
348
    it->second->presolve();
1557
348
    it->second->initialize();
1558
  }
1559
332
}
1560
1561
274
CardinalityExtension::CombinedCardinalityDecisionStrategy::
1562
    CombinedCardinalityDecisionStrategy(context::Context* satContext,
1563
274
                                        Valuation valuation)
1564
274
    : DecisionStrategyFmf(satContext, valuation)
1565
{
1566
274
}
1567
803
Node CardinalityExtension::CombinedCardinalityDecisionStrategy::mkLiteral(
1568
    unsigned i)
1569
{
1570
803
  NodeManager* nm = NodeManager::currentNM();
1571
803
  return nm->mkNode(COMBINED_CARDINALITY_CONSTRAINT, nm->mkConst(Rational(i)));
1572
}
1573
1574
std::string
1575
195854
CardinalityExtension::CombinedCardinalityDecisionStrategy::identify() const
1576
{
1577
195854
  return std::string("uf_combined_card");
1578
}
1579
1580
478707
void CardinalityExtension::preRegisterTerm(TNode n)
1581
{
1582
478707
  if (options::ufssMode() == options::UfssMode::FULL)
1583
  {
1584
    //initialize combined cardinality
1585
232011
    initializeCombinedCardinality();
1586
1587
232011
    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
464022
    TypeNode tn = n.getType();
1590
232011
    std::map< TypeNode, SortModel* >::iterator it = d_rep_model.find( tn );
1591
232011
    if( it==d_rep_model.end() ){
1592
227684
      SortModel* rm = NULL;
1593
227684
      if( tn.isSort() ){
1594
470
        Trace("uf-ss-register") << "Create sort model " << tn << "." << std::endl;
1595
470
        rm = new SortModel(n, d_state, d_im, this);
1596
      }
1597
227684
      if( rm ){
1598
470
        rm->initialize();
1599
470
        d_rep_model[tn] = rm;
1600
        //d_rep_model_init[tn] = true;
1601
      }
1602
    }else{
1603
      //ensure sort model is initialized
1604
4327
      it->second->initialize();
1605
    }
1606
  }
1607
478707
}
1608
1609
485588
SortModel* CardinalityExtension::getSortModel(Node n)
1610
{
1611
971176
  TypeNode tn = n.getType();
1612
485588
  std::map< TypeNode, SortModel* >::iterator it = d_rep_model.find( tn );
1613
  //pre-register the type if not done already
1614
485588
  if( it==d_rep_model.end() ){
1615
433307
    preRegisterTerm( n );
1616
433307
    it = d_rep_model.find( tn );
1617
  }
1618
485588
  if( it!=d_rep_model.end() ){
1619
52281
    return it->second;
1620
  }else{
1621
433307
    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
232011
void CardinalityExtension::initializeCombinedCardinality()
1657
{
1658
464022
  if (d_cc_dec_strat.get() != nullptr
1659
232011
      && !d_initializedCombinedCardinality.get())
1660
  {
1661
478
    d_initializedCombinedCardinality = true;
1662
956
    d_im.getDecisionManager()->registerStrategy(
1663
478
        DecisionManager::STRAT_UF_COMBINED_CARD, d_cc_dec_strat.get());
1664
  }
1665
232011
}
1666
1667
/** check */
1668
12900
void CardinalityExtension::checkCombinedCardinality()
1669
{
1670
12900
  Assert(options::ufssMode() == options::UfssMode::FULL);
1671
12900
  if( options::ufssFairness() ){
1672
12900
    Trace("uf-ss-com-card-debug") << "Check combined cardinality, get maximum negative cardinalities..." << std::endl;
1673
12900
    uint32_t totalCombinedCard = 0;
1674
12900
    uint32_t maxMonoSlave = 0;
1675
25800
    TypeNode maxSlaveType;
1676
78837
    for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
1677
65937
      uint32_t max_neg = it->second->getMaximumNegativeCardinality();
1678
65937
      if( !options::ufssFairnessMonotone() ){
1679
65767
        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
12900
    Trace("uf-ss-com-card-debug") << "Check combined cardinality, total combined card : " << totalCombinedCard << std::endl;
1693
12900
    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
12900
    uint32_t cc = d_min_pos_com_card.get();
1712
12900
    if (d_min_pos_com_card_set.get() && totalCombinedCard > cc)
1713
    {
1714
      //conflict
1715
2004
      Node com_lit = d_cc_dec_strat->getLiteral(cc);
1716
2004
      std::vector< Node > conf;
1717
1002
      conf.push_back( com_lit );
1718
1002
      uint32_t totalAdded = 0;
1719
3044
      for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin();
1720
3044
           it != d_rep_model.end(); ++it ){
1721
3044
        bool doAdd = true;
1722
3044
        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
3044
        if( doAdd ){
1730
3044
          uint32_t c = it->second->getMaximumNegativeCardinality();
1731
3044
          if( c>0 ){
1732
2368
            conf.push_back( it->second->getCardinalityLiteral( c ).negate() );
1733
2368
            totalAdded += c;
1734
          }
1735
3044
          if( totalAdded>cc ){
1736
1002
            break;
1737
          }
1738
        }
1739
      }
1740
2004
      Node cf = NodeManager::currentNM()->mkNode( AND, conf );
1741
2004
      Trace("uf-ss-lemma") << "*** Combined cardinality conflict : " << cf
1742
1002
                           << std::endl;
1743
2004
      Trace("uf-ss-com-card") << "*** Combined cardinality conflict : " << cf
1744
1002
                              << std::endl;
1745
1002
      d_im.conflict(cf, InferenceId::UF_CARD_COMBINED);
1746
    }
1747
  }
1748
}
1749
1750
282
CardinalityExtension::Statistics::Statistics()
1751
282
    : d_clique_conflicts(smtStatisticsRegistry().registerInt(
1752
564
        "CardinalityExtension::Clique_Conflicts")),
1753
282
      d_clique_lemmas(smtStatisticsRegistry().registerInt(
1754
564
          "CardinalityExtension::Clique_Lemmas")),
1755
282
      d_split_lemmas(smtStatisticsRegistry().registerInt(
1756
564
          "CardinalityExtension::Split_Lemmas")),
1757
282
      d_max_model_size(smtStatisticsRegistry().registerInt(
1758
1128
          "CardinalityExtension::Max_Model_Size"))
1759
{
1760
282
  d_max_model_size.maxAssign(1);
1761
282
}
1762
1763
}  // namespace uf
1764
}  // namespace theory
1765
1329994
}  // namespace cvc5