SHOGUN  6.1.3
KernelManager.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) The Shogun Machine Learning Toolbox
3  * Written (w) 2014 - 2017 Soumyajit De
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice, this
10  * list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
19  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * The views and conclusions contained in the software and documentation are those
27  * of the authors and should not be interpreted as representing official policies,
28  * either expressed or implied, of the Shogun Development Team.
29  */
30 
31 #include <vector>
32 #include <memory>
33 #include <shogun/io/SGIO.h>
35 #include <shogun/kernel/Kernel.h>
41 
42 using namespace shogun;
43 using namespace internal;
44 
45 KernelManager::KernelManager()
46 {
47  SG_SDEBUG("Kernel manager instance initialized!\n");
48 }
49 
50 KernelManager::KernelManager(index_t num_kernels)
51 {
52  SG_SDEBUG("Kernel manager instance initialized with %d kernels!\n", num_kernels);
53  m_kernels.resize(num_kernels);
54  m_precomputed_kernels.resize(num_kernels);
55  std::fill(m_kernels.begin(), m_kernels.end(), nullptr);
56  std::fill(m_precomputed_kernels.begin(), m_precomputed_kernels.end(), nullptr);
57 }
58 
59 KernelManager::~KernelManager()
60 {
61  clear();
62 }
63 
64 void KernelManager::clear()
65 {
66  m_kernels.resize(0);
67  m_precomputed_kernels.resize(0);
68 }
69 
70 InitPerKernel KernelManager::kernel_at(index_t i)
71 {
72  SG_SDEBUG("Entering!\n");
73  REQUIRE(i<num_kernels(),
74  "Value of i (%d) should be between 0 and %d, inclusive!",
75  i, num_kernels()-1);
76  SG_SDEBUG("Leaving!\n");
77  return InitPerKernel(m_kernels[i]);
78 }
79 
80 CKernel* KernelManager::kernel_at(index_t i) const
81 {
82  SG_SDEBUG("Entering!\n");
83  REQUIRE(i<num_kernels(),
84  "Value of i (%d) should be between 0 and %d, inclusive!",
85  i, num_kernels()-1);
86  if (m_precomputed_kernels[i]==nullptr)
87  {
88  SG_SDEBUG("Leaving!\n");
89  return m_kernels[i].get();
90  }
91  SG_SDEBUG("Precomputed kernel exists!\n");
92  SG_SDEBUG("Leaving!\n");
93  return m_precomputed_kernels[i].get();
94 }
95 
96 void KernelManager::push_back(CKernel* kernel)
97 {
98  SG_SDEBUG("Entering!\n");
99  SG_REF(kernel);
100  m_kernels.push_back(std::shared_ptr<CKernel>(kernel, [](CKernel* ptr) { SG_UNREF(ptr); }));
101  m_precomputed_kernels.push_back(nullptr);
102  SG_SDEBUG("Leaving!\n");
103 }
104 
105 const index_t KernelManager::num_kernels() const
106 {
107  // TODO in case there is an underflow, at least it is not silent
108  // a better handling is to use index_t based Shogun data structures
109  ASSERT((index_t)m_kernels.size()>=0);
110  return (index_t)m_kernels.size();
111 }
112 
113 void KernelManager::precompute_kernel_at(index_t i)
114 {
115  SG_SDEBUG("Entering!\n");
116  REQUIRE(i<num_kernels(),
117  "Value of i (%d) should be between 0 and %d, inclusive!",
118  i, num_kernels()-1);
119  auto kernel=m_kernels[i].get();
120  if (kernel->get_kernel_type()!=K_CUSTOM)
121  {
122  // TODO give option to use different policies to precompute the kernel matrix
123  // this one here is default setting : use shogun's pthread parallelism to compute
124  // the kernel matrix.
125  SGMatrix<float32_t> kernel_matrix=kernel->get_kernel_matrix<float32_t>();
126  m_precomputed_kernels[i]=std::shared_ptr<CCustomKernel>(new CCustomKernel(kernel_matrix));
127  SG_SDEBUG("Kernel type %s is precomputed and replaced internally with %s!\n",
128  kernel->get_name(), m_precomputed_kernels[i]->get_name());
129  }
130  SG_SDEBUG("Leaving!\n");
131 }
132 
133 void KernelManager::restore_kernel_at(index_t i)
134 {
135  SG_SDEBUG("Entering!\n");
136  REQUIRE(i<num_kernels(),
137  "Value of i (%d) should be between 0 and %d, inclusive!",
138  i, num_kernels()-1);
139  m_precomputed_kernels[i]=nullptr;
140  SG_SDEBUG("Precomputed kernel (if any) was deleted!\n");
141  SG_SDEBUG("Leaving!\n");
142 }
143 
144 bool KernelManager::same_distance_type() const
145 {
146  ASSERT(num_kernels()>0);
147  bool same=false;
148  EDistanceType distance_type=D_UNKNOWN;
149  for (auto i=0; i<num_kernels(); ++i)
150  {
151  CShiftInvariantKernel* shift_invariant_kernel=dynamic_cast<CShiftInvariantKernel*>(kernel_at(i));
152  if (shift_invariant_kernel!=nullptr)
153  {
154  auto current_distance_type=shift_invariant_kernel->get_distance_type();
155  if (distance_type==D_UNKNOWN)
156  {
157  distance_type=current_distance_type;
158  same=true;
159  }
160  else if (distance_type==current_distance_type)
161  same=true;
162  else
163  {
164  same=false;
165  break;
166  }
167  }
168  else
169  {
170  same=false;
171  SG_SINFO("Kernel at location %d is not of CShiftInvariantKernel type (was of %s type)!\n",
172  i, kernel_at(i)->get_name());
173  break;
174  }
175  }
176  return same;
177 }
178 
179 CDistance* KernelManager::get_distance_instance() const
180 {
181  REQUIRE(same_distance_type(), "Distance types for all the kernels are not the same!\n");
182 
183  CDistance* distance=nullptr;
184  CShiftInvariantKernel* kernel_0=dynamic_cast<CShiftInvariantKernel*>(kernel_at(0));
185  REQUIRE(kernel_0, "Kernel (%s) must be of CShiftInvariantKernel type!\n", kernel_at(0)->get_name());
186  if (kernel_0->get_distance_type()==D_EUCLIDEAN)
187  {
188  auto euclidean_distance=new CEuclideanDistance();
189  euclidean_distance->set_disable_sqrt(true);
190  distance=euclidean_distance;
191  }
192  else if (kernel_0->get_distance_type()==D_MANHATTAN)
193  {
194  auto manhattan_distance=new CManhattanMetric();
195  distance=manhattan_distance;
196  }
197  else
198  {
199  SG_SERROR("Unsupported distance type!\n");
200  }
201  return distance;
202 }
203 
204 void KernelManager::set_precomputed_distance(CCustomDistance* distance) const
205 {
206  REQUIRE(distance!=nullptr, "Distance instance cannot be null!\n");
207  for (auto i=0; i<num_kernels(); ++i)
208  {
209  CKernel* kernel=kernel_at(i);
210  CShiftInvariantKernel* shift_inv_kernel=dynamic_cast<CShiftInvariantKernel*>(kernel);
211  REQUIRE(shift_inv_kernel!=nullptr, "Kernel instance (was %s) must be of CShiftInvarintKernel type!\n", kernel->get_name());
212  shift_inv_kernel->m_precomputed_distance=distance;
213  shift_inv_kernel->num_lhs=distance->get_num_vec_lhs();
214  shift_inv_kernel->num_rhs=distance->get_num_vec_rhs();
215  }
216 }
217 
218 void KernelManager::unset_precomputed_distance() const
219 {
220  for (auto i=0; i<num_kernels(); ++i)
221  {
222  CKernel* kernel=kernel_at(i);
223  CShiftInvariantKernel* shift_inv_kernel=dynamic_cast<CShiftInvariantKernel*>(kernel);
224  REQUIRE(shift_inv_kernel!=nullptr, "Kernel instance (was %s) must be of CShiftInvarintKernel type!\n", kernel->get_name());
225  shift_inv_kernel->m_precomputed_distance=nullptr;
226  shift_inv_kernel->num_lhs=0;
227  shift_inv_kernel->num_rhs=0;
228  }
229 }
virtual const char * get_name() const =0
float distance(CJLCoverTreePoint p1, CJLCoverTreePoint p2, float64_t upper_bound)
Base class for the family of kernel functions that only depend on the difference of the inputs...
Class Distance, a base class for all the distances used in the Shogun toolbox.
Definition: Distance.h:87
int32_t index_t
Definition: common.h:72
int32_t num_rhs
number of feature vectors on right hand side
virtual int32_t get_num_vec_lhs()
The Custom Kernel allows for custom user provided kernel matrices.
Definition: CustomKernel.h:36
#define REQUIRE(x,...)
Definition: SGIO.h:181
class ManhattanMetric
virtual EDistanceType get_distance_type() const
SGMatrix< float64_t > get_kernel_matrix()
#define SG_REF(x)
Definition: SGObject.h:52
virtual int32_t get_num_vec_rhs()
#define ASSERT(x)
Definition: SGIO.h:176
EDistanceType
Definition: Distance.h:32
T get(const Tag< T > &_tag) const
Definition: SGObject.h:381
int32_t num_lhs
number of feature vectors on left hand side
float float32_t
Definition: common.h:59
#define SG_UNREF(x)
Definition: SGObject.h:53
all of classes and functions are contained in the shogun namespace
Definition: class_list.h:18
#define SG_SDEBUG(...)
Definition: SGIO.h:153
virtual EKernelType get_kernel_type()=0
#define SG_SERROR(...)
Definition: SGIO.h:164
#define SG_SINFO(...)
Definition: SGIO.h:158
The Kernel base class.
The Custom Distance allows for custom user provided distance matrices.
class EuclideanDistance

SHOGUN Machine Learning Toolbox - Documentation