Completed
Push — 0.7.dev ( e45971...bb7559 )
by Andrei
54s
created

calculate_ellipse_description()   A

Complexity

Conditions 1

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

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