GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/instantiate.cpp Lines: 274 343 79.9 %
Date: 2021-09-10 Branches: 529 1386 38.2 %

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_statistics_registry.h"
28
#include "theory/quantifiers/cegqi/inst_strategy_cegqi.h"
29
#include "theory/quantifiers/first_order_model.h"
30
#include "theory/quantifiers/quantifiers_attributes.h"
31
#include "theory/quantifiers/quantifiers_preprocess.h"
32
#include "theory/quantifiers/term_database.h"
33
#include "theory/quantifiers/term_enumeration.h"
34
#include "theory/quantifiers/term_registry.h"
35
#include "theory/quantifiers/term_util.h"
36
#include "theory/rewriter.h"
37
38
using namespace cvc5::kind;
39
using namespace cvc5::context;
40
41
namespace cvc5 {
42
namespace theory {
43
namespace quantifiers {
44
45
9913
Instantiate::Instantiate(Env& env,
46
                         QuantifiersState& qs,
47
                         QuantifiersInferenceManager& qim,
48
                         QuantifiersRegistry& qr,
49
                         TermRegistry& tr,
50
9913
                         ProofNodeManager* pnm)
51
    : QuantifiersUtil(env),
52
      d_qstate(qs),
53
      d_qim(qim),
54
      d_qreg(qr),
55
      d_treg(tr),
56
      d_pnm(pnm),
57
9913
      d_insts(qs.getUserContext()),
58
9913
      d_c_inst_match_trie_dom(qs.getUserContext()),
59
      d_pfInst(
60
2480
          pnm ? new CDProof(pnm, qs.getUserContext(), "Instantiate::pfInst")
61
32219
              : nullptr)
62
{
63
9913
}
64
65
29730
Instantiate::~Instantiate()
66
{
67
10621
  for (std::pair<const Node, CDInstMatchTrie*>& t : d_c_inst_match_trie)
68
  {
69
711
    delete t.second;
70
  }
71
9910
  d_c_inst_match_trie.clear();
72
19820
}
73
74
28088
bool Instantiate::reset(Theory::Effort e)
75
{
76
28088
  Trace("inst-debug") << "Reset, effort " << e << std::endl;
77
  // clear explicitly recorded instantiations
78
28088
  d_recordedInst.clear();
79
28088
  d_instDebugTemp.clear();
80
28088
  return true;
81
}
82
83
25073
void Instantiate::registerQuantifier(Node q) {}
84
2634
bool Instantiate::checkComplete(IncompleteId& incId)
85
{
86
2634
  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
2633
  return true;
94
}
95
96
6708
void Instantiate::addRewriter(InstantiationRewriter* ir)
97
{
98
6708
  d_instRewrite.push_back(ir);
99
6708
}
100
101
161321
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
161321
  d_qim.safePoint(Resource::QuantifierStep);
110
161321
  Assert(!d_qstate.isInConflict());
111
161321
  Assert(terms.size() == q[0].getNumChildren());
112
322642
  Trace("inst-add-debug") << "For quantified formula " << q
113
161321
                          << ", add instantiation: " << std::endl;
114
601058
  for (unsigned i = 0, size = terms.size(); i < size; i++)
115
  {
116
439737
    Trace("inst-add-debug") << "  " << q[0][i];
117
439737
    Trace("inst-add-debug2") << " -> " << terms[i];
118
879474
    TypeNode tn = q[0][i].getType();
119
439737
    if (terms[i].isNull())
120
    {
121
2046
      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
439737
    terms[i] = ensureType(terms[i], tn);
127
439737
    if (mkRep)
128
    {
129
      // pick the best possible representative for instantiation, based on past
130
      // use and simplicity of term
131
72883
      terms[i] = d_treg.getModel()->getInternalRepresentative(terms[i], q, i);
132
    }
133
439737
    Trace("inst-add-debug") << " -> " << terms[i] << std::endl;
134
439737
    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
439737
    bool bad_inst = false;
143
439737
    if (TermUtil::containsUninterpretedConstant(terms[i]))
144
    {
145
      Trace("inst") << "***& inst contains uninterpreted constant : "
146
                    << terms[i] << std::endl;
147
      bad_inst = true;
148
    }
149
439737
    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
439737
    else if (options::cegqi())
157
    {
158
852152
      Node icf = TermUtil::getInstConstAttr(terms[i]);
159
426076
      if (!icf.isNull())
160
      {
161
80
        if (icf == q)
162
        {
163
          Trace("inst") << "***& inst contains inst constant attr : "
164
                        << terms[i] << std::endl;
165
          bad_inst = true;
166
        }
167
80
        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
439737
    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
161321
  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
161321
  if (options::instNoEntail())
203
  {
204
    // should check consistency of equality engine
205
    // (if not aborting on utility's reset)
206
225181
    std::map<TNode, TNode> subs;
207
563705
    for (unsigned i = 0, size = terms.size(); i < size; i++)
208
    {
209
410225
      subs[q[0][i]] = terms[i];
210
    }
211
153480
    if (tdb->isEntailed(q[1], subs, false, true))
212
    {
213
81779
      Trace("inst-add-debug") << " --> Currently entailed." << std::endl;
214
81779
      ++(d_statistics.d_inst_duplicate_ent);
215
81779
      return false;
216
    }
217
  }
218
219
  // check based on instantiation level
220
79542
  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
79542
  bool recorded = recordInstantiationInternal(q, terms);
233
79542
  if (!recorded)
234
  {
235
40517
    Trace("inst-add-debug") << " --> Already exists (no record)." << std::endl;
236
40517
    ++(d_statistics.d_inst_duplicate_eq);
237
40517
    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
78050
  std::shared_ptr<LazyCDProof> pfTmp;
243
39025
  if (isProofEnabled())
244
  {
245
18164
    pfTmp.reset(new LazyCDProof(
246
9082
        d_pnm, nullptr, nullptr, "Instantiate::LazyCDProof::tmp"));
247
  }
248
249
  // construct the instantiation
250
39025
  Trace("inst-add-debug") << "Constructing instantiation..." << std::endl;
251
39025
  Assert(d_qreg.d_vars[q].size() == terms.size());
252
  // get the instantiation
253
  Node body = getInstantiation(
254
78050
      q, d_qreg.d_vars[q], terms, id, pfArg, doVts, pfTmp.get());
255
78050
  Node orig_body = body;
256
  // now preprocess, storing the trust node for the rewrite
257
78050
  TrustNode tpBody = d_qreg.getPreprocess().preprocess(body, true);
258
39025
  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
39025
  Trace("inst-debug") << "...preprocess to " << body << std::endl;
280
281
  // construct the lemma
282
39025
  Trace("inst-assert") << "(assert " << body << ")" << std::endl;
283
284
  // construct the instantiation, and rewrite the lemma
285
78050
  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
39025
  bool hasProof = false;
296
39025
  if (isProofEnabled())
297
  {
298
    // make the proof of body
299
18164
    std::shared_ptr<ProofNode> pfn = pfTmp->getProofFor(body);
300
    // make the scope proof to get (=> q body)
301
18164
    std::vector<Node> assumps;
302
9082
    assumps.push_back(q);
303
18164
    std::shared_ptr<ProofNode> pfns = d_pnm->mkScope({pfn}, assumps);
304
9082
    Assert(assumps.size() == 1 && assumps[0] == q);
305
    // store in the main proof
306
9082
    d_pfInst->addProof(pfns);
307
18164
    Node prevLem = lem;
308
9082
    lem = Rewriter::rewrite(lem);
309
9082
    if (prevLem != lem)
310
    {
311
4890
      d_pfInst->addStep(lem, PfRule::MACRO_SR_PRED_ELIM, {prevLem}, {});
312
    }
313
9082
    hasProof = true;
314
  }
315
  else
316
  {
317
29943
    lem = Rewriter::rewrite(lem);
318
  }
319
320
  // added lemma, which checks for lemma duplication
321
39025
  bool addedLem = false;
322
39025
  if (hasProof)
323
  {
324
    // use proof generator
325
9082
    addedLem =
326
18164
        d_qim.addPendingLemma(lem, id, LemmaProperty::NONE, d_pfInst.get());
327
  }
328
  else
329
  {
330
29943
    addedLem = d_qim.addPendingLemma(lem, id);
331
  }
332
333
39025
  if (!addedLem)
334
  {
335
945
    Trace("inst-add-debug") << " --> Lemma already exists." << std::endl;
336
945
    ++(d_statistics.d_inst_duplicate);
337
945
    return false;
338
  }
339
340
  // add to list of instantiations
341
38080
  InstLemmaList* ill = getOrMkInstLemmaList(q);
342
38080
  ill->d_list.push_back(body);
343
  // add to temporary debug statistics (# inst on this round)
344
38080
  d_instDebugTemp[q]++;
345
38080
  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
38080
  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
38080
  d_treg.processInstantiation(q, terms);
389
38080
  Trace("inst-add-debug") << " --> Success." << std::endl;
390
38080
  ++(d_statistics.d_instantiations);
391
38080
  return true;
392
}
393
394
3454
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
3454
  if (addInstantiation(q, terms, id, pfArg, mkRep, doVts))
404
  {
405
810
    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
144588
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
144588
  Assert(vars.size() == terms.size());
533
144588
  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
144588
      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
144588
  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
18164
    std::vector<Node> pfTerms = terms;
546
9082
    if (id != InferenceId::UNKNOWN)
547
    {
548
9082
      pfTerms.push_back(mkInferenceIdNode(id));
549
9082
      if (!pfArg.isNull())
550
      {
551
7025
        pfTerms.push_back(pfArg);
552
      }
553
    }
554
9082
    pf->addStep(body, PfRule::INSTANTIATE, {q}, pfTerms);
555
  }
556
557
  // run rewriters to rewrite the instantiation in sequence.
558
280340
  for (InstantiationRewriter*& ir : d_instRewrite)
559
  {
560
271504
    TrustNode trn = ir->rewriteInstantiation(q, terms, body, doVts);
561
135752
    if (!trn.isNull())
562
    {
563
158
      Node newBody = trn.getNode();
564
      // if using proofs, we store a preprocess + transformation step.
565
79
      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
79
      body = newBody;
576
    }
577
  }
578
144588
  return body;
579
}
580
581
93310
Node Instantiate::getInstantiation(Node q, std::vector<Node>& terms, bool doVts)
582
{
583
93310
  Assert(d_qreg.d_vars.find(q) != d_qreg.d_vars.end());
584
  return getInstantiation(
585
93310
      q, d_qreg.d_vars[q], terms, InferenceId::UNKNOWN, Node::null(), doVts);
586
}
587
588
79542
bool Instantiate::recordInstantiationInternal(Node q, std::vector<Node>& terms)
589
{
590
79542
  if (options::incrementalSolving())
591
  {
592
16402
    Trace("inst-add-debug")
593
8201
        << "Adding into context-dependent inst trie" << std::endl;
594
8201
    const auto res = d_c_inst_match_trie.insert({q, nullptr});
595
8201
    if (res.second)
596
    {
597
711
      res.first->second = new CDInstMatchTrie(d_qstate.getUserContext());
598
    }
599
8201
    d_c_inst_match_trie_dom.insert(q);
600
8201
    return res.first->second->addInstMatch(d_qstate, q, terms);
601
  }
602
71341
  Trace("inst-add-debug") << "Adding into inst trie" << std::endl;
603
71341
  return d_inst_match_trie[q].addInstMatch(d_qstate, q, terms);
604
}
605
606
bool Instantiate::removeInstantiationInternal(Node q, std::vector<Node>& terms)
607
{
608
  if (options::incrementalSolving())
609
  {
610
    std::map<Node, CDInstMatchTrie*>::iterator it = d_c_inst_match_trie.find(q);
611
    if (it != d_c_inst_match_trie.end())
612
    {
613
      return it->second->removeInstMatch(q, terms);
614
    }
615
    return false;
616
  }
617
  return d_inst_match_trie[q].removeInstMatch(q, terms);
618
}
619
620
68
void Instantiate::getInstantiatedQuantifiedFormulas(std::vector<Node>& qs) const
621
{
622
126
  for (NodeInstListMap::const_iterator it = d_insts.begin();
623
126
       it != d_insts.end();
624
       ++it)
625
  {
626
58
    qs.push_back(it->first);
627
  }
628
68
}
629
630
52
void Instantiate::getInstantiationTermVectors(
631
    Node q, std::vector<std::vector<Node> >& tvecs)
632
{
633
634
52
  if (options::incrementalSolving())
635
  {
636
    std::map<Node, CDInstMatchTrie*>::const_iterator it =
637
4
        d_c_inst_match_trie.find(q);
638
4
    if (it != d_c_inst_match_trie.end())
639
    {
640
4
      it->second->getInstantiations(q, tvecs);
641
    }
642
  }
643
  else
644
  {
645
    std::map<Node, InstMatchTrie>::const_iterator it =
646
48
        d_inst_match_trie.find(q);
647
48
    if (it != d_inst_match_trie.end())
648
    {
649
48
      it->second.getInstantiations(q, tvecs);
650
    }
651
  }
652
52
}
653
654
8
void Instantiate::getInstantiationTermVectors(
655
    std::map<Node, std::vector<std::vector<Node> > >& insts)
656
{
657
8
  if (options::incrementalSolving())
658
  {
659
8
    for (const auto& t : d_c_inst_match_trie)
660
    {
661
4
      getInstantiationTermVectors(t.first, insts[t.first]);
662
    }
663
  }
664
  else
665
  {
666
10
    for (const auto& t : d_inst_match_trie)
667
    {
668
6
      getInstantiationTermVectors(t.first, insts[t.first]);
669
    }
670
  }
671
8
}
672
673
16
void Instantiate::getInstantiations(Node q, std::vector<Node>& insts)
674
{
675
16
  Trace("inst-debug") << "get instantiations for " << q << std::endl;
676
16
  InstLemmaList* ill = getOrMkInstLemmaList(q);
677
16
  insts.insert(insts.end(), ill->d_list.begin(), ill->d_list.end());
678
  // also include recorded instantations (for qe-partial)
679
  std::map<Node, std::vector<Node> >::const_iterator it =
680
16
      d_recordedInst.find(q);
681
16
  if (it != d_recordedInst.end())
682
  {
683
1
    insts.insert(insts.end(), it->second.begin(), it->second.end());
684
  }
685
16
}
686
687
78050
bool Instantiate::isProofEnabled() const { return d_pfInst != nullptr; }
688
689
10729
void Instantiate::notifyEndRound()
690
{
691
  // debug information
692
10729
  if (Trace.isOn("inst-per-quant-round"))
693
  {
694
    for (std::pair<const Node, uint32_t>& i : d_instDebugTemp)
695
    {
696
      Trace("inst-per-quant-round")
697
          << " * " << i.second << " for " << i.first << std::endl;
698
    }
699
  }
700
10729
  if (Output.isOn(options::OutputTag::INST))
701
  {
702
2
    bool req = !options::printInstFull();
703
6
    for (std::pair<const Node, uint32_t>& i : d_instDebugTemp)
704
    {
705
8
      Node name;
706
4
      if (!d_qreg.getNameForQuant(i.first, name, req))
707
      {
708
        continue;
709
      }
710
8
      Output(options::OutputTag::INST) << "(num-instantiations " << name << " "
711
4
                                       << i.second << ")" << std::endl;
712
    }
713
  }
714
10729
}
715
716
5900
void Instantiate::debugPrintModel()
717
{
718
5900
  if (Trace.isOn("inst-per-quant"))
719
  {
720
    for (NodeInstListMap::iterator it = d_insts.begin(); it != d_insts.end();
721
         ++it)
722
    {
723
      Trace("inst-per-quant") << " * " << (*it).second->d_list.size() << " for "
724
                              << (*it).first << std::endl;
725
    }
726
  }
727
5900
}
728
729
439737
Node Instantiate::ensureType(Node n, TypeNode tn)
730
{
731
439737
  Trace("inst-add-debug2") << "Ensure " << n << " : " << tn << std::endl;
732
879474
  TypeNode ntn = n.getType();
733
439737
  Assert(ntn.isComparableTo(tn));
734
439737
  if (ntn.isSubtypeOf(tn))
735
  {
736
439725
    return n;
737
  }
738
12
  if (tn.isInteger())
739
  {
740
12
    return NodeManager::currentNM()->mkNode(TO_INTEGER, n);
741
  }
742
  return Node::null();
743
}
744
745
38097
InstLemmaList* Instantiate::getOrMkInstLemmaList(TNode q)
746
{
747
38097
  NodeInstListMap::iterator it = d_insts.find(q);
748
38097
  if (it != d_insts.end())
749
  {
750
31920
    return it->second.get();
751
  }
752
  std::shared_ptr<InstLemmaList> ill =
753
12354
      std::make_shared<InstLemmaList>(d_qstate.getUserContext());
754
6177
  d_insts.insert(q, ill);
755
6177
  return ill.get();
756
}
757
758
9913
Instantiate::Statistics::Statistics()
759
9913
    : d_instantiations(smtStatisticsRegistry().registerInt(
760
19826
        "Instantiate::Instantiations_Total")),
761
      d_inst_duplicate(
762
19826
          smtStatisticsRegistry().registerInt("Instantiate::Duplicate_Inst")),
763
9913
      d_inst_duplicate_eq(smtStatisticsRegistry().registerInt(
764
19826
          "Instantiate::Duplicate_Inst_Eq")),
765
9913
      d_inst_duplicate_ent(smtStatisticsRegistry().registerInt(
766
39652
          "Instantiate::Duplicate_Inst_Entailed"))
767
{
768
9913
}
769
770
}  // namespace quantifiers
771
}  // namespace theory
772
29502
}  // namespace cvc5