Completed
Push — master ( a63a82...61f52c )
by
unknown
01:32
created

hhn_network   B

Complexity

Total Complexity 41

Size/Duplication

Total Lines 367
Duplicated Lines 0 %
Metric Value
dl 0
loc 367
rs 8.2769
wmc 41

7 Methods

Rating   Name   Duplication   Size   Complexity  
B simulate_static() 0 47 6
A simulate() 0 15 1
F _calculate_states() 0 91 18
A allocate_sync_ensembles() 0 16 1
F hnn_state() 0 88 9
A __alfa_function() 0 13 1
B __init__() 0 38 5

How to fix   Complexity   

Complex Class

Complex classes like hhn_network 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
        for index in range(0, self._num_osc):
360
            if (self._pulse_generation[index] is False):
361
                if (next_membrane[index] > 0.0):
362
                    self._pulse_generation[index] = True;
363
                    self._pulse_generation_time[index].append(t);
364
            else:
365
                if (next_membrane[index] < 0.0):
366
                    self._pulse_generation[index] = False;
367
            
368
            # Update connection from CN2 to PN
369
            if (self._link_weight3[index] == 0.0):
370
                if ( (next_membrane[index] > self._params.threshold) and (next_membrane[index] > self._params.threshold) ):
371
                    self._link_pulse_counter[index] += step;
372
                
373
                    if (self._link_pulse_counter[index] >= 1 / self._params.eps):
374
                        self._link_weight3[index] = self._params.w3;
375
                        self._link_activation_time[index] = t;
376
            else:
377
                if ( not ((self._link_activation_time[index] < t) and (t < self._link_activation_time[index] + self._params.deltah)) ):
378
                    self._link_weight3[index] = 0.0;
379
                    self._link_pulse_counter[index] = 0.0;
380
                    
381
        
382
        
383
        # Updation states of CN
384
        for index in range(0, len(self._central_element)):
385
            if (self._central_element[index].pulse_generation is False):
386
                if (next_cn_membrane[index] > 0.0):
387
                    self._central_element[index].pulse_generation = True;
388
                    self._central_element[index].pulse_generation_time.append(t);
389
            else:
390
                if (next_cn_membrane[index] < 0.0):
391
                    self._central_element[index].pulse_generation = False;
392
            
393
            self._central_element[index].membrane_potential = next_cn_membrane[index];
394
            self._central_element[index].active_cond_sodium = next_cn_active_sodium[index];
395
            self._central_element[index].inactive_cond_sodium = next_cn_inactive_sodium[index];
396
            self._central_element[index].active_cond_potassium = next_cn_active_potassium[index];
397
        
398
        self._membrane_potential = next_membrane[:];
399
        self._active_cond_sodium = next_active_sodium[:];
400
        self._inactive_cond_sodium = next_inactive_sodium[:];
401
        self._active_cond_potassium = next_active_potassium[:];
402
        
403
        return next_membrane + next_cn_membrane;
404
    
405
    
406
    def hnn_state(self, inputs, t, argv):
407
        """!
408
        @brief Returns new values of excitatory and inhibitory parts of oscillator and potential of oscillator.
409
        
410
        @param[in] inputs (list): States of oscillator for integration [v, m, h, n] (see description below).
411
        @param[in] t (double): Current time of simulation.
412
        @param[in] argv (tuple): Extra arguments that are not used for integration - index of oscillator.
413
        
414
        @return (list) new values of oscillator [v, m, h, n], where:
415
                v - membrane potantial of oscillator,
416
                m - activation conductance of the sodium channel,
417
                h - inactication conductance of the sodium channel,
418
                n - activation conductance of the potassium channel.
419
        
420
        """
421
        
422
        index = argv;
423
        
424
        v = inputs[0]; # membrane potential (v).
425
        m = inputs[1]; # activation conductance of the sodium channel (m).
426
        h = inputs[2]; # inactivaton conductance of the sodium channel (h).
427
        n = inputs[3]; # activation conductance of the potassium channel (n).
428
        
429
        # Calculate ion current
430
        # gNa * m[i]^3 * h * (v[i] - vNa) + gK * n[i]^4 * (v[i] - vK) + gL  (v[i] - vL)
431
        active_sodium_part = self._params.gNa * (m ** 3) * h * (v - self._params.vNa);
432
        inactive_sodium_part = self._params.gK * (n ** 4) * (v - self._params.vK);
433
        active_potassium_part = self._params.gL * (v - self._params.vL);
434
        
435
        Iion = active_sodium_part + inactive_sodium_part + active_potassium_part;
436
        
437
        Iext = 0.0;
438
        Isyn = 0.0;
439
        if (index < self._num_osc): 
440
            # PN - peripheral neuron - calculation of external current and synaptic current.
441
            Iext = self._stimulus[index] * self._noise[index];    # probably noise can be pre-defined for reducting compexity            
442
            
443
            memory_impact1 = 0.0;
444
            for i in range(0, len(self._central_element[0].pulse_generation_time)):
445
                # TODO: alfa function shouldn't be calculated here (long procedure)
446
                memory_impact1 += self.__alfa_function(t - self._central_element[0].pulse_generation_time[i], self._params.alfa_inhibitory, self._params.betta_inhibitory);
447
            
448
            memory_impact2 = 0.0;
449
            for i in range(0, len(self._central_element[1].pulse_generation_time)):
450
                # TODO: alfa function shouldn't be calculated here (long procedure)
451
                memory_impact2 += self.__alfa_function(t - self._central_element[1].pulse_generation_time[i], self._params.alfa_inhibitory, self._params.betta_inhibitory);        
452
    
453
            Isyn = self._params.w2 * (v - self._params.Vsyninh) * memory_impact1 + self._link_weight3[index] * (v - self._params.Vsyninh) * memory_impact2;            
454
        else:
455
            # CN - central element.
456
            central_index = index - self._num_osc;
457
            if (central_index == 0):
458
                Iext = self._params.Icn1;   # CN1
459
                
460
                memory_impact = 0.0;
461
                for index_oscillator in range(0, self._num_osc):
462
                    for index_generation in range(0, len(self._pulse_generation_time[index_oscillator])):
463
                        # TODO: alfa function shouldn't be calculated here (long procedure)
464
                        memory_impact += self.__alfa_function(t - self._pulse_generation_time[index_oscillator][index_generation], self._params.alfa_excitatory, self._params.betta_excitatory);
465
                 
466
                Isyn = self._params.w1 * (v - self._params.Vsynexc) * memory_impact;
467
                
468
            elif (central_index == 1):
469
                Iext = self._params.Icn2;   # CN2
470
                Isyn = 0.0;
471
                
472
            else:
473
                assert 0;
474
        
475
        
476
        # Membrane potential
477
        dv = -Iion + Iext - Isyn;
478
        
479
        # Calculate variables
480
        potential = v - self._params.vRest;
481
        am = (2.5 - 0.1 * potential) / (math.exp(2.5 - 0.1 * potential) - 1.0);
482
        ah = 0.07 * math.exp(-potential / 20.0);
483
        an = (0.1 - 0.01 * potential) / (math.exp(1.0 - 0.1 * potential) - 1.0);
484
        
485
        bm = 4.0 * math.exp(-potential / 18.0);
486
        bh = 1.0 / (math.exp(3.0 - 0.1 * potential) + 1.0);
487
        bn = 0.125 * math.exp(-potential / 80.0);
488
        
489
        dm = am * (1.0 - m) - bm * m;
490
        dh = ah * (1.0 - h) - bh * h;
491
        dn = an * (1.0 - n) - bn * n;
492
        
493
        return [dv, dm, dh, dn];
494
        
495
        
496
    def allocate_sync_ensembles(self, tolerance = 0.1):
497
        """!
498
        @brief Allocates clusters in line with ensembles of synchronous oscillators where each. Synchronous ensemble corresponds to only one cluster.
499
        
500
        @param[in] tolerance (double): maximum error for allocation of synchronous ensemble oscillators.
501
        
502
        @return (list) Grours (lists) of indexes of synchronous oscillators. For example [ [index_osc1, index_osc3], [index_osc2], [index_osc4, index_osc5] ].
503
        
504
        """
505
        
506
        ignore = set();
507
        
508
        ignore.add(self._num_osc);
509
        ignore.add(self._num_osc + 1);
510
        
511
        return allocate_sync_ensembles(self._membrane_dynamic_pointer, tolerance, 20.0, ignore);
512
    
513
    
514
    def __alfa_function(self, time, alfa, betta):
515
        """!
516
        @brief Calculates value of alfa-function for difference between spike generation time and current simulation time.
517
        
518
        @param[in] time (double): Difference between last spike generation time and current time.
519
        @param[in] alfa (double): Alfa parameter for alfa-function.
520
        @param[in] betta (double): Betta parameter for alfa-function.
521
        
522
        @return (double) Value of alfa-function.
523
        
524
        """
525
        
526
        return alfa * time * math.exp(-betta * time);
527