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