Main MRPT website > C++ reference
MRPT logo
CBinaryRelation.h
Go to the documentation of this file.
00001 /* +---------------------------------------------------------------------------+
00002    |          The Mobile Robot Programming Toolkit (MRPT) C++ library          |
00003    |                                                                           |
00004    |                       http://www.mrpt.org/                                |
00005    |                                                                           |
00006    |   Copyright (C) 2005-2011  University of Malaga                           |
00007    |                                                                           |
00008    |    This software was written by the Machine Perception and Intelligent    |
00009    |      Robotics Lab, University of Malaga (Spain).                          |
00010    |    Contact: Jose-Luis Blanco  <jlblanco@ctima.uma.es>                     |
00011    |                                                                           |
00012    |  This file is part of the MRPT project.                                   |
00013    |                                                                           |
00014    |     MRPT is free software: you can redistribute it and/or modify          |
00015    |     it under the terms of the GNU General Public License as published by  |
00016    |     the Free Software Foundation, either version 3 of the License, or     |
00017    |     (at your option) any later version.                                   |
00018    |                                                                           |
00019    |   MRPT is distributed in the hope that it will be useful,                 |
00020    |     but WITHOUT ANY WARRANTY; without even the implied warranty of        |
00021    |     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         |
00022    |     GNU General Public License for more details.                          |
00023    |                                                                           |
00024    |     You should have received a copy of the GNU General Public License     |
00025    |     along with MRPT.  If not, see <http://www.gnu.org/licenses/>.         |
00026    |                                                                           |
00027    +---------------------------------------------------------------------------+ */
00028 #ifndef CBINARYRELATION_H_
00029 #define CBINARYRELATION_H_
00030 
00031 #include <mrpt/math/CMatrixTemplate.h>
00032 #include <mrpt/math/matrix_adaptors.h>
00033 
00034 #include <set>
00035 #include <iterator>
00036 #include <algorithm>
00037 #include <utility>
00038 
00039 namespace mrpt  {       namespace math  {
00040         using std::vector;
00041 
00042         /**
00043           * This class models a binary relation through the elements of any given set. I.e. for each pair of elements (A,B) it assigns two values, f(A,B) and f(B,A).
00044           * This class is useful when calling the base function is costly, since it acts like a proxy. It's also useful if the relationship values do not correspond
00045           * with the return value of a function. Although it theoretically supports objects with non-trivial constructors or destructors (indicated by specifying
00046           * "true" as the thrid parameter of the template instantiation), certain operations will cause memory leaks and may even cause undefined behaviour, so it's
00047           * reccomended to use only basic types for the parameter U. The parameter T may be any complex object, however, like a smart pointer.
00048          * \ingroup mrpt_base_grp
00049           */
00050         template<typename T,typename U,bool UIsObject=false> class CBinaryRelation      {
00051         private:
00052                 //TODO: VIRTUALIZE INSERTROWSANDCOLS!!! AND REIMPLEMENT IN CMATRIXTEMPLATEOBJECTS.
00053 
00054                 typedef typename detail::MatrixWrapper<U,UIsObject>::MatrixType MatrixType;     //!<Matrix type used to store the actual relation.
00055         public:
00056                 typedef U (*SimpleFunctionByReturnValue)(T,T);  //!< Simple function type, used to initialize chunks of the matrix.
00057                 typedef U (*FunctionByReturnValue)(const T &,const T &);        //!<Function type which obtains the relation value by a return value.
00058                 typedef void (*FunctionByReferencePass)(const T &,const T &,U &);       //!<Function type which obtains the relation value by reference pass.
00059                 typedef typename std::set<T>::const_iterator const_iterator;    //!<Constant iterator through the set elements.
00060                 typedef typename std::set<T>::const_reverse_iterator const_reverse_iterator;    //!<Constant reverse iterator through the set elements.
00061                 typedef CMatrixRowAccessor<U> AccessorForFirstElement;  //!<Accessor type to every value related to any element A, i.e., f(A,x).
00062                 typedef CMatrixColumnAccessor<U> AccessorForSecondElement;      //!<Accessor type to every value related to any element B, i.e., f(x,B).
00063                 typedef CConstMatrixRowAccessor<U> ConstAccessorForFirstElement;        //!<Const accessor type to every value related to any element A, i.e., f(A,x).
00064                 typedef CConstMatrixColumnAccessor<U> ConstAccessorForSecondElement;    //!<Const accessor type to every value related to any element B, i.e., f(x,B).
00065         private:
00066                 std::set<T> elements;   //!<Actual set of elements.
00067                 MatrixType relation;    //!<Matrix storing the relation.
00068 
00069                 /**
00070                   * Template used to make the function interface independent from the function type.
00071                   *  (wrapper for the global method - needed to make this compile under GCC).
00072                   */
00073                 template<typename FunctionType> inline void applyFunction(FunctionType fun,size_t e1,size_t e2,const T &T1,const T &T2) {
00074                         detail::applyFunction<T,U,UIsObject,FunctionType>(*this,fun,e1,e2,T1,T2);
00075                 }
00076 
00077         public:
00078                 /**
00079                   * Default constructor, doesn't initialize the relation.
00080                   */
00081                 explicit inline CBinaryRelation(const std::set<T> &els):elements(els),relation(els.size(),els.size())   {}
00082                 /**
00083                   * Constructor which initializes the relation using a given function.
00084                   */
00085                 template<typename FunctionType> inline CBinaryRelation(const std::set<T> &els,FunctionType fun):elements(els),relation(els.size(),els.size())   {
00086                         initializeWith(fun);
00087                 }
00088                 /**
00089                   * Initialize the whole relation with a given function.
00090                   */
00091                 template<typename FunctionType> void initializeWith(FunctionType fun)   {
00092                         typename std::set<T>::const_iterator it=elements.begin();
00093                         for (size_t i=0;i<elements.size();++i,++it)     {
00094                                 typename std::set<T>::const_iterator jt=elements.begin();
00095                                 for (size_t j=0;j<elements.size();++j,++jt) applyFunction(fun,i,j,*it,*jt);
00096                         }
00097                 }
00098                 /**
00099                   * Initialize the whole relation with a given function, assuming that the relation is symmetrical.
00100                   */
00101                 template<typename FunctionType> void initializeSymmetricallyWith(FunctionType fun)      {
00102                         typename std::set<T>::const_iterator it=elements.begin();
00103                         for (size_t i=0;i<elements.size();++i,++it)     {
00104                                 applyFunction(fun,i,i,*it,*it);
00105                                 typename std::set<T>::const_iterator jt=it;
00106                                 jt++;
00107                                 for (size_t j=i+1;j<elements.size();++j,++jt)   {
00108                                         applyFunction(fun,i,j,*it,*jt);
00109                                         relation(j,i)=relation(i,j);
00110                                 }
00111                         }
00112                 }
00113                 /**
00114                   * Manually set a relationship value, given the indices.
00115                   */
00116                 inline void setRelationValue(size_t e1,size_t e2,const U &newVal)       {
00117                         relation.get_unsafe(e1,e2)=newVal;
00118                 }
00119                 /**
00120                   * Get a relation value, given the indices.
00121                   */
00122                 inline const U &getRelationValue(size_t e1,size_t e2) const     {
00123                         return relation.get_unsafe(e1,e2);
00124                 }
00125                 inline const U &operator()(size_t e1,size_t e2) const   {
00126                         return getRelationValue(e1,e2);
00127                 }
00128                 /**
00129                   * Get a reference to a relation value given its indices, which allows both querying and setting the value.
00130                   */
00131                 inline U &getRelationValue(size_t e1,size_t e2) {
00132                         return relation.get_unsafe(e1,e2);
00133                 }
00134                 inline U &operator()(size_t e1,size_t e2)       {
00135                         return getRelationValue(e1,e2);
00136                 }
00137                 /**
00138                   * Manually set a relationship value, given the elements. Returns false if any of the elements is not present.
00139                   */
00140                 inline bool setRelationValue(const T &t1,const T &t2,const U &newVal)   {
00141                         typename std::set<T>::const_iterator b=elements.begin(),e=elements.end();
00142                         typename std::set<T>::const_iterator it1=std::find(b,e,t1),it2=std::find(b,e,t2);
00143                         if (it1==e||it2==e) return false;
00144                         setRelationValue(static_cast<size_t>(std::distance(b,it1)),static_cast<size_t>(std::distance(b,it2)),newVal);
00145                         return true;
00146                 }
00147                 /**
00148                   * Get a relation value, given the elements. Throws domain_error if any of the elements is not present.
00149                   */
00150                 inline U getRelationValue(const T &t1,const T &t2) const        {
00151                         typename std::set<T>::const_iterator b=elements.begin(),e=elements.end();
00152                         typename std::set<T>::const_iterator it1=std::find(b,e,t1),it2=std::find(b,e,t2);
00153                         if (it1==e||it2==e) throw std::domain_error("Element not found");
00154                         return getRelationValue(static_cast<size_t>(std::distance(b,it1)),static_cast<size_t>(std::distance(b,it2)));
00155                 }
00156                 /**
00157                   * Get a reference to a relation value given the elements, which allows both querying and setting. Throws domain_error if any of the elements is not
00158                   * present.
00159                   */
00160                 inline U &getRelationValue(const T &t1,const T &t2)     {
00161                         typename std::set<T>::const_iterator b=elements.begin(),e=elements.end();
00162                         typename std::set<T>::const_iterator it1=std::find(b,e,t1),it2=std::find(b,e,t2);
00163                         if (it1==e||it2==e) throw std::domain_error("Element not found");
00164                         return getRelationValue(static_cast<size_t>(std::distance(b,it1)),static_cast<size_t>(distance(b,it2)));
00165                 }
00166                 /**
00167                   * Gets an iterator to the starting point of the elements set.
00168                   */
00169                 inline const_iterator begin() const     {
00170                         return elements.begin();
00171                 }
00172                 /**
00173                   * Gets an iterator to the ending point of the elements set.
00174                   */
00175                 inline const_iterator end() const       {
00176                         return elements.end();
00177                 }
00178                 /**
00179                   * Gets a reverse iterator to the ending point of the elements set.
00180                   */
00181                 inline const_reverse_iterator rbegin() const    {
00182                         return elements.rbegin();
00183                 }
00184                 /**
00185                   * Gets a reverse iterator to the starting point of the elements set.
00186                   */
00187                 inline const_reverse_iterator rend() const      {
00188                         return elements.rend();
00189                 }
00190                 /**
00191                   * Operator for direct access to a element given its index.
00192                   */
00193                 T operator[](size_t i) const    {
00194                         ASSERT_BELOW_(i,elements.size())
00195                         typename std::set<T>::const_iterator it=elements.begin();
00196                         std::advance(it,i);
00197                         return *it;
00198                 }
00199                 /**
00200                   * Gets an accessor for every value related to an element A given its index, i.e., every f(A,x). This accessor is iterable.
00201                   */
00202                 inline AccessorForFirstElement getRelationFrom(size_t i)        {
00203                         return AccessorForFirstElement(relation,i);
00204                 }
00205                 /**
00206                   * Gets a constant accessor for every value related to an element A given its index, i.e., every f(A,x). This accessor is iterable.
00207                   */
00208                 inline ConstAccessorForFirstElement getRelationFrom(size_t i) const     {
00209                         return ConstAccessorForFirstElement(relation,i);
00210                 }
00211                 /**
00212                   * Gets an accessor for every value related to an element B given its index, i.e., every f(x,B). This accessor is iterable.
00213                   */
00214                 inline AccessorForSecondElement getRelationTo(size_t i) {
00215                         return AccessorForSecondElement(relation,i);
00216                 }
00217                 /**
00218                   * Gets a constant accessor for every value related to an element B given its index, i.e., every f(x,B). This accessor is fully iterable.
00219                   */
00220                 inline ConstAccessorForSecondElement getRelationTo(size_t i) const      {
00221                         return ConstAccessorForSecondElement(relation,i);
00222                 }
00223                 /**
00224                   * Gets an iterable accessor for every value related to an element A, i.e., every f(A,x). A domain_error will be thrown if the element is not present.
00225                   */
00226                 inline AccessorForFirstElement getRelationFrom(const T &t)      {
00227                         typename std::set<T>::const_iterator b=elements.begin(),e=elements.end();
00228                         typename std::set<T>::const_iterator it=std::find(b,e,t);
00229                         if (it==e) throw std::domain_error("Element not found");
00230                         return getRelationFrom(static_cast<size_t>(std::distance(b,it)));
00231                 }
00232                 /**
00233                   * Gets an iterable constant accessor for every value related to an element A, i.e., every f(A,x). A domain_error will be thrown if the element is not
00234                   * present.
00235                   */
00236                 inline ConstAccessorForFirstElement getRelationFrom(const T &t) const   {
00237                         typename std::set<T>::const_iterator b=elements.begin(),e=elements.end();
00238                         typename std::set<T>::const_iterator it=std::find(b,e,t);
00239                         if (it==e) throw std::domain_error("Element not found");
00240                         return getRelationFrom(static_cast<size_t>(std::distance(b,it)));
00241                 }
00242                 inline void getRelationFrom(size_t i,vector<U> &vec)    {
00243                         size_t N=elements.size();
00244                         ASSERT_(i<N);
00245                         vec.resize(N);
00246                         ConstAccessorForFirstElement access(relation,i);
00247                         std::copy(access.begin(),access.end(),vec.begin());
00248                 }
00249                 inline void getRelationFrom(const T &t,vector<U> &vec)  {
00250                         typename std::set<T>::const_iterator b=elements.begin(),e=elements.end();
00251                         typename std::set<T>::const_iterator it=std::find(b,e,t);
00252                         if (it==e) throw std::domain_error("Element not found");
00253                         getRelationFrom(static_cast<size_t>(std::distance(b,it)),vec);
00254                 }
00255                 /**
00256                   * Gets an iterable accessor for every value related to an element B, i.e., every f(x,B). A domain_error will be thrown if the element is not present.
00257                   */
00258                 inline AccessorForSecondElement getRelationTo(const T &t)       {
00259                         typename std::set<T>::const_iterator b=elements.begin(),e=elements.end();
00260                         typename std::set<T>::const_iterator it=std::find(b,e,t);
00261                         if (it==e) throw std::domain_error("Element not found");
00262                         return getRelationTo(static_cast<size_t>(std::distance(b,it)));
00263                 }
00264                 /**
00265                   * Gets an iterable constant accessor for every value related to an alement B, i.e., every f(x,B). A domain_error will be thrown if the element is not
00266                   * present.
00267                   */
00268                 inline ConstAccessorForSecondElement getRelationTo(const T &t) const    {
00269                         typename std::set<T>::const_iterator b=elements.begin(),e=elements.end();
00270                         typename std::set<T>::const_iterator it=std::find(b,e,t);
00271                         if (it==e) throw std::domain_error("Element not found");
00272                         return getRelationTo(static_cast<size_t>(std::distance(b,it)));
00273                 }
00274                 inline void getRelationTo(size_t i,vector<U> &vec)      {
00275                         size_t N=elements.size();
00276                         ASSERT_(i<N);
00277                         vec.resize(N);
00278                         ConstAccessorForSecondElement access(relation,i);
00279                         std::copy(access.begin(),access.end(),vec.begin());
00280                 }
00281                 inline void getRelationTo(const T &t,vector<U> &vec)    {
00282                         typename std::set<T>::const_iterator b=elements.begin(),e=elements.end();
00283                         typename std::set<T>::const_iterator it=std::find(b,e,t);
00284                         if (it==e) throw std::domain_error("Element not found");
00285                         getRelationTo(static_cast<size_t>(std::distance(b,it)),vec);
00286                 }
00287                 /**
00288                   * Removes an element at a concrete position.
00289                   */
00290                 void removeElementAt(size_t i)  {
00291                         ASSERT_(i<elements.size());
00292                         typename std::set<T>::const_iterator it=elements.begin();
00293                         std::advance(it,i);
00294                         elements.erase(i);
00295                         set<size_t> ii;
00296                         ii.insert(i);
00297                         relation.removeRowsAndCols(ii,ii);
00298                 }
00299                 /**
00300                   * Removes an element. Returns false if the element was not present and thus could'nt be eliminated.
00301                   */
00302                 bool removeElement(const T &el) {
00303                         typename std::set<T>::const_iterator b=elements.begin(),e=elements.end();
00304                         typename std::set<T>::const_iterator it=std::find(e,b,el);
00305                         if (it==e) return false;
00306                         removeElementAt(std::distance(b,it));
00307                         return true;
00308                 }
00309                 /**
00310                   * Removes a set of elements. Returns the number of elements which were actually erased.
00311                   */
00312                 size_t removeElements(const set<T> &vals)       {
00313                         set<size_t> positions;
00314                         for (typename set<T>::const_iterator it=vals.begin();it!=vals.end();++it)       {
00315                                 typename set<T>::iterator elsIt=std::find(elements.begin(),elements.end(),*it);
00316                                 if (elsIt!=elements.end()) positions.insert(std::distance(elements.begin(),elsIt));
00317                         }
00318 /*                      for (set<size_t>::const_reverse_iterator it=positions.rbegin();it!=positions.rend();++it)       {
00319                                 typename std::set<T>::const_iterator it2=elements.begin();
00320                                 std::advance(it2,*it);
00321                                 elements.erase(it2);
00322                         }
00323                         relation.removeRowsAndCols(positions,positions);*/
00324                         removeElementsAt(positions);
00325                         return positions.size();
00326                 }
00327                 void removeElementsAt(const set<size_t> &poss)  {
00328                         relation.removeRowsAndCols(poss,poss);
00329                         for (set<size_t>::const_reverse_iterator it=poss.rbegin();it!=poss.rend();++it) {
00330                                 typename std::set<T>::const_iterator it2=elements.begin();
00331                                 std::advance(it2,*it);
00332                                 elements.erase(it2);
00333                         }
00334                 }
00335                 /**
00336                   * Inserts an element. If the element was present, returns false and its current position. If it wasn't, returns true and the position in which it was
00337                   * inserted.
00338                   */
00339                 std::pair<bool,size_t> insertElement(const T &el)       {
00340                         std::pair<typename std::set<T>::iterator,bool> ins=elements.insert(el);
00341                         size_t dist=std::distance(elements.begin(),ins.first);
00342                         if (ins.second) {
00343                                 std::multiset<size_t> newEls;
00344                                 newEls.insert(dist);
00345                                 relation.insertRowsAndCols(newEls,newEls);
00346                                 return std::make_pair(true,dist);
00347                         }       else return std::make_pair(false,dist);
00348                 }
00349                 /**
00350                   * Inserts an element and initializes its relationship values, even if it was already present.
00351                   */
00352                 template<typename FunctionType> std::pair<bool,size_t> insertElement(const T &el,FunctionType fun)      {
00353                         std::pair<bool,size_t> ins=insertElement(el);
00354                         size_t pos=ins.second;
00355                         for (size_t i=0;i<elements.size();++i)  {
00356                                 const T &newEl=operator[](i);
00357                                 applyFunction(fun,pos,i,el,newEl);
00358                                 applyFunction(fun,i,pos,newEl,el);
00359                         }
00360                         return ins;
00361                 }
00362                 /**
00363                   * Inserts a set of elements into the relation. Does not initialize the actual relation.
00364                   */
00365                 size_t insertElements(const std::set<T> &els)   {
00366                         if (els.empty()) return 0;
00367                         //This code is much more complex than it should! Trying, for efficiency, to avoid multiple calls to insertElement makes things a lot harder.
00368                         //It raises the complexity level to N², but alleviates it greatly by making a single memory allocation. Multiple calls to insertElement will be
00369                         //faster only if the number of elements in the set is really large.
00370                         std::vector<size_t> added;
00371                         //std::vector<size_t> exist;
00372                         added.reserve(els.size());
00373                         for (typename std::set<T>::const_iterator it=els.begin();it!=els.end();++it)    {
00374                                 std::pair<typename std::set<T>::iterator,bool> ins=elements.insert(*it);
00375                                 size_t dist=std::distance(elements.begin(),ins.first);
00376                                 if (ins.second) {
00377                                         added.push_back(dist);
00378                                         for (std::vector<size_t>::iterator it2=added.begin();it2!=added.end();++it2) if (*it2>=dist) ++(*it2);
00379                                         //for (std::vector<size_t>::iterator it2=exist.begin();it2!=exist.end();++it2) if (*it2>=dist) ++(*it2);
00380                                 }//     else exist.push_back(dist);
00381                         }
00382                         std::sort(added.begin(),added.end());
00383                         for (size_t j=1;j<added.size();++j) added[j]-=j;
00384                         std::multiset<size_t> poss(added.begin(),added.end());
00385                         relation.insertRowsAndCols(poss,poss);
00386                         return added.size();
00387                 }
00388                 /**
00389                   * Inserts a set of elements into the relation, initializing the actual relation with a given function.
00390                   */
00391                 template<typename FunctionType> size_t insertElements(const std::set<T> &els,FunctionType fun)  {
00392                         if (els.empty()) return 0;
00393                         size_t howMany=insertElements(els);
00394                         std::set<size_t> poss;
00395                         {
00396                                 //Little scope for "begin" and "end"...
00397                                 typename std::set<T>::const_iterator begin=elements.begin(),end=elements.end();
00398                                 for (typename std::set<T>::const_iterator it=els.begin();it!=els.end();++it) poss.insert(std::distance(begin,find(begin,end,*it)));
00399                         }
00400                         std::set<size_t> nPoss;
00401                         std::set<size_t>::const_iterator begin=poss.begin(),end=poss.end();
00402                         for (size_t i=0;i<elements.size();++i) if (std::find(begin,end,i)==end) nPoss.insert(i);
00403                         vector<const T *> proxy;
00404                         proxy.reserve(poss.size());
00405                         for (std::set<size_t>::const_iterator it=begin;it!=end;++it)    {
00406                                 const T &e1=operator[](*it);
00407                                 proxy.push_back(&e1);
00408                                 size_t i=0;
00409                                 for (typename std::set<T>::const_iterator it2=elements.begin();it2!=elements.end();++it2,++i) applyFunction(fun,*it,i,e1,*it2);
00410                         }
00411                         for (std::set<size_t>::const_iterator it=nPoss.begin();it!=nPoss.end();++it)    {
00412                                 const T &e1=operator[](*it);
00413                                 typename std::vector<const T *>::const_iterator itV=proxy.begin();
00414                                 for (std::set<size_t>::const_iterator it2=poss.begin();it2!=poss.end();++it2,++itV) applyFunction(fun,*it,*it2,e1,**itV);
00415                         }
00416                         return howMany;
00417                 }
00418                 /**
00419                   * Completely resets the relation, using a new set of elements. Does not initialize the relation.
00420                   */
00421                 void setElements(const std::set<T> &newEls)     {
00422                         relation.setSize(0,0);
00423                         elements=newEls;
00424                         relation.setSize(newEls.size(),newEls.size());
00425                 }
00426                 /**
00427                   * Returns the amount of elements present in the relation.
00428                   */
00429                 inline size_t size() const      {
00430                         return elements.size();
00431                 }
00432         };
00433 
00434         namespace detail {
00435                 // generic version (specialization is after definition of CBinaryRelation):
00436                 template<typename T,typename U,bool UIsObject,typename FunctionType> inline void applyFunction(CBinaryRelation<T,U,UIsObject> &o, FunctionType fun,size_t e1,size_t e2,const T &T1,const T &T2) {
00437                         o.getRelationValue(e1,e2)=fun(T1,T2);
00438                 }
00439 
00440                 /** Template specialization by reference type.
00441                   */
00442                 template<typename T,typename U,bool UIsObject> inline void applyFunction(CBinaryRelation<T,U,UIsObject> &o,typename CBinaryRelation<T,U,UIsObject>::FunctionByReferencePass fun,size_t e1,size_t e2,const T &T1,const T &T2)    {
00443                         fun(T1,T2,o.getRelationValue(e1,e2));
00444                 }
00445         }
00446 
00447 
00448 }}      //End of namespaces
00449 #endif



Page generated by Doxygen 1.7.5 for MRPT 0.9.5 SVN: at Thu Oct 13 21:25:36 UTC 2011