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 |
326 |
BoundedIntegers::IntRangeDecisionHeuristic::IntRangeDecisionHeuristic( |
40 |
|
Node r, |
41 |
|
context::Context* c, |
42 |
|
context::Context* u, |
43 |
|
Valuation valuation, |
44 |
326 |
bool isProxy) |
45 |
326 |
: DecisionStrategyFmf(c, valuation), d_range(r), d_ranges_proxied(u) |
46 |
|
{ |
47 |
326 |
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 |
322 |
d_proxy_range = r; |
52 |
|
} |
53 |
326 |
if( !isProxy ){ |
54 |
314 |
Trace("bound-int") << "Introduce proxy " << d_proxy_range << " for " << d_range << std::endl; |
55 |
|
} |
56 |
326 |
} |
57 |
1037 |
Node BoundedIntegers::IntRangeDecisionHeuristic::mkLiteral(unsigned n) |
58 |
|
{ |
59 |
1037 |
NodeManager* nm = NodeManager::currentNM(); |
60 |
2074 |
Node cn = nm->mkConst(Rational(n == 0 ? 0 : n - 1)); |
61 |
2074 |
return nm->mkNode(n == 0 ? LT : LEQ, d_proxy_range, cn); |
62 |
|
} |
63 |
|
|
64 |
1122 |
Node BoundedIntegers::IntRangeDecisionHeuristic::proxyCurrentRangeLemma() |
65 |
|
{ |
66 |
1122 |
if (d_range == d_proxy_range) |
67 |
|
{ |
68 |
1118 |
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 |
1097 |
BoundedIntegers::BoundedIntegers(QuantifiersState& qs, |
92 |
|
QuantifiersInferenceManager& qim, |
93 |
|
QuantifiersRegistry& qr, |
94 |
1097 |
TermRegistry& tr) |
95 |
1097 |
: QuantifiersModule(qs, qim, qr, tr) |
96 |
|
{ |
97 |
1097 |
} |
98 |
|
|
99 |
2194 |
BoundedIntegers::~BoundedIntegers() {} |
100 |
|
|
101 |
1218 |
void BoundedIntegers::presolve() { |
102 |
1218 |
d_bnd_it.clear(); |
103 |
1218 |
} |
104 |
|
|
105 |
6658 |
bool BoundedIntegers::hasNonBoundVar( Node f, Node b, std::map< Node, bool >& visited ) { |
106 |
6658 |
if( visited.find( b )==visited.end() ){ |
107 |
6253 |
visited[b] = true; |
108 |
6253 |
if( b.getKind()==BOUND_VARIABLE ){ |
109 |
630 |
if( !isBound( f, b ) ){ |
110 |
330 |
return true; |
111 |
|
} |
112 |
|
}else{ |
113 |
9706 |
for( unsigned i=0; i<b.getNumChildren(); i++ ){ |
114 |
4452 |
if( hasNonBoundVar( f, b[i], visited ) ){ |
115 |
369 |
return true; |
116 |
|
} |
117 |
|
} |
118 |
|
} |
119 |
|
} |
120 |
5959 |
return false; |
121 |
|
} |
122 |
2206 |
bool BoundedIntegers::hasNonBoundVar( Node f, Node b ) { |
123 |
4412 |
std::map< Node, bool > visited; |
124 |
4412 |
return hasNonBoundVar( f, b, visited ); |
125 |
|
} |
126 |
|
|
127 |
689 |
bool BoundedIntegers::processEqDisjunct( Node q, Node n, Node& v, std::vector< Node >& v_cases ) { |
128 |
689 |
if( n.getKind()==EQUAL ){ |
129 |
1973 |
for( unsigned i=0; i<2; i++ ){ |
130 |
2630 |
Node t = n[i]; |
131 |
1342 |
if( !hasNonBoundVar( q, n[1-i] ) ){ |
132 |
1038 |
if( t==v ){ |
133 |
24 |
v_cases.push_back( n[1-i] ); |
134 |
24 |
return true; |
135 |
1014 |
}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 |
635 |
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 |
5972 |
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 |
5972 |
if( n.getKind()==OR || n.getKind()==AND ){ |
167 |
1140 |
if( (n.getKind()==OR)==pol ){ |
168 |
4004 |
for( unsigned i=0; i<n.getNumChildren(); i++) { |
169 |
3096 |
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 |
464 |
Node conj = n; |
174 |
232 |
if( !pol ){ |
175 |
|
conj = TermUtil::simpleNegate( conj ); |
176 |
|
} |
177 |
232 |
Trace("bound-int-debug") << "Process possible finite disequality conjunction : " << conj << std::endl; |
178 |
232 |
Assert(conj.getKind() == AND); |
179 |
464 |
Node v; |
180 |
464 |
std::vector< Node > v_cases; |
181 |
232 |
bool success = true; |
182 |
282 |
for( unsigned i=0; i<conj.getNumChildren(); i++ ){ |
183 |
258 |
if( conj[i].getKind()==NOT && processEqDisjunct( q, conj[i][0], v, v_cases ) ){ |
184 |
|
//continue |
185 |
|
}else{ |
186 |
208 |
Trace("bound-int-debug") << "...failed due to " << conj[i] << std::endl; |
187 |
208 |
success = false; |
188 |
208 |
break; |
189 |
|
} |
190 |
|
} |
191 |
232 |
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 |
4832 |
}else if( n.getKind()==EQUAL ){ |
201 |
925 |
if( !pol ){ |
202 |
|
// non-applied DER on x != t, x can be bound to { t } |
203 |
1214 |
Node v; |
204 |
1214 |
std::vector< Node > v_cases; |
205 |
607 |
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 |
3907 |
}else if( n.getKind()==NOT ){ |
217 |
1795 |
process( q, n[0], !pol, bound_lit_type_map, bound_lit_map, bound_lit_pol_map, bound_int_range_term, bound_fixed_set ); |
218 |
2112 |
}else if( n.getKind()==GEQ ){ |
219 |
1663 |
if( n[0].getType().isInteger() ){ |
220 |
3318 |
std::map< Node, Node > msum; |
221 |
1659 |
if (ArithMSum::getMonomialSumLit(n, msum)) |
222 |
|
{ |
223 |
1659 |
Trace("bound-int-debug") << "literal (polarity = " << pol << ") " << n << " is monomial sum : " << std::endl; |
224 |
1659 |
ArithMSum::debugPrintMonomialSum(msum, "bound-int-debug"); |
225 |
4979 |
for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){ |
226 |
3320 |
if ( !it->first.isNull() && it->first.getKind()==BOUND_VARIABLE && !isBound( q, it->first ) ){ |
227 |
|
//if not bound in another way |
228 |
789 |
if( bound_lit_type_map.find( it->first )==bound_lit_type_map.end() || bound_lit_type_map[it->first] == BOUND_INT_RANGE ){ |
229 |
1568 |
Node veq; |
230 |
784 |
if (ArithMSum::isolate(it->first, msum, veq, GEQ) != 0) |
231 |
|
{ |
232 |
1568 |
Node n1 = veq[0]; |
233 |
1568 |
Node n2 = veq[1]; |
234 |
784 |
if(pol){ |
235 |
|
//flip |
236 |
362 |
n1 = veq[1]; |
237 |
362 |
n2 = veq[0]; |
238 |
362 |
if( n1.getKind()==BOUND_VARIABLE ){ |
239 |
6 |
n2 = ArithMSum::offset(n2, 1); |
240 |
|
}else{ |
241 |
356 |
n1 = ArithMSum::offset(n1, -1); |
242 |
|
} |
243 |
362 |
veq = NodeManager::currentNM()->mkNode( GEQ, n1, n2 ); |
244 |
|
} |
245 |
784 |
Trace("bound-int-debug") << "Isolated for " << it->first << " : (" << n1 << " >= " << n2 << ")" << std::endl; |
246 |
1568 |
Node t = n1==it->first ? n2 : n1; |
247 |
784 |
if( !hasNonBoundVar( q, t ) ) { |
248 |
762 |
Trace("bound-int-debug") << "The bound is relevant." << std::endl; |
249 |
762 |
int loru = n1==it->first ? 0 : 1; |
250 |
762 |
bound_lit_type_map[it->first] = BOUND_INT_RANGE; |
251 |
762 |
bound_int_range_term[loru][it->first] = t; |
252 |
762 |
bound_lit_map[loru][it->first] = n; |
253 |
762 |
bound_lit_pol_map[loru][it->first] = pol; |
254 |
|
}else{ |
255 |
22 |
Trace("bound-int-debug") << "The term " << t << " has non-bound variable." << std::endl; |
256 |
|
} |
257 |
|
} |
258 |
|
} |
259 |
|
} |
260 |
|
} |
261 |
|
} |
262 |
|
} |
263 |
449 |
}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 |
369 |
Assert(n.getKind() != LEQ && n.getKind() != LT && n.getKind() != GT); |
278 |
|
} |
279 |
5972 |
} |
280 |
|
|
281 |
9231 |
bool BoundedIntegers::needsCheck( Theory::Effort e ) { |
282 |
9231 |
return e==Theory::EFFORT_LAST_CALL; |
283 |
|
} |
284 |
|
|
285 |
2815 |
void BoundedIntegers::check(Theory::Effort e, QEffort quant_e) |
286 |
|
{ |
287 |
2815 |
if (quant_e != QEFFORT_STANDARD) |
288 |
|
{ |
289 |
1875 |
return; |
290 |
|
} |
291 |
940 |
Trace("bint-engine") << "---Bounded Integers---" << std::endl; |
292 |
940 |
bool addedLemma = false; |
293 |
|
// make sure proxies are up-to-date with range |
294 |
2062 |
for (const Node& r : d_ranges) |
295 |
|
{ |
296 |
2244 |
Node prangeLem = d_rms[r]->proxyCurrentRangeLemma(); |
297 |
1122 |
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 |
940 |
Trace("bint-engine") << " addedLemma = " << addedLemma << std::endl; |
306 |
|
} |
307 |
545 |
void BoundedIntegers::setBoundedVar(Node q, Node v, BoundVarType bound_type) |
308 |
|
{ |
309 |
545 |
d_bound_type[q][v] = bound_type; |
310 |
545 |
d_set_nums[q][v] = d_set[q].size(); |
311 |
545 |
d_set[q].push_back( v ); |
312 |
1090 |
Trace("bound-int-var") << "Bound variable #" << d_set_nums[q][v] << " : " << v |
313 |
545 |
<< std::endl; |
314 |
545 |
} |
315 |
|
|
316 |
552 |
void BoundedIntegers::checkOwnership(Node f) |
317 |
|
{ |
318 |
|
//this needs to be done at preregister since it affects e.g. QuantDSplit's preregister |
319 |
552 |
Trace("bound-int") << "check ownership quantifier " << f << std::endl; |
320 |
552 |
NodeManager* nm = NodeManager::currentNM(); |
321 |
552 |
SkolemManager* sm = nm->getSkolemManager(); |
322 |
|
|
323 |
|
bool success; |
324 |
1081 |
do{ |
325 |
2162 |
std::map< Node, unsigned > bound_lit_type_map; |
326 |
2162 |
std::map< int, std::map< Node, Node > > bound_lit_map; |
327 |
2162 |
std::map< int, std::map< Node, bool > > bound_lit_pol_map; |
328 |
2162 |
std::map< int, std::map< Node, Node > > bound_int_range_term; |
329 |
2162 |
std::map< Node, std::vector< Node > > bound_fixed_set; |
330 |
1081 |
success = false; |
331 |
1081 |
process( f, f[1], true, bound_lit_type_map, bound_lit_map, bound_lit_pol_map, bound_int_range_term, bound_fixed_set ); |
332 |
|
//for( std::map< Node, Node >::iterator it = d_bounds[0][f].begin(); it != d_bounds[0][f].end(); ++it ){ |
333 |
1508 |
for( std::map< Node, unsigned >::iterator it = bound_lit_type_map.begin(); it != bound_lit_type_map.end(); ++it ){ |
334 |
854 |
Node v = it->first; |
335 |
427 |
if( !isBound( f, v ) ){ |
336 |
427 |
bool setBoundVar = false; |
337 |
427 |
if( it->second==BOUND_INT_RANGE ){ |
338 |
|
//must have both |
339 |
380 |
std::map<Node, Node>& blm0 = bound_lit_map[0]; |
340 |
380 |
std::map<Node, Node>& blm1 = bound_lit_map[1]; |
341 |
380 |
if (blm0.find(v) != blm0.end() && blm1.find(v) != blm1.end()) |
342 |
|
{ |
343 |
360 |
setBoundedVar( f, v, BOUND_INT_RANGE ); |
344 |
360 |
setBoundVar = true; |
345 |
1080 |
for( unsigned b=0; b<2; b++ ){ |
346 |
|
//set the bounds |
347 |
720 |
Assert(bound_int_range_term[b].find(v) |
348 |
|
!= bound_int_range_term[b].end()); |
349 |
720 |
d_bounds[b][f][v] = bound_int_range_term[b][v]; |
350 |
|
} |
351 |
720 |
Node r = nm->mkNode(MINUS, d_bounds[1][f][v], d_bounds[0][f][v]); |
352 |
360 |
d_range[f][v] = Rewriter::rewrite(r); |
353 |
360 |
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; |
354 |
|
} |
355 |
47 |
}else if( it->second==BOUND_SET_MEMBER ){ |
356 |
|
// only handles infinite element types currently (cardinality is not |
357 |
|
// supported for finite element types #1123). Regardless, this is |
358 |
|
// typically not a limitation since this variable can be bound in a |
359 |
|
// standard way below since its type is finite. |
360 |
35 |
if (!d_qstate.isFiniteType(v.getType())) |
361 |
|
{ |
362 |
35 |
setBoundedVar(f, v, BOUND_SET_MEMBER); |
363 |
35 |
setBoundVar = true; |
364 |
35 |
d_setm_range[f][v] = bound_lit_map[2][v][1]; |
365 |
35 |
d_setm_range_lit[f][v] = bound_lit_map[2][v]; |
366 |
35 |
d_range[f][v] = nm->mkNode(CARD, d_setm_range[f][v]); |
367 |
70 |
Trace("bound-int") << "Variable " << v |
368 |
35 |
<< " is bound because of set membership literal " |
369 |
35 |
<< bound_lit_map[2][v] << std::endl; |
370 |
|
} |
371 |
12 |
}else if( it->second==BOUND_FIXED_SET ){ |
372 |
12 |
setBoundedVar(f, v, BOUND_FIXED_SET); |
373 |
12 |
setBoundVar = true; |
374 |
34 |
for (unsigned i = 0; i < bound_fixed_set[v].size(); i++) |
375 |
|
{ |
376 |
44 |
Node t = bound_fixed_set[v][i]; |
377 |
22 |
if (expr::hasBoundVar(t)) |
378 |
|
{ |
379 |
6 |
d_fixed_set_ngr_range[f][v].push_back(t); |
380 |
|
} |
381 |
|
else |
382 |
|
{ |
383 |
16 |
d_fixed_set_gr_range[f][v].push_back(t); |
384 |
|
} |
385 |
|
} |
386 |
24 |
Trace("bound-int") << "Variable " << v |
387 |
12 |
<< " is bound because of disequality conjunction " |
388 |
12 |
<< bound_lit_map[3][v] << std::endl; |
389 |
|
} |
390 |
427 |
if( setBoundVar ){ |
391 |
407 |
success = true; |
392 |
|
//set Attributes on literals |
393 |
1221 |
for( unsigned b=0; b<2; b++ ){ |
394 |
814 |
std::map<Node, Node>& blm = bound_lit_map[b]; |
395 |
814 |
if (blm.find(v) != blm.end()) |
396 |
|
{ |
397 |
720 |
std::map<Node, bool>& blmp = bound_lit_pol_map[b]; |
398 |
|
// WARNING_CANDIDATE: |
399 |
|
// This assertion may fail. We intentionally do not enable this in |
400 |
|
// production as it is considered safe for this to fail. We fail |
401 |
|
// the assertion in debug mode to have this instance raised to |
402 |
|
// our attention. |
403 |
720 |
Assert(blmp.find(v) != blmp.end()); |
404 |
|
BoundIntLitAttribute bila; |
405 |
720 |
bound_lit_map[b][v].setAttribute(bila, blmp[v] ? 1 : 0); |
406 |
|
} |
407 |
|
else |
408 |
|
{ |
409 |
94 |
Assert(it->second != BOUND_INT_RANGE); |
410 |
|
} |
411 |
|
} |
412 |
|
} |
413 |
|
} |
414 |
|
} |
415 |
1081 |
if( !success ){ |
416 |
|
//resort to setting a finite bound on a variable |
417 |
1359 |
for( unsigned i=0; i<f[0].getNumChildren(); i++) { |
418 |
807 |
if( d_bound_type[f].find( f[0][i] )==d_bound_type[f].end() ){ |
419 |
334 |
TypeNode tn = f[0][i].getType(); |
420 |
538 |
if ((tn.isSort() && d_qstate.isFiniteType(tn)) |
421 |
648 |
|| d_qreg.getQuantifiersBoundInference().mayComplete(tn)) |
422 |
|
{ |
423 |
138 |
success = true; |
424 |
138 |
setBoundedVar( f, f[0][i], BOUND_FINITE ); |
425 |
138 |
break; |
426 |
|
} |
427 |
|
} |
428 |
|
} |
429 |
|
} |
430 |
|
}while( success ); |
431 |
|
|
432 |
552 |
if( Trace.isOn("bound-int") ){ |
433 |
|
Trace("bound-int") << "Bounds are : " << std::endl; |
434 |
|
for( unsigned i=0; i<f[0].getNumChildren(); i++) { |
435 |
|
Node v = f[0][i]; |
436 |
|
if( std::find( d_set[f].begin(), d_set[f].end(), v )!=d_set[f].end() ){ |
437 |
|
Assert(d_bound_type[f].find(v) != d_bound_type[f].end()); |
438 |
|
if( d_bound_type[f][v]==BOUND_INT_RANGE ){ |
439 |
|
Trace("bound-int") << " " << d_bounds[0][f][v] << " <= " << v << " <= " << d_bounds[1][f][v] << " (range is " << d_range[f][v] << ")" << std::endl; |
440 |
|
}else if( d_bound_type[f][v]==BOUND_SET_MEMBER ){ |
441 |
|
if( d_setm_range_lit[f][v][0]==v ){ |
442 |
|
Trace("bound-int") << " " << v << " in " << d_setm_range[f][v] << std::endl; |
443 |
|
}else{ |
444 |
|
Trace("bound-int") << " " << v << " unifiable in " << d_setm_range_lit[f][v] << std::endl; |
445 |
|
} |
446 |
|
}else if( d_bound_type[f][v]==BOUND_FIXED_SET ){ |
447 |
|
Trace("bound-int") << " " << v << " in { "; |
448 |
|
for (TNode fnr : d_fixed_set_ngr_range[f][v]) |
449 |
|
{ |
450 |
|
Trace("bound-int") << fnr << " "; |
451 |
|
} |
452 |
|
for (TNode fgr : d_fixed_set_gr_range[f][v]) |
453 |
|
{ |
454 |
|
Trace("bound-int") << fgr << " "; |
455 |
|
} |
456 |
|
Trace("bound-int") << "}" << std::endl; |
457 |
|
}else if( d_bound_type[f][v]==BOUND_FINITE ){ |
458 |
|
Trace("bound-int") << " " << v << " has small finite type." << std::endl; |
459 |
|
}else{ |
460 |
|
Trace("bound-int") << " " << v << " has unknown bound." << std::endl; |
461 |
|
Assert(false); |
462 |
|
} |
463 |
|
}else{ |
464 |
|
Trace("bound-int") << " " << "*** " << v << " is unbounded." << std::endl; |
465 |
|
} |
466 |
|
} |
467 |
|
} |
468 |
|
|
469 |
552 |
bool bound_success = true; |
470 |
1095 |
for( unsigned i=0; i<f[0].getNumChildren(); i++) { |
471 |
612 |
if( d_bound_type[f].find( f[0][i] )==d_bound_type[f].end() ){ |
472 |
69 |
Trace("bound-int-warn") << "Warning : Bounded Integers : Due to quantification on " << f[0][i] << ", could not find bounds for " << f << std::endl; |
473 |
69 |
bound_success = false; |
474 |
69 |
break; |
475 |
|
} |
476 |
|
} |
477 |
|
|
478 |
552 |
if( bound_success ){ |
479 |
483 |
d_bound_quants.push_back( f ); |
480 |
483 |
DecisionManager* dm = d_qim.getDecisionManager(); |
481 |
1026 |
for( unsigned i=0; i<d_set[f].size(); i++) { |
482 |
1086 |
Node v = d_set[f][i]; |
483 |
543 |
std::map< Node, Node >::iterator itr = d_range[f].find( v ); |
484 |
543 |
if( itr != d_range[f].end() ){ |
485 |
786 |
Node r = itr->second; |
486 |
393 |
Assert(!r.isNull()); |
487 |
393 |
bool isProxy = false; |
488 |
393 |
if (expr::hasBoundVar(r)) |
489 |
|
{ |
490 |
|
// introduce a new bound |
491 |
|
Node new_range = |
492 |
24 |
sm->mkDummySkolem("bir", r.getType(), "bound for term"); |
493 |
12 |
d_nground_range[f][v] = r; |
494 |
12 |
d_range[f][v] = new_range; |
495 |
12 |
r = new_range; |
496 |
12 |
isProxy = true; |
497 |
|
} |
498 |
393 |
if( !r.isConst() ){ |
499 |
357 |
if (d_rms.find(r) == d_rms.end()) |
500 |
|
{ |
501 |
326 |
Trace("bound-int") << "For " << v << ", bounded Integer Module will try to minimize : " << r << std::endl; |
502 |
326 |
d_ranges.push_back( r ); |
503 |
978 |
d_rms[r].reset( |
504 |
|
new IntRangeDecisionHeuristic(r, |
505 |
326 |
d_qstate.getSatContext(), |
506 |
326 |
d_qstate.getUserContext(), |
507 |
326 |
d_qstate.getValuation(), |
508 |
326 |
isProxy)); |
509 |
326 |
dm->registerStrategy(DecisionManager::STRAT_QUANT_BOUND_INT_SIZE, |
510 |
326 |
d_rms[r].get()); |
511 |
|
} |
512 |
|
} |
513 |
|
} |
514 |
|
} |
515 |
|
} |
516 |
552 |
} |
517 |
|
|
518 |
3659 |
bool BoundedIntegers::isBound(Node q, Node v) const |
519 |
|
{ |
520 |
3659 |
std::map<Node, std::vector<Node> >::const_iterator its = d_set.find(q); |
521 |
3659 |
if (its == d_set.end()) |
522 |
|
{ |
523 |
1529 |
return false; |
524 |
|
} |
525 |
4260 |
return std::find(its->second.begin(), its->second.end(), v) |
526 |
6390 |
!= its->second.end(); |
527 |
|
} |
528 |
|
|
529 |
6546 |
BoundVarType BoundedIntegers::getBoundVarType(Node q, Node v) const |
530 |
|
{ |
531 |
|
std::map<Node, std::map<Node, BoundVarType> >::const_iterator itb = |
532 |
6546 |
d_bound_type.find(q); |
533 |
6546 |
if (itb == d_bound_type.end()) |
534 |
|
{ |
535 |
|
return BOUND_NONE; |
536 |
|
} |
537 |
6546 |
std::map<Node, BoundVarType>::const_iterator it = itb->second.find(v); |
538 |
6546 |
if (it == itb->second.end()) |
539 |
|
{ |
540 |
22 |
return BOUND_NONE; |
541 |
|
} |
542 |
6524 |
return it->second; |
543 |
|
} |
544 |
|
|
545 |
3180 |
void BoundedIntegers::getBoundVarIndices(Node q, |
546 |
|
std::vector<unsigned>& indices) const |
547 |
|
{ |
548 |
3180 |
std::map<Node, std::vector<Node> >::const_iterator it = d_set.find(q); |
549 |
3180 |
if (it != d_set.end()) |
550 |
|
{ |
551 |
7416 |
for (const Node& v : it->second) |
552 |
|
{ |
553 |
4244 |
indices.push_back(TermUtil::getVariableNum(q, v)); |
554 |
|
} |
555 |
|
} |
556 |
3180 |
} |
557 |
|
|
558 |
4212 |
void BoundedIntegers::getBounds( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u ) { |
559 |
4212 |
l = d_bounds[0][f][v]; |
560 |
4212 |
u = d_bounds[1][f][v]; |
561 |
4212 |
if( d_nground_range[f].find(v)!=d_nground_range[f].end() ){ |
562 |
|
//get the substitution |
563 |
2384 |
std::vector< Node > vars; |
564 |
2384 |
std::vector< Node > subs; |
565 |
1192 |
if( getRsiSubsitution( f, v, vars, subs, rsi ) ){ |
566 |
1156 |
u = u.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); |
567 |
1156 |
l = l.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); |
568 |
|
}else{ |
569 |
36 |
u = Node::null(); |
570 |
36 |
l = Node::null(); |
571 |
|
} |
572 |
|
} |
573 |
4212 |
} |
574 |
|
|
575 |
2124 |
void BoundedIntegers::getBoundValues( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u ) { |
576 |
2124 |
getBounds( f, v, rsi, l, u ); |
577 |
2124 |
Trace("bound-int-rsi") << "Get value in model for..." << l << " and " << u << std::endl; |
578 |
2124 |
if( !l.isNull() ){ |
579 |
2088 |
l = d_treg.getModel()->getValue(l); |
580 |
|
} |
581 |
2124 |
if( !u.isNull() ){ |
582 |
2088 |
u = d_treg.getModel()->getValue(u); |
583 |
|
} |
584 |
2124 |
Trace("bound-int-rsi") << "Value is " << l << " ... " << u << std::endl; |
585 |
2124 |
return; |
586 |
|
} |
587 |
|
|
588 |
768 |
bool BoundedIntegers::isGroundRange(Node q, Node v) |
589 |
|
{ |
590 |
768 |
if (isBound(q, v)) |
591 |
|
{ |
592 |
768 |
if (d_bound_type[q][v] == BOUND_INT_RANGE) |
593 |
|
{ |
594 |
1872 |
return !expr::hasBoundVar(getLowerBound(q, v)) |
595 |
1872 |
&& !expr::hasBoundVar(getUpperBound(q, v)); |
596 |
|
} |
597 |
144 |
else if (d_bound_type[q][v] == BOUND_SET_MEMBER) |
598 |
|
{ |
599 |
12 |
return !expr::hasBoundVar(d_setm_range[q][v]); |
600 |
|
} |
601 |
132 |
else if (d_bound_type[q][v] == BOUND_FIXED_SET) |
602 |
|
{ |
603 |
132 |
return !d_fixed_set_ngr_range[q][v].empty(); |
604 |
|
} |
605 |
|
} |
606 |
|
return false; |
607 |
|
} |
608 |
|
|
609 |
70 |
Node BoundedIntegers::getSetRange( Node q, Node v, RepSetIterator * rsi ) { |
610 |
70 |
Node sr = d_setm_range[q][v]; |
611 |
70 |
if( d_nground_range[q].find(v)!=d_nground_range[q].end() ){ |
612 |
16 |
Trace("bound-int-rsi-debug") |
613 |
8 |
<< sr << " is non-ground, apply substitution..." << std::endl; |
614 |
|
//get the substitution |
615 |
16 |
std::vector< Node > vars; |
616 |
16 |
std::vector< Node > subs; |
617 |
8 |
if( getRsiSubsitution( q, v, vars, subs, rsi ) ){ |
618 |
8 |
Trace("bound-int-rsi-debug") |
619 |
4 |
<< " apply " << vars << " -> " << subs << std::endl; |
620 |
4 |
sr = sr.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); |
621 |
|
}else{ |
622 |
4 |
sr = Node::null(); |
623 |
|
} |
624 |
|
} |
625 |
70 |
return sr; |
626 |
|
} |
627 |
|
|
628 |
70 |
Node BoundedIntegers::getSetRangeValue( Node q, Node v, RepSetIterator * rsi ) { |
629 |
140 |
Node sr = getSetRange( q, v, rsi ); |
630 |
70 |
if (sr.isNull()) |
631 |
|
{ |
632 |
4 |
return sr; |
633 |
|
} |
634 |
66 |
Trace("bound-int-rsi") << "Get value in model for..." << sr << std::endl; |
635 |
66 |
Assert(!expr::hasFreeVar(sr)); |
636 |
132 |
Node sro = sr; |
637 |
66 |
sr = d_treg.getModel()->getValue(sr); |
638 |
|
// if non-constant, then sr does not occur in the model, we fail |
639 |
66 |
if (!sr.isConst()) |
640 |
|
{ |
641 |
|
return Node::null(); |
642 |
|
} |
643 |
66 |
Trace("bound-int-rsi") << "Value is " << sr << std::endl; |
644 |
66 |
if (sr.getKind() == EMPTYSET) |
645 |
|
{ |
646 |
2 |
return sr; |
647 |
|
} |
648 |
64 |
NodeManager* nm = NodeManager::currentNM(); |
649 |
128 |
Node nsr; |
650 |
128 |
TypeNode tne = sr.getType().getSetElementType(); |
651 |
|
|
652 |
|
// we can use choice functions for canonical symbolic instantiations |
653 |
64 |
unsigned srCard = 0; |
654 |
128 |
while (sr.getKind() == UNION) |
655 |
|
{ |
656 |
32 |
srCard++; |
657 |
32 |
sr = sr[0]; |
658 |
|
} |
659 |
64 |
Assert(sr.getKind() == SINGLETON); |
660 |
64 |
srCard++; |
661 |
|
// choices[i] stores the canonical symbolic representation of the (i+1)^th |
662 |
|
// element of sro |
663 |
128 |
std::vector<Node> choices; |
664 |
128 |
Node srCardN = nm->mkNode(CARD, sro); |
665 |
128 |
Node choice_i; |
666 |
160 |
for (unsigned i = 0; i < srCard; i++) |
667 |
|
{ |
668 |
96 |
if (i == d_setm_choice[sro].size()) |
669 |
|
{ |
670 |
38 |
choice_i = nm->mkBoundVar(tne); |
671 |
38 |
choices.push_back(choice_i); |
672 |
76 |
Node cBody = nm->mkNode(MEMBER, choice_i, sro); |
673 |
38 |
if (choices.size() > 1) |
674 |
|
{ |
675 |
14 |
cBody = nm->mkNode(AND, cBody, nm->mkNode(DISTINCT, choices)); |
676 |
|
} |
677 |
38 |
choices.pop_back(); |
678 |
76 |
Node bvl = nm->mkNode(BOUND_VAR_LIST, choice_i); |
679 |
76 |
Node cMinCard = nm->mkNode(LEQ, srCardN, nm->mkConst(Rational(i))); |
680 |
38 |
choice_i = nm->mkNode(WITNESS, bvl, nm->mkNode(OR, cMinCard, cBody)); |
681 |
38 |
d_setm_choice[sro].push_back(choice_i); |
682 |
|
} |
683 |
96 |
Assert(i < d_setm_choice[sro].size()); |
684 |
96 |
choice_i = d_setm_choice[sro][i]; |
685 |
96 |
choices.push_back(choice_i); |
686 |
192 |
Node sChoiceI = nm->mkSingleton(choice_i.getType(), choice_i); |
687 |
96 |
if (nsr.isNull()) |
688 |
|
{ |
689 |
64 |
nsr = sChoiceI; |
690 |
|
} |
691 |
|
else |
692 |
|
{ |
693 |
32 |
nsr = nm->mkNode(UNION, nsr, sChoiceI); |
694 |
|
} |
695 |
|
} |
696 |
|
// turns the concrete model value of sro into a canonical representation |
697 |
|
// e.g. |
698 |
|
// singleton(0) union singleton(1) |
699 |
|
// becomes |
700 |
|
// C1 union ( witness y. card(S)<=1 OR ( y in S AND distinct( y, C1 ) ) ) |
701 |
|
// where C1 = ( witness x. card(S)<=0 OR x in S ). |
702 |
64 |
Trace("bound-int-rsi") << "...reconstructed " << nsr << std::endl; |
703 |
64 |
return nsr; |
704 |
|
} |
705 |
|
|
706 |
1252 |
bool BoundedIntegers::getRsiSubsitution( Node q, Node v, std::vector< Node >& vars, std::vector< Node >& subs, RepSetIterator * rsi ) { |
707 |
|
|
708 |
1252 |
Trace("bound-int-rsi") << "Get bound value in model of variable " << v << std::endl; |
709 |
1252 |
Assert(d_set_nums[q].find(v) != d_set_nums[q].end()); |
710 |
1252 |
int vindex = d_set_nums[q][v]; |
711 |
1252 |
Assert(d_set_nums[q][v] == vindex); |
712 |
1252 |
Trace("bound-int-rsi-debug") << " index order is " << vindex << std::endl; |
713 |
|
//must take substitution for all variables that are iterating at higher level |
714 |
2784 |
for( int i=0; i<vindex; i++) { |
715 |
1532 |
Assert(d_set_nums[q][d_set[q][i]] == i); |
716 |
1532 |
Trace("bound-int-rsi") << "Look up the value for " << d_set[q][i] << " " << i << std::endl; |
717 |
1532 |
int vo = rsi->getVariableOrder(i); |
718 |
1532 |
Assert(q[0][vo] == d_set[q][i]); |
719 |
3064 |
Node t = rsi->getCurrentTerm(vo, true); |
720 |
1532 |
Trace("bound-int-rsi") << "term : " << t << std::endl; |
721 |
1532 |
vars.push_back( d_set[q][i] ); |
722 |
1532 |
subs.push_back( t ); |
723 |
|
} |
724 |
|
|
725 |
|
//check if it has been instantiated |
726 |
1252 |
if( !vars.empty() && !d_bnd_it[q][v].hasInstantiated(subs) ){ |
727 |
48 |
if( d_bound_type[q][v]==BOUND_INT_RANGE || d_bound_type[q][v]==BOUND_SET_MEMBER ){ |
728 |
|
//must add the lemma |
729 |
80 |
Node nn = d_nground_range[q][v]; |
730 |
40 |
nn = nn.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); |
731 |
80 |
Node lem = NodeManager::currentNM()->mkNode( LEQ, nn, d_range[q][v] ); |
732 |
40 |
Trace("bound-int-lemma") << "*** Add lemma to minimize instantiated non-ground term " << lem << std::endl; |
733 |
40 |
d_qim.lemma(lem, InferenceId::QUANTIFIERS_BINT_MIN_NG); |
734 |
|
} |
735 |
48 |
return false; |
736 |
|
}else{ |
737 |
1204 |
return true; |
738 |
|
} |
739 |
|
} |
740 |
|
|
741 |
80 |
Node BoundedIntegers::matchBoundVar( Node v, Node t, Node e ){ |
742 |
80 |
if( t==v ){ |
743 |
32 |
return e; |
744 |
48 |
}else if( t.getKind()==kind::APPLY_CONSTRUCTOR ){ |
745 |
32 |
if( e.getKind()==kind::APPLY_CONSTRUCTOR ){ |
746 |
|
if( t.getOperator() != e.getOperator() ) { |
747 |
|
return Node::null(); |
748 |
|
} |
749 |
|
} |
750 |
32 |
NodeManager* nm = NodeManager::currentNM(); |
751 |
32 |
const DType& dt = datatypes::utils::datatypeOf(t.getOperator()); |
752 |
32 |
unsigned index = datatypes::utils::indexOf(t.getOperator()); |
753 |
48 |
for( unsigned i=0; i<t.getNumChildren(); i++ ){ |
754 |
64 |
Node u; |
755 |
48 |
if( e.getKind()==kind::APPLY_CONSTRUCTOR ){ |
756 |
|
u = matchBoundVar( v, t[i], e[i] ); |
757 |
|
}else{ |
758 |
|
Node se = nm->mkNode(APPLY_SELECTOR_TOTAL, |
759 |
96 |
dt[index].getSelectorInternal(e.getType(), i), |
760 |
192 |
e); |
761 |
48 |
u = matchBoundVar( v, t[i], se ); |
762 |
|
} |
763 |
48 |
if( !u.isNull() ){ |
764 |
32 |
return u; |
765 |
|
} |
766 |
|
} |
767 |
|
} |
768 |
16 |
return Node::null(); |
769 |
|
} |
770 |
|
|
771 |
2558 |
bool BoundedIntegers::getBoundElements( RepSetIterator * rsi, bool initial, Node q, Node v, std::vector< Node >& elements ) { |
772 |
2558 |
if( initial || !isGroundRange( q, v ) ){ |
773 |
2288 |
elements.clear(); |
774 |
2288 |
BoundVarType bvt = getBoundVarType(q, v); |
775 |
2288 |
if( bvt==BOUND_INT_RANGE ){ |
776 |
4248 |
Node l, u; |
777 |
2124 |
getBoundValues( q, v, rsi, l, u ); |
778 |
2124 |
if( l.isNull() || u.isNull() ){ |
779 |
36 |
Trace("bound-int-warn") << "WARNING: Could not find integer bounds in model for " << v << " in " << q << std::endl; |
780 |
|
//failed, abort the iterator |
781 |
36 |
return false; |
782 |
|
}else{ |
783 |
2088 |
Trace("bound-int-rsi") << "Can limit bounds of " << v << " to " << l << "..." << u << std::endl; |
784 |
4176 |
Node range = Rewriter::rewrite( NodeManager::currentNM()->mkNode( MINUS, u, l ) ); |
785 |
4176 |
Node ra = Rewriter::rewrite( NodeManager::currentNM()->mkNode( LEQ, range, NodeManager::currentNM()->mkConst( Rational( 9999 ) ) ) ); |
786 |
4176 |
Node tl = l; |
787 |
4176 |
Node tu = u; |
788 |
2088 |
getBounds( q, v, rsi, tl, tu ); |
789 |
2088 |
Assert(!tl.isNull() && !tu.isNull()); |
790 |
2088 |
if (ra.isConst() && ra.getConst<bool>()) |
791 |
|
{ |
792 |
2088 |
long rr = range.getConst<Rational>().getNumerator().getLong()+1; |
793 |
2088 |
Trace("bound-int-rsi") << "Actual bound range is " << rr << std::endl; |
794 |
14881 |
for (long k = 0; k < rr; k++) |
795 |
|
{ |
796 |
25586 |
Node t = NodeManager::currentNM()->mkNode(PLUS, tl, NodeManager::currentNM()->mkConst( Rational(k) ) ); |
797 |
12793 |
t = Rewriter::rewrite( t ); |
798 |
12793 |
elements.push_back( t ); |
799 |
|
} |
800 |
2088 |
return true; |
801 |
|
}else{ |
802 |
|
Trace("fmf-incomplete") << "Incomplete because of integer quantification, bounds are too big for " << v << "." << std::endl; |
803 |
|
return false; |
804 |
|
} |
805 |
|
} |
806 |
164 |
}else if( bvt==BOUND_SET_MEMBER ){ |
807 |
140 |
Node srv = getSetRangeValue( q, v, rsi ); |
808 |
70 |
if( srv.isNull() ){ |
809 |
4 |
Trace("bound-int-warn") << "WARNING: Could not find set bound in model for " << v << " in " << q << std::endl; |
810 |
4 |
return false; |
811 |
|
}else{ |
812 |
66 |
Trace("bound-int-rsi") << "Bounded by set membership : " << srv << std::endl; |
813 |
66 |
if( srv.getKind()!=EMPTYSET ){ |
814 |
|
//collect the elements |
815 |
128 |
while( srv.getKind()==UNION ){ |
816 |
32 |
Assert(srv[1].getKind() == kind::SINGLETON); |
817 |
32 |
elements.push_back( srv[1][0] ); |
818 |
32 |
srv = srv[0]; |
819 |
|
} |
820 |
64 |
Assert(srv.getKind() == kind::SINGLETON); |
821 |
64 |
elements.push_back( srv[0] ); |
822 |
|
//check if we need to do matching, for literals like ( tuple( v ) in S ) |
823 |
128 |
Node t = d_setm_range_lit[q][v][0]; |
824 |
64 |
if( t!=v ){ |
825 |
32 |
std::vector< Node > elements_tmp; |
826 |
16 |
elements_tmp.insert( elements_tmp.end(), elements.begin(), elements.end() ); |
827 |
16 |
elements.clear(); |
828 |
48 |
for( unsigned i=0; i<elements_tmp.size(); i++ ){ |
829 |
|
//do matching to determine v -> u |
830 |
64 |
Node u = matchBoundVar( v, t, elements_tmp[i] ); |
831 |
32 |
Trace("bound-int-rsi-debug") << " unification : " << elements_tmp[i] << " = " << t << " yields " << v << " -> " << u << std::endl; |
832 |
32 |
if( !u.isNull() ){ |
833 |
32 |
elements.push_back( u ); |
834 |
|
} |
835 |
|
} |
836 |
|
} |
837 |
|
} |
838 |
66 |
return true; |
839 |
|
} |
840 |
94 |
}else if( bvt==BOUND_FIXED_SET ){ |
841 |
86 |
std::map< Node, std::vector< Node > >::iterator it = d_fixed_set_gr_range[q].find( v ); |
842 |
86 |
if( it!=d_fixed_set_gr_range[q].end() ){ |
843 |
174 |
for( unsigned i=0; i<it->second.size(); i++ ){ |
844 |
108 |
elements.push_back( it->second[i] ); |
845 |
|
} |
846 |
|
} |
847 |
86 |
it = d_fixed_set_ngr_range[q].find( v ); |
848 |
86 |
if( it!=d_fixed_set_ngr_range[q].end() ){ |
849 |
104 |
std::vector< Node > vars; |
850 |
104 |
std::vector< Node > subs; |
851 |
52 |
if( getRsiSubsitution( q, v, vars, subs, rsi ) ){ |
852 |
98 |
for( unsigned i=0; i<it->second.size(); i++ ){ |
853 |
108 |
Node t = it->second[i].substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); |
854 |
54 |
elements.push_back( t ); |
855 |
|
} |
856 |
44 |
return true; |
857 |
|
}else{ |
858 |
8 |
return false; |
859 |
|
} |
860 |
|
}else{ |
861 |
34 |
return true; |
862 |
|
} |
863 |
|
}else{ |
864 |
8 |
return false; |
865 |
|
} |
866 |
|
}else{ |
867 |
|
//no change required |
868 |
270 |
return true; |
869 |
|
} |
870 |
28191 |
} |