Som.h
1 /*
2 
3 MIT License
4 
5 Copyright (c) 2017 FMI Open Development / Markus Peura, first.last@fmi.fi
6 
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
13 
14 The above copyright notice and this permission notice shall be included in all
15 copies or substantial portions of the Software.
16 
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 SOFTWARE.
24 
25 */
26 /*
27 Part of Rack development has been done in the BALTRAD projects part-financed
28 by the European Union (European Regional Development Fund and European
29 Neighbourhood Partnership Instrument, Baltic Sea Region Programme 2007-2013)
30 */
31 #ifndef SOM_H_
32 #define SOM_H_
33 
34 
35 
36 
37 /*
38  g++ drain/examples/Som-example.cpp drain/util/{Caster,Variable,Debug}.cpp drain/image/{Geometry,Coordinates,Image,FilePng}.cpp -lpng -o Som-example
39  */
40 #include <iostream>
41 #include <vector>
42 #include <list>
43 #include <limits>
44 #include <sstream>
45 
46 #include <stdlib.h>
47 
48 #include "drain/Variable.h"
49 
50 
51 
52 namespace drain {
53 
54 // Consider
55 typedef std::vector<double> SomVector; // for operator(std::ostream &)
56 
64 template <class T = std::vector<double> >
65 class Som {
66 
67 public:
68 
69  Som(int width=0, int height=0);
70 
71 
75  inline
76  void setGeometry(int width, int height) {
77  this->width = width;
78  this->height = height;
79  map.resize(height);
80  for (int j = 0; j < height; ++j) {
81  map[j].resize(width);
82  }
83  }
84 
88  void fill(const T & sample){ // rename fill ?
89 
90  for (int i=0; i<width; i++){
91  for (int j=0; j<height; j++){
92  map[j][i] = sample;
93  }
94  }
95  }
96 
98 
105  void initialise(void (* init)(T & x)) {
106 
107  for (int i=0; i<width; i++){
108  for (int j=0; j<height; j++){
109  (*init)(map[j][i]);
110  }
111  }
112 
113  }
114 
115  inline
116  void setNeighbourhoodRadius(double r){
117  radius2 = r*r;
118  }
119 
120  inline
121  void setLearningCoefficient(double c){
123  }
124 
125 
126 
127  void setDistanceFunction(double (* d)(const T & x1, const T & x2)) {
128  distanceFunction = d;
129  }
130 
131  void setMixingFunction(void (* mix)(const T & x1, const T & x2, double coeff, T & m)) {
132  mixingFunction = mix;
133  }
134 
135 
137  inline
138  int getHeight() const {
139  return height;
140  }
141 
143  inline
144  int getWidth() const {
145  return width;
146  }
147 
149 
154  void findBestMatchingUnit(const T & sample, int & iBest, int & jBest){
155 
156  double d;
157  double dBest = std::numeric_limits<double>::max();
158 
159  for (int j=0; j<height; j++){
160  for (int i=0; i<width; i++){
161  d = (*distanceFunction)( sample, map[j][i]);
162  if (d < dBest){
163  dBest = d;
164  iBest = i;
165  jBest = j;
166  }
167  }
168  }
169  }
170 
171 
173 
176  void train(const T & x){
177  int iBest;
178  int jBest;
179  findBestMatchingUnit(x, iBest, jBest);
180  train(x, iBest, jBest);
181  /*
182  double f;
183  for (int j=0; j<height; ++j){
184  for (int i=0; i<width; ++i){
185  f = defaultNeighborhoodFunction(i-iBest, j-jBest);
186  (*mixingFunction)(map[j][i], x, f, map[j][i]);
187  }
188  }
189  */
190  };
191 
195  inline
196  void train(const T &x, int iBest, int jBest){
197  double f;
198  for (int j=0; j<height; ++j){
199  for (int i=0; i<width; ++i){
200  f = defaultNeighborhoodFunction(i-iBest, j-jBest);
201  (*mixingFunction)(map[j][i], x, f, map[j][i]);
202  }
203  }
204  };
205 
206 
207 
208  void toStream(std::ostream &ostr) const{
209 
210  std::string delimiter = "";
211 
212  ostr << title << "\n";
213  for (int j=0; j<height; j++){
214  for (int i=0; i<width; i++){
215  ostr << j << ',' << i << ':';
216  ostr << '\t' << map[j][i] << '\n';
217  //delimiter = "";
218  //result += "\n";
219  };
220  ostr << '\n';
221  };
222 
223  };
224 
225 
226  //static
227  double defaultNeighborhoodFunction(const int & i, const int & j) const {
228  return radius2 / (radius2 + i*i + j*j);
229  }
230 
231  static
232  double defaultDistanceMetric(const T & x1, const T & x2);
233 
234  static
235  void defaultMixingFunction(const T & x1, const T & x2, double coeff, T & m);
236 
237 
238 
239 
241  std::vector< std::vector<T> > map;
242 
243 protected:
244 
246 
249  double (* distanceFunction)(const T & x1, const T & x2);
250 
252 
255  void (* mixingFunction)(const T & x1, const T & x2, double alpha, T & result);
256 
257 
258  std::string title;
259 
260  // signed, because comparisons will typically involve signed integers
261  int width;
262 
263  // signed, because comparisons will typically involve signed integers
264  int height;
265 
267  double radius2;
268 
271 
272 };
273 
274 
275 
276 /*
277  For vectors and str objects having
278  */
279 template <class T>
280 double euclideanDistance2(const T & x1, const T & x2) {
281 
282  double d, result = 0.0;
283 
284  for (size_t i = 0; i < x1.size(); ++i) {// todo iterate
285  d = x1[i]-x2[i]; // todo dist();
286  result += d*d;
287  }
288 
289  return result;
290 
291 }
292 
293 template <class T>
294 void vectorMix(const T & x1, const T & x2, double coeff, T & m){ // todo iterate
295 
296  for (size_t k = 0; k < x1.size(); ++k)
297  m[k] = (1.0-coeff)*x1[k] + coeff*x2[k];
298 
299 }
300 
301 template <>
302 Som<>::Som(int width, int height){
303  setGeometry(width, height);
304  setDistanceFunction( euclideanDistance2 ); // consider Som<double>
305  setMixingFunction( vectorMix ); // consider Som<double>
306 }
307 
308 
309 
311 template <class T>
312 void uniformRandomVector256(std::vector<T> & x) {
313 
314  for (size_t k = 0; k < x.size(); ++k)
315  x[k] = static_cast<T>(rand() & 0xff);
316  //x[k] = static_cast<T2>(rand() & 0xffff)/static_cast<T2>(0xf00);
317 
318 }
319 
320 
321 
322 
323 
324 // Utilities
325 /*
326 template <class T>
327 static
328 double Som<std::vector<T> >::defaultNeighborhoodFunction(const int & i, const int & j) const {
329  return radius2 / (radius2 + i*i + j*j);
330 }
331  */
332 
333 
334 
335 /*
336 template <class T>
337 double Som<T>::defaultDistanceMetric(const T & x1, const T & x2) {
338 
339  double d, result = 0.0;
340 
341  for (int i = 0; i < x1.size(); ++i) {
342  d = x1[i]-x2[i];
343  result += d*d;
344  }
345 
346  return result;
347 
348 }
349  */
350 
351 //class Som< std::vector<T> >;
352 /*
353 template <class T>
354 double Som< std::vector<T> >::defaultDistanceMetric(const T & x1, const T & x2) {
355  return 123.456;
356 }
357  */
358 
359 /*
360 template <class T>
361 void Som<T>::defaultMixingFunction(const T & x1, const T & x2, double coeff, T & m){
362 
363  for (int k = 0; k < x1.size(); ++k)
364  m[k] = (1.0-coeff)*x1[k] + coeff*x2[k];
365 
366 }
367  */
368 
369 
370 
372 template <class T>
373 //std::ostream & operator<<(std::ostream & ostr, const NeuralVector<T> & n){
374 std::ostream & operator<<(std::ostream & ostr, const std::vector<T> & n){
375 
376  for (typename std::vector<T>::const_iterator it = n.begin(); it !=
377  n.end(); ++it)
378  ostr << *it << ' ';
379  //ostr << '\n';
380  return ostr;
381 };
382 
383 template <class T>
384 //std::ostream & operator<<(std::ostream & ostr, const NeuralVector<T> & n){
385 std::ostream & operator<<(std::ostream & ostr, const Som<T> & som){
386  som.toStream(ostr);
387  return ostr;
388 };
389 
390 
391 } // drain
392 
393 
394 
395 /* namespace drain */
396 
397 #endif /* SOM_H_ */
398 
399 // Drain
Definition: Som.h:65
double(* distanceFunction)(const T &x1, const T &x2)
The similarity metric applied in finding the best-matching unit.
Definition: Som.h:249
void(* mixingFunction)(const T &x1, const T &x2, double alpha, T &result)
Given objects x1 and x1 and a mixing coefficient coeff , outputs mixed object m.
Definition: Som.h:255
void setGeometry(int width, int height)
Definition: Som.h:76
void fill(const T &sample)
Definition: Som.h:88
double learningCoefficient
The radius of the neighbourhood kernel applied in training;.
Definition: Som.h:270
void train(const T &x)
Training with a single sample.
Definition: Som.h:176
int getHeight() const
The number of rows in the map.
Definition: Som.h:138
void train(const T &x, int iBest, int jBest)
Definition: Som.h:196
double radius2
The radius of the neighbourhood kernel applied in training;.
Definition: Som.h:267
std::vector< std::vector< T > > map
The actual neural network, two-dimensional map of units.
Definition: Som.h:241
void findBestMatchingUnit(const T &sample, int &iBest, int &jBest)
Finds the unit with state closesest to that of sample.
Definition: Som.h:154
void initialise(void(*init)(T &x))
Initialise the map with a user-defined function.
Definition: Som.h:105
int getWidth() const
The number of columns in the map.
Definition: Som.h:144
Definition: DataSelector.cpp:1277
void uniformRandomVector256(std::vector< T > &x)
For initialising vector Soms.
Definition: Som.h:312