OpenWalnut  1.4.0
WMatrixSym.h
00001 //---------------------------------------------------------------------------
00002 //
00003 // Project: OpenWalnut ( http://www.openwalnut.org )
00004 //
00005 // Copyright 2013 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
00006 // For more information see http://www.openwalnut.org/copying
00007 //
00008 // This file is part of OpenWalnut.
00009 //
00010 // OpenWalnut is free software: you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as published by
00012 // the Free Software Foundation, either version 3 of the License, or
00013 // (at your option) any later version.
00014 //
00015 // OpenWalnut is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 // GNU Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public License
00021 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
00022 //
00023 //---------------------------------------------------------------------------
00024 
00025 #ifndef WMATRIXSYM_H
00026 #define WMATRIXSYM_H
00027 
00028 #include <algorithm>
00029 #include <cassert>
00030 #include <iomanip>
00031 #include <sstream>
00032 #include <string>
00033 #include <vector>
00034 
00035 #include <boost/shared_ptr.hpp>
00036 
00037 #include "../exceptions/WOutOfBounds.h"
00038 
00039 /**
00040  * Symmetric square matrix, storing only the elements of the triangular matrix without the main
00041  * diagonal. So in case of a NxN matrix there are only (N^2-N)/2 elements stored.
00042  *
00043  * \note There exists also a WWriter and WReader for storing/reading the matrix in VTK file format.
00044  */
00045 template< typename T >
00046 class WMatrixSym
00047 {
00048 friend class WMatrixSymTest;
00049 public:
00050     /**
00051      * Type of stored elements.
00052      */
00053     typedef T value_type;
00054 
00055     /**
00056      * Shorthand for shared pointers.
00057      */
00058     typedef boost::shared_ptr< WMatrixSym < T > > SPtr;
00059 
00060     /**
00061      * Generates new symmetric matrix.
00062      *
00063      * \param n number of rows and cols
00064      */
00065     explicit WMatrixSym( size_t n );
00066 
00067     /**
00068      * Default constructor leaving all empty.
00069      */
00070     WMatrixSym();
00071 
00072     /**
00073      * Element acces operator as if the elements where stored as a normal matrix.
00074      *
00075      * \warning Acessing elements of the main diagonal is forbidden!
00076      *
00077      * \param i The i'th row
00078      * \param j The j'th column
00079      *
00080      * \return reference to the (i,j) element of the table
00081      */
00082     T& operator()( size_t i, size_t j ) throw( WOutOfBounds );
00083 
00084     /**
00085      * Const version of the element access.
00086      *
00087      * \warning Acessing elements of the main diagonal is forbidden!
00088      *
00089      * \param i The i'th row
00090      * \param j The j'th column
00091      *
00092      * \return Const reference to the (i,j) element of the table
00093      */
00094     const T& operator()( size_t i, size_t j ) const throw( WOutOfBounds );
00095 
00096     /**
00097      * Returns the number of elements stored in this matrix.
00098      * \return the number of elements stored in this matrix.
00099      */
00100     size_t numElements() const;
00101 
00102     /**
00103      * Returns the number of rows and cols of the matrix.
00104      * \return The number of rows and cols of the matrix.
00105      */
00106     size_t size() const;
00107 
00108     /**
00109      * Returns the elements stored inside of this container.
00110      *
00111      * \return Read-only reference to the elements stored inside this container.
00112      */
00113     const std::vector< T >& getData() const;
00114 
00115     /**
00116      * Resets the internal data to the given vector of elements.
00117      *
00118      * \param data new data in row major arrangement
00119      */
00120     void setData( const std::vector< T > &data ) throw( WOutOfBounds );
00121 
00122     /**
00123      * Renders the matrix to a full nxn matrix, where the main diagonal is set to 0.0 and the m(i,j) == m(j,i).
00124      * Each column is separated by exactly one space and each row is separated by a newline.
00125      *
00126      * @return Multiline string containing the nxn symmetric matrix.
00127      */
00128     std::string toString( void ) const;
00129 
00130 private:
00131     /**
00132      * Internal data structure to store the elements. The order is row major.
00133      */
00134     std::vector< T > m_data;
00135 
00136     /**
00137      * Number of rows and cols.
00138      */
00139     size_t m_n;
00140 };
00141 
00142 template< typename T >
00143 inline WMatrixSym< T >::WMatrixSym( size_t n )
00144     : m_data( ( n * ( n - 1 ) ) / 2, 0.0 ),
00145       m_n( n )
00146 {
00147 }
00148 
00149 template< typename T >
00150 inline WMatrixSym< T >::WMatrixSym()
00151     : m_n( 0 )
00152 {
00153 }
00154 
00155 template< typename T >
00156 inline const T& WMatrixSym< T >::operator()( size_t i, size_t j ) const throw( WOutOfBounds )
00157 {
00158     if( i == j || i >= m_n || j >= m_n )
00159     {
00160         std::stringstream ss;
00161         ss << "Invalid Element Access ( " << i << ", " << j << " ). No diagonal elements or indices bigger than " << m_n << " are allowed.";
00162         throw WOutOfBounds( ss.str() );
00163     }
00164     if( i > j )
00165     {
00166         std::swap( i, j );
00167     }
00168     return m_data[( i * m_n + j - ( i + 1 ) * ( i + 2 ) / 2 )];
00169 }
00170 
00171 
00172 template< typename T >
00173 inline T& WMatrixSym< T >::operator()( size_t i, size_t j ) throw( WOutOfBounds )
00174 {
00175     if( i == j || i >= m_n || j >= m_n )
00176     {
00177         std::stringstream ss;
00178         ss << "Invalid Element Access ( " << i << ", " << j << " ). No diagonal elements or indices bigger than " << m_n << " are allowed.";
00179         throw WOutOfBounds( ss.str() );
00180     }
00181     if( i > j )
00182     {
00183         std::swap( i, j );
00184     }
00185     return m_data[( i * m_n + j - ( i + 1 ) * ( i + 2 ) / 2 )];
00186 }
00187 
00188 
00189 template< typename T >
00190 inline std::string WMatrixSym< T >::toString( void ) const
00191 {
00192   std::stringstream ss;
00193   ss << std::setprecision( 9 ) << std::fixed;
00194   ss << *this;
00195   return ss.str();
00196 }
00197 
00198 /**
00199  * Compares two matrix elementwise. First tested their size, if equal elementwisely further tests.
00200  *
00201  * \tparam T Element type
00202  * \param lhs Left symmetric matrix operand
00203  * \param rhs Right symmetric matrix operand
00204  *
00205  * \return True if and only if all elements are equal.
00206  */
00207 template< typename T >
00208 inline bool operator==( WMatrixSym< T > const& lhs, WMatrixSym< T > const& rhs )
00209 {
00210     std::vector< T > l = lhs.getData();
00211     std::vector< T > r = rhs.getData();
00212     return l == r;
00213 }
00214 
00215 /**
00216  * Output operator for symmetric Matrix producing full square matrix. Each row in separate line.
00217  *
00218  * \tparam T Element type
00219  * \param os Output stream
00220  * \param m Matrix to put to output stream
00221  *
00222  * \return Output stream
00223  */
00224 template< typename T >
00225 inline std::ostream& operator<<( std::ostream& os, const WMatrixSym< T >& m )
00226 {
00227     size_t n = m.size();
00228     for( size_t i = 0; i < n; ++i )
00229     {
00230         for( size_t j = 0; j < n; ++j )
00231         {
00232             if( i != j )
00233             {
00234                 os << m( i, j );
00235             }
00236             else
00237             {
00238                 os << 0.0;
00239             }
00240             if( ( j + 1 ) < n )
00241             {
00242                 os << " ";
00243             }
00244         }
00245         if( ( i + 1 ) < n )
00246         {
00247             os << std::endl;
00248         }
00249     }
00250     return os;
00251 }
00252 
00253 /**
00254  * Read elemnts of full square matrix into symmetric matrix. Only elements of the upper triangle matrix will be used.
00255  * First all elements separated by white space are read and then dimension check is performed, to ensure all
00256  * elements fit into sym Matrix then.
00257  *
00258  * \throw WOutOfBounds exception if element number missmatch occours.
00259  *
00260  * \tparam T Element type
00261  * \param is Input Stream
00262  * \param m Sym. Matrix to populate
00263  *
00264  * \return Input Stream
00265  */
00266 template< typename T >
00267 inline std::istream& operator>>( std::istream& is, WMatrixSym< T >& m )
00268 {
00269     std::vector< T > elements;
00270     T elm;
00271     while( is >> elm )
00272     {
00273         elements.push_back( elm );
00274     }
00275     if( m.size() * m.size() != elements.size() )
00276     {
00277         std::stringstream ss;
00278         ss << "Error: Input stream has: " << elements.size() << " elements, while matrix given to accommodate expected: ";
00279         ss << m.size() * m.size() << " elements.";
00280         throw WOutOfBounds( ss.str() );
00281     }
00282     typename std::vector< T >::const_iterator it = elements.begin();
00283     for( size_t i = 0; i < m.size(); ++i )
00284     {
00285         for( size_t j = 0; j < m.size(); ++j )
00286         {
00287             if( j > i )
00288             {
00289                 m( i, j ) = *it;
00290             }
00291             ++it;
00292         }
00293     }
00294     return is;
00295 }
00296 
00297 template< typename T >
00298 inline size_t WMatrixSym< T >::numElements() const
00299 {
00300     return m_data.size();
00301 }
00302 
00303 template< typename T >
00304 inline size_t WMatrixSym< T >::size() const
00305 {
00306     return m_n;
00307 }
00308 
00309 template< typename T >
00310 inline const typename std::vector< T >& WMatrixSym< T >::getData() const
00311 {
00312     return m_data;
00313 }
00314 
00315 template< typename T >
00316 inline void WMatrixSym< T >::setData( const std::vector< T > &data ) throw( WOutOfBounds )
00317 {
00318     if( m_n * ( m_n - 1 ) / 2 != data.size() )
00319     {
00320         std::stringstream ss;
00321         ss << "Data vector length: " << data.size() << " doesn't fit to number of rows and cols: " << m_n;
00322         throw WOutOfBounds( ss.str() );
00323     }
00324     m_data = std::vector< T >( data ); // copy content
00325 }
00326 
00327 typedef WMatrixSym< double > WMatrixSymDBL;
00328 typedef WMatrixSym< float > WMatrixSymFLT;
00329 
00330 #endif  // WMATRIXSYM_H