Completed
Push — 0.7.dev ( f100af...2e222e )
by Andrei
01:05
created

fsync_network   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 148
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 148
rs 10
c 0
b 0
f 0
wmc 16

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __landau_stuart() 0 12 1
C simulate_static() 0 34 7
A __calculate() 0 20 2
A __calculate_amplitude() 0 17 1
A __synchronization_mechanism() 0 19 3
A __init__() 0 20 2
1
"""!
2
3
@brief Oscillatory Neural Network based on Kuramoto model in frequency domain.
4
@details Based on article description:
5
         - Y.Kuramoto. Chemical Oscillations, Waves, and Turbulence. 1984.
6
7
@authors Andrei Novikov ([email protected])
8
@date 2014-2017
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
29
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...
30
import random;
31
32
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...
33
34
from pyclustering.nnet import network, conn_type, conn_represent;
35
from pyclustering.utils import draw_dynamics, draw_dynamics_set;
36
37
38
class fsync_dynamic:
39
    """!
40
    @brief Represents output dynamic of Sync in frequency domain.
41
    
42
    """
43
44
45
    def __init__(self, amplitude, time):
46
        """!
47
        @brief Constructor of Sync dynamic in frequency domain.
48
        
49
        @param[in] amplitude (list): Dynamic of oscillators on each step of simulation.
50
        @param[in] time (list): Simulation time where each time-point corresponds to amplitude-point.
51
        
52
        """
53
54
        self.__amplitude = amplitude;
55
        self.__time = time;
56
57
58
    @property
59
    def output(self):
60
        """!
61
        @brief (list) Returns output dynamic of the Sync network (amplitudes of each oscillator in the network) during simulation.
62
        
63
        """
64
65
        return self.__amplitude;
66
67
68
    @property
69
    def time(self):
70
        """!
71
        @brief (list) Returns time-points corresponds to dynamic-points points.
72
        
73
        """
74
75
        return self.__time;
76
77
78
    def __len__(self):
79
        """!
80
        @brief (uint) Returns number of simulation steps that are stored in dynamic.
81
        
82
        """
83
        
84
        return len(self.__amplitude);
85
86
87
88
class fsync_visualizer:
89
    """!
90
    @brief Visualizer of output dynamic of sync network in frequency domain.
91
    
92
    """
93
94
    @staticmethod
95
    def show_output_dynamic(fsync_output_dynamic):
96
        """!
97
        @brief Shows output dynamic (output of each oscillator) during simulation.
98
        
99
        @param[in] fsync_output_dynamic (fsync_dynamic): Output dynamic of the fSync network.
100
        
101
        @see show_output_dynamics
102
        
103
        """
104
        
105
        draw_dynamics(fsync_output_dynamic.time, fsync_output_dynamic.output, x_title = "t", y_title = "amplitude");
106
107
108
    @staticmethod
109
    def show_output_dynamics(sync_output_dynamics):
110
        """!
111
        @brief Shows several output dynamics (output of each oscillator) during simulation.
112
        @details Each dynamic is presented on separate plot.
113
        
114
        @param[in] sync_output_dynamics (list): list of output dynamics 'fsync_dynamic' of the fSync network.
115
        
116
        @see show_output_dynamic
117
        
118
        """
119
        
120
        draw_dynamics_set(sync_output_dynamics, "t", "amplitude", None, None, False, False);
121
122
123
124
class fsync_network(network):
125
    """!
0 ignored issues
show
Bug introduced by
A suspicious escape sequence \d was found. Did you maybe forget to add an r prefix?

Escape sequences in Python are generally interpreted according to rules similar to standard C. Only if strings are prefixed with r or R are they interpreted as regular expressions.

The escape sequence that was used indicates that you might have intended to write a regular expression.

Learn more about the available escape sequences. in the Python documentation.

Loading history...
Bug introduced by
A suspicious escape sequence \o was found. Did you maybe forget to add an r prefix?

Escape sequences in Python are generally interpreted according to rules similar to standard C. Only if strings are prefixed with r or R are they interpreted as regular expressions.

The escape sequence that was used indicates that you might have intended to write a regular expression.

Learn more about the available escape sequences. in the Python documentation.

Loading history...
Bug introduced by
A suspicious escape sequence \s was found. Did you maybe forget to add an r prefix?

Escape sequences in Python are generally interpreted according to rules similar to standard C. Only if strings are prefixed with r or R are they interpreted as regular expressions.

The escape sequence that was used indicates that you might have intended to write a regular expression.

Learn more about the available escape sequences. in the Python documentation.

Loading history...
126
    @brief Model of oscillatory network that uses Landau-Stuart oscillator and Kuramoto model as a synchronization mechanism.
127
    @details Dynamic of each oscillator in the network is described by following differential equation:
128
    
129
    \f[
130
    \dot{z}_{i} = (i\omega_{i} + \rho^{2}_{i} - |z_{i}|^{2} )z_{i} + \sum_{j=0}^{N}k_{ij}(z_{j} - z_{i})
131
    \f]
132
    
133
    """
134
    
135
    __DEFAULT_FREQUENCY_VALUE = 1.0;
136
    __DEFAULT_RADIUS_VALUE = 1.0;
137
    __DEFAULT_COUPLING_STRENGTH = 1.0;
138
139
140
    def __init__(self, num_osc, factor_frequency = 1.0, factor_radius = 1.0, factor_coupling = 1.0, type_conn = conn_type.ALL_TO_ALL, representation = conn_represent.MATRIX):
141
        """!
142
        @brief Constructor of oscillatory network based on synchronization Kuramoto model and Landau-Stuart oscillator.
143
        
144
        @param[in] num_osc (uint): Amount oscillators in the network.
145
        @param[in] type_conn (conn_type): Type of connection between oscillators in the network (all-to-all, grid, bidirectional list, etc.).
146
        @param[in] representation (conn_represent): Internal representation of connection in the network: matrix or list.
147
        
148
        """
149
        
150
        super().__init__(num_osc, type_conn, representation);
151
        
152
        self.__frequency = fsync_network.__DEFAULT_FREQUENCY_VALUE * factor_frequency;
153
        self.__radius = fsync_network.__DEFAULT_RADIUS_VALUE * factor_radius;
154
        self.__coupling_strength = fsync_network.__DEFAULT_COUPLING_STRENGTH * factor_coupling;
155
        
156
        self.__landau_contant = numpy.array(1j * self.__frequency + self.__radius**2, dtype = numpy.complex128, ndmin = 1);
157
        
158
        random.seed();
159
        self.__amplitude = [ random.random() for _ in range(num_osc) ];
160
161
162
    def simulate_static(self, steps, time, collect_dynamic = False):
163
        """!
164
        @brief Performs static simulation of oscillatory network.
165
        
166
        @param[in] steps (uint): Number simulation steps.
167
        @param[in] time (double): Time of simulation.
168
        @param[in] collect_dynamic (bool): If True - returns whole dynamic of oscillatory network, otherwise returns only last values of dynamics.
169
        
170
        @return (list) Dynamic of oscillatory network. If argument 'collect_dynamic' is True, than return dynamic for the whole simulation time,
171
                otherwise returns only last values (last step of simulation) of output dynamic.
172
        
173
        @see simulate()
174
        @see simulate_dynamic()
175
        
176
        """
177
        
178
        dynamic_amplitude, dynamic_time = ([], []) if collect_dynamic is False else ([self.__amplitude], [0]);
179
        
180
        step = time / steps;
181
        int_step = step / 10.0;
182
        
183
        for t in numpy.arange(step, time + step, step):
184
            self.__amplitude = self.__calculate(t, step, int_step);
185
            
186
            if (collect_dynamic == True):
187
                dynamic_amplitude.append([ numpy.real(amplitude) for amplitude in self.__amplitude ]);
188
                dynamic_time.append(t);
189
        
190
        if (collect_dynamic != True):
191
            dynamic_amplitude.append([ numpy.real(amplitude) for amplitude in self.__amplitude ]);
192
            dynamic_time.append(time);
193
194
        output_sync_dynamic = fsync_dynamic(dynamic_amplitude, dynamic_time);
195
        return output_sync_dynamic;
196
197
198
    def __calculate(self, t, step, int_step):
199
        """!
200
        @brief Calculates new amplitudes for oscillators in the network in line with current step.
201
        
202
        @param[in] t (double): Time of simulation.
203
        @param[in] step (double): Step of solution at the end of which states of oscillators should be calculated.
204
        @param[in] int_step (double): Step differentiation that is used for solving differential equation.
205
        
206
        @return (list) New states (phases) for oscillators.
207
        
208
        """
209
        
210
        next_amplitudes = [0.0] * self._num_osc;
211
        
212
        for index in range (0, self._num_osc, 1):
213
            z = numpy.array(self.__amplitude[index], dtype = numpy.complex128, ndmin = 1);
214
            result = odeint(self.__calculate_amplitude, z.view(numpy.float64), numpy.arange(t - step, t, int_step), (index , ));
215
            next_amplitudes[index] = (result[len(result) - 1]).view(numpy.complex128);
216
        
217
        return next_amplitudes;
218
219
220
    def __landau_stuart(self, amplitude, index):
0 ignored issues
show
Unused Code introduced by
The argument index seems to be unused.
Loading history...
221
        """!
222
        @brief Calculate Landau-Stuart state.
223
        
224
        @param[in] amplitude (double): Current amplitude of oscillator.
225
        @param[in] index (uint): Oscillator index whose state is calculated. 
226
        
227
        @return (double) Landau-Stuart state.
228
        
229
        """
230
        
231
        return (self.__landau_contant - numpy.absolute(amplitude) ** 2) * amplitude;
232
233
234
    def __synchronization_mechanism(self, amplitude, index):
235
        """!
236
        @brief Calculate synchronization part using Kuramoto synchronization mechanism.
237
        
238
        @param[in] amplitude (double): Current amplitude of oscillator.
239
        @param[in] index (uint): Oscillator index whose synchronization influence is calculated.
240
        
241
        @return (double) Synchronization influence for the specified oscillator.
242
        
243
        """
244
        
245
        sync_influence = 0.0;
246
        
247
        for k in range(self._num_osc):
248
            if (self.has_connection(index, k) == True):
249
                amplitude_neighbor = numpy.array(self.__amplitude[k], dtype = numpy.complex128, ndmin = 1);
250
                sync_influence += amplitude_neighbor - amplitude;
251
        
252
        return sync_influence * self.__coupling_strength / self._num_osc;
253
254
255
    def __calculate_amplitude(self, amplitude, t, argv):
0 ignored issues
show
Unused Code introduced by
The argument t seems to be unused.
Loading history...
256
        """!
257
        @brief Returns new amplitude value for particular oscillator that is defined by index that is in 'argv' argument.
258
        @details The method is used for differential calculation.
259
        
260
        @param[in] amplitude (double): Current amplitude of oscillator.
261
        @param[in] t (double): Current time of simulation.
262
        @param[in] argv (uint): Index of the current oscillator.
263
        
264
        @return (double) New amplitude of the oscillator.
265
        
266
        """
267
        
268
        z = amplitude.view(numpy.complex);
269
        dzdt = self.__landau_stuart(z, argv) + self.__synchronization_mechanism(z, argv);
270
        
271
        return dzdt.view(numpy.float64);