transportationsolver.hxx

Go to the documentation of this file.
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 //#define TRWS_DEBUG_OUTPUT
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 /* List 2D class and implementation ==================================================== */
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     * after resizing all data is lost!
00129     */
00130    void resize(size_t xsize, size_t ysize, size_t nnz);
00131 
00132    /* tries to insert to the end of lists.
00133     * compares coordinates of the last element for this purpose
00134     * it it does not work, returns <false>
00135     */
00136    bool push(size_t x, size_t y, const T& val);
00137 
00138    /*
00139     * tries to insert to the position of the last
00140     * call of the function erase(). If it was not called yet -
00141     * the last position in the allocated memory.
00142     * If the insertion position is occupied,
00143     * returns <false>
00144     */
00145    bool insert(size_t x, size_t y, const T& val);
00146    void erase(iterator it);
00147    /*
00148     * index - index in the _buffer array
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    //iterator switchDirection(iterator it)const;
00174    template<class BinaryTable1D>
00175    T inner_product1D(const BinaryTable1D& bin)const;
00176 
00177    //pprecision - if non-zero contains an upper bound for the numerical precision of the returned  value
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    //size_t _nnz;
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    //_nnz=lst._nnz;
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      //the very last position in _buffer can not be occupied de to push(), only due to insert()
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 //DEBUG
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  * simple matrix class
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);}; //<! array entries will not be copied!
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  * Additionally to the functionality provided by std::copy_if it returns indexes of elements satisfying pred
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 //===== TransportationSolver class ==============================================
00594 /*
00595 * in class OPTIMIZER the member bool bop(const T& a, const T& b) has to be defined. If minimization is meant, then bop== operator <()
00596 * if maximization -> bop == operator >()
00597 * OPTIMIZER == ACC in opengm notation
00598 *
00599 * DenseMatrix represents a dense matrix type and has to
00600 *  - contain elements of the type floatType, defined in common.h
00601 *  and provide floatType operator ()(size_t index_a, size_t index_b) to access its elements
00602 *  Examples for Matrix:
00603 *  MatrixWrapper defined in simpleobjects.h
00604 *  boost::numeric::ublas::matrix<DD::floatType>;
00605 *
00606 *   see also tests/testcommon.h
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     * iterators xbegin and ybegin should point out to containers at least xsize and ysize long.
00657     * Only the first xsize and ysize will be used.
00658     * Iterator should support operation + n, i.e. begin+xsize should be defined
00659     * Non-necessary near-zero elements will NOT be considered automatically to avoid numerical problems and save computational time
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     * OutputMatrix should provide operator ()(size_t index_a, size_t index_b) to assign values to its elements
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;//helper function - determines, iterator direction and moves it to another element of a list fp with length 2
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;//relative precision of thresholding input marginal values
00701    FeasiblePoint _basicSolution;
00702    IndexArray _nonZeroXcoordinates;//_activeXbound;
00703    IndexArray _nonZeroYcoordinates;//_activeYbound;
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) )//100 - magic number
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    //north-west corner basic solution
00745    //_basicSolution.clear();
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       //_basicSolution.push(rbeg.index(), cbeg.index(),*rbeg);
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  * returns coordinate + direction of the point which is alone in its row/column.
00784  * e.g. (1,X) means that the column with X-coordinate equal to 1, contains a single element.
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           //xdual[x]=(*_pbin)(x,y)-ydual[y];
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              //ydual[y]=(*_pbin)(x,y)-xdual[x];
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;//_initCounter();
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 //helper function - determines, iterator direction and moves it to another element of a list fp with length 2
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    //going along the cycle to assign +/- to vertices correctly
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; //really minus list is in *pMinusList
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    //selecting the smallest number to add...
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         //changing
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    //checks current basic solution for optimality
01043    //1. build duals
01044    UnaryDense xduals,yduals;
01045    _BuildDuals(&xduals,&yduals);
01046    //2. check whether they satisfy dual constraints
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    //1. Create basic solution _basicSolution
01111    _InitBasicSolution(xarr,yarr);
01112 
01113    //2. Check optimality
01114    std::pair<size_t,size_t> move;
01115    bool objectiveImprovementFlag=true;
01116    size_t counter=0;//_initCounter();
01117 
01118    while ((objectiveImprovementFlag)&&(!_isOptimal(&move)))
01119    {
01120       objectiveImprovementFlag=_MovePotentials(move); //changes basic solution
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 };//TS
01165 
01166 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Generated on Mon Jun 17 16:31:06 2013 for OpenGM by  doxygen 1.6.3