GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/quantifiers_rewriter.cpp Lines: 893 1168 76.5 %
Date: 2021-05-22 Branches: 2048 5079 40.3 %

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
15674
bool QuantifiersRewriter::isLiteral( Node n ){
88
15674
  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
9168
  case EQUAL:
100
    //for boolean terms
101
9168
    return !n[0].getType().isBoolean();
102
    break;
103
6506
  default:
104
6506
    break;
105
  }
106
6506
  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
4346210
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
4346210
  if( visited.find( n )==visited.end() ){
126
3151326
    visited[n] = true;
127
3151326
    if( n.getKind()==BOUND_VARIABLE ){
128
541359
      if( std::find( args.begin(), args.end(), n )!=args.end() ){
129
434990
        activeMap[ n ] = true;
130
      }
131
    }else{
132
2609967
      if (n.hasOperator())
133
      {
134
1372509
        computeArgs(args, activeMap, n.getOperator(), visited);
135
      }
136
5326306
      for( int i=0; i<(int)n.getNumChildren(); i++ ){
137
2716339
        computeArgs( args, activeMap, n[i], visited );
138
      }
139
    }
140
  }
141
4346210
}
142
143
138075
void QuantifiersRewriter::computeArgVec(const std::vector<Node>& args,
144
                                        std::vector<Node>& activeArgs,
145
                                        Node n)
146
{
147
138075
  Assert(activeArgs.empty());
148
276150
  std::map< Node, bool > activeMap;
149
276150
  std::map< Node, bool > visited;
150
138075
  computeArgs( args, activeMap, n, visited );
151
138075
  if( !activeMap.empty() ){
152
2376585
    for( unsigned i=0; i<args.size(); i++ ){
153
2240166
      if( activeMap.find( args[i] )!=activeMap.end() ){
154
320890
        activeArgs.push_back( args[i] );
155
      }
156
    }
157
  }
158
138075
}
159
160
59681
void QuantifiersRewriter::computeArgVec2(const std::vector<Node>& args,
161
                                         std::vector<Node>& activeArgs,
162
                                         Node n,
163
                                         Node ipl)
164
{
165
59681
  Assert(activeArgs.empty());
166
119362
  std::map< Node, bool > activeMap;
167
119362
  std::map< Node, bool > visited;
168
59681
  computeArgs( args, activeMap, n, visited );
169
59681
  if( !activeMap.empty() ){
170
    //collect variables in inst pattern list only if we cannot eliminate quantifier
171
59606
    computeArgs( args, activeMap, ipl, visited );
172
174584
    for( unsigned i=0; i<args.size(); i++ ){
173
114978
      if( activeMap.find( args[i] )!=activeMap.end() ){
174
114100
        activeArgs.push_back( args[i] );
175
      }
176
    }
177
  }
178
59681
}
179
180
135001
RewriteResponse QuantifiersRewriter::preRewrite(TNode in) {
181
135001
  if( in.getKind()==kind::EXISTS || in.getKind()==kind::FORALL ){
182
79804
    Trace("quantifiers-rewrite-debug") << "pre-rewriting " << in << std::endl;
183
157845
    std::vector< Node > args;
184
157845
    Node body = in;
185
79804
    bool doRewrite = false;
186
94074
    while( body.getNumChildren()==2 && body.getKind()==body[1].getKind() ){
187
14297
      for( unsigned i=0; i<body[0].getNumChildren(); i++ ){
188
7162
        args.push_back( body[0][i] );
189
      }
190
7135
      body = body[1];
191
7135
      doRewrite = true;
192
    }
193
79804
    if( doRewrite ){
194
3526
      std::vector< Node > children;
195
3541
      for( unsigned i=0; i<body[0].getNumChildren(); i++ ){
196
1778
        args.push_back( body[0][i] );
197
      }
198
1763
      children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST,args) );
199
1763
      children.push_back( body[1] );
200
1763
      if( body.getNumChildren()==3 ){
201
39
        children.push_back( body[2] );
202
      }
203
3526
      Node n = NodeManager::currentNM()->mkNode( in.getKind(), children );
204
1763
      if( in!=n ){
205
1763
        Trace("quantifiers-pre-rewrite") << "*** pre-rewrite " << in << std::endl;
206
1763
        Trace("quantifiers-pre-rewrite") << " to " << std::endl;
207
1763
        Trace("quantifiers-pre-rewrite") << n << std::endl;
208
      }
209
1763
      return RewriteResponse(REWRITE_DONE, n);
210
    }
211
  }
212
133238
  return RewriteResponse(REWRITE_DONE, in);
213
}
214
215
246495
RewriteResponse QuantifiersRewriter::postRewrite(TNode in) {
216
246495
  Trace("quantifiers-rewrite-debug") << "post-rewriting " << in << std::endl;
217
246495
  RewriteStatus status = REWRITE_DONE;
218
492990
  Node ret = in;
219
246495
  RewriteStep rew_op = COMPUTE_LAST;
220
  //get the body
221
246495
  if( in.getKind()==EXISTS ){
222
5798
    std::vector< Node > children;
223
2899
    children.push_back( in[0] );
224
2899
    children.push_back( in[1].negate() );
225
2899
    if( in.getNumChildren()==3 ){
226
43
      children.push_back( in[2] );
227
    }
228
2899
    ret = NodeManager::currentNM()->mkNode( FORALL, children );
229
2899
    ret = ret.negate();
230
2899
    status = REWRITE_AGAIN_FULL;
231
243596
  }else if( in.getKind()==FORALL ){
232
133488
    if( in[1].isConst() && in.getNumChildren()==2 ){
233
946
      return RewriteResponse( status, in[1] );
234
    }else{
235
      //compute attributes
236
265084
      QAttributes qa;
237
132542
      QuantAttributes::computeQuantAttributes( in, qa );
238
1069709
      for (unsigned i = 0; i < COMPUTE_LAST; ++i)
239
      {
240
955049
        RewriteStep op = static_cast<RewriteStep>(i);
241
955049
        if( doOperation( in, op, qa ) ){
242
634047
          ret = computeOperation( in, op, qa );
243
634047
          if( ret!=in ){
244
17882
            rew_op = op;
245
17882
            status = REWRITE_AGAIN_FULL;
246
17882
            break;
247
          }
248
        }
249
      }
250
    }
251
  }
252
  //print if changed
253
245549
  if( in!=ret ){
254
20781
    Trace("quantifiers-rewrite") << "*** rewrite (op=" << rew_op << ") " << in << std::endl;
255
20781
    Trace("quantifiers-rewrite") << " to " << std::endl;
256
20781
    Trace("quantifiers-rewrite") << ret << std::endl;
257
  }
258
245549
  return RewriteResponse( status, ret );
259
}
260
261
704255
bool QuantifiersRewriter::addCheckElimChild( std::vector< Node >& children, Node c, Kind k, std::map< Node, bool >& lit_pol, bool& childrenChanged ){
262
1266419
  if( ( k==OR || k==AND ) && options::elimTautQuant() ){
263
1124107
    Node lit = c.getKind()==NOT ? c[0] : c;
264
562164
    bool pol = c.getKind()!=NOT;
265
562164
    std::map< Node, bool >::iterator it = lit_pol.find( lit );
266
562164
    if( it==lit_pol.end() ){
267
561254
      lit_pol[lit] = pol;
268
561254
      children.push_back( c );
269
    }else{
270
910
      childrenChanged = true;
271
910
      if( it->second!=pol ){
272
221
        return false;
273
      }
274
    }
275
  }else{
276
142091
    children.push_back( c );
277
  }
278
704034
  return true;
279
}
280
281
// eliminates IMPLIES/XOR, removes duplicates/infers tautologies of AND/OR, and computes NNF
282
822862
Node QuantifiersRewriter::computeElimSymbols( Node body ) {
283
822862
  Kind ok = body.getKind();
284
822862
  Kind k = ok;
285
822862
  bool negAllCh = false;
286
822862
  bool negCh1 = false;
287
822862
  if( ok==IMPLIES ){
288
11987
    k = OR;
289
11987
    negCh1 = true;
290
810875
  }else if( ok==XOR ){
291
745
    k = EQUAL;
292
745
    negCh1 = true;
293
810130
  }else if( ok==NOT ){
294
318175
    if( body[0].getKind()==NOT ){
295
      return computeElimSymbols( body[0][0] );
296
318175
    }else if( body[0].getKind()==OR || body[0].getKind()==IMPLIES ){
297
1685
      k = AND;
298
1685
      negAllCh = true;
299
1685
      negCh1 = body[0].getKind()==IMPLIES;
300
1685
      body = body[0];
301
316490
    }else if( body[0].getKind()==AND ){
302
5364
      k = OR;
303
5364
      negAllCh = true;
304
5364
      body = body[0];
305
311126
    }else if( body[0].getKind()==XOR || ( body[0].getKind()==EQUAL && body[0][0].getType().isBoolean() ) ){
306
2735
      k = EQUAL;
307
2735
      negCh1 = ( body[0].getKind()==EQUAL );
308
2735
      body = body[0];
309
308391
    }else if( body[0].getKind()==ITE ){
310
83
      k = body[0].getKind();
311
83
      negAllCh = true;
312
83
      negCh1 = true;
313
83
      body = body[0];
314
    }else{
315
308308
      return body;
316
    }
317
491955
  }else if( ( ok!=EQUAL || !body[0].getType().isBoolean() ) && ok!=ITE && ok!=AND && ok!=OR ){
318
    //a literal
319
296983
    return body;
320
  }
321
217571
  bool childrenChanged = false;
322
435142
  std::vector< Node > children;
323
435142
  std::map< Node, bool > lit_pol;
324
907670
  for( unsigned i=0; i<body.getNumChildren(); i++ ){
325
1380419
    Node c = computeElimSymbols( ( i==0 && negCh1 )!=negAllCh ? body[i].negate() : body[i] );
326
690320
    bool success = true;
327
690320
    if( c.getKind()==k && ( k==OR || k==AND ) ){
328
      //flatten
329
5386
      childrenChanged = true;
330
24706
      for( unsigned j=0; j<c.getNumChildren(); j++ ){
331
19321
        if( !addCheckElimChild( children, c[j], k, lit_pol, childrenChanged ) ){
332
1
          success = false;
333
1
          break;
334
        }
335
      }
336
    }else{
337
684934
      success = addCheckElimChild( children, c, k, lit_pol, childrenChanged );
338
    }
339
690320
    if( !success ){
340
      // tautology
341
221
      Assert(k == OR || k == AND);
342
221
      return NodeManager::currentNM()->mkConst( k==OR );
343
    }
344
690099
    childrenChanged = childrenChanged || c!=body[i];
345
  }
346
217350
  if( childrenChanged || k!=ok ){
347
26162
    return ( children.size()==1 && k!=NOT ) ? children[0] : NodeManager::currentNM()->mkNode( k, children );
348
  }else{
349
191188
    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
100827
Node QuantifiersRewriter::computeProcessTerms( Node body, std::vector< Node >& new_vars, std::vector< Node >& new_conds, Node q, QAttributes& qa ){
425
201654
  std::map< Node, Node > cache;
426
100827
  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
100827
  return computeProcessTerms2(body, cache, new_vars, new_conds);
443
}
444
445
2567209
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
2567209
  NodeManager* nm = NodeManager::currentNM();
451
5134418
  Trace("quantifiers-rewrite-term-debug2")
452
2567209
      << "computeProcessTerms " << body << std::endl;
453
2567209
  std::map< Node, Node >::iterator iti = cache.find( body );
454
2567209
  if( iti!=cache.end() ){
455
797664
    return iti->second;
456
  }
457
1769545
  bool changed = false;
458
3539090
  std::vector<Node> children;
459
4235927
  for (size_t i = 0; i < body.getNumChildren(); i++)
460
  {
461
    // do the recursive call on children
462
4932764
    Node nn = computeProcessTerms2(body[i], cache, new_vars, new_conds);
463
2466382
    children.push_back(nn);
464
2466382
    changed = changed || nn != body[i];
465
  }
466
467
  // make return value
468
3539090
  Node ret;
469
1769545
  if (changed)
470
  {
471
5197
    if (body.getMetaKind() == kind::metakind::PARAMETERIZED)
472
    {
473
190
      children.insert(children.begin(), body.getOperator());
474
    }
475
5197
    ret = nm->mkNode(body.getKind(), children);
476
  }
477
  else
478
  {
479
1764348
    ret = body;
480
  }
481
482
3539090
  Trace("quantifiers-rewrite-term-debug2")
483
1769545
      << "Returning " << ret << " for " << body << std::endl;
484
  // do context-independent rewriting
485
3539090
  if (ret.getKind() == EQUAL
486
1769545
      && options::iteLiftQuant() != options::IteLiftQuantMode::NONE)
487
  {
488
591340
    for (size_t i = 0; i < 2; i++)
489
    {
490
394640
      if (ret[i].getKind() == ITE)
491
      {
492
22630
        Node no = i == 0 ? ret[1] : ret[0];
493
11760
        if (no.getKind() != ITE)
494
        {
495
          bool doRewrite =
496
10442
              options::iteLiftQuant() == options::IteLiftQuantMode::ALL;
497
19994
          std::vector<Node> childrenIte;
498
10442
          childrenIte.push_back(ret[i][0]);
499
31326
          for (size_t j = 1; j <= 2; j++)
500
          {
501
            // check if it rewrites to a constant
502
41768
            Node nn = nm->mkNode(EQUAL, no, ret[i][j]);
503
20884
            nn = Rewriter::rewrite(nn);
504
20884
            childrenIte.push_back(nn);
505
20884
            if (nn.isConst())
506
            {
507
1244
              doRewrite = true;
508
            }
509
          }
510
10442
          if (doRewrite)
511
          {
512
890
            ret = nm->mkNode(ITE, childrenIte);
513
890
            break;
514
          }
515
        }
516
      }
517
    }
518
  }
519
1571955
  else if (ret.getKind() == SELECT && ret[0].getKind() == STORE)
520
  {
521
174
    Node st = ret[0];
522
174
    Node index = ret[1];
523
174
    std::vector<Node> iconds;
524
174
    std::vector<Node> elements;
525
573
    while (st.getKind() == STORE)
526
    {
527
243
      iconds.push_back(index.eqNode(st[1]));
528
243
      elements.push_back(st[2]);
529
243
      st = st[0];
530
    }
531
87
    ret = nm->mkNode(SELECT, st, index);
532
    // conditions
533
330
    for (int i = (iconds.size() - 1); i >= 0; i--)
534
    {
535
243
      ret = nm->mkNode(ITE, iconds[i], elements[i], ret);
536
    }
537
  }
538
1769545
  cache[body] = ret;
539
1769545
  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
99865
Node QuantifiersRewriter::computeCondSplit(Node body,
563
                                           const std::vector<Node>& args,
564
                                           QAttributes& qa)
565
{
566
99865
  NodeManager* nm = NodeManager::currentNM();
567
99865
  Kind bk = body.getKind();
568
200088
  if (options::iteDtTesterSplitQuant() && bk == ITE
569
199738
      && 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
314195
  if (!options::condVarSplitQuant())
586
  {
587
    return body;
588
  }
589
199730
  Trace("cond-var-split-debug")
590
99865
      << "Conditional var elim split " << body << "?" << std::endl;
591
592
99865
  if (bk == ITE
593
99997
      || (bk == EQUAL && body[0].getType().isBoolean()
594
41059
          && options::condVarSplitQuantAgg()))
595
  {
596
132
    Assert(!qa.isFunDef());
597
132
    bool do_split = false;
598
132
    unsigned index_max = bk == ITE ? 0 : 1;
599
240
    std::vector<Node> tmpArgs = args;
600
240
    for (unsigned index = 0; index <= index_max; index++)
601
    {
602
396
      if (hasVarElim(body[index], true, tmpArgs)
603
396
          || hasVarElim(body[index], false, tmpArgs))
604
      {
605
24
        do_split = true;
606
24
        break;
607
      }
608
    }
609
132
    if (do_split)
610
    {
611
48
      Node pos;
612
48
      Node neg;
613
24
      if (bk == ITE)
614
      {
615
24
        pos = nm->mkNode(OR, body[0].negate(), body[1]);
616
24
        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
48
      Trace("cond-var-split-debug") << "*** Split (conditional variable eq) "
624
24
                                    << body << " into : " << std::endl;
625
24
      Trace("cond-var-split-debug") << "   " << pos << std::endl;
626
24
      Trace("cond-var-split-debug") << "   " << neg << std::endl;
627
24
      return nm->mkNode(AND, pos, neg);
628
    }
629
  }
630
631
99841
  if (bk == OR)
632
  {
633
40385
    unsigned size = body.getNumChildren();
634
40385
    bool do_split = false;
635
40385
    unsigned split_index = 0;
636
162977
    for (unsigned i = 0; i < size; i++)
637
    {
638
      // check if this child is a (conditional) variable elimination
639
245323
      Node b = body[i];
640
122731
      if (b.getKind() == AND)
641
      {
642
13362
        std::vector<Node> vars;
643
13362
        std::vector<Node> subs;
644
13362
        std::vector<Node> tmpArgs = args;
645
26010
        for (unsigned j = 0, bsize = b.getNumChildren(); j < bsize; j++)
646
        {
647
19468
          if (getVarElimLit(b[j], false, tmpArgs, vars, subs))
648
          {
649
4638
            Trace("cond-var-split-debug") << "Variable elimination in child #"
650
2319
                                          << 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
2319
            if (options::condVarSplitQuantAgg() || size == 2)
655
            {
656
139
              do_split = true;
657
            }
658
            // other splitting criteria go here
659
660
2319
            if (do_split)
661
            {
662
139
              split_index = i;
663
139
              break;
664
            }
665
2180
            vars.clear();
666
2180
            subs.clear();
667
2180
            tmpArgs = args;
668
          }
669
        }
670
      }
671
122731
      if (do_split)
672
      {
673
139
        break;
674
      }
675
    }
676
40385
    if (do_split)
677
    {
678
278
      std::vector<Node> children;
679
417
      for (TNode bc : body)
680
      {
681
278
        children.push_back(bc);
682
      }
683
278
      std::vector<Node> split_children;
684
558
      for (TNode bci : body[split_index])
685
      {
686
419
        children[split_index] = bci;
687
419
        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
139
      return nm->mkNode(AND, split_children);
692
    }
693
  }
694
695
99702
  return body;
696
}
697
698
5682
bool QuantifiersRewriter::isVarElim(Node v, Node s)
699
{
700
5682
  Assert(v.getKind() == BOUND_VARIABLE);
701
5682
  return !expr::hasSubterm(s, v) && s.getType().isSubtypeOf(v.getType());
702
}
703
704
763
Node QuantifiersRewriter::getVarElimLitBv(Node lit,
705
                                          const std::vector<Node>& args,
706
                                          Node& var)
707
{
708
763
  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
763
  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
1526
  std::vector<Node> active_args;
722
763
  computeArgVec(args, active_args, lit);
723
724
1526
  BvInverter binv;
725
1628
  for (const Node& cvar : active_args)
726
  {
727
    // solve for the variable on this path using the inverter
728
1770
    std::vector<unsigned> path;
729
1770
    Node slit = binv.getPathToPv(lit, cvar, path);
730
905
    if (!slit.isNull())
731
    {
732
832
      Node slv = binv.solveBvLit(cvar, lit, path, nullptr);
733
436
      Trace("quant-velim-bv") << "...solution : " << slv << std::endl;
734
436
      if (!slv.isNull())
735
      {
736
68
        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
68
        if (isVarElim(var, slv))
741
        {
742
40
          return slv;
743
        }
744
      }
745
    }
746
    else
747
    {
748
469
      Trace("quant-velim-bv") << "...non-invertible path." << std::endl;
749
    }
750
  }
751
752
723
  return Node::null();
753
}
754
755
380
Node QuantifiersRewriter::getVarElimLitString(Node lit,
756
                                              const std::vector<Node>& args,
757
                                              Node& var)
758
{
759
380
  Assert(lit.getKind() == EQUAL);
760
380
  NodeManager* nm = NodeManager::currentNM();
761
1136
  for (unsigned i = 0; i < 2; i++)
762
  {
763
760
    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
376
  return Node::null();
800
}
801
802
210578
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
210578
  if (lit.getKind() == NOT)
809
  {
810
5603
    lit = lit[0];
811
5603
    pol = !pol;
812
5603
    Assert(lit.getKind() != NOT);
813
  }
814
210578
  NodeManager* nm = NodeManager::currentNM();
815
421156
  Trace("var-elim-quant-debug")
816
210578
      << "Eliminate : " << lit << ", pol = " << pol << "?" << std::endl;
817
421887
  if (lit.getKind() == APPLY_TESTER && pol && lit[0].getKind() == BOUND_VARIABLE
818
421230
      && 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
740705
  if (!options::varElimQuant())
851
  {
852
    return false;
853
  }
854
855
210541
  if (lit.getKind() == EQUAL)
856
  {
857
112709
    if (pol || lit[0].getType().isBoolean())
858
    {
859
168308
      for (unsigned i = 0; i < 2; i++)
860
      {
861
114213
        bool tpol = pol;
862
223356
        Node v_slv = lit[i];
863
114213
        if (v_slv.getKind() == NOT)
864
        {
865
5011
          v_slv = v_slv[0];
866
5011
          tpol = !tpol;
867
        }
868
        std::vector<Node>::iterator ita =
869
114213
            std::find(args.begin(), args.end(), v_slv);
870
114213
        if (ita != args.end())
871
        {
872
5351
          if (isVarElim(v_slv, lit[1 - i]))
873
          {
874
10140
            Node slv = lit[1 - i];
875
5070
            if (!tpol)
876
            {
877
89
              Assert(slv.getType().isBoolean());
878
89
              slv = slv.negate();
879
            }
880
10140
            Trace("var-elim-quant")
881
5070
                << "Variable eliminate based on equality : " << v_slv << " -> "
882
5070
                << slv << std::endl;
883
5070
            vars.push_back(v_slv);
884
5070
            subs.push_back(slv);
885
5070
            args.erase(ita);
886
5070
            return true;
887
          }
888
        }
889
      }
890
    }
891
  }
892
205471
  if (lit.getKind() == BOUND_VARIABLE)
893
  {
894
1435
    std::vector< Node >::iterator ita = std::find( args.begin(), args.end(), lit );
895
1435
    if( ita!=args.end() ){
896
1433
      Trace("var-elim-bool") << "Variable eliminate : " << lit << std::endl;
897
1433
      vars.push_back( lit );
898
1433
      subs.push_back( NodeManager::currentNM()->mkConst( pol ) );
899
1433
      args.erase( ita );
900
1433
      return true;
901
    }
902
  }
903
204038
  if (lit.getKind() == EQUAL && lit[0].getType().isReal() && pol)
904
  {
905
    // for arithmetic, solve the equality
906
22133
    std::map< Node, Node > msum;
907
11170
    if (ArithMSum::getMonomialSumLit(lit, msum))
908
    {
909
34149
      for( std::map< Node, Node >::iterator itm = msum.begin(); itm != msum.end(); ++itm ){
910
23186
        if( !itm->first.isNull() ){
911
19939
          std::vector< Node >::iterator ita = std::find( args.begin(), args.end(), itm->first );
912
19939
          if( ita!=args.end() ){
913
517
            Assert(pol);
914
827
            Node veq_c;
915
827
            Node val;
916
517
            int ires = ArithMSum::isolate(itm->first, msum, veq_c, val, EQUAL);
917
517
            if (ires != 0 && veq_c.isNull() && isVarElim(itm->first, val))
918
            {
919
414
              Trace("var-elim-quant")
920
207
                  << "Variable eliminate based on solved equality : "
921
207
                  << itm->first << " -> " << val << std::endl;
922
207
              vars.push_back(itm->first);
923
207
              subs.push_back(val);
924
207
              args.erase(ita);
925
207
              return true;
926
            }
927
          }
928
        }
929
      }
930
    }
931
  }
932
203831
  if (lit.getKind() == EQUAL && pol)
933
  {
934
67268
    Node var;
935
67268
    Node slv;
936
67268
    TypeNode tt = lit[0].getType();
937
33656
    if (tt.isBitVector())
938
    {
939
763
      slv = getVarElimLitBv(lit, args, var);
940
    }
941
32893
    else if (tt.isStringLike())
942
    {
943
380
      slv = getVarElimLitString(lit, args, var);
944
    }
945
33656
    if (!slv.isNull())
946
    {
947
44
      Assert(!var.isNull());
948
      std::vector<Node>::iterator ita =
949
44
          std::find(args.begin(), args.end(), var);
950
44
      Assert(ita != args.end());
951
88
      Trace("var-elim-quant")
952
44
          << "Variable eliminate based on theory-specific solving : " << var
953
44
          << " -> " << slv << std::endl;
954
44
      Assert(!expr::hasSubterm(slv, var));
955
44
      Assert(slv.getType().isSubtypeOf(var.getType()));
956
44
      vars.push_back(var);
957
44
      subs.push_back(slv);
958
44
      args.erase(ita);
959
44
      return true;
960
    }
961
  }
962
203787
  return false;
963
}
964
965
236029
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
236029
  Kind nk = n.getKind();
972
236029
  if (nk == NOT)
973
  {
974
86578
    n = n[0];
975
86578
    pol = !pol;
976
86578
    nk = n.getKind();
977
86578
    Assert(nk != NOT);
978
  }
979
236029
  if ((nk == AND && pol) || (nk == OR && !pol))
980
  {
981
172949
    for (const Node& cn : n)
982
    {
983
132167
      if (getVarElim(cn, pol, args, vars, subs))
984
      {
985
4137
        return true;
986
      }
987
    }
988
40782
    return false;
989
  }
990
191110
  return getVarElimLit(n, pol, args, vars, subs);
991
}
992
993
241
bool QuantifiersRewriter::hasVarElim(Node n, bool pol, std::vector<Node>& args)
994
{
995
482
  std::vector< Node > vars;
996
482
  std::vector< Node > subs;
997
482
  return getVarElim(n, pol, args, vars, subs);
998
}
999
1000
99069
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
198138
  std::map<Node, std::map<bool, std::map<Node, bool> > > num_bounds;
1008
198138
  QuantPhaseReq qpr(body);
1009
274301
  for (const std::pair<const Node, bool>& pr : qpr.d_phase_reqs)
1010
  {
1011
    // an inequality that is entailed with a given polarity
1012
193587
    Node lit = pr.first;
1013
175232
    if (lit.getKind() != GEQ)
1014
    {
1015
156877
      continue;
1016
    }
1017
18355
    bool pol = pr.second;
1018
36710
    Trace("var-elim-quant-debug") << "Process inequality bounds : " << lit
1019
18355
                                  << ", pol = " << pol << "..." << std::endl;
1020
    // solve the inequality
1021
36710
    std::map<Node, Node> msum;
1022
18355
    if (!ArithMSum::getMonomialSumLit(lit, msum))
1023
    {
1024
      // not an inequality, cannot use
1025
      continue;
1026
    }
1027
58916
    for (const std::pair<const Node, Node>& m : msum)
1028
    {
1029
40561
      if (!m.first.isNull())
1030
      {
1031
        std::vector<Node>::iterator ita =
1032
30242
            std::find(args.begin(), args.end(), m.first);
1033
30242
        if (ita != args.end())
1034
        {
1035
          // store that this literal is upper/lower bound for itm->first
1036
36900
          Node veq_c;
1037
36900
          Node val;
1038
          int ires =
1039
18450
              ArithMSum::isolate(m.first, msum, veq_c, val, lit.getKind());
1040
18450
          if (ires != 0 && veq_c.isNull())
1041
          {
1042
18124
            bool is_upper = pol != (ires == 1);
1043
36248
            Trace("var-elim-ineq-debug")
1044
18124
                << lit << " is a " << (is_upper ? "upper" : "lower")
1045
18124
                << " bound for " << m.first << std::endl;
1046
36248
            Trace("var-elim-ineq-debug")
1047
18124
                << "  pol/ires = " << pol << " " << ires << std::endl;
1048
18124
            num_bounds[m.first][is_upper][lit] = pol;
1049
          }
1050
          else
1051
          {
1052
652
            Trace("var-elim-ineq-debug")
1053
326
                << "...ineligible " << m.first
1054
326
                << " since it cannot be solved for (" << ires << ", " << veq_c
1055
326
                << ")." << std::endl;
1056
326
            num_bounds[m.first][true].clear();
1057
326
            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
23584
          std::unordered_set<Node> fvs;
1065
11792
          expr::getFreeVariables(m.first, fvs);
1066
21772
          for (const Node& v : fvs)
1067
          {
1068
19960
            Trace("var-elim-ineq-debug")
1069
9980
                << "...ineligible " << v
1070
9980
                << " since it is contained in monomial." << std::endl;
1071
9980
            num_bounds[v][true].clear();
1072
9980
            num_bounds[v][false].clear();
1073
          }
1074
        }
1075
      }
1076
    }
1077
  }
1078
1079
  // collect all variables that have only upper/lower bounds
1080
198138
  std::map<Node, bool> elig_vars;
1081
17382
  for (const std::pair<const Node, std::map<bool, std::map<Node, bool> > >& nb :
1082
99069
       num_bounds)
1083
  {
1084
17382
    if (nb.second.find(true) == nb.second.end())
1085
    {
1086
4960
      Trace("var-elim-ineq-debug")
1087
2480
          << "Variable " << nb.first << " has only lower bounds." << std::endl;
1088
2480
      elig_vars[nb.first] = false;
1089
    }
1090
14902
    else if (nb.second.find(false) == nb.second.end())
1091
    {
1092
3826
      Trace("var-elim-ineq-debug")
1093
1913
          << "Variable " << nb.first << " has only upper bounds." << std::endl;
1094
1913
      elig_vars[nb.first] = true;
1095
    }
1096
  }
1097
99069
  if (elig_vars.empty())
1098
  {
1099
95768
    return false;
1100
  }
1101
6602
  std::vector<Node> inactive_vars;
1102
6602
  std::map<Node, std::map<int, bool> > visited;
1103
6602
  std::map<Node, int> exclude;
1104
12539
  for (const std::pair<const Node, bool>& pr : qpr.d_phase_reqs)
1105
  {
1106
9238
    if (pr.first.getKind() == GEQ)
1107
    {
1108
5348
      exclude[pr.first] = pr.second ? -1 : 1;
1109
10696
      Trace("var-elim-ineq-debug")
1110
5348
          << "...exclude " << pr.first << " at polarity " << exclude[pr.first]
1111
5348
          << std::endl;
1112
    }
1113
  }
1114
  // traverse the body, invalidate variables if they occur in places other than
1115
  // the bounds they occur in
1116
6602
  std::unordered_map<TNode, std::unordered_set<int>> evisited;
1117
6602
  std::vector<TNode> evisit;
1118
6602
  std::vector<int> evisit_pol;
1119
6602
  TNode ecur;
1120
  int ecur_pol;
1121
3301
  evisit.push_back(body);
1122
3301
  evisit_pol.push_back(1);
1123
3301
  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
33952
  do
1130
  {
1131
37253
    ecur = evisit.back();
1132
37253
    evisit.pop_back();
1133
37253
    ecur_pol = evisit_pol.back();
1134
37253
    evisit_pol.pop_back();
1135
37253
    std::unordered_set<int>& epp = evisited[ecur];
1136
37253
    if (epp.find(ecur_pol) == epp.end())
1137
    {
1138
35050
      epp.insert(ecur_pol);
1139
35050
      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
4008
        elig_vars.erase(ecur);
1144
8016
        Trace("var-elim-ineq-debug") << "...found occurrence of " << ecur
1145
4008
                                     << ", mark ineligible" << std::endl;
1146
      }
1147
      else
1148
      {
1149
31042
        bool rec = true;
1150
31042
        bool pol = ecur_pol >= 0;
1151
31042
        bool hasPol = ecur_pol != 0;
1152
31042
        if (hasPol)
1153
        {
1154
14968
          std::map<Node, int>::iterator itx = exclude.find(ecur);
1155
14968
          if (itx != exclude.end() && itx->second == ecur_pol)
1156
          {
1157
            // already processed this literal as a bound
1158
2725
            rec = false;
1159
          }
1160
        }
1161
31042
        if (rec)
1162
        {
1163
73612
          for (unsigned j = 0, size = ecur.getNumChildren(); j < size; j++)
1164
          {
1165
            bool newHasPol;
1166
            bool newPol;
1167
45295
            QuantPhaseReq::getPolarity(ecur, j, hasPol, pol, newHasPol, newPol);
1168
45295
            evisit.push_back(ecur[j]);
1169
45295
            evisit_pol.push_back(newHasPol ? (newPol ? 1 : -1) : 0);
1170
          }
1171
        }
1172
      }
1173
    }
1174
37253
  } while (!evisit.empty() && !elig_vars.empty());
1175
1176
3301
  bool ret = false;
1177
3686
  for (const std::pair<const Node, bool>& ev : elig_vars)
1178
  {
1179
770
    Node v = ev.first;
1180
770
    Trace("var-elim-ineq-debug")
1181
385
        << 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
902
    for (const std::pair<const Node, bool>& nb : num_bounds[v][elig_vars[v]])
1185
    {
1186
1034
      Trace("var-elim-ineq-debug")
1187
517
          << "  subs : " << nb.first << " -> " << nb.second << std::endl;
1188
517
      bounds.push_back(nb.first);
1189
517
      subs.push_back(NodeManager::currentNM()->mkConst(nb.second));
1190
    }
1191
    // eliminate from args
1192
385
    std::vector<Node>::iterator ita = std::find(args.begin(), args.end(), v);
1193
385
    Assert(ita != args.end());
1194
385
    args.erase(ita);
1195
385
    ret = true;
1196
  }
1197
3301
  return ret;
1198
}
1199
1200
99479
Node QuantifiersRewriter::computeVarElimination( Node body, std::vector< Node >& args, QAttributes& qa ){
1201
198958
  if (!options::varElimQuant() && !options::dtVarExpandQuant()
1202
198603
      && !options::varIneqElimQuant())
1203
  {
1204
    return body;
1205
  }
1206
198958
  Node prev;
1207
306497
  while (prev != body && !args.empty())
1208
  {
1209
103509
    prev = body;
1210
1211
207018
    std::vector<Node> vars;
1212
207018
    std::vector<Node> subs;
1213
    // standard variable elimination
1214
103509
    if (options::varElimQuant())
1215
    {
1216
103509
      getVarElim(body, false, args, vars, subs);
1217
    }
1218
    // variable elimination based on one-direction inequalities
1219
103509
    if (vars.empty() && options::varIneqElimQuant())
1220
    {
1221
99069
      getVarElimIneq(body, args, vars, subs, qa);
1222
    }
1223
    // if we eliminated a variable, update body and reprocess
1224
103509
    if (!vars.empty())
1225
    {
1226
9484
      Trace("var-elim-quant-debug")
1227
4742
          << "VE " << vars.size() << "/" << args.size() << std::endl;
1228
4742
      Assert(vars.size() == subs.size());
1229
      // remake with eliminated nodes
1230
4742
      body =
1231
9484
          body.substitute(vars.begin(), vars.end(), subs.begin(), subs.end());
1232
4742
      body = Rewriter::rewrite(body);
1233
4742
      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
4742
      Trace("var-elim-quant") << "Return " << body << std::endl;
1239
    }
1240
  }
1241
99479
  return body;
1242
}
1243
1244
397491
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
397491
  NodeManager* nm = NodeManager::currentNM();
1252
397491
  Kind k = body.getKind();
1253
397491
  if (k == FORALL)
1254
  {
1255
14210
    if( ( pol || prenexAgg ) && ( options::prenexQuantUser() || body.getNumChildren()==2 ) ){
1256
2186
      std::vector< Node > terms;
1257
2186
      std::vector< Node > subs;
1258
1093
      BoundVarManager* bvm = nm->getBoundVarManager();
1259
      //for doing prenexing of same-signed quantifiers
1260
      //must rename each variable that already exists
1261
2815
      for (const Node& v : body[0])
1262
      {
1263
1722
        terms.push_back(v);
1264
3444
        TypeNode vt = v.getType();
1265
3444
        Node vv;
1266
1722
        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
3444
          Node cacheVal = BoundVarManager::getCacheValue(q, body, v);
1274
1722
          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
1722
        subs.push_back(vv);
1282
      }
1283
1093
      if (pol)
1284
      {
1285
1093
        args.insert(subs.begin(), subs.end());
1286
      }
1287
      else
1288
      {
1289
        nargs.insert(subs.begin(), subs.end());
1290
      }
1291
2186
      Node newBody = body[1];
1292
1093
      newBody = newBody.substitute( terms.begin(), terms.end(), subs.begin(), subs.end() );
1293
1093
      return newBody;
1294
    }
1295
  //must remove structure
1296
  }
1297
383281
  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
383281
  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
383281
  }else if( body.getType().isBoolean() ){
1311
383281
    Assert(k != EXISTS);
1312
383281
    bool childrenChanged = false;
1313
765504
    std::vector< Node > newChildren;
1314
1161646
    for (size_t i = 0, nchild = body.getNumChildren(); i < nchild; i++)
1315
    {
1316
      bool newHasPol;
1317
      bool newPol;
1318
778365
      QuantPhaseReq::getPolarity( body, i, true, pol, newHasPol, newPol );
1319
1258156
      if (!newHasPol)
1320
      {
1321
479791
        newChildren.push_back( body[i] );
1322
479791
        continue;
1323
      }
1324
597148
      Node n = computePrenex(q, body[i], args, nargs, newPol, prenexAgg);
1325
298574
      newChildren.push_back(n);
1326
298574
      childrenChanged = n != body[i] || childrenChanged;
1327
    }
1328
383281
    if( childrenChanged ){
1329
1058
      if (k == NOT && newChildren[0].getKind() == NOT)
1330
      {
1331
        return newChildren[0][0];
1332
      }
1333
1058
      return nm->mkNode(k, newChildren);
1334
    }
1335
  }
1336
395340
  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
41982
Node QuantifiersRewriter::computeSplit( std::vector< Node >& args, Node body, QAttributes& qa ) {
1426
41982
  Assert(body.getKind() == OR);
1427
41982
  size_t var_found_count = 0;
1428
41982
  size_t eqc_count = 0;
1429
41982
  size_t eqc_active = 0;
1430
83964
  std::map< Node, int > var_to_eqc;
1431
83964
  std::map< int, std::vector< Node > > eqc_to_var;
1432
83964
  std::map< int, std::vector< Node > > eqc_to_lit;
1433
1434
83964
  std::vector<Node> lits;
1435
1436
179294
  for( unsigned i=0; i<body.getNumChildren(); i++ ){
1437
    //get variables contained in the literal
1438
274624
    Node n = body[i];
1439
274624
    std::vector< Node > lit_args;
1440
137312
    computeArgVec( args, lit_args, n );
1441
137312
    if( lit_args.empty() ){
1442
1652
      lits.push_back( n );
1443
    }else {
1444
      //collect the equivalence classes this literal belongs to, and the new variables it contributes
1445
271320
      std::vector< int > eqcs;
1446
271320
      std::vector< Node > lit_new_args;
1447
      //for each variable in literal
1448
455627
      for( unsigned j=0; j<lit_args.size(); j++) {
1449
        //see if the variable has already been found
1450
319967
        if (var_to_eqc.find(lit_args[j])!=var_to_eqc.end()) {
1451
215775
          int eqc = var_to_eqc[lit_args[j]];
1452
215775
          if (std::find(eqcs.begin(), eqcs.end(), eqc)==eqcs.end()) {
1453
93410
            eqcs.push_back(eqc);
1454
          }
1455
        }else{
1456
104192
          var_found_count++;
1457
104192
          lit_new_args.push_back(lit_args[j]);
1458
        }
1459
      }
1460
135660
      if (eqcs.empty()) {
1461
47834
        eqcs.push_back(eqc_count);
1462
47834
        eqc_count++;
1463
47834
        eqc_active++;
1464
      }
1465
1466
135660
      int eqcz = eqcs[0];
1467
      //merge equivalence classes with eqcz
1468
141244
      for (unsigned j=1; j<eqcs.size(); j++) {
1469
5584
        int eqc = eqcs[j];
1470
        //move all variables from equivalence class
1471
29331
        for (unsigned k=0; k<eqc_to_var[eqc].size(); k++) {
1472
47494
          Node v = eqc_to_var[eqc][k];
1473
23747
          var_to_eqc[v] = eqcz;
1474
23747
          eqc_to_var[eqcz].push_back(v);
1475
        }
1476
5584
        eqc_to_var.erase(eqc);
1477
        //move all literals from equivalence class
1478
28072
        for (unsigned k=0; k<eqc_to_lit[eqc].size(); k++) {
1479
44976
          Node l = eqc_to_lit[eqc][k];
1480
22488
          eqc_to_lit[eqcz].push_back(l);
1481
        }
1482
5584
        eqc_to_lit.erase(eqc);
1483
5584
        eqc_active--;
1484
      }
1485
      //add variables to equivalence class
1486
239852
      for (unsigned j=0; j<lit_new_args.size(); j++) {
1487
104192
        var_to_eqc[lit_new_args[j]] = eqcz;
1488
104192
        eqc_to_var[eqcz].push_back(lit_new_args[j]);
1489
      }
1490
      //add literal to equivalence class
1491
135660
      eqc_to_lit[eqcz].push_back(n);
1492
    }
1493
  }
1494
41982
  if ( eqc_active>1 || !lits.empty() || var_to_eqc.size()!=args.size() ){
1495
604
    NodeManager* nm = NodeManager::currentNM();
1496
604
    Trace("clause-split-debug") << "Split quantified formula with body " << body << std::endl;
1497
604
    Trace("clause-split-debug") << "   Ground literals: " << std::endl;
1498
2256
    for( size_t i=0; i<lits.size(); i++) {
1499
1652
      Trace("clause-split-debug") << "      " << lits[i] << std::endl;
1500
    }
1501
604
    Trace("clause-split-debug") << std::endl;
1502
604
    Trace("clause-split-debug") << "Equivalence classes: " << std::endl;
1503
1476
    for (std::map< int, std::vector< Node > >::iterator it = eqc_to_lit.begin(); it != eqc_to_lit.end(); ++it ){
1504
872
      Trace("clause-split-debug") << "   Literals: " << std::endl;
1505
4051
      for (size_t i=0; i<it->second.size(); i++) {
1506
3179
        Trace("clause-split-debug") << "      " << it->second[i] << std::endl;
1507
      }
1508
872
      int eqc = it->first;
1509
872
      Trace("clause-split-debug") << "   Variables: " << std::endl;
1510
3682
      for (size_t i=0; i<eqc_to_var[eqc].size(); i++) {
1511
2810
        Trace("clause-split-debug") << "      " << eqc_to_var[eqc][i] << std::endl;
1512
      }
1513
872
      Trace("clause-split-debug") << std::endl;
1514
1744
      Node bvl = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, eqc_to_var[eqc]);
1515
      Node bd =
1516
1744
          it->second.size() == 1 ? it->second[0] : nm->mkNode(OR, it->second);
1517
1744
      Node fa = nm->mkNode(FORALL, bvl, bd);
1518
872
      lits.push_back(fa);
1519
    }
1520
604
    Assert(!lits.empty());
1521
1208
    Node nf = lits.size()==1 ? lits[0] : NodeManager::currentNM()->mkNode(OR,lits);
1522
604
    Trace("clause-split-debug") << "Made node : " << nf << std::endl;
1523
604
    return nf;
1524
  }else{
1525
41378
    return mkForAll( args, body, qa );
1526
  }
1527
}
1528
1529
101156
Node QuantifiersRewriter::mkForAll(const std::vector<Node>& args,
1530
                                   Node body,
1531
                                   QAttributes& qa)
1532
{
1533
101156
  if (args.empty())
1534
  {
1535
75
    return body;
1536
  }
1537
101081
  NodeManager* nm = NodeManager::currentNM();
1538
202162
  std::vector<Node> children;
1539
101081
  children.push_back(nm->mkNode(kind::BOUND_VAR_LIST, args));
1540
101081
  children.push_back(body);
1541
101081
  if (!qa.d_ipl.isNull())
1542
  {
1543
85
    children.push_back(qa.d_ipl);
1544
  }
1545
101081
  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
102375
Node QuantifiersRewriter::computeMiniscoping(Node q, QAttributes& qa)
1586
{
1587
102375
  NodeManager* nm = NodeManager::currentNM();
1588
204750
  std::vector<Node> args(q[0].begin(), q[0].end());
1589
204750
  Node body = q[1];
1590
102375
  if( body.getKind()==FORALL ){
1591
    //combine prenex
1592
174
    std::vector< Node > newArgs;
1593
87
    newArgs.insert(newArgs.end(), q[0].begin(), q[0].end());
1594
245
    for( unsigned i=0; i<body[0].getNumChildren(); i++ ){
1595
158
      newArgs.push_back( body[0][i] );
1596
    }
1597
87
    return mkForAll( newArgs, body[1], qa );
1598
102288
  }else if( body.getKind()==AND ){
1599
    // aggressive miniscoping implies that structural miniscoping should
1600
    // be applied first
1601
236823
    if (options::miniscopeQuant() || options::aggressiveMiniscopeQuant())
1602
    {
1603
625
      BoundVarManager* bvm = nm->getBoundVarManager();
1604
      // Break apart the quantifed formula
1605
      // forall x. P1 ^ ... ^ Pn ---> forall x. P1 ^ ... ^ forall x. Pn
1606
1250
      NodeBuilder t(kind::AND);
1607
1250
      std::vector<Node> argsc;
1608
3661
      for (size_t i = 0, nchild = body.getNumChildren(); i < nchild; i++)
1609
      {
1610
3036
        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
6152
          for (const Node& v : q[0])
1615
          {
1616
9232
            TypeNode vt = v.getType();
1617
9232
            Node cacheVal = BoundVarManager::getCacheValue(q, v, i);
1618
9232
            Node vv = bvm->mkBoundVar<QRewMiniscopeAttribute>(cacheVal, vt);
1619
4616
            argsc.push_back(vv);
1620
          }
1621
        }
1622
6072
        Node b = body[i];
1623
        Node bodyc =
1624
6072
            b.substitute(args.begin(), args.end(), argsc.begin(), argsc.end());
1625
3036
        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
1534
          t << b;
1630
        }
1631
        else
1632
        {
1633
          // make the miniscoped quantified formula
1634
3004
          Node cbvl = nm->mkNode(BOUND_VAR_LIST, argsc);
1635
3004
          Node qq = nm->mkNode(FORALL, cbvl, bodyc);
1636
1502
          t << qq;
1637
          // We used argsc, clear so we will construct a fresh copy above.
1638
1502
          argsc.clear();
1639
        }
1640
      }
1641
1250
      Node retVal = t;
1642
625
      return retVal;
1643
    }
1644
101050
  }else if( body.getKind()==OR ){
1645
43178
    if( options::quantSplit() ){
1646
      //splitting subsumes free variable miniscoping, apply it with higher priority
1647
41982
      return computeSplit( args, body, qa );
1648
    }
1649
2392
    else if (options::miniscopeQuantFreeVar()
1650
1196
             || 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
57872
  }else if( body.getKind()==NOT ){
1677
15674
    Assert(isLiteral(body[0]));
1678
  }
1679
  //remove variables that don't occur
1680
119354
  std::vector< Node > activeArgs;
1681
59677
  computeArgVec2( args, activeArgs, body, qa.d_ipl );
1682
59677
  return mkForAll( activeArgs, body, qa );
1683
}
1684
1685
10
Node QuantifiersRewriter::computeAggressiveMiniscoping( std::vector< Node >& args, Node body ){
1686
20
  std::map<Node, std::vector<Node> > varLits;
1687
20
  std::map<Node, std::vector<Node> > litVars;
1688
10
  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
20
  QAttributes qa;
1791
10
  return mkForAll( args, body, qa );
1792
}
1793
1794
955049
bool QuantifiersRewriter::doOperation(Node q,
1795
                                      RewriteStep computeOption,
1796
                                      QAttributes& qa)
1797
{
1798
  bool is_strict_trigger =
1799
955049
      qa.d_hasPattern
1800
955049
      && options::userPatternsQuant() == options::UserPatMode::TRUST;
1801
955049
  bool is_std = qa.isStandard() && !is_strict_trigger;
1802
955049
  if (computeOption == COMPUTE_ELIM_SYMBOLS)
1803
  {
1804
132542
    return true;
1805
  }
1806
822507
  else if (computeOption == COMPUTE_MINISCOPING)
1807
  {
1808
119531
    return is_std;
1809
  }
1810
702976
  else if (computeOption == COMPUTE_AGGRESSIVE_MINISCOPING)
1811
  {
1812
117995
    return options::aggressiveMiniscopeQuant() && is_std;
1813
  }
1814
584981
  else if (computeOption == COMPUTE_EXT_REWRITE)
1815
  {
1816
236001
    return options::extRewriteQuant();
1817
  }
1818
466986
  else if (computeOption == COMPUTE_PROCESS_TERMS)
1819
  {
1820
117983
    return is_std && options::iteLiftQuant() != options::IteLiftQuantMode::NONE;
1821
  }
1822
349003
  else if (computeOption == COMPUTE_COND_SPLIT)
1823
  {
1824
229288
    return (options::iteDtTesterSplitQuant() || options::condVarSplitQuant())
1825
229646
           && !is_strict_trigger;
1826
  }
1827
234180
  else if (computeOption == COMPUTE_PRENEX)
1828
  {
1829
117545
    return options::prenexQuant() != options::PrenexQuantMode::NONE
1830
117545
           && !options::aggressiveMiniscopeQuant() && is_std;
1831
  }
1832
116635
  else if (computeOption == COMPUTE_VAR_ELIMINATION)
1833
  {
1834
116635
    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
634047
Node QuantifiersRewriter::computeOperation(Node f,
1844
                                           RewriteStep computeOption,
1845
                                           QAttributes& qa)
1846
{
1847
634047
  Trace("quantifiers-rewrite-debug") << "Compute operation " << computeOption << " on " << f << " " << qa.d_qid_num << std::endl;
1848
634047
  if (computeOption == COMPUTE_MINISCOPING)
1849
  {
1850
102375
    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
102375
    return computeMiniscoping(f, qa);
1859
  }
1860
1063344
  std::vector<Node> args(f[0].begin(), f[0].end());
1861
1063344
  Node n = f[1];
1862
531672
  if (computeOption == COMPUTE_ELIM_SYMBOLS)
1863
  {
1864
132542
    n = computeElimSymbols(n);
1865
399130
  }else if( computeOption==COMPUTE_AGGRESSIVE_MINISCOPING ){
1866
10
    return computeAggressiveMiniscoping( args, n );
1867
  }
1868
399120
  else if (computeOption == COMPUTE_EXT_REWRITE)
1869
  {
1870
32
    return computeExtendedRewrite(f);
1871
  }
1872
399088
  else if (computeOption == COMPUTE_PROCESS_TERMS)
1873
  {
1874
201654
    std::vector< Node > new_conds;
1875
100827
    n = computeProcessTerms( n, args, new_conds, f, qa );
1876
100827
    if( !new_conds.empty() ){
1877
      new_conds.push_back( n );
1878
      n = NodeManager::currentNM()->mkNode( OR, new_conds );
1879
    }
1880
  }
1881
298261
  else if (computeOption == COMPUTE_COND_SPLIT)
1882
  {
1883
99865
    n = computeCondSplit(n, args, qa);
1884
  }
1885
198396
  else if (computeOption == COMPUTE_PRENEX)
1886
  {
1887
98917
    if (options::prenexQuant() == options::PrenexQuantMode::NORMAL)
1888
    {
1889
      //will rewrite at preprocess time
1890
      return f;
1891
    }
1892
    else
1893
    {
1894
197834
      std::unordered_set<Node> argsSet, nargsSet;
1895
98917
      n = computePrenex(f, n, argsSet, nargsSet, true, false);
1896
98917
      Assert(nargsSet.empty());
1897
98917
      args.insert(args.end(), argsSet.begin(), argsSet.end());
1898
    }
1899
  }
1900
99479
  else if (computeOption == COMPUTE_VAR_ELIMINATION)
1901
  {
1902
99479
    n = computeVarElimination( n, args, qa );
1903
  }
1904
531630
  Trace("quantifiers-rewrite-debug") << "Compute Operation: return " << n << ", " << args.size() << std::endl;
1905
531630
  if( f[1]==n && args.size()==f[0].getNumChildren() ){
1906
515296
    return f;
1907
  }else{
1908
16334
    if( args.empty() ){
1909
712
      return n;
1910
    }else{
1911
31244
      std::vector< Node > children;
1912
15622
      children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, args ) );
1913
15622
      children.push_back( n );
1914
15622
      if( !qa.d_ipl.isNull() && args.size()==f[0].getNumChildren() ){
1915
1833
        children.push_back( qa.d_ipl );
1916
      }
1917
15622
      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
811
Node QuantifiersRewriter::preSkolemizeQuantifiers( Node n, bool polarity, std::vector< TypeNode >& fvTypes, std::vector< TNode >& fvs ){
1933
811
  Trace("pre-sk") << "Pre-skolem " << n << " " << polarity << " " << fvs.size() << endl;
1934
811
  if( n.getKind()==kind::NOT ){
1935
252
    Node nn = preSkolemizeQuantifiers( n[0], !polarity, fvTypes, fvs );
1936
126
    return nn.negate();
1937
685
  }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
503
    if (expr::hasClosure(n))
1979
    {
1980
88
      if( ( n.getKind()==kind::ITE && n.getType().isBoolean() ) || ( n.getKind()==kind::EQUAL && n[0].getType().isBoolean() ) ){
1981
28
        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
74
      }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
449
  return n;
2005
}
2006
2007
90330
TrustNode QuantifiersRewriter::preprocess(Node n, bool isInst)
2008
{
2009
180660
  Node prev = n;
2010
2011
90330
  if( options::preSkolemQuant() ){
2012
547
    if( !isInst || !options::preSkolemQuantNested() ){
2013
481
      Trace("quantifiers-preprocess-debug") << "Pre-skolemize " << n << "..." << std::endl;
2014
      //apply pre-skolemization to existential quantifiers
2015
962
      std::vector< TypeNode > fvTypes;
2016
962
      std::vector< TNode > fvs;
2017
481
      n = preSkolemizeQuantifiers( prev, true, fvTypes, fvs );
2018
    }
2019
  }
2020
  //pull all quantifiers globally
2021
90330
  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
90330
  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
90314
  return TrustNode::null();
2036
}
2037
2038
}  // namespace quantifiers
2039
}  // namespace theory
2040
1809307
}  // namespace cvc5