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