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-2018
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 
242  Example:
243  @code
244  # load stimulus from file
245  stimulus = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1);
246 
247  # create chaotic neural network, amount of neurons should be equal to amout of stimulus
248  network_instance = cnn_network(len(stimulus));
249 
250  # simulate it during 100 steps
251  output_dynamic = network_instance.simulate(steps, stimulus);
252 
253  # display output dynamic of the network
254  cnn_visualizer.show_output_dynamic(output_dynamic);
255 
256  # dysplay dynamic matrix and observation matrix to show clustering
257  # phenomenon.
258  cnn_visualizer.show_dynamic_matrix(output_dynamic);
259  cnn_visualizer.show_observation_matrix(output_dynamic);
260  @endcode
261 
262  """
263 
264  def __init__(self, num_osc, conn_type = type_conn.ALL_TO_ALL, amount_neighbors = 3):
265  """!
266  @brief Constructor of chaotic neural network.
267 
268  @param[in] num_osc (uint): Amount of neurons in the chaotic neural network.
269  @param[in] conn_type (type_conn): CNN type connection for the network.
270  @param[in] amount_neighbors (uint): k-nearest neighbors for calculation scaling constant of weights.
271 
272  """
273 
274  self.__num_osc = num_osc
275  self.__conn_type = conn_type
276  self.__amount_neighbors = amount_neighbors
277 
278  self.__average_distance = 0.0
279  self.__weights = None
280  self.__weights_summary = None
281 
282  self.__location = None # just for network visualization
283 
284  random.seed()
285  self.__output = [ random.random() for _ in range(num_osc) ]
286 
287 
288  def __len__(self):
289  """!
290  @brief Returns size of the chaotic neural network that is defined by amount of neurons.
291 
292  """
293  return self.__num_osc
294 
295 
296  def simulate(self, steps, stimulus):
297  """!
298  @brief Simulates chaotic neural network with extrnal stimulus during specified steps.
299  @details Stimulus are considered as a coordinates of neurons and in line with that weights
300  are initialized.
301 
302  @param[in] steps (uint): Amount of steps for simulation.
303  @param[in] stimulus (list): Stimulus that are used for simulation.
304 
305  @return (cnn_dynamic) Output dynamic of the chaotic neural network.
306 
307  """
308 
309  self.__create_weights(stimulus)
310  self.__location = stimulus
311 
312  dynamic = cnn_dynamic([], [])
313  dynamic.output.append(self.__output)
314  dynamic.time.append(0)
315 
316  for step in range(1, steps, 1):
317  self.__output = self.__calculate_states()
318 
319  dynamic.output.append(self.__output)
320  dynamic.time.append(step)
321 
322  return dynamic
323 
324 
325  def __calculate_states(self):
326  """!
327  @brief Calculates new state of each neuron.
328  @detail There is no any assignment.
329 
330  @return (list) Returns new states (output).
331 
332  """
333 
334  output = [ 0.0 for _ in range(self.__num_osc) ]
335 
336  for i in range(self.__num_osc):
337  output[i] = self.__neuron_evolution(i)
338 
339  return output
340 
341 
342  def __neuron_evolution(self, index):
343  """!
344  @brief Calculates state of the neuron with specified index.
345 
346  @param[in] index (uint): Index of neuron in the network.
347 
348  @return (double) New output of the specified neuron.
349 
350  """
351  value = 0.0
352 
353  for index_neighbor in range(self.__num_osc):
354  value += self.__weights[index][index_neighbor] * (1.0 - 2.0 * (self.__output[index_neighbor] ** 2))
355 
356  return value / self.__weights_summary[index]
357 
358 
359  def __create_weights(self, stimulus):
360  """!
361  @brief Create weights between neurons in line with stimulus.
362 
363  @param[in] stimulus (list): External stimulus for the chaotic neural network.
364 
365  """
366 
367  self.__average_distance = average_neighbor_distance(stimulus, self.__amount_neighbors)
368 
369  self.__weights = [ [ 0.0 for _ in range(len(stimulus)) ] for _ in range(len(stimulus)) ]
370  self.__weights_summary = [ 0.0 for _ in range(self.__num_osc) ]
371 
372  if self.__conn_type == type_conn.ALL_TO_ALL:
373  self.__create_weights_all_to_all(stimulus)
374 
375  elif self.__conn_type == type_conn.TRIANGULATION_DELAUNAY:
377 
378 
379  def __create_weights_all_to_all(self, stimulus):
380  """!
381  @brief Create weight all-to-all structure between neurons in line with stimulus.
382 
383  @param[in] stimulus (list): External stimulus for the chaotic neural network.
384 
385  """
386 
387  for i in range(len(stimulus)):
388  for j in range(i + 1, len(stimulus)):
389  weight = self.__calculate_weight(stimulus[i], stimulus[j])
390 
391  self.__weights[i][j] = weight
392  self.__weights[j][i] = weight
393 
394  self.__weights_summary[i] += weight
395  self.__weights_summary[j] += weight
396 
397 
398  def __create_weights_delaunay_triangulation(self, stimulus):
399  """!
400  @brief Create weight Denlauny triangulation structure between neurons in line with stimulus.
401 
402  @param[in] stimulus (list): External stimulus for the chaotic neural network.
403 
404  """
405 
406  points = numpy.array(stimulus)
407  triangulation = Delaunay(points)
408 
409  for triangle in triangulation.simplices:
410  for index_tri_point1 in range(len(triangle)):
411  for index_tri_point2 in range(index_tri_point1 + 1, len(triangle)):
412  index_point1 = triangle[index_tri_point1]
413  index_point2 = triangle[index_tri_point2]
414 
415  weight = self.__calculate_weight(stimulus[index_point1], stimulus[index_point2])
416 
417  self.__weights[index_point1][index_point2] = weight
418  self.__weights[index_point2][index_point1] = weight
419 
420  self.__weights_summary[index_point1] += weight
421  self.__weights_summary[index_point2] += weight
422 
423 
424  def __calculate_weight(self, stimulus1, stimulus2):
425  """!
426  @brief Calculate weight between neurons that have external stimulus1 and stimulus2.
427 
428  @param[in] stimulus1 (list): External stimulus of the first neuron.
429  @param[in] stimulus2 (list): External stimulus of the second neuron.
430 
431  @return (double) Weight between neurons that are under specified stimulus.
432 
433  """
434 
435  distance = euclidean_distance_square(stimulus1, stimulus2)
436  return math.exp(-distance / (2.0 * self.__average_distance))
437 
438 
439  def show_network(self):
440  """!
441  @brief Shows structure of the network: neurons and connections between them.
442 
443  """
444 
445  dimension = len(self.__location[0])
446  if (dimension != 3) and (dimension != 2):
447  raise NameError('Network that is located in different from 2-d and 3-d dimensions can not be represented')
448 
449  (fig, axes) = self.__create_surface(dimension)
450 
451  for i in range(0, self.__num_osc, 1):
452  if dimension == 2:
453  axes.plot(self.__location[i][0], self.__location[i][1], 'bo')
454  for j in range(i, self.__num_osc, 1): # draw connection between two points only one time
455  if self.__weights[i][j] > 0.0:
456  axes.plot([self.__location[i][0], self.__location[j][0]], [self.__location[i][1], self.__location[j][1]], 'b-', linewidth = 0.5)
457 
458  elif dimension == 3:
459  axes.scatter(self.__location[i][0], self.__location[i][1], self.__location[i][2], c = 'b', marker = 'o')
460 
461  for j in range(i, self.__num_osc, 1): # draw connection between two points only one time
462  if self.__weights[i][j] > 0.0:
463  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)
464 
465  plt.grid()
466  plt.show()
467 
468 
469  def __create_surface(self, dimension):
470  """!
471  @brief Prepares surface for showing network structure in line with specified dimension.
472 
473  @param[in] dimension (uint): Dimension of processed data (external stimulus).
474 
475  @return (tuple) Description of surface for drawing network structure.
476 
477  """
478 
479  rcParams['font.sans-serif'] = ['Arial']
480  rcParams['font.size'] = 12
481 
482  fig = plt.figure()
483  axes = None
484  if dimension == 2:
485  axes = fig.add_subplot(111)
486  elif dimension == 3:
487  axes = fig.gca(projection='3d')
488 
489  surface_font = FontProperties()
490  surface_font.set_name('Arial')
491  surface_font.set_size('12')
492 
493  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:398
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:359
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:424
def __calculate_states(self)
Calculates new state of each neuron.
Definition: cnn.py:325
def __len__(self)
Returns size of the chaotic neural network that is defined by amount of neurons.
Definition: cnn.py:288
def show_network(self)
Shows structure of the network: neurons and connections between them.
Definition: cnn.py:439
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:379
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:469
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:342
def simulate(self, steps, stimulus)
Simulates chaotic neural network with extrnal stimulus during specified steps.
Definition: cnn.py:296
def __init__(self, num_osc, conn_type=type_conn.ALL_TO_ALL, amount_neighbors=3)
Constructor of chaotic neural network.
Definition: cnn.py:264
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