1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Mathias Preiner, 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 |
|
* Counterexample-guided quantifier instantiation. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "cvc5_private.h" |
17 |
|
|
18 |
|
#ifndef CVC5__THEORY__QUANTIFIERS__CEG_INSTANTIATOR_H |
19 |
|
#define CVC5__THEORY__QUANTIFIERS__CEG_INSTANTIATOR_H |
20 |
|
|
21 |
|
#include <vector> |
22 |
|
|
23 |
|
#include "expr/node.h" |
24 |
|
#include "theory/inference_id.h" |
25 |
|
#include "util/statistics_stats.h" |
26 |
|
|
27 |
|
namespace cvc5 { |
28 |
|
namespace theory { |
29 |
|
namespace quantifiers { |
30 |
|
|
31 |
|
class Instantiator; |
32 |
|
class InstantiatorPreprocess; |
33 |
|
class InstStrategyCegqi; |
34 |
|
class QuantifiersState; |
35 |
|
class TermRegistry; |
36 |
|
|
37 |
|
/** |
38 |
|
* Descriptions of the types of constraints that a term was solved for in. |
39 |
|
*/ |
40 |
|
enum CegTermType |
41 |
|
{ |
42 |
|
// invalid |
43 |
|
CEG_TT_INVALID, |
44 |
|
// term was the result of solving an equality |
45 |
|
CEG_TT_EQUAL, |
46 |
|
// term was the result of solving a non-strict lower bound x >= t |
47 |
|
CEG_TT_LOWER, |
48 |
|
// term was the result of solving a strict lower bound x > t |
49 |
|
CEG_TT_LOWER_STRICT, |
50 |
|
// term was the result of solving a non-strict upper bound x <= t |
51 |
|
CEG_TT_UPPER, |
52 |
|
// term was the result of solving a strict upper bound x < t |
53 |
|
CEG_TT_UPPER_STRICT, |
54 |
|
}; |
55 |
|
/** make (non-strict term type) c a strict term type */ |
56 |
|
CegTermType mkStrictCTT(CegTermType c); |
57 |
|
/** negate c (lower/upper bounds are swapped) */ |
58 |
|
CegTermType mkNegateCTT(CegTermType c); |
59 |
|
/** is c a strict term type? */ |
60 |
|
bool isStrictCTT(CegTermType c); |
61 |
|
/** is c a lower bound? */ |
62 |
|
bool isLowerBoundCTT(CegTermType c); |
63 |
|
/** is c an upper bound? */ |
64 |
|
bool isUpperBoundCTT(CegTermType c); |
65 |
|
|
66 |
|
/** Term Properties |
67 |
|
* |
68 |
|
* Stores properties for a variable to solve for in counterexample-guided |
69 |
|
* instantiation. |
70 |
|
* |
71 |
|
* For LIA, this includes the coefficient of the variable, and the bound type |
72 |
|
* for the variable. |
73 |
|
*/ |
74 |
2194321 |
class TermProperties { |
75 |
|
public: |
76 |
879637 |
TermProperties() : d_type(CEG_TT_EQUAL) {} |
77 |
3073912 |
virtual ~TermProperties() {} |
78 |
|
|
79 |
|
/** |
80 |
|
* Type for the solution term. For arithmetic this corresponds to bound type |
81 |
|
* of the constraint that the constraint the term was solved for in. |
82 |
|
*/ |
83 |
|
CegTermType d_type; |
84 |
|
// for arithmetic |
85 |
|
Node d_coeff; |
86 |
|
// get cache node |
87 |
|
// we consider terms + TermProperties that are unique up to their cache node |
88 |
|
// (see constructInstantiationInc) |
89 |
50115 |
virtual Node getCacheNode() const { return d_coeff; } |
90 |
|
// is non-basic |
91 |
136050 |
virtual bool isBasic() const { return d_coeff.isNull(); } |
92 |
|
// get modified term |
93 |
3930 |
virtual Node getModifiedTerm( Node pv ) const { |
94 |
3930 |
if( !d_coeff.isNull() ){ |
95 |
239 |
return NodeManager::currentNM()->mkNode( kind::MULT, d_coeff, pv ); |
96 |
|
}else{ |
97 |
3691 |
return pv; |
98 |
|
} |
99 |
|
} |
100 |
|
// compose property, should be such that: |
101 |
|
// p.getModifiedTerm( this.getModifiedTerm( x ) ) = this_updated.getModifiedTerm( x ) |
102 |
|
virtual void composeProperty(TermProperties& p); |
103 |
|
}; |
104 |
|
|
105 |
|
/** Solved form |
106 |
|
* This specifies a substitution: |
107 |
|
* { d_props[i].getModifiedTerm(d_vars[i]) -> d_subs[i] | i = 0...|d_vars| } |
108 |
|
*/ |
109 |
24230 |
class SolvedForm { |
110 |
|
public: |
111 |
|
// list of variables |
112 |
|
std::vector< Node > d_vars; |
113 |
|
// list of terms that they are substituted to |
114 |
|
std::vector< Node > d_subs; |
115 |
|
// properties for each variable |
116 |
|
std::vector< TermProperties > d_props; |
117 |
|
// the variables that have non-basic information regarding how they are substituted |
118 |
|
// an example is for linear arithmetic, we store "substitution with coefficients". |
119 |
|
std::vector<Node> d_non_basic; |
120 |
|
// push the substitution pv_prop.getModifiedTerm(pv) -> n |
121 |
|
void push_back(Node pv, Node n, TermProperties& pv_prop); |
122 |
|
// pop the substitution pv_prop.getModifiedTerm(pv) -> n |
123 |
|
void pop_back(Node pv, Node n, TermProperties& pv_prop); |
124 |
|
// is this solved form empty? |
125 |
2278 |
bool empty() { return d_vars.empty(); } |
126 |
|
public: |
127 |
|
// theta values (for LIA, see Section 4 of Reynolds/King/Kuncak FMSD 2017) |
128 |
|
std::vector< Node > d_theta; |
129 |
|
// get the current value for theta (for LIA, see Section 4 of Reynolds/King/Kuncak FMSD 2017) |
130 |
27906 |
Node getTheta() { |
131 |
27906 |
if( d_theta.empty() ){ |
132 |
27622 |
return Node::null(); |
133 |
|
}else{ |
134 |
284 |
return d_theta[d_theta.size()-1]; |
135 |
|
} |
136 |
|
} |
137 |
|
}; |
138 |
|
|
139 |
|
/** instantiation effort levels |
140 |
|
* |
141 |
|
* This effort is used to stratify the construction of |
142 |
|
* instantiations for some theories that may result to |
143 |
|
* using model value instantiations. |
144 |
|
*/ |
145 |
|
enum CegInstEffort |
146 |
|
{ |
147 |
|
// uninitialized |
148 |
|
CEG_INST_EFFORT_NONE, |
149 |
|
// standard effort level |
150 |
|
CEG_INST_EFFORT_STANDARD, |
151 |
|
// standard effort level, but we have used model values |
152 |
|
CEG_INST_EFFORT_STANDARD_MV, |
153 |
|
// full effort level |
154 |
|
CEG_INST_EFFORT_FULL |
155 |
|
}; |
156 |
|
|
157 |
|
std::ostream& operator<<(std::ostream& os, CegInstEffort e); |
158 |
|
|
159 |
|
/** instantiation phase for variables |
160 |
|
* |
161 |
|
* This indicates the phase in which we constructed |
162 |
|
* a substitution for individual variables. |
163 |
|
*/ |
164 |
|
enum CegInstPhase |
165 |
|
{ |
166 |
|
// uninitialized |
167 |
|
CEG_INST_PHASE_NONE, |
168 |
|
// instantiation constructed during traversal of equivalence classes |
169 |
|
CEG_INST_PHASE_EQC, |
170 |
|
// instantiation constructed during solving equalities |
171 |
|
CEG_INST_PHASE_EQUAL, |
172 |
|
// instantiation constructed by looking at theory assertions |
173 |
|
CEG_INST_PHASE_ASSERTION, |
174 |
|
// instantiation constructed by querying model value |
175 |
|
CEG_INST_PHASE_MVALUE, |
176 |
|
}; |
177 |
|
|
178 |
|
std::ostream& operator<<(std::ostream& os, CegInstPhase phase); |
179 |
|
|
180 |
|
/** |
181 |
|
* The handled status of a sort/term/quantified formula, indicating whether |
182 |
|
* counterexample-guided instantiation handles it. |
183 |
|
*/ |
184 |
|
enum CegHandledStatus |
185 |
|
{ |
186 |
|
// the sort/term/quantified formula is unhandled by cegqi |
187 |
|
CEG_UNHANDLED, |
188 |
|
// the sort/term/quantified formula is partially handled by cegqi |
189 |
|
CEG_PARTIALLY_HANDLED, |
190 |
|
// the sort/term/quantified formula is handled by cegqi |
191 |
|
CEG_HANDLED, |
192 |
|
// the sort/term/quantified formula is handled by cegqi, regardless of |
193 |
|
// additional factors |
194 |
|
CEG_HANDLED_UNCONDITIONAL, |
195 |
|
}; |
196 |
|
std::ostream& operator<<(std::ostream& os, CegHandledStatus status); |
197 |
|
|
198 |
|
/** Ceg instantiator |
199 |
|
* |
200 |
|
* This class manages counterexample-guided quantifier instantiation |
201 |
|
* for a single quantified formula. |
202 |
|
* |
203 |
|
* For details on counterexample-guided quantifier instantiation |
204 |
|
* (for linear arithmetic), see Reynolds/King/Kuncak FMSD 2017. |
205 |
|
*/ |
206 |
|
class CegInstantiator { |
207 |
|
public: |
208 |
|
/** |
209 |
|
* The instantiator will be constructing instantiations for quantified formula |
210 |
|
* q, parent is the owner of this object. |
211 |
|
*/ |
212 |
|
CegInstantiator(Node q, |
213 |
|
QuantifiersState& qs, |
214 |
|
TermRegistry& tr, |
215 |
|
InstStrategyCegqi* parent); |
216 |
|
virtual ~CegInstantiator(); |
217 |
|
/** check |
218 |
|
* This adds instantiations based on the state of d_vars in current context |
219 |
|
* on the output channel d_out of this class. |
220 |
|
*/ |
221 |
|
bool check(); |
222 |
|
/** Register the counterexample lemma |
223 |
|
* |
224 |
|
* @param lem contains the counterexample lemma of the quantified formula we |
225 |
|
* are processing. The counterexample lemma is the formula { ~phi[e/x] } in |
226 |
|
* Figure 1 of Reynolds et al. FMSD 2017. |
227 |
|
* @param ce_vars contains the variables e. Notice these are variables of |
228 |
|
* INST_CONSTANT kind, since we do not permit bound variables in assertions. |
229 |
|
* This method may add additional variables to this vector if it decides there |
230 |
|
* are additional auxiliary variables to solve for. |
231 |
|
* @param auxLems : if this method decides that additional lemmas should be |
232 |
|
* sent on the output channel, they are added to this vector, and sent out by |
233 |
|
* the caller of this method. |
234 |
|
*/ |
235 |
|
void registerCounterexampleLemma(Node lem, |
236 |
|
std::vector<Node>& ce_vars, |
237 |
|
std::vector<Node>& auxLems); |
238 |
|
//------------------------------interface for instantiators |
239 |
|
/** push stack variable |
240 |
|
* This adds a new variable to solve for in the stack |
241 |
|
* of variables we are processing. This stack is only |
242 |
|
* used for datatypes, where e.g. the DtInstantiator |
243 |
|
* solving for a list x may push the stack "variables" |
244 |
|
* head(x) and tail(x). |
245 |
|
*/ |
246 |
|
void pushStackVariable(Node v); |
247 |
|
/** pop stack variable */ |
248 |
|
void popStackVariable(); |
249 |
|
/** construct instantiation increment |
250 |
|
* |
251 |
|
* Adds the substitution { pv_prop.getModifiedTerm(pv) -> n } to the current |
252 |
|
* instantiation, specified by sf. |
253 |
|
* |
254 |
|
* This function returns true if a call to |
255 |
|
* Instantiate::addInstantiation(...) |
256 |
|
* was successfully made in a recursive call. |
257 |
|
* |
258 |
|
* The solved form sf is reverted to its original state if |
259 |
|
* this function returns false, or |
260 |
|
* revertOnSuccess is true and this function returns true. |
261 |
|
*/ |
262 |
|
bool constructInstantiationInc(Node pv, |
263 |
|
Node n, |
264 |
|
TermProperties& pv_prop, |
265 |
|
SolvedForm& sf, |
266 |
|
bool revertOnSuccess = false); |
267 |
|
/** get the current model value of term n */ |
268 |
|
Node getModelValue(Node n); |
269 |
|
/** get bound variable for type |
270 |
|
* |
271 |
|
* This gets the next (canonical) bound variable of |
272 |
|
* type tn. This can be used for instance when |
273 |
|
* constructing instantiations that involve witness expressions. |
274 |
|
*/ |
275 |
|
Node getBoundVariable(TypeNode tn); |
276 |
|
/** has this assertion been marked as solved? */ |
277 |
|
bool isSolvedAssertion(Node n) const; |
278 |
|
/** marked solved */ |
279 |
|
void markSolved(Node n, bool solved = true); |
280 |
|
//------------------------------end interface for instantiators |
281 |
|
|
282 |
|
/** |
283 |
|
* Get the number of atoms in the counterexample lemma of the quantified |
284 |
|
* formula we are processing with this class. |
285 |
|
*/ |
286 |
|
unsigned getNumCEAtoms() { return d_ce_atoms.size(); } |
287 |
|
/** |
288 |
|
* Get the i^th atom of the counterexample lemma of the quantified |
289 |
|
* formula we are processing with this class. |
290 |
|
*/ |
291 |
|
Node getCEAtom(unsigned i) { return d_ce_atoms[i]; } |
292 |
|
/** is n a term that is eligible for instantiation? */ |
293 |
|
bool isEligible(Node n); |
294 |
|
/** does n have variable pv? */ |
295 |
|
bool hasVariable(Node n, Node pv); |
296 |
|
/** are we processing a nested quantified formula? */ |
297 |
3121 |
bool hasNestedQuantification() const { return d_is_nested_quant; } |
298 |
|
/** |
299 |
|
* Are we allowed to instantiate the current quantified formula with n? This |
300 |
|
* includes restrictions such as if n is a variable, it must occur free in |
301 |
|
* the current quantified formula. |
302 |
|
*/ |
303 |
|
bool isEligibleForInstantiation(Node n) const; |
304 |
|
//------------------------------------ static queries |
305 |
|
/** Is k a kind for which counterexample-guided instantiation is possible? |
306 |
|
* |
307 |
|
* If this method returns CEG_UNHANDLED, then we prohibit cegqi for terms |
308 |
|
* involving this kind. If this method returns CEG_HANDLED, our approaches |
309 |
|
* for cegqi fully handle the kind. |
310 |
|
* |
311 |
|
* This typically corresponds to kinds that correspond to operators that |
312 |
|
* have total interpretations and are a part of the signature of |
313 |
|
* satisfaction complete theories (see Reynolds et al., CAV 2015). |
314 |
|
*/ |
315 |
|
static CegHandledStatus isCbqiKind(Kind k); |
316 |
|
/** is cbqi term? |
317 |
|
* |
318 |
|
* This method returns whether the term is handled by cegqi techniques, i.e. |
319 |
|
* whether all subterms of n have kinds that can be handled by cegqi. |
320 |
|
*/ |
321 |
|
static CegHandledStatus isCbqiTerm(Node n); |
322 |
|
/** is cbqi sort? |
323 |
|
* |
324 |
|
* This method returns whether the type tn is handled by cegqi techniques. |
325 |
|
* If the result is CEG_HANDLED_UNCONDITIONAL, then this indicates that a |
326 |
|
* variable of this type is handled regardless of the formula it appears in. |
327 |
|
*/ |
328 |
|
static CegHandledStatus isCbqiSort(TypeNode tn); |
329 |
|
/** is cbqi quantifier prefix |
330 |
|
* |
331 |
|
* This returns the minimum value of the above method for a bound variable |
332 |
|
* in the prefix of quantified formula q. |
333 |
|
*/ |
334 |
|
static CegHandledStatus isCbqiQuantPrefix(Node q); |
335 |
|
/** is cbqi quantified formula |
336 |
|
* |
337 |
|
* This returns whether quantified formula q can and should be handled by |
338 |
|
* counterexample-guided instantiation. If this function returns |
339 |
|
* a status CEG_HANDLED or above, then q is fully handled by counterexample |
340 |
|
* guided quantifier instantiation and need not be processed by any other |
341 |
|
* strategy for quantifiers (e.g. E-matching). Otherwise, if this function |
342 |
|
* returns CEG_PARTIALLY_HANDLED, then it may be worthwhile to handle the |
343 |
|
* quantified formula using cegqi, however other strategies should also be |
344 |
|
* tried. |
345 |
|
*/ |
346 |
|
static CegHandledStatus isCbqiQuant(Node q); |
347 |
|
//------------------------------------ end static queries |
348 |
|
private: |
349 |
|
/** The quantified formula of this instantiator */ |
350 |
|
Node d_quant; |
351 |
|
/** Reference to the quantifiers state */ |
352 |
|
QuantifiersState& d_qstate; |
353 |
|
/** Reference to the term registry */ |
354 |
|
TermRegistry& d_treg; |
355 |
|
/** The parent of this instantiator */ |
356 |
|
InstStrategyCegqi* d_parent; |
357 |
|
|
358 |
|
//-------------------------------globally cached |
359 |
|
/** cache from nodes to the set of variables it contains |
360 |
|
* (from the quantified formula we are instantiating). |
361 |
|
*/ |
362 |
|
std::unordered_map<Node, std::unordered_set<Node>> d_prog_var; |
363 |
|
/** cache of the set of terms that we have established are |
364 |
|
* ineligible for instantiation. |
365 |
|
*/ |
366 |
|
std::unordered_set<Node> d_inelig; |
367 |
|
/** ensures n is in d_prog_var and d_inelig. */ |
368 |
|
void computeProgVars(Node n); |
369 |
|
//-------------------------------end globally cached |
370 |
|
|
371 |
|
//-------------------------------cached per round |
372 |
|
/** current assertions per theory */ |
373 |
|
std::map<TheoryId, std::vector<Node> > d_curr_asserts; |
374 |
|
/** map from representatives to the terms in their equivalence class */ |
375 |
|
std::map<Node, std::vector<Node> > d_curr_eqc; |
376 |
|
/** map from types to representatives of that type */ |
377 |
|
std::map<TypeNode, std::vector<Node> > d_curr_type_eqc; |
378 |
|
/** solved asserts */ |
379 |
|
std::unordered_set<Node> d_solved_asserts; |
380 |
|
/** process assertions |
381 |
|
* This is called once at the beginning of check to |
382 |
|
* set up all necessary information for constructing instantiations, |
383 |
|
* such as the above data structures. |
384 |
|
*/ |
385 |
|
void processAssertions(); |
386 |
|
/** cache bound variables for type returned |
387 |
|
* by getBoundVariable(...). |
388 |
|
*/ |
389 |
|
std::unordered_map<TypeNode, std::vector<Node>> d_bound_var; |
390 |
|
/** current index of bound variables for type. |
391 |
|
* The next call to getBoundVariable(...) for |
392 |
|
* type tn returns the d_bound_var_index[tn]^th |
393 |
|
* element of d_bound_var[tn], or a fresh variable |
394 |
|
* if not in bounds. |
395 |
|
*/ |
396 |
|
std::unordered_map<TypeNode, unsigned> d_bound_var_index; |
397 |
|
//-------------------------------end cached per round |
398 |
|
|
399 |
|
//-------------------------------data per theory |
400 |
|
/** relevant theory ids |
401 |
|
* A list of theory ids that contain at least one |
402 |
|
* constraint in the body of the quantified formula we |
403 |
|
* are processing. |
404 |
|
*/ |
405 |
|
std::vector<TheoryId> d_tids; |
406 |
|
/** map from theory ids to instantiator preprocessors */ |
407 |
|
std::map<TheoryId, InstantiatorPreprocess*> d_tipp; |
408 |
|
/** registers all theory ids associated with type tn |
409 |
|
* |
410 |
|
* This recursively calls registerTheoryId for typeOf(tn') for |
411 |
|
* all parameters and datatype subfields of type tn. |
412 |
|
* visited stores the types we have already visited. |
413 |
|
*/ |
414 |
|
void registerTheoryIds(TypeNode tn, std::map<TypeNode, bool>& visited); |
415 |
|
/** register theory id tid |
416 |
|
* |
417 |
|
* This is called when the quantified formula we are processing |
418 |
|
* with this class involves theory tid. In this case, we will |
419 |
|
* construct instantiations based on the assertion list of this theory. |
420 |
|
*/ |
421 |
|
void registerTheoryId(TheoryId tid); |
422 |
|
//-------------------------------end data per theory |
423 |
|
|
424 |
|
//-------------------------------the variables |
425 |
|
/** the variables we are instantiating |
426 |
|
* |
427 |
|
* This is a superset of the variables for the instantiations we are |
428 |
|
* generating and sending on the output channel of this class. |
429 |
|
*/ |
430 |
|
std::vector<Node> d_vars; |
431 |
|
/** set form of d_vars */ |
432 |
|
std::unordered_set<Node> d_vars_set; |
433 |
|
/** index of variables reported in instantiation */ |
434 |
|
std::vector<unsigned> d_var_order_index; |
435 |
|
/** number of input variables |
436 |
|
* |
437 |
|
* These are the variables, in order, for the instantiations we are generating |
438 |
|
* and sending on the output channel of this class. |
439 |
|
*/ |
440 |
|
std::vector<Node> d_input_vars; |
441 |
|
/** register variable */ |
442 |
|
void registerVariable(Node v); |
443 |
|
//-------------------------------the variables |
444 |
|
|
445 |
|
//-------------------------------quantified formula info |
446 |
|
/** are we processing a nested quantified formula? */ |
447 |
|
bool d_is_nested_quant; |
448 |
|
/** the atoms of the CE lemma */ |
449 |
|
std::vector<Node> d_ce_atoms; |
450 |
|
/** collect atoms */ |
451 |
|
void collectCeAtoms(Node n, std::map<Node, bool>& visited); |
452 |
|
//-------------------------------end quantified formula info |
453 |
|
|
454 |
|
//-------------------------------current state |
455 |
|
/** the current effort level of the instantiator |
456 |
|
* This indicates the effort Instantiator objects |
457 |
|
* will put into the terms they return. |
458 |
|
*/ |
459 |
|
CegInstEffort d_effort; |
460 |
|
/** for each variable, the instantiator used for that variable */ |
461 |
|
std::map<Node, Instantiator*> d_active_instantiators; |
462 |
|
/** map from variables to the index in the prefix of the quantified |
463 |
|
* formula we are processing. |
464 |
|
*/ |
465 |
|
std::map<Node, unsigned> d_curr_index; |
466 |
|
/** map from variables to the phase in which we instantiated them */ |
467 |
|
std::map<Node, CegInstPhase> d_curr_iphase; |
468 |
|
/** cache of current substitutions tried between activate/deactivate */ |
469 |
|
std::map<Node, std::map<Node, std::map<Node, bool> > > d_curr_subs_proc; |
470 |
|
/** stack of temporary variables we are solving for, |
471 |
|
* e.g. subfields of datatypes. |
472 |
|
*/ |
473 |
|
std::vector<Node> d_stack_vars; |
474 |
|
/** activate instantiation variable v at index |
475 |
|
* |
476 |
|
* This is called when variable (inst constant) v is activated |
477 |
|
* for the quantified formula we are processing. |
478 |
|
* This method initializes the instantiator class for |
479 |
|
* that variable if necessary, where this class is |
480 |
|
* determined by the type of v. It also initializes |
481 |
|
* the cache of values we have tried substituting for v |
482 |
|
* (in d_curr_subs_proc), and stores its index. |
483 |
|
*/ |
484 |
|
void activateInstantiationVariable(Node v, unsigned index); |
485 |
|
/** deactivate instantiation variable |
486 |
|
* |
487 |
|
* This is called when variable (inst constant) v is deactivated |
488 |
|
* for the quantified formula we are processing. |
489 |
|
*/ |
490 |
|
void deactivateInstantiationVariable(Node v); |
491 |
|
/** |
492 |
|
* Have we tried an instantiation for v after the last call to |
493 |
|
* activateInstantiationVariable. |
494 |
|
*/ |
495 |
|
bool hasTriedInstantiation(Node v); |
496 |
|
//-------------------------------end current state |
497 |
|
|
498 |
|
//---------------------------------for applying substitutions |
499 |
|
/** can use basic substitution */ |
500 |
|
bool canApplyBasicSubstitution( Node n, std::vector< Node >& non_basic ); |
501 |
|
/** apply substitution |
502 |
|
* We wish to process the substitution: |
503 |
|
* ( pv = n * sf ) |
504 |
|
* where pv is a variable with type tn, and * denotes application of substitution. |
505 |
|
* The return value "ret" and pv_prop is such that the above equality is equivalent to |
506 |
|
* ( pv_prop.getModifiedTerm(pv) = ret ) |
507 |
|
*/ |
508 |
668259 |
Node applySubstitution( TypeNode tn, Node n, SolvedForm& sf, TermProperties& pv_prop, bool try_coeff = true ) { |
509 |
668259 |
return applySubstitution( tn, n, sf.d_vars, sf.d_subs, sf.d_props, sf.d_non_basic, pv_prop, try_coeff ); |
510 |
|
} |
511 |
|
/** apply substitution, with solved form expanded to subs/prop/non_basic/vars */ |
512 |
|
Node applySubstitution( TypeNode tn, Node n, std::vector< Node >& vars, std::vector< Node >& subs, std::vector< TermProperties >& prop, |
513 |
|
std::vector< Node >& non_basic, TermProperties& pv_prop, bool try_coeff = true ); |
514 |
|
/** apply substitution to literal lit |
515 |
|
* The return value is equivalent to ( lit * sf ) |
516 |
|
* where * denotes application of substitution. |
517 |
|
*/ |
518 |
426061 |
Node applySubstitutionToLiteral( Node lit, SolvedForm& sf ) { |
519 |
426061 |
return applySubstitutionToLiteral( lit, sf.d_vars, sf.d_subs, sf.d_props, sf.d_non_basic ); |
520 |
|
} |
521 |
|
/** apply substitution to literal lit, with solved form expanded to subs/prop/non_basic/vars */ |
522 |
|
Node applySubstitutionToLiteral( Node lit, std::vector< Node >& vars, std::vector< Node >& subs, std::vector< TermProperties >& prop, |
523 |
|
std::vector< Node >& non_basic ); |
524 |
|
//---------------------------------end for applying substitutions |
525 |
|
|
526 |
|
/** map from variables to their instantiators */ |
527 |
|
std::map<Node, Instantiator*> d_instantiator; |
528 |
|
|
529 |
|
/** construct instantiation |
530 |
|
* |
531 |
|
* This method attempts to find a term for the i^th variable in d_vars to |
532 |
|
* include in the current instantiation, given by sf. |
533 |
|
* |
534 |
|
* It returns true if a successful call to the output channel's |
535 |
|
* doAddInstantiation was made. |
536 |
|
*/ |
537 |
|
bool constructInstantiation(SolvedForm& sf, unsigned i); |
538 |
|
/** construct instantiation |
539 |
|
* |
540 |
|
* Helper method for the above method. This method attempts to find a term for |
541 |
|
* variable pv to include in the current instantiation, given by sf based |
542 |
|
* on equality and theory-specific instantiation techniques. The latter is |
543 |
|
* managed by the instantiator object vinst. Prior to calling this method, |
544 |
|
* the variable pv has been activated by a call to |
545 |
|
* activateInstantiationVariable. |
546 |
|
*/ |
547 |
|
bool constructInstantiation(SolvedForm& sf, Instantiator* vinst, Node pv); |
548 |
|
/** do add instantiation |
549 |
|
* This method is called by the above function after we finalize the |
550 |
|
* variables/substitution and auxiliary lemmas. |
551 |
|
* It returns true if a successful call to the output channel's |
552 |
|
* doAddInstantiation was made. |
553 |
|
*/ |
554 |
|
bool doAddInstantiation(std::vector<Node>& vars, std::vector<Node>& subs); |
555 |
|
|
556 |
|
//------------------------------------ static queries |
557 |
|
/** is cbqi sort |
558 |
|
* |
559 |
|
* Helper function for isCbqiSort. This function recurses over the structure |
560 |
|
* of the type tn, where visited stores the types we have visited. |
561 |
|
*/ |
562 |
|
static CegHandledStatus isCbqiSort( |
563 |
|
TypeNode tn, std::map<TypeNode, CegHandledStatus>& visited); |
564 |
|
//------------------------------------ end static queries |
565 |
|
}; |
566 |
|
|
567 |
|
/** Instantiator class |
568 |
|
* |
569 |
|
* This is a virtual class that is used for methods for constructing |
570 |
|
* substitutions for individual variables in counterexample-guided |
571 |
|
* instantiation techniques. |
572 |
|
* |
573 |
|
* This class contains a set of interface functions below, which are called |
574 |
|
* based on a fixed instantiation method implemented by CegInstantiator. |
575 |
|
* In these calls, the Instantiator in turn makes calls to methods in |
576 |
|
* CegInstanatior (primarily constructInstantiationInc). |
577 |
|
*/ |
578 |
|
class Instantiator { |
579 |
|
public: |
580 |
|
Instantiator(TypeNode tn); |
581 |
3013 |
virtual ~Instantiator() {} |
582 |
|
/** reset |
583 |
|
* This is called once, prior to any of the below methods are called. |
584 |
|
* This function sets up any initial information necessary for constructing |
585 |
|
* instantiations for pv based on the current context. |
586 |
|
*/ |
587 |
6642 |
virtual void reset(CegInstantiator* ci, |
588 |
|
SolvedForm& sf, |
589 |
|
Node pv, |
590 |
|
CegInstEffort effort) |
591 |
|
{ |
592 |
6642 |
} |
593 |
|
|
594 |
|
/** has process equal term |
595 |
|
* |
596 |
|
* Whether this instantiator implements processEqualTerm and |
597 |
|
* processEqualTerms. |
598 |
|
*/ |
599 |
39924 |
virtual bool hasProcessEqualTerm(CegInstantiator* ci, |
600 |
|
SolvedForm& sf, |
601 |
|
Node pv, |
602 |
|
CegInstEffort effort) |
603 |
|
{ |
604 |
39924 |
return false; |
605 |
|
} |
606 |
|
/** process equal term |
607 |
|
* |
608 |
|
* This method is called when the entailment: |
609 |
|
* E |= pv_prop.getModifiedTerm(pv) = n |
610 |
|
* holds in the current context E, and n is eligible for instantiation. |
611 |
|
* |
612 |
|
* Returns true if an instantiation was successfully added via a call to |
613 |
|
* CegInstantiator::constructInstantiationInc. |
614 |
|
*/ |
615 |
|
virtual bool processEqualTerm(CegInstantiator* ci, |
616 |
|
SolvedForm& sf, |
617 |
|
Node pv, |
618 |
|
TermProperties& pv_prop, |
619 |
|
Node n, |
620 |
|
CegInstEffort effort); |
621 |
|
/** process equal terms |
622 |
|
* |
623 |
|
* This method is called after process equal term, where eqc is the list of |
624 |
|
* eligible terms in the equivalence class of pv. |
625 |
|
* |
626 |
|
* Returns true if an instantiation was successfully added via a call to |
627 |
|
* CegInstantiator::constructInstantiationInc. |
628 |
|
*/ |
629 |
|
virtual bool processEqualTerms(CegInstantiator* ci, |
630 |
|
SolvedForm& sf, |
631 |
|
Node pv, |
632 |
|
std::vector<Node>& eqc, |
633 |
|
CegInstEffort effort) |
634 |
|
{ |
635 |
|
return false; |
636 |
|
} |
637 |
|
|
638 |
|
/** whether the instantiator implements processEquality */ |
639 |
11665 |
virtual bool hasProcessEquality(CegInstantiator* ci, |
640 |
|
SolvedForm& sf, |
641 |
|
Node pv, |
642 |
|
CegInstEffort effort) |
643 |
|
{ |
644 |
11665 |
return false; |
645 |
|
} |
646 |
|
/** process equality |
647 |
|
* The input is such that term_props.size() = terms.size() = 2 |
648 |
|
* This method is called when the entailment: |
649 |
|
* E ^ term_props[0].getModifiedTerm(x0) = |
650 |
|
* terms[0] ^ term_props[1].getModifiedTerm(x1) = terms[1] |= x0 = x1 |
651 |
|
* holds in current context E for fresh variables xi, terms[i] are eligible, |
652 |
|
* and at least one terms[i] contains pv for i = 0,1. |
653 |
|
* Notice in the basic case, E |= terms[0] = terms[1]. |
654 |
|
* |
655 |
|
* Returns true if an instantiation was successfully added via a call to |
656 |
|
* CegInstantiator::constructInstantiationInc. |
657 |
|
*/ |
658 |
|
virtual bool processEquality(CegInstantiator* ci, |
659 |
|
SolvedForm& sf, |
660 |
|
Node pv, |
661 |
|
std::vector<TermProperties>& term_props, |
662 |
|
std::vector<Node>& terms, |
663 |
|
CegInstEffort effort) |
664 |
|
{ |
665 |
|
return false; |
666 |
|
} |
667 |
|
|
668 |
|
/** whether the instantiator implements processAssertion for any literal */ |
669 |
6504 |
virtual bool hasProcessAssertion(CegInstantiator* ci, |
670 |
|
SolvedForm& sf, |
671 |
|
Node pv, |
672 |
|
CegInstEffort effort) |
673 |
|
{ |
674 |
6504 |
return false; |
675 |
|
} |
676 |
|
/** has process assertion |
677 |
|
* |
678 |
|
* This method is called when the entailment: |
679 |
|
* E |= lit |
680 |
|
* holds in current context E. Typically, lit belongs to the list of current |
681 |
|
* assertions. |
682 |
|
* |
683 |
|
* This method is used to determine whether the instantiator implements |
684 |
|
* processAssertion for literal lit. |
685 |
|
* If this method returns null, then this intantiator does not handle the |
686 |
|
* literal lit. Otherwise, this method returns a literal lit' such that: |
687 |
|
* (1) lit' is true in the current model, |
688 |
|
* (2) lit' implies lit. |
689 |
|
* where typically lit' = lit. |
690 |
|
*/ |
691 |
|
virtual Node hasProcessAssertion(CegInstantiator* ci, |
692 |
|
SolvedForm& sf, |
693 |
|
Node pv, |
694 |
|
Node lit, |
695 |
|
CegInstEffort effort) |
696 |
|
{ |
697 |
|
return Node::null(); |
698 |
|
} |
699 |
|
/** process assertion |
700 |
|
* This method processes the assertion slit for variable pv. |
701 |
|
* lit : the substituted form (under sf) of a literal returned by |
702 |
|
* hasProcessAssertion |
703 |
|
* alit : the asserted literal, given as input to hasProcessAssertion |
704 |
|
* |
705 |
|
* Returns true if an instantiation was successfully added via a call to |
706 |
|
* CegInstantiator::constructInstantiationInc. |
707 |
|
*/ |
708 |
|
virtual bool processAssertion(CegInstantiator* ci, |
709 |
|
SolvedForm& sf, |
710 |
|
Node pv, |
711 |
|
Node lit, |
712 |
|
Node alit, |
713 |
|
CegInstEffort effort) |
714 |
|
{ |
715 |
|
return false; |
716 |
|
} |
717 |
|
/** process assertions |
718 |
|
* |
719 |
|
* Called after processAssertion is called for each literal asserted to the |
720 |
|
* instantiator. |
721 |
|
* |
722 |
|
* Returns true if an instantiation was successfully added via a call to |
723 |
|
* CegInstantiator::constructInstantiationInc. |
724 |
|
*/ |
725 |
|
virtual bool processAssertions(CegInstantiator* ci, |
726 |
|
SolvedForm& sf, |
727 |
|
Node pv, |
728 |
|
CegInstEffort effort) |
729 |
|
{ |
730 |
|
return false; |
731 |
|
} |
732 |
|
|
733 |
|
/** do we use the model value as instantiation for pv? |
734 |
|
* This method returns true if we use model value instantiations |
735 |
|
* at the same effort level as those determined by this instantiator. |
736 |
|
*/ |
737 |
2356 |
virtual bool useModelValue(CegInstantiator* ci, |
738 |
|
SolvedForm& sf, |
739 |
|
Node pv, |
740 |
|
CegInstEffort effort) |
741 |
|
{ |
742 |
2356 |
return effort > CEG_INST_EFFORT_STANDARD; |
743 |
|
} |
744 |
|
/** do we allow the model value as instantiation for pv? */ |
745 |
11320 |
virtual bool allowModelValue(CegInstantiator* ci, |
746 |
|
SolvedForm& sf, |
747 |
|
Node pv, |
748 |
|
CegInstEffort effort) |
749 |
|
{ |
750 |
11320 |
return d_closed_enum_type; |
751 |
|
} |
752 |
|
|
753 |
|
/** do we need to postprocess the solved form for pv? */ |
754 |
12514 |
virtual bool needsPostProcessInstantiationForVariable(CegInstantiator* ci, |
755 |
|
SolvedForm& sf, |
756 |
|
Node pv, |
757 |
|
CegInstEffort effort) |
758 |
|
{ |
759 |
12514 |
return false; |
760 |
|
} |
761 |
|
/** postprocess the solved form for pv |
762 |
|
* |
763 |
|
* This method returns true if we successfully postprocessed the solved form. |
764 |
|
* lemmas is a set of lemmas we wish to return along with the instantiation. |
765 |
|
*/ |
766 |
|
virtual bool postProcessInstantiationForVariable(CegInstantiator* ci, |
767 |
|
SolvedForm& sf, |
768 |
|
Node pv, |
769 |
|
CegInstEffort effort) |
770 |
|
{ |
771 |
|
return true; |
772 |
|
} |
773 |
|
|
774 |
|
/** Identify this module (for debugging) */ |
775 |
148 |
virtual std::string identify() const { return "Default"; } |
776 |
|
protected: |
777 |
|
/** the type of the variable we are instantiating */ |
778 |
|
TypeNode d_type; |
779 |
|
/** whether d_type is a closed enumerable type */ |
780 |
|
bool d_closed_enum_type; |
781 |
|
}; |
782 |
|
|
783 |
|
class ModelValueInstantiator : public Instantiator { |
784 |
|
public: |
785 |
207 |
ModelValueInstantiator(TypeNode tn) : Instantiator(tn) {} |
786 |
414 |
virtual ~ModelValueInstantiator() {} |
787 |
6350 |
bool useModelValue(CegInstantiator* ci, |
788 |
|
SolvedForm& sf, |
789 |
|
Node pv, |
790 |
|
CegInstEffort effort) override |
791 |
|
{ |
792 |
6350 |
return true; |
793 |
|
} |
794 |
6350 |
std::string identify() const override { return "ModelValue"; } |
795 |
|
}; |
796 |
|
|
797 |
|
/** instantiator preprocess |
798 |
|
* |
799 |
|
* This class implements techniques for preprocessing the counterexample lemma |
800 |
|
* generated for counterexample-guided quantifier instantiation. |
801 |
|
*/ |
802 |
|
class InstantiatorPreprocess |
803 |
|
{ |
804 |
|
public: |
805 |
717 |
InstantiatorPreprocess() {} |
806 |
717 |
virtual ~InstantiatorPreprocess() {} |
807 |
|
/** register counterexample lemma |
808 |
|
* This implements theory-specific preprocessing and registration |
809 |
|
* of counterexample lemmas, with the same contract as |
810 |
|
* CegInstantiation::registerCounterexampleLemma. |
811 |
|
*/ |
812 |
|
virtual void registerCounterexampleLemma(Node lem, |
813 |
|
std::vector<Node>& ceVars, |
814 |
|
std::vector<Node>& auxLems) |
815 |
|
{ |
816 |
|
} |
817 |
|
}; |
818 |
|
|
819 |
|
} // namespace quantifiers |
820 |
|
} // namespace theory |
821 |
|
} // namespace cvc5 |
822 |
|
|
823 |
|
#endif |