Files
eigen/Eigen/src/SparseCore/SparseColEtree.h

207 lines
6.0 KiB
C
Raw Normal View History

2012-05-25 18:17:57 +02:00
// 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>
//
2012-08-01 11:38:32 +02:00
// 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/.
2012-05-25 18:17:57 +02:00
/*
* 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
namespace Eigen {
namespace internal {
2012-06-13 18:26:05 +02:00
/** Find the root of the tree/set containing the vertex i : Use Path halving */
2013-01-29 16:21:24 +01:00
template<typename Index, typename IndexVector>
Index etree_find (Index i, IndexVector& pp)
2012-06-13 18:26:05 +02:00
{
2013-01-29 16:21:24 +01:00
Index p = pp(i); // Parent
Index gp = pp(p); // Grand parent
2012-06-13 18:26:05 +02:00
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;
}
2012-05-25 18:17:57 +02:00
/** Compute the column elimination tree of a sparse matrix
2013-01-21 15:39:18 +01:00
* \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
2013-03-05 12:55:03 +01:00
* \param perm The permutation to apply to the column of \b mat
2012-05-25 18:17:57 +02:00
*/
template <typename MatrixType, typename IndexVector>
int coletree(const MatrixType& mat, IndexVector& parent, IndexVector& firstRowElt, typename MatrixType::Index *perm=0)
2012-05-25 18:17:57 +02:00
{
typedef typename MatrixType::Index Index;
Index nc = mat.cols(); // Number of columns
Index m = mat.rows();
Index diagSize = (std::min)(nc,m);
2012-06-11 18:52:26 +02:00
IndexVector root(nc); // root of subtree of etree
2012-05-25 18:17:57 +02:00
root.setZero();
2012-06-11 18:52:26 +02:00
IndexVector pp(nc); // disjoint sets
2012-05-25 18:17:57 +02:00
pp.setZero(); // Initialize disjoint sets
parent.resize(mat.cols());
2012-06-11 18:52:26 +02:00
//Compute first nonzero column in each row
2013-01-29 16:21:24 +01:00
Index row,col;
firstRowElt.resize(m);
firstRowElt.setConstant(nc);
firstRowElt.segment(0, diagSize).setLinSpaced(diagSize, 0, diagSize-1);
bool found_diag;
2012-05-25 18:17:57 +02:00
for (col = 0; col < nc; col++)
{
Index pcol = col;
if(perm) pcol = perm[col];
for (typename MatrixType::InnerIterator it(mat, pcol); it; ++it)
{
2012-05-25 18:17:57 +02:00
row = it.row();
firstRowElt(row) = (std::min)(firstRowElt(row), col);
2012-05-25 18:17:57 +02:00
}
}
/* Compute etree by Liu's algorithm for symmetric matrices,
except use (firstRowElt[r],c) in place of an edge (r,c) of A.
2012-05-25 18:17:57 +02:00
Thus each row clique in A'*A is replaced by a star
centered at its first vertex, which has the same fill. */
2013-01-29 16:21:24 +01:00
Index rset, cset, rroot;
2012-05-25 18:17:57 +02:00
for (col = 0; col < nc; col++)
{
found_diag = col>=m;
2012-07-06 20:18:16 +02:00
pp(col) = col;
cset = col;
2012-05-25 18:17:57 +02:00
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 */
Index pcol = col;
if(perm) pcol = perm[col];
for (typename MatrixType::InnerIterator it(mat, pcol); it||!found_diag; ++it)
2012-05-25 18:17:57 +02:00
{ // A sequence of interleaved find and union is performed
2013-01-29 16:21:24 +01:00
Index i = col;
if(it) i = it.index();
if (i == col) found_diag = true;
row = firstRowElt(i);
2012-05-25 18:17:57 +02:00
if (row >= col) continue;
rset = internal::etree_find(row, pp); // Find the name of the set containing row
2012-05-25 18:17:57 +02:00
rroot = root(rset);
if (rroot != col)
{
parent(rroot) = col;
2012-07-06 20:18:16 +02:00
pp(cset) = rset;
cset = rset;
2012-05-25 18:17:57 +02:00
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.
*/
2013-01-29 16:21:24 +01:00
template <typename Index, typename IndexVector>
void nr_etdfs (Index n, IndexVector& parent, IndexVector& first_kid, IndexVector& next_kid, IndexVector& post, Index postnum)
2012-05-25 18:17:57 +02:00
{
2013-01-29 16:21:24 +01:00
Index current = n, first, next;
2012-05-25 18:17:57 +02:00
while (postnum != n)
{
// No kid for the current node
first = first_kid(current);
2012-06-11 18:52:26 +02:00
// no kid for the current node
2012-05-25 18:17:57 +02:00
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++;
2012-06-11 18:52:26 +02:00
2012-05-25 18:17:57 +02:00
// Get the next kid
next = next_kid(current);
}
// stopping criterion
2012-06-11 18:52:26 +02:00
if (postnum == n+1) return;
2012-05-25 18:17:57 +02:00
// Updating current node
current = next;
}
else
{
current = first;
}
}
}
2012-06-13 18:26:05 +02:00
/**
2013-01-21 15:39:18 +01:00
* \brief Post order a tree
* \param n the number of nodes
2012-06-13 18:26:05 +02:00
* \param parent Input tree
* \param post postordered tree
*/
2013-01-29 16:21:24 +01:00
template <typename Index, typename IndexVector>
void treePostorder(Index n, IndexVector& parent, IndexVector& post)
2012-06-13 18:26:05 +02:00
{
IndexVector first_kid, next_kid; // Linked list of children
2013-01-29 16:21:24 +01:00
Index postnum;
2012-06-13 18:26:05 +02:00
// 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
2013-01-29 16:21:24 +01:00
Index v, dad;
2012-06-13 18:26:05 +02:00
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);
2012-06-13 18:26:05 +02:00
}
} // end namespace internal
} // end namespace Eigen
#endif // SPARSE_COLETREE_H