GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/instantiate.cpp Lines: 272 344 79.1 %
Date: 2021-09-29 Branches: 519 1392 37.3 %

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