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