diff options
author | Desire NUENTSA <desire.nuentsa_wakam@inria.fr> | 2012-05-25 18:17:57 +0200 |
---|---|---|
committer | Desire NUENTSA <desire.nuentsa_wakam@inria.fr> | 2012-05-25 18:17:57 +0200 |
commit | b6267507ea08bf572666bf634bc3a6fabe6aba11 (patch) | |
tree | 01843518d9cbc5208cc75a31672c7a93c3030af1 /Eigen/src | |
parent | b202c5ed2f3c4fac09c76e34ea728377a79fa15d (diff) |
Add preliminary files for SparseLU
Diffstat (limited to 'Eigen/src')
-rw-r--r-- | Eigen/src/SparseLU/SparseLU.h | 341 | ||||
-rw-r--r-- | Eigen/src/SparseLU/SparseLU_Coletree.h | 188 | ||||
-rw-r--r-- | Eigen/src/SparseLU/SparseLU_Matrix.h | 74 | ||||
-rw-r--r-- | Eigen/src/SparseLU/SparseLU_Memory.h | 242 | ||||
-rw-r--r-- | Eigen/src/SparseLU/SparseLU_Structs.h | 122 | ||||
-rw-r--r-- | Eigen/src/SparseLU/SparseLU_Utils.h | 32 | ||||
-rw-r--r-- | Eigen/src/SparseLU/SparseLU_heap_relax_snode.h | 133 | ||||
-rw-r--r-- | Eigen/src/SparseLU/SparseLU_panel_dfs.h | 221 | ||||
-rw-r--r-- | Eigen/src/SparseLU/SparseLU_pivotL.h | 132 | ||||
-rw-r--r-- | Eigen/src/SparseLU/SparseLU_relax_snode.h | 89 | ||||
-rw-r--r-- | Eigen/src/SparseLU/SparseLU_snode_bmod.h | 88 | ||||
-rw-r--r-- | Eigen/src/SparseLU/SparseLU_snode_dfs.h | 119 |
12 files changed, 1781 insertions, 0 deletions
diff --git a/Eigen/src/SparseLU/SparseLU.h b/Eigen/src/SparseLU/SparseLU.h new file mode 100644 index 000000000..f5a1c787e --- /dev/null +++ b/Eigen/src/SparseLU/SparseLU.h @@ -0,0 +1,341 @@ +// 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> +// +// Eigen is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// Alternatively, you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License and a copy of the GNU General Public License along with +// Eigen. If not, see <http://www.gnu.org/licenses/>. + + +#ifndef EIGEN_SPARSE_LU +#define EIGEN_SPARSE_LU + +#include <Ordering.h> +#include <SparseLU_Utils.h> +#include <SuperNodalMatrix.h> +#include <SparseLU_Structs.h> +#include <SparseLU_Memory.h> +#include <SparseLU_Coletree.h> +namespace Eigen { + +template <typename _MatrixType> +class SparseLU +{ + public: + typedef _MatrixType MatrixType; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::Index Index; + typedef SparseMatrix<Scalar,ColMajor,Index> NCMatrix; + typedef SuperNodalMatrix<Scalar, Index> SCMatrix; + typedef GlobalLU_t<Scalar, Index> Eigen_GlobalLU_t; + typedef Matrix<Scalar,Dynamic,1> VectorType; + typedef PermutationMatrix<Dynamic, Dynamic, Index> PermutationType; + public: + SparseLU():m_isInitialized(true),m_symmetricmode(false),m_fact(DOFACT),m_diagpivotthresh(1.0) + { + initperfvalues(); + } + SparseLU(const MatrixType& matrix):SparseLU() + { + + compute(matrix); + } + + ~SparseLU() + { + + } + + void analyzePattern (const MatrixType& matrix); + void factorize (const MatrixType& matrix); + void compute (const MatrixType& matrix); + + /** Indicate that the pattern of the input matrix is symmetric */ + void isSymmetric(bool sym) + { + m_symmetricmode = sym; + } + + /** Set the threshold used for a diagonal entry to be an acceptable pivot. */ + void diagPivotThresh(RealScalar thresh) + { + m_diagpivotthresh = thresh; + } + protected: + // Functions + void initperfvalues(); + + // Variables + mutable ComputationInfo m_info; + bool m_isInitialized; + bool m_factorizationIsOk; + bool m_analysisIsOk; + fact_t m_fact; + NCMatrix m_mat; // The input (permuted ) matrix + SCMatrix m_Lstore; // The lower triangular matrix (supernodal) + NCMatrix m_Ustore; //The upper triangular matrix + PermutationType m_perm_c; // Column permutation + PermutationType m_iperm_c; // Column permutation + PermutationType m_perm_r ; // Row permutation + PermutationType m_iperm_r ; // Inverse row permutation + VectorXi m_etree; // Column elimination tree + + Scalar *m_work; // + Index *m_iwork; // + static Eigen_GlobalLU_t m_Glu; // persistent data to facilitate multiple factors + // should be defined as a class member + // SuperLU/SparseLU options + bool m_symmetricmode; + + // values for performance + int m_panel_size; // a panel consists of at most <panel_size> consecutive columns + int m_relax; // To control degree of relaxing supernodes. If the number of nodes (columns) + // in a subtree of the elimination tree is less than relax, this subtree is considered + // as one supernode regardless of the row structures of those columns + int m_maxsuper; // The maximum size for a supernode in complete LU + int m_rowblk; // The minimum row dimension for 2-D blocking to be used; + int m_colblk; // The minimum column dimension for 2-D blocking to be used; + int m_fillfactor; // The estimated fills factors for L and U, compared with A + RealScalar m_diagpivotthresh; // Specifies the threshold used for a diagonal entry to be an acceptable pivot + + private: + // Copy constructor + SparseLU (SparseLU& ) {} + +}; // End class SparseLU + +/* Set the default values for performance */ +void SparseLU::initperfvalues() +{ + m_panel_size = 12; + m_relax = 1; + m_maxsuper = 100; + m_rowblk = 200; + m_colblk = 60; + m_fillfactor = 20; +} + + +/** + * Compute the column permutation to minimize the fill-in (file amd.c ) + * - Apply this permutation to the input matrix - + * - Compute the column elimination tree on the permuted matrix (file Eigen_Coletree.h) + * - Postorder the elimination tree and the column permutation (file Eigen_Coletree.h) + * - + */ +template <typename MatrixType> +void SparseLU::analyzePattern(const MatrixType& mat) +{ + // Compute the column permutation + AMDordering amd(mat); + m_perm_c = amd.get_perm_c(); + // Apply the permutation to the column of the input matrix + m_mat = mat * m_perm_c; //how is the permutation represented ??? + + // Compute the column elimination tree of the permuted matrix + if (m_etree.size() == 0) m_etree.resize(m_mat.cols()); + internal::sp_coletree(m_mat, m_etree); + + // In symmetric mode, do not do postorder here + if (m_symmetricmode == false) { + VectorXi post, iwork; + // Post order etree + post = internal::TreePostorder(m_mat.cols(), m_etree); + + // Renumber etree in postorder + iwork.resize(n+1); + for (i = 0; i < n; ++i) iwork(post(i)) = post(m_etree(i)); + m_etree = iwork; + + // Postmultiply A*Pc by post, + // i.e reorder the matrix according to the postorder of the etree + // FIXME Check if this is available : constructor from a vector + PermutationType post_perm(post); + m_mat = m_mat * post_perm; + + // Product of m_perm_c and post + for (i = 0; i < n; ++i) iwork(i) = m_perm_c(post_perm.indices()(i)); + m_perm_c = iwork; + } // end postordering +} + +/** + * - Numerical factorization + * - Interleaved with the symbolic factorization + * \tparam MatrixType The type of the matrix, it should be a column-major sparse matrix + * \return info where + * : successful exit + * = 0: successful exit + * > 0: if info = i, and i is + * <= A->ncol: U(i,i) is exactly zero. The factorization has + * been completed, but the factor U is exactly singular, + * and division by zero will occur if it is used to solve a + * system of equations. + * > A->ncol: number of bytes allocated when memory allocation + * failure occurred, plus A->ncol. If lwork = -1, it is + * the estimated amount of space needed, plus A->ncol. + */ +template <typename MatrixType> +int SparseLU::factorize(const MatrixType& matrix) +{ + + // Allocate storage common to the factor routines + int lwork = 0; + int info = LUMemInit(lwork); + eigen_assert ( (info == 0) && "Unable to allocate memory for the factors"); + + int m = m_mat.rows(); + int n = m_mat.cols(); + int maxpanel = m_panel_size * m; + + // Set up pointers for integer working arrays + Map<VectorXi> segrep(m_iwork, m); // + Map<VectorXi> parent(&segrep(0) + m, m); // + Map<VectorXi> xplore(&parent(0) + m, m); // + Map<VectorXi> repfnz(&xplore(0) + m, maxpanel); // + Map<VectorXi> panel_lsub(&repfnz(0) + maxpanel, maxpanel);// + Map<VectorXi> xprune(&panel_lsub(0) + maxpanel, n); // + Map<VectorXi> marker(&xprune(0)+n, m * LU_NO_MARKER); // + repfnz.setConstant(-1); + panel_lsub.setConstant(-1); + + // Set up pointers for scalar working arrays + VectorType dense(maxpanel); + dense.setZero(); + VectorType tempv(LU_NUM_TEMPV(m,m_panel_size,m_maxsuper,m_rowblk); + tempv.setZero(); + + // Setup Permutation vectors + PermutationType iperm_r; // inverse of perm_r + if (m_fact = SamePattern_SameRowPerm) + iperm_r = m_perm_r.inverse(); + // Compute the inverse of perm_c + PermutationType iperm_c; + iperm_c = m_perm_c.inverse(); + + // Identify initial relaxed snodes + VectorXi relax_end(n); + if ( m_symmetricmode = true ) + LU_heap_relax_snode(n, m_etree, m_relax, marker, relax_end); + else + LU_relax_snode(n, m_etree, m_relax, marker, relax_end); + + m_perm_r.setConstant(-1); + marker.setConstant(-1); + + VectorXi& xsup = m_Glu.xsup; + VectorXi& supno = m_GLu.supno; + VectorXi& xlsub = m_Glu.xlsub; + VectorXi& xlusup = m_GLu.xlusup; + VectorXi& xusub = m_Glu.xusub; + + supno(0) = -1; + xsup(0) = xlsub(0) = xusub(0) = xlusup(0); + int panel_size = m_panel_size; + int wdef = panel_size; // upper bound on panel width + + // Work on one 'panel' at a time. A panel is one of the following : + // (a) a relaxed supernode at the bottom of the etree, or + // (b) panel_size contiguous columns, <panel_size> defined by the user + register int jcol,kcol; + int min_mn = std::min(m,n); + VectorXi panel_histo(n); + bool ok = true; + Index nextu, nextlu, jsupno, fsupc, new_next; + int pivrow; // Pivotal row number in the original row matrix + int nseg1; // Number of segments in U-column above panel row jcol + int nseg; // Number of segments in each U-column + for (jcol = 0; jcol < min_mn; ) + { + if (relax_end(jcol) != -1) + { // Starting a relaxed node from jcol + kcol = relax_end(jcol); // End index of the relaxed snode + + // Factorize the relaxed supernode(jcol:kcol) + // First, determine the union of the row structure of the snode + info = LU_snode_dfs(jcol, kcol, m_mat.innerIndexPtr(), m_mat.outerIndexPtr(), xprune, marker); + if ( !info ) + { + ok = false; + break; + } + nextu = xusub(jcol); //starting location of column jcol in ucol + nextlu = xlusup(jcol); //Starting location of column jcol in lusup (rectangular supernodes) + jsupno = supno(jcol); // Supernode number which column jcol belongs to + fsupc = xsup(jsupno); //First column number of the current supernode + new_next = nextlu + (xlsub(fsupc+1)-xlsub(fsupc)) * (kcol - jcol + 1); + nzlumax = m_Glu.nzlumax; + while (new_next > nzlumax ) + { + m_Glu.lusup = LUMemXpand<Scalar>(jcol, nextlu, LUSUP, nzlumax); + m_GLu.nzlumax = nzlumax; + } + // Now, left-looking factorize each column within the snode + for (icol = jcol; icol<=kcol; icol++){ + xusub(icol+1) = nextu; + // Scatter into SPA dense(*) + for (typename MatrixType::InnerIterator it(m_mat, icol); it; ++it) + dense(it.row()) = it.val(); + + // Numeric update within the snode + LU_snode_bmod(icol, jsupno, fsupc, dense, tempv); + + // Eliminate the current column + info = LU_pivotL(icol, pivrow); + eigen_assert(info == 0 && "The matrix is structurally singular"); + } + jcol = icol; // The last column te be eliminated + } + else + { // Work on one panel of panel_size columns + + // Adjust panel size so that a panel won't overlap with the next relaxed snode. + panel_size = w_def; + for (k = jcol + 1; k < std::min(jcol+panel_size, min_mn); k++) + { + if (relax_end(k) != -1) + { + panel_size = k - jcol; + break; + } + } + if (k == min_mn) + panel_size = min_mn - jcol; + + // Symbolic outer factorization on a panel of columns + LU_panel_dfs(m, panel_size, jcol, m_mat, m_perm_r, nseg1, dense, panel_lsub, segrep, repfnz, xprune, marker, parent, xplore, m_Glu); + + // Numeric sup-panel updates in topological order + LU_panel_bmod(m, panel_size, jcol); + + // Sparse LU within the panel, and below the panel diagonal + for ( jj = jcol, j< jcol + panel_size; jj++) + { + k = (jj - jcol) * m; // Column index for w-wide arrays + } // end for + jcol += panel_size; // Move to the next panel + } // end else + } // end for -- end elimination + m_info = ok ? Success : NumericalIssue; + m_factorizationIsOk = ok; +} + + +} // End namespace Eigen +#endif
\ No newline at end of file diff --git a/Eigen/src/SparseLU/SparseLU_Coletree.h b/Eigen/src/SparseLU/SparseLU_Coletree.h new file mode 100644 index 000000000..d57048883 --- /dev/null +++ b/Eigen/src/SparseLU/SparseLU_Coletree.h @@ -0,0 +1,188 @@ +// 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> +// +// Eigen is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// Alternatively, you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License and a copy of the GNU General Public License along with +// Eigen. If not, see <http://www.gnu.org/licenses/>. + +/* + + * NOTE: This file is the modified version of sp_coletree.c file in SuperLU + + * -- SuperLU routine (version 3.1) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * August 1, 2008 + * + * 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_COLETREE_H +#define SPARSELU_COLETREE_H + +/** Compute the column elimination tree of a sparse matrix + * NOTE : The matrix is supposed to be in column-major format. + * + */ +template<typename MatrixType> +int LU_sp_coletree(const MatrixType& mat, VectorXi& parent) +{ + int nc = mat.cols(); // Number of columns + int nr = mat.rows(); // Number of rows + + VectorXi root(nc); // root of subtree of etree + root.setZero(); + VectorXi pp(nc); // disjoint sets + pp.setZero(); // Initialize disjoint sets + VectorXi firstcol(nr); // First nonzero column in each row + firstcol.setZero(); + + //Compute firstcol[row] + int row,col; + firstcol.setConstant(nc); //for (row = 0; row < nr; firstcol(row++) = nc); + for (col = 0; col < nc; col++) + { + for (typename MatrixType::InnerIterator it(mat, col); it; ++it) + { // Is it necessary to brows the whole matrix, the lower part should do the job ?? + row = it.row(); + firstcol(row) = std::min(firstcol(row), col); + } + } + /* Compute etree by Liu's algorithm for symmetric matrices, + except use (firstcol[r],c) in place of an edge (r,c) of A. + Thus each row clique in A'*A is replaced by a star + centered at its first vertex, which has the same fill. */ + int rset, cset, rroot; + for (col = 0; col < nc; col++) + { + pp(col) = cset = col; // Initially, each element is in its own set + root(cset) = col; + parent(col) = nc; + for (typename MatrixType::InnerIterator it(mat, col); it; ++it) + { // A sequence of interleaved find and union is performed + row = firstcol(it.row()); + if (row >= col) continue; + rset = internal::etree_find(row, pp); // Find the name of the set containing row + rroot = root(rset); + if (rroot != col) + { + parent(rroot) = col; + pp(cset) = cset = rset; // Get the union of cset and rset + root(cset) = col; + } + } + } + return 0; +} + +/** Find the root of the tree/set containing the vertex i : Use Path halving */ +int etree_find (int i, VectorXi& pp) +{ + int p = pp(i); // Parent + int gp = pp(p); // Grand parent + while (gp != p) + { + pp(i) = gp; // Parent pointer on find path is changed to former grand parent + i = gp; + p = pp(i); + gp = pp(p); + } + return p; +} + +/** + * Post order a tree + */ +VectorXi TreePostorder(int n, VectorXi& parent) +{ + VectorXi first_kid, next_kid; // Linked list of children + VectorXi post; // postordered etree + int postnum; + // Allocate storage for working arrays and results + first_kid.resize(n+1); + next_kid.setZero(n+1); + post.setZero(n+1); + + // Set up structure describing children + int v, dad; + first_kid.setConstant(-1); + for (v = n-1, v >= 0; v--) + { + dad = parent(v); + next_kid(v) = first_kid(dad); + first_kid(dad) = v; + } + + // Depth-first search from dummy root vertex #n + postnum = 0; + internal::nr_etdfs(n, parent, first_kid, next_kid, post, postnum); + return post; +} +/** + * Depth-first search from vertex n. No recursion. + * This routine was contributed by Cédric Doucet, CEDRAT Group, Meylan, France. +*/ +void nr_etdfs (int n, int *parent, int* first_kid, int *next_kid, int *post, int postnum) +{ + int current = n, first, next; + while (postnum != n) + { + // No kid for the current node + first = first_kid(current); + + // no first kid for the current node + if (first == -1) + { + // Numbering this node because it has no kid + post(current) = postnum++; + + // looking for the next kid + next = next_kid(current); + while (next == -1) + { + // No more kids : back to the parent node + current = parent(current); + // numbering the parent node + post(current) = postnum++; + // Get the next kid + next = next_kid(current); + } + // stopping criterion + if (postnum==n+1) return; + + // Updating current node + current = next; + } + else + { + current = first; + } + } +} + +#endif
\ No newline at end of file diff --git a/Eigen/src/SparseLU/SparseLU_Matrix.h b/Eigen/src/SparseLU/SparseLU_Matrix.h new file mode 100644 index 000000000..c4d56ee0a --- /dev/null +++ b/Eigen/src/SparseLU/SparseLU_Matrix.h @@ -0,0 +1,74 @@ +// 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> +// Copyright (C) 2012 Gael Guennebaud <gael.guennebaud@inria.fr> +// +// Eigen is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// Alternatively, you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License and a copy of the GNU General Public License along with +// Eigen. If not, see <http://www.gnu.org/licenses/>. + +#ifndef EIGEN_SPARSELU_MATRIX_H +#define EIGEN_SPARSELU_MATRIX_H + +/** \ingroup SparseLU_Module + * \brief a class to manipulate the supernodal matrices in the SparseLU factorization + * + * This class extends the class SparseMatrix and should contain the data to easily store + * and manipulate the supernodes during the factorization and solution phase of Sparse LU. + * Only the lower triangular matrix has supernodes. + * + * NOTE : This class corresponds to the SCformat structure in SuperLU + * + */ + +template <typename _Scalar, typename _Index> +class SuperNodalMatrix +{ + public: + SCMatrix() + { + + } + + ~SCMatrix() + { + + } + operator SparseMatrix(); + + protected: + Index nnz; // Number of nonzero values + Index nsupper; // Index of the last supernode + Scalar *nzval; //array of nonzero values packed by (supernode ??) column + Index *nzval_colptr; //nzval_colptr[j] Stores the location in nzval[] which starts column j + Index *rowind; // Array of compressed row indices of rectangular supernodes + Index rowind_colptr; //rowind_colptr[j] stores the location in rowind[] which starts column j + Index *col_to_sup; // col_to_sup[j] is the supernode number to which column j belongs + Index *sup_to_col; //sup_to_col[s] points to the starting column of the s-th supernode + // Index *nzval_colptr corresponds to m_outerIndex in SparseMatrix + + private : + SuperNodalMatrix(SparseMatrix& ) {} +}; + +SuperNodalMatrix::operator SparseMatrix() +{ + +} +#endif
\ No newline at end of file diff --git a/Eigen/src/SparseLU/SparseLU_Memory.h b/Eigen/src/SparseLU/SparseLU_Memory.h new file mode 100644 index 000000000..6e0fc658d --- /dev/null +++ b/Eigen/src/SparseLU/SparseLU_Memory.h @@ -0,0 +1,242 @@ +// 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> +// +// Eigen is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// Alternatively, you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License and a copy of the GNU General Public License along with +// Eigen. If not, see <http://www.gnu.org/licenses/>. + +/* + + * NOTE: This file is the modified version of [s,d,c,z]memory.c files in SuperLU + + * -- SuperLU routine (version 3.1) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * August 1, 2008 + * + * 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 EIGEN_SPARSELU_MEMORY +#define EIGEN_SPARSELU_MEMORY + +#define LU_Reduce(alpha) ((alpha + 1) / 2) // i.e (alpha-1)/2 + 1 +#define LU_GluIntArray(n) (5* (n) + 5) +#define LU_TempSpace(m, w) ( (2*w + 4 + LU_NO_MARKER) * m * sizeof(Index) \ + + (w + 1) * m * sizeof(Scalar) +namespace internal { + +/* Allocate various working space needed in the numerical factorization phase. + * m_work : space fot the output data structures (lwork is the size) + * m_Glu: persistent data to facilitate multiple factors : is it really necessary ?? + * NOTE Unlike SuperLU, this routine does not allow the user to provide the size to allocate + * nor it return an estimated amount of space required. + * + * Useful variables : + * - m_fillratio : Ratio of fill expected + * - lwork = -1 : return an estimated size of the required memory + * = 0 : Estimate and allocate the memory + */ +template <typename Scalar,typename Index> +int SparseLU::LUMemInit(int lwork) +{ + int iword = sizeof(Index); + int dword = sizeof(Scalar); + int n = m_Glu.n = m_mat.cols(); + int m = m_mat.rows(); + m_Glu.num_expansions = 0; // No memory expansions so far ?? + int estimated_size; + + + if (!m_Glu.expanders) + m_Glu.expanders = new ExpHeader(NO_MEMTYPE); + + if (m_fact_t != SamePattern_SameRowPerm) // Create space for a new factorization + { + // Guess the size for L\U factors + int annz = m_mat.nonZeros(); + int nzlmax, nzumax, nzlumax; + nzumax = nzlumax = m_fillratio * annz; // ??? + nzlmax = std::max(1, m_fill_ratio/4.) * annz; //??? + + // Return the estimated size to the user if necessary + if (lwork = -1) + { + estimated_size = LU_GluIntArray(n) * iword + LU_TempSpace(m, m_panel_size) + + (nzlmax + nzumax) * iword + (nzlumax+nzumax) * dword + n); + return estimated_size; + } + + // Setup the required space + // NOTE: In SuperLU, there is an option to let the user provide its own space. + + // Allocate Integer pointers for L\U factors.resize(n+1); + m_Glu.supno.resize(n+1); + m_Glu.xlsub.resize(n+1); + m_Glu.xlusup.resize(n+1); + m_Glu.xusub.resize(n+1); + + // Reserve memory for L/U factors + m_Glu.lusup = internal::expand<Scalar>(nzlumax, LUSUP, 0, 0, m_Glu); + m_Glu.ucol = internal::expand<Scalar>(nzumax, UCOL, 0, 0, m_Glu); + m_Glu.lsub = internal::expand<Index>(nzlmax, LSUB, 0, 0, m_Glu); + m_Glu.usub = internal::expand<Index>(nzumax, USUB, 0, 1, m_Glu); + + // Check if the memory is correctly allocated, + while ( !m_Glu.lusup || !m_Glu.ucol || !m_Glu.lsub || !m_Glu.usub) + { + //otherwise reduce the estimated size and retry + delete [] m_Glu.lusup; + delete [] m_Glu.ucol; + delete [] m_Glu.lsub; + delete [] m_Glu.usub; + + nzlumax /= 2; + nzumax /= 2; + nzlmax /= 2; + eigen_assert (nzlumax > annz && "Not enough memory to perform factorization"); + + m_Glu.lusup = internal::expand<Scalar>(nzlumax, LUSUP, 0, 0, m_Glu); + m_Glu.ucol = internal::expand<Scalar>(nzumax, UCOL, 0, 0, m_Glu); + m_Glu.lsub = internal::expand<Index>(nzlmax, LSUB, 0, 0, m_Glu); + m_Glu.usub = internal::expand<Index>(nzumax, USUB, 0, 1, m_Glu); + } + } + else // m_fact == SamePattern_SameRowPerm; + { + if (lwork = -1) + { + estimated_size = LU_GluIntArray(n) * iword + LU_TempSpace(m, m_panel_size) + + (Glu.nzlmax + Glu.nzumax) * iword + (Glu.nzlumax+Glu.nzumax) * dword + n); + return estimated_size; + } + // Use existing space from previous factorization + // Unlike in SuperLU, this should not be necessary here since m_Glu is persistent as a member of the class + m_Glu.xsup = m_Lstore.sup_to_col; + m_Glu.supno = m_Lstore.col_to_sup; + m_Glu.xlsub = m_Lstore.rowind_colptr; + m_Glu.xlusup = m_Lstore.nzval_colptr; + xusub = m_Ustore.outerIndexPtr(); + + m_Glu.expanders[LSUB].size = m_Glu.nzlmax; // Maximum value from previous factorization + m_Glu.expanders[LUSUP].size = m_Glu.nzlumax; + m_Glu.expanders[USUB].size = GLu.nzumax; + m_Glu.expanders[UCOL].size = m_Glu.nzumax; + m_Glu.lsub = GLu.expanders[LSUB].mem = m_Lstore.rowind; + m_Glu.lusup = GLu.expanders[LUSUP].mem = m_Lstore.nzval; + GLu.usub = m_Glu.expanders[USUB].mem = m_Ustore.InnerIndexPtr(); + m_Glu.ucol = m_Glu.expanders[UCOL].mem = m_Ustore.valuePtr(); + } + + // LUWorkInit : Now, allocate known working storage + int isize = (2 * m_panel_size + 3 + LU_NO_MARKER) * m + n; + int dsize = m * m_panel_size + LU_NUM_TEMPV(m, m_panel_size, m_maxsuper, m_rowblk); + m_iwork = new Index(isize); + eigen_assert( (m_iwork != 0) && "Malloc fails for iwork"); + m_work = new Scalar(dsize); + eigen_assert( (m_work != 0) && "Malloc fails for dwork"); + + ++m_Glu.num_expansions; + return 0; +} // end LuMemInit + +/** + * Expand the existing storage to accomodate more fill-ins + */ +template <typename DestType > +DestType* SparseLU::expand(int& prev_len, // Length from previous call + MemType type, // Which part of the memory to expand + int len_to_copy, // Size of the memory to be copied to new store + int keep_prev) // = 1: use prev_len; Do not expand this vector + // = 0: compute new_len to expand) +{ + + float alpha = 1.5; // Ratio of the memory increase + int new_len; // New size of the allocated memory + if(m_Glu.num_expansions == 0 || keep_prev) + new_len = prev_len; + else + new_len = alpha * prev_len; + + // Allocate new space + DestType *new_mem, *old_mem; + new_mem = new DestType(new_len); + if ( m_Glu.num_expansions != 0 ) // The memory has been expanded before + { + int tries = 0; + if (keep_prev) + { + if (!new_mem) return 0; + } + else + { + while ( !new_mem) + { + // Reduce the size and allocate again + if ( ++tries > 10) return 0; + alpha = LU_Reduce(alpha); + new_len = alpha * prev_len; + new_mem = new DestType(new_len); + } + } // keep_prev + //Copy the previous values to the newly allocated space + ExpHeader<DestType>* expanders = m_Glu.expanders; + std::memcpy(new_mem, expanders[type].mem, len_to_copy); + delete [] expanders[type].mem; + } + expanders[type].mem = new_mem; + expanders[type].size = new_len; + prev_len = new_len; + if(m_Glu.num_expansions) ++m_Glu.num_expansions; + return expanders[type].mem; +} + +/** + * \brief Expand the existing storage + * + * NOTE: The calling sequence of this function is different from that of SuperLU + * + * \return a pointer to the newly allocated space + */ +template <typename DestType> +DestType* SparseLU::LUMemXpand(int jcol, int next, MemType mem_type, int& maxlen) +{ + DestType *newmem; + if (memtype == USUB) + new_mem = expand<DestType>(maxlen, mem_type, next, 1); + else + new_mem = expand<DestType>(maxlen, mem_type, next, 0); + eigen_assert(new_mem && "Can't expand memory"); + + return new_mem; + +} + +}// Namespace Internal +#endif
\ No newline at end of file diff --git a/Eigen/src/SparseLU/SparseLU_Structs.h b/Eigen/src/SparseLU/SparseLU_Structs.h new file mode 100644 index 000000000..72e1db343 --- /dev/null +++ b/Eigen/src/SparseLU/SparseLU_Structs.h @@ -0,0 +1,122 @@ +// 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> +// +// Eigen is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// Alternatively, you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License and a copy of the GNU General Public License along with +// Eigen. If not, see <http://www.gnu.org/licenses/>. + +/* + * NOTE: Part of this file is the modified version of files slu_[s,d,c,z]defs.h + * -- SuperLU routine (version 4.1) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * November, 2010 + * + * Global data structures used in LU factorization - + * + * nsuper: #supernodes = nsuper + 1, numbered [0, nsuper]. + * (xsup,supno): supno[i] is the supernode no to which i belongs; + * xsup(s) points to the beginning of the s-th supernode. + * e.g. supno 0 1 2 2 3 3 3 4 4 4 4 4 (n=12) + * xsup 0 1 2 4 7 12 + * Note: dfs will be performed on supernode rep. relative to the new + * row pivoting ordering + * + * (xlsub,lsub): lsub[*] contains the compressed subscript of + * rectangular supernodes; xlsub[j] points to the starting + * location of the j-th column in lsub[*]. Note that xlsub + * is indexed by column. + * Storage: original row subscripts + * + * During the course of sparse LU factorization, we also use + * (xlsub,lsub) for the purpose of symmetric pruning. For each + * supernode {s,s+1,...,t=s+r} with first column s and last + * column t, the subscript set + * lsub[j], j=xlsub[s], .., xlsub[s+1]-1 + * is the structure of column s (i.e. structure of this supernode). + * It is used for the storage of numerical values. + * Furthermore, + * lsub[j], j=xlsub[t], .., xlsub[t+1]-1 + * is the structure of the last column t of this supernode. + * It is for the purpose of symmetric pruning. Therefore, the + * structural subscripts can be rearranged without making physical + * interchanges among the numerical values. + * + * However, if the supernode has only one column, then we + * only keep one set of subscripts. For any subscript interchange + * performed, similar interchange must be done on the numerical + * values. + * + * The last column structures (for pruning) will be removed + * after the numercial LU factorization phase. + * + * (xlusup,lusup): lusup[*] contains the numerical values of the + * rectangular supernodes; xlusup[j] points to the starting + * location of the j-th column in storage vector lusup[*] + * Note: xlusup is indexed by column. + * Each rectangular supernode is stored by column-major + * scheme, consistent with Fortran 2-dim array storage. + * + * (xusub,ucol,usub): ucol[*] stores the numerical values of + * U-columns outside the rectangular supernodes. The row + * subscript of nonzero ucol[k] is stored in usub[k]. + * xusub[i] points to the starting location of column i in ucol. + * Storage: new row subscripts; that is subscripts of PA. + */ +#ifndef EIGEN_LU_STRUCTS +#define EIGEN_LU_STRUCTS +namespace Eigen { + +#define NO_MEMTYPE 4 /* 0: lusup + 1: ucol + 2: lsub + 3: usub */ +typedef enum {NATURAL, MMD_ATA, MMD_AT_PLUS_A, COLAMD, MY_PREMC} colperm_t; +typedef enum {DOFACT, SamePattern, SamePattern_SameRowPerm, Factored} fact_t; +typedef enum {LUSUP, UCOL, LSUB, USUB, LLVL, ULVL} MemType; + +/** Headers for dynamically managed memory + \tparam BaseType can be int, real scalar or complex scalar*/ +template <typename BaseType> +struct ExpHeader { + int size; // Length of the memory that has been used */ + BaseType *mem; +} ExpHeader; + +template <typename VectorType, typename Index> +struct { + VectorXi xsup; // supernode and column mapping + VectorXi supno; // Supernode number corresponding to this column + VectorXi lsub; // Compressed L subscripts of rectangular supernodes + VectorXi xlsub; // xlsub(j) points to the starting location of the j-th column in lsub + VectorXi xlusup; + VectorXi xusub; + VectorType lusup; // L supernodes + VectorType ucol; // U columns + Index nzlmax; // Current max size of lsub + Index nzumax; // Current max size of ucol + Index nzlumax; // Current max size of lusup + Index n; // Number of columns in the matrix + int num_expansions; + ExpHeader *expanders; // Array of pointers to 4 types of memory +} GlobalLU_t; + +}// End namespace Eigen +#endif
\ No newline at end of file diff --git a/Eigen/src/SparseLU/SparseLU_Utils.h b/Eigen/src/SparseLU/SparseLU_Utils.h new file mode 100644 index 000000000..3c3b24a15 --- /dev/null +++ b/Eigen/src/SparseLU/SparseLU_Utils.h @@ -0,0 +1,32 @@ +// 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> +// +// Eigen is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// Alternatively, you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License and a copy of the GNU General Public License along with +// Eigen. If not, see <http://www.gnu.org/licenses/>. + +#ifdef EIGEN_SPARSELU_UTILS_H +#define EIGEN_SPARSELU_UTILS_H + +// Number of marker arrays used in the symbolic factorization each of size n +#define LU_NO_MARKER 3 +#define LU_NUM_TEMPV(m,w,t,b) (std::max(m, (t+b)*w) ) +#define LU_EMPTY (-1) +#endif
\ No newline at end of file diff --git a/Eigen/src/SparseLU/SparseLU_heap_relax_snode.h b/Eigen/src/SparseLU/SparseLU_heap_relax_snode.h new file mode 100644 index 000000000..908f4d4cb --- /dev/null +++ b/Eigen/src/SparseLU/SparseLU_heap_relax_snode.h @@ -0,0 +1,133 @@ +// 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> +// +// Eigen is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// Alternatively, you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License and a copy of the GNU General Public License along with +// Eigen. If not, see <http://www.gnu.org/licenses/>. + +/* This file is a modified version of heap_relax_snode.c file in SuperLU + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + * 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 EIGEN_HEAP_RELAX_SNODE_H +#define EIGEN_HEAP_RELAX_SNODE_H +#include <Eigen_coletree.h> +/** + * \brief Identify the initial relaxed supernodes + * + * This routine applied to a symmetric elimination tree. + * It assumes that the matrix has been reordered according to the postorder of the etree + * \param et elimination tree + * \param relax_columns Maximum number of columns allowed in a relaxed snode + * \param descendants Number of descendants of each node in the etree + * \param relax_end last column in a supernode + */ +void internal::LU_heap_relax_snode (const int n, VectorXi& et, const int relax_columns, VectorXi& descendants, VectorXi& relax_end) +{ + + // The etree may not be postordered, but its heap ordered + // Post order etree + VectorXi post = internal::TreePostorder(n, et); + VectorXi inv_post(n+1); + register int i; + for (i = 0; i < n+1; ++i) inv_post(post(i)) = i; + + // Renumber etree in postorder + VectorXi iwork(n); + VectorXi et_save(n+1); + for (i = 0; i < n; ++i) + { + iwork(post(i)) = post(et(i)); + } + et_save = et; // Save the original etree + et = iwork; + + // compute the number of descendants of each node in the etree + relax_end.setConstant(-1); + register int j, parent; + descendants.setZero(); + for (j = 0; j < n; j++) + { + parent = et(j); + if (parent != n) // not the dummy root + descendants(parent) += descendants(j) + 1; + } + + // Identify the relaxed supernodes by postorder traversal of the etree + register int snode_start; // beginning of a snode + register int k; + int nsuper_et_post = 0; // Number of relaxed snodes in postordered etree + int nsuper_et = 0; // Number of relaxed snodes in the original etree + for (j = 0; j < n; ) + { + parent = et(j); + snode_start = j; + while ( parent != n && descendants(parent) < relax_columns ) + { + j = parent; + parent = et(j); + } + // Found a supernode in postordered etree, j is the last column + ++nsuper_et_post; + k = n; + for (i = snode_start; i <= j; ++i) + k = std::min(k, inv_post(i)); + l = inv_post(j); + if ( (l - k) == (j - snode_start) ) // Same number of columns in the snode + { + // This is also a supernode in the original etree + relax_end(k) = l; // Record last column + ++nsuper_et; + } + else + { + for (i = snode_start; i <= j; ++i) + { + l = inv_post(i); + if (descendants(i) == 0) + { + relax_end(l) = l; + ++nsuper_et; + } + } + } + j++; + // Search for a new leaf + while (descendants(j) != 0 && j < n) j++; + } // End postorder traversal of the etree + + // Recover the original etree + et = et_save; +} +#endif diff --git a/Eigen/src/SparseLU/SparseLU_panel_dfs.h b/Eigen/src/SparseLU/SparseLU_panel_dfs.h new file mode 100644 index 000000000..550544d05 --- /dev/null +++ b/Eigen/src/SparseLU/SparseLU_panel_dfs.h @@ -0,0 +1,221 @@ +// 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> +// +// Eigen is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// Alternatively, you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License and a copy of the GNU General Public License along with +// Eigen. If not, see <http://www.gnu.org/licenses/>. + +/* + + * NOTE: This file is the modified version of xpanel_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 +/** + * \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 m number of rows in the matrix + * \param w Panel size + * \param jcol Starting column of the panel + * \param A Input matrix in column-major storage + * \param perm_r Row permutation + * \param nseg + * + */ +template <typename MatrixType, typename VectorType> +int SparseLU::LU_panel_dfs(const int m, const int w, const int jcol, MatrixType& A, VectorXi& perm_r, VectorXi& nseg, int& nseg, VectorType& dense, VectorXi& panel_lsub, VectorXi& segrep, VectorXi& repfnz, VectorXi& xprune, VectorXi& marker, VectorXi& parent, VectorXi& xplore, LU_GlobalLu_t& Glu) +{ + + int jj; // Index through each column in the panel + int nextl_col; // Next available position in panel_lsub[*,jj] + int krow; // Row index of the current element + int kperm; // permuted row index + int krep; // Supernode reprentative of the current row + int kmark; + int chperm, chmark, chrep, oldrep, kchild; + int myfnz; // First nonzero element in the current column + int xdfs, maxdfs, kpar; + + // Initialize pointers +// VectorXi& marker1 = marker.block(m, m); + VectorBlock<VectorXi> marker1(marker, m, m); + nseg = 0; + VectorXi& xsup = Glu.xsup; + VectorXi& supno = Glu.supno; + VectorXi& lsub = Glu.lsub; + VectorXi& xlsub = Glu.xlsub; + // For each column in the panel + for (jj = jcol; jj < jcol + w; jj++) + { + nextl_col = (jj - jcol) * m; + + //FIXME + VectorBlock<VectorXi> repfnz_col(repfnz.segment(nextl_col, m)); // First nonzero location in each row + VectorBlock<VectorXi> dense_col(dense.segment(nextl_col, m)); // Accumulate a column vector here + + + // For each nnz in A[*, jj] do depth first search + for (MatrixType::InnerIterator it(A, jj); it; ++it) + { + krow = it.row(); + dense_col(krow) = it.val(); + kmark = marker(krow); + if (kmark == jj) + continue; // krow visited before, go to the next nonzero + + // For each unmarked krow of jj + marker(krow) = jj; + kperm = perm_r(krow); + if (kperm == -1 ) { + // krow is in L : place it in structure of L(*, jj) + panel_lsub(nextl_col++) = krow; // krow is indexed into A + } + else + { + // krow is in U : if its supernode-representative krep + // has been explored, update repfnz(*) + krep = xsup(supno(kperm)+1) - 1; + myfnz = repfnz_col(krep); + + if (myfnz != -1 ) + { + // Representative visited before + if (myfnz > kperm ) repfnz_col(krep) = kperm; + + } + else + { + // Otherwise, perform dfs starting at krep + oldrep = -1; + parent(krep) = oldrep; + repfnz_col(krep) = kperm; + xdfs = xlsub(krep); + maxdfs = xprune(krep); + + do + { + // For each unmarked kchild of krep + while (xdfs < maxdfs) + { + kchild = lsub(xdfs); + xdfs++; + chmark = marker(kchild); + + if (chmark != jj ) + { + marker(kchild) = jj; + chperm = perm_r(kchild); + + if (chperm == -1) + { + // case kchild is in L: place it in L(*, j) + panel_lsub(nextl_col++) = kchild; + } + else + { + // case kchild is in U : + // chrep = its supernode-rep. If its rep has been explored, + // update its repfnz(*) + chrep = xsup(supno(chperm)+1) - 1; + myfnz = repfnz_col(chrep); + + if (myfnz != -1) + { // 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 = 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 (marker1(krep) < jcol ) + { + segrep(nseg) = krep; + ++nseg; + marker1(krep) = jj; + } + + kpar = parent(krep); // Pop recursion, mimic recursion + if (kpar == -1) + break; // dfs done + krep = kpar; + xdfs = xplore(krep); + maxdfs = xprune(krep); + + } while (kpar != -1); // Do until empty stack + + } // end if (myfnz = -1) + + } // end if (kperm == -1) + + }// end for nonzeros in column jj + + } // end for column jj + +} +#endif
\ No newline at end of file diff --git a/Eigen/src/SparseLU/SparseLU_pivotL.h b/Eigen/src/SparseLU/SparseLU_pivotL.h new file mode 100644 index 000000000..f939ef939 --- /dev/null +++ b/Eigen/src/SparseLU/SparseLU_pivotL.h @@ -0,0 +1,132 @@ +// 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> +// +// Eigen is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// Alternatively, you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License and a copy of the GNU General Public License along with +// Eigen. If not, see <http://www.gnu.org/licenses/>. + +/* + + * NOTE: This file is the modified version of dpivotL.c file in SuperLU + + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + * 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_PIVOTL_H +#define SPARSELU_PIVOTL_H +/** + * \brief Performs the numerical pivotin on the current column of L, and the CDIV operation. + * + * Here is the pivot policy : + * (1) + * + * \param jcol The current column of L + * \param pivrow [out] The pivot row + * + * + */ +int SparseLU::LU_pivotL(const int jcol, Index& pivrow) +{ + // Initialize pointers + VectorXi& lsub = m_Glu.lsub; // Compressed row subscripts of ( rectangular supernodes ??) + VectorXi& xlsub = m_Glu.xlsub; // xlsub[j] is the starting location of the j-th column in lsub(*) + Scalar* lusup = m_Glu.lusup.data(); // Numerical values of the rectangular supernodes + VectorXi& xlusup = m_Glu.xlusup; // xlusup[j] is the starting location of the j-th column in lusup(*) + + Index fsupc = (m_Glu.xsup)((m_Glu.supno)(jcol)); // First column in the supernode containing the column jcol + Index nsupc = jcol - fsupc; // Number of columns in the supernode portion, excluding jcol; nsupc >=0 + Index lptr = xlsub(fsupc); // pointer to the starting location of the row subscripts for this supernode portion + Index nsupr = xlsub(fsupc+1) - lptr; // Number of rows in the supernode + Scalar* lu_sup_ptr = &(lusup[xlusup(fsupc)]); // Start of the current supernode + Scalar* lu_col_ptr = &(lusup[xlusup(jcol)]); // Start of jcol in the supernode + Index* lsub_ptr = &(lsub.data()[lptr]); // Start of row indices of the supernode + + // Determine the largest abs numerical value for partial pivoting + Index diagind = m_iperm_c(jcol); // diagonal index + Scalar pivmax = 0.0; + Index pivptr = nsupc; + Index diag = -1; + Index old_pivptr = nsupc; + Scalar rtemp; + for (isub = nsupc; isub < nsupr; ++isub) { + rtemp = std::abs(lu_col_ptr[isub]); + if (rtemp > pivmax) { + pivmax = rtemp; + pivptr = isub; + } + if (lsub_ptr[isub] == diagind) diag = isub; + } + + // Test for singularity + if ( pivmax == 0.0 ) { + pivrow = lsub_ptr[pivptr]; + m_perm_r(pivrow) = jcol; + return (jcol+1); + } + + Scalar thresh = m_diagpivotthresh * pivmax; + + // Choose appropriate pivotal element + + { + // Test if the diagonal element can be used as a pivot (given the threshold value) + if (diag >= 0 ) + { + // Diagonal element exists + rtemp = std::abs(lu_col_ptr[diag]); + if (rtemp != Scalar(0.0) && rtemp >= thresh) pivptr = diag; + } + pivrow = lsub_ptr[pivptr]; + } + + // Record pivot row + perm_r(pivrow) = jcol; + // Interchange row subscripts + if (pivptr != nsupc ) + { + std::swap( lsub_ptr(pivptr), lsub_ptr(nsupc) ); + // Interchange numerical values as well, for the two rows in the whole snode + // such that L is indexed the same way as A + for (icol = 0; icol <= nsupc; icol++) + { + itemp = pivptr + icol * nsupr; + std::swap(lu_sup_ptr[itemp], lu_sup_ptr[nsupc + icol * nsupr]); + } + } + // cdiv operations + Scalar temp = Scalar(1.0) / lu_col_ptr[nsupc]; + for (k = nsupc+1; k < nsupr; k++) + lu_col_ptr[k] *= temp; + return 0; +} +#endif
\ No newline at end of file diff --git a/Eigen/src/SparseLU/SparseLU_relax_snode.h b/Eigen/src/SparseLU/SparseLU_relax_snode.h new file mode 100644 index 000000000..61b8e74bb --- /dev/null +++ b/Eigen/src/SparseLU/SparseLU_relax_snode.h @@ -0,0 +1,89 @@ +// 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> +// +// Eigen is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// Alternatively, you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License and a copy of the GNU General Public License along with +// Eigen. If not, see <http://www.gnu.org/licenses/>. + +/* This file is a modified version of heap_relax_snode.c file in SuperLU + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + * 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 EIGEN_HEAP_RELAX_SNODE_H +#define EIGEN_HEAP_RELAX_SNODE_H +#include <Eigen_coletree.h> +/** + * \brief Identify the initial relaxed supernodes + * + * This routine applied to a column elimination tree. + * It assumes that the matrix has been reordered according to the postorder of the etree + * \param et elimination tree + * \param relax_columns Maximum number of columns allowed in a relaxed snode + * \param descendants Number of descendants of each node in the etree + * \param relax_end last column in a supernode + */ +void internal::LU_relax_snode (const int n, VectorXi& et, const int relax_columns, VectorXi& descendants, VectorXi& relax_end) +{ + + // compute the number of descendants of each node in the etree + register int j, parent; + relax_end.setConstant(-1); + descendants.setZero(); + for (j = 0; j < n; j++) + { + parent = et(j); + if (parent != n) // not the dummy root + descendants(parent) += descendants(j) + 1; + } + + // Identify the relaxed supernodes by postorder traversal of the etree + register int snode_start; // beginning of a snode + for (j = 0; j < n; ) + { + parent = et(j); + snode_start = j; + while ( parent != n && descendants(parent) < relax_columns ) + { + j = parent; + parent = et(j); + } + // Found a supernode in postordered etree, j is the last column + relax_end(snode_start) = j; // Record last column + j++; + // Search for a new leaf + while (descendants(j) != 0 && j < n) j++; + } // End postorder traversal of the etree + +} +#endif diff --git a/Eigen/src/SparseLU/SparseLU_snode_bmod.h b/Eigen/src/SparseLU/SparseLU_snode_bmod.h new file mode 100644 index 000000000..fc6ffc320 --- /dev/null +++ b/Eigen/src/SparseLU/SparseLU_snode_bmod.h @@ -0,0 +1,88 @@ +// 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> +// +// Eigen is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// Alternatively, you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License and a copy of the GNU General Public License along with +// Eigen. If not, see <http://www.gnu.org/licenses/>. + +/* + + * NOTE: This file is the modified version of dsnode_bmod.c file in SuperLU + + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + * 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_SNODE_BMOD_H +#define SPARSELU_SNODE_BMOD_H +template <typename VectorType> +int SparseLU::LU_dsnode_bmod (const int jcol, const int jsupno, const int fsupc, + VectorType& dense, VectorType& tempv) +{ + VectorXi& lsub = m_Glu.lsub; // Compressed row subscripts of ( rectangular supernodes ??) + VectorXi& xlsub = m_Glu.xlsub; // xlsub[j] is the starting location of the j-th column in lsub(*) + Scalar* lusup = m_Glu.lusup.data(); // Numerical values of the rectangular supernodes + VectorXi& xlusup = m_Glu.xlusup; // xlusup[j] is the starting location of the j-th column in lusup(*) + + int nextlu = xlusup(jcol); // Starting location of the next column to add + int irow; + // Process the supernodal portion of L\U[*,jcol] + for (int isub = xlsub(fsupc); isub < xlsub(fsupc+1); isub++) + { + irow = lsub(isub); + lusup(nextlu) = dense(irow); + dense(irow) = 0; + ++nextlu; + } + xlusup(jcol + 1) = nextlu; // Initialize xlusup for next column ( jcol+1 ) + + if (fsupc < jcol ){ + int luptr = xlusup(fsupc); // points to the first column of the supernode + int nsupr = xlsub(fsupc + 1) -xlsub(fsupc); //Number of rows in the supernode + int nsupc = jcol - fsupc; // Number of columns in the supernodal portion of L\U[*,jcol] + int ufirst = xlusup(jcol); // points to the beginning of column jcol in supernode L\U(jsupno) + + int nrow = nsupr - nsupc; // Number of rows in the off-diagonal blocks + int incx = 1, incy = 1; + Scalar alpha = Scalar(-1.0); + Scalar beta = Scalar(1.0); + // Solve the triangular system for U(fsupc:jcol, jcol) with L(fspuc..., fsupc:jcol) + //BLASFUNC(trsv)("L", "N", "U", &nsupc, &(lusup[luptr]), &nsupr, &(lusup[ufirst]), &incx); + Map<Matrix<Scalar,Dynamic,Dynamic>, 0, OuterStride<> > A( &(lusup[luptr]), nsupc, nsupc, OuterStride<>(nsupr) ); + Map<Matrix<Scalar,Dynamic,1> > l(&(lusup[ufirst]), nsupc); + l = A.triangularView<Lower>().solve(l); + // Update the trailing part of the column jcol U(jcol:jcol+nrow, jcol) using L(jcol:jcol+nrow, fsupc:jcol) and U(fsupc:jcol) + BLASFUNC(gemv)("N", &nrow, &nsupc, &alpha, &lusup[luptr+nsupc], &nsupr, &lusup[ufirst], &incx, &beta, &lusup[ufirst+nsupc], &incy); + + return 0; +} +#endif
\ No newline at end of file diff --git a/Eigen/src/SparseLU/SparseLU_snode_dfs.h b/Eigen/src/SparseLU/SparseLU_snode_dfs.h new file mode 100644 index 000000000..c3048be54 --- /dev/null +++ b/Eigen/src/SparseLU/SparseLU_snode_dfs.h @@ -0,0 +1,119 @@ +// 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> +// +// Eigen is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// Alternatively, you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License and a copy of the GNU General Public License along with +// Eigen. If not, see <http://www.gnu.org/licenses/>. + +/* + + * NOTE: This file is the modified version of dsnode_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. + */ +#ifdef EIGEN_SNODE_DFS_H +#define EIGEN_SNODE_DFS_H + /** + * \brief Determine the union of the row structures of those columns within the relaxed snode. + * NOTE: The relaxed snodes are leaves of the supernodal etree, therefore, + * the portion outside the rectangular supernode must be zero. + * + * \param jcol start of the supernode + * \param kcol end of the supernode + * \param asub Row indices + * \param colptr Pointer to the beginning of each column + * \param xprune (out) The pruned tree ?? + * \param marker (in/out) working vector + */ + template <typename Index> + int SparseLU::LU_snode_dfs(const int jcol, const int kcol, const VectorXi* asub, const VectorXi* colptr, + VectorXi& xprune, VectorXi& marker, LU_GlobalLu_t *m_Glu) + { + VectorXi& xsup = m_Glu->xsup; + VectorXi& supno = m_Glu->supno; // Supernode number corresponding to this column + VectorXi& lsub = m_Glu->lsub; + VectorXi& xlsub = m_Glu->xlsub; + + int nsuper = ++supno(jcol); // Next available supernode number + register int nextl = xlsub(jcol); //Index of the starting location of the jcol-th column in lsub + register int i,k; + int krow,kmark; + for (i = jcol; i <=kcol; i++) + { + // For each nonzero in A(*,i) + for (k = colptr(i); k < colptr(i+1); k++) + { + krow = asub(k); + kmark = marker(krow); + if ( kmark != kcol ) + { + // First time to visit krow + marker(krow) = kcol; + lsub(nextl++) = krow; + if( nextl >= nzlmax ) + { + m_Glu->lsub = LUMemXpand<Index>(jcol, nextl, LSUB, nzlmax); + m_Glu->nzlmax = nzlmax; + lsub = m_Glu->lsub; + } + } + } + supno(i) = nsuper; + } + + // If supernode > 1, then make a copy of the subscripts for pruning + if (jcol < kcol) + { + int new_next = nextl + (nextl - xlsub(jcol)); + while (new_next > nzlmax) + { + m_Glu->lsub = LUMemXpand<Index>(jcol, nextl, LSUB, &nzlmax); + m_Glu->nzlmax= nzlmax; + lsub = m_Glu->lsub; + } + int ifrom, ito = nextl; + for (ifrom = xlsub(jcol); ifrom < nextl;) + lsub(ito++) = lsub(ifrom++); + for (i = jcol+1; i <=kcol; i++)xlsub(i) = nextl; + nextl = ito; + } + xsup(nsuper+1) = kcol + 1; // Start of next available supernode + supno(kcol+1) = nsuper; + xprune(kcol) = nextl; + xlsub(kcol+1) = nextl; + return 0; + } + + +#endif
\ No newline at end of file |