GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/term_database.h Lines: 3 3 100.0 %
Date: 2021-09-17 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
118897
class DbList
42
{
43
 public:
44
118897
  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(Env& env, QuantifiersState& qs, QuantifiersRegistry& qr);
77
  virtual ~TermDb();
78
  /** Finish init, which sets the inference manager */
79
  void finishInit(QuantifiersInferenceManager* qim);
80
  /** presolve (called once per user check-sat) */
81
  void presolve() override;
82
  /** reset (calculate which terms are active) */
83
  bool reset(Theory::Effort effort) override;
84
  /** register quantified formula */
85
  void registerQuantifier(Node q) override;
86
  /** identify */
87
27175
  std::string identify() const override { return "TermDb"; }
88
  /** get number of operators */
89
  size_t getNumOperators() const;
90
  /** get operator at index i */
91
  Node getOperator(size_t i) const;
92
  /** ground terms for operator
93
  * Get the number of ground terms with operator f that have been added to the
94
  * database
95
  */
96
  size_t getNumGroundTerms(Node f) const;
97
  /** get ground term for operator
98
  * Get the i^th ground term with operator f that has been added to the database
99
  */
100
  Node getGroundTerm(Node f, size_t i) const;
101
  /** get num type terms
102
  * Get the number of ground terms of tn that have been added to the database
103
  */
104
  size_t getNumTypeGroundTerms(TypeNode tn) const;
105
  /** get type ground term
106
  * Returns the i^th ground term of type tn
107
  */
108
  Node getTypeGroundTerm(TypeNode tn, size_t i) const;
109
  /** get or make ground term
110
   *
111
   * Returns the first ground term of type tn, or makes one if none exist. If
112
   * reqVar is true, then the ground term must be a variable.
113
   */
114
  Node getOrMakeTypeGroundTerm(TypeNode tn, bool reqVar = false);
115
  /** make fresh variable
116
  * Returns a fresh variable of type tn.
117
  * This will return only a single fresh
118
  * variable per type.
119
  */
120
  Node getOrMakeTypeFreshVariable(TypeNode tn);
121
  /**
122
   * Add a term to the database, which registers it as a term that may be
123
   * matched with via E-matching, and can be used in entailment tests below.
124
   */
125
  void addTerm(Node n);
126
  /** Get the currently added ground terms of the given type */
127
  DbList* getOrMkDbListForType(TypeNode tn);
128
  /** Get the currently added ground terms for the given operator */
129
  DbList* getOrMkDbListForOp(TNode op);
130
  /** get match operator for term n
131
  *
132
  * If n has a kind that we index, this function will
133
  * typically return n.getOperator().
134
  *
135
  * However, for parametric operators f, the match operator is an arbitrary
136
  * chosen f-application.  For example, consider array select:
137
  * A : (Array Int Int)
138
  * B : (Array Bool Int)
139
  * We require that terms like (select A 1) and (select B 2) are indexed in
140
  * separate
141
  * data structures despite the fact that
142
  *    (select A 1).getOperator()==(select B 2).getOperator().
143
  * Hence, for the above terms, we may return:
144
  * getMatchOperator( (select A 1) ) = (select A 1), and
145
  * getMatchOperator( (select B 2) ) = (select B 2).
146
  * The match operator is the first instance of an application of the parametric
147
  * operator of its type.
148
  *
149
  * If n has a kind that we do not index (like PLUS),
150
  * then this function returns Node::null().
151
  */
152
  Node getMatchOperator(Node n);
153
  /** get term arg index for all f-applications in the current context */
154
  TNodeTrie* getTermArgTrie(Node f);
155
  /** get the term arg trie for f-applications in the equivalence class of eqc.
156
   */
157
  TNodeTrie* getTermArgTrie(Node eqc, Node f);
158
  /** get congruent term
159
  * If possible, returns a term t such that:
160
  * (1) t is a term that is currently indexed by this database,
161
  * (2) t is of the form f( t1, ..., tk ) and n is of the form f( s1, ..., sk ),
162
  *     where ti is in the equivalence class of si for i=1...k.
163
  */
164
  TNode getCongruentTerm(Node f, Node n);
165
  /** get congruent term
166
  * If possible, returns a term t such that:
167
  * (1) t is a term that is currently indexed by this database,
168
  * (2) t is of the form f( t1, ..., tk ) where ti is in the
169
  *     equivalence class of args[i] for i=1...k.
170
  */
171
  TNode getCongruentTerm(Node f, std::vector<TNode>& args);
172
  /** in relevant domain
173
  * Returns true if there is at least one term t such that:
174
  * (1) t is a term that is currently indexed by this database,
175
  * (2) t is of the form f( t1, ..., tk ) and ti is in the
176
  *     equivalence class of r.
177
  */
178
  bool inRelevantDomain(TNode f, unsigned i, TNode r);
179
  /** evaluate term
180
   *
181
   * Returns a term n' such that n = n' is entailed based on the equality
182
   * information ee.  This function may generate new terms. In particular,
183
   * we typically rewrite subterms of n of maximal size to terms that exist in
184
   * the equality engine specified by ee.
185
   *
186
   * useEntailmentTests is whether to call the theory engine's entailmentTest
187
   * on literals n for which this call fails to find a term n' that is
188
   * equivalent to n, for increased precision. This is not frequently used.
189
   *
190
   * The vector exp stores the explanation for why n evaluates to that term,
191
   * that is, if this call returns a non-null node n', then:
192
   *   exp => n = n'
193
   *
194
   * If reqHasTerm, then we require that the returned term is a Boolean
195
   * combination of terms that exist in the equality engine used by this call.
196
   * If no such term is constructable, this call returns null. The motivation
197
   * for setting this to true is to "fail fast" if we require the return value
198
   * of this function to only involve existing terms. This is used e.g. in
199
   * the "propagating instances" portion of conflict-based instantiation
200
   * (quant_conflict_find.h).
201
   */
202
  Node evaluateTerm(TNode n,
203
                    std::vector<Node>& exp,
204
                    bool useEntailmentTests = false,
205
                    bool reqHasTerm = false);
206
  /** same as above, without exp */
207
  Node evaluateTerm(TNode n,
208
                    bool useEntailmentTests = false,
209
                    bool reqHasTerm = false);
210
  /** get entailed term
211
   *
212
   * If possible, returns a term n' such that:
213
   * (1) n' exists in the current equality engine (as specified by the state),
214
   * (2) n = n' is entailed in the current context.
215
   * It returns null if no such term can be found.
216
   * Wrt evaluateTerm, this version does not construct new terms, and
217
   * thus is less aggressive.
218
   */
219
  TNode getEntailedTerm(TNode n);
220
  /** get entailed term
221
   *
222
   * If possible, returns a term n' such that:
223
   * (1) n' exists in the current equality engine (as specified by the state),
224
   * (2) n * subs = n' is entailed in the current context, where * denotes
225
   * substitution application.
226
   * It returns null if no such term can be found.
227
   * subsRep is whether the substitution maps to terms that are representatives
228
   * according to the quantifiers state.
229
   * Wrt evaluateTerm, this version does not construct new terms, and
230
   * thus is less aggressive.
231
   */
232
  TNode getEntailedTerm(TNode n, std::map<TNode, TNode>& subs, bool subsRep);
233
  /** is entailed
234
   * Checks whether the current context entails n with polarity pol, based on
235
   * the equality information in the quantifiers state. Returns true if the
236
   * entailment can be successfully shown.
237
   */
238
  bool isEntailed(TNode n, bool pol);
239
  /** is entailed
240
   *
241
   * Checks whether the current context entails ( n * subs ) with polarity pol,
242
   * based on the equality information in the quantifiers state,
243
   * where * denotes substitution application.
244
   * subsRep is whether the substitution maps to terms that are representatives
245
   * according to in the quantifiers state.
246
   */
247
  bool isEntailed(TNode n,
248
                  std::map<TNode, TNode>& subs,
249
                  bool subsRep,
250
                  bool pol);
251
  /** is the term n active in the current context?
252
   *
253
  * By default, all terms are active. A term is inactive if:
254
  * (1) it is congruent to another term
255
  * (2) it is irrelevant based on the term database mode. This includes terms
256
  * that only appear in literals that are not relevant.
257
  * (3) it contains instantiation constants (used for CEGQI and cannot be used
258
  * in instantiation).
259
  * (4) it is explicitly set inactive by a call to setTermInactive(...).
260
  * We store whether a term is inactive in a SAT-context-dependent map.
261
  */
262
  bool isTermActive(Node n);
263
  /** set that term n is inactive in this context. */
264
  void setTermInactive(Node n);
265
  /** has term current
266
   *
267
   * This function is used in cases where we restrict which terms appear in the
268
   * database, such as for heuristics used in local theory extensions
269
   * and for --term-db-mode=relevant.
270
   * It returns whether the term n should be indexed in the current context.
271
   *
272
   * If the argument useMode is true, then this method returns a value based on
273
   * the option options::termDbMode().
274
   * Otherwise, it returns the lookup in the map d_has_map.
275
   */
276
  bool hasTermCurrent(Node n, bool useMode = true);
277
  /** is term eligble for instantiation? */
278
  bool isTermEligibleForInstantiation(TNode n, TNode f);
279
  /** get eligible term in equivalence class of r */
280
  Node getEligibleTermInEqc(TNode r);
281
282
 protected:
283
  /** The quantifiers state object */
284
  QuantifiersState& d_qstate;
285
  /** Pointer to the quantifiers inference manager */
286
  QuantifiersInferenceManager* d_qim;
287
  /** The quantifiers registry */
288
  QuantifiersRegistry& d_qreg;
289
  /** A context for the data structures below, when not context-dependent */
290
  context::Context d_termsContext;
291
  /** The context we are using for the data structures below */
292
  context::Context* d_termsContextUse;
293
  /** terms processed */
294
  NodeSet d_processed;
295
  /** map from types to ground terms for that type */
296
  TypeNodeDbListMap d_typeMap;
297
  /** list of all operators */
298
  NodeList d_ops;
299
  /** map from operators to ground terms for that operator */
300
  NodeDbListMap d_opMap;
301
  /** select op map */
302
  std::map< Node, std::map< TypeNode, Node > > d_par_op_map;
303
  /** whether master equality engine is UF-inconsistent */
304
  bool d_consistent_ee;
305
  /** boolean terms */
306
  Node d_true;
307
  Node d_false;
308
  /** map from type nodes to a fresh variable we introduced */
309
  std::unordered_map<TypeNode, Node> d_type_fv;
310
  /** inactive map */
311
  NodeBoolMap d_inactive_map;
312
  /** count of the number of non-redundant ground terms per operator */
313
  std::map< Node, int > d_op_nonred_count;
314
  /** mapping from terms to representatives of their arguments */
315
  std::map< TNode, std::vector< TNode > > d_arg_reps;
316
  /** map from operators to trie */
317
  std::map<Node, TNodeTrie> d_func_map_trie;
318
  std::map<Node, TNodeTrie> d_func_map_eqc_trie;
319
  /** mapping from operators to their representative relevant domains */
320
  std::map< Node, std::map< unsigned, std::vector< Node > > > d_func_map_rel_dom;
321
  /** has map */
322
  std::map< Node, bool > d_has_map;
323
  /** map from reps to a term in eqc in d_has_map */
324
  std::map<Node, Node> d_term_elig_eqc;
325
  /**
326
   * Dummy predicate that states terms should be considered first-class members
327
   * of equality engine (for higher-order).
328
   */
329
  std::map<TypeNode, Node> d_ho_type_match_pred;
330
  //----------------------------- implementation-specific
331
  /**
332
   * Reset internal, called when reset(e) is called. Returning false will cause
333
   * the overall reset to terminate early, returning false.
334
   */
335
  virtual bool resetInternal(Theory::Effort e);
336
  /**
337
   * Finish reset internal, called at the end of reset(e). Returning false will
338
   * cause the overall reset to return false.
339
   */
340
  virtual bool finishResetInternal(Theory::Effort e);
341
  /** Add term internal, called when addTerm(n) is called */
342
  virtual void addTermInternal(Node n);
343
  /** Get operators that we know are equivalent to f, typically only f itself */
344
  virtual void getOperatorsFor(TNode f, std::vector<TNode>& ops);
345
  /** get the chosen representative for operator op */
346
  virtual Node getOperatorRepresentative(TNode op) const;
347
  /**
348
   * This method is called when terms a and b are indexed by the same operator,
349
   * and have equivalent arguments. This method checks if we are in conflict,
350
   * which is the case if a and b are disequal in the equality engine.
351
   * If so, it adds the set of literals that are implied but do not hold, e.g.
352
   * the equality (= a b).
353
   */
354
  virtual bool checkCongruentDisequal(TNode a, TNode b, std::vector<Node>& exp);
355
  //----------------------------- end implementation-specific
356
  /** set has term */
357
  void setHasTerm( Node n );
358
  /** helper for evaluate term */
359
  Node evaluateTerm2(TNode n,
360
                     std::map<TNode, Node>& visited,
361
                     std::vector<Node>& exp,
362
                     bool useEntailmentTests,
363
                     bool computeExp,
364
                     bool reqHasTerm);
365
  /** helper for get entailed term */
366
  TNode getEntailedTerm2(TNode n,
367
                         std::map<TNode, TNode>& subs,
368
                         bool subsRep,
369
                         bool hasSubs);
370
  /** helper for is entailed */
371
  bool isEntailed2(TNode n,
372
                   std::map<TNode, TNode>& subs,
373
                   bool subsRep,
374
                   bool hasSubs,
375
                   bool pol);
376
  /** compute uf eqc terms :
377
  * Ensure entries for f are in d_func_map_eqc_trie for all equivalence classes
378
  */
379
  void computeUfEqcTerms( TNode f );
380
  /** compute uf terms
381
  * Ensure that an entry for f is in d_func_map_trie
382
  */
383
  void computeUfTerms( TNode f );
384
  /** compute arg reps
385
  * Ensure that an entry for n is in d_arg_reps
386
  */
387
  void computeArgReps(TNode n);
388
};/* class TermDb */
389
390
}  // namespace quantifiers
391
}  // namespace theory
392
}  // namespace cvc5
393
394
#endif /* CVC5__THEORY__QUANTIFIERS__TERM_DATABASE_H */