xref: /oneTBB/examples/graph/som/som.hpp (revision b15aabb3)
1 /*
2     Copyright (c) 2005-2021 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 
22 #ifndef TBB_examples_som_H
23 #define TBB_examples_som_H
24 
25 #include <cmath>
26 #include <cfloat>
27 #include <cstdio>
28 #include <cstdlib>
29 
30 #include <vector>
31 #include <iostream>
32 #include <tuple>
33 
34 #include "oneapi/tbb/blocked_range2d.h"
35 
36 typedef oneapi::tbb::blocked_range2d<int> subsquare_type;
37 typedef std::tuple<double, int, int> search_result_type;
38 
39 std::ostream &operator<<(std::ostream &out, const search_result_type &s);
40 
41 #define RADIUS 0 // for the std::gets
42 #define XV     1
43 #define YV     2
44 
45 // to have single definitions of static variables, define _MAIN_C_ in the main program
46 //
47 #ifdef _MAIN_C_
48 #define DEFINE  // nothing
49 #define INIT(n) = n
50 #else // not in main file
51 #define DEFINE  extern
52 #define INIT(n) // nothing
53 #endif // _MAIN_C_
54 
55 DEFINE int nElements INIT(3); // length of input vectors, matching vector in map
56 DEFINE double max_learning_rate INIT(0.8); // decays exponentially
57 DEFINE double radius_decay_rate;
58 DEFINE double learning_decay_rate INIT(0.005);
59 DEFINE double max_radius;
60 DEFINE bool extra_debug INIT(false);
61 DEFINE bool cancel_test INIT(false);
62 
63 DEFINE int xMax INIT(100);
64 DEFINE int yMax INIT(100);
65 DEFINE int nPasses INIT(100);
66 
67 enum InitializeType { InitializeRandom, InitializeGradient };
68 #define RED   0
69 #define GREEN 1
70 #define BLUE  2
71 class SOM_element;
72 void remark_SOM_element(const SOM_element &s);
73 
74 // all SOM_element vectors are the same length (nElements), so we do not have
75 // to range-check the vector accesses.
76 class SOM_element {
77     std::vector<double> w;
78 
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) {}
operator [](int indx)83     double &operator[](int indx) {
84         return w.at(indx);
85     }
operator [](int indx) const86     const double &operator[](int indx) const {
87         return w.at(indx);
88     }
operator ==(SOM_element const & other) const89     bool operator==(SOM_element const &other) const {
90         for (std::size_t i = 0; i < size(); ++i) {
91             if (w[i] != other.w[i]) {
92                 return false;
93             }
94         }
95         return true;
96     }
operator !=(SOM_element const & other) const97     bool operator!=(SOM_element const &other) const {
98         return !operator==(other);
99     }
elementwise_max(SOM_element const & other)100     void elementwise_max(SOM_element const &other) {
101         for (std::size_t i = 0; i < w.size(); ++i)
102             if (w[i] < other.w[i])
103                 w[i] = other.w[i];
104     }
elementwise_min(SOM_element const & other)105     void elementwise_min(SOM_element const &other) {
106         for (std::size_t i = 0; i < w.size(); ++i)
107             if (w[i] > other.w[i])
108                 w[i] = other.w[i];
109     }
size() const110     std::size_t size() const {
111         return w.size();
112     }
113 };
114 
115 typedef std::vector<SOM_element> teaching_vector_type;
116 
117 DEFINE SOM_element max_range;
118 DEFINE SOM_element min_range;
119 
120 extern double randval(double lowlimit, double highlimit);
121 
122 extern void find_data_ranges(teaching_vector_type &teaching,
123                              SOM_element &max_range,
124                              SOM_element &min_range);
125 
126 extern void add_fraction_of_difference(SOM_element &to, SOM_element &from, double frac);
127 
128 DEFINE teaching_vector_type my_teaching;
129 
130 class SOMap {
131     std::vector<std::vector<SOM_element>> my_map;
132 
133 public:
SOMap(int xSize,int ySize)134     SOMap(int xSize, int ySize) {
135         my_map.reserve(xSize);
136         for (int i = 0; i < xSize; ++i) {
137             my_map.push_back(teaching_vector_type());
138             my_map[i].reserve(ySize);
139             for (int j = 0; j < ySize; ++j) {
140                 my_map[i].push_back(SOM_element());
141             }
142         }
143     }
size()144     std::size_t size() {
145         return my_map.size();
146     }
147     void initialize(InitializeType it, SOM_element &max_range, SOM_element &min_range);
operator [](int indx)148     teaching_vector_type &operator[](int indx) {
149         return my_map[indx];
150     }
at(int xVal,int yVal)151     SOM_element &at(int xVal, int yVal) {
152         return my_map[xVal][yVal];
153     }
at(search_result_type const & s)154     SOM_element &at(search_result_type const &s) {
155         return my_map[std::get<1>(s)][std::get<2>(s)];
156     }
epoch_update(SOM_element const & s,int epoch,int min_x,int min_y,double radius,double learning_rate)157     void epoch_update(SOM_element const &s,
158                       int epoch,
159                       int min_x,
160                       int min_y,
161                       double radius,
162                       double learning_rate) {
163         int min_xiter = (int)((double)min_x - radius);
164         if (min_xiter < 0)
165             min_xiter = 0;
166         int max_xiter = (int)((double)min_x + radius);
167         if (max_xiter > (int)my_map.size() - 1)
168             max_xiter = (int)(my_map.size() - 1);
169         oneapi::tbb::blocked_range<int> br1(min_xiter, max_xiter, 1);
170         epoch_update_range(s, epoch, min_x, min_y, radius, learning_rate, br1);
171     }
172     void epoch_update_range(SOM_element const &s,
173                             int epoch,
174                             int min_x,
175                             int min_y,
176                             double radius,
177                             double learning_rate,
178                             oneapi::tbb::blocked_range<int> &r);
179     void teach(teaching_vector_type &id);
180     void debug_output();
181     // find BMU given an input, returns distance
182     double BMU_range(const SOM_element &s, int &xval, int &yval, subsquare_type &r);
BMU(const SOM_element & s,int & xval,int & yval)183     double BMU(const SOM_element &s, int &xval, int &yval) {
184         subsquare_type br(0, (int)my_map.size(), 1, 0, (int)my_map[0].size(), 1);
185         return BMU_range(s, xval, yval, br);
186     }
187 };
188 
189 extern double distance_squared(SOM_element x, SOM_element y);
190 void remark_SOM_element(const SOM_element &s);
191 
192 extern void readInputData();
193 #endif // TBB_examples_som_H
194