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