diff --git a/src/Benchmarks/SpMV/ReferenceFormats/Legacy/AdEllpack.h b/src/Benchmarks/SpMV/ReferenceFormats/Legacy/AdEllpack.h index 7ef968cddad9df39d3973881edab49c241d98e3a..ba0c007ba8d9b40b6c87a2c95442e912f216b783 100644 --- a/src/Benchmarks/SpMV/ReferenceFormats/Legacy/AdEllpack.h +++ b/src/Benchmarks/SpMV/ReferenceFormats/Legacy/AdEllpack.h @@ -132,6 +132,8 @@ public: typename _Index = Index > using Self = AdEllpack< _Real, _Device, _Index >; + static constexpr bool isSymmetric() { return false; }; + AdEllpack(); void setCompressedRowLengths( ConstRowsCapacitiesTypeView rowLengths ); diff --git a/src/Benchmarks/SpMV/ReferenceFormats/Legacy/BiEllpack.h b/src/Benchmarks/SpMV/ReferenceFormats/Legacy/BiEllpack.h index cdb2c97e4efca99e43bd8bcf6ac99acdbd33d4da..b9dee173c3024636be6e83d726693b569db394f4 100644 --- a/src/Benchmarks/SpMV/ReferenceFormats/Legacy/BiEllpack.h +++ b/src/Benchmarks/SpMV/ReferenceFormats/Legacy/BiEllpack.h @@ -59,6 +59,8 @@ public: typename _Index = Index > using Self = BiEllpack< _Real, _Device, _Index >; + static constexpr bool isSymmetric() { return false; }; + BiEllpack(); void setDimensions( const IndexType rows, diff --git a/src/Benchmarks/SpMV/ReferenceFormats/Legacy/CSR.h b/src/Benchmarks/SpMV/ReferenceFormats/Legacy/CSR.h index 487ed18bf5693fc709dfb93a655a2a53378c2658..2156850600d39bf35c44805dc494b0f5455a1a3b 100644 --- a/src/Benchmarks/SpMV/ReferenceFormats/Legacy/CSR.h +++ b/src/Benchmarks/SpMV/ReferenceFormats/Legacy/CSR.h @@ -104,8 +104,8 @@ public: using Self = CSR< _Real, _Device, _Index >; constexpr CSRKernel getSpMVKernelType() { return KernelType; }; - //enum SPMVCudaKernel { scalar, vector, hybrid }; + static constexpr bool isSymmetric() { return false; }; Containers::Vector< Block<Index>, Device, Index > blocks; diff --git a/src/Benchmarks/SpMV/ReferenceFormats/Legacy/ChunkedEllpack.h b/src/Benchmarks/SpMV/ReferenceFormats/Legacy/ChunkedEllpack.h index 0c310319ed01397909bd8c5a61d34bb5103fef46..00812d4c8e01efc2bc7cc0e005157cf3d2c18ded 100644 --- a/src/Benchmarks/SpMV/ReferenceFormats/Legacy/ChunkedEllpack.h +++ b/src/Benchmarks/SpMV/ReferenceFormats/Legacy/ChunkedEllpack.h @@ -93,6 +93,8 @@ public: typename _Index = Index > using Self = ChunkedEllpack< _Real, _Device, _Index >; + static constexpr bool isSymmetric() { return false; }; + ChunkedEllpack(); static String getSerializationType(); diff --git a/src/Benchmarks/SpMV/ReferenceFormats/Legacy/Ellpack.h b/src/Benchmarks/SpMV/ReferenceFormats/Legacy/Ellpack.h index 5aee8c78952f4466ee3226a4bcd1a5bfd276f986..c4a534f499002f2c8cdb5d13538379aeda771856 100644 --- a/src/Benchmarks/SpMV/ReferenceFormats/Legacy/Ellpack.h +++ b/src/Benchmarks/SpMV/ReferenceFormats/Legacy/Ellpack.h @@ -52,6 +52,8 @@ public: typename _Index = Index > using Self = Ellpack< _Real, _Device, _Index >; + static constexpr bool isSymmetric() { return false; }; + Ellpack(); static String getSerializationType(); diff --git a/src/Benchmarks/SpMV/ReferenceFormats/Legacy/Multidiagonal.h b/src/Benchmarks/SpMV/ReferenceFormats/Legacy/Multidiagonal.h index 8153854cca0bfc9342dae32f564c986cb49c6a32..f6f02d863d9833274478565f4240eb05ac95a102 100644 --- a/src/Benchmarks/SpMV/ReferenceFormats/Legacy/Multidiagonal.h +++ b/src/Benchmarks/SpMV/ReferenceFormats/Legacy/Multidiagonal.h @@ -50,6 +50,8 @@ public: typename _Index = Index > using Self = Multidiagonal< _Real, _Device, _Index >; + static constexpr bool isSymmetric() { return false; }; + Multidiagonal(); static String getSerializationType(); diff --git a/src/Benchmarks/SpMV/ReferenceFormats/Legacy/SlicedEllpack.h b/src/Benchmarks/SpMV/ReferenceFormats/Legacy/SlicedEllpack.h index e41949129bd239cae573b3e19ee74f0fec210574..b79797103b6023d967011dc0f72bc2cde1da4929 100644 --- a/src/Benchmarks/SpMV/ReferenceFormats/Legacy/SlicedEllpack.h +++ b/src/Benchmarks/SpMV/ReferenceFormats/Legacy/SlicedEllpack.h @@ -82,6 +82,8 @@ public: int _SliceSize = SliceSize > using Self = SlicedEllpack< _Real, _Device, _Index, _SliceSize >; + static constexpr bool isSymmetric() { return false; }; + SlicedEllpack(); static String getSerializationType(); diff --git a/src/TNL/Matrices/DenseMatrix.h b/src/TNL/Matrices/DenseMatrix.h index 32c4678d045bb3a7892f2f5fdc6c39b90b22ba40..f764bd595578ed33d32c2bc41c504f3ebdfc7a0f 100644 --- a/src/TNL/Matrices/DenseMatrix.h +++ b/src/TNL/Matrices/DenseMatrix.h @@ -63,11 +63,18 @@ class DenseMatrix : public Matrix< Real, Device, Index, RealAllocator > /** * \brief Matrix elements organization getter. - * + * * \return matrix elements organization - RowMajorOrder of ColumnMajorOrder. */ static constexpr ElementsOrganization getOrganization() { return Organization; }; + /** + * \brief This is only for compatibility with sparse matrices. + * + * \return \e \e false. + */ + static constexpr bool isSymmetric() { return false; }; + /** * \brief The allocator for matrix elements. */ diff --git a/src/TNL/Matrices/MatrixReader.h b/src/TNL/Matrices/MatrixReader.h index bafacecc9227cdab42b21944f39ae072d129b21f..6c0a38847855a6ed42bd8de7dad0bf017f180157 100644 --- a/src/TNL/Matrices/MatrixReader.h +++ b/src/TNL/Matrices/MatrixReader.h @@ -24,70 +24,103 @@ class MatrixReaderDeviceDependentCode {}; /// \endcond +/** + * \brief Helper class for reading of matrices from files. + * + * It supports [MTX format](https://math.nist.gov/MatrixMarket/formats.html). + * Currently only [Coordinate Format](https://math.nist.gov/MatrixMarket/formats.html#coord) is supported. + * + * \tparam Matrix is a type of matrix into which we want to import the MTX file. + */ template< typename Matrix > class MatrixReader { public: - typedef typename Matrix::IndexType IndexType; - typedef typename Matrix::DeviceType DeviceType; - typedef typename Matrix::RealType RealType; - - static void readMtxFile( const String& fileName, - Matrix& matrix, - bool verbose = false, - bool symReader = false ); - - static void readMtxFile( std::istream& file, - Matrix& matrix, - bool verbose = false, - bool symReader = false ); - - static void readMtxFileHostMatrix( std::istream& file, - Matrix& matrix, - typename Matrix::RowsCapacitiesType& rowLengths, - bool verbose, - bool symReader ); - + /** + * \brief Type of matrix elements values. + */ + typedef typename Matrix::RealType RealType; + + /** + * \brief Device where the matrix is allocated. + */ + typedef typename Matrix::DeviceType DeviceType; + + /** + * \brief Type used for indexing of matrix elements. + */ + typedef typename Matrix::IndexType IndexType; + + /** + * \brief Method for importing matrix from file with given filename. + * + * \param fileName is the name of the source file. + * \param matrix is the target matrix. + * \param verbose controls verbosity of the matrix import. + */ + static void readMtxFile( const String& fileName, + Matrix& matrix, + bool verbose = false ); - static void verifyMtxFile( std::istream& file, - const Matrix& matrix, + /** + * \brief Method for importing matrix from STL input stream. + * + * \param file is the input stream. + * \param matrix is the target matrix. + * \param verbose controls verbosity of the matrix import. + */ + static void readMtxFile( std::istream& file, + Matrix& matrix, bool verbose = false ); - static bool findLineByElement( std::istream& file, - const IndexType& row, - const IndexType& column, - String& line, - IndexType& lineNumber ); protected: - - static bool checkMtxHeader( const String& header, - bool& symmetric ); - - static void readMtxHeader( std::istream& file, - IndexType& rows, - IndexType& columns, - bool& symmetricMatrix, - bool verbose ); - - static void computeCompressedRowLengthsFromMtxFile( std::istream& file, - Containers::Vector< int, DeviceType, int >& rowLengths, - const int columns, - const int rows, - bool symmetricMatrix, - bool verbose, - bool symReader = false ); - - static void readMatrixElementsFromMtxFile( std::istream& file, - Matrix& matrix, - bool symmetricMatrix, - bool verbose, - bool symReader ); - - static void parseMtxLineWithElement( const String& line, - IndexType& row, - IndexType& column, - RealType& value ); + static void readMtxFileHostMatrix( std::istream& file, + Matrix& matrix, + typename Matrix::RowsCapacitiesType& rowLengths, + bool verbose ); + + + static void verifyMtxFile( std::istream& file, + const Matrix& matrix, + bool verbose = false ); + + static bool findLineByElement( std::istream& file, + const IndexType& row, + const IndexType& column, + String& line, + IndexType& lineNumber ); + + + static void checkMtxHeader( const String& header, + bool& symmetric ); + + static void readMtxHeader( std::istream& file, + IndexType& rows, + IndexType& columns, + bool& symmetricMatrix, + bool verbose ); + + static void computeCompressedRowLengthsFromMtxFile( std::istream& file, + Containers::Vector< int, DeviceType, int >& rowLengths, + const int columns, + const int rows, + bool symmetricSourceMatrix, + bool symmetricTargetMatrix, + bool verbose ); + + static void readMatrixElementsFromMtxFile( std::istream& file, + Matrix& matrix, + bool symmetricMatrix, + bool verbose ); + + static void parseMtxLineWithElement( const String& line, + IndexType& row, + IndexType& column, + RealType& value ); + + template< typename Device > + friend class MatrixReaderDeviceDependentCode; }; } // namespace Matrices diff --git a/src/TNL/Matrices/MatrixReader_impl.h b/src/TNL/Matrices/MatrixReader_impl.h index fb52c5659a35e98db4fe806cbeeca7b40ec1543f..92ab4102dcf5e7cc81d387bec57c1097d7a5674e 100644 --- a/src/TNL/Matrices/MatrixReader_impl.h +++ b/src/TNL/Matrices/MatrixReader_impl.h @@ -21,25 +21,25 @@ namespace TNL { namespace Matrices { template< typename Matrix > -void MatrixReader< Matrix >::readMtxFile( const String& fileName, - Matrix& matrix, - bool verbose, - bool symReader ) +void +MatrixReader< Matrix >::readMtxFile( const String& fileName, + Matrix& matrix, + bool verbose ) { std::fstream file; file.open( fileName.getString(), std::ios::in ); if( ! file ) throw std::runtime_error( std::string( "I am not able to open the file " ) + fileName.getString() ); - readMtxFile( file, matrix, verbose, symReader ); + readMtxFile( file, matrix, verbose ); } template< typename Matrix > -void MatrixReader< Matrix >::readMtxFile( std::istream& file, - Matrix& matrix, - bool verbose, - bool symReader ) +void +MatrixReader< Matrix >::readMtxFile( std::istream& file, + Matrix& matrix, + bool verbose ) { - MatrixReaderDeviceDependentCode< typename Matrix::DeviceType >::readMtxFile( file, matrix, verbose, symReader ); + MatrixReaderDeviceDependentCode< typename Matrix::DeviceType >::readMtxFile( file, matrix, verbose ); } template< typename Matrix > @@ -48,35 +48,34 @@ MatrixReader< Matrix >:: readMtxFileHostMatrix( std::istream& file, Matrix& matrix, typename Matrix::RowsCapacitiesType& rowLengths, - bool verbose, - bool symReader ) + bool verbose ) { IndexType rows, columns; - bool symmetricMatrix( false ); + bool symmetricSourceMatrix( false ); - readMtxHeader( file, rows, columns, symmetricMatrix, verbose ); + readMtxHeader( file, rows, columns, symmetricSourceMatrix, verbose ); - if( symReader && !symmetricMatrix ) + if( Matrix::isSymmetric() && !symmetricSourceMatrix ) throw std::runtime_error( "Matrix is not symmetric, but flag for symmetric matrix is given. Aborting." ); matrix.setDimensions( rows, columns ); rowLengths.setSize( rows ); - computeCompressedRowLengthsFromMtxFile( file, rowLengths, columns, rows, symmetricMatrix, verbose ); + computeCompressedRowLengthsFromMtxFile( file, rowLengths, columns, rows, symmetricSourceMatrix, Matrix::isSymmetric(), verbose ); matrix.setRowCapacities( rowLengths ); - readMatrixElementsFromMtxFile( file, matrix, symmetricMatrix, verbose, symReader ); + readMatrixElementsFromMtxFile( file, matrix, symmetricSourceMatrix, verbose ); } template< typename Matrix > -void MatrixReader< Matrix >::verifyMtxFile( std::istream& file, - const Matrix& matrix, - bool verbose ) +void +MatrixReader< Matrix >:: +verifyMtxFile( std::istream& file, const Matrix& matrix, bool verbose ) { - bool symmetricMatrix( false ); + bool symmetricSourceMatrix( false ); IndexType rows, columns; - readMtxHeader( file, rows, columns, symmetricMatrix, false ); + readMtxHeader( file, rows, columns, symmetricSourceMatrix, false ); file.clear(); file.seekg( 0, std::ios::beg ); String line; @@ -96,7 +95,7 @@ void MatrixReader< Matrix >::verifyMtxFile( std::istream& file, RealType value; parseMtxLineWithElement( line, row, column, value ); if( value != matrix.getElement( row-1, column-1 ) || - ( symmetricMatrix && value != matrix.getElement( column-1, row-1 ) ) ) + ( symmetricSourceMatrix && value != matrix.getElement( column-1, row-1 ) ) ) { std::stringstream str; str << "*** !!! VERIFICATION ERROR !!! *** " << std::endl @@ -106,7 +105,7 @@ void MatrixReader< Matrix >::verifyMtxFile( std::istream& file, throw std::runtime_error( str.str() ); } processedElements++; - if( symmetricMatrix && row != column ) + if( symmetricSourceMatrix && row != column ) processedElements++; if( verbose ) std::cout << " Verifying the matrix elements ... " << processedElements << " / " << matrix.getNumberOfMatrixElements() << " \r" << std::flush; @@ -121,15 +120,17 @@ void MatrixReader< Matrix >::verifyMtxFile( std::istream& file, } template< typename Matrix > -bool MatrixReader< Matrix >::findLineByElement( std::istream& file, - const IndexType& row, - const IndexType& column, - String& line, - IndexType& lineNumber ) +bool +MatrixReader< Matrix >:: +findLineByElement( std::istream& file, + const IndexType& row, + const IndexType& column, + String& line, + IndexType& lineNumber ) { file.clear(); file.seekg( 0, std::ios::beg ); - bool symmetricMatrix( false ); + bool symmetricSourceMatrix( false ); bool dimensionsLine( false ); lineNumber = 0; while( std::getline( file, line ) ) @@ -145,19 +146,19 @@ bool MatrixReader< Matrix >::findLineByElement( std::istream& file, RealType value; parseMtxLineWithElement( line, currentRow, currentColumn, value ); if( ( currentRow == row + 1 && currentColumn == column + 1 ) || - ( symmetricMatrix && currentRow == column + 1 && currentColumn == row + 1 ) ) + ( symmetricSourceMatrix && currentRow == column + 1 && currentColumn == row + 1 ) ) return true; } return false; } template< typename Matrix > -bool MatrixReader< Matrix >::checkMtxHeader( const String& header, - bool& symmetric ) +void +MatrixReader< Matrix >::checkMtxHeader( const String& header, bool& symmetric ) { std::vector< String > parsedLine = header.split( ' ', String::SplitSkip::SkipEmpty ); if( (int) parsedLine.size() < 5 || parsedLine[ 0 ] != "%%MatrixMarket" ) - return false; + throw std::runtime_error( "Unknown format of the source file. We expect line like this: %%MatrixMarket matrix coordinate real general" ); if( parsedLine[ 1 ] != "matrix" ) throw std::runtime_error( std::string( "Keyword 'matrix' is expected in the header line: " ) + header.getString() ); if( parsedLine[ 2 ] != "coordinates" && @@ -172,15 +173,15 @@ bool MatrixReader< Matrix >::checkMtxHeader( const String& header, else throw std::runtime_error( std::string( "Only 'general' matrices are supported, not " ) + parsedLine[ 4 ].getString() ); } - return true; } template< typename Matrix > -void MatrixReader< Matrix >::readMtxHeader( std::istream& file, - IndexType& rows, - IndexType& columns, - bool& symmetric, - bool verbose ) +void +MatrixReader< Matrix >::readMtxHeader( std::istream& file, + IndexType& rows, + IndexType& columns, + bool& symmetric, + bool verbose ) { file.clear(); file.seekg( 0, std::ios::beg ); @@ -192,14 +193,13 @@ void MatrixReader< Matrix >::readMtxHeader( std::istream& file, std::getline( file, line ); if( ! headerParsed ) { - headerParsed = checkMtxHeader( line, symmetric ); + checkMtxHeader( line, symmetric ); + headerParsed = true; if( verbose && symmetric ) std::cout << "The matrix is SYMMETRIC ... "; continue; } if( line[ 0 ] == '%' ) continue; - if( ! headerParsed ) - throw std::runtime_error( "Unknown format of the file. We expect line like this: %%MatrixMarket matrix coordinate real general" ); parsedLine = line.split( ' ', String::SplitSkip::SkipEmpty ); if( (int) parsedLine.size() != 3 ) @@ -217,13 +217,15 @@ void MatrixReader< Matrix >::readMtxHeader( std::istream& file, } template< typename Matrix > -void MatrixReader< Matrix >::computeCompressedRowLengthsFromMtxFile( std::istream& file, - Containers::Vector< int, DeviceType, int >& rowLengths, - const int columns, - const int rows, - bool symmetricMatrix, - bool verbose, - bool symReader ) +void +MatrixReader< Matrix >:: +computeCompressedRowLengthsFromMtxFile( std::istream& file, + Containers::Vector< int, DeviceType, int >& rowLengths, + const int columns, + const int rows, + bool symmetricSourceMatrix, + bool symmetricTargetMatrix, + bool verbose ) { file.clear(); file.seekg( 0, std::ios::beg ); @@ -254,10 +256,10 @@ void MatrixReader< Matrix >::computeCompressedRowLengthsFromMtxFile( std::istrea if( verbose ) std::cout << " Counting the matrix elements ... " << numberOfElements / 1000 << " thousands \r" << std::flush; - if( !symReader || - ( symReader && row >= column ) ) + if( !symmetricTargetMatrix || + ( symmetricTargetMatrix && row >= column ) ) rowLengths[ row - 1 ]++; - else if( symReader && row < column ) + else if( symmetricTargetMatrix && row < column ) rowLengths[ column - 1 ]++; if( rowLengths[ row - 1 ] > columns ) @@ -266,7 +268,7 @@ void MatrixReader< Matrix >::computeCompressedRowLengthsFromMtxFile( std::istrea str << "There are more elements ( " << rowLengths[ row - 1 ] << " ) than the matrix columns ( " << columns << " ) at the row " << row << "."; throw std::runtime_error( str.str() ); } - if( symmetricMatrix && row != column && symReader ) + if( symmetricSourceMatrix && row != column && symmetricTargetMatrix ) { rowLengths[ column - 1 ]++; if( rowLengths[ column - 1 ] > columns ) @@ -277,7 +279,7 @@ void MatrixReader< Matrix >::computeCompressedRowLengthsFromMtxFile( std::istrea } continue; } - else if( symmetricMatrix && row != column && !symReader ) + else if( symmetricSourceMatrix && row != column && !symmetricTargetMatrix ) rowLengths[ column - 1 ]++; } file.clear(); @@ -290,11 +292,12 @@ void MatrixReader< Matrix >::computeCompressedRowLengthsFromMtxFile( std::istrea } template< typename Matrix > -void MatrixReader< Matrix >::readMatrixElementsFromMtxFile( std::istream& file, - Matrix& matrix, - bool symmetricMatrix, - bool verbose, - bool symReader ) +void +MatrixReader< Matrix >:: +readMatrixElementsFromMtxFile( std::istream& file, + Matrix& matrix, + bool symmetricSourceMatrix, + bool verbose ) { file.clear(); file.seekg( 0, std::ios::beg ); @@ -316,16 +319,15 @@ void MatrixReader< Matrix >::readMatrixElementsFromMtxFile( std::istream& file, RealType value; parseMtxLineWithElement( line, row, column, value ); - if( !symReader || - ( symReader && row >= column ) ) + if( ! Matrix::isSymmetric() || ( Matrix::isSymmetric() && row >= column ) ) matrix.setElement( row - 1, column - 1, value ); - else if( symReader && row < column ) + else if( Matrix::isSymmetric() && row < column ) matrix.setElement( column - 1, row - 1, value ); processedElements++; - if( symmetricMatrix && row != column && symReader ) + if( symmetricSourceMatrix && row != column && Matrix::isSymmetric() ) continue; - else if( symmetricMatrix && row != column && !symReader ) + else if( symmetricSourceMatrix && row != column && ! Matrix::isSymmetric() ) { matrix.setElement( column - 1, row - 1, value ); processedElements++; @@ -342,10 +344,12 @@ void MatrixReader< Matrix >::readMatrixElementsFromMtxFile( std::istream& file, } template< typename Matrix > -void MatrixReader< Matrix >::parseMtxLineWithElement( const String& line, - IndexType& row, - IndexType& column, - RealType& value ) +void +MatrixReader< Matrix >:: +parseMtxLineWithElement( const String& line, + IndexType& row, + IndexType& column, + RealType& value ) { std::vector< String > parsedLine = line.split( ' ', String::SplitSkip::SkipEmpty ); if( (int) parsedLine.size() != 3 ) @@ -369,11 +373,10 @@ class MatrixReaderDeviceDependentCode< Devices::Host > template< typename Matrix > static void readMtxFile( std::istream& file, Matrix& matrix, - bool verbose, - bool symReader ) + bool verbose ) { typename Matrix::RowsCapacitiesType rowLengths; - MatrixReader< Matrix >::readMtxFileHostMatrix( file, matrix, rowLengths, verbose, symReader ); + MatrixReader< Matrix >::readMtxFileHostMatrix( file, matrix, rowLengths, verbose ); } }; @@ -385,15 +388,14 @@ class MatrixReaderDeviceDependentCode< Devices::Cuda > template< typename Matrix > static void readMtxFile( std::istream& file, Matrix& matrix, - bool verbose, - bool symReader ) + bool verbose ) { using HostMatrixType = typename Matrix::template Self< typename Matrix::RealType, Devices::Sequential >; using RowsCapacitiesType = typename HostMatrixType::RowsCapacitiesType; HostMatrixType hostMatrix; RowsCapacitiesType rowLengths; - MatrixReader< Matrix >::readMtxFileHostMatrix( file, matrix, rowLengths, verbose, symReader ); + MatrixReader< Matrix >::readMtxFileHostMatrix( file, matrix, rowLengths, verbose ); } }; /// \endcond diff --git a/src/TNL/Matrices/MultidiagonalMatrix.h b/src/TNL/Matrices/MultidiagonalMatrix.h index 797d16a3fd3340687b0b566a41eadbbc005d8d52..e943709fefe63932a3e5b0a15cafd51d77eb2d8a 100644 --- a/src/TNL/Matrices/MultidiagonalMatrix.h +++ b/src/TNL/Matrices/MultidiagonalMatrix.h @@ -100,6 +100,13 @@ class MultidiagonalMatrix : public Matrix< Real, Device, Index, RealAllocator > */ using IndexType = Index; + /** + * \brief This is only for compatibility with sparse matrices. + * + * \return \e \e false. + */ + static constexpr bool isSymmetric() { return false; }; + /** * \brief The allocator for matrix elements values. */ diff --git a/src/TNL/Matrices/TridiagonalMatrix.h b/src/TNL/Matrices/TridiagonalMatrix.h index 426fa2e74a5929d76628b896082a9f6d674b5a4a..8462a282f380282d71a0cf36de6b096c7184c7b8 100644 --- a/src/TNL/Matrices/TridiagonalMatrix.h +++ b/src/TNL/Matrices/TridiagonalMatrix.h @@ -88,6 +88,13 @@ class TridiagonalMatrix : public Matrix< Real, Device, Index, RealAllocator > */ using IndexType = Index; + /** + * \brief This is only for compatibility with sparse matrices. + * + * \return \e \e false. + */ + static constexpr bool isSymmetric() { return false; }; + /** * \brief The allocator for matrix elements values. */