Completed
Push — master ( 9cffad...7a46cc )
by Andrei
01:25
created

get_argument()   A

Complexity

Conditions 2

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
dl 0
loc 15
rs 9.4285
c 0
b 0
f 0
1
"""!
2
3
@brief Utils that are used by modules of pyclustering.
4
5
@authors Andrei Novikov ([email protected])
6
@date 2014-2018
7
@copyright GNU Public License
8
9
@cond GNU_PUBLIC_LICENSE
10
    PyClustering is free software: you can redistribute it and/or modify
11
    it under the terms of the GNU General Public License as published by
12
    the Free Software Foundation, either version 3 of the License, or
13
    (at your option) any later version.
14
    
15
    PyClustering is distributed in the hope that it will be useful,
16
    but WITHOUT ANY WARRANTY; without even the implied warranty of
17
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
    GNU General Public License for more details.
19
    
20
    You should have received a copy of the GNU General Public License
21
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
@endcond
23
24
"""
25
26
import time;
27
import numpy;
28
29
from PIL import Image;
30
from numpy import array;
31
32
import matplotlib.pyplot as plt;
33
from mpl_toolkits.mplot3d import Axes3D;
34
35
from sys import platform as _platform;
36
37
38
## The number \f$pi\f$ is a mathematical constant, the ratio of a circle's circumference to its diameter.
39
pi = 3.1415926535;
40
41
42
def read_sample(filename):
43
    """!
44
    @brief Returns data sample from simple text file.
45
    @details This function should be used for text file with following format:
46
    @code
47
    point_1_coord_1 point_1_coord_2 ... point_1_coord_n
48
    point_2_coord_1 point_2_coord_2 ... point_2_coord_n
49
    ... ...
50
    @endcode
51
    
52
    @param[in] filename (string): Path to file with data.
53
    
54
    @return (list) Points where each point represented by list of coordinates.
55
    
56
    """
57
    
58
    file = open(filename, 'r');
59
60
    sample = [[float(val) for val in line.split()] for line in file if len(line.strip()) > 0];
61
    
62
    file.close();
63
    return sample;
64
65
66
def calculate_distance_matrix(sample):
67
    """!
68
    @brief Calculates distance matrix for data sample (sequence of points) using Euclidean distance as a metric.
69
70
    @param[in] sample (array_like): Data points that are used for distance calculation.
71
72
    @return (list) Matrix distance between data points.
73
74
    """
75
76
    amount_rows = len(sample);
77
    return [ [ euclidean_distance(sample[i], sample[j]) for j in range(amount_rows) ] for i in range(amount_rows) ];
78
79
80
def read_image(filename):
81
    """!
82
    @brief Returns image as N-dimension (depends on the input image) matrix, where one element of list describes pixel.
83
    
84
    @param[in] filename (string): Path to image.
85
    
86
    @return (list) Pixels where each pixel described by list of RGB-values.
87
    
88
    """
89
    
90
    with Image.open(filename) as image_source:
91
        data = [pixel for pixel in image_source.getdata()];
92
        return data;
93
    
94
    return [];
95
96
97
def rgb2gray(image_rgb_array):
98
    """!
99
    @brief Returns image as 1-dimension (gray colored) matrix, where one element of list describes pixel.
100
    @details Luma coding is used for transformation and that is calculated directly from gamma-compressed primary intensities as a weighted sum:
101
    
102
    \f[Y = 0.2989R + 0.587G + 0.114B\f]
103
    
104
    @param[in] image_rgb_array (list): Image represented by RGB list.
105
    
106
    @return (list) Image as gray colored matrix, where one element of list describes pixel.
107
    
108
    @code
109
        colored_image = read_image(file_name);
110
        gray_image = rgb2gray(colored_image);
111
    @endcode
112
    
113
    @see read_image()
114
    
115
    """
116
    
117
    image_gray_array = [0.0] * len(image_rgb_array);
118
    for index in range(0, len(image_rgb_array), 1):
119
        image_gray_array[index] = float(image_rgb_array[index][0]) * 0.2989 + float(image_rgb_array[index][1]) * 0.5870 + float(image_rgb_array[index][2]) * 0.1140;
120
    
121
    return image_gray_array;
122
123
124
def stretch_pattern(image_source):
125
    """!
126
    @brief Returns stretched content as 1-dimension (gray colored) matrix with size of input image.
127
    
128
    @param[in] image_source (Image): PIL Image instance.
129
    
130
    @return (list, Image) Stretched image as gray colored matrix and source image.
131
    
132
    """
133
    wsize, hsize = image_source.size;
134
    
135
    # Crop digit exactly
136
    (ws, hs, we, he) = gray_pattern_borders(image_source);
137
    image_source = image_source.crop((ws, hs, we, he));
138
    
139
    # Stretch it to initial sizes
140
    image_source = image_source.resize((wsize, hsize), Image.ANTIALIAS);
141
    
142
    # Transform image to simple array
143
    data = [pixel for pixel in image_source.getdata()];
144
    image_pattern = rgb2gray(data);
145
    
146
    return (image_pattern, image_source);
147
148
149
def gray_pattern_borders(image):
150
    """!
151
    @brief Returns coordinates of gray image content on the input image.
152
    
153
    @param[in] image (Image): PIL Image instance that is processed.
154
    
155
    @return (tuple) Returns coordinates of gray image content as (width_start, height_start, width_end, height_end).
156
    
157
    """
158
    
159
    width, height = image.size;
160
    
161
    width_start = width;
162
    width_end = 0;
163
    height_start = height;
164
    height_end = 0;
165
    
166
    row, col = 0, 0;
167
    for pixel in image.getdata():
168
        value = float(pixel[0]) * 0.2989 + float(pixel[1]) * 0.5870 + float(pixel[2]) * 0.1140;
169
        
170
        if (value < 128):
171
            if (width_end < col): 
172
                width_end = col;
173
            
174
            if (height_end < row):
175
                height_end = row;
176
        
177
            if (width_start > col):
178
                width_start = col;
179
            
180
            if (height_start > row):
181
                height_start = row;
182
        
183
        col += 1;
184
        if (col >= width):
185
            col = 0;
186
            row += 1;
187
188
    return (width_start, height_start, width_end + 1, height_end + 1);
189
190
191
def average_neighbor_distance(points, num_neigh):
192
    """!
193
    @brief Returns average distance for establish links between specified number of nearest neighbors.
194
    
195
    @param[in] points (list): Input data, list of points where each point represented by list.
196
    @param[in] num_neigh (uint): Number of neighbors that should be used for distance calculation.
197
    
198
    @return (double) Average distance for establish links between 'num_neigh' in data set 'points'.
199
    
200
    """
201
    
202
    if (num_neigh > len(points) - 1):
203
        raise NameError('Impossible to calculate average distance to neighbors when number of object is less than number of neighbors.');
204
    
205
    dist_matrix = [ [ 0.0 for i in range(len(points)) ] for j in range(len(points)) ];
206
    for i in range(0, len(points), 1):
207
        for j in range(i + 1, len(points), 1):
208
            distance = euclidean_distance(points[i], points[j]);
209
            dist_matrix[i][j] = distance;
210
            dist_matrix[j][i] = distance;
211
            
212
        dist_matrix[i] = sorted(dist_matrix[i]);
213
214
    total_distance = 0;
215
    for i in range(0, len(points), 1):
216
        # start from 0 - first element is distance to itself.
217
        for j in range(0, num_neigh, 1):
218
            total_distance += dist_matrix[i][j + 1];
219
            
220
    return ( total_distance / (num_neigh * len(points)) );
221
222
223
def centroid(points, indexes = None):
224
    """!
225
    @brief Calculate centroid of input set of points. 
226
    
227
    @param[in] points (list): Set of points for centroid calculation.
228
    @param[in] indexes (list): Indexes of objects in input set of points that will be taken into account during centroid calculation.
229
    
230
    @return (list) centroid on the set of points where each element of list is corresponding to value in its dimension.
231
    
232
    """
233
    
234
    dimension = len(points[0]);
235
    centroid_value = [0.0] * dimension;
236
    
237
    range_points = None;
238
    if (indexes is None):
239
        range_points = range(len(points));
240
    else:
241
        range_points = indexes;
242
    
243
    for index_point in range_points:
244
        centroid_value = list_math_addition(centroid_value, points[index_point]);
245
    
246
    centroid_value = list_math_division_number(centroid_value, len(range_points));
247
    return centroid_value;
248
249
250
def median(points, indexes = None):
251
    """!
252
    @brief Calculate geometric median of input set of points using Euclidian distance. 
253
    
254
    @param[in] points (list): Set of points for median calculation.
255
    @param[in] indexes (list): Indexes of objects in input set of points that will be taken into account during median calculation.
256
    
257
    @return (uint) index of point in input set that corresponds to median.
258
    
259
    """
260
    
261
    index_median = None;
262
    distance = float('Inf');
263
    
264
    range_points = None;
265
    if (indexes is None):
266
        range_points = range(len(points));
267
    else:
268
        range_points = indexes;
269
    
270
    for index_candidate in range_points:
271
        distance_candidate = 0.0;
272
        for index in range_points:
273
            distance_candidate += euclidean_distance_square(points[index_candidate], points[index]);
274
        
275
        if (distance_candidate < distance):
276
            distance = distance_candidate;
277
            index_median = index_candidate;
278
    
279
    return index_median;
280
281
282
def euclidean_distance(a, b):
283
    """!
0 ignored issues
show
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...
284
    @brief Calculate Euclidean distance between vector a and b. 
285
    @details The Euclidean between vectors (points) a and b is calculated by following formula:
286
    
287
    \f[
288
    dist(a, b) = \sqrt{ \sum_{i=0}^{N}(b_{i} - a_{i})^{2}) };
289
    \f]
290
    
291
    Where N is a length of each vector.
292
    
293
    @param[in] a (list): The first vector.
294
    @param[in] b (list): The second vector.
295
    
296
    @return (double) Euclidian distance between two vectors.
297
    
298
    @note This function for calculation is faster then standard function in ~100 times!
299
    
300
    """
301
    
302
    distance = euclidean_distance_square(a, b);
303
    return distance**(0.5);
304
305
306
def euclidean_distance_square(a, b):
307
    """!
308
    @brief Calculate square Euclidian distance between vector a and b.
309
    
310
    @param[in] a (list): The first vector.
311
    @param[in] b (list): The second vector.
312
    
313
    @return (double) Square Euclidian distance between two vectors.
314
    
315
    """  
316
    
317
    if ( ((type(a) == float) and (type(b) == float)) or ((type(a) == int) and (type(b) == int)) ):
318
        return (a - b)**2.0;
319
    
320
    distance = 0.0;
321
    for i in range(0, len(a)):
322
        distance += (a[i] - b[i])**2.0;
323
        
324
    return distance;
325
326
327
def manhattan_distance(a, b):
328
    """!
329
    @brief Calculate Manhattan distance between vector a and b.
330
    
331
    @param[in] a (list): The first cluster.
332
    @param[in] b (list): The second cluster.
333
    
334
    @return (double) Manhattan distance between two vectors.
335
    
336
    """
337
    
338
    if ( ((type(a) == float) and (type(b) == float)) or ((type(a) == int) and (type(b) == int)) ):
339
        return abs(a - b);
340
    
341
    distance = 0.0;
342
    dimension = len(a);
343
    
344
    for i in range(0, dimension):
345
        distance += abs(a[i] - b[i]);
346
    
347
    return distance;
348
349
350
def average_inter_cluster_distance(cluster1, cluster2, data = None):
351
    """!
352
    @brief Calculates average inter-cluster distance between two clusters.
353
    @details Clusters can be represented by list of coordinates (in this case data shouldn't be specified),
354
             or by list of indexes of points from the data (represented by list of points), in this case 
355
             data should be specified.
356
             
357
    @param[in] cluster1 (list): The first cluster where each element can represent index from the data or object itself.
358
    @param[in] cluster2 (list): The second cluster where each element can represent index from the data or object itself.
359
    @param[in] data (list): If specified than elements of clusters will be used as indexes,
360
               otherwise elements of cluster will be considered as points.
361
    
362
    @return (double) Average inter-cluster distance between two clusters.
363
    
364
    """
365
    
366
    distance = 0.0;
367
    
368
    if (data is None):
369
        for i in range(len(cluster1)):
370
            for j in range(len(cluster2)):
371
                distance += euclidean_distance_square(cluster1[i], cluster2[j]);
372
    else:
373
        for i in range(len(cluster1)):
374
            for j in range(len(cluster2)):
375
                distance += euclidean_distance_square(data[ cluster1[i]], data[ cluster2[j]]);
376
    
377
    distance /= float(len(cluster1) * len(cluster2));
378
    return distance ** 0.5;
379
380
381
def average_intra_cluster_distance(cluster1, cluster2, data = None):
382
    """!
383
    @brief Calculates average intra-cluster distance between two clusters.
384
    @details Clusters can be represented by list of coordinates (in this case data shouldn't be specified),
385
             or by list of indexes of points from the data (represented by list of points), in this case 
386
             data should be specified.
387
    
388
    @param[in] cluster1 (list): The first cluster.
389
    @param[in] cluster2 (list): The second cluster.
390
    @param[in] data (list): If specified than elements of clusters will be used as indexes,
391
               otherwise elements of cluster will be considered as points.
392
    
393
    @return (double) Average intra-cluster distance between two clusters.
394
    
395
    """
396
        
397
    distance = 0.0;
398
    
399
    for i in range(len(cluster1) + len(cluster2)):
400
        for j in range(len(cluster1) + len(cluster2)):
401
            first_point = None;
402
            second_point = None;
403
            
404
            if (data is None):
405
                # the first point
406
                if (i < len(cluster1)): first_point = cluster1[i];
407
                else: first_point = cluster2[i - len(cluster1)];
408
                
409
                # the second point
410
                if (j < len(cluster1)): second_point = cluster1[j];
411
                else: second_point = cluster2[j - len(cluster1)];
412
                
413
            else:
414
                # the first point
415
                if (i < len(cluster1)): first_point = data[ cluster1[i] ];
416
                else: first_point = data[ cluster2[i - len(cluster1)] ];
417
            
418
                if (j < len(cluster1)): second_point = data[ cluster1[j] ];
419
                else: second_point = data[ cluster2[j - len(cluster1)] ];    
420
            
421
422
            
423
            distance += euclidean_distance_square(first_point, second_point);
424
    
425
    distance /= float( (len(cluster1) + len(cluster2)) * (len(cluster1) + len(cluster2) - 1.0) );
426
    return distance ** 0.5;
427
428
429
def variance_increase_distance(cluster1, cluster2, data = None):
430
    """!
431
    @brief Calculates variance increase distance between two clusters.
432
    @details Clusters can be represented by list of coordinates (in this case data shouldn't be specified),
433
             or by list of indexes of points from the data (represented by list of points), in this case 
434
             data should be specified.
435
    
436
    @param[in] cluster1 (list): The first cluster.
437
    @param[in] cluster2 (list): The second cluster.
438
    @param[in] data (list): If specified than elements of clusters will be used as indexes,
439
               otherwise elements of cluster will be considered as points.
440
    
441
    @return (double) Average variance increase distance between two clusters.
442
    
443
    """
444
    
445
    # calculate local sum
446
    member_cluster1 = None;
447
    member_cluster2 = None;
448
    
449
    if (data is None):
450
        member_cluster1 = [0.0] * len(cluster1[0]);
451
        member_cluster2 = [0.0] * len(cluster2[0]);
452
        
453
    else:
454
        member_cluster1 = [0.0] * len(data[0]);
455
        member_cluster2 = [0.0] * len(data[0]);
456
    
457
    for i in range(len(cluster1)):
458
        if (data is None):
459
            member_cluster1 = list_math_addition(member_cluster1, cluster1[i]);
460
        else:
461
            member_cluster1 = list_math_addition(member_cluster1, data[ cluster1[i] ]);
462
    
463
    
464
    for j in range(len(cluster2)):
465
        if (data is None):
466
            member_cluster2 = list_math_addition(member_cluster2, cluster2[j]);
467
        else:
468
            member_cluster2 = list_math_addition(member_cluster2, data[ cluster2[j] ]);
469
    
470
    member_cluster_general = list_math_addition(member_cluster1, member_cluster2);
471
    member_cluster_general = list_math_division_number(member_cluster_general, len(cluster1) + len(cluster2));
472
    
473
    member_cluster1 = list_math_division_number(member_cluster1, len(cluster1));
474
    member_cluster2 = list_math_division_number(member_cluster2, len(cluster2));
475
    
476
    # calculate global sum
477
    distance_general = 0.0;
478
    distance_cluster1 = 0.0;
479
    distance_cluster2 = 0.0;
480
    
481
    for i in range(len(cluster1)):
482
        if (data is None):
483
            distance_cluster1 += euclidean_distance_square(cluster1[i], member_cluster1);
484
            distance_general += euclidean_distance_square(cluster1[i], member_cluster_general);
485
            
486
        else:
487
            distance_cluster1 += euclidean_distance_square(data[ cluster1[i]], member_cluster1);
488
            distance_general += euclidean_distance_square(data[ cluster1[i]], member_cluster_general);
489
    
490
    for j in range(len(cluster2)):
491
        if (data is None):
492
            distance_cluster2 += euclidean_distance_square(cluster2[j], member_cluster2);
493
            distance_general += euclidean_distance_square(cluster2[j], member_cluster_general);
494
            
495
        else:
496
            distance_cluster2 += euclidean_distance_square(data[ cluster2[j]], member_cluster2);
497
            distance_general += euclidean_distance_square(data[ cluster2[j]], member_cluster_general);
498
    
499
    return distance_general - distance_cluster1 - distance_cluster2;
500
501
502
def calculate_ellipse_description(covariance, scale = 2.0):
503
    """!
504
    @brief Calculates description of ellipse using covariance matrix.
505
    
506
    @param[in] covariance (numpy.array): Covariance matrix for which ellipse area should be calculated.
507
    @param[in] scale (float): Scale of the ellipse.
508
    
509
    @return (float, float, float) Return ellipse description: angle, width, height.
510
    
511
    """
512
    
513
    eigh_values, eigh_vectors = numpy.linalg.eigh(covariance);
514
    order = eigh_values.argsort()[::-1];
515
    
516
    values, vectors = eigh_values[order], eigh_vectors[order];
517
    angle = numpy.degrees(numpy.arctan2(*vectors[:,0][::-1]));
518
519
    if (0.0 in values):
520
        return 0, 0, 0;
521
522
    width, height = 2.0 * scale * numpy.sqrt(values);
523
    return angle, width, height;
524
525
526
def data_corners(data, data_filter = None):
527
    """!
528
    @brief Finds maximum and minimum corner in each dimension of the specified data.
529
    
530
    @param[in] data (list): List of points that should be analysed.
531
    @param[in] data_filter (list): List of indexes of the data that should be analysed,
532
                if it is 'None' then whole 'data' is analysed to obtain corners.
533
    
534
    @return (list) Tuple of two points that corresponds to minimum and maximum corner (min_corner, max_corner).
535
    
536
    """
537
    
538
    dimensions = len(data[0]);
539
    
540
    bypass = data_filter;
541
    if (bypass is None):
542
        bypass = range(len(data));
543
    
544
    maximum_corner = data[bypass[0]][:];
545
    minimum_corner = data[bypass[0]][:];
546
    
547
    for index_point in bypass:
548
        for index_dimension in range(dimensions):
549
            if (data[index_point][index_dimension] > maximum_corner[index_dimension]):
550
                maximum_corner[index_dimension] = data[index_point][index_dimension];
551
            
552
            if (data[index_point][index_dimension] < minimum_corner[index_dimension]):
553
                minimum_corner[index_dimension] = data[index_point][index_dimension];
554
    
555
    return (minimum_corner, maximum_corner);
556
557
558
def norm_vector(vector):
559
    """!
560
    @brief Calculates norm of an input vector that is known as a vector length.
561
    
562
    @param[in] vector (list): The input vector whose length is calculated.
563
    
564
    @return (double) vector norm known as vector length.
565
    
566
    """
567
    
568
    length = 0.0;
569
    for component in vector:
570
        length += component * component;
571
    
572
    length = length ** 0.5;
573
    
574
    return length;
575
576
577
def unit_vector(vector):
578
    """!
579
    @brief Calculates unit vector.
580
    @details Unit vector calculates of an input vector involves two steps. 
581
              The first, calculate vector length. The second,
582
              divide each vector component by the obtained length.
583
    
584
    @param[in] vector (list): The input vector that is used for unit vector calculation.
585
    
586
    """
587
    
588
    length = norm_vector(vector);
589
    unit_vector_instance = [];
590
    
591
    for component in vector:
592
        unit_vector_instance.append(component / length);
593
    
594
    return unit_vector_instance;
595
596
597
def heaviside(value):
598
    """!
599
    @brief Calculates Heaviside function that represents step function.
600
    @details If input value is greater than 0 then returns 1, otherwise returns 0.
601
    
602
    @param[in] value (double): Argument of Heaviside function.
603
    
604
    @return (double) Value of Heaviside function.
605
    
606
    """
607
    if (value > 0.0): 
608
        return 1.0;
609
    
610
    return 0.0;
611
612
613
def timedcall(executable_function, *args):
614
    """!
615
    @brief Executes specified method or function with measuring of execution time.
616
    
617
    @param[in] executable_function (pointer): Pointer to function or method.
618
    @param[in] args (*): Arguments of called function or method.
619
    
620
    @return (tuple) Execution time and result of execution of function or method (execution_time, result_execution).
621
    
622
    """
623
    
624
    time_start = time.clock();
625
    result = executable_function(*args);
626
    time_end = time.clock();
627
    
628
    return (time_end - time_start, result);
629
630
631
def get_argument(argument_name, default_value, **kwargs):
632
    """!
633
    @brief Extract argument value without exception using default value in case of lack argument with specified name.
634
635
    @param[in] argument_name (string): Argument name (key in **kwargs) whose value is required.
636
    @param[in] default_value (any): Value that is returned if argument is not found in **kwargs.
637
    @param[in] **kwargs: Arbitrary keyword arguments.
638
639
    @return (any) Extracted argument if argument is contained by **kwargs, otherwise default value.
640
641
    """
642
    if (argument_name in kwargs):
643
        return kwargs[argument_name];
644
645
    return default_value;
646
647
648
def extract_number_oscillations(osc_dyn, index = 0, amplitude_threshold = 1.0):
649
    """!
650
    @brief Extracts number of oscillations of specified oscillator.
651
    
652
    @param[in] osc_dyn (list): Dynamic of oscillators.
653
    @param[in] index (uint): Index of oscillator in dynamic.
654
    @param[in] amplitude_threshold (double): Amplitude threshold when oscillation is taken into account, for example,
655
                when oscillator amplitude is greater than threshold then oscillation is incremented.
656
    
657
    @return (uint) Number of oscillations of specified oscillator.
658
    
659
    """
660
    
661
    number_oscillations = 0;
662
    waiting_differential = False;
663
    threshold_passed = False;
664
    high_level_trigger = True if (osc_dyn[0][index] > amplitude_threshold) else False;
665
    
666
    for values in osc_dyn:
667
        if ( (values[index] >= amplitude_threshold) and (high_level_trigger is False) ):
668
            high_level_trigger = True;
669
            threshold_passed = True;
670
        
671
        elif ( (values[index] < amplitude_threshold) and (high_level_trigger is True) ):
672
            high_level_trigger = False;
673
            threshold_passed = True;
674
        
675
        if (threshold_passed is True):
676
            threshold_passed = False;
677
            if (waiting_differential is True and high_level_trigger is False):
678
                number_oscillations += 1;
679
                waiting_differential = False;
680
681
            else:
682
                waiting_differential = True;
683
        
684
    return number_oscillations;
685
686
687
def allocate_sync_ensembles(dynamic, tolerance = 0.1, threshold = 1.0, ignore = None):
688
    """!
689
    @brief Allocate clusters in line with ensembles of synchronous oscillators where each
690
           synchronous ensemble corresponds to only one cluster.
691
    
692
    @param[in] dynamic (dynamic): Dynamic of each oscillator.
693
    @param[in] tolerance (double): Maximum error for allocation of synchronous ensemble oscillators.
694
    @param[in] threshold (double): Amlitude trigger when spike is taken into account.
695
    @param[in] ignore (bool): Set of indexes that shouldn't be taken into account.
696
    
697
    @return (list) Grours (lists) of indexes of synchronous oscillators, for example, 
698
            [ [index_osc1, index_osc3], [index_osc2], [index_osc4, index_osc5] ].
699
            
700
    """
701
    
702
    descriptors = [ [] for _ in range(len(dynamic[0])) ];
703
    
704
    # Check from the end for obtaining result
705
    for index_dyn in range(0, len(dynamic[0]), 1):
706
        if ((ignore is not None) and (index_dyn in ignore)):
707
            continue;
708
        
709
        time_stop_simulation = len(dynamic) - 1;
710
        active_state = False;
711
        
712
        if (dynamic[time_stop_simulation][index_dyn] > threshold):
713
            active_state = True;
714
            
715
        # if active state is detected, it means we don't have whole oscillatory period for the considered oscillator, should be skipped.
716
        if (active_state is True):
717
            while ( (dynamic[time_stop_simulation][index_dyn] > threshold) and (time_stop_simulation > 0) ):
718
                time_stop_simulation -= 1;
719
            
720
            # if there are no any oscillation than let's consider it like noise
721
            if (time_stop_simulation == 0):
722
                continue;
723
            
724
            # reset
725
            active_state = False;
726
        
727
        desc = [0, 0, 0]; # end, start, average time of oscillation
728
        for t in range(time_stop_simulation, 0, -1):
729
            if ( (dynamic[t][index_dyn] > threshold) and (active_state is False) ):
730
                desc[0] = t;
731
                active_state = True;
732
            elif ( (dynamic[t][index_dyn] < threshold) and (active_state is True) ):
733
                desc[1] = t;
734
                active_state = False;
735
                
736
                break;
737
        
738
        if (desc == [0, 0, 0]):
739
            continue;
740
        
741
        desc[2] = desc[1] + (desc[0] - desc[1]) / 2.0;
742
        descriptors[index_dyn] = desc;
743
    
744
    
745
    # Cluster allocation
746
    sync_ensembles = [];
747
    desc_sync_ensembles = [];
748
    
749
    for index_desc in range(0, len(descriptors), 1):
750
        if (descriptors[index_desc] == []):
751
            continue;
752
        
753
        if (len(sync_ensembles) == 0):
754
            desc_ensemble = descriptors[index_desc];
755
            reducer = (desc_ensemble[0] - desc_ensemble[1]) * tolerance;
756
            
757
            desc_ensemble[0] = desc_ensemble[2] + reducer;
758
            desc_ensemble[1] = desc_ensemble[2] - reducer;
759
            
760
            desc_sync_ensembles.append(desc_ensemble);
761
            sync_ensembles.append([ index_desc ]);
762
        else:
763
            oscillator_captured = False;
764
            for index_ensemble in range(0, len(sync_ensembles), 1):
765
                if ( (desc_sync_ensembles[index_ensemble][0] > descriptors[index_desc][2]) and (desc_sync_ensembles[index_ensemble][1] < descriptors[index_desc][2])):
766
                    sync_ensembles[index_ensemble].append(index_desc);
767
                    oscillator_captured = True;
768
                    break;
769
                
770
            if (oscillator_captured is False):
771
                desc_ensemble = descriptors[index_desc];
772
                reducer = (desc_ensemble[0] - desc_ensemble[1]) * tolerance;
773
        
774
                desc_ensemble[0] = desc_ensemble[2] + reducer;
775
                desc_ensemble[1] = desc_ensemble[2] - reducer;
776
        
777
                desc_sync_ensembles.append(desc_ensemble);
778
                sync_ensembles.append([ index_desc ]);
779
    
780
    return sync_ensembles;
781
    
782
    
783
def draw_clusters(data, clusters, noise = [], marker_descr = '.', hide_axes = False, axes = None, display_result = True):
784
    """!
785
    @brief Displays clusters for data in 2D or 3D.
786
    
787
    @param[in] data (list): Points that are described by coordinates represented.
788
    @param[in] clusters (list): Clusters that are represented by lists of indexes where each index corresponds to point in data.
789
    @param[in] noise (list): Points that are regarded to noise.
790
    @param[in] marker_descr (string): Marker for displaying points.
791
    @param[in] hide_axes (bool): If True - axes is not displayed.
792
    @param[in] axes (ax) Matplotlib axes where clusters should be drawn, if it is not specified (None) then new plot will be created.
793
    @param[in] display_result (bool): If specified then matplotlib axes will be used for drawing and plot will not be shown.
794
    
795
    @return (ax) Matplotlib axes where drawn clusters are presented.
796
    
797
    """
798
    # Get dimension
799
    dimension = 0;
800
    if ( (data is not None) and (clusters is not None) ):
801
        dimension = len(data[0]);
802
    elif ( (data is None) and (clusters is not None) ):
803
        dimension = len(clusters[0][0]);
804
    else:
805
        raise NameError('Data or clusters should be specified exactly.');
806
    
807
    "Draw clusters"
808
    colors = [ 'red', 'blue', 'darkgreen', 'brown', 'violet', 
809
               'deepskyblue', 'darkgrey', 'lightsalmon', 'deeppink', 'yellow',
810
               'black', 'mediumspringgreen', 'orange', 'darkviolet', 'darkblue',
811
               'silver', 'lime', 'pink', 'gold', 'bisque' ];
812
               
813
    if (len(clusters) > len(colors)):
814
        raise NameError('Impossible to represent clusters due to number of specified colors.');
815
    
816
    fig = plt.figure();
817
    
818
    if (axes is None):
819
        # Check for dimensions
820
        if ((dimension) == 1 or (dimension == 2)):
821
            axes = fig.add_subplot(111);
822
        elif (dimension == 3):
823
            axes = fig.gca(projection='3d');
824
        else:
825
            raise NameError('Drawer supports only 2d and 3d data representation');
826
    
827
    color_index = 0;
828
    for cluster in clusters:
829
        color = colors[color_index];
830
        for item in cluster:
831
            if (dimension == 1):
832
                if (data is None):
833
                    axes.plot(item[0], 0.0, color = color, marker = marker_descr);
834
                else:
835
                    axes.plot(data[item][0], 0.0, color = color, marker = marker_descr);
836
            
837
            if (dimension == 2):
838
                if (data is None):
839
                    axes.plot(item[0], item[1], color = color, marker = marker_descr);
840
                else:
841
                    axes.plot(data[item][0], data[item][1], color = color, marker = marker_descr);
842
                    
843 View Code Duplication
            elif (dimension == 3):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
844
                if (data is None):
845
                    axes.scatter(item[0], item[1], item[2], c = color, marker = marker_descr);
846
                else:
847
                    axes.scatter(data[item][0], data[item][1], data[item][2], c = color, marker = marker_descr);
848
        
849
        color_index += 1;
850
    
851
    for item in noise:
852
        if (dimension == 1):
853
            if (data is None):
854
                axes.plot(item[0], 0.0, 'w' + marker_descr);
855
            else:
856
                axes.plot(data[item][0], 0.0, 'w' + marker_descr);
857
858
        if (dimension == 2):
859
            if (data is None):
860
                axes.plot(item[0], item[1], 'w' + marker_descr);
861
            else:
862
                axes.plot(data[item][0], data[item][1], 'w' + marker_descr);
863
                
864 View Code Duplication
        elif (dimension == 3):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
865
            if (data is None):
866
                axes.scatter(item[0], item[1], item[2], c = 'w', marker = marker_descr);
867
            else:
868
                axes.scatter(data[item][0], data[item][1], data[item][2], c = 'w', marker = marker_descr);
869
    
870
    axes.grid(True);
871
    
872
    if (hide_axes is True):
873
        axes.xaxis.set_ticklabels([]);
874
        axes.yaxis.set_ticklabels([]);
875
        
876
        if (dimension == 3):
877
            axes.zaxis.set_ticklabels([]);
878
    
879
    if (display_result is True):
880
        plt.show();
881
882
    return axes;
883
884
885
def draw_dynamics(t, dyn, x_title = None, y_title = None, x_lim = None, y_lim = None, x_labels = True, y_labels = True, separate = False, axes = None):
886
    """!
887
    @brief Draw dynamics of neurons (oscillators) in the network.
888
    @details It draws if matplotlib is not specified (None), othewise it should be performed manually.
889
    
890
    @param[in] t (list): Values of time (used by x axis).
891
    @param[in] dyn (list): Values of output of oscillators (used by y axis).
892
    @param[in] x_title (string): Title for Y.
893
    @param[in] y_title (string): Title for X.
894
    @param[in] x_lim (double): X limit.
895
    @param[in] y_lim (double): Y limit.
896
    @param[in] x_labels (bool): If True - shows X labels.
897
    @param[in] y_labels (bool): If True - shows Y labels.
898
    @param[in] separate (list): Consists of lists of oscillators where each such list consists of oscillator indexes that will be shown on separated stage.
899
    @param[in] axes (ax): If specified then matplotlib axes will be used for drawing and plot will not be shown.
900
    
901
    @return (ax) Axes of matplotlib.
902
    
903
    """
904
         
905
    number_lines = 0;
906
    
907
    stage_xlim = None;
908
    if (x_lim is not None):
909
        stage_xlim = x_lim;
910
    elif (len(t) > 0):
911
        stage_xlim = [0, t[len(t) - 1]];
912
    
913
    if ( (isinstance(separate, bool) is True) and (separate is True) ):
914
        if (isinstance(dyn[0], list) is True):
915
            number_lines = len(dyn[0]);
916
        else:
917
            number_lines = 1;
918
            
919
    elif (isinstance(separate, list) is True):
920
        number_lines = len(separate);
921
        
922
    else:
923
        number_lines = 1;
924
    
925
    dysplay_result = False;
926
    if (axes is None):
927
        dysplay_result = True;
928
        (fig, axes) = plt.subplots(number_lines, 1);
929
    
930
    # Check if we have more than one dynamic
931
    if (isinstance(dyn[0], list) is True):
932
        num_items = len(dyn[0]);
933
        for index in range(0, num_items, 1):
934
            y = [item[index] for item in dyn];
935
            
936
            if (number_lines > 1):
937
                index_stage = -1;
938
                
939
                # Find required axes for the y
940
                if (isinstance(separate, bool) is True):
941
                    index_stage = index;
942
                    
943
                elif (isinstance(separate, list) is True):
944
                    for index_group in range(0, len(separate), 1):
945
                        if (index in separate[index_group]): 
946
                            index_stage = index_group;
947
                            break;
948
                
949
                if (index_stage != -1):
950
                    if (index_stage != number_lines - 1):
951
                        axes[index_stage].get_xaxis().set_visible(False);
952
                              
953
                    axes[index_stage].plot(t, y, 'b-', linewidth = 0.5); 
954
                    set_ax_param(axes[index_stage], x_title, y_title, stage_xlim, y_lim, x_labels, y_labels, True);
955
                
956
            else:
957
                axes.plot(t, y, 'b-', linewidth = 0.5);
958
                set_ax_param(axes, x_title, y_title, stage_xlim, y_lim, x_labels, y_labels, True);
959
    else:
960
        axes.plot(t, dyn, 'b-', linewidth = 0.5);
961
        set_ax_param(axes, x_title, y_title, stage_xlim, y_lim, x_labels, y_labels, True);
962
    
963
    if (dysplay_result is True):
964
        plt.show();
965
    
966
    return axes;
967
968
969
def set_ax_param(ax, x_title = None, y_title = None, x_lim = None, y_lim = None, x_labels = True, y_labels = True, grid = True):
970
    """!
971
    @brief Sets parameters for matplotlib ax.
972
    
973
    @param[in] ax (Axes): Axes for which parameters should applied.
974
    @param[in] x_title (string): Title for Y.
975
    @param[in] y_title (string): Title for X.
976
    @param[in] x_lim (double): X limit.
977
    @param[in] y_lim (double): Y limit.
978
    @param[in] x_labels (bool): If True - shows X labels.
979
    @param[in] y_labels (bool): If True - shows Y labels.
980
    @param[in] grid (bool): If True - shows grid.
981
    
982
    """
983
    from matplotlib.font_manager import FontProperties;
984
    from matplotlib import rcParams;
985
    
986
    if (_platform == "linux") or (_platform == "linux2"):
987
        rcParams['font.sans-serif'] = ['Liberation Serif'];
988
    else:
989
        rcParams['font.sans-serif'] = ['Arial'];
990
        
991
    rcParams['font.size'] = 12;
992
        
993
    surface_font = FontProperties();
994
    if (_platform == "linux") or (_platform == "linux2"):
995
        surface_font.set_name('Liberation Serif');
996
    else:
997
        surface_font.set_name('Arial');
998
        
999
    surface_font.set_size('12');
1000
    
1001
    if (y_title is not None): ax.set_ylabel(y_title, fontproperties = surface_font);
1002
    if (x_title is not None): ax.set_xlabel(x_title, fontproperties = surface_font);
1003
    
1004
    if (x_lim is not None): ax.set_xlim(x_lim[0], x_lim[1]);
1005
    if (y_lim is not None): ax.set_ylim(y_lim[0], y_lim[1]);
1006
    
1007
    if (x_labels is False): ax.xaxis.set_ticklabels([]);
1008
    if (y_labels is False): ax.yaxis.set_ticklabels([]);
1009
    
1010
    ax.grid(grid);
1011
1012
1013
def draw_dynamics_set(dynamics, xtitle = None, ytitle = None, xlim = None, ylim = None, xlabels = False, ylabels = False):
1014
    """!
1015
    @brief Draw lists of dynamics of neurons (oscillators) in the network.
1016
    
1017
    @param[in] dynamics (list): List of network outputs that are represented by values of output of oscillators (used by y axis).
1018
    @param[in] xtitle (string): Title for Y.
1019
    @param[in] ytitle (string): Title for X.
1020
    @param[in] xlim (double): X limit.
1021
    @param[in] ylim (double): Y limit.
1022
    @param[in] xlabels (bool): If True - shows X labels.
1023
    @param[in] ylabels (bool): If True - shows Y labels.
1024
    
1025
    """
1026
    # Calculate edge for confortable representation.
1027
    number_dynamics = len(dynamics);
1028
    if (number_dynamics == 1):
1029
        draw_dynamics(dynamics[0][0], dynamics[0][1], xtitle, ytitle, xlim, ylim, xlabels, ylabels);
1030
        return;
1031
    
1032
    number_cols = int(numpy.ceil(number_dynamics ** 0.5));
1033
    number_rows = int(numpy.ceil(number_dynamics / number_cols));
1034
1035
    real_index = 0, 0;
1036
    double_indexer = True;
1037
    if ( (number_cols == 1) or (number_rows == 1) ):
1038
        real_index = 0;
1039
        double_indexer = False;
1040
    
1041
    (_, axarr) = plt.subplots(number_rows, number_cols);
1042
    #plt.setp([ax for ax in axarr], visible = False);
1043
    
1044
    for dynamic in dynamics:
1045
        axarr[real_index] = draw_dynamics(dynamic[0], dynamic[1], xtitle, ytitle, xlim, ylim, xlabels, ylabels, axes = axarr[real_index]);
1046
        #plt.setp(axarr[real_index], visible = True);
1047
        
1048
        if (double_indexer is True):
1049
            real_index = real_index[0], real_index[1] + 1;
1050
            if (real_index[1] >= number_cols):
1051
                real_index = real_index[0] + 1, 0; 
1052
        else:
1053
            real_index += 1;
1054
            
1055
    plt.show();
1056
1057
1058
def draw_image_color_segments(source, clusters, hide_axes = True):
1059
    """!
1060
    @brief Shows image segments using colored image.
1061
    @details Each color on result image represents allocated segment. The first image is initial and other is result of segmentation.
1062
    
1063
    @param[in] source (string): Path to image.
1064
    @param[in] clusters (list): List of clusters (allocated segments of image) where each cluster
1065
                                consists of indexes of pixel from source image.
1066
    @param[in] hide_axes (bool): If True then axes will not be displayed.
1067
    
1068
    """
1069
        
1070
    image_source = Image.open(source);
1071
    image_size = image_source.size;
1072
    
1073
    (fig, axarr) = plt.subplots(1, 2);
1074
    
1075
    plt.setp([ax for ax in axarr], visible = False);
1076
    
1077
    available_colors = [ (0, 162, 232),   (34, 177, 76),   (237, 28, 36),
1078
                         (255, 242, 0),   (0, 0, 0),       (237, 28, 36),
1079
                         (255, 174, 201), (127, 127, 127), (185, 122, 87), 
1080
                         (200, 191, 231), (136, 0, 21),    (255, 127, 39),
1081
                         (63, 72, 204),   (195, 195, 195), (255, 201, 14),
1082
                         (239, 228, 176), (181, 230, 29),  (153, 217, 234),
1083
                         (112, 146, 180) ];
1084
    
1085
    image_color_segments = [(255, 255, 255)] * (image_size[0] * image_size[1]);
1086
    
1087
    for index_segment in range(len(clusters)):
1088
        for index_pixel in clusters[index_segment]:
1089
            image_color_segments[index_pixel] = available_colors[index_segment];
1090
    
1091
    stage = array(image_color_segments, numpy.uint8);
1092
    stage = numpy.reshape(stage, (image_size[1], image_size[0]) + ((3),)); # ((3),) it's size of RGB - third dimension.
1093
    image_cluster = Image.fromarray(stage, 'RGB');
1094
    
1095
    axarr[0].imshow(image_source, interpolation = 'none');
1096
    axarr[1].imshow(image_cluster, interpolation = 'none');
1097
    
1098
    for i in range(2):
1099
        plt.setp(axarr[i], visible = True);
1100
        
1101
        if (hide_axes is True):
1102
            axarr[i].xaxis.set_ticklabels([]);
1103
            axarr[i].yaxis.set_ticklabels([]);
1104
            axarr[i].xaxis.set_ticks_position('none');
1105
            axarr[i].yaxis.set_ticks_position('none');
1106
    
1107
    plt.show();
1108
1109
1110
def draw_image_mask_segments(source, clusters, hide_axes = True):
1111
    """!
1112
    @brief Shows image segments using black masks.
1113
    @details Each black mask of allocated segment is presented on separate plot.
1114
             The first image is initial and others are black masks of segments.
1115
    
1116
    @param[in] source (string): Path to image.
1117
    @param[in] clusters (list): List of clusters (allocated segments of image) where each cluster
1118
                                consists of indexes of pixel from source image.
1119
    @param[in] hide_axes (bool): If True then axes will not be displayed.
1120
    
1121
    """
1122
    if (len(clusters) == 0):
1123
        print("Warning: Nothing to draw - list of clusters is empty.")
1124
        return;
1125
        
1126
    image_source = Image.open(source);
1127
    image_size = image_source.size;
1128
    
1129
    # Calculate edge for confortable representation.
1130
    number_clusters = len(clusters) + 1; # show with the source image
1131
    
1132
    number_cols = int(numpy.ceil(number_clusters ** 0.5));
1133
    number_rows = int(numpy.ceil(number_clusters / number_cols));
1134
    
1135
1136
    real_index = 0, 0;
1137
    double_indexer = True;
1138
    if ( (number_cols == 1) or (number_rows == 1) ):
1139
        real_index = 0;
1140
        double_indexer = False;
1141
    
1142
    (fig, axarr) = plt.subplots(number_rows, number_cols);
1143
    plt.setp([ax for ax in axarr], visible = False);
1144
    
1145
    axarr[real_index].imshow(image_source, interpolation = 'none');
1146
    plt.setp(axarr[real_index], visible = True);
1147
    
1148
    if (hide_axes is True):
1149
        axarr[real_index].xaxis.set_ticklabels([]);
1150
        axarr[real_index].yaxis.set_ticklabels([]);
1151
        axarr[real_index].xaxis.set_ticks_position('none');
1152
        axarr[real_index].yaxis.set_ticks_position('none');
1153
            
1154
    if (double_indexer is True):
1155
        real_index = 0, 1;
1156
    else:
1157
        real_index += 1;
1158
    
1159
    for cluster in clusters:
1160
        stage_cluster = [(255, 255, 255)] * (image_size[0] * image_size[1]);
1161
        for index in cluster:
1162
            stage_cluster[index] = (0, 0, 0);
1163
          
1164
        stage = array(stage_cluster, numpy.uint8);
1165
        stage = numpy.reshape(stage, (image_size[1], image_size[0]) + ((3),)); # ((3),) it's size of RGB - third dimension.
1166
        
1167
        image_cluster = Image.fromarray(stage, 'RGB');
1168
        
1169
        axarr[real_index].imshow(image_cluster, interpolation = 'none');
1170
        plt.setp(axarr[real_index], visible = True);
1171
        
1172
        if (hide_axes is True):
1173
            axarr[real_index].xaxis.set_ticklabels([]);
1174
            axarr[real_index].yaxis.set_ticklabels([]);
1175
            
1176
            axarr[real_index].xaxis.set_ticks_position('none');
1177
            axarr[real_index].yaxis.set_ticks_position('none');
1178
        
1179
        if (double_indexer is True):
1180
            real_index = real_index[0], real_index[1] + 1;
1181
            if (real_index[1] >= number_cols):
1182
                real_index = real_index[0] + 1, 0; 
1183
        else:
1184
            real_index += 1;
1185
1186
            
1187
    plt.show();
1188
1189
1190
def linear_sum(list_vector):
1191
    """!
1192
    @brief Calculates linear sum of vector that is represented by list, each element can be represented by list - multidimensional elements.
1193
    
1194
    @param[in] list_vector (list): Input vector.
1195
    
1196
    @return (list|double) Linear sum of vector that can be represented by list in case of multidimensional elements.
1197
    
1198
    """
1199
    dimension = 1;
1200
    linear_sum = 0.0;
1201
    list_representation = (type(list_vector[0]) == list);
1202
    
1203
    if (list_representation is True):
1204
        dimension = len(list_vector[0]);
1205
        linear_sum = [0] * dimension;
1206
        
1207
    for index_element in range(0, len(list_vector)):
1208
        if (list_representation is True):
1209
            for index_dimension in range(0, dimension):
1210
                linear_sum[index_dimension] += list_vector[index_element][index_dimension];
1211
        else:
1212
            linear_sum += list_vector[index_element];
1213
1214
    return linear_sum;
1215
1216
1217
def square_sum(list_vector):
1218
    """!
1219
    @brief Calculates square sum of vector that is represented by list, each element can be represented by list - multidimensional elements.
1220
    
1221
    @param[in] list_vector (list): Input vector.
1222
    
1223
    @return (double) Square sum of vector.
1224
    
1225
    """
1226
    
1227
    square_sum = 0.0;
1228
    list_representation = (type(list_vector[0]) == list);
1229
        
1230
    for index_element in range(0, len(list_vector)):
1231
        if (list_representation is True):
1232
            square_sum += sum(list_math_multiplication(list_vector[index_element], list_vector[index_element]));
1233
        else:
1234
            square_sum += list_vector[index_element] * list_vector[index_element];
1235
         
1236
    return square_sum;
1237
1238
    
1239
def list_math_subtraction(a, b):
1240
    """!
1241
    @brief Calculates subtraction of two lists.
1242
    @details Each element from list 'a' is subtracted by element from list 'b' accordingly.
1243
    
1244
    @param[in] a (list): List of elements that supports mathematical subtraction.
1245
    @param[in] b (list): List of elements that supports mathematical subtraction.
1246
    
1247
    @return (list) Results of subtraction of two lists.
1248
    
1249
    """
1250
    return [a[i] - b[i] for i in range(len(a))];
1251
1252
1253
def list_math_substraction_number(a, b):
1254
    """!
1255
    @brief Calculates subtraction between list and number.
1256
    @details Each element from list 'a' is subtracted by number 'b'.
1257
    
1258
    @param[in] a (list): List of elements that supports mathematical subtraction.
1259
    @param[in] b (list): Value that supports mathematical subtraction.
1260
    
1261
    @return (list) Results of subtraction between list and number.
1262
    
1263
    """        
1264
    return [a[i] - b for i in range(len(a))];  
1265
1266
1267
def list_math_addition(a, b):
1268
    """!
1269
    @brief Addition of two lists.
1270
    @details Each element from list 'a' is added to element from list 'b' accordingly.
1271
    
1272
    @param[in] a (list): List of elements that supports mathematic addition..
1273
    @param[in] b (list): List of elements that supports mathematic addition..
1274
    
1275
    @return (list) Results of addtion of two lists.
1276
    
1277
    """    
1278
    return [a[i] + b[i] for i in range(len(a))];
1279
1280
1281
def list_math_addition_number(a, b):
1282
    """!
1283
    @brief Addition between list and number.
1284
    @details Each element from list 'a' is added to number 'b'.
1285
    
1286
    @param[in] a (list): List of elements that supports mathematic addition.
1287
    @param[in] b (double): Value that supports mathematic addition.
1288
    
1289
    @return (list) Result of addtion of two lists.
1290
    
1291
    """    
1292
    return [a[i] + b for i in range(len(a))];
1293
1294
1295
def list_math_division_number(a, b):
1296
    """!
1297
    @brief Division between list and number.
1298
    @details Each element from list 'a' is divided by number 'b'.
1299
    
1300
    @param[in] a (list): List of elements that supports mathematic division.
1301
    @param[in] b (double): Value that supports mathematic division.
1302
    
1303
    @return (list) Result of division between list and number.
1304
    
1305
    """    
1306
    return [a[i] / b for i in range(len(a))];
1307
1308
1309
def list_math_division(a, b):
1310
    """!
1311
    @brief Division of two lists.
1312
    @details Each element from list 'a' is divided by element from list 'b' accordingly.
1313
    
1314
    @param[in] a (list): List of elements that supports mathematic division.
1315
    @param[in] b (list): List of elements that supports mathematic division.
1316
    
1317
    @return (list) Result of division of two lists.
1318
    
1319
    """    
1320
    return [a[i] / b[i] for i in range(len(a))];
1321
1322
1323
def list_math_multiplication_number(a, b):
1324
    """!
1325
    @brief Multiplication between list and number.
1326
    @details Each element from list 'a' is multiplied by number 'b'.
1327
    
1328
    @param[in] a (list): List of elements that supports mathematic division.
1329
    @param[in] b (double): Number that supports mathematic division.
1330
    
1331
    @return (list) Result of division between list and number.
1332
    
1333
    """    
1334
    return [a[i] * b for i in range(len(a))];
1335
1336
1337
def list_math_multiplication(a, b):
1338
    """!
1339
    @brief Multiplication of two lists.
1340
    @details Each element from list 'a' is multiplied by element from list 'b' accordingly.
1341
    
1342
    @param[in] a (list): List of elements that supports mathematic multiplication.
1343
    @param[in] b (list): List of elements that supports mathematic multiplication.
1344
    
1345
    @return (list) Result of multiplication of elements in two lists.
1346
    
1347
    """        
1348
    return [a[i] * b[i] for i in range(len(a))];
1349