1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Tim King, Morgan Deters |
4 |
|
* |
5 |
|
* This file is part of the cvc5 project. |
6 |
|
* |
7 |
|
* Copyright (c) 2009-2021 by the authors listed in the file AUTHORS |
8 |
|
* in the top-level source directory and their institutional affiliations. |
9 |
|
* All rights reserved. See the file COPYING in the top-level source |
10 |
|
* directory for licensing information. |
11 |
|
* **************************************************************************** |
12 |
|
* |
13 |
|
* Implementation of representative set. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include <unordered_set> |
17 |
|
|
18 |
|
#include "theory/rep_set.h" |
19 |
|
#include "theory/type_enumerator.h" |
20 |
|
|
21 |
|
using namespace std; |
22 |
|
using namespace cvc5::kind; |
23 |
|
|
24 |
|
namespace cvc5 { |
25 |
|
namespace theory { |
26 |
|
|
27 |
19608 |
void RepSet::clear(){ |
28 |
19608 |
d_type_reps.clear(); |
29 |
19608 |
d_type_complete.clear(); |
30 |
19608 |
d_tmap.clear(); |
31 |
19608 |
d_values_to_terms.clear(); |
32 |
19608 |
} |
33 |
|
|
34 |
|
bool RepSet::hasRep(TypeNode tn, Node n) const |
35 |
|
{ |
36 |
|
std::map<TypeNode, std::vector<Node> >::const_iterator it = |
37 |
|
d_type_reps.find(tn); |
38 |
|
if( it==d_type_reps.end() ){ |
39 |
|
return false; |
40 |
|
}else{ |
41 |
|
return std::find( it->second.begin(), it->second.end(), n )!=it->second.end(); |
42 |
|
} |
43 |
|
} |
44 |
|
|
45 |
193804 |
size_t RepSet::getNumRepresentatives(TypeNode tn) const |
46 |
|
{ |
47 |
193804 |
const std::vector<Node>* reps = getTypeRepsOrNull(tn); |
48 |
193804 |
return (reps != nullptr) ? reps->size() : 0; |
49 |
|
} |
50 |
|
|
51 |
4266 |
Node RepSet::getRepresentative(TypeNode tn, unsigned i) const |
52 |
|
{ |
53 |
|
std::map<TypeNode, std::vector<Node> >::const_iterator it = |
54 |
4266 |
d_type_reps.find(tn); |
55 |
4266 |
Assert(it != d_type_reps.end()); |
56 |
4266 |
Assert(i < it->second.size()); |
57 |
4266 |
return it->second[i]; |
58 |
|
} |
59 |
|
|
60 |
197720 |
const std::vector<Node>* RepSet::getTypeRepsOrNull(TypeNode tn) const |
61 |
|
{ |
62 |
197720 |
auto it = d_type_reps.find(tn); |
63 |
197720 |
if (it == d_type_reps.end()) |
64 |
|
{ |
65 |
4 |
return nullptr; |
66 |
|
} |
67 |
197716 |
return &(it->second); |
68 |
|
} |
69 |
|
|
70 |
|
namespace { |
71 |
|
|
72 |
2042 |
bool containsStoreAll(Node n, std::unordered_set<Node>& cache) |
73 |
|
{ |
74 |
2042 |
if( std::find( cache.begin(), cache.end(), n )==cache.end() ){ |
75 |
2042 |
cache.insert(n); |
76 |
2042 |
if( n.getKind()==STORE_ALL ){ |
77 |
905 |
return true; |
78 |
|
}else{ |
79 |
1137 |
for( unsigned i=0; i<n.getNumChildren(); i++ ){ |
80 |
1133 |
if( containsStoreAll( n[i], cache ) ){ |
81 |
1133 |
return true; |
82 |
|
} |
83 |
|
} |
84 |
|
} |
85 |
|
} |
86 |
4 |
return false; |
87 |
|
} |
88 |
|
|
89 |
|
} // namespace |
90 |
|
|
91 |
593348 |
void RepSet::add( TypeNode tn, Node n ){ |
92 |
|
//for now, do not add array constants FIXME |
93 |
593348 |
if( tn.isArray() ){ |
94 |
913 |
std::unordered_set<Node> cache; |
95 |
909 |
if( containsStoreAll( n, cache ) ){ |
96 |
905 |
return; |
97 |
|
} |
98 |
|
} |
99 |
592443 |
Trace("rsi-debug") << "Add rep #" << d_type_reps[tn].size() << " for " << tn << " : " << n << std::endl; |
100 |
592443 |
Assert(n.getType().isSubtypeOf(tn)); |
101 |
592443 |
d_tmap[ n ] = (int)d_type_reps[tn].size(); |
102 |
592443 |
d_type_reps[tn].push_back( n ); |
103 |
|
} |
104 |
|
|
105 |
|
int RepSet::getIndexFor( Node n ) const { |
106 |
|
std::map< Node, int >::const_iterator it = d_tmap.find( n ); |
107 |
|
if( it!=d_tmap.end() ){ |
108 |
|
return it->second; |
109 |
|
}else{ |
110 |
|
return -1; |
111 |
|
} |
112 |
|
} |
113 |
|
|
114 |
2126 |
bool RepSet::complete( TypeNode t ){ |
115 |
2126 |
std::map< TypeNode, bool >::iterator it = d_type_complete.find( t ); |
116 |
2126 |
if( it==d_type_complete.end() ){ |
117 |
|
//remove all previous |
118 |
766 |
for( unsigned i=0; i<d_type_reps[t].size(); i++ ){ |
119 |
579 |
d_tmap.erase( d_type_reps[t][i] ); |
120 |
|
} |
121 |
187 |
d_type_reps[t].clear(); |
122 |
|
//now complete the type |
123 |
187 |
d_type_complete[t] = true; |
124 |
374 |
TypeEnumerator te(t); |
125 |
1375 |
while( !te.isFinished() ){ |
126 |
1188 |
Node n = *te; |
127 |
594 |
if( std::find( d_type_reps[t].begin(), d_type_reps[t].end(), n )==d_type_reps[t].end() ){ |
128 |
594 |
add( t, n ); |
129 |
|
} |
130 |
594 |
++te; |
131 |
|
} |
132 |
781 |
for( size_t i=0; i<d_type_reps[t].size(); i++ ){ |
133 |
594 |
Trace("reps-complete") << d_type_reps[t][i] << " "; |
134 |
|
} |
135 |
187 |
Trace("reps-complete") << std::endl; |
136 |
187 |
return true; |
137 |
|
}else{ |
138 |
1939 |
return it->second; |
139 |
|
} |
140 |
|
} |
141 |
|
|
142 |
44710 |
Node RepSet::getTermForRepresentative(Node n) const |
143 |
|
{ |
144 |
44710 |
std::map<Node, Node>::const_iterator it = d_values_to_terms.find(n); |
145 |
44710 |
if (it != d_values_to_terms.end()) |
146 |
|
{ |
147 |
43499 |
return it->second; |
148 |
|
} |
149 |
|
else |
150 |
|
{ |
151 |
1211 |
return Node::null(); |
152 |
|
} |
153 |
|
} |
154 |
|
|
155 |
591481 |
void RepSet::setTermForRepresentative(Node n, Node t) |
156 |
|
{ |
157 |
591481 |
d_values_to_terms[n] = t; |
158 |
591481 |
} |
159 |
|
|
160 |
|
Node RepSet::getDomainValue(TypeNode tn, const std::vector<Node>& exclude) const |
161 |
|
{ |
162 |
|
std::map<TypeNode, std::vector<Node> >::const_iterator it = |
163 |
|
d_type_reps.find(tn); |
164 |
|
if (it != d_type_reps.end()) |
165 |
|
{ |
166 |
|
// try to find a pre-existing arbitrary element |
167 |
|
for (size_t i = 0; i < it->second.size(); i++) |
168 |
|
{ |
169 |
|
if (std::find(exclude.begin(), exclude.end(), it->second[i]) |
170 |
|
== exclude.end()) |
171 |
|
{ |
172 |
|
return it->second[i]; |
173 |
|
} |
174 |
|
} |
175 |
|
} |
176 |
|
return Node::null(); |
177 |
|
} |
178 |
|
|
179 |
|
void RepSet::toStream(std::ostream& out){ |
180 |
|
for( std::map< TypeNode, std::vector< Node > >::iterator it = d_type_reps.begin(); it != d_type_reps.end(); ++it ){ |
181 |
|
if( !it->first.isFunction() && !it->first.isPredicate() ){ |
182 |
|
out << "(" << it->first << " " << it->second.size(); |
183 |
|
out << " ("; |
184 |
|
for( unsigned i=0; i<it->second.size(); i++ ){ |
185 |
|
if( i>0 ){ out << " "; } |
186 |
|
out << it->second[i]; |
187 |
|
} |
188 |
|
out << ")"; |
189 |
|
out << ")" << std::endl; |
190 |
|
} |
191 |
|
} |
192 |
|
} |
193 |
|
|
194 |
4246 |
RepSetIterator::RepSetIterator(const RepSet* rs, RepBoundExt* rext) |
195 |
4246 |
: d_rs(rs), d_rext(rext), d_incomplete(false) |
196 |
|
{ |
197 |
4246 |
} |
198 |
|
|
199 |
77776 |
unsigned RepSetIterator::domainSize(unsigned i) |
200 |
|
{ |
201 |
77776 |
unsigned v = d_var_order[i]; |
202 |
77776 |
return d_domain_elements[v].size(); |
203 |
|
} |
204 |
|
|
205 |
74437 |
TypeNode RepSetIterator::getTypeOf(unsigned i) const { return d_types[i]; } |
206 |
|
|
207 |
4246 |
bool RepSetIterator::setQuantifier(Node q) |
208 |
|
{ |
209 |
4246 |
Trace("rsi") << "Make rsi for quantified formula " << q << std::endl; |
210 |
4246 |
Assert(d_types.empty()); |
211 |
|
//store indicies |
212 |
10256 |
for (size_t i = 0; i < q[0].getNumChildren(); i++) |
213 |
|
{ |
214 |
6010 |
d_types.push_back(q[0][i].getType()); |
215 |
|
} |
216 |
4246 |
d_owner = q; |
217 |
4246 |
return initialize(); |
218 |
|
} |
219 |
|
|
220 |
|
bool RepSetIterator::setFunctionDomain(Node op) |
221 |
|
{ |
222 |
|
Trace("rsi") << "Make rsi for function " << op << std::endl; |
223 |
|
Assert(d_types.empty()); |
224 |
|
TypeNode tn = op.getType(); |
225 |
|
for( size_t i=0; i<tn.getNumChildren()-1; i++ ){ |
226 |
|
d_types.push_back( tn[i] ); |
227 |
|
} |
228 |
|
d_owner = op; |
229 |
|
return initialize(); |
230 |
|
} |
231 |
|
|
232 |
4246 |
bool RepSetIterator::initialize() |
233 |
|
{ |
234 |
4246 |
Trace("rsi") << "Initialize rep set iterator..." << std::endl; |
235 |
10256 |
for( unsigned v=0; v<d_types.size(); v++ ){ |
236 |
6010 |
d_index.push_back( 0 ); |
237 |
|
//store default index order |
238 |
6010 |
d_index_order.push_back( v ); |
239 |
6010 |
d_var_order[v] = v; |
240 |
|
//store default domain |
241 |
|
//d_domain.push_back( RepDomain() ); |
242 |
6010 |
d_domain_elements.push_back( std::vector< Node >() ); |
243 |
12020 |
TypeNode tn = d_types[v]; |
244 |
6010 |
Trace("rsi") << "Var #" << v << " is type " << tn << "..." << std::endl; |
245 |
6010 |
bool inc = true; |
246 |
6010 |
bool setEnum = false; |
247 |
|
//check if it is externally bound |
248 |
6010 |
if (d_rext) |
249 |
|
{ |
250 |
6010 |
inc = !d_rext->initializeRepresentativesForType(tn); |
251 |
6010 |
RsiEnumType rsiet = d_rext->setBound(d_owner, v, d_domain_elements[v]); |
252 |
6010 |
if (rsiet != ENUM_INVALID) |
253 |
|
{ |
254 |
2098 |
d_enum_type.push_back(rsiet); |
255 |
2098 |
inc = false; |
256 |
2098 |
setEnum = true; |
257 |
|
} |
258 |
|
} |
259 |
6010 |
if (inc) |
260 |
|
{ |
261 |
|
Trace("fmf-incomplete") << "Incomplete because of quantification of type " |
262 |
|
<< tn << std::endl; |
263 |
|
d_incomplete = true; |
264 |
|
} |
265 |
|
|
266 |
|
//if we have yet to determine the type of enumeration |
267 |
6010 |
if (!setEnum) |
268 |
|
{ |
269 |
3912 |
if (d_rs->hasType(tn)) |
270 |
|
{ |
271 |
3912 |
d_enum_type.push_back( ENUM_DEFAULT ); |
272 |
3912 |
if (const auto* type_reps = d_rs->getTypeRepsOrNull(tn)) |
273 |
|
{ |
274 |
3912 |
std::vector<Node>& v_domain_elements = d_domain_elements[v]; |
275 |
11736 |
v_domain_elements.insert(v_domain_elements.end(), |
276 |
11736 |
type_reps->begin(), type_reps->end()); |
277 |
|
} |
278 |
|
}else{ |
279 |
|
Assert(d_incomplete); |
280 |
|
return false; |
281 |
|
} |
282 |
|
} |
283 |
|
} |
284 |
|
|
285 |
4246 |
if (d_rext) |
286 |
|
{ |
287 |
8492 |
std::vector<unsigned> varOrder; |
288 |
4246 |
if (d_rext->getVariableOrder(d_owner, varOrder)) |
289 |
|
{ |
290 |
4246 |
if (Trace.isOn("bound-int-rsi")) |
291 |
|
{ |
292 |
|
Trace("bound-int-rsi") << "Variable order : "; |
293 |
|
for (unsigned i = 0; i < varOrder.size(); i++) |
294 |
|
{ |
295 |
|
Trace("bound-int-rsi") << varOrder[i] << " "; |
296 |
|
} |
297 |
|
Trace("bound-int-rsi") << std::endl; |
298 |
|
} |
299 |
8492 |
std::vector<unsigned> indexOrder; |
300 |
4246 |
indexOrder.resize(varOrder.size()); |
301 |
10256 |
for (unsigned i = 0; i < varOrder.size(); i++) |
302 |
|
{ |
303 |
6010 |
Assert(varOrder[i] < indexOrder.size()); |
304 |
6010 |
indexOrder[varOrder[i]] = i; |
305 |
|
} |
306 |
4246 |
if (Trace.isOn("bound-int-rsi")) |
307 |
|
{ |
308 |
|
Trace("bound-int-rsi") << "Will use index order : "; |
309 |
|
for (unsigned i = 0; i < indexOrder.size(); i++) |
310 |
|
{ |
311 |
|
Trace("bound-int-rsi") << indexOrder[i] << " "; |
312 |
|
} |
313 |
|
Trace("bound-int-rsi") << std::endl; |
314 |
|
} |
315 |
4246 |
setIndexOrder(indexOrder); |
316 |
|
} |
317 |
|
} |
318 |
|
//now reset the indices |
319 |
4246 |
do_reset_increment( -1, true ); |
320 |
4246 |
return true; |
321 |
|
} |
322 |
|
|
323 |
4246 |
void RepSetIterator::setIndexOrder(std::vector<unsigned>& indexOrder) |
324 |
|
{ |
325 |
4246 |
d_index_order.clear(); |
326 |
4246 |
d_index_order.insert( d_index_order.begin(), indexOrder.begin(), indexOrder.end() ); |
327 |
|
//make the d_var_order mapping |
328 |
10256 |
for( unsigned i=0; i<d_index_order.size(); i++ ){ |
329 |
6010 |
d_var_order[d_index_order[i]] = i; |
330 |
|
} |
331 |
4246 |
} |
332 |
|
|
333 |
13187 |
int RepSetIterator::resetIndex(unsigned i, bool initial) |
334 |
|
{ |
335 |
13187 |
d_index[i] = 0; |
336 |
13187 |
unsigned v = d_var_order[i]; |
337 |
13187 |
Trace("bound-int-rsi") << "Reset " << i << ", var order = " << v << ", initial = " << initial << std::endl; |
338 |
13187 |
if (d_rext) |
339 |
|
{ |
340 |
13187 |
if (!d_rext->resetIndex(this, d_owner, v, initial, d_domain_elements[v])) |
341 |
|
{ |
342 |
68 |
return -1; |
343 |
|
} |
344 |
|
} |
345 |
13119 |
return d_domain_elements[v].empty() ? 0 : 1; |
346 |
|
} |
347 |
|
|
348 |
31479 |
int RepSetIterator::incrementAtIndex(int i) |
349 |
|
{ |
350 |
31479 |
Assert(!isFinished()); |
351 |
|
#ifdef DISABLE_EVAL_SKIP_MULTIPLE |
352 |
|
i = (int)d_index.size()-1; |
353 |
|
#endif |
354 |
31479 |
Trace("rsi-debug") << "RepSetIterator::incrementAtIndex: " << i << std::endl; |
355 |
|
//increment d_index |
356 |
31479 |
if( i>=0){ |
357 |
31041 |
Trace("rsi-debug") << "domain size of " << i << " is " << domainSize(i) << std::endl; |
358 |
|
} |
359 |
54377 |
while( i>=0 && d_index[i]>=(int)(domainSize(i)-1) ){ |
360 |
11449 |
i--; |
361 |
11449 |
if( i>=0){ |
362 |
7847 |
Trace("rsi-debug") << "domain size of " << i << " is " << domainSize(i) << std::endl; |
363 |
|
} |
364 |
|
} |
365 |
31479 |
if( i==-1 ){ |
366 |
4040 |
Trace("rsi-debug") << "increment failed" << std::endl; |
367 |
4040 |
d_index.clear(); |
368 |
4040 |
return -1; |
369 |
|
}else{ |
370 |
27439 |
Trace("rsi-debug") << "increment " << i << std::endl; |
371 |
27439 |
d_index[i]++; |
372 |
27439 |
return do_reset_increment( i ); |
373 |
|
} |
374 |
|
} |
375 |
|
|
376 |
31685 |
int RepSetIterator::do_reset_increment( int i, bool initial ) { |
377 |
63370 |
Trace("rsi-debug") << "RepSetIterator::do_reset_increment: " << i |
378 |
31685 |
<< ", initial=" << initial << std::endl; |
379 |
44624 |
for( unsigned ii=(i+1); ii<d_index.size(); ii++ ){ |
380 |
13187 |
bool emptyDomain = false; |
381 |
13187 |
int ri_res = resetIndex( ii, initial ); |
382 |
13187 |
if( ri_res==-1 ){ |
383 |
|
//failed |
384 |
68 |
d_index.clear(); |
385 |
68 |
d_incomplete = true; |
386 |
68 |
break; |
387 |
13119 |
}else if( ri_res==0 ){ |
388 |
180 |
emptyDomain = true; |
389 |
|
} |
390 |
|
//force next iteration if currently an empty domain |
391 |
13119 |
if (emptyDomain) |
392 |
|
{ |
393 |
360 |
Trace("rsi-debug") << "This is an empty domain (index " << ii << ")." |
394 |
180 |
<< std::endl; |
395 |
180 |
if (ii > 0) |
396 |
|
{ |
397 |
|
// increment at the previous index |
398 |
222 |
return incrementAtIndex(ii - 1); |
399 |
|
} |
400 |
|
else |
401 |
|
{ |
402 |
|
// this is the first index, we are done |
403 |
138 |
d_index.clear(); |
404 |
138 |
return -1; |
405 |
|
} |
406 |
|
} |
407 |
|
} |
408 |
63010 |
Trace("rsi-debug") << "Finished, return " << i << std::endl; |
409 |
31505 |
return i; |
410 |
|
} |
411 |
|
|
412 |
30037 |
int RepSetIterator::increment(){ |
413 |
30037 |
if( !isFinished() ){ |
414 |
30037 |
return incrementAtIndex(d_index.size() - 1); |
415 |
|
}else{ |
416 |
|
return -1; |
417 |
|
} |
418 |
|
} |
419 |
|
|
420 |
125210 |
bool RepSetIterator::isFinished() const { return d_index.empty(); } |
421 |
|
|
422 |
77174 |
Node RepSetIterator::getCurrentTerm(unsigned i, bool valTerm) const |
423 |
|
{ |
424 |
77174 |
unsigned ii = d_index_order[i]; |
425 |
77174 |
unsigned curr = d_index[ii]; |
426 |
154348 |
Trace("rsi-debug") << "rsi : get term " << i |
427 |
77174 |
<< ", index order = " << d_index_order[i] << std::endl; |
428 |
154348 |
Trace("rsi-debug") << "rsi : curr = " << curr << " / " |
429 |
77174 |
<< d_domain_elements[i].size() << std::endl; |
430 |
77174 |
Assert(0 <= curr && curr < d_domain_elements[i].size()); |
431 |
154348 |
Node t = d_domain_elements[i][curr]; |
432 |
77174 |
if (valTerm) |
433 |
|
{ |
434 |
39633 |
Node tt = d_rs->getTermForRepresentative(t); |
435 |
38422 |
if (!tt.isNull()) |
436 |
|
{ |
437 |
37211 |
return tt; |
438 |
|
} |
439 |
|
} |
440 |
39963 |
return t; |
441 |
|
} |
442 |
|
|
443 |
|
void RepSetIterator::getCurrentTerms(std::vector<Node>& terms) const |
444 |
|
{ |
445 |
|
for (unsigned i = 0, size = d_index_order.size(); i < size; i++) |
446 |
|
{ |
447 |
|
terms.push_back(getCurrentTerm(i)); |
448 |
|
} |
449 |
|
} |
450 |
|
|
451 |
|
void RepSetIterator::debugPrint( const char* c ){ |
452 |
|
for( unsigned v=0; v<d_index.size(); v++ ){ |
453 |
|
Debug( c ) << v << " : " << getCurrentTerm( v ) << std::endl; |
454 |
|
} |
455 |
|
} |
456 |
|
|
457 |
|
void RepSetIterator::debugPrintSmall( const char* c ){ |
458 |
|
Debug( c ) << "RI: "; |
459 |
|
for( unsigned v=0; v<d_index.size(); v++ ){ |
460 |
|
Debug( c ) << v << ": " << getCurrentTerm( v ) << " "; |
461 |
|
} |
462 |
|
Debug( c ) << std::endl; |
463 |
|
} |
464 |
|
|
465 |
|
} // namespace theory |
466 |
28191 |
} // namespace cvc5 |