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