1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Tim King, Morgan Deters |
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 |
|
* Quantifiers conflict find class. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "cvc5_private.h" |
17 |
|
|
18 |
|
#ifndef QUANT_CONFLICT_FIND |
19 |
|
#define QUANT_CONFLICT_FIND |
20 |
|
|
21 |
|
#include <ostream> |
22 |
|
#include <vector> |
23 |
|
|
24 |
|
#include "context/cdhashmap.h" |
25 |
|
#include "context/cdlist.h" |
26 |
|
#include "expr/node_trie.h" |
27 |
|
#include "theory/quantifiers/quant_module.h" |
28 |
|
|
29 |
|
namespace cvc5 { |
30 |
|
namespace theory { |
31 |
|
namespace quantifiers { |
32 |
|
|
33 |
|
class QuantConflictFind; |
34 |
|
class QuantInfo; |
35 |
|
|
36 |
|
//match generator |
37 |
358276 |
class MatchGen { |
38 |
|
friend class QuantInfo; |
39 |
|
private: |
40 |
|
//current children information |
41 |
|
int d_child_counter; |
42 |
|
bool d_use_children; |
43 |
|
//children of this object |
44 |
|
std::vector< int > d_children_order; |
45 |
433179 |
unsigned getNumChildren() { return d_children.size(); } |
46 |
1672165 |
MatchGen * getChild( int i ) { return &d_children[d_children_order[i]]; } |
47 |
|
//MatchGen * getChild( int i ) { return &d_children[i]; } |
48 |
|
//current matching information |
49 |
|
std::vector<TNodeTrie*> d_qn; |
50 |
|
std::vector<std::map<TNode, TNodeTrie>::iterator> d_qni; |
51 |
|
bool doMatching( QuantConflictFind * p, QuantInfo * qi ); |
52 |
|
//for matching : each index is either a variable or a ground term |
53 |
|
unsigned d_qni_size; |
54 |
|
std::map< int, int > d_qni_var_num; |
55 |
|
std::map< int, TNode > d_qni_gterm; |
56 |
|
std::map< int, int > d_qni_bound; |
57 |
|
std::vector< int > d_qni_bound_except; |
58 |
|
std::map< int, TNode > d_qni_bound_cons; |
59 |
|
std::map< int, int > d_qni_bound_cons_var; |
60 |
|
std::map< int, int >::iterator d_binding_it; |
61 |
|
//std::vector< int > d_independent; |
62 |
|
bool d_matched_basis; |
63 |
|
bool d_binding; |
64 |
|
//int getVarBindingVar(); |
65 |
|
std::map< int, Node > d_ground_eval; |
66 |
|
//determine variable order |
67 |
|
void determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars ); |
68 |
|
void collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars, std::map< Node, bool >& visited, bool& hasNested ); |
69 |
|
public: |
70 |
|
//type of the match generator |
71 |
|
enum { |
72 |
|
typ_invalid, |
73 |
|
typ_ground, |
74 |
|
typ_pred, |
75 |
|
typ_eq, |
76 |
|
typ_formula, |
77 |
|
typ_var, |
78 |
|
typ_bool_var, |
79 |
|
typ_tconstraint, |
80 |
|
typ_tsym, |
81 |
|
}; |
82 |
|
void debugPrintType( const char * c, short typ, bool isTrace = false ); |
83 |
|
public: |
84 |
|
MatchGen(); |
85 |
|
MatchGen( QuantInfo * qi, Node n, bool isVar = false ); |
86 |
|
bool d_tgt; |
87 |
|
bool d_tgt_orig; |
88 |
|
bool d_wasSet; |
89 |
|
Node d_n; |
90 |
|
std::vector< MatchGen > d_children; |
91 |
|
short d_type; |
92 |
|
bool d_type_not; |
93 |
|
/** reset round |
94 |
|
* |
95 |
|
* Called once at the beginning of each full/last-call effort, prior to |
96 |
|
* processing this match generator. This method returns false if the reset |
97 |
|
* failed, e.g. if a conflict was encountered during term indexing. |
98 |
|
*/ |
99 |
|
bool reset_round(QuantConflictFind* p); |
100 |
|
void reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ); |
101 |
|
bool getNextMatch( QuantConflictFind * p, QuantInfo * qi ); |
102 |
448177 |
bool isValid() { return d_type!=typ_invalid; } |
103 |
|
void setInvalid(); |
104 |
|
|
105 |
|
// is this term treated as UF application? |
106 |
|
static bool isHandledBoolConnective( TNode n ); |
107 |
|
static bool isHandledUfTerm( TNode n ); |
108 |
|
static Node getMatchOperator( QuantConflictFind * p, Node n ); |
109 |
|
//can this node be handled by the algorithm |
110 |
|
static bool isHandled( TNode n ); |
111 |
|
}; |
112 |
|
|
113 |
|
//info for quantifiers |
114 |
|
class QuantInfo { |
115 |
|
private: |
116 |
|
void registerNode( Node n, bool hasPol, bool pol, bool beneathQuant = false ); |
117 |
|
void flatten( Node n, bool beneathQuant ); |
118 |
|
private: //for completing match |
119 |
|
std::vector< int > d_unassigned; |
120 |
|
std::vector< TypeNode > d_unassigned_tn; |
121 |
|
int d_unassigned_nvar; |
122 |
|
int d_una_index; |
123 |
|
std::vector< int > d_una_eqc_count; |
124 |
|
//optimization: track which arguments variables appear under UF terms in |
125 |
|
std::map< int, std::map< TNode, std::vector< unsigned > > > d_var_rel_dom; |
126 |
|
void getPropagateVars( QuantConflictFind * p, std::vector< TNode >& vars, TNode n, bool pol, std::map< TNode, bool >& visited ); |
127 |
|
//optimization: number of variables set, to track when we can stop |
128 |
|
std::map< int, bool > d_vars_set; |
129 |
|
std::vector< Node > d_extra_var; |
130 |
|
public: |
131 |
|
bool isBaseMatchComplete(); |
132 |
|
public: |
133 |
|
QuantInfo(); |
134 |
|
~QuantInfo(); |
135 |
|
/** Get quantifiers inference manager */ |
136 |
|
QuantifiersInferenceManager& getInferenceManager(); |
137 |
|
std::vector< TNode > d_vars; |
138 |
|
std::vector< TypeNode > d_var_types; |
139 |
|
std::map< TNode, int > d_var_num; |
140 |
|
std::vector< int > d_tsym_vars; |
141 |
|
std::map< TNode, bool > d_inMatchConstraint; |
142 |
7659919 |
int getVarNum( TNode v ) { return d_var_num.find( v )!=d_var_num.end() ? d_var_num[v] : -1; } |
143 |
423419 |
bool isVar( TNode v ) { return d_var_num.find( v )!=d_var_num.end(); } |
144 |
2243184 |
int getNumVars() { return (int)d_vars.size(); } |
145 |
414 |
TNode getVar( int i ) { return d_vars[i]; } |
146 |
|
|
147 |
|
typedef std::map< int, MatchGen * > VarMgMap; |
148 |
|
private: |
149 |
|
/** The parent who owns this class */ |
150 |
|
QuantConflictFind* d_parent; |
151 |
|
MatchGen * d_mg; |
152 |
|
VarMgMap d_var_mg; |
153 |
|
public: |
154 |
4261793 |
VarMgMap::const_iterator var_mg_find(int i) const { return d_var_mg.find(i); } |
155 |
3766709 |
VarMgMap::const_iterator var_mg_end() const { return d_var_mg.end(); } |
156 |
1389745 |
bool containsVarMg(int i) const { return var_mg_find(i) != var_mg_end(); } |
157 |
|
|
158 |
227318 |
bool matchGeneratorIsValid() const { return d_mg->isValid(); } |
159 |
356220 |
bool getNextMatch( QuantConflictFind * p ) { |
160 |
356220 |
return d_mg->getNextMatch(p, this); |
161 |
|
} |
162 |
|
|
163 |
|
Node d_q; |
164 |
|
bool reset_round( QuantConflictFind * p ); |
165 |
|
public: |
166 |
|
//initialize |
167 |
|
void initialize( QuantConflictFind * p, Node q, Node qn ); |
168 |
|
//current constraints |
169 |
|
std::vector< TNode > d_match; |
170 |
|
std::vector< TNode > d_match_term; |
171 |
|
std::map< int, std::map< TNode, int > > d_curr_var_deq; |
172 |
|
std::map< Node, bool > d_tconstraints; |
173 |
|
int getCurrentRepVar( int v ); |
174 |
|
TNode getCurrentValue( TNode n ); |
175 |
|
TNode getCurrentExpValue( TNode n ); |
176 |
|
bool getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq = false ); |
177 |
|
int addConstraint( QuantConflictFind * p, int v, TNode n, bool polarity ); |
178 |
|
int addConstraint( QuantConflictFind * p, int v, TNode n, int vn, bool polarity, bool doRemove ); |
179 |
|
bool setMatch( QuantConflictFind * p, int v, TNode n, bool isGroundRep, bool isGround ); |
180 |
|
void unsetMatch( QuantConflictFind * p, int v ); |
181 |
|
bool isMatchSpurious( QuantConflictFind * p ); |
182 |
|
bool isTConstraintSpurious( QuantConflictFind * p, std::vector< Node >& terms ); |
183 |
|
bool entailmentTest( QuantConflictFind * p, Node lit, bool chEnt = true ); |
184 |
|
bool completeMatch( QuantConflictFind * p, std::vector< int >& assigned, bool doContinue = false ); |
185 |
|
void revertMatch( QuantConflictFind * p, std::vector< int >& assigned ); |
186 |
|
void debugPrintMatch( const char * c ); |
187 |
|
bool isConstrainedVar( int v ); |
188 |
|
public: |
189 |
|
void getMatch( std::vector< Node >& terms ); |
190 |
|
}; |
191 |
|
|
192 |
9908 |
class QuantConflictFind : public QuantifiersModule |
193 |
|
{ |
194 |
|
friend class MatchGen; |
195 |
|
friend class QuantInfo; |
196 |
|
typedef context::CDHashMap<Node, bool> NodeBoolMap; |
197 |
|
|
198 |
|
private: |
199 |
|
context::CDO< bool > d_conflict; |
200 |
|
std::map< Kind, Node > d_zero; |
201 |
|
//for storing nodes created during t-constraint solving (prevents memory leaks) |
202 |
|
std::vector< Node > d_tempCache; |
203 |
|
//optimization: list of quantifiers that depend on ground function applications |
204 |
|
std::map< TNode, std::vector< Node > > d_func_rel_dom; |
205 |
|
std::map< TNode, bool > d_irr_func; |
206 |
|
std::map< Node, bool > d_irr_quant; |
207 |
|
void setIrrelevantFunction( TNode f ); |
208 |
|
private: |
209 |
|
std::map< Node, Node > d_op_node; |
210 |
|
std::map< Node, int > d_fid; |
211 |
|
public: //for ground terms |
212 |
|
Node d_true; |
213 |
|
Node d_false; |
214 |
|
TNode getZero( Kind k ); |
215 |
|
private: |
216 |
|
std::map< Node, QuantInfo > d_qinfo; |
217 |
|
private: //for equivalence classes |
218 |
|
// type -> list(eqc) |
219 |
|
std::map< TypeNode, std::vector< TNode > > d_eqcs; |
220 |
|
|
221 |
|
public: |
222 |
|
enum Effort : unsigned { |
223 |
|
EFFORT_CONFLICT, |
224 |
|
EFFORT_PROP_EQ, |
225 |
|
EFFORT_INVALID, |
226 |
|
}; |
227 |
|
void setEffort(Effort e) { d_effort = e; } |
228 |
|
|
229 |
1258326 |
inline bool atConflictEffort() const { |
230 |
1258326 |
return d_effort == QuantConflictFind::EFFORT_CONFLICT; |
231 |
|
} |
232 |
|
|
233 |
|
private: |
234 |
|
Effort d_effort; |
235 |
|
|
236 |
|
public: |
237 |
|
bool areMatchEqual( TNode n1, TNode n2 ); |
238 |
|
bool areMatchDisequal( TNode n1, TNode n2 ); |
239 |
|
|
240 |
|
public: |
241 |
|
QuantConflictFind(QuantifiersState& qs, |
242 |
|
QuantifiersInferenceManager& qim, |
243 |
|
QuantifiersRegistry& qr, |
244 |
|
TermRegistry& tr); |
245 |
|
|
246 |
|
/** register quantifier */ |
247 |
|
void registerQuantifier(Node q) override; |
248 |
|
|
249 |
|
public: |
250 |
|
/** needs check */ |
251 |
|
bool needsCheck(Theory::Effort level) override; |
252 |
|
/** reset round */ |
253 |
|
void reset_round(Theory::Effort level) override; |
254 |
|
/** check |
255 |
|
* |
256 |
|
* This method attempts to construct a conflicting or propagating instance. |
257 |
|
* If such an instance exists, then it makes a call to |
258 |
|
* Instantiation::addInstantiation. |
259 |
|
*/ |
260 |
|
void check(Theory::Effort level, QEffort quant_e) override; |
261 |
|
|
262 |
|
private: |
263 |
|
/** check quantified formula |
264 |
|
* |
265 |
|
* This method is called by the above check method for each quantified |
266 |
|
* formula q. It attempts to find a conflicting or propagating instance for |
267 |
|
* q, depending on the effort level (d_effort). |
268 |
|
* |
269 |
|
* isConflict: this is set to true if we discovered a conflicting instance. |
270 |
|
* This flag may be set instead of d_conflict if --qcf-all-conflict is true, |
271 |
|
* in which we continuing adding all conflicts. |
272 |
|
* addedLemmas: tracks the total number of lemmas added, and is incremented by |
273 |
|
* this method when applicable. |
274 |
|
*/ |
275 |
|
void checkQuantifiedFormula(Node q, bool& isConflict, unsigned& addedLemmas); |
276 |
|
|
277 |
|
private: |
278 |
|
void debugPrint( const char * c ); |
279 |
|
//for debugging |
280 |
|
std::vector< Node > d_quants; |
281 |
|
std::map< Node, int > d_quant_id; |
282 |
|
void debugPrintQuant( const char * c, Node q ); |
283 |
|
void debugPrintQuantBody( const char * c, Node q, Node n, bool doVarNum = true ); |
284 |
|
public: |
285 |
|
/** statistics class */ |
286 |
|
class Statistics { |
287 |
|
public: |
288 |
|
IntStat d_inst_rounds; |
289 |
|
IntStat d_entailment_checks; |
290 |
|
Statistics(); |
291 |
|
}; |
292 |
|
Statistics d_statistics; |
293 |
|
/** Identify this module */ |
294 |
153983 |
std::string identify() const override { return "QcfEngine"; } |
295 |
|
/** is n a propagating instance? |
296 |
|
* |
297 |
|
* A propagating instance is any formula that consists of Boolean connectives, |
298 |
|
* equality, quantified formulas, and terms that exist in the current |
299 |
|
* context (those in the master equality engine). |
300 |
|
* |
301 |
|
* Notice the distinction that quantified formulas that do not appear in the |
302 |
|
* current context are considered to be legal in propagating instances. This |
303 |
|
* choice is significant for TPTP, where a net of ~200 benchmarks are gained |
304 |
|
* due to this decision. |
305 |
|
* |
306 |
|
* Propagating instances are the second most useful kind of instantiation |
307 |
|
* after conflicting instances and are used as a second effort in the |
308 |
|
* algorithm performed by this class. |
309 |
|
*/ |
310 |
|
bool isPropagatingInstance(Node n) const; |
311 |
|
}; |
312 |
|
|
313 |
|
std::ostream& operator<<(std::ostream& os, const QuantConflictFind::Effort& e); |
314 |
|
|
315 |
|
} // namespace quantifiers |
316 |
|
} // namespace theory |
317 |
|
} // namespace cvc5 |
318 |
|
|
319 |
|
#endif |