Add EigenvalueRatioConstraint class for EMFit.

This commit is contained in:
Ryan Curtin
2013-10-03 15:07:15 +00:00
parent 7382ca52d0
commit b9673bb993
2 changed files with 80 additions and 0 deletions
+1
View File
@@ -9,6 +9,7 @@ set(SOURCES
no_constraint.hpp
positive_definite_constraint.hpp
diagonal_constraint.hpp
eigenvalue_ratio_constraint.hpp
)
# Add directory name to sources.
@@ -0,0 +1,79 @@
/**
* @file eigenvalue_ratio_constraint.hpp
* @author Ryan Curtin
*
* Constrain a covariance matrix to have a certain ratio of eigenvalues.
*/
#ifndef __MLPACK_METHODS_GMM_EIGENVALUE_RATIO_CONSTRAINT_HPP
#define __MLPACK_METHODS_GMM_EIGENVALUE_RATIO_CONSTRAINT_HPP
#include <mlpack/core.hpp>
namespace mlpack {
namespace gmm {
/**
* Given a vector of eigenvalue ratios, ensure that the covariance matrix always
* has those eigenvalue ratios. When you create this object, make sure that the
* vector of ratios that you pass does not go out of scope, because this object
* holds a reference to that vector instead of copying it.
*/
class EigenvalueRatioConstraint
{
public:
/**
* Create the EigenvalueRatioConstraint object with the given vector of
* eigenvalue ratios. These ratios are with respect to the first eigenvalue,
* which is the largest eigenvalue, so the first element of the vector should
* be 1. In addition, all other elements should be less than or equal to 1.
*/
EigenvalueRatioConstraint(const arma::vec& ratios) :
ratios(ratios)
{
// Check validity of ratios.
if (std::abs(ratios[0] - 1.0) > 1e-20)
Log::Fatal << "EigenvalueRatioConstraint::EigenvalueRatioConstraint(): "
<< "first element of ratio vector is not 1.0!" << std::endl;
for (size_t i = 1; i < ratios.n_elem; ++i)
{
if (ratios[i] > 1.0)
Log::Fatal << "EigenvalueRatioConstraint::EigenvalueRatioConstraint(): "
<< "element " << i << " of ratio vector is greater than 1.0!"
<< std::endl;
if (ratios[i] < 0.0)
Log::Warn << "EigenvalueRatioConstraint::EigenvalueRatioConstraint(): "
<< "element " << i << " of ratio vectors is negative and will "
<< "probably cause the covariance to be non-invertible..."
<< std::endl;
}
/**
* Apply the eigenvalue ratio constraint to the given covariance matrix.
*/
void ApplyConstraint(arma::mat& covariance) const
{
// Eigendecompose the matrix.
arma::vec eigenvalues;
arma::mat eigenvectors;
arma::eig_sym(eigenvalues, eigenvectors, covariance);
// Change the eigenvalues to what we are forcing them to be. There
// shouldn't be any negative eigenvalues anyway, so it doesn't matter if we
// are suddenly forcing them to be positive. If the first eigenvalue is
// negative, well, there are going to be some problems later...
eigenvalues = (eigenvalues[0] * ratios);
// Reassemble the matrix.
covariance = eigenvectors * arma::diagmat(eigenvalues) * eigenvectors.t();
}
private:
//! Ratios for eigenvalues.
const arma::vec& ratios;
};
}; // namespace gmm
}; // namespace mlpack
#endif