00001 #ifndef PRIMALSOLVER_H_
00002 #define PRIMALSOLVER_H_
00003 #include <iostream>
00004 #include <numeric>
00005 #include <utility>
00006 #include <queue>
00007 #include <algorithm>
00008 #include <functional>
00009 #include <stdexcept>
00010 #include <iomanip>
00011 #include <cassert>
00012 #include <cmath>
00013 #include <list>
00014 #include <limits>
00015
00016
00017
00018 #ifdef TRWS_DEBUG_OUTPUT
00019 #include <opengm/inference/trws/output_debug_utils.hxx>
00020 #endif
00021
00022 namespace TransportSolver
00023 {
00024
00025 #ifdef TRWS_DEBUG_OUTPUT
00026 using OUT::operator <<;
00027 #endif
00028
00029
00030
00031 template<class T>
00032 class List2D
00033 {
00034 public:
00035
00036 struct bufferElement;
00037
00038 struct listElement
00039 {
00040 listElement(size_t coordinate,bufferElement* pbufElement):
00041 _coordinate(coordinate), _pbufElement(pbufElement)
00042 {};
00043
00044 size_t _coordinate;
00045 bufferElement* _pbufElement;
00046 };
00047
00048 typedef std::list<listElement> List1D;
00049
00050 template<class Parent,class typeT>
00051 class iterator_template : public Parent
00052 {
00053 public:
00054 iterator_template(Parent it,const bufferElement* pbuffer0):Parent(it),_pbuffer0(pbuffer0){};
00055 typeT& operator * ()const{return this->Parent::operator *()._pbufElement->_value;}
00056
00057 size_t index()const
00058 {
00059 return (this->Parent::operator *()._pbufElement)-_pbuffer0;
00060 }
00061
00062 size_t coordinate()const{return this->Parent::operator *()._coordinate;}
00063 size_t x()const{return (*this->Parent::operator *()._pbufElement->_rowIterator)._coordinate;}
00064 size_t y()const{return (*this->Parent::operator *()._pbufElement->_colIterator)._coordinate;}
00065
00066 bool isRowIterator()const{return &(*(this->Parent::operator *()._pbufElement->_rowIterator)) == &(*Parent(*this));}
00067
00068 iterator_template changeDir()const{
00069 if (isRowIterator())
00070 return iterator_template(this->Parent::operator *()._pbufElement->_colIterator,_pbuffer0);
00071 else
00072 return iterator_template(this->Parent::operator *()._pbufElement->_rowIterator,_pbuffer0);
00073 }
00074
00075 iterator_template operator ++ (int){iterator_template it=*this; ++(*this); return it;}
00076 iterator_template& operator ++ (){Parent::operator ++(); return *this;}
00077 iterator_template& operator -- (){Parent::operator --(); return *this;}
00078 private:
00079 const bufferElement* _pbuffer0;
00080 };
00081
00082 typedef iterator_template<typename List1D::iterator,T> iterator;
00083 typedef iterator_template<typename List1D::const_iterator,const T> const_iterator;
00084
00085 typedef std::vector<List1D> List1DSeq;
00086
00087 struct bufferElement
00088 {
00089 bufferElement(const T& val,typename List1D::iterator rowIterator,typename List1D::iterator colIterator)
00090 :_value(val) {
00091 if (_value != NaN()) {
00092 _rowIterator = rowIterator;
00093 _colIterator = colIterator;
00094 }
00095 };
00096
00097 bufferElement(const bufferElement &other)
00098 : _value(other._value)
00099 {
00100 if (_value != NaN()) {
00101 _rowIterator = other._rowIterator;
00102 _colIterator = other._colIterator;
00103 }
00104 }
00105
00106 bufferElement & operator=(const bufferElement &other) {
00107 _value = other._value;
00108 if (_value != NaN()) {
00109 _rowIterator = other._rowIterator;
00110 _colIterator = other._colIterator;
00111 }
00112 return *this;
00113 }
00114
00115 T _value;
00116 typename List1D::iterator _rowIterator;
00117 typename List1D::iterator _colIterator;
00118 };
00119
00120 typedef std::vector<bufferElement> Buffer;
00121
00122 List2D(size_t xsize, size_t ysize, size_t nnz);
00123 List2D(const List2D&);
00124 List2D& operator = (const List2D&);
00125
00126 void clear();
00127
00128
00129
00130 void resize(size_t xsize, size_t ysize, size_t nnz);
00131
00132
00133
00134
00135
00136 bool push(size_t x, size_t y, const T& val);
00137
00138
00139
00140
00141
00142
00143
00144
00145 bool insert(size_t x, size_t y, const T& val);
00146 void erase(iterator it);
00147
00148
00149
00150 void erase(size_t index){erase(iterator(_buffer[index]._rowIterator,&_buffer[0]));}
00151
00152 void rowErase(size_t y);
00153 void colErase(size_t x);
00154
00155 size_t rowSize(size_t y)const{return _rowLists[y].size();};
00156 size_t xsize()const{return _colLists.size();}
00157 size_t colSize(size_t x)const{return _colLists[x].size();};
00158 size_t ysize()const{return _rowLists.size();}
00159 size_t nnz()const{return _buffer.size();}
00160
00161 iterator rowBegin(size_t y){return iterator(_rowLists[y].begin(),&_buffer[0]);}
00162 const_iterator rowBegin(size_t y)const{return const_iterator(_rowLists[y].begin(),&_buffer[0]);}
00163
00164 iterator rowEnd(size_t y){return iterator(_rowLists[y].end(),&_buffer[0]);}
00165 const_iterator rowEnd(size_t y)const{return const_iterator(_rowLists[y].end(),&_buffer[0]);}
00166
00167 iterator colBegin(size_t x){return iterator(_colLists[x].begin(),&_buffer[0]);}
00168 const_iterator colBegin(size_t x)const{return const_iterator(_colLists[x].begin(),&_buffer[0]);}
00169
00170 iterator colEnd(size_t x){return iterator(_colLists[x].end(),&_buffer[0]);}
00171 const_iterator colEnd(size_t x)const{return const_iterator(_colLists[x].end(),&_buffer[0]);}
00172
00173
00174 template<class BinaryTable1D>
00175 T inner_product1D(const BinaryTable1D& bin)const;
00176
00177
00178 template<class BinaryTable2D>
00179 T inner_product2D(const BinaryTable2D& bin, T* pprecision=0)const;
00180
00181 template<class BinaryTable2D>
00182 void get2DTable(BinaryTable2D* pbin)const;
00183
00184 T& buffer(size_t index){return _buffer[index]._value;}
00185 const T& buffer(size_t index)const{return _buffer[index]._value;}
00186
00187 std::pair<bool,T> getValue(size_t x,size_t y)const;
00188
00189 #ifdef TRWS_DEBUG_OUTPUT
00190 void PrintTestData(std::ostream& fout)const;
00191 #endif
00192 private:
00193 bool _insert(size_t x, size_t y, const T& val, size_t position);
00194 void _copy(const List2D<T>& lst);
00195 static T NaN(){return std::numeric_limits<T>::max();}
00196
00197
00198 size_t _insertPosition;
00199 size_t _pushPosition;
00200 List1DSeq _rowLists;
00201 List1DSeq _colLists;
00202 Buffer _buffer;
00203 };
00204
00205 template<class T>
00206 List2D<T>::List2D(size_t xsize, size_t ysize, size_t nnz):
00207 _insertPosition(nnz-1),
00208 _pushPosition(0),
00209 _rowLists(ysize),
00210 _colLists(xsize),
00211 _buffer(nnz,bufferElement(NaN(),typename List1D::iterator(),typename List1D::iterator()))
00212 {};
00213
00214 template<class T>
00215 List2D<T>::List2D(const List2D& lst)
00216 {
00217 _copy(lst);
00218 }
00219
00220 template<class T>
00221 void List2D<T>::resize(size_t xsize, size_t ysize, size_t nnz)
00222 {
00223 _rowLists.assign(ysize,List1D());
00224 _colLists.assign(xsize,List1D());
00225 _buffer.assign(nnz,bufferElement(NaN(),typename List1D::iterator(),typename List1D::iterator()));
00226 _insertPosition=nnz-1;
00227 _pushPosition=0;
00228 };
00229
00230
00231 template<class T>
00232 void List2D<T>::_copy(const List2D<T>& lst)
00233 {
00234 _buffer=lst._buffer;
00235
00236 _rowLists=lst._rowLists;
00237 typename List1DSeq::iterator itbeg=_rowLists.begin(), itend=_rowLists.end();
00238 for (;itbeg!=itend;++itbeg)
00239 {
00240 typename List1D::iterator beg=(*itbeg).begin(),end=(*itbeg).end();
00241 for (;beg!=end;++beg)
00242 {
00243 size_t offset=(*beg)._pbufElement-&(lst._buffer[0]);
00244 (*beg)._pbufElement= &_buffer[offset];
00245 (*beg)._pbufElement->_rowIterator=beg;
00246 }
00247 }
00248
00249 _colLists=lst._colLists;
00250 itbeg=_colLists.begin(), itend=_colLists.end();
00251 for (;itbeg!=itend;++itbeg)
00252 {
00253 typename List1D::iterator beg=(*itbeg).begin(),end=(*itbeg).end();
00254 for (;beg!=end;++beg)
00255 {
00256 size_t offset=(*beg)._pbufElement-&(lst._buffer[0]);
00257 (*beg)._pbufElement= &_buffer[offset];
00258 (*beg)._pbufElement->_colIterator=beg;
00259 }
00260 }
00261
00262
00263 _insertPosition=lst._insertPosition;
00264 _pushPosition=lst._pushPosition;
00265 };
00266
00267 template<class T>
00268 List2D<T>& List2D<T>::operator = (const List2D<T>& lst)
00269 {
00270 if (this==&lst)
00271 return *this;
00272
00273 _copy(lst);
00274
00275 return *this;
00276 }
00277
00278 template<class T>
00279 bool List2D<T>::insert(size_t x,size_t y,const T& val)
00280 {
00281 if (_insert(x,y,val,_insertPosition))
00282 {
00283 _insertPosition=_buffer.size();
00284 return true;
00285 }
00286
00287 return false;
00288 };
00289
00290 template<class T>
00291 bool List2D<T>::push(size_t x, size_t y, const T& val)
00292 {
00293 if (_insert(x,y,val,_pushPosition))
00294 {
00295 ++_pushPosition;
00296
00297 if (_pushPosition == (_buffer.size()-1))
00298 ++_pushPosition;
00299 return true;
00300 }
00301
00302 return false;
00303 }
00304
00305 template<class E>
00306 class coordLess
00307 {
00308 public:
00309 coordLess(size_t x):_x(x){}
00310 bool operator () (const E& e) const{return e._coordinate < _x;}
00311 private:
00312 size_t _x;
00313 };
00314
00315 template<class E>
00316 class coordMore
00317 {
00318 public:
00319 coordMore(size_t x):_x(x){}
00320 bool operator () (const E& e) const{return e._coordinate > _x;}
00321 private:
00322 size_t _x;
00323 };
00324
00325 template<class T>
00326 bool List2D<T>::_insert(size_t x, size_t y, const T& val, size_t position)
00327 {
00328 assert(x<_colLists.size());
00329 assert(y< _rowLists.size());
00330
00331 if (position >= _buffer.size())
00332 return false;
00333
00334 bufferElement& buf=_buffer[position];
00335 buf._value=val;
00336
00337 List1D& rowList=_rowLists[y];
00338 List1D& colList=_colLists[x];
00339
00340 typename List1D::iterator insertPosition=std::find_if(rowList.begin(),rowList.end(),coordMore<listElement>(x));
00341 buf._rowIterator=rowList.insert(insertPosition,listElement(x,&buf));
00342 insertPosition=std::find_if(colList.begin(),colList.end(),coordMore<listElement>(y));
00343 buf._colIterator=colList.insert(insertPosition,listElement(y,&buf));
00344
00345 return true;
00346 };
00347
00348 template<class T>
00349 void List2D<T>::erase(iterator it)
00350 {
00351 _insertPosition=it.index();
00352 size_t x=it.x(), y=it.y();
00353 _rowLists[y].erase(_buffer[_insertPosition]._rowIterator);
00354 _colLists[x].erase(_buffer[_insertPosition]._colIterator);
00355 _buffer[_insertPosition]._value=NaN();
00356 };
00357
00358 template<class T>
00359 void List2D<T>::rowErase(size_t y)
00360 {
00361 while (!_rowLists[y].empty())
00362 erase(iterator(_rowLists[y].begin(),&_buffer[0]));
00363 };
00364
00365 template<class T>
00366 void List2D<T>::colErase(size_t x)
00367 {
00368 while (!_colLists[x].empty())
00369 erase(iterator(_colLists[x].begin(),&_buffer[0]));
00370 };
00371
00372 template<class T>
00373 void List2D<T>::clear()
00374 {
00375 for (size_t x=0;x<_rowLists.size();++x)
00376 rowErase(x);
00377
00378 for (size_t y=0;y<_colLists.size();++y)
00379 colErase(y);
00380
00381 _pushPosition=0;
00382 _insertPosition=_buffer.size()-1;
00383 };
00384
00385 template<class T>
00386 template<class BinaryTable1D>
00387 T List2D<T>::inner_product1D(const BinaryTable1D& bin)const
00388 {
00389 T sum=0;
00390 for (size_t i=0; i<_colLists.size();++i)
00391 {
00392 typename List1D::const_iterator beg=_colLists[i].begin(), end=_colLists[i].end();
00393 for (;beg!=end;++beg)
00394 sum+=(*beg)._pbufElement->_value * bin[xsize()*((*beg)._coordinate)+i];
00395 };
00396 return sum;
00397 };
00398
00399 template<class T>
00400 template<class BinaryTable2D>
00401 T List2D<T>::inner_product2D(const BinaryTable2D& bin, T* pprecision)const
00402 {
00403 T floatTypeEps=std::numeric_limits<T>::epsilon();
00404 T precision_;
00405 T* pprecision_;
00406 if (pprecision!=0)
00407 pprecision_=pprecision;
00408 else
00409 pprecision_=&precision_;
00410
00411 *pprecision_=0;
00412
00413 T sum=0;
00414 for (size_t i=0; i<xsize();++i)
00415 {
00416 const_iterator beg=colBegin(i), end=colEnd(i);
00417 for (;beg!=end;++beg)
00418 {
00419 sum+=(*beg) * bin(beg.x(),beg.y());
00420 *pprecision_+=floatTypeEps*fabs(sum);
00421 }
00422 };
00423 return sum;
00424 };
00425
00426 template<class T>
00427 std::pair<bool,T> List2D<T>::getValue(size_t x,size_t y)const
00428 {
00429 typename List1D::const_iterator beg=_colLists[x].begin(), end=_colLists[x].end();
00430 for (;beg!=end;++beg)
00431 if ((*beg)._coordinate==y)
00432 return std::make_pair(true,(*beg)._pbufElement->_value);
00433
00434 return std::make_pair(false,(T)0);
00435 };
00436
00437 #ifdef TRWS_DEBUG_OUTPUT
00438 template<class T>
00439 void List2D<T>::PrintTestData(std::ostream& fout)const
00440 {
00441 fout << "_nnz=" <<_buffer.size()<<std::endl;
00442 fout << "_insertPosition=" << _insertPosition<<std::endl;
00443 fout << "_pushPosition=" << _pushPosition<<std::endl;
00444 fout << "xsize="<<_colLists.size()<<std::endl;
00445 fout << "ysize="<<_rowLists.size()<<std::endl;
00446
00447 std::vector<T> printBuffer(_buffer.size(),NaN());
00448
00449 fout << "row Lists: "<<std::endl;
00450 for (size_t i=0; i< _rowLists.size();++i)
00451 {
00452 fout << "y="<<i<<": ";
00453 typename List1D::const_iterator beg=_rowLists[i].begin(), end=_rowLists[i].end();
00454 for (;beg!=end;++beg)
00455 {
00456 fout <<"("<<(*beg)._coordinate<<","<<(*beg)._pbufElement->_value<<")";
00457 printBuffer[(*beg)._pbufElement-&_buffer[0]]=(*beg)._pbufElement->_value;
00458 }
00459 fout <<std::endl;
00460 }
00461
00462 fout << "column Lists: "<<std::endl;
00463 for (size_t i=0; i< _colLists.size();++i)
00464 {
00465 fout << "x="<<i<<": ";
00466 typename List1D::const_iterator beg=_colLists[i].begin(), end=_colLists[i].end();
00467 for (;beg!=end;++beg)
00468 {
00469 fout <<"("<<(*beg)._coordinate<<","<<(*beg)._pbufElement->_value<<")";
00470 }
00471 fout <<std::endl;
00472 }
00473
00474 fout << "buffer: ";
00475 for (size_t i=0;i<printBuffer.size();++i)
00476 if (printBuffer[i]!=NaN())
00477 fout << "("<<_buffer[i]._value<<","<<(*_buffer[i]._rowIterator)._coordinate <<","<< (*_buffer[i]._colIterator)._coordinate<<")";
00478 else
00479 fout << "(nan,nan,nan)";
00480 fout << std::endl;
00481
00482 };
00483 #endif
00484
00485 template<class T>
00486 template<class BinaryTable2D>
00487 void List2D<T>::get2DTable(BinaryTable2D* pbin)const
00488 {
00489 for (size_t x=0;x<xsize();++x)
00490 for (size_t y=0;y<ysize();++y)
00491 (*pbin)(x,y)=0;
00492
00493 for (size_t i=0; i<xsize();++i)
00494 {
00495 const_iterator beg=colBegin(i), end=colEnd(i);
00496 for (;beg!=end;++beg)
00497 (*pbin)(beg.x(),beg.y())=(*beg);
00498 };
00499 };
00500
00501
00502
00503
00504
00505
00506 template<class T>
00507 class MatrixWrapper
00508 {
00509 public:
00510 typedef typename std::vector<T>::const_iterator const_iterator;
00511 typedef typename std::vector<T>::iterator iterator;
00512 typedef T ValueType;
00513 MatrixWrapper():_xsize(0),_ysize(0){};
00514 MatrixWrapper(size_t xsize,size_t ysize):_xsize(xsize),_ysize(ysize),_array(xsize*ysize){};
00515 MatrixWrapper(size_t xsize,size_t ysize, T value):_xsize(xsize),_ysize(ysize),_array(xsize*ysize,value){};
00516 void resize(size_t xsize,size_t ysize){_xsize=xsize;_ysize=ysize;_array.resize(xsize*ysize);};
00517 void assign(size_t xsize,size_t ysize,T value){_xsize=xsize;_ysize=ysize;_array.assign(xsize*ysize,value);};
00518 const_iterator begin()const {return _array.begin();}
00519 const_iterator end ()const {return _array.end();}
00520 iterator begin() {return _array.begin();}
00521 iterator end () {return _array.end();}
00522
00523 const T& operator() (size_t x,size_t y)const{return _array[y*_xsize + x];}
00524 T& operator() (size_t x,size_t y) {return _array[y*_xsize + x];}
00525 size_t xsize()const{return _xsize;}
00526 size_t ysize()const{return _ysize;}
00527
00528 #ifdef TRWS_DEBUG_OUTPUT
00529 std::ostream& print(std::ostream& out)const
00530 {
00531 const_iterator it=begin();
00532 out<<"["<<_xsize<<","<<_ysize<<"](";
00533 for (size_t y=0;y<_ysize;++y)
00534 {
00535 if (y!=0) out << ",";
00536 out <<"(";
00537 for (size_t x=0;x<_xsize;++x)
00538 {
00539 if (x!=0) out << ",";
00540 out << *it;
00541 ++it;
00542 }
00543 out << ")";
00544 }
00545
00546 return out<<")";
00547 }
00548 #endif
00549
00550 private:
00551 size_t _xsize, _ysize;
00552 std::vector<T> _array;
00553 };
00554
00555 template<class T>
00556 void transpose(const MatrixWrapper<T>& input, MatrixWrapper<T>& result)
00557 {
00558 result.resize(input.xsize(),input.ysize());
00559 for (size_t x=0;x<input.xsize();++x)
00560 for (size_t y=0;y<input.ysize();++y)
00561 result(y,x)=input(x,y);
00562 }
00563
00564
00565
00566
00567 template <class InputIterator, class OutputIteratorValue,class OutputIteratorIndex, class UnaryPredicate>
00568 OutputIteratorValue copy_if (InputIterator first, InputIterator last,
00569 OutputIteratorValue result, OutputIteratorIndex resultIndex, UnaryPredicate pred)
00570 {
00571 size_t indx=0;
00572 while (first!=last) {
00573 if (pred(*first)) {
00574 *result = *first;
00575 *resultIndex=indx;
00576 ++resultIndex;
00577 ++result;
00578 }
00579 ++indx;
00580 ++first;
00581 }
00582 return result;
00583 }
00584
00585 template<class Iterator,class T>
00586 T _Normalize(Iterator begin,Iterator end,T initialValue)
00587 {
00588 T acc=std::accumulate(begin,end,(T)0.0);
00589 std::transform(begin,end,begin,std::bind1st(std::multiplies<T>(),1.0/acc));
00590 return initialValue+acc;
00591 };
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609 template<class OPTIMIZER, class DenseMatrix>
00610 class TransportationSolver
00611 {
00612 public:
00613 typedef typename DenseMatrix::ValueType floatType;
00614 typedef enum{X, Y} Direction;
00615 typedef std::pair<size_t,Direction> CoordDir;
00616 typedef std::queue<CoordDir> Queue;
00617 typedef List2D<floatType> FeasiblePoint;
00618 typedef std::vector<floatType> UnaryDense;
00619 typedef std::vector<size_t> IndexArray;
00620 typedef std::list<typename FeasiblePoint::const_iterator> CycleList;
00621
00622 static const floatType floatTypeEps;
00623 static const size_t defaultMaxIterationNumber;
00624 static const size_t MAXSIZE_T;
00625
00626 TransportationSolver(
00627 #ifdef TRWS_DEBUG_OUTPUT
00628 std::ostream& fout=std::cerr,
00629 #endif
00630 floatType relativePrecision=floatTypeEps,size_t maxIterationNumber=defaultMaxIterationNumber):
00631 #ifdef TRWS_DEBUG_OUTPUT
00632 _fout(fout),
00633 #endif
00634 _pbinInitial(0),_xsize(0),_ysize(0),_relativePrecision(relativePrecision),_basicSolution(0,0,0),_maxIterationNumber(maxIterationNumber)
00635 {
00636 assert(relativePrecision >0);
00637 };
00638
00639 TransportationSolver(const size_t& xsize,const size_t& ysize,const DenseMatrix& bin,
00640 #ifdef TRWS_DEBUG_OUTPUT
00641 std::ostream& fout=std::cout,
00642 #endif
00643 floatType relativePrecision=floatTypeEps,size_t maxIterationNumber=100):
00644 #ifdef TRWS_DEBUG_OUTPUT
00645 _fout(fout),
00646 #endif
00647 _pbinInitial(&bin),_xsize(xsize),_ysize(ysize),_relativePrecision(relativePrecision),_basicSolution(xsize,ysize,_nnz(xsize,ysize)),_maxIterationNumber(maxIterationNumber)
00648 {
00649 assert(relativePrecision >0);
00650 Init(xsize,ysize,bin);
00651 };
00652
00653
00654 void Init(size_t xsize,size_t ysize,const DenseMatrix& bin);
00655
00656
00657
00658
00659
00660
00661 template <class Iterator>
00662 floatType Solve(Iterator xbegin,Iterator ybegin);
00663
00664 floatType GetObjectiveValue()const{return _basicSolution.inner_product2D(_matrix, &_primalValueNumericalPrecision);};
00665
00666
00667
00668 template<class OutputMatrix>
00669 floatType GetSolution(OutputMatrix* pbin)const;
00670 #ifdef TRWS_DEBUG_OUTPUT
00671 void PrintTestData(std::ostream& fout)const;
00672 void PrintProblemDescription(const UnaryDense& xarr,const UnaryDense& yarr);
00673 #endif
00674 private:
00675 void _InitBasicSolution(const UnaryDense& xarr,const UnaryDense& yarr);
00676 bool _isOptimal(std::pair<size_t,size_t>* pmove);
00677 bool _CheckDualConstraints(const UnaryDense& xdual,const UnaryDense& ydual,std::pair<size_t,size_t>* pmove )const;
00678 CoordDir _findSingleNeighborNode(const FeasiblePoint&)const;
00679 void _BuildDuals(UnaryDense* pxdual,UnaryDense* pydual);
00680 void _FindCycle(FeasiblePoint* pfp,const std::pair<size_t,size_t>& move);
00681 void _ChangeSolution(const FeasiblePoint& fp,const std::pair<size_t,size_t>& move);
00682 bool _MovePotentials(const std::pair<size_t,size_t>& move);
00683
00684 void _move2Neighbor(const FeasiblePoint& fp,typename FeasiblePoint::const_iterator &it)const;
00685
00686 static size_t _nnz(size_t xsize,size_t ysize){return xsize+ysize;}
00687 template <class Iterator>
00688 static floatType _FilterBound(Iterator xbegin,size_t xsize,UnaryDense& out,IndexArray* pactiveIndexes, floatType precision);
00689 void _FilterObjectiveMatrix();
00690 void _checkCounter(size_t* pcounter,const char* errmess);
00691
00692 mutable floatType _primalValueNumericalPrecision;
00693 bool _recalculated;
00694 #ifdef TRWS_DEBUG_OUTPUT
00695 std::ostream& _fout;
00696 #endif
00697 const DenseMatrix* _pbinInitial;
00698 MatrixWrapper<floatType> _matrix;
00699 size_t _xsize,_ysize;
00700 floatType _relativePrecision;
00701 FeasiblePoint _basicSolution;
00702 IndexArray _nonZeroXcoordinates;
00703 IndexArray _nonZeroYcoordinates;
00704 size_t _maxIterationNumber;
00705 };
00706
00707 template<class OPTIMIZER,class DenseMatrix>
00708 const typename TransportationSolver<OPTIMIZER,DenseMatrix>::floatType TransportationSolver<OPTIMIZER,DenseMatrix>::floatTypeEps=std::numeric_limits<TransportationSolver<OPTIMIZER,DenseMatrix>::floatType>::epsilon();
00709
00710 template<class OPTIMIZER,class DenseMatrix>
00711 const size_t TransportationSolver<OPTIMIZER,DenseMatrix>::MAXSIZE_T=std::numeric_limits<size_t>::max();
00712
00713 template<class OPTIMIZER,class DenseMatrix>
00714 const size_t TransportationSolver<OPTIMIZER,DenseMatrix>::defaultMaxIterationNumber=100;
00715
00716 template<class OPTIMIZER,class DenseMatrix>
00717 void TransportationSolver<OPTIMIZER,DenseMatrix>::Init(size_t xsize,size_t ysize,const DenseMatrix& bin)
00718 {
00719 _pbinInitial=&bin;
00720 _xsize=xsize;
00721 _ysize=ysize;
00722 _basicSolution.resize(xsize,ysize,_nnz(xsize,ysize));
00723 _nonZeroXcoordinates.clear();
00724 _nonZeroYcoordinates.clear();
00725 _primalValueNumericalPrecision=0;
00726 };
00727
00728 template<class OPTIMIZER,class DenseMatrix>
00729 void TransportationSolver<OPTIMIZER,DenseMatrix>::
00730 _checkCounter (size_t* pcounter, const char* errmess)
00731 {
00732 if ((*pcounter)++ < std::max(_xsize*_ysize*100,_maxIterationNumber) )
00733 return;
00734
00735 throw std::runtime_error(errmess);
00736 };
00737
00738 template<class OPTIMIZER,class DenseMatrix>
00739 void TransportationSolver<OPTIMIZER,DenseMatrix>::
00740 _InitBasicSolution(const UnaryDense& xarr,const UnaryDense& yarr)
00741 {
00742 UnaryDense row=xarr;
00743 UnaryDense col=yarr;
00744
00745
00746 _basicSolution.resize(xarr.size(),yarr.size(),_nnz(xarr.size(),yarr.size()));
00747 typename UnaryDense::iterator rbeg=row.begin(), rend=row.end();
00748 typename UnaryDense::iterator cbeg=col.begin(), cend=col.end();
00749
00750 size_t counter=0;
00751 while ((rbeg!=rend)&&(cbeg!=cend))
00752 {
00753 if (*cbeg>=*rbeg)
00754 {
00755
00756 _basicSolution.push(rbeg-row.begin(), cbeg-col.begin(),*rbeg);
00757 (*cbeg)-=(*rbeg);
00758 if (rbeg!=rend)
00759 ++rbeg;
00760 else
00761 ++cbeg;
00762 }
00763 else
00764 {
00765 _basicSolution.push(rbeg-row.begin(),cbeg-col.begin(),*cbeg);
00766 (*rbeg)-=(*cbeg);
00767 if (cbeg!=cend)
00768 ++cbeg;
00769 else
00770 ++rbeg;
00771 }
00772
00773 _checkCounter(&counter,"_InitBasicSolution-infinite loop!\n");
00774 }
00775
00776 size_t basicNum=xarr.size()+yarr.size()-1;
00777 if (counter!=basicNum)
00778 throw std::runtime_error("TransportationSolver::_InitBasicSolution() : INTERNAL ERROR: Can not initialize basic solution!");
00779 };
00780
00781
00782
00783
00784
00785
00786
00787 template<class OPTIMIZER,class DenseMatrix>
00788 typename TransportationSolver<OPTIMIZER,DenseMatrix>::CoordDir
00789 TransportationSolver<OPTIMIZER,DenseMatrix>::_findSingleNeighborNode(const FeasiblePoint& fp)const
00790 {
00791 for (size_t i=0;i<_nonZeroXcoordinates.size();++i)
00792 if (fp.colSize(i)==1)
00793 return std::make_pair(i,X);
00794
00795 for (size_t i=0;i<_nonZeroYcoordinates.size();++i)
00796 if (fp.rowSize(i)==1)
00797 return std::make_pair(i,Y);
00798
00799 return std::make_pair(MAXSIZE_T,X);
00800 };
00801
00802 template<class OPTIMIZER,class DenseMatrix>
00803 void TransportationSolver<OPTIMIZER,DenseMatrix>::
00804 _BuildDuals(UnaryDense* pxdual,UnaryDense* pydual)
00805 {
00806 UnaryDense& xdual=*pxdual;
00807 UnaryDense& ydual=*pydual;
00808
00809 xdual.assign(_nonZeroXcoordinates.size(),0.0);
00810 ydual.assign(_nonZeroYcoordinates.size(),0.0);
00811
00812 FeasiblePoint fpcopy(_basicSolution);
00813 CoordDir currNode=_findSingleNeighborNode(fpcopy);
00814
00815 if (currNode.first==MAXSIZE_T)
00816 throw std::runtime_error("_BuildDuals: can not build duals: no single neighbor node available!");
00817
00818 if (currNode.second==X)
00819 {
00820 currNode.second=Y;
00821 currNode.first=fpcopy.colBegin(currNode.first).coordinate();
00822 }else
00823 {
00824 currNode.second=X;
00825 currNode.first=fpcopy.rowBegin(currNode.first).coordinate();
00826 }
00827
00828 Queue qu;
00829 qu.push(currNode);
00830
00831 size_t counter=0;
00832 do
00833 {
00834 if (qu.front().second==Y)
00835 {
00836 size_t y=qu.front().first;
00837
00838 typename FeasiblePoint::iterator beg=fpcopy.rowBegin(y),
00839 end=fpcopy.rowEnd(y);
00840 for (;beg!=end;++beg)
00841 {
00842 size_t x=beg.coordinate();
00843
00844 xdual[x]=_matrix(x,y)-ydual[y];
00845 qu.push(std::make_pair(x,X));
00846 }
00847 fpcopy.rowErase(y);
00848
00849 }else
00850 {
00851 size_t x=qu.front().first;
00852
00853 typename FeasiblePoint::iterator beg=fpcopy.colBegin(x),
00854 end=fpcopy.colEnd(x);
00855 for (;beg!=end;++beg)
00856 {
00857 size_t y=beg.coordinate();
00858
00859 ydual[y]=_matrix(x,y)-xdual[x];
00860 qu.push(std::make_pair(y,Y));
00861 }
00862
00863 fpcopy.colErase(x);
00864 }
00865
00866 qu.pop();
00867
00868 _checkCounter(&counter, "_BuildDuals-infinite loop!\n");
00869 }while (!qu.empty());
00870
00871 };
00872
00873 template<class OPTIMIZER,class DenseMatrix>
00874 bool TransportationSolver<OPTIMIZER,DenseMatrix>::
00875 _CheckDualConstraints(const UnaryDense& xdual,const UnaryDense& ydual,std::pair<size_t,size_t>* pmove)const
00876 {
00877 floatType eps=(OPTIMIZER::bop(1,0) ? 1.0 : -1.0)*floatTypeEps;
00878 floatType delta, precision;
00879
00880 typename MatrixWrapper<floatType>::const_iterator mit=_matrix.begin();
00881 for (typename UnaryDense::const_iterator ybeg=ydual.begin();ybeg<ydual.end();++ybeg)
00882 for (typename UnaryDense::const_iterator xbeg=xdual.begin();xbeg<xdual.end();++xbeg)
00883 {
00884 delta=*mit-*xbeg-*ybeg;
00885 precision=(fabs(*mit)+fabs(*xbeg)+fabs(*ybeg))*eps;
00886 if (OPTIMIZER::bop(delta,precision))
00887 {
00888 pmove->first=xbeg-xdual.begin(); pmove->second=ybeg-ydual.begin();
00889 return false;
00890 }
00891 ++mit;
00892 }
00893
00894 return true;
00895 };
00896
00897 template<class OPTIMIZER,class DenseMatrix>
00898 void TransportationSolver<OPTIMIZER,DenseMatrix>::
00899 _FindCycle(FeasiblePoint* pfp,const std::pair<size_t,size_t>& move)
00900 {
00901 FeasiblePoint& fp=*pfp;
00902
00903 fp.insert(move.first,move.second,0);
00904
00905 CoordDir cd=_findSingleNeighborNode(fp);
00906
00907 size_t counter=0;
00908 while (cd.first<MAXSIZE_T)
00909 {
00910 if (cd.second==X)
00911 fp.colErase(cd.first);
00912 else
00913 fp.rowErase(cd.first);
00914
00915 cd=_findSingleNeighborNode(fp);
00916
00917 _checkCounter(&counter,"_FindCycle-infinite loop!\n");
00918 }
00919 };
00920
00921
00922 template<class OPTIMIZER,class DenseMatrix>
00923 void TransportationSolver<OPTIMIZER,DenseMatrix>::
00924 _move2Neighbor(const FeasiblePoint& fp,typename FeasiblePoint::const_iterator &it)const
00925 {
00926 typename FeasiblePoint::const_iterator beg=fp.rowBegin(0);
00927 if (it.isRowIterator())
00928 {
00929 beg=fp.rowBegin(it.y());
00930 }
00931 else
00932 {
00933 beg=fp.colBegin(it.x());
00934 }
00935
00936 if (beg==it)
00937 ++it;
00938 else
00939 --it;
00940 };
00941
00942 template<class OPTIMIZER,class DenseMatrix>
00943 void TransportationSolver<OPTIMIZER,DenseMatrix>::
00944 _ChangeSolution(const FeasiblePoint& fp,const std::pair<size_t,size_t>& move)
00945 {
00946 size_t y=0;
00947 for (;y<fp.ysize();++y)
00948 {
00949 assert( (fp.rowSize(y)==2) || (fp.rowSize(y)==0) ) ;
00950 if (fp.rowSize(y)!=0)
00951 break;
00952 }
00953
00954 CycleList plusList, minusList;
00955 CycleList* pplus=&plusList, *pPlusList=0;
00956 CycleList* pminus=&minusList, *pMinusList=0;
00957
00958
00959 typename FeasiblePoint::const_iterator it=fp.rowBegin(y);
00960 std::pair<size_t,size_t> c0(it.x(),it.y());
00961 do{
00962 pplus->push_back(it);
00963 if ( (it.x()==move.first) && (it.y()==move.second) )
00964 {
00965 pMinusList=pminus;
00966 pPlusList =pplus;
00967 }
00968 it=it.changeDir();
00969 _move2Neighbor(fp,it);
00970 swap(pplus,pminus);
00971 }while (! ( (it.x()==c0.first) && (it.y()==c0.second) ) );
00972
00973 assert (pMinusList!=0);
00974 assert (pPlusList!=0);
00975
00976
00977 floatType min=std::numeric_limits<floatType>::max();
00978 typename CycleList::const_iterator iterMinVal, beg=pMinusList->begin(), end=pMinusList->end();
00979 for (;beg!=end;++beg)
00980 {
00981 if ( ( **beg < min) ||
00982 ( (**beg == min) &&
00983 ( (beg->y() < iterMinVal->y()) ||
00984 ( ((beg->y() == iterMinVal->y())
00985 && (beg->x() < iterMinVal->x())) ) ) ) )
00986 {
00987 min=**beg;
00988 iterMinVal=beg;
00989 }
00990 }
00991
00992
00993 _basicSolution.insert(move.first,move.second,0);
00994
00995 beg=pMinusList->begin(), end=pMinusList->end();
00996 for (;beg!=end;++beg)
00997 _basicSolution.buffer((*beg).index())-=min;
00998
00999 beg=pPlusList->begin(), end=pPlusList->end();
01000 for (;beg!=end;++beg)
01001 _basicSolution.buffer((*beg).index())+=min;
01002
01003 _basicSolution.erase((*iterMinVal).index());
01004 }
01005
01006 template<class OPTIMIZER,class DenseMatrix>
01007 bool TransportationSolver<OPTIMIZER,DenseMatrix>::
01008 _MovePotentials(const std::pair<size_t,size_t>& move)
01009 {
01010 floatType ObjVal=GetObjectiveValue();
01011 floatType primalValueNumericalPrecisionOld=_primalValueNumericalPrecision;
01012 FeasiblePoint fp=_basicSolution;
01013
01014 _FindCycle(&fp,move);
01015
01016 _ChangeSolution(fp,move);
01017
01018
01019 floatType newObjValue=GetObjectiveValue();
01020 if ( (OPTIMIZER::bop(ObjVal,newObjValue)) && (fabs(ObjVal-newObjValue)>(_primalValueNumericalPrecision+primalValueNumericalPrecisionOld) ) )
01021 {
01022 #ifdef TRWS_DEBUG_OUTPUT
01023 std::cerr<<_fout<<std::setprecision (std::numeric_limits<floatType>::digits10+1) << std::endl<<"ObjVal="<<ObjVal
01024 <<", newObjValue="<<newObjValue
01025 <<", fabs(ObjVal-newObjValue)="<<fabs(ObjVal-newObjValue)<<", _primalValueNumericalPrecision="<<_primalValueNumericalPrecision
01026 << ", primalValueNumericalPrecisionOld="<< primalValueNumericalPrecisionOld <<std::endl;
01027 _fout << "Basic solution before move:" <<std::endl;
01028 fp.PrintTestData(_fout);
01029 _fout << "Move:" << move<<std::endl;
01030 #endif
01031 return false;
01032 }
01033
01034 return true;
01035 };
01036
01037
01038 template<class OPTIMIZER,class DenseMatrix>
01039 bool TransportationSolver<OPTIMIZER,DenseMatrix>::
01040 _isOptimal(std::pair<size_t,size_t>* pmove)
01041 {
01042
01043
01044 UnaryDense xduals,yduals;
01045 _BuildDuals(&xduals,&yduals);
01046
01047 return _CheckDualConstraints(xduals,yduals,pmove);
01048 };
01049
01050 template<class OPTIMIZER,class DenseMatrix>
01051 template <class Iterator>
01052 typename TransportationSolver<OPTIMIZER,DenseMatrix>::floatType TransportationSolver<OPTIMIZER,DenseMatrix>::
01053 _FilterBound(Iterator xbegin,size_t xsize,UnaryDense& out,IndexArray* pactiveIndexes,floatType precision)
01054 {
01055 size_t numOfMeaningfulValues=std::count_if(xbegin,xbegin+xsize,std::bind2nd(std::greater<floatType>(),precision));
01056
01057 if (numOfMeaningfulValues==0)
01058 throw std::runtime_error("TransportationSolver:_FilterBound(): Error: empty output array. Was the _relativePrecision parameter selected properly?");
01059
01060 out.resize(numOfMeaningfulValues);
01061 pactiveIndexes->resize(numOfMeaningfulValues);
01062 TransportSolver::copy_if(xbegin,xbegin+xsize,out.begin(),pactiveIndexes->begin(),std::bind2nd(std::greater<floatType>(),precision));
01063 return _Normalize(out.begin(),out.end(),(floatType)0.0);
01064 }
01065
01066 #ifdef TRWS_DEBUG_OUTPUT
01067 template<class OPTIMIZER,class DenseMatrix>
01068 void TransportationSolver<OPTIMIZER,DenseMatrix>::
01069 PrintProblemDescription(const UnaryDense& xarr,const UnaryDense& yarr)
01070 {
01071 size_t maxprecision=std::numeric_limits<floatType>::digits10;
01072 _fout<< std::setprecision (maxprecision+1) << "xarr=" << xarr<< std::endl;;
01073 _fout<< std::setprecision (maxprecision+1) << "yarr=" << yarr << std::endl;
01074
01075 for (size_t x=0;x<xarr.size();++x)
01076 for (size_t y=0;y<yarr.size();++y)
01077 _fout << std::setprecision (maxprecision+1)<<"; bin("<<_nonZeroXcoordinates[x]<<","<<_nonZeroYcoordinates[y]<<")="<<_matrix(x,y)<<std::endl;
01078
01079 _fout <<std::endl<< "Current basic solution:"<<std::endl;
01080 _basicSolution.PrintTestData(_fout);
01081 }
01082 #endif
01083
01084 template<class OPTIMIZER,class DenseMatrix>
01085 void TransportationSolver<OPTIMIZER,DenseMatrix>::_FilterObjectiveMatrix()
01086 {
01087 _matrix.resize(_nonZeroXcoordinates.size(),_nonZeroYcoordinates.size());
01088 typename MatrixWrapper<floatType>::iterator begin=_matrix.begin();
01089 for (size_t y=0;y<_nonZeroYcoordinates.size();++y)
01090 for (size_t x=0;x<_nonZeroXcoordinates.size();++x)
01091 {
01092 size_t ycurr=_nonZeroYcoordinates[y];
01093 *begin=(*_pbinInitial)(_nonZeroXcoordinates[x],ycurr);
01094 ++begin;
01095 }
01096 }
01097
01098 template<class OPTIMIZER,class DenseMatrix>
01099 template<class Iterator>
01100 typename TransportationSolver<OPTIMIZER,DenseMatrix>::floatType TransportationSolver<OPTIMIZER,DenseMatrix>::
01101 Solve(Iterator xbegin,Iterator ybegin)
01102 {
01103 _recalculated=false;
01104 UnaryDense xarr,yarr;
01105
01106 _FilterBound(xbegin,_xsize,xarr,&_nonZeroXcoordinates,_relativePrecision*_xsize*_ysize);
01107 _FilterBound(ybegin,_ysize,yarr,&_nonZeroYcoordinates,_relativePrecision*_xsize*_ysize);
01108 _FilterObjectiveMatrix();
01109
01110
01111 _InitBasicSolution(xarr,yarr);
01112
01113
01114 std::pair<size_t,size_t> move;
01115 bool objectiveImprovementFlag=true;
01116 size_t counter=0;
01117
01118 while ((objectiveImprovementFlag)&&(!_isOptimal(&move)))
01119 {
01120 objectiveImprovementFlag=_MovePotentials(move);
01121 _checkCounter(&counter,"TransportationSolver::Solve(): maximal number of iterations reached! Try to increase <maxIterationNumber> in constructor.\n");
01122 if (!objectiveImprovementFlag)
01123 {
01124 #ifdef TRWS_DEBUG_OUTPUT
01125 PrintProblemDescription(xarr,yarr);
01126 #endif
01127 throw std::runtime_error("TransportationSolver::Solve: INTERNAL ERROR: Objective has become worse. Interrupting!");
01128 }
01129 }
01130 return GetObjectiveValue();
01131 };
01132
01133
01134 template<class OPTIMIZER,class DenseMatrix>
01135 template<class OutputMatrix>
01136 typename TransportationSolver<OPTIMIZER,DenseMatrix>::floatType TransportationSolver<OPTIMIZER,DenseMatrix>::GetSolution(OutputMatrix* pbin)const
01137 {
01138 for (size_t y=0;y<_ysize;++y)
01139 for (size_t x=0;x<_xsize;++x)
01140 (*pbin)(x,y)=0.0;
01141
01142 MatrixWrapper<floatType> matrix(_basicSolution.xsize(),_basicSolution.ysize());
01143 _basicSolution.get2DTable(&matrix);
01144 for (size_t y=0;y<matrix.ysize();++y)
01145 for (size_t x=0;x<matrix.xsize();++x)
01146 (*pbin)(_nonZeroXcoordinates[x],_nonZeroYcoordinates[y])=matrix(x,y);
01147
01148 return GetObjectiveValue();
01149 };
01150
01151 #ifdef TRWS_DEBUG_OUTPUT
01152 template<class OPTIMIZER,class DenseMatrix>
01153 void TransportationSolver<OPTIMIZER,DenseMatrix>::PrintTestData(std::ostream& fout)const
01154 {
01155 fout << "_relativePrecision="<<_relativePrecision<<std::endl;
01156 fout << "_xsize="<<_xsize<<", _ysize="<<_ysize<<std::endl;
01157 fout <<"_basicSolution:"<<std::endl;
01158 _basicSolution.PrintTestData(fout);
01159 fout <<std::endl<< "_nonZeroXcoordinates: "<<_nonZeroXcoordinates;
01160 fout <<std::endl<< "_nonZeroYcoordinates: "<<_nonZeroYcoordinates;
01161 };
01162 #endif
01163
01164 };
01165
01166 #endif