Completed
Push — master ( 05cd1c...6149f2 )
by Andrei
01:10
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
from pyclustering.utils.metric import distance_metric, type_metric;
38
39
40
## The number \f$pi\f$ is a mathematical constant, the ratio of a circle's circumference to its diameter.
41
pi = 3.1415926535;
42
43
44
def read_sample(filename):
45
    """!
46
    @brief Returns data sample from simple text file.
47
    @details This function should be used for text file with following format:
48
    @code
49
    point_1_coord_1 point_1_coord_2 ... point_1_coord_n
50
    point_2_coord_1 point_2_coord_2 ... point_2_coord_n
51
    ... ...
52
    @endcode
53
    
54
    @param[in] filename (string): Path to file with data.
55
    
56
    @return (list) Points where each point represented by list of coordinates.
57
    
58
    """
59
    
60
    file = open(filename, 'r');
61
62
    sample = [[float(val) for val in line.split()] for line in file if len(line.strip()) > 0];
63
    
64
    file.close();
65
    return sample;
66
67
68
def calculate_distance_matrix(sample):
69
    """!
70
    @brief Calculates distance matrix for data sample (sequence of points) using Euclidean distance as a metric.
71
72
    @param[in] sample (array_like): Data points that are used for distance calculation.
73
74
    @return (list) Matrix distance between data points.
75
76
    """
77
78
    amount_rows = len(sample);
79
    return [ [ euclidean_distance(sample[i], sample[j]) for j in range(amount_rows) ] for i in range(amount_rows) ];
80
81
82
def read_image(filename):
83
    """!
84
    @brief Returns image as N-dimension (depends on the input image) matrix, where one element of list describes pixel.
85
    
86
    @param[in] filename (string): Path to image.
87
    
88
    @return (list) Pixels where each pixel described by list of RGB-values.
89
    
90
    """
91
    
92
    with Image.open(filename) as image_source:
93
        data = [pixel for pixel in image_source.getdata()];
94
        return data;
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(data, indexes = None, **kwargs):
251
    """!
252
    @brief Calculate geometric median of input set of points using Euclidean distance.
253
    
254
    @param[in] data (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
    @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'metric', 'data_type').
257
258
    <b>Keyword Args:</b><br>
259
        - metric (distance_metric): Metric that is used for distance calculation between two points.
260
        - data_type (string): Data type of input sample 'data' (available values: 'points', 'distance_matrix').
261
262
    @return (uint) index of point in input set that corresponds to median.
263
    
264
    """
265
    
266
    index_median = None;
267
    distance = float('Inf');
268
269
    metric = kwargs.get('metric', type_metric.EUCLIDEAN_SQUARE);
270
    data_type = kwargs.get('data_type', 'points');
271
272
    if data_type == 'points':
273
        calculator = lambda index1, index2: metric(data[index1], data[index2]);
274
    elif data_type == 'distance_matrix':
275
        if isinstance(data, numpy.matrix):
276
            calculator = lambda index1, index2: data.item(index1, index2);
277
278
        else:
279
            calculator = lambda index1, index2: data[index1][index2];
280
    else:
281
        raise TypeError("Unknown type of data is specified '%s'." % data_type);
282
283
    if indexes is None:
284
        range_points = range(len(data));
285
    else:
286
        range_points = indexes;
287
    
288
    for index_candidate in range_points:
289
        distance_candidate = 0.0;
290
        for index in range_points:
291
            distance_candidate += calculator(index_candidate, index);
292
        
293
        if distance_candidate < distance:
294
            distance = distance_candidate;
295
            index_median = index_candidate;
296
    
297
    return index_median;
298
299
300
def euclidean_distance(a, b):
301
    """!
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...
302
    @brief Calculate Euclidean distance between vector a and b. 
303
    @details The Euclidean between vectors (points) a and b is calculated by following formula:
304
    
305
    \f[
306
    dist(a, b) = \sqrt{ \sum_{i=0}^{N}(b_{i} - a_{i})^{2}) };
307
    \f]
308
    
309
    Where N is a length of each vector.
310
    
311
    @param[in] a (list): The first vector.
312
    @param[in] b (list): The second vector.
313
    
314
    @return (double) Euclidian distance between two vectors.
315
    
316
    @note This function for calculation is faster then standard function in ~100 times!
317
    
318
    """
319
    
320
    distance = euclidean_distance_square(a, b);
321
    return distance**(0.5);
322
323
324
def euclidean_distance_square(a, b):
325
    """!
326
    @brief Calculate square Euclidian distance between vector a and b.
327
    
328
    @param[in] a (list): The first vector.
329
    @param[in] b (list): The second vector.
330
    
331
    @return (double) Square Euclidian distance between two vectors.
332
    
333
    """  
334
    
335
    if ( ((type(a) == float) and (type(b) == float)) or ((type(a) == int) and (type(b) == int)) ):
336
        return (a - b)**2.0;
337
    
338
    distance = 0.0;
339
    for i in range(0, len(a)):
340
        distance += (a[i] - b[i])**2.0;
341
        
342
    return distance;
343
344
345
def manhattan_distance(a, b):
346
    """!
347
    @brief Calculate Manhattan distance between vector a and b.
348
    
349
    @param[in] a (list): The first cluster.
350
    @param[in] b (list): The second cluster.
351
    
352
    @return (double) Manhattan distance between two vectors.
353
    
354
    """
355
    
356
    if ( ((type(a) == float) and (type(b) == float)) or ((type(a) == int) and (type(b) == int)) ):
357
        return abs(a - b);
358
    
359
    distance = 0.0;
360
    dimension = len(a);
361
    
362
    for i in range(0, dimension):
363
        distance += abs(a[i] - b[i]);
364
    
365
    return distance;
366
367
368
def average_inter_cluster_distance(cluster1, cluster2, data = None):
369
    """!
370
    @brief Calculates average inter-cluster distance between two clusters.
371
    @details Clusters can be represented by list of coordinates (in this case data shouldn't be specified),
372
             or by list of indexes of points from the data (represented by list of points), in this case 
373
             data should be specified.
374
             
375
    @param[in] cluster1 (list): The first cluster where each element can represent index from the data or object itself.
376
    @param[in] cluster2 (list): The second cluster where each element can represent index from the data or object itself.
377
    @param[in] data (list): If specified than elements of clusters will be used as indexes,
378
               otherwise elements of cluster will be considered as points.
379
    
380
    @return (double) Average inter-cluster distance between two clusters.
381
    
382
    """
383
    
384
    distance = 0.0;
385
    
386
    if (data is None):
387
        for i in range(len(cluster1)):
388
            for j in range(len(cluster2)):
389
                distance += euclidean_distance_square(cluster1[i], cluster2[j]);
390
    else:
391
        for i in range(len(cluster1)):
392
            for j in range(len(cluster2)):
393
                distance += euclidean_distance_square(data[ cluster1[i]], data[ cluster2[j]]);
394
    
395
    distance /= float(len(cluster1) * len(cluster2));
396
    return distance ** 0.5;
397
398
399
def average_intra_cluster_distance(cluster1, cluster2, data=None):
400
    """!
401
    @brief Calculates average intra-cluster distance between two clusters.
402
    @details Clusters can be represented by list of coordinates (in this case data shouldn't be specified),
403
             or by list of indexes of points from the data (represented by list of points), in this case 
404
             data should be specified.
405
    
406
    @param[in] cluster1 (list): The first cluster.
407
    @param[in] cluster2 (list): The second cluster.
408
    @param[in] data (list): If specified than elements of clusters will be used as indexes,
409
               otherwise elements of cluster will be considered as points.
410
    
411
    @return (double) Average intra-cluster distance between two clusters.
412
    
413
    """
414
        
415
    distance = 0.0
416
    
417
    for i in range(len(cluster1) + len(cluster2)):
418
        for j in range(len(cluster1) + len(cluster2)):
419
            if data is None:
420
                # the first point
421
                if i < len(cluster1):
422
                    first_point = cluster1[i]
423
                else:
424
                    first_point = cluster2[i - len(cluster1)]
425
                
426
                # the second point
427
                if j < len(cluster1):
428
                    second_point = cluster1[j]
429
                else:
430
                    second_point = cluster2[j - len(cluster1)]
431
                
432
            else:
433
                # the first point
434
                if i < len(cluster1):
435
                    first_point = data[cluster1[i]]
436
                else:
437
                    first_point = data[cluster2[i - len(cluster1)]]
438
            
439
                if j < len(cluster1):
440
                    second_point = data[cluster1[j]]
441
                else:
442
                    second_point = data[cluster2[j - len(cluster1)]]
443
            
444
            distance += euclidean_distance_square(first_point, second_point)
445
    
446
    distance /= float((len(cluster1) + len(cluster2)) * (len(cluster1) + len(cluster2) - 1.0))
447
    return distance ** 0.5
448
449
450
def variance_increase_distance(cluster1, cluster2, data = None):
451
    """!
452
    @brief Calculates variance increase distance between two clusters.
453
    @details Clusters can be represented by list of coordinates (in this case data shouldn't be specified),
454
             or by list of indexes of points from the data (represented by list of points), in this case 
455
             data should be specified.
456
    
457
    @param[in] cluster1 (list): The first cluster.
458
    @param[in] cluster2 (list): The second cluster.
459
    @param[in] data (list): If specified than elements of clusters will be used as indexes,
460
               otherwise elements of cluster will be considered as points.
461
    
462
    @return (double) Average variance increase distance between two clusters.
463
    
464
    """
465
    
466
    # calculate local sum
467
    if data is None:
468
        member_cluster1 = [0.0] * len(cluster1[0])
469
        member_cluster2 = [0.0] * len(cluster2[0])
470
        
471
    else:
472
        member_cluster1 = [0.0] * len(data[0])
473
        member_cluster2 = [0.0] * len(data[0])
474
    
475
    for i in range(len(cluster1)):
476
        if data is None:
477
            member_cluster1 = list_math_addition(member_cluster1, cluster1[i])
478
        else:
479
            member_cluster1 = list_math_addition(member_cluster1, data[ cluster1[i] ])
480
481
    for j in range(len(cluster2)):
482
        if data is None:
483
            member_cluster2 = list_math_addition(member_cluster2, cluster2[j])
484
        else:
485
            member_cluster2 = list_math_addition(member_cluster2, data[ cluster2[j] ])
486
    
487
    member_cluster_general = list_math_addition(member_cluster1, member_cluster2)
488
    member_cluster_general = list_math_division_number(member_cluster_general, len(cluster1) + len(cluster2))
489
    
490
    member_cluster1 = list_math_division_number(member_cluster1, len(cluster1))
491
    member_cluster2 = list_math_division_number(member_cluster2, len(cluster2))
492
    
493
    # calculate global sum
494
    distance_general = 0.0
495
    distance_cluster1 = 0.0
496
    distance_cluster2 = 0.0
497
    
498
    for i in range(len(cluster1)):
499
        if data is None:
500
            distance_cluster1 += euclidean_distance_square(cluster1[i], member_cluster1)
501
            distance_general += euclidean_distance_square(cluster1[i], member_cluster_general)
502
            
503
        else:
504
            distance_cluster1 += euclidean_distance_square(data[ cluster1[i]], member_cluster1)
505
            distance_general += euclidean_distance_square(data[ cluster1[i]], member_cluster_general)
506
    
507
    for j in range(len(cluster2)):
508
        if data is None:
509
            distance_cluster2 += euclidean_distance_square(cluster2[j], member_cluster2)
510
            distance_general += euclidean_distance_square(cluster2[j], member_cluster_general)
511
            
512
        else:
513
            distance_cluster2 += euclidean_distance_square(data[ cluster2[j]], member_cluster2)
514
            distance_general += euclidean_distance_square(data[ cluster2[j]], member_cluster_general)
515
    
516
    return distance_general - distance_cluster1 - distance_cluster2
517
518
519
def calculate_ellipse_description(covariance, scale = 2.0):
520
    """!
521
    @brief Calculates description of ellipse using covariance matrix.
522
    
523
    @param[in] covariance (numpy.array): Covariance matrix for which ellipse area should be calculated.
524
    @param[in] scale (float): Scale of the ellipse.
525
    
526
    @return (float, float, float) Return ellipse description: angle, width, height.
527
    
528
    """
529
    
530
    eigh_values, eigh_vectors = numpy.linalg.eigh(covariance)
531
    order = eigh_values.argsort()[::-1]
532
    
533
    values, vectors = eigh_values[order], eigh_vectors[order]
534
    angle = numpy.degrees(numpy.arctan2(*vectors[:,0][::-1]))
535
536
    if 0.0 in values:
537
        return 0, 0, 0
538
539
    width, height = 2.0 * scale * numpy.sqrt(values)
540
    return angle, width, height
541
542
543
def data_corners(data, data_filter = None):
544
    """!
545
    @brief Finds maximum and minimum corner in each dimension of the specified data.
546
    
547
    @param[in] data (list): List of points that should be analysed.
548
    @param[in] data_filter (list): List of indexes of the data that should be analysed,
549
                if it is 'None' then whole 'data' is analysed to obtain corners.
550
    
551
    @return (list) Tuple of two points that corresponds to minimum and maximum corner (min_corner, max_corner).
552
    
553
    """
554
    
555
    dimensions = len(data[0])
556
    
557
    bypass = data_filter
558
    if bypass is None:
559
        bypass = range(len(data))
560
    
561
    maximum_corner = data[bypass[0]][:]
562
    minimum_corner = data[bypass[0]][:]
563
    
564
    for index_point in bypass:
565
        for index_dimension in range(dimensions):
566
            if data[index_point][index_dimension] > maximum_corner[index_dimension]:
567
                maximum_corner[index_dimension] = data[index_point][index_dimension]
568
            
569
            if data[index_point][index_dimension] < minimum_corner[index_dimension]:
570
                minimum_corner[index_dimension] = data[index_point][index_dimension]
571
    
572
    return minimum_corner, maximum_corner
573
574
575
def norm_vector(vector):
576
    """!
577
    @brief Calculates norm of an input vector that is known as a vector length.
578
    
579
    @param[in] vector (list): The input vector whose length is calculated.
580
    
581
    @return (double) vector norm known as vector length.
582
    
583
    """
584
    
585
    length = 0.0
586
    for component in vector:
587
        length += component * component
588
    
589
    length = length ** 0.5
590
    
591
    return length
592
593
594
def unit_vector(vector):
595
    """!
596
    @brief Calculates unit vector.
597
    @details Unit vector calculates of an input vector involves two steps. 
598
              The first, calculate vector length. The second,
599
              divide each vector component by the obtained length.
600
    
601
    @param[in] vector (list): The input vector that is used for unit vector calculation.
602
    
603
    """
604
    
605
    length = norm_vector(vector);
606
    unit_vector_instance = [];
607
    
608
    for component in vector:
609
        unit_vector_instance.append(component / length);
610
    
611
    return unit_vector_instance;
612
613
614
def heaviside(value):
615
    """!
616
    @brief Calculates Heaviside function that represents step function.
617
    @details If input value is greater than 0 then returns 1, otherwise returns 0.
618
    
619
    @param[in] value (double): Argument of Heaviside function.
620
    
621
    @return (double) Value of Heaviside function.
622
    
623
    """
624
    if (value > 0.0): 
625
        return 1.0;
626
    
627
    return 0.0;
628
629
630
def timedcall(executable_function, *args):
631
    """!
632
    @brief Executes specified method or function with measuring of execution time.
633
    
634
    @param[in] executable_function (pointer): Pointer to function or method.
635
    @param[in] args (*): Arguments of called function or method.
636
    
637
    @return (tuple) Execution time and result of execution of function or method (execution_time, result_execution).
638
    
639
    """
640
    
641
    time_start = time.clock();
642
    result = executable_function(*args);
643
    time_end = time.clock();
644
    
645
    return (time_end - time_start, result);
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
            elif (dimension == 3):
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 View Code Duplication
        
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
849
        color_index += 1;
850
    
851
    for item in noise:
852
        if (dimension == 1):
853 View Code Duplication
            if (data is None):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
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
        elif (dimension == 3):
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 View Code Duplication
    
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
870
    axes.grid(True);
871
    
872
    if (hide_axes is True):
873
        axes.xaxis.set_ticklabels([]);
874 View Code Duplication
        axes.yaxis.set_ticklabels([]);
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
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