SparseLU_panel_dfs.h 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. // This file is part of Eigen, a lightweight C++ template library
  2. // for linear algebra.
  3. //
  4. // Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
  5. //
  6. // This Source Code Form is subject to the terms of the Mozilla
  7. // Public License v. 2.0. If a copy of the MPL was not distributed
  8. // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
  9. /*
  10. * NOTE: This file is the modified version of [s,d,c,z]panel_dfs.c file in SuperLU
  11. * -- SuperLU routine (version 2.0) --
  12. * Univ. of California Berkeley, Xerox Palo Alto Research Center,
  13. * and Lawrence Berkeley National Lab.
  14. * November 15, 1997
  15. *
  16. * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
  17. *
  18. * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
  19. * EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
  20. *
  21. * Permission is hereby granted to use or copy this program for any
  22. * purpose, provided the above notices are retained on all copies.
  23. * Permission to modify the code and to distribute modified code is
  24. * granted, provided the above notices are retained, and a notice that
  25. * the code was modified is included with the above copyright notice.
  26. */
  27. #ifndef SPARSELU_PANEL_DFS_H
  28. #define SPARSELU_PANEL_DFS_H
  29. namespace Eigen {
  30. namespace internal {
  31. template<typename IndexVector>
  32. struct panel_dfs_traits
  33. {
  34. typedef typename IndexVector::Scalar StorageIndex;
  35. panel_dfs_traits(Index jcol, StorageIndex* marker)
  36. : m_jcol(jcol), m_marker(marker)
  37. {}
  38. bool update_segrep(Index krep, StorageIndex jj)
  39. {
  40. if(m_marker[krep]<m_jcol)
  41. {
  42. m_marker[krep] = jj;
  43. return true;
  44. }
  45. return false;
  46. }
  47. void mem_expand(IndexVector& /*glu.lsub*/, Index /*nextl*/, Index /*chmark*/) {}
  48. enum { ExpandMem = false };
  49. Index m_jcol;
  50. StorageIndex* m_marker;
  51. };
  52. template <typename Scalar, typename StorageIndex>
  53. template <typename Traits>
  54. void SparseLUImpl<Scalar,StorageIndex>::dfs_kernel(const StorageIndex jj, IndexVector& perm_r,
  55. Index& nseg, IndexVector& panel_lsub, IndexVector& segrep,
  56. Ref<IndexVector> repfnz_col, IndexVector& xprune, Ref<IndexVector> marker, IndexVector& parent,
  57. IndexVector& xplore, GlobalLU_t& glu,
  58. Index& nextl_col, Index krow, Traits& traits
  59. )
  60. {
  61. StorageIndex kmark = marker(krow);
  62. // For each unmarked krow of jj
  63. marker(krow) = jj;
  64. StorageIndex kperm = perm_r(krow);
  65. if (kperm == emptyIdxLU ) {
  66. // krow is in L : place it in structure of L(*, jj)
  67. panel_lsub(nextl_col++) = StorageIndex(krow); // krow is indexed into A
  68. traits.mem_expand(panel_lsub, nextl_col, kmark);
  69. }
  70. else
  71. {
  72. // krow is in U : if its supernode-representative krep
  73. // has been explored, update repfnz(*)
  74. // krep = supernode representative of the current row
  75. StorageIndex krep = glu.xsup(glu.supno(kperm)+1) - 1;
  76. // First nonzero element in the current column:
  77. StorageIndex myfnz = repfnz_col(krep);
  78. if (myfnz != emptyIdxLU )
  79. {
  80. // Representative visited before
  81. if (myfnz > kperm ) repfnz_col(krep) = kperm;
  82. }
  83. else
  84. {
  85. // Otherwise, perform dfs starting at krep
  86. StorageIndex oldrep = emptyIdxLU;
  87. parent(krep) = oldrep;
  88. repfnz_col(krep) = kperm;
  89. StorageIndex xdfs = glu.xlsub(krep);
  90. Index maxdfs = xprune(krep);
  91. StorageIndex kpar;
  92. do
  93. {
  94. // For each unmarked kchild of krep
  95. while (xdfs < maxdfs)
  96. {
  97. StorageIndex kchild = glu.lsub(xdfs);
  98. xdfs++;
  99. StorageIndex chmark = marker(kchild);
  100. if (chmark != jj )
  101. {
  102. marker(kchild) = jj;
  103. StorageIndex chperm = perm_r(kchild);
  104. if (chperm == emptyIdxLU)
  105. {
  106. // case kchild is in L: place it in L(*, j)
  107. panel_lsub(nextl_col++) = kchild;
  108. traits.mem_expand(panel_lsub, nextl_col, chmark);
  109. }
  110. else
  111. {
  112. // case kchild is in U :
  113. // chrep = its supernode-rep. If its rep has been explored,
  114. // update its repfnz(*)
  115. StorageIndex chrep = glu.xsup(glu.supno(chperm)+1) - 1;
  116. myfnz = repfnz_col(chrep);
  117. if (myfnz != emptyIdxLU)
  118. { // Visited before
  119. if (myfnz > chperm)
  120. repfnz_col(chrep) = chperm;
  121. }
  122. else
  123. { // Cont. dfs at snode-rep of kchild
  124. xplore(krep) = xdfs;
  125. oldrep = krep;
  126. krep = chrep; // Go deeper down G(L)
  127. parent(krep) = oldrep;
  128. repfnz_col(krep) = chperm;
  129. xdfs = glu.xlsub(krep);
  130. maxdfs = xprune(krep);
  131. } // end if myfnz != -1
  132. } // end if chperm == -1
  133. } // end if chmark !=jj
  134. } // end while xdfs < maxdfs
  135. // krow has no more unexplored nbrs :
  136. // Place snode-rep krep in postorder DFS, if this
  137. // segment is seen for the first time. (Note that
  138. // "repfnz(krep)" may change later.)
  139. // Baktrack dfs to its parent
  140. if(traits.update_segrep(krep,jj))
  141. //if (marker1(krep) < jcol )
  142. {
  143. segrep(nseg) = krep;
  144. ++nseg;
  145. //marker1(krep) = jj;
  146. }
  147. kpar = parent(krep); // Pop recursion, mimic recursion
  148. if (kpar == emptyIdxLU)
  149. break; // dfs done
  150. krep = kpar;
  151. xdfs = xplore(krep);
  152. maxdfs = xprune(krep);
  153. } while (kpar != emptyIdxLU); // Do until empty stack
  154. } // end if (myfnz = -1)
  155. } // end if (kperm == -1)
  156. }
  157. /**
  158. * \brief Performs a symbolic factorization on a panel of columns [jcol, jcol+w)
  159. *
  160. * A supernode representative is the last column of a supernode.
  161. * The nonzeros in U[*,j] are segments that end at supernodes representatives
  162. *
  163. * The routine returns a list of the supernodal representatives
  164. * in topological order of the dfs that generates them. This list is
  165. * a superset of the topological order of each individual column within
  166. * the panel.
  167. * The location of the first nonzero in each supernodal segment
  168. * (supernodal entry location) is also returned. Each column has
  169. * a separate list for this purpose.
  170. *
  171. * Two markers arrays are used for dfs :
  172. * marker[i] == jj, if i was visited during dfs of current column jj;
  173. * marker1[i] >= jcol, if i was visited by earlier columns in this panel;
  174. *
  175. * \param[in] m number of rows in the matrix
  176. * \param[in] w Panel size
  177. * \param[in] jcol Starting column of the panel
  178. * \param[in] A Input matrix in column-major storage
  179. * \param[in] perm_r Row permutation
  180. * \param[out] nseg Number of U segments
  181. * \param[out] dense Accumulate the column vectors of the panel
  182. * \param[out] panel_lsub Subscripts of the row in the panel
  183. * \param[out] segrep Segment representative i.e first nonzero row of each segment
  184. * \param[out] repfnz First nonzero location in each row
  185. * \param[out] xprune The pruned elimination tree
  186. * \param[out] marker work vector
  187. * \param parent The elimination tree
  188. * \param xplore work vector
  189. * \param glu The global data structure
  190. *
  191. */
  192. template <typename Scalar, typename StorageIndex>
  193. 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)
  194. {
  195. Index nextl_col; // Next available position in panel_lsub[*,jj]
  196. // Initialize pointers
  197. VectorBlock<IndexVector> marker1(marker, m, m);
  198. nseg = 0;
  199. panel_dfs_traits<IndexVector> traits(jcol, marker1.data());
  200. // For each column in the panel
  201. for (StorageIndex jj = StorageIndex(jcol); jj < jcol + w; jj++)
  202. {
  203. nextl_col = (jj - jcol) * m;
  204. VectorBlock<IndexVector> repfnz_col(repfnz, nextl_col, m); // First nonzero location in each row
  205. VectorBlock<ScalarVector> dense_col(dense,nextl_col, m); // Accumulate a column vector here
  206. // For each nnz in A[*, jj] do depth first search
  207. for (typename MatrixType::InnerIterator it(A, jj); it; ++it)
  208. {
  209. Index krow = it.row();
  210. dense_col(krow) = it.value();
  211. StorageIndex kmark = marker(krow);
  212. if (kmark == jj)
  213. continue; // krow visited before, go to the next nonzero
  214. dfs_kernel(jj, perm_r, nseg, panel_lsub, segrep, repfnz_col, xprune, marker, parent,
  215. xplore, glu, nextl_col, krow, traits);
  216. }// end for nonzeros in column jj
  217. } // end for column jj
  218. }
  219. } // end namespace internal
  220. } // end namespace Eigen
  221. #endif // SPARSELU_PANEL_DFS_H