GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/quantifiers_rewriter.cpp Lines: 858 1073 80.0 %
Date: 2021-09-10 Branches: 1899 4445 42.7 %

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/bound_var_manager.h"
19
#include "expr/dtype.h"
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/quantifiers/bv_inverter.h"
27
#include "theory/quantifiers/ematching/trigger.h"
28
#include "theory/quantifiers/extended_rewrite.h"
29
#include "theory/quantifiers/quantifiers_attributes.h"
30
#include "theory/quantifiers/skolemize.h"
31
#include "theory/quantifiers/term_database.h"
32
#include "theory/quantifiers/term_util.h"
33
#include "theory/rewriter.h"
34
#include "theory/strings/theory_strings_utils.h"
35
#include "util/rational.h"
36
37
using namespace std;
38
using namespace cvc5::kind;
39
using namespace cvc5::context;
40
41
namespace cvc5 {
42
namespace theory {
43
namespace quantifiers {
44
45
/**
46
 * Attributes used for constructing bound variables in a canonical way. These
47
 * are attributes that map to bound variable, introduced for the following
48
 * purposes:
49
 * - QRewPrenexAttribute: cached on (v, body) where we are prenexing bound
50
 * variable v in a nested quantified formula within the given body.
51
 * - QRewMiniscopeAttribute: cached on (v, q, i) where q is being miniscoped
52
 * for F_i in its body (and F_1 ... F_n), and v is one of the bound variables
53
 * that q binds.
54
 * - QRewDtExpandAttribute: cached on (F, lit, a) where lit is the tested
55
 * literal used for expanding a quantified datatype variable in quantified
56
 * formula with body F, and a is the rational corresponding to the argument
57
 * position of the variable, e.g. lit is ((_ is C) x) and x is
58
 * replaced by (C y1 ... yn), where the argument position of yi is i.
59
 */
60
struct QRewPrenexAttributeId
61
{
62
};
63
typedef expr::Attribute<QRewPrenexAttributeId, Node> QRewPrenexAttribute;
64
struct QRewMiniscopeAttributeId
65
{
66
};
67
typedef expr::Attribute<QRewMiniscopeAttributeId, Node> QRewMiniscopeAttribute;
68
struct QRewDtExpandAttributeId
69
{
70
};
71
typedef expr::Attribute<QRewDtExpandAttributeId, Node> QRewDtExpandAttribute;
72
73
std::ostream& operator<<(std::ostream& out, RewriteStep s)
74
{
75
  switch (s)
76
  {
77
    case COMPUTE_ELIM_SYMBOLS: out << "COMPUTE_ELIM_SYMBOLS"; break;
78
    case COMPUTE_MINISCOPING: out << "COMPUTE_MINISCOPING"; break;
79
    case COMPUTE_AGGRESSIVE_MINISCOPING:
80
      out << "COMPUTE_AGGRESSIVE_MINISCOPING";
81
      break;
82
    case COMPUTE_EXT_REWRITE: out << "COMPUTE_EXT_REWRITE"; break;
83
    case COMPUTE_PROCESS_TERMS: out << "COMPUTE_PROCESS_TERMS"; break;
84
    case COMPUTE_PRENEX: out << "COMPUTE_PRENEX"; break;
85
    case COMPUTE_VAR_ELIMINATION: out << "COMPUTE_VAR_ELIMINATION"; break;
86
    case COMPUTE_COND_SPLIT: out << "COMPUTE_COND_SPLIT"; break;
87
    default: out << "UnknownRewriteStep"; break;
88
  }
89
  return out;
90
}
91
92
15002
bool QuantifiersRewriter::isLiteral( Node n ){
93
15002
  switch( n.getKind() ){
94
  case NOT:
95
    return n[0].getKind()!=NOT && isLiteral( n[0] );
96
    break;
97
  case OR:
98
  case AND:
99
  case IMPLIES:
100
  case XOR:
101
  case ITE:
102
    return false;
103
    break;
104
9001
  case EQUAL:
105
    //for boolean terms
106
9001
    return !n[0].getType().isBoolean();
107
    break;
108
6001
  default:
109
6001
    break;
110
  }
111
6001
  return true;
112
}
113
114
void QuantifiersRewriter::addNodeToOrBuilder(Node n, NodeBuilder& t)
115
{
116
  if( n.getKind()==OR ){
117
    for( int i=0; i<(int)n.getNumChildren(); i++ ){
118
      t << n[i];
119
    }
120
  }else{
121
    t << n;
122
  }
123
}
124
125
4933843
void QuantifiersRewriter::computeArgs(const std::vector<Node>& args,
126
                                      std::map<Node, bool>& activeMap,
127
                                      Node n,
128
                                      std::map<Node, bool>& visited)
129
{
130
4933843
  if( visited.find( n )==visited.end() ){
131
3535807
    visited[n] = true;
132
3535807
    if( n.getKind()==BOUND_VARIABLE ){
133
593324
      if( std::find( args.begin(), args.end(), n )!=args.end() ){
134
487036
        activeMap[ n ] = true;
135
      }
136
    }else{
137
2942483
      if (n.hasOperator())
138
      {
139
1546514
        computeArgs(args, activeMap, n.getOperator(), visited);
140
      }
141
6040106
      for( int i=0; i<(int)n.getNumChildren(); i++ ){
142
3097623
        computeArgs( args, activeMap, n[i], visited );
143
      }
144
    }
145
  }
146
4933843
}
147
148
152254
void QuantifiersRewriter::computeArgVec(const std::vector<Node>& args,
149
                                        std::vector<Node>& activeArgs,
150
                                        Node n)
151
{
152
152254
  Assert(activeArgs.empty());
153
304508
  std::map< Node, bool > activeMap;
154
304508
  std::map< Node, bool > visited;
155
152254
  computeArgs( args, activeMap, n, visited );
156
152254
  if( !activeMap.empty() ){
157
2429847
    for( unsigned i=0; i<args.size(); i++ ){
158
2279238
      if( activeMap.find( args[i] )!=activeMap.end() ){
159
348263
        activeArgs.push_back( args[i] );
160
      }
161
    }
162
  }
163
152254
}
164
165
68838
void QuantifiersRewriter::computeArgVec2(const std::vector<Node>& args,
166
                                         std::vector<Node>& activeArgs,
167
                                         Node n,
168
                                         Node ipl)
169
{
170
68838
  Assert(activeArgs.empty());
171
137676
  std::map< Node, bool > activeMap;
172
137676
  std::map< Node, bool > visited;
173
68838
  computeArgs( args, activeMap, n, visited );
174
68838
  if( !activeMap.empty() ){
175
    //collect variables in inst pattern list only if we cannot eliminate quantifier
176
68614
    computeArgs( args, activeMap, ipl, visited );
177
208399
    for( unsigned i=0; i<args.size(); i++ ){
178
139785
      if( activeMap.find( args[i] )!=activeMap.end() ){
179
138773
        activeArgs.push_back( args[i] );
180
      }
181
    }
182
  }
183
68838
}
184
185
135770
RewriteResponse QuantifiersRewriter::preRewrite(TNode in) {
186
135770
  if( in.getKind()==kind::EXISTS || in.getKind()==kind::FORALL ){
187
79693
    Trace("quantifiers-rewrite-debug") << "pre-rewriting " << in << std::endl;
188
157597
    std::vector< Node > args;
189
157597
    Node body = in;
190
79693
    bool doRewrite = false;
191
94015
    while( body.getNumChildren()==2 && body.getKind()==body[1].getKind() ){
192
14381
      for( unsigned i=0; i<body[0].getNumChildren(); i++ ){
193
7220
        args.push_back( body[0][i] );
194
      }
195
7161
      body = body[1];
196
7161
      doRewrite = true;
197
    }
198
79693
    if( doRewrite ){
199
3578
      std::vector< Node > children;
200
3618
      for( unsigned i=0; i<body[0].getNumChildren(); i++ ){
201
1829
        args.push_back( body[0][i] );
202
      }
203
1789
      children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST,args) );
204
1789
      children.push_back( body[1] );
205
1789
      if( body.getNumChildren()==3 ){
206
48
        children.push_back( body[2] );
207
      }
208
3578
      Node n = NodeManager::currentNM()->mkNode( in.getKind(), children );
209
1789
      if( in!=n ){
210
1789
        Trace("quantifiers-pre-rewrite") << "*** pre-rewrite " << in << std::endl;
211
1789
        Trace("quantifiers-pre-rewrite") << " to " << std::endl;
212
1789
        Trace("quantifiers-pre-rewrite") << n << std::endl;
213
      }
214
1789
      return RewriteResponse(REWRITE_DONE, n);
215
    }
216
  }
217
133981
  return RewriteResponse(REWRITE_DONE, in);
218
}
219
220
248216
RewriteResponse QuantifiersRewriter::postRewrite(TNode in) {
221
248216
  Trace("quantifiers-rewrite-debug") << "post-rewriting " << in << std::endl;
222
248216
  RewriteStatus status = REWRITE_DONE;
223
496432
  Node ret = in;
224
248216
  RewriteStep rew_op = COMPUTE_LAST;
225
  //get the body
226
248216
  if( in.getKind()==EXISTS ){
227
5508
    std::vector< Node > children;
228
2754
    children.push_back( in[0] );
229
2754
    children.push_back( in[1].negate() );
230
2754
    if( in.getNumChildren()==3 ){
231
43
      children.push_back( in[2] );
232
    }
233
2754
    ret = NodeManager::currentNM()->mkNode( FORALL, children );
234
2754
    ret = ret.negate();
235
2754
    status = REWRITE_AGAIN_FULL;
236
245462
  }else if( in.getKind()==FORALL ){
237
133602
    if( in[1].isConst() && in.getNumChildren()==2 ){
238
863
      return RewriteResponse( status, in[1] );
239
    }else{
240
      //compute attributes
241
265478
      QAttributes qa;
242
132739
      QuantAttributes::computeQuantAttributes( in, qa );
243
1067705
      for (unsigned i = 0; i < COMPUTE_LAST; ++i)
244
      {
245
953495
        RewriteStep op = static_cast<RewriteStep>(i);
246
953495
        if( doOperation( in, op, qa ) ){
247
704581
          ret = computeOperation( in, op, qa );
248
704581
          if( ret!=in ){
249
18529
            rew_op = op;
250
18529
            status = REWRITE_AGAIN_FULL;
251
18529
            break;
252
          }
253
        }
254
      }
255
    }
256
  }
257
  //print if changed
258
247353
  if( in!=ret ){
259
21283
    Trace("quantifiers-rewrite") << "*** rewrite (op=" << rew_op << ") " << in << std::endl;
260
21283
    Trace("quantifiers-rewrite") << " to " << std::endl;
261
21283
    Trace("quantifiers-rewrite") << ret << std::endl;
262
  }
263
247353
  return RewriteResponse( status, ret );
264
}
265
266
803403
bool QuantifiersRewriter::addCheckElimChild( std::vector< Node >& children, Node c, Kind k, std::map< Node, bool >& lit_pol, bool& childrenChanged ){
267
803403
  if( ( k==OR || k==AND ) && options::elimTautQuant() ){
268
1285405
    Node lit = c.getKind()==NOT ? c[0] : c;
269
642813
    bool pol = c.getKind()!=NOT;
270
642813
    std::map< Node, bool >::iterator it = lit_pol.find( lit );
271
642813
    if( it==lit_pol.end() ){
272
641901
      lit_pol[lit] = pol;
273
641901
      children.push_back( c );
274
    }else{
275
912
      childrenChanged = true;
276
912
      if( it->second!=pol ){
277
221
        return false;
278
      }
279
    }
280
  }else{
281
160590
    children.push_back( c );
282
  }
283
803182
  return true;
284
}
285
286
// eliminates IMPLIES/XOR, removes duplicates/infers tautologies of AND/OR, and computes NNF
287
921844
Node QuantifiersRewriter::computeElimSymbols( Node body ) {
288
921844
  Kind ok = body.getKind();
289
921844
  Kind k = ok;
290
921844
  bool negAllCh = false;
291
921844
  bool negCh1 = false;
292
921844
  if( ok==IMPLIES ){
293
11813
    k = OR;
294
11813
    negCh1 = true;
295
910031
  }else if( ok==XOR ){
296
767
    k = EQUAL;
297
767
    negCh1 = true;
298
909264
  }else if( ok==NOT ){
299
369860
    if( body[0].getKind()==NOT ){
300
      return computeElimSymbols( body[0][0] );
301
369860
    }else if( body[0].getKind()==OR || body[0].getKind()==IMPLIES ){
302
1675
      k = AND;
303
1675
      negAllCh = true;
304
1675
      negCh1 = body[0].getKind()==IMPLIES;
305
1675
      body = body[0];
306
368185
    }else if( body[0].getKind()==AND ){
307
5638
      k = OR;
308
5638
      negAllCh = true;
309
5638
      body = body[0];
310
362547
    }else if( body[0].getKind()==XOR || ( body[0].getKind()==EQUAL && body[0][0].getType().isBoolean() ) ){
311
2733
      k = EQUAL;
312
2733
      negCh1 = ( body[0].getKind()==EQUAL );
313
2733
      body = body[0];
314
359814
    }else if( body[0].getKind()==ITE ){
315
87
      k = body[0].getKind();
316
87
      negAllCh = true;
317
87
      negCh1 = true;
318
87
      body = body[0];
319
    }else{
320
359727
      return body;
321
    }
322
539404
  }else if( ( ok!=EQUAL || !body[0].getType().isBoolean() ) && ok!=ITE && ok!=AND && ok!=OR ){
323
    //a literal
324
321732
    return body;
325
  }
326
240385
  bool childrenChanged = false;
327
480770
  std::vector< Node > children;
328
480770
  std::map< Node, bool > lit_pol;
329
1029269
  for( unsigned i=0; i<body.getNumChildren(); i++ ){
330
1577989
    Node c = computeElimSymbols( ( i==0 && negCh1 )!=negAllCh ? body[i].negate() : body[i] );
331
789105
    bool success = true;
332
789105
    if( c.getKind()==k && ( k==OR || k==AND ) ){
333
      //flatten
334
5550
      childrenChanged = true;
335
25397
      for( unsigned j=0; j<c.getNumChildren(); j++ ){
336
19848
        if( !addCheckElimChild( children, c[j], k, lit_pol, childrenChanged ) ){
337
1
          success = false;
338
1
          break;
339
        }
340
      }
341
    }else{
342
783555
      success = addCheckElimChild( children, c, k, lit_pol, childrenChanged );
343
    }
344
789105
    if( !success ){
345
      // tautology
346
221
      Assert(k == OR || k == AND);
347
221
      return NodeManager::currentNM()->mkConst( k==OR );
348
    }
349
788884
    childrenChanged = childrenChanged || c!=body[i];
350
  }
351
240164
  if( childrenChanged || k!=ok ){
352
26453
    return ( children.size()==1 && k!=NOT ) ? children[0] : NodeManager::currentNM()->mkNode( k, children );
353
  }else{
354
213711
    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
114544
Node QuantifiersRewriter::computeProcessTerms( Node body, std::vector< Node >& new_vars, std::vector< Node >& new_conds, Node q, QAttributes& qa ){
430
229088
  std::map< Node, Node > cache;
431
114544
  if( qa.isFunDef() ){
432
    Node h = QuantAttributes::getFunDefHead( q );
433
    Assert(!h.isNull());
434
    // if it is a function definition, rewrite the body independently
435
    Node fbody = QuantAttributes::getFunDefBody( q );
436
    Trace("quantifiers-rewrite-debug") << "Decompose " << h << " / " << fbody << " as function definition for " << q << "." << std::endl;
437
    if (!fbody.isNull())
438
    {
439
      Node r = computeProcessTerms2(fbody, cache, new_vars, new_conds);
440
      Assert(new_vars.size() == h.getNumChildren());
441
      return Rewriter::rewrite(NodeManager::currentNM()->mkNode(EQUAL, h, r));
442
    }
443
    // It can happen that we can't infer the shape of the function definition,
444
    // for example: forall xy. f( x, y ) = 1 + f( x, y ), this is rewritten to
445
    // forall xy. false.
446
  }
447
114544
  return computeProcessTerms2(body, cache, new_vars, new_conds);
448
}
449
450
2944376
Node QuantifiersRewriter::computeProcessTerms2(Node body,
451
                                               std::map<Node, Node>& cache,
452
                                               std::vector<Node>& new_vars,
453
                                               std::vector<Node>& new_conds)
454
{
455
2944376
  NodeManager* nm = NodeManager::currentNM();
456
5888752
  Trace("quantifiers-rewrite-term-debug2")
457
2944376
      << "computeProcessTerms " << body << std::endl;
458
2944376
  std::map< Node, Node >::iterator iti = cache.find( body );
459
2944376
  if( iti!=cache.end() ){
460
958292
    return iti->second;
461
  }
462
1986084
  bool changed = false;
463
3972168
  std::vector<Node> children;
464
4815916
  for (size_t i = 0; i < body.getNumChildren(); i++)
465
  {
466
    // do the recursive call on children
467
5659664
    Node nn = computeProcessTerms2(body[i], cache, new_vars, new_conds);
468
2829832
    children.push_back(nn);
469
2829832
    changed = changed || nn != body[i];
470
  }
471
472
  // make return value
473
3972168
  Node ret;
474
1986084
  if (changed)
475
  {
476
4898
    if (body.getMetaKind() == kind::metakind::PARAMETERIZED)
477
    {
478
194
      children.insert(children.begin(), body.getOperator());
479
    }
480
4898
    ret = nm->mkNode(body.getKind(), children);
481
  }
482
  else
483
  {
484
1981186
    ret = body;
485
  }
486
487
3972168
  Trace("quantifiers-rewrite-term-debug2")
488
1986084
      << "Returning " << ret << " for " << body << std::endl;
489
  // do context-independent rewriting
490
3972168
  if (ret.getKind() == EQUAL
491
1986084
      && options::iteLiftQuant() != options::IteLiftQuantMode::NONE)
492
  {
493
695899
    for (size_t i = 0; i < 2; i++)
494
    {
495
464315
      if (ret[i].getKind() == ITE)
496
      {
497
20763
        Node no = i == 0 ? ret[1] : ret[0];
498
10794
        if (no.getKind() != ITE)
499
        {
500
          bool doRewrite =
501
9462
              options::iteLiftQuant() == options::IteLiftQuantMode::ALL;
502
18099
          std::vector<Node> childrenIte;
503
9462
          childrenIte.push_back(ret[i][0]);
504
28386
          for (size_t j = 1; j <= 2; j++)
505
          {
506
            // check if it rewrites to a constant
507
37848
            Node nn = nm->mkNode(EQUAL, no, ret[i][j]);
508
18924
            nn = Rewriter::rewrite(nn);
509
18924
            childrenIte.push_back(nn);
510
18924
            if (nn.isConst())
511
            {
512
1147
              doRewrite = true;
513
            }
514
          }
515
9462
          if (doRewrite)
516
          {
517
825
            ret = nm->mkNode(ITE, childrenIte);
518
825
            break;
519
          }
520
        }
521
      }
522
    }
523
  }
524
1753675
  else if (ret.getKind() == SELECT && ret[0].getKind() == STORE)
525
  {
526
184
    Node st = ret[0];
527
184
    Node index = ret[1];
528
184
    std::vector<Node> iconds;
529
184
    std::vector<Node> elements;
530
550
    while (st.getKind() == STORE)
531
    {
532
229
      iconds.push_back(index.eqNode(st[1]));
533
229
      elements.push_back(st[2]);
534
229
      st = st[0];
535
    }
536
92
    ret = nm->mkNode(SELECT, st, index);
537
    // conditions
538
321
    for (int i = (iconds.size() - 1); i >= 0; i--)
539
    {
540
229
      ret = nm->mkNode(ITE, iconds[i], elements[i], ret);
541
    }
542
  }
543
1986084
  cache[body] = ret;
544
1986084
  return ret;
545
}
546
547
25
Node QuantifiersRewriter::computeExtendedRewrite(Node q)
548
{
549
50
  Node body = q[1];
550
  // apply extended rewriter
551
50
  Node bodyr = Rewriter::callExtendedRewrite(body);
552
25
  if (body != bodyr)
553
  {
554
24
    std::vector<Node> children;
555
12
    children.push_back(q[0]);
556
12
    children.push_back(bodyr);
557
12
    if (q.getNumChildren() == 3)
558
    {
559
      children.push_back(q[2]);
560
    }
561
12
    return NodeManager::currentNM()->mkNode(FORALL, children);
562
  }
563
13
  return q;
564
}
565
566
114381
Node QuantifiersRewriter::computeCondSplit(Node body,
567
                                           const std::vector<Node>& args,
568
                                           QAttributes& qa)
569
{
570
114381
  NodeManager* nm = NodeManager::currentNM();
571
114381
  Kind bk = body.getKind();
572
229120
  if (options::iteDtTesterSplitQuant() && bk == ITE
573
228770
      && body[0].getKind() == APPLY_TESTER)
574
  {
575
    Trace("quantifiers-rewrite-ite-debug") << "DTT split : " << body << std::endl;
576
    std::map< Node, Node > pcons;
577
    std::map< Node, std::map< int, Node > > ncons;
578
    std::vector< Node > conj;
579
    computeDtTesterIteSplit( body, pcons, ncons, conj );
580
    Assert(!conj.empty());
581
    if( conj.size()>1 ){
582
      Trace("quantifiers-rewrite-ite") << "*** Split ITE (datatype tester) " << body << " into : " << std::endl;
583
      for( unsigned i=0; i<conj.size(); i++ ){
584
        Trace("quantifiers-rewrite-ite") << "   " << conj[i] << std::endl;
585
      }
586
      return nm->mkNode(AND, conj);
587
    }
588
  }
589
114381
  if (!options::condVarSplitQuant())
590
  {
591
    return body;
592
  }
593
228762
  Trace("cond-var-split-debug")
594
114381
      << "Conditional var elim split " << body << "?" << std::endl;
595
596
114381
  if (bk == ITE
597
114573
      || (bk == EQUAL && body[0].getType().isBoolean()
598
24432
          && options::condVarSplitQuantAgg()))
599
  {
600
192
    Assert(!qa.isFunDef());
601
192
    bool do_split = false;
602
192
    unsigned index_max = bk == ITE ? 0 : 1;
603
354
    std::vector<Node> tmpArgs = args;
604
354
    for (unsigned index = 0; index <= index_max; index++)
605
    {
606
576
      if (hasVarElim(body[index], true, tmpArgs)
607
576
          || hasVarElim(body[index], false, tmpArgs))
608
      {
609
30
        do_split = true;
610
30
        break;
611
      }
612
    }
613
192
    if (do_split)
614
    {
615
60
      Node pos;
616
60
      Node neg;
617
30
      if (bk == ITE)
618
      {
619
30
        pos = nm->mkNode(OR, body[0].negate(), body[1]);
620
30
        neg = nm->mkNode(OR, body[0], body[2]);
621
      }
622
      else
623
      {
624
        pos = nm->mkNode(OR, body[0].negate(), body[1]);
625
        neg = nm->mkNode(OR, body[0], body[1].negate());
626
      }
627
60
      Trace("cond-var-split-debug") << "*** Split (conditional variable eq) "
628
30
                                    << body << " into : " << std::endl;
629
30
      Trace("cond-var-split-debug") << "   " << pos << std::endl;
630
30
      Trace("cond-var-split-debug") << "   " << neg << std::endl;
631
30
      return nm->mkNode(AND, pos, neg);
632
    }
633
  }
634
635
114351
  if (bk == OR)
636
  {
637
46003
    unsigned size = body.getNumChildren();
638
46003
    bool do_split = false;
639
46003
    unsigned split_index = 0;
640
186025
    for (unsigned i = 0; i < size; i++)
641
    {
642
      // check if this child is a (conditional) variable elimination
643
280185
      Node b = body[i];
644
140163
      if (b.getKind() == AND)
645
      {
646
17166
        std::vector<Node> vars;
647
17166
        std::vector<Node> subs;
648
17166
        std::vector<Node> tmpArgs = args;
649
33276
        for (unsigned j = 0, bsize = b.getNumChildren(); j < bsize; j++)
650
        {
651
24834
          if (getVarElimLit(body, b[j], false, tmpArgs, vars, subs))
652
          {
653
4822
            Trace("cond-var-split-debug") << "Variable elimination in child #"
654
2411
                                          << j << " under " << i << std::endl;
655
            // Figure out if we should split
656
            // Currently we split if the aggressive option is set, or
657
            // if the top-level OR is binary.
658
2411
            if (options::condVarSplitQuantAgg() || size == 2)
659
            {
660
141
              do_split = true;
661
            }
662
            // other splitting criteria go here
663
664
2411
            if (do_split)
665
            {
666
141
              split_index = i;
667
141
              break;
668
            }
669
2270
            vars.clear();
670
2270
            subs.clear();
671
2270
            tmpArgs = args;
672
          }
673
        }
674
      }
675
140163
      if (do_split)
676
      {
677
141
        break;
678
      }
679
    }
680
46003
    if (do_split)
681
    {
682
282
      std::vector<Node> children;
683
423
      for (TNode bc : body)
684
      {
685
282
        children.push_back(bc);
686
      }
687
282
      std::vector<Node> split_children;
688
570
      for (TNode bci : body[split_index])
689
      {
690
429
        children[split_index] = bci;
691
429
        split_children.push_back(nm->mkNode(OR, children));
692
      }
693
      // split the AND child, for example:
694
      //  ( x!=a ^ P(x) ) V Q(x) ---> ( x!=a V Q(x) ) ^ ( P(x) V Q(x) )
695
141
      return nm->mkNode(AND, split_children);
696
    }
697
  }
698
699
114210
  return body;
700
}
701
702
6227
bool QuantifiersRewriter::isVarElim(Node v, Node s)
703
{
704
6227
  Assert(v.getKind() == BOUND_VARIABLE);
705
6227
  return !expr::hasSubterm(s, v) && s.getType().isSubtypeOf(v.getType());
706
}
707
708
38111
Node QuantifiersRewriter::getVarElimEq(Node lit,
709
                                       const std::vector<Node>& args,
710
                                       Node& var)
711
{
712
38111
  Assert(lit.getKind() == EQUAL);
713
38111
  Node slv;
714
76222
  TypeNode tt = lit[0].getType();
715
38111
  if (tt.isReal())
716
  {
717
15845
    slv = getVarElimEqReal(lit, args, var);
718
  }
719
22266
  else if (tt.isBitVector())
720
  {
721
731
    slv = getVarElimEqBv(lit, args, var);
722
  }
723
21535
  else if (tt.isStringLike())
724
  {
725
242
    slv = getVarElimEqString(lit, args, var);
726
  }
727
76222
  return slv;
728
}
729
730
15845
Node QuantifiersRewriter::getVarElimEqReal(Node lit,
731
                                           const std::vector<Node>& args,
732
                                           Node& var)
733
{
734
  // for arithmetic, solve the equality
735
31690
  std::map<Node, Node> msum;
736
15845
  if (!ArithMSum::getMonomialSumLit(lit, msum))
737
  {
738
    return Node::null();
739
  }
740
15845
  std::vector<Node>::const_iterator ita;
741
48133
  for (std::map<Node, Node>::iterator itm = msum.begin(); itm != msum.end();
742
       ++itm)
743
  {
744
32494
    if (itm->first.isNull())
745
    {
746
3269
      continue;
747
    }
748
29225
    ita = std::find(args.begin(), args.end(), itm->first);
749
29225
    if (ita != args.end())
750
    {
751
946
      Node veq_c;
752
946
      Node val;
753
576
      int ires = ArithMSum::isolate(itm->first, msum, veq_c, val, EQUAL);
754
576
      if (ires != 0 && veq_c.isNull() && isVarElim(itm->first, val))
755
      {
756
206
        var = itm->first;
757
206
        return val;
758
      }
759
    }
760
  }
761
15639
  return Node::null();
762
}
763
764
731
Node QuantifiersRewriter::getVarElimEqBv(Node lit,
765
                                         const std::vector<Node>& args,
766
                                         Node& var)
767
{
768
731
  if (Trace.isOn("quant-velim-bv"))
769
  {
770
    Trace("quant-velim-bv") << "Bv-Elim : " << lit << " varList = { ";
771
    for (const Node& v : args)
772
    {
773
      Trace("quant-velim-bv") << v << " ";
774
    }
775
    Trace("quant-velim-bv") << "} ?" << std::endl;
776
  }
777
731
  Assert(lit.getKind() == EQUAL);
778
  // TODO (#1494) : linearize the literal using utility
779
780
  // compute a subset active_args of the bound variables args that occur in lit
781
1462
  std::vector<Node> active_args;
782
731
  computeArgVec(args, active_args, lit);
783
784
1462
  BvInverter binv;
785
1546
  for (const Node& cvar : active_args)
786
  {
787
    // solve for the variable on this path using the inverter
788
1668
    std::vector<unsigned> path;
789
1668
    Node slit = binv.getPathToPv(lit, cvar, path);
790
853
    if (!slit.isNull())
791
    {
792
814
      Node slv = binv.solveBvLit(cvar, lit, path, nullptr);
793
426
      Trace("quant-velim-bv") << "...solution : " << slv << std::endl;
794
426
      if (!slv.isNull())
795
      {
796
66
        var = cvar;
797
        // if this is a proper variable elimination, that is, var = slv where
798
        // var is not in the free variables of slv, then we can return this
799
        // as the variable elimination for lit.
800
66
        if (isVarElim(var, slv))
801
        {
802
38
          return slv;
803
        }
804
      }
805
    }
806
    else
807
    {
808
427
      Trace("quant-velim-bv") << "...non-invertible path." << std::endl;
809
    }
810
  }
811
812
693
  return Node::null();
813
}
814
815
242
Node QuantifiersRewriter::getVarElimEqString(Node lit,
816
                                             const std::vector<Node>& args,
817
                                             Node& var)
818
{
819
242
  Assert(lit.getKind() == EQUAL);
820
242
  NodeManager* nm = NodeManager::currentNM();
821
722
  for (unsigned i = 0; i < 2; i++)
822
  {
823
484
    if (lit[i].getKind() == STRING_CONCAT)
824
    {
825
12
      TypeNode stype = lit[i].getType();
826
20
      for (unsigned j = 0, nchildren = lit[i].getNumChildren(); j < nchildren;
827
           j++)
828
      {
829
16
        if (std::find(args.begin(), args.end(), lit[i][j]) != args.end())
830
        {
831
12
          var = lit[i][j];
832
20
          Node slv = lit[1 - i];
833
20
          std::vector<Node> preL(lit[i].begin(), lit[i].begin() + j);
834
20
          std::vector<Node> postL(lit[i].begin() + j + 1, lit[i].end());
835
20
          Node tpre = strings::utils::mkConcat(preL, stype);
836
20
          Node tpost = strings::utils::mkConcat(postL, stype);
837
20
          Node slvL = nm->mkNode(STRING_LENGTH, slv);
838
20
          Node tpreL = nm->mkNode(STRING_LENGTH, tpre);
839
20
          Node tpostL = nm->mkNode(STRING_LENGTH, tpost);
840
12
          slv = nm->mkNode(
841
              STRING_SUBSTR,
842
              slv,
843
              tpreL,
844
24
              nm->mkNode(MINUS, slvL, nm->mkNode(PLUS, tpreL, tpostL)));
845
          // forall x. r ++ x ++ t = s => P( x )
846
          //   is equivalent to
847
          // r ++ s' ++ t = s => P( s' ) where
848
          // s' = substr( s, |r|, |s|-(|t|+|r|) ).
849
          // We apply this only if r,t,s do not contain free variables.
850
12
          if (!expr::hasFreeVar(slv))
851
          {
852
4
            return slv;
853
          }
854
        }
855
      }
856
    }
857
  }
858
859
238
  return Node::null();
860
}
861
862
239432
bool QuantifiersRewriter::getVarElimLit(Node body,
863
                                        Node lit,
864
                                        bool pol,
865
                                        std::vector<Node>& args,
866
                                        std::vector<Node>& vars,
867
                                        std::vector<Node>& subs)
868
{
869
239432
  if (lit.getKind() == NOT)
870
  {
871
6701
    lit = lit[0];
872
6701
    pol = !pol;
873
6701
    Assert(lit.getKind() != NOT);
874
  }
875
239432
  NodeManager* nm = NodeManager::currentNM();
876
478864
  Trace("var-elim-quant-debug")
877
239432
      << "Eliminate : " << lit << ", pol = " << pol << "?" << std::endl;
878
479664
  if (lit.getKind() == APPLY_TESTER && pol && lit[0].getKind() == BOUND_VARIABLE
879
478908
      && options::dtVarExpandQuant())
880
  {
881
88
    Trace("var-elim-dt") << "Expand datatype variable based on : " << lit
882
44
                         << std::endl;
883
    std::vector<Node>::iterator ita =
884
44
        std::find(args.begin(), args.end(), lit[0]);
885
44
    if (ita != args.end())
886
    {
887
44
      vars.push_back(lit[0]);
888
88
      Node tester = lit.getOperator();
889
44
      int index = datatypes::utils::indexOf(tester);
890
44
      const DType& dt = datatypes::utils::datatypeOf(tester);
891
44
      const DTypeConstructor& c = dt[index];
892
88
      std::vector<Node> newChildren;
893
44
      newChildren.push_back(c.getConstructor());
894
88
      std::vector<Node> newVars;
895
44
      BoundVarManager* bvm = nm->getBoundVarManager();
896
107
      for (unsigned j = 0, nargs = c.getNumArgs(); j < nargs; j++)
897
      {
898
126
        TypeNode tn = c[j].getRangeType();
899
126
        Node rn = nm->mkConst(Rational(j));
900
126
        Node cacheVal = BoundVarManager::getCacheValue(body, lit, rn);
901
126
        Node v = bvm->mkBoundVar<QRewDtExpandAttribute>(cacheVal, tn);
902
63
        newChildren.push_back(v);
903
63
        newVars.push_back(v);
904
      }
905
44
      subs.push_back(nm->mkNode(APPLY_CONSTRUCTOR, newChildren));
906
88
      Trace("var-elim-dt") << "...apply substitution " << subs[0] << "/"
907
44
                           << vars[0] << std::endl;
908
44
      args.erase(ita);
909
44
      args.insert(args.end(), newVars.begin(), newVars.end());
910
44
      return true;
911
    }
912
  }
913
  // all eliminations below guarded by varElimQuant()
914
239388
  if (!options::varElimQuant())
915
  {
916
    return false;
917
  }
918
919
239388
  if (lit.getKind() == EQUAL)
920
  {
921
133768
    if (pol || lit[0].getType().isBoolean())
922
    {
923
197795
      for (unsigned i = 0; i < 2; i++)
924
      {
925
134032
        bool tpol = pol;
926
262728
        Node v_slv = lit[i];
927
134032
        if (v_slv.getKind() == NOT)
928
        {
929
5548
          v_slv = v_slv[0];
930
5548
          tpol = !tpol;
931
        }
932
        std::vector<Node>::iterator ita =
933
134032
            std::find(args.begin(), args.end(), v_slv);
934
134032
        if (ita != args.end())
935
        {
936
5787
          if (isVarElim(v_slv, lit[1 - i]))
937
          {
938
10672
            Node slv = lit[1 - i];
939
5336
            if (!tpol)
940
            {
941
653
              Assert(slv.getType().isBoolean());
942
653
              slv = slv.negate();
943
            }
944
10672
            Trace("var-elim-quant")
945
5336
                << "Variable eliminate based on equality : " << v_slv << " -> "
946
5336
                << slv << std::endl;
947
5336
            vars.push_back(v_slv);
948
5336
            subs.push_back(slv);
949
5336
            args.erase(ita);
950
5336
            return true;
951
          }
952
        }
953
      }
954
    }
955
  }
956
234052
  if (lit.getKind() == BOUND_VARIABLE)
957
  {
958
1451
    std::vector< Node >::iterator ita = std::find( args.begin(), args.end(), lit );
959
1451
    if( ita!=args.end() ){
960
1449
      Trace("var-elim-bool") << "Variable eliminate : " << lit << std::endl;
961
1449
      vars.push_back( lit );
962
1449
      subs.push_back( NodeManager::currentNM()->mkConst( pol ) );
963
1449
      args.erase( ita );
964
1449
      return true;
965
    }
966
  }
967
232603
  if (lit.getKind() == EQUAL && pol)
968
  {
969
75974
    Node var;
970
75974
    Node slv = getVarElimEq(lit, args, var);
971
38111
    if (!slv.isNull())
972
    {
973
248
      Assert(!var.isNull());
974
      std::vector<Node>::iterator ita =
975
248
          std::find(args.begin(), args.end(), var);
976
248
      Assert(ita != args.end());
977
496
      Trace("var-elim-quant")
978
248
          << "Variable eliminate based on theory-specific solving : " << var
979
248
          << " -> " << slv << std::endl;
980
248
      Assert(!expr::hasSubterm(slv, var));
981
248
      Assert(slv.getType().isSubtypeOf(var.getType()));
982
248
      vars.push_back(var);
983
248
      subs.push_back(slv);
984
248
      args.erase(ita);
985
248
      return true;
986
    }
987
  }
988
232355
  return false;
989
}
990
991
117484
bool QuantifiersRewriter::getVarElim(Node body,
992
                                     std::vector<Node>& args,
993
                                     std::vector<Node>& vars,
994
                                     std::vector<Node>& subs)
995
{
996
117484
  return getVarElimInternal(body, body, false, args, vars, subs);
997
}
998
999
264356
bool QuantifiersRewriter::getVarElimInternal(Node body,
1000
                                             Node n,
1001
                                             bool pol,
1002
                                             std::vector<Node>& args,
1003
                                             std::vector<Node>& vars,
1004
                                             std::vector<Node>& subs)
1005
{
1006
264356
  Kind nk = n.getKind();
1007
264356
  if (nk == NOT)
1008
  {
1009
92445
    n = n[0];
1010
92445
    pol = !pol;
1011
92445
    nk = n.getKind();
1012
92445
    Assert(nk != NOT);
1013
  }
1014
264356
  if ((nk == AND && pol) || (nk == OR && !pol))
1015
  {
1016
191978
    for (const Node& cn : n)
1017
    {
1018
146518
      if (getVarElimInternal(body, cn, pol, args, vars, subs))
1019
      {
1020
4298
        return true;
1021
      }
1022
    }
1023
45460
    return false;
1024
  }
1025
214598
  return getVarElimLit(body, n, pol, args, vars, subs);
1026
}
1027
1028
354
bool QuantifiersRewriter::hasVarElim(Node n, bool pol, std::vector<Node>& args)
1029
{
1030
708
  std::vector< Node > vars;
1031
708
  std::vector< Node > subs;
1032
708
  return getVarElimInternal(n, n, pol, args, vars, subs);
1033
}
1034
1035
112744
bool QuantifiersRewriter::getVarElimIneq(Node body,
1036
                                         std::vector<Node>& args,
1037
                                         std::vector<Node>& bounds,
1038
                                         std::vector<Node>& subs,
1039
                                         QAttributes& qa)
1040
{
1041
112744
  Trace("var-elim-quant-debug") << "getVarElimIneq " << body << std::endl;
1042
  // For each variable v, we compute a set of implied bounds in the body
1043
  // of the quantified formula.
1044
  //   num_bounds[x][-1] stores the entailed lower bounds for x
1045
  //   num_bounds[x][1] stores the entailed upper bounds for x
1046
  //   num_bounds[x][0] stores the entailed disequalities for x
1047
  // These bounds are stored in a map that maps the literal for the bound to
1048
  // its required polarity. For example, for quantified formula
1049
  //   (forall ((x Int)) (or (= x 0) (>= x a)))
1050
  // we have:
1051
  //   num_bounds[x][0] contains { x -> { (= x 0) -> false } }
1052
  //   num_bounds[x][-1] contains { x -> { (>= x a) -> false } }
1053
  // This method succeeds in eliminating x if its only occurrences are in
1054
  // entailed disequalities, and one kind of bound. This is the case for the
1055
  // above quantified formula, which can be rewritten to false. The reason
1056
  // is that we can always chose a value for x that is arbitrarily large (resp.
1057
  // small) to satisfy all disequalities and inequalities for x.
1058
225488
  std::map<Node, std::map<int, std::map<Node, bool>>> num_bounds;
1059
  // The set of variables that we know we can not eliminate
1060
225488
  std::unordered_set<Node> ineligVars;
1061
  // compute the entailed literals
1062
225488
  QuantPhaseReq qpr(body);
1063
  // map to track which literals we have already processed, and hence can be
1064
  // excluded from the free variables check in the latter half of this method.
1065
225488
  std::map<Node, int> processed;
1066
308845
  for (const std::pair<const Node, bool>& pr : qpr.d_phase_reqs)
1067
  {
1068
    // an inequality that is entailed with a given polarity
1069
236604
    Node lit = pr.first;
1070
196101
    bool pol = pr.second;
1071
392202
    Trace("var-elim-quant-debug") << "Process inequality bounds : " << lit
1072
196101
                                  << ", pol = " << pol << "..." << std::endl;
1073
    bool canSolve =
1074
196101
        lit.getKind() == GEQ
1075
392202
        || (lit.getKind() == EQUAL && lit[0].getType().isReal() && !pol);
1076
196101
    if (!canSolve)
1077
    {
1078
155598
      continue;
1079
    }
1080
    // solve the inequality
1081
81006
    std::map<Node, Node> msum;
1082
40503
    if (!ArithMSum::getMonomialSumLit(lit, msum))
1083
    {
1084
      // not an inequality, cannot use
1085
      continue;
1086
    }
1087
40503
    processed[lit] = pol ? -1 : 1;
1088
125584
    for (const std::pair<const Node, Node>& m : msum)
1089
    {
1090
85081
      if (!m.first.isNull() && ineligVars.find(m.first) == ineligVars.end())
1091
      {
1092
        std::vector<Node>::iterator ita =
1093
69055
            std::find(args.begin(), args.end(), m.first);
1094
69055
        if (ita != args.end())
1095
        {
1096
          // store that this literal is upper/lower bound for itm->first
1097
62406
          Node veq_c;
1098
62406
          Node val;
1099
          int ires =
1100
31203
              ArithMSum::isolate(m.first, msum, veq_c, val, lit.getKind());
1101
31203
          if (ires != 0 && veq_c.isNull())
1102
          {
1103
30914
            if (lit.getKind() == GEQ)
1104
            {
1105
19520
              bool is_upper = pol != (ires == 1);
1106
39040
              Trace("var-elim-ineq-debug")
1107
19520
                  << lit << " is a " << (is_upper ? "upper" : "lower")
1108
19520
                  << " bound for " << m.first << std::endl;
1109
39040
              Trace("var-elim-ineq-debug")
1110
19520
                  << "  pol/ires = " << pol << " " << ires << std::endl;
1111
19520
              num_bounds[m.first][is_upper ? 1 : -1][lit] = pol;
1112
            }
1113
            else
1114
            {
1115
22788
              Trace("var-elim-ineq-debug")
1116
11394
                  << lit << " is a disequality for " << m.first << std::endl;
1117
11394
              num_bounds[m.first][0][lit] = pol;
1118
            }
1119
          }
1120
          else
1121
          {
1122
578
            Trace("var-elim-ineq-debug")
1123
289
                << "...ineligible " << m.first
1124
289
                << " since it cannot be solved for (" << ires << ", " << veq_c
1125
289
                << ")." << std::endl;
1126
289
            num_bounds.erase(m.first);
1127
289
            ineligVars.insert(m.first);
1128
          }
1129
        }
1130
        else
1131
        {
1132
          // compute variables in itm->first, these are not eligible for
1133
          // elimination
1134
75704
          std::unordered_set<Node> fvs;
1135
37852
          expr::getFreeVariables(m.first, fvs);
1136
79276
          for (const Node& v : fvs)
1137
          {
1138
82848
            Trace("var-elim-ineq-debug")
1139
41424
                << "...ineligible " << v
1140
41424
                << " since it is contained in monomial." << std::endl;
1141
41424
            num_bounds.erase(v);
1142
41424
            ineligVars.insert(v);
1143
          }
1144
        }
1145
      }
1146
    }
1147
  }
1148
1149
  // collect all variables that have only upper/lower bounds
1150
225488
  std::map<Node, bool> elig_vars;
1151
15007
  for (const std::pair<const Node, std::map<int, std::map<Node, bool>>>& nb :
1152
112744
       num_bounds)
1153
  {
1154
15007
    if (nb.second.find(1) == nb.second.end())
1155
    {
1156
16926
      Trace("var-elim-ineq-debug")
1157
8463
          << "Variable " << nb.first << " has only lower bounds." << std::endl;
1158
8463
      elig_vars[nb.first] = false;
1159
    }
1160
6544
    else if (nb.second.find(-1) == nb.second.end())
1161
    {
1162
4316
      Trace("var-elim-ineq-debug")
1163
2158
          << "Variable " << nb.first << " has only upper bounds." << std::endl;
1164
2158
      elig_vars[nb.first] = true;
1165
    }
1166
  }
1167
112744
  if (elig_vars.empty())
1168
  {
1169
103594
    return false;
1170
  }
1171
18300
  std::vector<Node> inactive_vars;
1172
18300
  std::map<Node, std::map<int, bool> > visited;
1173
  // traverse the body, invalidate variables if they occur in places other than
1174
  // the bounds they occur in
1175
18300
  std::unordered_map<TNode, std::unordered_set<int>> evisited;
1176
18300
  std::vector<TNode> evisit;
1177
18300
  std::vector<int> evisit_pol;
1178
18300
  TNode ecur;
1179
  int ecur_pol;
1180
9150
  evisit.push_back(body);
1181
9150
  evisit_pol.push_back(1);
1182
9150
  if (!qa.d_ipl.isNull())
1183
  {
1184
    // do not eliminate variables that occur in the annotation
1185
1424
    evisit.push_back(qa.d_ipl);
1186
1424
    evisit_pol.push_back(0);
1187
  }
1188
63414
  do
1189
  {
1190
72564
    ecur = evisit.back();
1191
72564
    evisit.pop_back();
1192
72564
    ecur_pol = evisit_pol.back();
1193
72564
    evisit_pol.pop_back();
1194
72564
    std::unordered_set<int>& epp = evisited[ecur];
1195
72564
    if (epp.find(ecur_pol) == epp.end())
1196
    {
1197
70993
      epp.insert(ecur_pol);
1198
70993
      if (elig_vars.find(ecur) != elig_vars.end())
1199
      {
1200
        // variable contained in a place apart from bounds, no longer eligible
1201
        // for elimination
1202
10184
        elig_vars.erase(ecur);
1203
20368
        Trace("var-elim-ineq-debug") << "...found occurrence of " << ecur
1204
10184
                                     << ", mark ineligible" << std::endl;
1205
      }
1206
      else
1207
      {
1208
60809
        bool rec = true;
1209
60809
        bool pol = ecur_pol >= 0;
1210
60809
        bool hasPol = ecur_pol != 0;
1211
60809
        if (hasPol)
1212
        {
1213
31919
          std::map<Node, int>::iterator itx = processed.find(ecur);
1214
31919
          if (itx != processed.end() && itx->second == ecur_pol)
1215
          {
1216
            // already processed this literal as a bound
1217
4999
            rec = false;
1218
          }
1219
        }
1220
60809
        if (rec)
1221
        {
1222
144463
          for (unsigned j = 0, size = ecur.getNumChildren(); j < size; j++)
1223
          {
1224
            bool newHasPol;
1225
            bool newPol;
1226
88653
            QuantPhaseReq::getPolarity(ecur, j, hasPol, pol, newHasPol, newPol);
1227
88653
            evisit.push_back(ecur[j]);
1228
88653
            evisit_pol.push_back(newHasPol ? (newPol ? 1 : -1) : 0);
1229
          }
1230
        }
1231
      }
1232
    }
1233
72564
  } while (!evisit.empty() && !elig_vars.empty());
1234
1235
9150
  bool ret = false;
1236
9150
  NodeManager* nm = NodeManager::currentNM();
1237
9587
  for (const std::pair<const Node, bool>& ev : elig_vars)
1238
  {
1239
874
    Node v = ev.first;
1240
874
    Trace("var-elim-ineq-debug")
1241
437
        << v << " is eligible for elimination." << std::endl;
1242
    // do substitution corresponding to infinite projection, all literals
1243
    // involving unbounded variable go to true/false
1244
    // disequalities of eligible variables are also eliminated
1245
437
    std::map<int, std::map<Node, bool>>& nbv = num_bounds[v];
1246
1311
    for (size_t i = 0; i < 2; i++)
1247
    {
1248
874
      size_t nindex = i == 0 ? (elig_vars[v] ? 1 : -1) : 0;
1249
1451
      for (const std::pair<const Node, bool>& nb : nbv[nindex])
1250
      {
1251
1154
        Trace("var-elim-ineq-debug")
1252
577
            << "  subs : " << nb.first << " -> " << nb.second << std::endl;
1253
577
        bounds.push_back(nb.first);
1254
577
        subs.push_back(nm->mkConst(nb.second));
1255
      }
1256
    }
1257
    // eliminate from args
1258
437
    std::vector<Node>::iterator ita = std::find(args.begin(), args.end(), v);
1259
437
    Assert(ita != args.end());
1260
437
    args.erase(ita);
1261
437
    ret = true;
1262
  }
1263
9150
  return ret;
1264
}
1265
1266
113148
Node QuantifiersRewriter::computeVarElimination( Node body, std::vector< Node >& args, QAttributes& qa ){
1267
226296
  if (!options::varElimQuant() && !options::dtVarExpandQuant()
1268
113148
      && !options::varIneqElimQuant())
1269
  {
1270
    return body;
1271
  }
1272
226296
  Trace("var-elim-quant-debug")
1273
113148
      << "computeVarElimination " << body << std::endl;
1274
226296
  Node prev;
1275
347898
  while (prev != body && !args.empty())
1276
  {
1277
117375
    prev = body;
1278
1279
234750
    std::vector<Node> vars;
1280
234750
    std::vector<Node> subs;
1281
    // standard variable elimination
1282
117375
    if (options::varElimQuant())
1283
    {
1284
117375
      getVarElim(body, args, vars, subs);
1285
    }
1286
    // variable elimination based on one-direction inequalities
1287
117375
    if (vars.empty() && options::varIneqElimQuant())
1288
    {
1289
112744
      getVarElimIneq(body, args, vars, subs, qa);
1290
    }
1291
    // if we eliminated a variable, update body and reprocess
1292
117375
    if (!vars.empty())
1293
    {
1294
9966
      Trace("var-elim-quant-debug")
1295
4983
          << "VE " << vars.size() << "/" << args.size() << std::endl;
1296
4983
      Assert(vars.size() == subs.size());
1297
      // remake with eliminated nodes
1298
4983
      body =
1299
9966
          body.substitute(vars.begin(), vars.end(), subs.begin(), subs.end());
1300
4983
      body = Rewriter::rewrite(body);
1301
4983
      if (!qa.d_ipl.isNull())
1302
      {
1303
52
        qa.d_ipl = qa.d_ipl.substitute(
1304
26
            vars.begin(), vars.end(), subs.begin(), subs.end());
1305
      }
1306
4983
      Trace("var-elim-quant") << "Return " << body << std::endl;
1307
    }
1308
  }
1309
113148
  return body;
1310
}
1311
1312
456410
Node QuantifiersRewriter::computePrenex(Node q,
1313
                                        Node body,
1314
                                        std::unordered_set<Node>& args,
1315
                                        std::unordered_set<Node>& nargs,
1316
                                        bool pol,
1317
                                        bool prenexAgg)
1318
{
1319
456410
  NodeManager* nm = NodeManager::currentNM();
1320
456410
  Kind k = body.getKind();
1321
456410
  if (k == FORALL)
1322
  {
1323
26856
    if ((pol || prenexAgg)
1324
15378
        && (options::prenexQuantUser() || !QuantAttributes::hasPattern(body)))
1325
    {
1326
2284
      std::vector< Node > terms;
1327
2284
      std::vector< Node > subs;
1328
1142
      BoundVarManager* bvm = nm->getBoundVarManager();
1329
      //for doing prenexing of same-signed quantifiers
1330
      //must rename each variable that already exists
1331
2917
      for (const Node& v : body[0])
1332
      {
1333
1775
        terms.push_back(v);
1334
3550
        TypeNode vt = v.getType();
1335
3550
        Node vv;
1336
1775
        if (!q.isNull())
1337
        {
1338
          // We cache based on the original quantified formula, the subformula
1339
          // that we are pulling variables from (body), and the variable v.
1340
          // The argument body is required since in rare cases, two subformulas
1341
          // may share the same variables. This is the case for define-fun
1342
          // or inferred substitutions that contain quantified formulas.
1343
3550
          Node cacheVal = BoundVarManager::getCacheValue(q, body, v);
1344
1775
          vv = bvm->mkBoundVar<QRewPrenexAttribute>(cacheVal, vt);
1345
        }
1346
        else
1347
        {
1348
          // not specific to a quantified formula, use normal
1349
          vv = nm->mkBoundVar(vt);
1350
        }
1351
1775
        subs.push_back(vv);
1352
      }
1353
1142
      if (pol)
1354
      {
1355
1142
        args.insert(subs.begin(), subs.end());
1356
      }
1357
      else
1358
      {
1359
        nargs.insert(subs.begin(), subs.end());
1360
      }
1361
2284
      Node newBody = body[1];
1362
1142
      newBody = newBody.substitute( terms.begin(), terms.end(), subs.begin(), subs.end() );
1363
1142
      return newBody;
1364
    }
1365
  //must remove structure
1366
  }
1367
442332
  else if (prenexAgg && k == ITE && body.getType().isBoolean())
1368
  {
1369
    Node nn = nm->mkNode(AND,
1370
                         nm->mkNode(OR, body[0].notNode(), body[1]),
1371
                         nm->mkNode(OR, body[0], body[2]));
1372
    return computePrenex(q, nn, args, nargs, pol, prenexAgg);
1373
  }
1374
442332
  else if (prenexAgg && k == EQUAL && body[0].getType().isBoolean())
1375
  {
1376
    Node nn = nm->mkNode(AND,
1377
                         nm->mkNode(OR, body[0].notNode(), body[1]),
1378
                         nm->mkNode(OR, body[0], body[1].notNode()));
1379
    return computePrenex(q, nn, args, nargs, pol, prenexAgg);
1380
442332
  }else if( body.getType().isBoolean() ){
1381
442332
    Assert(k != EXISTS);
1382
442332
    bool childrenChanged = false;
1383
883473
    std::vector< Node > newChildren;
1384
1350343
    for (size_t i = 0, nchild = body.getNumChildren(); i < nchild; i++)
1385
    {
1386
      bool newHasPol;
1387
      bool newPol;
1388
908011
      QuantPhaseReq::getPolarity( body, i, true, pol, newHasPol, newPol );
1389
1472972
      if (!newHasPol)
1390
      {
1391
564961
        newChildren.push_back( body[i] );
1392
564961
        continue;
1393
      }
1394
686100
      Node n = computePrenex(q, body[i], args, nargs, newPol, prenexAgg);
1395
343050
      newChildren.push_back(n);
1396
343050
      childrenChanged = n != body[i] || childrenChanged;
1397
    }
1398
442332
    if( childrenChanged ){
1399
1191
      if (k == NOT && newChildren[0].getKind() == NOT)
1400
      {
1401
        return newChildren[0][0];
1402
      }
1403
1191
      return nm->mkNode(k, newChildren);
1404
    }
1405
  }
1406
454077
  return body;
1407
}
1408
1409
46747
Node QuantifiersRewriter::computeSplit( std::vector< Node >& args, Node body, QAttributes& qa ) {
1410
46747
  Assert(body.getKind() == OR);
1411
46747
  size_t var_found_count = 0;
1412
46747
  size_t eqc_count = 0;
1413
46747
  size_t eqc_active = 0;
1414
93494
  std::map< Node, int > var_to_eqc;
1415
93494
  std::map< int, std::vector< Node > > eqc_to_var;
1416
93494
  std::map< int, std::vector< Node > > eqc_to_lit;
1417
1418
93494
  std::vector<Node> lits;
1419
1420
198270
  for( unsigned i=0; i<body.getNumChildren(); i++ ){
1421
    //get variables contained in the literal
1422
303046
    Node n = body[i];
1423
303046
    std::vector< Node > lit_args;
1424
151523
    computeArgVec( args, lit_args, n );
1425
151523
    if( lit_args.empty() ){
1426
1641
      lits.push_back( n );
1427
    }else {
1428
      //collect the equivalence classes this literal belongs to, and the new variables it contributes
1429
299764
      std::vector< int > eqcs;
1430
299764
      std::vector< Node > lit_new_args;
1431
      //for each variable in literal
1432
497274
      for( unsigned j=0; j<lit_args.size(); j++) {
1433
        //see if the variable has already been found
1434
347392
        if (var_to_eqc.find(lit_args[j])!=var_to_eqc.end()) {
1435
230638
          int eqc = var_to_eqc[lit_args[j]];
1436
230638
          if (std::find(eqcs.begin(), eqcs.end(), eqc)==eqcs.end()) {
1437
102860
            eqcs.push_back(eqc);
1438
          }
1439
        }else{
1440
116754
          var_found_count++;
1441
116754
          lit_new_args.push_back(lit_args[j]);
1442
        }
1443
      }
1444
149882
      if (eqcs.empty()) {
1445
53699
        eqcs.push_back(eqc_count);
1446
53699
        eqc_count++;
1447
53699
        eqc_active++;
1448
      }
1449
1450
149882
      int eqcz = eqcs[0];
1451
      //merge equivalence classes with eqcz
1452
156559
      for (unsigned j=1; j<eqcs.size(); j++) {
1453
6677
        int eqc = eqcs[j];
1454
        //move all variables from equivalence class
1455
31786
        for (unsigned k=0; k<eqc_to_var[eqc].size(); k++) {
1456
50218
          Node v = eqc_to_var[eqc][k];
1457
25109
          var_to_eqc[v] = eqcz;
1458
25109
          eqc_to_var[eqcz].push_back(v);
1459
        }
1460
6677
        eqc_to_var.erase(eqc);
1461
        //move all literals from equivalence class
1462
30478
        for (unsigned k=0; k<eqc_to_lit[eqc].size(); k++) {
1463
47602
          Node l = eqc_to_lit[eqc][k];
1464
23801
          eqc_to_lit[eqcz].push_back(l);
1465
        }
1466
6677
        eqc_to_lit.erase(eqc);
1467
6677
        eqc_active--;
1468
      }
1469
      //add variables to equivalence class
1470
266636
      for (unsigned j=0; j<lit_new_args.size(); j++) {
1471
116754
        var_to_eqc[lit_new_args[j]] = eqcz;
1472
116754
        eqc_to_var[eqcz].push_back(lit_new_args[j]);
1473
      }
1474
      //add literal to equivalence class
1475
149882
      eqc_to_lit[eqcz].push_back(n);
1476
    }
1477
  }
1478
46747
  if ( eqc_active>1 || !lits.empty() || var_to_eqc.size()!=args.size() ){
1479
625
    NodeManager* nm = NodeManager::currentNM();
1480
625
    Trace("clause-split-debug") << "Split quantified formula with body " << body << std::endl;
1481
625
    Trace("clause-split-debug") << "   Ground literals: " << std::endl;
1482
2266
    for( size_t i=0; i<lits.size(); i++) {
1483
1641
      Trace("clause-split-debug") << "      " << lits[i] << std::endl;
1484
    }
1485
625
    Trace("clause-split-debug") << std::endl;
1486
625
    Trace("clause-split-debug") << "Equivalence classes: " << std::endl;
1487
1525
    for (std::map< int, std::vector< Node > >::iterator it = eqc_to_lit.begin(); it != eqc_to_lit.end(); ++it ){
1488
900
      Trace("clause-split-debug") << "   Literals: " << std::endl;
1489
4252
      for (size_t i=0; i<it->second.size(); i++) {
1490
3352
        Trace("clause-split-debug") << "      " << it->second[i] << std::endl;
1491
      }
1492
900
      int eqc = it->first;
1493
900
      Trace("clause-split-debug") << "   Variables: " << std::endl;
1494
3833
      for (size_t i=0; i<eqc_to_var[eqc].size(); i++) {
1495
2933
        Trace("clause-split-debug") << "      " << eqc_to_var[eqc][i] << std::endl;
1496
      }
1497
900
      Trace("clause-split-debug") << std::endl;
1498
1800
      Node bvl = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, eqc_to_var[eqc]);
1499
      Node bd =
1500
1800
          it->second.size() == 1 ? it->second[0] : nm->mkNode(OR, it->second);
1501
1800
      Node fa = nm->mkNode(FORALL, bvl, bd);
1502
900
      lits.push_back(fa);
1503
    }
1504
625
    Assert(!lits.empty());
1505
1250
    Node nf = lits.size()==1 ? lits[0] : NodeManager::currentNM()->mkNode(OR,lits);
1506
625
    Trace("clause-split-debug") << "Made node : " << nf << std::endl;
1507
625
    return nf;
1508
  }else{
1509
46122
    return mkForAll( args, body, qa );
1510
  }
1511
}
1512
1513
114990
Node QuantifiersRewriter::mkForAll(const std::vector<Node>& args,
1514
                                   Node body,
1515
                                   QAttributes& qa)
1516
{
1517
114990
  if (args.empty())
1518
  {
1519
224
    return body;
1520
  }
1521
114766
  NodeManager* nm = NodeManager::currentNM();
1522
229532
  std::vector<Node> children;
1523
114766
  children.push_back(nm->mkNode(kind::BOUND_VAR_LIST, args));
1524
114766
  children.push_back(body);
1525
114766
  if (!qa.d_ipl.isNull())
1526
  {
1527
14670
    children.push_back(qa.d_ipl);
1528
  }
1529
114766
  return nm->mkNode(kind::FORALL, children);
1530
}
1531
1532
Node QuantifiersRewriter::mkForall(const std::vector<Node>& args,
1533
                                   Node body,
1534
                                   bool marked)
1535
{
1536
  std::vector< Node > iplc;
1537
  return mkForall( args, body, iplc, marked );
1538
}
1539
1540
Node QuantifiersRewriter::mkForall(const std::vector<Node>& args,
1541
                                   Node body,
1542
                                   std::vector<Node>& iplc,
1543
                                   bool marked)
1544
{
1545
  if (args.empty())
1546
  {
1547
    return body;
1548
  }
1549
  NodeManager* nm = NodeManager::currentNM();
1550
  std::vector<Node> children;
1551
  children.push_back(nm->mkNode(kind::BOUND_VAR_LIST, args));
1552
  children.push_back(body);
1553
  if (marked)
1554
  {
1555
    SkolemManager* sm = nm->getSkolemManager();
1556
    Node avar = sm->mkDummySkolem("id", nm->booleanType());
1557
    QuantIdNumAttribute ida;
1558
    avar.setAttribute(ida, 0);
1559
    iplc.push_back(nm->mkNode(kind::INST_ATTRIBUTE, avar));
1560
  }
1561
  if (!iplc.empty())
1562
  {
1563
    children.push_back(nm->mkNode(kind::INST_PATTERN_LIST, iplc));
1564
  }
1565
  return nm->mkNode(kind::FORALL, children);
1566
}
1567
1568
//computes miniscoping, also eliminates variables that do not occur free in body
1569
116370
Node QuantifiersRewriter::computeMiniscoping(Node q, QAttributes& qa)
1570
{
1571
116370
  NodeManager* nm = NodeManager::currentNM();
1572
232740
  std::vector<Node> args(q[0].begin(), q[0].end());
1573
232740
  Node body = q[1];
1574
116370
  if( body.getKind()==FORALL ){
1575
    //combine prenex
1576
32
    std::vector< Node > newArgs;
1577
16
    newArgs.insert(newArgs.end(), q[0].begin(), q[0].end());
1578
33
    for( unsigned i=0; i<body[0].getNumChildren(); i++ ){
1579
17
      newArgs.push_back( body[0][i] );
1580
    }
1581
16
    return mkForAll( newArgs, body[1], qa );
1582
116354
  }else if( body.getKind()==AND ){
1583
    // aggressive miniscoping implies that structural miniscoping should
1584
    // be applied first
1585
1595
    if (options::miniscopeQuant() || options::aggressiveMiniscopeQuant())
1586
    {
1587
769
      BoundVarManager* bvm = nm->getBoundVarManager();
1588
      // Break apart the quantifed formula
1589
      // forall x. P1 ^ ... ^ Pn ---> forall x. P1 ^ ... ^ forall x. Pn
1590
1538
      NodeBuilder t(kind::AND);
1591
1538
      std::vector<Node> argsc;
1592
4074
      for (size_t i = 0, nchild = body.getNumChildren(); i < nchild; i++)
1593
      {
1594
3305
        if (argsc.empty())
1595
        {
1596
          // If not done so, we must create fresh copy of args. This is to
1597
          // ensure that quantified formulas do not reuse variables.
1598
7332
          for (const Node& v : q[0])
1599
          {
1600
10922
            TypeNode vt = v.getType();
1601
10922
            Node cacheVal = BoundVarManager::getCacheValue(q, v, i);
1602
10922
            Node vv = bvm->mkBoundVar<QRewMiniscopeAttribute>(cacheVal, vt);
1603
5461
            argsc.push_back(vv);
1604
          }
1605
        }
1606
6610
        Node b = body[i];
1607
        Node bodyc =
1608
6610
            b.substitute(args.begin(), args.end(), argsc.begin(), argsc.end());
1609
3305
        if (b == bodyc)
1610
        {
1611
          // Did not contain variables in args, thus it is ground. Since we did
1612
          // not use them, we keep the variables argsc for the next child.
1613
1468
          t << b;
1614
        }
1615
        else
1616
        {
1617
          // make the miniscoped quantified formula
1618
3674
          Node cbvl = nm->mkNode(BOUND_VAR_LIST, argsc);
1619
3674
          Node qq = nm->mkNode(FORALL, cbvl, bodyc);
1620
1837
          t << qq;
1621
          // We used argsc, clear so we will construct a fresh copy above.
1622
1837
          argsc.clear();
1623
        }
1624
      }
1625
1538
      Node retVal = t;
1626
769
      return retVal;
1627
    }
1628
114759
  }else if( body.getKind()==OR ){
1629
47962
    if( options::quantSplit() ){
1630
      //splitting subsumes free variable miniscoping, apply it with higher priority
1631
46747
      return computeSplit( args, body, qa );
1632
    }
1633
2430
    else if (options::miniscopeQuantFreeVar()
1634
1215
             || options::aggressiveMiniscopeQuant())
1635
    {
1636
      // aggressive miniscoping implies that free variable miniscoping should
1637
      // be applied first
1638
4
      Node newBody = body;
1639
4
      NodeBuilder body_split(kind::OR);
1640
4
      NodeBuilder tb(kind::OR);
1641
12
      for (const Node& trm : body)
1642
      {
1643
8
        if (expr::hasSubterm(trm, args))
1644
        {
1645
4
          tb << trm;
1646
        }else{
1647
4
          body_split << trm;
1648
        }
1649
      }
1650
4
      if( tb.getNumChildren()==0 ){
1651
        return body_split;
1652
4
      }else if( body_split.getNumChildren()>0 ){
1653
4
        newBody = tb.getNumChildren()==1 ? tb.getChild( 0 ) : tb;
1654
8
        std::vector< Node > activeArgs;
1655
4
        computeArgVec2( args, activeArgs, newBody, qa.d_ipl );
1656
4
        body_split << mkForAll( activeArgs, newBody, qa );
1657
4
        return body_split.getNumChildren()==1 ? body_split.getChild( 0 ) : body_split;
1658
      }
1659
    }
1660
66797
  }else if( body.getKind()==NOT ){
1661
15002
    Assert(isLiteral(body[0]));
1662
  }
1663
  //remove variables that don't occur
1664
137668
  std::vector< Node > activeArgs;
1665
68834
  computeArgVec2( args, activeArgs, body, qa.d_ipl );
1666
68834
  return mkForAll( activeArgs, body, qa );
1667
}
1668
1669
14
Node QuantifiersRewriter::computeAggressiveMiniscoping( std::vector< Node >& args, Node body ){
1670
28
  std::map<Node, std::vector<Node> > varLits;
1671
28
  std::map<Node, std::vector<Node> > litVars;
1672
14
  if (body.getKind() == OR) {
1673
    Trace("ag-miniscope") << "compute aggressive miniscoping on " << body << std::endl;
1674
    for (size_t i = 0; i < body.getNumChildren(); i++) {
1675
      std::vector<Node> activeArgs;
1676
      computeArgVec(args, activeArgs, body[i]);
1677
      for (unsigned j = 0; j < activeArgs.size(); j++) {
1678
        varLits[activeArgs[j]].push_back(body[i]);
1679
      }
1680
      std::vector<Node>& lit_body_i = litVars[body[i]];
1681
      std::vector<Node>::iterator lit_body_i_begin = lit_body_i.begin();
1682
      std::vector<Node>::const_iterator active_begin = activeArgs.begin();
1683
      std::vector<Node>::const_iterator active_end = activeArgs.end();
1684
      lit_body_i.insert(lit_body_i_begin, active_begin, active_end);
1685
    }
1686
    //find the variable in the least number of literals
1687
    Node bestVar;
1688
    for( std::map< Node, std::vector<Node> >::iterator it = varLits.begin(); it != varLits.end(); ++it ){
1689
      if( bestVar.isNull() || varLits[bestVar].size()>it->second.size() ){
1690
        bestVar = it->first;
1691
      }
1692
    }
1693
    Trace("ag-miniscope-debug") << "Best variable " << bestVar << " occurs in " << varLits[bestVar].size() << "/ " << body.getNumChildren() << " literals." << std::endl;
1694
    if( !bestVar.isNull() && varLits[bestVar].size()<body.getNumChildren() ){
1695
      //we can miniscope
1696
      Trace("ag-miniscope") << "Miniscope on " << bestVar << std::endl;
1697
      //make the bodies
1698
      std::vector<Node> qlit1;
1699
      qlit1.insert( qlit1.begin(), varLits[bestVar].begin(), varLits[bestVar].end() );
1700
      std::vector<Node> qlitt;
1701
      //for all literals not containing bestVar
1702
      for( size_t i=0; i<body.getNumChildren(); i++ ){
1703
        if( std::find( qlit1.begin(), qlit1.end(), body[i] )==qlit1.end() ){
1704
          qlitt.push_back( body[i] );
1705
        }
1706
      }
1707
      //make the variable lists
1708
      std::vector<Node> qvl1;
1709
      std::vector<Node> qvl2;
1710
      std::vector<Node> qvsh;
1711
      for( unsigned i=0; i<args.size(); i++ ){
1712
        bool found1 = false;
1713
        bool found2 = false;
1714
        for( size_t j=0; j<varLits[args[i]].size(); j++ ){
1715
          if( !found1 && std::find( qlit1.begin(), qlit1.end(), varLits[args[i]][j] )!=qlit1.end() ){
1716
            found1 = true;
1717
          }else if( !found2 && std::find( qlitt.begin(), qlitt.end(), varLits[args[i]][j] )!=qlitt.end() ){
1718
            found2 = true;
1719
          }
1720
          if( found1 && found2 ){
1721
            break;
1722
          }
1723
        }
1724
        if( found1 ){
1725
          if( found2 ){
1726
            qvsh.push_back( args[i] );
1727
          }else{
1728
            qvl1.push_back( args[i] );
1729
          }
1730
        }else{
1731
          Assert(found2);
1732
          qvl2.push_back( args[i] );
1733
        }
1734
      }
1735
      Assert(!qvl1.empty());
1736
      //check for literals that only contain shared variables
1737
      std::vector<Node> qlitsh;
1738
      std::vector<Node> qlit2;
1739
      for( size_t i=0; i<qlitt.size(); i++ ){
1740
        bool hasVar2 = false;
1741
        for( size_t j=0; j<litVars[qlitt[i]].size(); j++ ){
1742
          if( std::find( qvl2.begin(), qvl2.end(), litVars[qlitt[i]][j] )!=qvl2.end() ){
1743
            hasVar2 = true;
1744
            break;
1745
          }
1746
        }
1747
        if( hasVar2 ){
1748
          qlit2.push_back( qlitt[i] );
1749
        }else{
1750
          qlitsh.push_back( qlitt[i] );
1751
        }
1752
      }
1753
      varLits.clear();
1754
      litVars.clear();
1755
      Trace("ag-miniscope-debug") << "Split into literals : " << qlit1.size() << " / " << qlit2.size() << " / " << qlitsh.size();
1756
      Trace("ag-miniscope-debug") << ", variables : " << qvl1.size() << " / " << qvl2.size() << " / " << qvsh.size() << std::endl;
1757
      Node n1 = qlit1.size()==1 ? qlit1[0] : NodeManager::currentNM()->mkNode( OR, qlit1 );
1758
      n1 = computeAggressiveMiniscoping( qvl1, n1 );
1759
      qlitsh.push_back( n1 );
1760
      if( !qlit2.empty() ){
1761
        Node n2 = qlit2.size()==1 ? qlit2[0] : NodeManager::currentNM()->mkNode( OR, qlit2 );
1762
        n2 = computeAggressiveMiniscoping( qvl2, n2 );
1763
        qlitsh.push_back( n2 );
1764
      }
1765
      Node n = NodeManager::currentNM()->mkNode( OR, qlitsh );
1766
      if( !qvsh.empty() ){
1767
        Node bvl = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, qvsh);
1768
        n = NodeManager::currentNM()->mkNode( FORALL, bvl, n );
1769
      }
1770
      Trace("ag-miniscope") << "Return " << n << " for " << body << std::endl;
1771
      return n;
1772
    }
1773
  }
1774
28
  QAttributes qa;
1775
14
  return mkForAll( args, body, qa );
1776
}
1777
1778
953495
bool QuantifiersRewriter::doOperation(Node q,
1779
                                      RewriteStep computeOption,
1780
                                      QAttributes& qa)
1781
{
1782
  bool is_strict_trigger =
1783
953495
      qa.d_hasPattern
1784
953495
      && options::userPatternsQuant() == options::UserPatMode::STRICT;
1785
953495
  bool is_std = qa.isStandard() && !is_strict_trigger;
1786
953495
  if (computeOption == COMPUTE_ELIM_SYMBOLS)
1787
  {
1788
132739
    return true;
1789
  }
1790
820756
  else if (computeOption == COMPUTE_MINISCOPING)
1791
  {
1792
119552
    return is_std;
1793
  }
1794
701204
  else if (computeOption == COMPUTE_AGGRESSIVE_MINISCOPING)
1795
  {
1796
117738
    return options::aggressiveMiniscopeQuant() && is_std;
1797
  }
1798
583466
  else if (computeOption == COMPUTE_EXT_REWRITE)
1799
  {
1800
117738
    return options::extRewriteQuant();
1801
  }
1802
465728
  else if (computeOption == COMPUTE_PROCESS_TERMS)
1803
  {
1804
117726
    return is_std && options::iteLiftQuant() != options::IteLiftQuantMode::NONE;
1805
  }
1806
348002
  else if (computeOption == COMPUTE_COND_SPLIT)
1807
  {
1808
228404
    return (options::iteDtTesterSplitQuant() || options::condVarSplitQuant())
1809
228762
           && !is_strict_trigger;
1810
  }
1811
233621
  else if (computeOption == COMPUTE_PRENEX)
1812
  {
1813
117291
    return options::prenexQuant() != options::PrenexQuantMode::NONE
1814
117291
           && !options::aggressiveMiniscopeQuant() && is_std;
1815
  }
1816
116330
  else if (computeOption == COMPUTE_VAR_ELIMINATION)
1817
  {
1818
116330
    return (options::varElimQuant() || options::dtVarExpandQuant()) && is_std;
1819
  }
1820
  else
1821
  {
1822
    return false;
1823
  }
1824
}
1825
1826
//general method for computing various rewrites
1827
704581
Node QuantifiersRewriter::computeOperation(Node f,
1828
                                           RewriteStep computeOption,
1829
                                           QAttributes& qa)
1830
{
1831
704581
  Trace("quantifiers-rewrite-debug") << "Compute operation " << computeOption << " on " << f << " " << qa.d_qid_num << std::endl;
1832
704581
  if (computeOption == COMPUTE_MINISCOPING)
1833
  {
1834
116370
    if (options::prenexQuant() == options::PrenexQuantMode::NORMAL)
1835
    {
1836
      if( !qa.d_qid_num.isNull() ){
1837
        //already processed this, return self
1838
        return f;
1839
      }
1840
    }
1841
    //return directly
1842
116370
    return computeMiniscoping(f, qa);
1843
  }
1844
1176422
  std::vector<Node> args(f[0].begin(), f[0].end());
1845
1176422
  Node n = f[1];
1846
588211
  if (computeOption == COMPUTE_ELIM_SYMBOLS)
1847
  {
1848
132739
    n = computeElimSymbols(n);
1849
455472
  }else if( computeOption==COMPUTE_AGGRESSIVE_MINISCOPING ){
1850
14
    return computeAggressiveMiniscoping( args, n );
1851
  }
1852
455458
  else if (computeOption == COMPUTE_EXT_REWRITE)
1853
  {
1854
25
    return computeExtendedRewrite(f);
1855
  }
1856
455433
  else if (computeOption == COMPUTE_PROCESS_TERMS)
1857
  {
1858
229088
    std::vector< Node > new_conds;
1859
114544
    n = computeProcessTerms( n, args, new_conds, f, qa );
1860
114544
    if( !new_conds.empty() ){
1861
      new_conds.push_back( n );
1862
      n = NodeManager::currentNM()->mkNode( OR, new_conds );
1863
    }
1864
  }
1865
340889
  else if (computeOption == COMPUTE_COND_SPLIT)
1866
  {
1867
114381
    n = computeCondSplit(n, args, qa);
1868
  }
1869
226508
  else if (computeOption == COMPUTE_PRENEX)
1870
  {
1871
113360
    if (options::prenexQuant() == options::PrenexQuantMode::NORMAL)
1872
    {
1873
      //will rewrite at preprocess time
1874
      return f;
1875
    }
1876
    else
1877
    {
1878
226720
      std::unordered_set<Node> argsSet, nargsSet;
1879
113360
      n = computePrenex(f, n, argsSet, nargsSet, true, false);
1880
113360
      Assert(nargsSet.empty());
1881
113360
      args.insert(args.end(), argsSet.begin(), argsSet.end());
1882
    }
1883
  }
1884
113148
  else if (computeOption == COMPUTE_VAR_ELIMINATION)
1885
  {
1886
113148
    n = computeVarElimination( n, args, qa );
1887
  }
1888
588172
  Trace("quantifiers-rewrite-debug") << "Compute Operation: return " << n << ", " << args.size() << std::endl;
1889
588172
  if( f[1]==n && args.size()==f[0].getNumChildren() ){
1890
571469
    return f;
1891
  }else{
1892
16703
    if( args.empty() ){
1893
756
      return n;
1894
    }else{
1895
31894
      std::vector< Node > children;
1896
15947
      children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, args ) );
1897
15947
      children.push_back( n );
1898
15947
      if( !qa.d_ipl.isNull() && args.size()==f[0].getNumChildren() ){
1899
2372
        children.push_back( qa.d_ipl );
1900
      }
1901
15947
      return NodeManager::currentNM()->mkNode(kind::FORALL, children );
1902
    }
1903
  }
1904
}
1905
1906
bool QuantifiersRewriter::isPrenexNormalForm( Node n ) {
1907
  if( n.getKind()==FORALL ){
1908
    return n[1].getKind()!=FORALL && isPrenexNormalForm( n[1] );
1909
  }else if( n.getKind()==NOT ){
1910
    return n[0].getKind()!=NOT && isPrenexNormalForm( n[0] );
1911
  }else{
1912
    return !expr::hasClosure(n);
1913
  }
1914
}
1915
1916
}  // namespace quantifiers
1917
}  // namespace theory
1918
29502
}  // namespace cvc5