1 /*
2     Copyright (c) 2005-2020 Intel Corporation
3 
4     Licensed under the Apache License, Version 2.0 (the "License");
5     you may not use this file except in compliance with the License.
6     You may obtain a copy of the License at
7 
8         http://www.apache.org/licenses/LICENSE-2.0
9 
10     Unless required by applicable law or agreed to in writing, software
11     distributed under the License is distributed on an "AS IS" BASIS,
12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13     See the License for the specific language governing permissions and
14     limitations under the License.
15 */
16 
17 //
18 // Self-organizing map
19 //
20 // support for self-ordering maps
21 #ifndef __SOM_H__
22 #define __SOM_H__
23 
24 #include <vector>
25 #include <cstdlib>
26 #include <cmath>
27 #include <cfloat>
28 #include <iostream>
29 #include <cstdio>
30 
31 #include "tbb/flow_graph.h"
32 #include "tbb/blocked_range2d.h"
33 
34 using namespace tbb;
35 using namespace tbb::flow;
36 
37 typedef blocked_range2d<int> subsquare_type;
38 typedef tuple<double,int,int> search_result_type;
39 
40 std::ostream& operator<<( std::ostream &out, const search_result_type &s);
41 
42 #define RADIUS 0  // for the std::gets
43 #define XV     1
44 #define YV     2
45 
46 // to have single definitions of static variables, define _MAIN_C_ in the main program
47 //
48 #ifdef _MAIN_C_
49 #define DEFINE // nothing
50 #define INIT(n) = n
51 #else // not in main file
52 #define DEFINE extern
53 #define INIT(n) // nothing
54 #endif  // _MAIN_C_
55 
56 DEFINE int nElements INIT(3);  // length of input vectors, matching vector in map
57 DEFINE double max_learning_rate INIT(0.8);  // decays exponentially
58 DEFINE double radius_decay_rate;
59 DEFINE double learning_decay_rate INIT(0.005);
60 DEFINE double max_radius;
61 DEFINE bool extra_debug INIT(false);
62 DEFINE bool cancel_test INIT(false);
63 
64 DEFINE int xMax INIT(100);
65 DEFINE int yMax INIT(100);
66 DEFINE int nPasses INIT(100);
67 
68 enum InitializeType { InitializeRandom, InitializeGradient };
69 #define RED 0
70 #define GREEN 1
71 #define BLUE 2
72 class SOM_element;
73 void remark_SOM_element(const SOM_element &s);
74 
75 // all SOM_element vectors are the same length (nElements), so we do not have
76 // to range-check the vector accesses.
77 class SOM_element {
78     std::vector<double> w;
79 public:
80     friend std::ostream& operator<<( std::ostream &out, const SOM_element &s);
81     friend void remark_SOM_element(const SOM_element &s);
SOM_element()82     SOM_element() : w(nElements,0.0) {}
83     double &operator[](int indx) { return w.at(indx); }
84     const double &operator[](int indx) const { return w.at(indx); }
85     bool operator==(SOM_element const &other) const {
86         for(size_t i=0;i<size();++i) {
87             if(w[i] != other.w[i]) {
88                 return false;
89             }
90         }
91         return true;
92     }
93     bool operator!=(SOM_element const &other) const { return !operator==(other); }
elementwise_max(SOM_element const & other)94     void elementwise_max(SOM_element const &other) {
95         for(size_t i = 0; i < w.size(); ++i) if(w[i] < other.w[i]) w[i] = other.w[i];
96     }
elementwise_min(SOM_element const & other)97     void elementwise_min(SOM_element const &other) {
98         for(size_t i = 0; i < w.size(); ++i) if(w[i] > other.w[i]) w[i] = other.w[i];
99     }
size()100     size_t size() const { return w.size(); }
101 };
102 
103 typedef std::vector<SOM_element> teaching_vector_type;
104 
105 DEFINE SOM_element max_range;
106 DEFINE SOM_element min_range;
107 
108 extern double randval( double lowlimit, double highlimit);
109 
110 extern void find_data_ranges(teaching_vector_type &teaching, SOM_element &max_range, SOM_element &min_range );
111 
112 extern void add_fraction_of_difference( SOM_element &to, SOM_element &from, double frac);
113 
114 DEFINE teaching_vector_type my_teaching;
115 
116 class SOMap {
117     std::vector< std::vector< SOM_element > > my_map;
118 public:
SOMap(int xSize,int ySize)119     SOMap(int xSize, int ySize) {
120         my_map.reserve(xSize);
121         for(int i = 0; i < xSize; ++i) {
122             my_map.push_back(teaching_vector_type());
123             my_map[i].reserve(ySize);
124             for(int j = 0; j < ySize;++j) {
125                 my_map[i].push_back(SOM_element());
126             }
127         }
128     }
size()129     size_t size() { return my_map.size(); }
130     void initialize(InitializeType it, SOM_element &max_range, SOM_element &min_range);
131     teaching_vector_type &operator[](int indx) { return my_map[indx]; }
at(int xVal,int yVal)132     SOM_element &at(int xVal, int yVal) { return my_map[xVal][yVal]; }
at(search_result_type const & s)133     SOM_element &at(search_result_type const &s) { return my_map[flow::get<1>(s)][flow::get<2>(s)]; }
epoch_update(SOM_element const & s,int epoch,int min_x,int min_y,double radius,double learning_rate)134     void epoch_update( SOM_element const &s, int epoch, int min_x, int min_y, double radius, double learning_rate) {
135         int min_xiter = (int)((double)min_x - radius);
136         if(min_xiter < 0) min_xiter = 0;
137         int max_xiter = (int)((double)min_x + radius);
138         if(max_xiter > (int)my_map.size()-1) max_xiter = (int)(my_map.size()-1);
139         blocked_range<int> br1(min_xiter, max_xiter, 1);
140         epoch_update_range(s, epoch, min_x, min_y, radius, learning_rate, br1);
141     }
142     void epoch_update_range( SOM_element const &s, int epoch, int min_x, int min_y, double radius, double learning_rate, blocked_range<int> &r);
143     void teach( teaching_vector_type &id);
144     void debug_output();
145     // find BMU given an input, returns distance
146     double BMU_range(const SOM_element &s, int &xval, int &yval, subsquare_type &r);
BMU(const SOM_element & s,int & xval,int & yval)147     double BMU(const SOM_element &s, int &xval, int &yval) {
148         subsquare_type br(0,(int)my_map.size(),1,0,(int)my_map[0].size(),1);
149         return BMU_range(s, xval, yval, br);
150     }
151 };
152 
153 extern double distance_squared(SOM_element x, SOM_element y);
154 void remark_SOM_element(const SOM_element &s);
155 
156 extern void readInputData();
157 #endif // __SOM_H__
158