blob: f5757b3199f010d2735f87af40ab75d62cc36acd [file] [log] [blame]
// 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_ORDERING_H
#define EIGEN_ORDERING_H
#include "Amd.h"
namespace Eigen {
#include "Eigen_Colamd.h"
namespace internal {
/**
* Get the symmetric pattern A^T+A from the input matrix A.
* FIXME: The values should not be considered here
*/
template<typename MatrixType>
void ordering_helper_at_plus_a(const MatrixType& mat, MatrixType& symmat)
{
MatrixType C;
C = mat.transpose(); // NOTE: Could be costly
for (int i = 0; i < C.rows(); i++)
{
for (typename MatrixType::InnerIterator it(C, i); it; ++it)
it.valueRef() = 0.0;
}
symmat = C + mat;
}
}
/**
* Get the approximate minimum degree ordering
* If the matrix is not structurally symmetric, an ordering of A^T+A is computed
* \tparam Index The type of indices of the matrix
*/
template <typename Index>
class AMDOrdering
{
public:
typedef PermutationMatrix<Dynamic, Dynamic, Index> PermutationType;
/** Compute the permutation vector from a sparse matrix
* This routine is much faster if the input matrix is column-major
*/
template <typename MatrixType>
void operator()(const MatrixType& mat, PermutationType& perm)
{
// Compute the symmetric pattern
SparseMatrix<typename MatrixType::Scalar, ColMajor, Index> symm;
internal::ordering_helper_at_plus_a(mat,symm);
// Call the AMD routine
//m_mat.prune(keep_diag());
internal::minimum_degree_ordering(symm, perm);
}
/** Compute the permutation with a selfadjoint matrix */
template <typename SrcType, unsigned int SrcUpLo>
void operator()(const SparseSelfAdjointView<SrcType, SrcUpLo>& mat, PermutationType& perm)
{
SparseMatrix<typename SrcType::Scalar, ColMajor, Index> C = mat;
// Call the AMD routine
// m_mat.prune(keep_diag()); //Remove the diagonal elements
internal::minimum_degree_ordering(C, perm);
}
};
/**
* Get the natural ordering
*
*NOTE Returns an empty permutation matrix
* \tparam Index The type of indices of the matrix
*/
template <typename Index>
class NaturalOrdering
{
public:
typedef PermutationMatrix<Dynamic, Dynamic, Index> PermutationType;
/** Compute the permutation vector from a column-major sparse matrix */
template <typename MatrixType>
void operator()(const MatrixType& mat, PermutationType& perm)
{
perm.resize(0);
}
};
/**
* Get the column approximate minimum degree ordering
* The matrix should be in column-major format
*/
template<typename Index>
class COLAMDOrdering;
#include "Eigen_Colamd.h"
template<typename Index>
class COLAMDOrdering
{
public:
typedef PermutationMatrix<Dynamic, Dynamic, Index> PermutationType;
typedef Matrix<Index, Dynamic, 1> IndexVector;
/** Compute the permutation vector form a sparse matrix */
template <typename MatrixType>
void operator() (const MatrixType& mat, PermutationType& perm)
{
int m = mat.rows();
int n = mat.cols();
int nnz = mat.nonZeros();
// Get the recommended value of Alen to be used by colamd
int Alen = internal::colamd_recommended(nnz, m, n);
// Set the default parameters
double knobs [COLAMD_KNOBS];
int stats [COLAMD_STATS];
internal::colamd_set_defaults(knobs);
int info;
IndexVector p(n+1), A(Alen);
for(int i=0; i <= n; i++) p(i) = mat.outerIndexPtr()[i];
for(int i=0; i < nnz; i++) A(i) = mat.innerIndexPtr()[i];
// Call Colamd routine to compute the ordering
info = internal::colamd(m, n, Alen, A.data(), p.data(), knobs, stats);
eigen_assert( info && "COLAMD failed " );
perm.resize(n);
for (int i = 0; i < n; i++) perm.indices()(p(i)) = i;
}
};
} // end namespace Eigen
#endif