GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/term_database.h Lines: 3 3 100.0 %
Date: 2021-05-22 Branches: 2 4 50.0 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Mathias Preiner
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
 * Term database class.
14
 */
15
16
#include "cvc5_private.h"
17
18
#ifndef CVC5__THEORY__QUANTIFIERS__TERM_DATABASE_H
19
#define CVC5__THEORY__QUANTIFIERS__TERM_DATABASE_H
20
21
#include <map>
22
#include <unordered_map>
23
24
#include "context/cdhashmap.h"
25
#include "context/cdhashset.h"
26
#include "expr/attribute.h"
27
#include "expr/node_trie.h"
28
#include "theory/quantifiers/quant_util.h"
29
#include "theory/theory.h"
30
#include "theory/type_enumerator.h"
31
32
namespace cvc5 {
33
namespace theory {
34
namespace quantifiers {
35
36
class QuantifiersState;
37
class QuantifiersInferenceManager;
38
class QuantifiersRegistry;
39
40
/** Context-dependent list of nodes */
41
117588
class DbList
42
{
43
 public:
44
117588
  DbList(context::Context* c) : d_list(c) {}
45
  /** The list */
46
  context::CDList<Node> d_list;
47
};
48
49
/** Term Database
50
 *
51
 * This class is a key utility used by
52
 * a number of approaches for quantifier instantiation,
53
 * including E-matching, conflict-based instantiation,
54
 * and model-based instantiation.
55
 *
56
 * The primary responsibilities for this class are to :
57
 * (1) Maintain a list of all ground terms that exist in the quantifier-free
58
 *     solvers, as notified through the master equality engine.
59
 * (2) Build TNodeTrie objects that index all ground terms, per operator.
60
 *
61
 * Like other utilities, its reset(...) function is called
62
 * at the beginning of full or last call effort checks.
63
 * This initializes the database for the round. However,
64
 * notice that TNodeTrie objects are computed
65
 * lazily for performance reasons.
66
 */
67
class TermDb : public QuantifiersUtil {
68
  using NodeBoolMap = context::CDHashMap<Node, bool>;
69
  using NodeList = context::CDList<Node>;
70
  using NodeSet = context::CDHashSet<Node>;
71
  using TypeNodeDbListMap =
72
      context::CDHashMap<TypeNode, std::shared_ptr<DbList>>;
73
  using NodeDbListMap = context::CDHashMap<Node, std::shared_ptr<DbList>>;
74
75
 public:
76
  TermDb(QuantifiersState& qs,
77
         QuantifiersRegistry& qr);
78
  ~TermDb();
79
  /** Finish init, which sets the inference manager */
80
  void finishInit(QuantifiersInferenceManager* qim);
81
  /** presolve (called once per user check-sat) */
82
  void presolve();
83
  /** reset (calculate which terms are active) */
84
  bool reset(Theory::Effort effort) override;
85
  /** register quantified formula */
86
  void registerQuantifier(Node q) override;
87
  /** identify */
88
24825
  std::string identify() const override { return "TermDb"; }
89
  /** get number of operators */
90
  size_t getNumOperators() const;
91
  /** get operator at index i */
92
  Node getOperator(size_t i) const;
93
  /** ground terms for operator
94
  * Get the number of ground terms with operator f that have been added to the
95
  * database
96
  */
97
  size_t getNumGroundTerms(Node f) const;
98
  /** get ground term for operator
99
  * Get the i^th ground term with operator f that has been added to the database
100
  */
101
  Node getGroundTerm(Node f, size_t i) const;
102
  /** get num type terms
103
  * Get the number of ground terms of tn that have been added to the database
104
  */
105
  size_t getNumTypeGroundTerms(TypeNode tn) const;
106
  /** get type ground term
107
  * Returns the i^th ground term of type tn
108
  */
109
  Node getTypeGroundTerm(TypeNode tn, size_t i) const;
110
  /** get or make ground term
111
   *
112
   * Returns the first ground term of type tn, or makes one if none exist. If
113
   * reqVar is true, then the ground term must be a variable.
114
   */
115
  Node getOrMakeTypeGroundTerm(TypeNode tn, bool reqVar = false);
116
  /** make fresh variable
117
  * Returns a fresh variable of type tn.
118
  * This will return only a single fresh
119
  * variable per type.
120
  */
121
  Node getOrMakeTypeFreshVariable(TypeNode tn);
122
  /**
123
   * Add a term to the database, which registers it as a term that may be
124
   * matched with via E-matching, and can be used in entailment tests below.
125
   */
126
  void addTerm(Node n);
127
  /** Get the currently added ground terms of the given type */
128
  DbList* getOrMkDbListForType(TypeNode tn);
129
  /** Get the currently added ground terms for the given operator */
130
  DbList* getOrMkDbListForOp(TNode op);
131
  /** get match operator for term n
132
  *
133
  * If n has a kind that we index, this function will
134
  * typically return n.getOperator().
135
  *
136
  * However, for parametric operators f, the match operator is an arbitrary
137
  * chosen f-application.  For example, consider array select:
138
  * A : (Array Int Int)
139
  * B : (Array Bool Int)
140
  * We require that terms like (select A 1) and (select B 2) are indexed in
141
  * separate
142
  * data structures despite the fact that
143
  *    (select A 1).getOperator()==(select B 2).getOperator().
144
  * Hence, for the above terms, we may return:
145
  * getMatchOperator( (select A 1) ) = (select A 1), and
146
  * getMatchOperator( (select B 2) ) = (select B 2).
147
  * The match operator is the first instance of an application of the parametric
148
  * operator of its type.
149
  *
150
  * If n has a kind that we do not index (like PLUS),
151
  * then this function returns Node::null().
152
  */
153
  Node getMatchOperator(Node n);
154
  /** get term arg index for all f-applications in the current context */
155
  TNodeTrie* getTermArgTrie(Node f);
156
  /** get the term arg trie for f-applications in the equivalence class of eqc.
157
   */
158
  TNodeTrie* getTermArgTrie(Node eqc, Node f);
159
  /** get congruent term
160
  * If possible, returns a term t such that:
161
  * (1) t is a term that is currently indexed by this database,
162
  * (2) t is of the form f( t1, ..., tk ) and n is of the form f( s1, ..., sk ),
163
  *     where ti is in the equivalence class of si for i=1...k.
164
  */
165
  TNode getCongruentTerm(Node f, Node n);
166
  /** get congruent term
167
  * If possible, returns a term t such that:
168
  * (1) t is a term that is currently indexed by this database,
169
  * (2) t is of the form f( t1, ..., tk ) where ti is in the
170
  *     equivalence class of args[i] for i=1...k.
171
  */
172
  TNode getCongruentTerm(Node f, std::vector<TNode>& args);
173
  /** in relevant domain
174
  * Returns true if there is at least one term t such that:
175
  * (1) t is a term that is currently indexed by this database,
176
  * (2) t is of the form f( t1, ..., tk ) and ti is in the
177
  *     equivalence class of r.
178
  */
179
  bool inRelevantDomain(TNode f, unsigned i, TNode r);
180
  /** evaluate term
181
   *
182
   * Returns a term n' such that n = n' is entailed based on the equality
183
   * information ee.  This function may generate new terms. In particular,
184
   * we typically rewrite subterms of n of maximal size to terms that exist in
185
   * the equality engine specified by ee.
186
   *
187
   * useEntailmentTests is whether to call the theory engine's entailmentTest
188
   * on literals n for which this call fails to find a term n' that is
189
   * equivalent to n, for increased precision. This is not frequently used.
190
   *
191
   * The vector exp stores the explanation for why n evaluates to that term,
192
   * that is, if this call returns a non-null node n', then:
193
   *   exp => n = n'
194
   *
195
   * If reqHasTerm, then we require that the returned term is a Boolean
196
   * combination of terms that exist in the equality engine used by this call.
197
   * If no such term is constructable, this call returns null. The motivation
198
   * for setting this to true is to "fail fast" if we require the return value
199
   * of this function to only involve existing terms. This is used e.g. in
200
   * the "propagating instances" portion of conflict-based instantiation
201
   * (quant_conflict_find.h).
202
   */
203
  Node evaluateTerm(TNode n,
204
                    std::vector<Node>& exp,
205
                    bool useEntailmentTests = false,
206
                    bool reqHasTerm = false);
207
  /** same as above, without exp */
208
  Node evaluateTerm(TNode n,
209
                    bool useEntailmentTests = false,
210
                    bool reqHasTerm = false);
211
  /** get entailed term
212
   *
213
   * If possible, returns a term n' such that:
214
   * (1) n' exists in the current equality engine (as specified by the state),
215
   * (2) n = n' is entailed in the current context.
216
   * It returns null if no such term can be found.
217
   * Wrt evaluateTerm, this version does not construct new terms, and
218
   * thus is less aggressive.
219
   */
220
  TNode getEntailedTerm(TNode n);
221
  /** get entailed term
222
   *
223
   * If possible, returns a term n' such that:
224
   * (1) n' exists in the current equality engine (as specified by the state),
225
   * (2) n * subs = n' is entailed in the current context, where * denotes
226
   * substitution application.
227
   * It returns null if no such term can be found.
228
   * subsRep is whether the substitution maps to terms that are representatives
229
   * according to the quantifiers state.
230
   * Wrt evaluateTerm, this version does not construct new terms, and
231
   * thus is less aggressive.
232
   */
233
  TNode getEntailedTerm(TNode n, std::map<TNode, TNode>& subs, bool subsRep);
234
  /** is entailed
235
   * Checks whether the current context entails n with polarity pol, based on
236
   * the equality information in the quantifiers state. Returns true if the
237
   * entailment can be successfully shown.
238
   */
239
  bool isEntailed(TNode n, bool pol);
240
  /** is entailed
241
   *
242
   * Checks whether the current context entails ( n * subs ) with polarity pol,
243
   * based on the equality information in the quantifiers state,
244
   * where * denotes substitution application.
245
   * subsRep is whether the substitution maps to terms that are representatives
246
   * according to in the quantifiers state.
247
   */
248
  bool isEntailed(TNode n,
249
                  std::map<TNode, TNode>& subs,
250
                  bool subsRep,
251
                  bool pol);
252
  /** is the term n active in the current context?
253
   *
254
  * By default, all terms are active. A term is inactive if:
255
  * (1) it is congruent to another term
256
  * (2) it is irrelevant based on the term database mode. This includes terms
257
  * that only appear in literals that are not relevant.
258
  * (3) it contains instantiation constants (used for CEGQI and cannot be used
259
  * in instantiation).
260
  * (4) it is explicitly set inactive by a call to setTermInactive(...).
261
  * We store whether a term is inactive in a SAT-context-dependent map.
262
  */
263
  bool isTermActive(Node n);
264
  /** set that term n is inactive in this context. */
265
  void setTermInactive(Node n);
266
  /** has term current
267
   *
268
   * This function is used in cases where we restrict which terms appear in the
269
   * database, such as for heuristics used in local theory extensions
270
   * and for --term-db-mode=relevant.
271
   * It returns whether the term n should be indexed in the current context.
272
   *
273
   * If the argument useMode is true, then this method returns a value based on
274
   * the option options::termDbMode().
275
   * Otherwise, it returns the lookup in the map d_has_map.
276
   */
277
  bool hasTermCurrent(Node n, bool useMode = true);
278
  /** is term eligble for instantiation? */
279
  bool isTermEligibleForInstantiation(TNode n, TNode f);
280
  /** get eligible term in equivalence class of r */
281
  Node getEligibleTermInEqc(TNode r);
282
  /** get higher-order type match predicate
283
   *
284
   * This predicate is used to force certain functions f of type tn to appear as
285
   * first-class representatives in the quantifier-free UF solver. For a typical
286
   * use case, we call getHoTypeMatchPredicate which returns a fresh predicate
287
   * P of type (tn -> Bool). Then, we add P( f ) as a lemma.
288
   */
289
  Node getHoTypeMatchPredicate(TypeNode tn);
290
291
 private:
292
  /** The quantifiers state object */
293
  QuantifiersState& d_qstate;
294
  /** Pointer to the quantifiers inference manager */
295
  QuantifiersInferenceManager* d_qim;
296
  /** The quantifiers registry */
297
  QuantifiersRegistry& d_qreg;
298
  /** A context for the data structures below, when not context-dependent */
299
  context::Context d_termsContext;
300
  /** The context we are using for the data structures below */
301
  context::Context* d_termsContextUse;
302
  /** terms processed */
303
  NodeSet d_processed;
304
  /** map from types to ground terms for that type */
305
  TypeNodeDbListMap d_typeMap;
306
  /** list of all operators */
307
  NodeList d_ops;
308
  /** map from operators to ground terms for that operator */
309
  NodeDbListMap d_opMap;
310
  /** select op map */
311
  std::map< Node, std::map< TypeNode, Node > > d_par_op_map;
312
  /** whether master equality engine is UF-inconsistent */
313
  bool d_consistent_ee;
314
  /** boolean terms */
315
  Node d_true;
316
  Node d_false;
317
  /** map from type nodes to a fresh variable we introduced */
318
  std::unordered_map<TypeNode, Node> d_type_fv;
319
  /** inactive map */
320
  NodeBoolMap d_inactive_map;
321
  /** count of the number of non-redundant ground terms per operator */
322
  std::map< Node, int > d_op_nonred_count;
323
  /** mapping from terms to representatives of their arguments */
324
  std::map< TNode, std::vector< TNode > > d_arg_reps;
325
  /** map from operators to trie */
326
  std::map<Node, TNodeTrie> d_func_map_trie;
327
  std::map<Node, TNodeTrie> d_func_map_eqc_trie;
328
  /** mapping from operators to their representative relevant domains */
329
  std::map< Node, std::map< unsigned, std::vector< Node > > > d_func_map_rel_dom;
330
  /** has map */
331
  std::map< Node, bool > d_has_map;
332
  /** map from reps to a term in eqc in d_has_map */
333
  std::map<Node, Node> d_term_elig_eqc;
334
  /**
335
   * Dummy predicate that states terms should be considered first-class members
336
   * of equality engine (for higher-order).
337
   */
338
  std::map<TypeNode, Node> d_ho_type_match_pred;
339
  /** set has term */
340
  void setHasTerm( Node n );
341
  /** helper for evaluate term */
342
  Node evaluateTerm2(TNode n,
343
                     std::map<TNode, Node>& visited,
344
                     std::vector<Node>& exp,
345
                     bool useEntailmentTests,
346
                     bool computeExp,
347
                     bool reqHasTerm);
348
  /** helper for get entailed term */
349
  TNode getEntailedTerm2(TNode n,
350
                         std::map<TNode, TNode>& subs,
351
                         bool subsRep,
352
                         bool hasSubs);
353
  /** helper for is entailed */
354
  bool isEntailed2(TNode n,
355
                   std::map<TNode, TNode>& subs,
356
                   bool subsRep,
357
                   bool hasSubs,
358
                   bool pol);
359
  /** compute uf eqc terms :
360
  * Ensure entries for f are in d_func_map_eqc_trie for all equivalence classes
361
  */
362
  void computeUfEqcTerms( TNode f );
363
  /** compute uf terms
364
  * Ensure that an entry for f is in d_func_map_trie
365
  */
366
  void computeUfTerms( TNode f );
367
  /** compute arg reps
368
  * Ensure that an entry for n is in d_arg_reps
369
  */
370
  void computeArgReps(TNode n);
371
  //------------------------------higher-order term indexing
372
  /**
373
   * Map from non-variable function terms to the operator used to purify it in
374
   * this database. For details, see addTermHo.
375
   */
376
  std::map<Node, Node> d_ho_fun_op_purify;
377
  /**
378
   * Map from terms to the term that they purified. For details, see addTermHo.
379
   */
380
  std::map<Node, Node> d_ho_purify_to_term;
381
  /**
382
   * Map from terms in the domain of the above map to an equality between that
383
   * term and its range in the above map.
384
   */
385
  std::map<Node, Node> d_ho_purify_to_eq;
386
  /** a map from matchable operators to their representative */
387
  std::map< TNode, TNode > d_ho_op_rep;
388
  /** for each representative matchable operator, the list of other matchable operators in their equivalence class */
389
  std::map<TNode, std::vector<TNode> > d_ho_op_slaves;
390
  /** add term higher-order
391
   *
392
   * This registers additional terms corresponding to (possibly multiple)
393
   * purifications of a higher-order term n.
394
   *
395
   * Consider the example:
396
   *    g : Int -> Int, f : Int x Int -> Int
397
   *    constraints: (@ f 0) = g, (f 0 1) = (@ (@ f 0) 1) = 3
398
   *    pattern: (g x)
399
   * where @ is HO_APPLY.
400
   * We have that (g x){ x -> 1 } is an E-match for (@ (@ f 0) 1).
401
   * With the standard registration in addTerm, we construct term indices for
402
   *   f, g, @ : Int x Int -> Int, @ : Int -> Int.
403
   * However, to match (g x) with (@ (@ f 0) 1), we require that
404
   *   [1] -> (@ (@ f 0) 1)
405
   * is an entry in the term index of g. To do this, we maintain a term
406
   * index for a fresh variable pfun, the purification variable for
407
   * (@ f 0). Thus, we register the term (pfun 1) in the call to this function
408
   * for (@ (@ f 0) 1). This ensures that, when processing the equality
409
   * (@ f 0) = g, we merge the term indices of g and pfun. Hence, the entry
410
   *   [1] -> (@ (@ f 0) 1)
411
   * is added to the term index of g, assuming g is the representative of
412
   * the equivalence class of g and pfun.
413
   *
414
   * Above, we set d_ho_fun_op_purify[(@ f 0)] = pfun, and
415
   * d_ho_purify_to_term[(pfun 1)] = (@ (@ f 0) 1).
416
   */
417
  void addTermHo(Node n);
418
  /** get operator representative */
419
  Node getOperatorRepresentative( TNode op ) const;
420
  //------------------------------end higher-order term indexing
421
};/* class TermDb */
422
423
}  // namespace quantifiers
424
}  // namespace theory
425
}  // namespace cvc5
426
427
#endif /* CVC5__THEORY__QUANTIFIERS__TERM_DATABASE_H */