syncsom.py
1 """!
2 
3 @brief Cluster analysis algorithm: SYNC-SOM
4 @details Implementation based on paper @cite article::syncsom::1.
5 
6 @authors Andrei Novikov (pyclustering@yandex.ru)
7 @date 2014-2020
8 @copyright GNU Public License
9 
10 @cond GNU_PUBLIC_LICENSE
11  PyClustering is free software: you can redistribute it and/or modify
12  it under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  PyClustering is distributed in the hope that it will be useful,
17  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  GNU General Public License for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with this program. If not, see <http://www.gnu.org/licenses/>.
23 @endcond
24 
25 """
26 
27 
28 from pyclustering.cluster.encoder import type_encoding
29 from pyclustering.cluster.syncnet import syncnet
30 
31 from pyclustering.nnet.som import som, type_conn
32 from pyclustering.nnet import initial_type
33 
34 from pyclustering.utils import euclidean_distance_square
35 
36 
37 class syncsom:
38  """!
39  @brief Class represents clustering algorithm SYNC-SOM. SYNC-SOM is bio-inspired algorithm that is based on oscillatory network
40  that uses self-organized feature map as the first layer.
41 
42  Example:
43  @code
44  # read sample for clustering
45  sample = read_sample(file);
46 
47  # create oscillatory network for cluster analysis where the first layer has
48  # size 10x10 and connectivity radius for objects 1.0.
49  network = syncsom(sample, 10, 10, 1.0);
50 
51  # simulate network (perform cluster analysis) and collect output dynamic
52  (dyn_time, dyn_phase) = network.process(True, 0.998);
53 
54  # obtain encoded clusters
55  encoded_clusters = network.get_som_clusters();
56 
57  # obtain real clusters
58  clusters = network.get_clusters();
59 
60  # show the first layer of the network
61  network.show_som_layer();
62 
63  # show the second layer of the network
64  network.show_sync_layer();
65  @endcode
66 
67  """
68 
69  @property
70  def som_layer(self):
71  """!
72  @brief The first layer of the oscillatory network - self-organized feature map.
73 
74  """
75  return self._som
76 
77 
78  @property
79  def sync_layer(self):
80  """!
81  @brief The second layer of the oscillatory network based on Kuramoto model.
82 
83  """
84  return self._sync
85 
86 
87  def __init__(self, data, rows, cols, radius):
88  """!
89  @brief Constructor of the double layer oscillatory network SYNC-SOM.
90 
91  @param[in] data (list): Input data that is presented as list of points (objects), each point should be represented by list or tuple.
92  @param[in] rows (uint): Rows of neurons (number of neurons in column) in the input layer (self-organized feature map).
93  @param[in] cols (uint): Columns of neurons (number of neurons in row) in the input later (self-organized feature map).
94  @param[in] radius (double): Connectivity radius between objects that defines connection between oscillators in the second layer.
95 
96  """
97 
98  self._data = data
99  self._radius = radius * radius
100 
101  self._som = som(rows, cols, conn_type=type_conn.grid_four, ccore=False) # The first (input) later - SOM layer.
102  self._som_osc_table = list()
103 
104  self._sync = None # The second (output) layer - Sync layer.
105  self._struct = None # Structure of connections between oscillators in the second layer - Sync layer.
106 
107  # For convenience
108  self._analyser = None
109 
110 
111  def process(self, collect_dynamic=False, order=0.999):
112  """!
113  @brief Performs simulation of the oscillatory network.
114 
115  @param[in] collect_dynamic (bool): If True - returns whole dynamic of oscillatory network, otherwise returns only last values of dynamics.
116  @param[in] order (double): Order of process synchronization that should be considered as end of clustering, destributed 0..1.
117 
118  @return (tuple) Dynamic of oscillatory network. If argument 'collect_dynamic' = True, than return dynamic for the whole simulation time,
119  otherwise returns only last values (last step of simulation) of dynamic.
120 
121  @see get_som_clusters()
122  @see get_clusters()
123  """
124 
125  # train self-organization map.
126  self._som.train(self._data, 100)
127 
128  # prepare to build list.
129  weights = list()
130  self._som_osc_table.clear() # must be cleared, if it's used before.
131  for i in range(self._som.size):
132  if self._som.awards[i] > 0:
133  weights.append(self._som.weights[i])
134  self._som_osc_table.append(i)
135 
136  # create oscillatory neural network.
137  self._sync = self.__create_sync_layer(weights)
138  self._analyser = self._sync.process(order, collect_dynamic=collect_dynamic)
139 
140  return self._analyser.time, self._analyser.output
141 
142 
143  def __create_sync_layer(self, weights):
144  """!
145  @brief Creates second layer of the network.
146 
147  @param[in] weights (list): List of weights of SOM neurons.
148 
149  @return (syncnet) Second layer of the network.
150 
151  """
152  sync_layer = syncnet(weights, 0.0, initial_phases = initial_type.RANDOM_GAUSSIAN, ccore=False)
153 
154  for oscillator_index1 in range(0, len(sync_layer)):
155  for oscillator_index2 in range(oscillator_index1 + 1, len(sync_layer)):
156  if self.__has_object_connection(oscillator_index1, oscillator_index2):
157  sync_layer.set_connection(oscillator_index1, oscillator_index2)
158 
159  return sync_layer
160 
161 
162  def __has_object_connection(self, oscillator_index1, oscillator_index2):
163  """!
164  @brief Searches for pair of objects that are encoded by specified neurons and that are connected in line with connectivity radius.
165 
166  @param[in] oscillator_index1 (uint): Index of the first oscillator in the second layer.
167  @param[in] oscillator_index2 (uint): Index of the second oscillator in the second layer.
168 
169  @return (bool) True - if there is pair of connected objects encoded by specified oscillators.
170 
171  """
172  som_neuron_index1 = self._som_osc_table[oscillator_index1]
173  som_neuron_index2 = self._som_osc_table[oscillator_index2]
174 
175  for index_object1 in self._som.capture_objects[som_neuron_index1]:
176  for index_object2 in self._som.capture_objects[som_neuron_index2]:
177  distance = euclidean_distance_square(self._data[index_object1], self._data[index_object2])
178  if distance <= self._radius:
179  return True
180 
181  return False
182 
183 
184  def get_som_clusters(self):
185  """!
186  @brief Returns clusters with SOM neurons that encode input features in line with result of synchronization in the second (Sync) layer.
187 
188  @return (list) List of clusters that are represented by lists of indexes of neurons that encode input data.
189 
190  @see process()
191  @see get_clusters()
192 
193  """
194 
195  sync_clusters = self._analyser.allocate_clusters()
196 
197  # Decode it to indexes of SOM neurons
198  som_clusters = list()
199  for oscillators in sync_clusters:
200  cluster = list()
201  for index_oscillator in oscillators:
202  index_neuron = self._som_osc_table[index_oscillator]
203  cluster.append(index_neuron)
204 
205  som_clusters.append(cluster)
206 
207  return som_clusters
208 
209 
210  def get_clusters(self, eps=0.1):
211  """!
212  @brief Returns clusters in line with ensembles of synchronous oscillators where each synchronous ensemble corresponds to only one cluster.
213 
214  @param[in] eps (double): Maximum error for allocation of synchronous ensemble oscillators.
215 
216  @return (list) List of grours (lists) of indexes of synchronous oscillators that corresponds to index of objects.
217 
218  @see process()
219  @see get_som_clusters()
220 
221  """
222 
223  sync_clusters = self._analyser.allocate_clusters(eps) # it isn't indexes of SOM neurons
224 
225  clusters = list()
226  for oscillators in sync_clusters:
227  cluster = list()
228  for index_oscillator in oscillators:
229  index_neuron = self._som_osc_table[index_oscillator]
230 
231  cluster += self._som.capture_objects[index_neuron]
232 
233  clusters.append(cluster)
234 
235  return clusters
236 
237 
239  """!
240  @brief Returns clustering result representation type that indicate how clusters are encoded.
241 
242  @return (type_encoding) Clustering result representation.
243 
244  @see get_clusters()
245 
246  """
247 
248  return type_encoding.CLUSTER_INDEX_LIST_SEPARATION
249 
250 
251  def show_som_layer(self):
252  """!
253  @brief Shows visual representation of the first (SOM) layer.
254 
255  """
256 
257  self._som.show_network()
258 
259 
260  def show_sync_layer(self):
261  """!
262  @brief Shows visual representation of the second (Sync) layer.
263 
264  """
265 
266  self._sync.show_network()
def show_som_layer(self)
Shows visual representation of the first (SOM) layer.
Definition: syncsom.py:251
def show_sync_layer(self)
Shows visual representation of the second (Sync) layer.
Definition: syncsom.py:260
def __init__(self, data, rows, cols, radius)
Constructor of the double layer oscillatory network SYNC-SOM.
Definition: syncsom.py:87
Utils that are used by modules of pyclustering.
Definition: __init__.py:1
def get_cluster_encoding(self)
Returns clustering result representation type that indicate how clusters are encoded.
Definition: syncsom.py:238
Module for representing clustering results.
Definition: encoder.py:1
Class represents clustering algorithm SyncNet.
Definition: syncnet.py:166
def process(self, collect_dynamic=False, order=0.999)
Performs simulation of the oscillatory network.
Definition: syncsom.py:111
def som_layer(self)
The first layer of the oscillatory network - self-organized feature map.
Definition: syncsom.py:70
def __create_sync_layer(self, weights)
Creates second layer of the network.
Definition: syncsom.py:143
def sync_layer(self)
The second layer of the oscillatory network based on Kuramoto model.
Definition: syncsom.py:79
def get_clusters(self, eps=0.1)
Returns clusters in line with ensembles of synchronous oscillators where each synchronous ensemble co...
Definition: syncsom.py:210
Cluster analysis algorithm: Sync.
Definition: syncnet.py:1
def get_som_clusters(self)
Returns clusters with SOM neurons that encode input features in line with result of synchronization i...
Definition: syncsom.py:184
Neural Network: Self-Organized Feature Map.
Definition: som.py:1
Represents self-organized feature map (SOM).
Definition: som.py:117
Class represents clustering algorithm SYNC-SOM.
Definition: syncsom.py:37
def __has_object_connection(self, oscillator_index1, oscillator_index2)
Searches for pair of objects that are encoded by specified neurons and that are connected in line wit...
Definition: syncsom.py:162
Neural and oscillatory network module.
Definition: __init__.py:1