42a1e2c6bbf8202ad21da97bcda4ebcfc753cac7
1 /******************************************************************************
2 * Top contributors (to current version):
3 * Mudathir Mohamed, Haniel Barbosa, Andrew Reynolds
5 * This file is part of the cvc5 project.
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 * ****************************************************************************
16 #include "theory/bags/theory_bags.h"
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"
24 using namespace cvc5::kind
;
30 TheoryBags::TheoryBags(Env
& env
, OutputChannel
& out
, Valuation valuation
)
31 : Theory(THEORY_BAGS
, env
, out
, valuation
),
32 d_state(getSatContext(), getUserContext(), valuation
),
33 d_im(*this, d_state
, d_pnm
),
34 d_ig(&d_state
, &d_im
),
35 d_notify(*this, d_im
),
37 d_rewriter(&d_statistics
.d_rewrites
),
38 d_termReg(d_state
, d_im
),
39 d_solver(d_state
, d_im
, d_termReg
)
41 // use the official theory state and inference manager objects
42 d_theoryState
= &d_state
;
43 d_inferManager
= &d_im
;
46 TheoryBags::~TheoryBags() {}
48 TheoryRewriter
* TheoryBags::getTheoryRewriter() { return &d_rewriter
; }
50 ProofRuleChecker
* TheoryBags::getProofChecker() { return nullptr; }
52 bool TheoryBags::needsEqualityEngine(EeSetupInfo
& esi
)
54 esi
.d_notify
= &d_notify
;
55 esi
.d_name
= "theory::bags::ee";
59 void TheoryBags::finishInit()
61 Assert(d_equalityEngine
!= nullptr);
63 // choice is used to eliminate witness
64 d_valuation
.setUnevaluatedKind(WITNESS
);
66 // functions we are doing congruence over
67 d_equalityEngine
->addFunctionKind(UNION_MAX
);
68 d_equalityEngine
->addFunctionKind(UNION_DISJOINT
);
69 d_equalityEngine
->addFunctionKind(INTERSECTION_MIN
);
70 d_equalityEngine
->addFunctionKind(DIFFERENCE_SUBTRACT
);
71 d_equalityEngine
->addFunctionKind(DIFFERENCE_REMOVE
);
72 d_equalityEngine
->addFunctionKind(BAG_COUNT
);
73 d_equalityEngine
->addFunctionKind(DUPLICATE_REMOVAL
);
74 d_equalityEngine
->addFunctionKind(MK_BAG
);
75 d_equalityEngine
->addFunctionKind(BAG_CARD
);
76 d_equalityEngine
->addFunctionKind(BAG_FROM_SET
);
77 d_equalityEngine
->addFunctionKind(BAG_TO_SET
);
80 void TheoryBags::postCheck(Effort effort
)
82 d_im
.doPendingFacts();
83 // TODO issue #78: add Assert(d_strat.isStrategyInit());
84 if (!d_state
.isInConflict() && !d_valuation
.needCheck())
85 // TODO issue #78: add && d_strat.hasStrategyEffort(e))
87 Trace("bags::TheoryBags::postCheck") << "effort: " << std::endl
;
89 // TODO issue #78: add ++(d_statistics.d_checkRuns);
90 bool sentLemma
= false;
91 bool hadPending
= false;
92 Trace("bags-check") << "Full effort check..." << std::endl
;
96 // TODO issue #78: add ++(d_statistics.d_strategyRuns);
97 Trace("bags-check") << " * Run strategy..." << std::endl
;
98 // TODO issue #78: add runStrategy(e);
100 d_solver
.postCheck();
102 // remember if we had pending facts or lemmas
103 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.
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 sentLemma
= d_im
.hasSentLemma();
114 if (Trace
.isOn("bags-check"))
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())
122 Trace("bags-check") << "(none)";
124 Trace("bags-check") << std::endl
;
126 // repeat if we did not add a lemma or conflict, and we had pending
128 } while (!d_state
.isInConflict() && !sentLemma
&& hadPending
);
130 Trace("bags-check") << "Theory of bags, done check : " << effort
<< std::endl
;
131 Assert(!d_im
.hasPendingFact());
132 Assert(!d_im
.hasPendingLemma());
135 void TheoryBags::notifyFact(TNode atom
,
142 bool TheoryBags::collectModelValues(TheoryModel
* m
,
143 const std::set
<Node
>& termSet
)
145 Trace("bags-model") << "TheoryBags : Collect model values" << std::endl
;
147 Trace("bags-model") << "Term set: " << termSet
<< std::endl
;
149 std::set
<Node
> processedBags
;
151 // get the relevant bag equivalence classes
152 for (const Node
& n
: termSet
)
154 TypeNode tn
= n
.getType();
157 // we are only concerned here about bag terms
160 Node r
= d_state
.getRepresentative(n
);
161 if (processedBags
.find(r
) != processedBags
.end())
163 // skip bags whose representatives are already processed
167 processedBags
.insert(r
);
169 std::set
<Node
> solverElements
= d_state
.getElements(r
);
170 std::set
<Node
> elements
;
171 // only consider terms in termSet and ignore other elements in the solver
172 std::set_intersection(termSet
.begin(),
174 solverElements
.begin(),
175 solverElements
.end(),
176 std::inserter(elements
, elements
.begin()));
177 Trace("bags-model") << "Elements of bag " << n
<< " are: " << std::endl
178 << elements
<< std::endl
;
179 std::map
<Node
, Node
> elementReps
;
180 for (const Node
& e
: elements
)
182 Node key
= d_state
.getRepresentative(e
);
183 Node countTerm
= NodeManager::currentNM()->mkNode(BAG_COUNT
, e
, r
);
184 Node value
= d_state
.getRepresentative(countTerm
);
185 elementReps
[key
] = value
;
187 Node rep
= NormalForm::constructBagFromElements(tn
, elementReps
);
188 rep
= Rewriter::rewrite(rep
);
190 Trace("bags-model") << "rep of " << n
<< " is: " << rep
<< std::endl
;
191 for (std::pair
<Node
, Node
> pair
: elementReps
)
193 m
->assertSkeleton(pair
.first
);
194 m
->assertSkeleton(pair
.second
);
196 m
->assertEquality(rep
, n
, true);
197 m
->assertSkeleton(rep
);
202 TrustNode
TheoryBags::explain(TNode node
) { return d_im
.explainLit(node
); }
204 Node
TheoryBags::getModelValue(TNode node
) { return Node::null(); }
206 void TheoryBags::preRegisterTerm(TNode n
)
208 Trace("bags::TheoryBags::preRegisterTerm") << n
<< std::endl
;
214 case BAG_IS_SINGLETON
:
216 std::stringstream ss
;
217 ss
<< "Term of kind " << n
.getKind() << " is not supported yet";
218 throw LogicException(ss
.str());
224 void TheoryBags::presolve() {}
226 /**************************** eq::NotifyClass *****************************/
228 void TheoryBags::eqNotifyNewClass(TNode n
) {}
230 void TheoryBags::eqNotifyMerge(TNode n1
, TNode n2
) {}
232 void TheoryBags::eqNotifyDisequal(TNode n1
, TNode n2
, TNode reason
) {}
234 void TheoryBags::NotifyClass::eqNotifyNewClass(TNode n
)
236 Debug("bags-eq") << "[bags-eq] eqNotifyNewClass:"
237 << " n = " << n
<< std::endl
;
238 d_theory
.eqNotifyNewClass(n
);
241 void TheoryBags::NotifyClass::eqNotifyMerge(TNode n1
, TNode n2
)
243 Debug("bags-eq") << "[bags-eq] eqNotifyMerge:"
244 << " n1 = " << n1
<< " n2 = " << n2
<< std::endl
;
245 d_theory
.eqNotifyMerge(n1
, n2
);
248 void TheoryBags::NotifyClass::eqNotifyDisequal(TNode n1
, TNode n2
, TNode reason
)
250 Debug("bags-eq") << "[bags-eq] eqNotifyDisequal:"
251 << " n1 = " << n1
<< " n2 = " << n2
<< " reason = " << reason
253 d_theory
.eqNotifyDisequal(n1
, n2
, reason
);
257 } // namespace theory