Completed
Push — 0.7.dev ( 0c43ad...a5d4ae )
by Andrei
01:12
created

knearest()   B

Complexity

Conditions 6

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

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