GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/cegqi/inst_strategy_cegqi.cpp Lines: 263 281 93.6 %
Date: 2021-11-07 Branches: 465 972 47.8 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Morgan Deters, Aina Niemetz
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 counterexample-guided quantifier instantiation strategies.
14
 */
15
#include "theory/quantifiers/cegqi/inst_strategy_cegqi.h"
16
17
#include "expr/node_algorithm.h"
18
#include "expr/skolem_manager.h"
19
#include "options/quantifiers_options.h"
20
#include "theory/quantifiers/first_order_model.h"
21
#include "theory/quantifiers/instantiate.h"
22
#include "theory/quantifiers/quantifiers_attributes.h"
23
#include "theory/quantifiers/quantifiers_rewriter.h"
24
#include "theory/quantifiers/term_database.h"
25
#include "theory/quantifiers/term_registry.h"
26
#include "theory/quantifiers/term_util.h"
27
#include "theory/rewriter.h"
28
#include "util/rational.h"
29
30
using namespace std;
31
using namespace cvc5::kind;
32
using namespace cvc5::context;
33
34
namespace cvc5 {
35
namespace theory {
36
namespace quantifiers {
37
38
12031
InstRewriterCegqi::InstRewriterCegqi(InstStrategyCegqi* p)
39
12031
    : InstantiationRewriter(), d_parent(p)
40
{
41
12031
}
42
43
52236
TrustNode InstRewriterCegqi::rewriteInstantiation(
44
    Node q, const std::vector<Node>& terms, Node inst, bool doVts)
45
{
46
52236
  return d_parent->rewriteInstantiation(q, terms, inst, doVts);
47
}
48
49
12031
InstStrategyCegqi::InstStrategyCegqi(Env& env,
50
                                     QuantifiersState& qs,
51
                                     QuantifiersInferenceManager& qim,
52
                                     QuantifiersRegistry& qr,
53
12031
                                     TermRegistry& tr)
54
    : QuantifiersModule(env, qs, qim, qr, tr),
55
12031
      d_irew(new InstRewriterCegqi(this)),
56
      d_cbqi_set_quant_inactive(false),
57
      d_incomplete_check(false),
58
12031
      d_added_cbqi_lemma(userContext()),
59
12031
      d_vtsCache(new VtsTermCache(qim)),
60
      d_bv_invert(nullptr),
61
      d_small_const_multiplier(
62
24062
          NodeManager::currentNM()->mkConst(Rational(1) / Rational(1000000))),
63
72186
      d_small_const(d_small_const_multiplier)
64
{
65
12031
  d_check_vts_lemma_lc = false;
66
12031
  if (options().quantifiers.cegqiBv)
67
  {
68
    // if doing instantiation for BV, need the inverter class
69
9396
    d_bv_invert.reset(new BvInverter);
70
  }
71
12031
  if (options().quantifiers.cegqiNestedQE)
72
  {
73
30
    d_nestedQe.reset(new NestedQe(d_env));
74
  }
75
12031
}
76
77
24052
InstStrategyCegqi::~InstStrategyCegqi() {}
78
79
90476
bool InstStrategyCegqi::needsCheck(Theory::Effort e)
80
{
81
90476
  return e>=Theory::EFFORT_LAST_CALL;
82
}
83
84
17656
QuantifiersModule::QEffort InstStrategyCegqi::needsModel(Theory::Effort e)
85
{
86
17656
  size_t nquant = d_treg.getModel()->getNumAssertedQuantifiers();
87
59831
  for (size_t i = 0; i < nquant; i++)
88
  {
89
88691
    Node q = d_treg.getModel()->getAssertedQuantifier(i);
90
46516
    if (doCbqi(q))
91
    {
92
4341
      return QEFFORT_STANDARD;
93
    }
94
  }
95
13315
  return QEFFORT_NONE;
96
}
97
98
2103
bool InstStrategyCegqi::registerCbqiLemma(Node q)
99
{
100
2103
  if( !hasAddedCbqiLemma( q ) ){
101
1933
    NodeManager* nm = NodeManager::currentNM();
102
1933
    d_added_cbqi_lemma.insert( q );
103
1933
    Trace("cegqi-debug") << "Do cbqi for " << q << std::endl;
104
    //add cbqi lemma
105
    //get the counterexample literal
106
3866
    Node ceLit = getCounterexampleLiteral(q);
107
3866
    Node ceBody = d_qreg.getInstConstantBody(q);
108
1933
    if( !ceBody.isNull() ){
109
      //add counterexample lemma
110
3866
      Node lem = NodeManager::currentNM()->mkNode( OR, ceLit.negate(), ceBody.negate() );
111
      //require any decision on cel to be phase=true
112
1933
      d_qim.addPendingPhaseRequirement(ceLit, true);
113
1933
      Debug("cegqi-debug") << "Require phase " << ceLit << " = true." << std::endl;
114
      //add counterexample lemma
115
1933
      lem = rewrite(lem);
116
1933
      Trace("cegqi-lemma") << "Counterexample lemma : " << lem << std::endl;
117
1934
      registerCounterexampleLemma( q, lem );
118
119
      //compute dependencies between quantified formulas
120
3864
      std::vector<Node> ics;
121
1932
      TermUtil::computeInstConstContains(q, ics);
122
1932
      d_parent_quant[q].clear();
123
1932
      d_children_quant[q].clear();
124
3864
      std::vector<Node> dep;
125
2382
      for (const Node& ic : ics)
126
      {
127
900
        Node qi = ic.getAttribute(InstConstantAttribute());
128
1350
        if (std::find(d_parent_quant[q].begin(), d_parent_quant[q].end(), qi)
129
1350
            == d_parent_quant[q].end())
130
        {
131
280
          d_parent_quant[q].push_back(qi);
132
280
          d_children_quant[qi].push_back(q);
133
          // may not have added the CEX lemma, but the literal is created by
134
          // the following call regardless. One rare case where this can happen
135
          // is if both sygus-inst and CEGQI are being run in parallel, and
136
          // a parent quantified formula is not handled by CEGQI, but a child
137
          // is.
138
560
          Node qicel = getCounterexampleLiteral(qi);
139
280
          dep.push_back(qi);
140
280
          dep.push_back(qicel);
141
        }
142
      }
143
1932
      if (!dep.empty())
144
      {
145
        // This lemma states that if the child is active, then the parent must
146
        // be asserted, in particular G => Q where G is the CEX literal for the
147
        // child and Q is the parent.
148
392
        Node dep_lemma = nm->mkNode(IMPLIES, ceLit, nm->mkNode(AND, dep));
149
392
        Trace("cegqi-lemma")
150
196
            << "Counterexample dependency lemma : " << dep_lemma << std::endl;
151
196
        d_qim.lemma(dep_lemma, InferenceId::QUANTIFIERS_CEGQI_CEX_DEP);
152
      }
153
154
      //must register all sub-quantifiers of counterexample lemma, register their lemmas
155
3864
      std::vector< Node > quants;
156
1932
      TermUtil::computeQuantContains( lem, quants );
157
2106
      for( unsigned i=0; i<quants.size(); i++ ){
158
174
        if( doCbqi( quants[i] ) ){
159
170
          registerCbqiLemma( quants[i] );
160
        }
161
      }
162
    }
163
    // The decision strategy for this quantified formula ensures that its
164
    // counterexample literal is decided on first. It is user-context dependent.
165
    std::map<Node, std::unique_ptr<DecisionStrategy>>::iterator itds =
166
1932
        d_dstrat.find(q);
167
1932
    DecisionStrategy* dlds = nullptr;
168
1932
    if (itds == d_dstrat.end())
169
    {
170
5796
      d_dstrat[q].reset(new DecisionStrategySingleton(
171
3864
          d_env, "CexLiteral", ceLit, d_qstate.getValuation()));
172
1932
      dlds = d_dstrat[q].get();
173
    }
174
    else
175
    {
176
      dlds = itds->second.get();
177
    }
178
    // it is appended to the list of strategies
179
1932
    d_qim.getDecisionManager()->registerStrategy(
180
        DecisionManager::STRAT_QUANT_CEGQI_FEASIBLE, dlds);
181
1932
    return true;
182
  }else{
183
170
    return false;
184
  }
185
}
186
187
34062
void InstStrategyCegqi::reset_round(Theory::Effort effort)
188
{
189
34062
  d_cbqi_set_quant_inactive = false;
190
34062
  d_incomplete_check = false;
191
34062
  d_active_quant.clear();
192
  //check if any cbqi lemma has not been added yet
193
34062
  FirstOrderModel* fm = d_treg.getModel();
194
34062
  size_t nquant = fm->getNumAssertedQuantifiers();
195
273776
  for (size_t i = 0; i < nquant; i++)
196
  {
197
479428
    Node q = fm->getAssertedQuantifier(i);
198
    //it is not active if it corresponds to a rewrite rule: we will process in rewrite engine
199
239714
    if( doCbqi( q ) ){
200
9545
      if (fm->isQuantifierActive(q))
201
      {
202
9545
        d_active_quant[q] = true;
203
9545
        Debug("cegqi-debug") << "Check quantified formula " << q << "..." << std::endl;
204
19090
        Node cel = getCounterexampleLiteral(q);
205
        bool value;
206
9545
        if (d_qstate.getValuation().hasSatValue(cel, value))
207
        {
208
9521
          Debug("cegqi-debug") << "...CE Literal has value " << value << std::endl;
209
9521
          if( !value ){
210
1456
            if (d_qstate.getValuation().isDecision(cel))
211
            {
212
              Trace("cegqi-warn") << "CBQI WARNING: Bad decision on CE Literal." << std::endl;
213
            }else{
214
1456
              Trace("cegqi") << "Inactive : " << q << std::endl;
215
1456
              fm->setQuantifierActive(q, false);
216
1456
              d_cbqi_set_quant_inactive = true;
217
1456
              d_active_quant.erase( q );
218
            }
219
          }
220
        }else{
221
24
          Debug("cegqi-debug") << "...CE Literal does not have value " << std::endl;
222
        }
223
      }
224
    }
225
  }
226
227
  //refinement: only consider innermost active quantified formulas
228
34062
  if (options().quantifiers.cegqiInnermost)
229
  {
230
34062
    if( !d_children_quant.empty() && !d_active_quant.empty() ){
231
6747
      Trace("cegqi-debug") << "Find non-innermost quantifiers..." << std::endl;
232
13494
      std::vector< Node > ninner;
233
14816
      for( std::map< Node, bool >::iterator it = d_active_quant.begin(); it != d_active_quant.end(); ++it ){
234
8069
        std::map< Node, std::vector< Node > >::iterator itc = d_children_quant.find( it->first );
235
8069
        if( itc!=d_children_quant.end() ){
236
8371
          for( unsigned j=0; j<itc->second.size(); j++ ){
237
492
            if( d_active_quant.find( itc->second[j] )!=d_active_quant.end() ){
238
186
              Trace("cegqi-debug") << "Do not consider " << it->first << " since it is not innermost (" << itc->second[j] << std::endl;
239
186
              ninner.push_back( it->first );
240
186
              break;
241
            }
242
          }
243
        }
244
      }
245
6747
      Trace("cegqi-debug") << "Found " << ninner.size() << " non-innermost." << std::endl;
246
6933
      for( unsigned i=0; i<ninner.size(); i++ ){
247
186
        Assert(d_active_quant.find(ninner[i]) != d_active_quant.end());
248
186
        d_active_quant.erase( ninner[i] );
249
      }
250
6747
      Assert(!d_active_quant.empty());
251
6747
      Trace("cegqi-debug") << "...done removing." << std::endl;
252
    }
253
  }
254
34062
  d_check_vts_lemma_lc = false;
255
34062
}
256
257
52765
void InstStrategyCegqi::check(Theory::Effort e, QEffort quant_e)
258
{
259
52765
  if (quant_e == QEFFORT_STANDARD)
260
  {
261
17596
    Assert(!d_qstate.isInConflict());
262
17596
    double clSet = 0;
263
17596
    if( Trace.isOn("cegqi-engine") ){
264
      clSet = double(clock())/double(CLOCKS_PER_SEC);
265
      Trace("cegqi-engine") << "---Cbqi Engine Round, effort = " << e << "---" << std::endl;
266
    }
267
17596
    size_t lastWaiting = d_qim.numPendingLemmas();
268
44582
    for( int ee=0; ee<=1; ee++ ){
269
      //for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
270
      //  Node q = d_quantEngine->getModel()->getAssertedQuantifier( i );
271
      //  if( doCbqi( q ) && d_quantEngine->getModel()->isQuantifierActive( q ) ){
272
36172
      for( std::map< Node, bool >::iterator it = d_active_quant.begin(); it != d_active_quant.end(); ++it ){
273
10166
        Node q = it->first;
274
5083
        Trace("cegqi") << "CBQI : Process quantifier " << q[0] << " at effort " << ee << std::endl;
275
5083
        process(q, e, ee);
276
5083
        if (d_qstate.isInConflict())
277
        {
278
          break;
279
        }
280
      }
281
31089
      if (d_qstate.isInConflict() || d_qim.numPendingLemmas() > lastWaiting)
282
      {
283
4103
        break;
284
      }
285
    }
286
17596
    if( Trace.isOn("cegqi-engine") ){
287
      if (d_qim.numPendingLemmas() > lastWaiting)
288
      {
289
        Trace("cegqi-engine")
290
            << "Added lemmas = " << (d_qim.numPendingLemmas() - lastWaiting)
291
            << std::endl;
292
      }
293
      double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
294
      Trace("cegqi-engine") << "Finished cbqi engine, time = " << (clSet2-clSet) << std::endl;
295
    }
296
  }
297
52765
}
298
299
5481
bool InstStrategyCegqi::checkComplete(IncompleteId& incId)
300
{
301
10962
  if ((!options().quantifiers.cegqiSat && d_cbqi_set_quant_inactive)
302
10962
      || d_incomplete_check)
303
  {
304
64
    incId = IncompleteId::QUANTIFIERS_CEGQI;
305
64
    return false;
306
  }
307
  else
308
  {
309
5417
    return true;
310
  }
311
}
312
313
1516
bool InstStrategyCegqi::checkCompleteFor(Node q)
314
{
315
1516
  std::map<Node, CegHandledStatus>::iterator it = d_do_cbqi.find(q);
316
1516
  if( it!=d_do_cbqi.end() ){
317
1516
    return it->second != CEG_UNHANDLED;
318
  }else{
319
    return false;
320
  }
321
}
322
323
24331
void InstStrategyCegqi::checkOwnership(Node q)
324
{
325
24331
  if (d_qreg.getOwner(q) == nullptr && doCbqi(q))
326
  {
327
1951
    if (d_do_cbqi[q] == CEG_HANDLED)
328
    {
329
      //take full ownership of the quantified formula
330
1934
      d_qreg.setOwner(q, this);
331
    }
332
  }
333
24331
}
334
335
24369
void InstStrategyCegqi::preRegisterQuantifier(Node q)
336
{
337
24369
  if (doCbqi(q))
338
  {
339
1951
    if (processNestedQe(q, true))
340
    {
341
      // will process using nested quantifier elimination
342
18
      return;
343
    }
344
    // register the cbqi lemma
345
1934
    if( registerCbqiLemma( q ) ){
346
1762
      Trace("cegqi") << "Registered cbqi lemma for quantifier : " << q << std::endl;
347
    }
348
  }
349
}
350
52236
TrustNode InstStrategyCegqi::rewriteInstantiation(
351
    Node q, const std::vector<Node>& terms, Node inst, bool doVts)
352
{
353
104472
  Node prevInst = inst;
354
52236
  if (doVts)
355
  {
356
    // do virtual term substitution
357
77
    inst = rewrite(inst);
358
77
    Trace("quant-vts-debug") << "Rewrite vts symbols in " << inst << std::endl;
359
77
    inst = d_vtsCache->rewriteVtsSymbols(inst);
360
77
    Trace("quant-vts-debug") << "...got " << inst << std::endl;
361
  }
362
52236
  if (prevInst != inst)
363
  {
364
    // not proof producing yet
365
77
    return TrustNode::mkTrustRewrite(prevInst, inst, nullptr);
366
  }
367
52159
  return TrustNode::null();
368
}
369
370
12031
InstantiationRewriter* InstStrategyCegqi::getInstRewriter() const
371
{
372
12031
  return d_irew.get();
373
}
374
375
1933
void InstStrategyCegqi::registerCounterexampleLemma(Node q, Node lem)
376
{
377
  // must register with the instantiator
378
  // must explicitly remove ITEs so that we record dependencies
379
3866
  std::vector<Node> ce_vars;
380
5905
  for (size_t i = 0, nics = d_qreg.getNumInstantiationConstants(q); i < nics;
381
       i++)
382
  {
383
3972
    ce_vars.push_back(d_qreg.getInstantiationConstant(q, i));
384
  }
385
  // send the lemma
386
1934
  d_qim.lemma(lem, InferenceId::QUANTIFIERS_CEGQI_CEX);
387
  // get the preprocessed form of the lemma we just sent
388
3864
  std::vector<Node> skolems;
389
3864
  std::vector<Node> skAsserts;
390
  Node ppLem =
391
3864
      d_qstate.getValuation().getPreprocessedTerm(lem, skAsserts, skolems);
392
3864
  std::vector<Node> lemp{ppLem};
393
1932
  lemp.insert(lemp.end(), skAsserts.begin(), skAsserts.end());
394
1932
  ppLem = NodeManager::currentNM()->mkAnd(lemp);
395
3864
  Trace("cegqi-debug") << "Counterexample lemma (post-preprocess): " << ppLem
396
1932
                       << std::endl;
397
3864
  std::vector<Node> auxLems;
398
1932
  CegInstantiator* cinst = getInstantiator(q);
399
1932
  cinst->registerCounterexampleLemma(ppLem, ce_vars, auxLems);
400
2071
  for (size_t i = 0, size = auxLems.size(); i < size; i++)
401
  {
402
278
    Trace("cegqi-debug") << "Auxiliary CE lemma " << i << " : " << auxLems[i]
403
139
                         << std::endl;
404
139
    d_qim.addPendingLemma(auxLems[i], InferenceId::QUANTIFIERS_CEGQI_CEX_AUX);
405
  }
406
1932
}
407
408
335104
bool InstStrategyCegqi::doCbqi(Node q)
409
{
410
335104
  std::map<Node, CegHandledStatus>::iterator it = d_do_cbqi.find(q);
411
335104
  if( it==d_do_cbqi.end() ){
412
24331
    CegHandledStatus ret = CegInstantiator::isCbqiQuant(q);
413
24331
    Trace("cegqi-quant") << "doCbqi " << q << " returned " << ret << std::endl;
414
24331
    d_do_cbqi[q] = ret;
415
24331
    return ret != CEG_UNHANDLED;
416
  }
417
310773
  return it->second != CEG_UNHANDLED;
418
}
419
420
5083
void InstStrategyCegqi::process( Node q, Theory::Effort effort, int e ) {
421
  // If we are doing nested quantifier elimination, check if q was already
422
  // processed.
423
5083
  if (processNestedQe(q, false))
424
  {
425
    // don't need to process this, since it has been reduced
426
26
    return;
427
  }
428
5057
  if( e==0 ){
429
4760
    CegInstantiator * cinst = getInstantiator( q );
430
4760
    Trace("inst-alg") << "-> Run cegqi for " << q << std::endl;
431
4760
    d_curr_quant = q;
432
4760
    if( !cinst->check() ){
433
300
      d_incomplete_check = true;
434
300
      d_check_vts_lemma_lc = true;
435
    }
436
4760
    d_curr_quant = Node::null();
437
297
  }else if( e==1 ){
438
    //minimize the free delta heuristically on demand
439
297
    if( d_check_vts_lemma_lc ){
440
83
      Trace("inst-alg") << "-> Minimize delta heuristic, for " << q << std::endl;
441
83
      d_check_vts_lemma_lc = false;
442
166
      d_small_const = NodeManager::currentNM()->mkNode(
443
83
          MULT, d_small_const, d_small_const_multiplier);
444
83
      d_small_const = rewrite(d_small_const);
445
      //heuristic for now, until we know how to do nested quantification
446
166
      Node delta = d_vtsCache->getVtsDelta(true, false);
447
83
      if( !delta.isNull() ){
448
        Trace("quant-vts-debug") << "Delta lemma for " << d_small_const << std::endl;
449
        Node delta_lem_ub = NodeManager::currentNM()->mkNode( LT, delta, d_small_const );
450
        d_qim.lemma(delta_lem_ub, InferenceId::QUANTIFIERS_CEGQI_VTS_UB_DELTA);
451
      }
452
166
      std::vector< Node > inf;
453
83
      d_vtsCache->getVtsTerms(inf, true, false, false);
454
83
      for( unsigned i=0; i<inf.size(); i++ ){
455
        Trace("quant-vts-debug") << "Infinity lemma for " << inf[i] << " " << d_small_const << std::endl;
456
        Node inf_lem_lb = NodeManager::currentNM()->mkNode( GT, inf[i], NodeManager::currentNM()->mkConst( Rational(1)/d_small_const.getConst<Rational>() ) );
457
        d_qim.lemma(inf_lem_lb, InferenceId::QUANTIFIERS_CEGQI_VTS_LB_INF);
458
      }
459
    }
460
  }
461
}
462
463
11758
Node InstStrategyCegqi::getCounterexampleLiteral(Node q)
464
{
465
11758
  std::map<Node, Node>::iterator it = d_ce_lit.find(q);
466
11758
  if (it != d_ce_lit.end())
467
  {
468
9811
    return it->second;
469
  }
470
1947
  NodeManager * nm = NodeManager::currentNM();
471
1947
  SkolemManager* sm = nm->getSkolemManager();
472
3894
  Node g = sm->mkDummySkolem("g", nm->booleanType());
473
  // ensure that it is a SAT literal
474
3894
  Node ceLit = d_qstate.getValuation().ensureLiteral(g);
475
1947
  d_ce_lit[q] = ceLit;
476
1947
  return ceLit;
477
}
478
479
5952
bool InstStrategyCegqi::doAddInstantiation( std::vector< Node >& subs ) {
480
5952
  Assert(!d_curr_quant.isNull());
481
  // check if we need virtual term substitution (if used delta or infinity)
482
5952
  bool usedVts = d_vtsCache->containsVtsTerm(subs, false);
483
5952
  Instantiate* inst = d_qim.getInstantiate();
484
  //if doing partial quantifier elimination, record the instantiation and set the incomplete flag instead of sending instantiation lemma
485
5952
  if (d_qreg.getQuantAttributes().isQuantElimPartial(d_curr_quant))
486
  {
487
1
    d_cbqi_set_quant_inactive = true;
488
1
    d_incomplete_check = true;
489
1
    inst->recordInstantiation(d_curr_quant, subs, usedVts);
490
1
    return true;
491
  }
492
17853
  else if (inst->addInstantiation(d_curr_quant,
493
                                  subs,
494
                                  InferenceId::QUANTIFIERS_INST_CEGQI,
495
11902
                                  Node::null(),
496
                                  false,
497
                                  usedVts))
498
  {
499
4459
    return true;
500
  }
501
  // this should never happen for monotonic selection strategies
502
1492
  Trace("cegqi-warn") << "WARNING: Existing instantiation" << std::endl;
503
1492
  return false;
504
}
505
506
6692
CegInstantiator * InstStrategyCegqi::getInstantiator( Node q ) {
507
  std::map<Node, std::unique_ptr<CegInstantiator>>::iterator it =
508
6692
      d_cinst.find(q);
509
6692
  if( it==d_cinst.end() ){
510
1932
    d_cinst[q].reset(new CegInstantiator(d_env, q, d_qstate, d_treg, this));
511
1932
    return d_cinst[q].get();
512
  }
513
4760
  return it->second.get();
514
}
515
516
2021
VtsTermCache* InstStrategyCegqi::getVtsTermCache() const
517
{
518
2021
  return d_vtsCache.get();
519
}
520
521
1224
BvInverter* InstStrategyCegqi::getBvInverter() const
522
{
523
1224
  return d_bv_invert.get();
524
}
525
526
7034
bool InstStrategyCegqi::processNestedQe(Node q, bool isPreregister)
527
{
528
7034
  if (d_nestedQe != nullptr)
529
  {
530
96
    if (isPreregister)
531
    {
532
      // If at preregister, we are done if we have nested quantification.
533
      // We will process nested quantification.
534
42
      return NestedQe::hasNestedQuantification(q);
535
    }
536
    // if not a preregister, we process, which may trigger quantifier
537
    // elimination in subsolvers.
538
82
    std::vector<Node> lems;
539
54
    if (d_nestedQe->process(q, lems))
540
    {
541
      // add lemmas to process
542
40
      for (const Node& lem : lems)
543
      {
544
14
        d_qim.addPendingLemma(lem, InferenceId::QUANTIFIERS_CEGQI_NESTED_QE);
545
      }
546
      // don't need to process this, since it has been reduced
547
26
      return true;
548
    }
549
  }
550
6966
  return false;
551
}
552
553
}  // namespace quantifiers
554
}  // namespace theory
555
31137
}  // namespace cvc5