diff --git a/src/TNL/Matrices/SparseMatrix.hpp b/src/TNL/Matrices/SparseMatrix.hpp index 03273c98b2128dfff41feeda0bed1aafc9c54536..3eccc7211dc37b6d42178aff66a512a020450e3e 100644 --- a/src/TNL/Matrices/SparseMatrix.hpp +++ b/src/TNL/Matrices/SparseMatrix.hpp @@ -11,6 +11,7 @@ #pragma once #include <functional> +#include <sstream> #include <TNL/Algorithms/Reduction.h> #include <TNL/Matrices/SparseMatrix.h> @@ -107,11 +108,27 @@ SparseMatrix( const IndexType rows, { Containers::Vector< IndexType, Devices::Host, IndexType > rowCapacities( rows, 0 ); for( const auto& i : data ) + { + if( std::get< 0 >( i ) >= rows ) + { + std::stringstream s; + s << "Wrong row index " << std::get< 0 >( i ) << " in an initializer list"; + throw std::logic_error( s.str() ); + } rowCapacities[ std::get< 0 >( i ) ]++; + } SparseMatrix< Real, Devices::Host, Index, MatrixType, Segments > hostMatrix( rows, columns ); hostMatrix.setCompressedRowLengths( rowCapacities ); for( const auto& i : data ) + { + if( std::get< 1 >( i ) >= columns ) + { + std::stringstream s; + s << "Wrong column index " << std::get< 1 >( i ) << " in an initializer list"; + throw std::logic_error( s.str() ); + } hostMatrix.setElement( std::get< 0 >( i ), std::get< 1 >( i ), std::get< 2 >( i ) ); + } ( *this ) = hostMatrix; } diff --git a/src/TNL/Matrices/SparseMatrixView.h b/src/TNL/Matrices/SparseMatrixView.h index 2756c80d7d2d3806c8e93ddfae12583cbeaabd5f..54d4f17660c85f08c2f7b4c74b46a180e588ff08 100644 --- a/src/TNL/Matrices/SparseMatrixView.h +++ b/src/TNL/Matrices/SparseMatrixView.h @@ -98,8 +98,8 @@ class SparseMatrixView : public MatrixView< Real, Device, Index > const IndexType column, const RealType& value ); - void addElement( const IndexType row, - const IndexType column, + void addElement( IndexType row, + IndexType column, const RealType& value, const RealType& thisElementMultiplicator = 1.0 ); diff --git a/src/TNL/Matrices/SparseMatrixView.hpp b/src/TNL/Matrices/SparseMatrixView.hpp index 16a8bc62f355c0331809951974cee569bfdaa175..62300217f83d32ff3d8734a450e394f4a522faa7 100644 --- a/src/TNL/Matrices/SparseMatrixView.hpp +++ b/src/TNL/Matrices/SparseMatrixView.hpp @@ -153,10 +153,36 @@ getNumberOfNonzeroMatrixElements() const { const auto columns_view = this->columnIndexes.getConstView(); const IndexType paddingIndex = this->getPaddingIndex(); - auto fetch = [=] __cuda_callable__ ( const IndexType i ) -> IndexType { - return ( columns_view[ i ] != paddingIndex ); - }; - return Algorithms::Reduction< DeviceType >::reduce( this->columnIndexes.getSize(), std::plus<>{}, fetch, 0 ); + if( ! isSymmetric() ) + { + auto fetch = [=] __cuda_callable__ ( const IndexType i ) -> IndexType { + return ( columns_view[ i ] != paddingIndex ); + }; + return Algorithms::Reduction< DeviceType >::reduce( this->columnIndexes.getSize(), std::plus<>{}, fetch, 0 ); + } + else + { + const auto rows = this->getRows(); + const auto columns = this->getColumns(); + Containers::Vector< IndexType, DeviceType, IndexType > row_sums( this->getRows(), 0 ); + auto row_sums_view = row_sums.getView(); + const auto columnIndexesView = this->columnIndexes.getConstView(); + auto fetch = [=] __cuda_callable__ ( IndexType row, IndexType localIdx, IndexType globalIdx, bool& compute ) -> RealType { + const IndexType column = columnIndexesView[ globalIdx ]; + compute = ( column != paddingIndex ); + if( ! compute ) + return 0.0; + return 1 + ( column != row && column < rows && row < columns ); // the addition is for non-diagonal elements + }; + auto reduction = [] __cuda_callable__ ( RealType& sum, const RealType& value ) { + sum += value; + }; + auto keeper = [=] __cuda_callable__ ( IndexType row, const RealType& value ) mutable { + row_sums_view[ row ] = value; + }; + this->segments.segmentsReduction( 0, this->getRows(), fetch, reduction, keeper, ( RealType ) 0.0 ); + return sum( row_sums ); + } } template< typename Real, @@ -206,8 +232,8 @@ template< typename Real, template< typename, typename > class SegmentsView > void SparseMatrixView< Real, Device, Index, MatrixType, SegmentsView >:: -addElement( const IndexType row, - const IndexType column, +addElement( IndexType row, + IndexType column, const RealType& value, const RealType& thisElementMultiplicator ) { @@ -216,6 +242,13 @@ addElement( const IndexType row, TNL_ASSERT_GE( column, 0, "Sparse matrix column index cannot be negative." ); TNL_ASSERT_LT( column, this->getColumns(), "Sparse matrix column index is larger than number of matrix columns." ); + if( isSymmetric() && row < column ) + { + swap( row, column ); + TNL_ASSERT_LT( row, this->getRows(), "Column index is out of the symmetric part of the matrix after transposition." ); + TNL_ASSERT_LT( column,this->getColumns(), "Row index is out of the symmetric part of the matrix after transposition." ); + } + const IndexType rowSize = this->segments.getSegmentSize( row ); IndexType col( this->getPaddingIndex() ); IndexType i; @@ -276,14 +309,21 @@ template< typename Real, template< typename, typename > class SegmentsView > Real SparseMatrixView< Real, Device, Index, MatrixType, SegmentsView >:: -getElement( const IndexType row, - const IndexType column ) const +getElement( IndexType row, + IndexType column ) const { TNL_ASSERT_GE( row, 0, "Sparse matrix row index cannot be negative." ); TNL_ASSERT_LT( row, this->getRows(), "Sparse matrix row index is larger than number of matrix rows." ); TNL_ASSERT_GE( column, 0, "Sparse matrix column index cannot be negative." ); TNL_ASSERT_LT( column, this->getColumns(), "Sparse matrix column index is larger than number of matrix columns." ); + if( isSymmetric() && row < column ) + { + swap( row, column ); + if( row >= this->getRows() || column >= this->getColumns() ) + return 0.0; + } + const IndexType rowSize = this->segments.getSegmentSize( row ); for( IndexType i = 0; i < rowSize; i++ ) { @@ -588,25 +628,40 @@ void SparseMatrixView< Real, Device, Index, MatrixType, SegmentsView >:: print( std::ostream& str ) const { - for( IndexType row = 0; row < this->getRows(); row++ ) + if( isSymmetric() ) { - str <<"Row: " << row << " -> "; - const IndexType rowLength = this->segments.getSegmentSize( row ); - for( IndexType i = 0; i < rowLength; i++ ) + for( IndexType row = 0; row < this->getRows(); row++ ) { - const IndexType globalIdx = this->segments.getGlobalIndex( row, i ); - const IndexType column = this->columnIndexes.getElement( globalIdx ); - if( column == this->getPaddingIndex() ) - break; - RealType value; - if( isBinary() ) - value = 1.0; - else - value = this->values.getElement( globalIdx ); - str << " Col:" << column << "->" << value << "\t"; + str <<"Row: " << row << " -> "; + for( IndexType column = 0; column < this->getColumns(); column++ ) + { + auto value = this->getElement( row, column ); + if( value ) + str << " Col:" << column << "->" << value << "\t"; + } + str << std::endl; } - str << std::endl; } + else + for( IndexType row = 0; row < this->getRows(); row++ ) + { + str <<"Row: " << row << " -> "; + const auto rowLength = this->segments.getSegmentSize( row ); + for( IndexType i = 0; i < rowLength; i++ ) + { + const IndexType globalIdx = this->segments.getGlobalIndex( row, i ); + const IndexType column = this->columnIndexes.getElement( globalIdx ); + if( column == this->getPaddingIndex() ) + break; + RealType value; + if( isBinary() ) + value = ( RealType ) 1.0; + else + value = this->values.getElement( globalIdx ); + str << " Col:" << column << "->" << value << "\t"; + } + str << std::endl; + } } template< typename Real, diff --git a/src/UnitTests/Matrices/SymmetricSparseMatrixTest.h b/src/UnitTests/Matrices/SymmetricSparseMatrixTest.h index 5582b138ddf3173ecbde7ecf9cee9e73a6acf69c..02fd8c585366f4da12d1218a28adca717dd2cdf2 100644 --- a/src/UnitTests/Matrices/SymmetricSparseMatrixTest.h +++ b/src/UnitTests/Matrices/SymmetricSparseMatrixTest.h @@ -45,6 +45,13 @@ TYPED_TEST( MatrixTest, setLikeTest ) test_SetLike< MatrixType, MatrixType >(); } +TYPED_TEST( MatrixTest, getNumberOfNonzeroMatrixElements ) +{ + using MatrixType = typename TestFixture::MatrixType; + + test_GetNumberOfNonzeroMatrixElements< MatrixType >(); +} + TYPED_TEST( MatrixTest, resetTest ) { using MatrixType = typename TestFixture::MatrixType; diff --git a/src/UnitTests/Matrices/SymmetricSparseMatrixTest.hpp b/src/UnitTests/Matrices/SymmetricSparseMatrixTest.hpp index 75b121060a93c760442d7a4dc61e909c357a6630..7c82784228195ee372bd14b63ea73574c6359240 100644 --- a/src/UnitTests/Matrices/SymmetricSparseMatrixTest.hpp +++ b/src/UnitTests/Matrices/SymmetricSparseMatrixTest.hpp @@ -73,11 +73,11 @@ void test_SetCompressedRowLengths() | 24 25 26 | \ 27 28 30 / */ - const IndexType rows = 10; + const IndexType rows = 11; const IndexType cols = 11; Matrix m( rows, cols ); - typename Matrix::CompressedRowLengthsVector rowLengths { 1, 2, 3, 3, 3, 3, 3, 3, 3, 3 }; + typename Matrix::CompressedRowLengthsVector rowLengths { 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3 }; m.setCompressedRowLengths( rowLengths ); // Insert values into the rows. @@ -120,9 +120,25 @@ void test_SetCompressedRowLengths() m.setElement( 7, 3, value++ ); m.setElement( 7, 7, value++ ); + // 8th row - lower part + m.setElement( 8, 2, value++ ); + m.setElement( 8, 4, value++ ); + m.setElement( 8, 8, value++ ); + + // 8th row - lower part + m.setElement( 9, 2, value++ ); + m.setElement( 9, 4, value++ ); + m.setElement( 9, 9, value++ ); + + // 8th row - lower part + m.setElement( 10, 2, value++ ); + m.setElement( 10, 5, value++ ); + m.setElement( 10, 10, value++ ); + rowLengths = 0; m.getCompressedRowLengths( rowLengths ); - typename Matrix::CompressedRowLengthsVector correctRowLengths{ 1, 2, 3, 3, 3, 3, 3, 3, 3, 3 }; + + typename Matrix::CompressedRowLengthsVector correctRowLengths{ 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3 }; EXPECT_EQ( rowLengths, correctRowLengths ); } @@ -170,8 +186,8 @@ void test_GetNumberOfNonzeroMatrixElements() 49 */ - const IndexType rows = 10; - const IndexType cols = 10; + const IndexType rows = 11; + const IndexType cols = 11; Matrix m( rows, cols, { { 0, 0, 1 }, @@ -276,7 +292,7 @@ void test_GetRow() EXPECT_EQ( m.getElement( 1, 0 ), 2 ); EXPECT_EQ( m.getElement( 1, 1 ), 3 ); - EXPECT_EQ( m.getElement( 1, 2 ), 4 ); + EXPECT_EQ( m.getElement( 1, 2 ), 5 ); EXPECT_EQ( m.getElement( 1, 3 ), 8 ); EXPECT_EQ( m.getElement( 1, 4 ), 10 ); EXPECT_EQ( m.getElement( 1, 5 ), 13 ); @@ -421,7 +437,7 @@ void test_SetElement() Matrix m( { 1, 1, 1, 4, 1, 1, 7, 1, 1, 1 }, 10 ); RealType value = 1; - for( IndexType i = 0; i < 4; i++ ) + for( IndexType i = 0; i < 3; i++ ) m.setElement( i, i, value++ ); for( IndexType i = 0; i < 4; i++ ) @@ -574,7 +590,7 @@ void test_AddElement() { 2, 1, 4 }, { 2, 2, 5 }, { 3, 2, 6 }, { 3, 3, 7 }, { 4, 3, 8 }, { 4, 4, 9 }, - { 5, 5, 10 } } ); + { 5, 4, 10 } } ); // Check the set elements EXPECT_EQ( m.getElement( 0, 0 ), 1 ); @@ -626,9 +642,12 @@ void test_AddElement() */ for( IndexType i = 1; i < rows; i++ ) + { m.addElement( i, i - 1, 1.0, 2.0 ); + m.addElement( i, i, 0.0, 2.0 ); + } - + std::cerr << m << std::endl; EXPECT_EQ( m.getElement( 0, 0 ), 2 ); EXPECT_EQ( m.getElement( 0, 1 ), 5 ); EXPECT_EQ( m.getElement( 0, 2 ), 0 );