1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Andres Noetzli, Mathias Preiner |
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 |
|
* Bounded integers module |
14 |
|
* |
15 |
|
* This class manages integer bounds for quantifiers. |
16 |
|
*/ |
17 |
|
|
18 |
|
#include "theory/quantifiers/fmf/bounded_integers.h" |
19 |
|
|
20 |
|
#include "expr/dtype_cons.h" |
21 |
|
#include "expr/node_algorithm.h" |
22 |
|
#include "expr/skolem_manager.h" |
23 |
|
#include "options/quantifiers_options.h" |
24 |
|
#include "theory/arith/arith_msum.h" |
25 |
|
#include "theory/datatypes/theory_datatypes_utils.h" |
26 |
|
#include "theory/decision_manager.h" |
27 |
|
#include "theory/quantifiers/first_order_model.h" |
28 |
|
#include "theory/quantifiers/fmf/model_engine.h" |
29 |
|
#include "theory/quantifiers/term_enumeration.h" |
30 |
|
#include "theory/quantifiers/term_util.h" |
31 |
|
#include "theory/rewriter.h" |
32 |
|
|
33 |
|
using namespace cvc5; |
34 |
|
using namespace std; |
35 |
|
using namespace cvc5::theory; |
36 |
|
using namespace cvc5::theory::quantifiers; |
37 |
|
using namespace cvc5::kind; |
38 |
|
|
39 |
678 |
BoundedIntegers::IntRangeDecisionHeuristic::IntRangeDecisionHeuristic( |
40 |
|
Node r, |
41 |
|
context::Context* c, |
42 |
|
context::Context* u, |
43 |
|
Valuation valuation, |
44 |
678 |
bool isProxy) |
45 |
678 |
: DecisionStrategyFmf(c, valuation), d_range(r), d_ranges_proxied(u) |
46 |
|
{ |
47 |
678 |
if( options::fmfBoundLazy() ){ |
48 |
4 |
SkolemManager* sm = NodeManager::currentNM()->getSkolemManager(); |
49 |
4 |
d_proxy_range = isProxy ? r : sm->mkDummySkolem("pbir", r.getType()); |
50 |
|
}else{ |
51 |
674 |
d_proxy_range = r; |
52 |
|
} |
53 |
678 |
if( !isProxy ){ |
54 |
580 |
Trace("bound-int") << "Introduce proxy " << d_proxy_range << " for " << d_range << std::endl; |
55 |
|
} |
56 |
678 |
} |
57 |
2028 |
Node BoundedIntegers::IntRangeDecisionHeuristic::mkLiteral(unsigned n) |
58 |
|
{ |
59 |
2028 |
NodeManager* nm = NodeManager::currentNM(); |
60 |
4056 |
Node cn = nm->mkConst(Rational(n == 0 ? 0 : n - 1)); |
61 |
4056 |
return nm->mkNode(n == 0 ? LT : LEQ, d_proxy_range, cn); |
62 |
|
} |
63 |
|
|
64 |
1999 |
Node BoundedIntegers::IntRangeDecisionHeuristic::proxyCurrentRangeLemma() |
65 |
|
{ |
66 |
1999 |
if (d_range == d_proxy_range) |
67 |
|
{ |
68 |
1995 |
return Node::null(); |
69 |
|
} |
70 |
4 |
unsigned curr = 0; |
71 |
4 |
if (!getAssertedLiteralIndex(curr)) |
72 |
|
{ |
73 |
|
return Node::null(); |
74 |
|
} |
75 |
4 |
if (d_ranges_proxied.find(curr) != d_ranges_proxied.end()) |
76 |
|
{ |
77 |
|
return Node::null(); |
78 |
|
} |
79 |
4 |
d_ranges_proxied[curr] = true; |
80 |
4 |
NodeManager* nm = NodeManager::currentNM(); |
81 |
8 |
Node currLit = getLiteral(curr); |
82 |
|
Node lem = |
83 |
|
nm->mkNode(EQUAL, |
84 |
|
currLit, |
85 |
8 |
nm->mkNode(curr == 0 ? LT : LEQ, |
86 |
|
d_range, |
87 |
16 |
nm->mkConst(Rational(curr == 0 ? 0 : curr - 1)))); |
88 |
4 |
return lem; |
89 |
|
} |
90 |
|
|
91 |
1211 |
BoundedIntegers::BoundedIntegers(Env& env, |
92 |
|
QuantifiersState& qs, |
93 |
|
QuantifiersInferenceManager& qim, |
94 |
|
QuantifiersRegistry& qr, |
95 |
1211 |
TermRegistry& tr) |
96 |
1211 |
: QuantifiersModule(env, qs, qim, qr, tr) |
97 |
|
{ |
98 |
1211 |
} |
99 |
|
|
100 |
2422 |
BoundedIntegers::~BoundedIntegers() {} |
101 |
|
|
102 |
1360 |
void BoundedIntegers::presolve() { |
103 |
1360 |
d_bnd_it.clear(); |
104 |
1360 |
} |
105 |
|
|
106 |
11550 |
bool BoundedIntegers::hasNonBoundVar( Node f, Node b, std::map< Node, bool >& visited ) { |
107 |
11550 |
if( visited.find( b )==visited.end() ){ |
108 |
10788 |
visited[b] = true; |
109 |
10788 |
if( b.getKind()==BOUND_VARIABLE ){ |
110 |
1167 |
if( !isBound( f, b ) ){ |
111 |
610 |
return true; |
112 |
|
} |
113 |
|
}else{ |
114 |
17041 |
for( unsigned i=0; i<b.getNumChildren(); i++ ){ |
115 |
8256 |
if( hasNonBoundVar( f, b[i], visited ) ){ |
116 |
836 |
return true; |
117 |
|
} |
118 |
|
} |
119 |
|
} |
120 |
|
} |
121 |
10104 |
return false; |
122 |
|
} |
123 |
3294 |
bool BoundedIntegers::hasNonBoundVar( Node f, Node b ) { |
124 |
6588 |
std::map< Node, bool > visited; |
125 |
6588 |
return hasNonBoundVar( f, b, visited ); |
126 |
|
} |
127 |
|
|
128 |
751 |
bool BoundedIntegers::processEqDisjunct( Node q, Node n, Node& v, std::vector< Node >& v_cases ) { |
129 |
751 |
if( n.getKind()==EQUAL ){ |
130 |
2171 |
for( unsigned i=0; i<2; i++ ){ |
131 |
2894 |
Node t = n[i]; |
132 |
1474 |
if( !hasNonBoundVar( q, n[1-i] ) ){ |
133 |
1054 |
if( t==v ){ |
134 |
24 |
v_cases.push_back( n[1-i] ); |
135 |
24 |
return true; |
136 |
1030 |
}else if( v.isNull() && t.getKind()==BOUND_VARIABLE ){ |
137 |
30 |
v = t; |
138 |
30 |
v_cases.push_back( n[1-i] ); |
139 |
30 |
return true; |
140 |
|
} |
141 |
|
} |
142 |
|
} |
143 |
|
} |
144 |
697 |
return false; |
145 |
|
} |
146 |
|
|
147 |
112 |
void BoundedIntegers::processMatchBoundVars( Node q, Node n, std::vector< Node >& bvs, std::map< Node, bool >& visited ){ |
148 |
112 |
if( visited.find( n )==visited.end() ){ |
149 |
112 |
visited[n] = true; |
150 |
112 |
if( n.getKind()==BOUND_VARIABLE && !isBound( q, n ) ){ |
151 |
43 |
bvs.push_back( n ); |
152 |
|
//injective operators |
153 |
69 |
}else if( n.getKind()==kind::APPLY_CONSTRUCTOR ){ |
154 |
60 |
for( unsigned i=0; i<n.getNumChildren(); i++ ){ |
155 |
36 |
processMatchBoundVars( q, n[i], bvs, visited ); |
156 |
|
} |
157 |
|
} |
158 |
|
} |
159 |
112 |
} |
160 |
|
|
161 |
10188 |
void BoundedIntegers::process( Node q, Node n, bool pol, |
162 |
|
std::map< Node, unsigned >& bound_lit_type_map, |
163 |
|
std::map< int, std::map< Node, Node > >& bound_lit_map, |
164 |
|
std::map< int, std::map< Node, bool > >& bound_lit_pol_map, |
165 |
|
std::map< int, std::map< Node, Node > >& bound_int_range_term, |
166 |
|
std::map< Node, std::vector< Node > >& bound_fixed_set ){ |
167 |
10188 |
if( n.getKind()==OR || n.getKind()==AND ){ |
168 |
1850 |
if( (n.getKind()==OR)==pol ){ |
169 |
7043 |
for( unsigned i=0; i<n.getNumChildren(); i++) { |
170 |
5543 |
process( q, n[i], pol, bound_lit_type_map, bound_lit_map, bound_lit_pol_map, bound_int_range_term, bound_fixed_set ); |
171 |
|
} |
172 |
|
}else{ |
173 |
|
//if we are ( x != t1 ^ ...^ x != tn ), then x can be bound to { t1...tn } |
174 |
700 |
Node conj = n; |
175 |
350 |
if( !pol ){ |
176 |
|
conj = TermUtil::simpleNegate( conj ); |
177 |
|
} |
178 |
350 |
Trace("bound-int-debug") << "Process possible finite disequality conjunction : " << conj << std::endl; |
179 |
350 |
Assert(conj.getKind() == AND); |
180 |
700 |
Node v; |
181 |
700 |
std::vector< Node > v_cases; |
182 |
350 |
bool success = true; |
183 |
400 |
for( unsigned i=0; i<conj.getNumChildren(); i++ ){ |
184 |
376 |
if( conj[i].getKind()==NOT && processEqDisjunct( q, conj[i][0], v, v_cases ) ){ |
185 |
|
//continue |
186 |
|
}else{ |
187 |
326 |
Trace("bound-int-debug") << "...failed due to " << conj[i] << std::endl; |
188 |
326 |
success = false; |
189 |
326 |
break; |
190 |
|
} |
191 |
|
} |
192 |
350 |
if( success && !isBound( q, v ) ){ |
193 |
10 |
Trace("bound-int-debug") << "Success with variable " << v << std::endl; |
194 |
10 |
bound_lit_type_map[v] = BOUND_FIXED_SET; |
195 |
10 |
bound_lit_map[3][v] = n; |
196 |
10 |
bound_lit_pol_map[3][v] = pol; |
197 |
10 |
bound_fixed_set[v].clear(); |
198 |
10 |
bound_fixed_set[v].insert( bound_fixed_set[v].end(), v_cases.begin(), v_cases.end() ); |
199 |
|
} |
200 |
|
} |
201 |
8338 |
}else if( n.getKind()==EQUAL ){ |
202 |
1233 |
if( !pol ){ |
203 |
|
// non-applied DER on x != t, x can be bound to { t } |
204 |
1290 |
Node v; |
205 |
1290 |
std::vector< Node > v_cases; |
206 |
645 |
if( processEqDisjunct( q, n, v, v_cases ) ){ |
207 |
4 |
if( !isBound( q, v ) ){ |
208 |
2 |
bound_lit_type_map[v] = BOUND_FIXED_SET; |
209 |
2 |
bound_lit_map[3][v] = n; |
210 |
2 |
bound_lit_pol_map[3][v] = pol; |
211 |
2 |
Assert(v_cases.size() == 1); |
212 |
2 |
bound_fixed_set[v].clear(); |
213 |
2 |
bound_fixed_set[v].push_back( v_cases[0] ); |
214 |
|
} |
215 |
|
} |
216 |
|
} |
217 |
7105 |
}else if( n.getKind()==NOT ){ |
218 |
2989 |
process( q, n[0], !pol, bound_lit_type_map, bound_lit_map, bound_lit_pol_map, bound_int_range_term, bound_fixed_set ); |
219 |
4116 |
}else if( n.getKind()==GEQ ){ |
220 |
3414 |
if( n[0].getType().isInteger() ){ |
221 |
6828 |
std::map< Node, Node > msum; |
222 |
3414 |
if (ArithMSum::getMonomialSumLit(n, msum)) |
223 |
|
{ |
224 |
3414 |
Trace("bound-int-debug") << "literal (polarity = " << pol << ") " << n << " is monomial sum : " << std::endl; |
225 |
3414 |
ArithMSum::debugPrintMonomialSum(msum, "bound-int-debug"); |
226 |
10564 |
for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){ |
227 |
7150 |
if ( !it->first.isNull() && it->first.getKind()==BOUND_VARIABLE && !isBound( q, it->first ) ){ |
228 |
|
//if not bound in another way |
229 |
1745 |
if( bound_lit_type_map.find( it->first )==bound_lit_type_map.end() || bound_lit_type_map[it->first] == BOUND_INT_RANGE ){ |
230 |
3480 |
Node veq; |
231 |
1740 |
if (ArithMSum::isolate(it->first, msum, veq, GEQ) != 0) |
232 |
|
{ |
233 |
3480 |
Node n1 = veq[0]; |
234 |
3480 |
Node n2 = veq[1]; |
235 |
1740 |
if(pol){ |
236 |
|
//flip |
237 |
863 |
n1 = veq[1]; |
238 |
863 |
n2 = veq[0]; |
239 |
863 |
if( n1.getKind()==BOUND_VARIABLE ){ |
240 |
2 |
n2 = ArithMSum::offset(n2, 1); |
241 |
|
}else{ |
242 |
861 |
n1 = ArithMSum::offset(n1, -1); |
243 |
|
} |
244 |
863 |
veq = NodeManager::currentNM()->mkNode( GEQ, n1, n2 ); |
245 |
|
} |
246 |
1740 |
Trace("bound-int-debug") << "Isolated for " << it->first << " : (" << n1 << " >= " << n2 << ")" << std::endl; |
247 |
3480 |
Node t = n1==it->first ? n2 : n1; |
248 |
1740 |
if( !hasNonBoundVar( q, t ) ) { |
249 |
1554 |
Trace("bound-int-debug") << "The bound is relevant." << std::endl; |
250 |
1554 |
int loru = n1==it->first ? 0 : 1; |
251 |
1554 |
bound_lit_type_map[it->first] = BOUND_INT_RANGE; |
252 |
1554 |
bound_int_range_term[loru][it->first] = t; |
253 |
1554 |
bound_lit_map[loru][it->first] = n; |
254 |
1554 |
bound_lit_pol_map[loru][it->first] = pol; |
255 |
|
}else{ |
256 |
186 |
Trace("bound-int-debug") << "The term " << t << " has non-bound variable." << std::endl; |
257 |
|
} |
258 |
|
} |
259 |
|
} |
260 |
|
} |
261 |
|
} |
262 |
|
} |
263 |
|
} |
264 |
702 |
}else if( n.getKind()==MEMBER ){ |
265 |
80 |
if( !pol && !hasNonBoundVar( q, n[1] ) ){ |
266 |
152 |
std::vector< Node > bound_vars; |
267 |
152 |
std::map< Node, bool > visited; |
268 |
76 |
processMatchBoundVars( q, n[0], bound_vars, visited ); |
269 |
119 |
for( unsigned i=0; i<bound_vars.size(); i++ ){ |
270 |
86 |
Node v = bound_vars[i]; |
271 |
43 |
Trace("bound-int-debug") << "literal (polarity = " << pol << ") " << n << " is membership." << std::endl; |
272 |
43 |
bound_lit_type_map[v] = BOUND_SET_MEMBER; |
273 |
43 |
bound_lit_map[2][v] = n; |
274 |
43 |
bound_lit_pol_map[2][v] = pol; |
275 |
|
} |
276 |
|
} |
277 |
|
}else{ |
278 |
622 |
Assert(n.getKind() != LEQ && n.getKind() != LT && n.getKind() != GT); |
279 |
|
} |
280 |
10188 |
} |
281 |
|
|
282 |
14581 |
bool BoundedIntegers::needsCheck( Theory::Effort e ) { |
283 |
14581 |
return e==Theory::EFFORT_LAST_CALL; |
284 |
|
} |
285 |
|
|
286 |
3329 |
void BoundedIntegers::check(Theory::Effort e, QEffort quant_e) |
287 |
|
{ |
288 |
3329 |
if (quant_e != QEFFORT_STANDARD) |
289 |
|
{ |
290 |
2220 |
return; |
291 |
|
} |
292 |
1109 |
Trace("bint-engine") << "---Bounded Integers---" << std::endl; |
293 |
1109 |
bool addedLemma = false; |
294 |
|
// make sure proxies are up-to-date with range |
295 |
3108 |
for (const Node& r : d_ranges) |
296 |
|
{ |
297 |
3998 |
Node prangeLem = d_rms[r]->proxyCurrentRangeLemma(); |
298 |
1999 |
if (!prangeLem.isNull()) |
299 |
|
{ |
300 |
8 |
Trace("bound-int-lemma") |
301 |
4 |
<< "*** bound int : proxy lemma : " << prangeLem << std::endl; |
302 |
4 |
d_qim.addPendingLemma(prangeLem, InferenceId::QUANTIFIERS_BINT_PROXY); |
303 |
4 |
addedLemma = true; |
304 |
|
} |
305 |
|
} |
306 |
1109 |
Trace("bint-engine") << " addedLemma = " << addedLemma << std::endl; |
307 |
|
} |
308 |
904 |
void BoundedIntegers::setBoundedVar(Node q, Node v, BoundVarType bound_type) |
309 |
|
{ |
310 |
904 |
d_bound_type[q][v] = bound_type; |
311 |
904 |
d_set_nums[q][v] = d_set[q].size(); |
312 |
904 |
d_set[q].push_back( v ); |
313 |
1808 |
Trace("bound-int-var") << "Bound variable #" << d_set_nums[q][v] << " : " << v |
314 |
904 |
<< std::endl; |
315 |
904 |
} |
316 |
|
|
317 |
881 |
void BoundedIntegers::checkOwnership(Node f) |
318 |
|
{ |
319 |
|
//this needs to be done at preregister since it affects e.g. QuantDSplit's preregister |
320 |
881 |
Trace("bound-int") << "check ownership quantifier " << f << std::endl; |
321 |
|
|
322 |
|
// determine if we should look at the quantified formula at all |
323 |
881 |
if (!options::fmfBound()) |
324 |
|
{ |
325 |
|
// only applying it to internal quantifiers |
326 |
684 |
QuantAttributes& qattr = d_qreg.getQuantAttributes(); |
327 |
684 |
if (!qattr.isInternal(f)) |
328 |
|
{ |
329 |
113 |
Trace("bound-int") << "...not internal, skip" << std::endl; |
330 |
113 |
return; |
331 |
|
} |
332 |
|
} |
333 |
|
|
334 |
768 |
NodeManager* nm = NodeManager::currentNM(); |
335 |
768 |
SkolemManager* sm = nm->getSkolemManager(); |
336 |
|
|
337 |
|
bool success; |
338 |
1656 |
do{ |
339 |
3312 |
std::map< Node, unsigned > bound_lit_type_map; |
340 |
3312 |
std::map< int, std::map< Node, Node > > bound_lit_map; |
341 |
3312 |
std::map< int, std::map< Node, bool > > bound_lit_pol_map; |
342 |
3312 |
std::map< int, std::map< Node, Node > > bound_int_range_term; |
343 |
3312 |
std::map< Node, std::vector< Node > > bound_fixed_set; |
344 |
1656 |
success = false; |
345 |
1656 |
process( f, f[1], true, bound_lit_type_map, bound_lit_map, bound_lit_pol_map, bound_int_range_term, bound_fixed_set ); |
346 |
|
//for( std::map< Node, Node >::iterator it = d_bounds[0][f].begin(); it != d_bounds[0][f].end(); ++it ){ |
347 |
2516 |
for( std::map< Node, unsigned >::iterator it = bound_lit_type_map.begin(); it != bound_lit_type_map.end(); ++it ){ |
348 |
1720 |
Node v = it->first; |
349 |
860 |
if( !isBound( f, v ) ){ |
350 |
860 |
bool setBoundVar = false; |
351 |
860 |
if( it->second==BOUND_INT_RANGE ){ |
352 |
|
//must have both |
353 |
813 |
std::map<Node, Node>& blm0 = bound_lit_map[0]; |
354 |
813 |
std::map<Node, Node>& blm1 = bound_lit_map[1]; |
355 |
813 |
if (blm0.find(v) != blm0.end() && blm1.find(v) != blm1.end()) |
356 |
|
{ |
357 |
715 |
setBoundedVar( f, v, BOUND_INT_RANGE ); |
358 |
715 |
setBoundVar = true; |
359 |
2145 |
for( unsigned b=0; b<2; b++ ){ |
360 |
|
//set the bounds |
361 |
1430 |
Assert(bound_int_range_term[b].find(v) |
362 |
|
!= bound_int_range_term[b].end()); |
363 |
1430 |
d_bounds[b][f][v] = bound_int_range_term[b][v]; |
364 |
|
} |
365 |
1430 |
Node r = nm->mkNode(MINUS, d_bounds[1][f][v], d_bounds[0][f][v]); |
366 |
715 |
d_range[f][v] = Rewriter::rewrite(r); |
367 |
715 |
Trace("bound-int") << "Variable " << v << " is bound because of int range literals " << bound_lit_map[0][v] << " and " << bound_lit_map[1][v] << std::endl; |
368 |
|
} |
369 |
47 |
}else if( it->second==BOUND_SET_MEMBER ){ |
370 |
|
// only handles infinite element types currently (cardinality is not |
371 |
|
// supported for finite element types #1123). Regardless, this is |
372 |
|
// typically not a limitation since this variable can be bound in a |
373 |
|
// standard way below since its type is finite. |
374 |
35 |
if (!d_qstate.isFiniteType(v.getType())) |
375 |
|
{ |
376 |
35 |
setBoundedVar(f, v, BOUND_SET_MEMBER); |
377 |
35 |
setBoundVar = true; |
378 |
35 |
d_setm_range[f][v] = bound_lit_map[2][v][1]; |
379 |
35 |
d_setm_range_lit[f][v] = bound_lit_map[2][v]; |
380 |
35 |
d_range[f][v] = nm->mkNode(CARD, d_setm_range[f][v]); |
381 |
70 |
Trace("bound-int") << "Variable " << v |
382 |
35 |
<< " is bound because of set membership literal " |
383 |
35 |
<< bound_lit_map[2][v] << std::endl; |
384 |
|
} |
385 |
12 |
}else if( it->second==BOUND_FIXED_SET ){ |
386 |
12 |
setBoundedVar(f, v, BOUND_FIXED_SET); |
387 |
12 |
setBoundVar = true; |
388 |
34 |
for (unsigned i = 0; i < bound_fixed_set[v].size(); i++) |
389 |
|
{ |
390 |
44 |
Node t = bound_fixed_set[v][i]; |
391 |
22 |
if (expr::hasBoundVar(t)) |
392 |
|
{ |
393 |
6 |
d_fixed_set_ngr_range[f][v].push_back(t); |
394 |
|
} |
395 |
|
else |
396 |
|
{ |
397 |
16 |
d_fixed_set_gr_range[f][v].push_back(t); |
398 |
|
} |
399 |
|
} |
400 |
24 |
Trace("bound-int") << "Variable " << v |
401 |
12 |
<< " is bound because of disequality conjunction " |
402 |
12 |
<< bound_lit_map[3][v] << std::endl; |
403 |
|
} |
404 |
860 |
if( setBoundVar ){ |
405 |
762 |
success = true; |
406 |
|
//set Attributes on literals |
407 |
2286 |
for( unsigned b=0; b<2; b++ ){ |
408 |
1524 |
std::map<Node, Node>& blm = bound_lit_map[b]; |
409 |
1524 |
if (blm.find(v) != blm.end()) |
410 |
|
{ |
411 |
1430 |
std::map<Node, bool>& blmp = bound_lit_pol_map[b]; |
412 |
|
// WARNING_CANDIDATE: |
413 |
|
// This assertion may fail. We intentionally do not enable this in |
414 |
|
// production as it is considered safe for this to fail. We fail |
415 |
|
// the assertion in debug mode to have this instance raised to |
416 |
|
// our attention. |
417 |
1430 |
Assert(blmp.find(v) != blmp.end()); |
418 |
|
BoundIntLitAttribute bila; |
419 |
1430 |
bound_lit_map[b][v].setAttribute(bila, blmp[v] ? 1 : 0); |
420 |
|
} |
421 |
|
else |
422 |
|
{ |
423 |
94 |
Assert(it->second != BOUND_INT_RANGE); |
424 |
|
} |
425 |
|
} |
426 |
|
} |
427 |
|
} |
428 |
|
} |
429 |
1656 |
if( !success ){ |
430 |
|
//resort to setting a finite bound on a variable |
431 |
1858 |
for( unsigned i=0; i<f[0].getNumChildren(); i++) { |
432 |
1090 |
if( d_bound_type[f].find( f[0][i] )==d_bound_type[f].end() ){ |
433 |
178 |
TypeNode tn = f[0][i].getType(); |
434 |
370 |
if ((tn.isSort() && d_qstate.isFiniteType(tn)) |
435 |
436 |
|| d_qreg.getQuantifiersBoundInference().mayComplete(tn)) |
436 |
|
{ |
437 |
142 |
success = true; |
438 |
142 |
setBoundedVar( f, f[0][i], BOUND_FINITE ); |
439 |
142 |
break; |
440 |
|
} |
441 |
|
} |
442 |
|
} |
443 |
|
} |
444 |
|
}while( success ); |
445 |
|
|
446 |
768 |
if( Trace.isOn("bound-int") ){ |
447 |
|
Trace("bound-int") << "Bounds are : " << std::endl; |
448 |
|
for( unsigned i=0; i<f[0].getNumChildren(); i++) { |
449 |
|
Node v = f[0][i]; |
450 |
|
if( std::find( d_set[f].begin(), d_set[f].end(), v )!=d_set[f].end() ){ |
451 |
|
Assert(d_bound_type[f].find(v) != d_bound_type[f].end()); |
452 |
|
if( d_bound_type[f][v]==BOUND_INT_RANGE ){ |
453 |
|
Trace("bound-int") << " " << d_bounds[0][f][v] << " <= " << v << " <= " << d_bounds[1][f][v] << " (range is " << d_range[f][v] << ")" << std::endl; |
454 |
|
}else if( d_bound_type[f][v]==BOUND_SET_MEMBER ){ |
455 |
|
if( d_setm_range_lit[f][v][0]==v ){ |
456 |
|
Trace("bound-int") << " " << v << " in " << d_setm_range[f][v] << std::endl; |
457 |
|
}else{ |
458 |
|
Trace("bound-int") << " " << v << " unifiable in " << d_setm_range_lit[f][v] << std::endl; |
459 |
|
} |
460 |
|
}else if( d_bound_type[f][v]==BOUND_FIXED_SET ){ |
461 |
|
Trace("bound-int") << " " << v << " in { "; |
462 |
|
for (TNode fnr : d_fixed_set_ngr_range[f][v]) |
463 |
|
{ |
464 |
|
Trace("bound-int") << fnr << " "; |
465 |
|
} |
466 |
|
for (TNode fgr : d_fixed_set_gr_range[f][v]) |
467 |
|
{ |
468 |
|
Trace("bound-int") << fgr << " "; |
469 |
|
} |
470 |
|
Trace("bound-int") << "}" << std::endl; |
471 |
|
}else if( d_bound_type[f][v]==BOUND_FINITE ){ |
472 |
|
Trace("bound-int") << " " << v << " has small finite type." << std::endl; |
473 |
|
}else{ |
474 |
|
Trace("bound-int") << " " << v << " has unknown bound." << std::endl; |
475 |
|
Assert(false); |
476 |
|
} |
477 |
|
}else{ |
478 |
|
Trace("bound-int") << " " << "*** " << v << " is unbounded." << std::endl; |
479 |
|
} |
480 |
|
} |
481 |
|
} |
482 |
|
|
483 |
768 |
bool bound_success = true; |
484 |
1670 |
for( unsigned i=0; i<f[0].getNumChildren(); i++) { |
485 |
914 |
if( d_bound_type[f].find( f[0][i] )==d_bound_type[f].end() ){ |
486 |
12 |
Trace("bound-int-warn") << "Warning : Bounded Integers : Due to quantification on " << f[0][i] << ", could not find bounds for " << f << std::endl; |
487 |
12 |
bound_success = false; |
488 |
12 |
break; |
489 |
|
} |
490 |
|
} |
491 |
|
|
492 |
768 |
if( bound_success ){ |
493 |
756 |
d_bound_quants.push_back( f ); |
494 |
756 |
DecisionManager* dm = d_qim.getDecisionManager(); |
495 |
1658 |
for( unsigned i=0; i<d_set[f].size(); i++) { |
496 |
1804 |
Node v = d_set[f][i]; |
497 |
902 |
std::map< Node, Node >::iterator itr = d_range[f].find( v ); |
498 |
902 |
if( itr != d_range[f].end() ){ |
499 |
1496 |
Node r = itr->second; |
500 |
748 |
Assert(!r.isNull()); |
501 |
748 |
bool isProxy = false; |
502 |
748 |
if (expr::hasBoundVar(r)) |
503 |
|
{ |
504 |
|
// introduce a new bound |
505 |
|
Node new_range = |
506 |
196 |
sm->mkDummySkolem("bir", r.getType(), "bound for term"); |
507 |
98 |
d_nground_range[f][v] = r; |
508 |
98 |
d_range[f][v] = new_range; |
509 |
98 |
r = new_range; |
510 |
98 |
isProxy = true; |
511 |
|
} |
512 |
748 |
if( !r.isConst() ){ |
513 |
708 |
if (d_rms.find(r) == d_rms.end()) |
514 |
|
{ |
515 |
678 |
Trace("bound-int") << "For " << v << ", bounded Integer Module will try to minimize : " << r << std::endl; |
516 |
678 |
d_ranges.push_back( r ); |
517 |
2034 |
d_rms[r].reset( |
518 |
|
new IntRangeDecisionHeuristic(r, |
519 |
678 |
d_qstate.getSatContext(), |
520 |
678 |
d_qstate.getUserContext(), |
521 |
678 |
d_qstate.getValuation(), |
522 |
678 |
isProxy)); |
523 |
678 |
dm->registerStrategy(DecisionManager::STRAT_QUANT_BOUND_INT_SIZE, |
524 |
678 |
d_rms[r].get()); |
525 |
|
} |
526 |
|
} |
527 |
|
} |
528 |
|
} |
529 |
|
} |
530 |
|
} |
531 |
|
|
532 |
6691 |
bool BoundedIntegers::isBound(Node q, Node v) const |
533 |
|
{ |
534 |
6691 |
std::map<Node, std::vector<Node> >::const_iterator its = d_set.find(q); |
535 |
6691 |
if (its == d_set.end()) |
536 |
|
{ |
537 |
2823 |
return false; |
538 |
|
} |
539 |
7736 |
return std::find(its->second.begin(), its->second.end(), v) |
540 |
11604 |
!= its->second.end(); |
541 |
|
} |
542 |
|
|
543 |
6941 |
BoundVarType BoundedIntegers::getBoundVarType(Node q, Node v) const |
544 |
|
{ |
545 |
|
std::map<Node, std::map<Node, BoundVarType> >::const_iterator itb = |
546 |
6941 |
d_bound_type.find(q); |
547 |
6941 |
if (itb == d_bound_type.end()) |
548 |
|
{ |
549 |
|
return BOUND_NONE; |
550 |
|
} |
551 |
6941 |
std::map<Node, BoundVarType>::const_iterator it = itb->second.find(v); |
552 |
6941 |
if (it == itb->second.end()) |
553 |
|
{ |
554 |
14 |
return BOUND_NONE; |
555 |
|
} |
556 |
6927 |
return it->second; |
557 |
|
} |
558 |
|
|
559 |
4475 |
void BoundedIntegers::getBoundVarIndices(Node q, |
560 |
|
std::vector<unsigned>& indices) const |
561 |
|
{ |
562 |
4475 |
std::map<Node, std::vector<Node> >::const_iterator it = d_set.find(q); |
563 |
4475 |
if (it != d_set.end()) |
564 |
|
{ |
565 |
10233 |
for (const Node& v : it->second) |
566 |
|
{ |
567 |
5816 |
indices.push_back(TermUtil::getVariableNum(q, v)); |
568 |
|
} |
569 |
|
} |
570 |
4475 |
} |
571 |
|
|
572 |
4743 |
void BoundedIntegers::getBounds( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u ) { |
573 |
4743 |
l = d_bounds[0][f][v]; |
574 |
4743 |
u = d_bounds[1][f][v]; |
575 |
4743 |
if( d_nground_range[f].find(v)!=d_nground_range[f].end() ){ |
576 |
|
//get the substitution |
577 |
2790 |
std::vector< Node > vars; |
578 |
2790 |
std::vector< Node > subs; |
579 |
1395 |
if( getRsiSubsitution( f, v, vars, subs, rsi ) ){ |
580 |
1320 |
u = u.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); |
581 |
1320 |
l = l.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); |
582 |
|
}else{ |
583 |
75 |
u = Node::null(); |
584 |
75 |
l = Node::null(); |
585 |
|
} |
586 |
|
} |
587 |
4743 |
} |
588 |
|
|
589 |
2409 |
void BoundedIntegers::getBoundValues( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u ) { |
590 |
2409 |
getBounds( f, v, rsi, l, u ); |
591 |
2409 |
Trace("bound-int-rsi") << "Get value in model for..." << l << " and " << u << std::endl; |
592 |
2409 |
if( !l.isNull() ){ |
593 |
2334 |
l = d_treg.getModel()->getValue(l); |
594 |
|
} |
595 |
2409 |
if( !u.isNull() ){ |
596 |
2334 |
u = d_treg.getModel()->getValue(u); |
597 |
|
} |
598 |
2409 |
Trace("bound-int-rsi") << "Value is " << l << " ... " << u << std::endl; |
599 |
2409 |
return; |
600 |
|
} |
601 |
|
|
602 |
794 |
bool BoundedIntegers::isGroundRange(Node q, Node v) |
603 |
|
{ |
604 |
794 |
if (isBound(q, v)) |
605 |
|
{ |
606 |
794 |
if (d_bound_type[q][v] == BOUND_INT_RANGE) |
607 |
|
{ |
608 |
1950 |
return !expr::hasBoundVar(getLowerBound(q, v)) |
609 |
1950 |
&& !expr::hasBoundVar(getUpperBound(q, v)); |
610 |
|
} |
611 |
144 |
else if (d_bound_type[q][v] == BOUND_SET_MEMBER) |
612 |
|
{ |
613 |
12 |
return !expr::hasBoundVar(d_setm_range[q][v]); |
614 |
|
} |
615 |
132 |
else if (d_bound_type[q][v] == BOUND_FIXED_SET) |
616 |
|
{ |
617 |
132 |
return !d_fixed_set_ngr_range[q][v].empty(); |
618 |
|
} |
619 |
|
} |
620 |
|
return false; |
621 |
|
} |
622 |
|
|
623 |
70 |
Node BoundedIntegers::getSetRange( Node q, Node v, RepSetIterator * rsi ) { |
624 |
70 |
Node sr = d_setm_range[q][v]; |
625 |
70 |
if( d_nground_range[q].find(v)!=d_nground_range[q].end() ){ |
626 |
16 |
Trace("bound-int-rsi-debug") |
627 |
8 |
<< sr << " is non-ground, apply substitution..." << std::endl; |
628 |
|
//get the substitution |
629 |
16 |
std::vector< Node > vars; |
630 |
16 |
std::vector< Node > subs; |
631 |
8 |
if( getRsiSubsitution( q, v, vars, subs, rsi ) ){ |
632 |
8 |
Trace("bound-int-rsi-debug") |
633 |
4 |
<< " apply " << vars << " -> " << subs << std::endl; |
634 |
4 |
sr = sr.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); |
635 |
|
}else{ |
636 |
4 |
sr = Node::null(); |
637 |
|
} |
638 |
|
} |
639 |
70 |
return sr; |
640 |
|
} |
641 |
|
|
642 |
70 |
Node BoundedIntegers::getSetRangeValue( Node q, Node v, RepSetIterator * rsi ) { |
643 |
140 |
Node sr = getSetRange( q, v, rsi ); |
644 |
70 |
if (sr.isNull()) |
645 |
|
{ |
646 |
4 |
return sr; |
647 |
|
} |
648 |
66 |
Trace("bound-int-rsi") << "Get value in model for..." << sr << std::endl; |
649 |
66 |
Assert(!expr::hasFreeVar(sr)); |
650 |
132 |
Node sro = sr; |
651 |
66 |
sr = d_treg.getModel()->getValue(sr); |
652 |
|
// if non-constant, then sr does not occur in the model, we fail |
653 |
66 |
if (!sr.isConst()) |
654 |
|
{ |
655 |
|
return Node::null(); |
656 |
|
} |
657 |
66 |
Trace("bound-int-rsi") << "Value is " << sr << std::endl; |
658 |
66 |
if (sr.getKind() == EMPTYSET) |
659 |
|
{ |
660 |
2 |
return sr; |
661 |
|
} |
662 |
64 |
NodeManager* nm = NodeManager::currentNM(); |
663 |
128 |
Node nsr; |
664 |
128 |
TypeNode tne = sr.getType().getSetElementType(); |
665 |
|
|
666 |
|
// we can use choice functions for canonical symbolic instantiations |
667 |
64 |
unsigned srCard = 0; |
668 |
128 |
while (sr.getKind() == UNION) |
669 |
|
{ |
670 |
32 |
srCard++; |
671 |
32 |
sr = sr[0]; |
672 |
|
} |
673 |
64 |
Assert(sr.getKind() == SINGLETON); |
674 |
64 |
srCard++; |
675 |
|
// choices[i] stores the canonical symbolic representation of the (i+1)^th |
676 |
|
// element of sro |
677 |
128 |
std::vector<Node> choices; |
678 |
128 |
Node srCardN = nm->mkNode(CARD, sro); |
679 |
128 |
Node choice_i; |
680 |
160 |
for (unsigned i = 0; i < srCard; i++) |
681 |
|
{ |
682 |
96 |
if (i == d_setm_choice[sro].size()) |
683 |
|
{ |
684 |
38 |
choice_i = nm->mkBoundVar(tne); |
685 |
38 |
choices.push_back(choice_i); |
686 |
76 |
Node cBody = nm->mkNode(MEMBER, choice_i, sro); |
687 |
38 |
if (choices.size() > 1) |
688 |
|
{ |
689 |
14 |
cBody = nm->mkNode(AND, cBody, nm->mkNode(DISTINCT, choices)); |
690 |
|
} |
691 |
38 |
choices.pop_back(); |
692 |
76 |
Node bvl = nm->mkNode(BOUND_VAR_LIST, choice_i); |
693 |
76 |
Node cMinCard = nm->mkNode(LEQ, srCardN, nm->mkConst(Rational(i))); |
694 |
38 |
choice_i = nm->mkNode(WITNESS, bvl, nm->mkNode(OR, cMinCard, cBody)); |
695 |
38 |
d_setm_choice[sro].push_back(choice_i); |
696 |
|
} |
697 |
96 |
Assert(i < d_setm_choice[sro].size()); |
698 |
96 |
choice_i = d_setm_choice[sro][i]; |
699 |
96 |
choices.push_back(choice_i); |
700 |
192 |
Node sChoiceI = nm->mkSingleton(choice_i.getType(), choice_i); |
701 |
96 |
if (nsr.isNull()) |
702 |
|
{ |
703 |
64 |
nsr = sChoiceI; |
704 |
|
} |
705 |
|
else |
706 |
|
{ |
707 |
32 |
nsr = nm->mkNode(UNION, nsr, sChoiceI); |
708 |
|
} |
709 |
|
} |
710 |
|
// turns the concrete model value of sro into a canonical representation |
711 |
|
// e.g. |
712 |
|
// singleton(0) union singleton(1) |
713 |
|
// becomes |
714 |
|
// C1 union ( witness y. card(S)<=1 OR ( y in S AND distinct( y, C1 ) ) ) |
715 |
|
// where C1 = ( witness x. card(S)<=0 OR x in S ). |
716 |
64 |
Trace("bound-int-rsi") << "...reconstructed " << nsr << std::endl; |
717 |
64 |
return nsr; |
718 |
|
} |
719 |
|
|
720 |
1455 |
bool BoundedIntegers::getRsiSubsitution( Node q, Node v, std::vector< Node >& vars, std::vector< Node >& subs, RepSetIterator * rsi ) { |
721 |
|
|
722 |
1455 |
Trace("bound-int-rsi") << "Get bound value in model of variable " << v << std::endl; |
723 |
1455 |
Assert(d_set_nums[q].find(v) != d_set_nums[q].end()); |
724 |
1455 |
int vindex = d_set_nums[q][v]; |
725 |
1455 |
Assert(d_set_nums[q][v] == vindex); |
726 |
1455 |
Trace("bound-int-rsi-debug") << " index order is " << vindex << std::endl; |
727 |
|
//must take substitution for all variables that are iterating at higher level |
728 |
3190 |
for( int i=0; i<vindex; i++) { |
729 |
1735 |
Assert(d_set_nums[q][d_set[q][i]] == i); |
730 |
1735 |
Trace("bound-int-rsi") << "Look up the value for " << d_set[q][i] << " " << i << std::endl; |
731 |
1735 |
int vo = rsi->getVariableOrder(i); |
732 |
1735 |
Assert(q[0][vo] == d_set[q][i]); |
733 |
3470 |
TypeNode tn = d_set[q][i].getType(); |
734 |
|
// If the type of tn is not closed enumerable, we must map the value back |
735 |
|
// to a term that appears in the same equivalence class as the constant. |
736 |
|
// Notice that this is to ensure that unhandled values (e.g. uninterpreted |
737 |
|
// constants, datatype values) do not enter instantiations/lemmas, which |
738 |
|
// can lead to refutation unsoundness. However, it is important that we |
739 |
|
// conversely do *not* map terms to values in other cases. In particular, |
740 |
|
// replacing a constant c with a term t can lead to solution unsoundness |
741 |
|
// if we are instantiating a quantified formula that corresponds to a |
742 |
|
// reduction for t, since then the reduction is using circular reasoning: |
743 |
|
// the current value of t is being used to reason about the range of |
744 |
|
// its axiomatization. This is limited to reductions in the theory of |
745 |
|
// strings, which use quantification on integers only. Note this |
746 |
|
// impacts only quantified formulas with 2+ dimensions and dependencies |
747 |
|
// between dimensions, e.g. str.indexof_re reduction. |
748 |
3470 |
Node t = rsi->getCurrentTerm(vo, !tn.isClosedEnumerable()); |
749 |
1735 |
Trace("bound-int-rsi") << "term : " << t << std::endl; |
750 |
1735 |
vars.push_back( d_set[q][i] ); |
751 |
1735 |
subs.push_back( t ); |
752 |
|
} |
753 |
|
|
754 |
|
//check if it has been instantiated |
755 |
1455 |
if( !vars.empty() && !d_bnd_it[q][v].hasInstantiated(subs) ){ |
756 |
87 |
if( d_bound_type[q][v]==BOUND_INT_RANGE || d_bound_type[q][v]==BOUND_SET_MEMBER ){ |
757 |
|
//must add the lemma |
758 |
158 |
Node nn = d_nground_range[q][v]; |
759 |
79 |
nn = nn.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); |
760 |
158 |
Node lem = NodeManager::currentNM()->mkNode( LEQ, nn, d_range[q][v] ); |
761 |
79 |
Trace("bound-int-lemma") << "*** Add lemma to minimize instantiated non-ground term " << lem << std::endl; |
762 |
79 |
d_qim.lemma(lem, InferenceId::QUANTIFIERS_BINT_MIN_NG); |
763 |
|
} |
764 |
87 |
return false; |
765 |
|
}else{ |
766 |
1368 |
return true; |
767 |
|
} |
768 |
|
} |
769 |
|
|
770 |
80 |
Node BoundedIntegers::matchBoundVar( Node v, Node t, Node e ){ |
771 |
80 |
if( t==v ){ |
772 |
32 |
return e; |
773 |
48 |
}else if( t.getKind()==kind::APPLY_CONSTRUCTOR ){ |
774 |
32 |
if( e.getKind()==kind::APPLY_CONSTRUCTOR ){ |
775 |
|
if( t.getOperator() != e.getOperator() ) { |
776 |
|
return Node::null(); |
777 |
|
} |
778 |
|
} |
779 |
32 |
NodeManager* nm = NodeManager::currentNM(); |
780 |
32 |
const DType& dt = datatypes::utils::datatypeOf(t.getOperator()); |
781 |
32 |
unsigned index = datatypes::utils::indexOf(t.getOperator()); |
782 |
48 |
for( unsigned i=0; i<t.getNumChildren(); i++ ){ |
783 |
64 |
Node u; |
784 |
48 |
if( e.getKind()==kind::APPLY_CONSTRUCTOR ){ |
785 |
|
u = matchBoundVar( v, t[i], e[i] ); |
786 |
|
}else{ |
787 |
|
Node se = nm->mkNode(APPLY_SELECTOR_TOTAL, |
788 |
96 |
dt[index].getSelectorInternal(e.getType(), i), |
789 |
192 |
e); |
790 |
48 |
u = matchBoundVar( v, t[i], se ); |
791 |
|
} |
792 |
48 |
if( !u.isNull() ){ |
793 |
32 |
return u; |
794 |
|
} |
795 |
|
} |
796 |
|
} |
797 |
16 |
return Node::null(); |
798 |
|
} |
799 |
|
|
800 |
2839 |
bool BoundedIntegers::getBoundElements( RepSetIterator * rsi, bool initial, Node q, Node v, std::vector< Node >& elements ) { |
801 |
2839 |
if( initial || !isGroundRange( q, v ) ){ |
802 |
2569 |
elements.clear(); |
803 |
2569 |
BoundVarType bvt = getBoundVarType(q, v); |
804 |
2569 |
if( bvt==BOUND_INT_RANGE ){ |
805 |
4818 |
Node l, u; |
806 |
2409 |
getBoundValues( q, v, rsi, l, u ); |
807 |
2409 |
if( l.isNull() || u.isNull() ){ |
808 |
75 |
Trace("bound-int-warn") << "WARNING: Could not find integer bounds in model for " << v << " in " << q << std::endl; |
809 |
|
//failed, abort the iterator |
810 |
75 |
return false; |
811 |
|
}else{ |
812 |
2334 |
Trace("bound-int-rsi") << "Can limit bounds of " << v << " to " << l << "..." << u << std::endl; |
813 |
4668 |
Node range = Rewriter::rewrite( NodeManager::currentNM()->mkNode( MINUS, u, l ) ); |
814 |
4668 |
Node ra = Rewriter::rewrite( NodeManager::currentNM()->mkNode( LEQ, range, NodeManager::currentNM()->mkConst( Rational( 9999 ) ) ) ); |
815 |
4668 |
Node tl = l; |
816 |
4668 |
Node tu = u; |
817 |
2334 |
getBounds( q, v, rsi, tl, tu ); |
818 |
2334 |
Assert(!tl.isNull() && !tu.isNull()); |
819 |
2334 |
if (ra.isConst() && ra.getConst<bool>()) |
820 |
|
{ |
821 |
2334 |
long rr = range.getConst<Rational>().getNumerator().getLong()+1; |
822 |
2334 |
Trace("bound-int-rsi") << "Actual bound range is " << rr << std::endl; |
823 |
15324 |
for (long k = 0; k < rr; k++) |
824 |
|
{ |
825 |
25980 |
Node t = NodeManager::currentNM()->mkNode(PLUS, tl, NodeManager::currentNM()->mkConst( Rational(k) ) ); |
826 |
12990 |
t = Rewriter::rewrite( t ); |
827 |
12990 |
elements.push_back( t ); |
828 |
|
} |
829 |
2334 |
return true; |
830 |
|
}else{ |
831 |
|
Trace("fmf-incomplete") << "Incomplete because of integer quantification, bounds are too big for " << v << "." << std::endl; |
832 |
|
return false; |
833 |
|
} |
834 |
|
} |
835 |
160 |
}else if( bvt==BOUND_SET_MEMBER ){ |
836 |
140 |
Node srv = getSetRangeValue( q, v, rsi ); |
837 |
70 |
if( srv.isNull() ){ |
838 |
4 |
Trace("bound-int-warn") << "WARNING: Could not find set bound in model for " << v << " in " << q << std::endl; |
839 |
4 |
return false; |
840 |
|
}else{ |
841 |
66 |
Trace("bound-int-rsi") << "Bounded by set membership : " << srv << std::endl; |
842 |
66 |
if( srv.getKind()!=EMPTYSET ){ |
843 |
|
//collect the elements |
844 |
128 |
while( srv.getKind()==UNION ){ |
845 |
32 |
Assert(srv[1].getKind() == kind::SINGLETON); |
846 |
32 |
elements.push_back( srv[1][0] ); |
847 |
32 |
srv = srv[0]; |
848 |
|
} |
849 |
64 |
Assert(srv.getKind() == kind::SINGLETON); |
850 |
64 |
elements.push_back( srv[0] ); |
851 |
|
//check if we need to do matching, for literals like ( tuple( v ) in S ) |
852 |
128 |
Node t = d_setm_range_lit[q][v][0]; |
853 |
64 |
if( t!=v ){ |
854 |
32 |
std::vector< Node > elements_tmp; |
855 |
16 |
elements_tmp.insert( elements_tmp.end(), elements.begin(), elements.end() ); |
856 |
16 |
elements.clear(); |
857 |
48 |
for( unsigned i=0; i<elements_tmp.size(); i++ ){ |
858 |
|
//do matching to determine v -> u |
859 |
64 |
Node u = matchBoundVar( v, t, elements_tmp[i] ); |
860 |
32 |
Trace("bound-int-rsi-debug") << " unification : " << elements_tmp[i] << " = " << t << " yields " << v << " -> " << u << std::endl; |
861 |
32 |
if( !u.isNull() ){ |
862 |
32 |
elements.push_back( u ); |
863 |
|
} |
864 |
|
} |
865 |
|
} |
866 |
|
} |
867 |
66 |
return true; |
868 |
|
} |
869 |
90 |
}else if( bvt==BOUND_FIXED_SET ){ |
870 |
86 |
std::map< Node, std::vector< Node > >::iterator it = d_fixed_set_gr_range[q].find( v ); |
871 |
86 |
if( it!=d_fixed_set_gr_range[q].end() ){ |
872 |
174 |
for( unsigned i=0; i<it->second.size(); i++ ){ |
873 |
108 |
elements.push_back( it->second[i] ); |
874 |
|
} |
875 |
|
} |
876 |
86 |
it = d_fixed_set_ngr_range[q].find( v ); |
877 |
86 |
if( it!=d_fixed_set_ngr_range[q].end() ){ |
878 |
104 |
std::vector< Node > vars; |
879 |
104 |
std::vector< Node > subs; |
880 |
52 |
if( getRsiSubsitution( q, v, vars, subs, rsi ) ){ |
881 |
98 |
for( unsigned i=0; i<it->second.size(); i++ ){ |
882 |
108 |
Node t = it->second[i].substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); |
883 |
54 |
elements.push_back( t ); |
884 |
|
} |
885 |
44 |
return true; |
886 |
|
}else{ |
887 |
8 |
return false; |
888 |
|
} |
889 |
|
}else{ |
890 |
34 |
return true; |
891 |
|
} |
892 |
|
}else{ |
893 |
4 |
return false; |
894 |
|
} |
895 |
|
}else{ |
896 |
|
//no change required |
897 |
270 |
return true; |
898 |
|
} |
899 |
29514 |
} |