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 |
120504 |
class DbList |
42 |
|
{ |
43 |
|
public: |
44 |
120504 |
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 |
|
virtual ~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() override; |
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 |
27559 |
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 |
|
|
283 |
|
protected: |
284 |
|
/** The quantifiers state object */ |
285 |
|
QuantifiersState& d_qstate; |
286 |
|
/** Pointer to the quantifiers inference manager */ |
287 |
|
QuantifiersInferenceManager* d_qim; |
288 |
|
/** The quantifiers registry */ |
289 |
|
QuantifiersRegistry& d_qreg; |
290 |
|
/** A context for the data structures below, when not context-dependent */ |
291 |
|
context::Context d_termsContext; |
292 |
|
/** The context we are using for the data structures below */ |
293 |
|
context::Context* d_termsContextUse; |
294 |
|
/** terms processed */ |
295 |
|
NodeSet d_processed; |
296 |
|
/** map from types to ground terms for that type */ |
297 |
|
TypeNodeDbListMap d_typeMap; |
298 |
|
/** list of all operators */ |
299 |
|
NodeList d_ops; |
300 |
|
/** map from operators to ground terms for that operator */ |
301 |
|
NodeDbListMap d_opMap; |
302 |
|
/** select op map */ |
303 |
|
std::map< Node, std::map< TypeNode, Node > > d_par_op_map; |
304 |
|
/** whether master equality engine is UF-inconsistent */ |
305 |
|
bool d_consistent_ee; |
306 |
|
/** boolean terms */ |
307 |
|
Node d_true; |
308 |
|
Node d_false; |
309 |
|
/** map from type nodes to a fresh variable we introduced */ |
310 |
|
std::unordered_map<TypeNode, Node> d_type_fv; |
311 |
|
/** inactive map */ |
312 |
|
NodeBoolMap d_inactive_map; |
313 |
|
/** count of the number of non-redundant ground terms per operator */ |
314 |
|
std::map< Node, int > d_op_nonred_count; |
315 |
|
/** mapping from terms to representatives of their arguments */ |
316 |
|
std::map< TNode, std::vector< TNode > > d_arg_reps; |
317 |
|
/** map from operators to trie */ |
318 |
|
std::map<Node, TNodeTrie> d_func_map_trie; |
319 |
|
std::map<Node, TNodeTrie> d_func_map_eqc_trie; |
320 |
|
/** mapping from operators to their representative relevant domains */ |
321 |
|
std::map< Node, std::map< unsigned, std::vector< Node > > > d_func_map_rel_dom; |
322 |
|
/** has map */ |
323 |
|
std::map< Node, bool > d_has_map; |
324 |
|
/** map from reps to a term in eqc in d_has_map */ |
325 |
|
std::map<Node, Node> d_term_elig_eqc; |
326 |
|
/** |
327 |
|
* Dummy predicate that states terms should be considered first-class members |
328 |
|
* of equality engine (for higher-order). |
329 |
|
*/ |
330 |
|
std::map<TypeNode, Node> d_ho_type_match_pred; |
331 |
|
//----------------------------- implementation-specific |
332 |
|
/** |
333 |
|
* Reset internal, called when reset(e) is called. Returning false will cause |
334 |
|
* the overall reset to terminate early, returning false. |
335 |
|
*/ |
336 |
|
virtual bool resetInternal(Theory::Effort e); |
337 |
|
/** |
338 |
|
* Finish reset internal, called at the end of reset(e). Returning false will |
339 |
|
* cause the overall reset to return false. |
340 |
|
*/ |
341 |
|
virtual bool finishResetInternal(Theory::Effort e); |
342 |
|
/** Add term internal, called when addTerm(n) is called */ |
343 |
|
virtual void addTermInternal(Node n); |
344 |
|
/** Get operators that we know are equivalent to f, typically only f itself */ |
345 |
|
virtual void getOperatorsFor(TNode f, std::vector<TNode>& ops); |
346 |
|
/** get the chosen representative for operator op */ |
347 |
|
virtual Node getOperatorRepresentative(TNode op) const; |
348 |
|
/** |
349 |
|
* This method is called when terms a and b are indexed by the same operator, |
350 |
|
* and have equivalent arguments. This method checks if we are in conflict, |
351 |
|
* which is the case if a and b are disequal in the equality engine. |
352 |
|
* If so, it adds the set of literals that are implied but do not hold, e.g. |
353 |
|
* the equality (= a b). |
354 |
|
*/ |
355 |
|
virtual bool checkCongruentDisequal(TNode a, TNode b, std::vector<Node>& exp); |
356 |
|
//----------------------------- end implementation-specific |
357 |
|
/** set has term */ |
358 |
|
void setHasTerm( Node n ); |
359 |
|
/** helper for evaluate term */ |
360 |
|
Node evaluateTerm2(TNode n, |
361 |
|
std::map<TNode, Node>& visited, |
362 |
|
std::vector<Node>& exp, |
363 |
|
bool useEntailmentTests, |
364 |
|
bool computeExp, |
365 |
|
bool reqHasTerm); |
366 |
|
/** helper for get entailed term */ |
367 |
|
TNode getEntailedTerm2(TNode n, |
368 |
|
std::map<TNode, TNode>& subs, |
369 |
|
bool subsRep, |
370 |
|
bool hasSubs); |
371 |
|
/** helper for is entailed */ |
372 |
|
bool isEntailed2(TNode n, |
373 |
|
std::map<TNode, TNode>& subs, |
374 |
|
bool subsRep, |
375 |
|
bool hasSubs, |
376 |
|
bool pol); |
377 |
|
/** compute uf eqc terms : |
378 |
|
* Ensure entries for f are in d_func_map_eqc_trie for all equivalence classes |
379 |
|
*/ |
380 |
|
void computeUfEqcTerms( TNode f ); |
381 |
|
/** compute uf terms |
382 |
|
* Ensure that an entry for f is in d_func_map_trie |
383 |
|
*/ |
384 |
|
void computeUfTerms( TNode f ); |
385 |
|
/** compute arg reps |
386 |
|
* Ensure that an entry for n is in d_arg_reps |
387 |
|
*/ |
388 |
|
void computeArgReps(TNode n); |
389 |
|
};/* class TermDb */ |
390 |
|
|
391 |
|
} // namespace quantifiers |
392 |
|
} // namespace theory |
393 |
|
} // namespace cvc5 |
394 |
|
|
395 |
|
#endif /* CVC5__THEORY__QUANTIFIERS__TERM_DATABASE_H */ |