GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/fmf/bounded_integers.cpp Lines: 490 524 93.5 %
Date: 2021-05-22 Branches: 1220 2694 45.3 %

Line Exec Source
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
331
BoundedIntegers::IntRangeDecisionHeuristic::IntRangeDecisionHeuristic(
40
    Node r,
41
    context::Context* c,
42
    context::Context* u,
43
    Valuation valuation,
44
331
    bool isProxy)
45
331
    : DecisionStrategyFmf(c, valuation), d_range(r), d_ranges_proxied(u)
46
{
47
331
  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
327
    d_proxy_range = r;
52
  }
53
331
  if( !isProxy ){
54
319
    Trace("bound-int") << "Introduce proxy " << d_proxy_range << " for " << d_range << std::endl;
55
  }
56
331
}
57
1064
Node BoundedIntegers::IntRangeDecisionHeuristic::mkLiteral(unsigned n)
58
{
59
1064
  NodeManager* nm = NodeManager::currentNM();
60
2128
  Node cn = nm->mkConst(Rational(n == 0 ? 0 : n - 1));
61
2128
  return nm->mkNode(n == 0 ? LT : LEQ, d_proxy_range, cn);
62
}
63
64
1152
Node BoundedIntegers::IntRangeDecisionHeuristic::proxyCurrentRangeLemma()
65
{
66
1152
  if (d_range == d_proxy_range)
67
  {
68
1148
    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
1098
BoundedIntegers::BoundedIntegers(QuantifiersState& qs,
92
                                 QuantifiersInferenceManager& qim,
93
                                 QuantifiersRegistry& qr,
94
1098
                                 TermRegistry& tr)
95
1098
    : QuantifiersModule(qs, qim, qr, tr)
96
{
97
1098
}
98
99
2196
BoundedIntegers::~BoundedIntegers() {}
100
101
1222
void BoundedIntegers::presolve() {
102
1222
  d_bnd_it.clear();
103
1222
}
104
105
6717
bool BoundedIntegers::hasNonBoundVar( Node f, Node b, std::map< Node, bool >& visited ) {
106
6717
  if( visited.find( b )==visited.end() ){
107
6303
    visited[b] = true;
108
6303
    if( b.getKind()==BOUND_VARIABLE ){
109
630
      if( !isBound( f, b ) ){
110
330
        return true;
111
      }
112
    }else{
113
9805
      for( unsigned i=0; i<b.getNumChildren(); i++ ){
114
4501
        if( hasNonBoundVar( f, b[i], visited ) ){
115
369
          return true;
116
        }
117
      }
118
    }
119
  }
120
6018
  return false;
121
}
122
2216
bool BoundedIntegers::hasNonBoundVar( Node f, Node b ) {
123
4432
  std::map< Node, bool > visited;
124
4432
  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
6034
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
6034
  if( n.getKind()==OR || n.getKind()==AND ){
167
1154
    if( (n.getKind()==OR)==pol ){
168
4046
      for( unsigned i=0; i<n.getNumChildren(); i++) {
169
3128
        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
472
      Node conj = n;
174
236
      if( !pol ){
175
        conj = TermUtil::simpleNegate( conj );
176
      }
177
236
      Trace("bound-int-debug") << "Process possible finite disequality conjunction : " << conj << std::endl;
178
236
      Assert(conj.getKind() == AND);
179
472
      Node v;
180
472
      std::vector< Node > v_cases;
181
236
      bool success = true;
182
286
      for( unsigned i=0; i<conj.getNumChildren(); i++ ){
183
262
        if( conj[i].getKind()==NOT && processEqDisjunct( q, conj[i][0], v, v_cases ) ){
184
          //continue
185
        }else{
186
212
          Trace("bound-int-debug") << "...failed due to " << conj[i] << std::endl;
187
212
          success = false;
188
212
          break;
189
        }
190
      }
191
236
      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
4880
  }else if( n.getKind()==EQUAL ){
201
927
    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
3953
  }else if( n.getKind()==NOT ){
217
1815
    process( q, n[0], !pol, bound_lit_type_map, bound_lit_map, bound_lit_pol_map, bound_int_range_term, bound_fixed_set );
218
2138
  }else if( n.getKind()==GEQ ){
219
1683
    if( n[0].getType().isInteger() ){
220
3358
      std::map< Node, Node > msum;
221
1679
      if (ArithMSum::getMonomialSumLit(n, msum))
222
      {
223
1679
        Trace("bound-int-debug") << "literal (polarity = " << pol << ") " << n << " is monomial sum : " << std::endl;
224
1679
        ArithMSum::debugPrintMonomialSum(msum, "bound-int-debug");
225
5039
        for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
226
3360
          if ( !it->first.isNull() && it->first.getKind()==BOUND_VARIABLE && !isBound( q, it->first ) ){
227
            //if not bound in another way
228
799
            if( bound_lit_type_map.find( it->first )==bound_lit_type_map.end() || bound_lit_type_map[it->first] == BOUND_INT_RANGE ){
229
1588
              Node veq;
230
794
              if (ArithMSum::isolate(it->first, msum, veq, GEQ) != 0)
231
              {
232
1588
                Node n1 = veq[0];
233
1588
                Node n2 = veq[1];
234
794
                if(pol){
235
                  //flip
236
365
                  n1 = veq[1];
237
365
                  n2 = veq[0];
238
365
                  if( n1.getKind()==BOUND_VARIABLE ){
239
6
                    n2 = ArithMSum::offset(n2, 1);
240
                  }else{
241
359
                    n1 = ArithMSum::offset(n1, -1);
242
                  }
243
365
                  veq = NodeManager::currentNM()->mkNode( GEQ, n1, n2 );
244
                }
245
794
                Trace("bound-int-debug") << "Isolated for " << it->first << " : (" << n1 << " >= " << n2 << ")" << std::endl;
246
1588
                Node t = n1==it->first ? n2 : n1;
247
794
                if( !hasNonBoundVar( q, t ) ) {
248
772
                  Trace("bound-int-debug") << "The bound is relevant." << std::endl;
249
772
                  int loru = n1==it->first ? 0 : 1;
250
772
                  bound_lit_type_map[it->first] = BOUND_INT_RANGE;
251
772
                  bound_int_range_term[loru][it->first] = t;
252
772
                  bound_lit_map[loru][it->first] = n;
253
772
                  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
455
  }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
375
    Assert(n.getKind() != LEQ && n.getKind() != LT && n.getKind() != GT);
278
  }
279
6034
}
280
281
9559
bool BoundedIntegers::needsCheck( Theory::Effort e ) {
282
9559
  return e==Theory::EFFORT_LAST_CALL;
283
}
284
285
2845
void BoundedIntegers::check(Theory::Effort e, QEffort quant_e)
286
{
287
2845
  if (quant_e != QEFFORT_STANDARD)
288
  {
289
1895
    return;
290
  }
291
950
  Trace("bint-engine") << "---Bounded Integers---" << std::endl;
292
950
  bool addedLemma = false;
293
  // make sure proxies are up-to-date with range
294
2102
  for (const Node& r : d_ranges)
295
  {
296
2304
    Node prangeLem = d_rms[r]->proxyCurrentRangeLemma();
297
1152
    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
950
  Trace("bint-engine") << "   addedLemma = " << addedLemma << std::endl;
306
}
307
550
void BoundedIntegers::setBoundedVar(Node q, Node v, BoundVarType bound_type)
308
{
309
550
  d_bound_type[q][v] = bound_type;
310
550
  d_set_nums[q][v] = d_set[q].size();
311
550
  d_set[q].push_back( v );
312
1100
  Trace("bound-int-var") << "Bound variable #" << d_set_nums[q][v] << " : " << v
313
550
                         << std::endl;
314
550
}
315
316
557
void BoundedIntegers::checkOwnership(Node f)
317
{
318
  //this needs to be done at preregister since it affects e.g. QuantDSplit's preregister
319
557
  Trace("bound-int") << "check ownership quantifier " << f << std::endl;
320
557
  NodeManager* nm = NodeManager::currentNM();
321
557
  SkolemManager* sm = nm->getSkolemManager();
322
323
  bool success;
324
1091
  do{
325
2182
    std::map< Node, unsigned > bound_lit_type_map;
326
2182
    std::map< int, std::map< Node, Node > > bound_lit_map;
327
2182
    std::map< int, std::map< Node, bool > > bound_lit_pol_map;
328
2182
    std::map< int, std::map< Node, Node > > bound_int_range_term;
329
2182
    std::map< Node, std::vector< Node > > bound_fixed_set;
330
1091
    success = false;
331
1091
    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
1523
    for( std::map< Node, unsigned >::iterator it = bound_lit_type_map.begin(); it != bound_lit_type_map.end(); ++it ){
334
864
      Node v = it->first;
335
432
      if( !isBound( f, v ) ){
336
432
        bool setBoundVar = false;
337
432
        if( it->second==BOUND_INT_RANGE ){
338
          //must have both
339
385
          std::map<Node, Node>& blm0 = bound_lit_map[0];
340
385
          std::map<Node, Node>& blm1 = bound_lit_map[1];
341
385
          if (blm0.find(v) != blm0.end() && blm1.find(v) != blm1.end())
342
          {
343
365
            setBoundedVar( f, v, BOUND_INT_RANGE );
344
365
            setBoundVar = true;
345
1095
            for( unsigned b=0; b<2; b++ ){
346
              //set the bounds
347
730
              Assert(bound_int_range_term[b].find(v)
348
                     != bound_int_range_term[b].end());
349
730
              d_bounds[b][f][v] = bound_int_range_term[b][v];
350
            }
351
730
            Node r = nm->mkNode(MINUS, d_bounds[1][f][v], d_bounds[0][f][v]);
352
365
            d_range[f][v] = Rewriter::rewrite(r);
353
365
            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
432
        if( setBoundVar ){
391
412
          success = true;
392
          //set Attributes on literals
393
1236
          for( unsigned b=0; b<2; b++ ){
394
824
            std::map<Node, Node>& blm = bound_lit_map[b];
395
824
            if (blm.find(v) != blm.end())
396
            {
397
730
              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
730
              Assert(blmp.find(v) != blmp.end());
404
              BoundIntLitAttribute bila;
405
730
              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
1091
    if( !success ){
416
      //resort to setting a finite bound on a variable
417
1369
      for( unsigned i=0; i<f[0].getNumChildren(); i++) {
418
812
        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
557
  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
557
  bool bound_success = true;
470
1105
  for( unsigned i=0; i<f[0].getNumChildren(); i++) {
471
617
    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
557
  if( bound_success ){
479
488
    d_bound_quants.push_back( f );
480
488
    DecisionManager* dm = d_qim.getDecisionManager();
481
1036
    for( unsigned i=0; i<d_set[f].size(); i++) {
482
1096
      Node v = d_set[f][i];
483
548
      std::map< Node, Node >::iterator itr = d_range[f].find( v );
484
548
      if( itr != d_range[f].end() ){
485
796
        Node r = itr->second;
486
398
        Assert(!r.isNull());
487
398
        bool isProxy = false;
488
398
        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
398
        if( !r.isConst() ){
499
362
          if (d_rms.find(r) == d_rms.end())
500
          {
501
331
            Trace("bound-int") << "For " << v << ", bounded Integer Module will try to minimize : " << r << std::endl;
502
331
            d_ranges.push_back( r );
503
993
            d_rms[r].reset(
504
                new IntRangeDecisionHeuristic(r,
505
331
                                              d_qstate.getSatContext(),
506
331
                                              d_qstate.getUserContext(),
507
331
                                              d_qstate.getValuation(),
508
331
                                              isProxy));
509
331
            dm->registerStrategy(DecisionManager::STRAT_QUANT_BOUND_INT_SIZE,
510
331
                                 d_rms[r].get());
511
          }
512
        }
513
      }
514
    }
515
  }
516
557
}
517
518
3684
bool BoundedIntegers::isBound(Node q, Node v) const
519
{
520
3684
  std::map<Node, std::vector<Node> >::const_iterator its = d_set.find(q);
521
3684
  if (its == d_set.end())
522
  {
523
1544
    return false;
524
  }
525
4280
  return std::find(its->second.begin(), its->second.end(), v)
526
6420
         != its->second.end();
527
}
528
529
6586
BoundVarType BoundedIntegers::getBoundVarType(Node q, Node v) const
530
{
531
  std::map<Node, std::map<Node, BoundVarType> >::const_iterator itb =
532
6586
      d_bound_type.find(q);
533
6586
  if (itb == d_bound_type.end())
534
  {
535
    return BOUND_NONE;
536
  }
537
6586
  std::map<Node, BoundVarType>::const_iterator it = itb->second.find(v);
538
6586
  if (it == itb->second.end())
539
  {
540
22
    return BOUND_NONE;
541
  }
542
6564
  return it->second;
543
}
544
545
3200
void BoundedIntegers::getBoundVarIndices(Node q,
546
                                         std::vector<unsigned>& indices) const
547
{
548
3200
  std::map<Node, std::vector<Node> >::const_iterator it = d_set.find(q);
549
3200
  if (it != d_set.end())
550
  {
551
7456
    for (const Node& v : it->second)
552
    {
553
4264
      indices.push_back(TermUtil::getVariableNum(q, v));
554
    }
555
  }
556
3200
}
557
558
4252
void BoundedIntegers::getBounds( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u ) {
559
4252
  l = d_bounds[0][f][v];
560
4252
  u = d_bounds[1][f][v];
561
4252
  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
4252
}
574
575
2144
void BoundedIntegers::getBoundValues( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u ) {
576
2144
  getBounds( f, v, rsi, l, u );
577
2144
  Trace("bound-int-rsi") << "Get value in model for..." << l << " and " << u << std::endl;
578
2144
  if( !l.isNull() ){
579
2108
    l = d_treg.getModel()->getValue(l);
580
  }
581
2144
  if( !u.isNull() ){
582
2108
    u = d_treg.getModel()->getValue(u);
583
  }
584
2144
  Trace("bound-int-rsi") << "Value is " << l << " ... " << u << std::endl;
585
2144
  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
2578
bool BoundedIntegers::getBoundElements( RepSetIterator * rsi, bool initial, Node q, Node v, std::vector< Node >& elements ) {
772
2578
  if( initial || !isGroundRange( q, v ) ){
773
2308
    elements.clear();
774
2308
    BoundVarType bvt = getBoundVarType(q, v);
775
2308
    if( bvt==BOUND_INT_RANGE ){
776
4288
      Node l, u;
777
2144
      getBoundValues( q, v, rsi, l, u );
778
2144
      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
2108
        Trace("bound-int-rsi") << "Can limit bounds of " << v << " to " << l << "..." << u << std::endl;
784
4216
        Node range = Rewriter::rewrite( NodeManager::currentNM()->mkNode( MINUS, u, l ) );
785
4216
        Node ra = Rewriter::rewrite( NodeManager::currentNM()->mkNode( LEQ, range, NodeManager::currentNM()->mkConst( Rational( 9999 ) ) ) );
786
4216
        Node tl = l;
787
4216
        Node tu = u;
788
2108
        getBounds( q, v, rsi, tl, tu );
789
2108
        Assert(!tl.isNull() && !tu.isNull());
790
2108
        if (ra.isConst() && ra.getConst<bool>())
791
        {
792
2108
          long rr = range.getConst<Rational>().getNumerator().getLong()+1;
793
2108
          Trace("bound-int-rsi")  << "Actual bound range is " << rr << std::endl;
794
14963
          for (long k = 0; k < rr; k++)
795
          {
796
25710
            Node t = NodeManager::currentNM()->mkNode(PLUS, tl, NodeManager::currentNM()->mkConst( Rational(k) ) );
797
12855
            t = Rewriter::rewrite( t );
798
12855
            elements.push_back( t );
799
          }
800
2108
          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
28194
}