Allow sparse vectors to be passed to metrics (this should get a bit of speedup).

Now we leave the computation up to Armadillo.
This commit is contained in:
Ryan Curtin
2011-12-13 08:59:08 +00:00
parent ef3145515b
commit 785a747777
6 changed files with 98 additions and 105 deletions
+1 -1
View File
@@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 2.8)
# Anything not in this list will not be compiled into MLPACK.
set(SOURCES
lmetric.hpp
lmetric.cpp
lmetric_impl.hpp
mahalanobis_distance.hpp
mahalanobis_distance_impl.hpp
)
-76
View File
@@ -1,76 +0,0 @@
/**
* @file lmetric.cpp
* @author Ryan Curtin
*
* Implementation of template specializations of LMetric class.
*/
#include "lmetric.hpp"
namespace mlpack {
namespace metric {
// L1-metric specializations; the root doesn't matter.
template<>
double LMetric<1, true>::Evaluate(const arma::vec& a, const arma::vec& b)
{
double sum = 0;
for (size_t i = 0; i < a.n_elem; i++)
sum += fabs(a[i] - b[i]);
return sum;
}
template<>
double LMetric<1, false>::Evaluate(const arma::vec& a, const arma::vec& b)
{
double sum = 0;
for (size_t i = 0; i < a.n_elem; i++)
sum += fabs(a[i] - b[i]);
return sum;
}
// L2-metric specializations.
template<>
double LMetric<2, true>::Evaluate(const arma::vec& a, const arma::vec& b)
{
double sum = 0;
for (size_t i = 0; i < a.n_elem; i++)
sum += pow(a[i] - b[i], 2.0); // fabs() not necessary when squaring.
return sqrt(sum);
}
template<>
double LMetric<2, false>::Evaluate(const arma::vec& a, const arma::vec& b)
{
double sum = 0;
for (size_t i = 0; i < a.n_elem; i++)
sum += pow(a[i] - b[i], 2.0);
return sum;
}
// L3-metric specialization (not very likely to be used, but just in case).
template<>
double LMetric<3, true>::Evaluate(const arma::vec& a, const arma::vec& b)
{
double sum = 0;
for (size_t i = 0; i < a.n_elem; i++)
sum += pow(fabs(a[i] - b[i]), 3.0);
return pow(sum, 1.0 / 3.0);
}
template<>
double LMetric<3, false>::Evaluate(const arma::vec& a, const arma::vec& b)
{
double sum = 0;
for (size_t i = 0; i < a.n_elem; i++)
sum += pow(fabs(a[i] - b[i]), 3.0);
return sum;
}
}; // namespace metric
}; // namespace mlpack
+5 -23
View File
@@ -63,31 +63,10 @@ class LMetric
/**
* Computes the distance between two points.
*/
static double Evaluate(const arma::vec& a, const arma::vec& b);
template<typename VecType>
static double Evaluate(const VecType& a, const VecType& b);
};
// Doxygen will not include this specialization.
//! @cond
// The implementation is not split into a _impl.h file because it is so simple;
// the unspecialized implementation of the one function is given below.
// Unspecialized implementation. This should almost never be used...
template<int t_pow, bool t_take_root>
double LMetric<t_pow, t_take_root>::Evaluate(const arma::vec& a,
const arma::vec& b)
{
double sum = 0;
for (size_t i = 0; i < a.n_elem; i++)
sum += pow(fabs(a[i] - b[i]), t_pow);
if (!t_take_root) // Suboptimal to have this here.
return sum;
return pow(sum, (1.0 / t_pow));
}
//! @endcond
// Convenience typedefs.
/***
@@ -108,4 +87,7 @@ typedef LMetric<2, true> EuclideanDistance;
}; // namespace metric
}; // namespace mlpack
// Include implementation.
#include "lmetric_impl.hpp"
#endif
+84
View File
@@ -0,0 +1,84 @@
/**
* @file lmetric_impl.hpp
* @author Ryan Curtin
*
* Implementation of template specializations of LMetric class.
*/
#ifndef __MLPACK_CORE_METRICS_LMETRIC_IMPL_HPP
#define __MLPACK_CORE_METRICS_LMETRIC_IMPL_HPP
// In case it hasn't been included.
#include "lmetric.hpp"
namespace mlpack {
namespace metric {
// Unspecialized implementation. This should almost never be used...
template<int t_pow, bool t_take_root>
template<typename VecType>
double LMetric<t_pow, t_take_root>::Evaluate(const VecType& a,
const VecType& b)
{
double sum = 0;
for (size_t i = 0; i < a.n_elem; i++)
sum += pow(fabs(a[i] - b[i]), t_pow);
if (!t_take_root) // Suboptimal to have this here.
return sum;
return pow(sum, (1.0 / t_pow));
}
// L1-metric specializations; the root doesn't matter.
template<>
template<typename VecType>
double LMetric<1, true>::Evaluate(const VecType& a, const VecType& b)
{
return accu(abs(a - b));
}
template<>
template<typename VecType>
double LMetric<1, false>::Evaluate(const VecType& a, const VecType& b)
{
return accu(abs(a - b));
}
// L2-metric specializations.
template<>
template<typename VecType>
double LMetric<2, true>::Evaluate(const VecType& a, const VecType& b)
{
return sqrt(accu(square(a - b)));
}
template<>
template<typename VecType>
double LMetric<2, false>::Evaluate(const VecType& a, const VecType& b)
{
return accu(square(a - b));
}
// L3-metric specialization (not very likely to be used, but just in case).
template<>
template<typename VecType>
double LMetric<3, true>::Evaluate(const VecType& a, const VecType& b)
{
double sum = 0;
for (size_t i = 0; i < a.n_elem; i++)
sum += pow(fabs(a[i] - b[i]), 3.0);
return pow(accu(pow(abs(a - b), 3.0)), 1.0 / 3.0);
}
template<>
template<typename VecType>
double LMetric<3, false>::Evaluate(const VecType& a, const VecType& b)
{
return accu(pow(abs(a - b), 3.0));
}
}; // namespace metric
}; // namespace mlpack
#endif
@@ -68,7 +68,8 @@ class MahalanobisDistance
* @param a First vector.
* @param b Second vector.
*/
double Evaluate(const arma::vec& a, const arma::vec& b);
template<typename VecType>
double Evaluate(const VecType& a, const VecType& b);
/**
* Access the covariance matrix.
@@ -16,8 +16,9 @@ namespace metric {
* Specialization for non-rooted case.
*/
template<>
double MahalanobisDistance<false>::Evaluate(const arma::vec& a,
const arma::vec& b)
template<typename VecType>
double MahalanobisDistance<false>::Evaluate(const VecType& a,
const VecType& b)
{
// Check if covariance matrix has been initialized.
if (covariance.n_rows == 0)
@@ -33,8 +34,9 @@ double MahalanobisDistance<false>::Evaluate(const arma::vec& a,
* sqrt().
*/
template<>
double MahalanobisDistance<true>::Evaluate(const arma::vec& a,
const arma::vec& b)
template<typename VecType>
double MahalanobisDistance<true>::Evaluate(const VecType& a,
const VecType& b)
{
// Check if covariance matrix has been initialized.
if (covariance.n_rows == 0)