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 |
15272 |
TheorySetsRels::TheorySetsRels(Env& env, |
38 |
|
SolverState& s, |
39 |
|
InferenceManager& im, |
40 |
|
SkolemCache& skc, |
41 |
15272 |
TermRegistry& treg) |
42 |
|
: EnvObj(env), |
43 |
|
d_state(s), |
44 |
|
d_im(im), |
45 |
|
d_skCache(skc), |
46 |
|
d_treg(treg), |
47 |
15272 |
d_shared_terms(userContext()) |
48 |
|
{ |
49 |
15272 |
d_trueNode = NodeManager::currentNM()->mkConst(true); |
50 |
15272 |
d_falseNode = NodeManager::currentNM()->mkConst(false); |
51 |
15272 |
} |
52 |
|
|
53 |
30534 |
TheorySetsRels::~TheorySetsRels() {} |
54 |
|
|
55 |
809 |
void TheorySetsRels::check(Theory::Effort level) |
56 |
|
{ |
57 |
1618 |
Trace("rels") << "\n[sets-rels] ******************************* Start the " |
58 |
809 |
"relational solver, effort = " |
59 |
809 |
<< level << " *******************************\n" |
60 |
809 |
<< std::endl; |
61 |
809 |
if (Theory::fullEffort(level)) |
62 |
|
{ |
63 |
809 |
collectRelsInfo(); |
64 |
809 |
check(); |
65 |
809 |
d_im.doPendingLemmas(); |
66 |
|
} |
67 |
809 |
Assert(!d_im.hasPendingLemma()); |
68 |
1618 |
Trace("rels") << "\n[sets-rels] ******************************* Done with " |
69 |
809 |
"the relational solver *******************************\n" |
70 |
809 |
<< std::endl; |
71 |
809 |
} |
72 |
|
|
73 |
809 |
void TheorySetsRels::check() { |
74 |
809 |
MEM_IT m_it = d_rReps_memberReps_cache.begin(); |
75 |
|
|
76 |
6515 |
while(m_it != d_rReps_memberReps_cache.end()) { |
77 |
5706 |
Node rel_rep = m_it->first; |
78 |
|
|
79 |
12219 |
for(unsigned int i = 0; i < m_it->second.size(); i++) { |
80 |
18732 |
Node mem = d_rReps_memberReps_cache[rel_rep][i]; |
81 |
18732 |
Node exp = d_rReps_memberReps_exp_cache[rel_rep][i]; |
82 |
|
std::map<kind::Kind_t, std::vector<Node> >& kind_terms = |
83 |
9366 |
d_terms_cache[rel_rep]; |
84 |
|
|
85 |
9366 |
if( kind_terms.find(kind::TRANSPOSE) != kind_terms.end() ) { |
86 |
1349 |
std::vector<Node>& tp_terms = kind_terms[TRANSPOSE]; |
87 |
1349 |
if( tp_terms.size() > 0 ) { |
88 |
1349 |
applyTransposeRule( tp_terms ); |
89 |
1349 |
applyTransposeRule( tp_terms[0], rel_rep, exp ); |
90 |
|
} |
91 |
|
} |
92 |
9366 |
if( kind_terms.find(kind::JOIN) != kind_terms.end() ) { |
93 |
1251 |
std::vector<Node>& join_terms = kind_terms[JOIN]; |
94 |
2794 |
for( unsigned int j = 0; j < join_terms.size(); j++ ) { |
95 |
1543 |
applyJoinRule( join_terms[j], rel_rep, exp ); |
96 |
|
} |
97 |
|
} |
98 |
9366 |
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 |
9366 |
if( kind_terms.find(kind::TCLOSURE) != kind_terms.end() ) { |
105 |
276 |
std::vector<Node>& tc_terms = kind_terms[TCLOSURE]; |
106 |
552 |
for( unsigned int j = 0; j < tc_terms.size(); j++ ) { |
107 |
276 |
applyTCRule( mem, tc_terms[j], rel_rep, exp ); |
108 |
|
} |
109 |
|
} |
110 |
9366 |
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 |
9366 |
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 |
2853 |
++m_it; |
124 |
|
} |
125 |
|
|
126 |
809 |
TERM_IT t_it = d_terms_cache.begin(); |
127 |
7995 |
while( t_it != d_terms_cache.end() ) { |
128 |
|
// check the terms in this equivalence class for e.g. upwards closure |
129 |
|
// (computeMembersForBinOpRel / computeMembersForUnaryOpRel). This is |
130 |
|
// done regardless of whether we have initialized |
131 |
|
// d_rReps_memberReps_cache for this equivalence class. |
132 |
7186 |
Trace("rels-debug") |
133 |
3593 |
<< "[sets-rels] Check equivalence class: " |
134 |
3593 |
<< t_it->first << std::endl; |
135 |
3593 |
KIND_TERM_IT k_t_it = t_it->second.begin(); |
136 |
|
|
137 |
6625 |
while (k_t_it != t_it->second.end()) |
138 |
|
{ |
139 |
3032 |
Trace("rels-debug") << "[sets-rels] Check " << k_t_it->second.size() |
140 |
1516 |
<< " terms of kind " << k_t_it->first << std::endl; |
141 |
1516 |
std::vector<Node>::iterator term_it = k_t_it->second.begin(); |
142 |
1516 |
if (k_t_it->first == kind::JOIN || k_t_it->first == kind::PRODUCT) |
143 |
|
{ |
144 |
2921 |
while (term_it != k_t_it->second.end()) |
145 |
|
{ |
146 |
1015 |
computeMembersForBinOpRel(*term_it); |
147 |
1015 |
++term_it; |
148 |
|
} |
149 |
|
} |
150 |
625 |
else if (k_t_it->first == kind::TRANSPOSE) |
151 |
|
{ |
152 |
1140 |
while (term_it != k_t_it->second.end()) |
153 |
|
{ |
154 |
380 |
computeMembersForUnaryOpRel(*term_it); |
155 |
380 |
++term_it; |
156 |
|
} |
157 |
|
} |
158 |
245 |
else if (k_t_it->first == kind::TCLOSURE) |
159 |
|
{ |
160 |
474 |
while (term_it != k_t_it->second.end()) |
161 |
|
{ |
162 |
158 |
buildTCGraphForRel(*term_it); |
163 |
158 |
++term_it; |
164 |
|
} |
165 |
|
} |
166 |
87 |
else if (k_t_it->first == kind::JOIN_IMAGE) |
167 |
|
{ |
168 |
213 |
while (term_it != k_t_it->second.end()) |
169 |
|
{ |
170 |
71 |
computeMembersForJoinImageTerm(*term_it); |
171 |
71 |
++term_it; |
172 |
|
} |
173 |
|
} |
174 |
16 |
else if (k_t_it->first == kind::IDEN) |
175 |
|
{ |
176 |
48 |
while (term_it != k_t_it->second.end()) |
177 |
|
{ |
178 |
16 |
computeMembersForIdenTerm(*term_it); |
179 |
16 |
++term_it; |
180 |
|
} |
181 |
|
} |
182 |
1516 |
++k_t_it; |
183 |
|
} |
184 |
3593 |
++t_it; |
185 |
|
} |
186 |
809 |
doTCInference(); |
187 |
|
|
188 |
|
// clean up |
189 |
809 |
d_tuple_reps.clear(); |
190 |
809 |
d_rReps_memberReps_exp_cache.clear(); |
191 |
809 |
d_terms_cache.clear(); |
192 |
809 |
d_membership_trie.clear(); |
193 |
809 |
d_rel_nodes.clear(); |
194 |
809 |
d_rReps_memberReps_cache.clear(); |
195 |
809 |
d_rRep_tcGraph.clear(); |
196 |
809 |
d_tcr_tcGraph_exps.clear(); |
197 |
809 |
d_tcr_tcGraph.clear(); |
198 |
809 |
} |
199 |
|
|
200 |
|
/* |
201 |
|
* Populate relational terms data structure |
202 |
|
*/ |
203 |
|
|
204 |
809 |
void TheorySetsRels::collectRelsInfo() { |
205 |
809 |
Trace("rels") << "[sets-rels] Start collecting relational terms..." << std::endl; |
206 |
809 |
eq::EqualityEngine* ee = d_state.getEqualityEngine(); |
207 |
809 |
eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(ee); |
208 |
47615 |
while( !eqcs_i.isFinished() ){ |
209 |
46806 |
Node eqc_rep = (*eqcs_i); |
210 |
23403 |
eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc_rep, ee); |
211 |
|
|
212 |
46806 |
TypeNode erType = eqc_rep.getType(); |
213 |
23403 |
Trace("rels-ee") << "[sets-rels-ee] Eqc term representative: " << eqc_rep << " with type " << eqc_rep.getType() << std::endl; |
214 |
|
|
215 |
147137 |
while( !eqc_i.isFinished() ){ |
216 |
123734 |
Node eqc_node = (*eqc_i); |
217 |
|
|
218 |
61867 |
Trace("rels-ee") << " term : " << eqc_node << std::endl; |
219 |
|
|
220 |
61867 |
if (erType.isBoolean() && eqc_rep.isConst()) |
221 |
|
{ |
222 |
|
// collect membership info |
223 |
25654 |
if( eqc_node.getKind() == kind::MEMBER && eqc_node[1].getType().getSetElementType().isTuple()) { |
224 |
28446 |
Node tup_rep = getRepresentative( eqc_node[0] ); |
225 |
28446 |
Node rel_rep = getRepresentative( eqc_node[1] ); |
226 |
|
|
227 |
14223 |
if( eqc_node[0].isVar() ){ |
228 |
1880 |
reduceTupleVar( eqc_node ); |
229 |
|
} |
230 |
|
|
231 |
14223 |
bool is_true_eq = eqc_rep.getConst<bool>(); |
232 |
28446 |
Node reason = is_true_eq ? eqc_node : eqc_node.negate(); |
233 |
|
|
234 |
14223 |
if( is_true_eq ) { |
235 |
13054 |
if( safelyAddToMap(d_rReps_memberReps_cache, rel_rep, tup_rep) ) { |
236 |
9366 |
d_rReps_memberReps_exp_cache[rel_rep].push_back(reason); |
237 |
9366 |
computeTupleReps(tup_rep); |
238 |
9366 |
d_membership_trie[rel_rep].addTerm(tup_rep, d_tuple_reps[tup_rep]); |
239 |
|
} |
240 |
|
} |
241 |
|
} |
242 |
|
// collect relational terms info |
243 |
|
} |
244 |
36213 |
else if (erType.isSet() && erType.getSetElementType().isTuple()) |
245 |
|
{ |
246 |
17886 |
if( eqc_node.getKind() == kind::TRANSPOSE || eqc_node.getKind() == kind::JOIN || |
247 |
10426 |
eqc_node.getKind() == kind::PRODUCT || eqc_node.getKind() == kind::TCLOSURE || |
248 |
11499 |
eqc_node.getKind() == kind::JOIN_IMAGE || eqc_node.getKind() == kind::IDEN ) { |
249 |
1640 |
d_terms_cache[eqc_rep][eqc_node.getKind()].push_back(eqc_node); |
250 |
|
} |
251 |
|
// need to add all tuple elements as shared terms |
252 |
|
} |
253 |
31321 |
else if (erType.isTuple() && !eqc_node.isConst() && !eqc_node.isVar()) |
254 |
|
{ |
255 |
12188 |
std::vector<TypeNode> tupleTypes = erType.getTupleTypes(); |
256 |
18407 |
for (unsigned i = 0, tlen = erType.getTupleLength(); i < tlen; i++) |
257 |
|
{ |
258 |
24626 |
Node element = RelsUtils::nthElementOfTuple(eqc_node, i); |
259 |
12313 |
if (!element.isConst()) |
260 |
|
{ |
261 |
10901 |
makeSharedTerm(element, tupleTypes[i]); |
262 |
|
} |
263 |
|
} |
264 |
|
} |
265 |
61867 |
++eqc_i; |
266 |
|
} |
267 |
23403 |
++eqcs_i; |
268 |
|
} |
269 |
809 |
Trace("rels-debug") << "[Theory::Rels] Done with collecting relational terms!" << std::endl; |
270 |
809 |
} |
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 |
140 |
void TheorySetsRels::computeMembersForJoinImageTerm( Node join_image_term ) { |
279 |
140 |
Trace("rels-debug") << "\n[Theory::Rels] *********** Compute members for JoinImage Term = " << join_image_term << std::endl; |
280 |
140 |
MEM_IT rel_mem_it = d_rReps_memberReps_cache.find( getRepresentative( join_image_term[0] ) ); |
281 |
|
|
282 |
140 |
if( rel_mem_it == d_rReps_memberReps_cache.end() ) { |
283 |
|
return; |
284 |
|
} |
285 |
140 |
NodeManager* nm = NodeManager::currentNM(); |
286 |
|
|
287 |
280 |
Node join_image_rel = join_image_term[0]; |
288 |
280 |
std::unordered_set<Node> hasChecked; |
289 |
280 |
Node join_image_rel_rep = getRepresentative( join_image_rel ); |
290 |
140 |
std::vector< Node >::iterator mem_rep_it = (*rel_mem_it).second.begin(); |
291 |
140 |
MEM_IT rel_mem_exp_it = d_rReps_memberReps_exp_cache.find( join_image_rel_rep ); |
292 |
140 |
std::vector< Node >::iterator mem_rep_exp_it = (*rel_mem_exp_it).second.begin(); |
293 |
140 |
unsigned int min_card = join_image_term[1].getConst<Rational>().getNumerator().getUnsignedInt(); |
294 |
|
|
295 |
1432 |
while( mem_rep_it != (*rel_mem_it).second.end() ) { |
296 |
856 |
Node fst_mem_rep = RelsUtils::nthElementOfTuple( *mem_rep_it, 0 ); |
297 |
|
|
298 |
854 |
if( hasChecked.find( fst_mem_rep ) != hasChecked.end() ) { |
299 |
208 |
++mem_rep_it; |
300 |
208 |
++mem_rep_exp_it; |
301 |
208 |
continue; |
302 |
|
} |
303 |
438 |
hasChecked.insert( fst_mem_rep ); |
304 |
|
|
305 |
|
const DType& dt = |
306 |
438 |
join_image_term.getType().getSetElementType().getDType(); |
307 |
|
Node new_membership = nm->mkNode( |
308 |
|
MEMBER, |
309 |
876 |
nm->mkNode(APPLY_CONSTRUCTOR, dt[0].getConstructor(), fst_mem_rep), |
310 |
1524 |
join_image_term); |
311 |
666 |
if (d_state.isEntailed(new_membership, true)) |
312 |
|
{ |
313 |
228 |
++mem_rep_it; |
314 |
228 |
++mem_rep_exp_it; |
315 |
228 |
continue; |
316 |
|
} |
317 |
|
|
318 |
420 |
std::vector< Node > reasons; |
319 |
420 |
std::vector< Node > existing_members; |
320 |
210 |
std::vector< Node >::iterator mem_rep_exp_it_snd = (*rel_mem_exp_it).second.begin(); |
321 |
|
|
322 |
1628 |
while( mem_rep_exp_it_snd != (*rel_mem_exp_it).second.end() ) { |
323 |
1493 |
Node fst_element_snd_mem = RelsUtils::nthElementOfTuple( (*mem_rep_exp_it_snd)[0], 0 ); |
324 |
|
|
325 |
784 |
if( areEqual( fst_mem_rep, fst_element_snd_mem ) ) { |
326 |
233 |
bool notExist = true; |
327 |
233 |
std::vector< Node >::iterator existing_mem_it = existing_members.begin(); |
328 |
391 |
Node snd_element_snd_mem = RelsUtils::nthElementOfTuple( (*mem_rep_exp_it_snd)[0], 1 ); |
329 |
|
|
330 |
315 |
while( existing_mem_it != existing_members.end() ) { |
331 |
41 |
if( areEqual( (*existing_mem_it), snd_element_snd_mem ) ) { |
332 |
|
notExist = false; |
333 |
|
break; |
334 |
|
} |
335 |
41 |
++existing_mem_it; |
336 |
|
} |
337 |
|
|
338 |
233 |
if( notExist ) { |
339 |
233 |
existing_members.push_back( snd_element_snd_mem ); |
340 |
233 |
reasons.push_back( *mem_rep_exp_it_snd ); |
341 |
233 |
if( fst_mem_rep != fst_element_snd_mem ) { |
342 |
11 |
reasons.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, fst_mem_rep, fst_element_snd_mem ) ); |
343 |
|
} |
344 |
233 |
if( join_image_rel != (*mem_rep_exp_it_snd)[1] ) { |
345 |
140 |
reasons.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, (*mem_rep_exp_it_snd)[1], join_image_rel )); |
346 |
|
} |
347 |
233 |
if( existing_members.size() == min_card ) { |
348 |
75 |
if( min_card >= 2) { |
349 |
31 |
new_membership = NodeManager::currentNM()->mkNode( kind::OR, new_membership, NodeManager::currentNM()->mkNode( kind::NOT, NodeManager::currentNM()->mkNode( kind::DISTINCT, existing_members ) )); |
350 |
|
} |
351 |
75 |
Assert(reasons.size() >= 1); |
352 |
75 |
sendInfer( |
353 |
|
new_membership, |
354 |
|
InferenceId::SETS_RELS_JOIN_IMAGE_UP, |
355 |
150 |
reasons.size() > 1 ? nm->mkNode(AND, reasons) : reasons[0]); |
356 |
75 |
break; |
357 |
|
} |
358 |
|
} |
359 |
|
} |
360 |
709 |
++mem_rep_exp_it_snd; |
361 |
|
} |
362 |
210 |
++mem_rep_it; |
363 |
210 |
++mem_rep_exp_it; |
364 |
|
} |
365 |
140 |
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 |
24 |
void TheorySetsRels::computeMembersForIdenTerm( Node iden_term ) { |
465 |
24 |
Trace("rels-debug") << "\n[Theory::Rels] *********** Compute members for Iden Term = " << iden_term << std::endl; |
466 |
38 |
Node iden_term_rel = iden_term[0]; |
467 |
38 |
Node iden_term_rel_rep = getRepresentative( iden_term_rel ); |
468 |
|
|
469 |
24 |
if( d_rReps_memberReps_cache.find( iden_term_rel_rep ) == d_rReps_memberReps_cache.end() ) { |
470 |
10 |
return; |
471 |
|
} |
472 |
14 |
NodeManager* nm = NodeManager::currentNM(); |
473 |
|
|
474 |
14 |
MEM_IT rel_mem_exp_it = d_rReps_memberReps_exp_cache.find( iden_term_rel_rep ); |
475 |
14 |
std::vector< Node >::iterator mem_rep_exp_it = (*rel_mem_exp_it).second.begin(); |
476 |
|
|
477 |
108 |
while( mem_rep_exp_it != (*rel_mem_exp_it).second.end() ) { |
478 |
94 |
Node reason = *mem_rep_exp_it; |
479 |
94 |
Node fst_exp_mem = RelsUtils::nthElementOfTuple( (*mem_rep_exp_it)[0], 0 ); |
480 |
94 |
Node new_mem = RelsUtils::constructPair( iden_term, fst_exp_mem, fst_exp_mem ); |
481 |
|
|
482 |
47 |
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 |
141 |
sendInfer( |
486 |
94 |
nm->mkNode(MEMBER, new_mem, iden_term), InferenceId::SETS_RELS_IDENTITY_UP, reason); |
487 |
47 |
++mem_rep_exp_it; |
488 |
|
} |
489 |
14 |
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 |
276 |
void TheorySetsRels::applyTCRule( Node mem_rep, Node tc_rel, Node tc_rel_rep, Node exp ) { |
512 |
552 |
Trace("rels-debug") << "[Theory::Rels] *********** Applying TCLOSURE rule on a tc term = " << tc_rel |
513 |
276 |
<< ", its representative = " << tc_rel_rep |
514 |
276 |
<< " with member rep = " << mem_rep << " and explanation = " << exp << std::endl; |
515 |
276 |
MEM_IT mem_it = d_rReps_memberReps_cache.find( tc_rel[0] ); |
516 |
|
|
517 |
818 |
if( mem_it != d_rReps_memberReps_cache.end() && d_rel_nodes.find( tc_rel ) == d_rel_nodes.end() |
518 |
653 |
&& d_rRep_tcGraph.find( getRepresentative( tc_rel[0] ) ) == d_rRep_tcGraph.end() ) { |
519 |
101 |
buildTCGraphForRel( tc_rel ); |
520 |
101 |
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 |
276 |
if( isTCReachable( mem_rep, tc_rel) ) { |
525 |
506 |
Trace("rels-debug") << "[Theory::Rels] mem_rep is a member of tc_rel[0] = " << tc_rel[0] |
526 |
253 |
<< " or can be infered by TC_Graph of tc_rel[0]! " << std::endl; |
527 |
253 |
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 |
13 |
std::map< Node, std::map< Node, Node > >::iterator tc_exp_it = d_tcr_tcGraph_exps.find( tc_rel ); |
539 |
|
|
540 |
13 |
TC_GRAPH_IT tc_graph_it = (tc_it->second).find( mem_rep_fst ); |
541 |
13 |
Assert(tc_exp_it != d_tcr_tcGraph_exps.end()); |
542 |
13 |
std::map< Node, Node >::iterator exp_map_it = (tc_exp_it->second).find( mem_rep_tup ); |
543 |
|
|
544 |
13 |
if( exp_map_it == (tc_exp_it->second).end() ) { |
545 |
13 |
(tc_exp_it->second)[mem_rep_tup] = exp; |
546 |
|
} |
547 |
|
|
548 |
13 |
if( tc_graph_it != (tc_it->second).end() ) { |
549 |
8 |
(tc_graph_it->second).insert( mem_rep_snd ); |
550 |
|
} else { |
551 |
10 |
std::unordered_set<Node> sets; |
552 |
5 |
sets.insert( mem_rep_snd ); |
553 |
5 |
(tc_it->second)[mem_rep_fst] = sets; |
554 |
|
} |
555 |
|
} else { |
556 |
20 |
std::map< Node, Node > exp_map; |
557 |
20 |
std::unordered_set<Node> sets; |
558 |
20 |
std::map<Node, std::unordered_set<Node> > element_map; |
559 |
10 |
sets.insert( mem_rep_snd ); |
560 |
10 |
element_map[mem_rep_fst] = sets; |
561 |
10 |
d_tcr_tcGraph[tc_rel] = element_map; |
562 |
10 |
exp_map[mem_rep_tup] = exp; |
563 |
10 |
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 |
5 |
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 |
276 |
bool TheorySetsRels::isTCReachable( Node mem_rep, Node tc_rel ) { |
606 |
276 |
MEM_IT mem_it = d_rReps_memberReps_cache.find( getRepresentative( tc_rel[0] ) ); |
607 |
|
|
608 |
276 |
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 |
168 |
return true; |
610 |
|
} |
611 |
|
|
612 |
108 |
TC_IT tc_it = d_rRep_tcGraph.find( getRepresentative(tc_rel[0]) ); |
613 |
108 |
if( tc_it != d_rRep_tcGraph.end() ) { |
614 |
98 |
bool isReachable = false; |
615 |
196 |
std::unordered_set<Node> seen; |
616 |
196 |
isTCReachable( getRepresentative( RelsUtils::nthElementOfTuple(mem_rep, 0) ), |
617 |
294 |
getRepresentative( RelsUtils::nthElementOfTuple(mem_rep, 1) ), seen, tc_it->second, isReachable ); |
618 |
98 |
return isReachable; |
619 |
|
} |
620 |
10 |
return false; |
621 |
|
} |
622 |
|
|
623 |
210 |
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 |
210 |
if(hasSeen.find(start) == hasSeen.end()) { |
631 |
210 |
hasSeen.insert(start); |
632 |
|
} |
633 |
|
|
634 |
210 |
TC_GRAPH_IT pair_set_it = tc_graph.find(start); |
635 |
|
|
636 |
210 |
if(pair_set_it != tc_graph.end()) { |
637 |
184 |
if(pair_set_it->second.find(dest) != pair_set_it->second.end()) { |
638 |
85 |
isReachable = true; |
639 |
170 |
return; |
640 |
|
} else { |
641 |
99 |
std::unordered_set<Node>::iterator set_it = pair_set_it->second.begin(); |
642 |
|
|
643 |
323 |
while( set_it != pair_set_it->second.end() ) { |
644 |
|
// need to check if *set_it has been looked already |
645 |
112 |
if( hasSeen.find(*set_it) == hasSeen.end() ) { |
646 |
112 |
isTCReachable( *set_it, dest, hasSeen, tc_graph, isReachable ); |
647 |
|
} |
648 |
112 |
++set_it; |
649 |
|
} |
650 |
|
} |
651 |
|
} |
652 |
|
} |
653 |
|
|
654 |
259 |
void TheorySetsRels::buildTCGraphForRel( Node tc_rel ) { |
655 |
518 |
std::map< Node, Node > rel_tc_graph_exps; |
656 |
518 |
std::map<Node, std::unordered_set<Node> > rel_tc_graph; |
657 |
|
|
658 |
518 |
Node rel_rep = getRepresentative( tc_rel[0] ); |
659 |
518 |
Node tc_rel_rep = getRepresentative( tc_rel ); |
660 |
259 |
const std::vector<Node>& members = d_rReps_memberReps_cache[rel_rep]; |
661 |
259 |
const std::vector<Node>& exps = d_rReps_memberReps_exp_cache[rel_rep]; |
662 |
|
|
663 |
734 |
for (size_t i = 0, msize = members.size(); i < msize; i++) |
664 |
|
{ |
665 |
950 |
Node fst_element_rep = getRepresentative( RelsUtils::nthElementOfTuple( members[i], 0 )); |
666 |
950 |
Node snd_element_rep = getRepresentative( RelsUtils::nthElementOfTuple( members[i], 1 )); |
667 |
950 |
Node tuple_rep = RelsUtils::constructPair( rel_rep, fst_element_rep, snd_element_rep ); |
668 |
|
std::map<Node, std::unordered_set<Node> >::iterator rel_tc_graph_it = |
669 |
475 |
rel_tc_graph.find(fst_element_rep); |
670 |
|
|
671 |
475 |
if( rel_tc_graph_it == rel_tc_graph.end() ) { |
672 |
818 |
std::unordered_set<Node> snd_elements; |
673 |
409 |
snd_elements.insert( snd_element_rep ); |
674 |
409 |
rel_tc_graph[fst_element_rep] = snd_elements; |
675 |
409 |
rel_tc_graph_exps[tuple_rep] = exps[i]; |
676 |
66 |
} else if( (rel_tc_graph_it->second).find( snd_element_rep ) == (rel_tc_graph_it->second).end() ) { |
677 |
66 |
(rel_tc_graph_it->second).insert( snd_element_rep ); |
678 |
66 |
rel_tc_graph_exps[tuple_rep] = exps[i]; |
679 |
|
} |
680 |
|
} |
681 |
|
|
682 |
259 |
if( members.size() > 0 ) { |
683 |
216 |
d_rRep_tcGraph[rel_rep] = rel_tc_graph; |
684 |
216 |
d_tcr_tcGraph_exps[tc_rel] = rel_tc_graph_exps; |
685 |
216 |
d_tcr_tcGraph[tc_rel] = rel_tc_graph; |
686 |
|
} |
687 |
259 |
} |
688 |
|
|
689 |
125 |
void TheorySetsRels::doTCInference( |
690 |
|
std::map<Node, std::unordered_set<Node> > rel_tc_graph, |
691 |
|
std::map<Node, Node> rel_tc_graph_exps, |
692 |
|
Node tc_rel) |
693 |
|
{ |
694 |
125 |
Trace("rels-debug") << "[Theory::Rels] ****** doTCInference !" << std::endl; |
695 |
350 |
for (TC_GRAPH_IT tc_graph_it = rel_tc_graph.begin(); |
696 |
350 |
tc_graph_it != rel_tc_graph.end(); |
697 |
|
++tc_graph_it) |
698 |
|
{ |
699 |
264 |
for (std::unordered_set<Node>::iterator snd_elements_it = |
700 |
225 |
tc_graph_it->second.begin(); |
701 |
489 |
snd_elements_it != tc_graph_it->second.end(); |
702 |
|
++snd_elements_it) |
703 |
|
{ |
704 |
528 |
std::vector< Node > reasons; |
705 |
528 |
std::unordered_set<Node> seen; |
706 |
528 |
Node tuple = RelsUtils::constructPair( tc_rel, getRepresentative( tc_graph_it->first ), getRepresentative( *snd_elements_it) ); |
707 |
264 |
Assert(rel_tc_graph_exps.find(tuple) != rel_tc_graph_exps.end()); |
708 |
528 |
Node exp = rel_tc_graph_exps.find( tuple )->second; |
709 |
|
|
710 |
264 |
reasons.push_back( exp ); |
711 |
264 |
seen.insert( tc_graph_it->first ); |
712 |
264 |
doTCInference( tc_rel, reasons, rel_tc_graph, rel_tc_graph_exps, tc_graph_it->first, *snd_elements_it, seen); |
713 |
|
} |
714 |
|
} |
715 |
125 |
Trace("rels-debug") << "[Theory::Rels] ****** Done with doTCInference !" << std::endl; |
716 |
125 |
} |
717 |
|
|
718 |
492 |
void TheorySetsRels::doTCInference( |
719 |
|
Node tc_rel, |
720 |
|
std::vector<Node> reasons, |
721 |
|
std::map<Node, std::unordered_set<Node> >& tc_graph, |
722 |
|
std::map<Node, Node>& rel_tc_graph_exps, |
723 |
|
Node start_node_rep, |
724 |
|
Node cur_node_rep, |
725 |
|
std::unordered_set<Node>& seen) |
726 |
|
{ |
727 |
492 |
NodeManager* nm = NodeManager::currentNM(); |
728 |
868 |
Node tc_mem = RelsUtils::constructPair( tc_rel, RelsUtils::nthElementOfTuple((reasons.front())[0], 0), RelsUtils::nthElementOfTuple((reasons.back())[0], 1) ); |
729 |
868 |
std::vector< Node > all_reasons( reasons ); |
730 |
|
|
731 |
821 |
for( unsigned int i = 0 ; i < reasons.size()-1; i++ ) { |
732 |
658 |
Node fst_element_end = RelsUtils::nthElementOfTuple( reasons[i][0], 1 ); |
733 |
658 |
Node snd_element_begin = RelsUtils::nthElementOfTuple( reasons[i+1][0], 0 ); |
734 |
329 |
if( fst_element_end != snd_element_begin ) { |
735 |
48 |
all_reasons.push_back( NodeManager::currentNM()->mkNode(kind::EQUAL, fst_element_end, snd_element_begin) ); |
736 |
|
} |
737 |
329 |
if( tc_rel != reasons[i][1] && tc_rel[0] != reasons[i][1] ) { |
738 |
8 |
all_reasons.push_back( NodeManager::currentNM()->mkNode(kind::EQUAL, tc_rel[0], reasons[i][1]) ); |
739 |
|
} |
740 |
|
} |
741 |
492 |
if( tc_rel != reasons.back()[1] && tc_rel[0] != reasons.back()[1] ) { |
742 |
8 |
all_reasons.push_back( NodeManager::currentNM()->mkNode(kind::EQUAL, tc_rel[0], reasons.back()[1]) ); |
743 |
|
} |
744 |
492 |
if( all_reasons.size() > 1) { |
745 |
236 |
sendInfer(nm->mkNode(MEMBER, tc_mem, tc_rel), |
746 |
|
InferenceId::SETS_RELS_TCLOSURE_FWD, |
747 |
472 |
nm->mkNode(AND, all_reasons)); |
748 |
|
} else { |
749 |
256 |
sendInfer(nm->mkNode(MEMBER, tc_mem, tc_rel), |
750 |
|
InferenceId::SETS_RELS_TCLOSURE_FWD, |
751 |
256 |
all_reasons.front()); |
752 |
|
} |
753 |
|
|
754 |
|
// check if cur_node has been traversed or not |
755 |
492 |
if( seen.find( cur_node_rep ) != seen.end() ) { |
756 |
116 |
return; |
757 |
|
} |
758 |
376 |
seen.insert( cur_node_rep ); |
759 |
376 |
TC_GRAPH_IT cur_set = tc_graph.find( cur_node_rep ); |
760 |
376 |
if( cur_set != tc_graph.end() ) { |
761 |
397 |
for (std::unordered_set<Node>::iterator set_it = cur_set->second.begin(); |
762 |
397 |
set_it != cur_set->second.end(); |
763 |
|
++set_it) |
764 |
|
{ |
765 |
456 |
Node new_pair = RelsUtils::constructPair( tc_rel, cur_node_rep, *set_it ); |
766 |
456 |
std::vector< Node > new_reasons( reasons ); |
767 |
228 |
new_reasons.push_back( rel_tc_graph_exps.find( new_pair )->second ); |
768 |
228 |
doTCInference( tc_rel, new_reasons, tc_graph, rel_tc_graph_exps, start_node_rep, *set_it, seen ); |
769 |
|
} |
770 |
|
} |
771 |
|
} |
772 |
|
|
773 |
|
/* product-split rule: (a, b) IS_IN (X PRODUCT Y) |
774 |
|
* ---------------------------------- |
775 |
|
* a IS_IN X && b IS_IN Y |
776 |
|
* |
777 |
|
* product-compose rule: (a, b) IS_IN X (c, d) IS_IN Y |
778 |
|
* --------------------------------- |
779 |
|
* (a, b, c, d) IS_IN (X PRODUCT Y) |
780 |
|
*/ |
781 |
|
|
782 |
|
|
783 |
169 |
void TheorySetsRels::applyProductRule( Node pt_rel, Node pt_rel_rep, Node exp ) { |
784 |
338 |
Trace("rels-debug") << "\n[Theory::Rels] *********** Applying PRODUCT rule on producted term = " << pt_rel |
785 |
169 |
<< ", its representative = " << pt_rel_rep |
786 |
169 |
<< " with explanation = " << exp << std::endl; |
787 |
|
|
788 |
169 |
if(d_rel_nodes.find( pt_rel ) == d_rel_nodes.end()) { |
789 |
114 |
Trace("rels-debug") << "\n[Theory::Rels] Apply PRODUCT-COMPOSE rule on term: " << pt_rel |
790 |
57 |
<< " with explanation: " << exp << std::endl; |
791 |
|
|
792 |
57 |
computeMembersForBinOpRel( pt_rel ); |
793 |
57 |
d_rel_nodes.insert( pt_rel ); |
794 |
|
} |
795 |
|
|
796 |
338 |
Node mem = exp[0]; |
797 |
338 |
std::vector<Node> r1_element; |
798 |
338 |
std::vector<Node> r2_element; |
799 |
169 |
const DType& dt1 = pt_rel[0].getType().getSetElementType().getDType(); |
800 |
169 |
unsigned int s1_len = pt_rel[0].getType().getSetElementType().getTupleLength(); |
801 |
169 |
unsigned int tup_len = pt_rel.getType().getSetElementType().getTupleLength(); |
802 |
|
|
803 |
169 |
r1_element.push_back(dt1[0].getConstructor()); |
804 |
|
|
805 |
169 |
unsigned int i = 0; |
806 |
743 |
for(; i < s1_len; ++i) { |
807 |
287 |
r1_element.push_back(RelsUtils::nthElementOfTuple(mem, i)); |
808 |
|
} |
809 |
169 |
const DType& dt2 = pt_rel[1].getType().getSetElementType().getDType(); |
810 |
169 |
r2_element.push_back(dt2[0].getConstructor()); |
811 |
743 |
for(; i < tup_len; ++i) { |
812 |
287 |
r2_element.push_back(RelsUtils::nthElementOfTuple(mem, i)); |
813 |
|
} |
814 |
338 |
Node reason = exp; |
815 |
338 |
Node mem1 = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, r1_element); |
816 |
338 |
Node mem2 = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, r2_element); |
817 |
338 |
Node fact_1 = NodeManager::currentNM()->mkNode(kind::MEMBER, mem1, pt_rel[0]); |
818 |
338 |
Node fact_2 = NodeManager::currentNM()->mkNode(kind::MEMBER, mem2, pt_rel[1]); |
819 |
|
|
820 |
169 |
if( pt_rel != exp[1] ) { |
821 |
12 |
reason = NodeManager::currentNM()->mkNode(kind::AND, exp, NodeManager::currentNM()->mkNode(kind::EQUAL, pt_rel, exp[1])); |
822 |
|
} |
823 |
169 |
sendInfer(fact_1, InferenceId::SETS_RELS_PRODUCT_SPLIT, reason); |
824 |
169 |
sendInfer(fact_2, InferenceId::SETS_RELS_PRODUCT_SPLIT, reason); |
825 |
169 |
} |
826 |
|
|
827 |
|
/* join-split rule: (a, b) IS_IN (X JOIN Y) |
828 |
|
* -------------------------------------------- |
829 |
|
* exists z | (a, z) IS_IN X && (z, b) IS_IN Y |
830 |
|
* |
831 |
|
* |
832 |
|
* join-compose rule: (a, b) IS_IN X (b, c) IS_IN Y NOT (t, u) IS_IN (X JOIN Y) |
833 |
|
* ------------------------------------------------------------- |
834 |
|
* (a, c) IS_IN (X JOIN Y) |
835 |
|
*/ |
836 |
|
|
837 |
1543 |
void TheorySetsRels::applyJoinRule( Node join_rel, Node join_rel_rep, Node exp ) { |
838 |
3086 |
Trace("rels-debug") << "\n[Theory::Rels] *********** Applying JOIN rule on joined term = " << join_rel |
839 |
1543 |
<< ", its representative = " << join_rel_rep |
840 |
1543 |
<< " with explanation = " << exp << std::endl; |
841 |
1543 |
if(d_rel_nodes.find( join_rel ) == d_rel_nodes.end()) { |
842 |
832 |
Trace("rels-debug") << "\n[Theory::Rels] Apply JOIN-COMPOSE rule on term: " << join_rel |
843 |
416 |
<< " with explanation: " << exp << std::endl; |
844 |
|
|
845 |
416 |
computeMembersForBinOpRel( join_rel ); |
846 |
416 |
d_rel_nodes.insert( join_rel ); |
847 |
|
} |
848 |
|
|
849 |
1830 |
Node mem = exp[0]; |
850 |
1830 |
std::vector<Node> r1_element; |
851 |
1830 |
std::vector<Node> r2_element; |
852 |
1830 |
Node r1_rep = getRepresentative(join_rel[0]); |
853 |
1830 |
Node r2_rep = getRepresentative(join_rel[1]); |
854 |
1830 |
TypeNode shared_type = r2_rep.getType().getSetElementType().getTupleTypes()[0]; |
855 |
1543 |
Node shared_x = d_skCache.mkTypedSkolemCached( |
856 |
1830 |
shared_type, mem, join_rel, SkolemCache::SK_JOIN, "srj"); |
857 |
1543 |
const DType& dt1 = join_rel[0].getType().getSetElementType().getDType(); |
858 |
1543 |
unsigned int s1_len = join_rel[0].getType().getSetElementType().getTupleLength(); |
859 |
1543 |
unsigned int tup_len = join_rel.getType().getSetElementType().getTupleLength(); |
860 |
|
|
861 |
1543 |
unsigned int i = 0; |
862 |
1543 |
r1_element.push_back(dt1[0].getConstructor()); |
863 |
4581 |
for(; i < s1_len-1; ++i) { |
864 |
1519 |
r1_element.push_back(RelsUtils::nthElementOfTuple(mem, i)); |
865 |
|
} |
866 |
1543 |
r1_element.push_back(shared_x); |
867 |
1543 |
const DType& dt2 = join_rel[1].getType().getSetElementType().getDType(); |
868 |
1543 |
r2_element.push_back(dt2[0].getConstructor()); |
869 |
1543 |
r2_element.push_back(shared_x); |
870 |
4685 |
for(; i < tup_len; ++i) { |
871 |
1571 |
r2_element.push_back(RelsUtils::nthElementOfTuple(mem, i)); |
872 |
|
} |
873 |
1830 |
Node mem1 = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, r1_element); |
874 |
1830 |
Node mem2 = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, r2_element); |
875 |
|
|
876 |
1543 |
computeTupleReps(mem1); |
877 |
1543 |
computeTupleReps(mem2); |
878 |
|
|
879 |
1830 |
std::vector<Node> elements = d_membership_trie[r1_rep].findTerms(d_tuple_reps[mem1]); |
880 |
|
|
881 |
1768 |
for(unsigned int j = 0; j < elements.size(); j++) { |
882 |
1706 |
std::vector<Node> new_tup; |
883 |
1481 |
new_tup.push_back(elements[j]); |
884 |
1481 |
new_tup.insert(new_tup.end(), d_tuple_reps[mem2].begin()+1, d_tuple_reps[mem2].end()); |
885 |
1481 |
if(d_membership_trie[r2_rep].existsTerm(new_tup) != Node::null()) { |
886 |
1256 |
return; |
887 |
|
} |
888 |
|
} |
889 |
574 |
Node reason = exp; |
890 |
287 |
if( join_rel != exp[1] ) { |
891 |
159 |
reason = NodeManager::currentNM()->mkNode(kind::AND, reason, NodeManager::currentNM()->mkNode(kind::EQUAL, join_rel, exp[1])); |
892 |
|
} |
893 |
574 |
Node fact = NodeManager::currentNM()->mkNode(kind::MEMBER, mem1, join_rel[0]); |
894 |
287 |
sendInfer(fact, InferenceId::SETS_RELS_JOIN_SPLIT_1, reason); |
895 |
287 |
fact = NodeManager::currentNM()->mkNode(kind::MEMBER, mem2, join_rel[1]); |
896 |
287 |
sendInfer(fact, InferenceId::SETS_RELS_JOIN_SPLIT_2, reason); |
897 |
287 |
makeSharedTerm(shared_x, shared_type); |
898 |
|
} |
899 |
|
|
900 |
|
/* |
901 |
|
* transpose-occur rule: (a, b) IS_IN X (TRANSPOSE X) in T |
902 |
|
* --------------------------------------- |
903 |
|
* (b, a) IS_IN (TRANSPOSE X) |
904 |
|
* |
905 |
|
* transpose-reverse rule: (a, b) IS_IN (TRANSPOSE X) |
906 |
|
* --------------------------------------- |
907 |
|
* (b, a) IS_IN X |
908 |
|
* |
909 |
|
*/ |
910 |
1349 |
void TheorySetsRels::applyTransposeRule( std::vector<Node> tp_terms ) { |
911 |
1349 |
if( tp_terms.size() < 1) { |
912 |
|
return; |
913 |
|
} |
914 |
1349 |
NodeManager* nm = NodeManager::currentNM(); |
915 |
1349 |
for( unsigned int i = 1; i < tp_terms.size(); i++ ) { |
916 |
|
Trace("rels-debug") << "\n[Theory::Rels] *********** Applying TRANSPOSE-Equal rule on transposed term = " << tp_terms[0] << " and " << tp_terms[i] << std::endl; |
917 |
|
sendInfer(nm->mkNode(EQUAL, tp_terms[0][0], tp_terms[i][0]), |
918 |
|
InferenceId::SETS_RELS_TRANSPOSE_EQ, |
919 |
|
nm->mkNode(EQUAL, tp_terms[0], tp_terms[i])); |
920 |
|
} |
921 |
|
} |
922 |
|
|
923 |
1349 |
void TheorySetsRels::applyTransposeRule( Node tp_rel, Node tp_rel_rep, Node exp ) { |
924 |
2698 |
Trace("rels-debug") << "\n[Theory::Rels] *********** Applying TRANSPOSE rule on transposed term = " << tp_rel |
925 |
1349 |
<< ", its representative = " << tp_rel_rep |
926 |
1349 |
<< " with explanation = " << exp << std::endl; |
927 |
1349 |
NodeManager* nm = NodeManager::currentNM(); |
928 |
|
|
929 |
1349 |
if(d_rel_nodes.find( tp_rel ) == d_rel_nodes.end()) { |
930 |
394 |
Trace("rels-debug") << "\n[Theory::Rels] Apply TRANSPOSE-Compose rule on term: " << tp_rel |
931 |
197 |
<< " with explanation: " << exp << std::endl; |
932 |
|
|
933 |
197 |
computeMembersForUnaryOpRel( tp_rel ); |
934 |
197 |
d_rel_nodes.insert( tp_rel ); |
935 |
|
} |
936 |
|
|
937 |
2698 |
Node reason = exp; |
938 |
2698 |
Node reversed_mem = RelsUtils::reverseTuple( exp[0] ); |
939 |
|
|
940 |
1349 |
if( tp_rel != exp[1] ) { |
941 |
155 |
reason = NodeManager::currentNM()->mkNode(kind::AND, reason, NodeManager::currentNM()->mkNode(kind::EQUAL, tp_rel, exp[1])); |
942 |
|
} |
943 |
1349 |
sendInfer(nm->mkNode(MEMBER, reversed_mem, tp_rel[0]), |
944 |
|
InferenceId::SETS_RELS_TRANSPOSE_REV, |
945 |
|
reason); |
946 |
1349 |
} |
947 |
|
|
948 |
809 |
void TheorySetsRels::doTCInference() { |
949 |
809 |
Trace("rels-debug") << "[Theory::Rels] ****** Finalizing transitive closure inferences!" << std::endl; |
950 |
809 |
TC_IT tc_graph_it = d_tcr_tcGraph.begin(); |
951 |
1059 |
while( tc_graph_it != d_tcr_tcGraph.end() ) { |
952 |
125 |
Assert(d_tcr_tcGraph_exps.find(tc_graph_it->first) |
953 |
|
!= d_tcr_tcGraph_exps.end()); |
954 |
125 |
doTCInference( tc_graph_it->second, d_tcr_tcGraph_exps.find(tc_graph_it->first)->second, tc_graph_it->first ); |
955 |
125 |
++tc_graph_it; |
956 |
|
} |
957 |
809 |
Trace("rels-debug") << "[Theory::Rels] ****** Done with finalizing transitive closure inferences!" << std::endl; |
958 |
809 |
} |
959 |
|
|
960 |
|
|
961 |
|
// Bottom-up fashion to compute relations with more than 1 arity |
962 |
2022 |
void TheorySetsRels::computeMembersForBinOpRel(Node rel) { |
963 |
2022 |
Trace("rels-debug") << "\n[Theory::Rels] computeMembersForBinOpRel for relation " << rel << std::endl; |
964 |
|
|
965 |
2022 |
switch(rel[0].getKind()) { |
966 |
288 |
case kind::TRANSPOSE: |
967 |
|
case kind::TCLOSURE: { |
968 |
288 |
computeMembersForUnaryOpRel(rel[0]); |
969 |
288 |
break; |
970 |
|
} |
971 |
280 |
case kind::JOIN: |
972 |
|
case kind::PRODUCT: { |
973 |
280 |
computeMembersForBinOpRel(rel[0]); |
974 |
280 |
break; |
975 |
|
} |
976 |
1454 |
default: |
977 |
1454 |
break; |
978 |
|
} |
979 |
2022 |
switch(rel[1].getKind()) { |
980 |
26 |
case kind::TRANSPOSE: { |
981 |
26 |
computeMembersForUnaryOpRel(rel[1]); |
982 |
26 |
break; |
983 |
|
} |
984 |
16 |
case kind::JOIN: |
985 |
|
case kind::PRODUCT: { |
986 |
16 |
computeMembersForBinOpRel(rel[1]); |
987 |
16 |
break; |
988 |
|
} |
989 |
1980 |
default: |
990 |
1980 |
break; |
991 |
|
} |
992 |
2022 |
composeMembersForRels(rel); |
993 |
2022 |
} |
994 |
|
|
995 |
|
// Bottom-up fashion to compute unary relation |
996 |
891 |
void TheorySetsRels::computeMembersForUnaryOpRel(Node rel) { |
997 |
891 |
Trace("rels-debug") << "\n[Theory::Rels] computeMembersForUnaryOpRel for relation " << rel << std::endl; |
998 |
|
|
999 |
891 |
switch(rel[0].getKind()) { |
1000 |
|
case kind::TRANSPOSE: |
1001 |
|
case kind::TCLOSURE: |
1002 |
|
computeMembersForUnaryOpRel(rel[0]); |
1003 |
|
break; |
1004 |
238 |
case kind::JOIN: |
1005 |
|
case kind::PRODUCT: |
1006 |
238 |
computeMembersForBinOpRel(rel[0]); |
1007 |
238 |
break; |
1008 |
653 |
default: |
1009 |
653 |
break; |
1010 |
|
} |
1011 |
|
|
1012 |
1672 |
Node rel0_rep = getRepresentative(rel[0]); |
1013 |
2673 |
if (d_rReps_memberReps_cache.find(rel0_rep) |
1014 |
2673 |
== d_rReps_memberReps_cache.end()) |
1015 |
|
{ |
1016 |
110 |
return; |
1017 |
|
} |
1018 |
781 |
NodeManager* nm = NodeManager::currentNM(); |
1019 |
|
|
1020 |
781 |
const std::vector<Node>& members = d_rReps_memberReps_cache[rel0_rep]; |
1021 |
781 |
const std::vector<Node>& exps = d_rReps_memberReps_exp_cache[rel0_rep]; |
1022 |
|
|
1023 |
781 |
Assert(members.size() == exps.size()); |
1024 |
|
|
1025 |
781 |
if (rel.getKind() == kind::TRANSPOSE) |
1026 |
|
{ |
1027 |
8457 |
for (size_t i = 0, msize = members.size(); i < msize; i++) |
1028 |
|
{ |
1029 |
15388 |
Node reason = exps[i]; |
1030 |
7694 |
if( rel[0] != exps[i][1] ) { |
1031 |
414 |
reason = nm->mkNode( |
1032 |
828 |
kind::AND, reason, nm->mkNode(kind::EQUAL, rel[0], exps[i][1])); |
1033 |
|
} |
1034 |
7694 |
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. For example, |
1043 |
|
* consider the case that (a, b) in r1, (c, d) in r2. |
1044 |
|
* |
1045 |
|
* For JOIN, we have three cases: |
1046 |
|
* if b = c, we infer (a, d) in (join r1 r2) |
1047 |
|
* else, we mark b and c as shared terms; their equality will be split in |
1048 |
|
* theory combination if necessary. |
1049 |
|
* |
1050 |
|
* For PRODUCT, we infer (a, b, c, d) in (product r1 r2). |
1051 |
|
*/ |
1052 |
2022 |
void TheorySetsRels::composeMembersForRels( Node rel ) { |
1053 |
2022 |
Trace("rels-debug") << "[Theory::Rels] Start composing members for relation = " << rel << std::endl; |
1054 |
3698 |
Node r1 = rel[0]; |
1055 |
3698 |
Node r2 = rel[1]; |
1056 |
3698 |
Node r1_rep = getRepresentative( r1 ); |
1057 |
3698 |
Node r2_rep = getRepresentative( r2 ); |
1058 |
|
|
1059 |
5839 |
if(d_rReps_memberReps_cache.find( r1_rep ) == d_rReps_memberReps_cache.end() || |
1060 |
3817 |
d_rReps_memberReps_cache.find( r2_rep ) == d_rReps_memberReps_cache.end() ) { |
1061 |
346 |
return; |
1062 |
|
} |
1063 |
1676 |
NodeManager* nm = NodeManager::currentNM(); |
1064 |
|
|
1065 |
3352 |
std::vector<Node> r1_rep_exps = d_rReps_memberReps_exp_cache[r1_rep]; |
1066 |
3352 |
std::vector<Node> r2_rep_exps = d_rReps_memberReps_exp_cache[r2_rep]; |
1067 |
1676 |
size_t r1_tuple_len = r1.getType().getSetElementType().getTupleLength(); |
1068 |
1676 |
size_t r2_tuple_len = r2.getType().getSetElementType().getTupleLength(); |
1069 |
|
|
1070 |
1676 |
Kind rk = rel.getKind(); |
1071 |
3352 |
TypeNode tn = rel.getType().getSetElementType(); |
1072 |
9586 |
for( unsigned int i = 0; i < r1_rep_exps.size(); i++ ) { |
1073 |
349239 |
for( unsigned int j = 0; j < r2_rep_exps.size(); j++ ) { |
1074 |
378087 |
std::vector<Node> tuple_elements; |
1075 |
341329 |
tuple_elements.push_back(tn.getDType()[0].getConstructor()); |
1076 |
378087 |
std::vector<Node> reasons; |
1077 |
341329 |
if (rk == kind::JOIN) |
1078 |
|
{ |
1079 |
|
Node r1_rmost = |
1080 |
376837 |
RelsUtils::nthElementOfTuple(r1_rep_exps[i][0], r1_tuple_len - 1); |
1081 |
376837 |
Node r2_lmost = RelsUtils::nthElementOfTuple(r2_rep_exps[j][0], 0); |
1082 |
|
// Since we require notification r1_rmost and r2_lmost are equal, |
1083 |
|
// they must be shared terms of theory of sets. Hence, we make the |
1084 |
|
// following calls to makeSharedTerm to ensure this is the case. |
1085 |
340704 |
makeSharedTerm(r1_rmost, r1_rmost.getType()); |
1086 |
340704 |
makeSharedTerm(r2_lmost, r2_lmost.getType()); |
1087 |
|
|
1088 |
681408 |
Trace("rels-debug") << "[Theory::Rels] r1_rmost: " << r1_rmost |
1089 |
340704 |
<< " of type " << r1_rmost.getType() << std::endl; |
1090 |
681408 |
Trace("rels-debug") << "[Theory::Rels] r2_lmost: " << r2_lmost |
1091 |
340704 |
<< " of type " << r2_lmost.getType() << std::endl; |
1092 |
340704 |
if (!areEqual(r1_rmost, r2_lmost)) |
1093 |
|
{ |
1094 |
|
|
1095 |
304571 |
continue; |
1096 |
|
} |
1097 |
36133 |
else if (r1_rmost != r2_lmost) |
1098 |
|
{ |
1099 |
10205 |
Trace("rels-debug") << "...equal" << std::endl; |
1100 |
10205 |
reasons.push_back(nm->mkNode(kind::EQUAL, r1_rmost, r2_lmost)); |
1101 |
|
} |
1102 |
|
} |
1103 |
|
|
1104 |
36758 |
if (rk == kind::PRODUCT || rk == kind::JOIN) |
1105 |
|
{ |
1106 |
36758 |
bool isProduct = rk == kind::PRODUCT; |
1107 |
36758 |
unsigned int k = 0; |
1108 |
36758 |
unsigned int l = 1; |
1109 |
|
|
1110 |
109950 |
for( ; k < r1_tuple_len - 1; ++k ) { |
1111 |
36596 |
tuple_elements.push_back( RelsUtils::nthElementOfTuple( r1_rep_exps[i][0], k ) ); |
1112 |
|
} |
1113 |
36758 |
if(isProduct) { |
1114 |
625 |
tuple_elements.push_back( RelsUtils::nthElementOfTuple( r1_rep_exps[i][0], k ) ); |
1115 |
625 |
tuple_elements.push_back( RelsUtils::nthElementOfTuple( r2_rep_exps[j][0], 0 ) ); |
1116 |
|
} |
1117 |
110102 |
for( ; l < r2_tuple_len; ++l ) { |
1118 |
36672 |
tuple_elements.push_back( RelsUtils::nthElementOfTuple( r2_rep_exps[j][0], l ) ); |
1119 |
|
} |
1120 |
|
|
1121 |
|
Node composed_tuple = |
1122 |
73516 |
nm->mkNode(kind::APPLY_CONSTRUCTOR, tuple_elements); |
1123 |
73516 |
Node fact = nm->mkNode(kind::MEMBER, composed_tuple, rel); |
1124 |
36758 |
reasons.push_back( r1_rep_exps[i] ); |
1125 |
36758 |
reasons.push_back( r2_rep_exps[j] ); |
1126 |
|
|
1127 |
36758 |
if( r1 != r1_rep_exps[i][1] ) { |
1128 |
211 |
reasons.push_back(nm->mkNode(kind::EQUAL, r1, r1_rep_exps[i][1])); |
1129 |
|
} |
1130 |
36758 |
if( r2 != r2_rep_exps[j][1] ) { |
1131 |
151 |
reasons.push_back(nm->mkNode(kind::EQUAL, r2, r2_rep_exps[j][1])); |
1132 |
|
} |
1133 |
36758 |
if( isProduct ) { |
1134 |
625 |
sendInfer( |
1135 |
1250 |
fact, InferenceId::SETS_RELS_PRODUCE_COMPOSE, nm->mkNode(kind::AND, reasons)); |
1136 |
|
} else { |
1137 |
36133 |
sendInfer( |
1138 |
72266 |
fact, InferenceId::SETS_RELS_JOIN_COMPOSE, nm->mkNode(kind::AND, reasons)); |
1139 |
|
} |
1140 |
|
} |
1141 |
|
} |
1142 |
|
} |
1143 |
|
|
1144 |
|
} |
1145 |
|
|
1146 |
|
void TheorySetsRels::processInference(Node conc, InferenceId id, Node exp) |
1147 |
|
{ |
1148 |
|
Trace("sets-pinfer") << "Process inference: " << exp << " => " << conc |
1149 |
|
<< std::endl; |
1150 |
|
if (!d_state.isEntailed(exp, true)) |
1151 |
|
{ |
1152 |
|
Trace("sets-pinfer") << " must assert as lemma" << std::endl; |
1153 |
|
// we wrap the spurious explanation into a splitting lemma |
1154 |
|
Node lem = NodeManager::currentNM()->mkNode(OR, exp.negate(), conc); |
1155 |
|
d_im.assertInference(lem, id, d_trueNode, 1); |
1156 |
|
return; |
1157 |
|
} |
1158 |
|
// try to assert it as a fact |
1159 |
|
d_im.assertInference(conc, id, exp); |
1160 |
|
} |
1161 |
|
|
1162 |
1300704 |
bool TheorySetsRels::isRelationKind( Kind k ) { |
1163 |
1300208 |
return k == TRANSPOSE || k == PRODUCT || k == JOIN || k == TCLOSURE |
1164 |
2599238 |
|| k == IDEN || k == JOIN_IMAGE; |
1165 |
|
} |
1166 |
|
|
1167 |
55339 |
Node TheorySetsRels::getRepresentative( Node t ) { |
1168 |
55339 |
return d_state.getRepresentative(t); |
1169 |
|
} |
1170 |
|
|
1171 |
1270802 |
bool TheorySetsRels::hasTerm(Node a) { return d_state.hasTerm(a); } |
1172 |
665239 |
bool TheorySetsRels::areEqual( Node a, Node b ){ |
1173 |
665239 |
Assert(a.getType() == b.getType()); |
1174 |
665239 |
Trace("rels-eq") << "[sets-rels]**** checking equality between " << a << " and " << b << std::endl; |
1175 |
665239 |
if(a == b) { |
1176 |
29838 |
return true; |
1177 |
635401 |
} else if( hasTerm( a ) && hasTerm( b ) ){ |
1178 |
635401 |
return d_state.areEqual(a, b); |
1179 |
|
} |
1180 |
|
TypeNode atn = a.getType(); |
1181 |
|
if (atn.isTuple()) |
1182 |
|
{ |
1183 |
|
size_t tlen = atn.getTupleLength(); |
1184 |
|
for (size_t i = 0; i < tlen; i++) |
1185 |
|
{ |
1186 |
|
if (!areEqual(RelsUtils::nthElementOfTuple(a, i), |
1187 |
|
RelsUtils::nthElementOfTuple(b, i))) |
1188 |
|
{ |
1189 |
|
return false; |
1190 |
|
} |
1191 |
|
} |
1192 |
|
return true; |
1193 |
|
} |
1194 |
|
else if (!atn.isBoolean()) |
1195 |
|
{ |
1196 |
|
// TODO(project##230): Find a safe type for the singleton operator |
1197 |
|
makeSharedTerm(a, atn); |
1198 |
|
makeSharedTerm(b, b.getType()); |
1199 |
|
} |
1200 |
|
return false; |
1201 |
|
} |
1202 |
|
|
1203 |
|
/* |
1204 |
|
* Make sure duplicate members are not added in map |
1205 |
|
*/ |
1206 |
13054 |
bool TheorySetsRels::safelyAddToMap(std::map< Node, std::vector<Node> >& map, Node rel_rep, Node member) { |
1207 |
13054 |
std::map< Node, std::vector< Node > >::iterator mem_it = map.find(rel_rep); |
1208 |
13054 |
if(mem_it == map.end()) { |
1209 |
5706 |
std::vector<Node> members; |
1210 |
2853 |
members.push_back(member); |
1211 |
2853 |
map[rel_rep] = members; |
1212 |
2853 |
return true; |
1213 |
|
} else { |
1214 |
10201 |
std::vector<Node>::iterator mems = mem_it->second.begin(); |
1215 |
650245 |
while(mems != mem_it->second.end()) { |
1216 |
323710 |
if(areEqual(*mems, member)) { |
1217 |
3688 |
return false; |
1218 |
|
} |
1219 |
320022 |
++mems; |
1220 |
|
} |
1221 |
6513 |
map[rel_rep].push_back(member); |
1222 |
6513 |
return true; |
1223 |
|
} |
1224 |
|
return false; |
1225 |
|
} |
1226 |
|
|
1227 |
693782 |
void TheorySetsRels::makeSharedTerm(Node n, TypeNode t) |
1228 |
|
{ |
1229 |
693782 |
if (d_shared_terms.find(n) != d_shared_terms.end()) |
1230 |
|
{ |
1231 |
692136 |
return; |
1232 |
|
} |
1233 |
1646 |
Trace("rels-share") << " [sets-rels] making shared term " << n << std::endl; |
1234 |
|
// force a proxy lemma to be sent for the singleton containing n |
1235 |
3292 |
Node ss = NodeManager::currentNM()->mkSingleton(t, n); |
1236 |
1646 |
d_treg.getProxy(ss); |
1237 |
1646 |
d_shared_terms.insert(n); |
1238 |
|
} |
1239 |
|
|
1240 |
|
/* |
1241 |
|
* For each tuple n, we store a mapping between n and a list of its elements representatives |
1242 |
|
* in d_tuple_reps. This would later be used for applying JOIN operator. |
1243 |
|
*/ |
1244 |
12591 |
void TheorySetsRels::computeTupleReps( Node n ) { |
1245 |
12591 |
if( d_tuple_reps.find( n ) == d_tuple_reps.end() ){ |
1246 |
23446 |
for( unsigned i = 0; i < n.getType().getTupleLength(); i++ ){ |
1247 |
15706 |
d_tuple_reps[n].push_back( getRepresentative( RelsUtils::nthElementOfTuple(n, i) ) ); |
1248 |
|
} |
1249 |
|
} |
1250 |
12591 |
} |
1251 |
|
|
1252 |
|
/* |
1253 |
|
* Node n[0] is a tuple variable, reduce n[0] to a concrete representation, |
1254 |
|
* which is (e1, ..., en) where e1, ... ,en are concrete elements of tuple n[0]. |
1255 |
|
*/ |
1256 |
1880 |
void TheorySetsRels::reduceTupleVar(Node n) { |
1257 |
1880 |
if(d_symbolic_tuples.find(n) == d_symbolic_tuples.end()) { |
1258 |
583 |
Trace("rels-debug") << "[Theory::Rels] Reduce tuple var: " << n[0] << " to a concrete one " << " node = " << n << std::endl; |
1259 |
1166 |
std::vector<Node> tuple_elements; |
1260 |
583 |
tuple_elements.push_back((n[0].getType().getDType())[0].getConstructor()); |
1261 |
1166 |
std::vector<TypeNode> tupleTypes = n[0].getType().getTupleTypes(); |
1262 |
1769 |
for (unsigned int i = 0; i < n[0].getType().getTupleLength(); i++) |
1263 |
|
{ |
1264 |
2372 |
Node element = RelsUtils::nthElementOfTuple(n[0], i); |
1265 |
1186 |
makeSharedTerm(element, tupleTypes[i]); |
1266 |
1186 |
tuple_elements.push_back(element); |
1267 |
|
} |
1268 |
1166 |
Node tuple_reduct = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, tuple_elements); |
1269 |
583 |
tuple_reduct = NodeManager::currentNM()->mkNode(kind::MEMBER,tuple_reduct, n[1]); |
1270 |
1166 |
Node tuple_reduction_lemma = NodeManager::currentNM()->mkNode(kind::EQUAL, n, tuple_reduct); |
1271 |
583 |
sendInfer(tuple_reduction_lemma, InferenceId::SETS_RELS_TUPLE_REDUCTION, d_trueNode); |
1272 |
583 |
d_symbolic_tuples.insert(n); |
1273 |
|
} |
1274 |
1880 |
} |
1275 |
|
|
1276 |
2974 |
std::vector<Node> TupleTrie::findTerms( std::vector< Node >& reps, int argIndex ) { |
1277 |
5948 |
std::vector<Node> nodes; |
1278 |
2974 |
std::map< Node, TupleTrie >::iterator it; |
1279 |
|
|
1280 |
2974 |
if( argIndex==(int)reps.size()-1 ){ |
1281 |
1455 |
if(reps[argIndex].getKind() == kind::SKOLEM) { |
1282 |
1306 |
it = d_data.begin(); |
1283 |
15948 |
while(it != d_data.end()) { |
1284 |
7321 |
nodes.push_back(it->first); |
1285 |
7321 |
++it; |
1286 |
|
} |
1287 |
|
} |
1288 |
1455 |
return nodes; |
1289 |
|
}else{ |
1290 |
1519 |
it = d_data.find( reps[argIndex] ); |
1291 |
1519 |
if( it==d_data.end() ){ |
1292 |
88 |
return nodes; |
1293 |
|
}else{ |
1294 |
1431 |
return it->second.findTerms( reps, argIndex+1 ); |
1295 |
|
} |
1296 |
|
} |
1297 |
|
} |
1298 |
|
|
1299 |
243 |
std::vector<Node> TupleTrie::findSuccessors( std::vector< Node >& reps, int argIndex ) { |
1300 |
486 |
std::vector<Node> nodes; |
1301 |
243 |
std::map< Node, TupleTrie >::iterator it; |
1302 |
|
|
1303 |
243 |
if( argIndex==(int)reps.size() ){ |
1304 |
104 |
it = d_data.begin(); |
1305 |
476 |
while(it != d_data.end()) { |
1306 |
186 |
nodes.push_back(it->first); |
1307 |
186 |
++it; |
1308 |
|
} |
1309 |
104 |
return nodes; |
1310 |
|
}else{ |
1311 |
139 |
it = d_data.find( reps[argIndex] ); |
1312 |
139 |
if( it==d_data.end() ){ |
1313 |
35 |
return nodes; |
1314 |
|
}else{ |
1315 |
104 |
return it->second.findSuccessors( reps, argIndex+1 ); |
1316 |
|
} |
1317 |
|
} |
1318 |
|
} |
1319 |
|
|
1320 |
4191 |
Node TupleTrie::existsTerm( std::vector< Node >& reps, int argIndex ) { |
1321 |
4191 |
if( argIndex==(int)reps.size() ){ |
1322 |
1256 |
if( d_data.empty() ){ |
1323 |
|
return Node::null(); |
1324 |
|
}else{ |
1325 |
1256 |
return d_data.begin()->first; |
1326 |
|
} |
1327 |
|
}else{ |
1328 |
2935 |
std::map< Node, TupleTrie >::iterator it = d_data.find( reps[argIndex] ); |
1329 |
2935 |
if( it==d_data.end() ){ |
1330 |
225 |
return Node::null(); |
1331 |
|
}else{ |
1332 |
2710 |
return it->second.existsTerm( reps, argIndex+1 ); |
1333 |
|
} |
1334 |
|
} |
1335 |
|
} |
1336 |
|
|
1337 |
28219 |
bool TupleTrie::addTerm( Node n, std::vector< Node >& reps, int argIndex ){ |
1338 |
28219 |
if( argIndex==(int)reps.size() ){ |
1339 |
9366 |
if( d_data.empty() ){ |
1340 |
|
//store n in d_data (this should be interpretted as the "data" and not as a reference to a child) |
1341 |
9366 |
d_data[n].clear(); |
1342 |
9366 |
return true; |
1343 |
|
}else{ |
1344 |
|
return false; |
1345 |
|
} |
1346 |
|
}else{ |
1347 |
18853 |
return d_data[reps[argIndex]].addTerm( n, reps, argIndex+1 ); |
1348 |
|
} |
1349 |
|
} |
1350 |
|
|
1351 |
|
void TupleTrie::debugPrint( const char * c, Node n, unsigned depth ) { |
1352 |
|
for( std::map< Node, TupleTrie >::iterator it = d_data.begin(); it != d_data.end(); ++it ){ |
1353 |
|
for( unsigned i=0; i<depth; i++ ){ Debug(c) << " "; } |
1354 |
|
Debug(c) << it->first << std::endl; |
1355 |
|
it->second.debugPrint( c, n, depth+1 ); |
1356 |
|
} |
1357 |
|
} |
1358 |
|
|
1359 |
47993 |
void TheorySetsRels::sendInfer(Node fact, InferenceId id, Node reason) |
1360 |
|
{ |
1361 |
95986 |
Trace("rels-lemma") << "Rels::lemma " << fact << " from " << reason |
1362 |
47993 |
<< " by " << id << std::endl; |
1363 |
95986 |
Node lemma = NodeManager::currentNM()->mkNode(IMPLIES, reason, fact); |
1364 |
47993 |
d_im.addPendingLemma(lemma, id); |
1365 |
47993 |
} |
1366 |
|
} |
1367 |
|
} |
1368 |
31137 |
} // namespace cvc5 |