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