Completed
Push — master ( 1c1955...027637 )
by Andrei
01:39
created

syncpr_visualizer.show_pattern()   F

Complexity

Conditions 11

Size

Total Lines 49

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
c 0
b 0
f 0
dl 0
loc 49
rs 3.1764

How to fix   Complexity   

Complexity

Complex classes like syncpr_visualizer.show_pattern() 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 Phase oscillatory network for patten recognition based on modified Kuramoto model.
4
@details Based on article description:
5
         - R.Follmann, E.E.N.Macau, E.Rosa, Jr., J.R.C.Piqueira. Phase Oscillatory Network and Visual Pattern Recognition. 2014.
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 solve_type, initial_type, conn_type;
29
from pyclustering.nnet.sync     import sync_network, sync_dynamic, sync_visualizer;
30
31
import pyclustering.core.syncpr_wrapper as wrapper;
32
33
from PIL import Image;
0 ignored issues
show
Configuration introduced by
The import PIL 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...
34
35
import matplotlib.pyplot as plt;
0 ignored issues
show
Configuration introduced by
The import matplotlib.pyplot 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...
36
import matplotlib.animation as animation;
0 ignored issues
show
Configuration introduced by
The import matplotlib.animation 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...
37
38
import math;
39
import cmath;
40
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...
41
42
43
class syncpr_dynamic(sync_dynamic):
44
    """!
45
    @brief Represents output dynamic of syncpr (Sync for Pattern Recognition).
46
    
47
    """
48
    
49
    def __init__(self, phase, time, ccore):
50
        """!
51
        @brief Constructor of syncpr dynamic.
52
        
53
        @param[in] phase (list): Dynamic of oscillators on each step of simulation. If ccore pointer is specified than it can be ignored.
54
        @param[in] time (list): Simulation time.
55
        @param[in] ccore (ctypes.pointer): Pointer to CCORE sync_dynamic instance in memory.
56
        
57
        """
58
        super().__init__(phase, time, ccore);
59
60
61
class syncpr_visualizer(sync_visualizer):
62
    """!
63
    @brief Visualizer of output dynamic of syncpr network (Sync for Pattern Recognition).
64
    
65
    """
66
    
67
    @staticmethod
68
    def show_pattern(syncpr_output_dynamic, image_height, image_width):
69
        """!
70
        @brief Displays evolution of phase oscillators as set of patterns where the last one means final result of recognition.
71
        
72
        @param[in] syncpr_output_dynamic (syncpr_dynamic): Output dynamic of a syncpr network.
73
        @param[in] image_height (uint): Height of the pattern (image_height * image_width should be equal to number of oscillators).
74
        @param[in] image_width (uint): Width of the pattern.
75
        
76
        """
77
        number_pictures = len(syncpr_output_dynamic);
78
        iteration_math_step = 1.0;
79
        if (number_pictures > 50):
80
            iteration_math_step = number_pictures / 50.0;
81
            number_pictures = 50;
82
        
83
        number_cols = int(numpy.ceil(number_pictures ** 0.5));
84
        number_rows = int(numpy.ceil(number_pictures / number_cols));
85
        
86
        real_index = 0, 0;
87
        double_indexer = True;
88
        if ( (number_cols == 1) or (number_rows == 1) ):
89
            real_index = 0;
90
            double_indexer = False;
91
        
92
        (_, axarr) = plt.subplots(number_rows, number_cols);
93
        
94
        if (number_pictures > 1):
95
            plt.setp([ax for ax in axarr], visible = False);
96
            
97
        iteration_display = 0.0;
98
        for iteration in range(len(syncpr_output_dynamic)):
99
            if (iteration >= iteration_display):
100
                iteration_display += iteration_math_step;
101
                
102
                ax_handle = axarr;
103
                if (number_pictures > 1):
104
                    ax_handle = axarr[real_index];
105
                    
106
                syncpr_visualizer.__show_pattern(ax_handle, syncpr_output_dynamic, image_height, image_width, iteration);
107
                
108
                if (double_indexer is True):
109
                    real_index = real_index[0], real_index[1] + 1;
110
                    if (real_index[1] >= number_cols):
111
                        real_index = real_index[0] + 1, 0; 
112
                else:
113
                    real_index += 1;
114
    
115
        plt.show();
116
    
117
    
118
    @staticmethod
119
    def animate_pattern_recognition(syncpr_output_dynamic, image_height, image_width, animation_velocity = 75, title = None, save_movie = None):
120
        """!
121
        @brief Shows animation of pattern recognition process that has been preformed by the oscillatory network.
122
        
123
        @param[in] syncpr_output_dynamic (syncpr_dynamic): Output dynamic of a syncpr network.
124
        @param[in] image_height (uint): Height of the pattern (image_height * image_width should be equal to number of oscillators).
125
        @param[in] image_width (uint): Width of the pattern.
126
        @param[in] animation_velocity (uint): Interval between frames in milliseconds.
127
        @param[in] title (string): Title of the animation that is displayed on a figure if it is specified.
128
        @param[in] save_movie (string): If it is specified then animation will be stored to file that is specified in this parameter.
129
        
130
        """
131
        figure = plt.figure();
132
        
133
        def init_frame():
134
            return frame_generation(0);
135
        
136
        def frame_generation(index_dynamic):
137
            figure.clf();
138
            
139
            if (title is not None):
140
                figure.suptitle(title, fontsize = 26, fontweight = 'bold')
141
            
142
            ax1 = figure.add_subplot(121, projection='polar');
143
            ax2 = figure.add_subplot(122);
144
            
145
            dynamic = syncpr_output_dynamic.output[index_dynamic];
146
            
147
            artist1, = ax1.plot(dynamic, [1.0] * len(dynamic), marker = 'o', color = 'blue', ls = '');
148
            artist2 = syncpr_visualizer.__show_pattern(ax2, syncpr_output_dynamic, image_height, image_width, index_dynamic);
149
            
150
            return [ artist1, artist2 ];
151
        
152
        cluster_animation = animation.FuncAnimation(figure, frame_generation, len(syncpr_output_dynamic), interval = animation_velocity, init_func = init_frame, repeat_delay = 5000);
153
154
        if (save_movie is not None):
155
#             plt.rcParams['animation.ffmpeg_path'] = 'C:\\Users\\annoviko\\programs\\ffmpeg-win64-static\\bin\\ffmpeg.exe';
156
#             ffmpeg_writer = animation.FFMpegWriter();
157
#             cluster_animation.save(save_movie, writer = ffmpeg_writer, fps = 15);
158
            cluster_animation.save(save_movie, writer = 'ffmpeg', fps = 15, bitrate = 1500);
159
        else:
160
            plt.show();
161
    
162
    
163
    @staticmethod
164
    def __show_pattern(ax_handle, syncpr_output_dynamic, image_height, image_width, iteration):
165
        """!
166
        @brief Draws pattern on specified ax.
167
        
168
        @param[in] ax_handle (Axis): Axis where pattern should be drawn.
169
        @param[in] syncpr_output_dynamic (syncpr_dynamic): Output dynamic of a syncpr network.
170
        @param[in] image_height (uint): Height of the pattern (image_height * image_width should be equal to number of oscillators).
171
        @param[in] image_width (uint): Width of the pattern.
172
        @param[in] iteration (uint): Simulation iteration that should be used for extracting pattern.
173
        
174
        @return (matplotlib.artist) Artist (pattern) that is rendered in the canvas.
175
        
176
        """
177
        
178
        current_dynamic = syncpr_output_dynamic.output[iteration];
179
        stage_picture = [(255, 255, 255)] * (image_height * image_width);
180
        for index_phase in range(len(current_dynamic)):
181
            phase = current_dynamic[index_phase];
182
            
183
            pixel_color = math.floor( phase * (255 / (2 * math.pi)) );
184
            stage_picture[index_phase] = (pixel_color, pixel_color, pixel_color);
185
          
186
        stage = numpy.array(stage_picture, numpy.uint8);
187
        stage = numpy.reshape(stage, (image_height, image_width) + ((3),)); # ((3),) it's size of RGB - third dimension.
188
        
189
        image_cluster = Image.fromarray(stage);
190
        
191
        artist = ax_handle.imshow(image_cluster, interpolation = 'none');
192
        plt.setp(ax_handle, visible = True);
193
        
194
        ax_handle.xaxis.set_ticklabels([]);
195
        ax_handle.yaxis.set_ticklabels([]);
196
        ax_handle.xaxis.set_ticks_position('none');
197
        ax_handle.yaxis.set_ticks_position('none');
198
        
199
        return artist;
200
201
202
class syncpr(sync_network):
203
    """!
204
    @brief Model of phase oscillatory network for pattern recognition that is based on the Kuramoto model.
205
    @details The model uses second-order and third-order modes of the Fourier components.
206
    
207
    Example:
208
    @code
209
    # Network size should be equal to size of pattern for learning.
210
    net = syncpr(size_network, 0.3, 0.3);
211
    
212
    # Train network using list of patterns (input images).
213
    net.train(image_samples);
214
    
215
    # Recognize image using 10 steps during 10 seconds of simulation.
216
    sync_output_dynamic = net.simulate(10, 10, pattern, solve_type.RK4, True);
217
    
218
    # Display output dynamic.
219
    syncpr_visualizer.show_output_dynamic(sync_output_dynamic);
220
    
221
    # Display evolution of recognition of the pattern.
222
    syncpr_visualizer.show_pattern(sync_output_dynamic, image_height, image_width);
223
    
224
    @endcode
225
    
226
    """
227
228
    def __init__(self, num_osc, increase_strength1, increase_strength2, ccore = False):
229
        """!
230
        @brief Constructor of oscillatory network for pattern recognition based on Kuramoto model.
231
        
232
        @param[in] num_osc (uint): Number of oscillators in the network.
233
        @param[in] increase_strength1 (double): Parameter for increasing strength of the second term of the Fourier component.
234
        @param[in] increase_strength2 (double): Parameter for increasing strength of the third term of the Fourier component.
235
        @param[in] ccore (bool): If True simulation is performed by CCORE library (C++ implementation of pyclustering).
236
        
237
        """
238
        
239
        if (ccore is True):
240
            self._ccore_network_pointer = wrapper.syncpr_create(num_osc, increase_strength1, increase_strength2);
241
            
242
        else:
243
            self._increase_strength1 = increase_strength1;
244
            self._increase_strength2 = increase_strength2;
245
            self._coupling = [ [0.0 for i in range(num_osc)] for j in range(num_osc) ];
246
        
247
            super().__init__(num_osc, 1, 0, conn_type.ALL_TO_ALL, initial_type.RANDOM_GAUSSIAN);
248
    
249
    
250
    def __del__(self):
251
        """!
252
        @brief Default destructor of syncpr.
253
        
254
        """
255
        
256
        if (self._ccore_network_pointer is not None):
257
            wrapper.syncpr_destroy(self._ccore_network_pointer);
258
            self._ccore_network_pointer = None;
259
260
261
    def __len__(self):
262
        """!
263
        @brief Returns size of the network.
264
        
265
        """        
266
        if (self._ccore_network_pointer is not None):
267
            return wrapper.syncpr_get_size(self._ccore_network_pointer);
268
        
269
        else:
270
            return self._num_osc;
271
    
272
    
273
    def train(self, samples):
274
        """!
275
        @brief Trains syncpr network using Hebbian rule for adjusting strength of connections between oscillators during training.
276
        
277
        @param[in] samples (list): list of patterns where each pattern is represented by list of features that are equal to [-1; 1].
278
        
279
        """
280
        
281
        # Verify pattern for learning
282
        for pattern in samples:
283
            self.__validate_pattern(pattern);
284
        
285
        if (self._ccore_network_pointer is not None):
286
            return wrapper.syncpr_train(self._ccore_network_pointer, samples);
287
        
288
        length = len(self);
289
        number_samples = len(samples);
290
        
291
        for i in range(length):
292
            for j in range(i + 1, len(self), 1):
293
                
294
                # go through via all patterns
295
                for p in range(number_samples):
296
                    value1 = samples[p][i];
297
                    value2 = samples[p][j];
298
                    
299
                    self._coupling[i][j] += value1 * value2;
300
                
301
                self._coupling[i][j] /= length;
302
                self._coupling[j][i] = self._coupling[i][j];
303
    
304
    
305
    def simulate(self, steps, time, pattern, solution = solve_type.RK4, collect_dynamic = True):
0 ignored issues
show
Bug introduced by
Arguments number differs from overridden 'simulate' method
Loading history...
306
        """!
307
        @brief Performs static simulation of syncpr oscillatory network.
308
        @details In other words network performs pattern recognition during simulation.
309
        
310
        @param[in] steps (uint): Number steps of simulations during simulation.
311
        @param[in] time (double): Time of simulation.
312
        @param[in] pattern (list): Pattern for recognition represented by list of features that are equal to [-1; 1].
313
        @param[in] solution (solve_type): Type of solver that should be used for simulation.
314
        @param[in] collect_dynamic (bool): If True - returns whole dynamic of oscillatory network, otherwise returns only last values of dynamics.
315
        
316
        @return (list) Dynamic of oscillatory network. If argument 'collect_dynamic' = True, than return dynamic for the whole simulation time,
317
                otherwise returns only last values (last step of simulation) of dynamic.
318
        
319
        @see simulate_dynamic()
320
        @see simulate_static()
321
        
322
        """
323
                    
324
        return self.simulate_static(steps, time, pattern, solution, collect_dynamic);
325
    
326
    
327
    def simulate_dynamic(self, pattern, order = 0.998, solution = solve_type.RK4, collect_dynamic = False, step = 0.1, int_step = 0.01, threshold_changes = 0.0000001):
0 ignored issues
show
Bug introduced by
Arguments number differs from overridden 'simulate_dynamic' method
Loading history...
328
        """!
329
        @brief Performs dynamic simulation of the network until stop condition is not reached.
330
        @details In other words network performs pattern recognition during simulation. 
331
                 Stop condition is defined by input argument 'order' that represents memory order, but
332
                 process of simulation can be stopped if convergance rate is low whose threshold is defined
333
                 by the argument 'threshold_changes'.
334
        
335
        @param[in] pattern (list): Pattern for recognition represented by list of features that are equal to [-1; 1].
336
        @param[in] order (double): Order of process synchronization, distributed 0..1.
337
        @param[in] solution (solve_type): Type of solution.
338
        @param[in] collect_dynamic (bool): If True - returns whole dynamic of oscillatory network, otherwise returns only last values of dynamics.
339
        @param[in] step (double): Time step of one iteration of simulation.
340
        @param[in] int_step (double): Integration step, should be less than step.
341
        @param[in] threshold_changes (double): Additional stop condition that helps prevent infinite simulation, defines limit of changes of oscillators between current and previous steps.
342
        
343
        @return (list) Dynamic of oscillatory network. If argument 'collect_dynamic' = True, than return dynamic for the whole simulation time,
344
                otherwise returns only last values (last step of simulation) of dynamic.
345
        
346
        @see simulate()
347
        @see simulate_static()
348
        
349
        """
350
        
351
        self.__validate_pattern(pattern);
352
        
353
        if (self._ccore_network_pointer is not None):
354
            ccore_instance_dynamic = wrapper.syncpr_simulate_dynamic(self._ccore_network_pointer, pattern, order, solution, collect_dynamic, step);
355
            return syncpr_dynamic(None, None, ccore_instance_dynamic);
356
        
357
        for i in range(0, len(pattern), 1):
358
            if (pattern[i] > 0.0):
359
                self._phases[i] = 0.0;
360
            else:
361
                self._phases[i] = math.pi / 2.0;
362
        
363
        # For statistics and integration
364
        time_counter = 0;
365
        
366
        # Prevent infinite loop. It's possible when required state cannot be reached.
367
        previous_order = 0;
368
        current_order = self.__calculate_memory_order(pattern);
369
        
370
        # If requested input dynamics
371
        dyn_phase = [];
372
        dyn_time = [];
373
        if (collect_dynamic == True):
374
            dyn_phase.append(self._phases);
375
            dyn_time.append(0);
376
        
377
        # Execute until sync state will be reached
378
        while (current_order < order):
379
            # update states of oscillators
380
            self._phases = self._calculate_phases(solution, time_counter, step, int_step);
381
            
382
            # update time
383
            time_counter += step;
384
            
385
            # if requested input dynamic
386
            if (collect_dynamic == True):
387
                dyn_phase.append(self._phases);
388
                dyn_time.append(time_counter);
389
                
390
            # update orders
391
            previous_order = current_order;
392
            current_order = self.__calculate_memory_order(pattern);
393
            
394
            # hang prevention
395
            if (abs(current_order - previous_order) < threshold_changes):
396
                break;
397
        
398
        if (collect_dynamic != True):
399
            dyn_phase.append(self._phases);
400
            dyn_time.append(time_counter);
401
        
402
        output_sync_dynamic = syncpr_dynamic(dyn_phase, dyn_time, None);
403
        return output_sync_dynamic;
404
405
406
    def simulate_static(self, steps, time, pattern, solution = solve_type.FAST, collect_dynamic = False):
0 ignored issues
show
Bug introduced by
Arguments number differs from overridden 'simulate_static' method
Loading history...
407
        """!
408
        @brief Performs static simulation of syncpr oscillatory network.
409
        @details In other words network performs pattern recognition during simulation.
410
        
411
        @param[in] steps (uint): Number steps of simulations during simulation.
412
        @param[in] time (double): Time of simulation.
413
        @param[in] pattern (list): Pattern for recognition represented by list of features that are equal to [-1; 1].
414
        @param[in] solution (solve_type): Type of solution.
415
        @param[in] collect_dynamic (bool): If True - returns whole dynamic of oscillatory network, otherwise returns only last values of dynamics.
416
        
417
        @return (list) Dynamic of oscillatory network. If argument 'collect_dynamic' = True, than return dynamic for the whole simulation time,
418
                otherwise returns only last values (last step of simulation) of dynamic.
419
        
420
        @see simulate()
421
        @see simulate_dynamic()
422
        
423
        """
424
        
425
        self.__validate_pattern(pattern);
426
        
427
        if (self._ccore_network_pointer is not None):
428
            ccore_instance_dynamic = wrapper.syncpr_simulate_static(self._ccore_network_pointer, steps, time, pattern, solution, collect_dynamic);
429
            return syncpr_dynamic(None, None, ccore_instance_dynamic);
430
        
431
        for i in range(0, len(pattern), 1):
432
            if (pattern[i] > 0.0):
433
                self._phases[i] = 0.0;
434
            else:
435
                self._phases[i] = math.pi / 2.0;
436
                
437
        return super().simulate_static(steps, time, solution, collect_dynamic);
438
    
439
    
440
    def memory_order(self, pattern):
441
        """!
442
        @brief Calculates function of the memorized pattern.
443
        @details Throws exception if length of pattern is not equal to size of the network or if it consists feature with value that are not equal to [-1; 1].
444
        
445
        @param[in] pattern (list): Pattern for recognition represented by list of features that are equal to [-1; 1].
446
        
447
        @return (double) Order of memory for the specified pattern.
448
        
449
        """
450
        
451
        self.__validate_pattern(pattern);
452
        
453
        if (self._ccore_network_pointer is not None):
454
            return wrapper.syncpr_memory_order(self._ccore_network_pointer, pattern);
455
        
456
        else:
457
            return self.__calculate_memory_order(pattern);
458
459
    
460
    def __calculate_memory_order(self, pattern):
461
        """!
462
        @brief Calculates function of the memorized pattern without any pattern validation.
463
        
464
        @param[in] pattern (list): Pattern for recognition represented by list of features that are equal to [-1; 1].
465
        
466
        @return (double) Order of memory for the specified pattern.
467
                
468
        """
469
        
470
        memory_order = 0.0;
471
        for index in range(len(self)):
472
            memory_order += pattern[index] * cmath.exp( 1j * self._phases[index] );
473
        
474
        memory_order /= len(self);
475
        return abs(memory_order);
476
        
477
    
478
    def _phase_kuramoto(self, teta, t, argv):
479
        """!
480
        @brief Returns result of phase calculation for specified oscillator in the network.
481
        
482
        @param[in] teta (double): Phase of the oscillator that is differentiated.
483
        @param[in] t (double): Current time of simulation.
484
        @param[in] argv (tuple): Index of the oscillator in the list.
485
        
486
        @return (double) New phase for specified oscillator (don't assign it here).
487
        
488
        """
489
        
490
        index = argv;
491
        
492
        phase = 0.0;
493
        term = 0.0;
494
        
495
        for k in range(0, self._num_osc):
496
            if (k != index):
497
                phase_delta = self._phases[k] - teta;
498
                
499
                phase += self._coupling[index][k] * math.sin(phase_delta);
500
                
501
                term1 = self._increase_strength1 * math.sin(2.0 * phase_delta);
502
                term2 = self._increase_strength2 * math.sin(3.0 * phase_delta);
503
                
504
                term += (term1 - term2);
505
                
506
        return ( phase + term / len(self) );
507
    
508
    
509
    def __validate_pattern(self, pattern):
510
        """!
511
        @brief Validates pattern.
512
        @details Throws exception if length of pattern is not equal to size of the network or if it consists feature with value that are not equal to [-1; 1].
513
        
514
        @param[in] pattern (list): Pattern for recognition represented by list of features that are equal to [-1; 1].
515
        
516
        """
517
        if (len(pattern) != len(self)):
518
            raise NameError('syncpr: length of the pattern (' + len(pattern) + ') should be equal to size of the network');
519
        
520
        for feature in pattern:
521
            if ( (feature != -1.0) and (feature != 1.0) ):
522
                raise NameError('syncpr: patten feature (' + feature + ') should be distributed in [-1; 1]');