GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/quantifiers_rewriter.cpp Lines: 893 1168 76.5 %
Date: 2021-08-16 Branches: 2018 4995 40.4 %

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
36
using namespace std;
37
using namespace cvc5::kind;
38
using namespace cvc5::context;
39
40
namespace cvc5 {
41
namespace theory {
42
namespace quantifiers {
43
44
/**
45
 * Attributes used for constructing bound variables in a canonical way. These
46
 * are attributes that map to bound variable, introduced for the following
47
 * purposes:
48
 * - QRewPrenexAttribute: cached on (v, body) where we are prenexing bound
49
 * variable v in a nested quantified formula within the given body.
50
 * - QRewMiniscopeAttribute: cached on (v, q, i) where q is being miniscoped
51
 * for F_i in its body (and F_1 ... F_n), and v is one of the bound variables
52
 * that q binds.
53
 * - QRewDtExpandAttribute: cached on
54
 */
55
struct QRewPrenexAttributeId
56
{
57
};
58
typedef expr::Attribute<QRewPrenexAttributeId, Node> QRewPrenexAttribute;
59
struct QRewMiniscopeAttributeId
60
{
61
};
62
typedef expr::Attribute<QRewMiniscopeAttributeId, Node> QRewMiniscopeAttribute;
63
struct QRewDtExpandAttributeId
64
{
65
};
66
typedef expr::Attribute<QRewDtExpandAttributeId, Node> QRewDtExpandAttribute;
67
68
std::ostream& operator<<(std::ostream& out, RewriteStep s)
69
{
70
  switch (s)
71
  {
72
    case COMPUTE_ELIM_SYMBOLS: out << "COMPUTE_ELIM_SYMBOLS"; break;
73
    case COMPUTE_MINISCOPING: out << "COMPUTE_MINISCOPING"; break;
74
    case COMPUTE_AGGRESSIVE_MINISCOPING:
75
      out << "COMPUTE_AGGRESSIVE_MINISCOPING";
76
      break;
77
    case COMPUTE_EXT_REWRITE: out << "COMPUTE_EXT_REWRITE"; break;
78
    case COMPUTE_PROCESS_TERMS: out << "COMPUTE_PROCESS_TERMS"; break;
79
    case COMPUTE_PRENEX: out << "COMPUTE_PRENEX"; break;
80
    case COMPUTE_VAR_ELIMINATION: out << "COMPUTE_VAR_ELIMINATION"; break;
81
    case COMPUTE_COND_SPLIT: out << "COMPUTE_COND_SPLIT"; break;
82
    default: out << "UnknownRewriteStep"; break;
83
  }
84
  return out;
85
}
86
87
14610
bool QuantifiersRewriter::isLiteral( Node n ){
88
14610
  switch( n.getKind() ){
89
  case NOT:
90
    return n[0].getKind()!=NOT && isLiteral( n[0] );
91
    break;
92
  case OR:
93
  case AND:
94
  case IMPLIES:
95
  case XOR:
96
  case ITE:
97
    return false;
98
    break;
99
8867
  case EQUAL:
100
    //for boolean terms
101
8867
    return !n[0].getType().isBoolean();
102
    break;
103
5743
  default:
104
5743
    break;
105
  }
106
5743
  return true;
107
}
108
109
void QuantifiersRewriter::addNodeToOrBuilder(Node n, NodeBuilder& t)
110
{
111
  if( n.getKind()==OR ){
112
    for( int i=0; i<(int)n.getNumChildren(); i++ ){
113
      t << n[i];
114
    }
115
  }else{
116
    t << n;
117
  }
118
}
119
120
4441829
void QuantifiersRewriter::computeArgs(const std::vector<Node>& args,
121
                                      std::map<Node, bool>& activeMap,
122
                                      Node n,
123
                                      std::map<Node, bool>& visited)
124
{
125
4441829
  if( visited.find( n )==visited.end() ){
126
3153964
    visited[n] = true;
127
3153964
    if( n.getKind()==BOUND_VARIABLE ){
128
538015
      if( std::find( args.begin(), args.end(), n )!=args.end() ){
129
434213
        activeMap[ n ] = true;
130
      }
131
    }else{
132
2615949
      if (n.hasOperator())
133
      {
134
1383017
        computeArgs(args, activeMap, n.getOperator(), visited);
135
      }
136
5421620
      for( int i=0; i<(int)n.getNumChildren(); i++ ){
137
2805671
        computeArgs( args, activeMap, n[i], visited );
138
      }
139
    }
140
  }
141
4441829
}
142
143
136330
void QuantifiersRewriter::computeArgVec(const std::vector<Node>& args,
144
                                        std::vector<Node>& activeArgs,
145
                                        Node n)
146
{
147
136330
  Assert(activeArgs.empty());
148
272660
  std::map< Node, bool > activeMap;
149
272660
  std::map< Node, bool > visited;
150
136330
  computeArgs( args, activeMap, n, visited );
151
136330
  if( !activeMap.empty() ){
152
2371050
    for( unsigned i=0; i<args.size(); i++ ){
153
2236371
      if( activeMap.find( args[i] )!=activeMap.end() ){
154
318224
        activeArgs.push_back( args[i] );
155
      }
156
    }
157
  }
158
136330
}
159
160
58480
void QuantifiersRewriter::computeArgVec2(const std::vector<Node>& args,
161
                                         std::vector<Node>& activeArgs,
162
                                         Node n,
163
                                         Node ipl)
164
{
165
58480
  Assert(activeArgs.empty());
166
116960
  std::map< Node, bool > activeMap;
167
116960
  std::map< Node, bool > visited;
168
58480
  computeArgs( args, activeMap, n, visited );
169
58480
  if( !activeMap.empty() ){
170
    //collect variables in inst pattern list only if we cannot eliminate quantifier
171
58331
    computeArgs( args, activeMap, ipl, visited );
172
175315
    for( unsigned i=0; i<args.size(); i++ ){
173
116984
      if( activeMap.find( args[i] )!=activeMap.end() ){
174
115989
        activeArgs.push_back( args[i] );
175
      }
176
    }
177
  }
178
58480
}
179
180
134408
RewriteResponse QuantifiersRewriter::preRewrite(TNode in) {
181
134408
  if( in.getKind()==kind::EXISTS || in.getKind()==kind::FORALL ){
182
79370
    Trace("quantifiers-rewrite-debug") << "pre-rewriting " << in << std::endl;
183
156952
    std::vector< Node > args;
184
156952
    Node body = in;
185
79370
    bool doRewrite = false;
186
93690
    while( body.getNumChildren()==2 && body.getKind()==body[1].getKind() ){
187
14379
      for( unsigned i=0; i<body[0].getNumChildren(); i++ ){
188
7219
        args.push_back( body[0][i] );
189
      }
190
7160
      body = body[1];
191
7160
      doRewrite = true;
192
    }
193
79370
    if( doRewrite ){
194
3576
      std::vector< Node > children;
195
3616
      for( unsigned i=0; i<body[0].getNumChildren(); i++ ){
196
1828
        args.push_back( body[0][i] );
197
      }
198
1788
      children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST,args) );
199
1788
      children.push_back( body[1] );
200
1788
      if( body.getNumChildren()==3 ){
201
47
        children.push_back( body[2] );
202
      }
203
3576
      Node n = NodeManager::currentNM()->mkNode( in.getKind(), children );
204
1788
      if( in!=n ){
205
1788
        Trace("quantifiers-pre-rewrite") << "*** pre-rewrite " << in << std::endl;
206
1788
        Trace("quantifiers-pre-rewrite") << " to " << std::endl;
207
1788
        Trace("quantifiers-pre-rewrite") << n << std::endl;
208
      }
209
1788
      return RewriteResponse(REWRITE_DONE, n);
210
    }
211
  }
212
132620
  return RewriteResponse(REWRITE_DONE, in);
213
}
214
215
245351
RewriteResponse QuantifiersRewriter::postRewrite(TNode in) {
216
245351
  Trace("quantifiers-rewrite-debug") << "post-rewriting " << in << std::endl;
217
245351
  RewriteStatus status = REWRITE_DONE;
218
490702
  Node ret = in;
219
245351
  RewriteStep rew_op = COMPUTE_LAST;
220
  //get the body
221
245351
  if( in.getKind()==EXISTS ){
222
5512
    std::vector< Node > children;
223
2756
    children.push_back( in[0] );
224
2756
    children.push_back( in[1].negate() );
225
2756
    if( in.getNumChildren()==3 ){
226
43
      children.push_back( in[2] );
227
    }
228
2756
    ret = NodeManager::currentNM()->mkNode( FORALL, children );
229
2756
    ret = ret.negate();
230
2756
    status = REWRITE_AGAIN_FULL;
231
242595
  }else if( in.getKind()==FORALL ){
232
132813
    if( in[1].isConst() && in.getNumChildren()==2 ){
233
852
      return RewriteResponse( status, in[1] );
234
    }else{
235
      //compute attributes
236
263922
      QAttributes qa;
237
131961
      QuantAttributes::computeQuantAttributes( in, qa );
238
1063501
      for (unsigned i = 0; i < COMPUTE_LAST; ++i)
239
      {
240
949501
        RewriteStep op = static_cast<RewriteStep>(i);
241
949501
        if( doOperation( in, op, qa ) ){
242
625508
          ret = computeOperation( in, op, qa );
243
625508
          if( ret!=in ){
244
17961
            rew_op = op;
245
17961
            status = REWRITE_AGAIN_FULL;
246
17961
            break;
247
          }
248
        }
249
      }
250
    }
251
  }
252
  //print if changed
253
244499
  if( in!=ret ){
254
20717
    Trace("quantifiers-rewrite") << "*** rewrite (op=" << rew_op << ") " << in << std::endl;
255
20717
    Trace("quantifiers-rewrite") << " to " << std::endl;
256
20717
    Trace("quantifiers-rewrite") << ret << std::endl;
257
  }
258
244499
  return RewriteResponse( status, ret );
259
}
260
261
793176
bool QuantifiersRewriter::addCheckElimChild( std::vector< Node >& children, Node c, Kind k, std::map< Node, bool >& lit_pol, bool& childrenChanged ){
262
793176
  if( ( k==OR || k==AND ) && options::elimTautQuant() ){
263
1267197
    Node lit = c.getKind()==NOT ? c[0] : c;
264
633709
    bool pol = c.getKind()!=NOT;
265
633709
    std::map< Node, bool >::iterator it = lit_pol.find( lit );
266
633709
    if( it==lit_pol.end() ){
267
632796
      lit_pol[lit] = pol;
268
632796
      children.push_back( c );
269
    }else{
270
913
      childrenChanged = true;
271
913
      if( it->second!=pol ){
272
221
        return false;
273
      }
274
    }
275
  }else{
276
159467
    children.push_back( c );
277
  }
278
792955
  return true;
279
}
280
281
// eliminates IMPLIES/XOR, removes duplicates/infers tautologies of AND/OR, and computes NNF
282
910840
Node QuantifiersRewriter::computeElimSymbols( Node body ) {
283
910840
  Kind ok = body.getKind();
284
910840
  Kind k = ok;
285
910840
  bool negAllCh = false;
286
910840
  bool negCh1 = false;
287
910840
  if( ok==IMPLIES ){
288
11819
    k = OR;
289
11819
    negCh1 = true;
290
899021
  }else if( ok==XOR ){
291
767
    k = EQUAL;
292
767
    negCh1 = true;
293
898254
  }else if( ok==NOT ){
294
366076
    if( body[0].getKind()==NOT ){
295
      return computeElimSymbols( body[0][0] );
296
366076
    }else if( body[0].getKind()==OR || body[0].getKind()==IMPLIES ){
297
1695
      k = AND;
298
1695
      negAllCh = true;
299
1695
      negCh1 = body[0].getKind()==IMPLIES;
300
1695
      body = body[0];
301
364381
    }else if( body[0].getKind()==AND ){
302
5617
      k = OR;
303
5617
      negAllCh = true;
304
5617
      body = body[0];
305
358764
    }else if( body[0].getKind()==XOR || ( body[0].getKind()==EQUAL && body[0][0].getType().isBoolean() ) ){
306
2732
      k = EQUAL;
307
2732
      negCh1 = ( body[0].getKind()==EQUAL );
308
2732
      body = body[0];
309
356032
    }else if( body[0].getKind()==ITE ){
310
87
      k = body[0].getKind();
311
87
      negAllCh = true;
312
87
      negCh1 = true;
313
87
      body = body[0];
314
    }else{
315
355945
      return body;
316
    }
317
532178
  }else if( ( ok!=EQUAL || !body[0].getType().isBoolean() ) && ok!=ITE && ok!=AND && ok!=OR ){
318
    //a literal
319
317858
    return body;
320
  }
321
237037
  bool childrenChanged = false;
322
474074
  std::vector< Node > children;
323
474074
  std::map< Node, bool > lit_pol;
324
1015695
  for( unsigned i=0; i<body.getNumChildren(); i++ ){
325
1557537
    Node c = computeElimSymbols( ( i==0 && negCh1 )!=negAllCh ? body[i].negate() : body[i] );
326
778879
    bool success = true;
327
778879
    if( c.getKind()==k && ( k==OR || k==AND ) ){
328
      //flatten
329
5542
      childrenChanged = true;
330
25380
      for( unsigned j=0; j<c.getNumChildren(); j++ ){
331
19839
        if( !addCheckElimChild( children, c[j], k, lit_pol, childrenChanged ) ){
332
1
          success = false;
333
1
          break;
334
        }
335
      }
336
    }else{
337
773337
      success = addCheckElimChild( children, c, k, lit_pol, childrenChanged );
338
    }
339
778879
    if( !success ){
340
      // tautology
341
221
      Assert(k == OR || k == AND);
342
221
      return NodeManager::currentNM()->mkConst( k==OR );
343
    }
344
778658
    childrenChanged = childrenChanged || c!=body[i];
345
  }
346
236816
  if( childrenChanged || k!=ok ){
347
26444
    return ( children.size()==1 && k!=NOT ) ? children[0] : NodeManager::currentNM()->mkNode( k, children );
348
  }else{
349
210372
    return body;
350
  }
351
}
352
353
void QuantifiersRewriter::computeDtTesterIteSplit( Node n, std::map< Node, Node >& pcons, std::map< Node, std::map< int, Node > >& ncons,
354
                                                   std::vector< Node >& conj ){
355
  if( n.getKind()==ITE && n[0].getKind()==APPLY_TESTER && n[1].getType().isBoolean() ){
356
    Trace("quantifiers-rewrite-ite-debug") << "Split tester condition : " << n << std::endl;
357
    Node x = n[0][0];
358
    std::map< Node, Node >::iterator itp = pcons.find( x );
359
    if( itp!=pcons.end() ){
360
      Trace("quantifiers-rewrite-ite-debug") << "...condition already set " << itp->second << std::endl;
361
      computeDtTesterIteSplit( n[ itp->second==n[0] ? 1 : 2 ], pcons, ncons, conj );
362
    }else{
363
      Node tester = n[0].getOperator();
364
      int index = datatypes::utils::indexOf(tester);
365
      std::map< int, Node >::iterator itn = ncons[x].find( index );
366
      if( itn!=ncons[x].end() ){
367
        Trace("quantifiers-rewrite-ite-debug") << "...condition negated " << itn->second << std::endl;
368
        computeDtTesterIteSplit( n[ 2 ], pcons, ncons, conj );
369
      }else{
370
        for( unsigned i=0; i<2; i++ ){
371
          if( i==0 ){
372
            pcons[x] = n[0];
373
          }else{
374
            pcons.erase( x );
375
            ncons[x][index] = n[0].negate();
376
          }
377
          computeDtTesterIteSplit( n[i+1], pcons, ncons, conj );
378
        }
379
        ncons[x].erase( index );
380
      }
381
    }
382
  }else{
383
    NodeManager* nm = NodeManager::currentNM();
384
    Trace("quantifiers-rewrite-ite-debug") << "Return value : " << n << std::endl;
385
    std::vector< Node > children;
386
    children.push_back( n );
387
    std::vector< Node > vars;
388
    //add all positive testers
389
    for( std::map< Node, Node >::iterator it = pcons.begin(); it != pcons.end(); ++it ){
390
      children.push_back( it->second.negate() );
391
      vars.push_back( it->first );
392
    }
393
    //add all negative testers
394
    for( std::map< Node, std::map< int, Node > >::iterator it = ncons.begin(); it != ncons.end(); ++it ){
395
      Node x = it->first;
396
      //only if we haven't settled on a positive tester
397
      if( std::find( vars.begin(), vars.end(), x )==vars.end() ){
398
        //check if we have exhausted all options but one
399
        const DType& dt = x.getType().getDType();
400
        std::vector< Node > nchildren;
401
        int pos_cons = -1;
402
        for( int i=0; i<(int)dt.getNumConstructors(); i++ ){
403
          std::map< int, Node >::iterator itt = it->second.find( i );
404
          if( itt==it->second.end() ){
405
            pos_cons = pos_cons==-1 ? i : -2;
406
          }else{
407
            nchildren.push_back( itt->second.negate() );
408
          }
409
        }
410
        if( pos_cons>=0 ){
411
          Node tester = dt[pos_cons].getTester();
412
          children.push_back(nm->mkNode(APPLY_TESTER, tester, x).negate());
413
        }else{
414
          children.insert( children.end(), nchildren.begin(), nchildren.end() );
415
        }
416
      }
417
    }
418
    //make condition/output pair
419
    Node c = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( OR, children );
420
    conj.push_back( c );
421
  }
422
}
423
424
98845
Node QuantifiersRewriter::computeProcessTerms( Node body, std::vector< Node >& new_vars, std::vector< Node >& new_conds, Node q, QAttributes& qa ){
425
197690
  std::map< Node, Node > cache;
426
98845
  if( qa.isFunDef() ){
427
    Node h = QuantAttributes::getFunDefHead( q );
428
    Assert(!h.isNull());
429
    // if it is a function definition, rewrite the body independently
430
    Node fbody = QuantAttributes::getFunDefBody( q );
431
    Trace("quantifiers-rewrite-debug") << "Decompose " << h << " / " << fbody << " as function definition for " << q << "." << std::endl;
432
    if (!fbody.isNull())
433
    {
434
      Node r = computeProcessTerms2(fbody, cache, new_vars, new_conds);
435
      Assert(new_vars.size() == h.getNumChildren());
436
      return Rewriter::rewrite(NodeManager::currentNM()->mkNode(EQUAL, h, r));
437
    }
438
    // It can happen that we can't infer the shape of the function definition,
439
    // for example: forall xy. f( x, y ) = 1 + f( x, y ), this is rewritten to
440
    // forall xy. false.
441
  }
442
98845
  return computeProcessTerms2(body, cache, new_vars, new_conds);
443
}
444
445
2651688
Node QuantifiersRewriter::computeProcessTerms2(Node body,
446
                                               std::map<Node, Node>& cache,
447
                                               std::vector<Node>& new_vars,
448
                                               std::vector<Node>& new_conds)
449
{
450
2651688
  NodeManager* nm = NodeManager::currentNM();
451
5303376
  Trace("quantifiers-rewrite-term-debug2")
452
2651688
      << "computeProcessTerms " << body << std::endl;
453
2651688
  std::map< Node, Node >::iterator iti = cache.find( body );
454
2651688
  if( iti!=cache.end() ){
455
877945
    return iti->second;
456
  }
457
1773743
  bool changed = false;
458
3547486
  std::vector<Node> children;
459
4326586
  for (size_t i = 0; i < body.getNumChildren(); i++)
460
  {
461
    // do the recursive call on children
462
5105686
    Node nn = computeProcessTerms2(body[i], cache, new_vars, new_conds);
463
2552843
    children.push_back(nn);
464
2552843
    changed = changed || nn != body[i];
465
  }
466
467
  // make return value
468
3547486
  Node ret;
469
1773743
  if (changed)
470
  {
471
5056
    if (body.getMetaKind() == kind::metakind::PARAMETERIZED)
472
    {
473
190
      children.insert(children.begin(), body.getOperator());
474
    }
475
5056
    ret = nm->mkNode(body.getKind(), children);
476
  }
477
  else
478
  {
479
1768687
    ret = body;
480
  }
481
482
3547486
  Trace("quantifiers-rewrite-term-debug2")
483
1773743
      << "Returning " << ret << " for " << body << std::endl;
484
  // do context-independent rewriting
485
3547486
  if (ret.getKind() == EQUAL
486
1773743
      && options::iteLiftQuant() != options::IteLiftQuantMode::NONE)
487
  {
488
595591
    for (size_t i = 0; i < 2; i++)
489
    {
490
397452
      if (ret[i].getKind() == ITE)
491
      {
492
20262
        Node no = i == 0 ? ret[1] : ret[0];
493
10557
        if (no.getKind() != ITE)
494
        {
495
          bool doRewrite =
496
9249
              options::iteLiftQuant() == options::IteLiftQuantMode::ALL;
497
17646
          std::vector<Node> childrenIte;
498
9249
          childrenIte.push_back(ret[i][0]);
499
27747
          for (size_t j = 1; j <= 2; j++)
500
          {
501
            // check if it rewrites to a constant
502
36996
            Node nn = nm->mkNode(EQUAL, no, ret[i][j]);
503
18498
            nn = Rewriter::rewrite(nn);
504
18498
            childrenIte.push_back(nn);
505
18498
            if (nn.isConst())
506
            {
507
1187
              doRewrite = true;
508
            }
509
          }
510
9249
          if (doRewrite)
511
          {
512
852
            ret = nm->mkNode(ITE, childrenIte);
513
852
            break;
514
          }
515
        }
516
      }
517
    }
518
  }
519
1574752
  else if (ret.getKind() == SELECT && ret[0].getKind() == STORE)
520
  {
521
166
    Node st = ret[0];
522
166
    Node index = ret[1];
523
166
    std::vector<Node> iconds;
524
166
    std::vector<Node> elements;
525
523
    while (st.getKind() == STORE)
526
    {
527
220
      iconds.push_back(index.eqNode(st[1]));
528
220
      elements.push_back(st[2]);
529
220
      st = st[0];
530
    }
531
83
    ret = nm->mkNode(SELECT, st, index);
532
    // conditions
533
303
    for (int i = (iconds.size() - 1); i >= 0; i--)
534
    {
535
220
      ret = nm->mkNode(ITE, iconds[i], elements[i], ret);
536
    }
537
  }
538
1773743
  cache[body] = ret;
539
1773743
  return ret;
540
}
541
542
32
Node QuantifiersRewriter::computeExtendedRewrite(Node q)
543
{
544
64
  Node body = q[1];
545
  // apply extended rewriter
546
64
  ExtendedRewriter er;
547
64
  Node bodyr = er.extendedRewrite(body);
548
32
  if (body != bodyr)
549
  {
550
24
    std::vector<Node> children;
551
12
    children.push_back(q[0]);
552
12
    children.push_back(bodyr);
553
12
    if (q.getNumChildren() == 3)
554
    {
555
      children.push_back(q[2]);
556
    }
557
12
    return NodeManager::currentNM()->mkNode(FORALL, children);
558
  }
559
20
  return q;
560
}
561
562
99059
Node QuantifiersRewriter::computeCondSplit(Node body,
563
                                           const std::vector<Node>& args,
564
                                           QAttributes& qa)
565
{
566
99059
  NodeManager* nm = NodeManager::currentNM();
567
99059
  Kind bk = body.getKind();
568
198476
  if (options::iteDtTesterSplitQuant() && bk == ITE
569
198126
      && body[0].getKind() == APPLY_TESTER)
570
  {
571
    Trace("quantifiers-rewrite-ite-debug") << "DTT split : " << body << std::endl;
572
    std::map< Node, Node > pcons;
573
    std::map< Node, std::map< int, Node > > ncons;
574
    std::vector< Node > conj;
575
    computeDtTesterIteSplit( body, pcons, ncons, conj );
576
    Assert(!conj.empty());
577
    if( conj.size()>1 ){
578
      Trace("quantifiers-rewrite-ite") << "*** Split ITE (datatype tester) " << body << " into : " << std::endl;
579
      for( unsigned i=0; i<conj.size(); i++ ){
580
        Trace("quantifiers-rewrite-ite") << "   " << conj[i] << std::endl;
581
      }
582
      return nm->mkNode(AND, conj);
583
    }
584
  }
585
99059
  if (!options::condVarSplitQuant())
586
  {
587
    return body;
588
  }
589
198118
  Trace("cond-var-split-debug")
590
99059
      << "Conditional var elim split " << body << "?" << std::endl;
591
592
99059
  if (bk == ITE
593
99185
      || (bk == EQUAL && body[0].getType().isBoolean()
594
20680
          && options::condVarSplitQuantAgg()))
595
  {
596
126
    Assert(!qa.isFunDef());
597
126
    bool do_split = false;
598
126
    unsigned index_max = bk == ITE ? 0 : 1;
599
234
    std::vector<Node> tmpArgs = args;
600
234
    for (unsigned index = 0; index <= index_max; index++)
601
    {
602
378
      if (hasVarElim(body[index], true, tmpArgs)
603
378
          || hasVarElim(body[index], false, tmpArgs))
604
      {
605
18
        do_split = true;
606
18
        break;
607
      }
608
    }
609
126
    if (do_split)
610
    {
611
36
      Node pos;
612
36
      Node neg;
613
18
      if (bk == ITE)
614
      {
615
18
        pos = nm->mkNode(OR, body[0].negate(), body[1]);
616
18
        neg = nm->mkNode(OR, body[0], body[2]);
617
      }
618
      else
619
      {
620
        pos = nm->mkNode(OR, body[0].negate(), body[1]);
621
        neg = nm->mkNode(OR, body[0], body[1].negate());
622
      }
623
36
      Trace("cond-var-split-debug") << "*** Split (conditional variable eq) "
624
18
                                    << body << " into : " << std::endl;
625
18
      Trace("cond-var-split-debug") << "   " << pos << std::endl;
626
18
      Trace("cond-var-split-debug") << "   " << neg << std::endl;
627
18
      return nm->mkNode(AND, pos, neg);
628
    }
629
  }
630
631
99041
  if (bk == OR)
632
  {
633
40869
    unsigned size = body.getNumChildren();
634
40869
    bool do_split = false;
635
40869
    unsigned split_index = 0;
636
165945
    for (unsigned i = 0; i < size; i++)
637
    {
638
      // check if this child is a (conditional) variable elimination
639
250285
      Node b = body[i];
640
125209
      if (b.getKind() == AND)
641
      {
642
14102
        std::vector<Node> vars;
643
14102
        std::vector<Node> subs;
644
14102
        std::vector<Node> tmpArgs = args;
645
27566
        for (unsigned j = 0, bsize = b.getNumChildren(); j < bsize; j++)
646
        {
647
20648
          if (getVarElimLit(b[j], false, tmpArgs, vars, subs))
648
          {
649
4846
            Trace("cond-var-split-debug") << "Variable elimination in child #"
650
2423
                                          << j << " under " << i << std::endl;
651
            // Figure out if we should split
652
            // Currently we split if the aggressive option is set, or
653
            // if the top-level OR is binary.
654
2423
            if (options::condVarSplitQuantAgg() || size == 2)
655
            {
656
133
              do_split = true;
657
            }
658
            // other splitting criteria go here
659
660
2423
            if (do_split)
661
            {
662
133
              split_index = i;
663
133
              break;
664
            }
665
2290
            vars.clear();
666
2290
            subs.clear();
667
2290
            tmpArgs = args;
668
          }
669
        }
670
      }
671
125209
      if (do_split)
672
      {
673
133
        break;
674
      }
675
    }
676
40869
    if (do_split)
677
    {
678
266
      std::vector<Node> children;
679
399
      for (TNode bc : body)
680
      {
681
266
        children.push_back(bc);
682
      }
683
266
      std::vector<Node> split_children;
684
538
      for (TNode bci : body[split_index])
685
      {
686
405
        children[split_index] = bci;
687
405
        split_children.push_back(nm->mkNode(OR, children));
688
      }
689
      // split the AND child, for example:
690
      //  ( x!=a ^ P(x) ) V Q(x) ---> ( x!=a V Q(x) ) ^ ( P(x) V Q(x) )
691
133
      return nm->mkNode(AND, split_children);
692
    }
693
  }
694
695
98908
  return body;
696
}
697
698
5801
bool QuantifiersRewriter::isVarElim(Node v, Node s)
699
{
700
5801
  Assert(v.getKind() == BOUND_VARIABLE);
701
5801
  return !expr::hasSubterm(s, v) && s.getType().isSubtypeOf(v.getType());
702
}
703
704
731
Node QuantifiersRewriter::getVarElimLitBv(Node lit,
705
                                          const std::vector<Node>& args,
706
                                          Node& var)
707
{
708
731
  if (Trace.isOn("quant-velim-bv"))
709
  {
710
    Trace("quant-velim-bv") << "Bv-Elim : " << lit << " varList = { ";
711
    for (const Node& v : args)
712
    {
713
      Trace("quant-velim-bv") << v << " ";
714
    }
715
    Trace("quant-velim-bv") << "} ?" << std::endl;
716
  }
717
731
  Assert(lit.getKind() == EQUAL);
718
  // TODO (#1494) : linearize the literal using utility
719
720
  // compute a subset active_args of the bound variables args that occur in lit
721
1462
  std::vector<Node> active_args;
722
731
  computeArgVec(args, active_args, lit);
723
724
1462
  BvInverter binv;
725
1546
  for (const Node& cvar : active_args)
726
  {
727
    // solve for the variable on this path using the inverter
728
1668
    std::vector<unsigned> path;
729
1668
    Node slit = binv.getPathToPv(lit, cvar, path);
730
853
    if (!slit.isNull())
731
    {
732
814
      Node slv = binv.solveBvLit(cvar, lit, path, nullptr);
733
426
      Trace("quant-velim-bv") << "...solution : " << slv << std::endl;
734
426
      if (!slv.isNull())
735
      {
736
66
        var = cvar;
737
        // if this is a proper variable elimination, that is, var = slv where
738
        // var is not in the free variables of slv, then we can return this
739
        // as the variable elimination for lit.
740
66
        if (isVarElim(var, slv))
741
        {
742
38
          return slv;
743
        }
744
      }
745
    }
746
    else
747
    {
748
427
      Trace("quant-velim-bv") << "...non-invertible path." << std::endl;
749
    }
750
  }
751
752
693
  return Node::null();
753
}
754
755
234
Node QuantifiersRewriter::getVarElimLitString(Node lit,
756
                                              const std::vector<Node>& args,
757
                                              Node& var)
758
{
759
234
  Assert(lit.getKind() == EQUAL);
760
234
  NodeManager* nm = NodeManager::currentNM();
761
698
  for (unsigned i = 0; i < 2; i++)
762
  {
763
468
    if (lit[i].getKind() == STRING_CONCAT)
764
    {
765
12
      TypeNode stype = lit[i].getType();
766
20
      for (unsigned j = 0, nchildren = lit[i].getNumChildren(); j < nchildren;
767
           j++)
768
      {
769
16
        if (std::find(args.begin(), args.end(), lit[i][j]) != args.end())
770
        {
771
12
          var = lit[i][j];
772
20
          Node slv = lit[1 - i];
773
20
          std::vector<Node> preL(lit[i].begin(), lit[i].begin() + j);
774
20
          std::vector<Node> postL(lit[i].begin() + j + 1, lit[i].end());
775
20
          Node tpre = strings::utils::mkConcat(preL, stype);
776
20
          Node tpost = strings::utils::mkConcat(postL, stype);
777
20
          Node slvL = nm->mkNode(STRING_LENGTH, slv);
778
20
          Node tpreL = nm->mkNode(STRING_LENGTH, tpre);
779
20
          Node tpostL = nm->mkNode(STRING_LENGTH, tpost);
780
12
          slv = nm->mkNode(
781
              STRING_SUBSTR,
782
              slv,
783
              tpreL,
784
24
              nm->mkNode(MINUS, slvL, nm->mkNode(PLUS, tpreL, tpostL)));
785
          // forall x. r ++ x ++ t = s => P( x )
786
          //   is equivalent to
787
          // r ++ s' ++ t = s => P( s' ) where
788
          // s' = substr( s, |r|, |s|-(|t|+|r|) ).
789
          // We apply this only if r,t,s do not contain free variables.
790
12
          if (!expr::hasFreeVar(slv))
791
          {
792
4
            return slv;
793
          }
794
        }
795
      }
796
    }
797
  }
798
799
230
  return Node::null();
800
}
801
802
209004
bool QuantifiersRewriter::getVarElimLit(Node lit,
803
                                        bool pol,
804
                                        std::vector<Node>& args,
805
                                        std::vector<Node>& vars,
806
                                        std::vector<Node>& subs)
807
{
808
209004
  if (lit.getKind() == NOT)
809
  {
810
5893
    lit = lit[0];
811
5893
    pol = !pol;
812
5893
    Assert(lit.getKind() != NOT);
813
  }
814
209004
  NodeManager* nm = NodeManager::currentNM();
815
418008
  Trace("var-elim-quant-debug")
816
209004
      << "Eliminate : " << lit << ", pol = " << pol << "?" << std::endl;
817
418799
  if (lit.getKind() == APPLY_TESTER && pol && lit[0].getKind() == BOUND_VARIABLE
818
418045
      && options::dtVarExpandQuant())
819
  {
820
74
    Trace("var-elim-dt") << "Expand datatype variable based on : " << lit
821
37
                         << std::endl;
822
    std::vector<Node>::iterator ita =
823
37
        std::find(args.begin(), args.end(), lit[0]);
824
37
    if (ita != args.end())
825
    {
826
37
      vars.push_back(lit[0]);
827
74
      Node tester = lit.getOperator();
828
37
      int index = datatypes::utils::indexOf(tester);
829
37
      const DType& dt = datatypes::utils::datatypeOf(tester);
830
37
      const DTypeConstructor& c = dt[index];
831
74
      std::vector<Node> newChildren;
832
37
      newChildren.push_back(c.getConstructor());
833
74
      std::vector<Node> newVars;
834
94
      for (unsigned j = 0, nargs = c.getNumArgs(); j < nargs; j++)
835
      {
836
114
        TypeNode tn = c[j].getRangeType();
837
114
        Node v = nm->mkBoundVar(tn);
838
57
        newChildren.push_back(v);
839
57
        newVars.push_back(v);
840
      }
841
37
      subs.push_back(nm->mkNode(APPLY_CONSTRUCTOR, newChildren));
842
74
      Trace("var-elim-dt") << "...apply substitution " << subs[0] << "/"
843
37
                           << vars[0] << std::endl;
844
37
      args.erase(ita);
845
37
      args.insert(args.end(), newVars.begin(), newVars.end());
846
37
      return true;
847
    }
848
  }
849
  // all eliminations below guarded by varElimQuant()
850
208967
  if (!options::varElimQuant())
851
  {
852
    return false;
853
  }
854
855
208967
  if (lit.getKind() == EQUAL)
856
  {
857
112466
    if (pol || lit[0].getType().isBoolean())
858
    {
859
171129
      for (unsigned i = 0; i < 2; i++)
860
      {
861
116201
        bool tpol = pol;
862
227214
        Node v_slv = lit[i];
863
116201
        if (v_slv.getKind() == NOT)
864
        {
865
4854
          v_slv = v_slv[0];
866
4854
          tpol = !tpol;
867
        }
868
        std::vector<Node>::iterator ita =
869
116201
            std::find(args.begin(), args.end(), v_slv);
870
116201
        if (ita != args.end())
871
        {
872
5477
          if (isVarElim(v_slv, lit[1 - i]))
873
          {
874
10376
            Node slv = lit[1 - i];
875
5188
            if (!tpol)
876
            {
877
652
              Assert(slv.getType().isBoolean());
878
652
              slv = slv.negate();
879
            }
880
10376
            Trace("var-elim-quant")
881
5188
                << "Variable eliminate based on equality : " << v_slv << " -> "
882
5188
                << slv << std::endl;
883
5188
            vars.push_back(v_slv);
884
5188
            subs.push_back(slv);
885
5188
            args.erase(ita);
886
5188
            return true;
887
          }
888
        }
889
      }
890
    }
891
  }
892
203779
  if (lit.getKind() == BOUND_VARIABLE)
893
  {
894
1446
    std::vector< Node >::iterator ita = std::find( args.begin(), args.end(), lit );
895
1446
    if( ita!=args.end() ){
896
1444
      Trace("var-elim-bool") << "Variable eliminate : " << lit << std::endl;
897
1444
      vars.push_back( lit );
898
1444
      subs.push_back( NodeManager::currentNM()->mkConst( pol ) );
899
1444
      args.erase( ita );
900
1444
      return true;
901
    }
902
  }
903
202335
  if (lit.getKind() == EQUAL && lit[0].getType().isReal() && pol)
904
  {
905
    // for arithmetic, solve the equality
906
21998
    std::map< Node, Node > msum;
907
11100
    if (ArithMSum::getMonomialSumLit(lit, msum))
908
    {
909
33896
      for( std::map< Node, Node >::iterator itm = msum.begin(); itm != msum.end(); ++itm ){
910
22998
        if( !itm->first.isNull() ){
911
19752
          std::vector< Node >::iterator ita = std::find( args.begin(), args.end(), itm->first );
912
19752
          if( ita!=args.end() ){
913
450
            Assert(pol);
914
698
            Node veq_c;
915
698
            Node val;
916
450
            int ires = ArithMSum::isolate(itm->first, msum, veq_c, val, EQUAL);
917
450
            if (ires != 0 && veq_c.isNull() && isVarElim(itm->first, val))
918
            {
919
404
              Trace("var-elim-quant")
920
202
                  << "Variable eliminate based on solved equality : "
921
202
                  << itm->first << " -> " << val << std::endl;
922
202
              vars.push_back(itm->first);
923
202
              subs.push_back(val);
924
202
              args.erase(ita);
925
202
              return true;
926
            }
927
          }
928
        }
929
      }
930
    }
931
  }
932
202133
  if (lit.getKind() == EQUAL && pol)
933
  {
934
66174
    Node var;
935
66174
    Node slv;
936
66174
    TypeNode tt = lit[0].getType();
937
33108
    if (tt.isBitVector())
938
    {
939
731
      slv = getVarElimLitBv(lit, args, var);
940
    }
941
32377
    else if (tt.isStringLike())
942
    {
943
234
      slv = getVarElimLitString(lit, args, var);
944
    }
945
33108
    if (!slv.isNull())
946
    {
947
42
      Assert(!var.isNull());
948
      std::vector<Node>::iterator ita =
949
42
          std::find(args.begin(), args.end(), var);
950
42
      Assert(ita != args.end());
951
84
      Trace("var-elim-quant")
952
42
          << "Variable eliminate based on theory-specific solving : " << var
953
42
          << " -> " << slv << std::endl;
954
42
      Assert(!expr::hasSubterm(slv, var));
955
42
      Assert(slv.getType().isSubtypeOf(var.getType()));
956
42
      vars.push_back(var);
957
42
      subs.push_back(slv);
958
42
      args.erase(ita);
959
42
      return true;
960
    }
961
  }
962
202091
  return false;
963
}
964
965
232676
bool QuantifiersRewriter::getVarElim(Node n,
966
                                     bool pol,
967
                                     std::vector<Node>& args,
968
                                     std::vector<Node>& vars,
969
                                     std::vector<Node>& subs)
970
{
971
232676
  Kind nk = n.getKind();
972
232676
  if (nk == NOT)
973
  {
974
83991
    n = n[0];
975
83991
    pol = !pol;
976
83991
    nk = n.getKind();
977
83991
    Assert(nk != NOT);
978
  }
979
232676
  if ((nk == AND && pol) || (nk == OR && !pol))
980
  {
981
170916
    for (const Node& cn : n)
982
    {
983
130742
      if (getVarElim(cn, pol, args, vars, subs))
984
      {
985
4146
        return true;
986
      }
987
    }
988
40174
    return false;
989
  }
990
188356
  return getVarElimLit(n, pol, args, vars, subs);
991
}
992
993
234
bool QuantifiersRewriter::hasVarElim(Node n, bool pol, std::vector<Node>& args)
994
{
995
468
  std::vector< Node > vars;
996
468
  std::vector< Node > subs;
997
468
  return getVarElim(n, pol, args, vars, subs);
998
}
999
1000
97124
bool QuantifiersRewriter::getVarElimIneq(Node body,
1001
                                         std::vector<Node>& args,
1002
                                         std::vector<Node>& bounds,
1003
                                         std::vector<Node>& subs,
1004
                                         QAttributes& qa)
1005
{
1006
  // elimination based on inequalities
1007
194248
  std::map<Node, std::map<bool, std::map<Node, bool> > > num_bounds;
1008
194248
  QuantPhaseReq qpr(body);
1009
269268
  for (const std::pair<const Node, bool>& pr : qpr.d_phase_reqs)
1010
  {
1011
    // an inequality that is entailed with a given polarity
1012
190715
    Node lit = pr.first;
1013
172144
    if (lit.getKind() != GEQ)
1014
    {
1015
153573
      continue;
1016
    }
1017
18571
    bool pol = pr.second;
1018
37142
    Trace("var-elim-quant-debug") << "Process inequality bounds : " << lit
1019
18571
                                  << ", pol = " << pol << "..." << std::endl;
1020
    // solve the inequality
1021
37142
    std::map<Node, Node> msum;
1022
18571
    if (!ArithMSum::getMonomialSumLit(lit, msum))
1023
    {
1024
      // not an inequality, cannot use
1025
      continue;
1026
    }
1027
59129
    for (const std::pair<const Node, Node>& m : msum)
1028
    {
1029
40558
      if (!m.first.isNull())
1030
      {
1031
        std::vector<Node>::iterator ita =
1032
30142
            std::find(args.begin(), args.end(), m.first);
1033
30142
        if (ita != args.end())
1034
        {
1035
          // store that this literal is upper/lower bound for itm->first
1036
37994
          Node veq_c;
1037
37994
          Node val;
1038
          int ires =
1039
18997
              ArithMSum::isolate(m.first, msum, veq_c, val, lit.getKind());
1040
18997
          if (ires != 0 && veq_c.isNull())
1041
          {
1042
18668
            bool is_upper = pol != (ires == 1);
1043
37336
            Trace("var-elim-ineq-debug")
1044
18668
                << lit << " is a " << (is_upper ? "upper" : "lower")
1045
18668
                << " bound for " << m.first << std::endl;
1046
37336
            Trace("var-elim-ineq-debug")
1047
18668
                << "  pol/ires = " << pol << " " << ires << std::endl;
1048
18668
            num_bounds[m.first][is_upper][lit] = pol;
1049
          }
1050
          else
1051
          {
1052
658
            Trace("var-elim-ineq-debug")
1053
329
                << "...ineligible " << m.first
1054
329
                << " since it cannot be solved for (" << ires << ", " << veq_c
1055
329
                << ")." << std::endl;
1056
329
            num_bounds[m.first][true].clear();
1057
329
            num_bounds[m.first][false].clear();
1058
          }
1059
        }
1060
        else
1061
        {
1062
          // compute variables in itm->first, these are not eligible for
1063
          // elimination
1064
22290
          std::unordered_set<Node> fvs;
1065
11145
          expr::getFreeVariables(m.first, fvs);
1066
20543
          for (const Node& v : fvs)
1067
          {
1068
18796
            Trace("var-elim-ineq-debug")
1069
9398
                << "...ineligible " << v
1070
9398
                << " since it is contained in monomial." << std::endl;
1071
9398
            num_bounds[v][true].clear();
1072
9398
            num_bounds[v][false].clear();
1073
          }
1074
        }
1075
      }
1076
    }
1077
  }
1078
1079
  // collect all variables that have only upper/lower bounds
1080
194248
  std::map<Node, bool> elig_vars;
1081
17553
  for (const std::pair<const Node, std::map<bool, std::map<Node, bool> > >& nb :
1082
97124
       num_bounds)
1083
  {
1084
17553
    if (nb.second.find(true) == nb.second.end())
1085
    {
1086
4924
      Trace("var-elim-ineq-debug")
1087
2462
          << "Variable " << nb.first << " has only lower bounds." << std::endl;
1088
2462
      elig_vars[nb.first] = false;
1089
    }
1090
15091
    else if (nb.second.find(false) == nb.second.end())
1091
    {
1092
4478
      Trace("var-elim-ineq-debug")
1093
2239
          << "Variable " << nb.first << " has only upper bounds." << std::endl;
1094
2239
      elig_vars[nb.first] = true;
1095
    }
1096
  }
1097
97124
  if (elig_vars.empty())
1098
  {
1099
93518
    return false;
1100
  }
1101
7212
  std::vector<Node> inactive_vars;
1102
7212
  std::map<Node, std::map<int, bool> > visited;
1103
7212
  std::map<Node, int> exclude;
1104
13486
  for (const std::pair<const Node, bool>& pr : qpr.d_phase_reqs)
1105
  {
1106
9880
    if (pr.first.getKind() == GEQ)
1107
    {
1108
5728
      exclude[pr.first] = pr.second ? -1 : 1;
1109
11456
      Trace("var-elim-ineq-debug")
1110
5728
          << "...exclude " << pr.first << " at polarity " << exclude[pr.first]
1111
5728
          << std::endl;
1112
    }
1113
  }
1114
  // traverse the body, invalidate variables if they occur in places other than
1115
  // the bounds they occur in
1116
7212
  std::unordered_map<TNode, std::unordered_set<int>> evisited;
1117
7212
  std::vector<TNode> evisit;
1118
7212
  std::vector<int> evisit_pol;
1119
7212
  TNode ecur;
1120
  int ecur_pol;
1121
3606
  evisit.push_back(body);
1122
3606
  evisit_pol.push_back(1);
1123
3606
  if (!qa.d_ipl.isNull())
1124
  {
1125
    // do not eliminate variables that occur in the annotation
1126
    evisit.push_back(qa.d_ipl);
1127
    evisit_pol.push_back(0);
1128
  }
1129
35661
  do
1130
  {
1131
39267
    ecur = evisit.back();
1132
39267
    evisit.pop_back();
1133
39267
    ecur_pol = evisit_pol.back();
1134
39267
    evisit_pol.pop_back();
1135
39267
    std::unordered_set<int>& epp = evisited[ecur];
1136
39267
    if (epp.find(ecur_pol) == epp.end())
1137
    {
1138
37046
      epp.insert(ecur_pol);
1139
37046
      if (elig_vars.find(ecur) != elig_vars.end())
1140
      {
1141
        // variable contained in a place apart from bounds, no longer eligible
1142
        // for elimination
1143
4320
        elig_vars.erase(ecur);
1144
8640
        Trace("var-elim-ineq-debug") << "...found occurrence of " << ecur
1145
4320
                                     << ", mark ineligible" << std::endl;
1146
      }
1147
      else
1148
      {
1149
32726
        bool rec = true;
1150
32726
        bool pol = ecur_pol >= 0;
1151
32726
        bool hasPol = ecur_pol != 0;
1152
32726
        if (hasPol)
1153
        {
1154
15832
          std::map<Node, int>::iterator itx = exclude.find(ecur);
1155
15832
          if (itx != exclude.end() && itx->second == ecur_pol)
1156
          {
1157
            // already processed this literal as a bound
1158
2777
            rec = false;
1159
          }
1160
        }
1161
32726
        if (rec)
1162
        {
1163
77957
          for (unsigned j = 0, size = ecur.getNumChildren(); j < size; j++)
1164
          {
1165
            bool newHasPol;
1166
            bool newPol;
1167
48008
            QuantPhaseReq::getPolarity(ecur, j, hasPol, pol, newHasPol, newPol);
1168
48008
            evisit.push_back(ecur[j]);
1169
48008
            evisit_pol.push_back(newHasPol ? (newPol ? 1 : -1) : 0);
1170
          }
1171
        }
1172
      }
1173
    }
1174
39267
  } while (!evisit.empty() && !elig_vars.empty());
1175
1176
3606
  bool ret = false;
1177
3987
  for (const std::pair<const Node, bool>& ev : elig_vars)
1178
  {
1179
762
    Node v = ev.first;
1180
762
    Trace("var-elim-ineq-debug")
1181
381
        << v << " is eligible for elimination." << std::endl;
1182
    // do substitution corresponding to infinite projection, all literals
1183
    // involving unbounded variable go to true/false
1184
894
    for (const std::pair<const Node, bool>& nb : num_bounds[v][elig_vars[v]])
1185
    {
1186
1026
      Trace("var-elim-ineq-debug")
1187
513
          << "  subs : " << nb.first << " -> " << nb.second << std::endl;
1188
513
      bounds.push_back(nb.first);
1189
513
      subs.push_back(NodeManager::currentNM()->mkConst(nb.second));
1190
    }
1191
    // eliminate from args
1192
381
    std::vector<Node>::iterator ita = std::find(args.begin(), args.end(), v);
1193
381
    Assert(ita != args.end());
1194
381
    args.erase(ita);
1195
381
    ret = true;
1196
  }
1197
3606
  return ret;
1198
}
1199
1200
97530
Node QuantifiersRewriter::computeVarElimination( Node body, std::vector< Node >& args, QAttributes& qa ){
1201
195060
  if (!options::varElimQuant() && !options::dtVarExpandQuant()
1202
97530
      && !options::varIneqElimQuant())
1203
  {
1204
    return body;
1205
  }
1206
195060
  Node prev;
1207
300708
  while (prev != body && !args.empty())
1208
  {
1209
101589
    prev = body;
1210
1211
203178
    std::vector<Node> vars;
1212
203178
    std::vector<Node> subs;
1213
    // standard variable elimination
1214
101589
    if (options::varElimQuant())
1215
    {
1216
101589
      getVarElim(body, false, args, vars, subs);
1217
    }
1218
    // variable elimination based on one-direction inequalities
1219
101589
    if (vars.empty() && options::varIneqElimQuant())
1220
    {
1221
97124
      getVarElimIneq(body, args, vars, subs, qa);
1222
    }
1223
    // if we eliminated a variable, update body and reprocess
1224
101589
    if (!vars.empty())
1225
    {
1226
9526
      Trace("var-elim-quant-debug")
1227
4763
          << "VE " << vars.size() << "/" << args.size() << std::endl;
1228
4763
      Assert(vars.size() == subs.size());
1229
      // remake with eliminated nodes
1230
4763
      body =
1231
9526
          body.substitute(vars.begin(), vars.end(), subs.begin(), subs.end());
1232
4763
      body = Rewriter::rewrite(body);
1233
4763
      if (!qa.d_ipl.isNull())
1234
      {
1235
        qa.d_ipl = qa.d_ipl.substitute(
1236
            vars.begin(), vars.end(), subs.begin(), subs.end());
1237
      }
1238
4763
      Trace("var-elim-quant") << "Return " << body << std::endl;
1239
    }
1240
  }
1241
97530
  return body;
1242
}
1243
1244
398473
Node QuantifiersRewriter::computePrenex(Node q,
1245
                                        Node body,
1246
                                        std::unordered_set<Node>& args,
1247
                                        std::unordered_set<Node>& nargs,
1248
                                        bool pol,
1249
                                        bool prenexAgg)
1250
{
1251
398473
  NodeManager* nm = NodeManager::currentNM();
1252
398473
  Kind k = body.getKind();
1253
398473
  if (k == FORALL)
1254
  {
1255
13548
    if( ( pol || prenexAgg ) && ( options::prenexQuantUser() || body.getNumChildren()==2 ) ){
1256
2152
      std::vector< Node > terms;
1257
2152
      std::vector< Node > subs;
1258
1076
      BoundVarManager* bvm = nm->getBoundVarManager();
1259
      //for doing prenexing of same-signed quantifiers
1260
      //must rename each variable that already exists
1261
2779
      for (const Node& v : body[0])
1262
      {
1263
1703
        terms.push_back(v);
1264
3406
        TypeNode vt = v.getType();
1265
3406
        Node vv;
1266
1703
        if (!q.isNull())
1267
        {
1268
          // We cache based on the original quantified formula, the subformula
1269
          // that we are pulling variables from (body), and the variable v.
1270
          // The argument body is required since in rare cases, two subformulas
1271
          // may share the same variables. This is the case for define-fun
1272
          // or inferred substitutions that contain quantified formulas.
1273
3406
          Node cacheVal = BoundVarManager::getCacheValue(q, body, v);
1274
1703
          vv = bvm->mkBoundVar<QRewPrenexAttribute>(cacheVal, vt);
1275
        }
1276
        else
1277
        {
1278
          // not specific to a quantified formula, use normal
1279
          vv = nm->mkBoundVar(vt);
1280
        }
1281
1703
        subs.push_back(vv);
1282
      }
1283
1076
      if (pol)
1284
      {
1285
1076
        args.insert(subs.begin(), subs.end());
1286
      }
1287
      else
1288
      {
1289
        nargs.insert(subs.begin(), subs.end());
1290
      }
1291
2152
      Node newBody = body[1];
1292
1076
      newBody = newBody.substitute( terms.begin(), terms.end(), subs.begin(), subs.end() );
1293
1076
      return newBody;
1294
    }
1295
  //must remove structure
1296
  }
1297
384925
  else if (prenexAgg && k == ITE && body.getType().isBoolean())
1298
  {
1299
    Node nn = nm->mkNode(AND,
1300
                         nm->mkNode(OR, body[0].notNode(), body[1]),
1301
                         nm->mkNode(OR, body[0], body[2]));
1302
    return computePrenex(q, nn, args, nargs, pol, prenexAgg);
1303
  }
1304
384925
  else if (prenexAgg && k == EQUAL && body[0].getType().isBoolean())
1305
  {
1306
    Node nn = nm->mkNode(AND,
1307
                         nm->mkNode(OR, body[0].notNode(), body[1]),
1308
                         nm->mkNode(OR, body[0], body[1].notNode()));
1309
    return computePrenex(q, nn, args, nargs, pol, prenexAgg);
1310
384925
  }else if( body.getType().isBoolean() ){
1311
384925
    Assert(k != EXISTS);
1312
384925
    bool childrenChanged = false;
1313
768805
    std::vector< Node > newChildren;
1314
1181400
    for (size_t i = 0, nchild = body.getNumChildren(); i < nchild; i++)
1315
    {
1316
      bool newHasPol;
1317
      bool newPol;
1318
796475
      QuantPhaseReq::getPolarity( body, i, true, pol, newHasPol, newPol );
1319
1292153
      if (!newHasPol)
1320
      {
1321
495678
        newChildren.push_back( body[i] );
1322
495678
        continue;
1323
      }
1324
601594
      Node n = computePrenex(q, body[i], args, nargs, newPol, prenexAgg);
1325
300797
      newChildren.push_back(n);
1326
300797
      childrenChanged = n != body[i] || childrenChanged;
1327
    }
1328
384925
    if( childrenChanged ){
1329
1045
      if (k == NOT && newChildren[0].getKind() == NOT)
1330
      {
1331
        return newChildren[0][0];
1332
      }
1333
1045
      return nm->mkNode(k, newChildren);
1334
    }
1335
  }
1336
396352
  return body;
1337
}
1338
1339
Node QuantifiersRewriter::computePrenexAgg(Node n,
1340
                                           std::map<Node, Node>& visited)
1341
{
1342
  std::map< Node, Node >::iterator itv = visited.find( n );
1343
  if( itv!=visited.end() ){
1344
    return itv->second;
1345
  }
1346
  if (!expr::hasClosure(n))
1347
  {
1348
    // trivial
1349
    return n;
1350
  }
1351
  NodeManager* nm = NodeManager::currentNM();
1352
  Node ret = n;
1353
  if (n.getKind() == NOT)
1354
  {
1355
    ret = computePrenexAgg(n[0], visited).negate();
1356
  }
1357
  else if (n.getKind() == FORALL)
1358
  {
1359
    std::vector<Node> children;
1360
    children.push_back(computePrenexAgg(n[1], visited));
1361
    std::vector<Node> args;
1362
    args.insert(args.end(), n[0].begin(), n[0].end());
1363
    // for each child, strip top level quant
1364
    for (unsigned i = 0; i < children.size(); i++)
1365
    {
1366
      if (children[i].getKind() == FORALL)
1367
      {
1368
        args.insert(args.end(), children[i][0].begin(), children[i][0].end());
1369
        children[i] = children[i][1];
1370
      }
1371
    }
1372
    // keep the pattern
1373
    std::vector<Node> iplc;
1374
    if (n.getNumChildren() == 3)
1375
    {
1376
      iplc.insert(iplc.end(), n[2].begin(), n[2].end());
1377
    }
1378
    Node nb = children.size() == 1 ? children[0] : nm->mkNode(OR, children);
1379
    ret = mkForall(args, nb, iplc, true);
1380
  }
1381
  else
1382
  {
1383
    std::unordered_set<Node> argsSet;
1384
    std::unordered_set<Node> nargsSet;
1385
    Node q;
1386
    Node nn = computePrenex(q, n, argsSet, nargsSet, true, true);
1387
    Assert(n != nn || argsSet.empty());
1388
    Assert(n != nn || nargsSet.empty());
1389
    if (n != nn)
1390
    {
1391
      Node nnn = computePrenexAgg(nn, visited);
1392
      // merge prenex
1393
      if (nnn.getKind() == FORALL)
1394
      {
1395
        argsSet.insert(nnn[0].begin(), nnn[0].end());
1396
        nnn = nnn[1];
1397
        // pos polarity variables are inner
1398
        if (!argsSet.empty())
1399
        {
1400
          nnn = mkForall({argsSet.begin(), argsSet.end()}, nnn, true);
1401
        }
1402
        argsSet.clear();
1403
      }
1404
      else if (nnn.getKind() == NOT && nnn[0].getKind() == FORALL)
1405
      {
1406
        nargsSet.insert(nnn[0][0].begin(), nnn[0][0].end());
1407
        nnn = nnn[0][1].negate();
1408
      }
1409
      if (!nargsSet.empty())
1410
      {
1411
        nnn = mkForall({nargsSet.begin(), nargsSet.end()}, nnn.negate(), true)
1412
                  .negate();
1413
      }
1414
      if (!argsSet.empty())
1415
      {
1416
        nnn = mkForall({argsSet.begin(), argsSet.end()}, nnn, true);
1417
      }
1418
      ret = nnn;
1419
    }
1420
  }
1421
  visited[n] = ret;
1422
  return ret;
1423
}
1424
1425
41281
Node QuantifiersRewriter::computeSplit( std::vector< Node >& args, Node body, QAttributes& qa ) {
1426
41281
  Assert(body.getKind() == OR);
1427
41281
  size_t var_found_count = 0;
1428
41281
  size_t eqc_count = 0;
1429
41281
  size_t eqc_active = 0;
1430
82562
  std::map< Node, int > var_to_eqc;
1431
82562
  std::map< int, std::vector< Node > > eqc_to_var;
1432
82562
  std::map< int, std::vector< Node > > eqc_to_lit;
1433
1434
82562
  std::vector<Node> lits;
1435
1436
176880
  for( unsigned i=0; i<body.getNumChildren(); i++ ){
1437
    //get variables contained in the literal
1438
271198
    Node n = body[i];
1439
271198
    std::vector< Node > lit_args;
1440
135599
    computeArgVec( args, lit_args, n );
1441
135599
    if( lit_args.empty() ){
1442
1647
      lits.push_back( n );
1443
    }else {
1444
      //collect the equivalence classes this literal belongs to, and the new variables it contributes
1445
267904
      std::vector< int > eqcs;
1446
267904
      std::vector< Node > lit_new_args;
1447
      //for each variable in literal
1448
451305
      for( unsigned j=0; j<lit_args.size(); j++) {
1449
        //see if the variable has already been found
1450
317353
        if (var_to_eqc.find(lit_args[j])!=var_to_eqc.end()) {
1451
214620
          int eqc = var_to_eqc[lit_args[j]];
1452
214620
          if (std::find(eqcs.begin(), eqcs.end(), eqc)==eqcs.end()) {
1453
92407
            eqcs.push_back(eqc);
1454
          }
1455
        }else{
1456
102733
          var_found_count++;
1457
102733
          lit_new_args.push_back(lit_args[j]);
1458
        }
1459
      }
1460
133952
      if (eqcs.empty()) {
1461
46962
        eqcs.push_back(eqc_count);
1462
46962
        eqc_count++;
1463
46962
        eqc_active++;
1464
      }
1465
1466
133952
      int eqcz = eqcs[0];
1467
      //merge equivalence classes with eqcz
1468
139369
      for (unsigned j=1; j<eqcs.size(); j++) {
1469
5417
        int eqc = eqcs[j];
1470
        //move all variables from equivalence class
1471
28896
        for (unsigned k=0; k<eqc_to_var[eqc].size(); k++) {
1472
46958
          Node v = eqc_to_var[eqc][k];
1473
23479
          var_to_eqc[v] = eqcz;
1474
23479
          eqc_to_var[eqcz].push_back(v);
1475
        }
1476
5417
        eqc_to_var.erase(eqc);
1477
        //move all literals from equivalence class
1478
27731
        for (unsigned k=0; k<eqc_to_lit[eqc].size(); k++) {
1479
44628
          Node l = eqc_to_lit[eqc][k];
1480
22314
          eqc_to_lit[eqcz].push_back(l);
1481
        }
1482
5417
        eqc_to_lit.erase(eqc);
1483
5417
        eqc_active--;
1484
      }
1485
      //add variables to equivalence class
1486
236685
      for (unsigned j=0; j<lit_new_args.size(); j++) {
1487
102733
        var_to_eqc[lit_new_args[j]] = eqcz;
1488
102733
        eqc_to_var[eqcz].push_back(lit_new_args[j]);
1489
      }
1490
      //add literal to equivalence class
1491
133952
      eqc_to_lit[eqcz].push_back(n);
1492
    }
1493
  }
1494
41281
  if ( eqc_active>1 || !lits.empty() || var_to_eqc.size()!=args.size() ){
1495
588
    NodeManager* nm = NodeManager::currentNM();
1496
588
    Trace("clause-split-debug") << "Split quantified formula with body " << body << std::endl;
1497
588
    Trace("clause-split-debug") << "   Ground literals: " << std::endl;
1498
2235
    for( size_t i=0; i<lits.size(); i++) {
1499
1647
      Trace("clause-split-debug") << "      " << lits[i] << std::endl;
1500
    }
1501
588
    Trace("clause-split-debug") << std::endl;
1502
588
    Trace("clause-split-debug") << "Equivalence classes: " << std::endl;
1503
1440
    for (std::map< int, std::vector< Node > >::iterator it = eqc_to_lit.begin(); it != eqc_to_lit.end(); ++it ){
1504
852
      Trace("clause-split-debug") << "   Literals: " << std::endl;
1505
4023
      for (size_t i=0; i<it->second.size(); i++) {
1506
3171
        Trace("clause-split-debug") << "      " << it->second[i] << std::endl;
1507
      }
1508
852
      int eqc = it->first;
1509
852
      Trace("clause-split-debug") << "   Variables: " << std::endl;
1510
3637
      for (size_t i=0; i<eqc_to_var[eqc].size(); i++) {
1511
2785
        Trace("clause-split-debug") << "      " << eqc_to_var[eqc][i] << std::endl;
1512
      }
1513
852
      Trace("clause-split-debug") << std::endl;
1514
1704
      Node bvl = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, eqc_to_var[eqc]);
1515
      Node bd =
1516
1704
          it->second.size() == 1 ? it->second[0] : nm->mkNode(OR, it->second);
1517
1704
      Node fa = nm->mkNode(FORALL, bvl, bd);
1518
852
      lits.push_back(fa);
1519
    }
1520
588
    Assert(!lits.empty());
1521
1176
    Node nf = lits.size()==1 ? lits[0] : NodeManager::currentNM()->mkNode(OR,lits);
1522
588
    Trace("clause-split-debug") << "Made node : " << nf << std::endl;
1523
588
    return nf;
1524
  }else{
1525
40693
    return mkForAll( args, body, qa );
1526
  }
1527
}
1528
1529
99203
Node QuantifiersRewriter::mkForAll(const std::vector<Node>& args,
1530
                                   Node body,
1531
                                   QAttributes& qa)
1532
{
1533
99203
  if (args.empty())
1534
  {
1535
149
    return body;
1536
  }
1537
99054
  NodeManager* nm = NodeManager::currentNM();
1538
198108
  std::vector<Node> children;
1539
99054
  children.push_back(nm->mkNode(kind::BOUND_VAR_LIST, args));
1540
99054
  children.push_back(body);
1541
99054
  if (!qa.d_ipl.isNull())
1542
  {
1543
200
    children.push_back(qa.d_ipl);
1544
  }
1545
99054
  return nm->mkNode(kind::FORALL, children);
1546
}
1547
1548
Node QuantifiersRewriter::mkForall(const std::vector<Node>& args,
1549
                                   Node body,
1550
                                   bool marked)
1551
{
1552
  std::vector< Node > iplc;
1553
  return mkForall( args, body, iplc, marked );
1554
}
1555
1556
Node QuantifiersRewriter::mkForall(const std::vector<Node>& args,
1557
                                   Node body,
1558
                                   std::vector<Node>& iplc,
1559
                                   bool marked)
1560
{
1561
  if (args.empty())
1562
  {
1563
    return body;
1564
  }
1565
  NodeManager* nm = NodeManager::currentNM();
1566
  std::vector<Node> children;
1567
  children.push_back(nm->mkNode(kind::BOUND_VAR_LIST, args));
1568
  children.push_back(body);
1569
  if (marked)
1570
  {
1571
    SkolemManager* sm = nm->getSkolemManager();
1572
    Node avar = sm->mkDummySkolem("id", nm->booleanType());
1573
    QuantIdNumAttribute ida;
1574
    avar.setAttribute(ida, 0);
1575
    iplc.push_back(nm->mkNode(kind::INST_ATTRIBUTE, avar));
1576
  }
1577
  if (!iplc.empty())
1578
  {
1579
    children.push_back(nm->mkNode(kind::INST_PATTERN_LIST, iplc));
1580
  }
1581
  return nm->mkNode(kind::FORALL, children);
1582
}
1583
1584
//computes miniscoping, also eliminates variables that do not occur free in body
1585
100391
Node QuantifiersRewriter::computeMiniscoping(Node q, QAttributes& qa)
1586
{
1587
100391
  NodeManager* nm = NodeManager::currentNM();
1588
200782
  std::vector<Node> args(q[0].begin(), q[0].end());
1589
200782
  Node body = q[1];
1590
100391
  if( body.getKind()==FORALL ){
1591
    //combine prenex
1592
32
    std::vector< Node > newArgs;
1593
16
    newArgs.insert(newArgs.end(), q[0].begin(), q[0].end());
1594
33
    for( unsigned i=0; i<body[0].getNumChildren(); i++ ){
1595
17
      newArgs.push_back( body[0][i] );
1596
    }
1597
16
    return mkForAll( newArgs, body[1], qa );
1598
100375
  }else if( body.getKind()==AND ){
1599
    // aggressive miniscoping implies that structural miniscoping should
1600
    // be applied first
1601
1258
    if (options::miniscopeQuant() || options::aggressiveMiniscopeQuant())
1602
    {
1603
614
      BoundVarManager* bvm = nm->getBoundVarManager();
1604
      // Break apart the quantifed formula
1605
      // forall x. P1 ^ ... ^ Pn ---> forall x. P1 ^ ... ^ forall x. Pn
1606
1228
      NodeBuilder t(kind::AND);
1607
1228
      std::vector<Node> argsc;
1608
3623
      for (size_t i = 0, nchild = body.getNumChildren(); i < nchild; i++)
1609
      {
1610
3009
        if (argsc.empty())
1611
        {
1612
          // If not done so, we must create fresh copy of args. This is to
1613
          // ensure that quantified formulas do not reuse variables.
1614
6076
          for (const Node& v : q[0])
1615
          {
1616
9134
            TypeNode vt = v.getType();
1617
9134
            Node cacheVal = BoundVarManager::getCacheValue(q, v, i);
1618
9134
            Node vv = bvm->mkBoundVar<QRewMiniscopeAttribute>(cacheVal, vt);
1619
4567
            argsc.push_back(vv);
1620
          }
1621
        }
1622
6018
        Node b = body[i];
1623
        Node bodyc =
1624
6018
            b.substitute(args.begin(), args.end(), argsc.begin(), argsc.end());
1625
3009
        if (b == bodyc)
1626
        {
1627
          // Did not contain variables in args, thus it is ground. Since we did
1628
          // not use them, we keep the variables argsc for the next child.
1629
1539
          t << b;
1630
        }
1631
        else
1632
        {
1633
          // make the miniscoped quantified formula
1634
2940
          Node cbvl = nm->mkNode(BOUND_VAR_LIST, argsc);
1635
2940
          Node qq = nm->mkNode(FORALL, cbvl, bodyc);
1636
1470
          t << qq;
1637
          // We used argsc, clear so we will construct a fresh copy above.
1638
1470
          argsc.clear();
1639
        }
1640
      }
1641
1228
      Node retVal = t;
1642
614
      return retVal;
1643
    }
1644
99117
  }else if( body.getKind()==OR ){
1645
42508
    if( options::quantSplit() ){
1646
      //splitting subsumes free variable miniscoping, apply it with higher priority
1647
41281
      return computeSplit( args, body, qa );
1648
    }
1649
2454
    else if (options::miniscopeQuantFreeVar()
1650
1227
             || options::aggressiveMiniscopeQuant())
1651
    {
1652
      // aggressive miniscoping implies that free variable miniscoping should
1653
      // be applied first
1654
4
      Node newBody = body;
1655
4
      NodeBuilder body_split(kind::OR);
1656
4
      NodeBuilder tb(kind::OR);
1657
12
      for (const Node& trm : body)
1658
      {
1659
8
        if (expr::hasSubterm(trm, args))
1660
        {
1661
4
          tb << trm;
1662
        }else{
1663
4
          body_split << trm;
1664
        }
1665
      }
1666
4
      if( tb.getNumChildren()==0 ){
1667
        return body_split;
1668
4
      }else if( body_split.getNumChildren()>0 ){
1669
4
        newBody = tb.getNumChildren()==1 ? tb.getChild( 0 ) : tb;
1670
8
        std::vector< Node > activeArgs;
1671
4
        computeArgVec2( args, activeArgs, newBody, qa.d_ipl );
1672
4
        body_split << mkForAll( activeArgs, newBody, qa );
1673
4
        return body_split.getNumChildren()==1 ? body_split.getChild( 0 ) : body_split;
1674
      }
1675
    }
1676
56609
  }else if( body.getKind()==NOT ){
1677
14610
    Assert(isLiteral(body[0]));
1678
  }
1679
  //remove variables that don't occur
1680
116952
  std::vector< Node > activeArgs;
1681
58476
  computeArgVec2( args, activeArgs, body, qa.d_ipl );
1682
58476
  return mkForAll( activeArgs, body, qa );
1683
}
1684
1685
14
Node QuantifiersRewriter::computeAggressiveMiniscoping( std::vector< Node >& args, Node body ){
1686
28
  std::map<Node, std::vector<Node> > varLits;
1687
28
  std::map<Node, std::vector<Node> > litVars;
1688
14
  if (body.getKind() == OR) {
1689
    Trace("ag-miniscope") << "compute aggressive miniscoping on " << body << std::endl;
1690
    for (size_t i = 0; i < body.getNumChildren(); i++) {
1691
      std::vector<Node> activeArgs;
1692
      computeArgVec(args, activeArgs, body[i]);
1693
      for (unsigned j = 0; j < activeArgs.size(); j++) {
1694
        varLits[activeArgs[j]].push_back(body[i]);
1695
      }
1696
      std::vector<Node>& lit_body_i = litVars[body[i]];
1697
      std::vector<Node>::iterator lit_body_i_begin = lit_body_i.begin();
1698
      std::vector<Node>::const_iterator active_begin = activeArgs.begin();
1699
      std::vector<Node>::const_iterator active_end = activeArgs.end();
1700
      lit_body_i.insert(lit_body_i_begin, active_begin, active_end);
1701
    }
1702
    //find the variable in the least number of literals
1703
    Node bestVar;
1704
    for( std::map< Node, std::vector<Node> >::iterator it = varLits.begin(); it != varLits.end(); ++it ){
1705
      if( bestVar.isNull() || varLits[bestVar].size()>it->second.size() ){
1706
        bestVar = it->first;
1707
      }
1708
    }
1709
    Trace("ag-miniscope-debug") << "Best variable " << bestVar << " occurs in " << varLits[bestVar].size() << "/ " << body.getNumChildren() << " literals." << std::endl;
1710
    if( !bestVar.isNull() && varLits[bestVar].size()<body.getNumChildren() ){
1711
      //we can miniscope
1712
      Trace("ag-miniscope") << "Miniscope on " << bestVar << std::endl;
1713
      //make the bodies
1714
      std::vector<Node> qlit1;
1715
      qlit1.insert( qlit1.begin(), varLits[bestVar].begin(), varLits[bestVar].end() );
1716
      std::vector<Node> qlitt;
1717
      //for all literals not containing bestVar
1718
      for( size_t i=0; i<body.getNumChildren(); i++ ){
1719
        if( std::find( qlit1.begin(), qlit1.end(), body[i] )==qlit1.end() ){
1720
          qlitt.push_back( body[i] );
1721
        }
1722
      }
1723
      //make the variable lists
1724
      std::vector<Node> qvl1;
1725
      std::vector<Node> qvl2;
1726
      std::vector<Node> qvsh;
1727
      for( unsigned i=0; i<args.size(); i++ ){
1728
        bool found1 = false;
1729
        bool found2 = false;
1730
        for( size_t j=0; j<varLits[args[i]].size(); j++ ){
1731
          if( !found1 && std::find( qlit1.begin(), qlit1.end(), varLits[args[i]][j] )!=qlit1.end() ){
1732
            found1 = true;
1733
          }else if( !found2 && std::find( qlitt.begin(), qlitt.end(), varLits[args[i]][j] )!=qlitt.end() ){
1734
            found2 = true;
1735
          }
1736
          if( found1 && found2 ){
1737
            break;
1738
          }
1739
        }
1740
        if( found1 ){
1741
          if( found2 ){
1742
            qvsh.push_back( args[i] );
1743
          }else{
1744
            qvl1.push_back( args[i] );
1745
          }
1746
        }else{
1747
          Assert(found2);
1748
          qvl2.push_back( args[i] );
1749
        }
1750
      }
1751
      Assert(!qvl1.empty());
1752
      //check for literals that only contain shared variables
1753
      std::vector<Node> qlitsh;
1754
      std::vector<Node> qlit2;
1755
      for( size_t i=0; i<qlitt.size(); i++ ){
1756
        bool hasVar2 = false;
1757
        for( size_t j=0; j<litVars[qlitt[i]].size(); j++ ){
1758
          if( std::find( qvl2.begin(), qvl2.end(), litVars[qlitt[i]][j] )!=qvl2.end() ){
1759
            hasVar2 = true;
1760
            break;
1761
          }
1762
        }
1763
        if( hasVar2 ){
1764
          qlit2.push_back( qlitt[i] );
1765
        }else{
1766
          qlitsh.push_back( qlitt[i] );
1767
        }
1768
      }
1769
      varLits.clear();
1770
      litVars.clear();
1771
      Trace("ag-miniscope-debug") << "Split into literals : " << qlit1.size() << " / " << qlit2.size() << " / " << qlitsh.size();
1772
      Trace("ag-miniscope-debug") << ", variables : " << qvl1.size() << " / " << qvl2.size() << " / " << qvsh.size() << std::endl;
1773
      Node n1 = qlit1.size()==1 ? qlit1[0] : NodeManager::currentNM()->mkNode( OR, qlit1 );
1774
      n1 = computeAggressiveMiniscoping( qvl1, n1 );
1775
      qlitsh.push_back( n1 );
1776
      if( !qlit2.empty() ){
1777
        Node n2 = qlit2.size()==1 ? qlit2[0] : NodeManager::currentNM()->mkNode( OR, qlit2 );
1778
        n2 = computeAggressiveMiniscoping( qvl2, n2 );
1779
        qlitsh.push_back( n2 );
1780
      }
1781
      Node n = NodeManager::currentNM()->mkNode( OR, qlitsh );
1782
      if( !qvsh.empty() ){
1783
        Node bvl = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, qvsh);
1784
        n = NodeManager::currentNM()->mkNode( FORALL, bvl, n );
1785
      }
1786
      Trace("ag-miniscope") << "Return " << n << " for " << body << std::endl;
1787
      return n;
1788
    }
1789
  }
1790
28
  QAttributes qa;
1791
14
  return mkForAll( args, body, qa );
1792
}
1793
1794
949501
bool QuantifiersRewriter::doOperation(Node q,
1795
                                      RewriteStep computeOption,
1796
                                      QAttributes& qa)
1797
{
1798
  bool is_strict_trigger =
1799
949501
      qa.d_hasPattern
1800
949501
      && options::userPatternsQuant() == options::UserPatMode::TRUST;
1801
949501
  bool is_std = qa.isStandard() && !is_strict_trigger;
1802
949501
  if (computeOption == COMPUTE_ELIM_SYMBOLS)
1803
  {
1804
131961
    return true;
1805
  }
1806
817540
  else if (computeOption == COMPUTE_MINISCOPING)
1807
  {
1808
118805
    return is_std;
1809
  }
1810
698735
  else if (computeOption == COMPUTE_AGGRESSIVE_MINISCOPING)
1811
  {
1812
117271
    return options::aggressiveMiniscopeQuant() && is_std;
1813
  }
1814
581464
  else if (computeOption == COMPUTE_EXT_REWRITE)
1815
  {
1816
117271
    return options::extRewriteQuant();
1817
  }
1818
464193
  else if (computeOption == COMPUTE_PROCESS_TERMS)
1819
  {
1820
117259
    return is_std && options::iteLiftQuant() != options::IteLiftQuantMode::NONE;
1821
  }
1822
346934
  else if (computeOption == COMPUTE_COND_SPLIT)
1823
  {
1824
227944
    return (options::iteDtTesterSplitQuant() || options::condVarSplitQuant())
1825
228302
           && !is_strict_trigger;
1826
  }
1827
232783
  else if (computeOption == COMPUTE_PRENEX)
1828
  {
1829
116839
    return options::prenexQuant() != options::PrenexQuantMode::NONE
1830
116839
           && !options::aggressiveMiniscopeQuant() && is_std;
1831
  }
1832
115944
  else if (computeOption == COMPUTE_VAR_ELIMINATION)
1833
  {
1834
115944
    return (options::varElimQuant() || options::dtVarExpandQuant()) && is_std;
1835
  }
1836
  else
1837
  {
1838
    return false;
1839
  }
1840
}
1841
1842
//general method for computing various rewrites
1843
625508
Node QuantifiersRewriter::computeOperation(Node f,
1844
                                           RewriteStep computeOption,
1845
                                           QAttributes& qa)
1846
{
1847
625508
  Trace("quantifiers-rewrite-debug") << "Compute operation " << computeOption << " on " << f << " " << qa.d_qid_num << std::endl;
1848
625508
  if (computeOption == COMPUTE_MINISCOPING)
1849
  {
1850
100391
    if (options::prenexQuant() == options::PrenexQuantMode::NORMAL)
1851
    {
1852
      if( !qa.d_qid_num.isNull() ){
1853
        //already processed this, return self
1854
        return f;
1855
      }
1856
    }
1857
    //return directly
1858
100391
    return computeMiniscoping(f, qa);
1859
  }
1860
1050234
  std::vector<Node> args(f[0].begin(), f[0].end());
1861
1050234
  Node n = f[1];
1862
525117
  if (computeOption == COMPUTE_ELIM_SYMBOLS)
1863
  {
1864
131961
    n = computeElimSymbols(n);
1865
393156
  }else if( computeOption==COMPUTE_AGGRESSIVE_MINISCOPING ){
1866
14
    return computeAggressiveMiniscoping( args, n );
1867
  }
1868
393142
  else if (computeOption == COMPUTE_EXT_REWRITE)
1869
  {
1870
32
    return computeExtendedRewrite(f);
1871
  }
1872
393110
  else if (computeOption == COMPUTE_PROCESS_TERMS)
1873
  {
1874
197690
    std::vector< Node > new_conds;
1875
98845
    n = computeProcessTerms( n, args, new_conds, f, qa );
1876
98845
    if( !new_conds.empty() ){
1877
      new_conds.push_back( n );
1878
      n = NodeManager::currentNM()->mkNode( OR, new_conds );
1879
    }
1880
  }
1881
294265
  else if (computeOption == COMPUTE_COND_SPLIT)
1882
  {
1883
99059
    n = computeCondSplit(n, args, qa);
1884
  }
1885
195206
  else if (computeOption == COMPUTE_PRENEX)
1886
  {
1887
97676
    if (options::prenexQuant() == options::PrenexQuantMode::NORMAL)
1888
    {
1889
      //will rewrite at preprocess time
1890
      return f;
1891
    }
1892
    else
1893
    {
1894
195352
      std::unordered_set<Node> argsSet, nargsSet;
1895
97676
      n = computePrenex(f, n, argsSet, nargsSet, true, false);
1896
97676
      Assert(nargsSet.empty());
1897
97676
      args.insert(args.end(), argsSet.begin(), argsSet.end());
1898
    }
1899
  }
1900
97530
  else if (computeOption == COMPUTE_VAR_ELIMINATION)
1901
  {
1902
97530
    n = computeVarElimination( n, args, qa );
1903
  }
1904
525071
  Trace("quantifiers-rewrite-debug") << "Compute Operation: return " << n << ", " << args.size() << std::endl;
1905
525071
  if( f[1]==n && args.size()==f[0].getNumChildren() ){
1906
508656
    return f;
1907
  }else{
1908
16415
    if( args.empty() ){
1909
704
      return n;
1910
    }else{
1911
31422
      std::vector< Node > children;
1912
15711
      children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, args ) );
1913
15711
      children.push_back( n );
1914
15711
      if( !qa.d_ipl.isNull() && args.size()==f[0].getNumChildren() ){
1915
2308
        children.push_back( qa.d_ipl );
1916
      }
1917
15711
      return NodeManager::currentNM()->mkNode(kind::FORALL, children );
1918
    }
1919
  }
1920
}
1921
1922
bool QuantifiersRewriter::isPrenexNormalForm( Node n ) {
1923
  if( n.getKind()==FORALL ){
1924
    return n[1].getKind()!=FORALL && isPrenexNormalForm( n[1] );
1925
  }else if( n.getKind()==NOT ){
1926
    return n[0].getKind()!=NOT && isPrenexNormalForm( n[0] );
1927
  }else{
1928
    return !expr::hasClosure(n);
1929
  }
1930
}
1931
1932
783
Node QuantifiersRewriter::preSkolemizeQuantifiers( Node n, bool polarity, std::vector< TypeNode >& fvTypes, std::vector< TNode >& fvs ){
1933
783
  Trace("pre-sk") << "Pre-skolem " << n << " " << polarity << " " << fvs.size() << endl;
1934
783
  if( n.getKind()==kind::NOT ){
1935
252
    Node nn = preSkolemizeQuantifiers( n[0], !polarity, fvTypes, fvs );
1936
126
    return nn.negate();
1937
657
  }else if( n.getKind()==kind::FORALL ){
1938
182
    if (n.getNumChildren() == 3)
1939
    {
1940
      // Do not pre-skolemize quantified formulas with three children.
1941
      // This includes non-standard quantified formulas
1942
      // like recursive function definitions, or sygus conjectures, and
1943
      // quantified formulas with triggers.
1944
90
      return n;
1945
    }
1946
92
    else if (polarity)
1947
    {
1948
68
      if( options::preSkolemQuant() && options::preSkolemQuantNested() ){
1949
100
        vector< Node > children;
1950
50
        children.push_back( n[0] );
1951
        //add children to current scope
1952
100
        std::vector< TypeNode > fvt;
1953
100
        std::vector< TNode > fvss;
1954
50
        fvt.insert( fvt.begin(), fvTypes.begin(), fvTypes.end() );
1955
50
        fvss.insert( fvss.begin(), fvs.begin(), fvs.end() );
1956
114
        for( int i=0; i<(int)n[0].getNumChildren(); i++ ){
1957
64
          fvt.push_back( n[0][i].getType() );
1958
64
          fvss.push_back( n[0][i] );
1959
        }
1960
        //process body
1961
50
        children.push_back( preSkolemizeQuantifiers( n[1], polarity, fvt, fvss ) );
1962
        //return processed quantifier
1963
50
        return NodeManager::currentNM()->mkNode( kind::FORALL, children );
1964
      }
1965
    }else{
1966
      //process body
1967
48
      Node nn = preSkolemizeQuantifiers( n[1], polarity, fvTypes, fvs );
1968
48
      std::vector< Node > sk;
1969
48
      Node sub;
1970
48
      std::vector< unsigned > sub_vars;
1971
      //return skolemized body
1972
      return Skolemize::mkSkolemizedBody(
1973
24
          n, nn, fvTypes, fvs, sk, sub, sub_vars);
1974
    }
1975
  }else{
1976
    //check if it contains a quantifier as a subterm
1977
    //if so, we will write this node
1978
475
    if (expr::hasClosure(n))
1979
    {
1980
74
      if( ( n.getKind()==kind::ITE && n.getType().isBoolean() ) || ( n.getKind()==kind::EQUAL && n[0].getType().isBoolean() ) ){
1981
14
        if( options::preSkolemQuantAgg() ){
1982
28
          Node nn;
1983
          //must remove structure
1984
14
          if( n.getKind()==kind::ITE ){
1985
            nn = NodeManager::currentNM()->mkNode( kind::AND,
1986
                  NodeManager::currentNM()->mkNode( kind::OR, n[0].notNode(), n[1] ),
1987
                  NodeManager::currentNM()->mkNode( kind::OR, n[0], n[2] ) );
1988
14
          }else if( n.getKind()==kind::EQUAL ){
1989
56
            nn = NodeManager::currentNM()->mkNode( kind::AND,
1990
28
                  NodeManager::currentNM()->mkNode( kind::OR, n[0].notNode(), n.getKind()==kind::XOR ? n[1].notNode() : n[1] ),
1991
28
                  NodeManager::currentNM()->mkNode( kind::OR, n[0], n.getKind()==kind::XOR ? n[1] : n[1].notNode() ) );
1992
          }
1993
14
          return preSkolemizeQuantifiers( nn, polarity, fvTypes, fvs );
1994
        }
1995
60
      }else if( n.getKind()==kind::AND || n.getKind()==kind::OR ){
1996
116
        vector< Node > children;
1997
174
        for( int i=0; i<(int)n.getNumChildren(); i++ ){
1998
116
          children.push_back( preSkolemizeQuantifiers( n[i], polarity, fvTypes, fvs ) );
1999
        }
2000
58
        return NodeManager::currentNM()->mkNode( n.getKind(), children );
2001
      }
2002
    }
2003
  }
2004
421
  return n;
2005
}
2006
2007
91331
TrustNode QuantifiersRewriter::preprocess(Node n, bool isInst)
2008
{
2009
182662
  Node prev = n;
2010
2011
91331
  if( options::preSkolemQuant() ){
2012
515
    if( !isInst || !options::preSkolemQuantNested() ){
2013
453
      Trace("quantifiers-preprocess-debug") << "Pre-skolemize " << n << "..." << std::endl;
2014
      //apply pre-skolemization to existential quantifiers
2015
906
      std::vector< TypeNode > fvTypes;
2016
906
      std::vector< TNode > fvs;
2017
453
      n = preSkolemizeQuantifiers( prev, true, fvTypes, fvs );
2018
    }
2019
  }
2020
  //pull all quantifiers globally
2021
91331
  if (options::prenexQuant() == options::PrenexQuantMode::NORMAL)
2022
  {
2023
    Trace("quantifiers-prenex") << "Prenexing : " << n << std::endl;
2024
    std::map<Node, Node> visited;
2025
    n = computePrenexAgg(n, visited);
2026
    n = Rewriter::rewrite( n );
2027
    Trace("quantifiers-prenex") << "Prenexing returned : " << n << std::endl;
2028
    //Assert( isPrenexNormalForm( n ) );
2029
  }
2030
91331
  if( n!=prev ){
2031
16
    Trace("quantifiers-preprocess") << "Preprocess " << prev << std::endl;
2032
16
    Trace("quantifiers-preprocess") << "..returned " << n << std::endl;
2033
16
    return TrustNode::mkTrustRewrite(prev, n, nullptr);
2034
  }
2035
91315
  return TrustNode::null();
2036
}
2037
2038
}  // namespace quantifiers
2039
}  // namespace theory
2040
29340
}  // namespace cvc5