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 |
9854 |
TheoryBags::TheoryBags(Env& env, OutputChannel& out, Valuation valuation) |
31 |
|
: Theory(THEORY_BAGS, env, out, valuation), |
32 |
|
d_state(env, valuation), |
33 |
|
d_im(*this, d_state, d_pnm), |
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(d_state, d_im), |
39 |
9854 |
d_solver(d_state, d_im, d_termReg) |
40 |
|
{ |
41 |
|
// use the official theory state and inference manager objects |
42 |
9854 |
d_theoryState = &d_state; |
43 |
9854 |
d_inferManager = &d_im; |
44 |
9854 |
} |
45 |
|
|
46 |
19708 |
TheoryBags::~TheoryBags() {} |
47 |
|
|
48 |
9854 |
TheoryRewriter* TheoryBags::getTheoryRewriter() { return &d_rewriter; } |
49 |
|
|
50 |
3769 |
ProofRuleChecker* TheoryBags::getProofChecker() { return nullptr; } |
51 |
|
|
52 |
9854 |
bool TheoryBags::needsEqualityEngine(EeSetupInfo& esi) |
53 |
|
{ |
54 |
9854 |
esi.d_notify = &d_notify; |
55 |
9854 |
esi.d_name = "theory::bags::ee"; |
56 |
9854 |
return true; |
57 |
|
} |
58 |
|
|
59 |
9854 |
void TheoryBags::finishInit() |
60 |
|
{ |
61 |
9854 |
Assert(d_equalityEngine != nullptr); |
62 |
|
|
63 |
|
// choice is used to eliminate witness |
64 |
9854 |
d_valuation.setUnevaluatedKind(WITNESS); |
65 |
|
|
66 |
|
// functions we are doing congruence over |
67 |
9854 |
d_equalityEngine->addFunctionKind(UNION_MAX); |
68 |
9854 |
d_equalityEngine->addFunctionKind(UNION_DISJOINT); |
69 |
9854 |
d_equalityEngine->addFunctionKind(INTERSECTION_MIN); |
70 |
9854 |
d_equalityEngine->addFunctionKind(DIFFERENCE_SUBTRACT); |
71 |
9854 |
d_equalityEngine->addFunctionKind(DIFFERENCE_REMOVE); |
72 |
9854 |
d_equalityEngine->addFunctionKind(BAG_COUNT); |
73 |
9854 |
d_equalityEngine->addFunctionKind(DUPLICATE_REMOVAL); |
74 |
9854 |
d_equalityEngine->addFunctionKind(MK_BAG); |
75 |
9854 |
d_equalityEngine->addFunctionKind(BAG_CARD); |
76 |
9854 |
d_equalityEngine->addFunctionKind(BAG_FROM_SET); |
77 |
9854 |
d_equalityEngine->addFunctionKind(BAG_TO_SET); |
78 |
9854 |
} |
79 |
|
|
80 |
24567 |
void TheoryBags::postCheck(Effort effort) |
81 |
|
{ |
82 |
24567 |
d_im.doPendingFacts(); |
83 |
|
// TODO issue #78: add Assert(d_strat.isStrategyInit()); |
84 |
24567 |
if (!d_state.isInConflict() && !d_valuation.needCheck()) |
85 |
|
// TODO issue #78: add && d_strat.hasStrategyEffort(e)) |
86 |
|
{ |
87 |
15075 |
Trace("bags::TheoryBags::postCheck") << "effort: " << std::endl; |
88 |
|
|
89 |
|
// TODO issue #78: add ++(d_statistics.d_checkRuns); |
90 |
15075 |
bool sentLemma = false; |
91 |
15075 |
bool hadPending = false; |
92 |
15075 |
Trace("bags-check") << "Full effort check..." << std::endl; |
93 |
|
do |
94 |
|
{ |
95 |
15075 |
d_im.reset(); |
96 |
|
// TODO issue #78: add ++(d_statistics.d_strategyRuns); |
97 |
15075 |
Trace("bags-check") << " * Run strategy..." << std::endl; |
98 |
|
// TODO issue #78: add runStrategy(e); |
99 |
|
|
100 |
15075 |
d_solver.postCheck(); |
101 |
|
|
102 |
|
// remember if we had pending facts or lemmas |
103 |
15075 |
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 |
15075 |
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 |
15075 |
sentLemma = d_im.hasSentLemma(); |
114 |
15075 |
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 |
15075 |
} while (!d_state.isInConflict() && !sentLemma && hadPending); |
129 |
|
} |
130 |
24567 |
Trace("bags-check") << "Theory of bags, done check : " << effort << std::endl; |
131 |
24567 |
Assert(!d_im.hasPendingFact()); |
132 |
24567 |
Assert(!d_im.hasPendingLemma()); |
133 |
24567 |
} |
134 |
|
|
135 |
2649 |
void TheoryBags::notifyFact(TNode atom, |
136 |
|
bool polarity, |
137 |
|
TNode fact, |
138 |
|
bool isInternal) |
139 |
|
{ |
140 |
2649 |
} |
141 |
|
|
142 |
4929 |
bool TheoryBags::collectModelValues(TheoryModel* m, |
143 |
|
const std::set<Node>& termSet) |
144 |
|
{ |
145 |
4929 |
Trace("bags-model") << "TheoryBags : Collect model values" << std::endl; |
146 |
|
|
147 |
4929 |
Trace("bags-model") << "Term set: " << termSet << std::endl; |
148 |
|
|
149 |
9858 |
std::set<Node> processedBags; |
150 |
|
|
151 |
|
// get the relevant bag equivalence classes |
152 |
5136 |
for (const Node& n : termSet) |
153 |
|
{ |
154 |
237 |
TypeNode tn = n.getType(); |
155 |
207 |
if (!tn.isBag()) |
156 |
|
{ |
157 |
|
// we are only concerned here about bag terms |
158 |
151 |
continue; |
159 |
|
} |
160 |
86 |
Node r = d_state.getRepresentative(n); |
161 |
56 |
if (processedBags.find(r) != processedBags.end()) |
162 |
|
{ |
163 |
|
// skip bags whose representatives are already processed |
164 |
26 |
continue; |
165 |
|
} |
166 |
|
|
167 |
30 |
processedBags.insert(r); |
168 |
|
|
169 |
60 |
std::set<Node> solverElements = d_state.getElements(r); |
170 |
60 |
std::set<Node> elements; |
171 |
|
// only consider terms in termSet and ignore other elements in the solver |
172 |
30 |
std::set_intersection(termSet.begin(), |
173 |
|
termSet.end(), |
174 |
|
solverElements.begin(), |
175 |
|
solverElements.end(), |
176 |
30 |
std::inserter(elements, elements.begin())); |
177 |
60 |
Trace("bags-model") << "Elements of bag " << n << " are: " << std::endl |
178 |
30 |
<< elements << std::endl; |
179 |
60 |
std::map<Node, Node> elementReps; |
180 |
72 |
for (const Node& e : elements) |
181 |
|
{ |
182 |
84 |
Node key = d_state.getRepresentative(e); |
183 |
84 |
Node countTerm = NodeManager::currentNM()->mkNode(BAG_COUNT, e, r); |
184 |
84 |
Node value = d_state.getRepresentative(countTerm); |
185 |
42 |
elementReps[key] = value; |
186 |
|
} |
187 |
60 |
Node rep = NormalForm::constructBagFromElements(tn, elementReps); |
188 |
30 |
rep = Rewriter::rewrite(rep); |
189 |
|
|
190 |
30 |
Trace("bags-model") << "rep of " << n << " is: " << rep << std::endl; |
191 |
72 |
for (std::pair<Node, Node> pair : elementReps) |
192 |
|
{ |
193 |
42 |
m->assertSkeleton(pair.first); |
194 |
42 |
m->assertSkeleton(pair.second); |
195 |
|
} |
196 |
30 |
m->assertEquality(rep, n, true); |
197 |
30 |
m->assertSkeleton(rep); |
198 |
|
} |
199 |
9858 |
return true; |
200 |
|
} |
201 |
|
|
202 |
925 |
TrustNode TheoryBags::explain(TNode node) { return d_im.explainLit(node); } |
203 |
|
|
204 |
|
Node TheoryBags::getModelValue(TNode node) { return Node::null(); } |
205 |
|
|
206 |
1367 |
void TheoryBags::preRegisterTerm(TNode n) |
207 |
|
{ |
208 |
1367 |
Trace("bags::TheoryBags::preRegisterTerm") << n << std::endl; |
209 |
1367 |
switch (n.getKind()) |
210 |
|
{ |
211 |
|
case BAG_CARD: |
212 |
|
case BAG_FROM_SET: |
213 |
|
case BAG_TO_SET: |
214 |
|
case BAG_IS_SINGLETON: |
215 |
|
{ |
216 |
|
std::stringstream ss; |
217 |
|
ss << "Term of kind " << n.getKind() << " is not supported yet"; |
218 |
|
throw LogicException(ss.str()); |
219 |
|
} |
220 |
1367 |
default: break; |
221 |
|
} |
222 |
1367 |
} |
223 |
|
|
224 |
15205 |
void TheoryBags::presolve() {} |
225 |
|
|
226 |
|
/**************************** eq::NotifyClass *****************************/ |
227 |
|
|
228 |
1181 |
void TheoryBags::eqNotifyNewClass(TNode n) {} |
229 |
|
|
230 |
1941 |
void TheoryBags::eqNotifyMerge(TNode n1, TNode n2) {} |
231 |
|
|
232 |
246 |
void TheoryBags::eqNotifyDisequal(TNode n1, TNode n2, TNode reason) {} |
233 |
|
|
234 |
1181 |
void TheoryBags::NotifyClass::eqNotifyNewClass(TNode n) |
235 |
|
{ |
236 |
2362 |
Debug("bags-eq") << "[bags-eq] eqNotifyNewClass:" |
237 |
1181 |
<< " n = " << n << std::endl; |
238 |
1181 |
d_theory.eqNotifyNewClass(n); |
239 |
1181 |
} |
240 |
|
|
241 |
1941 |
void TheoryBags::NotifyClass::eqNotifyMerge(TNode n1, TNode n2) |
242 |
|
{ |
243 |
3882 |
Debug("bags-eq") << "[bags-eq] eqNotifyMerge:" |
244 |
1941 |
<< " n1 = " << n1 << " n2 = " << n2 << std::endl; |
245 |
1941 |
d_theory.eqNotifyMerge(n1, n2); |
246 |
1941 |
} |
247 |
|
|
248 |
246 |
void TheoryBags::NotifyClass::eqNotifyDisequal(TNode n1, TNode n2, TNode reason) |
249 |
|
{ |
250 |
492 |
Debug("bags-eq") << "[bags-eq] eqNotifyDisequal:" |
251 |
246 |
<< " n1 = " << n1 << " n2 = " << n2 << " reason = " << reason |
252 |
246 |
<< std::endl; |
253 |
246 |
d_theory.eqNotifyDisequal(n1, n2, reason); |
254 |
246 |
} |
255 |
|
|
256 |
|
} // namespace bags |
257 |
|
} // namespace theory |
258 |
29349 |
} // namespace cvc5 |