1 /**
2  * @file core/metrics/ip_metric_impl.hpp
3  * @author Ryan Curtin
4  *
5  * Implementation of the IPMetric.
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_METHODS_FASTMKS_IP_METRIC_IMPL_HPP
13 #define MLPACK_METHODS_FASTMKS_IP_METRIC_IMPL_HPP
14 
15 // In case it hasn't been included yet.
16 #include "ip_metric.hpp"
17 
18 #include <mlpack/core/metrics/lmetric.hpp>
19 #include <mlpack/core/kernels/linear_kernel.hpp>
20 
21 namespace mlpack {
22 namespace metric {
23 
24 // Constructor with no instantiated kernel.
25 template<typename KernelType>
IPMetric()26 IPMetric<KernelType>::IPMetric() :
27     kernel(new KernelType()),
28     kernelOwner(true)
29 {
30   // Nothing to do.
31 }
32 
33 // Constructor with instantiated kernel.
34 template<typename KernelType>
IPMetric(KernelType & kernel)35 IPMetric<KernelType>::IPMetric(KernelType& kernel) :
36     kernel(&kernel),
37     kernelOwner(false)
38 {
39   // Nothing to do.
40 }
41 
42 // Destructor for the IPMetric.
43 template<typename KernelType>
~IPMetric()44 IPMetric<KernelType>::~IPMetric()
45 {
46   if (kernelOwner)
47     delete kernel;
48 }
49 
50 template<typename KernelType>
IPMetric(const IPMetric & other)51 IPMetric<KernelType>::IPMetric(const IPMetric& other) :
52   kernel(new KernelType(*other.kernel)),
53   kernelOwner(true)
54 {
55   // Nothing to do.
56 }
57 
58 template<typename KernelType>
operator =(const IPMetric & other)59 IPMetric<KernelType>& IPMetric<KernelType>::operator=(const IPMetric& other)
60 {
61   if (this == &other)
62     return *this;
63 
64   if (kernelOwner)
65     delete kernel;
66 
67   kernel = new KernelType(*other.kernel);
68   kernelOwner = true;
69   return *this;
70 }
71 
72 template<typename KernelType>
73 template<typename Vec1Type, typename Vec2Type>
Evaluate(const Vec1Type & a,const Vec2Type & b)74 inline typename Vec1Type::elem_type IPMetric<KernelType>::Evaluate(
75     const Vec1Type& a,
76     const Vec2Type& b)
77 {
78   // This is the metric induced by the kernel function.
79   // Maybe we can do better by caching some of this?
80   return sqrt(kernel->Evaluate(a, a) + kernel->Evaluate(b, b) -
81       2 * kernel->Evaluate(a, b));
82 }
83 
84 // Serialize the kernel.
85 template<typename KernelType>
86 template<typename Archive>
serialize(Archive & ar,const unsigned int)87 void IPMetric<KernelType>::serialize(Archive& ar,
88                                      const unsigned int /* version */)
89 {
90   // If we're loading, we need to allocate space for the kernel, and we will own
91   // the kernel.
92   if (Archive::is_loading::value)
93   {
94     if (kernelOwner)
95       delete kernel;
96     kernelOwner = true;
97   }
98 
99   ar & BOOST_SERIALIZATION_NVP(kernel);
100 }
101 
102 // A specialization for the linear kernel, which actually just turns out to be
103 // the Euclidean distance.
104 template<>
105 template<typename Vec1Type, typename Vec2Type>
Evaluate(const Vec1Type & a,const Vec2Type & b)106 inline typename Vec1Type::elem_type IPMetric<kernel::LinearKernel>::Evaluate(
107     const Vec1Type& a,
108     const Vec2Type& b)
109 {
110   return metric::LMetric<2, true>::Evaluate(a, b);
111 }
112 
113 } // namespace metric
114 } // namespace mlpack
115 
116 #endif
117