| // 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 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 SPARSE_COLETREE_H | 
 | #define SPARSE_COLETREE_H | 
 |  | 
 | #include "./InternalHeaderCheck.h" | 
 |  | 
 | namespace Eigen { | 
 |  | 
 | namespace internal { | 
 |  | 
 | /** Find the root of the tree/set containing the vertex i : Use Path halving */  | 
 | template<typename Index, typename IndexVector> | 
 | Index etree_find (Index i, IndexVector& pp) | 
 | { | 
 |   Index p = pp(i); // Parent  | 
 |   Index 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;  | 
 | } | 
 |  | 
 | /** Compute the column elimination tree of a sparse matrix | 
 |   * \param mat The matrix in column-major format.  | 
 |   * \param parent The elimination tree | 
 |   * \param firstRowElt The column index of the first element in each row | 
 |   * \param perm The permutation to apply to the column of \b mat | 
 |   */ | 
 | template <typename MatrixType, typename IndexVector> | 
 | int coletree(const MatrixType& mat, IndexVector& parent, IndexVector& firstRowElt, typename MatrixType::StorageIndex *perm=0) | 
 | { | 
 |   typedef typename MatrixType::StorageIndex StorageIndex; | 
 |   StorageIndex nc = convert_index<StorageIndex>(mat.cols()); // Number of columns | 
 |   StorageIndex m = convert_index<StorageIndex>(mat.rows()); | 
 |   StorageIndex diagSize = (std::min)(nc,m); | 
 |   IndexVector root(nc); // root of subtree of etree  | 
 |   root.setZero(); | 
 |   IndexVector pp(nc); // disjoint sets  | 
 |   pp.setZero(); // Initialize disjoint sets  | 
 |   parent.resize(mat.cols()); | 
 |   //Compute first nonzero column in each row  | 
 |   firstRowElt.resize(m); | 
 |   firstRowElt.setConstant(nc); | 
 |   firstRowElt.segment(0, diagSize).setLinSpaced(diagSize, 0, diagSize-1); | 
 |   bool found_diag; | 
 |   for (StorageIndex col = 0; col < nc; col++) | 
 |   { | 
 |     StorageIndex pcol = col; | 
 |     if(perm) pcol  = perm[col]; | 
 |     for (typename MatrixType::InnerIterator it(mat, pcol); it; ++it) | 
 |     {  | 
 |       Index row = it.row(); | 
 |       firstRowElt(row) = (std::min)(firstRowElt(row), col); | 
 |     } | 
 |   } | 
 |   /* Compute etree by Liu's algorithm for symmetric matrices, | 
 |           except use (firstRowElt[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. */ | 
 |   StorageIndex rset, cset, rroot; | 
 |   for (StorageIndex col = 0; col < nc; col++)  | 
 |   { | 
 |     found_diag = col>=m; | 
 |     pp(col) = col;  | 
 |     cset = col;  | 
 |     root(cset) = col;  | 
 |     parent(col) = nc;  | 
 |     /* The diagonal element is treated here even if it does not exist in the matrix | 
 |      * hence the loop is executed once more */  | 
 |     StorageIndex pcol = col; | 
 |     if(perm) pcol  = perm[col]; | 
 |     for (typename MatrixType::InnerIterator it(mat, pcol); it||!found_diag; ++it) | 
 |     { //  A sequence of interleaved find and union is performed  | 
 |       Index i = col; | 
 |       if(it) i = it.index(); | 
 |       if (i == col) found_diag = true; | 
 |        | 
 |       StorageIndex row = firstRowElt(i); | 
 |       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) = rset;  | 
 |         cset = rset;  | 
 |         root(cset) = col;  | 
 |       } | 
 |     } | 
 |   } | 
 |   return 0;   | 
 | } | 
 |  | 
 | /**  | 
 |   * Depth-first search from vertex n.  No recursion. | 
 |   * This routine was contributed by Cédric Doucet, CEDRAT Group, Meylan, France. | 
 | */ | 
 | template <typename IndexVector> | 
 | void nr_etdfs (typename IndexVector::Scalar n, IndexVector& parent, IndexVector& first_kid, IndexVector& next_kid, IndexVector& post, typename IndexVector::Scalar postnum) | 
 | { | 
 |   typedef typename IndexVector::Scalar StorageIndex; | 
 |   StorageIndex current = n, first, next; | 
 |   while (postnum != n)  | 
 |   { | 
 |     // No kid for the current node | 
 |     first = first_kid(current); | 
 |      | 
 |     // no 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;  | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 |  | 
 | /** | 
 |   * \brief Post order a tree  | 
 |   * \param n the number of nodes | 
 |   * \param parent Input tree | 
 |   * \param post postordered tree | 
 |   */ | 
 | template <typename IndexVector> | 
 | void treePostorder(typename IndexVector::Scalar n, IndexVector& parent, IndexVector& post) | 
 | { | 
 |   typedef typename IndexVector::Scalar StorageIndex; | 
 |   IndexVector first_kid, next_kid; // Linked list of children  | 
 |   StorageIndex 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 | 
 |   first_kid.setConstant(-1);  | 
 |   for (StorageIndex v = n-1; v >= 0; v--)  | 
 |   { | 
 |     StorageIndex 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); | 
 | } | 
 |  | 
 | } // end namespace internal | 
 |  | 
 | } // end namespace Eigen | 
 |  | 
 | #endif // SPARSE_COLETREE_H |