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