GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/quantifiers_rewriter.cpp Lines: 866 1077 80.4 %
Date: 2021-09-15 Branches: 1873 4387 42.7 %

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