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