Completed
Push — master ( 8edca8...4108fb )
by Andrei
01:34
created

hhn_network.__update_peripheral_neurons()   F

Complexity

Conditions 11

Size

Total Lines 39

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 11
dl 0
loc 39
rs 3.1764

How to fix   Complexity   

Complexity

Complex classes like hhn_network.__update_peripheral_neurons() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
"""!
2
3
@brief Oscillatory Neural Network based on Hodgkin-Huxley Neuron Model
4
@details Based on article description:
5
         - D.Chik, R.Borisyuk, Y.Kazanovich. Selective attention model with spiking elements. 2009.
6
7
@authors Andrei Novikov ([email protected])
8
@date 2014-2016
9
@copyright GNU Public License
10
11
@cond GNU_PUBLIC_LICENSE
12
    PyClustering is free software: you can redistribute it and/or modify
13
    it under the terms of the GNU General Public License as published by
14
    the Free Software Foundation, either version 3 of the License, or
15
    (at your option) any later version.
16
    
17
    PyClustering is distributed in the hope that it will be useful,
18
    but WITHOUT ANY WARRANTY; without even the implied warranty of
19
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
    GNU General Public License for more details.
21
    
22
    You should have received a copy of the GNU General Public License
23
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24
@endcond
25
26
"""
27
28
from pyclustering.nnet import *;
0 ignored issues
show
Unused Code introduced by
IntEnum was imported with wildcard, but is not used.
Loading history...
Unused Code introduced by
initial_type was imported with wildcard, but is not used.
Loading history...
29
30
from scipy.integrate import odeint;
0 ignored issues
show
Configuration introduced by
The import scipy.integrate could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
31
32
from pyclustering.utils import allocate_sync_ensembles;
33
34
import numpy;
0 ignored issues
show
Configuration introduced by
The import numpy could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
35
import random;
36
37
class hhn_parameters:
38
    """!
39
    @brief Describes parameters of Hodgkin-Huxley Oscillatory Network.
40
    
41
    @see hhn_network
42
    
43
    """  
44
    
45
    ## Intrinsic noise.
46
    nu      = random.random() * 2.0 - 1.0;
47
    
48
    ## Maximal conductivity for sodium current.
49
    gNa     = 120.0 * (1 + 0.02 * nu);
50
    
51
    ## Maximal conductivity for potassium current.
52
    gK      = 36.0 * (1 + 0.02 * nu);
53
    
54
    ## Maximal conductivity for leakage current.
55
    gL      = 0.3 * (1 + 0.02 * nu);
56
    
57
    
58
    ## Reverse potential of sodium current [mV].
59
    vNa     = 50.0;
60
    
61
    ## Reverse potential of potassium current [mV].
62
    vK      = -77.0;
63
    
64
    ## Reverse potantial of leakage current [mV].
65
    vL      = -54.4;
66
    
67
    ## Rest potential [mV].
68
    vRest   = -65.0;    
69
    
70
    
71
    ## External current [mV] for central element 1.
72
    Icn1    = 5.0;
73
    
74
    ## External current [mV] for central element 2.
75
    Icn2    = 30.0;
76
    
77
    
78
    ## Synaptic reversal potential [mV] for inhibitory effects.
79
    Vsyninh = -80.0;    
80
    
81
    ## Synaptic reversal potential [mV] for exciting effects.
82
    Vsynexc = 0.0;
83
    
84
    ## Alfa-parameter for alfa-function for inhibitory effect.
85
    alfa_inhibitory     = 6.0;
86
    
87
    ## Betta-parameter for alfa-function for inhibitory effect.
88
    betta_inhibitory    = 0.3;
89
    
90
    
91
    ## Alfa-parameter for alfa-function for excitatoty effect.
92
    alfa_excitatory     = 40.0;
93
    
94
    ## Betta-parameter for alfa-function for excitatoty effect.
95
    betta_excitatory    = 2.0;
96
    
97
    
98
    ## Strength of the synaptic connection from PN to CN1.
99
    w1 = 0.1;
100
    
101
    ## Strength of the synaptic connection from CN1 to PN.
102
    w2 = 9.0;
103
    
104
    ## Strength of the synaptic connection from CN2 to PN.
105
    w3 = 5.0;
106
    
107
    
108
    ## Period of time [ms] when high strength value of synaptic connection exists from CN2 to PN.
109
    deltah = 650.0;
110
    
111
    ## Threshold of the membrane potential that should exceeded by oscillator to be considered as an active.
112
    threshold = -10;
113
    
114
    ## Affects pulse counter.
115
    eps = 0.16;
116
117
118
class central_element:
119
    """!
120
    @brief Central element consist of two central neurons that are described by a little bit different dynamic than peripheral.
121
    
122
    @see hhn_network
123
    
124
    """
125
    
126
    ## Membrane potential of cenral neuron (V).
127
    membrane_potential      = 0.0;
128
    
129
    ## Activation conductance of the sodium channel (m).
130
    active_cond_sodium      = 0.0;
131
    
132
    ## Inactivaton conductance of the sodium channel (h).
133
    inactive_cond_sodium    = 0.0;
134
    
135
    ## Inactivaton conductance of the sodium channel (h)
136
    active_cond_potassium   = 0.0;
137
    
138
    ## Times of pulse generation by central neuron.
139
    pulse_generation_time = None;
140
    
141
    ## Spike generation of central neuron.
142
    pulse_generation = False;
143
    
144
    def __init__(self):
145
        """!
146
        @brief Constructor of central element.
147
        
148
        """
149
        
150
        self.pulse_generation_time = [];
151
    
152
    def __repr__(self):
153
        """!
154
        @brief Returns string that represents central element.
155
        
156
        """
157
        return "%s, %s" % (self.membrane_potential, self.pulse_generation_time);
158
159
160
class hhn_network(network):
161
    """!
162
    @brief Oscillatory Neural Network with central element based on Hodgkin-Huxley neuron model. Interaction between oscillators is performed via
163
           central element (no connection between oscillators that are called as peripheral). Peripheral oscillators receive external stimulus.
164
           Central element consist of two oscillators: the first is used for synchronization some ensemble of oscillators and the second controls
165
           synchronization of the first cental oscillator with verious ensembles.
166
    
167
    Example:
168
    @code
169
        # change period of time when high strength value of synaptic connection exists from CN2 to PN.
170
        params = hhn_parameters();
171
        params.deltah = 400;
172
        
173
        # create oscillatory network with stimulus
174
        net = hhn_network(6, [0, 0, 25, 25, 47, 47], params);
175
        
176
        # simulate network
177
        (t, dyn) = net.simulate(1200, 600);
178
        
179
        # draw network output during simulation
180
        draw_dynamics(t, dyn, x_title = "Time", y_title = "V", separate = True);
181
    @endcode
182
    
183
    """
184
    
185
    _name = "Oscillatory Neural Network based on Hodgkin-Huxley Neuron Model"
186
    
187
    # States of peripheral oscillators
188
    _membrane_potential     = None;          # membrane potential of neuron (V)
189
    _active_cond_sodium     = None;          # activation conductance of the sodium channel (m)
190
    _inactive_cond_sodium   = None;          # inactivaton conductance of the sodium channel (h)
191
    _active_cond_potassium  = None;          # activation conductance of the potassium channel (n)
192
    _link_activation_time   = None;          # time of set w3 - connection from CN2 to PN for each oscillator.
193
    _link_weight3           = None;          # connection strength for each oscillator from CN2 to PN.
194
    
195
    _pulse_generation_time  = None;          # time of spike generation for each oscillator.
196
    _pulse_generation       = None;          # spike generation for each oscillator.
197
    
198
    _stimulus = None;               # stimulus of each oscillator
199
    _noise = None;                  # Noise for each oscillator
200
    
201
    _central_element = None;        # Central element description
202
    
203
    _params = None;                 # parameters of the network
204
    
205
    _membrane_dynamic_pointer = None;        # final result is stored here.
206
    
207
    def __init__(self, num_osc, stimulus = None, parameters = None, type_conn = None, type_conn_represent = conn_represent.MATRIX):
208
        """!
209
        @brief Constructor of oscillatory network based on Hodgkin-Huxley meuron model.
210
        
211
        @param[in] num_osc (uint): Number of peripheral oscillators in the network.
212
        @param[in] stimulus (list): List of stimulus for oscillators, number of stimulus should be equal to number of peripheral oscillators.
213
        @param[in] parameters (hhn_parameters): Parameters of the network.
214
        @param[in] type_conn (conn_type): Type of connections between oscillators in the network (ignored for this type of 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, conn_type.NONE, type_conn_represent);
220
        
221
        self._membrane_potential        = [0.0] * self._num_osc;
222
        self._active_cond_sodium        = [0.0] * self._num_osc;
223
        self._inactive_cond_sodium      = [0.0] * self._num_osc;
224
        self._active_cond_potassium     = [0.0] * self._num_osc;
225
        self._link_activation_time      = [0.0] * self._num_osc;
226
        self._link_pulse_counter        = [0.0] * self._num_osc;
227
        self._link_deactivation_time    = [0.0] * self._num_osc;
228
        self._link_weight3              = [0.0] * self._num_osc;
229
        self._pulse_generation_time     = [ [] for i in range(self._num_osc) ];
230
        self._pulse_generation          = [False] * self._num_osc;
231
        
232
        self._noise = [random.random() * 2.0 - 1.0 for i in range(self._num_osc)];
233
        
234
        self._central_element = [central_element(), central_element()];
235
        
236
        if (stimulus is None):
237
            self._stimulus = [0.0] * self._num_osc;
238
        else:
239
            self._stimulus = stimulus;
240
        
241
        if (parameters is not None):
242
            self._params = parameters;
243
        else:
244
            self._params = hhn_parameters();
245
    
246
    
247
    def simulate(self, steps, time, solution = solve_type.RK4, collect_dynamic = True):
248
        """!
249
        @brief Performs static simulation of oscillatory network based on Hodgkin-Huxley neuron model.
250
        
251
        @param[in] steps (uint): Number steps of simulations during simulation.
252
        @param[in] time (double): Time of simulation.
253
        @param[in] solution (solve_type): Type of solver for differential equations.
254
        @param[in] collect_dynamic (bool): If True - returns whole dynamic of oscillatory network, otherwise returns only last values of dynamics.
255
        
256
        @return (list) Dynamic of oscillatory network. If argument 'collect_dynamic' = True, than return dynamic for the whole simulation time,
257
                otherwise returns only last values (last step of simulation) of dynamic.
258
        
259
        """
260
        
261
        return self.simulate_static(steps, time, solution, collect_dynamic);
262
    
263
    
264
    def simulate_static(self, steps, time, solution = solve_type.RK4, collect_dynamic = False):
265
        """!
266
        @brief Performs static simulation of oscillatory network based on Hodgkin-Huxley neuron model.
267
        
268
        @param[in] steps (uint): Number steps of simulations during simulation.
269
        @param[in] time (double): Time of simulation.
270
        @param[in] solution (solve_type): Type of solver for differential equations.
271
        @param[in] collect_dynamic (bool): If True - returns whole dynamic of oscillatory network, otherwise returns only last values of dynamics.
272
        
273
        @return (list) Dynamic of oscillatory network. If argument 'collect_dynamic' = True, than return dynamic for the whole simulation time,
274
                otherwise returns only last values (last step of simulation) of dynamic.
275
        
276
        """
277
        
278
        self._membrane_dynamic_pointer = None;
279
        
280
        # Check solver before simulation
281
        if (solution == solve_type.FAST):
282
            raise NameError("Solver FAST is not support due to low accuracy that leads to huge error.");
283
        elif (solution == solve_type.RKF45):
284
            raise NameError("Solver RKF45 is not support in python version.");
285
        
286
        dyn_memb = None;
287
        dyn_time = None;
288
        
289
        # Store only excitatory of the oscillator
290
        if (collect_dynamic == True):
291
            dyn_memb = [];
292
            dyn_time = [];
293
            
294
        step = time / steps;
295
        int_step = step / 10.0;
296
        
297
        for t in numpy.arange(step, time + step, step):
298
            # update states of oscillators
299
            memb = self._calculate_states(solution, t, step, int_step);
300
            
301
            # update states of oscillators
302
            if (collect_dynamic == True):
303
                dyn_memb.append(memb);
304
                dyn_time.append(t);
305
            else:
306
                dyn_memb = memb;
307
                dyn_time = t;
308
        
309
        self._membrane_dynamic_pointer = dyn_memb;
310
        return (dyn_time, dyn_memb);
311
    
312
    
313
    def _calculate_states(self, solution, t, step, int_step):
0 ignored issues
show
Unused Code introduced by
The argument solution seems to be unused.
Loading history...
314
        """!
315
        @brief Caclculates new state of each oscillator in the network. Returns only excitatory state of oscillators.
316
        
317
        @param[in] solution (solve_type): Type solver of the differential equations.
318
        @param[in] t (double): Current time of simulation.
319
        @param[in] step (uint): Step of solution at the end of which states of oscillators should be calculated.
320
        @param[in] int_step (double): Differentiation step that is used for solving differential equation.
321
        
322
        @return (list) New states of membrance potentials for peripheral oscillators and for cental elements as a list where
323
                the last two values correspond to central element 1 and 2.
324
                 
325
        """
326
        
327
        next_membrane           = [0.0] * self._num_osc;
328
        next_active_sodium      = [0.0] * self._num_osc;
329
        next_inactive_sodium    = [0.0] * self._num_osc;
330
        next_active_potassium   = [0.0] * self._num_osc;
331
        
332
        # Update states of oscillators
333
        for index in range (0, self._num_osc, 1):
334
            result = odeint(self.hnn_state, 
335
                            [ self._membrane_potential[index], self._active_cond_sodium[index], self._inactive_cond_sodium[index], self._active_cond_potassium[index] ], 
336
                            numpy.arange(t - step, t, int_step), 
337
                            (index , ));
338
                            
339
            [ next_membrane[index], next_active_sodium[index], next_inactive_sodium[index], next_active_potassium[index] ] = result[len(result) - 1][0:4];        
340
        
341
        next_cn_membrane            = [0.0, 0.0];
342
        next_cn_active_sodium       = [0.0, 0.0];
343
        next_cn_inactive_sodium     = [0.0, 0.0];
344
        next_cn_active_potassium    = [0.0, 0.0];
345
        
346
        # Update states of central elements
347
        for index in range(0, len(self._central_element)):
348
            result = odeint(self.hnn_state, 
349
                            [ self._central_element[index].membrane_potential, self._central_element[index].active_cond_sodium, self._central_element[index].inactive_cond_sodium, self._central_element[index].active_cond_potassium ], 
350
                            numpy.arange(t - step, t, int_step), 
351
                            (self._num_osc + index , ));
352
                            
353
            [ next_cn_membrane[index], next_cn_active_sodium[index], next_cn_inactive_sodium[index], next_cn_active_potassium[index] ] = result[len(result) - 1][0:4];
354
        
355
        # Noise generation
356
        self._noise = [ 1.0 + 0.01 * (random.random() * 2.0 - 1.0) for i in range(self._num_osc)];
357
        
358
        # Updating states of PNs
359
        self.__update_peripheral_neurons(t, step, next_membrane, next_active_sodium, next_inactive_sodium, next_active_potassium);
360
        
361
        # Updation states of CN
362
        self.__update_central_neurons(t, next_cn_membrane, next_cn_active_sodium, next_cn_inactive_sodium, next_cn_active_potassium);
363
        
364
        return next_membrane + next_cn_membrane;
365
    
366
    
367
    def __update_peripheral_neurons(self, t, step, next_membrane, next_active_sodium, next_inactive_sodium, next_active_potassium):
368
        """!
369
        @brief Update peripheral neurons in line with new values of current in channels.
370
        
371
        @param[in] t (doubles): Current time of simulation.
372
        @param[in] step (uint): Step (time duration) during simulation when states of oscillators should be calculated.
373
        @param[in] next_membrane (list): New values of membrane potentials for peripheral neurons.
374
        @Param[in] next_active_sodium (list): New values of activation conductances of the sodium channels for peripheral neurons.
375
        @param[in] next_inactive_sodium (list): New values of inactivaton conductances of the sodium channels for peripheral neurons.
376
        @param[in] next_active_potassium (list): New values of activation conductances of the potassium channel for peripheral neurons.
377
        
378
        """
379
        
380
        self._membrane_potential = next_membrane[:];
381
        self._active_cond_sodium = next_active_sodium[:];
382
        self._inactive_cond_sodium = next_inactive_sodium[:];
383
        self._active_cond_potassium = next_active_potassium[:];
384
        
385
        for index in range(0, self._num_osc):
386
            if (self._pulse_generation[index] is False):
387
                if (self._membrane_potential[index] > 0.0):
388
                    self._pulse_generation[index] = True;
389
                    self._pulse_generation_time[index].append(t);
390
            else:
391
                if (self._membrane_potential[index] < 0.0):
392
                    self._pulse_generation[index] = False;
393
            
394
            # Update connection from CN2 to PN
395
            if (self._link_weight3[index] == 0.0):
396
                if ( (self._membrane_potential[index] > self._params.threshold) and (self._membrane_potential[index] > self._params.threshold) ):
397
                    self._link_pulse_counter[index] += step;
398
                
399
                    if (self._link_pulse_counter[index] >= 1 / self._params.eps):
400
                        self._link_weight3[index] = self._params.w3;
401
                        self._link_activation_time[index] = t;
402
            else:
403
                if ( not ((self._link_activation_time[index] < t) and (t < self._link_activation_time[index] + self._params.deltah)) ):
404
                    self._link_weight3[index] = 0.0;
405
                    self._link_pulse_counter[index] = 0.0;
406
    
407
    
408
    def __update_central_neurons(self, t, next_cn_membrane, next_cn_active_sodium, next_cn_inactive_sodium, next_cn_active_potassium):
409
        """!
410
        @brief Update of central neurons in line with new values of current in channels.
411
        
412
        @param[in] t (doubles): Current time of simulation.
413
        @param[in] next_membrane (list): New values of membrane potentials for central neurons.
414
        @Param[in] next_active_sodium (list): New values of activation conductances of the sodium channels for central neurons.
415
        @param[in] next_inactive_sodium (list): New values of inactivaton conductances of the sodium channels for central neurons.
416
        @param[in] next_active_potassium (list): New values of activation conductances of the potassium channel for central neurons.
417
        
418
        """
419
        
420
        for index in range(0, len(self._central_element)):
421
            self._central_element[index].membrane_potential = next_cn_membrane[index];
422
            self._central_element[index].active_cond_sodium = next_cn_active_sodium[index];
423
            self._central_element[index].inactive_cond_sodium = next_cn_inactive_sodium[index];
424
            self._central_element[index].active_cond_potassium = next_cn_active_potassium[index];
425
            
426
            if (self._central_element[index].pulse_generation is False):
427
                if (self._central_element[index].membrane_potential > 0.0):
428
                    self._central_element[index].pulse_generation = True;
429
                    self._central_element[index].pulse_generation_time.append(t);
430
            else:
431
                if (self._central_element[index].membrane_potential < 0.0):
432
                    self._central_element[index].pulse_generation = False;
433
    
434
    
435
    def hnn_state(self, inputs, t, argv):
436
        """!
437
        @brief Returns new values of excitatory and inhibitory parts of oscillator and potential of oscillator.
438
        
439
        @param[in] inputs (list): States of oscillator for integration [v, m, h, n] (see description below).
440
        @param[in] t (double): Current time of simulation.
441
        @param[in] argv (tuple): Extra arguments that are not used for integration - index of oscillator.
442
        
443
        @return (list) new values of oscillator [v, m, h, n], where:
444
                v - membrane potantial of oscillator,
445
                m - activation conductance of the sodium channel,
446
                h - inactication conductance of the sodium channel,
447
                n - activation conductance of the potassium channel.
448
        
449
        """
450
        
451
        index = argv;
452
        
453
        v = inputs[0]; # membrane potential (v).
454
        m = inputs[1]; # activation conductance of the sodium channel (m).
455
        h = inputs[2]; # inactivaton conductance of the sodium channel (h).
456
        n = inputs[3]; # activation conductance of the potassium channel (n).
457
        
458
        # Calculate ion current
459
        # gNa * m[i]^3 * h * (v[i] - vNa) + gK * n[i]^4 * (v[i] - vK) + gL  (v[i] - vL)
460
        active_sodium_part = self._params.gNa * (m ** 3) * h * (v - self._params.vNa);
461
        inactive_sodium_part = self._params.gK * (n ** 4) * (v - self._params.vK);
462
        active_potassium_part = self._params.gL * (v - self._params.vL);
463
        
464
        Iion = active_sodium_part + inactive_sodium_part + active_potassium_part;
465
        
466
        Iext = 0.0;
467
        Isyn = 0.0;
468
        if (index < self._num_osc): 
469
            # PN - peripheral neuron - calculation of external current and synaptic current.
470
            Iext = self._stimulus[index] * self._noise[index];    # probably noise can be pre-defined for reducting compexity            
471
            
472
            memory_impact1 = 0.0;
473
            for i in range(0, len(self._central_element[0].pulse_generation_time)):
474
                # TODO: alfa function shouldn't be calculated here (long procedure)
475
                memory_impact1 += self.__alfa_function(t - self._central_element[0].pulse_generation_time[i], self._params.alfa_inhibitory, self._params.betta_inhibitory);
476
            
477
            memory_impact2 = 0.0;
478
            for i in range(0, len(self._central_element[1].pulse_generation_time)):
479
                # TODO: alfa function shouldn't be calculated here (long procedure)
480
                memory_impact2 += self.__alfa_function(t - self._central_element[1].pulse_generation_time[i], self._params.alfa_inhibitory, self._params.betta_inhibitory);        
481
    
482
            Isyn = self._params.w2 * (v - self._params.Vsyninh) * memory_impact1 + self._link_weight3[index] * (v - self._params.Vsyninh) * memory_impact2;            
483
        else:
484
            # CN - central element.
485
            central_index = index - self._num_osc;
486
            if (central_index == 0):
487
                Iext = self._params.Icn1;   # CN1
488
                
489
                memory_impact = 0.0;
490
                for index_oscillator in range(0, self._num_osc):
491
                    for index_generation in range(0, len(self._pulse_generation_time[index_oscillator])):
492
                        # TODO: alfa function shouldn't be calculated here (long procedure)
493
                        memory_impact += self.__alfa_function(t - self._pulse_generation_time[index_oscillator][index_generation], self._params.alfa_excitatory, self._params.betta_excitatory);
494
                 
495
                Isyn = self._params.w1 * (v - self._params.Vsynexc) * memory_impact;
496
                
497
            elif (central_index == 1):
498
                Iext = self._params.Icn2;   # CN2
499
                Isyn = 0.0;
500
                
501
            else:
502
                assert 0;
503
        
504
        
505
        # Membrane potential
506
        dv = -Iion + Iext - Isyn;
507
        
508
        # Calculate variables
509
        potential = v - self._params.vRest;
510
        am = (2.5 - 0.1 * potential) / (math.exp(2.5 - 0.1 * potential) - 1.0);
511
        ah = 0.07 * math.exp(-potential / 20.0);
512
        an = (0.1 - 0.01 * potential) / (math.exp(1.0 - 0.1 * potential) - 1.0);
513
        
514
        bm = 4.0 * math.exp(-potential / 18.0);
515
        bh = 1.0 / (math.exp(3.0 - 0.1 * potential) + 1.0);
516
        bn = 0.125 * math.exp(-potential / 80.0);
517
        
518
        dm = am * (1.0 - m) - bm * m;
519
        dh = ah * (1.0 - h) - bh * h;
520
        dn = an * (1.0 - n) - bn * n;
521
        
522
        return [dv, dm, dh, dn];
523
        
524
        
525
    def allocate_sync_ensembles(self, tolerance = 0.1):
526
        """!
527
        @brief Allocates clusters in line with ensembles of synchronous oscillators where each. Synchronous ensemble corresponds to only one cluster.
528
        
529
        @param[in] tolerance (double): maximum error for allocation of synchronous ensemble oscillators.
530
        
531
        @return (list) Grours (lists) of indexes of synchronous oscillators. For example [ [index_osc1, index_osc3], [index_osc2], [index_osc4, index_osc5] ].
532
        
533
        """
534
        
535
        ignore = set();
536
        
537
        ignore.add(self._num_osc);
538
        ignore.add(self._num_osc + 1);
539
        
540
        return allocate_sync_ensembles(self._membrane_dynamic_pointer, tolerance, 20.0, ignore);
541
    
542
    
543
    def __alfa_function(self, time, alfa, betta):
544
        """!
545
        @brief Calculates value of alfa-function for difference between spike generation time and current simulation time.
546
        
547
        @param[in] time (double): Difference between last spike generation time and current time.
548
        @param[in] alfa (double): Alfa parameter for alfa-function.
549
        @param[in] betta (double): Betta parameter for alfa-function.
550
        
551
        @return (double) Value of alfa-function.
552
        
553
        """
554
        
555
        return alfa * time * math.exp(-betta * time);
556