1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Morgan Deters, Tim King |
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 theory of UF with cardinality. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "theory/uf/cardinality_extension.h" |
17 |
|
|
18 |
|
#include <sstream> |
19 |
|
|
20 |
|
#include "expr/skolem_manager.h" |
21 |
|
#include "options/smt_options.h" |
22 |
|
#include "options/uf_options.h" |
23 |
|
#include "smt/logic_exception.h" |
24 |
|
#include "theory/decision_manager.h" |
25 |
|
#include "theory/quantifiers/term_database.h" |
26 |
|
#include "theory/quantifiers_engine.h" |
27 |
|
#include "theory/theory_engine.h" |
28 |
|
#include "theory/theory_model.h" |
29 |
|
#include "theory/uf/equality_engine.h" |
30 |
|
#include "theory/uf/theory_uf.h" |
31 |
|
|
32 |
|
using namespace std; |
33 |
|
using namespace cvc5::kind; |
34 |
|
using namespace cvc5::context; |
35 |
|
|
36 |
|
namespace cvc5 { |
37 |
|
namespace theory { |
38 |
|
namespace uf { |
39 |
|
|
40 |
|
/* These are names are unambigious are we use abbreviations. */ |
41 |
|
typedef CardinalityExtension::SortModel SortModel; |
42 |
|
typedef SortModel::Region Region; |
43 |
|
typedef Region::RegionNodeInfo RegionNodeInfo; |
44 |
|
typedef RegionNodeInfo::DiseqList DiseqList; |
45 |
|
|
46 |
2442 |
Region::Region(SortModel* cf, context::Context* c) |
47 |
|
: d_cf( cf ) |
48 |
|
, d_testCliqueSize( c, 0 ) |
49 |
|
, d_splitsSize( c, 0 ) |
50 |
|
, d_testClique( c ) |
51 |
|
, d_splits( c ) |
52 |
|
, d_reps_size( c, 0 ) |
53 |
|
, d_total_diseq_external( c, 0 ) |
54 |
|
, d_total_diseq_internal( c, 0 ) |
55 |
2442 |
, d_valid( c, true ) {} |
56 |
|
|
57 |
7326 |
Region::~Region() { |
58 |
11668 |
for(iterator i = begin(), iend = end(); i != iend; ++i) { |
59 |
9226 |
RegionNodeInfo* regionNodeInfo = (*i).second; |
60 |
9226 |
delete regionNodeInfo; |
61 |
|
} |
62 |
2442 |
d_nodes.clear(); |
63 |
4884 |
} |
64 |
|
|
65 |
4820 |
void Region::addRep( Node n ) { |
66 |
4820 |
setRep( n, true ); |
67 |
4820 |
} |
68 |
|
|
69 |
405 |
void Region::takeNode( Region* r, Node n ){ |
70 |
405 |
Assert(!hasRep(n)); |
71 |
405 |
Assert(r->hasRep(n)); |
72 |
|
//add representative |
73 |
405 |
setRep( n, true ); |
74 |
|
//take disequalities from r |
75 |
405 |
RegionNodeInfo* rni = r->d_nodes[n]; |
76 |
1215 |
for( int t=0; t<2; t++ ){ |
77 |
810 |
DiseqList* del = rni->get(t); |
78 |
2372 |
for(DiseqList::iterator it = del->begin(); it != del->end(); ++it ){ |
79 |
1562 |
if( (*it).second ){ |
80 |
1024 |
r->setDisequal( n, (*it).first, t, false ); |
81 |
1024 |
if( t==0 ){ |
82 |
534 |
if( hasRep( (*it).first ) ){ |
83 |
478 |
setDisequal( (*it).first, n, 0, false ); |
84 |
478 |
setDisequal( (*it).first, n, 1, true ); |
85 |
478 |
setDisequal( n, (*it).first, 1, true ); |
86 |
|
}else{ |
87 |
56 |
setDisequal( n, (*it).first, 0, true ); |
88 |
|
} |
89 |
|
}else{ |
90 |
490 |
r->setDisequal( (*it).first, n, 1, false ); |
91 |
490 |
r->setDisequal( (*it).first, n, 0, true ); |
92 |
490 |
setDisequal( n, (*it).first, 0, true ); |
93 |
|
} |
94 |
|
} |
95 |
|
} |
96 |
|
} |
97 |
|
//remove representative |
98 |
405 |
r->setRep( n, false ); |
99 |
405 |
} |
100 |
|
|
101 |
42679 |
void Region::combine( Region* r ){ |
102 |
|
//take all nodes from r |
103 |
231179 |
for(Region::iterator it = r->d_nodes.begin(); it != r->d_nodes.end(); ++it) { |
104 |
188500 |
if( it->second->valid() ){ |
105 |
45593 |
setRep( it->first, true ); |
106 |
|
} |
107 |
|
} |
108 |
231179 |
for(Region::iterator it = r->d_nodes.begin(); it != r->d_nodes.end(); ++it){ |
109 |
188500 |
if( it->second->valid() ){ |
110 |
|
//take disequalities from r |
111 |
91186 |
Node n = it->first; |
112 |
45593 |
RegionNodeInfo* rni = it->second; |
113 |
136779 |
for( int t=0; t<2; t++ ){ |
114 |
91186 |
RegionNodeInfo::DiseqList* del = rni->get(t); |
115 |
231312 |
for( RegionNodeInfo::DiseqList::iterator it2 = del->begin(), |
116 |
91186 |
it2end = del->end(); it2 != it2end; ++it2 ){ |
117 |
140126 |
if( (*it2).second ){ |
118 |
129008 |
if( t==0 && hasRep( (*it2).first ) ){ |
119 |
55161 |
setDisequal( (*it2).first, n, 0, false ); |
120 |
55161 |
setDisequal( (*it2).first, n, 1, true ); |
121 |
55161 |
setDisequal( n, (*it2).first, 1, true ); |
122 |
|
}else{ |
123 |
73847 |
setDisequal( n, (*it2).first, t, true ); |
124 |
|
} |
125 |
|
} |
126 |
|
} |
127 |
|
} |
128 |
|
} |
129 |
|
} |
130 |
42679 |
r->d_valid = false; |
131 |
42679 |
} |
132 |
|
|
133 |
|
/** setEqual */ |
134 |
33897 |
void Region::setEqual( Node a, Node b ){ |
135 |
33897 |
Assert(hasRep(a) && hasRep(b)); |
136 |
|
//move disequalities of b over to a |
137 |
101691 |
for( int t=0; t<2; t++ ){ |
138 |
67794 |
DiseqList* del = d_nodes[b]->get(t); |
139 |
122497 |
for( DiseqList::iterator it = del->begin(); it != del->end(); ++it ){ |
140 |
54703 |
if( (*it).second ){ |
141 |
80930 |
Node n = (*it).first; |
142 |
|
//get the region that contains the endpoint of the disequality b != ... |
143 |
40465 |
Region* nr = d_cf->d_regions[ d_cf->d_regions_map[ n ] ]; |
144 |
40465 |
if( !isDisequal( a, n, t ) ){ |
145 |
18177 |
setDisequal( a, n, t, true ); |
146 |
18177 |
nr->setDisequal( n, a, t, true ); |
147 |
|
} |
148 |
40465 |
setDisequal( b, n, t, false ); |
149 |
40465 |
nr->setDisequal( n, b, t, false ); |
150 |
|
} |
151 |
|
} |
152 |
|
} |
153 |
|
//remove b from representatives |
154 |
33897 |
setRep( b, false ); |
155 |
33897 |
} |
156 |
|
|
157 |
387122 |
void Region::setDisequal( Node n1, Node n2, int type, bool valid ){ |
158 |
|
//Debug("uf-ss-region-debug") << "set disequal " << n1 << " " << n2 << " " |
159 |
|
// << type << " " << valid << std::endl; |
160 |
|
//debugPrint("uf-ss-region-debug"); |
161 |
|
//Assert( isDisequal( n1, n2, type )!=valid ); |
162 |
387122 |
if( isDisequal( n1, n2, type )!=valid ){ //DO_THIS: make assertion |
163 |
386316 |
d_nodes[ n1 ]->get(type)->setDisequal( n2, valid ); |
164 |
386316 |
if( type==0 ){ |
165 |
170528 |
d_total_diseq_external = d_total_diseq_external + ( valid ? 1 : -1 ); |
166 |
|
}else{ |
167 |
215788 |
d_total_diseq_internal = d_total_diseq_internal + ( valid ? 1 : -1 ); |
168 |
215788 |
if( valid ){ |
169 |
|
//if they are both a part of testClique, then remove split |
170 |
305698 |
if( d_testClique.find( n1 )!=d_testClique.end() && d_testClique[n1] && |
171 |
154368 |
d_testClique.find( n2 )!=d_testClique.end() && d_testClique[n2] ){ |
172 |
3038 |
Node eq = NodeManager::currentNM()->mkNode( EQUAL, n1, n2 ); |
173 |
1519 |
if( d_splits.find( eq )!=d_splits.end() && d_splits[ eq ] ){ |
174 |
1490 |
Debug("uf-ss-debug") << "removing split for " << n1 << " " << n2 |
175 |
745 |
<< std::endl; |
176 |
745 |
d_splits[ eq ] = false; |
177 |
745 |
d_splitsSize = d_splitsSize - 1; |
178 |
|
} |
179 |
|
} |
180 |
|
} |
181 |
|
} |
182 |
|
} |
183 |
387122 |
} |
184 |
|
|
185 |
85120 |
void Region::setRep( Node n, bool valid ) { |
186 |
85120 |
Assert(hasRep(n) != valid); |
187 |
85120 |
if( valid && d_nodes.find( n )==d_nodes.end() ){ |
188 |
9226 |
d_nodes[n] = new RegionNodeInfo(d_cf->d_state.getSatContext()); |
189 |
|
} |
190 |
85120 |
d_nodes[n]->setValid(valid); |
191 |
85120 |
d_reps_size = d_reps_size + ( valid ? 1 : -1 ); |
192 |
|
//removing a member of the test clique from this region |
193 |
85120 |
if( d_testClique.find( n ) != d_testClique.end() && d_testClique[n] ){ |
194 |
1605 |
Assert(!valid); |
195 |
1605 |
d_testClique[n] = false; |
196 |
1605 |
d_testCliqueSize = d_testCliqueSize - 1; |
197 |
|
//remove all splits involving n |
198 |
14286 |
for( split_iterator it = begin_splits(); it != end_splits(); ++it ){ |
199 |
12681 |
if( (*it).second ){ |
200 |
4009 |
if( (*it).first[0]==n || (*it).first[1]==n ){ |
201 |
3969 |
d_splits[ (*it).first ] = false; |
202 |
3969 |
d_splitsSize = d_splitsSize - 1; |
203 |
|
} |
204 |
|
} |
205 |
|
} |
206 |
|
} |
207 |
85120 |
} |
208 |
|
|
209 |
473363 |
bool Region::isDisequal( Node n1, Node n2, int type ) { |
210 |
473363 |
RegionNodeInfo::DiseqList* del = d_nodes[ n1 ]->get(type); |
211 |
473363 |
return del->isSet(n2) && del->getDisequalityValue(n2); |
212 |
|
} |
213 |
|
|
214 |
|
struct sortInternalDegree { |
215 |
|
Region* r; |
216 |
15202 |
bool operator() (Node i, Node j) { |
217 |
30404 |
return (r->getRegionInfo(i)->getNumInternalDisequalities() > |
218 |
30404 |
r->getRegionInfo(j)->getNumInternalDisequalities()); |
219 |
|
} |
220 |
|
}; |
221 |
|
|
222 |
|
struct sortExternalDegree { |
223 |
|
Region* r; |
224 |
|
bool operator() (Node i,Node j) { |
225 |
|
return (r->getRegionInfo(i)->getNumExternalDisequalities() > |
226 |
|
r->getRegionInfo(j)->getNumExternalDisequalities()); |
227 |
|
} |
228 |
|
}; |
229 |
|
|
230 |
|
int gmcCount = 0; |
231 |
|
|
232 |
98424 |
bool Region::getMustCombine( int cardinality ){ |
233 |
98424 |
if (d_total_diseq_external >= static_cast<unsigned>(cardinality)) |
234 |
|
{ |
235 |
|
//The number of external disequalities is greater than or equal to |
236 |
|
//cardinality. Thus, a clique of size cardinality+1 may exist |
237 |
|
//between nodes in d_regions[i] and other regions Check if this is |
238 |
|
//actually the case: must have n nodes with outgoing degree |
239 |
|
//(cardinality+1-n) for some n>0 |
240 |
21549 |
std::vector< int > degrees; |
241 |
141647 |
for( Region::iterator it = begin(); it != end(); ++it ){ |
242 |
134456 |
RegionNodeInfo* rni = it->second; |
243 |
134456 |
if( rni->valid() ){ |
244 |
61043 |
if( rni->getNumDisequalities() >= cardinality ){ |
245 |
47621 |
int outDeg = rni->getNumExternalDisequalities(); |
246 |
47621 |
if( outDeg>=cardinality ){ |
247 |
|
//we have 1 node of degree greater than (cardinality) |
248 |
16115 |
return true; |
249 |
39957 |
}else if( outDeg>=1 ){ |
250 |
38851 |
degrees.push_back( outDeg ); |
251 |
38851 |
if( (int)degrees.size()>=cardinality ){ |
252 |
|
//we have (cardinality) nodes of degree 1 |
253 |
787 |
return true; |
254 |
|
} |
255 |
|
} |
256 |
|
} |
257 |
|
} |
258 |
|
} |
259 |
7191 |
gmcCount++; |
260 |
7191 |
if( gmcCount%100==0 ){ |
261 |
122 |
Trace("gmc-count") << gmcCount << " " << cardinality |
262 |
61 |
<< " sample : " << degrees.size() << std::endl; |
263 |
|
} |
264 |
|
//this should happen relatively infrequently.... |
265 |
7191 |
std::sort( degrees.begin(), degrees.end() ); |
266 |
38271 |
for( int i=0; i<(int)degrees.size(); i++ ){ |
267 |
32364 |
if( degrees[i]>=cardinality+1-((int)degrees.size()-i) ){ |
268 |
1284 |
return true; |
269 |
|
} |
270 |
|
} |
271 |
|
} |
272 |
88689 |
return false; |
273 |
|
} |
274 |
|
|
275 |
934412 |
bool Region::check( Theory::Effort level, int cardinality, |
276 |
|
std::vector< Node >& clique ) { |
277 |
934412 |
if( d_reps_size>unsigned(cardinality) ){ |
278 |
78921 |
if( d_total_diseq_internal==d_reps_size*( d_reps_size - 1 ) ){ |
279 |
56342 |
if( d_reps_size>1 ){ |
280 |
|
//quick clique check, all reps form a clique |
281 |
24398 |
for( iterator it = begin(); it != end(); ++it ){ |
282 |
21604 |
if( it->second->valid() ){ |
283 |
17140 |
clique.push_back( it->first ); |
284 |
|
} |
285 |
|
} |
286 |
2794 |
Trace("quick-clique") << "Found quick clique" << std::endl; |
287 |
2794 |
return true; |
288 |
|
}else{ |
289 |
53548 |
return false; |
290 |
|
} |
291 |
|
} |
292 |
22579 |
else if (level==Theory::EFFORT_FULL) |
293 |
|
{ |
294 |
|
//build test clique, up to size cardinality+1 |
295 |
1943 |
if( d_testCliqueSize<=unsigned(cardinality) ){ |
296 |
3774 |
std::vector< Node > newClique; |
297 |
1887 |
if( d_testCliqueSize<unsigned(cardinality) ){ |
298 |
14142 |
for( iterator it = begin(); it != end(); ++it ){ |
299 |
|
//if not in the test clique, add it to the set of new members |
300 |
41568 |
if( it->second->valid() && |
301 |
20787 |
( d_testClique.find( it->first ) == d_testClique.end() || |
302 |
2 |
!d_testClique[ it->first ] ) ){ |
303 |
|
//if( it->second->getNumInternalDisequalities()>cardinality || |
304 |
|
// level==Theory::EFFORT_FULL ){ |
305 |
8172 |
newClique.push_back( it->first ); |
306 |
|
//} |
307 |
|
} |
308 |
|
} |
309 |
|
//choose remaining nodes with the highest degrees |
310 |
|
sortInternalDegree sidObj; |
311 |
1531 |
sidObj.r = this; |
312 |
1531 |
std::sort( newClique.begin(), newClique.end(), sidObj ); |
313 |
1531 |
int offset = ( cardinality - d_testCliqueSize ) + 1; |
314 |
1531 |
newClique.erase( newClique.begin() + offset, newClique.end() ); |
315 |
|
}else{ |
316 |
|
//scan for the highest degree |
317 |
356 |
int maxDeg = -1; |
318 |
712 |
Node maxNode; |
319 |
3754 |
for( std::map< Node, RegionNodeInfo* >::iterator |
320 |
356 |
it = d_nodes.begin(); it != d_nodes.end(); ++it ){ |
321 |
|
//if not in the test clique, add it to the set of new members |
322 |
9863 |
if( it->second->valid() && |
323 |
7345 |
( d_testClique.find( it->first )==d_testClique.end() || |
324 |
1609 |
!d_testClique[ it->first ] ) ){ |
325 |
373 |
if( it->second->getNumInternalDisequalities()>maxDeg ){ |
326 |
358 |
maxDeg = it->second->getNumInternalDisequalities(); |
327 |
358 |
maxNode = it->first; |
328 |
|
} |
329 |
|
} |
330 |
|
} |
331 |
356 |
Assert(maxNode != Node::null()); |
332 |
356 |
newClique.push_back( maxNode ); |
333 |
|
} |
334 |
|
//check splits internal to new members |
335 |
10314 |
for( int j=0; j<(int)newClique.size(); j++ ){ |
336 |
16854 |
Debug("uf-ss-debug") << "Choose to add clique member " |
337 |
8427 |
<< newClique[j] << std::endl; |
338 |
39328 |
for( int k=(j+1); k<(int)newClique.size(); k++ ){ |
339 |
30901 |
if( !isDisequal( newClique[j], newClique[k], 1 ) ){ |
340 |
7632 |
Node at_j = newClique[j]; |
341 |
7632 |
Node at_k = newClique[k]; |
342 |
|
Node j_eq_k = |
343 |
7632 |
NodeManager::currentNM()->mkNode( EQUAL, at_j, at_k ); |
344 |
3816 |
d_splits[ j_eq_k ] = true; |
345 |
3816 |
d_splitsSize = d_splitsSize + 1; |
346 |
|
} |
347 |
|
} |
348 |
|
//check disequalities with old members |
349 |
11420 |
for( NodeBoolMap::iterator it = d_testClique.begin(); |
350 |
11420 |
it != d_testClique.end(); ++it ){ |
351 |
2993 |
if( (*it).second ){ |
352 |
1613 |
if( !isDisequal( (*it).first, newClique[j], 1 ) ){ |
353 |
2138 |
Node at_it = (*it).first; |
354 |
2138 |
Node at_j = newClique[j]; |
355 |
2138 |
Node it_eq_j = at_it.eqNode(at_j); |
356 |
1069 |
d_splits[ it_eq_j ] = true; |
357 |
1069 |
d_splitsSize = d_splitsSize + 1; |
358 |
|
} |
359 |
|
} |
360 |
|
} |
361 |
|
} |
362 |
|
//add new clique members to test clique |
363 |
10314 |
for( int j=0; j<(int)newClique.size(); j++ ){ |
364 |
8427 |
d_testClique[ newClique[j] ] = true; |
365 |
8427 |
d_testCliqueSize = d_testCliqueSize + 1; |
366 |
|
} |
367 |
|
} |
368 |
|
// Check if test clique has larger size than cardinality, and |
369 |
|
// forms a clique. |
370 |
1943 |
if( d_testCliqueSize >= unsigned(cardinality+1) && d_splitsSize==0 ){ |
371 |
|
//test clique is a clique |
372 |
120 |
for( NodeBoolMap::iterator it = d_testClique.begin(); |
373 |
120 |
it != d_testClique.end(); ++it ){ |
374 |
88 |
if( (*it).second ){ |
375 |
86 |
clique.push_back( (*it).first ); |
376 |
|
} |
377 |
|
} |
378 |
32 |
return true; |
379 |
|
} |
380 |
|
} |
381 |
|
} |
382 |
878038 |
return false; |
383 |
|
} |
384 |
|
|
385 |
|
void Region::getNumExternalDisequalities( |
386 |
|
std::map< Node, int >& num_ext_disequalities ){ |
387 |
|
for( Region::iterator it = begin(); it != end(); ++it ){ |
388 |
|
RegionNodeInfo* rni = it->second; |
389 |
|
if( rni->valid() ){ |
390 |
|
DiseqList* del = rni->get(0); |
391 |
|
for( DiseqList::iterator it2 = del->begin(); it2 != del->end(); ++it2 ){ |
392 |
|
if( (*it2).second ){ |
393 |
|
num_ext_disequalities[ (*it2).first ]++; |
394 |
|
} |
395 |
|
} |
396 |
|
} |
397 |
|
} |
398 |
|
} |
399 |
|
|
400 |
2378 |
void Region::debugPrint( const char* c, bool incClique ) { |
401 |
2378 |
Debug( c ) << "Num reps: " << d_reps_size << std::endl; |
402 |
6913 |
for( Region::iterator it = begin(); it != end(); ++it ){ |
403 |
4535 |
RegionNodeInfo* rni = it->second; |
404 |
4535 |
if( rni->valid() ){ |
405 |
|
Node n = it->first; |
406 |
|
Debug( c ) << " " << n << std::endl; |
407 |
|
for( int i=0; i<2; i++ ){ |
408 |
|
Debug( c ) << " " << ( i==0 ? "Ext" : "Int" ) << " disequal:"; |
409 |
|
DiseqList* del = rni->get(i); |
410 |
|
for( DiseqList::iterator it2 = del->begin(); it2 != del->end(); ++it2 ){ |
411 |
|
if( (*it2).second ){ |
412 |
|
Debug( c ) << " " << (*it2).first; |
413 |
|
} |
414 |
|
} |
415 |
|
Debug( c ) << ", total = " << del->size() << std::endl; |
416 |
|
} |
417 |
|
} |
418 |
|
} |
419 |
2378 |
Debug( c ) << "Total disequal: " << d_total_diseq_external << " external,"; |
420 |
2378 |
Debug( c ) << " " << d_total_diseq_internal << " internal." << std::endl; |
421 |
|
|
422 |
2378 |
if( incClique ){ |
423 |
2378 |
if( !d_testClique.empty() ){ |
424 |
|
Debug( c ) << "Candidate clique members: " << std::endl; |
425 |
|
Debug( c ) << " "; |
426 |
|
for( NodeBoolMap::iterator it = d_testClique.begin(); |
427 |
|
it != d_testClique.end(); ++ it ){ |
428 |
|
if( (*it).second ){ |
429 |
|
Debug( c ) << (*it).first << " "; |
430 |
|
} |
431 |
|
} |
432 |
|
Debug( c ) << ", size = " << d_testCliqueSize << std::endl; |
433 |
|
} |
434 |
2378 |
if( !d_splits.empty() ){ |
435 |
|
Debug( c ) << "Required splits: " << std::endl; |
436 |
|
Debug( c ) << " "; |
437 |
|
for( NodeBoolMap::iterator it = d_splits.begin(); it != d_splits.end(); |
438 |
|
++ it ){ |
439 |
|
if( (*it).second ){ |
440 |
|
Debug( c ) << (*it).first << " "; |
441 |
|
} |
442 |
|
} |
443 |
|
Debug( c ) << ", size = " << d_splitsSize << std::endl; |
444 |
|
} |
445 |
|
} |
446 |
2378 |
} |
447 |
|
|
448 |
463 |
SortModel::CardinalityDecisionStrategy::CardinalityDecisionStrategy( |
449 |
463 |
Node t, context::Context* satContext, Valuation valuation) |
450 |
463 |
: DecisionStrategyFmf(satContext, valuation), d_cardinality_term(t) |
451 |
|
{ |
452 |
463 |
} |
453 |
1116 |
Node SortModel::CardinalityDecisionStrategy::mkLiteral(unsigned i) |
454 |
|
{ |
455 |
1116 |
NodeManager* nm = NodeManager::currentNM(); |
456 |
|
return nm->mkNode( |
457 |
1116 |
CARDINALITY_CONSTRAINT, d_cardinality_term, nm->mkConst(Rational(i + 1))); |
458 |
|
} |
459 |
532405 |
std::string SortModel::CardinalityDecisionStrategy::identify() const |
460 |
|
{ |
461 |
532405 |
return std::string("uf_card"); |
462 |
|
} |
463 |
|
|
464 |
463 |
SortModel::SortModel(Node n, |
465 |
|
TheoryState& state, |
466 |
|
TheoryInferenceManager& im, |
467 |
463 |
CardinalityExtension* thss) |
468 |
|
: d_type(n.getType()), |
469 |
|
d_state(state), |
470 |
|
d_im(im), |
471 |
|
d_thss(thss), |
472 |
463 |
d_regions_index(d_state.getSatContext(), 0), |
473 |
463 |
d_regions_map(d_state.getSatContext()), |
474 |
463 |
d_split_score(d_state.getSatContext()), |
475 |
463 |
d_disequalities_index(d_state.getSatContext(), 0), |
476 |
463 |
d_reps(d_state.getSatContext(), 0), |
477 |
463 |
d_cardinality(d_state.getSatContext(), 1), |
478 |
463 |
d_hasCard(d_state.getSatContext(), false), |
479 |
463 |
d_maxNegCard(d_state.getSatContext(), 0), |
480 |
463 |
d_initialized(d_state.getUserContext(), false), |
481 |
4630 |
d_c_dec_strat(nullptr) |
482 |
|
{ |
483 |
463 |
d_cardinality_term = n; |
484 |
|
|
485 |
1277202 |
if (options::ufssMode() == options::UfssMode::FULL) |
486 |
|
{ |
487 |
|
// Register the strategy with the decision manager of the theory. |
488 |
|
// We are guaranteed that the decision manager is ready since we |
489 |
|
// construct this module during TheoryUF::finishInit. |
490 |
1389 |
d_c_dec_strat.reset(new CardinalityDecisionStrategy( |
491 |
926 |
n, d_state.getSatContext(), thss->getTheory()->getValuation())); |
492 |
|
} |
493 |
463 |
} |
494 |
|
|
495 |
1389 |
SortModel::~SortModel() { |
496 |
2905 |
for(std::vector<Region*>::iterator i = d_regions.begin(); |
497 |
2905 |
i != d_regions.end(); ++i) { |
498 |
2442 |
Region* region = *i; |
499 |
2442 |
delete region; |
500 |
|
} |
501 |
463 |
d_regions.clear(); |
502 |
926 |
} |
503 |
|
|
504 |
|
/** initialize */ |
505 |
5064 |
void SortModel::initialize() |
506 |
|
{ |
507 |
5064 |
if (d_c_dec_strat.get() != nullptr && !d_initialized) |
508 |
|
{ |
509 |
807 |
d_initialized = true; |
510 |
|
// Strategy is user-context-dependent, since it is in sync with |
511 |
|
// user-context-dependent flag d_initialized. |
512 |
1614 |
d_im.getDecisionManager()->registerStrategy(DecisionManager::STRAT_UF_CARD, |
513 |
807 |
d_c_dec_strat.get()); |
514 |
|
} |
515 |
5064 |
} |
516 |
|
|
517 |
|
/** new node */ |
518 |
4820 |
void SortModel::newEqClass( Node n ){ |
519 |
4820 |
if (!d_state.isInConflict()) |
520 |
|
{ |
521 |
4820 |
if( d_regions_map.find( n )==d_regions_map.end() ){ |
522 |
4820 |
d_regions_map[n] = d_regions_index; |
523 |
4820 |
Debug("uf-ss") << "CardinalityExtension: New Eq Class " << n << std::endl; |
524 |
9640 |
Debug("uf-ss-debug") << d_regions_index << " " << (int)d_regions.size() |
525 |
4820 |
<< std::endl; |
526 |
4820 |
if (d_regions_index < d_regions.size()) |
527 |
|
{ |
528 |
2378 |
d_regions[d_regions_index]->debugPrint("uf-ss-debug", true); |
529 |
2378 |
d_regions[d_regions_index]->setValid(true); |
530 |
2378 |
Assert(d_regions[d_regions_index]->getNumReps() == 0); |
531 |
|
}else{ |
532 |
2442 |
d_regions.push_back(new Region(this, d_state.getSatContext())); |
533 |
|
} |
534 |
4820 |
d_regions[d_regions_index]->addRep(n); |
535 |
4820 |
d_regions_index = d_regions_index + 1; |
536 |
|
|
537 |
4820 |
d_reps = d_reps + 1; |
538 |
|
} |
539 |
|
} |
540 |
4820 |
} |
541 |
|
|
542 |
|
/** merge */ |
543 |
33897 |
void SortModel::merge( Node a, Node b ){ |
544 |
33897 |
if (d_state.isInConflict()) |
545 |
|
{ |
546 |
|
return; |
547 |
|
} |
548 |
67794 |
Debug("uf-ss") << "CardinalityExtension: Merging " << a << " = " << b << "..." |
549 |
33897 |
<< std::endl; |
550 |
33897 |
if (a != b) |
551 |
|
{ |
552 |
33897 |
Assert(d_regions_map.find(a) != d_regions_map.end()); |
553 |
33897 |
Assert(d_regions_map.find(b) != d_regions_map.end()); |
554 |
33897 |
int ai = d_regions_map[a]; |
555 |
33897 |
int bi = d_regions_map[b]; |
556 |
33897 |
Debug("uf-ss") << " regions: " << ai << " " << bi << std::endl; |
557 |
33897 |
if (ai != bi) |
558 |
|
{ |
559 |
30359 |
if (d_regions[ai]->getNumReps() == 1) |
560 |
|
{ |
561 |
20614 |
int ri = combineRegions(bi, ai); |
562 |
20614 |
d_regions[ri]->setEqual(a, b); |
563 |
20614 |
checkRegion(ri); |
564 |
|
} |
565 |
9745 |
else if (d_regions[bi]->getNumReps() == 1) |
566 |
|
{ |
567 |
9340 |
int ri = combineRegions(ai, bi); |
568 |
9340 |
d_regions[ri]->setEqual(a, b); |
569 |
9340 |
checkRegion(ri); |
570 |
|
} |
571 |
|
else |
572 |
|
{ |
573 |
|
// Either move a to d_regions[bi], or b to d_regions[ai]. |
574 |
405 |
RegionNodeInfo* a_region_info = d_regions[ai]->getRegionInfo(a); |
575 |
405 |
RegionNodeInfo* b_region_info = d_regions[bi]->getRegionInfo(b); |
576 |
405 |
int aex = (a_region_info->getNumInternalDisequalities() |
577 |
405 |
- getNumDisequalitiesToRegion(a, bi)); |
578 |
405 |
int bex = (b_region_info->getNumInternalDisequalities() |
579 |
405 |
- getNumDisequalitiesToRegion(b, ai)); |
580 |
|
// Based on which would produce the fewest number of |
581 |
|
// external disequalities. |
582 |
405 |
if (aex < bex) |
583 |
|
{ |
584 |
158 |
moveNode(a, bi); |
585 |
158 |
d_regions[bi]->setEqual(a, b); |
586 |
|
}else{ |
587 |
247 |
moveNode(b, ai); |
588 |
247 |
d_regions[ai]->setEqual( a, b ); |
589 |
|
} |
590 |
405 |
checkRegion(ai); |
591 |
405 |
checkRegion(bi); |
592 |
|
} |
593 |
|
} |
594 |
|
else |
595 |
|
{ |
596 |
3538 |
d_regions[ai]->setEqual(a, b); |
597 |
3538 |
checkRegion(ai); |
598 |
|
} |
599 |
33897 |
d_regions_map[b] = -1; |
600 |
|
} |
601 |
33897 |
d_reps = d_reps - 1; |
602 |
|
} |
603 |
|
|
604 |
|
/** assert terms are disequal */ |
605 |
13262 |
void SortModel::assertDisequal( Node a, Node b, Node reason ){ |
606 |
13262 |
if (d_state.isInConflict()) |
607 |
|
{ |
608 |
|
return; |
609 |
|
} |
610 |
|
// if they are not already disequal |
611 |
13262 |
eq::EqualityEngine* ee = d_thss->getTheory()->getEqualityEngine(); |
612 |
13262 |
a = ee->getRepresentative(a); |
613 |
13262 |
b = ee->getRepresentative(b); |
614 |
13262 |
int ai = d_regions_map[a]; |
615 |
13262 |
int bi = d_regions_map[b]; |
616 |
13262 |
if (d_regions[ai]->isDisequal(a, b, ai == bi)) |
617 |
|
{ |
618 |
|
// already disequal |
619 |
|
return; |
620 |
|
} |
621 |
26524 |
Debug("uf-ss") << "Assert disequal " << a << " != " << b << "..." |
622 |
13262 |
<< std::endl; |
623 |
26524 |
Debug("uf-ss-disequal") << "Assert disequal " << a << " != " << b << "..." |
624 |
13262 |
<< std::endl; |
625 |
|
// add to list of disequalities |
626 |
13262 |
if (d_disequalities_index < d_disequalities.size()) |
627 |
|
{ |
628 |
10133 |
d_disequalities[d_disequalities_index] = reason; |
629 |
|
} |
630 |
|
else |
631 |
|
{ |
632 |
3129 |
d_disequalities.push_back(reason); |
633 |
|
} |
634 |
13262 |
d_disequalities_index = d_disequalities_index + 1; |
635 |
|
// now, add disequalities to regions |
636 |
13262 |
Assert(d_regions_map.find(a) != d_regions_map.end()); |
637 |
13262 |
Assert(d_regions_map.find(b) != d_regions_map.end()); |
638 |
13262 |
Debug("uf-ss") << " regions: " << ai << " " << bi << std::endl; |
639 |
13262 |
if (ai == bi) |
640 |
|
{ |
641 |
|
// internal disequality |
642 |
443 |
d_regions[ai]->setDisequal(a, b, 1, true); |
643 |
443 |
d_regions[ai]->setDisequal(b, a, 1, true); |
644 |
|
// do not need to check if it needs to combine (no new ext. disequalities) |
645 |
443 |
checkRegion(ai, false); |
646 |
|
} |
647 |
|
else |
648 |
|
{ |
649 |
|
// external disequality |
650 |
12819 |
d_regions[ai]->setDisequal(a, b, 0, true); |
651 |
12819 |
d_regions[bi]->setDisequal(b, a, 0, true); |
652 |
12819 |
checkRegion(ai); |
653 |
12819 |
checkRegion(bi); |
654 |
|
} |
655 |
|
} |
656 |
|
|
657 |
|
bool SortModel::areDisequal( Node a, Node b ) { |
658 |
|
Assert(a == d_thss->getTheory()->getEqualityEngine()->getRepresentative(a)); |
659 |
|
Assert(b == d_thss->getTheory()->getEqualityEngine()->getRepresentative(b)); |
660 |
|
if( d_regions_map.find( a )!=d_regions_map.end() && |
661 |
|
d_regions_map.find( b )!=d_regions_map.end() ){ |
662 |
|
int ai = d_regions_map[a]; |
663 |
|
int bi = d_regions_map[b]; |
664 |
|
return d_regions[ai]->isDisequal(a, b, ai==bi ? 1 : 0); |
665 |
|
}else{ |
666 |
|
return false; |
667 |
|
} |
668 |
|
} |
669 |
|
|
670 |
284745 |
void SortModel::check(Theory::Effort level) |
671 |
|
{ |
672 |
284745 |
Assert(options::ufssMode() == options::UfssMode::FULL); |
673 |
284745 |
if (!d_hasCard && d_state.isInConflict()) |
674 |
|
{ |
675 |
|
// not necessary to check |
676 |
|
return; |
677 |
|
} |
678 |
569490 |
Debug("uf-ss") << "CardinalityExtension: Check " << level << " " << d_type |
679 |
284745 |
<< std::endl; |
680 |
284745 |
if (level == Theory::EFFORT_FULL) |
681 |
|
{ |
682 |
9688 |
Debug("fmf-full-check") << std::endl; |
683 |
19376 |
Debug("fmf-full-check") |
684 |
9688 |
<< "Full check for SortModel " << d_type << ", status : " << std::endl; |
685 |
9688 |
debugPrint("fmf-full-check"); |
686 |
9688 |
Debug("fmf-full-check") << std::endl; |
687 |
|
} |
688 |
284745 |
if (d_reps <= (unsigned)d_cardinality) |
689 |
|
{ |
690 |
215462 |
Debug("uf-ss-debug") << "We have " << d_reps << " representatives for type " |
691 |
107731 |
<< d_type << ", <= " << d_cardinality << std::endl; |
692 |
107731 |
if( level==Theory::EFFORT_FULL ){ |
693 |
9510 |
Debug("uf-ss-sat") << "We have " << d_reps << " representatives for type " |
694 |
4755 |
<< d_type << ", <= " << d_cardinality << std::endl; |
695 |
|
} |
696 |
107731 |
return; |
697 |
|
} |
698 |
|
// first check if we can generate a clique conflict |
699 |
|
// do a check within each region |
700 |
1627814 |
for (size_t i = 0; i < d_regions_index; i++) |
701 |
|
{ |
702 |
1451571 |
if (d_regions[i]->valid()) |
703 |
|
{ |
704 |
1670319 |
std::vector<Node> clique; |
705 |
835545 |
if (d_regions[i]->check(level, d_cardinality, clique)) |
706 |
|
{ |
707 |
|
// add clique lemma |
708 |
771 |
addCliqueLemma(clique); |
709 |
771 |
return; |
710 |
|
} |
711 |
|
else |
712 |
|
{ |
713 |
834774 |
Trace("uf-ss-debug") << "No clique in Region #" << i << std::endl; |
714 |
|
} |
715 |
|
} |
716 |
|
} |
717 |
|
// do splitting on demand |
718 |
176243 |
bool addedLemma = false; |
719 |
176243 |
if (level == Theory::EFFORT_FULL) |
720 |
|
{ |
721 |
4901 |
Trace("uf-ss-debug") << "Add splits?" << std::endl; |
722 |
|
// see if we have any recommended splits from large regions |
723 |
64199 |
for (size_t i = 0; i < d_regions_index; i++) |
724 |
|
{ |
725 |
59298 |
if (d_regions[i]->valid() && d_regions[i]->getNumReps() > d_cardinality) |
726 |
|
{ |
727 |
1911 |
int sp = addSplit(d_regions[i]); |
728 |
1911 |
if (sp == 1) |
729 |
|
{ |
730 |
1911 |
addedLemma = true; |
731 |
|
} |
732 |
|
else if (sp == -1) |
733 |
|
{ |
734 |
|
check(level); |
735 |
|
return; |
736 |
|
} |
737 |
|
} |
738 |
|
} |
739 |
|
} |
740 |
|
// If no added lemmas, force continuation via combination of regions. |
741 |
176243 |
if (level != Theory::EFFORT_FULL || addedLemma) |
742 |
|
{ |
743 |
173253 |
return; |
744 |
|
} |
745 |
|
// check at full effort |
746 |
2990 |
Trace("uf-ss-debug") << "No splits added. " << d_cardinality << std::endl; |
747 |
2990 |
Trace("uf-ss-si") << "Must combine region" << std::endl; |
748 |
2990 |
bool recheck = false; |
749 |
2990 |
SortInference* si = d_state.getSortInference(); |
750 |
2990 |
if (si != nullptr) |
751 |
|
{ |
752 |
|
// If sort inference is enabled, search for regions with same sort. |
753 |
96 |
std::map<int, int> sortsFound; |
754 |
448 |
for (size_t i = 0; i < d_regions_index; i++) |
755 |
|
{ |
756 |
448 |
if (d_regions[i]->valid()) |
757 |
|
{ |
758 |
144 |
Node op = d_regions[i]->frontKey(); |
759 |
96 |
int sort_id = si->getSortId(op); |
760 |
96 |
if (sortsFound.find(sort_id) != sortsFound.end()) |
761 |
|
{ |
762 |
96 |
Debug("fmf-full-check") << "Combined regions " << i << " " |
763 |
48 |
<< sortsFound[sort_id] << std::endl; |
764 |
48 |
combineRegions(sortsFound[sort_id], i); |
765 |
48 |
recheck = true; |
766 |
48 |
break; |
767 |
|
} |
768 |
|
else |
769 |
|
{ |
770 |
48 |
sortsFound[sort_id] = i; |
771 |
|
} |
772 |
|
} |
773 |
|
} |
774 |
|
} |
775 |
2990 |
if (!recheck) |
776 |
|
{ |
777 |
|
// naive strategy, force region combination involving the first |
778 |
|
// valid region |
779 |
9018 |
for (size_t i = 0; i < d_regions_index; i++) |
780 |
|
{ |
781 |
9018 |
if (d_regions[i]->valid()) |
782 |
|
{ |
783 |
2942 |
int fcr = forceCombineRegion(i, false); |
784 |
5884 |
Debug("fmf-full-check") |
785 |
2942 |
<< "Combined regions " << i << " " << fcr << std::endl; |
786 |
5884 |
Trace("uf-ss-debug") |
787 |
2942 |
<< "Combined regions " << i << " " << fcr << std::endl; |
788 |
2942 |
recheck = true; |
789 |
2942 |
break; |
790 |
|
} |
791 |
|
} |
792 |
|
} |
793 |
2990 |
if (recheck) |
794 |
|
{ |
795 |
2990 |
Trace("uf-ss-debug") << "Must recheck." << std::endl; |
796 |
2990 |
check(level); |
797 |
|
} |
798 |
|
} |
799 |
|
|
800 |
344 |
void SortModel::presolve() { |
801 |
344 |
d_initialized = false; |
802 |
344 |
} |
803 |
|
|
804 |
810 |
int SortModel::getNumDisequalitiesToRegion( Node n, int ri ){ |
805 |
810 |
int ni = d_regions_map[n]; |
806 |
810 |
int counter = 0; |
807 |
810 |
DiseqList* del = d_regions[ni]->getRegionInfo(n)->get(0); |
808 |
2365 |
for( DiseqList::iterator it = del->begin(); it != del->end(); ++it ){ |
809 |
1555 |
if( (*it).second ){ |
810 |
710 |
if( d_regions_map[ (*it).first ]==ri ){ |
811 |
622 |
counter++; |
812 |
|
} |
813 |
|
} |
814 |
|
} |
815 |
810 |
return counter; |
816 |
|
} |
817 |
|
|
818 |
9735 |
void SortModel::getDisequalitiesToRegions(int ri, |
819 |
|
std::map< int, int >& regions_diseq) |
820 |
|
{ |
821 |
9735 |
Region* region = d_regions[ri]; |
822 |
111239 |
for(Region::iterator it = region->begin(); it != region->end(); ++it ){ |
823 |
101504 |
if( it->second->valid() ){ |
824 |
26498 |
DiseqList* del = it->second->get(0); |
825 |
207889 |
for( DiseqList::iterator it2 = del->begin(); it2 != del->end(); ++it2 ){ |
826 |
181391 |
if( (*it2).second ){ |
827 |
124813 |
Assert(isValid(d_regions_map[(*it2).first])); |
828 |
|
//Notice() << "Found disequality with " << (*it2).first << ", region = " << d_regions_map[ (*it2).first ] << std::endl; |
829 |
124813 |
regions_diseq[ d_regions_map[ (*it2).first ] ]++; |
830 |
|
} |
831 |
|
} |
832 |
|
} |
833 |
|
} |
834 |
9735 |
} |
835 |
|
|
836 |
|
void SortModel::setSplitScore( Node n, int s ){ |
837 |
|
if( d_split_score.find( n )!=d_split_score.end() ){ |
838 |
|
int ss = d_split_score[ n ]; |
839 |
|
d_split_score[ n ] = s>ss ? s : ss; |
840 |
|
}else{ |
841 |
|
d_split_score[ n ] = s; |
842 |
|
} |
843 |
|
for( int i=0; i<(int)n.getNumChildren(); i++ ){ |
844 |
|
setSplitScore( n[i], s+1 ); |
845 |
|
} |
846 |
|
} |
847 |
|
|
848 |
9119 |
void SortModel::assertCardinality(uint32_t c, bool val) |
849 |
|
{ |
850 |
9119 |
if (!d_state.isInConflict()) |
851 |
|
{ |
852 |
18238 |
Trace("uf-ss-assert") |
853 |
9119 |
<< "Assert cardinality " << d_type << " " << c << " " << val |
854 |
9119 |
<< " level = " |
855 |
9119 |
<< d_thss->getTheory()->getValuation().getAssertionLevel() << std::endl; |
856 |
9119 |
Assert(c > 0); |
857 |
18118 |
Node cl = getCardinalityLiteral( c ); |
858 |
9119 |
if( val ){ |
859 |
7711 |
bool doCheckRegions = !d_hasCard; |
860 |
7711 |
bool prevHasCard = d_hasCard; |
861 |
7711 |
d_hasCard = true; |
862 |
7711 |
if (!prevHasCard || c < d_cardinality) |
863 |
|
{ |
864 |
7703 |
d_cardinality = c; |
865 |
7703 |
simpleCheckCardinality(); |
866 |
7703 |
if (d_state.isInConflict()) |
867 |
|
{ |
868 |
120 |
return; |
869 |
|
} |
870 |
|
} |
871 |
|
//should check all regions now |
872 |
7591 |
if (doCheckRegions) |
873 |
|
{ |
874 |
49462 |
for (size_t i = 0; i < d_regions_index; i++) |
875 |
|
{ |
876 |
41912 |
if( d_regions[i]->valid() ){ |
877 |
35211 |
checkRegion( i ); |
878 |
35211 |
if (d_state.isInConflict()) |
879 |
|
{ |
880 |
|
return; |
881 |
|
} |
882 |
|
} |
883 |
|
} |
884 |
|
} |
885 |
|
// we assert it positively, if its beyond the bound, abort |
886 |
22773 |
if (options::ufssAbortCardinality() >= 0 |
887 |
7591 |
&& c >= static_cast<uint32_t>(options::ufssAbortCardinality())) |
888 |
|
{ |
889 |
|
std::stringstream ss; |
890 |
|
ss << "Maximum cardinality (" << options::ufssAbortCardinality() |
891 |
|
<< ") for finite model finding exceeded." << std::endl; |
892 |
|
throw LogicException(ss.str()); |
893 |
|
} |
894 |
|
} |
895 |
|
else |
896 |
|
{ |
897 |
1408 |
if (c > d_maxNegCard.get()) |
898 |
|
{ |
899 |
2476 |
Trace("uf-ss-com-card-debug") << "Maximum negative cardinality for " |
900 |
1238 |
<< d_type << " is now " << c << std::endl; |
901 |
1238 |
d_maxNegCard.set(c); |
902 |
1238 |
simpleCheckCardinality(); |
903 |
|
} |
904 |
|
} |
905 |
|
} |
906 |
|
} |
907 |
|
|
908 |
105329 |
void SortModel::checkRegion( int ri, bool checkCombine ){ |
909 |
105329 |
if( isValid(ri) && d_hasCard ){ |
910 |
98867 |
Assert(d_cardinality > 0); |
911 |
98867 |
if( checkCombine && d_regions[ri]->getMustCombine( d_cardinality ) ){ |
912 |
9735 |
int riNew = forceCombineRegion( ri, true ); |
913 |
9735 |
if( riNew>=0 ){ |
914 |
9735 |
checkRegion( riNew, checkCombine ); |
915 |
|
} |
916 |
|
} |
917 |
|
//now check if region is in conflict |
918 |
197734 |
std::vector< Node > clique; |
919 |
98867 |
if( d_regions[ri]->check( Theory::EFFORT_STANDARD, d_cardinality, clique ) ){ |
920 |
|
//explain clique |
921 |
2055 |
addCliqueLemma(clique); |
922 |
|
} |
923 |
|
} |
924 |
105329 |
} |
925 |
|
|
926 |
12677 |
int SortModel::forceCombineRegion( int ri, bool useDensity ){ |
927 |
12677 |
if( !useDensity ){ |
928 |
25393 |
for( int i=0; i<(int)d_regions_index; i++ ){ |
929 |
25393 |
if( ri!=i && d_regions[i]->valid() ){ |
930 |
2942 |
return combineRegions( ri, i ); |
931 |
|
} |
932 |
|
} |
933 |
|
return -1; |
934 |
|
}else{ |
935 |
|
//this region must merge with another |
936 |
9735 |
if( Debug.isOn("uf-ss-check-region") ){ |
937 |
|
Debug("uf-ss-check-region") << "We must combine Region #" << ri << ". " << std::endl; |
938 |
|
d_regions[ri]->debugPrint("uf-ss-check-region"); |
939 |
|
} |
940 |
|
//take region with maximum disequality density |
941 |
9735 |
double maxScore = 0; |
942 |
9735 |
int maxRegion = -1; |
943 |
19470 |
std::map< int, int > regions_diseq; |
944 |
9735 |
getDisequalitiesToRegions( ri, regions_diseq ); |
945 |
59293 |
for( std::map< int, int >::iterator it = regions_diseq.begin(); it != regions_diseq.end(); ++it ){ |
946 |
49558 |
Debug("uf-ss-check-region") << it->first << " : " << it->second << std::endl; |
947 |
|
} |
948 |
59293 |
for( std::map< int, int >::iterator it = regions_diseq.begin(); it != regions_diseq.end(); ++it ){ |
949 |
49558 |
Assert(it->first != ri); |
950 |
49558 |
Assert(isValid(it->first)); |
951 |
49558 |
Assert(d_regions[it->first]->getNumReps() > 0); |
952 |
49558 |
double tempScore = double(it->second)/double(d_regions[it->first]->getNumReps() ); |
953 |
49558 |
if( tempScore>maxScore ){ |
954 |
11521 |
maxRegion = it->first; |
955 |
11521 |
maxScore = tempScore; |
956 |
|
} |
957 |
|
} |
958 |
9735 |
if( maxRegion!=-1 ){ |
959 |
9735 |
if( Debug.isOn("uf-ss-check-region") ){ |
960 |
|
Debug("uf-ss-check-region") << "Combine with region #" << maxRegion << ":" << std::endl; |
961 |
|
d_regions[maxRegion]->debugPrint("uf-ss-check-region"); |
962 |
|
} |
963 |
9735 |
return combineRegions( ri, maxRegion ); |
964 |
|
} |
965 |
|
return -1; |
966 |
|
} |
967 |
|
} |
968 |
|
|
969 |
|
|
970 |
42679 |
int SortModel::combineRegions( int ai, int bi ){ |
971 |
42679 |
Debug("uf-ss-region") << "uf-ss: Combine Region #" << bi << " with Region #" << ai << std::endl; |
972 |
42679 |
Assert(isValid(ai) && isValid(bi)); |
973 |
42679 |
Region* region_bi = d_regions[bi]; |
974 |
231179 |
for(Region::iterator it = region_bi->begin(); it != region_bi->end(); ++it){ |
975 |
188500 |
Region::RegionNodeInfo* rni = it->second; |
976 |
188500 |
if( rni->valid() ){ |
977 |
45593 |
d_regions_map[ it->first ] = ai; |
978 |
|
} |
979 |
|
} |
980 |
|
//update regions disequal DO_THIS? |
981 |
42679 |
d_regions[ai]->combine( d_regions[bi] ); |
982 |
42679 |
d_regions[bi]->setValid( false ); |
983 |
42679 |
return ai; |
984 |
|
} |
985 |
|
|
986 |
405 |
void SortModel::moveNode( Node n, int ri ){ |
987 |
405 |
Debug("uf-ss-region") << "uf-ss: Move node " << n << " to Region #" << ri << std::endl; |
988 |
405 |
Assert(isValid(d_regions_map[n])); |
989 |
405 |
Assert(isValid(ri)); |
990 |
|
//move node to region ri |
991 |
405 |
d_regions[ri]->takeNode( d_regions[ d_regions_map[n] ], n ); |
992 |
405 |
d_regions_map[n] = ri; |
993 |
405 |
} |
994 |
|
|
995 |
1911 |
int SortModel::addSplit(Region* r) |
996 |
|
{ |
997 |
3822 |
Node s; |
998 |
1911 |
if( r->hasSplits() ){ |
999 |
|
//take the first split you find |
1000 |
9935 |
for( Region::split_iterator it = r->begin_splits(); |
1001 |
9935 |
it != r->end_splits(); ++it ){ |
1002 |
9935 |
if( (*it).second ){ |
1003 |
1911 |
s = (*it).first; |
1004 |
1911 |
break; |
1005 |
|
} |
1006 |
|
} |
1007 |
1911 |
Assert(s != Node::null()); |
1008 |
|
} |
1009 |
1911 |
if (!s.isNull() ){ |
1010 |
|
//add lemma to output channel |
1011 |
1911 |
Assert(s.getKind() == EQUAL); |
1012 |
3822 |
Node ss = Rewriter::rewrite( s ); |
1013 |
1911 |
if( ss.getKind()!=EQUAL ){ |
1014 |
|
Node b_t = NodeManager::currentNM()->mkConst( true ); |
1015 |
|
Node b_f = NodeManager::currentNM()->mkConst( false ); |
1016 |
|
if( ss==b_f ){ |
1017 |
|
Trace("uf-ss-lemma") << "....Assert disequal directly : " |
1018 |
|
<< s[0] << " " << s[1] << std::endl; |
1019 |
|
assertDisequal( s[0], s[1], b_t ); |
1020 |
|
return -1; |
1021 |
|
}else{ |
1022 |
|
Trace("uf-ss-warn") << "Split on unknown literal : " << ss << std::endl; |
1023 |
|
} |
1024 |
|
if (ss == b_t) |
1025 |
|
{ |
1026 |
|
CVC5Message() << "Bad split " << s << std::endl; |
1027 |
|
AlwaysAssert(false); |
1028 |
|
} |
1029 |
|
} |
1030 |
1911 |
if (Trace.isOn("uf-ss-split-si")) |
1031 |
|
{ |
1032 |
|
SortInference* si = d_state.getSortInference(); |
1033 |
|
if (si != nullptr) |
1034 |
|
{ |
1035 |
|
for (size_t i = 0; i < 2; i++) |
1036 |
|
{ |
1037 |
|
int sid = si->getSortId(ss[i]); |
1038 |
|
Trace("uf-ss-split-si") << sid << " "; |
1039 |
|
} |
1040 |
|
Trace("uf-ss-split-si") << std::endl; |
1041 |
|
} |
1042 |
|
} |
1043 |
|
//Trace("uf-ss-lemma") << d_th->getEqualityEngine()->areEqual( s[0], s[1] ) << " "; |
1044 |
|
//Trace("uf-ss-lemma") << d_th->getEqualityEngine()->areDisequal( s[0], s[1] ) << std::endl; |
1045 |
|
//Trace("uf-ss-lemma") << s[0].getType() << " " << s[1].getType() << std::endl; |
1046 |
|
//Notice() << "*** Split on " << s << std::endl; |
1047 |
|
//split on the equality s |
1048 |
3822 |
Node lem = NodeManager::currentNM()->mkNode( kind::OR, ss, ss.negate() ); |
1049 |
|
// send lemma, with caching |
1050 |
1911 |
if (d_im.lemma(lem, InferenceId::UF_CARD_SPLIT)) |
1051 |
|
{ |
1052 |
1911 |
Trace("uf-ss-lemma") << "*** Split on " << s << std::endl; |
1053 |
|
//tell the sat solver to explore the equals branch first |
1054 |
1911 |
d_im.requirePhase(ss, true); |
1055 |
1911 |
++( d_thss->d_statistics.d_split_lemmas ); |
1056 |
|
} |
1057 |
1911 |
return 1; |
1058 |
|
}else{ |
1059 |
|
return 0; |
1060 |
|
} |
1061 |
|
} |
1062 |
|
|
1063 |
2826 |
void SortModel::addCliqueLemma(std::vector<Node>& clique) |
1064 |
|
{ |
1065 |
2826 |
Assert(d_hasCard); |
1066 |
2826 |
Assert(d_cardinality > 0); |
1067 |
8982 |
while (clique.size() > d_cardinality + 1) |
1068 |
|
{ |
1069 |
3078 |
clique.pop_back(); |
1070 |
|
} |
1071 |
|
// add as lemma |
1072 |
5652 |
std::vector<Node> eqs; |
1073 |
16974 |
for (unsigned i = 0, size = clique.size(); i < size; i++) |
1074 |
|
{ |
1075 |
66257 |
for (unsigned j = 0; j < i; j++) |
1076 |
|
{ |
1077 |
52109 |
eqs.push_back(clique[i].eqNode(clique[j])); |
1078 |
|
} |
1079 |
|
} |
1080 |
2826 |
eqs.push_back(d_cardinality_literal[d_cardinality].notNode()); |
1081 |
5652 |
Node lem = NodeManager::currentNM()->mkNode(OR, eqs); |
1082 |
|
// send lemma, with caching |
1083 |
2826 |
if (d_im.lemma(lem, InferenceId::UF_CARD_CLIQUE)) |
1084 |
|
{ |
1085 |
2826 |
Trace("uf-ss-lemma") << "*** Add clique lemma " << lem << std::endl; |
1086 |
2826 |
++(d_thss->d_statistics.d_clique_lemmas); |
1087 |
|
} |
1088 |
2826 |
} |
1089 |
|
|
1090 |
8941 |
void SortModel::simpleCheckCardinality() { |
1091 |
8941 |
if( d_maxNegCard.get()!=0 && d_hasCard.get() && d_cardinality.get()<d_maxNegCard.get() ){ |
1092 |
252 |
Node lem = NodeManager::currentNM()->mkNode( AND, getCardinalityLiteral( d_cardinality.get() ), |
1093 |
504 |
getCardinalityLiteral( d_maxNegCard.get() ).negate() ); |
1094 |
126 |
Trace("uf-ss-lemma") << "*** Simple cardinality conflict : " << lem << std::endl; |
1095 |
126 |
d_im.conflict(lem, InferenceId::UF_CARD_SIMPLE_CONFLICT); |
1096 |
|
} |
1097 |
8941 |
} |
1098 |
|
|
1099 |
9688 |
void SortModel::debugPrint( const char* c ){ |
1100 |
9688 |
if( Debug.isOn( c ) ){ |
1101 |
|
Debug( c ) << "Number of reps = " << d_reps << std::endl; |
1102 |
|
Debug( c ) << "Cardinality req = " << d_cardinality << std::endl; |
1103 |
|
unsigned debugReps = 0; |
1104 |
|
for( unsigned i=0; i<d_regions_index; i++ ){ |
1105 |
|
Region* region = d_regions[i]; |
1106 |
|
if( region->valid() ){ |
1107 |
|
Debug( c ) << "Region #" << i << ": " << std::endl; |
1108 |
|
region->debugPrint( c, true ); |
1109 |
|
Debug( c ) << std::endl; |
1110 |
|
for( Region::iterator it = region->begin(); it != region->end(); ++it ){ |
1111 |
|
if( it->second->valid() ){ |
1112 |
|
if( d_regions_map[ it->first ]!=(int)i ){ |
1113 |
|
Debug( c ) << "***Bad regions map : " << it->first |
1114 |
|
<< " " << d_regions_map[ it->first ].get() << std::endl; |
1115 |
|
} |
1116 |
|
} |
1117 |
|
} |
1118 |
|
debugReps += region->getNumReps(); |
1119 |
|
} |
1120 |
|
} |
1121 |
|
|
1122 |
|
if( debugReps!=d_reps ){ |
1123 |
|
Debug( c ) << "***Bad reps: " << d_reps << ", " |
1124 |
|
<< "actual = " << debugReps << std::endl; |
1125 |
|
} |
1126 |
|
} |
1127 |
9688 |
} |
1128 |
|
|
1129 |
1706 |
bool SortModel::checkLastCall() |
1130 |
|
{ |
1131 |
1706 |
NodeManager* nm = NodeManager::currentNM(); |
1132 |
1706 |
SkolemManager* sm = nm->getSkolemManager(); |
1133 |
1706 |
TheoryModel* m = d_state.getModel(); |
1134 |
1706 |
if( Trace.isOn("uf-ss-warn") ){ |
1135 |
|
std::vector< Node > eqcs; |
1136 |
|
eq::EqClassesIterator eqcs_i = |
1137 |
|
eq::EqClassesIterator(m->getEqualityEngine()); |
1138 |
|
while( !eqcs_i.isFinished() ){ |
1139 |
|
Node eqc = (*eqcs_i); |
1140 |
|
if( eqc.getType()==d_type ){ |
1141 |
|
if( std::find( eqcs.begin(), eqcs.end(), eqc )==eqcs.end() ){ |
1142 |
|
eqcs.push_back( eqc ); |
1143 |
|
//we must ensure that this equivalence class has been accounted for |
1144 |
|
if( d_regions_map.find( eqc )==d_regions_map.end() ){ |
1145 |
|
Trace("uf-ss-warn") << "WARNING : equivalence class " << eqc << " unaccounted for." << std::endl; |
1146 |
|
Trace("uf-ss-warn") << " type : " << d_type << std::endl; |
1147 |
|
Trace("uf-ss-warn") << " kind : " << eqc.getKind() << std::endl; |
1148 |
|
} |
1149 |
|
} |
1150 |
|
} |
1151 |
|
++eqcs_i; |
1152 |
|
} |
1153 |
|
} |
1154 |
1706 |
RepSet* rs = m->getRepSetPtr(); |
1155 |
1706 |
size_t nReps = rs->getNumRepresentatives(d_type); |
1156 |
1706 |
if (nReps != d_maxNegCard + 1) |
1157 |
|
{ |
1158 |
30 |
Trace("uf-ss-warn") << "WARNING : Model does not have same # " |
1159 |
15 |
"representatives as cardinality for " |
1160 |
15 |
<< d_type << "." << std::endl; |
1161 |
30 |
Trace("uf-ss-warn") << " Max neg cardinality : " << d_maxNegCard |
1162 |
15 |
<< std::endl; |
1163 |
15 |
Trace("uf-ss-warn") << " # Reps : " << nReps << std::endl; |
1164 |
15 |
if (d_maxNegCard >= nReps) |
1165 |
|
{ |
1166 |
315 |
while (d_fresh_aloc_reps.size() <= d_maxNegCard) |
1167 |
|
{ |
1168 |
300 |
std::stringstream ss; |
1169 |
150 |
ss << "r_" << d_type << "_"; |
1170 |
|
Node nn = sm->mkDummySkolem( |
1171 |
300 |
ss.str(), d_type, "enumeration to meet negative card constraint"); |
1172 |
150 |
d_fresh_aloc_reps.push_back( nn ); |
1173 |
|
} |
1174 |
15 |
if (d_maxNegCard == 0) |
1175 |
|
{ |
1176 |
|
rs->d_type_reps[d_type].push_back(d_fresh_aloc_reps[0]); |
1177 |
|
} |
1178 |
|
else |
1179 |
|
{ |
1180 |
|
//must add lemma |
1181 |
30 |
std::vector< Node > force_cl; |
1182 |
165 |
for (size_t i = 0; i <= d_maxNegCard; i++) |
1183 |
|
{ |
1184 |
1309 |
for (size_t j = (i + 1); j <= d_maxNegCard; j++) |
1185 |
|
{ |
1186 |
1159 |
force_cl.push_back( |
1187 |
2318 |
d_fresh_aloc_reps[i].eqNode(d_fresh_aloc_reps[j]).negate()); |
1188 |
|
} |
1189 |
|
} |
1190 |
30 |
Node cl = getCardinalityLiteral( d_maxNegCard ); |
1191 |
30 |
Node lem = nm->mkNode(OR, cl, nm->mkAnd(force_cl)); |
1192 |
15 |
Trace("uf-ss-lemma") << "*** Enforce negative cardinality constraint lemma : " << lem << std::endl; |
1193 |
15 |
d_im.lemma(lem, InferenceId::UF_CARD_ENFORCE_NEGATIVE); |
1194 |
15 |
return false; |
1195 |
|
} |
1196 |
|
} |
1197 |
|
} |
1198 |
1691 |
return true; |
1199 |
|
} |
1200 |
|
|
1201 |
|
int SortModel::getNumRegions(){ |
1202 |
|
int count = 0; |
1203 |
|
for( int i=0; i<(int)d_regions_index; i++ ){ |
1204 |
|
if( d_regions[i]->valid() ){ |
1205 |
|
count++; |
1206 |
|
} |
1207 |
|
} |
1208 |
|
return count; |
1209 |
|
} |
1210 |
|
|
1211 |
11744 |
Node SortModel::getCardinalityLiteral(uint32_t c) |
1212 |
|
{ |
1213 |
11744 |
Assert(c > 0); |
1214 |
11744 |
std::map<uint32_t, Node>::iterator itcl = d_cardinality_literal.find(c); |
1215 |
11744 |
if (itcl != d_cardinality_literal.end()) |
1216 |
|
{ |
1217 |
10767 |
return itcl->second; |
1218 |
|
} |
1219 |
|
// get the literal from the decision strategy |
1220 |
1954 |
Node lit = d_c_dec_strat->getLiteral(c - 1); |
1221 |
977 |
d_cardinality_literal[c] = lit; |
1222 |
|
|
1223 |
|
// return the literal |
1224 |
977 |
return lit; |
1225 |
|
} |
1226 |
|
|
1227 |
271 |
CardinalityExtension::CardinalityExtension(TheoryState& state, |
1228 |
|
TheoryInferenceManager& im, |
1229 |
271 |
TheoryUF* th) |
1230 |
|
: d_state(state), |
1231 |
|
d_im(im), |
1232 |
|
d_th(th), |
1233 |
|
d_rep_model(), |
1234 |
|
d_min_pos_com_card(state.getSatContext(), 0), |
1235 |
|
d_min_pos_com_card_set(state.getSatContext(), false), |
1236 |
|
d_cc_dec_strat(nullptr), |
1237 |
271 |
d_initializedCombinedCardinality(state.getUserContext(), false), |
1238 |
271 |
d_card_assertions_eqv_lemma(state.getUserContext()), |
1239 |
|
d_min_pos_tn_master_card(state.getSatContext(), 0), |
1240 |
|
d_min_pos_tn_master_card_set(state.getSatContext(), false), |
1241 |
813 |
d_rel_eqc(state.getSatContext()) |
1242 |
|
{ |
1243 |
13228 |
if (options::ufssMode() == options::UfssMode::FULL && options::ufssFairness()) |
1244 |
|
{ |
1245 |
|
// Register the strategy with the decision manager of the theory. |
1246 |
|
// We are guaranteed that the decision manager is ready since we |
1247 |
|
// construct this module during TheoryUF::finishInit. |
1248 |
789 |
d_cc_dec_strat.reset(new CombinedCardinalityDecisionStrategy( |
1249 |
526 |
state.getSatContext(), th->getValuation())); |
1250 |
|
} |
1251 |
271 |
} |
1252 |
|
|
1253 |
542 |
CardinalityExtension::~CardinalityExtension() |
1254 |
|
{ |
1255 |
734 |
for (std::map<TypeNode, SortModel*>::iterator it = d_rep_model.begin(); |
1256 |
734 |
it != d_rep_model.end(); ++it) { |
1257 |
463 |
delete it->second; |
1258 |
|
} |
1259 |
271 |
} |
1260 |
|
|
1261 |
|
/** ensure eqc */ |
1262 |
|
void CardinalityExtension::ensureEqc(SortModel* c, Node a) |
1263 |
|
{ |
1264 |
|
if( !hasEqc( a ) ){ |
1265 |
|
d_rel_eqc[a] = true; |
1266 |
|
Trace("uf-ss-solver") << "CardinalityExtension: New eq class " << a << " : " |
1267 |
|
<< a.getType() << std::endl; |
1268 |
|
c->newEqClass( a ); |
1269 |
|
Trace("uf-ss-solver") << "CardinalityExtension: Done New eq class." |
1270 |
|
<< std::endl; |
1271 |
|
} |
1272 |
|
} |
1273 |
|
|
1274 |
|
void CardinalityExtension::ensureEqcRec(Node n) |
1275 |
|
{ |
1276 |
|
if( !hasEqc( n ) ){ |
1277 |
|
SortModel* c = getSortModel( n ); |
1278 |
|
if( c ){ |
1279 |
|
ensureEqc( c, n ); |
1280 |
|
} |
1281 |
|
for( unsigned i=0; i<n.getNumChildren(); i++ ){ |
1282 |
|
ensureEqcRec( n[i] ); |
1283 |
|
} |
1284 |
|
} |
1285 |
|
} |
1286 |
|
|
1287 |
|
/** has eqc */ |
1288 |
|
bool CardinalityExtension::hasEqc(Node a) |
1289 |
|
{ |
1290 |
|
NodeBoolMap::iterator it = d_rel_eqc.find( a ); |
1291 |
|
return it!=d_rel_eqc.end() && (*it).second; |
1292 |
|
} |
1293 |
|
|
1294 |
|
/** new node */ |
1295 |
31433 |
void CardinalityExtension::newEqClass(Node a) |
1296 |
|
{ |
1297 |
31433 |
SortModel* c = getSortModel( a ); |
1298 |
31433 |
if( c ){ |
1299 |
9640 |
Trace("uf-ss-solver") << "CardinalityExtension: New eq class " << a << " : " |
1300 |
4820 |
<< a.getType() << std::endl; |
1301 |
4820 |
c->newEqClass( a ); |
1302 |
9640 |
Trace("uf-ss-solver") << "CardinalityExtension: Done New eq class." |
1303 |
4820 |
<< std::endl; |
1304 |
|
} |
1305 |
31433 |
} |
1306 |
|
|
1307 |
|
/** merge */ |
1308 |
427051 |
void CardinalityExtension::merge(Node a, Node b) |
1309 |
|
{ |
1310 |
|
//TODO: ensure they are relevant |
1311 |
427051 |
SortModel* c = getSortModel( a ); |
1312 |
427051 |
if( c ){ |
1313 |
67794 |
Trace("uf-ss-solver") << "CardinalityExtension: Merge " << a << " " << b |
1314 |
33897 |
<< " : " << a.getType() << std::endl; |
1315 |
33897 |
c->merge( a, b ); |
1316 |
33897 |
Trace("uf-ss-solver") << "CardinalityExtension: Done Merge." << std::endl; |
1317 |
|
} |
1318 |
427051 |
} |
1319 |
|
|
1320 |
|
/** assert terms are disequal */ |
1321 |
25575 |
void CardinalityExtension::assertDisequal(Node a, Node b, Node reason) |
1322 |
|
{ |
1323 |
25575 |
SortModel* c = getSortModel( a ); |
1324 |
25575 |
if( c ){ |
1325 |
26524 |
Trace("uf-ss-solver") << "CardinalityExtension: Assert disequal " << a |
1326 |
13262 |
<< " " << b << " : " << a.getType() << std::endl; |
1327 |
13262 |
c->assertDisequal( a, b, reason ); |
1328 |
26524 |
Trace("uf-ss-solver") << "CardinalityExtension: Done Assert disequal." |
1329 |
13262 |
<< std::endl; |
1330 |
|
} |
1331 |
25575 |
} |
1332 |
|
|
1333 |
|
/** assert a node */ |
1334 |
292813 |
void CardinalityExtension::assertNode(Node n, bool isDecision) |
1335 |
|
{ |
1336 |
292813 |
Trace("uf-ss") << "Assert " << n << " " << isDecision << std::endl; |
1337 |
292813 |
bool polarity = n.getKind() != kind::NOT; |
1338 |
585626 |
TNode lit = polarity ? n : n[0]; |
1339 |
292813 |
if (options::ufssMode() == options::UfssMode::FULL) |
1340 |
|
{ |
1341 |
157409 |
if( lit.getKind()==CARDINALITY_CONSTRAINT ){ |
1342 |
18270 |
TypeNode tn = lit[0].getType(); |
1343 |
9135 |
Assert(tn.isSort()); |
1344 |
9135 |
Assert(d_rep_model[tn]); |
1345 |
|
uint32_t nCard = |
1346 |
9135 |
lit[1].getConst<Rational>().getNumerator().getUnsignedInt(); |
1347 |
18270 |
Node ct = d_rep_model[tn]->getCardinalityTerm(); |
1348 |
9135 |
Trace("uf-ss-debug") << "...check cardinality terms : " << lit[0] << " " << ct << std::endl; |
1349 |
9135 |
if( lit[0]==ct ){ |
1350 |
9119 |
if( options::ufssFairnessMonotone() ){ |
1351 |
54 |
SortInference* si = d_state.getSortInference(); |
1352 |
54 |
Trace("uf-ss-com-card-debug") << "...set master/slave" << std::endl; |
1353 |
54 |
if( tn!=d_tn_mono_master ){ |
1354 |
42 |
std::map< TypeNode, bool >::iterator it = d_tn_mono_slave.find( tn ); |
1355 |
42 |
if( it==d_tn_mono_slave.end() ){ |
1356 |
|
bool isMonotonic; |
1357 |
10 |
if (si != nullptr) |
1358 |
|
{ |
1359 |
|
isMonotonic = si->isMonotonic(tn); |
1360 |
|
}else{ |
1361 |
|
//if ground, everything is monotonic |
1362 |
10 |
isMonotonic = true; |
1363 |
|
} |
1364 |
10 |
if( isMonotonic ){ |
1365 |
10 |
if( d_tn_mono_master.isNull() ){ |
1366 |
4 |
Trace("uf-ss-com-card-debug") << "uf-ss-fair-monotone: Set master : " << tn << std::endl; |
1367 |
4 |
d_tn_mono_master = tn; |
1368 |
|
}else{ |
1369 |
6 |
Trace("uf-ss-com-card-debug") << "uf-ss-fair-monotone: Set slave : " << tn << std::endl; |
1370 |
6 |
d_tn_mono_slave[tn] = true; |
1371 |
|
} |
1372 |
|
}else{ |
1373 |
|
Trace("uf-ss-com-card-debug") << "uf-ss-fair-monotone: Set non-monotonic : " << tn << std::endl; |
1374 |
|
d_tn_mono_slave[tn] = false; |
1375 |
|
} |
1376 |
|
} |
1377 |
|
} |
1378 |
|
//set the minimum positive cardinality for master if necessary |
1379 |
54 |
if( polarity && tn==d_tn_mono_master ){ |
1380 |
16 |
Trace("uf-ss-com-card-debug") << "...set min positive cardinality" << std::endl; |
1381 |
32 |
if (!d_min_pos_tn_master_card_set.get() |
1382 |
16 |
|| nCard < d_min_pos_tn_master_card.get()) |
1383 |
|
{ |
1384 |
16 |
d_min_pos_tn_master_card_set.set(true); |
1385 |
16 |
d_min_pos_tn_master_card.set( nCard ); |
1386 |
|
} |
1387 |
|
} |
1388 |
|
} |
1389 |
9119 |
Trace("uf-ss-com-card-debug") << "...assert cardinality" << std::endl; |
1390 |
9119 |
d_rep_model[tn]->assertCardinality(nCard, polarity); |
1391 |
|
//check if combined cardinality is violated |
1392 |
9119 |
checkCombinedCardinality(); |
1393 |
|
}else{ |
1394 |
|
//otherwise, make equal via lemma |
1395 |
16 |
if( d_card_assertions_eqv_lemma.find( lit )==d_card_assertions_eqv_lemma.end() ){ |
1396 |
16 |
Node eqv_lit = NodeManager::currentNM()->mkNode( CARDINALITY_CONSTRAINT, ct, lit[1] ); |
1397 |
8 |
eqv_lit = lit.eqNode( eqv_lit ); |
1398 |
8 |
Trace("uf-ss-lemma") << "*** Cardinality equiv lemma : " << eqv_lit << std::endl; |
1399 |
8 |
d_im.lemma(eqv_lit, InferenceId::UF_CARD_EQUIV); |
1400 |
8 |
d_card_assertions_eqv_lemma[lit] = true; |
1401 |
|
} |
1402 |
|
} |
1403 |
148274 |
}else if( lit.getKind()==COMBINED_CARDINALITY_CONSTRAINT ){ |
1404 |
4537 |
if( polarity ){ |
1405 |
|
//safe to assume int here |
1406 |
|
uint32_t nCard = |
1407 |
3575 |
lit[0].getConst<Rational>().getNumerator().getUnsignedInt(); |
1408 |
3575 |
if (!d_min_pos_com_card_set.get() || nCard < d_min_pos_com_card.get()) |
1409 |
|
{ |
1410 |
3575 |
d_min_pos_com_card_set.set(true); |
1411 |
3575 |
d_min_pos_com_card.set( nCard ); |
1412 |
3575 |
checkCombinedCardinality(); |
1413 |
|
} |
1414 |
|
} |
1415 |
|
}else{ |
1416 |
143737 |
if( Trace.isOn("uf-ss-warn") ){ |
1417 |
|
////FIXME: this is too strict: theory propagations are showing up as isDecision=true, but |
1418 |
|
//// a theory propagation is not a decision. |
1419 |
|
if( isDecision ){ |
1420 |
|
for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ |
1421 |
|
if( !it->second->hasCardinalityAsserted() ){ |
1422 |
|
Trace("uf-ss-warn") << "WARNING: Assert " << n << " as a decision before cardinality for " << it->first << "." << std::endl; |
1423 |
|
// CVC5Message() << "Error: constraint asserted before cardinality |
1424 |
|
// for " << it->first << std::endl; Unimplemented(); |
1425 |
|
} |
1426 |
|
} |
1427 |
|
} |
1428 |
|
} |
1429 |
|
} |
1430 |
|
} |
1431 |
|
else |
1432 |
|
{ |
1433 |
135404 |
if( lit.getKind()==CARDINALITY_CONSTRAINT || lit.getKind()==COMBINED_CARDINALITY_CONSTRAINT ){ |
1434 |
|
// cardinality constraint from user input, set incomplete |
1435 |
2 |
Trace("uf-ss") << "Literal " << lit << " not handled when uf ss mode is not FULL, set incomplete." << std::endl; |
1436 |
2 |
d_im.setIncomplete(IncompleteId::UF_CARD_MODE); |
1437 |
|
} |
1438 |
|
} |
1439 |
292813 |
Trace("uf-ss") << "Assert: done " << n << " " << isDecision << std::endl; |
1440 |
292813 |
} |
1441 |
|
|
1442 |
|
bool CardinalityExtension::areDisequal(Node a, Node b) |
1443 |
|
{ |
1444 |
|
if( a==b ){ |
1445 |
|
return false; |
1446 |
|
} |
1447 |
|
eq::EqualityEngine* ee = d_th->getEqualityEngine(); |
1448 |
|
a = ee->getRepresentative(a); |
1449 |
|
b = ee->getRepresentative(b); |
1450 |
|
if (ee->areDisequal(a, b, false)) |
1451 |
|
{ |
1452 |
|
return true; |
1453 |
|
} |
1454 |
|
SortModel* c = getSortModel(a); |
1455 |
|
if (c) |
1456 |
|
{ |
1457 |
|
return c->areDisequal(a, b); |
1458 |
|
} |
1459 |
|
return false; |
1460 |
|
} |
1461 |
|
|
1462 |
|
/** check */ |
1463 |
136929 |
void CardinalityExtension::check(Theory::Effort level) |
1464 |
|
{ |
1465 |
136929 |
if (level == Theory::EFFORT_LAST_CALL) |
1466 |
|
{ |
1467 |
|
// if last call, call last call check for each sort |
1468 |
2683 |
for (std::pair<const TypeNode, SortModel*>& r : d_rep_model) |
1469 |
|
{ |
1470 |
1706 |
if (!r.second->checkLastCall()) |
1471 |
|
{ |
1472 |
15 |
break; |
1473 |
|
} |
1474 |
|
} |
1475 |
992 |
return; |
1476 |
|
} |
1477 |
135937 |
if (!d_state.isInConflict()) |
1478 |
|
{ |
1479 |
135937 |
if (options::ufssMode() == options::UfssMode::FULL) |
1480 |
|
{ |
1481 |
126136 |
Trace("uf-ss-solver") |
1482 |
63068 |
<< "CardinalityExtension: check " << level << std::endl; |
1483 |
63068 |
if (level == Theory::EFFORT_FULL) |
1484 |
|
{ |
1485 |
3519 |
if (Debug.isOn("uf-ss-debug")) |
1486 |
|
{ |
1487 |
|
debugPrint("uf-ss-debug"); |
1488 |
|
} |
1489 |
3519 |
if (Trace.isOn("uf-ss-state")) |
1490 |
|
{ |
1491 |
|
Trace("uf-ss-state") |
1492 |
|
<< "CardinalityExtension::check " << level << std::endl; |
1493 |
|
for (std::pair<const TypeNode, SortModel*>& rm : d_rep_model) |
1494 |
|
{ |
1495 |
|
Trace("uf-ss-state") << " " << rm.first << " has cardinality " |
1496 |
|
<< rm.second->getCardinality() << std::endl; |
1497 |
|
} |
1498 |
|
} |
1499 |
|
} |
1500 |
344823 |
for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ |
1501 |
281755 |
it->second->check(level); |
1502 |
281755 |
if (d_state.isInConflict()) |
1503 |
|
{ |
1504 |
|
break; |
1505 |
|
} |
1506 |
|
} |
1507 |
|
} |
1508 |
72869 |
else if (options::ufssMode() == options::UfssMode::NO_MINIMAL) |
1509 |
|
{ |
1510 |
72869 |
if( level==Theory::EFFORT_FULL ){ |
1511 |
|
// split on an equality between two equivalence classes (at most one per type) |
1512 |
1790 |
std::map< TypeNode, std::vector< Node > > eqc_list; |
1513 |
1790 |
std::map< TypeNode, bool > type_proc; |
1514 |
895 |
eq::EqClassesIterator eqcs_i(d_th->getEqualityEngine()); |
1515 |
265659 |
while( !eqcs_i.isFinished() ){ |
1516 |
264764 |
Node a = *eqcs_i; |
1517 |
264764 |
TypeNode tn = a.getType(); |
1518 |
132382 |
if( tn.isSort() ){ |
1519 |
9953 |
if( type_proc.find( tn )==type_proc.end() ){ |
1520 |
9101 |
std::map< TypeNode, std::vector< Node > >::iterator itel = eqc_list.find( tn ); |
1521 |
9101 |
if( itel!=eqc_list.end() ){ |
1522 |
17971 |
for( unsigned j=0; j<itel->second.size(); j++ ){ |
1523 |
25163 |
Node b = itel->second[j]; |
1524 |
12833 |
if( !d_th->getEqualityEngine()->areDisequal( a, b, false ) ){ |
1525 |
1006 |
Node eq = Rewriter::rewrite( a.eqNode( b ) ); |
1526 |
1006 |
Node lem = NodeManager::currentNM()->mkNode( kind::OR, eq, eq.negate() ); |
1527 |
503 |
Trace("uf-ss-lemma") << "*** Split (no-minimal) : " << lem << std::endl; |
1528 |
503 |
d_im.lemma(lem, InferenceId::UF_CARD_SPLIT); |
1529 |
503 |
d_im.requirePhase(eq, true); |
1530 |
503 |
type_proc[tn] = true; |
1531 |
503 |
break; |
1532 |
|
} |
1533 |
|
} |
1534 |
|
} |
1535 |
9101 |
eqc_list[tn].push_back( a ); |
1536 |
|
} |
1537 |
|
} |
1538 |
132382 |
++eqcs_i; |
1539 |
|
} |
1540 |
|
} |
1541 |
|
} |
1542 |
|
else |
1543 |
|
{ |
1544 |
|
// unhandled uf ss mode |
1545 |
|
Assert(false); |
1546 |
|
} |
1547 |
271874 |
Trace("uf-ss-solver") << "Done CardinalityExtension: check " << level |
1548 |
135937 |
<< std::endl; |
1549 |
|
} |
1550 |
|
} |
1551 |
|
|
1552 |
314 |
void CardinalityExtension::presolve() |
1553 |
|
{ |
1554 |
314 |
d_initializedCombinedCardinality = false; |
1555 |
658 |
for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ |
1556 |
344 |
it->second->presolve(); |
1557 |
344 |
it->second->initialize(); |
1558 |
|
} |
1559 |
314 |
} |
1560 |
|
|
1561 |
263 |
CardinalityExtension::CombinedCardinalityDecisionStrategy:: |
1562 |
|
CombinedCardinalityDecisionStrategy(context::Context* satContext, |
1563 |
263 |
Valuation valuation) |
1564 |
263 |
: DecisionStrategyFmf(satContext, valuation) |
1565 |
|
{ |
1566 |
263 |
} |
1567 |
781 |
Node CardinalityExtension::CombinedCardinalityDecisionStrategy::mkLiteral( |
1568 |
|
unsigned i) |
1569 |
|
{ |
1570 |
781 |
NodeManager* nm = NodeManager::currentNM(); |
1571 |
781 |
return nm->mkNode(COMBINED_CARDINALITY_CONSTRAINT, nm->mkConst(Rational(i))); |
1572 |
|
} |
1573 |
|
|
1574 |
|
std::string |
1575 |
194663 |
CardinalityExtension::CombinedCardinalityDecisionStrategy::identify() const |
1576 |
|
{ |
1577 |
194663 |
return std::string("uf_combined_card"); |
1578 |
|
} |
1579 |
|
|
1580 |
476669 |
void CardinalityExtension::preRegisterTerm(TNode n) |
1581 |
|
{ |
1582 |
476669 |
if (options::ufssMode() == options::UfssMode::FULL) |
1583 |
|
{ |
1584 |
|
//initialize combined cardinality |
1585 |
229973 |
initializeCombinedCardinality(); |
1586 |
|
|
1587 |
229973 |
Trace("uf-ss-register") << "Preregister " << n << "." << std::endl; |
1588 |
|
//shouldn't have to preregister this type (it may be that there are no quantifiers over tn) |
1589 |
459946 |
TypeNode tn = n.getType(); |
1590 |
229973 |
std::map< TypeNode, SortModel* >::iterator it = d_rep_model.find( tn ); |
1591 |
229973 |
if( it==d_rep_model.end() ){ |
1592 |
225716 |
SortModel* rm = NULL; |
1593 |
225716 |
if( tn.isSort() ){ |
1594 |
463 |
Trace("uf-ss-register") << "Create sort model " << tn << "." << std::endl; |
1595 |
463 |
rm = new SortModel(n, d_state, d_im, this); |
1596 |
|
} |
1597 |
225716 |
if( rm ){ |
1598 |
463 |
rm->initialize(); |
1599 |
463 |
d_rep_model[tn] = rm; |
1600 |
|
//d_rep_model_init[tn] = true; |
1601 |
|
} |
1602 |
|
}else{ |
1603 |
|
//ensure sort model is initialized |
1604 |
4257 |
it->second->initialize(); |
1605 |
|
} |
1606 |
|
} |
1607 |
476669 |
} |
1608 |
|
|
1609 |
484059 |
SortModel* CardinalityExtension::getSortModel(Node n) |
1610 |
|
{ |
1611 |
968118 |
TypeNode tn = n.getType(); |
1612 |
484059 |
std::map< TypeNode, SortModel* >::iterator it = d_rep_model.find( tn ); |
1613 |
|
//pre-register the type if not done already |
1614 |
484059 |
if( it==d_rep_model.end() ){ |
1615 |
432080 |
preRegisterTerm( n ); |
1616 |
432080 |
it = d_rep_model.find( tn ); |
1617 |
|
} |
1618 |
484059 |
if( it!=d_rep_model.end() ){ |
1619 |
51979 |
return it->second; |
1620 |
|
}else{ |
1621 |
432080 |
return NULL; |
1622 |
|
} |
1623 |
|
} |
1624 |
|
|
1625 |
|
/** get cardinality for sort */ |
1626 |
|
int CardinalityExtension::getCardinality(Node n) |
1627 |
|
{ |
1628 |
|
SortModel* c = getSortModel( n ); |
1629 |
|
if( c ){ |
1630 |
|
return c->getCardinality(); |
1631 |
|
}else{ |
1632 |
|
return -1; |
1633 |
|
} |
1634 |
|
} |
1635 |
|
|
1636 |
|
int CardinalityExtension::getCardinality(TypeNode tn) |
1637 |
|
{ |
1638 |
|
std::map< TypeNode, SortModel* >::iterator it = d_rep_model.find( tn ); |
1639 |
|
if( it!=d_rep_model.end() && it->second ){ |
1640 |
|
return it->second->getCardinality(); |
1641 |
|
} |
1642 |
|
return -1; |
1643 |
|
} |
1644 |
|
|
1645 |
|
//print debug |
1646 |
|
void CardinalityExtension::debugPrint(const char* c) |
1647 |
|
{ |
1648 |
|
for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ |
1649 |
|
Debug( c ) << "Conflict find structure for " << it->first << ": " << std::endl; |
1650 |
|
it->second->debugPrint( c ); |
1651 |
|
Debug( c ) << std::endl; |
1652 |
|
} |
1653 |
|
} |
1654 |
|
|
1655 |
|
/** initialize */ |
1656 |
229973 |
void CardinalityExtension::initializeCombinedCardinality() |
1657 |
|
{ |
1658 |
459946 |
if (d_cc_dec_strat.get() != nullptr |
1659 |
229973 |
&& !d_initializedCombinedCardinality.get()) |
1660 |
|
{ |
1661 |
455 |
d_initializedCombinedCardinality = true; |
1662 |
910 |
d_im.getDecisionManager()->registerStrategy( |
1663 |
455 |
DecisionManager::STRAT_UF_COMBINED_CARD, d_cc_dec_strat.get()); |
1664 |
|
} |
1665 |
229973 |
} |
1666 |
|
|
1667 |
|
/** check */ |
1668 |
12694 |
void CardinalityExtension::checkCombinedCardinality() |
1669 |
|
{ |
1670 |
12694 |
Assert(options::ufssMode() == options::UfssMode::FULL); |
1671 |
12694 |
if( options::ufssFairness() ){ |
1672 |
12694 |
Trace("uf-ss-com-card-debug") << "Check combined cardinality, get maximum negative cardinalities..." << std::endl; |
1673 |
12694 |
uint32_t totalCombinedCard = 0; |
1674 |
12694 |
uint32_t maxMonoSlave = 0; |
1675 |
25388 |
TypeNode maxSlaveType; |
1676 |
78428 |
for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){ |
1677 |
65734 |
uint32_t max_neg = it->second->getMaximumNegativeCardinality(); |
1678 |
65734 |
if( !options::ufssFairnessMonotone() ){ |
1679 |
65564 |
totalCombinedCard += max_neg; |
1680 |
|
}else{ |
1681 |
170 |
std::map< TypeNode, bool >::iterator its = d_tn_mono_slave.find( it->first ); |
1682 |
170 |
if( its==d_tn_mono_slave.end() || !its->second ){ |
1683 |
74 |
totalCombinedCard += max_neg; |
1684 |
|
}else{ |
1685 |
96 |
if( max_neg>maxMonoSlave ){ |
1686 |
8 |
maxMonoSlave = max_neg; |
1687 |
8 |
maxSlaveType = it->first; |
1688 |
|
} |
1689 |
|
} |
1690 |
|
} |
1691 |
|
} |
1692 |
12694 |
Trace("uf-ss-com-card-debug") << "Check combined cardinality, total combined card : " << totalCombinedCard << std::endl; |
1693 |
12694 |
if( options::ufssFairnessMonotone() ){ |
1694 |
70 |
Trace("uf-ss-com-card-debug") << "Max slave monotonic negated cardinality : " << maxMonoSlave << std::endl; |
1695 |
140 |
if (!d_min_pos_tn_master_card_set.get() |
1696 |
70 |
&& maxMonoSlave > d_min_pos_tn_master_card.get()) |
1697 |
|
{ |
1698 |
|
uint32_t mc = d_min_pos_tn_master_card.get(); |
1699 |
|
std::vector< Node > conf; |
1700 |
|
conf.push_back( d_rep_model[d_tn_mono_master]->getCardinalityLiteral( mc ) ); |
1701 |
|
conf.push_back( d_rep_model[maxSlaveType]->getCardinalityLiteral( maxMonoSlave ).negate() ); |
1702 |
|
Node cf = NodeManager::currentNM()->mkNode( AND, conf ); |
1703 |
|
Trace("uf-ss-lemma") << "*** Combined monotone cardinality conflict" |
1704 |
|
<< " : " << cf << std::endl; |
1705 |
|
Trace("uf-ss-com-card") << "*** Combined monotone cardinality conflict" |
1706 |
|
<< " : " << cf << std::endl; |
1707 |
|
d_im.conflict(cf, InferenceId::UF_CARD_MONOTONE_COMBINED); |
1708 |
|
return; |
1709 |
|
} |
1710 |
|
} |
1711 |
12694 |
uint32_t cc = d_min_pos_com_card.get(); |
1712 |
12694 |
if (d_min_pos_com_card_set.get() && totalCombinedCard > cc) |
1713 |
|
{ |
1714 |
|
//conflict |
1715 |
1984 |
Node com_lit = d_cc_dec_strat->getLiteral(cc); |
1716 |
1984 |
std::vector< Node > conf; |
1717 |
992 |
conf.push_back( com_lit ); |
1718 |
992 |
uint32_t totalAdded = 0; |
1719 |
3034 |
for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); |
1720 |
3034 |
it != d_rep_model.end(); ++it ){ |
1721 |
3034 |
bool doAdd = true; |
1722 |
3034 |
if( options::ufssFairnessMonotone() ){ |
1723 |
|
std::map< TypeNode, bool >::iterator its = |
1724 |
|
d_tn_mono_slave.find( it->first ); |
1725 |
|
if( its!=d_tn_mono_slave.end() && its->second ){ |
1726 |
|
doAdd = false; |
1727 |
|
} |
1728 |
|
} |
1729 |
3034 |
if( doAdd ){ |
1730 |
3034 |
uint32_t c = it->second->getMaximumNegativeCardinality(); |
1731 |
3034 |
if( c>0 ){ |
1732 |
2358 |
conf.push_back( it->second->getCardinalityLiteral( c ).negate() ); |
1733 |
2358 |
totalAdded += c; |
1734 |
|
} |
1735 |
3034 |
if( totalAdded>cc ){ |
1736 |
992 |
break; |
1737 |
|
} |
1738 |
|
} |
1739 |
|
} |
1740 |
1984 |
Node cf = NodeManager::currentNM()->mkNode( AND, conf ); |
1741 |
1984 |
Trace("uf-ss-lemma") << "*** Combined cardinality conflict : " << cf |
1742 |
992 |
<< std::endl; |
1743 |
1984 |
Trace("uf-ss-com-card") << "*** Combined cardinality conflict : " << cf |
1744 |
992 |
<< std::endl; |
1745 |
992 |
d_im.conflict(cf, InferenceId::UF_CARD_COMBINED); |
1746 |
|
} |
1747 |
|
} |
1748 |
|
} |
1749 |
|
|
1750 |
271 |
CardinalityExtension::Statistics::Statistics() |
1751 |
271 |
: d_clique_conflicts(smtStatisticsRegistry().registerInt( |
1752 |
542 |
"CardinalityExtension::Clique_Conflicts")), |
1753 |
271 |
d_clique_lemmas(smtStatisticsRegistry().registerInt( |
1754 |
542 |
"CardinalityExtension::Clique_Lemmas")), |
1755 |
271 |
d_split_lemmas(smtStatisticsRegistry().registerInt( |
1756 |
542 |
"CardinalityExtension::Split_Lemmas")), |
1757 |
271 |
d_max_model_size(smtStatisticsRegistry().registerInt( |
1758 |
1084 |
"CardinalityExtension::Max_Model_Size")) |
1759 |
|
{ |
1760 |
271 |
d_max_model_size.maxAssign(1); |
1761 |
271 |
} |
1762 |
|
|
1763 |
|
} // namespace uf |
1764 |
|
} // namespace theory |
1765 |
1325022 |
} // namespace cvc5 |