1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Paul Meng, Gereon Kremer |
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 |
|
* Extension to Sets theory. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "theory/sets/theory_sets_rels.h" |
17 |
|
|
18 |
|
#include "expr/skolem_manager.h" |
19 |
|
#include "theory/sets/theory_sets.h" |
20 |
|
#include "theory/sets/theory_sets_private.h" |
21 |
|
#include "util/rational.h" |
22 |
|
|
23 |
|
using namespace std; |
24 |
|
using namespace cvc5::kind; |
25 |
|
|
26 |
|
namespace cvc5 { |
27 |
|
namespace theory { |
28 |
|
namespace sets { |
29 |
|
|
30 |
|
typedef std::map< Node, std::vector< Node > >::iterator MEM_IT; |
31 |
|
typedef std::map< kind::Kind_t, std::vector< Node > >::iterator KIND_TERM_IT; |
32 |
|
typedef std::map<Node, std::unordered_set<Node> >::iterator TC_GRAPH_IT; |
33 |
|
typedef std::map< Node, std::map< kind::Kind_t, std::vector< Node > > >::iterator TERM_IT; |
34 |
|
typedef std::map<Node, std::map<Node, std::unordered_set<Node> > >::iterator |
35 |
|
TC_IT; |
36 |
|
|
37 |
9915 |
TheorySetsRels::TheorySetsRels(SolverState& s, |
38 |
|
InferenceManager& im, |
39 |
|
SkolemCache& skc, |
40 |
9915 |
TermRegistry& treg) |
41 |
|
: d_state(s), |
42 |
|
d_im(im), |
43 |
|
d_skCache(skc), |
44 |
|
d_treg(treg), |
45 |
9915 |
d_shared_terms(s.getUserContext()) |
46 |
|
{ |
47 |
9915 |
d_trueNode = NodeManager::currentNM()->mkConst(true); |
48 |
9915 |
d_falseNode = NodeManager::currentNM()->mkConst(false); |
49 |
9915 |
} |
50 |
|
|
51 |
9912 |
TheorySetsRels::~TheorySetsRels() {} |
52 |
|
|
53 |
769 |
void TheorySetsRels::check(Theory::Effort level) |
54 |
|
{ |
55 |
1538 |
Trace("rels") << "\n[sets-rels] ******************************* Start the " |
56 |
769 |
"relational solver, effort = " |
57 |
769 |
<< level << " *******************************\n" |
58 |
769 |
<< std::endl; |
59 |
769 |
if (Theory::fullEffort(level)) |
60 |
|
{ |
61 |
769 |
collectRelsInfo(); |
62 |
769 |
check(); |
63 |
769 |
d_im.doPendingLemmas(); |
64 |
|
} |
65 |
769 |
Assert(!d_im.hasPendingLemma()); |
66 |
1538 |
Trace("rels") << "\n[sets-rels] ******************************* Done with " |
67 |
769 |
"the relational solver *******************************\n" |
68 |
769 |
<< std::endl; |
69 |
769 |
} |
70 |
|
|
71 |
769 |
void TheorySetsRels::check() { |
72 |
769 |
MEM_IT m_it = d_rReps_memberReps_cache.begin(); |
73 |
|
|
74 |
6329 |
while(m_it != d_rReps_memberReps_cache.end()) { |
75 |
5560 |
Node rel_rep = m_it->first; |
76 |
|
|
77 |
12070 |
for(unsigned int i = 0; i < m_it->second.size(); i++) { |
78 |
18580 |
Node mem = d_rReps_memberReps_cache[rel_rep][i]; |
79 |
18580 |
Node exp = d_rReps_memberReps_exp_cache[rel_rep][i]; |
80 |
|
std::map<kind::Kind_t, std::vector<Node> >& kind_terms = |
81 |
9290 |
d_terms_cache[rel_rep]; |
82 |
|
|
83 |
9290 |
if( kind_terms.find(kind::TRANSPOSE) != kind_terms.end() ) { |
84 |
1337 |
std::vector<Node>& tp_terms = kind_terms[TRANSPOSE]; |
85 |
1337 |
if( tp_terms.size() > 0 ) { |
86 |
1337 |
applyTransposeRule( tp_terms ); |
87 |
1337 |
applyTransposeRule( tp_terms[0], rel_rep, exp ); |
88 |
|
} |
89 |
|
} |
90 |
9290 |
if( kind_terms.find(kind::JOIN) != kind_terms.end() ) { |
91 |
1242 |
std::vector<Node>& join_terms = kind_terms[JOIN]; |
92 |
2740 |
for( unsigned int j = 0; j < join_terms.size(); j++ ) { |
93 |
1498 |
applyJoinRule( join_terms[j], rel_rep, exp ); |
94 |
|
} |
95 |
|
} |
96 |
9290 |
if( kind_terms.find(kind::PRODUCT) != kind_terms.end() ) { |
97 |
169 |
std::vector<Node>& product_terms = kind_terms[PRODUCT]; |
98 |
338 |
for( unsigned int j = 0; j < product_terms.size(); j++ ) { |
99 |
169 |
applyProductRule( product_terms[j], rel_rep, exp ); |
100 |
|
} |
101 |
|
} |
102 |
9290 |
if( kind_terms.find(kind::TCLOSURE) != kind_terms.end() ) { |
103 |
266 |
std::vector<Node>& tc_terms = kind_terms[TCLOSURE]; |
104 |
532 |
for( unsigned int j = 0; j < tc_terms.size(); j++ ) { |
105 |
266 |
applyTCRule( mem, tc_terms[j], rel_rep, exp ); |
106 |
|
} |
107 |
|
} |
108 |
9290 |
if( kind_terms.find(kind::JOIN_IMAGE) != kind_terms.end() ) { |
109 |
139 |
std::vector<Node>& join_image_terms = kind_terms[JOIN_IMAGE]; |
110 |
278 |
for( unsigned int j = 0; j < join_image_terms.size(); j++ ) { |
111 |
139 |
applyJoinImageRule( mem, join_image_terms[j], exp ); |
112 |
|
} |
113 |
|
} |
114 |
9290 |
if( kind_terms.find(kind::IDEN) != kind_terms.end() ) { |
115 |
23 |
std::vector<Node>& iden_terms = kind_terms[IDEN]; |
116 |
46 |
for( unsigned int j = 0; j < iden_terms.size(); j++ ) { |
117 |
23 |
applyIdenRule( mem, iden_terms[j], exp ); |
118 |
|
} |
119 |
|
} |
120 |
|
} |
121 |
2780 |
++m_it; |
122 |
|
} |
123 |
|
|
124 |
769 |
TERM_IT t_it = d_terms_cache.begin(); |
125 |
7695 |
while( t_it != d_terms_cache.end() ) { |
126 |
3463 |
if( d_rReps_memberReps_cache.find(t_it->first) == d_rReps_memberReps_cache.end() ) { |
127 |
683 |
Trace("rels-debug") << "[sets-rels] A term does not have membership constraints: " << t_it->first << std::endl; |
128 |
683 |
KIND_TERM_IT k_t_it = t_it->second.begin(); |
129 |
|
|
130 |
2049 |
while( k_t_it != t_it->second.end() ) { |
131 |
683 |
if( k_t_it->first == kind::JOIN || k_t_it->first == kind::PRODUCT ) { |
132 |
477 |
std::vector<Node>::iterator term_it = k_t_it->second.begin(); |
133 |
1447 |
while(term_it != k_t_it->second.end()) { |
134 |
485 |
computeMembersForBinOpRel( *term_it ); |
135 |
485 |
++term_it; |
136 |
|
} |
137 |
206 |
} else if( k_t_it->first == kind::TRANSPOSE ) { |
138 |
171 |
std::vector<Node>::iterator term_it = k_t_it->second.begin(); |
139 |
513 |
while( term_it != k_t_it->second.end() ) { |
140 |
171 |
computeMembersForUnaryOpRel( *term_it ); |
141 |
171 |
++term_it; |
142 |
|
} |
143 |
35 |
} else if ( k_t_it->first == kind::TCLOSURE ) { |
144 |
25 |
std::vector<Node>::iterator term_it = k_t_it->second.begin(); |
145 |
75 |
while( term_it != k_t_it->second.end() ) { |
146 |
25 |
buildTCGraphForRel( *term_it ); |
147 |
25 |
++term_it; |
148 |
|
} |
149 |
10 |
} else if( k_t_it->first == kind::JOIN_IMAGE ) { |
150 |
2 |
std::vector<Node>::iterator term_it = k_t_it->second.begin(); |
151 |
6 |
while( term_it != k_t_it->second.end() ) { |
152 |
2 |
computeMembersForJoinImageTerm( *term_it ); |
153 |
2 |
++term_it; |
154 |
|
} |
155 |
8 |
} else if( k_t_it->first == kind::IDEN ) { |
156 |
8 |
std::vector<Node>::iterator term_it = k_t_it->second.begin(); |
157 |
24 |
while( term_it != k_t_it->second.end() ) { |
158 |
8 |
computeMembersForIdenTerm( *term_it ); |
159 |
8 |
++term_it; |
160 |
|
} |
161 |
|
} |
162 |
683 |
++k_t_it; |
163 |
|
} |
164 |
|
} |
165 |
3463 |
++t_it; |
166 |
|
} |
167 |
769 |
doTCInference(); |
168 |
|
|
169 |
|
// clean up |
170 |
769 |
d_tuple_reps.clear(); |
171 |
769 |
d_rReps_memberReps_exp_cache.clear(); |
172 |
769 |
d_terms_cache.clear(); |
173 |
769 |
d_membership_trie.clear(); |
174 |
769 |
d_rel_nodes.clear(); |
175 |
769 |
d_rReps_memberReps_cache.clear(); |
176 |
769 |
d_rRep_tcGraph.clear(); |
177 |
769 |
d_tcr_tcGraph_exps.clear(); |
178 |
769 |
d_tcr_tcGraph.clear(); |
179 |
769 |
} |
180 |
|
|
181 |
|
/* |
182 |
|
* Populate relational terms data structure |
183 |
|
*/ |
184 |
|
|
185 |
769 |
void TheorySetsRels::collectRelsInfo() { |
186 |
769 |
Trace("rels") << "[sets-rels] Start collecting relational terms..." << std::endl; |
187 |
769 |
eq::EqualityEngine* ee = d_state.getEqualityEngine(); |
188 |
769 |
eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(ee); |
189 |
45429 |
while( !eqcs_i.isFinished() ){ |
190 |
44660 |
Node eqc_rep = (*eqcs_i); |
191 |
22330 |
eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc_rep, ee); |
192 |
|
|
193 |
44660 |
TypeNode erType = eqc_rep.getType(); |
194 |
22330 |
Trace("rels-ee") << "[sets-rels-ee] Eqc term representative: " << eqc_rep << " with type " << eqc_rep.getType() << std::endl; |
195 |
|
|
196 |
138662 |
while( !eqc_i.isFinished() ){ |
197 |
116332 |
Node eqc_node = (*eqc_i); |
198 |
|
|
199 |
58166 |
Trace("rels-ee") << " term : " << eqc_node << std::endl; |
200 |
|
|
201 |
58166 |
if (erType.isBoolean() && eqc_rep.isConst()) |
202 |
|
{ |
203 |
|
// collect membership info |
204 |
24082 |
if( eqc_node.getKind() == kind::MEMBER && eqc_node[1].getType().getSetElementType().isTuple()) { |
205 |
28168 |
Node tup_rep = getRepresentative( eqc_node[0] ); |
206 |
28168 |
Node rel_rep = getRepresentative( eqc_node[1] ); |
207 |
|
|
208 |
14084 |
if( eqc_node[0].isVar() ){ |
209 |
1882 |
reduceTupleVar( eqc_node ); |
210 |
|
} |
211 |
|
|
212 |
14084 |
bool is_true_eq = eqc_rep.getConst<bool>(); |
213 |
28168 |
Node reason = is_true_eq ? eqc_node : eqc_node.negate(); |
214 |
|
|
215 |
14084 |
if( is_true_eq ) { |
216 |
12949 |
if( safelyAddToMap(d_rReps_memberReps_cache, rel_rep, tup_rep) ) { |
217 |
9290 |
d_rReps_memberReps_exp_cache[rel_rep].push_back(reason); |
218 |
9290 |
computeTupleReps(tup_rep); |
219 |
9290 |
d_membership_trie[rel_rep].addTerm(tup_rep, d_tuple_reps[tup_rep]); |
220 |
|
} |
221 |
|
} |
222 |
|
} |
223 |
|
// collect relational terms info |
224 |
|
} |
225 |
34084 |
else if (erType.isSet() && erType.getSetElementType().isTuple()) |
226 |
|
{ |
227 |
16938 |
if( eqc_node.getKind() == kind::TRANSPOSE || eqc_node.getKind() == kind::JOIN || |
228 |
9936 |
eqc_node.getKind() == kind::PRODUCT || eqc_node.getKind() == kind::TCLOSURE || |
229 |
10951 |
eqc_node.getKind() == kind::JOIN_IMAGE || eqc_node.getKind() == kind::IDEN ) { |
230 |
3036 |
std::vector<Node> terms; |
231 |
3036 |
std::map< kind::Kind_t, std::vector<Node> > rel_terms; |
232 |
1518 |
TERM_IT terms_it = d_terms_cache.find(eqc_rep); |
233 |
|
|
234 |
1518 |
if( terms_it == d_terms_cache.end() ) { |
235 |
1400 |
terms.push_back(eqc_node); |
236 |
1400 |
rel_terms[eqc_node.getKind()] = terms; |
237 |
1400 |
d_terms_cache[eqc_rep] = rel_terms; |
238 |
|
} else { |
239 |
118 |
KIND_TERM_IT kind_term_it = terms_it->second.find(eqc_node.getKind()); |
240 |
|
|
241 |
118 |
if( kind_term_it == terms_it->second.end() ) { |
242 |
38 |
terms.push_back(eqc_node); |
243 |
38 |
d_terms_cache[eqc_rep][eqc_node.getKind()] = terms; |
244 |
|
} else { |
245 |
80 |
kind_term_it->second.push_back(eqc_node); |
246 |
|
} |
247 |
|
} |
248 |
|
} |
249 |
|
// need to add all tuple elements as shared terms |
250 |
|
} |
251 |
29456 |
else if (erType.isTuple() && !eqc_node.isConst() && !eqc_node.isVar()) |
252 |
|
{ |
253 |
11792 |
std::vector<TypeNode> tupleTypes = erType.getTupleTypes(); |
254 |
17813 |
for (unsigned i = 0, tlen = erType.getTupleLength(); i < tlen; i++) |
255 |
|
{ |
256 |
23834 |
Node element = RelsUtils::nthElementOfTuple(eqc_node, i); |
257 |
11917 |
if (!element.isConst()) |
258 |
|
{ |
259 |
10557 |
makeSharedTerm(element, tupleTypes[i]); |
260 |
|
} |
261 |
|
} |
262 |
|
} |
263 |
58166 |
++eqc_i; |
264 |
|
} |
265 |
22330 |
++eqcs_i; |
266 |
|
} |
267 |
769 |
Trace("rels-debug") << "[Theory::Rels] Done with collecting relational terms!" << std::endl; |
268 |
769 |
} |
269 |
|
|
270 |
|
/* JOIN-IMAGE UP : (x, x1) IS_IN R, ..., (x, xn) IS_IN R (R JOIN_IMAGE n) |
271 |
|
* ------------------------------------------------------- |
272 |
|
* x IS_IN (R JOIN_IMAGE n) || NOT DISTINCT(x1, ... , xn) |
273 |
|
* |
274 |
|
*/ |
275 |
|
|
276 |
71 |
void TheorySetsRels::computeMembersForJoinImageTerm( Node join_image_term ) { |
277 |
71 |
Trace("rels-debug") << "\n[Theory::Rels] *********** Compute members for JoinImage Term = " << join_image_term << std::endl; |
278 |
71 |
MEM_IT rel_mem_it = d_rReps_memberReps_cache.find( getRepresentative( join_image_term[0] ) ); |
279 |
|
|
280 |
71 |
if( rel_mem_it == d_rReps_memberReps_cache.end() ) { |
281 |
|
return; |
282 |
|
} |
283 |
71 |
NodeManager* nm = NodeManager::currentNM(); |
284 |
|
|
285 |
142 |
Node join_image_rel = join_image_term[0]; |
286 |
142 |
std::unordered_set<Node> hasChecked; |
287 |
142 |
Node join_image_rel_rep = getRepresentative( join_image_rel ); |
288 |
71 |
std::vector< Node >::iterator mem_rep_it = (*rel_mem_it).second.begin(); |
289 |
71 |
MEM_IT rel_mem_exp_it = d_rReps_memberReps_exp_cache.find( join_image_rel_rep ); |
290 |
71 |
std::vector< Node >::iterator mem_rep_exp_it = (*rel_mem_exp_it).second.begin(); |
291 |
71 |
unsigned int min_card = join_image_term[1].getConst<Rational>().getNumerator().getUnsignedInt(); |
292 |
|
|
293 |
721 |
while( mem_rep_it != (*rel_mem_it).second.end() ) { |
294 |
431 |
Node fst_mem_rep = RelsUtils::nthElementOfTuple( *mem_rep_it, 0 ); |
295 |
|
|
296 |
430 |
if( hasChecked.find( fst_mem_rep ) != hasChecked.end() ) { |
297 |
105 |
++mem_rep_it; |
298 |
105 |
++mem_rep_exp_it; |
299 |
105 |
continue; |
300 |
|
} |
301 |
220 |
hasChecked.insert( fst_mem_rep ); |
302 |
|
|
303 |
|
const DType& dt = |
304 |
220 |
join_image_term.getType().getSetElementType().getDType(); |
305 |
|
Node new_membership = nm->mkNode( |
306 |
|
MEMBER, |
307 |
440 |
nm->mkNode(APPLY_CONSTRUCTOR, dt[0].getConstructor(), fst_mem_rep), |
308 |
766 |
join_image_term); |
309 |
334 |
if (d_state.isEntailed(new_membership, true)) |
310 |
|
{ |
311 |
114 |
++mem_rep_it; |
312 |
114 |
++mem_rep_exp_it; |
313 |
114 |
continue; |
314 |
|
} |
315 |
|
|
316 |
212 |
std::vector< Node > reasons; |
317 |
212 |
std::vector< Node > existing_members; |
318 |
106 |
std::vector< Node >::iterator mem_rep_exp_it_snd = (*rel_mem_exp_it).second.begin(); |
319 |
|
|
320 |
818 |
while( mem_rep_exp_it_snd != (*rel_mem_exp_it).second.end() ) { |
321 |
750 |
Node fst_element_snd_mem = RelsUtils::nthElementOfTuple( (*mem_rep_exp_it_snd)[0], 0 ); |
322 |
|
|
323 |
394 |
if( areEqual( fst_mem_rep, fst_element_snd_mem ) ) { |
324 |
118 |
bool notExist = true; |
325 |
118 |
std::vector< Node >::iterator existing_mem_it = existing_members.begin(); |
326 |
198 |
Node snd_element_snd_mem = RelsUtils::nthElementOfTuple( (*mem_rep_exp_it_snd)[0], 1 ); |
327 |
|
|
328 |
160 |
while( existing_mem_it != existing_members.end() ) { |
329 |
21 |
if( areEqual( (*existing_mem_it), snd_element_snd_mem ) ) { |
330 |
|
notExist = false; |
331 |
|
break; |
332 |
|
} |
333 |
21 |
++existing_mem_it; |
334 |
|
} |
335 |
|
|
336 |
118 |
if( notExist ) { |
337 |
118 |
existing_members.push_back( snd_element_snd_mem ); |
338 |
118 |
reasons.push_back( *mem_rep_exp_it_snd ); |
339 |
118 |
if( fst_mem_rep != fst_element_snd_mem ) { |
340 |
6 |
reasons.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, fst_mem_rep, fst_element_snd_mem ) ); |
341 |
|
} |
342 |
118 |
if( join_image_rel != (*mem_rep_exp_it_snd)[1] ) { |
343 |
70 |
reasons.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, (*mem_rep_exp_it_snd)[1], join_image_rel )); |
344 |
|
} |
345 |
118 |
if( existing_members.size() == min_card ) { |
346 |
38 |
if( min_card >= 2) { |
347 |
16 |
new_membership = NodeManager::currentNM()->mkNode( kind::OR, new_membership, NodeManager::currentNM()->mkNode( kind::NOT, NodeManager::currentNM()->mkNode( kind::DISTINCT, existing_members ) )); |
348 |
|
} |
349 |
38 |
Assert(reasons.size() >= 1); |
350 |
38 |
sendInfer( |
351 |
|
new_membership, |
352 |
|
InferenceId::SETS_RELS_JOIN_IMAGE_UP, |
353 |
76 |
reasons.size() > 1 ? nm->mkNode(AND, reasons) : reasons[0]); |
354 |
38 |
break; |
355 |
|
} |
356 |
|
} |
357 |
|
} |
358 |
356 |
++mem_rep_exp_it_snd; |
359 |
|
} |
360 |
106 |
++mem_rep_it; |
361 |
106 |
++mem_rep_exp_it; |
362 |
|
} |
363 |
71 |
Trace("rels-debug") << "\n[Theory::Rels] *********** Done with computing members for JoinImage Term" << join_image_term << "*********** " << std::endl; |
364 |
|
} |
365 |
|
|
366 |
|
/* JOIN-IMAGE DOWN : (x) IS_IN (R JOIN_IMAGE n) |
367 |
|
* ------------------------------------------------------- |
368 |
|
* (x, x1) IS_IN R .... (x, xn) IS_IN R DISTINCT(x1, ... |
369 |
|
* , xn) |
370 |
|
* |
371 |
|
*/ |
372 |
139 |
void TheorySetsRels::applyJoinImageRule( Node mem_rep, Node join_image_term, Node exp ) { |
373 |
278 |
Trace("rels-debug") << "\n[Theory::Rels] *********** applyJoinImageRule on " << join_image_term |
374 |
139 |
<< " with mem_rep = " << mem_rep << " and exp = " << exp << std::endl; |
375 |
139 |
if( d_rel_nodes.find( join_image_term ) == d_rel_nodes.end() ) { |
376 |
69 |
computeMembersForJoinImageTerm( join_image_term ); |
377 |
69 |
d_rel_nodes.insert( join_image_term ); |
378 |
|
} |
379 |
|
|
380 |
176 |
Node join_image_rel = join_image_term[0]; |
381 |
176 |
Node join_image_rel_rep = getRepresentative( join_image_rel ); |
382 |
139 |
MEM_IT rel_mem_it = d_rReps_memberReps_cache.find( join_image_rel_rep ); |
383 |
139 |
unsigned int min_card = join_image_term[1].getConst<Rational>().getNumerator().getUnsignedInt(); |
384 |
|
|
385 |
139 |
if( rel_mem_it != d_rReps_memberReps_cache.end() ) { |
386 |
139 |
if( d_membership_trie.find( join_image_rel_rep ) != d_membership_trie.end() ) { |
387 |
139 |
computeTupleReps( mem_rep ); |
388 |
139 |
if( d_membership_trie[join_image_rel_rep].findSuccessors(d_tuple_reps[mem_rep]).size() >= min_card ) { |
389 |
102 |
return; |
390 |
|
} |
391 |
|
} |
392 |
|
} |
393 |
37 |
NodeManager* nm = NodeManager::currentNM(); |
394 |
37 |
SkolemManager* sm = nm->getSkolemManager(); |
395 |
74 |
Node reason = exp; |
396 |
74 |
Node conclusion = d_trueNode; |
397 |
74 |
std::vector< Node > distinct_skolems; |
398 |
74 |
Node fst_mem_element = RelsUtils::nthElementOfTuple( exp[0], 0 ); |
399 |
|
|
400 |
37 |
if( exp[1] != join_image_term ) { |
401 |
4 |
reason = |
402 |
8 |
nm->mkNode(AND, reason, nm->mkNode(EQUAL, exp[1], join_image_term)); |
403 |
|
} |
404 |
108 |
for( unsigned int i = 0; i < min_card; i++ ) { |
405 |
|
Node skolem = sm->mkDummySkolem( |
406 |
142 |
"jig", join_image_rel.getType()[0].getTupleTypes()[0]); |
407 |
71 |
distinct_skolems.push_back( skolem ); |
408 |
71 |
conclusion = nm->mkNode( |
409 |
|
AND, |
410 |
|
conclusion, |
411 |
284 |
nm->mkNode( |
412 |
|
MEMBER, |
413 |
142 |
RelsUtils::constructPair(join_image_rel, fst_mem_element, skolem), |
414 |
|
join_image_rel)); |
415 |
|
} |
416 |
37 |
if( distinct_skolems.size() >= 2 ) { |
417 |
31 |
conclusion = |
418 |
62 |
nm->mkNode(AND, conclusion, nm->mkNode(DISTINCT, distinct_skolems)); |
419 |
|
} |
420 |
37 |
sendInfer(conclusion, InferenceId::SETS_RELS_JOIN_IMAGE_DOWN, reason); |
421 |
37 |
Trace("rels-debug") << "\n[Theory::Rels] *********** Done with applyJoinImageRule ***********" << std::endl; |
422 |
|
} |
423 |
|
|
424 |
|
/* IDENTITY-DOWN : (x, y) IS_IN IDEN(R) |
425 |
|
* ------------------------------------------------------- |
426 |
|
* x = y, (x IS_IN R) |
427 |
|
* |
428 |
|
*/ |
429 |
|
|
430 |
23 |
void TheorySetsRels::applyIdenRule( Node mem_rep, Node iden_term, Node exp) { |
431 |
46 |
Trace("rels-debug") << "\n[Theory::Rels] *********** applyIdenRule on " << iden_term |
432 |
23 |
<< " with mem_rep = " << mem_rep << " and exp = " << exp << std::endl; |
433 |
23 |
NodeManager* nm = NodeManager::currentNM(); |
434 |
23 |
if( d_rel_nodes.find( iden_term ) == d_rel_nodes.end() ) { |
435 |
8 |
computeMembersForIdenTerm( iden_term ); |
436 |
8 |
d_rel_nodes.insert( iden_term ); |
437 |
|
} |
438 |
46 |
Node reason = exp; |
439 |
46 |
Node fst_mem = RelsUtils::nthElementOfTuple( exp[0], 0 ); |
440 |
46 |
Node snd_mem = RelsUtils::nthElementOfTuple( exp[0], 1 ); |
441 |
23 |
const DType& dt = iden_term[0].getType().getSetElementType().getDType(); |
442 |
|
Node fact = nm->mkNode( |
443 |
|
MEMBER, |
444 |
46 |
nm->mkNode(APPLY_CONSTRUCTOR, dt[0].getConstructor(), fst_mem), |
445 |
92 |
iden_term[0]); |
446 |
|
|
447 |
23 |
if( exp[1] != iden_term ) { |
448 |
7 |
reason = NodeManager::currentNM()->mkNode( kind::AND, reason, NodeManager::currentNM()->mkNode( kind::EQUAL, exp[1], iden_term ) ); |
449 |
|
} |
450 |
23 |
sendInfer(nm->mkNode(AND, fact, nm->mkNode(EQUAL, fst_mem, snd_mem)), |
451 |
|
InferenceId::SETS_RELS_IDENTITY_DOWN, |
452 |
|
reason); |
453 |
23 |
Trace("rels-debug") << "\n[Theory::Rels] *********** Done with applyIdenRule on " << iden_term << std::endl; |
454 |
23 |
} |
455 |
|
|
456 |
|
/* IDEN UP : (x) IS_IN R IDEN(R) IN T |
457 |
|
* -------------------------------- |
458 |
|
* (x, x) IS_IN IDEN(R) |
459 |
|
* |
460 |
|
*/ |
461 |
|
|
462 |
16 |
void TheorySetsRels::computeMembersForIdenTerm( Node iden_term ) { |
463 |
16 |
Trace("rels-debug") << "\n[Theory::Rels] *********** Compute members for Iden Term = " << iden_term << std::endl; |
464 |
26 |
Node iden_term_rel = iden_term[0]; |
465 |
26 |
Node iden_term_rel_rep = getRepresentative( iden_term_rel ); |
466 |
|
|
467 |
16 |
if( d_rReps_memberReps_cache.find( iden_term_rel_rep ) == d_rReps_memberReps_cache.end() ) { |
468 |
6 |
return; |
469 |
|
} |
470 |
10 |
NodeManager* nm = NodeManager::currentNM(); |
471 |
|
|
472 |
10 |
MEM_IT rel_mem_exp_it = d_rReps_memberReps_exp_cache.find( iden_term_rel_rep ); |
473 |
10 |
std::vector< Node >::iterator mem_rep_exp_it = (*rel_mem_exp_it).second.begin(); |
474 |
|
|
475 |
72 |
while( mem_rep_exp_it != (*rel_mem_exp_it).second.end() ) { |
476 |
62 |
Node reason = *mem_rep_exp_it; |
477 |
62 |
Node fst_exp_mem = RelsUtils::nthElementOfTuple( (*mem_rep_exp_it)[0], 0 ); |
478 |
62 |
Node new_mem = RelsUtils::constructPair( iden_term, fst_exp_mem, fst_exp_mem ); |
479 |
|
|
480 |
31 |
if( (*mem_rep_exp_it)[1] != iden_term_rel ) { |
481 |
|
reason = NodeManager::currentNM()->mkNode( kind::AND, reason, NodeManager::currentNM()->mkNode( kind::EQUAL, (*mem_rep_exp_it)[1], iden_term_rel ) ); |
482 |
|
} |
483 |
93 |
sendInfer( |
484 |
62 |
nm->mkNode(MEMBER, new_mem, iden_term), InferenceId::SETS_RELS_IDENTITY_UP, reason); |
485 |
31 |
++mem_rep_exp_it; |
486 |
|
} |
487 |
10 |
Trace("rels-debug") << "\n[Theory::Rels] *********** Done with computing members for Iden Term = " << iden_term << std::endl; |
488 |
|
} |
489 |
|
|
490 |
|
|
491 |
|
/* |
492 |
|
* Construct transitive closure graph for tc_rep based on the members of tc_r_rep |
493 |
|
*/ |
494 |
|
|
495 |
|
/* |
496 |
|
* TCLOSURE TCLOSURE(x) = x | x.x | x.x.x | ... (| is union) |
497 |
|
* |
498 |
|
* TCLOSURE-UP I: (a, b) IS_IN x TCLOSURE(x) in T |
499 |
|
* --------------------------------------------- |
500 |
|
* (a, b) IS_IN TCLOSURE(x) |
501 |
|
* |
502 |
|
* |
503 |
|
* |
504 |
|
* TCLOSURE-UP II : (a, b) IS_IN TCLOSURE(x) (b, c) IS_IN TCLOSURE(x) |
505 |
|
* ----------------------------------------------------------- |
506 |
|
* (a, c) IS_IN TCLOSURE(x) |
507 |
|
* |
508 |
|
*/ |
509 |
266 |
void TheorySetsRels::applyTCRule( Node mem_rep, Node tc_rel, Node tc_rel_rep, Node exp ) { |
510 |
532 |
Trace("rels-debug") << "[Theory::Rels] *********** Applying TCLOSURE rule on a tc term = " << tc_rel |
511 |
266 |
<< ", its representative = " << tc_rel_rep |
512 |
266 |
<< " with member rep = " << mem_rep << " and explanation = " << exp << std::endl; |
513 |
266 |
MEM_IT mem_it = d_rReps_memberReps_cache.find( tc_rel[0] ); |
514 |
|
|
515 |
790 |
if( mem_it != d_rReps_memberReps_cache.end() && d_rel_nodes.find( tc_rel ) == d_rel_nodes.end() |
516 |
625 |
&& d_rRep_tcGraph.find( getRepresentative( tc_rel[0] ) ) == d_rRep_tcGraph.end() ) { |
517 |
93 |
buildTCGraphForRel( tc_rel ); |
518 |
93 |
d_rel_nodes.insert( tc_rel ); |
519 |
|
} |
520 |
|
|
521 |
|
// mem_rep is a member of tc_rel[0] or mem_rep can be infered by TC_Graph of tc_rel[0], thus skip |
522 |
266 |
if( isTCReachable( mem_rep, tc_rel) ) { |
523 |
486 |
Trace("rels-debug") << "[Theory::Rels] mem_rep is a member of tc_rel[0] = " << tc_rel[0] |
524 |
243 |
<< " or can be infered by TC_Graph of tc_rel[0]! " << std::endl; |
525 |
243 |
return; |
526 |
|
} |
527 |
23 |
NodeManager* nm = NodeManager::currentNM(); |
528 |
|
|
529 |
|
// add mem_rep to d_tcrRep_tcGraph |
530 |
23 |
TC_IT tc_it = d_tcr_tcGraph.find( tc_rel ); |
531 |
46 |
Node mem_rep_fst = getRepresentative( RelsUtils::nthElementOfTuple( mem_rep, 0 ) ); |
532 |
46 |
Node mem_rep_snd = getRepresentative( RelsUtils::nthElementOfTuple( mem_rep, 1 ) ); |
533 |
46 |
Node mem_rep_tup = RelsUtils::constructPair( tc_rel, mem_rep_fst, mem_rep_snd ); |
534 |
|
|
535 |
23 |
if( tc_it != d_tcr_tcGraph.end() ) { |
536 |
15 |
std::map< Node, std::map< Node, Node > >::iterator tc_exp_it = d_tcr_tcGraph_exps.find( tc_rel ); |
537 |
|
|
538 |
15 |
TC_GRAPH_IT tc_graph_it = (tc_it->second).find( mem_rep_fst ); |
539 |
15 |
Assert(tc_exp_it != d_tcr_tcGraph_exps.end()); |
540 |
15 |
std::map< Node, Node >::iterator exp_map_it = (tc_exp_it->second).find( mem_rep_tup ); |
541 |
|
|
542 |
15 |
if( exp_map_it == (tc_exp_it->second).end() ) { |
543 |
15 |
(tc_exp_it->second)[mem_rep_tup] = exp; |
544 |
|
} |
545 |
|
|
546 |
15 |
if( tc_graph_it != (tc_it->second).end() ) { |
547 |
8 |
(tc_graph_it->second).insert( mem_rep_snd ); |
548 |
|
} else { |
549 |
14 |
std::unordered_set<Node> sets; |
550 |
7 |
sets.insert( mem_rep_snd ); |
551 |
7 |
(tc_it->second)[mem_rep_fst] = sets; |
552 |
|
} |
553 |
|
} else { |
554 |
16 |
std::map< Node, Node > exp_map; |
555 |
16 |
std::unordered_set<Node> sets; |
556 |
16 |
std::map<Node, std::unordered_set<Node> > element_map; |
557 |
8 |
sets.insert( mem_rep_snd ); |
558 |
8 |
element_map[mem_rep_fst] = sets; |
559 |
8 |
d_tcr_tcGraph[tc_rel] = element_map; |
560 |
8 |
exp_map[mem_rep_tup] = exp; |
561 |
8 |
d_tcr_tcGraph_exps[tc_rel] = exp_map; |
562 |
|
} |
563 |
46 |
Node fst_element = RelsUtils::nthElementOfTuple( exp[0], 0 ); |
564 |
46 |
Node snd_element = RelsUtils::nthElementOfTuple( exp[0], 1 ); |
565 |
69 |
Node sk_1 = d_skCache.mkTypedSkolemCached(fst_element.getType(), |
566 |
|
exp[0], |
567 |
|
tc_rel[0], |
568 |
|
SkolemCache::SK_TCLOSURE_DOWN1, |
569 |
92 |
"stc1"); |
570 |
69 |
Node sk_2 = d_skCache.mkTypedSkolemCached(fst_element.getType(), |
571 |
|
exp[0], |
572 |
|
tc_rel[0], |
573 |
|
SkolemCache::SK_TCLOSURE_DOWN2, |
574 |
92 |
"stc2"); |
575 |
46 |
Node mem_of_r = nm->mkNode(MEMBER, exp[0], tc_rel[0]); |
576 |
46 |
Node sk_eq = nm->mkNode(EQUAL, sk_1, sk_2); |
577 |
46 |
Node reason = exp; |
578 |
|
|
579 |
23 |
if( tc_rel != exp[1] ) { |
580 |
3 |
reason = nm->mkNode(AND, reason, nm->mkNode(EQUAL, tc_rel, exp[1])); |
581 |
|
} |
582 |
|
|
583 |
|
Node conc = nm->mkNode( |
584 |
|
OR, |
585 |
|
mem_of_r, |
586 |
138 |
nm->mkNode( |
587 |
|
AND, |
588 |
92 |
nm->mkNode(MEMBER, |
589 |
46 |
RelsUtils::constructPair(tc_rel, fst_element, sk_1), |
590 |
|
tc_rel[0]), |
591 |
92 |
nm->mkNode(MEMBER, |
592 |
46 |
RelsUtils::constructPair(tc_rel, sk_2, snd_element), |
593 |
|
tc_rel[0]), |
594 |
46 |
nm->mkNode(OR, |
595 |
|
sk_eq, |
596 |
92 |
nm->mkNode(MEMBER, |
597 |
46 |
RelsUtils::constructPair(tc_rel, sk_1, sk_2), |
598 |
46 |
tc_rel)))); |
599 |
|
|
600 |
23 |
sendInfer(conc, InferenceId::SETS_RELS_TCLOSURE_UP, reason); |
601 |
|
} |
602 |
|
|
603 |
266 |
bool TheorySetsRels::isTCReachable( Node mem_rep, Node tc_rel ) { |
604 |
266 |
MEM_IT mem_it = d_rReps_memberReps_cache.find( getRepresentative( tc_rel[0] ) ); |
605 |
|
|
606 |
266 |
if( mem_it != d_rReps_memberReps_cache.end() && std::find( (mem_it->second).begin(), (mem_it->second).end(), mem_rep) != (mem_it->second).end() ) { |
607 |
154 |
return true; |
608 |
|
} |
609 |
|
|
610 |
112 |
TC_IT tc_it = d_rRep_tcGraph.find( getRepresentative(tc_rel[0]) ); |
611 |
112 |
if( tc_it != d_rRep_tcGraph.end() ) { |
612 |
104 |
bool isReachable = false; |
613 |
208 |
std::unordered_set<Node> seen; |
614 |
208 |
isTCReachable( getRepresentative( RelsUtils::nthElementOfTuple(mem_rep, 0) ), |
615 |
312 |
getRepresentative( RelsUtils::nthElementOfTuple(mem_rep, 1) ), seen, tc_it->second, isReachable ); |
616 |
104 |
return isReachable; |
617 |
|
} |
618 |
8 |
return false; |
619 |
|
} |
620 |
|
|
621 |
220 |
void TheorySetsRels::isTCReachable( |
622 |
|
Node start, |
623 |
|
Node dest, |
624 |
|
std::unordered_set<Node>& hasSeen, |
625 |
|
std::map<Node, std::unordered_set<Node> >& tc_graph, |
626 |
|
bool& isReachable) |
627 |
|
{ |
628 |
220 |
if(hasSeen.find(start) == hasSeen.end()) { |
629 |
220 |
hasSeen.insert(start); |
630 |
|
} |
631 |
|
|
632 |
220 |
TC_GRAPH_IT pair_set_it = tc_graph.find(start); |
633 |
|
|
634 |
220 |
if(pair_set_it != tc_graph.end()) { |
635 |
192 |
if(pair_set_it->second.find(dest) != pair_set_it->second.end()) { |
636 |
89 |
isReachable = true; |
637 |
178 |
return; |
638 |
|
} else { |
639 |
103 |
std::unordered_set<Node>::iterator set_it = pair_set_it->second.begin(); |
640 |
|
|
641 |
335 |
while( set_it != pair_set_it->second.end() ) { |
642 |
|
// need to check if *set_it has been looked already |
643 |
116 |
if( hasSeen.find(*set_it) == hasSeen.end() ) { |
644 |
116 |
isTCReachable( *set_it, dest, hasSeen, tc_graph, isReachable ); |
645 |
|
} |
646 |
116 |
++set_it; |
647 |
|
} |
648 |
|
} |
649 |
|
} |
650 |
|
} |
651 |
|
|
652 |
118 |
void TheorySetsRels::buildTCGraphForRel( Node tc_rel ) { |
653 |
236 |
std::map< Node, Node > rel_tc_graph_exps; |
654 |
236 |
std::map<Node, std::unordered_set<Node> > rel_tc_graph; |
655 |
|
|
656 |
236 |
Node rel_rep = getRepresentative( tc_rel[0] ); |
657 |
236 |
Node tc_rel_rep = getRepresentative( tc_rel ); |
658 |
236 |
std::vector< Node > members = d_rReps_memberReps_cache[rel_rep]; |
659 |
236 |
std::vector< Node > exps = d_rReps_memberReps_exp_cache[rel_rep]; |
660 |
|
|
661 |
355 |
for( unsigned int i = 0; i < members.size(); i++ ) { |
662 |
474 |
Node fst_element_rep = getRepresentative( RelsUtils::nthElementOfTuple( members[i], 0 )); |
663 |
474 |
Node snd_element_rep = getRepresentative( RelsUtils::nthElementOfTuple( members[i], 1 )); |
664 |
474 |
Node tuple_rep = RelsUtils::constructPair( rel_rep, fst_element_rep, snd_element_rep ); |
665 |
|
std::map<Node, std::unordered_set<Node> >::iterator rel_tc_graph_it = |
666 |
237 |
rel_tc_graph.find(fst_element_rep); |
667 |
|
|
668 |
237 |
if( rel_tc_graph_it == rel_tc_graph.end() ) { |
669 |
400 |
std::unordered_set<Node> snd_elements; |
670 |
200 |
snd_elements.insert( snd_element_rep ); |
671 |
200 |
rel_tc_graph[fst_element_rep] = snd_elements; |
672 |
200 |
rel_tc_graph_exps[tuple_rep] = exps[i]; |
673 |
37 |
} else if( (rel_tc_graph_it->second).find( snd_element_rep ) == (rel_tc_graph_it->second).end() ) { |
674 |
37 |
(rel_tc_graph_it->second).insert( snd_element_rep ); |
675 |
37 |
rel_tc_graph_exps[tuple_rep] = exps[i]; |
676 |
|
} |
677 |
|
} |
678 |
|
|
679 |
118 |
if( members.size() > 0 ) { |
680 |
105 |
d_rRep_tcGraph[rel_rep] = rel_tc_graph; |
681 |
105 |
d_tcr_tcGraph_exps[tc_rel] = rel_tc_graph_exps; |
682 |
105 |
d_tcr_tcGraph[tc_rel] = rel_tc_graph; |
683 |
|
} |
684 |
118 |
} |
685 |
|
|
686 |
113 |
void TheorySetsRels::doTCInference( |
687 |
|
std::map<Node, std::unordered_set<Node> > rel_tc_graph, |
688 |
|
std::map<Node, Node> rel_tc_graph_exps, |
689 |
|
Node tc_rel) |
690 |
|
{ |
691 |
113 |
Trace("rels-debug") << "[Theory::Rels] ****** doTCInference !" << std::endl; |
692 |
328 |
for (TC_GRAPH_IT tc_graph_it = rel_tc_graph.begin(); |
693 |
328 |
tc_graph_it != rel_tc_graph.end(); |
694 |
|
++tc_graph_it) |
695 |
|
{ |
696 |
260 |
for (std::unordered_set<Node>::iterator snd_elements_it = |
697 |
215 |
tc_graph_it->second.begin(); |
698 |
475 |
snd_elements_it != tc_graph_it->second.end(); |
699 |
|
++snd_elements_it) |
700 |
|
{ |
701 |
520 |
std::vector< Node > reasons; |
702 |
520 |
std::unordered_set<Node> seen; |
703 |
520 |
Node tuple = RelsUtils::constructPair( tc_rel, getRepresentative( tc_graph_it->first ), getRepresentative( *snd_elements_it) ); |
704 |
260 |
Assert(rel_tc_graph_exps.find(tuple) != rel_tc_graph_exps.end()); |
705 |
520 |
Node exp = rel_tc_graph_exps.find( tuple )->second; |
706 |
|
|
707 |
260 |
reasons.push_back( exp ); |
708 |
260 |
seen.insert( tc_graph_it->first ); |
709 |
260 |
doTCInference( tc_rel, reasons, rel_tc_graph, rel_tc_graph_exps, tc_graph_it->first, *snd_elements_it, seen); |
710 |
|
} |
711 |
|
} |
712 |
113 |
Trace("rels-debug") << "[Theory::Rels] ****** Done with doTCInference !" << std::endl; |
713 |
113 |
} |
714 |
|
|
715 |
491 |
void TheorySetsRels::doTCInference( |
716 |
|
Node tc_rel, |
717 |
|
std::vector<Node> reasons, |
718 |
|
std::map<Node, std::unordered_set<Node> >& tc_graph, |
719 |
|
std::map<Node, Node>& rel_tc_graph_exps, |
720 |
|
Node start_node_rep, |
721 |
|
Node cur_node_rep, |
722 |
|
std::unordered_set<Node>& seen) |
723 |
|
{ |
724 |
491 |
NodeManager* nm = NodeManager::currentNM(); |
725 |
888 |
Node tc_mem = RelsUtils::constructPair( tc_rel, RelsUtils::nthElementOfTuple((reasons.front())[0], 0), RelsUtils::nthElementOfTuple((reasons.back())[0], 1) ); |
726 |
888 |
std::vector< Node > all_reasons( reasons ); |
727 |
|
|
728 |
814 |
for( unsigned int i = 0 ; i < reasons.size()-1; i++ ) { |
729 |
646 |
Node fst_element_end = RelsUtils::nthElementOfTuple( reasons[i][0], 1 ); |
730 |
646 |
Node snd_element_begin = RelsUtils::nthElementOfTuple( reasons[i+1][0], 0 ); |
731 |
323 |
if( fst_element_end != snd_element_begin ) { |
732 |
28 |
all_reasons.push_back( NodeManager::currentNM()->mkNode(kind::EQUAL, fst_element_end, snd_element_begin) ); |
733 |
|
} |
734 |
323 |
if( tc_rel != reasons[i][1] && tc_rel[0] != reasons[i][1] ) { |
735 |
|
all_reasons.push_back( NodeManager::currentNM()->mkNode(kind::EQUAL, tc_rel[0], reasons[i][1]) ); |
736 |
|
} |
737 |
|
} |
738 |
491 |
if( tc_rel != reasons.back()[1] && tc_rel[0] != reasons.back()[1] ) { |
739 |
8 |
all_reasons.push_back( NodeManager::currentNM()->mkNode(kind::EQUAL, tc_rel[0], reasons.back()[1]) ); |
740 |
|
} |
741 |
491 |
if( all_reasons.size() > 1) { |
742 |
234 |
sendInfer(nm->mkNode(MEMBER, tc_mem, tc_rel), |
743 |
|
InferenceId::SETS_RELS_TCLOSURE_FWD, |
744 |
468 |
nm->mkNode(AND, all_reasons)); |
745 |
|
} else { |
746 |
257 |
sendInfer(nm->mkNode(MEMBER, tc_mem, tc_rel), |
747 |
|
InferenceId::SETS_RELS_TCLOSURE_FWD, |
748 |
257 |
all_reasons.front()); |
749 |
|
} |
750 |
|
|
751 |
|
// check if cur_node has been traversed or not |
752 |
491 |
if( seen.find( cur_node_rep ) != seen.end() ) { |
753 |
94 |
return; |
754 |
|
} |
755 |
397 |
seen.insert( cur_node_rep ); |
756 |
397 |
TC_GRAPH_IT cur_set = tc_graph.find( cur_node_rep ); |
757 |
397 |
if( cur_set != tc_graph.end() ) { |
758 |
388 |
for (std::unordered_set<Node>::iterator set_it = cur_set->second.begin(); |
759 |
388 |
set_it != cur_set->second.end(); |
760 |
|
++set_it) |
761 |
|
{ |
762 |
462 |
Node new_pair = RelsUtils::constructPair( tc_rel, cur_node_rep, *set_it ); |
763 |
462 |
std::vector< Node > new_reasons( reasons ); |
764 |
231 |
new_reasons.push_back( rel_tc_graph_exps.find( new_pair )->second ); |
765 |
231 |
doTCInference( tc_rel, new_reasons, tc_graph, rel_tc_graph_exps, start_node_rep, *set_it, seen ); |
766 |
|
} |
767 |
|
} |
768 |
|
} |
769 |
|
|
770 |
|
/* product-split rule: (a, b) IS_IN (X PRODUCT Y) |
771 |
|
* ---------------------------------- |
772 |
|
* a IS_IN X && b IS_IN Y |
773 |
|
* |
774 |
|
* product-compose rule: (a, b) IS_IN X (c, d) IS_IN Y |
775 |
|
* --------------------------------- |
776 |
|
* (a, b, c, d) IS_IN (X PRODUCT Y) |
777 |
|
*/ |
778 |
|
|
779 |
|
|
780 |
169 |
void TheorySetsRels::applyProductRule( Node pt_rel, Node pt_rel_rep, Node exp ) { |
781 |
338 |
Trace("rels-debug") << "\n[Theory::Rels] *********** Applying PRODUCT rule on producted term = " << pt_rel |
782 |
169 |
<< ", its representative = " << pt_rel_rep |
783 |
169 |
<< " with explanation = " << exp << std::endl; |
784 |
|
|
785 |
169 |
if(d_rel_nodes.find( pt_rel ) == d_rel_nodes.end()) { |
786 |
114 |
Trace("rels-debug") << "\n[Theory::Rels] Apply PRODUCT-COMPOSE rule on term: " << pt_rel |
787 |
57 |
<< " with explanation: " << exp << std::endl; |
788 |
|
|
789 |
57 |
computeMembersForBinOpRel( pt_rel ); |
790 |
57 |
d_rel_nodes.insert( pt_rel ); |
791 |
|
} |
792 |
|
|
793 |
338 |
Node mem = exp[0]; |
794 |
338 |
std::vector<Node> r1_element; |
795 |
338 |
std::vector<Node> r2_element; |
796 |
169 |
const DType& dt1 = pt_rel[0].getType().getSetElementType().getDType(); |
797 |
169 |
unsigned int s1_len = pt_rel[0].getType().getSetElementType().getTupleLength(); |
798 |
169 |
unsigned int tup_len = pt_rel.getType().getSetElementType().getTupleLength(); |
799 |
|
|
800 |
169 |
r1_element.push_back(dt1[0].getConstructor()); |
801 |
|
|
802 |
169 |
unsigned int i = 0; |
803 |
743 |
for(; i < s1_len; ++i) { |
804 |
287 |
r1_element.push_back(RelsUtils::nthElementOfTuple(mem, i)); |
805 |
|
} |
806 |
169 |
const DType& dt2 = pt_rel[1].getType().getSetElementType().getDType(); |
807 |
169 |
r2_element.push_back(dt2[0].getConstructor()); |
808 |
743 |
for(; i < tup_len; ++i) { |
809 |
287 |
r2_element.push_back(RelsUtils::nthElementOfTuple(mem, i)); |
810 |
|
} |
811 |
338 |
Node reason = exp; |
812 |
338 |
Node mem1 = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, r1_element); |
813 |
338 |
Node mem2 = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, r2_element); |
814 |
338 |
Node fact_1 = NodeManager::currentNM()->mkNode(kind::MEMBER, mem1, pt_rel[0]); |
815 |
338 |
Node fact_2 = NodeManager::currentNM()->mkNode(kind::MEMBER, mem2, pt_rel[1]); |
816 |
|
|
817 |
169 |
if( pt_rel != exp[1] ) { |
818 |
12 |
reason = NodeManager::currentNM()->mkNode(kind::AND, exp, NodeManager::currentNM()->mkNode(kind::EQUAL, pt_rel, exp[1])); |
819 |
|
} |
820 |
169 |
sendInfer(fact_1, InferenceId::SETS_RELS_PRODUCT_SPLIT, reason); |
821 |
169 |
sendInfer(fact_2, InferenceId::SETS_RELS_PRODUCT_SPLIT, reason); |
822 |
169 |
} |
823 |
|
|
824 |
|
/* join-split rule: (a, b) IS_IN (X JOIN Y) |
825 |
|
* -------------------------------------------- |
826 |
|
* exists z | (a, z) IS_IN X && (z, b) IS_IN Y |
827 |
|
* |
828 |
|
* |
829 |
|
* join-compose rule: (a, b) IS_IN X (b, c) IS_IN Y NOT (t, u) IS_IN (X JOIN Y) |
830 |
|
* ------------------------------------------------------------- |
831 |
|
* (a, c) IS_IN (X JOIN Y) |
832 |
|
*/ |
833 |
|
|
834 |
1498 |
void TheorySetsRels::applyJoinRule( Node join_rel, Node join_rel_rep, Node exp ) { |
835 |
2996 |
Trace("rels-debug") << "\n[Theory::Rels] *********** Applying JOIN rule on joined term = " << join_rel |
836 |
1498 |
<< ", its representative = " << join_rel_rep |
837 |
1498 |
<< " with explanation = " << exp << std::endl; |
838 |
1498 |
if(d_rel_nodes.find( join_rel ) == d_rel_nodes.end()) { |
839 |
802 |
Trace("rels-debug") << "\n[Theory::Rels] Apply JOIN-COMPOSE rule on term: " << join_rel |
840 |
401 |
<< " with explanation: " << exp << std::endl; |
841 |
|
|
842 |
401 |
computeMembersForBinOpRel( join_rel ); |
843 |
401 |
d_rel_nodes.insert( join_rel ); |
844 |
|
} |
845 |
|
|
846 |
1751 |
Node mem = exp[0]; |
847 |
1751 |
std::vector<Node> r1_element; |
848 |
1751 |
std::vector<Node> r2_element; |
849 |
1751 |
Node r1_rep = getRepresentative(join_rel[0]); |
850 |
1751 |
Node r2_rep = getRepresentative(join_rel[1]); |
851 |
1751 |
TypeNode shared_type = r2_rep.getType().getSetElementType().getTupleTypes()[0]; |
852 |
1498 |
Node shared_x = d_skCache.mkTypedSkolemCached( |
853 |
1751 |
shared_type, mem, join_rel, SkolemCache::SK_JOIN, "srj"); |
854 |
1498 |
const DType& dt1 = join_rel[0].getType().getSetElementType().getDType(); |
855 |
1498 |
unsigned int s1_len = join_rel[0].getType().getSetElementType().getTupleLength(); |
856 |
1498 |
unsigned int tup_len = join_rel.getType().getSetElementType().getTupleLength(); |
857 |
|
|
858 |
1498 |
unsigned int i = 0; |
859 |
1498 |
r1_element.push_back(dt1[0].getConstructor()); |
860 |
4446 |
for(; i < s1_len-1; ++i) { |
861 |
1474 |
r1_element.push_back(RelsUtils::nthElementOfTuple(mem, i)); |
862 |
|
} |
863 |
1498 |
r1_element.push_back(shared_x); |
864 |
1498 |
const DType& dt2 = join_rel[1].getType().getSetElementType().getDType(); |
865 |
1498 |
r2_element.push_back(dt2[0].getConstructor()); |
866 |
1498 |
r2_element.push_back(shared_x); |
867 |
4550 |
for(; i < tup_len; ++i) { |
868 |
1526 |
r2_element.push_back(RelsUtils::nthElementOfTuple(mem, i)); |
869 |
|
} |
870 |
1751 |
Node mem1 = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, r1_element); |
871 |
1751 |
Node mem2 = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, r2_element); |
872 |
|
|
873 |
1498 |
computeTupleReps(mem1); |
874 |
1498 |
computeTupleReps(mem2); |
875 |
|
|
876 |
1751 |
std::vector<Node> elements = d_membership_trie[r1_rep].findTerms(d_tuple_reps[mem1]); |
877 |
|
|
878 |
1715 |
for(unsigned int j = 0; j < elements.size(); j++) { |
879 |
1679 |
std::vector<Node> new_tup; |
880 |
1462 |
new_tup.push_back(elements[j]); |
881 |
1462 |
new_tup.insert(new_tup.end(), d_tuple_reps[mem2].begin()+1, d_tuple_reps[mem2].end()); |
882 |
1462 |
if(d_membership_trie[r2_rep].existsTerm(new_tup) != Node::null()) { |
883 |
1245 |
return; |
884 |
|
} |
885 |
|
} |
886 |
506 |
Node reason = exp; |
887 |
253 |
if( join_rel != exp[1] ) { |
888 |
129 |
reason = NodeManager::currentNM()->mkNode(kind::AND, reason, NodeManager::currentNM()->mkNode(kind::EQUAL, join_rel, exp[1])); |
889 |
|
} |
890 |
506 |
Node fact = NodeManager::currentNM()->mkNode(kind::MEMBER, mem1, join_rel[0]); |
891 |
253 |
sendInfer(fact, InferenceId::SETS_RELS_JOIN_SPLIT_1, reason); |
892 |
253 |
fact = NodeManager::currentNM()->mkNode(kind::MEMBER, mem2, join_rel[1]); |
893 |
253 |
sendInfer(fact, InferenceId::SETS_RELS_JOIN_SPLIT_2, reason); |
894 |
253 |
makeSharedTerm(shared_x, shared_type); |
895 |
|
} |
896 |
|
|
897 |
|
/* |
898 |
|
* transpose-occur rule: (a, b) IS_IN X (TRANSPOSE X) in T |
899 |
|
* --------------------------------------- |
900 |
|
* (b, a) IS_IN (TRANSPOSE X) |
901 |
|
* |
902 |
|
* transpose-reverse rule: (a, b) IS_IN (TRANSPOSE X) |
903 |
|
* --------------------------------------- |
904 |
|
* (b, a) IS_IN X |
905 |
|
* |
906 |
|
*/ |
907 |
1337 |
void TheorySetsRels::applyTransposeRule( std::vector<Node> tp_terms ) { |
908 |
1337 |
if( tp_terms.size() < 1) { |
909 |
|
return; |
910 |
|
} |
911 |
1337 |
NodeManager* nm = NodeManager::currentNM(); |
912 |
1337 |
for( unsigned int i = 1; i < tp_terms.size(); i++ ) { |
913 |
|
Trace("rels-debug") << "\n[Theory::Rels] *********** Applying TRANSPOSE-Equal rule on transposed term = " << tp_terms[0] << " and " << tp_terms[i] << std::endl; |
914 |
|
sendInfer(nm->mkNode(EQUAL, tp_terms[0][0], tp_terms[i][0]), |
915 |
|
InferenceId::SETS_RELS_TRANSPOSE_EQ, |
916 |
|
nm->mkNode(EQUAL, tp_terms[0], tp_terms[i])); |
917 |
|
} |
918 |
|
} |
919 |
|
|
920 |
1337 |
void TheorySetsRels::applyTransposeRule( Node tp_rel, Node tp_rel_rep, Node exp ) { |
921 |
2674 |
Trace("rels-debug") << "\n[Theory::Rels] *********** Applying TRANSPOSE rule on transposed term = " << tp_rel |
922 |
1337 |
<< ", its representative = " << tp_rel_rep |
923 |
1337 |
<< " with explanation = " << exp << std::endl; |
924 |
1337 |
NodeManager* nm = NodeManager::currentNM(); |
925 |
|
|
926 |
1337 |
if(d_rel_nodes.find( tp_rel ) == d_rel_nodes.end()) { |
927 |
382 |
Trace("rels-debug") << "\n[Theory::Rels] Apply TRANSPOSE-Compose rule on term: " << tp_rel |
928 |
191 |
<< " with explanation: " << exp << std::endl; |
929 |
|
|
930 |
191 |
computeMembersForUnaryOpRel( tp_rel ); |
931 |
191 |
d_rel_nodes.insert( tp_rel ); |
932 |
|
} |
933 |
|
|
934 |
2674 |
Node reason = exp; |
935 |
2674 |
Node reversed_mem = RelsUtils::reverseTuple( exp[0] ); |
936 |
|
|
937 |
1337 |
if( tp_rel != exp[1] ) { |
938 |
155 |
reason = NodeManager::currentNM()->mkNode(kind::AND, reason, NodeManager::currentNM()->mkNode(kind::EQUAL, tp_rel, exp[1])); |
939 |
|
} |
940 |
1337 |
sendInfer(nm->mkNode(MEMBER, reversed_mem, tp_rel[0]), |
941 |
|
InferenceId::SETS_RELS_TRANSPOSE_REV, |
942 |
|
reason); |
943 |
1337 |
} |
944 |
|
|
945 |
769 |
void TheorySetsRels::doTCInference() { |
946 |
769 |
Trace("rels-debug") << "[Theory::Rels] ****** Finalizing transitive closure inferences!" << std::endl; |
947 |
769 |
TC_IT tc_graph_it = d_tcr_tcGraph.begin(); |
948 |
995 |
while( tc_graph_it != d_tcr_tcGraph.end() ) { |
949 |
113 |
Assert(d_tcr_tcGraph_exps.find(tc_graph_it->first) |
950 |
|
!= d_tcr_tcGraph_exps.end()); |
951 |
113 |
doTCInference( tc_graph_it->second, d_tcr_tcGraph_exps.find(tc_graph_it->first)->second, tc_graph_it->first ); |
952 |
113 |
++tc_graph_it; |
953 |
|
} |
954 |
769 |
Trace("rels-debug") << "[Theory::Rels] ****** Done with finalizing transitive closure inferences!" << std::endl; |
955 |
769 |
} |
956 |
|
|
957 |
|
|
958 |
|
// Bottom-up fashion to compute relations with more than 1 arity |
959 |
1289 |
void TheorySetsRels::computeMembersForBinOpRel(Node rel) { |
960 |
1289 |
Trace("rels-debug") << "\n[Theory::Rels] computeMembersForBinOpRel for relation " << rel << std::endl; |
961 |
|
|
962 |
1289 |
switch(rel[0].getKind()) { |
963 |
220 |
case kind::TRANSPOSE: |
964 |
|
case kind::TCLOSURE: { |
965 |
220 |
computeMembersForUnaryOpRel(rel[0]); |
966 |
220 |
break; |
967 |
|
} |
968 |
210 |
case kind::JOIN: |
969 |
|
case kind::PRODUCT: { |
970 |
210 |
computeMembersForBinOpRel(rel[0]); |
971 |
210 |
break; |
972 |
|
} |
973 |
859 |
default: |
974 |
859 |
break; |
975 |
|
} |
976 |
1289 |
switch(rel[1].getKind()) { |
977 |
|
case kind::TRANSPOSE: { |
978 |
|
computeMembersForUnaryOpRel(rel[1]); |
979 |
|
break; |
980 |
|
} |
981 |
16 |
case kind::JOIN: |
982 |
|
case kind::PRODUCT: { |
983 |
16 |
computeMembersForBinOpRel(rel[1]); |
984 |
16 |
break; |
985 |
|
} |
986 |
1273 |
default: |
987 |
1273 |
break; |
988 |
|
} |
989 |
3669 |
if(d_rReps_memberReps_cache.find(getRepresentative(rel[0])) == d_rReps_memberReps_cache.end() || |
990 |
2380 |
d_rReps_memberReps_cache.find(getRepresentative(rel[1])) == d_rReps_memberReps_cache.end()) { |
991 |
259 |
return; |
992 |
|
} |
993 |
1030 |
composeMembersForRels(rel); |
994 |
|
} |
995 |
|
|
996 |
|
// Bottom-up fashion to compute unary relation |
997 |
582 |
void TheorySetsRels::computeMembersForUnaryOpRel(Node rel) { |
998 |
582 |
Trace("rels-debug") << "\n[Theory::Rels] computeMembersForUnaryOpRel for relation " << rel << std::endl; |
999 |
|
|
1000 |
582 |
switch(rel[0].getKind()) { |
1001 |
|
case kind::TRANSPOSE: |
1002 |
|
case kind::TCLOSURE: |
1003 |
|
computeMembersForUnaryOpRel(rel[0]); |
1004 |
|
break; |
1005 |
120 |
case kind::JOIN: |
1006 |
|
case kind::PRODUCT: |
1007 |
120 |
computeMembersForBinOpRel(rel[0]); |
1008 |
120 |
break; |
1009 |
462 |
default: |
1010 |
462 |
break; |
1011 |
|
} |
1012 |
|
|
1013 |
1067 |
Node rel0_rep = getRepresentative(rel[0]); |
1014 |
1746 |
if (d_rReps_memberReps_cache.find(rel0_rep) |
1015 |
1746 |
== d_rReps_memberReps_cache.end()) |
1016 |
|
{ |
1017 |
97 |
return; |
1018 |
|
} |
1019 |
485 |
NodeManager* nm = NodeManager::currentNM(); |
1020 |
|
|
1021 |
970 |
std::vector<Node> members = d_rReps_memberReps_cache[rel0_rep]; |
1022 |
970 |
std::vector<Node> exps = d_rReps_memberReps_exp_cache[rel0_rep]; |
1023 |
|
|
1024 |
485 |
Assert(members.size() == exps.size()); |
1025 |
|
|
1026 |
5777 |
for(unsigned int i = 0; i < members.size(); i++) { |
1027 |
10584 |
Node reason = exps[i]; |
1028 |
5292 |
if( rel.getKind() == kind::TRANSPOSE) { |
1029 |
5269 |
if( rel[0] != exps[i][1] ) { |
1030 |
214 |
reason = NodeManager::currentNM()->mkNode(kind::AND, reason, NodeManager::currentNM()->mkNode(kind::EQUAL, rel[0], exps[i][1])); |
1031 |
|
} |
1032 |
5269 |
sendInfer(nm->mkNode(MEMBER, RelsUtils::reverseTuple(exps[i][0]), rel), |
1033 |
|
InferenceId::SETS_RELS_TRANSPOSE_REV, |
1034 |
|
reason); |
1035 |
|
} |
1036 |
|
} |
1037 |
|
} |
1038 |
|
|
1039 |
|
/* |
1040 |
|
* Explicitly compose the join or product relations of r1 and r2 |
1041 |
|
* e.g. If (a, b) in X and (b, c) in Y, (a, c) in (X JOIN Y) |
1042 |
|
* |
1043 |
|
*/ |
1044 |
1030 |
void TheorySetsRels::composeMembersForRels( Node rel ) { |
1045 |
1030 |
Trace("rels-debug") << "[Theory::Rels] Start composing members for relation = " << rel << std::endl; |
1046 |
2060 |
Node r1 = rel[0]; |
1047 |
2060 |
Node r2 = rel[1]; |
1048 |
2060 |
Node r1_rep = getRepresentative( r1 ); |
1049 |
2060 |
Node r2_rep = getRepresentative( r2 ); |
1050 |
|
|
1051 |
3090 |
if(d_rReps_memberReps_cache.find( r1_rep ) == d_rReps_memberReps_cache.end() || |
1052 |
2060 |
d_rReps_memberReps_cache.find( r2_rep ) == d_rReps_memberReps_cache.end() ) { |
1053 |
|
return; |
1054 |
|
} |
1055 |
1030 |
NodeManager* nm = NodeManager::currentNM(); |
1056 |
|
|
1057 |
2060 |
std::vector<Node> r1_rep_exps = d_rReps_memberReps_exp_cache[r1_rep]; |
1058 |
2060 |
std::vector<Node> r2_rep_exps = d_rReps_memberReps_exp_cache[r2_rep]; |
1059 |
1030 |
unsigned int r1_tuple_len = r1.getType().getSetElementType().getTupleLength(); |
1060 |
1030 |
unsigned int r2_tuple_len = r2.getType().getSetElementType().getTupleLength(); |
1061 |
|
|
1062 |
6414 |
for( unsigned int i = 0; i < r1_rep_exps.size(); i++ ) { |
1063 |
252085 |
for( unsigned int j = 0; j < r2_rep_exps.size(); j++ ) { |
1064 |
493402 |
std::vector<Node> tuple_elements; |
1065 |
493402 |
TypeNode tn = rel.getType().getSetElementType(); |
1066 |
493402 |
Node r1_rmost = RelsUtils::nthElementOfTuple( r1_rep_exps[i][0], r1_tuple_len-1 ); |
1067 |
493402 |
Node r2_lmost = RelsUtils::nthElementOfTuple( r2_rep_exps[j][0], 0 ); |
1068 |
246701 |
tuple_elements.push_back(tn.getDType()[0].getConstructor()); |
1069 |
|
|
1070 |
493402 |
Trace("rels-debug") << "[Theory::Rels] r1_rmost: " << r1_rmost |
1071 |
246701 |
<< " of type " << r1_rmost.getType() << std::endl; |
1072 |
493402 |
Trace("rels-debug") << "[Theory::Rels] r2_lmost: " << r2_lmost |
1073 |
246701 |
<< " of type " << r2_lmost.getType() << std::endl; |
1074 |
|
|
1075 |
493402 |
if (rel.getKind() == kind::PRODUCT |
1076 |
493402 |
|| (rel.getKind() == kind::JOIN && areEqual(r1_rmost, r2_lmost))) |
1077 |
|
{ |
1078 |
26097 |
bool isProduct = rel.getKind() == kind::PRODUCT; |
1079 |
26097 |
unsigned int k = 0; |
1080 |
26097 |
unsigned int l = 1; |
1081 |
|
|
1082 |
78137 |
for( ; k < r1_tuple_len - 1; ++k ) { |
1083 |
26020 |
tuple_elements.push_back( RelsUtils::nthElementOfTuple( r1_rep_exps[i][0], k ) ); |
1084 |
|
} |
1085 |
26097 |
if(isProduct) { |
1086 |
348 |
tuple_elements.push_back( RelsUtils::nthElementOfTuple( r1_rep_exps[i][0], k ) ); |
1087 |
348 |
tuple_elements.push_back( RelsUtils::nthElementOfTuple( r2_rep_exps[j][0], 0 ) ); |
1088 |
|
} |
1089 |
78225 |
for( ; l < r2_tuple_len; ++l ) { |
1090 |
26064 |
tuple_elements.push_back( RelsUtils::nthElementOfTuple( r2_rep_exps[j][0], l ) ); |
1091 |
|
} |
1092 |
|
|
1093 |
52194 |
Node composed_tuple = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, tuple_elements); |
1094 |
52194 |
Node fact = NodeManager::currentNM()->mkNode(kind::MEMBER, composed_tuple, rel); |
1095 |
52194 |
std::vector<Node> reasons; |
1096 |
26097 |
reasons.push_back( r1_rep_exps[i] ); |
1097 |
26097 |
reasons.push_back( r2_rep_exps[j] ); |
1098 |
|
|
1099 |
26097 |
if( r1 != r1_rep_exps[i][1] ) { |
1100 |
73 |
reasons.push_back( NodeManager::currentNM()->mkNode(kind::EQUAL, r1, r1_rep_exps[i][1]) ); |
1101 |
|
} |
1102 |
26097 |
if( r2 != r2_rep_exps[j][1] ) { |
1103 |
51 |
reasons.push_back( NodeManager::currentNM()->mkNode(kind::EQUAL, r2, r2_rep_exps[j][1]) ); |
1104 |
|
} |
1105 |
26097 |
if( isProduct ) { |
1106 |
348 |
sendInfer( |
1107 |
696 |
fact, InferenceId::SETS_RELS_PRODUCE_COMPOSE, nm->mkNode(kind::AND, reasons)); |
1108 |
|
} else { |
1109 |
25749 |
if( r1_rmost != r2_lmost ) { |
1110 |
6623 |
reasons.push_back( NodeManager::currentNM()->mkNode(kind::EQUAL, r1_rmost, r2_lmost) ); |
1111 |
|
} |
1112 |
25749 |
sendInfer( |
1113 |
51498 |
fact, InferenceId::SETS_RELS_JOIN_COMPOSE, nm->mkNode(kind::AND, reasons)); |
1114 |
|
} |
1115 |
|
} |
1116 |
|
} |
1117 |
|
} |
1118 |
|
|
1119 |
|
} |
1120 |
|
|
1121 |
|
void TheorySetsRels::processInference(Node conc, InferenceId id, Node exp) |
1122 |
|
{ |
1123 |
|
Trace("sets-pinfer") << "Process inference: " << exp << " => " << conc |
1124 |
|
<< std::endl; |
1125 |
|
if (!d_state.isEntailed(exp, true)) |
1126 |
|
{ |
1127 |
|
Trace("sets-pinfer") << " must assert as lemma" << std::endl; |
1128 |
|
// we wrap the spurious explanation into a splitting lemma |
1129 |
|
Node lem = NodeManager::currentNM()->mkNode(OR, exp.negate(), conc); |
1130 |
|
d_im.assertInference(lem, id, d_trueNode, 1); |
1131 |
|
return; |
1132 |
|
} |
1133 |
|
// try to assert it as a fact |
1134 |
|
d_im.assertInference(conc, id, exp); |
1135 |
|
} |
1136 |
|
|
1137 |
521090 |
bool TheorySetsRels::isRelationKind( Kind k ) { |
1138 |
520614 |
return k == TRANSPOSE || k == PRODUCT || k == JOIN || k == TCLOSURE |
1139 |
1040116 |
|| k == IDEN || k == JOIN_IMAGE; |
1140 |
|
} |
1141 |
|
|
1142 |
53852 |
Node TheorySetsRels::getRepresentative( Node t ) { |
1143 |
53852 |
return d_state.getRepresentative(t); |
1144 |
|
} |
1145 |
|
|
1146 |
1095138 |
bool TheorySetsRels::hasTerm(Node a) { return d_state.hasTerm(a); } |
1147 |
570466 |
bool TheorySetsRels::areEqual( Node a, Node b ){ |
1148 |
570466 |
Assert(a.getType() == b.getType()); |
1149 |
570466 |
Trace("rels-eq") << "[sets-rels]**** checking equality between " << a << " and " << b << std::endl; |
1150 |
570466 |
if(a == b) { |
1151 |
22897 |
return true; |
1152 |
547569 |
} else if( hasTerm( a ) && hasTerm( b ) ){ |
1153 |
547569 |
return d_state.areEqual(a, b); |
1154 |
|
} else if(a.getType().isTuple()) { |
1155 |
|
bool equal = true; |
1156 |
|
for(unsigned int i = 0; i < a.getType().getTupleLength(); i++) { |
1157 |
|
equal = equal && areEqual(RelsUtils::nthElementOfTuple(a, i), RelsUtils::nthElementOfTuple(b, i)); |
1158 |
|
} |
1159 |
|
return equal; |
1160 |
|
} else if(!a.getType().isBoolean()){ |
1161 |
|
// TODO(project##230): Find a safe type for the singleton operator |
1162 |
|
makeSharedTerm(a, a.getType()); |
1163 |
|
makeSharedTerm(b, b.getType()); |
1164 |
|
} |
1165 |
|
return false; |
1166 |
|
} |
1167 |
|
|
1168 |
|
/* |
1169 |
|
* Make sure duplicate members are not added in map |
1170 |
|
*/ |
1171 |
12949 |
bool TheorySetsRels::safelyAddToMap(std::map< Node, std::vector<Node> >& map, Node rel_rep, Node member) { |
1172 |
12949 |
std::map< Node, std::vector< Node > >::iterator mem_it = map.find(rel_rep); |
1173 |
12949 |
if(mem_it == map.end()) { |
1174 |
5560 |
std::vector<Node> members; |
1175 |
2780 |
members.push_back(member); |
1176 |
2780 |
map[rel_rep] = members; |
1177 |
2780 |
return true; |
1178 |
|
} else { |
1179 |
10169 |
std::vector<Node>::iterator mems = mem_it->second.begin(); |
1180 |
650247 |
while(mems != mem_it->second.end()) { |
1181 |
323698 |
if(areEqual(*mems, member)) { |
1182 |
3659 |
return false; |
1183 |
|
} |
1184 |
320039 |
++mems; |
1185 |
|
} |
1186 |
6510 |
map[rel_rep].push_back(member); |
1187 |
6510 |
return true; |
1188 |
|
} |
1189 |
|
return false; |
1190 |
|
} |
1191 |
|
|
1192 |
12008 |
void TheorySetsRels::makeSharedTerm(Node n, TypeNode t) |
1193 |
|
{ |
1194 |
12008 |
if (d_shared_terms.find(n) != d_shared_terms.end()) |
1195 |
|
{ |
1196 |
10648 |
return; |
1197 |
|
} |
1198 |
1360 |
Trace("rels-share") << " [sets-rels] making shared term " << n << std::endl; |
1199 |
|
// force a proxy lemma to be sent for the singleton containing n |
1200 |
2720 |
Node ss = NodeManager::currentNM()->mkSingleton(t, n); |
1201 |
1360 |
d_treg.getProxy(ss); |
1202 |
1360 |
d_shared_terms.insert(n); |
1203 |
|
} |
1204 |
|
|
1205 |
|
/* |
1206 |
|
* For each tuple n, we store a mapping between n and a list of its elements representatives |
1207 |
|
* in d_tuple_reps. This would later be used for applying JOIN operator. |
1208 |
|
*/ |
1209 |
12425 |
void TheorySetsRels::computeTupleReps( Node n ) { |
1210 |
12425 |
if( d_tuple_reps.find( n ) == d_tuple_reps.end() ){ |
1211 |
23008 |
for( unsigned i = 0; i < n.getType().getTupleLength(); i++ ){ |
1212 |
15414 |
d_tuple_reps[n].push_back( getRepresentative( RelsUtils::nthElementOfTuple(n, i) ) ); |
1213 |
|
} |
1214 |
|
} |
1215 |
12425 |
} |
1216 |
|
|
1217 |
|
/* |
1218 |
|
* Node n[0] is a tuple variable, reduce n[0] to a concrete representation, |
1219 |
|
* which is (e1, ..., en) where e1, ... ,en are concrete elements of tuple n[0]. |
1220 |
|
*/ |
1221 |
1882 |
void TheorySetsRels::reduceTupleVar(Node n) { |
1222 |
1882 |
if(d_symbolic_tuples.find(n) == d_symbolic_tuples.end()) { |
1223 |
589 |
Trace("rels-debug") << "[Theory::Rels] Reduce tuple var: " << n[0] << " to a concrete one " << " node = " << n << std::endl; |
1224 |
1178 |
std::vector<Node> tuple_elements; |
1225 |
589 |
tuple_elements.push_back((n[0].getType().getDType())[0].getConstructor()); |
1226 |
1178 |
std::vector<TypeNode> tupleTypes = n[0].getType().getTupleTypes(); |
1227 |
1787 |
for (unsigned int i = 0; i < n[0].getType().getTupleLength(); i++) |
1228 |
|
{ |
1229 |
2396 |
Node element = RelsUtils::nthElementOfTuple(n[0], i); |
1230 |
1198 |
makeSharedTerm(element, tupleTypes[i]); |
1231 |
1198 |
tuple_elements.push_back(element); |
1232 |
|
} |
1233 |
1178 |
Node tuple_reduct = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, tuple_elements); |
1234 |
589 |
tuple_reduct = NodeManager::currentNM()->mkNode(kind::MEMBER,tuple_reduct, n[1]); |
1235 |
1178 |
Node tuple_reduction_lemma = NodeManager::currentNM()->mkNode(kind::EQUAL, n, tuple_reduct); |
1236 |
589 |
sendInfer(tuple_reduction_lemma, InferenceId::SETS_RELS_TUPLE_REDUCTION, d_trueNode); |
1237 |
589 |
d_symbolic_tuples.insert(n); |
1238 |
|
} |
1239 |
1882 |
} |
1240 |
|
|
1241 |
2898 |
std::vector<Node> TupleTrie::findTerms( std::vector< Node >& reps, int argIndex ) { |
1242 |
5796 |
std::vector<Node> nodes; |
1243 |
2898 |
std::map< Node, TupleTrie >::iterator it; |
1244 |
|
|
1245 |
2898 |
if( argIndex==(int)reps.size()-1 ){ |
1246 |
1424 |
if(reps[argIndex].getKind() == kind::SKOLEM) { |
1247 |
1287 |
it = d_data.begin(); |
1248 |
15891 |
while(it != d_data.end()) { |
1249 |
7302 |
nodes.push_back(it->first); |
1250 |
7302 |
++it; |
1251 |
|
} |
1252 |
|
} |
1253 |
1424 |
return nodes; |
1254 |
|
}else{ |
1255 |
1474 |
it = d_data.find( reps[argIndex] ); |
1256 |
1474 |
if( it==d_data.end() ){ |
1257 |
74 |
return nodes; |
1258 |
|
}else{ |
1259 |
1400 |
return it->second.findTerms( reps, argIndex+1 ); |
1260 |
|
} |
1261 |
|
} |
1262 |
|
} |
1263 |
|
|
1264 |
243 |
std::vector<Node> TupleTrie::findSuccessors( std::vector< Node >& reps, int argIndex ) { |
1265 |
486 |
std::vector<Node> nodes; |
1266 |
243 |
std::map< Node, TupleTrie >::iterator it; |
1267 |
|
|
1268 |
243 |
if( argIndex==(int)reps.size() ){ |
1269 |
104 |
it = d_data.begin(); |
1270 |
476 |
while(it != d_data.end()) { |
1271 |
186 |
nodes.push_back(it->first); |
1272 |
186 |
++it; |
1273 |
|
} |
1274 |
104 |
return nodes; |
1275 |
|
}else{ |
1276 |
139 |
it = d_data.find( reps[argIndex] ); |
1277 |
139 |
if( it==d_data.end() ){ |
1278 |
35 |
return nodes; |
1279 |
|
}else{ |
1280 |
104 |
return it->second.findSuccessors( reps, argIndex+1 ); |
1281 |
|
} |
1282 |
|
} |
1283 |
|
} |
1284 |
|
|
1285 |
4146 |
Node TupleTrie::existsTerm( std::vector< Node >& reps, int argIndex ) { |
1286 |
4146 |
if( argIndex==(int)reps.size() ){ |
1287 |
1245 |
if( d_data.empty() ){ |
1288 |
|
return Node::null(); |
1289 |
|
}else{ |
1290 |
1245 |
return d_data.begin()->first; |
1291 |
|
} |
1292 |
|
}else{ |
1293 |
2901 |
std::map< Node, TupleTrie >::iterator it = d_data.find( reps[argIndex] ); |
1294 |
2901 |
if( it==d_data.end() ){ |
1295 |
217 |
return Node::null(); |
1296 |
|
}else{ |
1297 |
2684 |
return it->second.existsTerm( reps, argIndex+1 ); |
1298 |
|
} |
1299 |
|
} |
1300 |
|
} |
1301 |
|
|
1302 |
27991 |
bool TupleTrie::addTerm( Node n, std::vector< Node >& reps, int argIndex ){ |
1303 |
27991 |
if( argIndex==(int)reps.size() ){ |
1304 |
9290 |
if( d_data.empty() ){ |
1305 |
|
//store n in d_data (this should be interpretted as the "data" and not as a reference to a child) |
1306 |
9290 |
d_data[n].clear(); |
1307 |
9290 |
return true; |
1308 |
|
}else{ |
1309 |
|
return false; |
1310 |
|
} |
1311 |
|
}else{ |
1312 |
18701 |
return d_data[reps[argIndex]].addTerm( n, reps, argIndex+1 ); |
1313 |
|
} |
1314 |
|
} |
1315 |
|
|
1316 |
|
void TupleTrie::debugPrint( const char * c, Node n, unsigned depth ) { |
1317 |
|
for( std::map< Node, TupleTrie >::iterator it = d_data.begin(); it != d_data.end(); ++it ){ |
1318 |
|
for( unsigned i=0; i<depth; i++ ){ Debug(c) << " "; } |
1319 |
|
Debug(c) << it->first << std::endl; |
1320 |
|
it->second.debugPrint( c, n, depth+1 ); |
1321 |
|
} |
1322 |
|
} |
1323 |
|
|
1324 |
34779 |
void TheorySetsRels::sendInfer(Node fact, InferenceId id, Node reason) |
1325 |
|
{ |
1326 |
69558 |
Trace("rels-lemma") << "Rels::lemma " << fact << " from " << reason |
1327 |
34779 |
<< " by " << id << std::endl; |
1328 |
69558 |
Node lemma = NodeManager::currentNM()->mkNode(IMPLIES, reason, fact); |
1329 |
34779 |
d_im.addPendingLemma(lemma, id); |
1330 |
34779 |
} |
1331 |
|
} |
1332 |
|
} |
1333 |
29511 |
} // namespace cvc5 |