Completed
Push — master ( c8bc69...89bc14 )
by Andrei
17:38
created

euclidean_distance_square()   B

Complexity

Conditions 6

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

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