|  | // 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> | 
|  | // | 
|  | // 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/. | 
|  |  | 
|  | /* | 
|  |  | 
|  | * NOTE: This file is the modified version of [s,d,c,z]panel_dfs.c file in SuperLU | 
|  |  | 
|  | * -- SuperLU routine (version 2.0) -- | 
|  | * Univ. of California Berkeley, Xerox Palo Alto Research Center, | 
|  | * and Lawrence Berkeley National Lab. | 
|  | * November 15, 1997 | 
|  | * | 
|  | * Copyright (c) 1994 by Xerox Corporation.  All rights reserved. | 
|  | * | 
|  | * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY | 
|  | * EXPRESSED OR IMPLIED.  ANY USE IS AT YOUR OWN RISK. | 
|  | * | 
|  | * Permission is hereby granted to use or copy this program for any | 
|  | * purpose, provided the above notices are retained on all copies. | 
|  | * Permission to modify the code and to distribute modified code is | 
|  | * granted, provided the above notices are retained, and a notice that | 
|  | * the code was modified is included with the above copyright notice. | 
|  | */ | 
|  | #ifndef SPARSELU_PANEL_DFS_H | 
|  | #define SPARSELU_PANEL_DFS_H | 
|  |  | 
|  | // IWYU pragma: private | 
|  | #include "./InternalHeaderCheck.h" | 
|  |  | 
|  | namespace Eigen { | 
|  |  | 
|  | namespace internal { | 
|  |  | 
|  | template <typename IndexVector> | 
|  | struct panel_dfs_traits { | 
|  | typedef typename IndexVector::Scalar StorageIndex; | 
|  | panel_dfs_traits(Index jcol, StorageIndex* marker) : m_jcol(jcol), m_marker(marker) {} | 
|  | bool update_segrep(Index krep, StorageIndex jj) { | 
|  | if (m_marker[krep] < m_jcol) { | 
|  | m_marker[krep] = jj; | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  | void mem_expand(IndexVector& /*glu.lsub*/, Index /*nextl*/, Index /*chmark*/) {} | 
|  | enum { ExpandMem = false }; | 
|  | Index m_jcol; | 
|  | StorageIndex* m_marker; | 
|  | }; | 
|  |  | 
|  | template <typename Scalar, typename StorageIndex> | 
|  | template <typename Traits> | 
|  | void 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) { | 
|  | 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) | 
|  | } | 
|  |  | 
|  | /** | 
|  | * \brief 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; | 
|  | * | 
|  | * \param[in] m number of rows in the matrix | 
|  | * \param[in] w Panel size | 
|  | * \param[in] jcol Starting  column of the panel | 
|  | * \param[in] A Input matrix in column-major storage | 
|  | * \param[in] perm_r Row permutation | 
|  | * \param[out] nseg Number of U segments | 
|  | * \param[out] dense Accumulate the column vectors of the panel | 
|  | * \param[out] panel_lsub Subscripts of the row in the panel | 
|  | * \param[out] segrep Segment representative i.e first nonzero row of each segment | 
|  | * \param[out] repfnz First nonzero location in each row | 
|  | * \param[out] xprune The pruned elimination tree | 
|  | * \param[out] marker work vector | 
|  | * \param  parent The elimination tree | 
|  | * \param xplore work vector | 
|  | * \param glu The global data structure | 
|  | * | 
|  | */ | 
|  |  | 
|  | template <typename Scalar, typename StorageIndex> | 
|  | void 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) { | 
|  | 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 | 
|  | } | 
|  |  | 
|  | }  // end namespace internal | 
|  | }  // end namespace Eigen | 
|  |  | 
|  | #endif  // SPARSELU_PANEL_DFS_H |