MOAB
4.9.3pre
|
#include <SparseLUImpl.h>
Public Types | |
typedef Matrix< Scalar, Dynamic, 1 > | ScalarVector |
typedef Matrix< StorageIndex, Dynamic, 1 > | IndexVector |
typedef Matrix< Scalar, Dynamic, Dynamic, ColMajor > | ScalarMatrix |
typedef Map< ScalarMatrix, 0, OuterStride<> > | MappedMatrixBlock |
typedef ScalarVector::RealScalar | RealScalar |
typedef Ref< Matrix< Scalar, Dynamic, 1 > > | BlockScalarVector |
typedef Ref< Matrix < StorageIndex, Dynamic, 1 > > | BlockIndexVector |
typedef LU_GlobalLU_t < IndexVector, ScalarVector > | GlobalLU_t |
typedef SparseMatrix< Scalar, ColMajor, StorageIndex > | MatrixType |
Protected Member Functions | |
template<typename VectorType > | |
Index | expand (VectorType &vec, Index &length, Index nbElts, Index keep_prev, Index &num_expansions) |
Index | memInit (Index m, Index n, Index annz, Index lwork, Index fillratio, Index panel_size, GlobalLU_t &glu) |
Allocate various working space for the numerical factorization phase. | |
template<typename VectorType > | |
Index | memXpand (VectorType &vec, Index &maxlen, Index nbElts, MemType memtype, Index &num_expansions) |
Expand the existing storage. | |
void | heap_relax_snode (const Index n, IndexVector &et, const Index relax_columns, IndexVector &descendants, IndexVector &relax_end) |
Identify the initial relaxed supernodes. | |
void | relax_snode (const Index n, IndexVector &et, const Index relax_columns, IndexVector &descendants, IndexVector &relax_end) |
Identify the initial relaxed supernodes. | |
Index | snode_dfs (const Index jcol, const Index kcol, const MatrixType &mat, IndexVector &xprune, IndexVector &marker, GlobalLU_t &glu) |
Index | snode_bmod (const Index jcol, const Index fsupc, ScalarVector &dense, GlobalLU_t &glu) |
Index | pivotL (const Index jcol, const RealScalar &diagpivotthresh, IndexVector &perm_r, IndexVector &iperm_c, Index &pivrow, GlobalLU_t &glu) |
Performs the numerical pivotin on the current column of L, and the CDIV operation. | |
template<typename Traits > | |
void | dfs_kernel (const StorageIndex jj, IndexVector &perm_r, Index &nseg, IndexVector &panel_lsub, IndexVector &segrep, Ref< IndexVector > repfnz_col, IndexVector &xprune, Ref< IndexVector > marker, IndexVector &parent, IndexVector &xplore, GlobalLU_t &glu, Index &nextl_col, Index krow, Traits &traits) |
void | panel_dfs (const Index m, const Index w, const Index jcol, MatrixType &A, IndexVector &perm_r, Index &nseg, ScalarVector &dense, IndexVector &panel_lsub, IndexVector &segrep, IndexVector &repfnz, IndexVector &xprune, IndexVector &marker, IndexVector &parent, IndexVector &xplore, GlobalLU_t &glu) |
Performs a symbolic factorization on a panel of columns [jcol, jcol+w) | |
void | panel_bmod (const Index m, const Index w, const Index jcol, const Index nseg, ScalarVector &dense, ScalarVector &tempv, IndexVector &segrep, IndexVector &repfnz, GlobalLU_t &glu) |
Performs numeric block updates (sup-panel) in topological order. | |
Index | column_dfs (const Index m, const Index jcol, IndexVector &perm_r, Index maxsuper, Index &nseg, BlockIndexVector lsub_col, IndexVector &segrep, BlockIndexVector repfnz, IndexVector &xprune, IndexVector &marker, IndexVector &parent, IndexVector &xplore, GlobalLU_t &glu) |
Performs a symbolic factorization on column jcol and decide the supernode boundary. | |
Index | column_bmod (const Index jcol, const Index nseg, BlockScalarVector dense, ScalarVector &tempv, BlockIndexVector segrep, BlockIndexVector repfnz, Index fpanelc, GlobalLU_t &glu) |
Performs numeric block updates (sup-col) in topological order. | |
Index | copy_to_ucol (const Index jcol, const Index nseg, IndexVector &segrep, BlockIndexVector repfnz, IndexVector &perm_r, BlockScalarVector dense, GlobalLU_t &glu) |
Performs numeric block updates (sup-col) in topological order. | |
void | pruneL (const Index jcol, const IndexVector &perm_r, const Index pivrow, const Index nseg, const IndexVector &segrep, BlockIndexVector repfnz, IndexVector &xprune, GlobalLU_t &glu) |
Prunes the L-structure. | |
void | countnz (const Index n, Index &nnzL, Index &nnzU, GlobalLU_t &glu) |
Count Nonzero elements in the factors. | |
void | fixupL (const Index n, const IndexVector &perm_r, GlobalLU_t &glu) |
Fix up the data storage lsub for L-subscripts. | |
Friends | |
struct | column_dfs_traits |
Base class for sparseLU
Definition at line 20 of file SparseLUImpl.h.
typedef Ref<Matrix<StorageIndex,Dynamic,1> > Eigen::internal::SparseLUImpl< Scalar, StorageIndex >::BlockIndexVector |
Definition at line 29 of file SparseLUImpl.h.
typedef Ref<Matrix<Scalar,Dynamic,1> > Eigen::internal::SparseLUImpl< Scalar, StorageIndex >::BlockScalarVector |
Definition at line 28 of file SparseLUImpl.h.
typedef LU_GlobalLU_t<IndexVector, ScalarVector> Eigen::internal::SparseLUImpl< Scalar, StorageIndex >::GlobalLU_t |
Definition at line 30 of file SparseLUImpl.h.
typedef Matrix<StorageIndex,Dynamic,1> Eigen::internal::SparseLUImpl< Scalar, StorageIndex >::IndexVector |
Reimplemented in Eigen::SparseLU< _MatrixType, _OrderingType >.
Definition at line 24 of file SparseLUImpl.h.
typedef Map<ScalarMatrix, 0, OuterStride<> > Eigen::internal::SparseLUImpl< Scalar, StorageIndex >::MappedMatrixBlock |
Definition at line 26 of file SparseLUImpl.h.
typedef SparseMatrix<Scalar,ColMajor,StorageIndex> Eigen::internal::SparseLUImpl< Scalar, StorageIndex >::MatrixType |
Reimplemented in Eigen::SparseLU< _MatrixType, _OrderingType >.
Definition at line 31 of file SparseLUImpl.h.
typedef ScalarVector::RealScalar Eigen::internal::SparseLUImpl< Scalar, StorageIndex >::RealScalar |
Reimplemented in Eigen::SparseLU< _MatrixType, _OrderingType >.
Definition at line 27 of file SparseLUImpl.h.
typedef Matrix<Scalar,Dynamic,Dynamic,ColMajor> Eigen::internal::SparseLUImpl< Scalar, StorageIndex >::ScalarMatrix |
Definition at line 25 of file SparseLUImpl.h.
typedef Matrix<Scalar,Dynamic,1> Eigen::internal::SparseLUImpl< Scalar, StorageIndex >::ScalarVector |
Reimplemented in Eigen::SparseLU< _MatrixType, _OrderingType >.
Definition at line 23 of file SparseLUImpl.h.
Index Eigen::internal::SparseLUImpl< Scalar, StorageIndex >::column_bmod | ( | const Index | jcol, |
const Index | nseg, | ||
BlockScalarVector | dense, | ||
ScalarVector & | tempv, | ||
BlockIndexVector | segrep, | ||
BlockIndexVector | repfnz, | ||
Index | fpanelc, | ||
GlobalLU_t & | glu | ||
) | [protected] |
Performs numeric block updates (sup-col) in topological order.
jcol | current column to update |
nseg | Number of segments in the U part |
dense | Store the full representation of the column |
tempv | working array |
segrep | segment representative ... |
repfnz | ??? First nonzero column in each row ??? ... |
fpanelc | First column in the current panel |
glu | Global LU data. |
Definition at line 53 of file SparseLU_column_bmod.h.
{ Index jsupno, k, ksub, krep, ksupno; Index lptr, nrow, isub, irow, nextlu, new_next, ufirst; Index fsupc, nsupc, nsupr, luptr, kfnz, no_zeros; /* krep = representative of current k-th supernode * fsupc = first supernodal column * nsupc = number of columns in a supernode * nsupr = number of rows in a supernode * luptr = location of supernodal LU-block in storage * kfnz = first nonz in the k-th supernodal segment * no_zeros = no lf leading zeros in a supernodal U-segment */ jsupno = glu.supno(jcol); // For each nonzero supernode segment of U[*,j] in topological order k = nseg - 1; Index d_fsupc; // distance between the first column of the current panel and the // first column of the current snode Index fst_col; // First column within small LU update Index segsize; for (ksub = 0; ksub < nseg; ksub++) { krep = segrep(k); k--; ksupno = glu.supno(krep); if (jsupno != ksupno ) { // outside the rectangular supernode fsupc = glu.xsup(ksupno); fst_col = (std::max)(fsupc, fpanelc); // Distance from the current supernode to the current panel; // d_fsupc = 0 if fsupc > fpanelc d_fsupc = fst_col - fsupc; luptr = glu.xlusup(fst_col) + d_fsupc; lptr = glu.xlsub(fsupc) + d_fsupc; kfnz = repfnz(krep); kfnz = (std::max)(kfnz, fpanelc); segsize = krep - kfnz + 1; nsupc = krep - fst_col + 1; nsupr = glu.xlsub(fsupc+1) - glu.xlsub(fsupc); nrow = nsupr - d_fsupc - nsupc; Index lda = glu.xlusup(fst_col+1) - glu.xlusup(fst_col); // Perform a triangular solver and block update, // then scatter the result of sup-col update to dense no_zeros = kfnz - fst_col; if(segsize==1) LU_kernel_bmod<1>::run(segsize, dense, tempv, glu.lusup, luptr, lda, nrow, glu.lsub, lptr, no_zeros); else LU_kernel_bmod<Dynamic>::run(segsize, dense, tempv, glu.lusup, luptr, lda, nrow, glu.lsub, lptr, no_zeros); } // end if jsupno } // end for each segment // Process the supernodal portion of L\U[*,j] nextlu = glu.xlusup(jcol); fsupc = glu.xsup(jsupno); // copy the SPA dense into L\U[*,j] Index mem; new_next = nextlu + glu.xlsub(fsupc + 1) - glu.xlsub(fsupc); Index offset = internal::first_multiple<Index>(new_next, internal::packet_traits<Scalar>::size) - new_next; if(offset) new_next += offset; while (new_next > glu.nzlumax ) { mem = memXpand<ScalarVector>(glu.lusup, glu.nzlumax, nextlu, LUSUP, glu.num_expansions); if (mem) return mem; } for (isub = glu.xlsub(fsupc); isub < glu.xlsub(fsupc+1); isub++) { irow = glu.lsub(isub); glu.lusup(nextlu) = dense(irow); dense(irow) = Scalar(0.0); ++nextlu; } if(offset) { glu.lusup.segment(nextlu,offset).setZero(); nextlu += offset; } glu.xlusup(jcol + 1) = StorageIndex(nextlu); // close L\U(*,jcol); /* For more updates within the panel (also within the current supernode), * should start from the first column of the panel, or the first column * of the supernode, whichever is bigger. There are two cases: * 1) fsupc < fpanelc, then fst_col <-- fpanelc * 2) fsupc >= fpanelc, then fst_col <-- fsupc */ fst_col = (std::max)(fsupc, fpanelc); if (fst_col < jcol) { // Distance between the current supernode and the current panel // d_fsupc = 0 if fsupc >= fpanelc d_fsupc = fst_col - fsupc; lptr = glu.xlsub(fsupc) + d_fsupc; luptr = glu.xlusup(fst_col) + d_fsupc; nsupr = glu.xlsub(fsupc+1) - glu.xlsub(fsupc); // leading dimension nsupc = jcol - fst_col; // excluding jcol nrow = nsupr - d_fsupc - nsupc; // points to the beginning of jcol in snode L\U(jsupno) ufirst = glu.xlusup(jcol) + d_fsupc; Index lda = glu.xlusup(jcol+1) - glu.xlusup(jcol); MappedMatrixBlock A( &(glu.lusup.data()[luptr]), nsupc, nsupc, OuterStride<>(lda) ); VectorBlock<ScalarVector> u(glu.lusup, ufirst, nsupc); u = A.template triangularView<UnitLower>().solve(u); new (&A) MappedMatrixBlock ( &(glu.lusup.data()[luptr+nsupc]), nrow, nsupc, OuterStride<>(lda) ); VectorBlock<ScalarVector> l(glu.lusup, ufirst+nsupc, nrow); l.noalias() -= A * u; } // End if fst_col return 0; }
Index Eigen::internal::SparseLUImpl< Scalar, StorageIndex >::column_dfs | ( | const Index | m, |
const Index | jcol, | ||
IndexVector & | perm_r, | ||
Index | maxsuper, | ||
Index & | nseg, | ||
BlockIndexVector | lsub_col, | ||
IndexVector & | segrep, | ||
BlockIndexVector | repfnz, | ||
IndexVector & | xprune, | ||
IndexVector & | marker, | ||
IndexVector & | parent, | ||
IndexVector & | xplore, | ||
GlobalLU_t & | glu | ||
) | [protected] |
Performs a symbolic factorization on column jcol and decide the supernode boundary.
A supernode representative is the last column of a supernode. The nonzeros in U[*,j] are segments that end at supernodes representatives. The routine returns a list of the supernodal representatives in topological order of the dfs that generates them. The location of the first nonzero in each supernodal segment (supernodal entry location) is also returned.
m | number of rows in the matrix | |
jcol | Current column | |
perm_r | Row permutation | |
maxsuper | Maximum number of column allowed in a supernode | |
[in,out] | nseg | Number of segments in current U[*,j] - new segments appended |
lsub_col | defines the rhs vector to start the dfs | |
[in,out] | segrep | Segment representatives - new segments appended |
repfnz | First nonzero location in each row | |
xprune | ||
marker | marker[i] == jj, if i was visited during dfs of current column jj; | |
parent | ||
xplore | working array | |
glu | global LU data |
Definition at line 93 of file SparseLU_column_dfs.h.
{ Index jsuper = glu.supno(jcol); Index nextl = glu.xlsub(jcol); VectorBlock<IndexVector> marker2(marker, 2*m, m); column_dfs_traits<IndexVector, ScalarVector> traits(jcol, jsuper, glu, *this); // For each nonzero in A(*,jcol) do dfs for (Index k = 0; ((k < m) ? lsub_col[k] != emptyIdxLU : false) ; k++) { Index krow = lsub_col(k); lsub_col(k) = emptyIdxLU; Index kmark = marker2(krow); // krow was visited before, go to the next nonz; if (kmark == jcol) continue; dfs_kernel(StorageIndex(jcol), perm_r, nseg, glu.lsub, segrep, repfnz, xprune, marker2, parent, xplore, glu, nextl, krow, traits); } // for each nonzero ... Index fsupc; StorageIndex nsuper = glu.supno(jcol); StorageIndex jcolp1 = StorageIndex(jcol) + 1; Index jcolm1 = jcol - 1; // check to see if j belongs in the same supernode as j-1 if ( jcol == 0 ) { // Do nothing for column 0 nsuper = glu.supno(0) = 0 ; } else { fsupc = glu.xsup(nsuper); StorageIndex jptr = glu.xlsub(jcol); // Not yet compressed StorageIndex jm1ptr = glu.xlsub(jcolm1); // Use supernodes of type T2 : see SuperLU paper if ( (nextl-jptr != jptr-jm1ptr-1) ) jsuper = emptyIdxLU; // Make sure the number of columns in a supernode doesn't // exceed threshold if ( (jcol - fsupc) >= maxsuper) jsuper = emptyIdxLU; /* If jcol starts a new supernode, reclaim storage space in * glu.lsub from previous supernode. Note we only store * the subscript set of the first and last columns of * a supernode. (first for num values, last for pruning) */ if (jsuper == emptyIdxLU) { // starts a new supernode if ( (fsupc < jcolm1-1) ) { // >= 3 columns in nsuper StorageIndex ito = glu.xlsub(fsupc+1); glu.xlsub(jcolm1) = ito; StorageIndex istop = ito + jptr - jm1ptr; xprune(jcolm1) = istop; // intialize xprune(jcol-1) glu.xlsub(jcol) = istop; for (StorageIndex ifrom = jm1ptr; ifrom < nextl; ++ifrom, ++ito) glu.lsub(ito) = glu.lsub(ifrom); nextl = ito; // = istop + length(jcol) } nsuper++; glu.supno(jcol) = nsuper; } // if a new supernode } // end else: jcol > 0 // Tidy up the pointers before exit glu.xsup(nsuper+1) = jcolp1; glu.supno(jcolp1) = nsuper; xprune(jcol) = StorageIndex(nextl); // Intialize upper bound for pruning glu.xlsub(jcolp1) = StorageIndex(nextl); return 0; }
Index Eigen::internal::SparseLUImpl< Scalar, StorageIndex >::copy_to_ucol | ( | const Index | jcol, |
const Index | nseg, | ||
IndexVector & | segrep, | ||
BlockIndexVector | repfnz, | ||
IndexVector & | perm_r, | ||
BlockScalarVector | dense, | ||
GlobalLU_t & | glu | ||
) | [protected] |
Performs numeric block updates (sup-col) in topological order.
jcol | current column to update |
nseg | Number of segments in the U part |
segrep | segment representative ... |
repfnz | First nonzero column in each row ... |
perm_r | Row permutation |
dense | Store the full representation of the column |
glu | Global LU data. |
Definition at line 50 of file SparseLU_copy_to_ucol.h.
{ Index ksub, krep, ksupno; Index jsupno = glu.supno(jcol); // For each nonzero supernode segment of U[*,j] in topological order Index k = nseg - 1, i; StorageIndex nextu = glu.xusub(jcol); Index kfnz, isub, segsize; Index new_next,irow; Index fsupc, mem; for (ksub = 0; ksub < nseg; ksub++) { krep = segrep(k); k--; ksupno = glu.supno(krep); if (jsupno != ksupno ) // should go into ucol(); { kfnz = repfnz(krep); if (kfnz != emptyIdxLU) { // Nonzero U-segment fsupc = glu.xsup(ksupno); isub = glu.xlsub(fsupc) + kfnz - fsupc; segsize = krep - kfnz + 1; new_next = nextu + segsize; while (new_next > glu.nzumax) { mem = memXpand<ScalarVector>(glu.ucol, glu.nzumax, nextu, UCOL, glu.num_expansions); if (mem) return mem; mem = memXpand<IndexVector>(glu.usub, glu.nzumax, nextu, USUB, glu.num_expansions); if (mem) return mem; } for (i = 0; i < segsize; i++) { irow = glu.lsub(isub); glu.usub(nextu) = perm_r(irow); // Unlike the L part, the U part is stored in its final order glu.ucol(nextu) = dense(irow); dense(irow) = Scalar(0.0); nextu++; isub++; } } // end nonzero U-segment } // end if jsupno } // end for each segment glu.xusub(jcol + 1) = nextu; // close U(*,jcol) return 0; }
void Eigen::internal::SparseLUImpl< Scalar, StorageIndex >::countnz | ( | const Index | n, |
Index & | nnzL, | ||
Index & | nnzU, | ||
GlobalLU_t & | glu | ||
) | [protected] |
Count Nonzero elements in the factors.
Definition at line 21 of file SparseLU_Utils.h.
{ nnzL = 0; nnzU = (glu.xusub)(n); Index nsuper = (glu.supno)(n); Index jlen; Index i, j, fsupc; if (n <= 0 ) return; // For each supernode for (i = 0; i <= nsuper; i++) { fsupc = glu.xsup(i); jlen = glu.xlsub(fsupc+1) - glu.xlsub(fsupc); for (j = fsupc; j < glu.xsup(i+1); j++) { nnzL += jlen; nnzU += j - fsupc + 1; jlen--; } } }
void Eigen::internal::SparseLUImpl< Scalar, StorageIndex >::dfs_kernel | ( | const StorageIndex | jj, |
IndexVector & | perm_r, | ||
Index & | nseg, | ||
IndexVector & | panel_lsub, | ||
IndexVector & | segrep, | ||
Ref< IndexVector > | repfnz_col, | ||
IndexVector & | xprune, | ||
Ref< IndexVector > | marker, | ||
IndexVector & | parent, | ||
IndexVector & | xplore, | ||
GlobalLU_t & | glu, | ||
Index & | nextl_col, | ||
Index | krow, | ||
Traits & | traits | ||
) | [protected] |
Definition at line 62 of file SparseLU_panel_dfs.h.
{ StorageIndex kmark = marker(krow); // For each unmarked krow of jj marker(krow) = jj; StorageIndex kperm = perm_r(krow); if (kperm == emptyIdxLU ) { // krow is in L : place it in structure of L(*, jj) panel_lsub(nextl_col++) = StorageIndex(krow); // krow is indexed into A traits.mem_expand(panel_lsub, nextl_col, kmark); } else { // krow is in U : if its supernode-representative krep // has been explored, update repfnz(*) // krep = supernode representative of the current row StorageIndex krep = glu.xsup(glu.supno(kperm)+1) - 1; // First nonzero element in the current column: StorageIndex myfnz = repfnz_col(krep); if (myfnz != emptyIdxLU ) { // Representative visited before if (myfnz > kperm ) repfnz_col(krep) = kperm; } else { // Otherwise, perform dfs starting at krep StorageIndex oldrep = emptyIdxLU; parent(krep) = oldrep; repfnz_col(krep) = kperm; StorageIndex xdfs = glu.xlsub(krep); Index maxdfs = xprune(krep); StorageIndex kpar; do { // For each unmarked kchild of krep while (xdfs < maxdfs) { StorageIndex kchild = glu.lsub(xdfs); xdfs++; StorageIndex chmark = marker(kchild); if (chmark != jj ) { marker(kchild) = jj; StorageIndex chperm = perm_r(kchild); if (chperm == emptyIdxLU) { // case kchild is in L: place it in L(*, j) panel_lsub(nextl_col++) = kchild; traits.mem_expand(panel_lsub, nextl_col, chmark); } else { // case kchild is in U : // chrep = its supernode-rep. If its rep has been explored, // update its repfnz(*) StorageIndex chrep = glu.xsup(glu.supno(chperm)+1) - 1; myfnz = repfnz_col(chrep); if (myfnz != emptyIdxLU) { // Visited before if (myfnz > chperm) repfnz_col(chrep) = chperm; } else { // Cont. dfs at snode-rep of kchild xplore(krep) = xdfs; oldrep = krep; krep = chrep; // Go deeper down G(L) parent(krep) = oldrep; repfnz_col(krep) = chperm; xdfs = glu.xlsub(krep); maxdfs = xprune(krep); } // end if myfnz != -1 } // end if chperm == -1 } // end if chmark !=jj } // end while xdfs < maxdfs // krow has no more unexplored nbrs : // Place snode-rep krep in postorder DFS, if this // segment is seen for the first time. (Note that // "repfnz(krep)" may change later.) // Baktrack dfs to its parent if(traits.update_segrep(krep,jj)) //if (marker1(krep) < jcol ) { segrep(nseg) = krep; ++nseg; //marker1(krep) = jj; } kpar = parent(krep); // Pop recursion, mimic recursion if (kpar == emptyIdxLU) break; // dfs done krep = kpar; xdfs = xplore(krep); maxdfs = xprune(krep); } while (kpar != emptyIdxLU); // Do until empty stack } // end if (myfnz = -1) } // end if (kperm == -1) }
Index Eigen::internal::SparseLUImpl< Scalar, StorageIndex >::expand | ( | VectorType & | vec, |
Index & | length, | ||
Index | nbElts, | ||
Index | keep_prev, | ||
Index & | num_expansions | ||
) | [protected] |
Expand the existing storage to accomodate more fill-ins
vec | Valid pointer to the vector to allocate or expand | |
[in,out] | length | At input, contain the current length of the vector that is to be increased. At output, length of the newly allocated vector |
[in] | nbElts | Current number of elements in the factors |
keep_prev | 1: use length and do not expand the vector; 0: compute new_len and expand | |
[in,out] | num_expansions | Number of times the memory has been expanded |
Definition at line 63 of file SparseLU_Memory.h.
{ float alpha = 1.5; // Ratio of the memory increase Index new_len; // New size of the allocated memory if(num_expansions == 0 || keep_prev) new_len = length ; // First time allocate requested else new_len = (std::max)(length+1,Index(alpha * length)); VectorType old_vec; // Temporary vector to hold the previous values if (nbElts > 0 ) old_vec = vec.segment(0,nbElts); //Allocate or expand the current vector #ifdef EIGEN_EXCEPTIONS try #endif { vec.resize(new_len); } #ifdef EIGEN_EXCEPTIONS catch(std::bad_alloc& ) #else if(!vec.size()) #endif { if (!num_expansions) { // First time to allocate from LUMemInit() // Let LUMemInit() deals with it. return -1; } if (keep_prev) { // In this case, the memory length should not not be reduced return new_len; } else { // Reduce the size and increase again Index tries = 0; // Number of attempts do { alpha = (alpha + 1)/2; new_len = (std::max)(length+1,Index(alpha * length)); #ifdef EIGEN_EXCEPTIONS try #endif { vec.resize(new_len); } #ifdef EIGEN_EXCEPTIONS catch(std::bad_alloc& ) #else if (!vec.size()) #endif { tries += 1; if ( tries > 10) return new_len; } } while (!vec.size()); } } //Copy the previous values to the newly allocated space if (nbElts > 0) vec.segment(0, nbElts) = old_vec; length = new_len; if(num_expansions) ++num_expansions; return 0; }
void Eigen::internal::SparseLUImpl< Scalar, StorageIndex >::fixupL | ( | const Index | n, |
const IndexVector & | perm_r, | ||
GlobalLU_t & | glu | ||
) | [protected] |
Fix up the data storage lsub for L-subscripts.
It removes the subscripts sets for structural pruning, and applies permutation to the remaining subscripts
Definition at line 52 of file SparseLU_Utils.h.
{ Index fsupc, i, j, k, jstart; StorageIndex nextl = 0; Index nsuper = (glu.supno)(n); // For each supernode for (i = 0; i <= nsuper; i++) { fsupc = glu.xsup(i); jstart = glu.xlsub(fsupc); glu.xlsub(fsupc) = nextl; for (j = jstart; j < glu.xlsub(fsupc + 1); j++) { glu.lsub(nextl) = perm_r(glu.lsub(j)); // Now indexed into P*A nextl++; } for (k = fsupc+1; k < glu.xsup(i+1); k++) glu.xlsub(k) = nextl; // other columns in supernode i } glu.xlsub(n) = nextl; }
void Eigen::internal::SparseLUImpl< Scalar, StorageIndex >::heap_relax_snode | ( | const Index | n, |
IndexVector & | et, | ||
const Index | relax_columns, | ||
IndexVector & | descendants, | ||
IndexVector & | relax_end | ||
) | [protected] |
Identify the initial relaxed supernodes.
This routine applied to a symmetric elimination tree. It assumes that the matrix has been reordered according to the postorder of the etree
n | The number of columns |
et | elimination tree |
relax_columns | Maximum number of columns allowed in a relaxed snode |
descendants | Number of descendants of each node in the etree |
relax_end | last column in a supernode |
Definition at line 46 of file SparseLU_heap_relax_snode.h.
{ // The etree may not be postordered, but its heap ordered IndexVector post; internal::treePostorder(StorageIndex(n), et, post); // Post order etree IndexVector inv_post(n+1); for (StorageIndex i = 0; i < n+1; ++i) inv_post(post(i)) = i; // inv_post = post.inverse()??? // Renumber etree in postorder IndexVector iwork(n); IndexVector et_save(n+1); for (Index i = 0; i < n; ++i) { iwork(post(i)) = post(et(i)); } et_save = et; // Save the original etree et = iwork; // compute the number of descendants of each node in the etree relax_end.setConstant(emptyIdxLU); Index j, parent; descendants.setZero(); for (j = 0; j < n; j++) { parent = et(j); if (parent != n) // not the dummy root descendants(parent) += descendants(j) + 1; } // Identify the relaxed supernodes by postorder traversal of the etree Index snode_start; // beginning of a snode StorageIndex k; Index nsuper_et_post = 0; // Number of relaxed snodes in postordered etree Index nsuper_et = 0; // Number of relaxed snodes in the original etree StorageIndex l; for (j = 0; j < n; ) { parent = et(j); snode_start = j; while ( parent != n && descendants(parent) < relax_columns ) { j = parent; parent = et(j); } // Found a supernode in postordered etree, j is the last column ++nsuper_et_post; k = StorageIndex(n); for (Index i = snode_start; i <= j; ++i) k = (std::min)(k, inv_post(i)); l = inv_post(j); if ( (l - k) == (j - snode_start) ) // Same number of columns in the snode { // This is also a supernode in the original etree relax_end(k) = l; // Record last column ++nsuper_et; } else { for (Index i = snode_start; i <= j; ++i) { l = inv_post(i); if (descendants(i) == 0) { relax_end(l) = l; ++nsuper_et; } } } j++; // Search for a new leaf while (descendants(j) != 0 && j < n) j++; } // End postorder traversal of the etree // Recover the original etree et = et_save; }
Index Eigen::internal::SparseLUImpl< Scalar, StorageIndex >::memInit | ( | Index | m, |
Index | n, | ||
Index | annz, | ||
Index | lwork, | ||
Index | fillratio, | ||
Index | panel_size, | ||
GlobalLU_t & | glu | ||
) | [protected] |
Allocate various working space for the numerical factorization phase.
m | number of rows of the input matrix |
n | number of columns |
annz | number of initial nonzeros in the matrix |
lwork | if lwork=-1, this routine returns an estimated size of the required memory |
glu | persistent data to facilitate multiple factors : will be deleted later ?? |
fillratio | estimated ratio of fill in the factors |
panel_size | Size of a panel |
Definition at line 151 of file SparseLU_Memory.h.
{ Index& num_expansions = glu.num_expansions; //No memory expansions so far num_expansions = 0; glu.nzumax = glu.nzlumax = (std::min)(fillratio * (annz+1) / n, m) * n; // estimated number of nonzeros in U glu.nzlmax = (std::max)(Index(4), fillratio) * (annz+1) / 4; // estimated nnz in L factor // Return the estimated size to the user if necessary Index tempSpace; tempSpace = (2*panel_size + 4 + LUNoMarker) * m * sizeof(Index) + (panel_size + 1) * m * sizeof(Scalar); if (lwork == emptyIdxLU) { Index estimated_size; estimated_size = (5 * n + 5) * sizeof(Index) + tempSpace + (glu.nzlmax + glu.nzumax) * sizeof(Index) + (glu.nzlumax+glu.nzumax) * sizeof(Scalar) + n; return estimated_size; } // Setup the required space // First allocate Integer pointers for L\U factors glu.xsup.resize(n+1); glu.supno.resize(n+1); glu.xlsub.resize(n+1); glu.xlusup.resize(n+1); glu.xusub.resize(n+1); // Reserve memory for L/U factors do { if( (expand<ScalarVector>(glu.lusup, glu.nzlumax, 0, 0, num_expansions)<0) || (expand<ScalarVector>(glu.ucol, glu.nzumax, 0, 0, num_expansions)<0) || (expand<IndexVector> (glu.lsub, glu.nzlmax, 0, 0, num_expansions)<0) || (expand<IndexVector> (glu.usub, glu.nzumax, 0, 1, num_expansions)<0) ) { //Reduce the estimated size and retry glu.nzlumax /= 2; glu.nzumax /= 2; glu.nzlmax /= 2; if (glu.nzlumax < annz ) return glu.nzlumax; } } while (!glu.lusup.size() || !glu.ucol.size() || !glu.lsub.size() || !glu.usub.size()); ++num_expansions; return 0; } // end LuMemInit
Index Eigen::internal::SparseLUImpl< Scalar, StorageIndex >::memXpand | ( | VectorType & | vec, |
Index & | maxlen, | ||
Index | nbElts, | ||
MemType | memtype, | ||
Index & | num_expansions | ||
) | [protected] |
Expand the existing storage.
vec | vector to expand | |
[in,out] | maxlen | On input, previous size of vec (Number of elements to copy ). on output, new size |
nbElts | current number of elements in the vector. | |
memtype | Type of the element to expand | |
num_expansions | Number of expansions |
Definition at line 209 of file SparseLU_Memory.h.
void Eigen::internal::SparseLUImpl< Scalar, StorageIndex >::panel_bmod | ( | const Index | m, |
const Index | w, | ||
const Index | jcol, | ||
const Index | nseg, | ||
ScalarVector & | dense, | ||
ScalarVector & | tempv, | ||
IndexVector & | segrep, | ||
IndexVector & | repfnz, | ||
GlobalLU_t & | glu | ||
) | [protected] |
Performs numeric block updates (sup-panel) in topological order.
Before entering this routine, the original nonzeros in the panel were already copied i nto the spa[m,w]
m | number of rows in the matrix |
w | Panel size |
jcol | Starting column of the panel |
nseg | Number of segments in the U part |
dense | Store the full representation of the panel |
tempv | working array |
segrep | segment representative... first row in the segment |
repfnz | First nonzero rows |
glu | Global LU data. |
Definition at line 56 of file SparseLU_panel_bmod.h.
{ Index ksub,jj,nextl_col; Index fsupc, nsupc, nsupr, nrow; Index krep, kfnz; Index lptr; // points to the row subscripts of a supernode Index luptr; // ... Index segsize,no_zeros ; // For each nonz supernode segment of U[*,j] in topological order Index k = nseg - 1; const Index PacketSize = internal::packet_traits<Scalar>::size; for (ksub = 0; ksub < nseg; ksub++) { // For each updating supernode /* krep = representative of current k-th supernode * fsupc = first supernodal column * nsupc = number of columns in a supernode * nsupr = number of rows in a supernode */ krep = segrep(k); k--; fsupc = glu.xsup(glu.supno(krep)); nsupc = krep - fsupc + 1; nsupr = glu.xlsub(fsupc+1) - glu.xlsub(fsupc); nrow = nsupr - nsupc; lptr = glu.xlsub(fsupc); // loop over the panel columns to detect the actual number of columns and rows Index u_rows = 0; Index u_cols = 0; for (jj = jcol; jj < jcol + w; jj++) { nextl_col = (jj-jcol) * m; VectorBlock<IndexVector> repfnz_col(repfnz, nextl_col, m); // First nonzero column index for each row kfnz = repfnz_col(krep); if ( kfnz == emptyIdxLU ) continue; // skip any zero segment segsize = krep - kfnz + 1; u_cols++; u_rows = (std::max)(segsize,u_rows); } if(nsupc >= 2) { Index ldu = internal::first_multiple<Index>(u_rows, PacketSize); Map<ScalarMatrix, Aligned, OuterStride<> > U(tempv.data(), u_rows, u_cols, OuterStride<>(ldu)); // gather U Index u_col = 0; for (jj = jcol; jj < jcol + w; jj++) { nextl_col = (jj-jcol) * m; VectorBlock<IndexVector> repfnz_col(repfnz, nextl_col, m); // First nonzero column index for each row VectorBlock<ScalarVector> dense_col(dense, nextl_col, m); // Scatter/gather entire matrix column from/to here kfnz = repfnz_col(krep); if ( kfnz == emptyIdxLU ) continue; // skip any zero segment segsize = krep - kfnz + 1; luptr = glu.xlusup(fsupc); no_zeros = kfnz - fsupc; Index isub = lptr + no_zeros; Index off = u_rows-segsize; for (Index i = 0; i < off; i++) U(i,u_col) = 0; for (Index i = 0; i < segsize; i++) { Index irow = glu.lsub(isub); U(i+off,u_col) = dense_col(irow); ++isub; } u_col++; } // solve U = A^-1 U luptr = glu.xlusup(fsupc); Index lda = glu.xlusup(fsupc+1) - glu.xlusup(fsupc); no_zeros = (krep - u_rows + 1) - fsupc; luptr += lda * no_zeros + no_zeros; MappedMatrixBlock A(glu.lusup.data()+luptr, u_rows, u_rows, OuterStride<>(lda) ); U = A.template triangularView<UnitLower>().solve(U); // update luptr += u_rows; MappedMatrixBlock B(glu.lusup.data()+luptr, nrow, u_rows, OuterStride<>(lda) ); eigen_assert(tempv.size()>w*ldu + nrow*w + 1); Index ldl = internal::first_multiple<Index>(nrow, PacketSize); Index offset = (PacketSize-internal::first_default_aligned(B.data(), PacketSize)) % PacketSize; MappedMatrixBlock L(tempv.data()+w*ldu+offset, nrow, u_cols, OuterStride<>(ldl)); L.setZero(); internal::sparselu_gemm<Scalar>(L.rows(), L.cols(), B.cols(), B.data(), B.outerStride(), U.data(), U.outerStride(), L.data(), L.outerStride()); // scatter U and L u_col = 0; for (jj = jcol; jj < jcol + w; jj++) { nextl_col = (jj-jcol) * m; VectorBlock<IndexVector> repfnz_col(repfnz, nextl_col, m); // First nonzero column index for each row VectorBlock<ScalarVector> dense_col(dense, nextl_col, m); // Scatter/gather entire matrix column from/to here kfnz = repfnz_col(krep); if ( kfnz == emptyIdxLU ) continue; // skip any zero segment segsize = krep - kfnz + 1; no_zeros = kfnz - fsupc; Index isub = lptr + no_zeros; Index off = u_rows-segsize; for (Index i = 0; i < segsize; i++) { Index irow = glu.lsub(isub++); dense_col(irow) = U.coeff(i+off,u_col); U.coeffRef(i+off,u_col) = 0; } // Scatter l into SPA dense[] for (Index i = 0; i < nrow; i++) { Index irow = glu.lsub(isub++); dense_col(irow) -= L.coeff(i,u_col); L.coeffRef(i,u_col) = 0; } u_col++; } } else // level 2 only { // Sequence through each column in the panel for (jj = jcol; jj < jcol + w; jj++) { nextl_col = (jj-jcol) * m; VectorBlock<IndexVector> repfnz_col(repfnz, nextl_col, m); // First nonzero column index for each row VectorBlock<ScalarVector> dense_col(dense, nextl_col, m); // Scatter/gather entire matrix column from/to here kfnz = repfnz_col(krep); if ( kfnz == emptyIdxLU ) continue; // skip any zero segment segsize = krep - kfnz + 1; luptr = glu.xlusup(fsupc); Index lda = glu.xlusup(fsupc+1)-glu.xlusup(fsupc);// nsupr // Perform a trianglar solve and block update, // then scatter the result of sup-col update to dense[] no_zeros = kfnz - fsupc; if(segsize==1) LU_kernel_bmod<1>::run(segsize, dense_col, tempv, glu.lusup, luptr, lda, nrow, glu.lsub, lptr, no_zeros); else if(segsize==2) LU_kernel_bmod<2>::run(segsize, dense_col, tempv, glu.lusup, luptr, lda, nrow, glu.lsub, lptr, no_zeros); else if(segsize==3) LU_kernel_bmod<3>::run(segsize, dense_col, tempv, glu.lusup, luptr, lda, nrow, glu.lsub, lptr, no_zeros); else LU_kernel_bmod<Dynamic>::run(segsize, dense_col, tempv, glu.lusup, luptr, lda, nrow, glu.lsub, lptr, no_zeros); } // End for each column in the panel } } // End for each updating supernode } // end panel bmod
void Eigen::internal::SparseLUImpl< Scalar, StorageIndex >::panel_dfs | ( | const Index | m, |
const Index | w, | ||
const Index | jcol, | ||
MatrixType & | A, | ||
IndexVector & | perm_r, | ||
Index & | nseg, | ||
ScalarVector & | dense, | ||
IndexVector & | panel_lsub, | ||
IndexVector & | segrep, | ||
IndexVector & | repfnz, | ||
IndexVector & | xprune, | ||
IndexVector & | marker, | ||
IndexVector & | parent, | ||
IndexVector & | xplore, | ||
GlobalLU_t & | glu | ||
) | [protected] |
Performs a symbolic factorization on a panel of columns [jcol, jcol+w)
A supernode representative is the last column of a supernode. The nonzeros in U[*,j] are segments that end at supernodes representatives
The routine returns a list of the supernodal representatives in topological order of the dfs that generates them. This list is a superset of the topological order of each individual column within the panel. The location of the first nonzero in each supernodal segment (supernodal entry location) is also returned. Each column has a separate list for this purpose.
Two markers arrays are used for dfs : marker[i] == jj, if i was visited during dfs of current column jj; marker1[i] >= jcol, if i was visited by earlier columns in this panel;
[in] | m | number of rows in the matrix |
[in] | w | Panel size |
[in] | jcol | Starting column of the panel |
[in] | A | Input matrix in column-major storage |
[in] | perm_r | Row permutation |
[out] | nseg | Number of U segments |
[out] | dense | Accumulate the column vectors of the panel |
[out] | panel_lsub | Subscripts of the row in the panel |
[out] | segrep | Segment representative i.e first nonzero row of each segment |
[out] | repfnz | First nonzero location in each row |
[out] | xprune | The pruned elimination tree |
[out] | marker | work vector |
parent | The elimination tree | |
xplore | work vector | |
glu | The global data structure |
Definition at line 219 of file SparseLU_panel_dfs.h.
{ Index nextl_col; // Next available position in panel_lsub[*,jj] // Initialize pointers VectorBlock<IndexVector> marker1(marker, m, m); nseg = 0; panel_dfs_traits<IndexVector> traits(jcol, marker1.data()); // For each column in the panel for (StorageIndex jj = StorageIndex(jcol); jj < jcol + w; jj++) { nextl_col = (jj - jcol) * m; VectorBlock<IndexVector> repfnz_col(repfnz, nextl_col, m); // First nonzero location in each row VectorBlock<ScalarVector> dense_col(dense,nextl_col, m); // Accumulate a column vector here // For each nnz in A[*, jj] do depth first search for (typename MatrixType::InnerIterator it(A, jj); it; ++it) { Index krow = it.row(); dense_col(krow) = it.value(); StorageIndex kmark = marker(krow); if (kmark == jj) continue; // krow visited before, go to the next nonzero dfs_kernel(jj, perm_r, nseg, panel_lsub, segrep, repfnz_col, xprune, marker, parent, xplore, glu, nextl_col, krow, traits); }// end for nonzeros in column jj } // end for column jj }
Index Eigen::internal::SparseLUImpl< Scalar, StorageIndex >::pivotL | ( | const Index | jcol, |
const RealScalar & | diagpivotthresh, | ||
IndexVector & | perm_r, | ||
IndexVector & | iperm_c, | ||
Index & | pivrow, | ||
GlobalLU_t & | glu | ||
) | [protected] |
Performs the numerical pivotin on the current column of L, and the CDIV operation.
Pivot policy : (1) Compute thresh = u * max_(i>=j) abs(A_ij); (2) IF user specifies pivot row k and abs(A_kj) >= thresh THEN pivot row = k; ELSE IF abs(A_jj) >= thresh THEN pivot row = j; ELSE pivot row = m;
Note: If you absolutely want to use a given pivot order, then set u=0.0.
jcol | The current column of L | |
diagpivotthresh | diagonal pivoting threshold | |
[in,out] | perm_r | Row permutation (threshold pivoting) |
[in] | iperm_c | column permutation - used to finf diagonal of Pc*A*Pc' |
[out] | pivrow | The pivot row |
glu | Global LU data |
Definition at line 60 of file SparseLU_pivotL.h.
{ Index fsupc = (glu.xsup)((glu.supno)(jcol)); // First column in the supernode containing the column jcol Index nsupc = jcol - fsupc; // Number of columns in the supernode portion, excluding jcol; nsupc >=0 Index lptr = glu.xlsub(fsupc); // pointer to the starting location of the row subscripts for this supernode portion Index nsupr = glu.xlsub(fsupc+1) - lptr; // Number of rows in the supernode Index lda = glu.xlusup(fsupc+1) - glu.xlusup(fsupc); // leading dimension Scalar* lu_sup_ptr = &(glu.lusup.data()[glu.xlusup(fsupc)]); // Start of the current supernode Scalar* lu_col_ptr = &(glu.lusup.data()[glu.xlusup(jcol)]); // Start of jcol in the supernode StorageIndex* lsub_ptr = &(glu.lsub.data()[lptr]); // Start of row indices of the supernode // Determine the largest abs numerical value for partial pivoting Index diagind = iperm_c(jcol); // diagonal index RealScalar pivmax(-1.0); Index pivptr = nsupc; Index diag = emptyIdxLU; RealScalar rtemp; Index isub, icol, itemp, k; for (isub = nsupc; isub < nsupr; ++isub) { using std::abs; rtemp = abs(lu_col_ptr[isub]); if (rtemp > pivmax) { pivmax = rtemp; pivptr = isub; } if (lsub_ptr[isub] == diagind) diag = isub; } // Test for singularity if ( pivmax <= RealScalar(0.0) ) { // if pivmax == -1, the column is structurally empty, otherwise it is only numerically zero pivrow = pivmax < RealScalar(0.0) ? diagind : lsub_ptr[pivptr]; perm_r(pivrow) = StorageIndex(jcol); return (jcol+1); } RealScalar thresh = diagpivotthresh * pivmax; // Choose appropriate pivotal element { // Test if the diagonal element can be used as a pivot (given the threshold value) if (diag >= 0 ) { // Diagonal element exists using std::abs; rtemp = abs(lu_col_ptr[diag]); if (rtemp != RealScalar(0.0) && rtemp >= thresh) pivptr = diag; } pivrow = lsub_ptr[pivptr]; } // Record pivot row perm_r(pivrow) = StorageIndex(jcol); // Interchange row subscripts if (pivptr != nsupc ) { std::swap( lsub_ptr[pivptr], lsub_ptr[nsupc] ); // Interchange numerical values as well, for the two rows in the whole snode // such that L is indexed the same way as A for (icol = 0; icol <= nsupc; icol++) { itemp = pivptr + icol * lda; std::swap(lu_sup_ptr[itemp], lu_sup_ptr[nsupc + icol * lda]); } } // cdiv operations Scalar temp = Scalar(1.0) / lu_col_ptr[nsupc]; for (k = nsupc+1; k < nsupr; k++) lu_col_ptr[k] *= temp; return 0; }
void Eigen::internal::SparseLUImpl< Scalar, StorageIndex >::pruneL | ( | const Index | jcol, |
const IndexVector & | perm_r, | ||
const Index | pivrow, | ||
const Index | nseg, | ||
const IndexVector & | segrep, | ||
BlockIndexVector | repfnz, | ||
IndexVector & | xprune, | ||
GlobalLU_t & | glu | ||
) | [protected] |
Prunes the L-structure.
It prunes the L-structure of supernodes whose L-structure contains the current pivot row "pivrow"
jcol | The current column of L | |
[in] | perm_r | Row permutation |
[out] | pivrow | The pivot row |
nseg | Number of segments | |
segrep | ||
repfnz | ||
[out] | xprune | |
glu | Global LU data |
Definition at line 53 of file SparseLU_pruneL.h.
{ // For each supernode-rep irep in U(*,j] Index jsupno = glu.supno(jcol); Index i,irep,irep1; bool movnum, do_prune = false; Index kmin = 0, kmax = 0, minloc, maxloc,krow; for (i = 0; i < nseg; i++) { irep = segrep(i); irep1 = irep + 1; do_prune = false; // Don't prune with a zero U-segment if (repfnz(irep) == emptyIdxLU) continue; // If a snode overlaps with the next panel, then the U-segment // is fragmented into two parts -- irep and irep1. We should let // pruning occur at the rep-column in irep1s snode. if (glu.supno(irep) == glu.supno(irep1) ) continue; // don't prune // If it has not been pruned & it has a nonz in row L(pivrow,i) if (glu.supno(irep) != jsupno ) { if ( xprune (irep) >= glu.xlsub(irep1) ) { kmin = glu.xlsub(irep); kmax = glu.xlsub(irep1) - 1; for (krow = kmin; krow <= kmax; krow++) { if (glu.lsub(krow) == pivrow) { do_prune = true; break; } } } if (do_prune) { // do a quicksort-type partition // movnum=true means that the num values have to be exchanged movnum = false; if (irep == glu.xsup(glu.supno(irep)) ) // Snode of size 1 movnum = true; while (kmin <= kmax) { if (perm_r(glu.lsub(kmax)) == emptyIdxLU) kmax--; else if ( perm_r(glu.lsub(kmin)) != emptyIdxLU) kmin++; else { // kmin below pivrow (not yet pivoted), and kmax // above pivrow: interchange the two suscripts std::swap(glu.lsub(kmin), glu.lsub(kmax)); // If the supernode has only one column, then we // only keep one set of subscripts. For any subscript // intercnahge performed, similar interchange must be // done on the numerical values. if (movnum) { minloc = glu.xlusup(irep) + ( kmin - glu.xlsub(irep) ); maxloc = glu.xlusup(irep) + ( kmax - glu.xlsub(irep) ); std::swap(glu.lusup(minloc), glu.lusup(maxloc)); } kmin++; kmax--; } } // end while xprune(irep) = StorageIndex(kmin); //Pruning } // end if do_prune } // end pruning } // End for each U-segment }
void Eigen::internal::SparseLUImpl< Scalar, StorageIndex >::relax_snode | ( | const Index | n, |
IndexVector & | et, | ||
const Index | relax_columns, | ||
IndexVector & | descendants, | ||
IndexVector & | relax_end | ||
) | [protected] |
Identify the initial relaxed supernodes.
This routine is applied to a column elimination tree. It assumes that the matrix has been reordered according to the postorder of the etree
n | the number of columns |
et | elimination tree |
relax_columns | Maximum number of columns allowed in a relaxed snode |
descendants | Number of descendants of each node in the etree |
relax_end | last column in a supernode |
Definition at line 47 of file SparseLU_relax_snode.h.
{ // compute the number of descendants of each node in the etree Index parent; relax_end.setConstant(emptyIdxLU); descendants.setZero(); for (Index j = 0; j < n; j++) { parent = et(j); if (parent != n) // not the dummy root descendants(parent) += descendants(j) + 1; } // Identify the relaxed supernodes by postorder traversal of the etree Index snode_start; // beginning of a snode for (Index j = 0; j < n; ) { parent = et(j); snode_start = j; while ( parent != n && descendants(parent) < relax_columns ) { j = parent; parent = et(j); } // Found a supernode in postordered etree, j is the last column relax_end(snode_start) = StorageIndex(j); // Record last column j++; // Search for a new leaf while (descendants(j) != 0 && j < n) j++; } // End postorder traversal of the etree }
Index Eigen::internal::SparseLUImpl< Scalar, StorageIndex >::snode_bmod | ( | const Index | jcol, |
const Index | fsupc, | ||
ScalarVector & | dense, | ||
GlobalLU_t & | glu | ||
) | [protected] |
Index Eigen::internal::SparseLUImpl< Scalar, StorageIndex >::snode_dfs | ( | const Index | jcol, |
const Index | kcol, | ||
const MatrixType & | mat, | ||
IndexVector & | xprune, | ||
IndexVector & | marker, | ||
GlobalLU_t & | glu | ||
) | [protected] |
friend struct column_dfs_traits [friend] |
Definition at line 60 of file SparseLUImpl.h.