mirror of
https://gitlab.com/libeigen/eigen.git
synced 2025-07-23 05:14:26 +08:00
302 lines
9.8 KiB
C++
302 lines
9.8 KiB
C++
// This file is part of Eigen, a lightweight C++ template library
|
|
// for linear algebra.
|
|
//
|
|
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
|
|
// Copyright (C) 2012 Gael Guennebaud <gael.guennebaud@inria.fr>
|
|
//
|
|
// 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/.
|
|
|
|
#ifndef EIGEN_SPARSELU_SUPERNODAL_MATRIX_H
|
|
#define EIGEN_SPARSELU_SUPERNODAL_MATRIX_H
|
|
|
|
namespace Eigen {
|
|
namespace internal {
|
|
|
|
/** \ingroup SparseLU_Module
|
|
* \brief a class to manipulate the L supernodal factor from the SparseLU factorization
|
|
*
|
|
* This class contain the data to easily store
|
|
* and manipulate the supernodes during the factorization and solution phase of Sparse LU.
|
|
* Only the lower triangular matrix has supernodes.
|
|
*
|
|
* NOTE : This class corresponds to the SCformat structure in SuperLU
|
|
*
|
|
*/
|
|
/* TODO
|
|
* InnerIterator as for sparsematrix
|
|
* SuperInnerIterator to iterate through all supernodes
|
|
* Function for triangular solve
|
|
*/
|
|
template <typename _Scalar, typename _StorageIndex>
|
|
class MappedSuperNodalMatrix
|
|
{
|
|
public:
|
|
typedef _Scalar Scalar;
|
|
typedef _StorageIndex StorageIndex;
|
|
typedef Matrix<StorageIndex,Dynamic,1> IndexVector;
|
|
typedef Matrix<Scalar,Dynamic,1> ScalarVector;
|
|
public:
|
|
MappedSuperNodalMatrix()
|
|
{
|
|
|
|
}
|
|
MappedSuperNodalMatrix(Index m, Index n, ScalarVector& nzval, IndexVector& nzval_colptr, IndexVector& rowind,
|
|
IndexVector& rowind_colptr, IndexVector& col_to_sup, IndexVector& sup_to_col )
|
|
{
|
|
setInfos(m, n, nzval, nzval_colptr, rowind, rowind_colptr, col_to_sup, sup_to_col);
|
|
}
|
|
|
|
~MappedSuperNodalMatrix()
|
|
{
|
|
|
|
}
|
|
/**
|
|
* Set appropriate pointers for the lower triangular supernodal matrix
|
|
* These infos are available at the end of the numerical factorization
|
|
* FIXME This class will be modified such that it can be use in the course
|
|
* of the factorization.
|
|
*/
|
|
void setInfos(Index m, Index n, ScalarVector& nzval, IndexVector& nzval_colptr, IndexVector& rowind,
|
|
IndexVector& rowind_colptr, IndexVector& col_to_sup, IndexVector& sup_to_col )
|
|
{
|
|
m_row = m;
|
|
m_col = n;
|
|
m_nzval = nzval.data();
|
|
m_nzval_colptr = nzval_colptr.data();
|
|
m_rowind = rowind.data();
|
|
m_rowind_colptr = rowind_colptr.data();
|
|
m_nsuper = col_to_sup(n);
|
|
m_col_to_sup = col_to_sup.data();
|
|
m_sup_to_col = sup_to_col.data();
|
|
}
|
|
|
|
/**
|
|
* Number of rows
|
|
*/
|
|
Index rows() { return m_row; }
|
|
|
|
/**
|
|
* Number of columns
|
|
*/
|
|
Index cols() { return m_col; }
|
|
|
|
/**
|
|
* Return the array of nonzero values packed by column
|
|
*
|
|
* The size is nnz
|
|
*/
|
|
Scalar* valuePtr() { return m_nzval; }
|
|
|
|
const Scalar* valuePtr() const
|
|
{
|
|
return m_nzval;
|
|
}
|
|
/**
|
|
* Return the pointers to the beginning of each column in \ref valuePtr()
|
|
*/
|
|
StorageIndex* colIndexPtr()
|
|
{
|
|
return m_nzval_colptr;
|
|
}
|
|
|
|
const StorageIndex* colIndexPtr() const
|
|
{
|
|
return m_nzval_colptr;
|
|
}
|
|
|
|
/**
|
|
* Return the array of compressed row indices of all supernodes
|
|
*/
|
|
StorageIndex* rowIndex() { return m_rowind; }
|
|
|
|
const StorageIndex* rowIndex() const
|
|
{
|
|
return m_rowind;
|
|
}
|
|
|
|
/**
|
|
* Return the location in \em rowvaluePtr() which starts each column
|
|
*/
|
|
StorageIndex* rowIndexPtr() { return m_rowind_colptr; }
|
|
|
|
const StorageIndex* rowIndexPtr() const
|
|
{
|
|
return m_rowind_colptr;
|
|
}
|
|
|
|
/**
|
|
* Return the array of column-to-supernode mapping
|
|
*/
|
|
StorageIndex* colToSup() { return m_col_to_sup; }
|
|
|
|
const StorageIndex* colToSup() const
|
|
{
|
|
return m_col_to_sup;
|
|
}
|
|
/**
|
|
* Return the array of supernode-to-column mapping
|
|
*/
|
|
StorageIndex* supToCol() { return m_sup_to_col; }
|
|
|
|
const StorageIndex* supToCol() const
|
|
{
|
|
return m_sup_to_col;
|
|
}
|
|
|
|
/**
|
|
* Return the number of supernodes
|
|
*/
|
|
Index nsuper() const
|
|
{
|
|
return m_nsuper;
|
|
}
|
|
|
|
class InnerIterator;
|
|
template<typename Dest>
|
|
void solveInPlace( MatrixBase<Dest>&X) const;
|
|
|
|
|
|
|
|
|
|
protected:
|
|
Index m_row; // Number of rows
|
|
Index m_col; // Number of columns
|
|
Index m_nsuper; // Number of supernodes
|
|
Scalar* m_nzval; //array of nonzero values packed by column
|
|
StorageIndex* m_nzval_colptr; //nzval_colptr[j] Stores the location in nzval[] which starts column j
|
|
StorageIndex* m_rowind; // Array of compressed row indices of rectangular supernodes
|
|
StorageIndex* m_rowind_colptr; //rowind_colptr[j] stores the location in rowind[] which starts column j
|
|
StorageIndex* m_col_to_sup; // col_to_sup[j] is the supernode number to which column j belongs
|
|
StorageIndex* m_sup_to_col; //sup_to_col[s] points to the starting column of the s-th supernode
|
|
|
|
private :
|
|
};
|
|
|
|
/**
|
|
* \brief InnerIterator class to iterate over nonzero values of the current column in the supernodal matrix L
|
|
*
|
|
*/
|
|
template<typename Scalar, typename StorageIndex>
|
|
class MappedSuperNodalMatrix<Scalar,StorageIndex>::InnerIterator
|
|
{
|
|
public:
|
|
InnerIterator(const MappedSuperNodalMatrix& mat, Index outer)
|
|
: m_matrix(mat),
|
|
m_outer(outer),
|
|
m_supno(mat.colToSup()[outer]),
|
|
m_idval(mat.colIndexPtr()[outer]),
|
|
m_startidval(m_idval),
|
|
m_endidval(mat.colIndexPtr()[outer+1]),
|
|
m_idrow(mat.rowIndexPtr()[mat.supToCol()[mat.colToSup()[outer]]]),
|
|
m_endidrow(mat.rowIndexPtr()[mat.supToCol()[mat.colToSup()[outer]]+1])
|
|
{}
|
|
inline InnerIterator& operator++()
|
|
{
|
|
m_idval++;
|
|
m_idrow++;
|
|
return *this;
|
|
}
|
|
inline Scalar value() const { return m_matrix.valuePtr()[m_idval]; }
|
|
|
|
inline Scalar& valueRef() { return const_cast<Scalar&>(m_matrix.valuePtr()[m_idval]); }
|
|
|
|
inline Index index() const { return m_matrix.rowIndex()[m_idrow]; }
|
|
inline Index row() const { return index(); }
|
|
inline Index col() const { return m_outer; }
|
|
|
|
inline Index supIndex() const { return m_supno; }
|
|
|
|
inline operator bool() const
|
|
{
|
|
return ( (m_idval < m_endidval) && (m_idval >= m_startidval)
|
|
&& (m_idrow < m_endidrow) );
|
|
}
|
|
|
|
protected:
|
|
const MappedSuperNodalMatrix& m_matrix; // Supernodal lower triangular matrix
|
|
const Index m_outer; // Current column
|
|
const Index m_supno; // Current SuperNode number
|
|
Index m_idval; // Index to browse the values in the current column
|
|
const Index m_startidval; // Start of the column value
|
|
const Index m_endidval; // End of the column value
|
|
Index m_idrow; // Index to browse the row indices
|
|
Index m_endidrow; // End index of row indices of the current column
|
|
};
|
|
|
|
/**
|
|
* \brief Solve with the supernode triangular matrix
|
|
*
|
|
*/
|
|
template<typename Scalar, typename Index_>
|
|
template<typename Dest>
|
|
void MappedSuperNodalMatrix<Scalar,Index_>::solveInPlace( MatrixBase<Dest>&X) const
|
|
{
|
|
/* Explicit type conversion as the Index type of MatrixBase<Dest> may be wider than Index */
|
|
// eigen_assert(X.rows() <= NumTraits<Index>::highest());
|
|
// eigen_assert(X.cols() <= NumTraits<Index>::highest());
|
|
Index n = int(X.rows());
|
|
Index nrhs = Index(X.cols());
|
|
const Scalar * Lval = valuePtr(); // Nonzero values
|
|
Matrix<Scalar,Dynamic,Dest::ColsAtCompileTime, ColMajor> work(n, nrhs); // working vector
|
|
work.setZero();
|
|
for (Index k = 0; k <= nsuper(); k ++)
|
|
{
|
|
Index fsupc = supToCol()[k]; // First column of the current supernode
|
|
Index istart = rowIndexPtr()[fsupc]; // Pointer index to the subscript of the current column
|
|
Index nsupr = rowIndexPtr()[fsupc+1] - istart; // Number of rows in the current supernode
|
|
Index nsupc = supToCol()[k+1] - fsupc; // Number of columns in the current supernode
|
|
Index nrow = nsupr - nsupc; // Number of rows in the non-diagonal part of the supernode
|
|
Index irow; //Current index row
|
|
|
|
if (nsupc == 1 )
|
|
{
|
|
for (Index j = 0; j < nrhs; j++)
|
|
{
|
|
InnerIterator it(*this, fsupc);
|
|
++it; // Skip the diagonal element
|
|
for (; it; ++it)
|
|
{
|
|
irow = it.row();
|
|
X(irow, j) -= X(fsupc, j) * it.value();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// The supernode has more than one column
|
|
Index luptr = colIndexPtr()[fsupc];
|
|
Index lda = colIndexPtr()[fsupc+1] - luptr;
|
|
|
|
// Triangular solve
|
|
Map<const Matrix<Scalar,Dynamic,Dynamic, ColMajor>, 0, OuterStride<> > A( &(Lval[luptr]), nsupc, nsupc, OuterStride<>(lda) );
|
|
Map< Matrix<Scalar,Dynamic,Dest::ColsAtCompileTime, ColMajor>, 0, OuterStride<> > U (&(X(fsupc,0)), nsupc, nrhs, OuterStride<>(n) );
|
|
U = A.template triangularView<UnitLower>().solve(U);
|
|
|
|
// Matrix-vector product
|
|
new (&A) Map<const Matrix<Scalar,Dynamic,Dynamic, ColMajor>, 0, OuterStride<> > ( &(Lval[luptr+nsupc]), nrow, nsupc, OuterStride<>(lda) );
|
|
work.topRows(nrow).noalias() = A * U;
|
|
|
|
//Begin Scatter
|
|
for (Index j = 0; j < nrhs; j++)
|
|
{
|
|
Index iptr = istart + nsupc;
|
|
for (Index i = 0; i < nrow; i++)
|
|
{
|
|
irow = rowIndex()[iptr];
|
|
X(irow, j) -= work(i, j); // Scatter operation
|
|
work(i, j) = Scalar(0);
|
|
iptr++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} // end namespace internal
|
|
|
|
} // end namespace Eigen
|
|
|
|
#endif // EIGEN_SPARSELU_MATRIX_H
|