pyclustering  0.10.1
pyclustring is a Python, C++ data mining library.
hysteresis.py
1 """!
2 
3 @brief Neural Network: Hysteresis Oscillatory Network
4 @details Implementation based on paper @cite article::nnet::hysteresis::1.
5 
6 @authors Andrei Novikov (pyclustering@yandex.ru)
7 @date 2014-2020
8 @copyright BSD-3-Clause
9 
10 """
11 
12 import numpy
13 
14 from scipy.integrate import odeint
15 
16 from pyclustering.nnet import *
17 
18 from pyclustering.utils import draw_dynamics
19 
20 
22  """!
23  @brief Represents output dynamic of hysteresis oscillatory network.
24 
25  """
26 
27  @property
28  def output(self):
29  """!
30  @brief (list) Returns outputs of oscillator during simulation.
31 
32  """
33  return self._dynamic;
34 
35 
36  @property
37  def time(self):
38  """!
39  @brief (list) Returns sampling times when dynamic is measured during simulation.
40 
41  """
42 
43  return self._time;
44 
45 
46  def __init__(self, amplitudes, time):
47  """!
48  @brief Constructor of hysteresis neural network dynamic.
49 
50  @param[in] amplitudes (list): Dynamic (amplitudes) of oscillators on each step of simulation.
51  @param[in] time (list): Simulation time (timestamps of simulation steps) when amplitudes are stored.
52 
53  """
54 
55  if (len(amplitudes) != len(time)):
56  raise NameError("Length of list of dynamics of oscillators should be equal to length of simulation timestamps of steps.");
57 
58  self._dynamic = amplitudes;
59 
60  self._time = time;
61 
62 
63  def __len__(self):
64  """!
65  @brief (uint) Returns number of simulation steps that are stored in dynamic.
66 
67  """
68 
69  return len(self._dynamic);
70 
71 
72  def allocate_sync_ensembles(self, tolerance = 0.1, threshold_steps = 1):
73  """!
74  @brief Allocate clusters in line with ensembles of synchronous oscillators where each
75  synchronous ensemble corresponds to only one cluster.
76 
77  @param[in] tolerance (double): Maximum error for allocation of synchronous ensemble oscillators.
78  @param[in] threshold_steps (uint): Number of steps from the end of simulation that should be analysed for ensemble allocation.
79  If amout of simulation steps has been less than threshold steps than amount of steps will be reduced to amout
80  of simulation steps.
81 
82  @return (list) Grours of indexes of synchronous oscillators, for example, [ [index_osc1, index_osc3], [index_osc2], [index_osc4, index_osc5] ]."
83 
84  """
85 
86  clusters = [ [0] ];
87 
88  number_oscillators = len(self._dynamic[0]);
89 
90  for i in range(1, number_oscillators, 1):
91  captured_neuron = True;
92  for cluster in clusters:
93  neuron_index = cluster[0];
94 
95  analysis_steps = threshold_steps;
96  if (len(self._dynamic) < analysis_steps):
97  analysis_steps = len(self._dynamic);
98 
99  analysis_start_step_index = len(self._dynamic) - 1;
100 
101  for step in range(analysis_start_step_index, analysis_start_step_index - analysis_steps, -1):
102  neuron_amplitude = self._dynamic[step][neuron_index];
103  candidate_amplitude = self._dynamic[step][i];
104 
105  if ( not (candidate_amplitude < (neuron_amplitude + tolerance)) or not (candidate_amplitude > (neuron_amplitude - tolerance)) ):
106  captured_neuron = False;
107  break;
108 
109  if ( captured_neuron is True ):
110  cluster.append(i);
111  break;
112 
113  if (captured_neuron is False):
114  clusters.append([i]);
115 
116  return clusters;
117 
118 
120  """!
121  @brief Visualizer of output dynamic of hysteresis oscillatory network.
122 
123  """
124 
125  @staticmethod
126  def show_output_dynamic(hysteresis_output_dynamic):
127  """!
128  @brief Shows output dynamic (output of each oscillator) during simulation.
129 
130  @param[in] hysteresis_output_dynamic (hysteresis_dynamic): Output dynamic of the hysteresis oscillatory network.
131 
132  """
133 
134  draw_dynamics(hysteresis_output_dynamic.time, hysteresis_output_dynamic.output, x_title = "Time", y_title = "x(t)");
135 
136 
138  """!
139  @brief Hysteresis oscillatory network that uses relaxation oscillators that are represented by objective hysteresis neurons whose output in range [-1, +1].
140 
141  Examples:
142  @code
143  # create hysteresis oscillatory network with 5 oscillators.
144  network = hysteresis_network(5);
145 
146  # set initial states (from range [-1, +1]).
147  network.states = [1 0 1 0 1];
148 
149  # set initial outputs.
150  network.outputs = [1 1 1 1 1];
151 
152  # perform simulation of the network during 1000 steps in 10 time units.
153  output_dynamic = network.simulate(1000, 10);
154 
155  # show output dynamic of the network.
156  hysteresis_visualizer.show_output_dynamic(output_dynamic);
157 
158  # obtain synchronous ensembles.
159  ensembles = output_dynamic.allocate_sync_ensembles(tolerance = 0.5, threshold_steps = 5);
160  print(ensembles);
161  @endcode
162 
163  """
164 
165  @property
166  def outputs(self):
167  """!
168  @brief Returns current outputs of neurons.
169 
170  @return (list) Current outputs of neurons.
171 
172  """
173 
174  return self._outputs;
175 
176  @outputs.setter
177  def outputs(self, values):
178  """!
179  @brief Sets outputs of neurons.
180 
181  """
182 
183  self._outputs = [val for val in values];
184  self._outputs_buffer = [val for val in values];
185 
186  @property
187  def states(self):
188  """!
189  @brief Return current states of neurons.
190 
191  @return (list) States of neurons.
192 
193  """
194 
195  return self._states;
196 
197  @states.setter
198  def states(self, values):
199  """!
200  @brief Set current states of neurons.
201 
202  """
203 
204  self._states = [val for val in values];
205 
206 
207  def __init__(self, num_osc, own_weight = -4, neigh_weight = -1, type_conn = conn_type.ALL_TO_ALL, type_conn_represent = conn_represent.MATRIX):
208  """!
209  @brief Constructor of hysteresis oscillatory network.
210 
211  @param[in] num_osc (uint): Number of oscillators in the network.
212  @param[in] own_weight (double): Weight of connection from oscillator to itself - own weight.
213  @param[in] neigh_weight (double): Weight of connection between oscillators.
214  @param[in] type_conn (conn_type): Type of connection between oscillators in the network.
215  @param[in] type_conn_represent (conn_represent): Internal representation of connection in the network: matrix or list.
216 
217  """
218 
219  super().__init__(num_osc, type_conn, type_conn_represent);
220 
221  # list of states of neurons.
222  self._states = [0] * self._num_osc;
223 
224  # list of current outputs of neurons.
225  self._outputs = [-1] * self._num_osc;
226 
227  # list of previous outputs of neurons
228  self._outputs_buffer = [-1] * self._num_osc;
229 
230  # matrix of connection weights between neurons.
231  self._weight = list();
232  for index in range(0, self._num_osc, 1):
233  self._weight.append( [neigh_weight] * self._num_osc);
234  self._weight[index][index] = own_weight;
235 
236 
237  def _neuron_states(self, inputs, t, argv):
238  """!
239  @brief Returns new value of the neuron (oscillator).
240 
241  @param[in] inputs (list): Initial values (current) of the neuron - excitatory.
242  @param[in] t (double): Current time of simulation.
243  @param[in] argv (tuple): Extra arguments that are not used for integration - index of the neuron.
244 
245  @return (double) New value of the neuron.
246 
247  """
248 
249  xi = inputs[0];
250  index = argv;
251 
252  # own impact
253  impact = self._weight[index][index] * self._outputs[index];
254 
255  for i in range(0, self._num_osc, 1):
256  if (self.has_connection(i, index)):
257  impact += self._weight[index][i] * self._outputs[i];
258 
259  x = -xi + impact;
260 
261  if (xi > 1): self._outputs_buffer[index] = 1;
262  if (xi < -1): self._outputs_buffer[index] = -1;
263 
264  return x;
265 
266 
267  def simulate(self, steps, time, solution = solve_type.RK4, collect_dynamic = True):
268  """!
269  @brief Performs static simulation of hysteresis oscillatory network.
270 
271  @param[in] steps (uint): Number steps of simulations during simulation.
272  @param[in] time (double): Time of simulation.
273  @param[in] solution (solve_type): Type of solution (solving).
274  @param[in] collect_dynamic (bool): If True - returns whole dynamic of oscillatory network, otherwise returns only last values of dynamics.
275 
276  @return (hysteresis_dynamic) Dynamic of oscillatory network. If argument 'collect_dynamic' = True, than return dynamic for the whole simulation time,
277  otherwise returns only last values (last step of simulation) of dynamic.
278  """
279 
280  return self.simulate_static(steps, time, solution, collect_dynamic);
281 
282 
283  def simulate_static(self, steps, time, solution = solve_type.RK4, collect_dynamic = False):
284  """!
285  @brief Performs static simulation of hysteresis oscillatory network.
286 
287  @param[in] steps (uint): Number steps of simulations during simulation.
288  @param[in] time (double): Time of simulation.
289  @param[in] solution (solve_type): Type of solution (solving).
290  @param[in] collect_dynamic (bool): If True - returns whole dynamic of oscillatory network, otherwise returns only last values of dynamics.
291 
292  @return (hysteresis_dynamic) Dynamic of oscillatory network. If argument 'collect_dynamic' = True, than return dynamic for the whole simulation time,
293  otherwise returns only last values (last step of simulation) of dynamic.
294 
295  """
296 
297  # Check solver before simulation
298  if (solution == solve_type.FAST):
299  raise NameError("Solver FAST is not support due to low accuracy that leads to huge error.");
300  elif (solution == solve_type.RKF45):
301  raise NameError("Solver RKF45 is not support in python version.");
302 
303  dyn_state = None;
304  dyn_time = None;
305 
306  if (collect_dynamic == True):
307  dyn_state = [];
308  dyn_time = [];
309 
310  dyn_state.append(self._states);
311  dyn_time.append(0);
312 
313  step = time / steps;
314  int_step = step / 10.0;
315 
316  for t in numpy.arange(step, time + step, step):
317  # update states of oscillators
318  self._states = self._calculate_states(solution, t, step, int_step);
319 
320  # update states of oscillators
321  if (collect_dynamic is True):
322  dyn_state.append(self._states);
323  dyn_time.append(t);
324 
325  if (collect_dynamic is False):
326  dyn_state.append(self._states);
327  dyn_time.append(time);
328 
329  return hysteresis_dynamic(dyn_state, dyn_time);
330 
331 
332  def _calculate_states(self, solution, t, step, int_step):
333  """!
334  @brief Calculates new states for neurons using differential calculus. Returns new states for neurons.
335 
336  @param[in] solution (solve_type): Type solver of the differential equation.
337  @param[in] t (double): Current time of simulation.
338  @param[in] step (double): Step of solution at the end of which states of oscillators should be calculated.
339  @param[in] int_step (double): Step differentiation that is used for solving differential equation.
340 
341  @return (list) New states for neurons.
342 
343  """
344 
345  next_states = [0] * self._num_osc;
346 
347  for index in range (0, self._num_osc, 1):
348  result = odeint(self._neuron_states, self._states[index], numpy.arange(t - step, t, int_step), (index , ));
349  next_states[index] = result[len(result) - 1][0];
350 
351  self._outputs = [val for val in self._outputs_buffer];
352  return next_states;
pyclustering.nnet.hysteresis.hysteresis_network.__init__
def __init__(self, num_osc, own_weight=-4, neigh_weight=-1, type_conn=conn_type.ALL_TO_ALL, type_conn_represent=conn_represent.MATRIX)
Constructor of hysteresis oscillatory network.
Definition: hysteresis.py:207
pyclustering.nnet.hysteresis.hysteresis_dynamic.__len__
def __len__(self)
(uint) Returns number of simulation steps that are stored in dynamic.
Definition: hysteresis.py:63
pyclustering.nnet.hysteresis.hysteresis_network.outputs
def outputs(self)
Returns current outputs of neurons.
Definition: hysteresis.py:166
pyclustering.nnet.hysteresis.hysteresis_network._outputs
_outputs
Definition: hysteresis.py:183
pyclustering.nnet.hysteresis.hysteresis_dynamic
Represents output dynamic of hysteresis oscillatory network.
Definition: hysteresis.py:21
pyclustering.nnet.hysteresis.hysteresis_network._weight
_weight
Definition: hysteresis.py:231
pyclustering.nnet.hysteresis.hysteresis_network._outputs_buffer
_outputs_buffer
Definition: hysteresis.py:184
pyclustering.nnet.network._num_osc
int _num_osc
Definition: __init__.py:88
pyclustering.nnet.hysteresis.hysteresis_network._neuron_states
def _neuron_states(self, inputs, t, argv)
Returns new value of the neuron (oscillator).
Definition: hysteresis.py:237
pyclustering.nnet.hysteresis.hysteresis_dynamic.output
def output(self)
(list) Returns outputs of oscillator during simulation.
Definition: hysteresis.py:28
pyclustering.nnet.hysteresis.hysteresis_network.simulate
def simulate(self, steps, time, solution=solve_type.RK4, collect_dynamic=True)
Performs static simulation of hysteresis oscillatory network.
Definition: hysteresis.py:267
pyclustering.nnet.hysteresis.hysteresis_network
Hysteresis oscillatory network that uses relaxation oscillators that are represented by objective hys...
Definition: hysteresis.py:137
pyclustering.nnet.network
Common network description that consists of information about oscillators and connection between them...
Definition: __init__.py:82
pyclustering.nnet.network.has_connection
def has_connection(self, i, j)
Returns True if there is connection between i and j oscillators and False - if connection doesn't exi...
Definition: __init__.py:351
pyclustering.nnet.hysteresis.hysteresis_network._calculate_states
def _calculate_states(self, solution, t, step, int_step)
Calculates new states for neurons using differential calculus.
Definition: hysteresis.py:332
pyclustering.nnet.hysteresis.hysteresis_network.states
def states(self)
Return current states of neurons.
Definition: hysteresis.py:187
pyclustering.nnet.hysteresis.hysteresis_dynamic._time
_time
Definition: hysteresis.py:60
pyclustering.nnet.hysteresis.hysteresis_dynamic._dynamic
_dynamic
Definition: hysteresis.py:58
pyclustering.nnet.hysteresis.hysteresis_dynamic.time
def time(self)
(list) Returns sampling times when dynamic is measured during simulation.
Definition: hysteresis.py:37
pyclustering.nnet.hysteresis.hysteresis_visualizer.show_output_dynamic
def show_output_dynamic(hysteresis_output_dynamic)
Shows output dynamic (output of each oscillator) during simulation.
Definition: hysteresis.py:126
pyclustering.nnet
Neural and oscillatory network module. Consists of models of bio-inspired networks.
Definition: __init__.py:1
pyclustering.nnet.hysteresis.hysteresis_network.simulate_static
def simulate_static(self, steps, time, solution=solve_type.RK4, collect_dynamic=False)
Performs static simulation of hysteresis oscillatory network.
Definition: hysteresis.py:283
pyclustering.nnet.hysteresis.hysteresis_visualizer
Visualizer of output dynamic of hysteresis oscillatory network.
Definition: hysteresis.py:119
pyclustering.nnet.hysteresis.hysteresis_network._states
_states
Definition: hysteresis.py:204
pyclustering.utils
Utils that are used by modules of pyclustering.
Definition: __init__.py:1
pyclustering.nnet.hysteresis.hysteresis_dynamic.allocate_sync_ensembles
def allocate_sync_ensembles(self, tolerance=0.1, threshold_steps=1)
Allocate clusters in line with ensembles of synchronous oscillators where each synchronous ensemble c...
Definition: hysteresis.py:72
pyclustering.nnet.hysteresis.hysteresis_dynamic.__init__
def __init__(self, amplitudes, time)
Constructor of hysteresis neural network dynamic.
Definition: hysteresis.py:46