GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/ematching/trigger.cpp Lines: 94 115 81.7 %
Date: 2021-08-01 Branches: 167 458 36.5 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Morgan Deters, Tim King
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 trigger class.
14
 */
15
16
#include "theory/quantifiers/ematching/trigger.h"
17
18
#include "expr/skolem_manager.h"
19
#include "options/base_options.h"
20
#include "options/outputc.h"
21
#include "options/quantifiers_options.h"
22
#include "theory/quantifiers/ematching/candidate_generator.h"
23
#include "theory/quantifiers/ematching/inst_match_generator.h"
24
#include "theory/quantifiers/ematching/inst_match_generator_multi.h"
25
#include "theory/quantifiers/ematching/inst_match_generator_multi_linear.h"
26
#include "theory/quantifiers/ematching/inst_match_generator_simple.h"
27
#include "theory/quantifiers/ematching/pattern_term_selector.h"
28
#include "theory/quantifiers/ematching/trigger_trie.h"
29
#include "theory/quantifiers/inst_match.h"
30
#include "theory/quantifiers/instantiate.h"
31
#include "theory/quantifiers/quantifiers_attributes.h"
32
#include "theory/quantifiers/quantifiers_inference_manager.h"
33
#include "theory/quantifiers/quantifiers_registry.h"
34
#include "theory/quantifiers/quantifiers_state.h"
35
#include "theory/quantifiers/term_util.h"
36
#include "theory/valuation.h"
37
38
using namespace cvc5::kind;
39
40
namespace cvc5 {
41
namespace theory {
42
namespace quantifiers {
43
namespace inst {
44
45
/** trigger class constructor */
46
16852
Trigger::Trigger(QuantifiersState& qs,
47
                 QuantifiersInferenceManager& qim,
48
                 QuantifiersRegistry& qr,
49
                 TermRegistry& tr,
50
                 Node q,
51
16852
                 std::vector<Node>& nodes)
52
16852
    : d_qstate(qs), d_qim(qim), d_qreg(qr), d_treg(tr), d_quant(q)
53
{
54
  // We must ensure that the ground subterms of the trigger have been
55
  // preprocessed.
56
16852
  Valuation& val = d_qstate.getValuation();
57
35205
  for (const Node& n : nodes)
58
  {
59
36706
    Node np = ensureGroundTermPreprocessed(val, n, d_groundTerms);
60
18353
    d_nodes.push_back(np);
61
  }
62
16852
  d_trNode = NodeManager::currentNM()->mkNode(SEXPR, d_nodes);
63
16852
  if (Trace.isOn("trigger"))
64
  {
65
    QuantAttributes& qa = d_qreg.getQuantAttributes();
66
    Trace("trigger") << "Trigger for " << qa.quantToString(q) << ": "
67
                     << std::endl;
68
    for (const Node& n : d_nodes)
69
    {
70
      Trace("trigger") << "   " << n << std::endl;
71
    }
72
  }
73
16852
  if (Output.isOn(options::OutputTag::TRIGGER))
74
  {
75
    QuantAttributes& qa = d_qreg.getQuantAttributes();
76
    Output(options::OutputTag::TRIGGER)
77
        << "(trigger " << qa.quantToString(q) << " (";
78
    for (size_t i = 0, nnodes = d_nodes.size(); i < nnodes; i++)
79
    {
80
      // note we must display the original form, so we go back to bound vars
81
      Node ns = d_qreg.substituteInstConstantsToBoundVariables(d_nodes[i], q);
82
      Output(options::OutputTag::TRIGGER) << (i > 0 ? " " : "") << ns;
83
    }
84
    Output(options::OutputTag::TRIGGER) << "))" << std::endl;
85
  }
86
16852
  QuantifiersStatistics& stats = qs.getStats();
87
16852
  if( d_nodes.size()==1 ){
88
15632
    if (TriggerTermInfo::isSimpleTrigger(d_nodes[0]))
89
    {
90
7646
      d_mg = new InstMatchGeneratorSimple(this, q, d_nodes[0]);
91
7646
      ++(stats.d_triggers);
92
    }else{
93
7986
      d_mg = InstMatchGenerator::mkInstMatchGenerator(this, q, d_nodes[0]);
94
7986
      ++(stats.d_simple_triggers);
95
    }
96
  }else{
97
2440
    if( options::multiTriggerCache() ){
98
10
      d_mg = new InstMatchGeneratorMulti(this, q, d_nodes);
99
    }else{
100
1210
      d_mg = InstMatchGenerator::mkInstMatchGeneratorMulti(this, q, d_nodes);
101
    }
102
1220
    if (Trace.isOn("multi-trigger"))
103
    {
104
      Trace("multi-trigger") << "Trigger for " << q << ": " << std::endl;
105
      for (const Node& nc : d_nodes)
106
      {
107
        Trace("multi-trigger") << "   " << nc << std::endl;
108
      }
109
    }
110
1220
    ++(stats.d_multi_triggers);
111
  }
112
113
16852
  Trace("trigger-debug") << "Finished making trigger." << std::endl;
114
16852
}
115
116
50520
Trigger::~Trigger() {
117
16852
  delete d_mg;
118
33668
}
119
120
145640
void Trigger::resetInstantiationRound() { d_mg->resetInstantiationRound(); }
121
122
145640
void Trigger::reset(Node eqc) { d_mg->reset(eqc); }
123
124
22266
bool Trigger::isMultiTrigger() const { return d_nodes.size() > 1; }
125
126
Node Trigger::getInstPattern() const
127
{
128
  return NodeManager::currentNM()->mkNode( INST_PATTERN, d_nodes );
129
}
130
131
47191
uint64_t Trigger::addInstantiations()
132
{
133
47191
  uint64_t gtAddedLemmas = 0;
134
47191
  if (!d_groundTerms.empty())
135
  {
136
    // for each ground term t that does not exist in the equality engine, we
137
    // add a purification lemma of the form (k = t).
138
3951
    eq::EqualityEngine* ee = d_qstate.getEqualityEngine();
139
8035
    for (const Node& gt : d_groundTerms)
140
    {
141
4084
      if (!ee->hasTerm(gt))
142
      {
143
472
        SkolemManager* sm = NodeManager::currentNM()->getSkolemManager();
144
944
        Node k = sm->mkPurifySkolem(gt, "gt");
145
944
        Node eq = k.eqNode(gt);
146
944
        Trace("trigger-gt-lemma")
147
472
            << "Trigger: ground term purify lemma: " << eq << std::endl;
148
472
        d_qim.addPendingLemma(eq, InferenceId::UNKNOWN);
149
472
        gtAddedLemmas++;
150
      }
151
    }
152
  }
153
47191
  uint64_t addedLemmas = d_mg->addInstantiations(d_quant);
154
47191
  if (Debug.isOn("inst-trigger"))
155
  {
156
    if (addedLemmas > 0)
157
    {
158
      Debug("inst-trigger") << "Added " << addedLemmas
159
                            << " lemmas, trigger was " << d_nodes << std::endl;
160
    }
161
  }
162
47191
  return gtAddedLemmas + addedLemmas;
163
}
164
165
120584
bool Trigger::sendInstantiation(std::vector<Node>& m, InferenceId id)
166
{
167
120584
  return d_qim.getInstantiate()->addInstantiation(d_quant, m, id, d_trNode);
168
}
169
170
120776
bool Trigger::sendInstantiation(InstMatch& m, InferenceId id)
171
{
172
120776
  return sendInstantiation(m.d_vals, id);
173
}
174
175
int Trigger::getActiveScore() { return d_mg->getActiveScore(); }
176
177
18353
Node Trigger::ensureGroundTermPreprocessed(Valuation& val,
178
                                           Node n,
179
                                           std::vector<Node>& gts)
180
{
181
18353
  NodeManager* nm = NodeManager::currentNM();
182
36706
  std::unordered_map<TNode, Node> visited;
183
18353
  std::unordered_map<TNode, Node>::iterator it;
184
36706
  std::vector<TNode> visit;
185
36706
  TNode cur;
186
18353
  visit.push_back(n);
187
138297
  do
188
  {
189
156650
    cur = visit.back();
190
156650
    visit.pop_back();
191
156650
    it = visited.find(cur);
192
156650
    if (it == visited.end())
193
    {
194
106058
      if (cur.getNumChildren() == 0)
195
      {
196
55984
        visited[cur] = cur;
197
      }
198
50074
      else if (!TermUtil::hasInstConstAttr(cur))
199
      {
200
        // cur has no INST_CONSTANT, thus is ground.
201
3070
        Node vcur = val.getPreprocessedTerm(cur);
202
1535
        gts.push_back(vcur);
203
1535
        visited[cur] = vcur;
204
      }
205
      else
206
      {
207
48539
        visited[cur] = Node::null();
208
48539
        visit.push_back(cur);
209
48539
        visit.insert(visit.end(), cur.begin(), cur.end());
210
      }
211
    }
212
50592
    else if (it->second.isNull())
213
    {
214
97078
      Node ret = cur;
215
48539
      bool childChanged = false;
216
97078
      std::vector<Node> children;
217
48539
      if (cur.getMetaKind() == metakind::PARAMETERIZED)
218
      {
219
40792
        children.push_back(cur.getOperator());
220
      }
221
138297
      for (const Node& cn : cur)
222
      {
223
89758
        it = visited.find(cn);
224
89758
        Assert(it != visited.end());
225
89758
        Assert(!it->second.isNull());
226
89758
        childChanged = childChanged || cn != it->second;
227
89758
        children.push_back(it->second);
228
      }
229
48539
      if (childChanged)
230
      {
231
521
        ret = nm->mkNode(cur.getKind(), children);
232
      }
233
48539
      visited[cur] = ret;
234
    }
235
156650
  } while (!visit.empty());
236
18353
  Assert(visited.find(n) != visited.end());
237
18353
  Assert(!visited.find(n)->second.isNull());
238
36706
  return visited[n];
239
}
240
241
33280
void Trigger::debugPrint(const char* c) const
242
{
243
33280
  Trace(c) << "TRIGGER( " << d_nodes << " )" << std::endl;
244
33280
}
245
246
}  // namespace inst
247
}  // namespace quantifiers
248
}  // namespace theory
249
30500
}  // namespace cvc5