1 /********************* */
2 /*! \file congruence_manager.cpp
4 ** Original author: taking
5 ** Major contributors: none
6 ** Minor contributors (to current version): dejan, mdeters
7 ** This file is part of the CVC4 prototype.
8 ** Copyright (c) 2009-2012 New York University and The University of Iowa
9 ** See the file COPYING in the top-level source directory for licensing
10 ** information.\endverbatim
12 ** \brief [[ Add one-line brief description here ]]
14 ** [[ Add lengthier description here ]]
15 ** \todo document this file
18 #include "theory/arith/congruence_manager.h"
20 #include "theory/arith/constraint.h"
21 #include "theory/arith/arith_utilities.h"
27 ArithCongruenceManager::ArithCongruenceManager(context::Context
* c
, ConstraintDatabase
& cd
, TNodeCallBack
& setup
, const ArithVarNodeMap
& av2Node
, NodeCallBack
& raiseConflict
)
29 d_raiseConflict(raiseConflict
),
34 d_constraintDatabase(cd
),
35 d_setupLiteral(setup
),
37 d_ee(d_notify
, c
, "theory::arith::ArithCongruenceManager")
40 ArithCongruenceManager::Statistics::Statistics():
41 d_watchedVariables("theory::arith::congruence::watchedVariables", 0),
42 d_watchedVariableIsZero("theory::arith::congruence::watchedVariableIsZero", 0),
43 d_watchedVariableIsNotZero("theory::arith::congruence::watchedVariableIsNotZero", 0),
44 d_equalsConstantCalls("theory::arith::congruence::equalsConstantCalls", 0),
45 d_propagations("theory::arith::congruence::propagations", 0),
46 d_propagateConstraints("theory::arith::congruence::propagateConstraints", 0),
47 d_conflicts("theory::arith::congruence::conflicts", 0)
49 StatisticsRegistry::registerStat(&d_watchedVariables
);
50 StatisticsRegistry::registerStat(&d_watchedVariableIsZero
);
51 StatisticsRegistry::registerStat(&d_watchedVariableIsNotZero
);
52 StatisticsRegistry::registerStat(&d_equalsConstantCalls
);
53 StatisticsRegistry::registerStat(&d_propagations
);
54 StatisticsRegistry::registerStat(&d_propagateConstraints
);
55 StatisticsRegistry::registerStat(&d_conflicts
);
58 ArithCongruenceManager::Statistics::~Statistics(){
59 StatisticsRegistry::unregisterStat(&d_watchedVariables
);
60 StatisticsRegistry::unregisterStat(&d_watchedVariableIsZero
);
61 StatisticsRegistry::unregisterStat(&d_watchedVariableIsNotZero
);
62 StatisticsRegistry::unregisterStat(&d_equalsConstantCalls
);
63 StatisticsRegistry::unregisterStat(&d_propagations
);
64 StatisticsRegistry::unregisterStat(&d_propagateConstraints
);
65 StatisticsRegistry::unregisterStat(&d_conflicts
);
68 void ArithCongruenceManager::setMasterEqualityEngine(eq::EqualityEngine
* eq
) {
69 d_ee
.setMasterEqualityEngine(eq
);
72 void ArithCongruenceManager::watchedVariableIsZero(Constraint lb
, Constraint ub
){
73 Assert(lb
->isLowerBound());
74 Assert(ub
->isUpperBound());
75 Assert(lb
->getVariable() == ub
->getVariable());
76 Assert(lb
->getValue().sgn() == 0);
77 Assert(ub
->getValue().sgn() == 0);
79 ++(d_statistics
.d_watchedVariableIsZero
);
81 ArithVar s
= lb
->getVariable();
82 Node reason
= ConstraintValue::explainConflict(lb
,ub
);
84 d_keepAlive
.push_back(reason
);
85 assertionToEqualityEngine(true, s
, reason
);
88 void ArithCongruenceManager::watchedVariableIsZero(Constraint eq
){
89 Assert(eq
->isEquality());
90 Assert(eq
->getValue().sgn() == 0);
92 ++(d_statistics
.d_watchedVariableIsZero
);
94 ArithVar s
= eq
->getVariable();
96 //Explain for conflict is correct as these proofs are generated
98 //These will be safe for propagation later as well
99 Node reason
= eq
->explainForConflict();
101 d_keepAlive
.push_back(reason
);
102 assertionToEqualityEngine(true, s
, reason
);
105 void ArithCongruenceManager::watchedVariableCannotBeZero(Constraint c
){
106 ++(d_statistics
.d_watchedVariableIsNotZero
);
108 ArithVar s
= c
->getVariable();
110 //Explain for conflict is correct as these proofs are generated and stored eagerly
111 //These will be safe for propagation later as well
112 Node reason
= c
->explainForConflict();
114 d_keepAlive
.push_back(reason
);
115 assertionToEqualityEngine(false, s
, reason
);
119 bool ArithCongruenceManager::propagate(TNode x
){
120 Debug("arith::congruenceManager")<< "ArithCongruenceManager::propagate("<<x
<<")"<<std::endl
;
125 Node rewritten
= Rewriter::rewrite(x
);
127 //Need to still propagate this!
128 if(rewritten
.getKind() == kind::CONST_BOOLEAN
){
131 if(rewritten
.getConst
<bool>()){
134 ++(d_statistics
.d_conflicts
);
136 Node conf
= flattenAnd(explainInternal(x
));
138 Debug("arith::congruenceManager") << "rewritten to false "<<x
<<" with explanation "<< conf
<< std::endl
;
143 Assert(rewritten
.getKind() != kind::CONST_BOOLEAN
);
145 Constraint c
= d_constraintDatabase
.lookup(rewritten
);
146 if(c
== NullConstraint
){
147 //using setup as there may not be a corresponding congruence literal yet
148 d_setupLiteral(rewritten
);
149 c
= d_constraintDatabase
.lookup(rewritten
);
150 Assert(c
!= NullConstraint
);
153 Debug("arith::congruenceManager")<< "x is "
154 << c
->hasProof() << " "
155 << (x
== rewritten
) << " "
156 << c
->canBePropagated() << " "
157 << c
->negationHasProof() << std::endl
;
159 if(c
->negationHasProof()){
160 Node expC
= explainInternal(x
);
161 Node neg
= c
->getNegation()->explainForConflict();
162 Node conf
= expC
.andNode(neg
);
163 Node final
= flattenAnd(conf
);
165 ++(d_statistics
.d_conflicts
);
166 raiseConflict(final
);
167 Debug("arith::congruenceManager") << "congruenceManager found a conflict " << final
<< std::endl
;
171 // Cases for propagation
173 // S : x == rewritten
174 // P : c can be propagated
177 // 000 : propagate x, and mark C it as being explained
178 // 001 : propagate x, and propagate c after marking it as being explained
179 // 01* : propagate x, mark c but do not propagate c
180 // 10* : propagate x, do not mark c and do not propagate c
181 // 11* : drop the constraint, do not propagate x or c
183 if(!c
->hasProof() && x
!= rewritten
){
184 if(c
->assertedToTheTheory()){
185 pushBack(x
, rewritten
, c
->getWitness());
187 pushBack(x
, rewritten
);
190 c
->setEqualityEngineProof();
191 if(c
->canBePropagated() && !c
->assertedToTheTheory()){
193 ++(d_statistics
.d_propagateConstraints
);
196 }else if(!c
->hasProof() && x
== rewritten
){
197 if(c
->assertedToTheTheory()){
198 pushBack(x
, c
->getWitness());
202 c
->setEqualityEngineProof();
203 }else if(c
->hasProof() && x
!= rewritten
){
204 if(c
->assertedToTheTheory()){
205 pushBack(x
, rewritten
, c
->getWitness());
207 pushBack(x
, rewritten
);
210 Assert(c
->hasProof() && x
== rewritten
);
215 void ArithCongruenceManager::explain(TNode literal
, std::vector
<TNode
>& assumptions
) {
216 if (literal
.getKind() != kind::NOT
) {
217 d_ee
.explainEquality(literal
[0], literal
[1], true, assumptions
);
219 d_ee
.explainEquality(literal
[0][0], literal
[0][1], false, assumptions
);
223 void ArithCongruenceManager::enqueueIntoNB(const std::set
<TNode
> s
, NodeBuilder
<>& nb
){
224 std::set
<TNode
>::const_iterator it
= s
.begin();
225 std::set
<TNode
>::const_iterator it_end
= s
.end();
226 for(; it
!= it_end
; ++it
) {
231 Node
ArithCongruenceManager::explainInternal(TNode internal
){
232 std::vector
<TNode
> assumptions
;
233 explain(internal
, assumptions
);
235 std::set
<TNode
> assumptionSet
;
236 assumptionSet
.insert(assumptions
.begin(), assumptions
.end());
238 if (assumptionSet
.size() == 1) {
239 // All the same, or just one
240 return assumptions
[0];
242 NodeBuilder
<> conjunction(kind::AND
);
243 enqueueIntoNB(assumptionSet
, conjunction
);
247 Node
ArithCongruenceManager::explain(TNode external
){
248 Node internal
= externalToInternal(external
);
249 return explainInternal(internal
);
252 void ArithCongruenceManager::explain(TNode external
, NodeBuilder
<>& out
){
253 Node internal
= externalToInternal(external
);
255 std::vector
<TNode
> assumptions
;
256 explain(internal
, assumptions
);
257 std::set
<TNode
> assumptionSet
;
258 assumptionSet
.insert(assumptions
.begin(), assumptions
.end());
260 enqueueIntoNB(assumptionSet
, out
);
263 void ArithCongruenceManager::addWatchedPair(ArithVar s
, TNode x
, TNode y
){
264 Assert(!isWatchedVariable(s
));
266 Debug("arith::congruenceManager")
267 << "addWatchedPair(" << s
<< ", " << x
<< ", " << y
<< ")" << std::endl
;
270 ++(d_statistics
.d_watchedVariables
);
272 d_watchedVariables
.add(s
);
274 Node eq
= x
.eqNode(y
);
275 d_watchedEqualities
.set(s
, eq
);
278 void ArithCongruenceManager::assertionToEqualityEngine(bool isEquality
, ArithVar s
, TNode reason
){
279 Assert(isWatchedVariable(s
));
281 TNode eq
= d_watchedEqualities
[s
];
282 Assert(eq
.getKind() == kind::EQUAL
);
285 d_ee
.assertEquality(eq
, true, reason
);
287 d_ee
.assertEquality(eq
, false, reason
);
291 void ArithCongruenceManager::equalsConstant(Constraint c
){
292 Assert(c
->isEquality());
294 ++(d_statistics
.d_equalsConstantCalls
);
295 Debug("equalsConstant") << "equals constant " << c
<< std::endl
;
297 ArithVar x
= c
->getVariable();
298 Node xAsNode
= d_av2Node
.asNode(x
);
299 Node asRational
= mkRationalNode(c
->getValue().getNoninfinitesimalPart());
302 //No guarentee this is in normal form!
303 Node eq
= xAsNode
.eqNode(asRational
);
304 d_keepAlive
.push_back(eq
);
306 Node reason
= c
->explainForConflict();
307 d_keepAlive
.push_back(reason
);
309 d_ee
.assertEquality(eq
, true, reason
);
312 void ArithCongruenceManager::equalsConstant(Constraint lb
, Constraint ub
){
313 Assert(lb
->isLowerBound());
314 Assert(ub
->isUpperBound());
315 Assert(lb
->getVariable() == ub
->getVariable());
317 ++(d_statistics
.d_equalsConstantCalls
);
318 Debug("equalsConstant") << "equals constant " << lb
<< std::endl
321 ArithVar x
= lb
->getVariable();
322 Node reason
= ConstraintValue::explainConflict(lb
,ub
);
324 Node xAsNode
= d_av2Node
.asNode(x
);
325 Node asRational
= mkRationalNode(lb
->getValue().getNoninfinitesimalPart());
327 //No guarentee this is in normal form!
328 Node eq
= xAsNode
.eqNode(asRational
);
329 d_keepAlive
.push_back(eq
);
330 d_keepAlive
.push_back(reason
);
333 d_ee
.assertEquality(eq
, true, reason
);
336 void ArithCongruenceManager::addSharedTerm(Node x
){
337 d_ee
.addTriggerTerm(x
, THEORY_ARITH
);
340 }/* CVC4::theory::arith namespace */
341 }/* CVC4::theory namespace */
342 }/* CVC4 namespace */