GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/bags/theory_bags.cpp Lines: 105 117 89.7 %
Date: 2021-11-07 Branches: 154 384 40.1 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Mudathir Mohamed, Haniel Barbosa, Andrew Reynolds
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
 * Bags theory.
14
 */
15
16
#include "theory/bags/theory_bags.h"
17
18
#include "proof/proof_checker.h"
19
#include "smt/logic_exception.h"
20
#include "theory/bags/normal_form.h"
21
#include "theory/rewriter.h"
22
#include "theory/theory_model.h"
23
24
using namespace cvc5::kind;
25
26
namespace cvc5 {
27
namespace theory {
28
namespace bags {
29
30
15273
TheoryBags::TheoryBags(Env& env, OutputChannel& out, Valuation valuation)
31
    : Theory(THEORY_BAGS, env, out, valuation),
32
      d_state(env, valuation),
33
      d_im(env, *this, d_state),
34
      d_ig(&d_state, &d_im),
35
      d_notify(*this, d_im),
36
      d_statistics(),
37
      d_rewriter(&d_statistics.d_rewrites),
38
      d_termReg(env, d_state, d_im),
39
15273
      d_solver(env, d_state, d_im, d_termReg)
40
{
41
  // use the official theory state and inference manager objects
42
15273
  d_theoryState = &d_state;
43
15273
  d_inferManager = &d_im;
44
15273
}
45
46
30536
TheoryBags::~TheoryBags() {}
47
48
15273
TheoryRewriter* TheoryBags::getTheoryRewriter() { return &d_rewriter; }
49
50
7989
ProofRuleChecker* TheoryBags::getProofChecker() { return nullptr; }
51
52
15273
bool TheoryBags::needsEqualityEngine(EeSetupInfo& esi)
53
{
54
15273
  esi.d_notify = &d_notify;
55
15273
  esi.d_name = "theory::bags::ee";
56
15273
  return true;
57
}
58
59
15273
void TheoryBags::finishInit()
60
{
61
15273
  Assert(d_equalityEngine != nullptr);
62
63
  // choice is used to eliminate witness
64
15273
  d_valuation.setUnevaluatedKind(WITNESS);
65
66
  // functions we are doing congruence over
67
15273
  d_equalityEngine->addFunctionKind(UNION_MAX);
68
15273
  d_equalityEngine->addFunctionKind(UNION_DISJOINT);
69
15273
  d_equalityEngine->addFunctionKind(INTERSECTION_MIN);
70
15273
  d_equalityEngine->addFunctionKind(DIFFERENCE_SUBTRACT);
71
15273
  d_equalityEngine->addFunctionKind(DIFFERENCE_REMOVE);
72
15273
  d_equalityEngine->addFunctionKind(BAG_COUNT);
73
15273
  d_equalityEngine->addFunctionKind(DUPLICATE_REMOVAL);
74
15273
  d_equalityEngine->addFunctionKind(MK_BAG);
75
15273
  d_equalityEngine->addFunctionKind(BAG_CARD);
76
15273
  d_equalityEngine->addFunctionKind(BAG_FROM_SET);
77
15273
  d_equalityEngine->addFunctionKind(BAG_TO_SET);
78
15273
}
79
80
29321
void TheoryBags::postCheck(Effort effort)
81
{
82
29321
  d_im.doPendingFacts();
83
  // TODO issue #78: add Assert(d_strat.isStrategyInit());
84
29321
  if (!d_state.isInConflict() && !d_valuation.needCheck())
85
  // TODO issue #78:  add && d_strat.hasStrategyEffort(e))
86
  {
87
18192
    Trace("bags::TheoryBags::postCheck") << "effort: " << std::endl;
88
89
    // TODO issue #78: add ++(d_statistics.d_checkRuns);
90
18192
    bool sentLemma = false;
91
18192
    bool hadPending = false;
92
18192
    Trace("bags-check") << "Full effort check..." << std::endl;
93
    do
94
    {
95
18192
      d_im.reset();
96
      // TODO issue #78: add ++(d_statistics.d_strategyRuns);
97
18192
      Trace("bags-check") << "  * Run strategy..." << std::endl;
98
      // TODO issue #78: add runStrategy(e);
99
100
18192
      d_solver.postCheck();
101
102
      // remember if we had pending facts or lemmas
103
18192
      hadPending = d_im.hasPending();
104
      // Send the facts *and* the lemmas. We send lemmas regardless of whether
105
      // we send facts since some lemmas cannot be dropped. Other lemmas are
106
      // otherwise avoided by aborting the strategy when a fact is ready.
107
18192
      d_im.doPending();
108
      // Did we successfully send a lemma? Notice that if hasPending = true
109
      // and sentLemma = false, then the above call may have:
110
      // (1) had no pending lemmas, but successfully processed pending facts,
111
      // (2) unsuccessfully processed pending lemmas.
112
      // In either case, we repeat the strategy if we are not in conflict.
113
18192
      sentLemma = d_im.hasSentLemma();
114
18192
      if (Trace.isOn("bags-check"))
115
      {
116
        // TODO: clean this Trace("bags-check") << "  ...finish run strategy: ";
117
        Trace("bags-check") << (hadPending ? "hadPending " : "");
118
        Trace("bags-check") << (sentLemma ? "sentLemma " : "");
119
        Trace("bags-check") << (d_state.isInConflict() ? "conflict " : "");
120
        if (!hadPending && !sentLemma && !d_state.isInConflict())
121
        {
122
          Trace("bags-check") << "(none)";
123
        }
124
        Trace("bags-check") << std::endl;
125
      }
126
      // repeat if we did not add a lemma or conflict, and we had pending
127
      // facts or lemmas.
128
18192
    } while (!d_state.isInConflict() && !sentLemma && hadPending);
129
  }
130
29321
  Trace("bags-check") << "Theory of bags, done check : " << effort << std::endl;
131
29321
  Assert(!d_im.hasPendingFact());
132
29321
  Assert(!d_im.hasPendingLemma());
133
29321
}
134
135
4139
void TheoryBags::notifyFact(TNode atom,
136
                            bool polarity,
137
                            TNode fact,
138
                            bool isInternal)
139
{
140
4139
}
141
142
7022
bool TheoryBags::collectModelValues(TheoryModel* m,
143
                                    const std::set<Node>& termSet)
144
{
145
7022
  Trace("bags-model") << "TheoryBags : Collect model values" << std::endl;
146
147
7022
  Trace("bags-model") << "Term set: " << termSet << std::endl;
148
149
14044
  std::set<Node> processedBags;
150
151
  // get the relevant bag equivalence classes
152
7438
  for (const Node& n : termSet)
153
  {
154
468
    TypeNode tn = n.getType();
155
416
    if (!tn.isBag())
156
    {
157
      // we are only concerned here about bag terms
158
301
      continue;
159
    }
160
167
    Node r = d_state.getRepresentative(n);
161
115
    if (processedBags.find(r) != processedBags.end())
162
    {
163
      // skip bags whose representatives are already processed
164
63
      continue;
165
    }
166
167
52
    processedBags.insert(r);
168
169
104
    std::set<Node> solverElements = d_state.getElements(r);
170
104
    std::set<Node> elements;
171
    // only consider terms in termSet and ignore other elements in the solver
172
52
    std::set_intersection(termSet.begin(),
173
                          termSet.end(),
174
                          solverElements.begin(),
175
                          solverElements.end(),
176
52
                          std::inserter(elements, elements.begin()));
177
104
    Trace("bags-model") << "Elements of bag " << n << " are: " << std::endl
178
52
                        << elements << std::endl;
179
104
    std::map<Node, Node> elementReps;
180
113
    for (const Node& e : elements)
181
    {
182
122
      Node key = d_state.getRepresentative(e);
183
122
      Node countTerm = NodeManager::currentNM()->mkNode(BAG_COUNT, e, r);
184
122
      Node value = d_state.getRepresentative(countTerm);
185
61
      elementReps[key] = value;
186
    }
187
104
    Node rep = NormalForm::constructBagFromElements(tn, elementReps);
188
52
    rep = rewrite(rep);
189
52
    Trace("bags-model") << "rep of " << n << " is: " << rep << std::endl;
190
52
    m->assertEquality(rep, n, true);
191
52
    m->assertSkeleton(rep);
192
  }
193
14044
  return true;
194
}
195
196
1016
TrustNode TheoryBags::explain(TNode node) { return d_im.explainLit(node); }
197
198
Node TheoryBags::getModelValue(TNode node) { return Node::null(); }
199
200
1965
void TheoryBags::preRegisterTerm(TNode n)
201
{
202
1965
  Trace("bags::TheoryBags::preRegisterTerm") << n << std::endl;
203
1965
  switch (n.getKind())
204
  {
205
    case BAG_CARD:
206
    case BAG_FROM_SET:
207
    case BAG_TO_SET:
208
    case BAG_IS_SINGLETON:
209
    {
210
      std::stringstream ss;
211
      ss << "Term of kind " << n.getKind() << " is not supported yet";
212
      throw LogicException(ss.str());
213
    }
214
1965
    default: break;
215
  }
216
1965
}
217
218
20560
void TheoryBags::presolve() {}
219
220
/**************************** eq::NotifyClass *****************************/
221
222
1902
void TheoryBags::eqNotifyNewClass(TNode n) {}
223
224
3342
void TheoryBags::eqNotifyMerge(TNode n1, TNode n2) {}
225
226
388
void TheoryBags::eqNotifyDisequal(TNode n1, TNode n2, TNode reason) {}
227
228
1902
void TheoryBags::NotifyClass::eqNotifyNewClass(TNode n)
229
{
230
3804
  Debug("bags-eq") << "[bags-eq] eqNotifyNewClass:"
231
1902
                   << " n = " << n << std::endl;
232
1902
  d_theory.eqNotifyNewClass(n);
233
1902
}
234
235
3342
void TheoryBags::NotifyClass::eqNotifyMerge(TNode n1, TNode n2)
236
{
237
6684
  Debug("bags-eq") << "[bags-eq] eqNotifyMerge:"
238
3342
                   << " n1 = " << n1 << " n2 = " << n2 << std::endl;
239
3342
  d_theory.eqNotifyMerge(n1, n2);
240
3342
}
241
242
388
void TheoryBags::NotifyClass::eqNotifyDisequal(TNode n1, TNode n2, TNode reason)
243
{
244
776
  Debug("bags-eq") << "[bags-eq] eqNotifyDisequal:"
245
388
                   << " n1 = " << n1 << " n2 = " << n2 << " reason = " << reason
246
388
                   << std::endl;
247
388
  d_theory.eqNotifyDisequal(n1, n2, reason);
248
388
}
249
250
}  // namespace bags
251
}  // namespace theory
252
31137
}  // namespace cvc5