__init__.py
1 """!
2 
3 @brief Neural and oscillatory network module. Consists of models of bio-inspired networks.
4 
5 @authors Andrei Novikov (pyclustering@yandex.ru)
6 @date 2014-2020
7 @copyright GNU Public License
8 
9 @cond GNU_PUBLIC_LICENSE
10  PyClustering is free software: you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation, either version 3 of the License, or
13  (at your option) any later version.
14 
15  PyClustering is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with this program. If not, see <http://www.gnu.org/licenses/>.
22 @endcond
23 
24 """
25 
26 import math;
27 
28 from enum import IntEnum;
29 
30 class initial_type(IntEnum):
31  """!
32  @brief Enumerator of types of oscillator output initialization.
33 
34  """
35 
36 
37  RANDOM_GAUSSIAN = 0;
38 
39 
40  EQUIPARTITION = 1;
41 
42 
43 class solve_type(IntEnum):
44  """!
45  @brief Enumerator of solver types that are used for network simulation.
46 
47  """
48 
49 
50  FAST = 0; # Usual calculation: x(k + 1) = x(k) + f(x(k)).
51 
52 
53  RK4 = 1;
54 
55 
56  RKF45 = 2;
57 
58 
59 class conn_type(IntEnum):
60  """!
61  @brief Enumerator of connection types between oscillators.
62 
63  """
64 
65 
66  NONE = 0;
67 
68 
69  ALL_TO_ALL = 1;
70 
71 
72  GRID_FOUR = 2;
73 
74 
75  GRID_EIGHT = 3;
76 
77 
78  LIST_BIDIR = 4;
79 
80 
81  DYNAMIC = 5;
82 
83 
84 class conn_represent(IntEnum):
85  """!
86  @brief Enumerator of internal network connection representation between oscillators.
87 
88  """
89 
90 
91  LIST = 0;
92 
93 
94  MATRIX = 1;
95 
96 
97 class network:
98  """!
99  @brief Common network description that consists of information about oscillators and connection between them.
100 
101  """
102 
103  _num_osc = 0;
104 
105  _osc_conn = None;
106  _conn_represent = None;
107  __conn_type = None;
108 
109  __height = 0;
110  __width = 0;
111 
112 
113  @property
114  def height(self):
115  """!
116  @brief Height of the network grid (that is defined by amout of oscillators in each column), this value is zero in case of non-grid structure.
117 
118  @note This property returns valid value only for network with grid structure.
119 
120  """
121  return self.__height;
122 
123 
124  @property
125  def width(self):
126  """!
127  @brief Width of the network grid, this value is zero in case of non-grid structure.
128 
129  @note This property returns valid value only for network with grid structure.
130 
131  """
132  return self.__width;
133 
134 
135  @property
136  def structure(self):
137  """!
138  @brief Type of network structure that is used for connecting oscillators.
139 
140  """
141  return self.__conn_type;
142 
143 
144  def __init__(self, num_osc, type_conn = conn_type.ALL_TO_ALL, conn_repr = conn_represent.MATRIX, height = None, width = None):
145  """!
146  @brief Constructor of the network.
147 
148  @param[in] num_osc (uint): Number of oscillators in the network that defines size of the network.
149  @param[in] type_conn (conn_type): Type of connections that are used in the network between oscillators.
150  @param[in] conn_repr (conn_represent): Type of representation of connections.
151  @param[in] height (uint): Number of oscillators in column of the network, this argument is used
152  only for network with grid structure (GRID_FOUR, GRID_EIGHT), for other types this argument is ignored.
153  @param[in] width (uint): Number of oscillotors in row of the network, this argument is used only
154  for network with grid structure (GRID_FOUR, GRID_EIGHT), for other types this argument is ignored.
155 
156  """
157 
158  self._num_osc = num_osc;
159  self._conn_represent = conn_repr;
160  self.__conn_type = type_conn;
161 
162  if (conn_repr is None):
163  self._conn_represent = conn_represent.MATRIX;
164 
165  if ( (type_conn == conn_type.GRID_EIGHT) or (type_conn == conn_type.GRID_FOUR) ):
166  if ( (height is not None) and (width is not None) ):
167  self.__height = height;
168  self.__width = width;
169  else:
170  side_size = self._num_osc ** (0.5);
171  if (side_size - math.floor(side_size) > 0):
172  raise NameError("Invalid number of oscillators '" + str(num_osc) + "' in the network in case of grid structure (root square should be extractable for the number of oscillators).");
173 
174  self.__height = int(side_size);
175  self.__width = self.__height;
176 
177  if (self.__height * self.__width != self._num_osc):
178  raise NameError('Width (' + str(self.__width) + ') x Height (' + str(self.__height) + ') must be equal to Size (' + str(self._num_osc) + ') in case of grid structure');
179 
180  self._create_structure(type_conn);
181 
182 
183  def __len__(self):
184  """!
185  @brief Returns size of the network that is defined by amount of oscillators.
186 
187  """
188  return self._num_osc;
189 
190 
191  def __create_connection(self, index1, index2):
192  if (self._conn_represent == conn_represent.MATRIX):
193  self._osc_conn[index1][index2] = True;
194  else:
195  self._osc_conn[index1].append(index2);
196 
197 
198  def __create_all_to_all_connections(self):
199  """!
200  @brief Creates connections between all oscillators.
201 
202  """
203 
204  if (self._conn_represent == conn_represent.MATRIX):
205  for index in range(0, self._num_osc, 1):
206  self._osc_conn.append([True] * self._num_osc);
207  self._osc_conn[index][index] = False;
208 
209  elif (self._conn_represent == conn_represent.LIST):
210  for index in range(0, self._num_osc, 1):
211  self._osc_conn.append([neigh for neigh in range(0, self._num_osc, 1) if index != neigh]);
212 
213 
214  def __create_grid_four_connections(self):
215  """!
216  @brief Creates network with connections that make up four grid structure.
217  @details Each oscillator may be connected with four neighbors in line with 'grid' structure: right, upper, left, lower.
218 
219  """
220 
221  side_size = self.__width;
222  if (self._conn_represent == conn_represent.MATRIX):
223  self._osc_conn = [[0] * self._num_osc for index in range(0, self._num_osc, 1)];
224  elif (self._conn_represent == conn_represent.LIST):
225  self._osc_conn = [[] for index in range(0, self._num_osc, 1)];
226  else:
227  raise NameError("Unknown type of representation of connections");
228 
229  for index in range(0, self._num_osc, 1):
230  upper_index = index - side_size;
231  lower_index = index + side_size;
232  left_index = index - 1;
233  right_index = index + 1;
234 
235  node_row_index = math.ceil(index / side_size);
236  if (upper_index >= 0):
237  self.__create_connection(index, upper_index);
238 
239  if (lower_index < self._num_osc):
240  self.__create_connection(index, lower_index);
241 
242  if ( (left_index >= 0) and (math.ceil(left_index / side_size) == node_row_index) ):
243  self.__create_connection(index, left_index);
244 
245  if ( (right_index < self._num_osc) and (math.ceil(right_index / side_size) == node_row_index) ):
246  self.__create_connection(index, right_index);
247 
248 
249  def __create_grid_eight_connections(self):
250  """!
251  @brief Creates network with connections that make up eight grid structure.
252  @details Each oscillator may be connected with eight neighbors in line with grid structure: right, right-upper, upper, upper-left, left, left-lower, lower, lower-right.
253 
254  """
255 
256  self.__create_grid_four_connections(); # create connection with right, upper, left, lower.
257  side_size = self.__width;
258 
259  for index in range(0, self._num_osc, 1):
260  upper_left_index = index - side_size - 1;
261  upper_right_index = index - side_size + 1;
262 
263  lower_left_index = index + side_size - 1;
264  lower_right_index = index + side_size + 1;
265 
266  node_row_index = math.floor(index / side_size);
267  upper_row_index = node_row_index - 1;
268  lower_row_index = node_row_index + 1;
269 
270  if ( (upper_left_index >= 0) and (math.floor(upper_left_index / side_size) == upper_row_index) ):
271  self.__create_connection(index, upper_left_index);
272 
273  if ( (upper_right_index >= 0) and (math.floor(upper_right_index / side_size) == upper_row_index) ):
274  self.__create_connection(index, upper_right_index);
275 
276  if ( (lower_left_index < self._num_osc) and (math.floor(lower_left_index / side_size) == lower_row_index) ):
277  self.__create_connection(index, lower_left_index);
278 
279  if ( (lower_right_index < self._num_osc) and (math.floor(lower_right_index / side_size) == lower_row_index) ):
280  self.__create_connection(index, lower_right_index);
281 
282 
283  def __create_list_bidir_connections(self):
284  """!
285  @brief Creates network as bidirectional list.
286  @details Each oscillator may be conneted with two neighbors in line with classical list structure: right, left.
287 
288  """
289 
290  if (self._conn_represent == conn_represent.MATRIX):
291  for index in range(0, self._num_osc, 1):
292  self._osc_conn.append([0] * self._num_osc);
293  self._osc_conn[index][index] = False;
294  if (index > 0):
295  self._osc_conn[index][index - 1] = True;
296 
297  if (index < (self._num_osc - 1)):
298  self._osc_conn[index][index + 1] = True;
299 
300  elif (self._conn_represent == conn_represent.LIST):
301  for index in range(self._num_osc):
302  self._osc_conn.append([]);
303  if (index > 0):
304  self._osc_conn[index].append(index - 1);
305 
306  if (index < (self._num_osc - 1)):
307  self._osc_conn[index].append(index + 1);
308 
309 
310  def __create_none_connections(self):
311  """!
312  @brief Creates network without connections.
313 
314  """
315  if (self._conn_represent == conn_represent.MATRIX):
316  for _ in range(0, self._num_osc, 1):
317  self._osc_conn.append([False] * self._num_osc);
318  elif (self._conn_represent == conn_represent.LIST):
319  self._osc_conn = [[] for _ in range(0, self._num_osc, 1)];
320 
321 
322  def __create_dynamic_connection(self):
323  """!
324  @brief Prepare storage for dynamic connections.
325 
326  """
327  if (self._conn_represent == conn_represent.MATRIX):
328  for _ in range(0, self._num_osc, 1):
329  self._osc_conn.append([False] * self._num_osc);
330  elif (self._conn_represent == conn_represent.LIST):
331  self._osc_conn = [[] for _ in range(0, self._num_osc, 1)];
332 
333 
334  def _create_structure(self, type_conn = conn_type.ALL_TO_ALL):
335  """!
336  @brief Creates connection in line with representation of matrix connections [NunOsc x NumOsc].
337 
338  @param[in] type_conn (conn_type): Connection type (all-to-all, bidirectional list, grid structure, etc.) that is used by the network.
339 
340  """
341 
342  self._osc_conn = list();
343 
344  if (type_conn == conn_type.NONE):
346 
347  elif (type_conn == conn_type.ALL_TO_ALL):
349 
350  elif (type_conn == conn_type.GRID_FOUR):
352 
353  elif (type_conn == conn_type.GRID_EIGHT):
355 
356  elif (type_conn == conn_type.LIST_BIDIR):
358 
359  elif (type_conn == conn_type.DYNAMIC):
361 
362  else:
363  raise NameError('The unknown type of connections');
364 
365 
366  def has_connection(self, i, j):
367  """!
368  @brief Returns True if there is connection between i and j oscillators and False - if connection doesn't exist.
369 
370  @param[in] i (uint): index of an oscillator in the network.
371  @param[in] j (uint): index of an oscillator in the network.
372 
373  """
374  if (self._conn_represent == conn_represent.MATRIX):
375  return (self._osc_conn[i][j]);
376 
377  elif (self._conn_represent == conn_represent.LIST):
378  for neigh_index in range(0, len(self._osc_conn[i]), 1):
379  if (self._osc_conn[i][neigh_index] == j):
380  return True;
381  return False;
382 
383  else:
384  raise NameError("Unknown type of representation of coupling");
385 
386 
387  def set_connection(self, i, j):
388  """!
389  @brief Couples two specified oscillators in the network with dynamic connections.
390 
391  @param[in] i (uint): index of an oscillator that should be coupled with oscillator 'j' in the network.
392  @param[in] j (uint): index of an oscillator that should be coupled with oscillator 'i' in the network.
393 
394  @note This method can be used only in case of DYNAMIC connections, otherwise it throws expection.
395 
396  """
397 
398  if (self.structure != conn_type.DYNAMIC):
399  raise NameError("Connection between oscillators can be changed only in case of dynamic type.");
400 
401  if (self._conn_represent == conn_represent.MATRIX):
402  self._osc_conn[i][j] = True;
403  self._osc_conn[j][i] = True;
404  else:
405  self._osc_conn[i].append(j);
406  self._osc_conn[j].append(i);
407 
408 
409  def get_neighbors(self, index):
410  """!
411  @brief Finds neighbors of the oscillator with specified index.
412 
413  @param[in] index (uint): index of oscillator for which neighbors should be found in the network.
414 
415  @return (list) Indexes of neighbors of the specified oscillator.
416 
417  """
418 
419  if (self._conn_represent == conn_represent.LIST):
420  return self._osc_conn[index]; # connections are represented by list.
421  elif (self._conn_represent == conn_represent.MATRIX):
422  return [neigh_index for neigh_index in range(self._num_osc) if self._osc_conn[index][neigh_index] == True];
423  else:
424  raise NameError("Unknown type of representation of connections");
def __create_list_bidir_connections(self)
Creates network as bidirectional list.
Definition: __init__.py:283
def __create_all_to_all_connections(self)
Creates connections between all oscillators.
Definition: __init__.py:198
Enumerator of internal network connection representation between oscillators.
Definition: __init__.py:84
def __len__(self)
Returns size of the network that is defined by amount of oscillators.
Definition: __init__.py:183
def __create_none_connections(self)
Creates network without connections.
Definition: __init__.py:310
def __init__(self, num_osc, type_conn=conn_type.ALL_TO_ALL, conn_repr=conn_represent.MATRIX, height=None, width=None)
Constructor of the network.
Definition: __init__.py:144
Enumerator of solver types that are used for network simulation.
Definition: __init__.py:43
def set_connection(self, i, j)
Couples two specified oscillators in the network with dynamic connections.
Definition: __init__.py:387
def width(self)
Width of the network grid, this value is zero in case of non-grid structure.
Definition: __init__.py:125
Enumerator of connection types between oscillators.
Definition: __init__.py:59
def __create_grid_eight_connections(self)
Creates network with connections that make up eight grid structure.
Definition: __init__.py:249
def has_connection(self, i, j)
Returns True if there is connection between i and j oscillators and False - if connection doesn&#39;t exi...
Definition: __init__.py:366
def get_neighbors(self, index)
Finds neighbors of the oscillator with specified index.
Definition: __init__.py:409
Enumerator of types of oscillator output initialization.
Definition: __init__.py:30
def _create_structure(self, type_conn=conn_type.ALL_TO_ALL)
Creates connection in line with representation of matrix connections [NunOsc x NumOsc].
Definition: __init__.py:334
def structure(self)
Type of network structure that is used for connecting oscillators.
Definition: __init__.py:136
Common network description that consists of information about oscillators and connection between them...
Definition: __init__.py:97
def height(self)
Height of the network grid (that is defined by amout of oscillators in each column), this value is zero in case of non-grid structure.
Definition: __init__.py:114
def __create_grid_four_connections(self)
Creates network with connections that make up four grid structure.
Definition: __init__.py:214
def __create_dynamic_connection(self)
Prepare storage for dynamic connections.
Definition: __init__.py:322
def __create_connection(self, index1, index2)
Definition: __init__.py:191