2008-06-23 13:25:22 +00:00
// This file is part of Eigen, a lightweight C++ template library
2009-05-22 20:25:33 +02:00
// for linear algebra.
2008-06-23 13:25:22 +00:00
//
2014-06-23 10:40:03 +02:00
// Copyright (C) 2008-2014 Gael Guennebaud <gael.guennebaud@inria.fr>
2008-06-23 13:25:22 +00:00
//
2012-07-13 14:42:47 -04:00
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
2008-06-23 13:25:22 +00:00
# ifndef EIGEN_SPARSEMATRIX_H
# define EIGEN_SPARSEMATRIX_H
2021-09-10 19:12:26 +00:00
# include "./InternalHeaderCheck.h"
2012-04-15 11:06:28 +01:00
namespace Eigen {
2011-11-28 16:36:37 +01:00
/** \ingroup SparseCore_Module
2008-06-23 13:25:22 +00:00
*
2009-05-19 09:40:00 +02:00
* \ class SparseMatrix
*
2011-11-28 16:36:37 +01:00
* \ brief A versatible sparse matrix representation
2009-05-19 09:40:00 +02:00
*
2011-11-28 16:36:37 +01:00
* This class implements a more versatile variants of the common \ em compressed row / column storage format .
* Each colmun ' s ( resp . row ) non zeros are stored as a pair of value with associated row ( resp . colmiun ) index .
* All the non zeros are stored in a single large buffer . Unlike the \ em compressed format , there might be extra
2018-03-11 10:01:44 -04:00
* space in between the nonzeros of two successive colmuns ( resp . rows ) such that insertion of new non - zero
2011-11-28 16:36:37 +01:00
* can be done with limited memory reallocation and copies .
*
* A call to the function makeCompressed ( ) turns the matrix into the standard \ em compressed format
* compatible with many library .
*
* More details on this storage sceheme are given in the \ ref TutorialSparse " manual pages " .
2008-06-23 13:25:22 +00:00
*
2021-08-04 22:41:52 +00:00
* \ tparam Scalar_ the scalar type , i . e . the type of the coefficients
* \ tparam Options_ Union of bit flags controlling the storage scheme . Currently the only possibility
2013-06-28 15:56:43 +02:00
* is ColMajor or RowMajor . The default is 0 which means column - major .
2021-08-04 22:41:52 +00:00
* \ tparam StorageIndex_ the type of the indices . It has to be a \ b signed type ( e . g . , short , int , std : : ptrdiff_t ) . Default is \ c int .
2017-01-03 11:19:14 +01:00
*
* \ warning In % Eigen 3.2 , the undocumented type \ c SparseMatrix : : Index was improperly defined as the storage index type ( e . g . , int ) ,
* whereas it is now ( starting from % Eigen 3.3 ) deprecated and always defined as Eigen : : Index .
* Codes making use of \ c SparseMatrix : : Index , might thus likely have to be changed to use \ c SparseMatrix : : StorageIndex instead .
2008-06-23 13:25:22 +00:00
*
2011-02-13 22:50:57 +00:00
* This class can be extended with the help of the plugin mechanism described on the page
2016-08-30 11:10:08 +02:00
* \ ref TopicCustomizing_Plugins by defining the preprocessor symbol \ c EIGEN_SPARSEMATRIX_PLUGIN .
2008-06-23 13:25:22 +00:00
*/
2010-10-25 10:15:22 -04:00
namespace internal {
2021-08-04 22:41:52 +00:00
template < typename Scalar_ , int Options_ , typename StorageIndex_ >
struct traits < SparseMatrix < Scalar_ , Options_ , StorageIndex_ > >
2008-06-23 13:25:22 +00:00
{
2021-08-04 22:41:52 +00:00
typedef Scalar_ Scalar ;
typedef StorageIndex_ StorageIndex ;
2010-04-16 10:13:32 -04:00
typedef Sparse StorageKind ;
typedef MatrixXpr XprKind ;
2008-06-23 13:25:22 +00:00
enum {
RowsAtCompileTime = Dynamic ,
ColsAtCompileTime = Dynamic ,
MaxRowsAtCompileTime = Dynamic ,
MaxColsAtCompileTime = Dynamic ,
2021-08-04 22:41:52 +00:00
Flags = Options_ | NestByRefBit | LvalueBit | CompressedAccessBit ,
2009-01-19 15:20:45 +00:00
SupportedAccessPatterns = InnerRandomAccessPattern
2008-06-23 13:25:22 +00:00
} ;
} ;
2011-01-07 05:16:01 -05:00
2021-08-04 22:41:52 +00:00
template < typename Scalar_ , int Options_ , typename StorageIndex_ , int DiagIndex >
struct traits < Diagonal < SparseMatrix < Scalar_ , Options_ , StorageIndex_ > , DiagIndex > >
2011-12-04 21:49:21 +01:00
{
2021-08-04 22:41:52 +00:00
typedef SparseMatrix < Scalar_ , Options_ , StorageIndex_ > MatrixType ;
2015-06-19 17:56:39 +02:00
typedef typename ref_selector < MatrixType > : : type MatrixTypeNested ;
2022-03-16 16:43:40 +00:00
typedef std : : remove_reference_t < MatrixTypeNested > MatrixTypeNested_ ;
2011-12-04 21:49:21 +01:00
2021-08-04 22:41:52 +00:00
typedef Scalar_ Scalar ;
2011-12-04 21:49:21 +01:00
typedef Dense StorageKind ;
2021-08-04 22:41:52 +00:00
typedef StorageIndex_ StorageIndex ;
2011-12-04 21:49:21 +01:00
typedef MatrixXpr XprKind ;
enum {
RowsAtCompileTime = Dynamic ,
ColsAtCompileTime = 1 ,
MaxRowsAtCompileTime = Dynamic ,
MaxColsAtCompileTime = 1 ,
2014-12-01 14:41:39 +01:00
Flags = LvalueBit
} ;
} ;
2021-08-04 22:41:52 +00:00
template < typename Scalar_ , int Options_ , typename StorageIndex_ , int DiagIndex >
struct traits < Diagonal < const SparseMatrix < Scalar_ , Options_ , StorageIndex_ > , DiagIndex > >
: public traits < Diagonal < SparseMatrix < Scalar_ , Options_ , StorageIndex_ > , DiagIndex > >
2014-12-01 14:41:39 +01:00
{
enum {
2014-07-22 12:54:03 +02:00
Flags = 0
2011-12-04 21:49:21 +01:00
} ;
} ;
2023-01-11 06:24:49 +00:00
template < typename StorageIndex >
struct sparse_reserve_op {
EIGEN_DEVICE_FUNC sparse_reserve_op ( Index begin , Index end , Index size ) {
Index range = numext : : mini ( end - begin , size ) ;
m_begin = begin ;
m_end = begin + range ;
m_val = StorageIndex ( size / range ) ;
m_remainder = StorageIndex ( size % range ) ;
}
template < typename IndexType >
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE StorageIndex operator ( ) ( IndexType i ) const {
if ( ( i > = m_begin ) & & ( i < m_end ) )
return m_val + ( ( i - m_begin ) < m_remainder ? 1 : 0 ) ;
else
return 0 ;
}
StorageIndex m_val , m_remainder ;
Index m_begin , m_end ;
} ;
template < typename Scalar >
struct functor_traits < sparse_reserve_op < Scalar > > {
enum { Cost = 1 , PacketAccess = false , IsRepeatable = true } ;
} ;
2010-10-25 10:15:22 -04:00
} // end namespace internal
2008-06-23 13:25:22 +00:00
2021-08-04 22:41:52 +00:00
template < typename Scalar_ , int Options_ , typename StorageIndex_ >
2008-08-26 19:12:23 +00:00
class SparseMatrix
2021-08-04 22:41:52 +00:00
: public SparseCompressedBase < SparseMatrix < Scalar_ , Options_ , StorageIndex_ > >
2008-06-23 13:25:22 +00:00
{
2015-02-07 22:00:46 +01:00
typedef SparseCompressedBase < SparseMatrix > Base ;
2015-10-08 22:06:49 +02:00
using Base : : convert_index ;
2021-08-04 22:41:52 +00:00
friend class SparseVector < Scalar_ , 0 , StorageIndex_ > ;
2019-01-29 10:10:07 +01:00
template < typename , typename , typename , typename , typename >
friend struct internal : : Assignment ;
2015-10-08 22:06:49 +02:00
public :
2015-02-07 22:00:46 +01:00
using Base : : isCompressed ;
2015-04-01 22:27:34 +02:00
using Base : : nonZeros ;
2015-10-08 22:06:49 +02:00
EIGEN_SPARSE_PUBLIC_INTERFACE ( SparseMatrix )
2015-06-24 17:49:20 +02:00
using Base : : operator + = ;
using Base : : operator - = ;
2009-03-26 17:11:43 +00:00
2021-11-19 15:58:04 +00:00
typedef Eigen : : Map < SparseMatrix < Scalar , Flags , StorageIndex > > Map ;
2014-12-01 14:41:39 +01:00
typedef Diagonal < SparseMatrix > DiagonalReturnType ;
typedef Diagonal < const SparseMatrix > ConstDiagonalReturnType ;
2015-02-07 22:00:46 +01:00
typedef typename Base : : InnerIterator InnerIterator ;
typedef typename Base : : ReverseInnerIterator ReverseInnerIterator ;
2014-12-01 14:41:39 +01:00
2014-09-23 14:28:23 +02:00
2009-05-19 09:40:00 +02:00
using Base : : IsRowMajor ;
2014-12-04 22:48:53 +01:00
typedef internal : : CompressedStorage < Scalar , StorageIndex > Storage ;
2010-10-27 14:31:23 +02:00
enum {
2021-08-04 22:41:52 +00:00
Options = Options_
2010-10-27 14:31:23 +02:00
} ;
2008-06-23 13:25:22 +00:00
2014-12-04 22:48:53 +01:00
typedef typename Base : : IndexVector IndexVector ;
typedef typename Base : : ScalarVector ScalarVector ;
2008-06-23 13:25:22 +00:00
protected :
2021-11-12 01:14:41 +02:00
typedef SparseMatrix < Scalar , ( Flags & ~ RowMajorBit ) | ( IsRowMajor ? RowMajorBit : 0 ) , StorageIndex > TransposedSparseMatrix ;
2008-06-23 13:25:22 +00:00
2015-02-13 18:57:41 +01:00
Index m_outerSize ;
Index m_innerSize ;
2014-12-04 22:48:53 +01:00
StorageIndex * m_outerIndex ;
StorageIndex * m_innerNonZeros ; // optional, if null then the data is compressed
2011-12-02 10:00:24 +01:00
Storage m_data ;
2008-06-29 21:29:12 +00:00
2008-06-26 23:22:26 +00:00
public :
2011-09-08 13:42:54 +02:00
2011-12-02 10:00:24 +01:00
/** \returns the number of rows of the matrix */
2015-02-13 18:57:41 +01:00
inline Index rows ( ) const { return IsRowMajor ? m_outerSize : m_innerSize ; }
2011-12-02 10:00:24 +01:00
/** \returns the number of columns of the matrix */
2015-02-13 18:57:41 +01:00
inline Index cols ( ) const { return IsRowMajor ? m_innerSize : m_outerSize ; }
2009-03-26 17:11:43 +00:00
2011-12-02 10:00:24 +01:00
/** \returns the number of rows (resp. columns) of the matrix if the storage order column major (resp. row major) */
2015-02-13 18:57:41 +01:00
inline Index innerSize ( ) const { return m_innerSize ; }
2011-12-02 10:00:24 +01:00
/** \returns the number of columns (resp. rows) of the matrix if the storage order column major (resp. row major) */
2015-02-13 18:57:41 +01:00
inline Index outerSize ( ) const { return m_outerSize ; }
2011-09-08 13:42:54 +02:00
2011-12-04 12:19:26 +01:00
/** \returns a const pointer to the array of values.
* This function is aimed at interoperability with other libraries .
* \ sa innerIndexPtr ( ) , outerIndexPtr ( ) */
2016-02-27 14:55:40 +01:00
inline const Scalar * valuePtr ( ) const { return m_data . valuePtr ( ) ; }
2011-12-04 12:19:26 +01:00
/** \returns a non-const pointer to the array of values.
* This function is aimed at interoperability with other libraries .
* \ sa innerIndexPtr ( ) , outerIndexPtr ( ) */
2016-02-27 14:55:40 +01:00
inline Scalar * valuePtr ( ) { return m_data . valuePtr ( ) ; }
2011-12-04 12:19:26 +01:00
/** \returns a const pointer to the array of inner indices.
* This function is aimed at interoperability with other libraries .
* \ sa valuePtr ( ) , outerIndexPtr ( ) */
2016-02-27 14:55:40 +01:00
inline const StorageIndex * innerIndexPtr ( ) const { return m_data . indexPtr ( ) ; }
2011-12-04 12:19:26 +01:00
/** \returns a non-const pointer to the array of inner indices.
* This function is aimed at interoperability with other libraries .
* \ sa valuePtr ( ) , outerIndexPtr ( ) */
2016-02-27 14:55:40 +01:00
inline StorageIndex * innerIndexPtr ( ) { return m_data . indexPtr ( ) ; }
2011-12-04 12:19:26 +01:00
/** \returns a const pointer to the array of the starting positions of the inner vectors.
* This function is aimed at interoperability with other libraries .
* \ sa valuePtr ( ) , innerIndexPtr ( ) */
2014-12-04 22:48:53 +01:00
inline const StorageIndex * outerIndexPtr ( ) const { return m_outerIndex ; }
2011-12-04 12:19:26 +01:00
/** \returns a non-const pointer to the array of the starting positions of the inner vectors.
* This function is aimed at interoperability with other libraries .
* \ sa valuePtr ( ) , innerIndexPtr ( ) */
2014-12-04 22:48:53 +01:00
inline StorageIndex * outerIndexPtr ( ) { return m_outerIndex ; }
2011-12-04 12:19:26 +01:00
/** \returns a const pointer to the array of the number of non zeros of the inner vectors.
* This function is aimed at interoperability with other libraries .
* \ warning it returns the null pointer 0 in compressed mode */
2014-12-04 22:48:53 +01:00
inline const StorageIndex * innerNonZeroPtr ( ) const { return m_innerNonZeros ; }
2011-12-04 12:19:26 +01:00
/** \returns a non-const pointer to the array of the number of non zeros of the inner vectors.
* This function is aimed at interoperability with other libraries .
* \ warning it returns the null pointer 0 in compressed mode */
2014-12-04 22:48:53 +01:00
inline StorageIndex * innerNonZeroPtr ( ) { return m_innerNonZeros ; }
2011-11-30 19:24:43 +01:00
2011-12-02 19:00:16 +01:00
/** \internal */
2010-06-14 16:26:33 +02:00
inline Storage & data ( ) { return m_data ; }
2011-12-02 19:00:16 +01:00
/** \internal */
2010-06-14 16:26:33 +02:00
inline const Storage & data ( ) const { return m_data ; }
2011-11-28 16:36:37 +01:00
/** \returns the value of the matrix at position \a i, \a j
* This function returns Scalar ( 0 ) if the element is an explicit \ em zero */
2014-12-05 12:49:30 +01:00
inline Scalar coeff ( Index row , Index col ) const
2008-06-23 13:25:22 +00:00
{
2013-06-28 16:16:02 +02:00
eigen_assert ( row > = 0 & & row < rows ( ) & & col > = 0 & & col < cols ( ) ) ;
2010-05-30 16:00:58 -04:00
const Index outer = IsRowMajor ? row : col ;
const Index inner = IsRowMajor ? col : row ;
2011-09-08 13:42:54 +02:00
Index end = m_innerNonZeros ? m_outerIndex [ outer ] + m_innerNonZeros [ outer ] : m_outerIndex [ outer + 1 ] ;
2023-01-07 22:09:42 +00:00
return m_data . atInRange ( m_outerIndex [ outer ] , end , inner ) ;
2008-06-23 13:25:22 +00:00
}
2011-11-28 16:36:37 +01:00
/** \returns a non-const reference to the value of the matrix at position \a i, \a j
2011-12-02 19:00:16 +01:00
*
* If the element does not exist then it is inserted via the insert ( Index , Index ) function
* which itself turns the matrix into a non compressed form if that was not the case .
*
* This is a O ( log ( nnz_j ) ) operation ( binary search ) plus the cost of insert ( Index , Index )
* function if the element does not already exist .
*/
2010-05-30 16:00:58 -04:00
inline Scalar & coeffRef ( Index row , Index col )
2008-06-23 13:25:22 +00:00
{
2013-06-28 16:16:02 +02:00
eigen_assert ( row > = 0 & & row < rows ( ) & & col > = 0 & & col < cols ( ) ) ;
2010-05-30 16:00:58 -04:00
const Index outer = IsRowMajor ? row : col ;
const Index inner = IsRowMajor ? col : row ;
Index start = m_outerIndex [ outer ] ;
2023-01-07 22:09:42 +00:00
Index end = m_innerNonZeros ? m_outerIndex [ outer ] + m_innerNonZeros [ outer ] : m_outerIndex [ outer + 1 ] ;
eigen_assert ( end > = start & & " you probably called coeffRef on a non finalized matrix " ) ;
if ( end < = start ) return insertAtByOuterInner ( outer , inner , start ) ;
Index dst = m_data . searchLowerIndex ( start , end , inner ) ;
if ( ( dst < end ) & & ( m_data . index ( dst ) = = inner ) )
return m_data . value ( dst ) ;
2011-12-02 19:00:16 +01:00
else
2023-01-07 22:09:42 +00:00
return insertAtByOuterInner ( outer , inner , dst ) ;
2011-12-02 19:00:16 +01:00
}
/** \returns a reference to a novel non zero coefficient with coordinates \a row x \a col.
* The non zero coefficient must \ b not already exist .
*
* If the matrix \ c * this is in compressed mode , then \ c * this is turned into uncompressed
2015-03-04 09:39:26 +01:00
* mode while reserving room for 2 x this - > innerSize ( ) non zeros if reserve ( Index ) has not been called earlier .
* In this case , the insertion procedure is optimized for a \ e sequential insertion mode where elements are assumed to be
* inserted by increasing outer - indices .
*
* If that ' s not the case , then it is strongly recommended to either use a triplet - list to assemble the matrix , or to first
* call reserve ( const SizesType & ) to reserve the appropriate number of non - zero elements per inner vector .
2011-12-02 19:00:16 +01:00
*
2015-03-04 09:39:26 +01:00
* Assuming memory has been appropriately reserved , this function performs a sorted insertion in O ( 1 )
* if the elements of each inner vector are inserted in increasing inner index order , and in O ( nnz_j ) for a random insertion .
2011-12-02 19:00:16 +01:00
*
*/
2023-01-07 22:09:42 +00:00
inline Scalar & insert ( Index row , Index col ) ;
2008-06-23 13:25:22 +00:00
public :
2015-02-16 15:56:11 +01:00
/** Removes all non zeros but keep allocated memory
*
* This function does not free the currently allocated memory . To release as much as memory as possible ,
* call \ code mat . data ( ) . squeeze ( ) ; \ endcode after resizing it .
*
* \ sa resize ( Index , Index ) , data ( )
*/
2008-12-17 18:37:04 +00:00
inline void setZero ( )
{
m_data . clear ( ) ;
2021-05-11 09:52:00 -07:00
std : : fill_n ( m_outerIndex , m_outerSize + 1 , StorageIndex ( 0 ) ) ;
if ( m_innerNonZeros ) {
std : : fill_n ( m_innerNonZeros , m_outerSize , StorageIndex ( 0 ) ) ;
}
2008-12-17 18:37:04 +00:00
}
2011-09-08 13:42:54 +02:00
/** Preallocates \a reserveSize non zeros.
*
* Precondition : the matrix must be in compressed mode . */
2010-05-30 16:00:58 -04:00
inline void reserve ( Index reserveSize )
2009-05-04 14:25:12 +00:00
{
2011-12-10 23:08:10 +01:00
eigen_assert ( isCompressed ( ) & & " This function does not make sense in non compressed mode. " ) ;
2009-05-04 14:25:12 +00:00
m_data . reserve ( reserveSize ) ;
}
2011-09-08 13:42:54 +02:00
2011-09-20 02:04:03 +02:00
# ifdef EIGEN_PARSED_BY_DOXYGEN
2011-11-28 16:36:37 +01:00
/** Preallocates \a reserveSize[\c j] non zeros for each column (resp. row) \c j.
2011-09-08 13:42:54 +02:00
*
2015-04-24 09:44:24 +02:00
* This function turns the matrix in non - compressed mode .
*
* The type \ c SizesType must expose the following interface :
\ code
typedef value_type ;
const value_type & operator [ ] ( i ) const ;
\ endcode
* for \ c i in the [ 0 , this - > outerSize ( ) [ range .
* Typical choices include std : : vector < int > , Eigen : : VectorXi , Eigen : : VectorXi : : Constant , etc .
*/
2011-09-08 13:42:54 +02:00
template < class SizesType >
2011-09-20 02:04:03 +02:00
inline void reserve ( const SizesType & reserveSizes ) ;
# else
template < class SizesType >
2015-04-24 09:44:24 +02:00
inline void reserve ( const SizesType & reserveSizes , const typename SizesType : : value_type & enableif =
2021-12-01 00:48:34 +00:00
typename SizesType : : value_type ( ) )
2011-09-20 02:04:03 +02:00
{
EIGEN_UNUSED_VARIABLE ( enableif ) ;
reserveInnerVectors ( reserveSizes ) ;
}
# endif // EIGEN_PARSED_BY_DOXYGEN
protected :
template < class SizesType >
inline void reserveInnerVectors ( const SizesType & reserveSizes )
{
2011-12-10 23:08:10 +01:00
if ( isCompressed ( ) )
2011-09-08 13:42:54 +02:00
{
2015-02-13 18:57:41 +01:00
Index totalReserveSize = 0 ;
2023-01-07 22:09:42 +00:00
for ( Index j = 0 ; j < m_outerSize ; + + j ) totalReserveSize + = reserveSizes [ j ] ;
// if reserveSizes is empty, don't do anything!
if ( totalReserveSize = = 0 ) return ;
2011-09-08 13:42:54 +02:00
// turn the matrix into non-compressed mode
2022-08-23 21:44:22 +00:00
m_innerNonZeros = internal : : conditional_aligned_new_auto < StorageIndex , true > ( m_outerSize ) ;
2011-09-08 13:42:54 +02:00
// temporarily use m_innerSizes to hold the new starting points.
2014-12-04 22:48:53 +01:00
StorageIndex * newOuterIndex = m_innerNonZeros ;
2011-09-08 13:42:54 +02:00
2014-12-04 22:48:53 +01:00
StorageIndex count = 0 ;
2011-09-08 13:42:54 +02:00
for ( Index j = 0 ; j < m_outerSize ; + + j )
{
newOuterIndex [ j ] = count ;
count + = reserveSizes [ j ] + ( m_outerIndex [ j + 1 ] - m_outerIndex [ j ] ) ;
}
2023-01-07 22:09:42 +00:00
2011-09-08 13:42:54 +02:00
m_data . reserve ( totalReserveSize ) ;
2014-12-04 22:48:53 +01:00
StorageIndex previousOuterIndex = m_outerIndex [ m_outerSize ] ;
2013-03-20 21:58:24 +01:00
for ( Index j = m_outerSize - 1 ; j > = 0 ; - - j )
2011-09-08 13:42:54 +02:00
{
2014-12-04 22:48:53 +01:00
StorageIndex innerNNZ = previousOuterIndex - m_outerIndex [ j ] ;
2023-01-07 22:09:42 +00:00
StorageIndex begin = m_outerIndex [ j ] ;
StorageIndex end = begin + innerNNZ ;
StorageIndex target = newOuterIndex [ j ] ;
internal : : smart_memmove ( innerIndexPtr ( ) + begin , innerIndexPtr ( ) + end , innerIndexPtr ( ) + target ) ;
internal : : smart_memmove ( valuePtr ( ) + begin , valuePtr ( ) + end , valuePtr ( ) + target ) ;
2011-09-08 13:42:54 +02:00
previousOuterIndex = m_outerIndex [ j ] ;
m_outerIndex [ j ] = newOuterIndex [ j ] ;
m_innerNonZeros [ j ] = innerNNZ ;
}
2020-08-26 12:32:20 +02:00
if ( m_outerSize > 0 )
m_outerIndex [ m_outerSize ] = m_outerIndex [ m_outerSize - 1 ] + m_innerNonZeros [ m_outerSize - 1 ] + reserveSizes [ m_outerSize - 1 ] ;
2011-09-08 13:42:54 +02:00
m_data . resize ( m_outerIndex [ m_outerSize ] ) ;
}
else
{
2022-08-23 21:44:22 +00:00
StorageIndex * newOuterIndex = internal : : conditional_aligned_new_auto < StorageIndex , true > ( m_outerSize + 1 ) ;
2012-07-19 00:07:06 +02:00
2014-12-04 22:48:53 +01:00
StorageIndex count = 0 ;
2011-09-08 13:42:54 +02:00
for ( Index j = 0 ; j < m_outerSize ; + + j )
{
newOuterIndex [ j ] = count ;
2014-12-04 22:48:53 +01:00
StorageIndex alreadyReserved = ( m_outerIndex [ j + 1 ] - m_outerIndex [ j ] ) - m_innerNonZeros [ j ] ;
StorageIndex toReserve = std : : max < StorageIndex > ( reserveSizes [ j ] , alreadyReserved ) ;
2011-09-08 13:42:54 +02:00
count + = toReserve + m_innerNonZeros [ j ] ;
}
newOuterIndex [ m_outerSize ] = count ;
m_data . resize ( count ) ;
2013-03-20 21:58:24 +01:00
for ( Index j = m_outerSize - 1 ; j > = 0 ; - - j )
2011-09-08 13:42:54 +02:00
{
2023-01-07 22:09:42 +00:00
StorageIndex offset = newOuterIndex [ j ] - m_outerIndex [ j ] ;
2011-09-08 13:42:54 +02:00
if ( offset > 0 )
{
2014-12-04 22:48:53 +01:00
StorageIndex innerNNZ = m_innerNonZeros [ j ] ;
2023-01-07 22:09:42 +00:00
StorageIndex begin = m_outerIndex [ j ] ;
StorageIndex end = begin + innerNNZ ;
StorageIndex target = newOuterIndex [ j ] ;
internal : : smart_memmove ( innerIndexPtr ( ) + begin , innerIndexPtr ( ) + end , innerIndexPtr ( ) + target ) ;
internal : : smart_memmove ( valuePtr ( ) + begin , valuePtr ( ) + end , valuePtr ( ) + target ) ;
2011-09-08 13:42:54 +02:00
}
}
std : : swap ( m_outerIndex , newOuterIndex ) ;
2022-08-23 21:44:22 +00:00
internal : : conditional_aligned_delete_auto < StorageIndex , true > ( newOuterIndex , m_outerSize + 1 ) ;
2011-09-08 13:42:54 +02:00
}
}
2011-09-20 02:04:03 +02:00
public :
2008-06-23 13:25:22 +00:00
2010-06-02 13:32:13 +02:00
//--- low level purely coherent filling ---
2008-06-23 13:25:22 +00:00
2011-11-28 16:36:37 +01:00
/** \internal
* \ returns a reference to the non zero coefficient at position \ a row , \ a col assuming that :
2010-06-02 13:32:13 +02:00
* - the nonzero does not already exist
* - the new coefficient is the last one according to the storage order
*
* Before filling a given inner vector you must call the statVec ( Index ) function .
*
* After an insertion session , you should call the finalize ( ) function .
*
2010-06-02 17:56:35 +02:00
* \ sa insert , insertBackByOuterInner , startVec */
2010-06-02 13:32:13 +02:00
inline Scalar & insertBack ( Index row , Index col )
{
2010-06-02 17:56:35 +02:00
return insertBackByOuterInner ( IsRowMajor ? row : col , IsRowMajor ? col : row ) ;
2008-06-23 13:25:22 +00:00
}
2009-05-07 13:13:42 +00:00
2011-11-28 16:36:37 +01:00
/** \internal
* \ sa insertBack , startVec */
2010-06-02 13:32:13 +02:00
inline Scalar & insertBackByOuterInner ( Index outer , Index inner )
2009-05-04 14:25:12 +00:00
{
2015-02-16 13:19:05 +01:00
eigen_assert ( Index ( m_outerIndex [ outer + 1 ] ) = = m_data . size ( ) & & " Invalid ordered insertion (invalid outer index) " ) ;
2010-10-25 10:15:22 -04:00
eigen_assert ( ( m_outerIndex [ outer + 1 ] - m_outerIndex [ outer ] = = 0 | | m_data . index ( m_data . size ( ) - 1 ) < inner ) & & " Invalid ordered insertion (invalid inner index) " ) ;
2023-01-07 22:09:42 +00:00
StorageIndex p = m_outerIndex [ outer + 1 ] ;
2009-05-04 14:25:12 +00:00
+ + m_outerIndex [ outer + 1 ] ;
2013-07-29 20:13:52 +09:00
m_data . append ( Scalar ( 0 ) , inner ) ;
2010-11-26 08:36:16 +01:00
return m_data . value ( p ) ;
2009-05-04 14:25:12 +00:00
}
2009-05-07 13:13:42 +00:00
2011-11-28 16:36:37 +01:00
/** \internal
* \ warning use it only if you know what you are doing */
2010-06-02 17:56:35 +02:00
inline Scalar & insertBackByOuterInnerUnordered ( Index outer , Index inner )
2010-01-05 15:57:16 +01:00
{
2023-01-07 22:09:42 +00:00
StorageIndex p = m_outerIndex [ outer + 1 ] ;
2010-01-05 15:57:16 +01:00
+ + m_outerIndex [ outer + 1 ] ;
2013-07-29 20:13:52 +09:00
m_data . append ( Scalar ( 0 ) , inner ) ;
2010-11-26 08:36:16 +01:00
return m_data . value ( p ) ;
2010-01-05 15:57:16 +01:00
}
2011-11-28 16:36:37 +01:00
/** \internal
* \ sa insertBack , insertBackByOuterInner */
2010-05-30 16:00:58 -04:00
inline void startVec ( Index outer )
2009-05-04 14:25:12 +00:00
{
2014-02-15 09:35:23 +01:00
eigen_assert ( m_outerIndex [ outer ] = = Index ( m_data . size ( ) ) & & " You must call startVec for each inner vector sequentially " ) ;
2010-10-25 10:15:22 -04:00
eigen_assert ( m_outerIndex [ outer + 1 ] = = 0 & & " You must call startVec for each inner vector sequentially " ) ;
2009-05-04 14:25:12 +00:00
m_outerIndex [ outer + 1 ] = m_outerIndex [ outer ] ;
}
2009-05-07 13:13:42 +00:00
2011-12-02 19:00:16 +01:00
/** \internal
* Must be called after inserting a set of non zero entries using the low level compressed API .
2009-05-04 14:25:12 +00:00
*/
inline void finalize ( )
2008-06-23 13:25:22 +00:00
{
2011-12-10 23:08:10 +01:00
if ( isCompressed ( ) )
2008-06-23 13:25:22 +00:00
{
2015-02-13 18:57:41 +01:00
StorageIndex size = internal : : convert_index < StorageIndex > ( m_data . size ( ) ) ;
2011-09-08 13:42:54 +02:00
Index i = m_outerSize ;
// find the last filled column
while ( i > = 0 & & m_outerIndex [ i ] = = 0 )
- - i ;
2008-06-23 13:25:22 +00:00
+ + i ;
2011-09-08 13:42:54 +02:00
while ( i < = m_outerSize )
{
m_outerIndex [ i ] = size ;
+ + i ;
}
}
}
2011-12-02 19:00:16 +01:00
//---
2012-01-28 11:13:59 +01:00
template < typename InputIterators >
void setFromTriplets ( const InputIterators & begin , const InputIterators & end ) ;
2011-12-02 19:00:16 +01:00
2015-10-13 11:30:41 +02:00
template < typename InputIterators , typename DupFunctor >
void setFromTriplets ( const InputIterators & begin , const InputIterators & end , DupFunctor dup_func ) ;
2023-01-07 22:09:42 +00:00
template < typename Derived , typename DupFunctor >
void collapseDuplicates ( DenseBase < Derived > & wi , DupFunctor dup_func = DupFunctor ( ) ) ;
template < typename InputIterators >
void setFromSortedTriplets ( const InputIterators & begin , const InputIterators & end ) ;
2015-10-06 13:29:41 +02:00
2023-01-07 22:09:42 +00:00
template < typename InputIterators , typename DupFunctor >
void setFromSortedTriplets ( const InputIterators & begin , const InputIterators & end , DupFunctor dup_func ) ;
2012-01-28 11:13:59 +01:00
//---
2011-09-08 13:42:54 +02:00
2011-12-02 19:00:16 +01:00
/** \internal
* same as insert ( Index , Index ) except that the indices are given relative to the storage order */
2013-02-28 19:31:03 +01:00
Scalar & insertByOuterInner ( Index j , Index i )
2011-12-02 19:00:16 +01:00
{
return insert ( IsRowMajor ? j : i , IsRowMajor ? i : j ) ;
}
2011-11-28 16:36:37 +01:00
/** Turns the matrix into the \em compressed format.
*/
2011-09-08 13:42:54 +02:00
void makeCompressed ( )
{
2023-01-07 22:09:42 +00:00
if ( isCompressed ( ) ) return ;
2011-09-08 13:42:54 +02:00
2015-02-18 11:29:54 +01:00
eigen_internal_assert ( m_outerIndex ! = 0 & & m_outerSize > 0 ) ;
2023-01-07 22:09:42 +00:00
StorageIndex start = m_outerIndex [ 1 ] ;
2011-09-08 13:42:54 +02:00
m_outerIndex [ 1 ] = m_innerNonZeros [ 0 ] ;
for ( Index j = 1 ; j < m_outerSize ; + + j )
{
2023-01-07 22:09:42 +00:00
StorageIndex end = start + m_innerNonZeros [ j ] ;
StorageIndex target = m_outerIndex [ j ] ;
if ( start ! = target )
2011-09-08 13:42:54 +02:00
{
2023-01-07 22:09:42 +00:00
internal : : smart_memmove ( innerIndexPtr ( ) + start , innerIndexPtr ( ) + end , innerIndexPtr ( ) + target ) ;
internal : : smart_memmove ( valuePtr ( ) + start , valuePtr ( ) + end , valuePtr ( ) + target ) ;
2011-09-08 13:42:54 +02:00
}
2023-01-07 22:09:42 +00:00
start = m_outerIndex [ j + 1 ] ;
m_outerIndex [ j + 1 ] = m_outerIndex [ j ] + m_innerNonZeros [ j ] ;
2008-06-23 13:25:22 +00:00
}
2022-08-23 21:44:22 +00:00
internal : : conditional_aligned_delete_auto < StorageIndex , true > ( m_innerNonZeros , m_outerSize ) ;
2011-09-08 13:42:54 +02:00
m_innerNonZeros = 0 ;
m_data . resize ( m_outerIndex [ m_outerSize ] ) ;
m_data . squeeze ( ) ;
2008-06-23 13:25:22 +00:00
}
2009-03-26 17:11:43 +00:00
2012-07-27 16:38:20 +02:00
/** Turns the matrix into the uncompressed mode */
2012-09-07 13:14:57 +02:00
void uncompress ( )
2012-07-27 16:38:20 +02:00
{
2023-01-07 22:09:42 +00:00
if ( m_innerNonZeros ! = 0 ) return ;
2022-08-23 21:44:22 +00:00
m_innerNonZeros = internal : : conditional_aligned_new_auto < StorageIndex , true > ( m_outerSize ) ;
2023-01-07 22:09:42 +00:00
typename IndexVector : : AlignedMapType innerNonZeroMap ( m_innerNonZeros , m_outerSize ) ;
typename IndexVector : : ConstAlignedMapType outerIndexMap ( m_outerIndex , m_outerSize ) ;
typename IndexVector : : ConstMapType nextOuterIndexMap ( m_outerIndex + 1 , m_outerSize ) ;
innerNonZeroMap = nextOuterIndexMap - outerIndexMap ;
2012-07-27 16:38:20 +02:00
}
2019-01-28 17:29:50 +01:00
2018-03-11 10:01:44 -04:00
/** Suppresses all nonzeros which are \b much \b smaller \b than \a reference under the tolerance \a epsilon */
2012-06-28 21:01:02 +02:00
void prune ( const Scalar & reference , const RealScalar & epsilon = NumTraits < RealScalar > : : dummy_precision ( ) )
2010-10-28 11:39:31 +02:00
{
2010-11-02 14:32:41 +01:00
prune ( default_prunning_func ( reference , epsilon ) ) ;
2010-10-28 11:39:31 +02:00
}
2011-12-20 18:37:24 +01:00
/** Turns the matrix into compressed format, and suppresses all nonzeros which do not satisfy the predicate \a keep.
2010-10-28 11:39:31 +02:00
* The functor type \ a KeepFunc must implement the following function :
* \ code
* bool operator ( ) ( const Index & row , const Index & col , const Scalar & value ) const ;
* \ endcode
* \ sa prune ( Scalar , RealScalar )
*/
template < typename KeepFunc >
void prune ( const KeepFunc & keep = KeepFunc ( ) )
2009-01-21 18:46:04 +00:00
{
2014-12-04 22:48:53 +01:00
StorageIndex k = 0 ;
2010-10-28 11:39:31 +02:00
for ( Index j = 0 ; j < m_outerSize ; + + j )
2009-01-21 18:46:04 +00:00
{
2023-01-07 22:09:42 +00:00
StorageIndex previousStart = m_outerIndex [ j ] ;
if ( isCompressed ( ) )
m_outerIndex [ j ] = k ;
else
k = m_outerIndex [ j ] ;
StorageIndex end = isCompressed ( ) ? m_outerIndex [ j + 1 ] : previousStart + m_innerNonZeros [ j ] ;
for ( StorageIndex i = previousStart ; i < end ; + + i )
2009-01-21 18:46:04 +00:00
{
2023-01-07 22:09:42 +00:00
StorageIndex row = IsRowMajor ? StorageIndex ( j ) : m_data . index ( i ) ;
StorageIndex col = IsRowMajor ? m_data . index ( i ) : StorageIndex ( j ) ;
bool keepEntry = keep ( row , col , m_data . value ( i ) ) ;
if ( keepEntry ) {
2009-01-21 18:46:04 +00:00
m_data . value ( k ) = m_data . value ( i ) ;
m_data . index ( k ) = m_data . index ( i ) ;
+ + k ;
2023-01-07 22:09:42 +00:00
} else if ( ! isCompressed ( ) )
m_innerNonZeros [ j ] - - ;
2009-01-21 18:46:04 +00:00
}
}
2023-01-07 22:09:42 +00:00
if ( isCompressed ( ) ) {
m_outerIndex [ m_outerSize ] = k ;
m_data . resize ( k , 0 ) ;
}
2009-01-21 18:46:04 +00:00
}
2008-06-23 13:25:22 +00:00
2012-07-19 00:07:06 +02:00
/** Resizes the matrix to a \a rows x \a cols matrix leaving old values untouched.
2016-01-25 11:56:25 +01:00
*
* If the sizes of the matrix are decreased , then the matrix is turned to \ b uncompressed - mode
* and the storage of the out of bounds coefficients is kept and reserved .
* Call makeCompressed ( ) to pack the entries and squeeze extra memory .
*
* \ sa reserve ( ) , setZero ( ) , makeCompressed ( )
2012-07-19 00:07:06 +02:00
*/
2023-01-07 22:09:42 +00:00
void conservativeResize ( Index rows , Index cols ) {
2013-07-12 14:10:02 +02:00
// If one dimension is null, then there is nothing to be preserved
2023-01-07 22:09:42 +00:00
if ( rows = = 0 | | cols = = 0 ) return resize ( rows , cols ) ;
2012-07-19 00:07:06 +02:00
2023-01-07 22:09:42 +00:00
Index newOuterSize = IsRowMajor ? rows : cols ;
Index newInnerSize = IsRowMajor ? cols : rows ;
2012-07-19 00:07:06 +02:00
2023-01-07 22:09:42 +00:00
Index innerChange = newInnerSize - innerSize ( ) ;
Index outerChange = newOuterSize - outerSize ( ) ;
if ( outerChange ! = 0 ) {
m_outerIndex = internal : : conditional_aligned_realloc_new_auto < StorageIndex , true > (
outerIndexPtr ( ) , newOuterSize + 1 , outerSize ( ) + 1 ) ;
if ( ! isCompressed ( ) )
m_innerNonZeros = internal : : conditional_aligned_realloc_new_auto < StorageIndex , true > (
innerNonZeroPtr ( ) , newOuterSize , outerSize ( ) ) ;
if ( outerChange > 0 ) {
StorageIndex lastIdx = outerSize ( ) = = 0 ? StorageIndex ( 0 ) : outerIndexPtr ( ) [ outerSize ( ) ] ;
std : : fill_n ( outerIndexPtr ( ) + outerSize ( ) , outerChange + 1 , lastIdx ) ;
if ( ! isCompressed ( ) ) std : : fill_n ( innerNonZeroPtr ( ) + outerSize ( ) , outerChange , StorageIndex ( 0 ) ) ;
}
2013-07-12 14:10:02 +02:00
}
2023-01-07 22:09:42 +00:00
m_outerSize = newOuterSize ;
if ( innerChange < 0 ) {
for ( Index j = 0 ; j < outerSize ( ) ; j + + ) {
Index start = outerIndexPtr ( ) [ j ] ;
Index end = isCompressed ( ) ? outerIndexPtr ( ) [ j + 1 ] : start + innerNonZeroPtr ( ) [ j ] ;
Index lb = data ( ) . searchLowerIndex ( start , end , newInnerSize ) ;
if ( lb ! = end ) {
uncompress ( ) ;
innerNonZeroPtr ( ) [ j ] = StorageIndex ( lb - start ) ;
}
2012-07-19 00:07:06 +02:00
}
2013-07-12 14:10:02 +02:00
}
m_innerSize = newInnerSize ;
2012-07-19 00:07:06 +02:00
2023-01-07 22:09:42 +00:00
Index newSize = outerIndexPtr ( ) [ outerSize ( ) ] ;
eigen_assert ( newSize < = m_data . size ( ) ) ;
m_data . resize ( newSize ) ;
2012-07-19 00:07:06 +02:00
}
2011-12-02 19:00:16 +01:00
/** Resizes the matrix to a \a rows x \a cols matrix and initializes it to zero.
2015-02-16 15:56:11 +01:00
*
* This function does not free the currently allocated memory . To release as much as memory as possible ,
* call \ code mat . data ( ) . squeeze ( ) ; \ endcode after resizing it .
*
2015-10-13 10:55:58 +02:00
* \ sa reserve ( ) , setZero ( )
2009-06-08 14:12:11 +02:00
*/
2010-05-30 16:00:58 -04:00
void resize ( Index rows , Index cols )
2008-06-23 13:25:22 +00:00
{
2015-02-13 18:57:41 +01:00
const Index outerSize = IsRowMajor ? rows : cols ;
m_innerSize = IsRowMajor ? cols : rows ;
2008-06-29 21:29:12 +00:00
m_data . clear ( ) ;
2009-07-05 10:48:57 +02:00
if ( m_outerSize ! = outerSize | | m_outerSize = = 0 )
2008-06-23 13:25:22 +00:00
{
2022-08-23 21:44:22 +00:00
m_outerIndex = internal : : conditional_aligned_realloc_new_auto < StorageIndex , true > ( m_outerIndex , outerSize + 1 ,
m_outerSize + 1 ) ;
2008-06-29 21:29:12 +00:00
m_outerSize = outerSize ;
2008-06-23 13:25:22 +00:00
}
2011-09-08 13:42:54 +02:00
if ( m_innerNonZeros )
{
2022-08-23 21:44:22 +00:00
internal : : conditional_aligned_delete_auto < StorageIndex , true > ( m_innerNonZeros , m_outerSize ) ;
2011-09-08 13:42:54 +02:00
m_innerNonZeros = 0 ;
}
2021-05-11 09:52:00 -07:00
std : : fill_n ( m_outerIndex , m_outerSize + 1 , StorageIndex ( 0 ) ) ;
2008-06-23 13:25:22 +00:00
}
2010-06-02 13:32:13 +02:00
2011-12-02 19:00:16 +01:00
/** \internal
* Resize the nonzero vector to \ a size */
2010-05-30 16:00:58 -04:00
void resizeNonZeros ( Index size )
2008-10-20 17:03:09 +00:00
{
m_data . resize ( size ) ;
}
2008-06-23 13:25:22 +00:00
2014-12-01 14:45:15 +01:00
/** \returns a const expression of the diagonal coefficients. */
2014-12-01 14:41:39 +01:00
const ConstDiagonalReturnType diagonal ( ) const { return ConstDiagonalReturnType ( * this ) ; }
2014-12-01 14:45:15 +01:00
/** \returns a read-write expression of the diagonal coefficients.
* \ warning If the diagonal entries are written , then all diagonal
* entries \ b must already exist , otherwise an assertion will be raised .
*/
2014-12-01 14:41:39 +01:00
DiagonalReturnType diagonal ( ) { return DiagonalReturnType ( * this ) ; }
2011-12-04 21:49:21 +01:00
2010-06-02 13:32:13 +02:00
/** Default constructor yielding an empty \c 0 \c x \c 0 matrix */
2008-10-05 13:38:38 +00:00
inline SparseMatrix ( )
2011-09-08 13:42:54 +02:00
: m_outerSize ( - 1 ) , m_innerSize ( 0 ) , m_outerIndex ( 0 ) , m_innerNonZeros ( 0 )
2008-12-17 18:37:04 +00:00
{
resize ( 0 , 0 ) ;
}
2008-10-05 13:38:38 +00:00
2010-06-02 13:32:13 +02:00
/** Constructs a \a rows \c x \a cols empty matrix */
2010-05-30 16:00:58 -04:00
inline SparseMatrix ( Index rows , Index cols )
2011-09-08 13:42:54 +02:00
: m_outerSize ( 0 ) , m_innerSize ( 0 ) , m_outerIndex ( 0 ) , m_innerNonZeros ( 0 )
2008-06-23 13:25:22 +00:00
{
resize ( rows , cols ) ;
}
2010-06-02 13:32:13 +02:00
/** Constructs a sparse matrix from the sparse expression \a other */
2008-06-28 23:07:14 +00:00
template < typename OtherDerived >
2009-01-14 14:24:10 +00:00
inline SparseMatrix ( const SparseMatrixBase < OtherDerived > & other )
2011-09-08 13:42:54 +02:00
: m_outerSize ( 0 ) , m_innerSize ( 0 ) , m_outerIndex ( 0 ) , m_innerNonZeros ( 0 )
2008-06-28 23:07:14 +00:00
{
2013-05-17 14:02:20 +02:00
EIGEN_STATIC_ASSERT ( ( internal : : is_same < Scalar , typename OtherDerived : : Scalar > : : value ) ,
YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY )
2014-07-01 11:48:49 +02:00
const bool needToTranspose = ( Flags & RowMajorBit ) ! = ( internal : : evaluator < OtherDerived > : : Flags & RowMajorBit ) ;
2015-10-06 11:32:02 +02:00
if ( needToTranspose )
* this = other . derived ( ) ;
else
{
# ifdef EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN
EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN
# endif
internal : : call_assignment_no_alias ( * this , other . derived ( ) ) ;
}
2008-06-28 23:07:14 +00:00
}
2021-09-16 20:43:54 +00:00
2013-06-28 22:56:26 +02:00
/** Constructs a sparse matrix from the sparse selfadjoint view \a other */
template < typename OtherDerived , unsigned int UpLo >
inline SparseMatrix ( const SparseSelfAdjointView < OtherDerived , UpLo > & other )
: m_outerSize ( 0 ) , m_innerSize ( 0 ) , m_outerIndex ( 0 ) , m_innerNonZeros ( 0 )
{
2014-07-22 09:32:40 +02:00
Base : : operator = ( other ) ;
2013-06-28 22:56:26 +02:00
}
2008-06-28 23:07:14 +00:00
2022-11-30 18:16:47 +00:00
inline SparseMatrix ( SparseMatrix & & other ) : Base ( ) , m_outerSize ( 0 ) , m_innerSize ( 0 ) , m_outerIndex ( 0 ) , m_innerNonZeros ( 0 )
{
* this = other . derived ( ) . markAsRValue ( ) ;
}
2011-12-02 19:00:16 +01:00
/** Copy constructor (it performs a deep copy) */
2008-12-27 18:13:29 +00:00
inline SparseMatrix ( const SparseMatrix & other )
2011-09-08 13:42:54 +02:00
: Base ( ) , m_outerSize ( 0 ) , m_innerSize ( 0 ) , m_outerIndex ( 0 ) , m_innerNonZeros ( 0 )
2008-12-27 18:13:29 +00:00
{
* this = other . derived ( ) ;
}
2012-07-25 23:03:10 +02:00
/** \brief Copy constructor with in-place evaluation */
template < typename OtherDerived >
SparseMatrix ( const ReturnByValue < OtherDerived > & other )
: Base ( ) , m_outerSize ( 0 ) , m_innerSize ( 0 ) , m_outerIndex ( 0 ) , m_innerNonZeros ( 0 )
{
initAssignment ( other ) ;
other . evalTo ( * this ) ;
}
2021-09-16 20:43:54 +00:00
2015-06-24 18:11:06 +02:00
/** \brief Copy constructor with in-place evaluation */
template < typename OtherDerived >
explicit SparseMatrix ( const DiagonalBase < OtherDerived > & other )
: Base ( ) , m_outerSize ( 0 ) , m_innerSize ( 0 ) , m_outerIndex ( 0 ) , m_innerNonZeros ( 0 )
{
* this = other . derived ( ) ;
}
2012-07-25 23:03:10 +02:00
2011-12-02 19:00:16 +01:00
/** Swaps the content of two sparse matrices of the same type.
* This is a fast operation that simply swaps the underlying pointers and parameters . */
2008-06-29 21:29:12 +00:00
inline void swap ( SparseMatrix & other )
2008-06-23 13:25:22 +00:00
{
2008-11-05 13:47:55 +00:00
//EIGEN_DBG_SPARSE(std::cout << "SparseMatrix:: swap\n");
2008-06-29 21:29:12 +00:00
std : : swap ( m_outerIndex , other . m_outerIndex ) ;
std : : swap ( m_innerSize , other . m_innerSize ) ;
std : : swap ( m_outerSize , other . m_outerSize ) ;
2011-09-08 13:42:54 +02:00
std : : swap ( m_innerNonZeros , other . m_innerNonZeros ) ;
2008-06-29 21:29:12 +00:00
m_data . swap ( other . m_data ) ;
2008-06-23 13:25:22 +00:00
}
2015-10-25 22:01:58 +01:00
/** Sets *this to the identity matrix.
* This function also turns the matrix into compressed mode , and drop any reserved memory . */
2013-05-21 17:35:10 +02:00
inline void setIdentity ( )
{
eigen_assert ( rows ( ) = = cols ( ) & & " ONLY FOR SQUARED MATRICES " ) ;
2023-01-07 22:09:42 +00:00
if ( m_innerNonZeros ) {
internal : : conditional_aligned_delete_auto < StorageIndex , true > ( m_innerNonZeros , m_outerSize ) ;
m_innerNonZeros = 0 ;
}
m_data . resize ( rows ( ) ) ;
// is it necessary to squeeze?
m_data . squeeze ( ) ;
typename IndexVector : : AlignedMapType outerIndexMap ( outerIndexPtr ( ) , rows ( ) + 1 ) ;
typename IndexVector : : AlignedMapType innerIndexMap ( innerIndexPtr ( ) , rows ( ) ) ;
typename ScalarVector : : AlignedMapType valueMap ( valuePtr ( ) , rows ( ) ) ;
outerIndexMap . setEqualSpaced ( StorageIndex ( 0 ) , StorageIndex ( 1 ) ) ;
innerIndexMap . setEqualSpaced ( StorageIndex ( 0 ) , StorageIndex ( 1 ) ) ;
valueMap . setOnes ( ) ;
2013-05-21 17:35:10 +02:00
}
2022-11-30 18:16:47 +00:00
2008-06-26 23:22:26 +00:00
inline SparseMatrix & operator = ( const SparseMatrix & other )
2008-06-23 13:25:22 +00:00
{
2008-06-26 23:22:26 +00:00
if ( other . isRValue ( ) )
2008-06-23 13:25:22 +00:00
{
2008-06-29 21:29:12 +00:00
swap ( other . const_cast_derived ( ) ) ;
2008-06-26 23:22:26 +00:00
}
2013-05-17 14:39:31 +02:00
else if ( this ! = & other )
2008-06-26 23:22:26 +00:00
{
2015-06-09 23:11:24 +02:00
# ifdef EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN
EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN
# endif
2011-11-30 19:24:43 +01:00
initAssignment ( other ) ;
2011-12-10 23:08:10 +01:00
if ( other . isCompressed ( ) )
2011-09-08 13:42:54 +02:00
{
2019-11-05 17:17:58 -08:00
internal : : smart_copy ( other . m_outerIndex , other . m_outerIndex + m_outerSize + 1 , m_outerIndex ) ;
2011-09-08 13:42:54 +02:00
m_data = other . m_data ;
}
else
{
Base : : operator = ( other ) ;
}
2008-06-23 13:25:22 +00:00
}
2008-08-22 01:19:53 +00:00
return * this ;
2008-06-23 13:25:22 +00:00
}
2022-11-30 18:16:47 +00:00
inline SparseMatrix & operator = ( SparseMatrix & & other ) {
return * this = other . derived ( ) . markAsRValue ( ) ;
}
2014-07-30 15:22:50 +02:00
# ifndef EIGEN_PARSED_BY_DOXYGEN
2011-01-28 09:55:32 +01:00
template < typename OtherDerived >
inline SparseMatrix & operator = ( const EigenBase < OtherDerived > & other )
2011-11-30 19:39:20 +01:00
{ return Base : : operator = ( other . derived ( ) ) ; }
2020-05-30 23:14:29 +02:00
template < typename Lhs , typename Rhs >
inline SparseMatrix & operator = ( const Product < Lhs , Rhs , AliasFreeProduct > & other ) ;
2014-07-30 15:22:50 +02:00
# endif // EIGEN_PARSED_BY_DOXYGEN
2010-01-05 19:56:59 +01:00
2008-06-26 23:22:26 +00:00
template < typename OtherDerived >
2013-02-28 19:31:03 +01:00
EIGEN_DONT_INLINE SparseMatrix & operator = ( const SparseMatrixBase < OtherDerived > & other ) ;
2008-06-23 13:25:22 +00:00
2022-07-29 18:02:51 +00:00
# ifndef EIGEN_NO_IO
2008-06-23 13:25:22 +00:00
friend std : : ostream & operator < < ( std : : ostream & s , const SparseMatrix & m )
{
2008-06-26 23:22:26 +00:00
EIGEN_DBG_SPARSE (
s < < " Nonzero entries: \n " ;
2011-12-20 18:31:00 +01:00
if ( m . isCompressed ( ) )
2016-12-01 16:05:42 +01:00
{
2011-12-20 18:31:00 +01:00
for ( Index i = 0 ; i < m . nonZeros ( ) ; + + i )
s < < " ( " < < m . m_data . value ( i ) < < " , " < < m . m_data . index ( i ) < < " ) " ;
2016-12-01 16:05:42 +01:00
}
2011-12-20 18:31:00 +01:00
else
2016-12-01 16:05:42 +01:00
{
2011-12-20 18:31:00 +01:00
for ( Index i = 0 ; i < m . outerSize ( ) ; + + i )
{
2014-02-15 09:35:23 +01:00
Index p = m . m_outerIndex [ i ] ;
Index pe = m . m_outerIndex [ i ] + m . m_innerNonZeros [ i ] ;
2011-12-20 18:31:00 +01:00
Index k = p ;
2016-12-01 16:05:42 +01:00
for ( ; k < pe ; + + k ) {
2011-12-20 18:31:00 +01:00
s < < " ( " < < m . m_data . value ( k ) < < " , " < < m . m_data . index ( k ) < < " ) " ;
2016-12-01 16:05:42 +01:00
}
for ( ; k < m . m_outerIndex [ i + 1 ] ; + + k ) {
2011-12-20 18:31:00 +01:00
s < < " (_,_) " ;
2016-12-01 16:05:42 +01:00
}
2011-12-20 18:31:00 +01:00
}
2016-12-01 16:05:42 +01:00
}
2008-06-23 13:25:22 +00:00
s < < std : : endl ;
2008-06-26 23:22:26 +00:00
s < < std : : endl ;
2011-12-20 18:31:00 +01:00
s < < " Outer pointers: \n " ;
2016-12-01 16:05:42 +01:00
for ( Index i = 0 ; i < m . outerSize ( ) ; + + i ) {
2008-06-29 21:29:12 +00:00
s < < m . m_outerIndex [ i ] < < " " ;
2016-12-01 16:05:42 +01:00
}
2009-02-10 10:00:00 +00:00
s < < " $ " < < std : : endl ;
2011-12-20 18:31:00 +01:00
if ( ! m . isCompressed ( ) )
{
s < < " Inner non zeros: \n " ;
2016-12-01 16:05:42 +01:00
for ( Index i = 0 ; i < m . outerSize ( ) ; + + i ) {
2011-12-20 18:31:00 +01:00
s < < m . m_innerNonZeros [ i ] < < " " ;
2016-12-01 16:05:42 +01:00
}
2011-12-20 18:31:00 +01:00
s < < " $ " < < std : : endl ;
}
2008-06-26 23:22:26 +00:00
s < < std : : endl ;
) ;
s < < static_cast < const SparseMatrixBase < SparseMatrix > & > ( m ) ;
2008-06-23 13:25:22 +00:00
return s ;
}
2022-07-29 18:02:51 +00:00
# endif
2008-06-23 13:25:22 +00:00
/** Destructor */
inline ~ SparseMatrix ( )
{
2022-08-23 21:44:22 +00:00
internal : : conditional_aligned_delete_auto < StorageIndex , true > ( m_outerIndex , m_outerSize + 1 ) ;
internal : : conditional_aligned_delete_auto < StorageIndex , true > ( m_innerNonZeros , m_outerSize ) ;
2008-06-23 13:25:22 +00:00
}
2009-05-19 09:40:00 +02:00
/** Overloaded for performance */
Scalar sum ( ) const ;
2011-11-28 16:36:37 +01:00
# ifdef EIGEN_SPARSEMATRIX_PLUGIN
# include EIGEN_SPARSEMATRIX_PLUGIN
# endif
2010-06-02 13:32:13 +02:00
2011-11-28 16:36:37 +01:00
protected :
2011-11-30 19:24:43 +01:00
template < typename Other >
void initAssignment ( const Other & other )
{
2014-12-04 22:48:53 +01:00
resize ( other . rows ( ) , other . cols ( ) ) ;
2011-11-30 19:24:43 +01:00
if ( m_innerNonZeros )
{
2022-08-23 21:44:22 +00:00
internal : : conditional_aligned_delete_auto < StorageIndex , true > ( m_innerNonZeros , m_outerSize ) ;
2011-11-30 19:24:43 +01:00
m_innerNonZeros = 0 ;
}
}
2011-11-28 16:36:37 +01:00
/** \internal
* \ sa insert ( Index , Index ) */
2023-01-07 22:09:42 +00:00
EIGEN_DEPRECATED EIGEN_DONT_INLINE Scalar & insertCompressed ( Index row , Index col ) ;
2010-06-02 13:32:13 +02:00
2011-12-02 19:00:16 +01:00
/** \internal
* A vector object that is equal to 0 everywhere but v at the position i */
2011-11-28 16:36:37 +01:00
class SingletonVector
{
2014-12-04 22:48:53 +01:00
StorageIndex m_index ;
StorageIndex m_value ;
2011-11-28 16:36:37 +01:00
public :
2014-12-04 22:48:53 +01:00
typedef StorageIndex value_type ;
2011-11-28 16:36:37 +01:00
SingletonVector ( Index i , Index v )
2014-12-04 22:48:53 +01:00
: m_index ( convert_index ( i ) ) , m_value ( convert_index ( v ) )
2011-11-28 16:36:37 +01:00
{ }
2014-12-04 22:48:53 +01:00
StorageIndex operator [ ] ( Index i ) const { return i = = m_index ? m_value : 0 ; }
2011-11-28 16:36:37 +01:00
} ;
/** \internal
* \ sa insert ( Index , Index ) */
2023-01-07 22:09:42 +00:00
EIGEN_DEPRECATED EIGEN_DONT_INLINE Scalar & insertUncompressed ( Index row , Index col ) ;
2010-11-02 14:32:41 +01:00
2012-01-28 11:13:59 +01:00
public :
/** \internal
* \ sa insert ( Index , Index ) */
2012-06-28 21:01:02 +02:00
EIGEN_STRONG_INLINE Scalar & insertBackUncompressed ( Index row , Index col )
2012-01-28 11:13:59 +01:00
{
const Index outer = IsRowMajor ? row : col ;
const Index inner = IsRowMajor ? col : row ;
eigen_assert ( ! isCompressed ( ) ) ;
eigen_assert ( m_innerNonZeros [ outer ] < = ( m_outerIndex [ outer + 1 ] - m_outerIndex [ outer ] ) ) ;
2012-06-28 21:01:02 +02:00
Index p = m_outerIndex [ outer ] + m_innerNonZeros [ outer ] + + ;
2014-12-04 22:48:53 +01:00
m_data . index ( p ) = convert_index ( inner ) ;
2018-10-12 10:22:19 +02:00
return ( m_data . value ( p ) = Scalar ( 0 ) ) ;
2012-01-28 11:13:59 +01:00
}
2019-01-29 10:10:07 +01:00
protected :
struct IndexPosPair {
IndexPosPair ( Index a_i , Index a_p ) : i ( a_i ) , p ( a_p ) { }
Index i ;
Index p ;
} ;
/** \internal assign \a diagXpr to the diagonal of \c *this
* There are different strategies :
* 1 - if * this is overwritten ( Func = = assign_op ) or * this is empty , then we can work treat * this as a dense vector expression .
* 2 - otherwise , for each diagonal coeff ,
* 2. a - if it already exists , then we update it ,
2023-01-07 22:09:42 +00:00
* 2. b - if the correct position is at the end of the vector , and there is capacity , push to back
* 2. b - otherwise , the insertion requires a data move , record insertion locations and handle in a second pass
* 3 - at the end , if some entries failed to be updated in - place , then we alloc a new buffer , copy each chunk at the right position , and insert the new elements .
2019-01-29 10:10:07 +01:00
*/
template < typename DiagXpr , typename Func >
void assignDiagonal ( const DiagXpr diagXpr , const Func & assignFunc )
{
2023-01-07 22:09:42 +00:00
constexpr StorageIndex kEmptyIndexVal ( - 1 ) ;
typedef typename IndexVector : : AlignedMapType IndexMap ;
typedef typename ScalarVector : : AlignedMapType ValueMap ;
2019-01-29 10:10:07 +01:00
Index n = diagXpr . size ( ) ;
const bool overwrite = internal : : is_same < Func , internal : : assign_op < Scalar , Scalar > > : : value ;
if ( overwrite )
{
if ( ( this - > rows ( ) ! = n ) | | ( this - > cols ( ) ! = n ) )
this - > resize ( n , n ) ;
}
2023-01-07 22:09:42 +00:00
if ( data ( ) . size ( ) = = 0 | | overwrite )
2019-01-29 10:10:07 +01:00
{
2023-01-07 22:09:42 +00:00
if ( ! isCompressed ( ) ) {
internal : : conditional_aligned_delete_auto < StorageIndex , true > ( m_innerNonZeros , m_outerSize ) ;
m_innerNonZeros = 0 ;
}
resizeNonZeros ( n ) ;
IndexMap outerIndexMap ( outerIndexPtr ( ) , n + 1 ) ;
IndexMap innerIndexMap ( innerIndexPtr ( ) , n ) ;
ValueMap valueMap ( valuePtr ( ) , n ) ;
outerIndexMap . setEqualSpaced ( StorageIndex ( 0 ) , StorageIndex ( 1 ) ) ;
innerIndexMap . setEqualSpaced ( StorageIndex ( 0 ) , StorageIndex ( 1 ) ) ;
valueMap . setZero ( ) ;
internal : : call_assignment_no_alias ( valueMap , diagXpr , assignFunc ) ;
2019-01-29 10:10:07 +01:00
}
else
{
2023-01-07 22:09:42 +00:00
internal : : evaluator < DiagXpr > diaEval ( diagXpr ) ;
ei_declare_aligned_stack_constructed_variable ( StorageIndex , tmp , n , 0 ) ;
typename IndexVector : : AlignedMapType insertionLocations ( tmp , n ) ;
insertionLocations . setConstant ( kEmptyIndexVal ) ;
Index deferredInsertions = 0 ;
Index shift = 0 ;
for ( Index j = 0 ; j < n ; j + + ) {
Index begin = outerIndexPtr ( ) [ j ] ;
Index end = isCompressed ( ) ? outerIndexPtr ( ) [ j + 1 ] : begin + innerNonZeroPtr ( ) [ j ] ;
Index capacity = outerIndexPtr ( ) [ j + 1 ] - end ;
Index dst = data ( ) . searchLowerIndex ( begin , end , j ) ;
// the entry exists: update it now
if ( dst ! = end & & data ( ) . index ( dst ) = = j ) assignFunc . assignCoeff ( data ( ) . value ( dst ) , diaEval . coeff ( j ) ) ;
// the entry belongs at the back of the vector: push to back
else if ( dst = = end & & capacity > 0 )
assignFunc . assignCoeff ( insertBackUncompressed ( j , j ) , diaEval . coeff ( j ) ) ;
// the insertion requires a data move, record insertion location and handle in second pass
else {
2023-01-11 06:24:49 +00:00
insertionLocations . coeffRef ( j ) = StorageIndex ( dst ) ;
2023-01-07 22:09:42 +00:00
deferredInsertions + + ;
// if there is no capacity, all vectors to the right of this are shifted
if ( capacity = = 0 ) shift + + ;
}
2019-01-29 10:10:07 +01:00
}
2023-01-07 22:09:42 +00:00
if ( deferredInsertions > 0 ) {
data ( ) . resize ( data ( ) . size ( ) + shift ) ;
Index copyEnd = isCompressed ( ) ? outerIndexPtr ( ) [ outerSize ( ) ]
: outerIndexPtr ( ) [ outerSize ( ) - 1 ] + innerNonZeroPtr ( ) [ outerSize ( ) - 1 ] ;
for ( Index j = outerSize ( ) - 1 ; deferredInsertions > 0 ; j - - ) {
Index begin = outerIndexPtr ( ) [ j ] ;
Index end = isCompressed ( ) ? outerIndexPtr ( ) [ j + 1 ] : begin + innerNonZeroPtr ( ) [ j ] ;
Index capacity = outerIndexPtr ( ) [ j + 1 ] - end ;
bool doInsertion = insertionLocations ( j ) > = 0 ;
bool breakUpCopy = doInsertion & & ( capacity > 0 ) ;
// break up copy for sorted insertion into inactive nonzeros
// optionally, add another criterium, i.e. 'breakUpCopy || (capacity > threhsold)'
// where `threshold >= 0` to skip inactive nonzeros in each vector
// this reduces the total number of copied elements, but requires more moveChunk calls
if ( breakUpCopy ) {
Index copyBegin = outerIndexPtr ( ) [ j + 1 ] ;
Index to = copyBegin + shift ;
Index chunkSize = copyEnd - copyBegin ;
if ( chunkSize > 0 ) data ( ) . moveChunk ( copyBegin , to , chunkSize ) ;
copyEnd = end ;
}
outerIndexPtr ( ) [ j + 1 ] + = shift ;
if ( doInsertion ) {
// if there is capacity, shift into the inactive nonzeros
if ( capacity > 0 ) shift + + ;
Index copyBegin = insertionLocations ( j ) ;
Index to = copyBegin + shift ;
Index chunkSize = copyEnd - copyBegin ;
if ( chunkSize > 0 ) data ( ) . moveChunk ( copyBegin , to , chunkSize ) ;
Index dst = to - 1 ;
data ( ) . index ( dst ) = StorageIndex ( j ) ;
assignFunc . assignCoeff ( data ( ) . value ( dst ) = Scalar ( 0 ) , diaEval . coeff ( j ) ) ;
if ( ! isCompressed ( ) ) innerNonZeroPtr ( ) [ j ] + + ;
shift - - ;
deferredInsertions - - ;
copyEnd = copyBegin ;
}
}
}
eigen_assert ( ( shift = = 0 ) & & ( deferredInsertions = = 0 ) ) ;
2019-01-29 10:10:07 +01:00
}
}
2012-01-28 11:13:59 +01:00
2023-01-07 22:09:42 +00:00
/* Provides a consistent reserve and reallocation strategy for insertCompressed and insertUncompressed
If there is insufficient space for one insertion , the size of the memory buffer is doubled */
inline void checkAllocatedSpaceAndMaybeExpand ( ) ;
/* These functions are used to avoid a redundant binary search operation in functions such as coeffRef() and assume `dst` is the appropriate sorted insertion point */
EIGEN_STRONG_INLINE Scalar & insertAtByOuterInner ( Index outer , Index inner , Index dst ) ;
Scalar & insertCompressedAtByOuterInner ( Index outer , Index inner , Index dst ) ;
Scalar & insertUncompressedAtByOuterInner ( Index outer , Index inner , Index dst ) ;
2010-11-02 14:32:41 +01:00
private :
2021-09-16 20:43:54 +00:00
EIGEN_STATIC_ASSERT ( NumTraits < StorageIndex > : : IsSigned , THE_INDEX_TYPE_MUST_BE_A_SIGNED_TYPE )
EIGEN_STATIC_ASSERT ( ( Options & ( ColMajor | RowMajor ) ) = = Options , INVALID_MATRIX_TEMPLATE_PARAMETERS )
2011-12-04 22:14:53 +01:00
2010-11-02 14:32:41 +01:00
struct default_prunning_func {
2012-06-28 21:01:02 +02:00
default_prunning_func ( const Scalar & ref , const RealScalar & eps ) : reference ( ref ) , epsilon ( eps ) { }
2010-11-02 14:32:41 +01:00
inline bool operator ( ) ( const Index & , const Index & , const Scalar & value ) const
{
return ! internal : : isMuchSmallerThan ( value , reference , epsilon ) ;
}
Scalar reference ;
RealScalar epsilon ;
} ;
2008-06-23 13:25:22 +00:00
} ;
2012-01-28 11:13:59 +01:00
namespace internal {
2023-01-07 22:09:42 +00:00
// Creates a compressed sparse matrix from a range of unsorted triplets
// Requires temporary storage to handle duplicate entries
template < typename InputIterator , typename SparseMatrixType , typename DupFunctor >
void set_from_triplets ( const InputIterator & begin , const InputIterator & end , SparseMatrixType & mat ,
DupFunctor dup_func ) {
constexpr bool IsRowMajor = SparseMatrixType : : IsRowMajor ;
2014-12-04 22:48:53 +01:00
typedef typename SparseMatrixType : : StorageIndex StorageIndex ;
2023-01-07 22:09:42 +00:00
typedef typename VectorX < StorageIndex > : : AlignedMapType IndexMap ;
if ( begin = = end ) return ;
// free innerNonZeroPtr (if present) and zero outerIndexPtr
mat . resize ( mat . rows ( ) , mat . cols ( ) ) ;
// allocate temporary storage for nonzero insertion (outer size) and duplicate removal (inner size)
ei_declare_aligned_stack_constructed_variable ( StorageIndex , tmp , numext : : maxi ( mat . innerSize ( ) , mat . outerSize ( ) ) , 0 ) ;
// scan triplets to determine allocation size before constructing matrix
IndexMap outerIndexMap ( mat . outerIndexPtr ( ) , mat . outerSize ( ) + 1 ) ;
for ( InputIterator it ( begin ) ; it ! = end ; + + it ) {
eigen_assert ( it - > row ( ) > = 0 & & it - > row ( ) < mat . rows ( ) & & it - > col ( ) > = 0 & & it - > col ( ) < mat . cols ( ) ) ;
StorageIndex j = IsRowMajor ? it - > row ( ) : it - > col ( ) ;
outerIndexMap . coeffRef ( j + 1 ) + + ;
}
2012-01-28 11:13:59 +01:00
2023-01-07 22:09:42 +00:00
// finalize outer indices and allocate memory
std : : partial_sum ( outerIndexMap . begin ( ) , outerIndexMap . end ( ) , outerIndexMap . begin ( ) ) ;
Index nonZeros = mat . outerIndexPtr ( ) [ mat . outerSize ( ) ] ;
mat . resizeNonZeros ( nonZeros ) ;
// use tmp to track nonzero insertions
IndexMap back ( tmp , mat . outerSize ( ) ) ;
back = outerIndexMap . head ( mat . outerSize ( ) ) ;
// push triplets to back of each inner vector
for ( InputIterator it ( begin ) ; it ! = end ; + + it ) {
StorageIndex j = IsRowMajor ? it - > row ( ) : it - > col ( ) ;
StorageIndex i = IsRowMajor ? it - > col ( ) : it - > row ( ) ;
mat . data ( ) . index ( back . coeff ( j ) ) = i ;
mat . data ( ) . value ( back . coeff ( j ) ) = it - > value ( ) ;
back . coeffRef ( j ) + + ;
}
2013-05-03 14:28:37 +02:00
2023-01-07 22:09:42 +00:00
// use tmp to collapse duplicates
IndexMap wi ( tmp , mat . innerSize ( ) ) ;
mat . collapseDuplicates ( wi , dup_func ) ;
mat . sortInnerIndices ( ) ;
}
2013-05-03 14:28:37 +02:00
2023-01-07 22:09:42 +00:00
// Creates a compressed sparse matrix from a sorted range of triplets
template < typename InputIterator , typename SparseMatrixType , typename DupFunctor >
void set_from_triplets_sorted ( const InputIterator & begin , const InputIterator & end , SparseMatrixType & mat ,
DupFunctor dup_func ) {
constexpr bool IsRowMajor = SparseMatrixType : : IsRowMajor ;
typedef typename SparseMatrixType : : StorageIndex StorageIndex ;
typedef typename VectorX < StorageIndex > : : AlignedMapType IndexMap ;
if ( begin = = end ) return ;
constexpr StorageIndex kEmptyIndexValue ( - 1 ) ;
// deallocate inner nonzeros if present and zero outerIndexPtr
mat . resize ( mat . rows ( ) , mat . cols ( ) ) ;
// use outer indices to count non zero entries (excluding duplicate entries)
StorageIndex previous_j = kEmptyIndexValue ;
StorageIndex previous_i = kEmptyIndexValue ;
// scan triplets to determine allocation size before constructing matrix
IndexMap outerIndexMap ( mat . outerIndexPtr ( ) , mat . outerSize ( ) + 1 ) ;
for ( InputIterator it ( begin ) ; it ! = end ; + + it ) {
eigen_assert ( it - > row ( ) > = 0 & & it - > row ( ) < mat . rows ( ) & & it - > col ( ) > = 0 & & it - > col ( ) < mat . cols ( ) ) ;
StorageIndex j = IsRowMajor ? it - > row ( ) : it - > col ( ) ;
StorageIndex i = IsRowMajor ? it - > col ( ) : it - > row ( ) ;
eigen_assert ( j > previous_j | | ( j = = previous_j & & i > = previous_i ) ) ;
// identify duplicates by examining previous location
bool duplicate = ( previous_j = = j ) & & ( previous_i = = i ) ;
if ( ! duplicate ) outerIndexMap . coeffRef ( j + 1 ) + + ;
previous_j = j ;
previous_i = i ;
2013-05-03 14:28:37 +02:00
}
2023-01-07 22:09:42 +00:00
// finalize outer indices and allocate memory
std : : partial_sum ( outerIndexMap . begin ( ) , outerIndexMap . end ( ) , outerIndexMap . begin ( ) ) ;
Index nonZeros = mat . outerIndexPtr ( ) [ mat . outerSize ( ) ] ;
mat . resizeNonZeros ( nonZeros ) ;
previous_i = kEmptyIndexValue ;
previous_j = kEmptyIndexValue ;
Index back = 0 ;
for ( InputIterator it ( begin ) ; it ! = end ; + + it ) {
StorageIndex j = IsRowMajor ? it - > row ( ) : it - > col ( ) ;
StorageIndex i = IsRowMajor ? it - > col ( ) : it - > row ( ) ;
bool duplicate = ( previous_j = = j ) & & ( previous_i = = i ) ;
if ( duplicate ) {
mat . data ( ) . value ( back - 1 ) = dup_func ( mat . data ( ) . value ( back - 1 ) , it - > value ( ) ) ;
} else {
// push triplets to back
mat . data ( ) . index ( back ) = i ;
mat . data ( ) . value ( back ) = it - > value ( ) ;
previous_j = j ;
previous_i = i ;
back + + ;
}
}
// matrix is finalized
2012-01-28 11:13:59 +01:00
}
}
2012-12-24 13:33:22 +01:00
/** Fill the matrix \c *this with the list of \em triplets defined by the iterator range \a begin - \a end.
2012-01-28 11:13:59 +01:00
*
* A \ em triplet is a tuple ( i , j , value ) defining a non - zero element .
* The input list of triplets does not have to be sorted , and can contains duplicated elements .
* In any case , the result is a \ b sorted and \ b compressed sparse matrix where the duplicates have been summed up .
* This is a \ em O ( n ) operation , with \ em n the number of triplet elements .
* The initial contents of \ c * this is destroyed .
* The matrix \ c * this must be properly resized beforehand using the SparseMatrix ( Index , Index ) constructor ,
* or the resize ( Index , Index ) method . The sizes are not extracted from the triplet list .
*
* The \ a InputIterators value_type must provide the following interface :
* \ code
* Scalar value ( ) const ; // the value
* Scalar row ( ) const ; // the row index i
* Scalar col ( ) const ; // the column index j
* \ endcode
* See for instance the Eigen : : Triplet template class .
*
* Here is a typical usage example :
* \ code
typedef Triplet < double > T ;
std : : vector < T > tripletList ;
2020-12-09 14:48:24 +01:00
tripletList . reserve ( estimation_of_entries ) ;
2012-01-28 11:13:59 +01:00
for ( . . . )
{
// ...
tripletList . push_back ( T ( i , j , v_ij ) ) ;
}
SparseMatrixType m ( rows , cols ) ;
m . setFromTriplets ( tripletList . begin ( ) , tripletList . end ( ) ) ;
// m is ready to go!
* \ endcode
*
* \ warning The list of triplets is read multiple times ( at least twice ) . Therefore , it is not recommended to define
* an abstract iterator over a complex data - structure that would be expensive to evaluate . The triplets should rather
2018-03-11 10:01:44 -04:00
* be explicitly stored into a std : : vector for instance .
2012-01-28 11:13:59 +01:00
*/
2021-08-04 22:41:52 +00:00
template < typename Scalar , int Options_ , typename StorageIndex_ >
2012-01-28 11:13:59 +01:00
template < typename InputIterators >
2021-08-04 22:41:52 +00:00
void SparseMatrix < Scalar , Options_ , StorageIndex_ > : : setFromTriplets ( const InputIterators & begin , const InputIterators & end )
2012-01-28 11:13:59 +01:00
{
2021-08-04 22:41:52 +00:00
internal : : set_from_triplets < InputIterators , SparseMatrix < Scalar , Options_ , StorageIndex_ > > ( begin , end , * this , internal : : scalar_sum_op < Scalar , Scalar > ( ) ) ;
2015-10-06 13:29:41 +02:00
}
2023-01-07 22:09:42 +00:00
/** The same as setFromTriplets but triplets are assumed to be pre-sorted. This is faster and requires less temporary storage.
* Two triplets ` a ` and ` b ` are appropriately ordered if :
* \ code
* ColMajor : ( ( a . col ( ) ! = b . col ( ) ) ? ( a . col ( ) < b . col ( ) ) : ( a . row ( ) < b . row ( ) )
* RowMajor : ( ( a . row ( ) ! = b . row ( ) ) ? ( a . row ( ) < b . row ( ) ) : ( a . col ( ) < b . col ( ) )
* \ endcode
*/
template < typename Scalar , int Options_ , typename StorageIndex_ >
template < typename InputIterators >
void SparseMatrix < Scalar , Options_ , StorageIndex_ > : : setFromSortedTriplets ( const InputIterators & begin , const InputIterators & end )
{
internal : : set_from_triplets_sorted < InputIterators , SparseMatrix < Scalar , Options_ , StorageIndex_ > > ( begin , end , * this , internal : : scalar_sum_op < Scalar , Scalar > ( ) ) ;
}
2015-10-13 11:30:41 +02:00
/** The same as setFromTriplets but when duplicates are met the functor \a dup_func is applied:
2015-10-06 13:29:41 +02:00
* \ code
2015-10-13 11:30:41 +02:00
* value = dup_func ( OldValue , NewValue )
2023-01-07 22:09:42 +00:00
* \ endcode
* Here is a C + + 11 example keeping the latest entry only :
* \ code
* mat . setFromTriplets ( triplets . begin ( ) , triplets . end ( ) , [ ] ( const Scalar & , const Scalar & b ) { return b ; } ) ;
* \ endcode
*/
template < typename Scalar , int Options_ , typename StorageIndex_ >
template < typename InputIterators , typename DupFunctor >
void SparseMatrix < Scalar , Options_ , StorageIndex_ > : : setFromTriplets ( const InputIterators & begin , const InputIterators & end , DupFunctor dup_func )
{
internal : : set_from_triplets < InputIterators , SparseMatrix < Scalar , Options_ , StorageIndex_ > , DupFunctor > ( begin , end , * this , dup_func ) ;
}
/** The same as setFromSortedTriplets but when duplicates are met the functor \a dup_func is applied:
* \ code
* value = dup_func ( OldValue , NewValue )
* \ endcode
2015-10-13 11:30:41 +02:00
* Here is a C + + 11 example keeping the latest entry only :
* \ code
* mat . setFromTriplets ( triplets . begin ( ) , triplets . end ( ) , [ ] ( const Scalar & , const Scalar & b ) { return b ; } ) ;
* \ endcode
*/
2021-08-04 22:41:52 +00:00
template < typename Scalar , int Options_ , typename StorageIndex_ >
2023-01-07 22:09:42 +00:00
template < typename InputIterators , typename DupFunctor >
void SparseMatrix < Scalar , Options_ , StorageIndex_ > : : setFromSortedTriplets ( const InputIterators & begin , const InputIterators & end , DupFunctor dup_func )
2015-10-06 13:29:41 +02:00
{
2023-01-07 22:09:42 +00:00
internal : : set_from_triplets_sorted < InputIterators , SparseMatrix < Scalar , Options_ , StorageIndex_ > , DupFunctor > ( begin , end , * this , dup_func ) ;
2012-01-28 11:13:59 +01:00
}
/** \internal */
2021-08-04 22:41:52 +00:00
template < typename Scalar , int Options_ , typename StorageIndex_ >
2023-01-07 22:09:42 +00:00
template < typename Derived , typename DupFunctor >
void SparseMatrix < Scalar , Options_ , StorageIndex_ > : : collapseDuplicates ( DenseBase < Derived > & wi , DupFunctor dup_func )
2012-01-28 11:13:59 +01:00
{
2023-01-07 22:09:42 +00:00
eigen_assert ( wi . size ( ) > = m_innerSize ) ;
constexpr StorageIndex kEmptyIndexValue ( - 1 ) ;
wi . setConstant ( kEmptyIndexValue ) ;
2014-12-04 22:48:53 +01:00
StorageIndex count = 0 ;
2012-01-28 11:13:59 +01:00
// for each inner-vector, wi[inner_index] will hold the position of first element into the index/value buffers
2023-01-07 22:09:42 +00:00
for ( Index j = 0 ; j < m_outerSize ; + + j ) {
StorageIndex start = count ;
StorageIndex oldEnd = isCompressed ( ) ? m_outerIndex [ j + 1 ] : m_outerIndex [ j ] + m_innerNonZeros [ j ] ;
for ( StorageIndex k = m_outerIndex [ j ] ; k < oldEnd ; + + k ) {
StorageIndex i = m_data . index ( k ) ;
if ( wi ( i ) > = start ) {
2012-01-28 11:13:59 +01:00
// we already meet this entry => accumulate it
2015-10-13 11:30:41 +02:00
m_data . value ( wi ( i ) ) = dup_func ( m_data . value ( wi ( i ) ) , m_data . value ( k ) ) ;
2023-01-07 22:09:42 +00:00
} else {
2012-01-28 11:13:59 +01:00
m_data . value ( count ) = m_data . value ( k ) ;
m_data . index ( count ) = m_data . index ( k ) ;
wi ( i ) = count ;
+ + count ;
}
}
m_outerIndex [ j ] = start ;
}
m_outerIndex [ m_outerSize ] = count ;
// turn the matrix into compressed form
2023-01-07 22:09:42 +00:00
if ( m_innerNonZeros ) {
internal : : conditional_aligned_delete_auto < StorageIndex , true > ( m_innerNonZeros , m_outerSize ) ;
m_innerNonZeros = 0 ;
}
2012-01-28 11:13:59 +01:00
m_data . resize ( m_outerIndex [ m_outerSize ] ) ;
}
2023-01-07 22:09:42 +00:00
/** \internal */
2021-08-04 22:41:52 +00:00
template < typename Scalar , int Options_ , typename StorageIndex_ >
2014-06-20 15:42:13 +02:00
template < typename OtherDerived >
2021-08-04 22:41:52 +00:00
EIGEN_DONT_INLINE SparseMatrix < Scalar , Options_ , StorageIndex_ > & SparseMatrix < Scalar , Options_ , StorageIndex_ > : : operator = ( const SparseMatrixBase < OtherDerived > & other )
2014-06-20 15:42:13 +02:00
{
EIGEN_STATIC_ASSERT ( ( internal : : is_same < Scalar , typename OtherDerived : : Scalar > : : value ) ,
YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY )
2014-07-19 14:55:56 +02:00
2015-02-07 22:00:46 +01:00
# ifdef EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN
EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN
# endif
2014-06-27 15:53:51 +02:00
const bool needToTranspose = ( Flags & RowMajorBit ) ! = ( internal : : evaluator < OtherDerived > : : Flags & RowMajorBit ) ;
2014-06-20 15:42:13 +02:00
if ( needToTranspose )
{
2015-10-14 10:16:48 +02:00
# ifdef EIGEN_SPARSE_TRANSPOSED_COPY_PLUGIN
EIGEN_SPARSE_TRANSPOSED_COPY_PLUGIN
# endif
2014-06-20 15:42:13 +02:00
// two passes algorithm:
// 1 - compute the number of coeffs per dest inner vector
// 2 - do the actual copy/eval
// Since each coeff of the rhs has to be evaluated twice, let's evaluate it if needed
2014-07-19 14:55:56 +02:00
typedef typename internal : : nested_eval < OtherDerived , 2 , typename internal : : plain_matrix_type < OtherDerived > : : type > : : type OtherCopy ;
2022-03-16 16:43:40 +00:00
typedef internal : : remove_all_t < OtherCopy > OtherCopy_ ;
2022-01-10 20:53:29 +00:00
typedef internal : : evaluator < OtherCopy_ > OtherCopyEval ;
2014-06-20 15:42:13 +02:00
OtherCopy otherCopy ( other . derived ( ) ) ;
OtherCopyEval otherCopyEval ( otherCopy ) ;
SparseMatrix dest ( other . rows ( ) , other . cols ( ) ) ;
2014-12-04 22:48:53 +01:00
Eigen : : Map < IndexVector > ( dest . m_outerIndex , dest . outerSize ( ) ) . setZero ( ) ;
2014-06-20 15:42:13 +02:00
// pass 1
// FIXME the above copy could be merged with that pass
for ( Index j = 0 ; j < otherCopy . outerSize ( ) ; + + j )
for ( typename OtherCopyEval : : InnerIterator it ( otherCopyEval , j ) ; it ; + + it )
+ + dest . m_outerIndex [ it . index ( ) ] ;
// prefix sum
2014-12-04 22:48:53 +01:00
StorageIndex count = 0 ;
IndexVector positions ( dest . outerSize ( ) ) ;
2014-06-20 15:42:13 +02:00
for ( Index j = 0 ; j < dest . outerSize ( ) ; + + j )
{
2016-05-26 17:35:53 +02:00
StorageIndex tmp = dest . m_outerIndex [ j ] ;
2014-06-20 15:42:13 +02:00
dest . m_outerIndex [ j ] = count ;
positions [ j ] = count ;
count + = tmp ;
}
dest . m_outerIndex [ dest . outerSize ( ) ] = count ;
// alloc
dest . m_data . resize ( count ) ;
// pass 2
2014-12-04 22:48:53 +01:00
for ( StorageIndex j = 0 ; j < otherCopy . outerSize ( ) ; + + j )
2014-06-20 15:42:13 +02:00
{
for ( typename OtherCopyEval : : InnerIterator it ( otherCopyEval , j ) ; it ; + + it )
{
Index pos = positions [ it . index ( ) ] + + ;
dest . m_data . index ( pos ) = j ;
dest . m_data . value ( pos ) = it . value ( ) ;
}
}
this - > swap ( dest ) ;
return * this ;
}
else
{
if ( other . isRValue ( ) )
2014-07-01 11:48:49 +02:00
{
2014-06-20 15:42:13 +02:00
initAssignment ( other . derived ( ) ) ;
2014-07-01 11:48:49 +02:00
}
2014-06-20 15:42:13 +02:00
// there is no special optimization
return Base : : operator = ( other . derived ( ) ) ;
}
}
2013-02-28 19:31:03 +01:00
2023-01-07 22:09:42 +00:00
template < typename Scalar_ , int Options_ , typename StorageIndex_ >
inline typename SparseMatrix < Scalar_ , Options_ , StorageIndex_ > : : Scalar & SparseMatrix < Scalar_ , Options_ , StorageIndex_ > : : insert (
Index row , Index col ) {
Index outer = IsRowMajor ? row : col ;
Index inner = IsRowMajor ? col : row ;
Index start = outerIndexPtr ( ) [ outer ] ;
Index end = isCompressed ( ) ? outerIndexPtr ( ) [ outer + 1 ] : start + innerNonZeroPtr ( ) [ outer ] ;
Index dst = data ( ) . searchLowerIndex ( start , end , inner ) ;
eigen_assert ( ( dst = = end | | data ( ) . index ( dst ) ! = inner ) & &
" you cannot insert an element that already exists, you must call coeffRef to this end " ) ;
return insertAtByOuterInner ( outer , inner , dst ) ;
2015-03-04 09:39:26 +01:00
}
2013-02-28 19:31:03 +01:00
2023-01-07 22:09:42 +00:00
template < typename Scalar_ , int Options_ , typename StorageIndex_ >
EIGEN_STRONG_INLINE typename SparseMatrix < Scalar_ , Options_ , StorageIndex_ > : : Scalar &
SparseMatrix < Scalar_ , Options_ , StorageIndex_ > : : insertAtByOuterInner ( Index outer , Index inner , Index dst ) {
2023-01-11 06:24:49 +00:00
uncompress ( ) ;
return insertUncompressedAtByOuterInner ( outer , inner , dst ) ;
2023-01-07 22:09:42 +00:00
}
2013-02-28 19:31:03 +01:00
2023-01-07 22:09:42 +00:00
template < typename Scalar_ , int Options_ , typename StorageIndex_ >
EIGEN_DEPRECATED EIGEN_DONT_INLINE typename SparseMatrix < Scalar_ , Options_ , StorageIndex_ > : : Scalar &
SparseMatrix < Scalar_ , Options_ , StorageIndex_ > : : insertUncompressed ( Index row , Index col ) {
eigen_assert ( ! isCompressed ( ) ) ;
Index outer = IsRowMajor ? row : col ;
Index inner = IsRowMajor ? col : row ;
Index start = outerIndexPtr ( ) [ outer ] ;
Index end = start + innerNonZeroPtr ( ) [ outer ] ;
Index dst = data ( ) . searchLowerIndex ( start , end , inner ) ;
eigen_assert ( ( dst = = end | | data ( ) . index ( dst ) ! = inner ) & &
" you cannot insert an element that already exists, you must call coeffRef to this end " ) ;
return insertUncompressedAtByOuterInner ( outer , inner , dst ) ;
2013-02-28 19:31:03 +01:00
}
2023-01-07 22:09:42 +00:00
template < typename Scalar_ , int Options_ , typename StorageIndex_ >
EIGEN_DEPRECATED EIGEN_DONT_INLINE typename SparseMatrix < Scalar_ , Options_ , StorageIndex_ > : : Scalar &
SparseMatrix < Scalar_ , Options_ , StorageIndex_ > : : insertCompressed ( Index row , Index col ) {
2013-02-28 19:31:03 +01:00
eigen_assert ( isCompressed ( ) ) ;
2023-01-07 22:09:42 +00:00
Index outer = IsRowMajor ? row : col ;
Index inner = IsRowMajor ? col : row ;
Index start = outerIndexPtr ( ) [ outer ] ;
Index end = outerIndexPtr ( ) [ outer + 1 ] ;
Index dst = data ( ) . searchLowerIndex ( start , end , inner ) ;
eigen_assert ( ( dst = = end | | data ( ) . index ( dst ) ! = inner ) & &
" you cannot insert an element that already exists, you must call coeffRef to this end " ) ;
return insertCompressedAtByOuterInner ( outer , inner , dst ) ;
}
2013-02-28 19:31:03 +01:00
2023-01-07 22:09:42 +00:00
template < typename Scalar_ , int Options_ , typename StorageIndex_ >
EIGEN_STRONG_INLINE void SparseMatrix < Scalar_ , Options_ , StorageIndex_ > : : checkAllocatedSpaceAndMaybeExpand ( ) {
// if there is no capacity for a single insertion, double the capacity
if ( data ( ) . allocatedSize ( ) < = data ( ) . size ( ) ) {
// increase capacity by a mininum of 32
Index minReserve = 32 ;
Index reserveSize = numext : : maxi ( minReserve , data ( ) . allocatedSize ( ) ) ;
data ( ) . reserve ( reserveSize ) ;
2013-02-28 19:31:03 +01:00
}
2023-01-07 22:09:42 +00:00
}
2013-02-28 19:31:03 +01:00
2023-01-07 22:09:42 +00:00
template < typename Scalar_ , int Options_ , typename StorageIndex_ >
typename SparseMatrix < Scalar_ , Options_ , StorageIndex_ > : : Scalar &
SparseMatrix < Scalar_ , Options_ , StorageIndex_ > : : insertCompressedAtByOuterInner ( Index outer , Index inner , Index dst ) {
eigen_assert ( isCompressed ( ) ) ;
// compressed insertion always requires expanding the buffer
checkAllocatedSpaceAndMaybeExpand ( ) ;
data ( ) . resize ( data ( ) . size ( ) + 1 ) ;
Index chunkSize = outerIndexPtr ( ) [ outerSize ( ) ] - dst ;
// shift the existing data to the right if necessary
if ( chunkSize > 0 ) data ( ) . moveChunk ( dst , dst + 1 , chunkSize ) ;
// update nonzero counts
2023-01-11 06:24:49 +00:00
typename IndexVector : : AlignedMapType outerIndexMap ( outerIndexPtr ( ) , outerSize ( ) + 1 ) ;
outerIndexMap . segment ( outer + 1 , outerSize ( ) - outer ) . array ( ) + = 1 ;
2023-01-07 22:09:42 +00:00
// initialize the coefficient
data ( ) . index ( dst ) = StorageIndex ( inner ) ;
// return a reference to the coefficient
return data ( ) . value ( dst ) = Scalar ( 0 ) ;
}
2013-02-28 19:31:03 +01:00
2023-01-07 22:09:42 +00:00
template < typename Scalar_ , int Options_ , typename StorageIndex_ >
typename SparseMatrix < Scalar_ , Options_ , StorageIndex_ > : : Scalar &
SparseMatrix < Scalar_ , Options_ , StorageIndex_ > : : insertUncompressedAtByOuterInner ( Index outer , Index inner , Index dst ) {
eigen_assert ( ! isCompressed ( ) ) ;
// find nearest outer vector to the right with capacity (if any) to minimize copy size
Index target = outer ;
for ( ; target < outerSize ( ) ; target + + ) {
Index start = outerIndexPtr ( ) [ target ] ;
Index end = start + innerNonZeroPtr ( ) [ target ] ;
Index capacity = outerIndexPtr ( ) [ target + 1 ] - end ;
if ( capacity > 0 ) {
// `target` has room for interior insertion
Index chunkSize = end - dst ;
// shift the existing data to the right if necessary
2023-01-11 06:24:49 +00:00
if ( chunkSize > 0 ) data ( ) . moveChunk ( dst , dst + 1 , chunkSize ) ;
2023-01-07 22:09:42 +00:00
break ;
2013-02-28 19:31:03 +01:00
}
}
2023-01-07 22:09:42 +00:00
if ( target = = outerSize ( ) ) {
2023-01-11 06:24:49 +00:00
// no room for interior insertion (to the right of `outer`)
target = outer ;
Index dst_offset = dst - outerIndexPtr ( ) [ target ] ;
Index totalCapacity = data ( ) . allocatedSize ( ) - data ( ) . size ( ) ;
eigen_assert ( totalCapacity > = 0 ) ;
if ( totalCapacity = = 0 ) {
// there is no room left. we must reallocate. reserve space in each vector
constexpr StorageIndex kReserveSizePerVector ( 2 ) ;
reserveInnerVectors ( IndexVector : : Constant ( outerSize ( ) , kReserveSizePerVector ) ) ;
} else {
// dont reallocate, but re-distribute the remaining capacity to the right of `outer`
// each vector in the range [outer,outerSize) will receive totalCapacity / (outerSize - outer) nonzero
// reservations each vector in the range [outer,remainder) will receive an additional nonzero reservation where
// remainder = totalCapacity % (outerSize - outer)
typedef internal : : sparse_reserve_op < StorageIndex > ReserveSizesOp ;
typedef CwiseNullaryOp < ReserveSizesOp , IndexVector > ReserveSizesXpr ;
ReserveSizesXpr reserveSizesXpr ( outerSize ( ) , 1 , ReserveSizesOp ( target , outerSize ( ) , totalCapacity ) ) ;
eigen_assert ( reserveSizesXpr . sum ( ) = = totalCapacity ) ;
reserveInnerVectors ( reserveSizesXpr ) ;
}
Index start = outerIndexPtr ( ) [ target ] ;
Index end = start + innerNonZeroPtr ( ) [ target ] ;
dst = start + dst_offset ;
Index chunkSize = end - dst ;
2023-01-07 22:09:42 +00:00
if ( chunkSize > 0 ) data ( ) . moveChunk ( dst , dst + 1 , chunkSize ) ;
2013-02-28 19:31:03 +01:00
}
2023-01-07 22:09:42 +00:00
// update nonzero counts
innerNonZeroPtr ( ) [ outer ] + + ;
2023-01-11 06:24:49 +00:00
typename IndexVector : : AlignedMapType outerIndexMap ( outerIndexPtr ( ) , outerSize ( ) + 1 ) ;
outerIndexMap . segment ( outer + 1 , target - outer ) . array ( ) + = 1 ;
2023-01-07 22:09:42 +00:00
// initialize the coefficient
data ( ) . index ( dst ) = StorageIndex ( inner ) ;
// return a reference to the coefficient
return data ( ) . value ( dst ) = Scalar ( 0 ) ;
2013-02-28 19:31:03 +01:00
}
2014-06-20 15:42:13 +02:00
namespace internal {
2023-01-07 22:09:42 +00:00
template < typename Scalar_ , int Options_ , typename StorageIndex_ >
struct evaluator < SparseMatrix < Scalar_ , Options_ , StorageIndex_ > >
: evaluator < SparseCompressedBase < SparseMatrix < Scalar_ , Options_ , StorageIndex_ > > > {
typedef evaluator < SparseCompressedBase < SparseMatrix < Scalar_ , Options_ , StorageIndex_ > > > Base ;
typedef SparseMatrix < Scalar_ , Options_ , StorageIndex_ > SparseMatrixType ;
evaluator ( ) : Base ( ) { }
explicit evaluator ( const SparseMatrixType & mat ) : Base ( mat ) { }
} ;
2014-06-20 15:42:13 +02:00
}
2022-11-21 19:43:07 +00:00
// Specialization for SparseMatrix.
2022-11-30 18:16:47 +00:00
// Serializes [rows, cols, isCompressed, outerSize, innerBufferSize,
// innerNonZeros, outerIndices, innerIndices, values].
2022-11-21 19:43:07 +00:00
template < typename Scalar , int Options , typename StorageIndex >
class Serializer < SparseMatrix < Scalar , Options , StorageIndex > , void > {
public :
typedef SparseMatrix < Scalar , Options , StorageIndex > SparseMat ;
struct Header {
typename SparseMat : : Index rows ;
typename SparseMat : : Index cols ;
bool compressed ;
Index outer_size ;
2022-11-30 18:16:47 +00:00
Index inner_buffer_size ;
2022-11-21 19:43:07 +00:00
} ;
EIGEN_DEVICE_FUNC size_t size ( const SparseMat & value ) const {
// innerNonZeros.
2022-11-30 18:16:47 +00:00
std : : size_t num_storage_indices = value . isCompressed ( ) ? 0 : value . outerSize ( ) ;
2022-11-21 19:43:07 +00:00
// Outer indices.
num_storage_indices + = value . outerSize ( ) + 1 ;
// Inner indices.
2022-11-30 18:16:47 +00:00
const StorageIndex inner_buffer_size = value . outerIndexPtr ( ) [ value . outerSize ( ) ] ;
num_storage_indices + = inner_buffer_size ;
2022-11-21 19:43:07 +00:00
// Values.
2022-11-30 18:16:47 +00:00
std : : size_t num_values = inner_buffer_size ;
2022-11-21 19:43:07 +00:00
return sizeof ( Header ) + sizeof ( Scalar ) * num_values +
sizeof ( StorageIndex ) * num_storage_indices ;
}
EIGEN_DEVICE_FUNC uint8_t * serialize ( uint8_t * dest , uint8_t * end ,
const SparseMat & value ) {
if ( EIGEN_PREDICT_FALSE ( dest = = nullptr ) ) return nullptr ;
if ( EIGEN_PREDICT_FALSE ( dest + size ( value ) > end ) ) return nullptr ;
const size_t header_bytes = sizeof ( Header ) ;
Header header = { value . rows ( ) , value . cols ( ) , value . isCompressed ( ) ,
2022-11-30 18:16:47 +00:00
value . outerSize ( ) , value . outerIndexPtr ( ) [ value . outerSize ( ) ] } ;
2022-11-21 19:43:07 +00:00
EIGEN_USING_STD ( memcpy )
memcpy ( dest , & header , header_bytes ) ;
dest + = header_bytes ;
// innerNonZeros.
if ( ! header . compressed ) {
2022-12-16 21:50:00 +00:00
std : : size_t data_bytes = sizeof ( StorageIndex ) * header . outer_size ;
2022-11-21 19:43:07 +00:00
memcpy ( dest , value . innerNonZeroPtr ( ) , data_bytes ) ;
dest + = data_bytes ;
}
// Outer indices.
2022-11-30 18:16:47 +00:00
std : : size_t data_bytes = sizeof ( StorageIndex ) * ( header . outer_size + 1 ) ;
2022-11-21 19:43:07 +00:00
memcpy ( dest , value . outerIndexPtr ( ) , data_bytes ) ;
dest + = data_bytes ;
// Inner indices.
2022-11-30 18:16:47 +00:00
data_bytes = sizeof ( StorageIndex ) * header . inner_buffer_size ;
2022-11-21 19:43:07 +00:00
memcpy ( dest , value . innerIndexPtr ( ) , data_bytes ) ;
dest + = data_bytes ;
// Values.
2022-11-30 18:16:47 +00:00
data_bytes = sizeof ( Scalar ) * header . inner_buffer_size ;
2022-11-21 19:43:07 +00:00
memcpy ( dest , value . valuePtr ( ) , data_bytes ) ;
dest + = data_bytes ;
return dest ;
}
EIGEN_DEVICE_FUNC const uint8_t * deserialize ( const uint8_t * src ,
const uint8_t * end ,
SparseMat & value ) const {
if ( EIGEN_PREDICT_FALSE ( src = = nullptr ) ) return nullptr ;
if ( EIGEN_PREDICT_FALSE ( src + sizeof ( Header ) > end ) ) return nullptr ;
const size_t header_bytes = sizeof ( Header ) ;
Header header ;
EIGEN_USING_STD ( memcpy )
memcpy ( & header , src , header_bytes ) ;
src + = header_bytes ;
value . setZero ( ) ;
value . resize ( header . rows , header . cols ) ;
if ( header . compressed ) {
value . makeCompressed ( ) ;
} else {
value . uncompress ( ) ;
2022-11-30 18:16:47 +00:00
}
// Adjust value ptr size.
value . data ( ) . resize ( header . inner_buffer_size ) ;
// Initialize compressed state and inner non-zeros.
if ( ! header . compressed ) {
// Inner non-zero counts.
std : : size_t data_bytes = sizeof ( StorageIndex ) * header . outer_size ;
if ( EIGEN_PREDICT_FALSE ( src + data_bytes > end ) ) return nullptr ;
memcpy ( value . innerNonZeroPtr ( ) , src , data_bytes ) ;
src + = data_bytes ;
2022-11-21 19:43:07 +00:00
}
// Outer indices.
2022-11-30 18:16:47 +00:00
std : : size_t data_bytes = sizeof ( StorageIndex ) * ( header . outer_size + 1 ) ;
if ( EIGEN_PREDICT_FALSE ( src + data_bytes > end ) ) return nullptr ;
2022-11-21 19:43:07 +00:00
memcpy ( value . outerIndexPtr ( ) , src , data_bytes ) ;
src + = data_bytes ;
// Inner indices.
2022-11-30 18:16:47 +00:00
data_bytes = sizeof ( StorageIndex ) * header . inner_buffer_size ;
2022-11-21 19:43:07 +00:00
if ( EIGEN_PREDICT_FALSE ( src + data_bytes > end ) ) return nullptr ;
memcpy ( value . innerIndexPtr ( ) , src , data_bytes ) ;
src + = data_bytes ;
// Values.
2022-11-30 18:16:47 +00:00
data_bytes = sizeof ( Scalar ) * header . inner_buffer_size ;
2022-11-21 19:43:07 +00:00
if ( EIGEN_PREDICT_FALSE ( src + data_bytes > end ) ) return nullptr ;
memcpy ( value . valuePtr ( ) , src , data_bytes ) ;
src + = data_bytes ;
return src ;
}
} ;
2012-04-15 11:06:28 +01:00
} // end namespace Eigen
2008-06-23 13:25:22 +00:00
# endif // EIGEN_SPARSEMATRIX_H