1 /********************* */
2 /*! \file term_database.h
4 ** Top contributors (to current version):
5 ** Andrew Reynolds, Morgan Deters, Tim King
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2019 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.\endverbatim
12 ** \brief term database class
15 #include "cvc4_private.h"
17 #ifndef CVC4__THEORY__QUANTIFIERS__TERM_DATABASE_H
18 #define CVC4__THEORY__QUANTIFIERS__TERM_DATABASE_H
21 #include <unordered_set>
23 #include "expr/attribute.h"
24 #include "expr/node_trie.h"
25 #include "theory/quantifiers/quant_util.h"
26 #include "theory/theory.h"
27 #include "theory/type_enumerator.h"
32 class QuantifiersEngine
;
36 class HigherOrderTrigger
;
39 namespace quantifiers
{
42 class FullModelChecker
;
46 class QuantConflictFind
;
48 class ConjectureGenerator
;
54 * This class is a key utility used by
55 * a number of approaches for quantifier instantiation,
56 * including E-matching, conflict-based instantiation,
57 * and model-based instantiation.
59 * The primary responsibilities for this class are to :
60 * (1) Maintain a list of all ground terms that exist in the quantifier-free
61 * solvers, as notified through the master equality engine.
62 * (2) Build TNodeTrie objects that index all ground terms, per operator.
64 * Like other utilities, its reset(...) function is called
65 * at the beginning of full or last call effort checks.
66 * This initializes the database for the round. However,
67 * notice that TNodeTrie objects are computed
68 * lazily for performance reasons.
70 class TermDb
: public QuantifiersUtil
{
71 friend class ::CVC4::theory::QuantifiersEngine
;
72 // TODO: eliminate these
73 friend class ::CVC4::theory::quantifiers::ConjectureGenerator
;
74 friend class ::CVC4::theory::quantifiers::TermGenEnv
;
75 typedef context::CDHashMap
<Node
, int, NodeHashFunction
> NodeIntMap
;
76 typedef context::CDHashMap
<Node
, bool, NodeHashFunction
> NodeBoolMap
;
79 TermDb(context::Context
* c
, context::UserContext
* u
, QuantifiersEngine
* qe
);
81 /** presolve (called once per user check-sat) */
83 /** reset (calculate which terms are active) */
84 bool reset(Theory::Effort effort
) override
;
85 /** register quantified formula */
86 void registerQuantifier(Node q
) override
;
88 std::string
identify() const override
{ return "TermDb"; }
89 /** get number of operators */
90 unsigned getNumOperators();
91 /** get operator at index i */
92 Node
getOperator(unsigned i
);
93 /** ground terms for operator
94 * Get the number of ground terms with operator f that have been added to the
97 unsigned 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
101 Node
getGroundTerm(Node f
, unsigned i
) const;
102 /** get num type terms
103 * Get the number of ground terms of tn that have been added to the database
105 unsigned getNumTypeGroundTerms(TypeNode tn
) const;
106 /** get type ground term
107 * Returns the i^th ground term of type tn
109 Node
getTypeGroundTerm(TypeNode tn
, unsigned i
) const;
110 /** get or make ground term
111 * Returns the first ground term of type tn,
112 * or makes one if none exist.
114 Node
getOrMakeTypeGroundTerm(TypeNode tn
);
115 /** make fresh variable
116 * Returns a fresh variable of type tn.
117 * This will return only a single fresh
120 Node
getOrMakeTypeFreshVariable(TypeNode tn
);
121 /** add a term to the database
122 * withinQuant is whether n is within the body of a quantified formula
123 * withinInstClosure is whether n is within an inst-closure operator (see
124 * Bansal et al CAV 2015).
127 std::set
<Node
>& added
,
128 bool withinQuant
= false,
129 bool withinInstClosure
= false);
130 /** get match operator for term n
132 * If n has a kind that we index, this function will
133 * typically return n.getOperator().
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
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.
149 * If n has a kind that we do not index (like PLUS),
150 * then this function returns Node::null().
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.
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.
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.
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.
178 bool inRelevantDomain(TNode f
, unsigned i
, TNode r
);
181 * Returns a term n' such that n = n' is entailed based on the equality
182 * information qy. 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 qy.
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.
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:
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).
202 Node
evaluateTerm(TNode n
,
203 std::vector
<Node
>& exp
,
204 EqualityQuery
* qy
= NULL
,
205 bool useEntailmentTests
= false,
206 bool reqHasTerm
= false);
207 /** same as above, without exp */
208 Node
evaluateTerm(TNode n
,
209 EqualityQuery
* qy
= NULL
,
210 bool useEntailmentTests
= false,
211 bool reqHasTerm
= false);
212 /** get entailed term
214 * If possible, returns a term n' such that:
215 * (1) n' exists in the current equality engine (as specified by qy),
216 * (2) n = n' is entailed in the current context.
217 * It returns null if no such term can be found.
218 * Wrt evaluateTerm, this version does not construct new terms, and
219 * thus is less aggressive.
221 TNode
getEntailedTerm(TNode n
, EqualityQuery
* qy
= NULL
);
222 /** get entailed term
224 * If possible, returns a term n' such that:
225 * (1) n' exists in the current equality engine (as specified by qy),
226 * (2) n * subs = n' is entailed in the current context, where * is denotes
227 * substitution application.
228 * It returns null if no such term can be found.
229 * subsRep is whether the substitution maps to terms that are representatives
231 * Wrt evaluateTerm, this version does not construct new terms, and
232 * thus is less aggressive.
234 TNode
getEntailedTerm(TNode n
,
235 std::map
<TNode
, TNode
>& subs
,
237 EqualityQuery
* qy
= NULL
);
239 * Checks whether the current context entails n with polarity pol, based on the
240 * equality information qy.
241 * Returns true if the entailment can be successfully shown.
243 bool isEntailed(TNode n
, bool pol
, EqualityQuery
* qy
= NULL
);
246 * Checks whether the current context entails ( n * subs ) with polarity pol,
247 * based on the equality information qy,
248 * where * denotes substitution application.
249 * subsRep is whether the substitution maps to terms that are representatives
252 bool isEntailed(TNode n
,
253 std::map
<TNode
, TNode
>& subs
,
256 EqualityQuery
* qy
= NULL
);
257 /** is the term n active in the current context?
259 * By default, all terms are active. A term is inactive if:
260 * (1) it is congruent to another term
261 * (2) it is irrelevant based on the term database mode. This includes terms
262 * that only appear in literals that are not relevant.
263 * (3) it contains instantiation constants (used for CEGQI and cannot be used
265 * (4) it is explicitly set inactive by a call to setTermInactive(...).
266 * We store whether a term is inactive in a SAT-context-dependent map.
268 bool isTermActive(Node n
);
269 /** set that term n is inactive in this context. */
270 void setTermInactive(Node n
);
273 * This function is used in cases where we restrict which terms appear in the
274 * database, such as for heuristics used in local theory extensions
275 * and for --term-db-mode=relevant.
276 * It returns whether the term n should be indexed in the current context.
278 bool hasTermCurrent(Node n
, bool useMode
= true);
279 /** is term eligble for instantiation? */
280 bool isTermEligibleForInstantiation(TNode n
, TNode f
, bool print
= false);
281 /** get eligible term in equivalence class of r */
282 Node
getEligibleTermInEqc(TNode r
);
283 /** is r a inst closure node?
284 * This terminology was used for specifying
285 * a particular status of nodes for
286 * Bansal et al., CAV 2015.
288 bool isInstClosure(Node r
);
291 /** reference to the quantifiers engine */
292 QuantifiersEngine
* d_quantEngine
;
293 /** terms processed */
294 std::unordered_set
< Node
, NodeHashFunction
> d_processed
;
295 /** terms processed */
296 std::unordered_set
< Node
, NodeHashFunction
> d_iclosure_processed
;
298 std::map
< Node
, std::map
< TypeNode
, Node
> > d_par_op_map
;
299 /** whether master equality engine is UF-inconsistent */
300 bool d_consistent_ee
;
304 /** list of all operators */
305 std::vector
<Node
> d_ops
;
306 /** map from operators to ground terms for that operator */
307 std::map
< Node
, std::vector
< Node
> > d_op_map
;
308 /** map from type nodes to terms of that type */
309 std::map
< TypeNode
, std::vector
< Node
> > d_type_map
;
310 /** map from type nodes to a fresh variable we introduced */
311 std::unordered_map
<TypeNode
, Node
, TypeNodeHashFunction
> d_type_fv
;
313 NodeBoolMap d_inactive_map
;
314 /** count of the number of non-redundant ground terms per operator */
315 std::map
< Node
, int > d_op_nonred_count
;
316 /** mapping from terms to representatives of their arguments */
317 std::map
< TNode
, std::vector
< TNode
> > d_arg_reps
;
318 /** map from operators to trie */
319 std::map
<Node
, TNodeTrie
> d_func_map_trie
;
320 std::map
<Node
, TNodeTrie
> d_func_map_eqc_trie
;
321 /** mapping from operators to their representative relevant domains */
322 std::map
< Node
, std::map
< unsigned, std::vector
< Node
> > > d_func_map_rel_dom
;
324 std::map
< Node
, bool > d_has_map
;
325 /** map from reps to a term in eqc in d_has_map */
326 std::map
< Node
, Node
> d_term_elig_eqc
;
328 void setHasTerm( Node n
);
329 /** helper for evaluate term */
330 Node
evaluateTerm2(TNode n
,
331 std::map
<TNode
, Node
>& visited
,
332 std::vector
<Node
>& exp
,
334 bool useEntailmentTests
,
337 /** helper for get entailed term */
338 TNode
getEntailedTerm2( TNode n
, std::map
< TNode
, TNode
>& subs
, bool subsRep
, bool hasSubs
, EqualityQuery
* qy
);
339 /** helper for is entailed */
340 bool isEntailed2( TNode n
, std::map
< TNode
, TNode
>& subs
, bool subsRep
, bool hasSubs
, bool pol
, EqualityQuery
* qy
);
341 /** compute uf eqc terms :
342 * Ensure entries for f are in d_func_map_eqc_trie for all equivalence classes
344 void computeUfEqcTerms( TNode f
);
346 * Ensure that an entry for f is in d_func_map_trie
348 void computeUfTerms( TNode f
);
350 * Ensure that an entry for n is in d_arg_reps
352 void computeArgReps(TNode n
);
353 //------------------------------higher-order term indexing
355 * Map from non-variable function terms to the operator used to purify it in
356 * this database. For details, see addTermHo.
358 std::map
<Node
, Node
> d_ho_fun_op_purify
;
360 * Map from terms to the term that they purified. For details, see addTermHo.
362 std::map
<Node
, Node
> d_ho_purify_to_term
;
364 * Map from terms in the domain of the above map to an equality between that
365 * term and its range in the above map.
367 std::map
<Node
, Node
> d_ho_purify_to_eq
;
368 /** a map from matchable operators to their representative */
369 std::map
< TNode
, TNode
> d_ho_op_rep
;
370 /** for each representative matchable operator, the list of other matchable operators in their equivalence class */
371 std::map
<TNode
, std::vector
<TNode
> > d_ho_op_slaves
;
372 /** add term higher-order
374 * This registers additional terms corresponding to (possibly multiple)
375 * purifications of a higher-order term n.
377 * Consider the example:
378 * g : Int -> Int, f : Int x Int -> Int
379 * constraints: (@ f 0) = g, (f 0 1) = (@ (@ f 0) 1) = 3
381 * where @ is HO_APPLY.
382 * We have that (g x){ x -> 1 } is an E-match for (@ (@ f 0) 1).
383 * With the standard registration in addTerm, we construct term indices for
384 * f, g, @ : Int x Int -> Int, @ : Int -> Int.
385 * However, to match (g x) with (@ (@ f 0) 1), we require that
386 * [1] -> (@ (@ f 0) 1)
387 * is an entry in the term index of g. To do this, we maintain a term
388 * index for a fresh variable pfun, the purification variable for
389 * (@ f 0). Thus, we register the term (psk 1) in the call to this function
390 * for (@ (@ f 0) 1). This ensures that, when processing the equality
391 * (@ f 0) = g, we merge the term indices of g and pfun. Hence, the entry
392 * [1] -> (@ (@ f 0) 1)
393 * is added to the term index of g, assuming g is the representative of
394 * the equivalence class of g and pfun.
396 * Above, we set d_ho_fun_op_purify[(@ f 0)] = pfun, and
397 * d_ho_purify_to_term[(@ (@ f 0) 1)] = (psk 1).
399 void addTermHo(Node n
,
400 std::set
<Node
>& added
,
402 bool withinInstClosure
);
403 /** get operator representative */
404 Node
getOperatorRepresentative( TNode op
) const;
405 //------------------------------end higher-order term indexing
408 }/* CVC4::theory::quantifiers namespace */
409 }/* CVC4::theory namespace */
410 }/* CVC4 namespace */
412 #endif /* CVC4__THEORY__QUANTIFIERS__TERM_DATABASE_H */