GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/instantiate.cpp Lines: 276 345 80.0 %
Date: 2021-08-06 Branches: 533 1398 38.1 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Tim King, Morgan Deters
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 instantiate.
14
 */
15
16
#include "theory/quantifiers/instantiate.h"
17
18
#include "expr/node_algorithm.h"
19
#include "options/base_options.h"
20
#include "options/outputc.h"
21
#include "options/printer_options.h"
22
#include "options/quantifiers_options.h"
23
#include "options/smt_options.h"
24
#include "proof/lazy_proof.h"
25
#include "proof/proof_node_manager.h"
26
#include "smt/logic_exception.h"
27
#include "smt/smt_engine.h"
28
#include "smt/smt_engine_scope.h"
29
#include "smt/smt_statistics_registry.h"
30
#include "theory/quantifiers/cegqi/inst_strategy_cegqi.h"
31
#include "theory/quantifiers/first_order_model.h"
32
#include "theory/quantifiers/quantifiers_attributes.h"
33
#include "theory/quantifiers/quantifiers_rewriter.h"
34
#include "theory/quantifiers/term_database.h"
35
#include "theory/quantifiers/term_enumeration.h"
36
#include "theory/quantifiers/term_registry.h"
37
#include "theory/quantifiers/term_util.h"
38
#include "theory/rewriter.h"
39
40
using namespace cvc5::kind;
41
using namespace cvc5::context;
42
43
namespace cvc5 {
44
namespace theory {
45
namespace quantifiers {
46
47
9853
Instantiate::Instantiate(QuantifiersState& qs,
48
                         QuantifiersInferenceManager& qim,
49
                         QuantifiersRegistry& qr,
50
                         TermRegistry& tr,
51
9853
                         ProofNodeManager* pnm)
52
    : d_qstate(qs),
53
      d_qim(qim),
54
      d_qreg(qr),
55
      d_treg(tr),
56
      d_pnm(pnm),
57
9853
      d_insts(qs.getUserContext()),
58
9853
      d_c_inst_match_trie_dom(qs.getUserContext()),
59
      d_pfInst(
60
2490
          pnm ? new CDProof(pnm, qs.getUserContext(), "Instantiate::pfInst")
61
32049
              : nullptr)
62
{
63
9853
}
64
65
29559
Instantiate::~Instantiate()
66
{
67
10554
  for (std::pair<const Node, CDInstMatchTrie*>& t : d_c_inst_match_trie)
68
  {
69
701
    delete t.second;
70
  }
71
9853
  d_c_inst_match_trie.clear();
72
19706
}
73
74
28525
bool Instantiate::reset(Theory::Effort e)
75
{
76
28525
  Trace("inst-debug") << "Reset, effort " << e << std::endl;
77
  // clear explicitly recorded instantiations
78
28525
  d_recordedInst.clear();
79
28525
  d_instDebugTemp.clear();
80
28525
  return true;
81
}
82
83
24969
void Instantiate::registerQuantifier(Node q) {}
84
2732
bool Instantiate::checkComplete(IncompleteId& incId)
85
{
86
2732
  if (!d_recordedInst.empty())
87
  {
88
2
    Trace("quant-engine-debug")
89
1
        << "Set incomplete due to recorded instantiations." << std::endl;
90
1
    incId = IncompleteId::QUANTIFIERS_RECORDED_INST;
91
1
    return false;
92
  }
93
2731
  return true;
94
}
95
96
6647
void Instantiate::addRewriter(InstantiationRewriter* ir)
97
{
98
6647
  d_instRewrite.push_back(ir);
99
6647
}
100
101
159598
bool Instantiate::addInstantiation(Node q,
102
                                   std::vector<Node>& terms,
103
                                   InferenceId id,
104
                                   Node pfArg,
105
                                   bool mkRep,
106
                                   bool doVts)
107
{
108
  // For resource-limiting (also does a time check).
109
159598
  d_qim.safePoint(Resource::QuantifierStep);
110
159598
  Assert(!d_qstate.isInConflict());
111
159598
  Assert(terms.size() == q[0].getNumChildren());
112
319196
  Trace("inst-add-debug") << "For quantified formula " << q
113
159598
                          << ", add instantiation: " << std::endl;
114
598558
  for (unsigned i = 0, size = terms.size(); i < size; i++)
115
  {
116
438960
    Trace("inst-add-debug") << "  " << q[0][i];
117
438960
    Trace("inst-add-debug2") << " -> " << terms[i];
118
877920
    TypeNode tn = q[0][i].getType();
119
438960
    if (terms[i].isNull())
120
    {
121
2045
      terms[i] = d_treg.getTermForType(tn);
122
    }
123
    // Ensure the type is correct, this for instance ensures that real terms
124
    // are cast to integers for { x -> t } where x has type Int and t has
125
    // type Real.
126
438960
    terms[i] = ensureType(terms[i], tn);
127
438960
    if (mkRep)
128
    {
129
      // pick the best possible representative for instantiation, based on past
130
      // use and simplicity of term
131
69632
      terms[i] = d_treg.getModel()->getInternalRepresentative(terms[i], q, i);
132
    }
133
438960
    Trace("inst-add-debug") << " -> " << terms[i] << std::endl;
134
438960
    if (terms[i].isNull())
135
    {
136
      Trace("inst-add-debug")
137
          << " --> Failed to make term vector, due to term/type restrictions."
138
          << std::endl;
139
      return false;
140
    }
141
#ifdef CVC5_ASSERTIONS
142
438960
    bool bad_inst = false;
143
438960
    if (TermUtil::containsUninterpretedConstant(terms[i]))
144
    {
145
      Trace("inst") << "***& inst contains uninterpreted constant : "
146
                    << terms[i] << std::endl;
147
      bad_inst = true;
148
    }
149
438960
    else if (!terms[i].getType().isSubtypeOf(q[0][i].getType()))
150
    {
151
      Trace("inst") << "***& inst bad type : " << terms[i] << " "
152
                    << terms[i].getType() << "/" << q[0][i].getType()
153
                    << std::endl;
154
      bad_inst = true;
155
    }
156
438960
    else if (options::cegqi())
157
    {
158
850598
      Node icf = TermUtil::getInstConstAttr(terms[i]);
159
425299
      if (!icf.isNull())
160
      {
161
82
        if (icf == q)
162
        {
163
          Trace("inst") << "***& inst contains inst constant attr : "
164
                        << terms[i] << std::endl;
165
          bad_inst = true;
166
        }
167
82
        else if (expr::hasSubterm(terms[i], d_qreg.d_inst_constants[q]))
168
        {
169
          Trace("inst") << "***& inst contains inst constants : " << terms[i]
170
                        << std::endl;
171
          bad_inst = true;
172
        }
173
      }
174
    }
175
    // this assertion is critical to soundness
176
438960
    if (bad_inst)
177
    {
178
      Trace("inst") << "***& Bad Instantiate " << q << " with " << std::endl;
179
      for (unsigned j = 0; j < terms.size(); j++)
180
      {
181
        Trace("inst") << "   " << terms[j] << std::endl;
182
      }
183
      Assert(false);
184
    }
185
#endif
186
  }
187
188
159598
  TermDb* tdb = d_treg.getTermDatabase();
189
  // Note we check for entailment before checking for term vector duplication.
190
  // Although checking for term vector duplication is a faster check, it is
191
  // included automatically with recordInstantiationInternal, hence we prefer
192
  // two checks instead of three. In experiments, it is 1% slower or so to call
193
  // existsInstantiation here.
194
  // Alternatively, we could return an (index, trie node) in the call to
195
  // existsInstantiation here, where this would return the node in the trie
196
  // where we determined that there is definitely no duplication, and then
197
  // continue from that point in recordInstantiation below. However, for
198
  // simplicity, we do not pursue this option (as it would likely only
199
  // lead to very small gains).
200
201
  // check for positive entailment
202
331200
  if (options::instNoEntail())
203
  {
204
    // should check consistency of equality engine
205
    // (if not aborting on utility's reset)
206
233768
    std::map<TNode, TNode> subs;
207
568188
    for (unsigned i = 0, size = terms.size(); i < size; i++)
208
    {
209
412383
      subs[q[0][i]] = terms[i];
210
    }
211
155805
    if (tdb->isEntailed(q[1], subs, false, true))
212
    {
213
77842
      Trace("inst-add-debug") << " --> Currently entailed." << std::endl;
214
77842
      ++(d_statistics.d_inst_duplicate_ent);
215
77842
      return false;
216
    }
217
  }
218
219
  // check based on instantiation level
220
81756
  if (options::instMaxLevel() != -1)
221
  {
222
1345
    for (Node& t : terms)
223
    {
224
970
      if (!tdb->isTermEligibleForInstantiation(t, q))
225
      {
226
        return false;
227
      }
228
    }
229
  }
230
231
  // record the instantiation
232
81756
  bool recorded = recordInstantiationInternal(q, terms);
233
81756
  if (!recorded)
234
  {
235
44139
    Trace("inst-add-debug") << " --> Already exists (no record)." << std::endl;
236
44139
    ++(d_statistics.d_inst_duplicate_eq);
237
44139
    return false;
238
  }
239
240
  // Set up a proof if proofs are enabled. This proof stores a proof of
241
  // the instantiation body with q as a free assumption.
242
75234
  std::shared_ptr<LazyCDProof> pfTmp;
243
37617
  if (isProofEnabled())
244
  {
245
17988
    pfTmp.reset(new LazyCDProof(
246
8994
        d_pnm, nullptr, nullptr, "Instantiate::LazyCDProof::tmp"));
247
  }
248
249
  // construct the instantiation
250
37617
  Trace("inst-add-debug") << "Constructing instantiation..." << std::endl;
251
37617
  Assert(d_qreg.d_vars[q].size() == terms.size());
252
  // get the instantiation
253
  Node body = getInstantiation(
254
75234
      q, d_qreg.d_vars[q], terms, id, pfArg, doVts, pfTmp.get());
255
75234
  Node orig_body = body;
256
  // now preprocess, storing the trust node for the rewrite
257
75234
  TrustNode tpBody = QuantifiersRewriter::preprocess(body, true);
258
37617
  if (!tpBody.isNull())
259
  {
260
    Assert(tpBody.getKind() == TrustNodeKind::REWRITE);
261
    body = tpBody.getNode();
262
    // do a tranformation step
263
    if (pfTmp != nullptr)
264
    {
265
      //              ----------------- from preprocess
266
      // orig_body    orig_body = body
267
      // ------------------------------ EQ_RESOLVE
268
      // body
269
      Node proven = tpBody.getProven();
270
      // add the transformation proof, or the trusted rule if none provided
271
      pfTmp->addLazyStep(proven,
272
                         tpBody.getGenerator(),
273
                         PfRule::QUANTIFIERS_PREPROCESS,
274
                         true,
275
                         "Instantiate::getInstantiation:qpreprocess");
276
      pfTmp->addStep(body, PfRule::EQ_RESOLVE, {orig_body, proven}, {});
277
    }
278
  }
279
37617
  Trace("inst-debug") << "...preprocess to " << body << std::endl;
280
281
  // construct the lemma
282
37617
  Trace("inst-assert") << "(assert " << body << ")" << std::endl;
283
284
  // construct the instantiation, and rewrite the lemma
285
75234
  Node lem = NodeManager::currentNM()->mkNode(kind::IMPLIES, q, body);
286
287
  // If proofs are enabled, construct the proof, which is of the form:
288
  // ... free assumption q ...
289
  // ------------------------- from pfTmp
290
  // body
291
  // ------------------------- SCOPE
292
  // (=> q body)
293
  // -------------------------- MACRO_SR_PRED_ELIM
294
  // lem
295
37617
  bool hasProof = false;
296
37617
  if (isProofEnabled())
297
  {
298
    // make the proof of body
299
17988
    std::shared_ptr<ProofNode> pfn = pfTmp->getProofFor(body);
300
    // make the scope proof to get (=> q body)
301
17988
    std::vector<Node> assumps;
302
8994
    assumps.push_back(q);
303
17988
    std::shared_ptr<ProofNode> pfns = d_pnm->mkScope({pfn}, assumps);
304
8994
    Assert(assumps.size() == 1 && assumps[0] == q);
305
    // store in the main proof
306
8994
    d_pfInst->addProof(pfns);
307
17988
    Node prevLem = lem;
308
8994
    lem = Rewriter::rewrite(lem);
309
8994
    if (prevLem != lem)
310
    {
311
4829
      d_pfInst->addStep(lem, PfRule::MACRO_SR_PRED_ELIM, {prevLem}, {});
312
    }
313
8994
    hasProof = true;
314
  }
315
  else
316
  {
317
28623
    lem = Rewriter::rewrite(lem);
318
  }
319
320
  // added lemma, which checks for lemma duplication
321
37617
  bool addedLem = false;
322
37617
  if (hasProof)
323
  {
324
    // use proof generator
325
8994
    addedLem =
326
17988
        d_qim.addPendingLemma(lem, id, LemmaProperty::NONE, d_pfInst.get());
327
  }
328
  else
329
  {
330
28623
    addedLem = d_qim.addPendingLemma(lem, id);
331
  }
332
333
37617
  if (!addedLem)
334
  {
335
1011
    Trace("inst-add-debug") << " --> Lemma already exists." << std::endl;
336
1011
    ++(d_statistics.d_inst_duplicate);
337
1011
    return false;
338
  }
339
340
  // add to list of instantiations
341
36606
  InstLemmaList* ill = getOrMkInstLemmaList(q);
342
36606
  ill->d_list.push_back(body);
343
  // add to temporary debug statistics (# inst on this round)
344
36606
  d_instDebugTemp[q]++;
345
36606
  if (Trace.isOn("inst"))
346
  {
347
    Trace("inst") << "*** Instantiate " << q << " with " << std::endl;
348
    for (unsigned i = 0, size = terms.size(); i < size; i++)
349
    {
350
      if (Trace.isOn("inst"))
351
      {
352
        Trace("inst") << "   " << terms[i];
353
        if (Trace.isOn("inst-debug"))
354
        {
355
          Trace("inst-debug") << ", type=" << terms[i].getType()
356
                              << ", var_type=" << q[0][i].getType();
357
        }
358
        Trace("inst") << std::endl;
359
      }
360
    }
361
  }
362
36606
  if (options::instMaxLevel() != -1)
363
  {
364
346
    if (doVts)
365
    {
366
      // virtual term substitution/instantiation level features are
367
      // incompatible
368
      std::stringstream ss;
369
      ss << "Cannot combine instantiation strategies that require virtual term "
370
            "substitution with those that restrict instantiation levels";
371
      throw LogicException(ss.str());
372
    }
373
    else
374
    {
375
346
      uint64_t maxInstLevel = 0;
376
1263
      for (const Node& tc : terms)
377
      {
378
1834
        if (tc.hasAttribute(InstLevelAttribute())
379
917
            && tc.getAttribute(InstLevelAttribute()) > maxInstLevel)
380
        {
381
          maxInstLevel = tc.getAttribute(InstLevelAttribute());
382
        }
383
      }
384
346
      QuantAttributes::setInstantiationLevelAttr(
385
          orig_body, q[1], maxInstLevel + 1);
386
    }
387
  }
388
36606
  d_treg.processInstantiation(q, terms);
389
36606
  Trace("inst-add-debug") << " --> Success." << std::endl;
390
36606
  ++(d_statistics.d_instantiations);
391
36606
  return true;
392
}
393
394
3449
bool Instantiate::addInstantiationExpFail(Node q,
395
                                          std::vector<Node>& terms,
396
                                          std::vector<bool>& failMask,
397
                                          InferenceId id,
398
                                          Node pfArg,
399
                                          bool mkRep,
400
                                          bool doVts,
401
                                          bool expFull)
402
{
403
3449
  if (addInstantiation(q, terms, id, pfArg, mkRep, doVts))
404
  {
405
805
    return true;
406
  }
407
2644
  size_t tsize = terms.size();
408
2644
  failMask.resize(tsize, true);
409
2644
  if (tsize == 1)
410
  {
411
    // will never succeed with 1 variable
412
626
    return false;
413
  }
414
2018
  TermDb* tdb = d_treg.getTermDatabase();
415
2018
  Trace("inst-exp-fail") << "Explain inst failure..." << terms << std::endl;
416
  // set up information for below
417
2018
  std::vector<Node>& vars = d_qreg.d_vars[q];
418
2018
  Assert(tsize == vars.size());
419
4036
  std::map<TNode, TNode> subs;
420
14078
  for (size_t i = 0; i < tsize; i++)
421
  {
422
12060
    subs[vars[i]] = terms[i];
423
  }
424
  // get the instantiation body
425
2018
  InferenceId idNone = InferenceId::UNKNOWN;
426
4036
  Node nulln;
427
4036
  Node ibody = getInstantiation(q, vars, terms, idNone, nulln, doVts);
428
2018
  ibody = Rewriter::rewrite(ibody);
429
14022
  for (size_t i = 0; i < tsize; i++)
430
  {
431
    // process consecutively in reverse order, which is important since we use
432
    // the fail mask for incrementing in a lexicographic order
433
12060
    size_t ii = (tsize - 1) - i;
434
    // replace with the identity substitution
435
24064
    Node prev = terms[ii];
436
12060
    terms[ii] = vars[ii];
437
12060
    subs.erase(vars[ii]);
438
12060
    if (subs.empty())
439
    {
440
      // will never succeed with empty substitution
441
56
      break;
442
    }
443
12004
    Trace("inst-exp-fail") << "- revert " << ii << std::endl;
444
    // check whether we are still redundant
445
12004
    bool success = false;
446
    // check entailment, only if option is set
447
12004
    if (options::instNoEntail())
448
    {
449
12004
      Trace("inst-exp-fail") << "  check entailment" << std::endl;
450
12004
      success = tdb->isEntailed(q[1], subs, false, true);
451
12004
      Trace("inst-exp-fail") << "  entailed: " << success << std::endl;
452
    }
453
    // check whether the instantiation rewrites to the same thing
454
12004
    if (!success)
455
    {
456
19810
      Node ibodyc = getInstantiation(q, vars, terms, idNone, nulln, doVts);
457
9905
      ibodyc = Rewriter::rewrite(ibodyc);
458
9905
      success = (ibodyc == ibody);
459
9905
      Trace("inst-exp-fail") << "  rewrite invariant: " << success << std::endl;
460
    }
461
12004
    if (success)
462
    {
463
      // if we still fail, we are not critical
464
2171
      failMask[ii] = false;
465
    }
466
    else
467
    {
468
9833
      subs[vars[ii]] = prev;
469
9833
      terms[ii] = prev;
470
      // not necessary to proceed if expFull is false
471
9833
      if (!expFull)
472
      {
473
        break;
474
      }
475
    }
476
  }
477
2018
  if (Trace.isOn("inst-exp-fail"))
478
  {
479
    Trace("inst-exp-fail") << "Fail mask: ";
480
    for (bool b : failMask)
481
    {
482
      Trace("inst-exp-fail") << (b ? 1 : 0);
483
    }
484
    Trace("inst-exp-fail") << std::endl;
485
  }
486
2018
  return false;
487
}
488
489
1
void Instantiate::recordInstantiation(Node q,
490
                                      std::vector<Node>& terms,
491
                                      bool doVts)
492
{
493
1
  Trace("inst-debug") << "Record instantiation for " << q << std::endl;
494
  // get the instantiation list, which ensures that q is marked as a quantified
495
  // formula we instantiated, despite only recording an instantiation here
496
1
  getOrMkInstLemmaList(q);
497
2
  Node inst = getInstantiation(q, terms, doVts);
498
1
  d_recordedInst[q].push_back(inst);
499
1
}
500
501
bool Instantiate::existsInstantiation(Node q,
502
                                      std::vector<Node>& terms,
503
                                      bool modEq)
504
{
505
  if (options::incrementalSolving())
506
  {
507
    std::map<Node, CDInstMatchTrie*>::iterator it = d_c_inst_match_trie.find(q);
508
    if (it != d_c_inst_match_trie.end())
509
    {
510
      return it->second->existsInstMatch(d_qstate, q, terms, modEq);
511
    }
512
  }
513
  else
514
  {
515
    std::map<Node, InstMatchTrie>::iterator it = d_inst_match_trie.find(q);
516
    if (it != d_inst_match_trie.end())
517
    {
518
      return it->second.existsInstMatch(d_qstate, q, terms, modEq);
519
    }
520
  }
521
  return false;
522
}
523
524
139571
Node Instantiate::getInstantiation(Node q,
525
                                   std::vector<Node>& vars,
526
                                   std::vector<Node>& terms,
527
                                   InferenceId id,
528
                                   Node pfArg,
529
                                   bool doVts,
530
                                   LazyCDProof* pf)
531
{
532
139571
  Assert(vars.size() == terms.size());
533
139571
  Assert(q[0].getNumChildren() == vars.size());
534
  // Notice that this could be optimized, but no significant performance
535
  // improvements were observed with alternative implementations (see #1386).
536
  Node body =
537
139571
      q[1].substitute(vars.begin(), vars.end(), terms.begin(), terms.end());
538
539
  // store the proof of the instantiated body, with (open) assumption q
540
139571
  if (pf != nullptr)
541
  {
542
    // additional arguments: if the inference id is not unknown, include it,
543
    // followed by the proof argument if non-null. The latter is used e.g.
544
    // to track which trigger caused an instantiation.
545
17988
    std::vector<Node> pfTerms = terms;
546
8994
    if (id != InferenceId::UNKNOWN)
547
    {
548
8994
      pfTerms.push_back(mkInferenceIdNode(id));
549
8994
      if (!pfArg.isNull())
550
      {
551
6962
        pfTerms.push_back(pfArg);
552
      }
553
    }
554
8994
    pf->addStep(body, PfRule::INSTANTIATE, {q}, pfTerms);
555
  }
556
557
  // run rewriters to rewrite the instantiation in sequence.
558
270306
  for (InstantiationRewriter*& ir : d_instRewrite)
559
  {
560
261470
    TrustNode trn = ir->rewriteInstantiation(q, terms, body, doVts);
561
130735
    if (!trn.isNull())
562
    {
563
166
      Node newBody = trn.getNode();
564
      // if using proofs, we store a preprocess + transformation step.
565
83
      if (pf != nullptr)
566
      {
567
46
        Node proven = trn.getProven();
568
23
        pf->addLazyStep(proven,
569
                        trn.getGenerator(),
570
                        PfRule::THEORY_PREPROCESS,
571
                        true,
572
                        "Instantiate::getInstantiation:rewrite_inst");
573
23
        pf->addStep(newBody, PfRule::EQ_RESOLVE, {body, proven}, {});
574
      }
575
83
      body = newBody;
576
    }
577
  }
578
139571
  return body;
579
}
580
581
89700
Node Instantiate::getInstantiation(Node q, std::vector<Node>& terms, bool doVts)
582
{
583
89700
  Assert(d_qreg.d_vars.find(q) != d_qreg.d_vars.end());
584
  return getInstantiation(
585
89700
      q, d_qreg.d_vars[q], terms, InferenceId::UNKNOWN, Node::null(), doVts);
586
}
587
588
81756
bool Instantiate::recordInstantiationInternal(Node q, std::vector<Node>& terms)
589
{
590
81756
  if (options::incrementalSolving())
591
  {
592
12800
    Trace("inst-add-debug")
593
6400
        << "Adding into context-dependent inst trie" << std::endl;
594
    CDInstMatchTrie* imt;
595
6400
    std::map<Node, CDInstMatchTrie*>::iterator it = d_c_inst_match_trie.find(q);
596
6400
    if (it != d_c_inst_match_trie.end())
597
    {
598
5699
      imt = it->second;
599
    }
600
    else
601
    {
602
701
      imt = new CDInstMatchTrie(d_qstate.getUserContext());
603
701
      d_c_inst_match_trie[q] = imt;
604
    }
605
6400
    d_c_inst_match_trie_dom.insert(q);
606
6400
    return imt->addInstMatch(d_qstate, q, terms);
607
  }
608
75356
  Trace("inst-add-debug") << "Adding into inst trie" << std::endl;
609
75356
  return d_inst_match_trie[q].addInstMatch(d_qstate, q, terms);
610
}
611
612
bool Instantiate::removeInstantiationInternal(Node q, std::vector<Node>& terms)
613
{
614
  if (options::incrementalSolving())
615
  {
616
    std::map<Node, CDInstMatchTrie*>::iterator it = d_c_inst_match_trie.find(q);
617
    if (it != d_c_inst_match_trie.end())
618
    {
619
      return it->second->removeInstMatch(q, terms);
620
    }
621
    return false;
622
  }
623
  return d_inst_match_trie[q].removeInstMatch(q, terms);
624
}
625
626
68
void Instantiate::getInstantiatedQuantifiedFormulas(std::vector<Node>& qs) const
627
{
628
126
  for (NodeInstListMap::const_iterator it = d_insts.begin();
629
126
       it != d_insts.end();
630
       ++it)
631
  {
632
58
    qs.push_back(it->first);
633
  }
634
68
}
635
636
52
void Instantiate::getInstantiationTermVectors(
637
    Node q, std::vector<std::vector<Node> >& tvecs)
638
{
639
640
52
  if (options::incrementalSolving())
641
  {
642
    std::map<Node, CDInstMatchTrie*>::const_iterator it =
643
4
        d_c_inst_match_trie.find(q);
644
4
    if (it != d_c_inst_match_trie.end())
645
    {
646
4
      it->second->getInstantiations(q, tvecs);
647
    }
648
  }
649
  else
650
  {
651
    std::map<Node, InstMatchTrie>::const_iterator it =
652
48
        d_inst_match_trie.find(q);
653
48
    if (it != d_inst_match_trie.end())
654
    {
655
48
      it->second.getInstantiations(q, tvecs);
656
    }
657
  }
658
52
}
659
660
8
void Instantiate::getInstantiationTermVectors(
661
    std::map<Node, std::vector<std::vector<Node> > >& insts)
662
{
663
8
  if (options::incrementalSolving())
664
  {
665
8
    for (const auto& t : d_c_inst_match_trie)
666
    {
667
4
      getInstantiationTermVectors(t.first, insts[t.first]);
668
    }
669
  }
670
  else
671
  {
672
10
    for (const auto& t : d_inst_match_trie)
673
    {
674
6
      getInstantiationTermVectors(t.first, insts[t.first]);
675
    }
676
  }
677
8
}
678
679
16
void Instantiate::getInstantiations(Node q, std::vector<Node>& insts)
680
{
681
16
  Trace("inst-debug") << "get instantiations for " << q << std::endl;
682
16
  InstLemmaList* ill = getOrMkInstLemmaList(q);
683
16
  insts.insert(insts.end(), ill->d_list.begin(), ill->d_list.end());
684
  // also include recorded instantations (for qe-partial)
685
  std::map<Node, std::vector<Node> >::const_iterator it =
686
16
      d_recordedInst.find(q);
687
16
  if (it != d_recordedInst.end())
688
  {
689
1
    insts.insert(insts.end(), it->second.begin(), it->second.end());
690
  }
691
16
}
692
693
75234
bool Instantiate::isProofEnabled() const { return d_pfInst != nullptr; }
694
695
10939
void Instantiate::notifyEndRound()
696
{
697
  // debug information
698
10939
  if (Trace.isOn("inst-per-quant-round"))
699
  {
700
    for (std::pair<const Node, uint32_t>& i : d_instDebugTemp)
701
    {
702
      Trace("inst-per-quant-round")
703
          << " * " << i.second << " for " << i.first << std::endl;
704
    }
705
  }
706
10939
  if (Output.isOn(options::OutputTag::INST))
707
  {
708
4
    bool req = !options::printInstFull();
709
6
    for (std::pair<const Node, uint32_t>& i : d_instDebugTemp)
710
    {
711
8
      Node name;
712
4
      if (!d_qreg.getNameForQuant(i.first, name, req))
713
      {
714
        continue;
715
      }
716
8
      Output(options::OutputTag::INST) << "(num-instantiations " << name << " "
717
4
                                       << i.second << ")" << std::endl;
718
    }
719
  }
720
10939
}
721
722
5821
void Instantiate::debugPrintModel()
723
{
724
5821
  if (Trace.isOn("inst-per-quant"))
725
  {
726
    for (NodeInstListMap::iterator it = d_insts.begin(); it != d_insts.end();
727
         ++it)
728
    {
729
      Trace("inst-per-quant") << " * " << (*it).second->d_list.size() << " for "
730
                              << (*it).first << std::endl;
731
    }
732
  }
733
5821
}
734
735
438960
Node Instantiate::ensureType(Node n, TypeNode tn)
736
{
737
438960
  Trace("inst-add-debug2") << "Ensure " << n << " : " << tn << std::endl;
738
877920
  TypeNode ntn = n.getType();
739
438960
  Assert(ntn.isComparableTo(tn));
740
438960
  if (ntn.isSubtypeOf(tn))
741
  {
742
438948
    return n;
743
  }
744
12
  if (tn.isInteger())
745
  {
746
12
    return NodeManager::currentNM()->mkNode(TO_INTEGER, n);
747
  }
748
  return Node::null();
749
}
750
751
36623
InstLemmaList* Instantiate::getOrMkInstLemmaList(TNode q)
752
{
753
36623
  NodeInstListMap::iterator it = d_insts.find(q);
754
36623
  if (it != d_insts.end())
755
  {
756
30548
    return it->second.get();
757
  }
758
  std::shared_ptr<InstLemmaList> ill =
759
12150
      std::make_shared<InstLemmaList>(d_qstate.getUserContext());
760
6075
  d_insts.insert(q, ill);
761
6075
  return ill.get();
762
}
763
764
9853
Instantiate::Statistics::Statistics()
765
9853
    : d_instantiations(smtStatisticsRegistry().registerInt(
766
19706
        "Instantiate::Instantiations_Total")),
767
      d_inst_duplicate(
768
19706
          smtStatisticsRegistry().registerInt("Instantiate::Duplicate_Inst")),
769
9853
      d_inst_duplicate_eq(smtStatisticsRegistry().registerInt(
770
19706
          "Instantiate::Duplicate_Inst_Eq")),
771
9853
      d_inst_duplicate_ent(smtStatisticsRegistry().registerInt(
772
39412
          "Instantiate::Duplicate_Inst_Entailed"))
773
{
774
9853
}
775
776
}  // namespace quantifiers
777
}  // namespace theory
778
29322
}  // namespace cvc5