GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/quantifiers_rewriter.cpp Lines: 875 1086 80.6 %
Date: 2021-11-07 Branches: 1893 4423 42.8 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Morgan Deters, Haniel Barbosa
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
 * Implementation of QuantifiersRewriter class.
14
 */
15
16
#include "theory/quantifiers/quantifiers_rewriter.h"
17
18
#include "expr/ascription_type.h"
19
#include "expr/bound_var_manager.h"
20
#include "expr/dtype.h"
21
#include "expr/dtype_cons.h"
22
#include "expr/node_algorithm.h"
23
#include "expr/skolem_manager.h"
24
#include "options/quantifiers_options.h"
25
#include "theory/arith/arith_msum.h"
26
#include "theory/datatypes/theory_datatypes_utils.h"
27
#include "theory/quantifiers/bv_inverter.h"
28
#include "theory/quantifiers/ematching/trigger.h"
29
#include "theory/quantifiers/extended_rewrite.h"
30
#include "theory/quantifiers/quantifiers_attributes.h"
31
#include "theory/quantifiers/skolemize.h"
32
#include "theory/quantifiers/term_database.h"
33
#include "theory/quantifiers/term_util.h"
34
#include "theory/rewriter.h"
35
#include "theory/strings/theory_strings_utils.h"
36
#include "util/rational.h"
37
38
using namespace std;
39
using namespace cvc5::kind;
40
using namespace cvc5::context;
41
42
namespace cvc5 {
43
namespace theory {
44
namespace quantifiers {
45
46
/**
47
 * Attributes used for constructing bound variables in a canonical way. These
48
 * are attributes that map to bound variable, introduced for the following
49
 * purposes:
50
 * - QRewPrenexAttribute: cached on (v, body) where we are prenexing bound
51
 * variable v in a nested quantified formula within the given body.
52
 * - QRewMiniscopeAttribute: cached on (v, q, i) where q is being miniscoped
53
 * for F_i in its body (and F_1 ... F_n), and v is one of the bound variables
54
 * that q binds.
55
 * - QRewDtExpandAttribute: cached on (F, lit, a) where lit is the tested
56
 * literal used for expanding a quantified datatype variable in quantified
57
 * formula with body F, and a is the rational corresponding to the argument
58
 * position of the variable, e.g. lit is ((_ is C) x) and x is
59
 * replaced by (C y1 ... yn), where the argument position of yi is i.
60
 */
61
struct QRewPrenexAttributeId
62
{
63
};
64
typedef expr::Attribute<QRewPrenexAttributeId, Node> QRewPrenexAttribute;
65
struct QRewMiniscopeAttributeId
66
{
67
};
68
typedef expr::Attribute<QRewMiniscopeAttributeId, Node> QRewMiniscopeAttribute;
69
struct QRewDtExpandAttributeId
70
{
71
};
72
typedef expr::Attribute<QRewDtExpandAttributeId, Node> QRewDtExpandAttribute;
73
74
std::ostream& operator<<(std::ostream& out, RewriteStep s)
75
{
76
  switch (s)
77
  {
78
    case COMPUTE_ELIM_SYMBOLS: out << "COMPUTE_ELIM_SYMBOLS"; break;
79
    case COMPUTE_MINISCOPING: out << "COMPUTE_MINISCOPING"; break;
80
    case COMPUTE_AGGRESSIVE_MINISCOPING:
81
      out << "COMPUTE_AGGRESSIVE_MINISCOPING";
82
      break;
83
    case COMPUTE_EXT_REWRITE: out << "COMPUTE_EXT_REWRITE"; break;
84
    case COMPUTE_PROCESS_TERMS: out << "COMPUTE_PROCESS_TERMS"; break;
85
    case COMPUTE_PRENEX: out << "COMPUTE_PRENEX"; break;
86
    case COMPUTE_VAR_ELIMINATION: out << "COMPUTE_VAR_ELIMINATION"; break;
87
    case COMPUTE_COND_SPLIT: out << "COMPUTE_COND_SPLIT"; break;
88
    default: out << "UnknownRewriteStep"; break;
89
  }
90
  return out;
91
}
92
93
15434
QuantifiersRewriter::QuantifiersRewriter(const Options& opts) : d_opts(opts) {}
94
95
15402
bool QuantifiersRewriter::isLiteral( Node n ){
96
15402
  switch( n.getKind() ){
97
  case NOT:
98
    return n[0].getKind()!=NOT && isLiteral( n[0] );
99
    break;
100
  case OR:
101
  case AND:
102
  case IMPLIES:
103
  case XOR:
104
  case ITE:
105
    return false;
106
    break;
107
9077
  case EQUAL:
108
    //for boolean terms
109
9077
    return !n[0].getType().isBoolean();
110
    break;
111
6325
  default:
112
6325
    break;
113
  }
114
6325
  return true;
115
}
116
117
5186074
void QuantifiersRewriter::computeArgs(const std::vector<Node>& args,
118
                                      std::map<Node, bool>& activeMap,
119
                                      Node n,
120
                                      std::map<Node, bool>& visited)
121
{
122
5186074
  if( visited.find( n )==visited.end() ){
123
3677820
    visited[n] = true;
124
3677820
    if( n.getKind()==BOUND_VARIABLE ){
125
611482
      if( std::find( args.begin(), args.end(), n )!=args.end() ){
126
502215
        activeMap[ n ] = true;
127
      }
128
    }else{
129
3066338
      if (n.hasOperator())
130
      {
131
1622708
        computeArgs(args, activeMap, n.getOperator(), visited);
132
      }
133
6329016
      for( int i=0; i<(int)n.getNumChildren(); i++ ){
134
3262678
        computeArgs( args, activeMap, n[i], visited );
135
      }
136
    }
137
  }
138
5186074
}
139
140
154896
void QuantifiersRewriter::computeArgVec(const std::vector<Node>& args,
141
                                        std::vector<Node>& activeArgs,
142
                                        Node n)
143
{
144
154896
  Assert(activeArgs.empty());
145
309792
  std::map< Node, bool > activeMap;
146
309792
  std::map< Node, bool > visited;
147
154896
  computeArgs( args, activeMap, n, visited );
148
154896
  if( !activeMap.empty() ){
149
2439857
    for( unsigned i=0; i<args.size(); i++ ){
150
2286621
      if( activeMap.find( args[i] )!=activeMap.end() ){
151
352353
        activeArgs.push_back( args[i] );
152
      }
153
    }
154
  }
155
154896
}
156
157
73021
void QuantifiersRewriter::computeArgVec2(const std::vector<Node>& args,
158
                                         std::vector<Node>& activeArgs,
159
                                         Node n,
160
                                         Node ipl)
161
{
162
73021
  Assert(activeArgs.empty());
163
146042
  std::map< Node, bool > activeMap;
164
146042
  std::map< Node, bool > visited;
165
73021
  computeArgs( args, activeMap, n, visited );
166
73021
  if( !activeMap.empty() ){
167
    //collect variables in inst pattern list only if we cannot eliminate quantifier
168
72771
    computeArgs( args, activeMap, ipl, visited );
169
223723
    for( unsigned i=0; i<args.size(); i++ ){
170
150952
      if( activeMap.find( args[i] )!=activeMap.end() ){
171
149862
        activeArgs.push_back( args[i] );
172
      }
173
    }
174
  }
175
73021
}
176
177
143131
RewriteResponse QuantifiersRewriter::preRewrite(TNode in) {
178
143131
  if( in.getKind()==kind::EXISTS || in.getKind()==kind::FORALL ){
179
84038
    Trace("quantifiers-rewrite-debug") << "pre-rewriting " << in << std::endl;
180
166287
    std::vector< Node > args;
181
166287
    Node body = in;
182
84038
    bool doRewrite = false;
183
98360
    while( body.getNumChildren()==2 && body.getKind()==body[1].getKind() ){
184
14381
      for( unsigned i=0; i<body[0].getNumChildren(); i++ ){
185
7220
        args.push_back( body[0][i] );
186
      }
187
7161
      body = body[1];
188
7161
      doRewrite = true;
189
    }
190
84038
    if( doRewrite ){
191
3578
      std::vector< Node > children;
192
3618
      for( unsigned i=0; i<body[0].getNumChildren(); i++ ){
193
1829
        args.push_back( body[0][i] );
194
      }
195
1789
      children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST,args) );
196
1789
      children.push_back( body[1] );
197
1789
      if( body.getNumChildren()==3 ){
198
48
        children.push_back( body[2] );
199
      }
200
3578
      Node n = NodeManager::currentNM()->mkNode( in.getKind(), children );
201
1789
      if( in!=n ){
202
1789
        Trace("quantifiers-pre-rewrite") << "*** pre-rewrite " << in << std::endl;
203
1789
        Trace("quantifiers-pre-rewrite") << " to " << std::endl;
204
1789
        Trace("quantifiers-pre-rewrite") << n << std::endl;
205
      }
206
1789
      return RewriteResponse(REWRITE_DONE, n);
207
    }
208
  }
209
141342
  return RewriteResponse(REWRITE_DONE, in);
210
}
211
212
261136
RewriteResponse QuantifiersRewriter::postRewrite(TNode in) {
213
261136
  Trace("quantifiers-rewrite-debug") << "post-rewriting " << in << std::endl;
214
261136
  RewriteStatus status = REWRITE_DONE;
215
522272
  Node ret = in;
216
261136
  RewriteStep rew_op = COMPUTE_LAST;
217
  //get the body
218
261136
  if( in.getKind()==EXISTS ){
219
6454
    std::vector< Node > children;
220
3227
    children.push_back( in[0] );
221
3227
    children.push_back( in[1].negate() );
222
3227
    if( in.getNumChildren()==3 ){
223
45
      children.push_back( in[2] );
224
    }
225
3227
    ret = NodeManager::currentNM()->mkNode( FORALL, children );
226
3227
    ret = ret.negate();
227
3227
    status = REWRITE_AGAIN_FULL;
228
257909
  }else if( in.getKind()==FORALL ){
229
140099
    if( in[1].isConst() && in.getNumChildren()==2 ){
230
952
      return RewriteResponse( status, in[1] );
231
    }else{
232
      //compute attributes
233
278294
      QAttributes qa;
234
139147
      QuantAttributes::computeQuantAttributes( in, qa );
235
1119108
      for (unsigned i = 0; i < COMPUTE_LAST; ++i)
236
      {
237
999602
        RewriteStep op = static_cast<RewriteStep>(i);
238
999602
        if( doOperation( in, op, qa ) ){
239
735992
          ret = computeOperation( in, op, qa );
240
735992
          if( ret!=in ){
241
19641
            rew_op = op;
242
19641
            status = REWRITE_AGAIN_FULL;
243
19641
            break;
244
          }
245
        }
246
      }
247
    }
248
  }
249
  //print if changed
250
260184
  if( in!=ret ){
251
22868
    Trace("quantifiers-rewrite") << "*** rewrite (op=" << rew_op << ") " << in << std::endl;
252
22868
    Trace("quantifiers-rewrite") << " to " << std::endl;
253
22868
    Trace("quantifiers-rewrite") << ret << std::endl;
254
  }
255
260184
  return RewriteResponse( status, ret );
256
}
257
258
840490
bool QuantifiersRewriter::addCheckElimChild(std::vector<Node>& children,
259
                                            Node c,
260
                                            Kind k,
261
                                            std::map<Node, bool>& lit_pol,
262
                                            bool& childrenChanged) const
263
{
264
840490
  if ((k == OR || k == AND) && d_opts.quantifiers.elimTautQuant)
265
  {
266
1353618
    Node lit = c.getKind()==NOT ? c[0] : c;
267
676934
    bool pol = c.getKind()!=NOT;
268
676934
    std::map< Node, bool >::iterator it = lit_pol.find( lit );
269
676934
    if( it==lit_pol.end() ){
270
675971
      lit_pol[lit] = pol;
271
675971
      children.push_back( c );
272
    }else{
273
963
      childrenChanged = true;
274
963
      if( it->second!=pol ){
275
250
        return false;
276
      }
277
676684
    }
278
  }
279
  else
280
  {
281
163556
    children.push_back( c );
282
  }
283
840240
  return true;
284
}
285
286
964870
Node QuantifiersRewriter::computeElimSymbols(Node body) const
287
{
288
964870
  Kind ok = body.getKind();
289
964870
  Kind k = ok;
290
964870
  bool negAllCh = false;
291
964870
  bool negCh1 = false;
292
964870
  if( ok==IMPLIES ){
293
12028
    k = OR;
294
12028
    negCh1 = true;
295
952842
  }else if( ok==XOR ){
296
771
    k = EQUAL;
297
771
    negCh1 = true;
298
952071
  }else if( ok==NOT ){
299
388609
    if( body[0].getKind()==NOT ){
300
      return computeElimSymbols( body[0][0] );
301
388609
    }else if( body[0].getKind()==OR || body[0].getKind()==IMPLIES ){
302
1751
      k = AND;
303
1751
      negAllCh = true;
304
1751
      negCh1 = body[0].getKind()==IMPLIES;
305
1751
      body = body[0];
306
386858
    }else if( body[0].getKind()==AND ){
307
6142
      k = OR;
308
6142
      negAllCh = true;
309
6142
      body = body[0];
310
380716
    }else if( body[0].getKind()==XOR || ( body[0].getKind()==EQUAL && body[0][0].getType().isBoolean() ) ){
311
2834
      k = EQUAL;
312
2834
      negCh1 = ( body[0].getKind()==EQUAL );
313
2834
      body = body[0];
314
377882
    }else if( body[0].getKind()==ITE ){
315
95
      k = body[0].getKind();
316
95
      negAllCh = true;
317
95
      negCh1 = true;
318
95
      body = body[0];
319
    }else{
320
377787
      return body;
321
    }
322
563462
  }else if( ( ok!=EQUAL || !body[0].getType().isBoolean() ) && ok!=ITE && ok!=AND && ok!=OR ){
323
    //a literal
324
336591
    return body;
325
  }
326
250492
  bool childrenChanged = false;
327
500984
  std::vector< Node > children;
328
500984
  std::map< Node, bool > lit_pol;
329
1075965
  for( unsigned i=0; i<body.getNumChildren(); i++ ){
330
1651196
    Node c = computeElimSymbols( ( i==0 && negCh1 )!=negAllCh ? body[i].negate() : body[i] );
331
825723
    bool success = true;
332
825723
    if( c.getKind()==k && ( k==OR || k==AND ) ){
333
      //flatten
334
5735
      childrenChanged = true;
335
26236
      for( unsigned j=0; j<c.getNumChildren(); j++ ){
336
20502
        if( !addCheckElimChild( children, c[j], k, lit_pol, childrenChanged ) ){
337
1
          success = false;
338
1
          break;
339
        }
340
      }
341
    }else{
342
819988
      success = addCheckElimChild( children, c, k, lit_pol, childrenChanged );
343
    }
344
825723
    if( !success ){
345
      // tautology
346
250
      Assert(k == OR || k == AND);
347
250
      return NodeManager::currentNM()->mkConst( k==OR );
348
    }
349
825473
    childrenChanged = childrenChanged || c!=body[i];
350
  }
351
250242
  if( childrenChanged || k!=ok ){
352
27462
    return ( children.size()==1 && k!=NOT ) ? children[0] : NodeManager::currentNM()->mkNode( k, children );
353
  }else{
354
222780
    return body;
355
  }
356
}
357
358
void QuantifiersRewriter::computeDtTesterIteSplit( Node n, std::map< Node, Node >& pcons, std::map< Node, std::map< int, Node > >& ncons,
359
                                                   std::vector< Node >& conj ){
360
  if( n.getKind()==ITE && n[0].getKind()==APPLY_TESTER && n[1].getType().isBoolean() ){
361
    Trace("quantifiers-rewrite-ite-debug") << "Split tester condition : " << n << std::endl;
362
    Node x = n[0][0];
363
    std::map< Node, Node >::iterator itp = pcons.find( x );
364
    if( itp!=pcons.end() ){
365
      Trace("quantifiers-rewrite-ite-debug") << "...condition already set " << itp->second << std::endl;
366
      computeDtTesterIteSplit( n[ itp->second==n[0] ? 1 : 2 ], pcons, ncons, conj );
367
    }else{
368
      Node tester = n[0].getOperator();
369
      int index = datatypes::utils::indexOf(tester);
370
      std::map< int, Node >::iterator itn = ncons[x].find( index );
371
      if( itn!=ncons[x].end() ){
372
        Trace("quantifiers-rewrite-ite-debug") << "...condition negated " << itn->second << std::endl;
373
        computeDtTesterIteSplit( n[ 2 ], pcons, ncons, conj );
374
      }else{
375
        for( unsigned i=0; i<2; i++ ){
376
          if( i==0 ){
377
            pcons[x] = n[0];
378
          }else{
379
            pcons.erase( x );
380
            ncons[x][index] = n[0].negate();
381
          }
382
          computeDtTesterIteSplit( n[i+1], pcons, ncons, conj );
383
        }
384
        ncons[x].erase( index );
385
      }
386
    }
387
  }else{
388
    NodeManager* nm = NodeManager::currentNM();
389
    Trace("quantifiers-rewrite-ite-debug") << "Return value : " << n << std::endl;
390
    std::vector< Node > children;
391
    children.push_back( n );
392
    std::vector< Node > vars;
393
    //add all positive testers
394
    for( std::map< Node, Node >::iterator it = pcons.begin(); it != pcons.end(); ++it ){
395
      children.push_back( it->second.negate() );
396
      vars.push_back( it->first );
397
    }
398
    //add all negative testers
399
    for( std::map< Node, std::map< int, Node > >::iterator it = ncons.begin(); it != ncons.end(); ++it ){
400
      Node x = it->first;
401
      //only if we haven't settled on a positive tester
402
      if( std::find( vars.begin(), vars.end(), x )==vars.end() ){
403
        //check if we have exhausted all options but one
404
        const DType& dt = x.getType().getDType();
405
        std::vector< Node > nchildren;
406
        int pos_cons = -1;
407
        for( int i=0; i<(int)dt.getNumConstructors(); i++ ){
408
          std::map< int, Node >::iterator itt = it->second.find( i );
409
          if( itt==it->second.end() ){
410
            pos_cons = pos_cons==-1 ? i : -2;
411
          }else{
412
            nchildren.push_back( itt->second.negate() );
413
          }
414
        }
415
        if( pos_cons>=0 ){
416
          Node tester = dt[pos_cons].getTester();
417
          children.push_back(nm->mkNode(APPLY_TESTER, tester, x).negate());
418
        }else{
419
          children.insert( children.end(), nchildren.begin(), nchildren.end() );
420
        }
421
      }
422
    }
423
    //make condition/output pair
424
    Node c = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( OR, children );
425
    conj.push_back( c );
426
  }
427
}
428
429
119432
Node QuantifiersRewriter::computeProcessTerms(Node body,
430
                                              std::vector<Node>& new_vars,
431
                                              std::vector<Node>& new_conds,
432
                                              Node q,
433
                                              QAttributes& qa) const
434
{
435
238864
  std::map< Node, Node > cache;
436
119432
  if( qa.isFunDef() ){
437
    Node h = QuantAttributes::getFunDefHead( q );
438
    Assert(!h.isNull());
439
    // if it is a function definition, rewrite the body independently
440
    Node fbody = QuantAttributes::getFunDefBody( q );
441
    Trace("quantifiers-rewrite-debug") << "Decompose " << h << " / " << fbody << " as function definition for " << q << "." << std::endl;
442
    if (!fbody.isNull())
443
    {
444
      Node r = computeProcessTerms2(fbody, cache, new_vars, new_conds);
445
      Assert(new_vars.size() == h.getNumChildren());
446
      return Rewriter::rewrite(NodeManager::currentNM()->mkNode(EQUAL, h, r));
447
    }
448
    // It can happen that we can't infer the shape of the function definition,
449
    // for example: forall xy. f( x, y ) = 1 + f( x, y ), this is rewritten to
450
    // forall xy. false.
451
  }
452
119432
  return computeProcessTerms2(body, cache, new_vars, new_conds);
453
}
454
455
3109677
Node QuantifiersRewriter::computeProcessTerms2(
456
    Node body,
457
    std::map<Node, Node>& cache,
458
    std::vector<Node>& new_vars,
459
    std::vector<Node>& new_conds) const
460
{
461
3109677
  NodeManager* nm = NodeManager::currentNM();
462
6219354
  Trace("quantifiers-rewrite-term-debug2")
463
3109677
      << "computeProcessTerms " << body << std::endl;
464
3109677
  std::map< Node, Node >::iterator iti = cache.find( body );
465
3109677
  if( iti!=cache.end() ){
466
1023036
    return iti->second;
467
  }
468
2086641
  bool changed = false;
469
4173282
  std::vector<Node> children;
470
5076886
  for (size_t i = 0; i < body.getNumChildren(); i++)
471
  {
472
    // do the recursive call on children
473
5980490
    Node nn = computeProcessTerms2(body[i], cache, new_vars, new_conds);
474
2990245
    children.push_back(nn);
475
2990245
    changed = changed || nn != body[i];
476
  }
477
478
  // make return value
479
4173282
  Node ret;
480
2086641
  if (changed)
481
  {
482
5730
    if (body.getMetaKind() == kind::metakind::PARAMETERIZED)
483
    {
484
197
      children.insert(children.begin(), body.getOperator());
485
    }
486
5730
    ret = nm->mkNode(body.getKind(), children);
487
  }
488
  else
489
  {
490
2080911
    ret = body;
491
  }
492
493
4173282
  Trace("quantifiers-rewrite-term-debug2")
494
2086641
      << "Returning " << ret << " for " << body << std::endl;
495
  // do context-independent rewriting
496
4173282
  if (ret.getKind() == EQUAL
497
2086641
      && d_opts.quantifiers.iteLiftQuant != options::IteLiftQuantMode::NONE)
498
  {
499
726413
    for (size_t i = 0; i < 2; i++)
500
    {
501
484693
      if (ret[i].getKind() == ITE)
502
      {
503
23725
        Node no = i == 0 ? ret[1] : ret[0];
504
12328
        if (no.getKind() != ITE)
505
        {
506
11012
          bool doRewrite =
507
11012
              d_opts.quantifiers.iteLiftQuant == options::IteLiftQuantMode::ALL;
508
21093
          std::vector<Node> childrenIte;
509
11012
          childrenIte.push_back(ret[i][0]);
510
33036
          for (size_t j = 1; j <= 2; j++)
511
          {
512
            // check if it rewrites to a constant
513
44048
            Node nn = nm->mkNode(EQUAL, no, ret[i][j]);
514
22024
            nn = Rewriter::rewrite(nn);
515
22024
            childrenIte.push_back(nn);
516
22024
            if (nn.isConst())
517
            {
518
1300
              doRewrite = true;
519
            }
520
          }
521
11012
          if (doRewrite)
522
          {
523
931
            ret = nm->mkNode(ITE, childrenIte);
524
931
            break;
525
          }
526
        }
527
      }
528
    }
529
  }
530
1843990
  else if (ret.getKind() == SELECT && ret[0].getKind() == STORE)
531
  {
532
192
    Node st = ret[0];
533
192
    Node index = ret[1];
534
192
    std::vector<Node> iconds;
535
192
    std::vector<Node> elements;
536
602
    while (st.getKind() == STORE)
537
    {
538
253
      iconds.push_back(index.eqNode(st[1]));
539
253
      elements.push_back(st[2]);
540
253
      st = st[0];
541
    }
542
96
    ret = nm->mkNode(SELECT, st, index);
543
    // conditions
544
349
    for (int i = (iconds.size() - 1); i >= 0; i--)
545
    {
546
253
      ret = nm->mkNode(ITE, iconds[i], elements[i], ret);
547
    }
548
  }
549
2086641
  cache[body] = ret;
550
2086641
  return ret;
551
}
552
553
39
Node QuantifiersRewriter::computeExtendedRewrite(Node q, const QAttributes& qa)
554
{
555
  // do not apply to recursive functions
556
39
  if (qa.isFunDef())
557
  {
558
8
    return q;
559
  }
560
62
  Node body = q[1];
561
  // apply extended rewriter
562
62
  Node bodyr = Rewriter::callExtendedRewrite(body);
563
31
  if (body != bodyr)
564
  {
565
24
    std::vector<Node> children;
566
12
    children.push_back(q[0]);
567
12
    children.push_back(bodyr);
568
12
    if (q.getNumChildren() == 3)
569
    {
570
      children.push_back(q[2]);
571
    }
572
12
    return NodeManager::currentNM()->mkNode(FORALL, children);
573
  }
574
19
  return q;
575
}
576
577
119679
Node QuantifiersRewriter::computeCondSplit(Node body,
578
                                           const std::vector<Node>& args,
579
                                           QAttributes& qa) const
580
{
581
119679
  NodeManager* nm = NodeManager::currentNM();
582
119679
  Kind bk = body.getKind();
583
239718
  if (d_opts.quantifiers.iteDtTesterSplitQuant && bk == ITE
584
239366
      && body[0].getKind() == APPLY_TESTER)
585
  {
586
    Trace("quantifiers-rewrite-ite-debug") << "DTT split : " << body << std::endl;
587
    std::map< Node, Node > pcons;
588
    std::map< Node, std::map< int, Node > > ncons;
589
    std::vector< Node > conj;
590
    computeDtTesterIteSplit( body, pcons, ncons, conj );
591
    Assert(!conj.empty());
592
    if( conj.size()>1 ){
593
      Trace("quantifiers-rewrite-ite") << "*** Split ITE (datatype tester) " << body << " into : " << std::endl;
594
      for( unsigned i=0; i<conj.size(); i++ ){
595
        Trace("quantifiers-rewrite-ite") << "   " << conj[i] << std::endl;
596
      }
597
      return nm->mkNode(AND, conj);
598
    }
599
  }
600
119679
  if (!d_opts.quantifiers.condVarSplitQuant)
601
  {
602
    return body;
603
  }
604
239358
  Trace("cond-var-split-debug")
605
119679
      << "Conditional var elim split " << body << "?" << std::endl;
606
607
119679
  if (bk == ITE
608
119871
      || (bk == EQUAL && body[0].getType().isBoolean()
609
25060
          && d_opts.quantifiers.condVarSplitQuantAgg))
610
  {
611
192
    Assert(!qa.isFunDef());
612
192
    bool do_split = false;
613
192
    unsigned index_max = bk == ITE ? 0 : 1;
614
354
    std::vector<Node> tmpArgs = args;
615
354
    for (unsigned index = 0; index <= index_max; index++)
616
    {
617
576
      if (hasVarElim(body[index], true, tmpArgs)
618
576
          || hasVarElim(body[index], false, tmpArgs))
619
      {
620
30
        do_split = true;
621
30
        break;
622
      }
623
    }
624
192
    if (do_split)
625
    {
626
60
      Node pos;
627
60
      Node neg;
628
30
      if (bk == ITE)
629
      {
630
30
        pos = nm->mkNode(OR, body[0].negate(), body[1]);
631
30
        neg = nm->mkNode(OR, body[0], body[2]);
632
      }
633
      else
634
      {
635
        pos = nm->mkNode(OR, body[0].negate(), body[1]);
636
        neg = nm->mkNode(OR, body[0], body[1].negate());
637
      }
638
60
      Trace("cond-var-split-debug") << "*** Split (conditional variable eq) "
639
30
                                    << body << " into : " << std::endl;
640
30
      Trace("cond-var-split-debug") << "   " << pos << std::endl;
641
30
      Trace("cond-var-split-debug") << "   " << neg << std::endl;
642
30
      return nm->mkNode(AND, pos, neg);
643
    }
644
  }
645
646
119649
  if (bk == OR)
647
  {
648
47443
    unsigned size = body.getNumChildren();
649
47443
    bool do_split = false;
650
47443
    unsigned split_index = 0;
651
192925
    for (unsigned i = 0; i < size; i++)
652
    {
653
      // check if this child is a (conditional) variable elimination
654
291107
      Node b = body[i];
655
145625
      if (b.getKind() == AND)
656
      {
657
18050
        std::vector<Node> vars;
658
18050
        std::vector<Node> subs;
659
18050
        std::vector<Node> tmpArgs = args;
660
35674
        for (unsigned j = 0, bsize = b.getNumChildren(); j < bsize; j++)
661
        {
662
26792
          if (getVarElimLit(body, b[j], false, tmpArgs, vars, subs))
663
          {
664
5402
            Trace("cond-var-split-debug") << "Variable elimination in child #"
665
2701
                                          << j << " under " << i << std::endl;
666
            // Figure out if we should split
667
            // Currently we split if the aggressive option is set, or
668
            // if the top-level OR is binary.
669
2701
            if (d_opts.quantifiers.condVarSplitQuantAgg || size == 2)
670
            {
671
143
              do_split = true;
672
            }
673
            // other splitting criteria go here
674
675
2701
            if (do_split)
676
            {
677
143
              split_index = i;
678
143
              break;
679
            }
680
2558
            vars.clear();
681
2558
            subs.clear();
682
2558
            tmpArgs = args;
683
          }
684
        }
685
      }
686
145625
      if (do_split)
687
      {
688
143
        break;
689
      }
690
    }
691
47443
    if (do_split)
692
    {
693
286
      std::vector<Node> children;
694
429
      for (TNode bc : body)
695
      {
696
286
        children.push_back(bc);
697
      }
698
286
      std::vector<Node> split_children;
699
577
      for (TNode bci : body[split_index])
700
      {
701
434
        children[split_index] = bci;
702
434
        split_children.push_back(nm->mkNode(OR, children));
703
      }
704
      // split the AND child, for example:
705
      //  ( x!=a ^ P(x) ) V Q(x) ---> ( x!=a V Q(x) ) ^ ( P(x) V Q(x) )
706
143
      return nm->mkNode(AND, split_children);
707
    }
708
  }
709
710
119506
  return body;
711
}
712
713
7052
bool QuantifiersRewriter::isVarElim(Node v, Node s)
714
{
715
7052
  Assert(v.getKind() == BOUND_VARIABLE);
716
7052
  return !expr::hasSubterm(s, v) && s.getType().isSubtypeOf(v.getType());
717
}
718
719
38331
Node QuantifiersRewriter::getVarElimEq(Node lit,
720
                                       const std::vector<Node>& args,
721
                                       Node& var)
722
{
723
38331
  Assert(lit.getKind() == EQUAL);
724
38331
  Node slv;
725
76662
  TypeNode tt = lit[0].getType();
726
38331
  if (tt.isReal())
727
  {
728
15975
    slv = getVarElimEqReal(lit, args, var);
729
  }
730
22356
  else if (tt.isBitVector())
731
  {
732
751
    slv = getVarElimEqBv(lit, args, var);
733
  }
734
21605
  else if (tt.isStringLike())
735
  {
736
220
    slv = getVarElimEqString(lit, args, var);
737
  }
738
76662
  return slv;
739
}
740
741
15975
Node QuantifiersRewriter::getVarElimEqReal(Node lit,
742
                                           const std::vector<Node>& args,
743
                                           Node& var)
744
{
745
  // for arithmetic, solve the equality
746
31950
  std::map<Node, Node> msum;
747
15975
  if (!ArithMSum::getMonomialSumLit(lit, msum))
748
  {
749
    return Node::null();
750
  }
751
15975
  std::vector<Node>::const_iterator ita;
752
48505
  for (std::map<Node, Node>::iterator itm = msum.begin(); itm != msum.end();
753
       ++itm)
754
  {
755
32742
    if (itm->first.isNull())
756
    {
757
3335
      continue;
758
    }
759
29407
    ita = std::find(args.begin(), args.end(), itm->first);
760
29407
    if (ita != args.end())
761
    {
762
988
      Node veq_c;
763
988
      Node val;
764
600
      int ires = ArithMSum::isolate(itm->first, msum, veq_c, val, EQUAL);
765
600
      if (ires != 0 && veq_c.isNull() && isVarElim(itm->first, val))
766
      {
767
212
        var = itm->first;
768
212
        return val;
769
      }
770
    }
771
  }
772
15763
  return Node::null();
773
}
774
775
751
Node QuantifiersRewriter::getVarElimEqBv(Node lit,
776
                                         const std::vector<Node>& args,
777
                                         Node& var)
778
{
779
751
  if (Trace.isOn("quant-velim-bv"))
780
  {
781
    Trace("quant-velim-bv") << "Bv-Elim : " << lit << " varList = { ";
782
    for (const Node& v : args)
783
    {
784
      Trace("quant-velim-bv") << v << " ";
785
    }
786
    Trace("quant-velim-bv") << "} ?" << std::endl;
787
  }
788
751
  Assert(lit.getKind() == EQUAL);
789
  // TODO (#1494) : linearize the literal using utility
790
791
  // compute a subset active_args of the bound variables args that occur in lit
792
1502
  std::vector<Node> active_args;
793
751
  computeArgVec(args, active_args, lit);
794
795
1502
  BvInverter binv;
796
1594
  for (const Node& cvar : active_args)
797
  {
798
    // solve for the variable on this path using the inverter
799
1726
    std::vector<unsigned> path;
800
1726
    Node slit = binv.getPathToPv(lit, cvar, path);
801
883
    if (!slit.isNull())
802
    {
803
848
      Node slv = binv.solveBvLit(cvar, lit, path, nullptr);
804
444
      Trace("quant-velim-bv") << "...solution : " << slv << std::endl;
805
444
      if (!slv.isNull())
806
      {
807
76
        var = cvar;
808
        // if this is a proper variable elimination, that is, var = slv where
809
        // var is not in the free variables of slv, then we can return this
810
        // as the variable elimination for lit.
811
76
        if (isVarElim(var, slv))
812
        {
813
40
          return slv;
814
        }
815
      }
816
    }
817
    else
818
    {
819
439
      Trace("quant-velim-bv") << "...non-invertible path." << std::endl;
820
    }
821
  }
822
823
711
  return Node::null();
824
}
825
826
220
Node QuantifiersRewriter::getVarElimEqString(Node lit,
827
                                             const std::vector<Node>& args,
828
                                             Node& var)
829
{
830
220
  Assert(lit.getKind() == EQUAL);
831
220
  NodeManager* nm = NodeManager::currentNM();
832
656
  for (unsigned i = 0; i < 2; i++)
833
  {
834
440
    if (lit[i].getKind() == STRING_CONCAT)
835
    {
836
12
      TypeNode stype = lit[i].getType();
837
20
      for (unsigned j = 0, nchildren = lit[i].getNumChildren(); j < nchildren;
838
           j++)
839
      {
840
16
        if (std::find(args.begin(), args.end(), lit[i][j]) != args.end())
841
        {
842
12
          var = lit[i][j];
843
20
          Node slv = lit[1 - i];
844
20
          std::vector<Node> preL(lit[i].begin(), lit[i].begin() + j);
845
20
          std::vector<Node> postL(lit[i].begin() + j + 1, lit[i].end());
846
20
          Node tpre = strings::utils::mkConcat(preL, stype);
847
20
          Node tpost = strings::utils::mkConcat(postL, stype);
848
20
          Node slvL = nm->mkNode(STRING_LENGTH, slv);
849
20
          Node tpreL = nm->mkNode(STRING_LENGTH, tpre);
850
20
          Node tpostL = nm->mkNode(STRING_LENGTH, tpost);
851
12
          slv = nm->mkNode(
852
              STRING_SUBSTR,
853
              slv,
854
              tpreL,
855
24
              nm->mkNode(MINUS, slvL, nm->mkNode(PLUS, tpreL, tpostL)));
856
          // forall x. r ++ x ++ t = s => P( x )
857
          //   is equivalent to
858
          // r ++ s' ++ t = s => P( s' ) where
859
          // s' = substr( s, |r|, |s|-(|t|+|r|) ).
860
          // We apply this only if r,t,s do not contain free variables.
861
12
          if (!expr::hasFreeVar(slv))
862
          {
863
4
            return slv;
864
          }
865
        }
866
      }
867
    }
868
  }
869
870
216
  return Node::null();
871
}
872
873
252348
bool QuantifiersRewriter::getVarElimLit(Node body,
874
                                        Node lit,
875
                                        bool pol,
876
                                        std::vector<Node>& args,
877
                                        std::vector<Node>& vars,
878
                                        std::vector<Node>& subs) const
879
{
880
252348
  if (lit.getKind() == NOT)
881
  {
882
7141
    lit = lit[0];
883
7141
    pol = !pol;
884
7141
    Assert(lit.getKind() != NOT);
885
  }
886
252348
  NodeManager* nm = NodeManager::currentNM();
887
504696
  Trace("var-elim-quant-debug")
888
252348
      << "Eliminate : " << lit << ", pol = " << pol << "?" << std::endl;
889
505522
  if (lit.getKind() == APPLY_TESTER && pol && lit[0].getKind() == BOUND_VARIABLE
890
504744
      && d_opts.quantifiers.dtVarExpandQuant)
891
  {
892
96
    Trace("var-elim-dt") << "Expand datatype variable based on : " << lit
893
48
                         << std::endl;
894
    std::vector<Node>::iterator ita =
895
48
        std::find(args.begin(), args.end(), lit[0]);
896
48
    if (ita != args.end())
897
    {
898
48
      vars.push_back(lit[0]);
899
96
      Node tester = lit.getOperator();
900
48
      int index = datatypes::utils::indexOf(tester);
901
48
      const DType& dt = datatypes::utils::datatypeOf(tester);
902
48
      const DTypeConstructor& c = dt[index];
903
96
      std::vector<Node> newChildren;
904
96
      Node cons = c.getConstructor();
905
96
      TypeNode tspec;
906
      // take into account if parametric
907
48
      if (dt.isParametric())
908
      {
909
2
        tspec = c.getSpecializedConstructorType(lit[0].getType());
910
6
        cons = nm->mkNode(
911
4
            APPLY_TYPE_ASCRIPTION, nm->mkConst(AscriptionType(tspec)), cons);
912
      }
913
      else
914
      {
915
46
        tspec = cons.getType();
916
      }
917
48
      newChildren.push_back(cons);
918
96
      std::vector<Node> newVars;
919
48
      BoundVarManager* bvm = nm->getBoundVarManager();
920
117
      for (size_t j = 0, nargs = c.getNumArgs(); j < nargs; j++)
921
      {
922
138
        TypeNode tn = tspec[j];
923
138
        Node rn = nm->mkConst(Rational(j));
924
138
        Node cacheVal = BoundVarManager::getCacheValue(body, lit, rn);
925
138
        Node v = bvm->mkBoundVar<QRewDtExpandAttribute>(cacheVal, tn);
926
69
        newChildren.push_back(v);
927
69
        newVars.push_back(v);
928
      }
929
48
      subs.push_back(nm->mkNode(APPLY_CONSTRUCTOR, newChildren));
930
96
      Trace("var-elim-dt") << "...apply substitution " << subs[0] << "/"
931
48
                           << vars[0] << std::endl;
932
48
      args.erase(ita);
933
48
      args.insert(args.end(), newVars.begin(), newVars.end());
934
48
      return true;
935
    }
936
  }
937
  // all eliminations below guarded by varElimQuant()
938
252300
  if (!d_opts.quantifiers.varElimQuant)
939
  {
940
    return false;
941
  }
942
943
252300
  if (lit.getKind() == EQUAL)
944
  {
945
137639
    if (pol || lit[0].getType().isBoolean())
946
    {
947
201252
      for (unsigned i = 0; i < 2; i++)
948
      {
949
136597
        bool tpol = pol;
950
267103
        Node v_slv = lit[i];
951
136597
        if (v_slv.getKind() == NOT)
952
        {
953
5676
          v_slv = v_slv[0];
954
5676
          tpol = !tpol;
955
        }
956
        std::vector<Node>::iterator ita =
957
136597
            std::find(args.begin(), args.end(), v_slv);
958
136597
        if (ita != args.end())
959
        {
960
6596
          if (isVarElim(v_slv, lit[1 - i]))
961
          {
962
12182
            Node slv = lit[1 - i];
963
6091
            if (!tpol)
964
            {
965
660
              Assert(slv.getType().isBoolean());
966
660
              slv = slv.negate();
967
            }
968
12182
            Trace("var-elim-quant")
969
6091
                << "Variable eliminate based on equality : " << v_slv << " -> "
970
6091
                << slv << std::endl;
971
6091
            vars.push_back(v_slv);
972
6091
            subs.push_back(slv);
973
6091
            args.erase(ita);
974
6091
            return true;
975
          }
976
        }
977
      }
978
    }
979
  }
980
246209
  if (lit.getKind() == BOUND_VARIABLE)
981
  {
982
1564
    std::vector< Node >::iterator ita = std::find( args.begin(), args.end(), lit );
983
1564
    if( ita!=args.end() ){
984
1562
      Trace("var-elim-bool") << "Variable eliminate : " << lit << std::endl;
985
1562
      vars.push_back( lit );
986
1562
      subs.push_back( NodeManager::currentNM()->mkConst( pol ) );
987
1562
      args.erase( ita );
988
1562
      return true;
989
    }
990
  }
991
244647
  if (lit.getKind() == EQUAL && pol)
992
  {
993
76406
    Node var;
994
76406
    Node slv = getVarElimEq(lit, args, var);
995
38331
    if (!slv.isNull())
996
    {
997
256
      Assert(!var.isNull());
998
      std::vector<Node>::iterator ita =
999
256
          std::find(args.begin(), args.end(), var);
1000
256
      Assert(ita != args.end());
1001
512
      Trace("var-elim-quant")
1002
256
          << "Variable eliminate based on theory-specific solving : " << var
1003
256
          << " -> " << slv << std::endl;
1004
256
      Assert(!expr::hasSubterm(slv, var));
1005
256
      Assert(slv.getType().isSubtypeOf(var.getType()));
1006
256
      vars.push_back(var);
1007
256
      subs.push_back(slv);
1008
256
      args.erase(ita);
1009
256
      return true;
1010
    }
1011
  }
1012
244391
  return false;
1013
}
1014
1015
123126
bool QuantifiersRewriter::getVarElim(Node body,
1016
                                     std::vector<Node>& args,
1017
                                     std::vector<Node>& vars,
1018
                                     std::vector<Node>& subs) const
1019
{
1020
123126
  return getVarElimInternal(body, body, false, args, vars, subs);
1021
}
1022
1023
277686
bool QuantifiersRewriter::getVarElimInternal(Node body,
1024
                                             Node n,
1025
                                             bool pol,
1026
                                             std::vector<Node>& args,
1027
                                             std::vector<Node>& vars,
1028
                                             std::vector<Node>& subs) const
1029
{
1030
277686
  Kind nk = n.getKind();
1031
277686
  if (nk == NOT)
1032
  {
1033
97246
    n = n[0];
1034
97246
    pol = !pol;
1035
97246
    nk = n.getKind();
1036
97246
    Assert(nk != NOT);
1037
  }
1038
277686
  if ((nk == AND && pol) || (nk == OR && !pol))
1039
  {
1040
201488
    for (const Node& cn : n)
1041
    {
1042
154206
      if (getVarElimInternal(body, cn, pol, args, vars, subs))
1043
      {
1044
4848
        return true;
1045
      }
1046
    }
1047
47282
    return false;
1048
  }
1049
225556
  return getVarElimLit(body, n, pol, args, vars, subs);
1050
}
1051
1052
354
bool QuantifiersRewriter::hasVarElim(Node n,
1053
                                     bool pol,
1054
                                     std::vector<Node>& args) const
1055
{
1056
708
  std::vector< Node > vars;
1057
708
  std::vector< Node > subs;
1058
708
  return getVarElimInternal(n, n, pol, args, vars, subs);
1059
}
1060
1061
117774
bool QuantifiersRewriter::getVarElimIneq(Node body,
1062
                                         std::vector<Node>& args,
1063
                                         std::vector<Node>& bounds,
1064
                                         std::vector<Node>& subs,
1065
                                         QAttributes& qa)
1066
{
1067
117774
  Trace("var-elim-quant-debug") << "getVarElimIneq " << body << std::endl;
1068
  // For each variable v, we compute a set of implied bounds in the body
1069
  // of the quantified formula.
1070
  //   num_bounds[x][-1] stores the entailed lower bounds for x
1071
  //   num_bounds[x][1] stores the entailed upper bounds for x
1072
  //   num_bounds[x][0] stores the entailed disequalities for x
1073
  // These bounds are stored in a map that maps the literal for the bound to
1074
  // its required polarity. For example, for quantified formula
1075
  //   (forall ((x Int)) (or (= x 0) (>= x a)))
1076
  // we have:
1077
  //   num_bounds[x][0] contains { x -> { (= x 0) -> false } }
1078
  //   num_bounds[x][-1] contains { x -> { (>= x a) -> false } }
1079
  // This method succeeds in eliminating x if its only occurrences are in
1080
  // entailed disequalities, and one kind of bound. This is the case for the
1081
  // above quantified formula, which can be rewritten to false. The reason
1082
  // is that we can always chose a value for x that is arbitrarily large (resp.
1083
  // small) to satisfy all disequalities and inequalities for x.
1084
235548
  std::map<Node, std::map<int, std::map<Node, bool>>> num_bounds;
1085
  // The set of variables that we know we can not eliminate
1086
235548
  std::unordered_set<Node> ineligVars;
1087
  // compute the entailed literals
1088
235548
  QuantPhaseReq qpr(body);
1089
  // map to track which literals we have already processed, and hence can be
1090
  // excluded from the free variables check in the latter half of this method.
1091
235548
  std::map<Node, int> processed;
1092
322725
  for (const std::pair<const Node, bool>& pr : qpr.d_phase_reqs)
1093
  {
1094
    // an inequality that is entailed with a given polarity
1095
250462
    Node lit = pr.first;
1096
204951
    bool pol = pr.second;
1097
409902
    Trace("var-elim-quant-debug") << "Process inequality bounds : " << lit
1098
204951
                                  << ", pol = " << pol << "..." << std::endl;
1099
    bool canSolve =
1100
204951
        lit.getKind() == GEQ
1101
409902
        || (lit.getKind() == EQUAL && lit[0].getType().isReal() && !pol);
1102
204951
    if (!canSolve)
1103
    {
1104
159440
      continue;
1105
    }
1106
    // solve the inequality
1107
91022
    std::map<Node, Node> msum;
1108
45511
    if (!ArithMSum::getMonomialSumLit(lit, msum))
1109
    {
1110
      // not an inequality, cannot use
1111
      continue;
1112
    }
1113
45511
    processed[lit] = pol ? -1 : 1;
1114
141990
    for (const std::pair<const Node, Node>& m : msum)
1115
    {
1116
96479
      if (!m.first.isNull() && ineligVars.find(m.first) == ineligVars.end())
1117
      {
1118
        std::vector<Node>::iterator ita =
1119
76650
            std::find(args.begin(), args.end(), m.first);
1120
76650
        if (ita != args.end())
1121
        {
1122
          // store that this literal is upper/lower bound for itm->first
1123
75096
          Node veq_c;
1124
75096
          Node val;
1125
          int ires =
1126
37548
              ArithMSum::isolate(m.first, msum, veq_c, val, lit.getKind());
1127
37548
          if (ires != 0 && veq_c.isNull())
1128
          {
1129
37078
            if (lit.getKind() == GEQ)
1130
            {
1131
25482
              bool is_upper = pol != (ires == 1);
1132
50964
              Trace("var-elim-ineq-debug")
1133
25482
                  << lit << " is a " << (is_upper ? "upper" : "lower")
1134
25482
                  << " bound for " << m.first << std::endl;
1135
50964
              Trace("var-elim-ineq-debug")
1136
25482
                  << "  pol/ires = " << pol << " " << ires << std::endl;
1137
25482
              num_bounds[m.first][is_upper ? 1 : -1][lit] = pol;
1138
            }
1139
            else
1140
            {
1141
23192
              Trace("var-elim-ineq-debug")
1142
11596
                  << lit << " is a disequality for " << m.first << std::endl;
1143
11596
              num_bounds[m.first][0][lit] = pol;
1144
            }
1145
          }
1146
          else
1147
          {
1148
940
            Trace("var-elim-ineq-debug")
1149
470
                << "...ineligible " << m.first
1150
470
                << " since it cannot be solved for (" << ires << ", " << veq_c
1151
470
                << ")." << std::endl;
1152
470
            num_bounds.erase(m.first);
1153
470
            ineligVars.insert(m.first);
1154
          }
1155
        }
1156
        else
1157
        {
1158
          // compute variables in itm->first, these are not eligible for
1159
          // elimination
1160
78204
          std::unordered_set<Node> fvs;
1161
39102
          expr::getFreeVariables(m.first, fvs);
1162
82299
          for (const Node& v : fvs)
1163
          {
1164
86394
            Trace("var-elim-ineq-debug")
1165
43197
                << "...ineligible " << v
1166
43197
                << " since it is contained in monomial." << std::endl;
1167
43197
            num_bounds.erase(v);
1168
43197
            ineligVars.insert(v);
1169
          }
1170
        }
1171
      }
1172
    }
1173
  }
1174
1175
  // collect all variables that have only upper/lower bounds
1176
235548
  std::map<Node, bool> elig_vars;
1177
17682
  for (const std::pair<const Node, std::map<int, std::map<Node, bool>>>& nb :
1178
117774
       num_bounds)
1179
  {
1180
17682
    if (nb.second.find(1) == nb.second.end())
1181
    {
1182
18024
      Trace("var-elim-ineq-debug")
1183
9012
          << "Variable " << nb.first << " has only lower bounds." << std::endl;
1184
9012
      elig_vars[nb.first] = false;
1185
    }
1186
8670
    else if (nb.second.find(-1) == nb.second.end())
1187
    {
1188
4846
      Trace("var-elim-ineq-debug")
1189
2423
          << "Variable " << nb.first << " has only upper bounds." << std::endl;
1190
2423
      elig_vars[nb.first] = true;
1191
    }
1192
  }
1193
117774
  if (elig_vars.empty())
1194
  {
1195
107983
    return false;
1196
  }
1197
19582
  std::vector<Node> inactive_vars;
1198
19582
  std::map<Node, std::map<int, bool> > visited;
1199
  // traverse the body, invalidate variables if they occur in places other than
1200
  // the bounds they occur in
1201
19582
  std::unordered_map<TNode, std::unordered_set<int>> evisited;
1202
19582
  std::vector<TNode> evisit;
1203
19582
  std::vector<int> evisit_pol;
1204
19582
  TNode ecur;
1205
  int ecur_pol;
1206
9791
  evisit.push_back(body);
1207
9791
  evisit_pol.push_back(1);
1208
9791
  if (!qa.d_ipl.isNull())
1209
  {
1210
    // do not eliminate variables that occur in the annotation
1211
1432
    evisit.push_back(qa.d_ipl);
1212
1432
    evisit_pol.push_back(0);
1213
  }
1214
68591
  do
1215
  {
1216
78382
    ecur = evisit.back();
1217
78382
    evisit.pop_back();
1218
78382
    ecur_pol = evisit_pol.back();
1219
78382
    evisit_pol.pop_back();
1220
78382
    std::unordered_set<int>& epp = evisited[ecur];
1221
78382
    if (epp.find(ecur_pol) == epp.end())
1222
    {
1223
76697
      epp.insert(ecur_pol);
1224
76697
      if (elig_vars.find(ecur) != elig_vars.end())
1225
      {
1226
        // variable contained in a place apart from bounds, no longer eligible
1227
        // for elimination
1228
10725
        elig_vars.erase(ecur);
1229
21450
        Trace("var-elim-ineq-debug") << "...found occurrence of " << ecur
1230
10725
                                     << ", mark ineligible" << std::endl;
1231
      }
1232
      else
1233
      {
1234
65972
        bool rec = true;
1235
65972
        bool pol = ecur_pol >= 0;
1236
65972
        bool hasPol = ecur_pol != 0;
1237
65972
        if (hasPol)
1238
        {
1239
35761
          std::map<Node, int>::iterator itx = processed.find(ecur);
1240
35761
          if (itx != processed.end() && itx->second == ecur_pol)
1241
          {
1242
            // already processed this literal as a bound
1243
6348
            rec = false;
1244
          }
1245
        }
1246
65972
        if (rec)
1247
        {
1248
155579
          for (unsigned j = 0, size = ecur.getNumChildren(); j < size; j++)
1249
          {
1250
            bool newHasPol;
1251
            bool newPol;
1252
95955
            QuantPhaseReq::getPolarity(ecur, j, hasPol, pol, newHasPol, newPol);
1253
95955
            evisit.push_back(ecur[j]);
1254
95955
            evisit_pol.push_back(newHasPol ? (newPol ? 1 : -1) : 0);
1255
          }
1256
        }
1257
      }
1258
    }
1259
78382
  } while (!evisit.empty() && !elig_vars.empty());
1260
1261
9791
  bool ret = false;
1262
9791
  NodeManager* nm = NodeManager::currentNM();
1263
10501
  for (const std::pair<const Node, bool>& ev : elig_vars)
1264
  {
1265
1420
    Node v = ev.first;
1266
1420
    Trace("var-elim-ineq-debug")
1267
710
        << v << " is eligible for elimination." << std::endl;
1268
    // do substitution corresponding to infinite projection, all literals
1269
    // involving unbounded variable go to true/false
1270
    // disequalities of eligible variables are also eliminated
1271
710
    std::map<int, std::map<Node, bool>>& nbv = num_bounds[v];
1272
2130
    for (size_t i = 0; i < 2; i++)
1273
    {
1274
1420
      size_t nindex = i == 0 ? (elig_vars[v] ? 1 : -1) : 0;
1275
2311
      for (const std::pair<const Node, bool>& nb : nbv[nindex])
1276
      {
1277
1782
        Trace("var-elim-ineq-debug")
1278
891
            << "  subs : " << nb.first << " -> " << nb.second << std::endl;
1279
891
        bounds.push_back(nb.first);
1280
891
        subs.push_back(nm->mkConst(nb.second));
1281
      }
1282
    }
1283
    // eliminate from args
1284
710
    std::vector<Node>::iterator ita = std::find(args.begin(), args.end(), v);
1285
710
    Assert(ita != args.end());
1286
710
    args.erase(ita);
1287
710
    ret = true;
1288
  }
1289
9791
  return ret;
1290
}
1291
1292
118015
Node QuantifiersRewriter::computeVarElimination(Node body,
1293
                                                std::vector<Node>& args,
1294
                                                QAttributes& qa) const
1295
{
1296
118015
  if (!d_opts.quantifiers.varElimQuant && !d_opts.quantifiers.dtVarExpandQuant
1297
      && !d_opts.quantifiers.varIneqElimQuant)
1298
  {
1299
    return body;
1300
  }
1301
236030
  Trace("var-elim-quant-debug")
1302
118015
      << "computeVarElimination " << body << std::endl;
1303
236030
  Node prev;
1304
363945
  while (prev != body && !args.empty())
1305
  {
1306
122965
    prev = body;
1307
1308
245930
    std::vector<Node> vars;
1309
245930
    std::vector<Node> subs;
1310
    // standard variable elimination
1311
122965
    if (d_opts.quantifiers.varElimQuant)
1312
    {
1313
122965
      getVarElim(body, args, vars, subs);
1314
    }
1315
    // variable elimination based on one-direction inequalities
1316
122965
    if (vars.empty() && d_opts.quantifiers.varIneqElimQuant)
1317
    {
1318
117774
      getVarElimIneq(body, args, vars, subs, qa);
1319
    }
1320
    // if we eliminated a variable, update body and reprocess
1321
122965
    if (!vars.empty())
1322
    {
1323
11596
      Trace("var-elim-quant-debug")
1324
5798
          << "VE " << vars.size() << "/" << args.size() << std::endl;
1325
5798
      Assert(vars.size() == subs.size());
1326
      // remake with eliminated nodes
1327
5798
      body =
1328
11596
          body.substitute(vars.begin(), vars.end(), subs.begin(), subs.end());
1329
5798
      body = Rewriter::rewrite(body);
1330
5798
      if (!qa.d_ipl.isNull())
1331
      {
1332
54
        qa.d_ipl = qa.d_ipl.substitute(
1333
27
            vars.begin(), vars.end(), subs.begin(), subs.end());
1334
      }
1335
5798
      Trace("var-elim-quant") << "Return " << body << std::endl;
1336
    }
1337
  }
1338
118015
  return body;
1339
}
1340
1341
489799
Node QuantifiersRewriter::computePrenex(Node q,
1342
                                        Node body,
1343
                                        std::unordered_set<Node>& args,
1344
                                        std::unordered_set<Node>& nargs,
1345
                                        bool pol,
1346
                                        bool prenexAgg) const
1347
{
1348
489799
  NodeManager* nm = NodeManager::currentNM();
1349
489799
  Kind k = body.getKind();
1350
489799
  if (k == FORALL)
1351
  {
1352
27623
    if ((pol || prenexAgg)
1353
16921
        && (d_opts.quantifiers.prenexQuantUser
1354
15772
            || !QuantAttributes::hasPattern(body)))
1355
    {
1356
2298
      std::vector< Node > terms;
1357
2298
      std::vector< Node > subs;
1358
1149
      BoundVarManager* bvm = nm->getBoundVarManager();
1359
      //for doing prenexing of same-signed quantifiers
1360
      //must rename each variable that already exists
1361
2931
      for (const Node& v : body[0])
1362
      {
1363
1782
        terms.push_back(v);
1364
3564
        TypeNode vt = v.getType();
1365
3564
        Node vv;
1366
1782
        if (!q.isNull())
1367
        {
1368
          // We cache based on the original quantified formula, the subformula
1369
          // that we are pulling variables from (body), and the variable v.
1370
          // The argument body is required since in rare cases, two subformulas
1371
          // may share the same variables. This is the case for define-fun
1372
          // or inferred substitutions that contain quantified formulas.
1373
3564
          Node cacheVal = BoundVarManager::getCacheValue(q, body, v);
1374
1782
          vv = bvm->mkBoundVar<QRewPrenexAttribute>(cacheVal, vt);
1375
        }
1376
        else
1377
        {
1378
          // not specific to a quantified formula, use normal
1379
          vv = nm->mkBoundVar(vt);
1380
        }
1381
1782
        subs.push_back(vv);
1382
      }
1383
1149
      if (pol)
1384
      {
1385
1149
        args.insert(subs.begin(), subs.end());
1386
      }
1387
      else
1388
      {
1389
        nargs.insert(subs.begin(), subs.end());
1390
      }
1391
2298
      Node newBody = body[1];
1392
1149
      newBody = newBody.substitute( terms.begin(), terms.end(), subs.begin(), subs.end() );
1393
1149
      return newBody;
1394
    }
1395
  //must remove structure
1396
  }
1397
475334
  else if (prenexAgg && k == ITE && body.getType().isBoolean())
1398
  {
1399
    Node nn = nm->mkNode(AND,
1400
                         nm->mkNode(OR, body[0].notNode(), body[1]),
1401
                         nm->mkNode(OR, body[0], body[2]));
1402
    return computePrenex(q, nn, args, nargs, pol, prenexAgg);
1403
  }
1404
475334
  else if (prenexAgg && k == EQUAL && body[0].getType().isBoolean())
1405
  {
1406
    Node nn = nm->mkNode(AND,
1407
                         nm->mkNode(OR, body[0].notNode(), body[1]),
1408
                         nm->mkNode(OR, body[0], body[1].notNode()));
1409
    return computePrenex(q, nn, args, nargs, pol, prenexAgg);
1410
475334
  }else if( body.getType().isBoolean() ){
1411
475334
    Assert(k != EXISTS);
1412
475334
    bool childrenChanged = false;
1413
949471
    std::vector< Node > newChildren;
1414
1451278
    for (size_t i = 0, nchild = body.getNumChildren(); i < nchild; i++)
1415
    {
1416
      bool newHasPol;
1417
      bool newPol;
1418
975944
      QuantPhaseReq::getPolarity( body, i, true, pol, newHasPol, newPol );
1419
1580302
      if (!newHasPol)
1420
      {
1421
604358
        newChildren.push_back( body[i] );
1422
604358
        continue;
1423
      }
1424
743172
      Node n = computePrenex(q, body[i], args, nargs, newPol, prenexAgg);
1425
371586
      newChildren.push_back(n);
1426
371586
      childrenChanged = n != body[i] || childrenChanged;
1427
    }
1428
475334
    if( childrenChanged ){
1429
1197
      if (k == NOT && newChildren[0].getKind() == NOT)
1430
      {
1431
        return newChildren[0][0];
1432
      }
1433
1197
      return nm->mkNode(k, newChildren);
1434
    }
1435
  }
1436
487453
  return body;
1437
}
1438
1439
47575
Node QuantifiersRewriter::computeSplit(std::vector<Node>& args,
1440
                                       Node body,
1441
                                       QAttributes& qa) const
1442
{
1443
47575
  Assert(body.getKind() == OR);
1444
47575
  size_t var_found_count = 0;
1445
47575
  size_t eqc_count = 0;
1446
47575
  size_t eqc_active = 0;
1447
95150
  std::map< Node, int > var_to_eqc;
1448
95150
  std::map< int, std::vector< Node > > eqc_to_var;
1449
95150
  std::map< int, std::vector< Node > > eqc_to_lit;
1450
1451
95150
  std::vector<Node> lits;
1452
1453
201720
  for( unsigned i=0; i<body.getNumChildren(); i++ ){
1454
    //get variables contained in the literal
1455
308290
    Node n = body[i];
1456
308290
    std::vector< Node > lit_args;
1457
154145
    computeArgVec( args, lit_args, n );
1458
154145
    if( lit_args.empty() ){
1459
1656
      lits.push_back( n );
1460
    }else {
1461
      //collect the equivalence classes this literal belongs to, and the new variables it contributes
1462
304978
      std::vector< int > eqcs;
1463
304978
      std::vector< Node > lit_new_args;
1464
      //for each variable in literal
1465
503941
      for( unsigned j=0; j<lit_args.size(); j++) {
1466
        //see if the variable has already been found
1467
351452
        if (var_to_eqc.find(lit_args[j])!=var_to_eqc.end()) {
1468
232787
          int eqc = var_to_eqc[lit_args[j]];
1469
232787
          if (std::find(eqcs.begin(), eqcs.end(), eqc)==eqcs.end()) {
1470
104623
            eqcs.push_back(eqc);
1471
          }
1472
        }else{
1473
118665
          var_found_count++;
1474
118665
          lit_new_args.push_back(lit_args[j]);
1475
        }
1476
      }
1477
152489
      if (eqcs.empty()) {
1478
54788
        eqcs.push_back(eqc_count);
1479
54788
        eqc_count++;
1480
54788
        eqc_active++;
1481
      }
1482
1483
152489
      int eqcz = eqcs[0];
1484
      //merge equivalence classes with eqcz
1485
159411
      for (unsigned j=1; j<eqcs.size(); j++) {
1486
6922
        int eqc = eqcs[j];
1487
        //move all variables from equivalence class
1488
32353
        for (unsigned k=0; k<eqc_to_var[eqc].size(); k++) {
1489
50862
          Node v = eqc_to_var[eqc][k];
1490
25431
          var_to_eqc[v] = eqcz;
1491
25431
          eqc_to_var[eqcz].push_back(v);
1492
        }
1493
6922
        eqc_to_var.erase(eqc);
1494
        //move all literals from equivalence class
1495
31076
        for (unsigned k=0; k<eqc_to_lit[eqc].size(); k++) {
1496
48308
          Node l = eqc_to_lit[eqc][k];
1497
24154
          eqc_to_lit[eqcz].push_back(l);
1498
        }
1499
6922
        eqc_to_lit.erase(eqc);
1500
6922
        eqc_active--;
1501
      }
1502
      //add variables to equivalence class
1503
271154
      for (unsigned j=0; j<lit_new_args.size(); j++) {
1504
118665
        var_to_eqc[lit_new_args[j]] = eqcz;
1505
118665
        eqc_to_var[eqcz].push_back(lit_new_args[j]);
1506
      }
1507
      //add literal to equivalence class
1508
152489
      eqc_to_lit[eqcz].push_back(n);
1509
    }
1510
  }
1511
47575
  if ( eqc_active>1 || !lits.empty() || var_to_eqc.size()!=args.size() ){
1512
696
    NodeManager* nm = NodeManager::currentNM();
1513
696
    Trace("clause-split-debug") << "Split quantified formula with body " << body << std::endl;
1514
696
    Trace("clause-split-debug") << "   Ground literals: " << std::endl;
1515
2352
    for( size_t i=0; i<lits.size(); i++) {
1516
1656
      Trace("clause-split-debug") << "      " << lits[i] << std::endl;
1517
    }
1518
696
    Trace("clause-split-debug") << std::endl;
1519
696
    Trace("clause-split-debug") << "Equivalence classes: " << std::endl;
1520
1683
    for (std::map< int, std::vector< Node > >::iterator it = eqc_to_lit.begin(); it != eqc_to_lit.end(); ++it ){
1521
987
      Trace("clause-split-debug") << "   Literals: " << std::endl;
1522
4657
      for (size_t i=0; i<it->second.size(); i++) {
1523
3670
        Trace("clause-split-debug") << "      " << it->second[i] << std::endl;
1524
      }
1525
987
      int eqc = it->first;
1526
987
      Trace("clause-split-debug") << "   Variables: " << std::endl;
1527
4140
      for (size_t i=0; i<eqc_to_var[eqc].size(); i++) {
1528
3153
        Trace("clause-split-debug") << "      " << eqc_to_var[eqc][i] << std::endl;
1529
      }
1530
987
      Trace("clause-split-debug") << std::endl;
1531
1974
      Node bvl = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, eqc_to_var[eqc]);
1532
      Node bd =
1533
1974
          it->second.size() == 1 ? it->second[0] : nm->mkNode(OR, it->second);
1534
1974
      Node fa = nm->mkNode(FORALL, bvl, bd);
1535
987
      lits.push_back(fa);
1536
    }
1537
696
    Assert(!lits.empty());
1538
1392
    Node nf = lits.size()==1 ? lits[0] : NodeManager::currentNM()->mkNode(OR,lits);
1539
696
    Trace("clause-split-debug") << "Made node : " << nf << std::endl;
1540
696
    return nf;
1541
  }else{
1542
46879
    return mkForAll( args, body, qa );
1543
  }
1544
}
1545
1546
119930
Node QuantifiersRewriter::mkForAll(const std::vector<Node>& args,
1547
                                   Node body,
1548
                                   QAttributes& qa)
1549
{
1550
119930
  if (args.empty())
1551
  {
1552
250
    return body;
1553
  }
1554
119680
  NodeManager* nm = NodeManager::currentNM();
1555
239360
  std::vector<Node> children;
1556
119680
  children.push_back(nm->mkNode(kind::BOUND_VAR_LIST, args));
1557
119680
  children.push_back(body);
1558
119680
  if (!qa.d_ipl.isNull())
1559
  {
1560
14923
    children.push_back(qa.d_ipl);
1561
  }
1562
119680
  return nm->mkNode(kind::FORALL, children);
1563
}
1564
1565
Node QuantifiersRewriter::mkForall(const std::vector<Node>& args,
1566
                                   Node body,
1567
                                   bool marked)
1568
{
1569
  std::vector< Node > iplc;
1570
  return mkForall( args, body, iplc, marked );
1571
}
1572
1573
Node QuantifiersRewriter::mkForall(const std::vector<Node>& args,
1574
                                   Node body,
1575
                                   std::vector<Node>& iplc,
1576
                                   bool marked)
1577
{
1578
  if (args.empty())
1579
  {
1580
    return body;
1581
  }
1582
  NodeManager* nm = NodeManager::currentNM();
1583
  std::vector<Node> children;
1584
  children.push_back(nm->mkNode(kind::BOUND_VAR_LIST, args));
1585
  children.push_back(body);
1586
  if (marked)
1587
  {
1588
    SkolemManager* sm = nm->getSkolemManager();
1589
    Node avar = sm->mkDummySkolem("id", nm->booleanType());
1590
    QuantIdNumAttribute ida;
1591
    avar.setAttribute(ida, 0);
1592
    iplc.push_back(nm->mkNode(kind::INST_ATTRIBUTE, avar));
1593
  }
1594
  if (!iplc.empty())
1595
  {
1596
    children.push_back(nm->mkNode(kind::INST_PATTERN_LIST, iplc));
1597
  }
1598
  return nm->mkNode(kind::FORALL, children);
1599
}
1600
1601
//computes miniscoping, also eliminates variables that do not occur free in body
1602
121453
Node QuantifiersRewriter::computeMiniscoping(Node q, QAttributes& qa) const
1603
{
1604
121453
  NodeManager* nm = NodeManager::currentNM();
1605
242906
  std::vector<Node> args(q[0].begin(), q[0].end());
1606
242906
  Node body = q[1];
1607
121453
  if( body.getKind()==FORALL ){
1608
    //combine prenex
1609
32
    std::vector< Node > newArgs;
1610
16
    newArgs.insert(newArgs.end(), q[0].begin(), q[0].end());
1611
33
    for( unsigned i=0; i<body[0].getNumChildren(); i++ ){
1612
17
      newArgs.push_back( body[0][i] );
1613
    }
1614
16
    return mkForAll( newArgs, body[1], qa );
1615
121437
  }else if( body.getKind()==AND ){
1616
    // aggressive miniscoping implies that structural miniscoping should
1617
    // be applied first
1618
2162
    if (d_opts.quantifiers.miniscopeQuant
1619
1323
        || d_opts.quantifiers.aggressiveMiniscopeQuant)
1620
    {
1621
841
      BoundVarManager* bvm = nm->getBoundVarManager();
1622
      // Break apart the quantifed formula
1623
      // forall x. P1 ^ ... ^ Pn ---> forall x. P1 ^ ... ^ forall x. Pn
1624
1682
      NodeBuilder t(kind::AND);
1625
1682
      std::vector<Node> argsc;
1626
4381
      for (size_t i = 0, nchild = body.getNumChildren(); i < nchild; i++)
1627
      {
1628
3540
        if (argsc.empty())
1629
        {
1630
          // If not done so, we must create fresh copy of args. This is to
1631
          // ensure that quantified formulas do not reuse variables.
1632
7965
          for (const Node& v : q[0])
1633
          {
1634
11910
            TypeNode vt = v.getType();
1635
11910
            Node cacheVal = BoundVarManager::getCacheValue(q, v, i);
1636
11910
            Node vv = bvm->mkBoundVar<QRewMiniscopeAttribute>(cacheVal, vt);
1637
5955
            argsc.push_back(vv);
1638
          }
1639
        }
1640
7080
        Node b = body[i];
1641
        Node bodyc =
1642
7080
            b.substitute(args.begin(), args.end(), argsc.begin(), argsc.end());
1643
3540
        if (b == bodyc)
1644
        {
1645
          // Did not contain variables in args, thus it is ground. Since we did
1646
          // not use them, we keep the variables argsc for the next child.
1647
1576
          t << b;
1648
        }
1649
        else
1650
        {
1651
          // make the miniscoped quantified formula
1652
3928
          Node cbvl = nm->mkNode(BOUND_VAR_LIST, argsc);
1653
3928
          Node qq = nm->mkNode(FORALL, cbvl, bodyc);
1654
1964
          t << qq;
1655
          // We used argsc, clear so we will construct a fresh copy above.
1656
1964
          argsc.clear();
1657
        }
1658
      }
1659
1682
      Node retVal = t;
1660
841
      return retVal;
1661
    }
1662
119275
  }else if( body.getKind()==OR ){
1663
49799
    if (d_opts.quantifiers.quantSplit)
1664
    {
1665
      //splitting subsumes free variable miniscoping, apply it with higher priority
1666
47575
      return computeSplit( args, body, qa );
1667
    }
1668
2224
    else if (d_opts.quantifiers.miniscopeQuantFreeVar
1669
2224
             || d_opts.quantifiers.aggressiveMiniscopeQuant)
1670
    {
1671
      // aggressive miniscoping implies that free variable miniscoping should
1672
      // be applied first
1673
4
      Node newBody = body;
1674
4
      NodeBuilder body_split(kind::OR);
1675
4
      NodeBuilder tb(kind::OR);
1676
12
      for (const Node& trm : body)
1677
      {
1678
8
        if (expr::hasSubterm(trm, args))
1679
        {
1680
4
          tb << trm;
1681
        }else{
1682
4
          body_split << trm;
1683
        }
1684
      }
1685
4
      if( tb.getNumChildren()==0 ){
1686
        return body_split;
1687
4
      }else if( body_split.getNumChildren()>0 ){
1688
4
        newBody = tb.getNumChildren()==1 ? tb.getChild( 0 ) : tb;
1689
8
        std::vector< Node > activeArgs;
1690
4
        computeArgVec2( args, activeArgs, newBody, qa.d_ipl );
1691
4
        body_split << mkForAll( activeArgs, newBody, qa );
1692
4
        return body_split.getNumChildren()==1 ? body_split.getChild( 0 ) : body_split;
1693
      }
1694
    }
1695
69476
  }else if( body.getKind()==NOT ){
1696
15402
    Assert(isLiteral(body[0]));
1697
  }
1698
  //remove variables that don't occur
1699
146034
  std::vector< Node > activeArgs;
1700
73017
  computeArgVec2( args, activeArgs, body, qa.d_ipl );
1701
73017
  return mkForAll( activeArgs, body, qa );
1702
}
1703
1704
14
Node QuantifiersRewriter::computeAggressiveMiniscoping(std::vector<Node>& args,
1705
                                                       Node body) const
1706
{
1707
28
  std::map<Node, std::vector<Node> > varLits;
1708
28
  std::map<Node, std::vector<Node> > litVars;
1709
14
  if (body.getKind() == OR) {
1710
    Trace("ag-miniscope") << "compute aggressive miniscoping on " << body << std::endl;
1711
    for (size_t i = 0; i < body.getNumChildren(); i++) {
1712
      std::vector<Node> activeArgs;
1713
      computeArgVec(args, activeArgs, body[i]);
1714
      for (unsigned j = 0; j < activeArgs.size(); j++) {
1715
        varLits[activeArgs[j]].push_back(body[i]);
1716
      }
1717
      std::vector<Node>& lit_body_i = litVars[body[i]];
1718
      std::vector<Node>::iterator lit_body_i_begin = lit_body_i.begin();
1719
      std::vector<Node>::const_iterator active_begin = activeArgs.begin();
1720
      std::vector<Node>::const_iterator active_end = activeArgs.end();
1721
      lit_body_i.insert(lit_body_i_begin, active_begin, active_end);
1722
    }
1723
    //find the variable in the least number of literals
1724
    Node bestVar;
1725
    for( std::map< Node, std::vector<Node> >::iterator it = varLits.begin(); it != varLits.end(); ++it ){
1726
      if( bestVar.isNull() || varLits[bestVar].size()>it->second.size() ){
1727
        bestVar = it->first;
1728
      }
1729
    }
1730
    Trace("ag-miniscope-debug") << "Best variable " << bestVar << " occurs in " << varLits[bestVar].size() << "/ " << body.getNumChildren() << " literals." << std::endl;
1731
    if( !bestVar.isNull() && varLits[bestVar].size()<body.getNumChildren() ){
1732
      //we can miniscope
1733
      Trace("ag-miniscope") << "Miniscope on " << bestVar << std::endl;
1734
      //make the bodies
1735
      std::vector<Node> qlit1;
1736
      qlit1.insert( qlit1.begin(), varLits[bestVar].begin(), varLits[bestVar].end() );
1737
      std::vector<Node> qlitt;
1738
      //for all literals not containing bestVar
1739
      for( size_t i=0; i<body.getNumChildren(); i++ ){
1740
        if( std::find( qlit1.begin(), qlit1.end(), body[i] )==qlit1.end() ){
1741
          qlitt.push_back( body[i] );
1742
        }
1743
      }
1744
      //make the variable lists
1745
      std::vector<Node> qvl1;
1746
      std::vector<Node> qvl2;
1747
      std::vector<Node> qvsh;
1748
      for( unsigned i=0; i<args.size(); i++ ){
1749
        bool found1 = false;
1750
        bool found2 = false;
1751
        for( size_t j=0; j<varLits[args[i]].size(); j++ ){
1752
          if( !found1 && std::find( qlit1.begin(), qlit1.end(), varLits[args[i]][j] )!=qlit1.end() ){
1753
            found1 = true;
1754
          }else if( !found2 && std::find( qlitt.begin(), qlitt.end(), varLits[args[i]][j] )!=qlitt.end() ){
1755
            found2 = true;
1756
          }
1757
          if( found1 && found2 ){
1758
            break;
1759
          }
1760
        }
1761
        if( found1 ){
1762
          if( found2 ){
1763
            qvsh.push_back( args[i] );
1764
          }else{
1765
            qvl1.push_back( args[i] );
1766
          }
1767
        }else{
1768
          Assert(found2);
1769
          qvl2.push_back( args[i] );
1770
        }
1771
      }
1772
      Assert(!qvl1.empty());
1773
      //check for literals that only contain shared variables
1774
      std::vector<Node> qlitsh;
1775
      std::vector<Node> qlit2;
1776
      for( size_t i=0; i<qlitt.size(); i++ ){
1777
        bool hasVar2 = false;
1778
        for( size_t j=0; j<litVars[qlitt[i]].size(); j++ ){
1779
          if( std::find( qvl2.begin(), qvl2.end(), litVars[qlitt[i]][j] )!=qvl2.end() ){
1780
            hasVar2 = true;
1781
            break;
1782
          }
1783
        }
1784
        if( hasVar2 ){
1785
          qlit2.push_back( qlitt[i] );
1786
        }else{
1787
          qlitsh.push_back( qlitt[i] );
1788
        }
1789
      }
1790
      varLits.clear();
1791
      litVars.clear();
1792
      Trace("ag-miniscope-debug") << "Split into literals : " << qlit1.size() << " / " << qlit2.size() << " / " << qlitsh.size();
1793
      Trace("ag-miniscope-debug") << ", variables : " << qvl1.size() << " / " << qvl2.size() << " / " << qvsh.size() << std::endl;
1794
      Node n1 = qlit1.size()==1 ? qlit1[0] : NodeManager::currentNM()->mkNode( OR, qlit1 );
1795
      n1 = computeAggressiveMiniscoping( qvl1, n1 );
1796
      qlitsh.push_back( n1 );
1797
      if( !qlit2.empty() ){
1798
        Node n2 = qlit2.size()==1 ? qlit2[0] : NodeManager::currentNM()->mkNode( OR, qlit2 );
1799
        n2 = computeAggressiveMiniscoping( qvl2, n2 );
1800
        qlitsh.push_back( n2 );
1801
      }
1802
      Node n = NodeManager::currentNM()->mkNode( OR, qlitsh );
1803
      if( !qvsh.empty() ){
1804
        Node bvl = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, qvsh);
1805
        n = NodeManager::currentNM()->mkNode( FORALL, bvl, n );
1806
      }
1807
      Trace("ag-miniscope") << "Return " << n << " for " << body << std::endl;
1808
      return n;
1809
    }
1810
  }
1811
28
  QAttributes qa;
1812
14
  return mkForAll( args, body, qa );
1813
}
1814
1815
999602
bool QuantifiersRewriter::doOperation(Node q,
1816
                                      RewriteStep computeOption,
1817
                                      QAttributes& qa) const
1818
{
1819
999602
  bool is_strict_trigger =
1820
999602
      qa.d_hasPattern
1821
999602
      && d_opts.quantifiers.userPatternsQuant == options::UserPatMode::STRICT;
1822
999602
  bool is_std = qa.isStandard() && !is_strict_trigger;
1823
999602
  if (computeOption == COMPUTE_ELIM_SYMBOLS)
1824
  {
1825
139147
    return true;
1826
  }
1827
860455
  else if (computeOption == COMPUTE_MINISCOPING)
1828
  {
1829
125454
    return is_std;
1830
  }
1831
735001
  else if (computeOption == COMPUTE_AGGRESSIVE_MINISCOPING)
1832
  {
1833
123445
    return d_opts.quantifiers.aggressiveMiniscopeQuant && is_std;
1834
  }
1835
611556
  else if (computeOption == COMPUTE_EXT_REWRITE)
1836
  {
1837
123445
    return d_opts.quantifiers.extRewriteQuant;
1838
  }
1839
488111
  else if (computeOption == COMPUTE_PROCESS_TERMS)
1840
  {
1841
    return is_std
1842
123433
           && d_opts.quantifiers.iteLiftQuant
1843
123433
                  != options::IteLiftQuantMode::NONE;
1844
  }
1845
364678
  else if (computeOption == COMPUTE_COND_SPLIT)
1846
  {
1847
119679
    return (d_opts.quantifiers.iteDtTesterSplitQuant
1848
119319
            || d_opts.quantifiers.condVarSplitQuant)
1849
239358
           && !is_strict_trigger;
1850
  }
1851
244999
  else if (computeOption == COMPUTE_PRENEX)
1852
  {
1853
122983
    return d_opts.quantifiers.prenexQuant != options::PrenexQuantMode::NONE
1854
122983
           && !d_opts.quantifiers.aggressiveMiniscopeQuant && is_std;
1855
  }
1856
122016
  else if (computeOption == COMPUTE_VAR_ELIMINATION)
1857
  {
1858
122016
    return (d_opts.quantifiers.varElimQuant
1859
            || d_opts.quantifiers.dtVarExpandQuant)
1860
244032
           && is_std;
1861
  }
1862
  else
1863
  {
1864
    return false;
1865
  }
1866
}
1867
1868
//general method for computing various rewrites
1869
735992
Node QuantifiersRewriter::computeOperation(Node f,
1870
                                           RewriteStep computeOption,
1871
                                           QAttributes& qa) const
1872
{
1873
735992
  Trace("quantifiers-rewrite-debug") << "Compute operation " << computeOption << " on " << f << " " << qa.d_qid_num << std::endl;
1874
735992
  if (computeOption == COMPUTE_MINISCOPING)
1875
  {
1876
121453
    if (d_opts.quantifiers.prenexQuant == options::PrenexQuantMode::NORMAL)
1877
    {
1878
      if( !qa.d_qid_num.isNull() ){
1879
        //already processed this, return self
1880
        return f;
1881
      }
1882
    }
1883
    //return directly
1884
121453
    return computeMiniscoping(f, qa);
1885
  }
1886
1229078
  std::vector<Node> args(f[0].begin(), f[0].end());
1887
1229078
  Node n = f[1];
1888
614539
  if (computeOption == COMPUTE_ELIM_SYMBOLS)
1889
  {
1890
139147
    n = computeElimSymbols(n);
1891
475392
  }else if( computeOption==COMPUTE_AGGRESSIVE_MINISCOPING ){
1892
14
    return computeAggressiveMiniscoping( args, n );
1893
  }
1894
475378
  else if (computeOption == COMPUTE_EXT_REWRITE)
1895
  {
1896
39
    return computeExtendedRewrite(f, qa);
1897
  }
1898
475339
  else if (computeOption == COMPUTE_PROCESS_TERMS)
1899
  {
1900
238864
    std::vector< Node > new_conds;
1901
119432
    n = computeProcessTerms( n, args, new_conds, f, qa );
1902
119432
    if( !new_conds.empty() ){
1903
      new_conds.push_back( n );
1904
      n = NodeManager::currentNM()->mkNode( OR, new_conds );
1905
    }
1906
  }
1907
355907
  else if (computeOption == COMPUTE_COND_SPLIT)
1908
  {
1909
119679
    n = computeCondSplit(n, args, qa);
1910
  }
1911
236228
  else if (computeOption == COMPUTE_PRENEX)
1912
  {
1913
118213
    if (d_opts.quantifiers.prenexQuant == options::PrenexQuantMode::NORMAL)
1914
    {
1915
      //will rewrite at preprocess time
1916
      return f;
1917
    }
1918
    else
1919
    {
1920
236426
      std::unordered_set<Node> argsSet, nargsSet;
1921
118213
      n = computePrenex(f, n, argsSet, nargsSet, true, false);
1922
118213
      Assert(nargsSet.empty());
1923
118213
      args.insert(args.end(), argsSet.begin(), argsSet.end());
1924
    }
1925
  }
1926
118015
  else if (computeOption == COMPUTE_VAR_ELIMINATION)
1927
  {
1928
118015
    n = computeVarElimination( n, args, qa );
1929
  }
1930
614486
  Trace("quantifiers-rewrite-debug") << "Compute Operation: return " << n << ", " << args.size() << std::endl;
1931
614486
  if( f[1]==n && args.size()==f[0].getNumChildren() ){
1932
596866
    return f;
1933
  }else{
1934
17620
    if( args.empty() ){
1935
848
      return n;
1936
    }else{
1937
33544
      std::vector< Node > children;
1938
16772
      children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, args ) );
1939
16772
      children.push_back( n );
1940
16772
      if( !qa.d_ipl.isNull() && args.size()==f[0].getNumChildren() ){
1941
2414
        children.push_back( qa.d_ipl );
1942
      }
1943
16772
      return NodeManager::currentNM()->mkNode(kind::FORALL, children );
1944
    }
1945
  }
1946
}
1947
1948
bool QuantifiersRewriter::isPrenexNormalForm( Node n ) {
1949
  if( n.getKind()==FORALL ){
1950
    return n[1].getKind()!=FORALL && isPrenexNormalForm( n[1] );
1951
  }else if( n.getKind()==NOT ){
1952
    return n[0].getKind()!=NOT && isPrenexNormalForm( n[0] );
1953
  }else{
1954
    return !expr::hasClosure(n);
1955
  }
1956
}
1957
1958
}  // namespace quantifiers
1959
}  // namespace theory
1960
31137
}  // namespace cvc5