cnn.py
1 """!
2 
3 @brief Chaotic Neural Network
4 @details Implementation based on paper @cite article::nnet::cnn::1, @cite inproceedings::nnet::cnn::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 import math
28 import numpy
29 import random
30 import warnings
31 
32 try:
33  import matplotlib.pyplot as plt
34 
35  from matplotlib import rcParams
36  from matplotlib.font_manager import FontProperties
37 except Exception as error_instance:
38  warnings.warn("Impossible to import matplotlib (please, install 'matplotlib'), pyclustering's visualization "
39  "functionality is not available (details: '%s')." % str(error_instance))
40 
41 from enum import IntEnum
42 
43 from scipy.spatial import Delaunay
44 
45 from pyclustering.utils import euclidean_distance_square, average_neighbor_distance, heaviside, draw_dynamics
46 
47 
48 class type_conn(IntEnum):
49  """!
50  @brief Enumeration of connection types for Chaotic Neural Network.
51 
52  @see cnn_network
53 
54  """
55 
56 
57  ALL_TO_ALL = 0,
58 
59 
60  TRIANGULATION_DELAUNAY = 1,
61 
62 
64  """!
65  @brief Container of output dynamic of the chaotic neural network where states of each neuron during simulation are stored.
66 
67  @see cnn_network
68 
69  """
70 
71  def __init__(self, output=None, time=None):
72  """!
73  @brief Costructor of the chaotic neural network output dynamic.
74 
75  @param[in] output (list): Dynamic of oscillators on each step of simulation.
76  @param[in] time (list): Simulation time.
77 
78  """
79 
80 
81  self.output = output or []
82 
83 
84  self.time = time or []
85 
86 
87  def __len__(self):
88  """!
89  @brief (uint) Returns amount of simulation steps that are stored.
90 
91  """
92  return len(self.output)
93 
94 
96  """!
97  @brief Allocates observation matrix in line with output dynamic of the network.
98  @details Matrix where state of each neuron is denoted by zero/one in line with Heaviside function on each iteration.
99 
100  @return (list) Observation matrix of the network dynamic.
101 
102  """
103  number_neurons = len(self.output[0])
104  observation_matrix = []
105 
106  for iteration in range(len(self.output)):
107  obervation_column = []
108  for index_neuron in range(number_neurons):
109  obervation_column.append(heaviside(self.output[iteration][index_neuron]))
110 
111  observation_matrix.append(obervation_column)
112 
113  return observation_matrix
114 
115 
116  def __allocate_neuron_patterns(self, start_iteration, stop_iteration):
117  """!
118  @brief Allocates observation transposed matrix of neurons that is limited by specified periods of simulation.
119  @details Matrix where state of each neuron is denoted by zero/one in line with Heaviside function on each iteration.
120 
121  @return (list) Transposed observation matrix that is limited by specified periods of simulation.
122 
123  """
124 
125  pattern_matrix = []
126  for index_neuron in range(len(self.output[0])):
127  pattern_neuron = []
128  for iteration in range(start_iteration, stop_iteration):
129  pattern_neuron.append(heaviside(self.output[iteration][index_neuron]))
130 
131  pattern_matrix.append(pattern_neuron)
132 
133  return pattern_matrix
134 
135 
136  def allocate_sync_ensembles(self, steps):
137  """!
138  @brief Allocate clusters in line with ensembles of synchronous neurons where each synchronous ensemble corresponds to only one cluster.
139 
140  @param[in] steps (double): Amount of steps from the end that is used for analysis. During specified period chaotic neural network should have stable output
141  otherwise inccorect results are allocated.
142 
143  @return (list) Grours (lists) of indexes of synchronous oscillators.
144  For example [ [index_osc1, index_osc3], [index_osc2], [index_osc4, index_osc5] ].
145 
146  """
147 
148  iterations = steps
149  if iterations >= len(self.output):
150  iterations = len(self.output)
151 
152  ensembles = []
153 
154  start_iteration = len(self.output) - iterations
155  end_iteration = len(self.output)
156 
157  pattern_matrix = self.__allocate_neuron_patterns(start_iteration, end_iteration)
158 
159  ensembles.append( [0] )
160 
161  for index_neuron in range(1, len(self.output[0])):
162  neuron_pattern = pattern_matrix[index_neuron][:]
163 
164  neuron_assigned = False
165 
166  for ensemble in ensembles:
167  ensemble_pattern = pattern_matrix[ensemble[0]][:]
168 
169  if neuron_pattern == ensemble_pattern:
170  ensemble.append(index_neuron)
171  neuron_assigned = True
172  break
173 
174  if neuron_assigned is False:
175  ensembles.append( [index_neuron] )
176 
177  return ensembles
178 
179 
181  """!
182  @brief Visualizer of output dynamic of chaotic neural network (CNN).
183 
184  """
185 
186  @staticmethod
187  def show_output_dynamic(cnn_output_dynamic):
188  """!
189  @brief Shows output dynamic (output of each neuron) during simulation.
190 
191  @param[in] cnn_output_dynamic (cnn_dynamic): Output dynamic of the chaotic neural network.
192 
193  @see show_dynamic_matrix
194  @see show_observation_matrix
195 
196  """
197 
198  draw_dynamics(cnn_output_dynamic.time, cnn_output_dynamic.output, x_title="t", y_title="x")
199 
200 
201  @staticmethod
202  def show_dynamic_matrix(cnn_output_dynamic):
203  """!
204  @brief Shows output dynamic as matrix in grey colors.
205  @details This type of visualization is convenient for observing allocated clusters.
206 
207  @param[in] cnn_output_dynamic (cnn_dynamic): Output dynamic of the chaotic neural network.
208 
209  @see show_output_dynamic
210  @see show_observation_matrix
211 
212  """
213 
214  network_dynamic = numpy.array(cnn_output_dynamic.output)
215 
216  plt.imshow(network_dynamic.T, cmap=plt.get_cmap('gray'), interpolation='None', vmin=0.0, vmax=1.0)
217  plt.show()
218 
219 
220  @staticmethod
221  def show_observation_matrix(cnn_output_dynamic):
222  """!
223  @brief Shows observation matrix as black/white blocks.
224  @details This type of visualization is convenient for observing allocated clusters.
225 
226  @param[in] cnn_output_dynamic (cnn_dynamic): Output dynamic of the chaotic neural network.
227 
228  @see show_output_dynamic
229  @see show_dynamic_matrix
230 
231  """
232 
233  observation_matrix = numpy.array(cnn_output_dynamic.allocate_observation_matrix())
234  plt.imshow(observation_matrix.T, cmap = plt.get_cmap('gray'), interpolation='None', vmin = 0.0, vmax = 1.0)
235  plt.show()
236 
237 
239  """!
240  @brief Chaotic neural network based on system of logistic map where clustering phenomenon can be observed.
241  @details Here is an example how to perform cluster analysis using chaotic neural network:
242  @code
243  from pyclustering.cluster import cluster_visualizer
244  from pyclustering.samples.definitions import SIMPLE_SAMPLES
245  from pyclustering.utils import read_sample
246  from pyclustering.nnet.cnn import cnn_network, cnn_visualizer
247 
248  # Load stimulus from file.
249  stimulus = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE3)
250 
251  # Create chaotic neural network, amount of neurons should be equal to amount of stimulus.
252  network_instance = cnn_network(len(stimulus))
253 
254  # Perform simulation during 100 steps.
255  steps = 100
256  output_dynamic = network_instance.simulate(steps, stimulus)
257 
258  # Display output dynamic of the network.
259  cnn_visualizer.show_output_dynamic(output_dynamic)
260 
261  # Display dynamic matrix and observation matrix to show clustering phenomenon.
262  cnn_visualizer.show_dynamic_matrix(output_dynamic)
263  cnn_visualizer.show_observation_matrix(output_dynamic)
264 
265  # Visualize clustering results.
266  clusters = output_dynamic.allocate_sync_ensembles(10)
267  visualizer = cluster_visualizer()
268  visualizer.append_clusters(clusters, stimulus)
269  visualizer.show()
270  @endcode
271 
272  """
273 
274  def __init__(self, num_osc, conn_type = type_conn.ALL_TO_ALL, amount_neighbors = 3):
275  """!
276  @brief Constructor of chaotic neural network.
277 
278  @param[in] num_osc (uint): Amount of neurons in the chaotic neural network.
279  @param[in] conn_type (type_conn): CNN type connection for the network.
280  @param[in] amount_neighbors (uint): k-nearest neighbors for calculation scaling constant of weights.
281 
282  """
283 
284  self.__num_osc = num_osc
285  self.__conn_type = conn_type
286  self.__amount_neighbors = amount_neighbors
287 
288  self.__average_distance = 0.0
289  self.__weights = None
290  self.__weights_summary = None
291 
292  self.__location = None # just for network visualization
293 
294  random.seed()
295  self.__output = [ random.random() for _ in range(num_osc) ]
296 
297 
298  def __len__(self):
299  """!
300  @brief Returns size of the chaotic neural network that is defined by amount of neurons.
301 
302  """
303  return self.__num_osc
304 
305 
306  def simulate(self, steps, stimulus):
307  """!
308  @brief Simulates chaotic neural network with extrnal stimulus during specified steps.
309  @details Stimulus are considered as a coordinates of neurons and in line with that weights
310  are initialized.
311 
312  @param[in] steps (uint): Amount of steps for simulation.
313  @param[in] stimulus (list): Stimulus that are used for simulation.
314 
315  @return (cnn_dynamic) Output dynamic of the chaotic neural network.
316 
317  """
318 
319  self.__create_weights(stimulus)
320  self.__location = stimulus
321 
322  dynamic = cnn_dynamic([], [])
323  dynamic.output.append(self.__output)
324  dynamic.time.append(0)
325 
326  for step in range(1, steps, 1):
327  self.__output = self.__calculate_states()
328 
329  dynamic.output.append(self.__output)
330  dynamic.time.append(step)
331 
332  return dynamic
333 
334 
335  def __calculate_states(self):
336  """!
337  @brief Calculates new state of each neuron.
338  @detail There is no any assignment.
339 
340  @return (list) Returns new states (output).
341 
342  """
343 
344  output = [ 0.0 for _ in range(self.__num_osc) ]
345 
346  for i in range(self.__num_osc):
347  output[i] = self.__neuron_evolution(i)
348 
349  return output
350 
351 
352  def __neuron_evolution(self, index):
353  """!
354  @brief Calculates state of the neuron with specified index.
355 
356  @param[in] index (uint): Index of neuron in the network.
357 
358  @return (double) New output of the specified neuron.
359 
360  """
361  value = 0.0
362 
363  for index_neighbor in range(self.__num_osc):
364  value += self.__weights[index][index_neighbor] * (1.0 - 2.0 * (self.__output[index_neighbor] ** 2))
365 
366  return value / self.__weights_summary[index]
367 
368 
369  def __create_weights(self, stimulus):
370  """!
371  @brief Create weights between neurons in line with stimulus.
372 
373  @param[in] stimulus (list): External stimulus for the chaotic neural network.
374 
375  """
376 
377  self.__average_distance = average_neighbor_distance(stimulus, self.__amount_neighbors)
378 
379  self.__weights = [ [ 0.0 for _ in range(len(stimulus)) ] for _ in range(len(stimulus)) ]
380  self.__weights_summary = [ 0.0 for _ in range(self.__num_osc) ]
381 
382  if self.__conn_type == type_conn.ALL_TO_ALL:
383  self.__create_weights_all_to_all(stimulus)
384 
385  elif self.__conn_type == type_conn.TRIANGULATION_DELAUNAY:
387 
388 
389  def __create_weights_all_to_all(self, stimulus):
390  """!
391  @brief Create weight all-to-all structure between neurons in line with stimulus.
392 
393  @param[in] stimulus (list): External stimulus for the chaotic neural network.
394 
395  """
396 
397  for i in range(len(stimulus)):
398  for j in range(i + 1, len(stimulus)):
399  weight = self.__calculate_weight(stimulus[i], stimulus[j])
400 
401  self.__weights[i][j] = weight
402  self.__weights[j][i] = weight
403 
404  self.__weights_summary[i] += weight
405  self.__weights_summary[j] += weight
406 
407 
408  def __create_weights_delaunay_triangulation(self, stimulus):
409  """!
410  @brief Create weight Denlauny triangulation structure between neurons in line with stimulus.
411 
412  @param[in] stimulus (list): External stimulus for the chaotic neural network.
413 
414  """
415 
416  points = numpy.array(stimulus)
417  triangulation = Delaunay(points)
418 
419  for triangle in triangulation.simplices:
420  for index_tri_point1 in range(len(triangle)):
421  for index_tri_point2 in range(index_tri_point1 + 1, len(triangle)):
422  index_point1 = triangle[index_tri_point1]
423  index_point2 = triangle[index_tri_point2]
424 
425  weight = self.__calculate_weight(stimulus[index_point1], stimulus[index_point2])
426 
427  self.__weights[index_point1][index_point2] = weight
428  self.__weights[index_point2][index_point1] = weight
429 
430  self.__weights_summary[index_point1] += weight
431  self.__weights_summary[index_point2] += weight
432 
433 
434  def __calculate_weight(self, stimulus1, stimulus2):
435  """!
436  @brief Calculate weight between neurons that have external stimulus1 and stimulus2.
437 
438  @param[in] stimulus1 (list): External stimulus of the first neuron.
439  @param[in] stimulus2 (list): External stimulus of the second neuron.
440 
441  @return (double) Weight between neurons that are under specified stimulus.
442 
443  """
444 
445  distance = euclidean_distance_square(stimulus1, stimulus2)
446  return math.exp(-distance / (2.0 * self.__average_distance))
447 
448 
449  def show_network(self):
450  """!
451  @brief Shows structure of the network: neurons and connections between them.
452 
453  """
454 
455  dimension = len(self.__location[0])
456  if (dimension != 3) and (dimension != 2):
457  raise NameError('Network that is located in different from 2-d and 3-d dimensions can not be represented')
458 
459  (fig, axes) = self.__create_surface(dimension)
460 
461  for i in range(0, self.__num_osc, 1):
462  if dimension == 2:
463  axes.plot(self.__location[i][0], self.__location[i][1], 'bo')
464  for j in range(i, self.__num_osc, 1): # draw connection between two points only one time
465  if self.__weights[i][j] > 0.0:
466  axes.plot([self.__location[i][0], self.__location[j][0]], [self.__location[i][1], self.__location[j][1]], 'b-', linewidth = 0.5)
467 
468  elif dimension == 3:
469  axes.scatter(self.__location[i][0], self.__location[i][1], self.__location[i][2], c = 'b', marker = 'o')
470 
471  for j in range(i, self.__num_osc, 1): # draw connection between two points only one time
472  if self.__weights[i][j] > 0.0:
473  axes.plot([self.__location[i][0], self.__location[j][0]], [self.__location[i][1], self.__location[j][1]], [self.__location[i][2], self.__location[j][2]], 'b-', linewidth = 0.5)
474 
475  plt.grid()
476  plt.show()
477 
478 
479  def __create_surface(self, dimension):
480  """!
481  @brief Prepares surface for showing network structure in line with specified dimension.
482 
483  @param[in] dimension (uint): Dimension of processed data (external stimulus).
484 
485  @return (tuple) Description of surface for drawing network structure.
486 
487  """
488 
489  rcParams['font.sans-serif'] = ['Arial']
490  rcParams['font.size'] = 12
491 
492  fig = plt.figure()
493  axes = None
494  if dimension == 2:
495  axes = fig.add_subplot(111)
496  elif dimension == 3:
497  axes = fig.gca(projection='3d')
498 
499  surface_font = FontProperties()
500  surface_font.set_name('Arial')
501  surface_font.set_size('12')
502 
503  return (fig, axes)
output
Output value of each neuron on each iteration.
Definition: cnn.py:81
def __create_weights_delaunay_triangulation(self, stimulus)
Create weight Denlauny triangulation structure between neurons in line with stimulus.
Definition: cnn.py:408
def show_dynamic_matrix(cnn_output_dynamic)
Shows output dynamic as matrix in grey colors.
Definition: cnn.py:202
time
Sequence of simulation steps of the network.
Definition: cnn.py:84
Utils that are used by modules of pyclustering.
Definition: __init__.py:1
def show_output_dynamic(cnn_output_dynamic)
Shows output dynamic (output of each neuron) during simulation.
Definition: cnn.py:187
def __create_weights(self, stimulus)
Create weights between neurons in line with stimulus.
Definition: cnn.py:369
Visualizer of output dynamic of chaotic neural network (CNN).
Definition: cnn.py:180
Enumeration of connection types for Chaotic Neural Network.
Definition: cnn.py:48
def __allocate_neuron_patterns(self, start_iteration, stop_iteration)
Allocates observation transposed matrix of neurons that is limited by specified periods of simulation...
Definition: cnn.py:116
def __calculate_weight(self, stimulus1, stimulus2)
Calculate weight between neurons that have external stimulus1 and stimulus2.
Definition: cnn.py:434
def __calculate_states(self)
Calculates new state of each neuron.
Definition: cnn.py:335
def __len__(self)
Returns size of the chaotic neural network that is defined by amount of neurons.
Definition: cnn.py:298
def show_network(self)
Shows structure of the network: neurons and connections between them.
Definition: cnn.py:449
Container of output dynamic of the chaotic neural network where states of each neuron during simulati...
Definition: cnn.py:63
def __create_weights_all_to_all(self, stimulus)
Create weight all-to-all structure between neurons in line with stimulus.
Definition: cnn.py:389
def show_observation_matrix(cnn_output_dynamic)
Shows observation matrix as black/white blocks.
Definition: cnn.py:221
def __create_surface(self, dimension)
Prepares surface for showing network structure in line with specified dimension.
Definition: cnn.py:479
def __len__(self)
(uint) Returns amount of simulation steps that are stored.
Definition: cnn.py:87
def allocate_sync_ensembles(self, steps)
Allocate clusters in line with ensembles of synchronous neurons where each synchronous ensemble corre...
Definition: cnn.py:136
def __neuron_evolution(self, index)
Calculates state of the neuron with specified index.
Definition: cnn.py:352
def simulate(self, steps, stimulus)
Simulates chaotic neural network with extrnal stimulus during specified steps.
Definition: cnn.py:306
def __init__(self, num_osc, conn_type=type_conn.ALL_TO_ALL, amount_neighbors=3)
Constructor of chaotic neural network.
Definition: cnn.py:274
Chaotic neural network based on system of logistic map where clustering phenomenon can be observed...
Definition: cnn.py:238
def allocate_observation_matrix(self)
Allocates observation matrix in line with output dynamic of the network.
Definition: cnn.py:95
def __init__(self, output=None, time=None)
Costructor of the chaotic neural network output dynamic.
Definition: cnn.py:71