GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/uf/cardinality_extension.h Lines: 53 55 96.4 %
Date: 2021-09-15 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 "smt/env_obj.h"
24
#include "theory/decision_strategy.h"
25
#include "theory/theory.h"
26
#include "util/statistics_stats.h"
27
28
namespace cvc5 {
29
namespace theory {
30
namespace uf {
31
32
class TheoryUF;
33
34
/**
35
 * This module implements a theory solver for UF with cardinality constraints.
36
 * For high level details, see Reynolds et al "Finite Model Finding in SMT",
37
 * CAV 2013, or Reynolds dissertation "Finite Model Finding in Satisfiability
38
 * Modulo Theories".
39
 */
40
class CardinalityExtension : protected EnvObj
41
{
42
 protected:
43
  typedef context::CDHashMap<Node, bool> NodeBoolMap;
44
  typedef context::CDHashMap<Node, int> NodeIntMap;
45
46
 public:
47
  /**
48
   * Information for incremental conflict/clique finding for a
49
   * particular sort.
50
   */
51
  class SortModel
52
  {
53
   private:
54
    std::map< Node, std::vector< int > > d_totality_lems;
55
    std::map< TypeNode, std::map< int, std::vector< Node > > > d_sym_break_terms;
56
    std::map< Node, int > d_sym_break_index;
57
58
   public:
59
    /**
60
     * A partition of the current equality graph for which cliques
61
     * can occur internally.
62
     */
63
    class Region
64
    {
65
     public:
66
      /** information stored about each node in region */
67
      class RegionNodeInfo {
68
      public:
69
        /** disequality list for node */
70
        class DiseqList {
71
        public:
72
19308
          DiseqList( context::Context* c )
73
19308
            : d_size( c, 0 ), d_disequalities( c ) {}
74
19308
          ~DiseqList(){}
75
76
373151
          void setDisequal( Node n, bool valid ){
77
373151
            Assert((!isSet(n)) || getDisequalityValue(n) != valid);
78
373151
            d_disequalities[ n ] = valid;
79
373151
            d_size = d_size + ( valid ? 1 : -1 );
80
373151
          }
81
1146915
          bool isSet(Node n) const {
82
1146915
            return d_disequalities.find(n) != d_disequalities.end();
83
          }
84
316209
          bool getDisequalityValue(Node n) const {
85
316209
            Assert(isSet(n));
86
316209
            return (*(d_disequalities.find(n))).second;
87
          }
88
89
199980
          int size() const { return d_size; }
90
91
          typedef NodeBoolMap::iterator iterator;
92
176534
          iterator begin() { return d_disequalities.begin(); }
93
409193
          iterator end() { return d_disequalities.end(); }
94
95
        private:
96
          context::CDO< int > d_size;
97
          NodeBoolMap d_disequalities;
98
        }; /* class DiseqList */
99
       public:
100
        /** constructor */
101
9654
        RegionNodeInfo( context::Context* c )
102
9654
          : d_internal(c), d_external(c), d_valid(c, true) {
103
9654
          d_disequalities[0] = &d_internal;
104
9654
          d_disequalities[1] = &d_external;
105
9654
        }
106
9654
        ~RegionNodeInfo(){}
107
108
60620
        int getNumDisequalities() const {
109
60620
          return d_disequalities[0]->size() + d_disequalities[1]->size();
110
        }
111
46846
        int getNumExternalDisequalities() const {
112
46846
          return d_disequalities[0]->size();
113
        }
114
31894
        int getNumInternalDisequalities() const {
115
31894
          return d_disequalities[1]->size();
116
        }
117
118
1031268
        bool valid() const { return d_valid; }
119
80905
        void setValid(bool valid) { d_valid = valid; }
120
121
1007240
        DiseqList* get(unsigned i) { return d_disequalities[i]; }
122
123
       private:
124
        DiseqList d_internal;
125
        DiseqList d_external;
126
        context::CDO< bool > d_valid;
127
        DiseqList* d_disequalities[2];
128
      }; /* class RegionNodeInfo */
129
130
    private:
131
      /** conflict find pointer */
132
      SortModel* d_cf;
133
134
      context::CDO<size_t> d_testCliqueSize;
135
      context::CDO< unsigned > d_splitsSize;
136
      //a postulated clique
137
      NodeBoolMap d_testClique;
138
      //disequalities needed for this clique to happen
139
      NodeBoolMap d_splits;
140
      //number of valid representatives in this region
141
      context::CDO<size_t> d_reps_size;
142
      //total disequality size (external)
143
      context::CDO< unsigned > d_total_diseq_external;
144
      //total disequality size (internal)
145
      context::CDO< unsigned > d_total_diseq_internal;
146
      /** set rep */
147
      void setRep( Node n, bool valid );
148
      //region node infomation
149
      std::map< Node, RegionNodeInfo* > d_nodes;
150
      //whether region is valid
151
      context::CDO< bool > d_valid;
152
153
     public:
154
      //constructor
155
      Region( SortModel* cf, context::Context* c );
156
      virtual ~Region();
157
158
      typedef std::map< Node, RegionNodeInfo* >::iterator iterator;
159
74865
      iterator begin() { return d_nodes.begin(); }
160
516636
      iterator end() { return d_nodes.end(); }
161
162
      typedef NodeBoolMap::iterator split_iterator;
163
3578
      split_iterator begin_splits() { return d_splits.begin(); }
164
23373
      split_iterator end_splits() { return d_splits.end(); }
165
166
      /** Returns a RegionInfo. */
167
32176
      RegionNodeInfo* getRegionInfo(Node n) {
168
32176
        Assert(d_nodes.find(n) != d_nodes.end());
169
32176
        return (* (d_nodes.find(n))).second;
170
      }
171
172
      /** Returns whether or not d_valid is set in current context. */
173
3000227
      bool valid() const { return d_valid; }
174
175
      /** Sets d_valid to the value valid in the current context.*/
176
42828
      void setValid(bool valid) { d_valid = valid; }
177
178
      /** add rep */
179
      void addRep( Node n );
180
      //take node from region
181
      void takeNode( Region* r, Node n );
182
      //merge with other region
183
      void combine( Region* r );
184
      /** merge */
185
      void setEqual( Node a, Node b );
186
      //set n1 != n2 to value 'valid', type is whether it is internal/external
187
      void setDisequal( Node n1, Node n2, int type, bool valid );
188
      //get num reps
189
164721
      size_t getNumReps() const { return d_reps_size; }
190
      //get test clique size
191
      size_t getTestCliqueSize() const { return d_testCliqueSize; }
192
      // has representative
193
251460
      bool hasRep( Node n ) {
194
251460
        return d_nodes.find(n) != d_nodes.end() && d_nodes[n]->valid();
195
      }
196
      // is disequal
197
      bool isDisequal( Node n1, Node n2, int type );
198
      /** get must merge */
199
      bool getMustCombine( int cardinality );
200
      /** has splits */
201
2016
      bool hasSplits() { return d_splitsSize>0; }
202
      /** get external disequalities */
203
      void getNumExternalDisequalities(std::map< Node, int >& num_ext_disequalities );
204
      /** check for cliques */
205
      bool check( Theory::Effort level, int cardinality, std::vector< Node >& clique );
206
      //print debug
207
      void debugPrint( const char* c, bool incClique = false );
208
209
      // Returns the first key in d_nodes.
210
108
      Node frontKey() const { return d_nodes.begin()->first; }
211
    }; /* class Region */
212
213
   private:
214
    /** the type this model is for */
215
    TypeNode d_type;
216
    /** Reference to the state object */
217
    TheoryState& d_state;
218
    /** Reference to the inference manager */
219
    TheoryInferenceManager& d_im;
220
    /** Pointer to the cardinality extension that owns this. */
221
    CardinalityExtension* d_thss;
222
    /** regions used to d_region_index */
223
    context::CDO<size_t> d_regions_index;
224
    /** vector of regions */
225
    std::vector< Region* > d_regions;
226
    /** map from Nodes to index of d_regions they exist in, -1 means invalid */
227
    NodeIntMap d_regions_map;
228
    /** the score for each node for splitting */
229
    NodeIntMap d_split_score;
230
    /** number of valid disequalities in d_disequalities */
231
    context::CDO< unsigned > d_disequalities_index;
232
    /** list of all disequalities */
233
    std::vector< Node > d_disequalities;
234
    /** number of representatives in all regions */
235
    context::CDO< unsigned > d_reps;
236
237
    /** get number of disequalities from node n to region ri */
238
    int getNumDisequalitiesToRegion( Node n, int ri );
239
    /** get number of disequalities from Region r to other regions */
240
    void getDisequalitiesToRegions( int ri, std::map< int, int >& regions_diseq );
241
    /** is valid */
242
351612
    bool isValid( int ri ) {
243
351612
      return ri>=0 && ri<(int)d_regions_index && d_regions[ ri ]->valid();
244
    }
245
    /** set split score */
246
    void setSplitScore( Node n, int s );
247
    /** check if we need to combine region ri */
248
    void checkRegion( int ri, bool checkCombine = true );
249
    /** force combine region */
250
    int forceCombineRegion( int ri, bool useDensity = true );
251
    /** merge regions */
252
    int combineRegions( int ai, int bi );
253
    /** move node n to region ri */
254
    void moveNode( Node n, int ri );
255
    /** allocate cardinality */
256
    void allocateCardinality();
257
    /**
258
     * Add splits. Returns
259
     *   0 = no split,
260
     *  -1 = entailed disequality added, or
261
     *   1 = split added.
262
     */
263
    int addSplit(Region* r);
264
    /** add clique lemma */
265
    void addCliqueLemma(std::vector<Node>& clique);
266
    /** cardinality */
267
    context::CDO<uint32_t> d_cardinality;
268
    /** cardinality lemma term */
269
    Node d_cardinality_term;
270
    /** cardinality literals */
271
    std::map<uint32_t, Node> d_cardinality_literal;
272
    /** whether a positive cardinality constraint has been asserted */
273
    context::CDO< bool > d_hasCard;
274
    /** clique lemmas that have been asserted */
275
    std::map< int, std::vector< std::vector< Node > > > d_cliques;
276
    /** maximum negatively asserted cardinality */
277
    context::CDO<uint32_t> d_maxNegCard;
278
    /** list of fresh representatives allocated */
279
    std::vector< Node > d_fresh_aloc_reps;
280
    /** whether we are initialized */
281
    context::CDO< bool > d_initialized;
282
    /** simple check cardinality */
283
    void simpleCheckCardinality();
284
285
   public:
286
    SortModel(Node n,
287
              TheoryState& state,
288
              TheoryInferenceManager& im,
289
              CardinalityExtension* thss);
290
    virtual ~SortModel();
291
    /** initialize */
292
    void initialize();
293
    /** new node */
294
    void newEqClass( Node n );
295
    /** merge */
296
    void merge( Node a, Node b );
297
    /** assert terms are disequal */
298
    void assertDisequal( Node a, Node b, Node reason );
299
    /** are disequal */
300
    bool areDisequal( Node a, Node b );
301
    /** check */
302
    void check(Theory::Effort level);
303
    /** presolve */
304
    void presolve();
305
    /** assert cardinality */
306
    void assertCardinality(uint32_t c, bool val);
307
    /** get cardinality */
308
    uint32_t getCardinality() const { return d_cardinality; }
309
    /** has cardinality */
310
    bool hasCardinalityAsserted() const { return d_hasCard; }
311
    /** get cardinality term */
312
9082
    Node getCardinalityTerm() const { return d_cardinality_term; }
313
    /** get cardinality literal */
314
    Node getCardinalityLiteral(uint32_t c);
315
    /** get maximum negative cardinality */
316
64831
    uint32_t getMaximumNegativeCardinality() const
317
    {
318
64831
      return d_maxNegCard.get();
319
    }
320
    //print debug
321
    void debugPrint( const char* c );
322
    /**
323
     * Check at last call effort. This will verify that the model is minimal.
324
     * This return lemmas if there are terms in the model that the cardinality
325
     * extension was not notified of.
326
     *
327
     * @return false if current model is not minimal. In this case, lemmas are
328
     * sent on the output channel of the UF theory.
329
     */
330
    bool checkLastCall();
331
    /** get number of regions (for debugging) */
332
    int getNumRegions();
333
334
   private:
335
    /**
336
     * Decision strategy for cardinality constraints. This asserts
337
     * the minimal constraint positively in the SAT context. For details, see
338
     * Section 6.3 of Reynolds et al, "Constraint Solving for Finite Model
339
     * Finding in SMT Solvers", TPLP 2017.
340
     */
341
920
    class CardinalityDecisionStrategy : public DecisionStrategyFmf
342
    {
343
     public:
344
      CardinalityDecisionStrategy(Env& env, Node t, Valuation valuation);
345
      /** make literal (the i^th combined cardinality literal) */
346
      Node mkLiteral(unsigned i) override;
347
      /** identify */
348
      std::string identify() const override;
349
350
     private:
351
      /** the cardinality term */
352
      Node d_cardinality_term;
353
    };
354
    /** cardinality decision strategy */
355
    std::unique_ptr<CardinalityDecisionStrategy> d_c_dec_strat;
356
  }; /** class SortModel */
357
358
 public:
359
  CardinalityExtension(Env& env,
360
                       TheoryState& state,
361
                       TheoryInferenceManager& im,
362
                       TheoryUF* th);
363
  ~CardinalityExtension();
364
  /** get theory */
365
22248
  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
560
  class CombinedCardinalityDecisionStrategy : public DecisionStrategyFmf
437
  {
438
   public:
439
    CombinedCardinalityDecisionStrategy(Env& env, Valuation valuation);
440
    /** make literal (the i^th combined cardinality literal) */
441
    Node mkLiteral(unsigned i) override;
442
    /** identify */
443
    std::string identify() const override;
444
  };
445
  /** combined cardinality decision strategy */
446
  std::unique_ptr<CombinedCardinalityDecisionStrategy> d_cc_dec_strat;
447
  /** Have we initialized combined cardinality? */
448
  context::CDO<bool> d_initializedCombinedCardinality;
449
450
  /** cardinality literals for which we have added */
451
  NodeBoolMap d_card_assertions_eqv_lemma;
452
  /** the master monotone type (if ufssFairnessMonotone enabled) */
453
  TypeNode d_tn_mono_master;
454
  std::map<TypeNode, bool> d_tn_mono_slave;
455
  /** The minimum positive asserted master cardinality */
456
  context::CDO<uint32_t> d_min_pos_tn_master_card;
457
  /** Whether the field above has been set */
458
  context::CDO<bool> d_min_pos_tn_master_card_set;
459
  /** relevant eqc */
460
  NodeBoolMap d_rel_eqc;
461
}; /* class CardinalityExtension */
462
463
}  // namespace uf
464
}  // namespace theory
465
}  // namespace cvc5
466
467
#endif /* CVC5__THEORY_UF_STRONG_SOLVER_H */