1 /********************* */
4 ** Top contributors (to current version):
5 ** Tim King, Andrew Reynolds
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2020 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.\endverbatim
12 ** \brief [[ Add one-line brief description here ]]
14 ** [[ Add lengthier description here ]]
15 ** \todo document this file
23 #include "base/output.h"
24 #include "cvc4autoconfig.h"
25 #include "theory/arith/approx_simplex.h"
26 #include "theory/arith/constraint.h"
27 #include "theory/arith/cut_log.h"
28 #include "theory/arith/normal_form.h"
29 #include "util/ostream_util.h"
37 NodeLog::const_iterator
NodeLog::begin() const { return d_cuts
.begin(); }
38 NodeLog::const_iterator
NodeLog::end() const { return d_cuts
.end(); }
40 NodeLog
& TreeLog::getNode(int nid
) {
41 ToNodeMap::iterator i
= d_toNode
.find(nid
);
42 Assert(i
!= d_toNode
.end());
46 TreeLog::const_iterator
TreeLog::begin() const { return d_toNode
.begin(); }
47 TreeLog::const_iterator
TreeLog::end() const { return d_toNode
.end(); }
49 int TreeLog::getExecutionOrd(){
50 int res
= next_exec_ord
;
54 void TreeLog::makeInactive(){ d_active
= false; }
55 void TreeLog::makeActive(){ d_active
= true; }
56 bool TreeLog::isActivelyLogging() const { return d_active
; }
59 PrimitiveVec::PrimitiveVec()
65 PrimitiveVec::~PrimitiveVec(){
68 bool PrimitiveVec::initialized() const {
71 void PrimitiveVec::clear() {
80 void PrimitiveVec::setup(int l
){
81 Assert(!initialized());
83 inds
= new int[1+len
];
84 coeffs
= new double[1+len
];
86 void PrimitiveVec::print(std::ostream
& out
) const{
87 Assert(initialized());
88 StreamFormatScope
scope(out
);
90 out
<< len
<< " " << std::setprecision(15);
91 for(int i
= 1; i
<= len
; ++i
){
92 out
<< "["<< inds
[i
] <<", " << coeffs
[i
]<<"]";
95 std::ostream
& operator<<(std::ostream
& os
, const PrimitiveVec
& pv
){
100 CutInfo::CutInfo(CutInfoKlass kl
, int eid
, int o
)
104 d_cutType(kind::UNDEFINED_KIND
),
109 d_exactPrecision(nullptr),
110 d_explanation(nullptr)
116 int CutInfo::getId() const {
120 int CutInfo::getRowId() const{
124 void CutInfo::setRowId(int rid
){
128 void CutInfo::print(ostream
& out
) const{
129 out
<< "[CutInfo " << d_execOrd
<< " " << d_poolOrd
130 << " " << d_klass
<< " " << d_cutType
<< " " << d_cutRhs
136 PrimitiveVec
& CutInfo::getCutVector(){
140 const PrimitiveVec
& CutInfo::getCutVector() const{
144 // void CutInfo::init_cut(int l){
148 Kind
CutInfo::getKind() const{
152 void CutInfo::setKind(Kind k
){
153 Assert(k
== kind::LEQ
|| k
== kind::GEQ
);
157 double CutInfo::getRhs() const{
161 void CutInfo::setRhs(double r
){
165 bool CutInfo::reconstructed() const { return d_exactPrecision
!= nullptr; }
167 CutInfoKlass
CutInfo::getKlass() const{
171 int CutInfo::poolOrdinal() const{
175 void CutInfo::setDimensions(int N
, int M
){
180 int CutInfo::getN() const{
184 int CutInfo::getMAtCreation() const{
185 return d_mAtCreation
;
188 /* Returns true if the cut has an explanation. */
189 bool CutInfo::proven() const { return d_explanation
!= nullptr; }
191 bool CutInfo::operator<(const CutInfo
& o
) const{
192 return d_execOrd
< o
.d_execOrd
;
196 void CutInfo::setReconstruction(const DenseVector
& ep
){
197 Assert(!reconstructed());
198 d_exactPrecision
.reset(new DenseVector(ep
));
201 void CutInfo::setExplanation(const ConstraintCPVec
& ex
){
202 Assert(reconstructed());
203 if (d_explanation
== nullptr)
205 d_explanation
.reset(new ConstraintCPVec(ex
));
213 void CutInfo::swapExplanation(ConstraintCPVec
& ex
){
214 Assert(reconstructed());
216 if (d_explanation
== nullptr)
218 d_explanation
.reset(new ConstraintCPVec());
220 d_explanation
->swap(ex
);
223 const DenseVector
& CutInfo::getReconstruction() const {
224 Assert(reconstructed());
225 return *d_exactPrecision
;
228 void CutInfo::clearReconstruction(){
230 d_explanation
= nullptr;
234 d_exactPrecision
= nullptr;
237 Assert(!reconstructed());
241 const ConstraintCPVec
& CutInfo::getExplanation() const {
243 return *d_explanation
;
246 std::ostream
& operator<<(std::ostream
& os
, const CutInfo
& ci
){
251 std::ostream
& operator<<(std::ostream
& out
, CutInfoKlass kl
){
254 out
<< "MirCutKlass"; break;
256 out
<< "GmiCutKlass"; break;
258 out
<< "BranchCutKlass"; break;
259 case RowsDeletedKlass
:
260 out
<< "RowDeletedKlass"; break;
262 out
<< "UnknownKlass"; break;
264 out
<< "unexpected CutInfoKlass"; break;
268 bool NodeLog::isBranch() const{
286 NodeLog::NodeLog(TreeLog
* tl
, int node
, const RowIdMap
& m
)
297 , d_rowId2ArithVar(m
)
300 NodeLog::NodeLog(TreeLog
* tl
, NodeLog
* parent
, int node
)
315 CutSet::iterator i
= d_cuts
.begin(), iend
= d_cuts
.end();
316 for(; i
!= iend
; ++i
){
321 Assert(d_cuts
.empty());
324 std::ostream
& operator<<(std::ostream
& os
, const NodeLog
& nl
){
329 void NodeLog::copyParentRowIds() {
330 Assert(d_parent
!= NULL
);
331 d_rowId2ArithVar
= d_parent
->d_rowId2ArithVar
;
334 int NodeLog::branchVariable() const {
337 double NodeLog::branchValue() const{
340 int NodeLog::getNodeId() const {
343 int NodeLog::getDownId() const{
346 int NodeLog::getUpId() const{
349 void NodeLog::addSelected(int ord
, int sel
){
350 Assert(d_rowIdsSelected
.find(ord
) == d_rowIdsSelected
.end());
351 d_rowIdsSelected
[ord
] = sel
;
352 Debug("approx::nodelog") << "addSelected("<< ord
<< ", "<< sel
<< ")" << endl
;
354 void NodeLog::applySelected() {
355 CutSet::iterator iter
= d_cuts
.begin(), iend
= d_cuts
.end(), todelete
;
357 CutInfo
* curr
= *iter
;
358 int poolOrd
= curr
->poolOrdinal();
359 if(curr
->getRowId() >= 0 ){
360 // selected previously, kip
362 }else if(curr
->getKlass() == RowsDeletedKlass
){
365 }else if(curr
->getKlass() == BranchCutKlass
){
368 }else if(d_rowIdsSelected
.find(poolOrd
) == d_rowIdsSelected
.end()){
371 d_cuts
.erase(todelete
);
374 Debug("approx::nodelog") << "applySelected " << curr
->getId() << " " << poolOrd
<< "->" << d_rowIdsSelected
[poolOrd
] << endl
;
375 curr
->setRowId( d_rowIdsSelected
[poolOrd
] );
379 d_rowIdsSelected
.clear();
382 void NodeLog::applyRowsDeleted(const RowsDeleted
& rd
) {
383 std::map
<int, CutInfo
*> currInOrd
; //sorted
385 const PrimitiveVec
& cv
= rd
.getCutVector();
386 std::vector
<int> sortedRemoved (cv
.inds
+1, cv
.inds
+cv
.len
+1);
387 sortedRemoved
.push_back(INT_MAX
);
388 std::sort(sortedRemoved
.begin(), sortedRemoved
.end());
390 if(Debug
.isOn("approx::nodelog")){
391 Debug("approx::nodelog") << "Removing #" << sortedRemoved
.size()<< "...";
392 for(unsigned k
= 0; k
<sortedRemoved
.size(); k
++){
393 Debug("approx::nodelog") << ", " << sortedRemoved
[k
];
395 Debug("approx::nodelog") << endl
;
396 Debug("approx::nodelog") << "cv.len" << cv
.len
<< endl
;
399 int min
= sortedRemoved
.front();
401 CutSet::iterator iter
= d_cuts
.begin(), iend
= d_cuts
.end();
403 CutInfo
* curr
= *iter
;
404 if(curr
->getId() < rd
.getId()){
405 if(d_rowId2ArithVar
.find(curr
->getRowId()) != d_rowId2ArithVar
.end()){
406 if(curr
->getRowId() >= min
){
407 currInOrd
.insert(make_pair(curr
->getRowId(), curr
));
414 RowIdMap::const_iterator i
, end
;
415 i
=d_rowId2ArithVar
.begin(), end
= d_rowId2ArithVar
.end();
416 for(; i
!= end
; ++i
){
417 int key
= (*i
).first
;
419 if(currInOrd
.find(key
) == currInOrd
.end()){
420 CutInfo
* null
= NULL
;
421 currInOrd
.insert(make_pair(key
, null
));
428 std::map
<int, CutInfo
*>::iterator j
, jend
;
431 for(j
= currInOrd
.begin(), jend
=currInOrd
.end(); j
!=jend
; ++j
){
432 int origOrd
= (*j
).first
;
433 ArithVar v
= d_rowId2ArithVar
[origOrd
];
434 int headRemovedOrd
= sortedRemoved
[posInSorted
];
435 while(headRemovedOrd
< origOrd
){
437 headRemovedOrd
= sortedRemoved
[posInSorted
];
439 // headRemoveOrd >= origOrd
440 Assert(headRemovedOrd
>= origOrd
);
442 CutInfo
* ci
= (*j
).second
;
443 if(headRemovedOrd
== origOrd
){
446 Debug("approx::nodelog") << "deleting from above because of " << rd
<< endl
;
447 Debug("approx::nodelog") << "had " << origOrd
<< " <-> " << v
<< endl
;
448 d_rowId2ArithVar
.erase(origOrd
);
450 Debug("approx::nodelog") << "deleting " << ci
<< " because of " << rd
<< endl
;
451 Debug("approx::nodelog") << "had " << origOrd
<< " <-> " << v
<< endl
;
452 d_rowId2ArithVar
.erase(origOrd
);
456 Assert(headRemovedOrd
> origOrd
);
457 // headRemoveOrd > origOrd
458 int newOrd
= origOrd
- posInSorted
;
461 Debug("approx::nodelog") << "shifting above down due to " << rd
<< endl
;
462 Debug("approx::nodelog") << "had " << origOrd
<< " <-> " << v
<< endl
;
463 Debug("approx::nodelog") << "now have " << newOrd
<< " <-> " << v
<< endl
;
464 d_rowId2ArithVar
.erase(origOrd
);
467 Debug("approx::nodelog") << "shifting " << ci
<< " down due to " << rd
<< endl
;
468 Debug("approx::nodelog") << "had " << origOrd
<< " <-> " << v
<< endl
;
469 Debug("approx::nodelog") << "now have " << newOrd
<< " <-> " << v
<< endl
;
470 ci
->setRowId(newOrd
);
471 d_rowId2ArithVar
.erase(origOrd
);
479 // void NodeLog::adjustRowId(CutInfo& ci, const RowsDeleted& rd) {
480 // int origRowId = ci.getRowId();
481 // int newRowId = ci.getRowId();
482 // ArithVar v = d_rowId2ArithVar[origRowId];
484 // const PrimitiveVec& cv = rd.getCutVector();
486 // for(int j = 1, N = cv.len; j <= N; j++){
487 // int ind = cv.inds[j];
488 // if(ind == origRowId){
491 // }else if(ind < origRowId){
497 // cout << "deleting " << ci << " because of " << rd << endl;
498 // cout << "had " << origRowId << " <-> " << v << endl;
499 // d_rowId2ArithVar.erase(origRowId);
501 // }else if(newRowId != origRowId){
502 // cout << "adjusting " << ci << " because of " << rd << endl;
503 // cout << "had " << origRowId << " <-> " << v << endl;
504 // cout << "now have " << newRowId << " <-> " << v << endl;
505 // d_rowId2ArithVar.erase(origRowId);
506 // ci.setRowId(newRowId);
507 // mapRowId(newRowId, v);
509 // cout << "row id unchanged " << ci << " because of " << rd << endl;
514 ArithVar
NodeLog::lookupRowId(int rowId
) const{
515 RowIdMap::const_iterator i
= d_rowId2ArithVar
.find(rowId
);
516 if(i
== d_rowId2ArithVar
.end()){
517 return ARITHVAR_SENTINEL
;
523 void NodeLog::mapRowId(int rowId
, ArithVar v
){
524 Assert(lookupRowId(rowId
) == ARITHVAR_SENTINEL
);
525 Debug("approx::nodelog")
526 << "On " << getNodeId()
527 << " adding row id " << rowId
<< " <-> " << v
<< endl
;
528 d_rowId2ArithVar
[rowId
] = v
;
533 void NodeLog::addCut(CutInfo
* ci
){
538 void NodeLog::print(ostream
& o
) const{
539 o
<< "[n" << getNodeId();
540 for(const_iterator iter
= begin(), iend
= end(); iter
!= iend
; ++iter
){
541 CutInfo
* cut
= *iter
;
542 o
<< ", " << cut
->poolOrdinal();
543 if(cut
->getRowId() >= 0){
544 o
<< " " << cut
->getRowId();
547 o
<< "]" << std::endl
;
550 void NodeLog::closeNode(){
551 Assert(d_stat
== Open
);
555 void NodeLog::setBranch(int br
, double val
, int d
, int u
){
556 Assert(d_stat
== Open
);
571 NodeLog::RowIdMap empty
;
575 int TreeLog::getRootId() const{
579 NodeLog
& TreeLog::getRootNode(){
580 return getNode(getRootId());
583 void TreeLog::clear(){
593 void TreeLog::reset(const NodeLog::RowIdMap
& m
){
595 d_toNode
.insert(make_pair(getRootId(), NodeLog(this, getRootId(), m
)));
598 void TreeLog::addCut(){ d_numCuts
++; }
599 uint32_t TreeLog::cutCount() const { return d_numCuts
; }
600 void TreeLog::logBranch(uint32_t x
){
603 uint32_t TreeLog::numBranches(uint32_t x
){
604 return d_branches
.count(x
);
607 void TreeLog::branch(int nid
, int br
, double val
, int dn
, int up
){
608 NodeLog
& nl
= getNode(nid
);
609 nl
.setBranch(br
, val
, dn
, up
);
611 d_toNode
.insert(make_pair(dn
, NodeLog(this, &nl
, dn
)));
612 d_toNode
.insert(make_pair(up
, NodeLog(this, &nl
, up
)));
615 void TreeLog::close(int nid
){
616 NodeLog
& nl
= getNode(nid
);
622 // void TreeLog::applySelected() {
623 // std::map<int, NodeLog>::iterator iter, end;
624 // for(iter = d_toNode.begin(), end = d_toNode.end(); iter != end; ++iter){
625 // NodeLog& onNode = (*iter).second;
626 // //onNode.applySelected();
630 void TreeLog::print(ostream
& o
) const{
631 o
<< "TreeLog: " << d_toNode
.size() << std::endl
;
632 for(const_iterator iter
= begin(), iend
= end(); iter
!= iend
; ++iter
){
633 const NodeLog
& onNode
= (*iter
).second
;
638 void TreeLog::applyRowsDeleted(int nid
, const RowsDeleted
& rd
){
639 NodeLog
& nl
= getNode(nid
);
640 nl
.applyRowsDeleted(rd
);
643 void TreeLog::mapRowId(int nid
, int ind
, ArithVar v
){
644 NodeLog
& nl
= getNode(nid
);
648 void DenseVector::purge() {
653 RowsDeleted::RowsDeleted(int execOrd
, int nrows
, const int num
[])
654 : CutInfo(RowsDeletedKlass
, execOrd
, 0)
656 d_cutVec
.setup(nrows
);
657 for(int j
=1; j
<= nrows
; j
++){
658 d_cutVec
.coeffs
[j
] = 0;
659 d_cutVec
.inds
[j
] = num
[j
];
663 BranchCutInfo::BranchCutInfo(int execOrd
, int br
, Kind dir
, double val
)
664 : CutInfo(BranchCutKlass
, execOrd
, 0)
667 d_cutVec
.inds
[1] = br
;
668 d_cutVec
.coeffs
[1] = +1.0;
673 void TreeLog::printBranchInfo(ostream
& os
) const{
675 DenseMultiset::const_iterator iter
= d_branches
.begin(), iend
= d_branches
.end();
676 for(; iter
!= iend
; ++iter
){
680 os
<< "printBranchInfo() : " << total
<< endl
;
681 iter
= d_branches
.begin(), iend
= d_branches
.end();
682 for(; iter
!= iend
; ++iter
){
684 os
<< "["<<el
<<", " << d_branches
.count(el
) << "]";
690 void DenseVector::print(std::ostream
& os
) const {
694 void DenseVector::print(ostream
& out
, const DenseMap
<Rational
>& v
){
695 out
<< "[DenseVec len " << v
.size();
696 DenseMap
<Rational
>::const_iterator iter
, end
;
697 for(iter
= v
.begin(), end
= v
.end(); iter
!= end
; ++iter
){
699 out
<< ", "<< x
<< " " << v
[x
];
704 }/* CVC4::theory::arith namespace */
705 }/* CVC4::theory namespace */
706 }/* CVC4 namespace */