GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/uf/cardinality_extension.h Lines: 53 55 96.4 %
Date: 2021-05-22 Branches: 38 104 36.5 %

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
 * Theory of UF with cardinality.
14
 */
15
16
#include "cvc5_private.h"
17
18
#ifndef CVC5__THEORY_UF_STRONG_SOLVER_H
19
#define CVC5__THEORY_UF_STRONG_SOLVER_H
20
21
#include "context/cdhashmap.h"
22
#include "context/context.h"
23
#include "theory/decision_strategy.h"
24
#include "theory/theory.h"
25
#include "util/statistics_stats.h"
26
27
namespace cvc5 {
28
namespace theory {
29
namespace uf {
30
31
class TheoryUF;
32
33
/**
34
 * This module implements a theory solver for UF with cardinality constraints.
35
 * For high level details, see Reynolds et al "Finite Model Finding in SMT",
36
 * CAV 2013, or Reynolds dissertation "Finite Model Finding in Satisfiability
37
 * Modulo Theories".
38
 */
39
class CardinalityExtension
40
{
41
 protected:
42
  typedef context::CDHashMap<Node, bool> NodeBoolMap;
43
  typedef context::CDHashMap<Node, int> NodeIntMap;
44
45
 public:
46
  /**
47
   * Information for incremental conflict/clique finding for a
48
   * particular sort.
49
   */
50
  class SortModel
51
  {
52
   private:
53
    std::map< Node, std::vector< int > > d_totality_lems;
54
    std::map< TypeNode, std::map< int, std::vector< Node > > > d_sym_break_terms;
55
    std::map< Node, int > d_sym_break_index;
56
57
   public:
58
    /**
59
     * A partition of the current equality graph for which cliques
60
     * can occur internally.
61
     */
62
    class Region
63
    {
64
     public:
65
      /** information stored about each node in region */
66
      class RegionNodeInfo {
67
      public:
68
        /** disequality list for node */
69
        class DiseqList {
70
        public:
71
18612
          DiseqList( context::Context* c )
72
18612
            : d_size( c, 0 ), d_disequalities( c ) {}
73
18612
          ~DiseqList(){}
74
75
387044
          void setDisequal( Node n, bool valid ){
76
387044
            Assert((!isSet(n)) || getDisequalityValue(n) != valid);
77
387044
            d_disequalities[ n ] = valid;
78
387044
            d_size = d_size + ( valid ? 1 : -1 );
79
387044
          }
80
1189264
          bool isSet(Node n) const {
81
1189264
            return d_disequalities.find(n) != d_disequalities.end();
82
          }
83
327867
          bool getDisequalityValue(Node n) const {
84
327867
            Assert(isSet(n));
85
327867
            return (*(d_disequalities.find(n))).second;
86
          }
87
88
201981
          int size() const { return d_size; }
89
90
          typedef NodeBoolMap::iterator iterator;
91
187652
          iterator begin() { return d_disequalities.begin(); }
92
427056
          iterator end() { return d_disequalities.end(); }
93
94
        private:
95
          context::CDO< int > d_size;
96
          NodeBoolMap d_disequalities;
97
        }; /* class DiseqList */
98
       public:
99
        /** constructor */
100
9306
        RegionNodeInfo( context::Context* c )
101
9306
          : d_internal(c), d_external(c), d_valid(c, true) {
102
9306
          d_disequalities[0] = &d_internal;
103
9306
          d_disequalities[1] = &d_external;
104
9306
        }
105
9306
        ~RegionNodeInfo(){}
106
107
61100
        int getNumDisequalities() const {
108
61100
          return d_disequalities[0]->size() + d_disequalities[1]->size();
109
        }
110
47674
        int getNumExternalDisequalities() const {
111
47674
          return d_disequalities[0]->size();
112
        }
113
32107
        int getNumInternalDisequalities() const {
114
32107
          return d_disequalities[1]->size();
115
        }
116
117
1086131
        bool valid() const { return d_valid; }
118
85444
        void setValid(bool valid) { d_valid = valid; }
119
120
1049049
        DiseqList* get(unsigned i) { return d_disequalities[i]; }
121
122
       private:
123
        DiseqList d_internal;
124
        DiseqList d_external;
125
        context::CDO< bool > d_valid;
126
        DiseqList* d_disequalities[2];
127
      }; /* class RegionNodeInfo */
128
129
    private:
130
      /** conflict find pointer */
131
      SortModel* d_cf;
132
133
      context::CDO<size_t> d_testCliqueSize;
134
      context::CDO< unsigned > d_splitsSize;
135
      //a postulated clique
136
      NodeBoolMap d_testClique;
137
      //disequalities needed for this clique to happen
138
      NodeBoolMap d_splits;
139
      //number of valid representatives in this region
140
      context::CDO<size_t> d_reps_size;
141
      //total disequality size (external)
142
      context::CDO< unsigned > d_total_diseq_external;
143
      //total disequality size (internal)
144
      context::CDO< unsigned > d_total_diseq_internal;
145
      /** set rep */
146
      void setRep( Node n, bool valid );
147
      //region node infomation
148
      std::map< Node, RegionNodeInfo* > d_nodes;
149
      //whether region is valid
150
      context::CDO< bool > d_valid;
151
152
     public:
153
      //constructor
154
      Region( SortModel* cf, context::Context* c );
155
      virtual ~Region();
156
157
      typedef std::map< Node, RegionNodeInfo* >::iterator iterator;
158
77566
      iterator begin() { return d_nodes.begin(); }
159
533241
      iterator end() { return d_nodes.end(); }
160
161
      typedef NodeBoolMap::iterator split_iterator;
162
3554
      split_iterator begin_splits() { return d_splits.begin(); }
163
24309
      split_iterator end_splits() { return d_splits.end(); }
164
165
      /** Returns a RegionInfo. */
166
32178
      RegionNodeInfo* getRegionInfo(Node n) {
167
32178
        Assert(d_nodes.find(n) != d_nodes.end());
168
32178
        return (* (d_nodes.find(n))).second;
169
      }
170
171
      /** Returns whether or not d_valid is set in current context. */
172
1954551
      bool valid() const { return d_valid; }
173
174
      /** Sets d_valid to the value valid in the current context.*/
175
45259
      void setValid(bool valid) { d_valid = valid; }
176
177
      /** add rep */
178
      void addRep( Node n );
179
      //take node from region
180
      void takeNode( Region* r, Node n );
181
      //merge with other region
182
      void combine( Region* r );
183
      /** merge */
184
      void setEqual( Node a, Node b );
185
      //set n1 != n2 to value 'valid', type is whether it is internal/external
186
      void setDisequal( Node n1, Node n2, int type, bool valid );
187
      //get num reps
188
163255
      size_t getNumReps() const { return d_reps_size; }
189
      //get test clique size
190
      size_t getTestCliqueSize() const { return d_testCliqueSize; }
191
      // has representative
192
266058
      bool hasRep( Node n ) {
193
266058
        return d_nodes.find(n) != d_nodes.end() && d_nodes[n]->valid();
194
      }
195
      // is disequal
196
      bool isDisequal( Node n1, Node n2, int type );
197
      /** get must merge */
198
      bool getMustCombine( int cardinality );
199
      /** has splits */
200
1933
      bool hasSplits() { return d_splitsSize>0; }
201
      /** get external disequalities */
202
      void getNumExternalDisequalities(std::map< Node, int >& num_ext_disequalities );
203
      /** check for cliques */
204
      bool check( Theory::Effort level, int cardinality, std::vector< Node >& clique );
205
      //print debug
206
      void debugPrint( const char* c, bool incClique = false );
207
208
      // Returns the first key in d_nodes.
209
96
      Node frontKey() const { return d_nodes.begin()->first; }
210
    }; /* class Region */
211
212
   private:
213
    /** the type this model is for */
214
    TypeNode d_type;
215
    /** Reference to the state object */
216
    TheoryState& d_state;
217
    /** Reference to the inference manager */
218
    TheoryInferenceManager& d_im;
219
    /** Pointer to the cardinality extension that owns this. */
220
    CardinalityExtension* d_thss;
221
    /** regions used to d_region_index */
222
    context::CDO<size_t> d_regions_index;
223
    /** vector of regions */
224
    std::vector< Region* > d_regions;
225
    /** map from Nodes to index of d_regions they exist in, -1 means invalid */
226
    NodeIntMap d_regions_map;
227
    /** the score for each node for splitting */
228
    NodeIntMap d_split_score;
229
    /** number of valid disequalities in d_disequalities */
230
    context::CDO< unsigned > d_disequalities_index;
231
    /** list of all disequalities */
232
    std::vector< Node > d_disequalities;
233
    /** number of representatives in all regions */
234
    context::CDO< unsigned > d_reps;
235
236
    /** get number of disequalities from node n to region ri */
237
    int getNumDisequalitiesToRegion( Node n, int ri );
238
    /** get number of disequalities from Region r to other regions */
239
    void getDisequalitiesToRegions( int ri, std::map< int, int >& regions_diseq );
240
    /** is valid */
241
367008
    bool isValid( int ri ) {
242
367008
      return ri>=0 && ri<(int)d_regions_index && d_regions[ ri ]->valid();
243
    }
244
    /** set split score */
245
    void setSplitScore( Node n, int s );
246
    /** check if we need to combine region ri */
247
    void checkRegion( int ri, bool checkCombine = true );
248
    /** force combine region */
249
    int forceCombineRegion( int ri, bool useDensity = true );
250
    /** merge regions */
251
    int combineRegions( int ai, int bi );
252
    /** move node n to region ri */
253
    void moveNode( Node n, int ri );
254
    /** allocate cardinality */
255
    void allocateCardinality();
256
    /**
257
     * Add splits. Returns
258
     *   0 = no split,
259
     *  -1 = entailed disequality added, or
260
     *   1 = split added.
261
     */
262
    int addSplit(Region* r);
263
    /** add clique lemma */
264
    void addCliqueLemma(std::vector<Node>& clique);
265
    /** cardinality */
266
    context::CDO<uint32_t> d_cardinality;
267
    /** cardinality lemma term */
268
    Node d_cardinality_term;
269
    /** cardinality literals */
270
    std::map<uint32_t, Node> d_cardinality_literal;
271
    /** whether a positive cardinality constraint has been asserted */
272
    context::CDO< bool > d_hasCard;
273
    /** clique lemmas that have been asserted */
274
    std::map< int, std::vector< std::vector< Node > > > d_cliques;
275
    /** maximum negatively asserted cardinality */
276
    context::CDO<uint32_t> d_maxNegCard;
277
    /** list of fresh representatives allocated */
278
    std::vector< Node > d_fresh_aloc_reps;
279
    /** whether we are initialized */
280
    context::CDO< bool > d_initialized;
281
    /** simple check cardinality */
282
    void simpleCheckCardinality();
283
284
   public:
285
    SortModel(Node n,
286
              TheoryState& state,
287
              TheoryInferenceManager& im,
288
              CardinalityExtension* thss);
289
    virtual ~SortModel();
290
    /** initialize */
291
    void initialize();
292
    /** new node */
293
    void newEqClass( Node n );
294
    /** merge */
295
    void merge( Node a, Node b );
296
    /** assert terms are disequal */
297
    void assertDisequal( Node a, Node b, Node reason );
298
    /** are disequal */
299
    bool areDisequal( Node a, Node b );
300
    /** check */
301
    void check(Theory::Effort level);
302
    /** presolve */
303
    void presolve();
304
    /** assert cardinality */
305
    void assertCardinality(uint32_t c, bool val);
306
    /** get cardinality */
307
    uint32_t getCardinality() const { return d_cardinality; }
308
    /** has cardinality */
309
    bool hasCardinalityAsserted() const { return d_hasCard; }
310
    /** get cardinality term */
311
9258
    Node getCardinalityTerm() const { return d_cardinality_term; }
312
    /** get cardinality literal */
313
    Node getCardinalityLiteral(uint32_t c);
314
    /** get maximum negative cardinality */
315
68981
    uint32_t getMaximumNegativeCardinality() const
316
    {
317
68981
      return d_maxNegCard.get();
318
    }
319
    //print debug
320
    void debugPrint( const char* c );
321
    /**
322
     * Check at last call effort. This will verify that the model is minimal.
323
     * This return lemmas if there are terms in the model that the cardinality
324
     * extension was not notified of.
325
     *
326
     * @return false if current model is not minimal. In this case, lemmas are
327
     * sent on the output channel of the UF theory.
328
     */
329
    bool checkLastCall();
330
    /** get number of regions (for debugging) */
331
    int getNumRegions();
332
333
   private:
334
    /**
335
     * Decision strategy for cardinality constraints. This asserts
336
     * the minimal constraint positively in the SAT context. For details, see
337
     * Section 6.3 of Reynolds et al, "Constraint Solving for Finite Model
338
     * Finding in SMT Solvers", TPLP 2017.
339
     */
340
940
    class CardinalityDecisionStrategy : public DecisionStrategyFmf
341
    {
342
     public:
343
      CardinalityDecisionStrategy(Node t,
344
                                  context::Context* satContext,
345
                                  Valuation valuation);
346
      /** make literal (the i^th combined cardinality literal) */
347
      Node mkLiteral(unsigned i) override;
348
      /** identify */
349
      std::string identify() const override;
350
351
     private:
352
      /** the cardinality term */
353
      Node d_cardinality_term;
354
    };
355
    /** cardinality decision strategy */
356
    std::unique_ptr<CardinalityDecisionStrategy> d_c_dec_strat;
357
  }; /** class SortModel */
358
359
 public:
360
  CardinalityExtension(TheoryState& state,
361
                       TheoryInferenceManager& im,
362
                       TheoryUF* th);
363
  ~CardinalityExtension();
364
  /** get theory */
365
23102
  TheoryUF* getTheory() { return d_th; }
366
  /** new node */
367
  void newEqClass( Node n );
368
  /** merge */
369
  void merge( Node a, Node b );
370
  /** assert terms are disequal */
371
  void assertDisequal( Node a, Node b, Node reason );
372
  /** assert node */
373
  void assertNode( Node n, bool isDecision );
374
  /** are disequal */
375
  bool areDisequal( Node a, Node b );
376
  /** check */
377
  void check( Theory::Effort level );
378
  /** presolve */
379
  void presolve();
380
  /** preregister a term */
381
  void preRegisterTerm( TNode n );
382
  /** identify */
383
  std::string identify() const { return std::string("CardinalityExtension"); }
384
  //print debug
385
  void debugPrint( const char* c );
386
  /** get cardinality for node */
387
  int getCardinality( Node n );
388
  /** get cardinality for type */
389
  int getCardinality( TypeNode tn );
390
  /** has eqc */
391
  bool hasEqc(Node a);
392
393
  class Statistics {
394
   public:
395
    IntStat d_clique_conflicts;
396
    IntStat d_clique_lemmas;
397
    IntStat d_split_lemmas;
398
    IntStat d_max_model_size;
399
    Statistics();
400
  };
401
  /** statistics class */
402
  Statistics d_statistics;
403
404
 private:
405
  /** get sort model */
406
  SortModel* getSortModel(Node n);
407
  /** initialize */
408
  void initializeCombinedCardinality();
409
  /** check */
410
  void checkCombinedCardinality();
411
  /** ensure eqc */
412
  void ensureEqc(SortModel* c, Node a);
413
  /** ensure eqc for all subterms of n */
414
  void ensureEqcRec(Node n);
415
416
  /** Reference to the state object */
417
  TheoryState& d_state;
418
  /** Reference to the inference manager */
419
  TheoryInferenceManager& d_im;
420
  /** theory uf pointer */
421
  TheoryUF* d_th;
422
  /** rep model structure, one for each type */
423
  std::map<TypeNode, SortModel*> d_rep_model;
424
425
  /** minimum positive combined cardinality */
426
  context::CDO<uint32_t> d_min_pos_com_card;
427
  /** Whether the field above has been set */
428
  context::CDO<bool> d_min_pos_com_card_set;
429
  /**
430
   * Decision strategy for combined cardinality constraints. This asserts
431
   * the minimal combined cardinality constraint positively in the SAT
432
   * context. It is enabled by options::ufssFairness(). For details, see
433
   * the extension to multiple sorts in Section 6.3 of Reynolds et al,
434
   * "Constraint Solving for Finite Model Finding in SMT Solvers", TPLP 2017.
435
   */
436
548
  class CombinedCardinalityDecisionStrategy : public DecisionStrategyFmf
437
  {
438
   public:
439
    CombinedCardinalityDecisionStrategy(context::Context* satContext,
440
                                        Valuation valuation);
441
    /** make literal (the i^th combined cardinality literal) */
442
    Node mkLiteral(unsigned i) override;
443
    /** identify */
444
    std::string identify() const override;
445
  };
446
  /** combined cardinality decision strategy */
447
  std::unique_ptr<CombinedCardinalityDecisionStrategy> d_cc_dec_strat;
448
  /** Have we initialized combined cardinality? */
449
  context::CDO<bool> d_initializedCombinedCardinality;
450
451
  /** cardinality literals for which we have added */
452
  NodeBoolMap d_card_assertions_eqv_lemma;
453
  /** the master monotone type (if ufssFairnessMonotone enabled) */
454
  TypeNode d_tn_mono_master;
455
  std::map<TypeNode, bool> d_tn_mono_slave;
456
  /** The minimum positive asserted master cardinality */
457
  context::CDO<uint32_t> d_min_pos_tn_master_card;
458
  /** Whether the field above has been set */
459
  context::CDO<bool> d_min_pos_tn_master_card_set;
460
  /** relevant eqc */
461
  NodeBoolMap d_rel_eqc;
462
}; /* class CardinalityExtension */
463
464
}  // namespace uf
465
}  // namespace theory
466
}  // namespace cvc5
467
468
#endif /* CVC5__THEORY_UF_STRONG_SOLVER_H */