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:
@@ -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
|
||||
)
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user