Completed
Push — 0.7.dev ( 589c41...121506 )
by Andrei
56s
created

read_sample()   B

Complexity

Conditions 4

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
dl 0
loc 22
rs 8.9197
c 0
b 0
f 0
1
"""!
2
3
@brief Utils that are used by modules of pyclustering.
4
5
@authors Andrei Novikov ([email protected])
6
@date 2014-2017
7
@copyright GNU Public License
8
9
@cond GNU_PUBLIC_LICENSE
10
    PyClustering is free software: you can redistribute it and/or modify
11
    it under the terms of the GNU General Public License as published by
12
    the Free Software Foundation, either version 3 of the License, or
13
    (at your option) any later version.
14
    
15
    PyClustering is distributed in the hope that it will be useful,
16
    but WITHOUT ANY WARRANTY; without even the implied warranty of
17
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
    GNU General Public License for more details.
19
    
20
    You should have received a copy of the GNU General Public License
21
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
@endcond
23
24
"""
25
26
import time;
27
import numpy;
28
29
from PIL import Image;
30
from numpy import array;
31
32
import matplotlib.pyplot as plt;
33
from mpl_toolkits.mplot3d import Axes3D;
34
35
from sys import platform as _platform;
36
37
38
## The number \f$pi\f$ is a mathematical constant, the ratio of a circle's circumference to its diameter.
39
pi = 3.1415926535;
40
41
42
def read_sample(filename):
43
    """!
44
    @brief Returns data sample from simple text file.
45
    @details This function should be used for text file with following format:
46
    @code
47
    point_1_coord_1 point_1_coord_2 ... point_1_coord_n
48
    point_2_coord_1 point_2_coord_2 ... point_2_coord_n
49
    ... ...
50
    @endcode
51
    
52
    @param[in] filename (string): Path to file with data.
53
    
54
    @return (list) Points where each point represented by list of coordinates.
55
    
56
    """
57
    
58
    file = open(filename, 'r');
59
60
    sample = [[float(val) for val in line.split()] for line in file if len(line.strip()) > 0];
61
    
62
    file.close();
63
    return sample;
64
65
66
def read_image(filename):
67
    """!
68
    @brief Returns image as N-dimension (depends on the input image) matrix, where one element of list describes pixel.
69
    
70
    @param[in] filename (string): Path to image.
71
    
72
    @return (list) Pixels where each pixel described by list of RGB-values.
73
    
74
    """
75
    
76
    image_source = Image.open(filename);
77
    data = [pixel for pixel in image_source.getdata()];
78
    
79
    del image_source;
80
    image_source = None;
81
    return data;
82
83
84
def rgb2gray(image_rgb_array):
85
    """!
86
    @brief Returns image as 1-dimension (gray colored) matrix, where one element of list describes pixel.
87
    @details Luma coding is used for transformation and that is calculated directly from gamma-compressed primary intensities as a weighted sum:
88
    
89
    \f[Y = 0.2989R + 0.587G + 0.114B\f]
90
    
91
    @param[in] image_rgb_array (list): Image represented by RGB list.
92
    
93
    @return (list) Image as gray colored matrix, where one element of list describes pixel.
94
    
95
    @code
96
        colored_image = read_image(file_name);
97
        gray_image = rgb2gray(colored_image);
98
    @endcode
99
    
100
    @see read_image()
101
    
102
    """
103
    
104
    image_gray_array = [0.0] * len(image_rgb_array);
105
    for index in range(0, len(image_rgb_array), 1):
106
        image_gray_array[index] = float(image_rgb_array[index][0]) * 0.2989 + float(image_rgb_array[index][1]) * 0.5870 + float(image_rgb_array[index][2]) * 0.1140;
107
    
108
    return image_gray_array;
109
110
111
def stretch_pattern(image_source):
112
    """!
113
    @brief Returns stretched content as 1-dimension (gray colored) matrix with size of input image.
114
    
115
    @param[in] image_source (Image): PIL Image instance.
116
    
117
    @return (list, Image) Stretched image as gray colored matrix and source image.
118
    
119
    """
120
    wsize, hsize = image_source.size;
121
    
122
    # Crop digit exactly
123
    (ws, hs, we, he) = gray_pattern_borders(image_source);
124
    image_source = image_source.crop((ws, hs, we, he));
125
    
126
    # Stretch it to initial sizes
127
    image_source = image_source.resize((wsize, hsize), Image.ANTIALIAS);
128
    
129
    # Transform image to simple array
130
    data = [pixel for pixel in image_source.getdata()];
131
    image_pattern = rgb2gray(data);
132
    
133
    return (image_pattern, image_source);
134
135
136
def gray_pattern_borders(image):
137
    """!
138
    @brief Returns coordinates of gray image content on the input image.
139
    
140
    @param[in] image (Image): PIL Image instance that is processed.
141
    
142
    @return (tuple) Returns coordinates of gray image content as (width_start, height_start, width_end, height_end).
143
    
144
    """
145
    
146
    width, height = image.size;
147
    
148
    width_start = width;
149
    width_end = 0;
150
    height_start = height;
151
    height_end = 0;
152
    
153
    row, col = 0, 0;
154
    for pixel in image.getdata():
155
        value = float(pixel[0]) * 0.2989 + float(pixel[1]) * 0.5870 + float(pixel[2]) * 0.1140;
156
        
157
        if (value < 128):
158
            if (width_end < col): 
159
                width_end = col;
160
            
161
            if (height_end < row):
162
                height_end = row;
163
        
164
            if (width_start > col):
165
                width_start = col;
166
            
167
            if (height_start > row):
168
                height_start = row;
169
        
170
        col += 1;
171
        if (col >= width):
172
            col = 0;
173
            row += 1;
174
175
    return (width_start, height_start, width_end + 1, height_end + 1);
176
177
178
def knearest(points, k):
179
    """!
180
    @brief Calculates k-nearest graph.
181
    
182
    @param[in] points (list): Input data, list of points where each point represented by list.
183
    @param[in] k (uint): Minimum number of neighbors for each point.
184
    
185
    @return (list) k-nearest graph.
186
    
187
    """
188
    
189
    graph = [];
190
    for i in range(len(points)):
191
        candidates = [];
192
        for j in range(i + i, len(points), 1):
193
            distance = euclidean_distance_sqrt(points[i], points[j]);
194
            if (len(candidates) < k):
195
                candidates.append((j, distance));
196
            else:
197
                index_loser, value_loser = max(candidates, key = lambda value: value[1]);
198
                if (value_loser[1] > distance):
199
                    candidates[index_loser] = (j, distance);
200
    
201
        graph.append(candidates);
202
    
203
    return graph;
204
205
206
def average_neighbor_distance(points, num_neigh):
207
    """!
208
    @brief Returns average distance for establish links between specified number of nearest neighbors.
209
    
210
    @param[in] points (list): Input data, list of points where each point represented by list.
211
    @param[in] num_neigh (uint): Number of neighbors that should be used for distance calculation.
212
    
213
    @return (double) Average distance for establish links between 'num_neigh' in data set 'points'.
214
    
215
    """
216
    
217
    if (num_neigh > len(points) - 1):
218
        raise NameError('Impossible to calculate average distance to neighbors when number of object is less than number of neighbors.');
219
    
220
    dist_matrix = [ [ 0.0 for i in range(len(points)) ] for j in range(len(points)) ];
221
    for i in range(0, len(points), 1):
222
        for j in range(i + 1, len(points), 1):
223
            distance = euclidean_distance(points[i], points[j]);
224
            dist_matrix[i][j] = distance;
225
            dist_matrix[j][i] = distance;
226
            
227
        dist_matrix[i] = sorted(dist_matrix[i]);
228
229
    total_distance = 0;
230
    for i in range(0, len(points), 1):
231
        # start from 0 - first element is distance to itself.
232
        for j in range(0, num_neigh, 1):
233
            total_distance += dist_matrix[i][j + 1];
234
            
235
    return ( total_distance / (num_neigh * len(points)) );
236
237
238
def centroid(points, indexes = None):
239
    """!
240
    @brief Calculate centroid of input set of points. 
241
    
242
    @param[in] points (list): Set of points for centroid calculation.
243
    @param[in] indexes (list): Indexes of objects in input set of points that will be taken into account during centroid calculation.
244
    
245
    @return (list) centroid on the set of points where each element of list is corresponding to value in its dimension.
246
    
247
    """
248
    
249
    dimension = len(points[0]);
250
    centroid_value = [0.0] * dimension;
251
    
252
    range_points = None;
253
    if (indexes is None):
254
        range_points = range(len(points));
255
    else:
256
        range_points = indexes;
257
    
258
    for index_point in range_points:
259
        centroid_value = list_math_addition(centroid_value, points[index_point]);
260
    
261
    centroid_value = list_math_division_number(centroid_value, len(range_points));
262
    return centroid_value;
263
264
265
def median(points, indexes = None):
266
    """!
267
    @brief Calculate geometric median of input set of points using Euclidian distance. 
268
    
269
    @param[in] points (list): Set of points for median calculation.
270
    @param[in] indexes (list): Indexes of objects in input set of points that will be taken into account during median calculation.
271
    
272
    @return (uint) index of point in input set that corresponds to median.
273
    
274
    """
275
    
276
    index_median = None;
277
    distance = float('Inf');
278
    
279
    range_points = None;
280
    if (indexes is None):
281
        range_points = range(len(points));
282
    else:
283
        range_points = indexes;
284
    
285
    for index_candidate in range_points:
286
        distance_candidate = 0.0;
287
        for index in range_points:
288
            distance_candidate += euclidean_distance_sqrt(points[index_candidate], points[index]);
289
        
290
        if (distance_candidate < distance):
291
            distance = distance_candidate;
292
            index_median = index_candidate;
293
    
294
    return index_median;
295
296
297
def euclidean_distance(a, b):
298
    """!
0 ignored issues
show
Bug introduced by
A suspicious escape sequence \s was found. Did you maybe forget to add an r prefix?

Escape sequences in Python are generally interpreted according to rules similar to standard C. Only if strings are prefixed with r or R are they interpreted as regular expressions.

The escape sequence that was used indicates that you might have intended to write a regular expression.

Learn more about the available escape sequences. in the Python documentation.

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