1 /**
2 * @file core/metrics/lmetric_impl.hpp
3 * @author Ryan Curtin
4 *
5 * Implementation of template specializations of LMetric class.
6 *
7 * mlpack is free software; you may redistribute it and/or modify it under the
8 * terms of the 3-clause BSD license. You should have received a copy of the
9 * 3-clause BSD license along with mlpack. If not, see
10 * http://www.opensource.org/licenses/BSD-3-Clause for more information.
11 */
12 #ifndef MLPACK_CORE_METRICS_LMETRIC_IMPL_HPP
13 #define MLPACK_CORE_METRICS_LMETRIC_IMPL_HPP
14
15 // In case it hasn't been included.
16 #include "lmetric.hpp"
17
18 namespace mlpack {
19 namespace metric {
20
21 // Unspecialized implementation. This should almost never be used...
22 template<int Power, bool TakeRoot>
23 template<typename VecTypeA, typename VecTypeB>
Evaluate(const VecTypeA & a,const VecTypeB & b)24 typename VecTypeA::elem_type LMetric<Power, TakeRoot>::Evaluate(
25 const VecTypeA& a,
26 const VecTypeB& b)
27 {
28 typename VecTypeA::elem_type sum = 0;
29 for (size_t i = 0; i < a.n_elem; ++i)
30 sum += std::pow(fabs(a[i] - b[i]), Power);
31
32 if (!TakeRoot) // The compiler should optimize this correctly at compile-time.
33 return sum;
34
35 return std::pow(sum, (1.0 / Power));
36 }
37
38 // L1-metric specializations; the root doesn't matter.
39 template<>
40 template<typename VecTypeA, typename VecTypeB>
Evaluate(const VecTypeA & a,const VecTypeB & b)41 typename VecTypeA::elem_type LMetric<1, true>::Evaluate(
42 const VecTypeA& a,
43 const VecTypeB& b)
44 {
45 return arma::accu(abs(a - b));
46 }
47
48 template<>
49 template<typename VecTypeA, typename VecTypeB>
Evaluate(const VecTypeA & a,const VecTypeB & b)50 typename VecTypeA::elem_type LMetric<1, false>::Evaluate(
51 const VecTypeA& a,
52 const VecTypeB& b)
53 {
54 return arma::accu(abs(a - b));
55 }
56
57 // L2-metric specializations.
58 template<>
59 template<typename VecTypeA, typename VecTypeB>
Evaluate(const VecTypeA & a,const VecTypeB & b)60 typename VecTypeA::elem_type LMetric<2, true>::Evaluate(
61 const VecTypeA& a,
62 const VecTypeB& b)
63 {
64 return arma::norm(a - b, 2);
65 }
66
67 template<>
68 template<typename VecTypeA, typename VecTypeB>
Evaluate(const VecTypeA & a,const VecTypeB & b)69 typename VecTypeA::elem_type LMetric<2, false>::Evaluate(
70 const VecTypeA& a,
71 const VecTypeB& b)
72 {
73 return accu(arma::square(a - b));
74 }
75
76 // L3-metric specialization (not very likely to be used, but just in case).
77 template<>
78 template<typename VecTypeA, typename VecTypeB>
Evaluate(const VecTypeA & a,const VecTypeB & b)79 typename VecTypeA::elem_type LMetric<3, true>::Evaluate(
80 const VecTypeA& a,
81 const VecTypeB& b)
82 {
83 typename VecTypeA::elem_type sum = 0;
84 for (size_t i = 0; i < a.n_elem; ++i)
85 sum += std::pow(fabs(a[i] - b[i]), 3.0);
86
87 return std::pow(arma::accu(arma::pow(arma::abs(a - b), 3.0)), 1.0 / 3.0);
88 }
89
90 template<>
91 template<typename VecTypeA, typename VecTypeB>
Evaluate(const VecTypeA & a,const VecTypeB & b)92 typename VecTypeA::elem_type LMetric<3, false>::Evaluate(
93 const VecTypeA& a,
94 const VecTypeB& b)
95 {
96 return arma::accu(arma::pow(arma::abs(a - b), 3.0));
97 }
98
99 // L-infinity (Chebyshev distance) specialization
100 template<>
101 template<typename VecTypeA, typename VecTypeB>
Evaluate(const VecTypeA & a,const VecTypeB & b)102 typename VecTypeA::elem_type LMetric<INT_MAX, false>::Evaluate(
103 const VecTypeA& a,
104 const VecTypeB& b)
105 {
106 return arma::as_scalar(arma::max(arma::abs(a - b)));
107 }
108
109 } // namespace metric
110 } // namespace mlpack
111
112 #endif
113