1 /********************* */
4 ** Original author: taking
5 ** Major contributors: none
6 ** Minor contributors (to current version): none
7 ** This file is part of the CVC4 prototype.
8 ** Copyright (c) 2009, 2010 The Analysis of Computer Systems Group (ACSys)
9 ** Courant Institute of Mathematical Sciences
10 ** New York University
11 ** See the file COPYING in the top-level source directory for licensing
12 ** information.\endverbatim
14 ** \brief [[ Add one-line brief description here ]]
16 ** [[ Add lengthier description here ]]
17 ** \todo document this file
21 #include "theory/arith/tableau.h"
25 using namespace CVC4::theory
;
26 using namespace CVC4::theory::arith
;
30 void Tableau::addRow(ArithVar basicVar,
31 const std::vector<Rational>& coeffs,
32 const std::vector<ArithVar>& variables){
34 Assert(coeffs.size() == variables.size());
36 //The new basic variable cannot already be a basic variable
37 Assert(!d_basicVariables.isMember(basicVar));
38 d_basicVariables.add(basicVar);
39 ReducedRowVector* row_current = new ReducedRowVector(basicVar,variables, coeffs,d_rowCount, d_columnMatrix);
40 d_rowsTable[basicVar] = row_current;
42 //A variable in the row may have been made non-basic already.
43 //If this is the case we fake pivoting this variable
44 vector<ArithVar>::const_iterator varsIter = variables.begin();
45 vector<ArithVar>::const_iterator varsEnd = variables.end();
47 for( ; varsIter != varsEnd; ++varsIter){
48 ArithVar var = *varsIter;
50 if(d_basicVariables.isMember(var)){
51 EntryID varID = find(basicVar, var);
52 TableauEntry& entry = d_entryManager.get(varID);
53 const Rational& coeff = entry.getCoefficient();
55 loadRowIntoMergeBuffer(var);
56 rowPlusRowTimesConstant(coeff, basicVar, var);
57 emptyRowFromMergeBuffer(var);
64 ReducedRowVector* Tableau::removeRow(ArithVar basic){
65 Assert(isBasic(basic));
67 ReducedRowVector* row = d_rowsTable[basic];
69 d_basicVariables.remove(basic);
70 d_rowsTable[basic] = NULL;
76 void Tableau::pivot(ArithVar oldBasic
, ArithVar newBasic
){
77 Assert(isBasic(oldBasic
));
78 Assert(!isBasic(newBasic
));
79 Assert(mergeBufferIsEmpty());
81 //cout << oldBasic << "," << newBasic << endl;
82 Debug("tableau") << "Tableau::pivot(" << oldBasic
<<", " << newBasic
<<")" << endl
;
84 rowPivot(oldBasic
, newBasic
);
85 loadRowIntoMergeBuffer(newBasic
);
87 ColIterator colIter
= colIterator(newBasic
);
88 while(!colIter
.atEnd()){
89 EntryID id
= colIter
.getID();
90 TableauEntry
& entry
= d_entryManager
.get(id
);
92 ++colIter
; //needs to be incremented before the variable is removed
93 if(entry
.getRowVar() == newBasic
){ continue; }
95 ArithVar basicTo
= entry
.getRowVar();
96 Rational coeff
= entry
.getCoefficient();
98 rowPlusRowTimesConstant(basicTo
, coeff
, newBasic
);
100 emptyRowFromMergeBuffer(newBasic
);
102 //Clear the column for used for this variable
104 Assert(mergeBufferIsEmpty());
105 Assert(!isBasic(oldBasic
));
106 Assert(isBasic(newBasic
));
107 Assert(getColLength(newBasic
) == 1);
110 Tableau::~Tableau(){}
112 void Tableau::setColumnUnused(ArithVar v
){
113 ColIterator colIter
= colIterator(v
);
114 while(!colIter
.atEnd()){
118 void Tableau::printTableau(){
119 Debug("tableau") << "Tableau::d_activeRows" << endl
;
121 ArithVarSet::const_iterator basicIter
= beginBasic(), endIter
= endBasic();
122 for(; basicIter
!= endIter
; ++basicIter
){
123 ArithVar basic
= *basicIter
;
128 void Tableau::printRow(ArithVar basic
){
129 Debug("tableau") << "{" << basic
<< ":";
130 for(RowIterator entryIter
= rowIterator(basic
); !entryIter
.atEnd(); ++entryIter
){
131 const TableauEntry
& entry
= *entryIter
;
133 Debug("tableau") << ",";
135 Debug("tableau") << "}" << endl
;
138 void Tableau::printEntry(const TableauEntry
& entry
){
139 Debug("tableau") << entry
.getColVar() << "*" << entry
.getCoefficient();
142 uint32_t Tableau::numNonZeroEntriesByRow() const {
144 ArithVarSet::const_iterator i
= d_basicVariables
.begin(), end
= d_basicVariables
.end();
145 for(; i
!= end
; ++i
){
147 rowSum
+= getRowLength(basic
);
152 uint32_t Tableau::numNonZeroEntriesByCol() const {
154 VectorSizeTable::const_iterator i
= d_colLengths
.begin();
155 VectorSizeTable::const_iterator end
= d_colLengths
.end();
156 for(; i
!= end
; ++i
){
163 EntryID
Tableau::findOnRow(ArithVar row
, ArithVar col
){
164 for(RowIterator i
= rowIterator(row
); !i
.atEnd(); ++i
){
165 EntryID id
= i
.getID();
166 const TableauEntry
& entry
= *i
;
167 ArithVar colVar
= entry
.getColVar();
173 return ENTRYID_SENTINEL
;
176 EntryID
Tableau::findOnCol(ArithVar row
, ArithVar col
){
177 for(ColIterator i
= colIterator(col
); !i
.atEnd(); ++i
){
178 EntryID id
= i
.getID();
179 const TableauEntry
& entry
= *i
;
180 ArithVar rowVar
= entry
.getRowVar();
186 return ENTRYID_SENTINEL
;
189 const TableauEntry
& Tableau::findEntry(ArithVar row
, ArithVar col
){
190 bool colIsShorter
= getColLength(col
) < getRowLength(row
);
191 EntryID id
= colIsShorter
? findOnCol(row
,col
) : findOnRow(row
,col
);
192 if(id
== ENTRYID_SENTINEL
){
195 return d_entryManager
.get(id
);
199 void Tableau::removeRow(ArithVar basic
){
200 RowIterator i
= rowIterator(basic
);
202 EntryID id
= i
.getID();
206 d_basicVariables
.remove(basic
);
209 void Tableau::loadRowIntoMergeBuffer(ArithVar basic
){
210 Assert(mergeBufferIsEmpty());
211 for(RowIterator i
= rowIterator(basic
); !i
.atEnd(); ++i
){
212 EntryID id
= i
.getID();
213 const TableauEntry
& entry
= *i
;
214 ArithVar colVar
= entry
.getColVar();
215 d_mergeBuffer
[colVar
] = make_pair(id
, false);
219 void Tableau::emptyRowFromMergeBuffer(ArithVar basic
){
220 Assert(isBasic(basic
));
221 for(RowIterator i
= rowIterator(basic
); !i
.atEnd(); ++i
){
222 const TableauEntry
& entry
= *i
;
223 ArithVar colVar
= entry
.getColVar();
224 Assert(d_mergeBuffer
[colVar
].first
== i
.getID());
225 d_mergeBuffer
[colVar
] = make_pair(ENTRYID_SENTINEL
, false);
228 Assert(mergeBufferIsEmpty());
233 * Changes basic to newbasic (a variable on the row).
235 void Tableau::rowPivot(ArithVar basicOld
, ArithVar basicNew
){
236 Assert(mergeBufferIsEmpty());
237 Assert(isBasic(basicOld
));
238 Assert(!isBasic(basicNew
));
240 EntryID newBasicID
= findOnRow(basicOld
, basicNew
);
242 Assert(newBasicID
!= ENTRYID_SENTINEL
);
244 TableauEntry
& newBasicEntry
= d_entryManager
.get(newBasicID
);
245 Rational negInverseA_rs
= -(newBasicEntry
.getCoefficient().inverse());
247 for(RowIterator i
= rowIterator(basicOld
); !i
.atEnd(); ++i
){
248 EntryID id
= i
.getID();
249 TableauEntry
& entry
= d_entryManager
.get(id
);
251 entry
.getCoefficient() *= negInverseA_rs
;
252 entry
.setRowVar(basicNew
);
255 d_rowHeads
[basicNew
] = d_rowHeads
[basicOld
];
256 d_rowHeads
[basicOld
] = ENTRYID_SENTINEL
;
258 d_rowLengths
[basicNew
] = d_rowLengths
[basicOld
];
259 d_rowLengths
[basicOld
] = 0;
261 d_basicVariables
.remove(basicOld
);
262 d_basicVariables
.add(basicNew
);
265 void Tableau::addEntry(ArithVar row
, ArithVar col
, const Rational
& coeff
){
268 EntryID newId
= d_entryManager
.newEntry();
269 TableauEntry
& newEntry
= d_entryManager
.get(newId
);
270 newEntry
= TableauEntry( row
, col
,
271 d_rowHeads
[row
], d_colHeads
[col
],
272 ENTRYID_SENTINEL
, ENTRYID_SENTINEL
,
274 Assert(newEntry
.getCoefficient() != 0);
276 Debug("tableau") << "addEntry(" << row
<< "," << col
<<"," << coeff
<< ")" << endl
;
280 if(d_rowHeads
[row
] != ENTRYID_SENTINEL
)
281 d_entryManager
.get(d_rowHeads
[row
]).setPrevRowID(newId
);
283 if(d_colHeads
[col
] != ENTRYID_SENTINEL
)
284 d_entryManager
.get(d_colHeads
[col
]).setPrevColID(newId
);
286 d_rowHeads
[row
] = newId
;
287 d_colHeads
[col
] = newId
;
292 void Tableau::removeEntry(EntryID id
){
293 Assert(d_entriesInUse
> 0);
296 TableauEntry
& entry
= d_entryManager
.get(id
);
298 ArithVar row
= entry
.getRowVar();
299 ArithVar col
= entry
.getColVar();
301 Assert(d_rowLengths
[row
] > 0);
302 Assert(d_colLengths
[col
] > 0);
308 EntryID prevRow
= entry
.getPrevRowID();
309 EntryID prevCol
= entry
.getPrevColID();
311 EntryID nextRow
= entry
.getNextRowID();
312 EntryID nextCol
= entry
.getNextColID();
314 if(d_rowHeads
[row
] == id
){
315 d_rowHeads
[row
] = nextRow
;
317 if(d_colHeads
[col
] == id
){
318 d_colHeads
[col
] = nextCol
;
323 if(prevRow
!= ENTRYID_SENTINEL
){
324 d_entryManager
.get(prevRow
).setNextRowID(nextRow
);
326 if(nextRow
!= ENTRYID_SENTINEL
){
327 d_entryManager
.get(nextRow
).setPrevRowID(prevRow
);
330 if(prevCol
!= ENTRYID_SENTINEL
){
331 d_entryManager
.get(prevCol
).setNextColID(nextCol
);
333 if(nextCol
!= ENTRYID_SENTINEL
){
334 d_entryManager
.get(nextCol
).setPrevColID(prevCol
);
337 d_entryManager
.freeEntry(id
);
340 void Tableau::rowPlusRowTimesConstant(ArithVar basicTo
, const Rational
& c
, ArithVar basicFrom
){
342 Debug("tableau") << "rowPlusRowTimesConstant("
343 << basicTo
<< "," << c
<< "," << basicFrom
<< ")"
346 Assert(debugNoZeroCoefficients(basicTo
));
347 Assert(debugNoZeroCoefficients(basicFrom
));
350 Assert(isBasic(basicTo
));
351 Assert(isBasic(basicFrom
));
352 Assert( d_usedList
.empty() );
355 RowIterator i
= rowIterator(basicTo
);
357 EntryID id
= i
.getID();
358 TableauEntry
& entry
= d_entryManager
.get(id
);
359 ArithVar colVar
= entry
.getColVar();
362 if(bufferPairIsNotEmpty(d_mergeBuffer
[colVar
])){
363 d_mergeBuffer
[colVar
].second
= true;
364 d_usedList
.push_back(colVar
);
366 EntryID inOtherRow
= d_mergeBuffer
[colVar
].first
;
367 const TableauEntry
& other
= d_entryManager
.get(inOtherRow
);
368 entry
.getCoefficient() += c
* other
.getCoefficient();
370 if(entry
.getCoefficient().sgn() == 0){
376 for(RowIterator i
= rowIterator(basicFrom
); !i
.atEnd(); ++i
){
377 const TableauEntry
& entry
= *i
;
378 ArithVar colVar
= entry
.getColVar();
380 if(!(d_mergeBuffer
[colVar
]).second
){
381 Rational newCoeff
= c
* entry
.getCoefficient();
382 addEntry(basicTo
, colVar
, newCoeff
);
388 if(Debug
.isOn("tableau")) { printTableau(); }
391 void Tableau::clearUsedList(){
392 ArithVarArray::iterator i
, end
;
393 for(i
= d_usedList
.begin(), end
= d_usedList
.end(); i
!= end
; ++i
){
395 d_mergeBuffer
[pos
].second
= false;
400 void Tableau::addRow(ArithVar basic
,
401 const std::vector
<Rational
>& coefficients
,
402 const std::vector
<ArithVar
>& variables
)
404 Assert(coefficients
.size() == variables
.size() );
405 Assert(!isBasic(basic
));
407 d_basicVariables
.add(basic
);
409 if(Debug
.isOn("tableau")){ printTableau(); }
411 addEntry(basic
, basic
, Rational(-1));
413 vector
<Rational
>::const_iterator coeffIter
= coefficients
.begin();
414 vector
<ArithVar
>::const_iterator varsIter
= variables
.begin();
415 vector
<ArithVar
>::const_iterator varsEnd
= variables
.end();
417 for(; varsIter
!= varsEnd
; ++coeffIter
, ++varsIter
){
418 const Rational
& coeff
= *coeffIter
;
419 ArithVar var_i
= *varsIter
;
420 addEntry(basic
, var_i
, coeff
);
423 varsIter
= variables
.begin();
424 coeffIter
= coefficients
.begin();
425 for(; varsIter
!= varsEnd
; ++coeffIter
, ++varsIter
){
426 ArithVar var
= *varsIter
;
429 Rational coeff
= *coeffIter
;
431 loadRowIntoMergeBuffer(var
);
432 rowPlusRowTimesConstant(basic
, coeff
, var
);
433 emptyRowFromMergeBuffer(var
);
437 if(Debug
.isOn("tableau")) { printTableau(); }
439 Assert(debugNoZeroCoefficients(basic
));
441 Assert(debugMatchingCountsForRow(basic
));
442 Assert(getColLength(basic
) == 1);
445 bool Tableau::debugNoZeroCoefficients(ArithVar basic
){
446 for(RowIterator i
=rowIterator(basic
); !i
.atEnd(); ++i
){
447 const TableauEntry
& entry
= *i
;
448 if(entry
.getCoefficient() == 0){
454 bool Tableau::debugMatchingCountsForRow(ArithVar basic
){
455 for(RowIterator i
=rowIterator(basic
); !i
.atEnd(); ++i
){
456 const TableauEntry
& entry
= *i
;
457 ArithVar colVar
= entry
.getColVar();
458 uint32_t count
= debugCountColLength(colVar
);
459 Debug("tableau") << "debugMatchingCountsForRow "
460 << basic
<< ":" << colVar
<< " " << count
461 <<" "<< d_colLengths
[colVar
] << endl
;
462 if( count
!= d_colLengths
[colVar
] ){
470 uint32_t Tableau::debugCountColLength(ArithVar var
){
471 Debug("tableau") << var
<< " ";
473 for(ColIterator i
=colIterator(var
); !i
.atEnd(); ++i
){
474 const TableauEntry
& entry
= *i
;
475 Debug("tableau") << "(" << entry
.getRowVar() << ", " << i
.getID() << ") ";
478 Debug("tableau") << endl
;
482 uint32_t Tableau::debugCountRowLength(ArithVar var
){
484 for(RowIterator i
=rowIterator(var
); !i
.atEnd(); ++i
){
491 void ReducedRowVector::enqueueNonBasicVariablesAndCoefficients(std::vector< ArithVar >& variables,std::vector< Rational >& coefficients) const{
492 for(const_iterator i=begin(), endEntries=end(); i != endEntries; ++i){
493 ArithVar var = (*i).getArithVar();
494 const Rational& q = (*i).getCoefficient();
496 variables.push_back(var);
497 coefficients.push_back(q);
502 Node
Tableau::rowAsEquality(ArithVar basic
, const ArithVarToNodeMap
& map
){
503 using namespace CVC4::kind
;
505 Assert(getRowLength(basic
) >= 2);
507 vector
<Node
> nonBasicPairs
;
508 for(RowIterator i
= rowIterator(basic
); !i
.atEnd(); ++i
){
509 const TableauEntry
& entry
= *i
;
510 ArithVar colVar
= entry
.getColVar();
511 if(colVar
== basic
) continue;
512 Node var
= (map
.find(colVar
))->second
;
513 Node coeff
= mkRationalNode(entry
.getCoefficient());
515 Node mult
= NodeBuilder
<2>(MULT
) << coeff
<< var
;
516 nonBasicPairs
.push_back(mult
);
519 Node sum
= Node::null();
520 if(nonBasicPairs
.size() == 1 ){
521 sum
= nonBasicPairs
.front();
523 Assert(nonBasicPairs
.size() >= 2);
524 NodeBuilder
<> sumBuilder(PLUS
);
525 sumBuilder
.append(nonBasicPairs
);
528 Node basicVar
= (map
.find(basic
))->second
;
529 return NodeBuilder
<2>(EQUAL
) << basicVar
<< sum
;
532 double Tableau::densityMeasure() const{
533 Assert(numNonZeroEntriesByRow() == numNonZeroEntries());
534 Assert(numNonZeroEntriesByCol() == numNonZeroEntries());
536 uint32_t n
= getNumRows();
540 uint32_t s
= numNonZeroEntries();
541 uint32_t m
= d_colHeads
.size();
542 uint32_t divisor
= (n
*(m
- n
+ 1));
547 Assert(divisor
>= s
);
549 return (double(s
)) / divisor
;
553 void TableauEntryManager::freeEntry(EntryID id
){
554 Assert(get(id
).blank());
557 d_freedEntries
.push(id
);
561 EntryID
TableauEntryManager::newEntry(){
563 if(d_freedEntries
.empty()){
564 newId
= d_entries
.size();
565 d_entries
.push_back(TableauEntry());
567 newId
= d_freedEntries
.front();
568 d_freedEntries
.pop();