| /* |
| Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho |
| All rights reserved. |
|
|
| Redistribution and use in source and binary forms, with or without modification, |
| are permitted provided that the following conditions are met: |
|
|
| Redistributions of source code must retain the above copyright notice, this list of |
| conditions and the following disclaimer. Redistributions in binary form must reproduce |
| the above copyright notice, this list of conditions and the following disclaimer |
| in the documentation and/or other materials provided with the distribution. |
|
|
| Neither the name of the Johns Hopkins University nor the names of its contributors |
| may be used to endorse or promote products derived from this software without specific |
| prior written permission. |
|
|
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY |
| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES |
| OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT |
| SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
| INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED |
| TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
| ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
| DAMAGE. |
| */ |
| |
| #include <float.h> |
| #include <string.h> |
| |
| |
| /////////////////// |
| // SparseMatrix // |
| /////////////////// |
| /////////////////////////////////////// |
| // SparseMatrix Methods and Memebers // |
| /////////////////////////////////////// |
| |
| template< class T > |
| void SparseMatrix< T >::_init( void ) |
| { |
| _contiguous = false; |
| _maxEntriesPerRow = 0; |
| rows = 0; |
| rowSizes = NullPointer( int ); |
| m_ppElements = NullPointer( Pointer( MatrixEntry< T > ) ); |
| } |
| |
| template< class T > SparseMatrix< T >::SparseMatrix( void ){ _init(); } |
| |
| template< class T > SparseMatrix< T >::SparseMatrix( int rows ){ _init() , Resize( rows ); } |
| template< class T > SparseMatrix< T >::SparseMatrix( int rows , int maxEntriesPerRow ){ _init() , Resize( rows , maxEntriesPerRow ); } |
| |
| template< class T > |
| SparseMatrix< T >::SparseMatrix( const SparseMatrix& M ) |
| { |
| _init(); |
| if( M._contiguous ) Resize( M.rows , M._maxEntriesPerRow ); |
| else Resize( M.rows ); |
| for( int i=0 ; i<rows ; i++ ) |
| { |
| SetRowSize( i , M.rowSizes[i] ); |
| memcpy( (*this)[i] , M[i] , sizeof( MatrixEntry< T > ) * rowSizes[i] ); |
| } |
| } |
| template<class T> |
| int SparseMatrix<T>::Entries( void ) const |
| { |
| int e = 0; |
| for( int i=0 ; i<rows ; i++ ) e += int( rowSizes[i] ); |
| return e; |
| } |
| template<class T> |
| SparseMatrix<T>& SparseMatrix<T>::operator = (const SparseMatrix<T>& M) |
| { |
| if( M._contiguous ) Resize( M.rows , M._maxEntriesPerRow ); |
| else Resize( M.rows ); |
| for( int i=0 ; i<rows ; i++ ) |
| { |
| SetRowSize( i , M.rowSizes[i] ); |
| memcpy( (*this)[i] , M[i] , sizeof( MatrixEntry< T > ) * rowSizes[i] ); |
| } |
| return *this; |
| } |
| |
| template<class T> |
| SparseMatrix<T>::~SparseMatrix( void ){ Resize( 0 ); } |
| |
| template< class T > |
| bool SparseMatrix< T >::write( const char* fileName ) const |
| { |
| FILE* fp = fopen( fileName , "wb" ); |
| if( !fp ) return false; |
| bool ret = write( fp ); |
| fclose( fp ); |
| return ret; |
| } |
| template< class T > |
| bool SparseMatrix< T >::read( const char* fileName ) |
| { |
| FILE* fp = fopen( fileName , "rb" ); |
| if( !fp ) return false; |
| bool ret = read( fp ); |
| fclose( fp ); |
| return ret; |
| } |
| template< class T > |
| bool SparseMatrix< T >::write( FILE* fp ) const |
| { |
| if( fwrite( &rows , sizeof( int ) , 1 , fp )!=1 ) return false; |
| if( fwrite( rowSizes , sizeof( int ) , rows , fp )!=rows ) return false; |
| for( int i=0 ; i<rows ; i++ ) if( fwrite( (*this)[i] , sizeof( MatrixEntry< T > ) , rowSizes[i] , fp )!=rowSizes[i] ) return false; |
| return true; |
| } |
| template< class T > |
| bool SparseMatrix< T >::read( FILE* fp ) |
| { |
| int r; |
| if( fread( &r , sizeof( int ) , 1 , fp )!=1 ) return false; |
| Resize( r ); |
| if( fread( rowSizes , sizeof( int ) , rows , fp )!=rows ) return false; |
| for( int i=0 ; i<rows ; i++ ) |
| { |
| r = rowSizes[i]; |
| rowSizes[i] = 0; |
| SetRowSize( i , r ); |
| if( fread( (*this)[i] , sizeof( MatrixEntry< T > ) , rowSizes[i] , fp )!=rowSizes[i] ) return false; |
| } |
| return true; |
| } |
| |
| |
| template< class T > |
| void SparseMatrix< T >::Resize( int r ) |
| { |
| if( rows>0 ) |
| { |
| if( _contiguous ){ if( _maxEntriesPerRow ) FreePointer( m_ppElements[0] ); } |
| else for( int i=0 ; i<rows ; i++ ){ if( rowSizes[i] ) FreePointer( m_ppElements[i] ); } |
| FreePointer( m_ppElements ); |
| FreePointer( rowSizes ); |
| } |
| rows = r; |
| if( r ) |
| { |
| rowSizes = AllocPointer< int >( r ); |
| m_ppElements = AllocPointer< Pointer( MatrixEntry< T > ) >( r ); |
| memset( rowSizes , 0 , sizeof( int ) * r ); |
| } |
| _contiguous = false; |
| _maxEntriesPerRow = 0; |
| } |
| template< class T > |
| void SparseMatrix< T >::Resize( int r , int e ) |
| { |
| if( rows>0 ) |
| { |
| if( _contiguous ){ if( _maxEntriesPerRow ) FreePointer( m_ppElements[0] ); } |
| else for( int i=0 ; i<rows ; i++ ){ if( rowSizes[i] ) FreePointer( m_ppElements[i] ); } |
| FreePointer( m_ppElements ); |
| FreePointer( rowSizes ); |
| } |
| rows = r; |
| if( r ) |
| { |
| rowSizes = AllocPointer< int >( r ); |
| m_ppElements = AllocPointer< Pointer( MatrixEntry< T > ) >( r ); |
| m_ppElements[0] = AllocPointer< MatrixEntry< T > >( r * e ); |
| memset( rowSizes , 0 , sizeof( int ) * r ); |
| for( int i=1 ; i<r ; i++ ) m_ppElements[i] = m_ppElements[i-1] + e; |
| } |
| _contiguous = true; |
| _maxEntriesPerRow = e; |
| } |
| |
| template<class T> |
| void SparseMatrix< T >::SetRowSize( int row , int count ) |
| { |
| if( _contiguous ) |
| { |
| if( count>_maxEntriesPerRow ) fprintf( stderr , "[ERROR] Cannot set row size on contiguous matrix: %d<=%d\n" , count , _maxEntriesPerRow ) , exit( 0 ); |
| rowSizes[row] = count; |
| } |
| else if( row>=0 && row<rows ) |
| { |
| if( rowSizes[row] ) FreePointer( m_ppElements[row] ); |
| if( count>0 ) m_ppElements[row] = AllocPointer< MatrixEntry< T > >( count ); |
| // [WARNING] Why wasn't this line here before??? |
| rowSizes[row] = count; |
| } |
| } |
| |
| |
| template<class T> |
| void SparseMatrix<T>::SetZero() |
| { |
| Resize(this->m_N, this->m_M); |
| } |
| |
| template<class T> |
| SparseMatrix<T> SparseMatrix<T>::operator * (const T& V) const |
| { |
| SparseMatrix<T> M(*this); |
| M *= V; |
| return M; |
| } |
| |
| template<class T> |
| SparseMatrix<T>& SparseMatrix<T>::operator *= (const T& V) |
| { |
| for( int i=0 ; i<rows ; i++ ) for( int ii=0 ; ii<rowSizes[i] ; i++ ) m_ppElements[i][ii].Value *= V; |
| return *this; |
| } |
| |
| template< class T > |
| template< class T2 > |
| void SparseMatrix< T >::Multiply( ConstPointer( T2 ) in , Pointer( T2 ) out , int threads ) const |
| { |
| #pragma omp parallel for num_threads( threads ) |
| for( int i=0 ; i<rows ; i++ ) |
| { |
| T2 _out(0); |
| ConstPointer( MatrixEntry< T > ) start = m_ppElements[i]; |
| ConstPointer( MatrixEntry< T > ) end = start + rowSizes[i]; |
| ConstPointer( MatrixEntry< T > ) e; |
| for( e=start ; e!=end ; e++ ) _out += in[ e->N ] * e->Value; |
| out[i] = _out; |
| } |
| } |
| template< class T > |
| template< class T2 > |
| void SparseMatrix< T >::MultiplyAndAddAverage( ConstPointer( T2 ) in , Pointer( T2 ) out , int threads ) const |
| { |
| T2 average = 0; |
| for( int i=0 ; i<rows ; i++ ) average += in[i]; |
| average /= rows; |
| Multiply( in , out , threads ); |
| |
| for( int i=0 ; i<rows ; i++ ) out[i] += average; |
| } |
|
|
|
|
| template< class T > |
| template< class T2 > |
| int SparseMatrix<T>::SolveJacobi( const SparseMatrix<T>& M , ConstPointer( T2 ) diagonal , ConstPointer( T2 ) b , Pointer( T2 ) x , Pointer( T2 ) Mx , T2 sor , int threads ) |
| { |
| M.Multiply( x , Mx , threads ); |
| |
| for( int j=0 ; j<int(M.rows) ; j++ ) if( diagonal[j] ) x[j] += ( b[j]-Mx[j] ) * sor / diagonal[j]; |
| |
| for( int j=0 ; j<int(M.rows) ; j++ ) x[j] += ( b[j]-Mx[j] ) * sor / diagonal[j]; |
| |
| return M.rows; |
| } |
| template< class T > |
| template< class T2 > |
| int SparseMatrix<T>::SolveJacobi( const SparseMatrix<T>& M , ConstPointer( T2 ) b , Pointer( T2 ) x , Pointer( T2 ) Mx , T2 sor , int threads ) |
| { |
| M.Multiply( x , Mx , threads ); |
| |
| for( int j=0 ; j<int(M.rows) ; j++ ) |
| { |
| T diagonal = M[j][0].Value; |
| if( diagonal ) x[j] += ( b[j]-Mx[j] ) * sor / diagonal; |
| } |
| |
| for( int j=0 ; j<int(M.rows) ; j++ ) x[j] += ( b[j]-Mx[j] ) * sor / M[j][0].Value; |
| |
| return M.rows; |
| } |
| template<class T> |
| template<class T2> |
| int SparseMatrix<T>::SolveGS( const SparseMatrix<T>& M , ConstPointer( T2 ) diagonal , ConstPointer( T2 ) b , Pointer( T2 ) x , bool forward ) |
| { |
| |
| { \ |
| ConstPointer( MatrixEntry< T > ) start = M[j]; \ |
| ConstPointer( MatrixEntry< T > ) end = start + M.rowSizes[j]; \ |
| ConstPointer( MatrixEntry< T > ) e; \ |
| T2 _b = b[j]; \ |
| for( e=start ; e!=end ; e++ ) _b -= x[ e->N ] * e->Value; \ |
| x[j] += _b / diagonal[j]; \ |
| } |
|
|
| |
| if( forward ) for( int j=0 ; j<int(M.rows) ; j++ ){ if( diagonal[j] ){ ITERATE; } } |
| else for( int j=int(M.rows)-1 ; j>=0 ; j-- ){ if( diagonal[j] ){ ITERATE; } } |
| |
| if( forward ) for( int j=0 ; j<int(M.rows) ; j++ ){ ITERATE; } |
| else for( int j=int(M.rows)-1 ; j>=0 ; j-- ){ ITERATE; } |
| |
| |
| return M.rows; |
| } |
| template<class T> |
| template<class T2> |
| int SparseMatrix<T>::SolveGS( const std::vector< std::vector< int > >& mcIndices , const SparseMatrix<T>& M , ConstPointer( T2 ) diagonal , ConstPointer( T2 ) b , Pointer( T2 ) x , bool forward , int threads ) |
| { |
| int sum=0; |
| |
| |
| |
| |
| |
| |
| |
| { \ |
| SetOMPParallel \ |
| for( int k=0 ; k<int( indices.size() ) ; k++ ) if( diagonal[indices[k]] ) \ |
| { \ |
| int jj = indices[k]; \ |
| ConstPointer( MatrixEntry< T > ) start = M[jj]; \ |
| ConstPointer( MatrixEntry< T > ) end = start + M.rowSizes[jj]; \ |
| ConstPointer( MatrixEntry< T > ) e; \ |
| T2 _b = b[jj]; \ |
| for( e=start ; e!=end ; e++ ) _b -= x[ e->N ] * e->Value; \ |
| x[jj] += _b / diagonal[jj]; \ |
| } \ |
| } |
| |
| |
| { \ |
| SetOMPParallel \ |
| for( int k=0 ; k<int( indices.size() ) ; k++ ) \ |
| { \ |
| int jj = indices[k]; \ |
| ConstPointer( MatrixEntry< T > ) start = M[jj]; \ |
| ConstPointer( MatrixEntry< T > ) end = start + M.rowSizes[jj]; \ |
| ConstPointer( MatrixEntry< T > ) e; \ |
| T2 _b = b[jj]; \ |
| for( e=start ; e!=end ; e++ ) _b -= x[ e->N ] * e->Value; \ |
| x[jj] += _b / diagonal[jj]; \ |
| } \ |
| } |
| |
| if( forward ) for( int j=0 ; j<mcIndices.size() ; j++ ){ sum += int( mcIndices[j].size() ) ; ITERATE( mcIndices[j] ); } |
| else for( int j=int( mcIndices.size() )-1 ; j>=0 ; j-- ){ sum += int( mcIndices[j].size() ) ; ITERATE( mcIndices[j] ); } |
| |
| |
| return sum; |
| } |
| template<class T> |
| template<class T2> |
| int SparseMatrix<T>::SolveGS( const SparseMatrix<T>& M , ConstPointer( T2 ) b , Pointer( T2 ) x , bool forward ) |
| { |
| int start = forward ? 0 : M.rows-1 , end = forward ? M.rows : -1 , dir = forward ? 1 : -1; |
| for( int j=start ; j!=end ; j+=dir ) |
| { |
| T diagonal = M[j][0].Value; |
| |
| if( diagonal ) |
| |
| { |
| ConstPointer( MatrixEntry< T > ) start = M[j]; |
| ConstPointer( MatrixEntry< T > ) end = start + M.rowSizes[j]; |
| ConstPointer( MatrixEntry< T > ) e; |
| start++; |
| T2 _b = b[j]; |
| for( e=start ; e!=end ; e++ ) _b -= x[ e->N ] * e->Value; |
| x[j] = _b / diagonal; |
| } |
| } |
| return M.rows; |
| } |
| template<class T> |
| template<class T2> |
| int SparseMatrix<T>::SolveGS( const std::vector< std::vector< int > >& mcIndices , const SparseMatrix<T>& M , ConstPointer( T2 ) b , Pointer( T2 ) x , bool forward , int threads ) |
| { |
| int sum=0 , start = forward ? 0 : int( mcIndices.size() )-1 , end = forward ? int( mcIndices.size() ) : -1 , dir = forward ? 1 : -1; |
| for( int j=start ; j!=end ; j+=dir ) |
| { |
| const std::vector< int >& _mcIndices = mcIndices[j]; |
| sum += int( _mcIndices.size() ); |
| { |
| |
| for( int k=0 ; k<int( _mcIndices.size() ) ; k++ ) |
| { |
| int jj = _mcIndices[k]; |
| T diagonal = M[jj][0].Value; |
| |
| if( diagonal ) |
| |
| { |
| ConstPointer( MatrixEntry< T > ) start = M[jj]; |
| ConstPointer( MatrixEntry< T > ) end = start + M.rowSizes[jj]; |
| ConstPointer( MatrixEntry< T > ) e; |
| start++; |
| T2 _b = b[jj]; |
| for( e=start ; e!=end ; e++ ) _b -= x[ e->N ] * e->Value; |
| x[jj] = _b / diagonal; |
| } |
| } |
| } |
| } |
| return sum; |
| } |
|
|
| template< class T > |
| template< class T2 > |
| void SparseMatrix< T >::getDiagonal( Pointer( T2 ) diagonal , int threads ) const |
| { |
| |
| for( int i=0 ; i<rows ; i++ ) |
| { |
| T2 d = 0.; |
| ConstPointer( MatrixEntry< T > ) start = m_ppElements[i]; |
| ConstPointer( MatrixEntry< T > ) end = start + rowSizes[i]; |
| ConstPointer( MatrixEntry< T > ) e; |
| for( e=start ; e!=end ; e++ ) if( e->N==i ) d += e->Value; |
| diagonal[i] = d; |
| } |
| } |
| template< class T > |
| template< class T2 > |
| int SparseMatrix< T >::SolveCG( const SparseMatrix<T>& A , ConstPointer( T2 ) b , int iters , Pointer( T2 ) x , T2 eps , int reset , bool addDCTerm , bool solveNormal , int threads ) |
| { |
| eps *= eps; |
| int dim = A.rows; |
| Pointer( T2 ) r = AllocPointer< T2 >( dim ); |
| Pointer( T2 ) d = AllocPointer< T2 >( dim ); |
| Pointer( T2 ) q = AllocPointer< T2 >( dim ); |
| Pointer( T2 ) temp = NullPointer( T2 ); |
| if( reset ) memset( x , 0 , sizeof(T2)* dim ); |
| if( solveNormal ) temp = AllocPointer< T2 >( dim ); |
|
|
| double delta_new = 0 , delta_0; |
| if( solveNormal ) |
| { |
| if( addDCTerm ) A.MultiplyAndAddAverage( ( ConstPointer( T2 ) )x , temp , threads ) , A.MultiplyAndAddAverage( ( ConstPointer( T2 ) )temp , r , threads ) , A.MultiplyAndAddAverage( ( ConstPointer( T2 ) )b , temp , threads ); |
| else A.Multiply( ( ConstPointer( T2 ) )x , temp , threads ) , A.Multiply( ( ConstPointer( T2 ) )temp , r , threads ) , A.Multiply( ( ConstPointer( T2 ) )b , temp , threads ); |
| |
| for( int i=0 ; i<dim ; i++ ) d[i] = r[i] = temp[i] - r[i] , delta_new += r[i] * r[i]; |
| } |
| else |
| { |
| if( addDCTerm ) A.MultiplyAndAddAverage( ( ConstPointer( T2 ) )x , r , threads ); |
| else A.Multiply( ( ConstPointer( T2 ) )x , r , threads ); |
| |
| for( int i=0 ; i<dim ; i++ ) d[i] = r[i] = b[i] - r[i] , delta_new += r[i] * r[i]; |
| } |
| delta_0 = delta_new; |
| if( delta_new<eps ) |
| { |
| // fprintf( stderr , "[WARNING] Initial residual too low: %g < %f\n" , delta_new , eps ); |
| FreePointer( r ); |
| FreePointer( d ); |
| FreePointer( q ); |
| FreePointer( temp ); |
| return 0; |
| } |
| int ii; |
| for( ii=0 ; ii<iters && delta_new>eps*delta_0 ; ii++ ) |
| { |
| if( solveNormal ) |
| if( addDCTerm ) A.MultiplyAndAddAverage( ( ConstPointer( T2 ) )d , temp , threads ) , A.MultiplyAndAddAverage( ( ConstPointer( T2 ) )temp , q , threads ); |
| else A.Multiply( ( ConstPointer( T2 ) )d , temp , threads ) , A.Multiply( ( ConstPointer( T2 ) )temp , q , threads ); |
| else |
| if( addDCTerm ) A.MultiplyAndAddAverage( ( ConstPointer( T2 ) )d , q , threads ); |
| else A.Multiply( ( ConstPointer( T2 ) )d , q , threads ); |
| double dDotQ = 0; |
| |
| for( int i=0 ; i<dim ; i++ ) dDotQ += d[i] * q[i]; |
| T2 alpha = T2( delta_new / dDotQ ); |
| double delta_old = delta_new; |
| delta_new = 0; |
| if( (ii%50)==(50-1) ) |
| { |
| |
| for( int i=0 ; i<dim ; i++ ) x[i] += d[i] * alpha; |
| if( solveNormal ) |
| if( addDCTerm ) A.MultiplyAndAddAverage( ( ConstPointer( T2 ) )x , temp , threads ) , A.MultiplyAndAddAverage( ( ConstPointer( T2 ) )temp , r , threads ); |
| else A.Multiply( ( ConstPointer( T2 ) )x , temp , threads ) , A.Multiply( ( ConstPointer( T2 ) )temp , r , threads ); |
| else |
| if( addDCTerm ) A.MultiplyAndAddAverage( ( ConstPointer( T2 ) )x , r , threads ); |
| else A.Multiply( ( ConstPointer( T2 ) )x , r , threads ); |
| |
| for( int i=0 ; i<dim ; i++ ) r[i] = b[i] - r[i] , delta_new += r[i] * r[i] , x[i] += d[i] * alpha; |
| } |
| else |
| |
| for( int i=0 ; i<dim ; i++ ) r[i] -= q[i] * alpha , delta_new += r[i] * r[i] , x[i] += d[i] * alpha; |
|
|
| T2 beta = T2( delta_new / delta_old ); |
| |
| for( int i=0 ; i<dim ; i++ ) d[i] = r[i] + d[i] * beta; |
| } |
| FreePointer( r ); |
| FreePointer( d ); |
| FreePointer( q ); |
| FreePointer( temp ); |
| return ii; |
| } |
|
|