diff --git a/src/mlpack/core/metrics/CMakeLists.txt b/src/mlpack/core/metrics/CMakeLists.txt index 35d7f5fc4c..4063b70388 100644 --- a/src/mlpack/core/metrics/CMakeLists.txt +++ b/src/mlpack/core/metrics/CMakeLists.txt @@ -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 ) diff --git a/src/mlpack/core/metrics/lmetric.cpp b/src/mlpack/core/metrics/lmetric.cpp deleted file mode 100644 index ca98ec0e65..0000000000 --- a/src/mlpack/core/metrics/lmetric.cpp +++ /dev/null @@ -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 diff --git a/src/mlpack/core/metrics/lmetric.hpp b/src/mlpack/core/metrics/lmetric.hpp index c1b805e62e..fdb6d55b89 100644 --- a/src/mlpack/core/metrics/lmetric.hpp +++ b/src/mlpack/core/metrics/lmetric.hpp @@ -63,31 +63,10 @@ class LMetric /** * Computes the distance between two points. */ - static double Evaluate(const arma::vec& a, const arma::vec& b); + template + 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 -double LMetric::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 diff --git a/src/mlpack/core/metrics/lmetric_impl.hpp b/src/mlpack/core/metrics/lmetric_impl.hpp new file mode 100644 index 0000000000..2153ad2865 --- /dev/null +++ b/src/mlpack/core/metrics/lmetric_impl.hpp @@ -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 +template +double LMetric::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 +double LMetric<1, true>::Evaluate(const VecType& a, const VecType& b) +{ + return accu(abs(a - b)); +} + +template<> +template +double LMetric<1, false>::Evaluate(const VecType& a, const VecType& b) +{ + return accu(abs(a - b)); +} + +// L2-metric specializations. +template<> +template +double LMetric<2, true>::Evaluate(const VecType& a, const VecType& b) +{ + return sqrt(accu(square(a - b))); +} + +template<> +template +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 +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 +double LMetric<3, false>::Evaluate(const VecType& a, const VecType& b) +{ + return accu(pow(abs(a - b), 3.0)); +} + +}; // namespace metric +}; // namespace mlpack + +#endif diff --git a/src/mlpack/core/metrics/mahalanobis_distance.hpp b/src/mlpack/core/metrics/mahalanobis_distance.hpp index c90987853c..24b52040c6 100644 --- a/src/mlpack/core/metrics/mahalanobis_distance.hpp +++ b/src/mlpack/core/metrics/mahalanobis_distance.hpp @@ -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 + double Evaluate(const VecType& a, const VecType& b); /** * Access the covariance matrix. diff --git a/src/mlpack/core/metrics/mahalanobis_distance_impl.hpp b/src/mlpack/core/metrics/mahalanobis_distance_impl.hpp index 53d220c0a1..a7fcef4bc3 100644 --- a/src/mlpack/core/metrics/mahalanobis_distance_impl.hpp +++ b/src/mlpack/core/metrics/mahalanobis_distance_impl.hpp @@ -16,8 +16,9 @@ namespace metric { * Specialization for non-rooted case. */ template<> -double MahalanobisDistance::Evaluate(const arma::vec& a, - const arma::vec& b) +template +double MahalanobisDistance::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::Evaluate(const arma::vec& a, * sqrt(). */ template<> -double MahalanobisDistance::Evaluate(const arma::vec& a, - const arma::vec& b) +template +double MahalanobisDistance::Evaluate(const VecType& a, + const VecType& b) { // Check if covariance matrix has been initialized. if (covariance.n_rows == 0)