Completed
Push — master ( af3192...a7eabf )
by Andrei
02:20
created

median()   F

Complexity

Conditions 9

Size

Total Lines 44

Duplication

Lines 0
Ratio 0 %

Importance

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