| // 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 |