2012-05-25 18:17:57 +02:00
// 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>
//
2012-08-01 11:38:32 +02: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/.
2012-05-25 18:17:57 +02:00
2012-08-03 13:05:27 +02:00
# ifndef EIGEN_SPARSE_LU_H
# define EIGEN_SPARSE_LU_H
2012-05-25 18:17:57 +02:00
2012-06-01 18:44:51 +02:00
namespace Eigen {
2012-06-12 18:19:59 +02:00
// Data structure needed by all routines
2012-06-13 18:26:05 +02:00
# include "SparseLU_Structs.h"
# include "SparseLU_Matrix.h"
2012-05-25 18:17:57 +02:00
2012-09-25 09:53:40 +02:00
// Base structure containing all the factorization routines
# include "SparseLUBase.h"
2012-06-11 18:52:26 +02:00
/**
* \ ingroup SparseLU_Module
* \ brief Sparse supernodal LU factorization for general matrices
*
2012-09-25 11:48:18 +02:00
* This class implements the supernodal LU factorization for general matrices .
* It uses the main techniques from the sequential SuperLU package
* ( http : //crd-legacy.lbl.gov/~xiaoye/SuperLU/). It handles transparently real
* and complex arithmetics with single and double precision , depending on the
* scalar type of your input matrix .
* The code has been optimized to provide BLAS - 3 operations during supernode - panel updates .
* It benefits directly from the built - in high - performant Eigen BLAS routines .
* Moreover , when the size of a supernode is very small , the BLAS calls are avoided to
* enable a better optimization from the compiler . For best performance ,
* you should compile it with NDEBUG flag to avoid the numerous bounds checking on vectors .
*
* An important parameter of this class is the ordering method . It is used to reorder the columns
* ( and eventually the rows ) of the matrix to reduce the number of new elements that are created during
* numerical factorization . The cheapest method available is COLAMD .
* See \ link Ordering_Modules the Ordering module \ endlink for the list of
* built - in and external ordering methods .
*
* Simple example with key steps
* \ code
* VectorXd x ( n ) , b ( n ) ;
* SparseMatrix < double , ColMajor > A ;
* SparseLU < SparseMatrix < scalar , ColMajor > , COLAMDOrdering < int > > solver ;
* // fill A and b;
* // Compute the ordering permutation vector from the structural pattern of A
* solver . analyzePattern ( A ) ;
* // Compute the numerical factorization
* solver . factorize ( A ) ;
* //Use the factors to solve the linear system
* x = solver . solve ( b ) ;
* \ endcode
*
* \ WARNING The input matrix A should be in a \ b compressed and \ b column - major form .
* Otherwise an expensive copy will be made . You can call the inexpensive makeCompressed ( ) to get a compressed matrix .
*
* \ NOTE Unlike the initial SuperLU implementation , there is no step to equilibrate the matrix .
* For badly scaled matrices , this step can be useful to reduce the pivoting during factorization .
2012-09-25 11:55:33 +02:00
* If this is the case for your matrices , you can try the basic scaling method at
* " unsupported/Eigen/src/IterativeSolvers/Scaling.h "
2012-06-11 18:52:26 +02:00
*
* \ tparam _MatrixType The type of the sparse matrix . It must be a column - major SparseMatrix < >
2012-09-25 11:48:18 +02:00
* \ tparam _OrderingType The ordering method to use , either AMD , COLAMD or METIS
*
*
* \ sa \ ref TutorialSparseDirectSolvers
* \ sa \ ref Ordering_Modules
2012-06-11 18:52:26 +02:00
*/
2012-06-13 18:26:05 +02:00
template < typename _MatrixType , typename _OrderingType >
2012-05-25 18:17:57 +02:00
class SparseLU
{
public :
typedef _MatrixType MatrixType ;
2012-06-13 18:26:05 +02:00
typedef _OrderingType OrderingType ;
2012-05-25 18:17:57 +02:00
typedef typename MatrixType : : Scalar Scalar ;
2012-06-13 18:26:05 +02:00
typedef typename MatrixType : : RealScalar RealScalar ;
2012-05-25 18:17:57 +02:00
typedef typename MatrixType : : Index Index ;
typedef SparseMatrix < Scalar , ColMajor , Index > NCMatrix ;
typedef SuperNodalMatrix < Scalar , Index > SCMatrix ;
2012-06-07 19:06:22 +02:00
typedef Matrix < Scalar , Dynamic , 1 > ScalarVector ;
typedef Matrix < Index , Dynamic , 1 > IndexVector ;
2012-05-25 18:17:57 +02:00
typedef PermutationMatrix < Dynamic , Dynamic , Index > PermutationType ;
2012-09-25 09:53:40 +02:00
2012-05-25 18:17:57 +02:00
public :
2012-06-14 18:45:04 +02:00
SparseLU ( ) : m_isInitialized ( true ) , m_Ustore ( 0 , 0 , 0 , 0 , 0 , 0 ) , m_symmetricmode ( false ) , m_diagpivotthresh ( 1.0 )
2012-05-25 18:17:57 +02:00
{
initperfvalues ( ) ;
}
2012-06-14 18:45:04 +02:00
SparseLU ( const MatrixType & matrix ) : m_isInitialized ( true ) , m_Ustore ( 0 , 0 , 0 , 0 , 0 , 0 ) , m_symmetricmode ( false ) , m_diagpivotthresh ( 1.0 )
2012-05-25 18:17:57 +02:00
{
2012-06-14 18:45:04 +02:00
initperfvalues ( ) ;
2012-05-25 18:17:57 +02:00
compute ( matrix ) ;
}
~ SparseLU ( )
{
2012-06-11 18:52:26 +02:00
// Free all explicit dynamic pointers
2012-05-25 18:17:57 +02:00
}
void analyzePattern ( const MatrixType & matrix ) ;
void factorize ( const MatrixType & matrix ) ;
2012-09-25 09:53:40 +02:00
void simplicialfactorize ( const MatrixType & matrix ) ;
2012-06-11 18:52:26 +02:00
/**
* Compute the symbolic and numeric factorization of the input sparse matrix .
* The input matrix should be in column - major storage .
*/
void compute ( const MatrixType & matrix )
{
// Analyze
analyzePattern ( matrix ) ;
//Factorize
factorize ( matrix ) ;
2012-06-13 18:26:05 +02:00
}
2012-05-25 18:17:57 +02:00
2012-06-13 18:26:05 +02:00
inline Index rows ( ) const { return m_mat . rows ( ) ; }
inline Index cols ( ) const { return m_mat . cols ( ) ; }
2012-05-25 18:17:57 +02:00
/** Indicate that the pattern of the input matrix is symmetric */
void isSymmetric ( bool sym )
{
m_symmetricmode = sym ;
}
/** Set the threshold used for a diagonal entry to be an acceptable pivot. */
void diagPivotThresh ( RealScalar thresh )
{
m_diagpivotthresh = thresh ;
}
2012-07-18 16:59:00 +02:00
/** Return the number of nonzero elements in the L factor */
int nnzL ( )
{
if ( m_factorizationIsOk )
return m_nnzL ;
else
{
std : : cerr < < " Numerical factorization should be done before \n " ;
return 0 ;
}
}
/** Return the number of nonzero elements in the U factor */
int nnzU ( )
{
if ( m_factorizationIsOk )
return m_nnzU ;
else
{
std : : cerr < < " Numerical factorization should be done before \n " ;
return 0 ;
}
}
2012-06-13 18:26:05 +02:00
/** \returns the solution X of \f$ A X = B \f$ using the current decomposition of A.
2012-06-08 17:23:38 +02:00
*
* \ sa compute ( )
*/
2012-08-03 13:05:27 +02:00
template < typename Rhs >
inline const internal : : solve_retval < SparseLU , Rhs > solve ( const MatrixBase < Rhs > & B ) const
{
eigen_assert ( m_factorizationIsOk & & " SparseLU is not initialized. " ) ;
eigen_assert ( rows ( ) = = B . rows ( )
& & " SparseLU::solve(): invalid number of rows of the right hand side matrix B " ) ;
return internal : : solve_retval < SparseLU , Rhs > ( * this , B . derived ( ) ) ;
}
2012-06-13 18:26:05 +02:00
2012-06-14 18:45:04 +02:00
/** \brief Reports whether previous computation was successful.
*
* \ returns \ c Success if computation was succesful ,
* \ c NumericalIssue if the PaStiX reports a problem
* \ c InvalidInput if the input matrix is invalid
*
* \ sa iparm ( )
*/
ComputationInfo info ( ) const
{
eigen_assert ( m_isInitialized & & " Decomposition is not initialized. " ) ;
return m_info ;
}
2012-06-13 18:26:05 +02:00
template < typename Rhs , typename Dest >
2012-06-15 17:23:54 +02:00
bool _solve ( const MatrixBase < Rhs > & B , MatrixBase < Dest > & _X ) const
{
Dest & X ( _X . derived ( ) ) ;
eigen_assert ( m_factorizationIsOk & & " The matrix should be factorized first " ) ;
2012-06-13 18:26:05 +02:00
EIGEN_STATIC_ASSERT ( ( Dest : : Flags & RowMajorBit ) = = 0 ,
THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES ) ;
int nrhs = B . cols ( ) ;
2012-07-13 17:32:25 +02:00
Index n = B . rows ( ) ;
2012-06-13 18:26:05 +02:00
2012-07-13 17:32:25 +02:00
// Permute the right hand side to form X = Pr*B
// on return, X is overwritten by the computed solution
X . resize ( n , nrhs ) ;
2012-08-03 13:05:27 +02:00
for ( int j = 0 ; j < nrhs ; + + j )
X . col ( j ) = m_perm_r * B . col ( j ) ;
2012-06-13 18:26:05 +02:00
2012-08-07 17:10:42 +02:00
//Forward substitution with L
m_Lstore . solveInPlace ( X ) ;
2012-06-13 18:26:05 +02:00
2012-08-07 17:10:42 +02:00
// Backward solve with U
for ( int k = m_Lstore . nsuper ( ) ; k > = 0 ; k - - )
2012-06-13 18:26:05 +02:00
{
2012-08-07 17:10:42 +02:00
Index fsupc = m_Lstore . supToCol ( ) [ k ] ;
Index istart = m_Lstore . rowIndexPtr ( ) [ fsupc ] ;
Index nsupr = m_Lstore . rowIndexPtr ( ) [ fsupc + 1 ] - istart ;
Index nsupc = m_Lstore . supToCol ( ) [ k + 1 ] - fsupc ;
Index luptr = m_Lstore . colIndexPtr ( ) [ fsupc ] ;
2012-06-13 18:26:05 +02:00
if ( nsupc = = 1 )
{
2012-08-07 17:10:42 +02:00
for ( int j = 0 ; j < nrhs ; j + + )
2012-06-13 18:26:05 +02:00
{
2012-08-07 17:10:42 +02:00
X ( fsupc , j ) / = m_Lstore . valuePtr ( ) [ luptr ] ;
2012-06-13 18:26:05 +02:00
}
}
else
{
2012-08-07 17:10:42 +02:00
Map < const Matrix < Scalar , Dynamic , Dynamic > , 0 , OuterStride < > > A ( & ( m_Lstore . valuePtr ( ) [ luptr ] ) , nsupc , nsupc , OuterStride < > ( nsupr ) ) ;
Map < Matrix < Scalar , Dynamic , Dynamic > , 0 , OuterStride < > > U ( & ( X ( fsupc , 0 ) ) , nsupc , nrhs , OuterStride < > ( n ) ) ;
2012-06-13 18:26:05 +02:00
U = A . template triangularView < Upper > ( ) . solve ( U ) ;
}
2012-08-07 17:10:42 +02:00
for ( int j = 0 ; j < nrhs ; + + j )
2012-06-13 18:26:05 +02:00
{
2012-08-07 17:10:42 +02:00
for ( int jcol = fsupc ; jcol < fsupc + nsupc ; jcol + + )
2012-06-13 18:26:05 +02:00
{
2012-08-07 17:10:42 +02:00
typename MappedSparseMatrix < Scalar > : : InnerIterator it ( m_Ustore , jcol ) ;
for ( ; it ; + + it )
2012-06-13 18:26:05 +02:00
{
2012-08-07 17:10:42 +02:00
Index irow = it . index ( ) ;
X ( irow , j ) - = X ( jcol , j ) * it . value ( ) ;
2012-06-13 18:26:05 +02:00
}
}
}
} // End For U-solve
// Permute back the solution
2012-08-07 17:10:42 +02:00
for ( int j = 0 ; j < nrhs ; + + j )
2012-08-03 13:05:27 +02:00
X . col ( j ) = m_perm_c . inverse ( ) * X . col ( j ) ;
2012-06-13 18:26:05 +02:00
return true ;
2012-06-08 17:23:38 +02:00
}
2012-06-13 18:26:05 +02:00
2012-05-25 18:17:57 +02:00
protected :
// Functions
2012-06-13 18:26:05 +02:00
void initperfvalues ( )
{
2012-09-04 12:21:07 +02:00
m_perfv . panel_size = 12 ;
2012-09-10 12:41:26 +02:00
m_perfv . relax = 1 ;
2012-09-04 12:21:07 +02:00
m_perfv . maxsuper = 100 ;
m_perfv . rowblk = 200 ;
m_perfv . colblk = 60 ;
m_perfv . fillfactor = 20 ;
2012-06-13 18:26:05 +02:00
}
2012-05-25 18:17:57 +02:00
// Variables
mutable ComputationInfo m_info ;
bool m_isInitialized ;
bool m_factorizationIsOk ;
bool m_analysisIsOk ;
NCMatrix m_mat ; // The input (permuted ) matrix
SCMatrix m_Lstore ; // The lower triangular matrix (supernodal)
2012-06-14 18:45:04 +02:00
MappedSparseMatrix < Scalar > m_Ustore ; // The upper triangular matrix
2012-05-25 18:17:57 +02:00
PermutationType m_perm_c ; // Column permutation
PermutationType m_perm_r ; // Row permutation
2012-06-07 19:06:22 +02:00
IndexVector m_etree ; // Column elimination tree
2012-05-25 18:17:57 +02:00
2012-09-25 09:53:40 +02:00
LU_GlobalLU_t < IndexVector , ScalarVector > m_glu ;
2012-06-12 18:19:59 +02:00
2012-05-25 18:17:57 +02:00
// SuperLU/SparseLU options
bool m_symmetricmode ;
// values for performance
2012-09-04 12:21:07 +02:00
LU_perfvalues m_perfv ;
2012-05-25 18:17:57 +02:00
RealScalar m_diagpivotthresh ; // Specifies the threshold used for a diagonal entry to be an acceptable pivot
2012-06-11 18:52:26 +02:00
int m_nnzL , m_nnzU ; // Nonzeros in L and U factors
2012-05-25 18:17:57 +02:00
private :
// Copy constructor
SparseLU ( SparseLU & ) { }
} ; // End class SparseLU
2012-06-12 18:19:59 +02:00
// Functions needed by the anaysis phase
2012-05-25 18:17:57 +02:00
/**
2012-09-25 11:48:18 +02:00
* Compute the column permutation to minimize the fill - in
2012-06-11 18:52:26 +02:00
*
2012-05-25 18:17:57 +02:00
* - Apply this permutation to the input matrix -
2012-06-11 18:52:26 +02:00
*
2012-09-25 11:48:18 +02:00
* - Compute the column elimination tree on the permuted matrix
2012-06-11 18:52:26 +02:00
*
2012-09-25 11:48:18 +02:00
* - Postorder the elimination tree and the column permutation
2012-06-11 18:52:26 +02:00
*
2012-05-25 18:17:57 +02:00
*/
2012-06-11 18:52:26 +02:00
template < typename MatrixType , typename OrderingType >
2012-06-13 18:26:05 +02:00
void SparseLU < MatrixType , OrderingType > : : analyzePattern ( const MatrixType & mat )
2012-05-25 18:17:57 +02:00
{
2012-06-11 18:52:26 +02:00
//TODO It is possible as in SuperLU to compute row and columns scaling vectors to equilibrate the matrix mat.
2012-07-06 20:18:16 +02:00
OrderingType ord ;
ord ( mat , m_perm_c ) ;
2012-07-18 16:59:00 +02:00
2012-05-25 18:17:57 +02:00
// Apply the permutation to the column of the input matrix
2012-07-27 16:38:20 +02:00
// m_mat = mat * m_perm_c.inverse(); //FIXME It should be less expensive here to permute only the structural pattern of the matrix
//First copy the whole input matrix.
m_mat = mat ;
2012-09-07 13:14:57 +02:00
m_mat . uncompress ( ) ; //NOTE: The effect of this command is only to create the InnerNonzeros pointers. FIXME : This vector is filled but not subsequently used.
2012-07-27 16:38:20 +02:00
//Then, permute only the column pointers
for ( int i = 0 ; i < mat . cols ( ) ; i + + )
{
m_mat . outerIndexPtr ( ) [ m_perm_c . indices ( ) ( i ) ] = mat . outerIndexPtr ( ) [ i ] ;
m_mat . innerNonZeroPtr ( ) [ m_perm_c . indices ( ) ( i ) ] = mat . outerIndexPtr ( ) [ i + 1 ] - mat . outerIndexPtr ( ) [ i ] ;
}
2012-05-25 18:17:57 +02:00
// Compute the column elimination tree of the permuted matrix
2012-08-03 13:05:27 +02:00
/*if (m_etree.size() == 0) */ m_etree . resize ( m_mat . cols ( ) ) ;
2012-07-06 20:18:16 +02:00
2012-09-25 09:53:40 +02:00
SparseLUBase < Scalar , Index > : : LU_sp_coletree ( m_mat , m_etree ) ;
2012-07-06 20:18:16 +02:00
2012-05-25 18:17:57 +02:00
// In symmetric mode, do not do postorder here
2012-06-11 18:52:26 +02:00
if ( ! m_symmetricmode ) {
2012-06-07 19:06:22 +02:00
IndexVector post , iwork ;
2012-05-25 18:17:57 +02:00
// Post order etree
2012-09-25 09:53:40 +02:00
SparseLUBase < Scalar , Index > : : LU_TreePostorder ( m_mat . cols ( ) , m_etree , post ) ;
2012-05-25 18:17:57 +02:00
2012-07-06 20:18:16 +02:00
2012-05-25 18:17:57 +02:00
// Renumber etree in postorder
2012-06-13 18:26:05 +02:00
int m = m_mat . cols ( ) ;
iwork . resize ( m + 1 ) ;
for ( int i = 0 ; i < m ; + + i ) iwork ( post ( i ) ) = post ( m_etree ( i ) ) ;
2012-06-11 18:52:26 +02:00
m_etree = iwork ;
// Postmultiply A*Pc by post, i.e reorder the matrix according to the postorder of the etree
2012-07-13 17:32:25 +02:00
PermutationType post_perm ( m ) ; //FIXME Use directly a constructor with post
2012-06-14 18:45:04 +02:00
for ( int i = 0 ; i < m ; i + + )
post_perm . indices ( ) ( i ) = post ( i ) ;
2012-07-13 17:32:25 +02:00
// Combine the two permutations : postorder the permutation for future use
m_perm_c = post_perm * m_perm_c ;
2012-07-06 20:18:16 +02:00
2012-05-25 18:17:57 +02:00
} // end postordering
2012-06-11 18:52:26 +02:00
2012-06-13 18:26:05 +02:00
m_analysisIsOk = true ;
2012-05-25 18:17:57 +02:00
}
2012-09-25 09:53:40 +02:00
// Functions needed by the numerical factorization phase
2012-06-12 18:19:59 +02:00
2012-06-14 18:45:04 +02:00
2012-05-25 18:17:57 +02:00
/**
* - Numerical factorization
* - Interleaved with the symbolic factorization
2012-09-25 11:48:18 +02:00
* On exit , info is
*
* = 0 : successful factorization
*
2012-05-25 18:17:57 +02:00
* > 0 : if info = i , and i is
2012-09-25 11:48:18 +02:00
*
2012-05-25 18:17:57 +02:00
* < = A - > ncol : U ( i , i ) is exactly zero . The factorization has
* been completed , but the factor U is exactly singular ,
* and division by zero will occur if it is used to solve a
* system of equations .
2012-09-25 11:48:18 +02:00
*
2012-05-25 18:17:57 +02:00
* > A - > ncol : number of bytes allocated when memory allocation
* failure occurred , plus A - > ncol . If lwork = - 1 , it is
* the estimated amount of space needed , plus A - > ncol .
*/
2012-06-13 18:26:05 +02:00
template < typename MatrixType , typename OrderingType >
void SparseLU < MatrixType , OrderingType > : : factorize ( const MatrixType & matrix )
2012-05-25 18:17:57 +02:00
{
2012-06-13 18:26:05 +02:00
eigen_assert ( m_analysisIsOk & & " analyzePattern() should be called first " ) ;
2012-06-11 18:52:26 +02:00
eigen_assert ( ( matrix . rows ( ) = = matrix . cols ( ) ) & & " Only for squared matrices " ) ;
2012-06-14 18:45:04 +02:00
typedef typename IndexVector : : Scalar Index ;
2012-06-13 18:26:05 +02:00
2012-06-11 18:52:26 +02:00
// Apply the column permutation computed in analyzepattern()
2012-07-27 16:38:20 +02:00
// m_mat = matrix * m_perm_c.inverse();
m_mat = matrix ;
2012-09-07 13:14:57 +02:00
m_mat . uncompress ( ) ; //NOTE: The effect of this command is only to create the InnerNonzeros pointers.
2012-07-27 16:38:20 +02:00
//Then, permute only the column pointers
for ( int i = 0 ; i < matrix . cols ( ) ; i + + )
{
m_mat . outerIndexPtr ( ) [ m_perm_c . indices ( ) ( i ) ] = matrix . outerIndexPtr ( ) [ i ] ;
m_mat . innerNonZeroPtr ( ) [ m_perm_c . indices ( ) ( i ) ] = matrix . outerIndexPtr ( ) [ i + 1 ] - matrix . outerIndexPtr ( ) [ i ] ;
}
2012-05-25 18:17:57 +02:00
int m = m_mat . rows ( ) ;
int n = m_mat . cols ( ) ;
2012-06-11 18:52:26 +02:00
int nnz = m_mat . nonZeros ( ) ;
2012-09-04 12:21:07 +02:00
int maxpanel = m_perfv . panel_size * m ;
2012-07-13 17:32:25 +02:00
// Allocate working storage common to the factor routines
2012-06-11 18:52:26 +02:00
int lwork = 0 ;
2012-09-25 09:53:40 +02:00
int info = SparseLUBase < Scalar , Index > : : LUMemInit ( m , n , nnz , lwork , m_perfv . fillfactor , m_perfv . panel_size , m_glu ) ;
2012-06-11 18:52:26 +02:00
if ( info )
{
std : : cerr < < " UNABLE TO ALLOCATE WORKING MEMORY \n \n " ;
m_factorizationIsOk = false ;
return ;
}
2012-05-25 18:17:57 +02:00
2012-06-14 18:45:04 +02:00
// Set up pointers for integer working arrays
2012-07-13 17:32:25 +02:00
IndexVector segrep ( m ) ; segrep . setZero ( ) ;
IndexVector parent ( m ) ; parent . setZero ( ) ;
IndexVector xplore ( m ) ; xplore . setZero ( ) ;
2012-06-14 18:45:04 +02:00
IndexVector repfnz ( maxpanel ) ;
IndexVector panel_lsub ( maxpanel ) ;
2012-07-10 19:16:57 +02:00
IndexVector xprune ( n ) ; xprune . setZero ( ) ;
2012-07-13 17:32:25 +02:00
IndexVector marker ( m * LU_NO_MARKER ) ; marker . setZero ( ) ;
2012-06-08 17:23:38 +02:00
2012-05-25 18:17:57 +02:00
repfnz . setConstant ( - 1 ) ;
panel_lsub . setConstant ( - 1 ) ;
// Set up pointers for scalar working arrays
2012-06-14 18:45:04 +02:00
ScalarVector dense ;
dense . setZero ( maxpanel ) ;
ScalarVector tempv ;
2012-09-04 12:21:07 +02:00
tempv . setZero ( LU_NUM_TEMPV ( m , m_perfv . panel_size , m_perfv . maxsuper , m_perfv . rowblk ) ) ;
2012-05-25 18:17:57 +02:00
// Compute the inverse of perm_c
2012-07-13 17:32:25 +02:00
PermutationType iperm_c ( m_perm_c . inverse ( ) ) ;
2012-05-25 18:17:57 +02:00
// Identify initial relaxed snodes
2012-06-07 19:06:22 +02:00
IndexVector relax_end ( n ) ;
2012-06-14 18:45:04 +02:00
if ( m_symmetricmode = = true )
2012-09-25 09:53:40 +02:00
SparseLUBase < Scalar , Index > : : LU_heap_relax_snode ( n , m_etree , m_perfv . relax , marker , relax_end ) ;
2012-05-25 18:17:57 +02:00
else
2012-09-25 09:53:40 +02:00
SparseLUBase < Scalar , Index > : : LU_relax_snode ( n , m_etree , m_perfv . relax , marker , relax_end ) ;
2012-05-25 18:17:57 +02:00
2012-07-06 20:18:16 +02:00
2012-06-14 18:45:04 +02:00
m_perm_r . resize ( m ) ;
2012-07-13 17:32:25 +02:00
m_perm_r . indices ( ) . setConstant ( - 1 ) ;
2012-05-25 18:17:57 +02:00
marker . setConstant ( - 1 ) ;
2012-09-25 09:53:40 +02:00
m_glu . supno ( 0 ) = IND_EMPTY ; m_glu . xsup . setConstant ( 0 ) ;
m_glu . xsup ( 0 ) = m_glu . xlsub ( 0 ) = m_glu . xusub ( 0 ) = m_glu . xlusup ( 0 ) = Index ( 0 ) ;
2012-05-25 18:17:57 +02:00
// Work on one 'panel' at a time. A panel is one of the following :
// (a) a relaxed supernode at the bottom of the etree, or
// (b) panel_size contiguous columns, <panel_size> defined by the user
2012-06-14 18:45:04 +02:00
int jcol , kcol ;
2012-06-07 19:06:22 +02:00
IndexVector panel_histo ( n ) ;
2012-05-25 18:17:57 +02:00
Index nextu , nextlu , jsupno , fsupc , new_next ;
2012-06-11 18:52:26 +02:00
Index pivrow ; // Pivotal row number in the original row matrix
2012-05-25 18:17:57 +02:00
int nseg1 ; // Number of segments in U-column above panel row jcol
int nseg ; // Number of segments in each U-column
2012-06-14 18:45:04 +02:00
int irep , icol ;
int i , k , jj ;
2012-06-11 18:52:26 +02:00
for ( jcol = 0 ; jcol < n ; )
2012-05-25 18:17:57 +02:00
{
2012-05-30 18:09:26 +02:00
if ( relax_end ( jcol ) ! = IND_EMPTY )
2012-05-25 18:17:57 +02:00
{ // Starting a relaxed node from jcol
kcol = relax_end ( jcol ) ; // End index of the relaxed snode
// Factorize the relaxed supernode(jcol:kcol)
// First, determine the union of the row structure of the snode
2012-09-25 09:53:40 +02:00
info = SparseLUBase < Scalar , Index > : : LU_snode_dfs ( jcol , kcol , m_mat , xprune , marker , m_glu ) ;
2012-06-07 19:06:22 +02:00
if ( info )
2012-05-25 18:17:57 +02:00
{
2012-06-12 18:19:59 +02:00
std : : cerr < < " MEMORY ALLOCATION FAILED IN SNODE_DFS() \n " ;
2012-05-29 17:55:38 +02:00
m_info = NumericalIssue ;
m_factorizationIsOk = false ;
return ;
2012-05-25 18:17:57 +02:00
}
2012-09-25 09:53:40 +02:00
nextu = m_glu . xusub ( jcol ) ; //starting location of column jcol in ucol
nextlu = m_glu . xlusup ( jcol ) ; //Starting location of column jcol in lusup (rectangular supernodes)
jsupno = m_glu . supno ( jcol ) ; // Supernode number which column jcol belongs to
fsupc = m_glu . xsup ( jsupno ) ; //First column number of the current supernode
new_next = nextlu + ( m_glu . xlsub ( fsupc + 1 ) - m_glu . xlsub ( fsupc ) ) * ( kcol - jcol + 1 ) ;
2012-06-13 18:26:05 +02:00
int mem ;
2012-09-25 09:53:40 +02:00
while ( new_next > m_glu . nzlumax )
2012-05-25 18:17:57 +02:00
{
2012-09-25 09:53:40 +02:00
mem = SparseLUBase < Scalar , Index > : : LUMemXpand ( m_glu . lusup , m_glu . nzlumax , nextlu , LUSUP , m_glu . num_expansions ) ;
2012-06-07 19:06:22 +02:00
if ( mem )
{
2012-06-11 18:52:26 +02:00
std : : cerr < < " MEMORY ALLOCATION FAILED FOR L FACTOR \n " ;
2012-06-07 19:06:22 +02:00
m_factorizationIsOk = false ;
return ;
}
2012-05-25 18:17:57 +02:00
}
2012-06-11 18:52:26 +02:00
2012-05-25 18:17:57 +02:00
// Now, left-looking factorize each column within the snode
for ( icol = jcol ; icol < = kcol ; icol + + ) {
2012-09-25 09:53:40 +02:00
m_glu . xusub ( icol + 1 ) = nextu ;
2012-05-25 18:17:57 +02:00
// Scatter into SPA dense(*)
for ( typename MatrixType : : InnerIterator it ( m_mat , icol ) ; it ; + + it )
2012-06-14 18:45:04 +02:00
dense ( it . row ( ) ) = it . value ( ) ;
2012-05-25 18:17:57 +02:00
// Numeric update within the snode
2012-09-25 09:53:40 +02:00
SparseLUBase < Scalar , Index > : : LU_snode_bmod ( icol , fsupc , dense , m_glu ) ;
2012-05-25 18:17:57 +02:00
// Eliminate the current column
2012-09-25 09:53:40 +02:00
info = SparseLUBase < Scalar , Index > : : LU_pivotL ( icol , m_diagpivotthresh , m_perm_r . indices ( ) , iperm_c . indices ( ) , pivrow , m_glu ) ;
2012-06-07 19:06:22 +02:00
if ( info )
2012-05-30 18:09:26 +02:00
{
m_info = NumericalIssue ;
2012-06-12 18:19:59 +02:00
std : : cerr < < " THE MATRIX IS STRUCTURALLY SINGULAR ... ZERO COLUMN AT " < < info < < std : : endl ;
2012-05-30 18:09:26 +02:00
m_factorizationIsOk = false ;
return ;
}
2012-05-25 18:17:57 +02:00
}
jcol = icol ; // The last column te be eliminated
}
else
{ // Work on one panel of panel_size columns
// Adjust panel size so that a panel won't overlap with the next relaxed snode.
2012-09-04 12:21:07 +02:00
int panel_size = m_perfv . panel_size ; // upper bound on panel width
2012-09-25 09:58:29 +02:00
for ( k = jcol + 1 ; k < ( std : : min ) ( jcol + panel_size , n ) ; k + + )
2012-05-25 18:17:57 +02:00
{
2012-05-30 18:09:26 +02:00
if ( relax_end ( k ) ! = IND_EMPTY )
2012-05-25 18:17:57 +02:00
{
panel_size = k - jcol ;
break ;
}
}
2012-06-11 18:52:26 +02:00
if ( k = = n )
panel_size = n - jcol ;
2012-05-25 18:17:57 +02:00
// Symbolic outer factorization on a panel of columns
2012-09-25 09:53:40 +02:00
SparseLUBase < Scalar , Index > : : LU_panel_dfs ( m , panel_size , jcol , m_mat , m_perm_r . indices ( ) , nseg1 , dense , panel_lsub , segrep , repfnz , xprune , marker , parent , xplore , m_glu ) ;
2012-05-25 18:17:57 +02:00
// Numeric sup-panel updates in topological order
2012-09-25 09:53:40 +02:00
SparseLUBase < Scalar , Index > : : LU_panel_bmod ( m , panel_size , jcol , nseg1 , dense , tempv , segrep , repfnz , m_perfv , m_glu ) ;
2012-05-25 18:17:57 +02:00
// Sparse LU within the panel, and below the panel diagonal
2012-06-14 18:45:04 +02:00
for ( jj = jcol ; jj < jcol + panel_size ; jj + + )
2012-05-25 18:17:57 +02:00
{
k = ( jj - jcol ) * m ; // Column index for w-wide arrays
2012-05-29 17:55:38 +02:00
nseg = nseg1 ; // begin after all the panel segments
//Depth-first-search for the current column
2012-06-12 18:19:59 +02:00
VectorBlock < IndexVector > panel_lsubk ( panel_lsub , k , m ) ;
2012-07-09 19:09:48 +02:00
VectorBlock < IndexVector > repfnz_k ( repfnz , k , m ) ;
2012-09-25 09:53:40 +02:00
info = SparseLUBase < Scalar , Index > : : LU_column_dfs ( m , jj , m_perm_r . indices ( ) , m_perfv . maxsuper , nseg , panel_lsubk , segrep , repfnz_k , xprune , marker , parent , xplore , m_glu ) ;
2012-06-15 17:23:54 +02:00
if ( info )
2012-05-29 17:55:38 +02:00
{
2012-06-12 18:19:59 +02:00
std : : cerr < < " UNABLE TO EXPAND MEMORY IN COLUMN_DFS() \n " ;
2012-05-29 17:55:38 +02:00
m_info = NumericalIssue ;
m_factorizationIsOk = false ;
return ;
}
// Numeric updates to this column
2012-06-14 18:45:04 +02:00
VectorBlock < ScalarVector > dense_k ( dense , k , m ) ;
2012-06-15 17:23:54 +02:00
VectorBlock < IndexVector > segrep_k ( segrep , nseg1 , m - nseg1 ) ;
2012-09-25 09:53:40 +02:00
info = SparseLUBase < Scalar , Index > : : LU_column_bmod ( jj , ( nseg - nseg1 ) , dense_k , tempv , segrep_k , repfnz_k , jcol , m_glu ) ;
2012-06-07 19:06:22 +02:00
if ( info )
2012-05-30 18:09:26 +02:00
{
2012-06-12 18:19:59 +02:00
std : : cerr < < " UNABLE TO EXPAND MEMORY IN COLUMN_BMOD() \n " ;
2012-05-30 18:09:26 +02:00
m_info = NumericalIssue ;
m_factorizationIsOk = false ;
return ;
}
// Copy the U-segments to ucol(*)
2012-09-25 09:53:40 +02:00
info = SparseLUBase < Scalar , Index > : : LU_copy_to_ucol ( jj , nseg , segrep , repfnz_k , m_perm_r . indices ( ) , dense_k , m_glu ) ;
2012-06-07 19:06:22 +02:00
if ( info )
2012-05-31 17:10:29 +02:00
{
2012-06-12 18:19:59 +02:00
std : : cerr < < " UNABLE TO EXPAND MEMORY IN COPY_TO_UCOL() \n " ;
2012-05-31 17:10:29 +02:00
m_info = NumericalIssue ;
m_factorizationIsOk = false ;
return ;
}
2012-05-30 18:09:26 +02:00
// Form the L-segment
2012-09-25 09:53:40 +02:00
info = SparseLUBase < Scalar , Index > : : LU_pivotL ( jj , m_diagpivotthresh , m_perm_r . indices ( ) , iperm_c . indices ( ) , pivrow , m_glu ) ;
2012-06-07 19:06:22 +02:00
if ( info )
2012-05-29 17:55:38 +02:00
{
2012-06-12 18:19:59 +02:00
std : : cerr < < " THE MATRIX IS STRUCTURALLY SINGULAR ... ZERO COLUMN AT " < < info < < std : : endl ;
2012-05-29 17:55:38 +02:00
m_info = NumericalIssue ;
m_factorizationIsOk = false ;
return ;
}
2012-05-30 18:09:26 +02:00
// Prune columns (0:jj-1) using column jj
2012-09-25 09:53:40 +02:00
SparseLUBase < Scalar , Index > : : LU_pruneL ( jj , m_perm_r . indices ( ) , pivrow , nseg , segrep , repfnz_k , xprune , m_glu ) ;
2012-05-30 18:09:26 +02:00
2012-05-31 17:10:29 +02:00
// Reset repfnz for this column
for ( i = 0 ; i < nseg ; i + + )
{
irep = segrep ( i ) ;
2012-07-10 19:16:57 +02:00
repfnz_k ( irep ) = IND_EMPTY ;
2012-05-31 17:10:29 +02:00
}
} // end SparseLU within the panel
2012-05-25 18:17:57 +02:00
jcol + = panel_size ; // Move to the next panel
} // end else
} // end for -- end elimination
2012-05-31 17:10:29 +02:00
// Count the number of nonzeros in factors
2012-09-25 09:53:40 +02:00
SparseLUBase < Scalar , Index > : : LU_countnz ( n , m_nnzL , m_nnzU , m_glu ) ;
2012-05-31 17:10:29 +02:00
// Apply permutation to the L subscripts
2012-09-25 09:53:40 +02:00
SparseLUBase < Scalar , Index > : : LU_fixupL ( n , m_perm_r . indices ( ) , m_glu ) ;
2012-05-31 17:10:29 +02:00
2012-06-01 18:44:51 +02:00
// Create supernode matrix L
2012-06-13 18:26:05 +02:00
m_Lstore . setInfos ( m , n , m_glu . lusup , m_glu . xlusup , m_glu . lsub , m_glu . xlsub , m_glu . supno , m_glu . xsup ) ;
// Create the column major upper sparse matrix U;
2012-06-14 18:45:04 +02:00
new ( & m_Ustore ) MappedSparseMatrix < Scalar > ( m , n , m_nnzU , m_glu . xusub . data ( ) , m_glu . usub . data ( ) , m_glu . ucol . data ( ) ) ;
2012-06-08 17:23:38 +02:00
2012-05-29 17:55:38 +02:00
m_info = Success ;
2012-06-13 18:26:05 +02:00
m_factorizationIsOk = true ;
2012-05-25 18:17:57 +02:00
}
2012-09-25 09:53:40 +02:00
// #include "SparseLU_simplicialfactorize.h"
2012-08-03 13:05:27 +02:00
namespace internal {
2012-06-08 17:23:38 +02:00
template < typename _MatrixType , typename Derived , typename Rhs >
struct solve_retval < SparseLU < _MatrixType , Derived > , Rhs >
: solve_retval_base < SparseLU < _MatrixType , Derived > , Rhs >
{
typedef SparseLU < _MatrixType , Derived > Dec ;
EIGEN_MAKE_SOLVE_HELPERS ( Dec , Rhs )
template < typename Dest > void evalTo ( Dest & dst ) const
{
2012-08-03 13:05:27 +02:00
dec ( ) . _solve ( rhs ( ) , dst ) ;
2012-06-08 17:23:38 +02:00
}
} ;
2012-08-03 13:05:27 +02:00
} // end namespace internal
2012-06-08 17:23:38 +02:00
2012-05-25 18:17:57 +02:00
} // End namespace Eigen
2012-09-25 09:53:40 +02:00
# endif