def variance_increase_distance(cluster1, cluster2, data = None):

<EOL>if data is None:<EOL><INDENT>member_cluster1 = [<NUM_LIT:0.0>] * len(cluster1[<NUM_LIT:0>])<EOL>member_cluster2 = [<NUM_LIT:0.0>] * len(cluster2[<NUM_LIT:0>])<EOL><DEDENT>else:<EOL><INDENT>member_cluster1 = [<NUM_LIT:0.0>] * len(data[<NUM_LIT:0>])<EOL>member_cluster2 = [<NUM_LIT:0.0>] * len(data[<NUM_LIT:0>])<EOL><DEDENT>for i in range(len(cluster1)):<EOL><INDENT>if data is None:<EOL><INDENT>member_cluster1 = list_math_addition(member_cluster1, cluster1[i])<EOL><DEDENT>else:<EOL><INDENT>member_cluster1 = list_math_addition(member_cluster1, data[ cluster1[i] ])<EOL><DEDENT><DEDENT>for j in range(len(cluster2)):<EOL><INDENT>if data is None:<EOL><INDENT>member_cluster2 = list_math_addition(member_cluster2, cluster2[j])<EOL><DEDENT>else:<EOL><INDENT>member_cluster2 = list_math_addition(member_cluster2, data[ cluster2[j] ])<EOL><DEDENT><DEDENT>member_cluster_general = list_math_addition(member_cluster1, member_cluster2)<EOL>member_cluster_general = list_math_division_number(member_cluster_general, len(cluster1) + len(cluster2))<EOL>member_cluster1 = list_math_division_number(member_cluster1, len(cluster1))<EOL>member_cluster2 = list_math_division_number(member_cluster2, len(cluster2))<EOL>distance_general = <NUM_LIT:0.0><EOL>distance_cluster1 = <NUM_LIT:0.0><EOL>distance_cluster2 = <NUM_LIT:0.0><EOL>for i in range(len(cluster1)):<EOL><INDENT>if data is None:<EOL><INDENT>distance_cluster1 += euclidean_distance_square(cluster1[i], member_cluster1)<EOL>distance_general += euclidean_distance_square(cluster1[i], member_cluster_general)<EOL><DEDENT>else:<EOL><INDENT>distance_cluster1 += euclidean_distance_square(data[ cluster1[i]], member_cluster1)<EOL>distance_general += euclidean_distance_square(data[ cluster1[i]], member_cluster_general)<EOL><DEDENT><DEDENT>for j in range(len(cluster2)):<EOL><INDENT>if data is None:<EOL><INDENT>distance_cluster2 += euclidean_distance_square(cluster2[j], member_cluster2)<EOL>distance_general += euclidean_distance_square(cluster2[j], member_cluster_general)<EOL><DEDENT>else:<EOL><INDENT>distance_cluster2 += euclidean_distance_square(data[ cluster2[j]], member_cluster2)<EOL>distance_general += euclidean_distance_square(data[ cluster2[j]], member_cluster_general)<EOL><DEDENT><DEDENT>return distance_general - distance_cluster1 - distance_cluster2<EOL>

!
    @brief Calculates variance increase distance between two clusters.
    @details Clusters can be represented by list of coordinates (in this case data shouldn't be specified),
             or by list of indexes of points from the data (represented by list of points), in this case
             data should be specified.

    @param[in] cluster1 (list): The first cluster.
    @param[in] cluster2 (list): The second cluster.
    @param[in] data (list): If specified than elements of clusters will be used as indexes,
               otherwise elements of cluster will be considered as points.

    @return (double) Average variance increase distance between two clusters.


def calculate_ellipse_description(covariance, scale = <NUM_LIT>):

eigh_values, eigh_vectors = numpy.linalg.eigh(covariance)<EOL>order = eigh_values.argsort()[::-<NUM_LIT:1>]<EOL>values, vectors = eigh_values[order], eigh_vectors[order]<EOL>angle = numpy.degrees(numpy.arctan2(*vectors[:,<NUM_LIT:0>][::-<NUM_LIT:1>]))<EOL>if <NUM_LIT:0.0> in values:<EOL><INDENT>return <NUM_LIT:0>, <NUM_LIT:0>, <NUM_LIT:0><EOL><DEDENT>width, height = <NUM_LIT> * scale * numpy.sqrt(values)<EOL>return angle, width, height<EOL>

!
    @brief Calculates description of ellipse using covariance matrix.

    @param[in] covariance (numpy.array): Covariance matrix for which ellipse area should be calculated.
    @param[in] scale (float): Scale of the ellipse.

    @return (float, float, float) Return ellipse description: angle, width, height.


def data_corners(data, data_filter = None):

dimensions = len(data[<NUM_LIT:0>])<EOL>bypass = data_filter<EOL>if bypass is None:<EOL><INDENT>bypass = range(len(data))<EOL><DEDENT>maximum_corner = list(data[bypass[<NUM_LIT:0>]][:])<EOL>minimum_corner = list(data[bypass[<NUM_LIT:0>]][:])<EOL>for index_point in bypass:<EOL><INDENT>for index_dimension in range(dimensions):<EOL><INDENT>if data[index_point][index_dimension] > maximum_corner[index_dimension]:<EOL><INDENT>maximum_corner[index_dimension] = data[index_point][index_dimension]<EOL><DEDENT>if data[index_point][index_dimension] < minimum_corner[index_dimension]:<EOL><INDENT>minimum_corner[index_dimension] = data[index_point][index_dimension]<EOL><DEDENT><DEDENT><DEDENT>return minimum_corner, maximum_corner<EOL>

!
    @brief Finds maximum and minimum corner in each dimension of the specified data.

    @param[in] data (list): List of points that should be analysed.
    @param[in] data_filter (list): List of indexes of the data that should be analysed,
                if it is 'None' then whole 'data' is analysed to obtain corners.

    @return (list) Tuple of two points that corresponds to minimum and maximum corner (min_corner, max_corner).


length = <NUM_LIT:0.0><EOL>for component in vector:<EOL><INDENT>length += component * component<EOL><DEDENT>length = length ** <NUM_LIT:0.5><EOL>return length<EOL>

!
    @brief Calculates norm of an input vector that is known as a vector length.

    @param[in] vector (list): The input vector whose length is calculated.

    @return (double) vector norm known as vector length.


if (value > <NUM_LIT:0.0>): <EOL><INDENT>return <NUM_LIT:1.0>;<EOL><DEDENT>return <NUM_LIT:0.0><EOL>

!
    @brief Calculates Heaviside function that represents step function.
    @details If input value is greater than 0 then returns 1, otherwise returns 0.

    @param[in] value (double): Argument of Heaviside function.

    @return (double) Value of Heaviside function.


time_start = time.clock();<EOL>result = executable_function(*args);<EOL>time_end = time.clock();<EOL>return (time_end - time_start, result)<EOL>

!
    @brief Executes specified method or function with measuring of execution time.

    @param[in] executable_function (pointer): Pointer to function or method.
    @param[in] args (*): Arguments of called function or method.

    @return (tuple) Execution time and result of execution of function or method (execution_time, result_execution).


def extract_number_oscillations(osc_dyn, index = <NUM_LIT:0>, amplitude_threshold = <NUM_LIT:1.0>):

number_oscillations = <NUM_LIT:0>;<EOL>waiting_differential = False;<EOL>threshold_passed = False;<EOL>high_level_trigger = True if (osc_dyn[<NUM_LIT:0>][index] > amplitude_threshold) else False;<EOL>for values in osc_dyn:<EOL><INDENT>if ( (values[index] >= amplitude_threshold) and (high_level_trigger is False) ):<EOL><INDENT>high_level_trigger = True;<EOL>threshold_passed = True;<EOL><DEDENT>elif ( (values[index] < amplitude_threshold) and (high_level_trigger is True) ):<EOL><INDENT>high_level_trigger = False;<EOL>threshold_passed = True;<EOL><DEDENT>if (threshold_passed is True):<EOL><INDENT>threshold_passed = False;<EOL>if (waiting_differential is True and high_level_trigger is False):<EOL><INDENT>number_oscillations += <NUM_LIT:1>;<EOL>waiting_differential = False;<EOL><DEDENT>else:<EOL><INDENT>waiting_differential = True;<EOL><DEDENT><DEDENT><DEDENT>return number_oscillations<EOL>

!
    @brief Extracts number of oscillations of specified oscillator.

    @param[in] osc_dyn (list): Dynamic of oscillators.
    @param[in] index (uint): Index of oscillator in dynamic.
    @param[in] amplitude_threshold (double): Amplitude threshold when oscillation is taken into account, for example,
                when oscillator amplitude is greater than threshold then oscillation is incremented.

    @return (uint) Number of oscillations of specified oscillator.


def allocate_sync_ensembles(dynamic, tolerance = <NUM_LIT:0.1>, threshold = <NUM_LIT:1.0>, ignore = None):

descriptors = [ [] for _ in range(len(dynamic[<NUM_LIT:0>])) ];<EOL>for index_dyn in range(<NUM_LIT:0>, len(dynamic[<NUM_LIT:0>]), <NUM_LIT:1>):<EOL><INDENT>if ((ignore is not None) and (index_dyn in ignore)):<EOL><INDENT>continue;<EOL><DEDENT>time_stop_simulation = len(dynamic) - <NUM_LIT:1>;<EOL>active_state = False;<EOL>if (dynamic[time_stop_simulation][index_dyn] > threshold):<EOL><INDENT>active_state = True;<EOL><DEDENT>if (active_state is True):<EOL><INDENT>while ( (dynamic[time_stop_simulation][index_dyn] > threshold) and (time_stop_simulation > <NUM_LIT:0>) ):<EOL><INDENT>time_stop_simulation -= <NUM_LIT:1>;<EOL><DEDENT>if (time_stop_simulation == <NUM_LIT:0>):<EOL><INDENT>continue;<EOL><DEDENT>active_state = False;<EOL><DEDENT>desc = [<NUM_LIT:0>, <NUM_LIT:0>, <NUM_LIT:0>]; <EOL>for t in range(time_stop_simulation, <NUM_LIT:0>, -<NUM_LIT:1>):<EOL><INDENT>if ( (dynamic[t][index_dyn] > threshold) and (active_state is False) ):<EOL><INDENT>desc[<NUM_LIT:0>] = t;<EOL>active_state = True;<EOL><DEDENT>elif ( (dynamic[t][index_dyn] < threshold) and (active_state is True) ):<EOL><INDENT>desc[<NUM_LIT:1>] = t;<EOL>active_state = False;<EOL>break;<EOL><DEDENT><DEDENT>if (desc == [<NUM_LIT:0>, <NUM_LIT:0>, <NUM_LIT:0>]):<EOL><INDENT>continue;<EOL><DEDENT>desc[<NUM_LIT:2>] = desc[<NUM_LIT:1>] + (desc[<NUM_LIT:0>] - desc[<NUM_LIT:1>]) / <NUM_LIT>;<EOL>descriptors[index_dyn] = desc;<EOL><DEDENT>sync_ensembles = [];<EOL>desc_sync_ensembles = [];<EOL>for index_desc in range(<NUM_LIT:0>, len(descriptors), <NUM_LIT:1>):<EOL><INDENT>if (descriptors[index_desc] == []):<EOL><INDENT>continue;<EOL><DEDENT>if (len(sync_ensembles) == <NUM_LIT:0>):<EOL><INDENT>desc_ensemble = descriptors[index_desc];<EOL>reducer = (desc_ensemble[<NUM_LIT:0>] - desc_ensemble[<NUM_LIT:1>]) * tolerance;<EOL>desc_ensemble[<NUM_LIT:0>] = desc_ensemble[<NUM_LIT:2>] + reducer;<EOL>desc_ensemble[<NUM_LIT:1>] = desc_ensemble[<NUM_LIT:2>] - reducer;<EOL>desc_sync_ensembles.append(desc_ensemble);<EOL>sync_ensembles.append([ index_desc ]);<EOL><DEDENT>else:<EOL><INDENT>oscillator_captured = False;<EOL>for index_ensemble in range(<NUM_LIT:0>, len(sync_ensembles), <NUM_LIT:1>):<EOL><INDENT>if ( (desc_sync_ensembles[index_ensemble][<NUM_LIT:0>] > descriptors[index_desc][<NUM_LIT:2>]) and (desc_sync_ensembles[index_ensemble][<NUM_LIT:1>] < descriptors[index_desc][<NUM_LIT:2>])):<EOL><INDENT>sync_ensembles[index_ensemble].append(index_desc);<EOL>oscillator_captured = True;<EOL>break;<EOL><DEDENT><DEDENT>if (oscillator_captured is False):<EOL><INDENT>desc_ensemble = descriptors[index_desc];<EOL>reducer = (desc_ensemble[<NUM_LIT:0>] - desc_ensemble[<NUM_LIT:1>]) * tolerance;<EOL>desc_ensemble[<NUM_LIT:0>] = desc_ensemble[<NUM_LIT:2>] + reducer;<EOL>desc_ensemble[<NUM_LIT:1>] = desc_ensemble[<NUM_LIT:2>] - reducer;<EOL>desc_sync_ensembles.append(desc_ensemble);<EOL>sync_ensembles.append([ index_desc ]);<EOL><DEDENT><DEDENT><DEDENT>return sync_ensembles<EOL>

!
    @brief Allocate clusters in line with ensembles of synchronous oscillators where each
           synchronous ensemble corresponds to only one cluster.

    @param[in] dynamic (dynamic): Dynamic of each oscillator.
    @param[in] tolerance (double): Maximum error for allocation of synchronous ensemble oscillators.
    @param[in] threshold (double): Amlitude trigger when spike is taken into account.
    @param[in] ignore (bool): Set of indexes that shouldn't be taken into account.

    @return (list) Grours (lists) of indexes of synchronous oscillators, for example,
            [ [index_osc1, index_osc3], [index_osc2], [index_osc4, index_osc5] ].


def draw_clusters(data, clusters, noise = [], marker_descr = '<STR_LIT:.>', hide_axes = False, axes = None, display_result = True):

<EOL>dimension = <NUM_LIT:0>;<EOL>if ( (data is not None) and (clusters is not None) ):<EOL><INDENT>dimension = len(data[<NUM_LIT:0>]);<EOL><DEDENT>elif ( (data is None) and (clusters is not None) ):<EOL><INDENT>dimension = len(clusters[<NUM_LIT:0>][<NUM_LIT:0>]);<EOL><DEDENT>else:<EOL><INDENT>raise NameError('<STR_LIT>');<EOL><DEDENT>"<STR_LIT>"<EOL>colors = [ '<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>', <EOL>'<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>',<EOL>'<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>',<EOL>'<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>' ];<EOL>if (len(clusters) > len(colors)):<EOL><INDENT>raise NameError('<STR_LIT>');<EOL><DEDENT>fig = plt.figure();<EOL>if (axes is None):<EOL><INDENT>if ((dimension) == <NUM_LIT:1> or (dimension == <NUM_LIT:2>)):<EOL><INDENT>axes = fig.add_subplot(<NUM_LIT>);<EOL><DEDENT>elif (dimension == <NUM_LIT:3>):<EOL><INDENT>axes = fig.gca(projection='<STR_LIT>');<EOL><DEDENT>else:<EOL><INDENT>raise NameError('<STR_LIT>');<EOL><DEDENT><DEDENT>color_index = <NUM_LIT:0>;<EOL>for cluster in clusters:<EOL><INDENT>color = colors[color_index];<EOL>for item in cluster:<EOL><INDENT>if (dimension == <NUM_LIT:1>):<EOL><INDENT>if (data is None):<EOL><INDENT>axes.plot(item[<NUM_LIT:0>], <NUM_LIT:0.0>, color = color, marker = marker_descr);<EOL><DEDENT>else:<EOL><INDENT>axes.plot(data[item][<NUM_LIT:0>], <NUM_LIT:0.0>, color = color, marker = marker_descr);<EOL><DEDENT><DEDENT>if (dimension == <NUM_LIT:2>):<EOL><INDENT>if (data is None):<EOL><INDENT>axes.plot(item[<NUM_LIT:0>], item[<NUM_LIT:1>], color = color, marker = marker_descr);<EOL><DEDENT>else:<EOL><INDENT>axes.plot(data[item][<NUM_LIT:0>], data[item][<NUM_LIT:1>], color = color, marker = marker_descr);<EOL><DEDENT><DEDENT>elif (dimension == <NUM_LIT:3>):<EOL><INDENT>if (data is None):<EOL><INDENT>axes.scatter(item[<NUM_LIT:0>], item[<NUM_LIT:1>], item[<NUM_LIT:2>], c = color, marker = marker_descr);<EOL><DEDENT>else:<EOL><INDENT>axes.scatter(data[item][<NUM_LIT:0>], data[item][<NUM_LIT:1>], data[item][<NUM_LIT:2>], c = color, marker = marker_descr);<EOL><DEDENT><DEDENT><DEDENT>color_index += <NUM_LIT:1>;<EOL><DEDENT>for item in noise:<EOL><INDENT>if (dimension == <NUM_LIT:1>):<EOL><INDENT>if (data is None):<EOL><INDENT>axes.plot(item[<NUM_LIT:0>], <NUM_LIT:0.0>, '<STR_LIT:w>' + marker_descr);<EOL><DEDENT>else:<EOL><INDENT>axes.plot(data[item][<NUM_LIT:0>], <NUM_LIT:0.0>, '<STR_LIT:w>' + marker_descr);<EOL><DEDENT><DEDENT>if (dimension == <NUM_LIT:2>):<EOL><INDENT>if (data is None):<EOL><INDENT>axes.plot(item[<NUM_LIT:0>], item[<NUM_LIT:1>], '<STR_LIT:w>' + marker_descr);<EOL><DEDENT>else:<EOL><INDENT>axes.plot(data[item][<NUM_LIT:0>], data[item][<NUM_LIT:1>], '<STR_LIT:w>' + marker_descr);<EOL><DEDENT><DEDENT>elif (dimension == <NUM_LIT:3>):<EOL><INDENT>if (data is None):<EOL><INDENT>axes.scatter(item[<NUM_LIT:0>], item[<NUM_LIT:1>], item[<NUM_LIT:2>], c = '<STR_LIT:w>', marker = marker_descr);<EOL><DEDENT>else:<EOL><INDENT>axes.scatter(data[item][<NUM_LIT:0>], data[item][<NUM_LIT:1>], data[item][<NUM_LIT:2>], c = '<STR_LIT:w>', marker = marker_descr);<EOL><DEDENT><DEDENT><DEDENT>axes.grid(True);<EOL>if (hide_axes is True):<EOL><INDENT>axes.xaxis.set_ticklabels([]);<EOL>axes.yaxis.set_ticklabels([]);<EOL>if (dimension == <NUM_LIT:3>):<EOL><INDENT>axes.zaxis.set_ticklabels([]);<EOL><DEDENT><DEDENT>if (display_result is True):<EOL><INDENT>plt.show();<EOL><DEDENT>return axes<EOL>

!
    @brief Displays clusters for data in 2D or 3D.

    @param[in] data (list): Points that are described by coordinates represented.
    @param[in] clusters (list): Clusters that are represented by lists of indexes where each index corresponds to point in data.
    @param[in] noise (list): Points that are regarded to noise.
    @param[in] marker_descr (string): Marker for displaying points.
    @param[in] hide_axes (bool): If True - axes is not displayed.
    @param[in] axes (ax) Matplotlib axes where clusters should be drawn, if it is not specified (None) then new plot will be created.
    @param[in] display_result (bool): If specified then matplotlib axes will be used for drawing and plot will not be shown.

    @return (ax) Matplotlib axes where drawn clusters are presented.


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):

number_lines = <NUM_LIT:0>;<EOL>stage_xlim = None;<EOL>if (x_lim is not None):<EOL><INDENT>stage_xlim = x_lim;<EOL><DEDENT>elif (len(t) > <NUM_LIT:0>):<EOL><INDENT>stage_xlim = [<NUM_LIT:0>, t[len(t) - <NUM_LIT:1>]];<EOL><DEDENT>if ( (isinstance(separate, bool) is True) and (separate is True) ):<EOL><INDENT>if (isinstance(dyn[<NUM_LIT:0>], list) is True):<EOL><INDENT>number_lines = len(dyn[<NUM_LIT:0>]);<EOL><DEDENT>else:<EOL><INDENT>number_lines = <NUM_LIT:1>;<EOL><DEDENT><DEDENT>elif (isinstance(separate, list) is True):<EOL><INDENT>number_lines = len(separate);<EOL><DEDENT>else:<EOL><INDENT>number_lines = <NUM_LIT:1>;<EOL><DEDENT>dysplay_result = False;<EOL>if (axes is None):<EOL><INDENT>dysplay_result = True;<EOL>(fig, axes) = plt.subplots(number_lines, <NUM_LIT:1>);<EOL><DEDENT>if (isinstance(dyn[<NUM_LIT:0>], list) is True):<EOL><INDENT>num_items = len(dyn[<NUM_LIT:0>]);<EOL>for index in range(<NUM_LIT:0>, num_items, <NUM_LIT:1>):<EOL><INDENT>y = [item[index] for item in dyn];<EOL>if (number_lines > <NUM_LIT:1>):<EOL><INDENT>index_stage = -<NUM_LIT:1>;<EOL>if (isinstance(separate, bool) is True):<EOL><INDENT>index_stage = index;<EOL><DEDENT>elif (isinstance(separate, list) is True):<EOL><INDENT>for index_group in range(<NUM_LIT:0>, len(separate), <NUM_LIT:1>):<EOL><INDENT>if (index in separate[index_group]): <EOL><INDENT>index_stage = index_group;<EOL>break;<EOL><DEDENT><DEDENT><DEDENT>if (index_stage != -<NUM_LIT:1>):<EOL><INDENT>if (index_stage != number_lines - <NUM_LIT:1>):<EOL><INDENT>axes[index_stage].get_xaxis().set_visible(False);<EOL><DEDENT>axes[index_stage].plot(t, y, '<STR_LIT>', linewidth = <NUM_LIT:0.5>); <EOL>set_ax_param(axes[index_stage], x_title, y_title, stage_xlim, y_lim, x_labels, y_labels, True);<EOL><DEDENT><DEDENT>else:<EOL><INDENT>axes.plot(t, y, '<STR_LIT>', linewidth = <NUM_LIT:0.5>);<EOL>set_ax_param(axes, x_title, y_title, stage_xlim, y_lim, x_labels, y_labels, True);<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>axes.plot(t, dyn, '<STR_LIT>', linewidth = <NUM_LIT:0.5>);<EOL>set_ax_param(axes, x_title, y_title, stage_xlim, y_lim, x_labels, y_labels, True);<EOL><DEDENT>if (dysplay_result is True):<EOL><INDENT>plt.show();<EOL><DEDENT>return axes<EOL>

!
    @brief Draw dynamics of neurons (oscillators) in the network.
    @details It draws if matplotlib is not specified (None), othewise it should be performed manually.

    @param[in] t (list): Values of time (used by x axis).
    @param[in] dyn (list): Values of output of oscillators (used by y axis).
    @param[in] x_title (string): Title for Y.
    @param[in] y_title (string): Title for X.
    @param[in] x_lim (double): X limit.
    @param[in] y_lim (double): Y limit.
    @param[in] x_labels (bool): If True - shows X labels.
    @param[in] y_labels (bool): If True - shows Y labels.
    @param[in] separate (list): Consists of lists of oscillators where each such list consists of oscillator indexes that will be shown on separated stage.
    @param[in] axes (ax): If specified then matplotlib axes will be used for drawing and plot will not be shown.

    @return (ax) Axes of matplotlib.


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):

from matplotlib.font_manager import FontProperties;<EOL>from matplotlib import rcParams;<EOL>if (_platform == "<STR_LIT>") or (_platform == "<STR_LIT>"):<EOL><INDENT>rcParams['<STR_LIT>'] = ['<STR_LIT>'];<EOL><DEDENT>else:<EOL><INDENT>rcParams['<STR_LIT>'] = ['<STR_LIT>'];<EOL><DEDENT>rcParams['<STR_LIT>'] = <NUM_LIT:12>;<EOL>surface_font = FontProperties();<EOL>if (_platform == "<STR_LIT>") or (_platform == "<STR_LIT>"):<EOL><INDENT>surface_font.set_name('<STR_LIT>');<EOL><DEDENT>else:<EOL><INDENT>surface_font.set_name('<STR_LIT>');<EOL><DEDENT>surface_font.set_size('<STR_LIT>');<EOL>if (y_title is not None): ax.set_ylabel(y_title, fontproperties = surface_font);<EOL>if (x_title is not None): ax.set_xlabel(x_title, fontproperties = surface_font);<EOL>if (x_lim is not None): ax.set_xlim(x_lim[<NUM_LIT:0>], x_lim[<NUM_LIT:1>]);<EOL>if (y_lim is not None): ax.set_ylim(y_lim[<NUM_LIT:0>], y_lim[<NUM_LIT:1>]);<EOL>if (x_labels is False): ax.xaxis.set_ticklabels([]);<EOL>if (y_labels is False): ax.yaxis.set_ticklabels([]);<EOL>ax.grid(grid)<EOL>

!
    @brief Sets parameters for matplotlib ax.

    @param[in] ax (Axes): Axes for which parameters should applied.
    @param[in] x_title (string): Title for Y.
    @param[in] y_title (string): Title for X.
    @param[in] x_lim (double): X limit.
    @param[in] y_lim (double): Y limit.
    @param[in] x_labels (bool): If True - shows X labels.
    @param[in] y_labels (bool): If True - shows Y labels.
    @param[in] grid (bool): If True - shows grid.


def draw_dynamics_set(dynamics, xtitle = None, ytitle = None, xlim = None, ylim = None, xlabels = False, ylabels = False):

<EOL>number_dynamics = len(dynamics);<EOL>if (number_dynamics == <NUM_LIT:1>):<EOL><INDENT>draw_dynamics(dynamics[<NUM_LIT:0>][<NUM_LIT:0>], dynamics[<NUM_LIT:0>][<NUM_LIT:1>], xtitle, ytitle, xlim, ylim, xlabels, ylabels);<EOL>return;<EOL><DEDENT>number_cols = int(numpy.ceil(number_dynamics ** <NUM_LIT:0.5>));<EOL>number_rows = int(numpy.ceil(number_dynamics / number_cols));<EOL>real_index = <NUM_LIT:0>, <NUM_LIT:0>;<EOL>double_indexer = True;<EOL>if ( (number_cols == <NUM_LIT:1>) or (number_rows == <NUM_LIT:1>) ):<EOL><INDENT>real_index = <NUM_LIT:0>;<EOL>double_indexer = False;<EOL><DEDENT>(_, axarr) = plt.subplots(number_rows, number_cols);<EOL>for dynamic in dynamics:<EOL><INDENT>axarr[real_index] = draw_dynamics(dynamic[<NUM_LIT:0>], dynamic[<NUM_LIT:1>], xtitle, ytitle, xlim, ylim, xlabels, ylabels, axes = axarr[real_index]);<EOL>if (double_indexer is True):<EOL><INDENT>real_index = real_index[<NUM_LIT:0>], real_index[<NUM_LIT:1>] + <NUM_LIT:1>;<EOL>if (real_index[<NUM_LIT:1>] >= number_cols):<EOL><INDENT>real_index = real_index[<NUM_LIT:0>] + <NUM_LIT:1>, <NUM_LIT:0>; <EOL><DEDENT><DEDENT>else:<EOL><INDENT>real_index += <NUM_LIT:1>;<EOL><DEDENT><DEDENT>plt.show()<EOL>

!
    @brief Draw lists of dynamics of neurons (oscillators) in the network.

    @param[in] dynamics (list): List of network outputs that are represented by values of output of oscillators (used by y axis).
    @param[in] xtitle (string): Title for Y.
    @param[in] ytitle (string): Title for X.
    @param[in] xlim (double): X limit.
    @param[in] ylim (double): Y limit.
    @param[in] xlabels (bool): If True - shows X labels.
    @param[in] ylabels (bool): If True - shows Y labels.


def draw_image_color_segments(source, clusters, hide_axes = True):

image_source = Image.open(source);<EOL>image_size = image_source.size;<EOL>(fig, axarr) = plt.subplots(<NUM_LIT:1>, <NUM_LIT:2>);<EOL>plt.setp([ax for ax in axarr], visible = False);<EOL>available_colors = [ (<NUM_LIT:0>, <NUM_LIT>, <NUM_LIT>),   (<NUM_LIT>, <NUM_LIT>, <NUM_LIT>),   (<NUM_LIT>, <NUM_LIT>, <NUM_LIT>),<EOL>(<NUM_LIT:255>, <NUM_LIT>, <NUM_LIT:0>),   (<NUM_LIT:0>, <NUM_LIT:0>, <NUM_LIT:0>),       (<NUM_LIT>, <NUM_LIT>, <NUM_LIT>),<EOL>(<NUM_LIT:255>, <NUM_LIT>, <NUM_LIT>), (<NUM_LIT>, <NUM_LIT>, <NUM_LIT>), (<NUM_LIT>, <NUM_LIT>, <NUM_LIT>), <EOL>(<NUM_LIT:200>, <NUM_LIT>, <NUM_LIT>), (<NUM_LIT>, <NUM_LIT:0>, <NUM_LIT>),    (<NUM_LIT:255>, <NUM_LIT>, <NUM_LIT>),<EOL>(<NUM_LIT>, <NUM_LIT>, <NUM_LIT>),   (<NUM_LIT>, <NUM_LIT>, <NUM_LIT>), (<NUM_LIT:255>, <NUM_LIT>, <NUM_LIT>),<EOL>(<NUM_LIT>, <NUM_LIT>, <NUM_LIT>), (<NUM_LIT>, <NUM_LIT>, <NUM_LIT>),  (<NUM_LIT>, <NUM_LIT>, <NUM_LIT>),<EOL>(<NUM_LIT>, <NUM_LIT>, <NUM_LIT>) ];<EOL>image_color_segments = [(<NUM_LIT:255>, <NUM_LIT:255>, <NUM_LIT:255>)] * (image_size[<NUM_LIT:0>] * image_size[<NUM_LIT:1>]);<EOL>for index_segment in range(len(clusters)):<EOL><INDENT>for index_pixel in clusters[index_segment]:<EOL><INDENT>image_color_segments[index_pixel] = available_colors[index_segment];<EOL><DEDENT><DEDENT>stage = array(image_color_segments, numpy.uint8);<EOL>stage = numpy.reshape(stage, (image_size[<NUM_LIT:1>], image_size[<NUM_LIT:0>]) + ((<NUM_LIT:3>),)); <EOL>image_cluster = Image.fromarray(stage, '<STR_LIT>');<EOL>axarr[<NUM_LIT:0>].imshow(image_source, interpolation = '<STR_LIT:none>');<EOL>axarr[<NUM_LIT:1>].imshow(image_cluster, interpolation = '<STR_LIT:none>');<EOL>for i in range(<NUM_LIT:2>):<EOL><INDENT>plt.setp(axarr[i], visible = True);<EOL>if (hide_axes is True):<EOL><INDENT>axarr[i].xaxis.set_ticklabels([]);<EOL>axarr[i].yaxis.set_ticklabels([]);<EOL>axarr[i].xaxis.set_ticks_position('<STR_LIT:none>');<EOL>axarr[i].yaxis.set_ticks_position('<STR_LIT:none>');<EOL><DEDENT><DEDENT>plt.show()<EOL>

!
    @brief Shows image segments using colored image.
    @details Each color on result image represents allocated segment. The first image is initial and other is result of segmentation.

    @param[in] source (string): Path to image.
    @param[in] clusters (list): List of clusters (allocated segments of image) where each cluster
                                consists of indexes of pixel from source image.
    @param[in] hide_axes (bool): If True then axes will not be displayed.


def draw_image_mask_segments(source, clusters, hide_axes = True):

if (len(clusters) == <NUM_LIT:0>):<EOL><INDENT>print("<STR_LIT>")<EOL>return;<EOL><DEDENT>image_source = Image.open(source);<EOL>image_size = image_source.size;<EOL>number_clusters = len(clusters) + <NUM_LIT:1>; <EOL>number_cols = int(numpy.ceil(number_clusters ** <NUM_LIT:0.5>));<EOL>number_rows = int(numpy.ceil(number_clusters / number_cols));<EOL>real_index = <NUM_LIT:0>, <NUM_LIT:0>;<EOL>double_indexer = True;<EOL>if ( (number_cols == <NUM_LIT:1>) or (number_rows == <NUM_LIT:1>) ):<EOL><INDENT>real_index = <NUM_LIT:0>;<EOL>double_indexer = False;<EOL><DEDENT>(fig, axarr) = plt.subplots(number_rows, number_cols);<EOL>plt.setp([ax for ax in axarr], visible = False);<EOL>axarr[real_index].imshow(image_source, interpolation = '<STR_LIT:none>');<EOL>plt.setp(axarr[real_index], visible = True);<EOL>if (hide_axes is True):<EOL><INDENT>axarr[real_index].xaxis.set_ticklabels([]);<EOL>axarr[real_index].yaxis.set_ticklabels([]);<EOL>axarr[real_index].xaxis.set_ticks_position('<STR_LIT:none>');<EOL>axarr[real_index].yaxis.set_ticks_position('<STR_LIT:none>');<EOL><DEDENT>if (double_indexer is True):<EOL><INDENT>real_index = <NUM_LIT:0>, <NUM_LIT:1>;<EOL><DEDENT>else:<EOL><INDENT>real_index += <NUM_LIT:1>;<EOL><DEDENT>for cluster in clusters:<EOL><INDENT>stage_cluster = [(<NUM_LIT:255>, <NUM_LIT:255>, <NUM_LIT:255>)] * (image_size[<NUM_LIT:0>] * image_size[<NUM_LIT:1>]);<EOL>for index in cluster:<EOL><INDENT>stage_cluster[index] = (<NUM_LIT:0>, <NUM_LIT:0>, <NUM_LIT:0>);<EOL><DEDENT>stage = array(stage_cluster, numpy.uint8);<EOL>stage = numpy.reshape(stage, (image_size[<NUM_LIT:1>], image_size[<NUM_LIT:0>]) + ((<NUM_LIT:3>),)); <EOL>image_cluster = Image.fromarray(stage, '<STR_LIT>');<EOL>axarr[real_index].imshow(image_cluster, interpolation = '<STR_LIT:none>');<EOL>plt.setp(axarr[real_index], visible = True);<EOL>if (hide_axes is True):<EOL><INDENT>axarr[real_index].xaxis.set_ticklabels([]);<EOL>axarr[real_index].yaxis.set_ticklabels([]);<EOL>axarr[real_index].xaxis.set_ticks_position('<STR_LIT:none>');<EOL>axarr[real_index].yaxis.set_ticks_position('<STR_LIT:none>');<EOL><DEDENT>if (double_indexer is True):<EOL><INDENT>real_index = real_index[<NUM_LIT:0>], real_index[<NUM_LIT:1>] + <NUM_LIT:1>;<EOL>if (real_index[<NUM_LIT:1>] >= number_cols):<EOL><INDENT>real_index = real_index[<NUM_LIT:0>] + <NUM_LIT:1>, <NUM_LIT:0>; <EOL><DEDENT><DEDENT>else:<EOL><INDENT>real_index += <NUM_LIT:1>;<EOL><DEDENT><DEDENT>plt.show()<EOL>

!
    @brief Shows image segments using black masks.
    @details Each black mask of allocated segment is presented on separate plot.
             The first image is initial and others are black masks of segments.

    @param[in] source (string): Path to image.
    @param[in] clusters (list): List of clusters (allocated segments of image) where each cluster
                                consists of indexes of pixel from source image.
    @param[in] hide_axes (bool): If True then axes will not be displayed.


dimension = <NUM_LIT:1>;<EOL>linear_sum = <NUM_LIT:0.0>;<EOL>list_representation = (type(list_vector[<NUM_LIT:0>]) == list);<EOL>if (list_representation is True):<EOL><INDENT>dimension = len(list_vector[<NUM_LIT:0>]);<EOL>linear_sum = [<NUM_LIT:0>] * dimension;<EOL><DEDENT>for index_element in range(<NUM_LIT:0>, len(list_vector)):<EOL><INDENT>if (list_representation is True):<EOL><INDENT>for index_dimension in range(<NUM_LIT:0>, dimension):<EOL><INDENT>linear_sum[index_dimension] += list_vector[index_element][index_dimension];<EOL><DEDENT><DEDENT>else:<EOL><INDENT>linear_sum += list_vector[index_element];<EOL><DEDENT><DEDENT>return linear_sum<EOL>

!
    @brief Calculates linear sum of vector that is represented by list, each element can be represented by list - multidimensional elements.

    @param[in] list_vector (list): Input vector.

    @return (list|double) Linear sum of vector that can be represented by list in case of multidimensional elements.


square_sum = <NUM_LIT:0.0>;<EOL>list_representation = (type(list_vector[<NUM_LIT:0>]) == list);<EOL>for index_element in range(<NUM_LIT:0>, len(list_vector)):<EOL><INDENT>if (list_representation is True):<EOL><INDENT>square_sum += sum(list_math_multiplication(list_vector[index_element], list_vector[index_element]));<EOL><DEDENT>else:<EOL><INDENT>square_sum += list_vector[index_element] * list_vector[index_element];<EOL><DEDENT><DEDENT>return square_sum<EOL>

!
    @brief Calculates square sum of vector that is represented by list, each element can be represented by list - multidimensional elements.

    @param[in] list_vector (list): Input vector.

    @return (double) Square sum of vector.


return [a[i] - b[i] for i in range(len(a))]<EOL>

!
    @brief Calculates subtraction of two lists.
    @details Each element from list 'a' is subtracted by element from list 'b' accordingly.

    @param[in] a (list): List of elements that supports mathematical subtraction.
    @param[in] b (list): List of elements that supports mathematical subtraction.

    @return (list) Results of subtraction of two lists.


return [a[i] - b for i in range(len(a))]<EOL>

!
    @brief Calculates subtraction between list and number.
    @details Each element from list 'a' is subtracted by number 'b'.

    @param[in] a (list): List of elements that supports mathematical subtraction.
    @param[in] b (list): Value that supports mathematical subtraction.

    @return (list) Results of subtraction between list and number.


return [a[i] + b[i] for i in range(len(a))]<EOL>

!
    @brief Addition of two lists.
    @details Each element from list 'a' is added to element from list 'b' accordingly.

    @param[in] a (list): List of elements that supports mathematic addition..
    @param[in] b (list): List of elements that supports mathematic addition..

    @return (list) Results of addtion of two lists.


return [a[i] + b for i in range(len(a))]<EOL>

!
    @brief Addition between list and number.
    @details Each element from list 'a' is added to number 'b'.

    @param[in] a (list): List of elements that supports mathematic addition.
    @param[in] b (double): Value that supports mathematic addition.

    @return (list) Result of addtion of two lists.


return [a[i] / b for i in range(len(a))]<EOL>

!
    @brief Division between list and number.
    @details Each element from list 'a' is divided by number 'b'.

    @param[in] a (list): List of elements that supports mathematic division.
    @param[in] b (double): Value that supports mathematic division.

    @return (list) Result of division between list and number.


return [a[i] / b[i] for i in range(len(a))]<EOL>

!
    @brief Division of two lists.
    @details Each element from list 'a' is divided by element from list 'b' accordingly.

    @param[in] a (list): List of elements that supports mathematic division.
    @param[in] b (list): List of elements that supports mathematic division.

    @return (list) Result of division of two lists.


return [a[i] * b for i in range(len(a))]<EOL>

!
    @brief Multiplication between list and number.
    @details Each element from list 'a' is multiplied by number 'b'.

    @param[in] a (list): List of elements that supports mathematic division.
    @param[in] b (double): Number that supports mathematic division.

    @return (list) Result of division between list and number.


return [a[i] * b[i] for i in range(len(a))]<EOL>

!
    @brief Multiplication of two lists.
    @details Each element from list 'a' is multiplied by element from list 'b' accordingly.

    @param[in] a (list): List of elements that supports mathematic multiplication.
    @param[in] b (list): List of elements that supports mathematic multiplication.

    @return (list) Result of multiplication of elements in two lists.


distance = euclidean_distance_square(point1, point2)<EOL>return distance ** <NUM_LIT:0.5><EOL>

!
    @brief Calculate Euclidean distance between two vectors.
    @details The Euclidean between vectors (points) a and b is calculated by following formula:

    \f[
    dist(a, b) = \sqrt{ \sum_{i=0}^{N}(a_{i} - b_{i})^{2} };
    \f]

    Where N is a length of each vector.

    @param[in] point1 (array_like): The first vector.
    @param[in] point2 (array_like): The second vector.

    @return (double) Euclidean distance between two vectors.

    @see euclidean_distance_square, manhattan_distance, chebyshev_distance


return numpy.sum(numpy.sqrt(numpy.square(object1 - object2)), axis=<NUM_LIT:1>).T<EOL>

!
    @brief Calculate Euclidean distance between two objects using numpy.

    @param[in] object1 (array_like): The first array_like object.
    @param[in] object2 (array_like): The second array_like object.

    @return (double) Euclidean distance between two objects.


distance = <NUM_LIT:0.0><EOL>for i in range(len(point1)):<EOL><INDENT>distance += (point1[i] - point2[i]) ** <NUM_LIT><EOL><DEDENT>return distance<EOL>

!
    @brief Calculate square Euclidean distance between two vectors.

    \f[
    dist(a, b) = \sum_{i=0}^{N}(a_{i} - b_{i})^{2};
    \f]

    @param[in] point1 (array_like): The first vector.
    @param[in] point2 (array_like): The second vector.

    @return (double) Square Euclidean distance between two vectors.

    @see euclidean_distance, manhattan_distance, chebyshev_distance


return numpy.sum(numpy.square(object1 - object2), axis=<NUM_LIT:1>).T<EOL>

!
    @brief Calculate square Euclidean distance between two objects using numpy.

    @param[in] object1 (array_like): The first array_like object.
    @param[in] object2 (array_like): The second array_like object.

    @return (double) Square Euclidean distance between two objects.


distance = <NUM_LIT:0.0><EOL>dimension = len(point1)<EOL>for i in range(dimension):<EOL><INDENT>distance += abs(point1[i] - point2[i])<EOL><DEDENT>return distance<EOL>

!
    @brief Calculate Manhattan distance between between two vectors.

    \f[
    dist(a, b) = \sum_{i=0}^{N}\left | a_{i} - b_{i} \right |;
    \f]

    @param[in] point1 (array_like): The first vector.
    @param[in] point2 (array_like): The second vector.

    @return (double) Manhattan distance between two vectors.

    @see euclidean_distance_square, euclidean_distance, chebyshev_distance


return numpy.sum(numpy.absolute(object1 - object2), axis=<NUM_LIT:1>).T<EOL>

!
    @brief Calculate Manhattan distance between two objects using numpy.

    @param[in] object1 (array_like): The first array_like object.
    @param[in] object2 (array_like): The second array_like object.

    @return (double) Manhattan distance between two objects.


distance = <NUM_LIT:0.0><EOL>dimension = len(point1)<EOL>for i in range(dimension):<EOL><INDENT>distance = max(distance, abs(point1[i] - point2[i]))<EOL><DEDENT>return distance<EOL>

!
    @brief Calculate Chebyshev distance between between two vectors.

    \f[
    dist(a, b) = \max_{}i\left (\left | a_{i} - b_{i} \right |\right );
    \f]

    @param[in] point1 (array_like): The first vector.
    @param[in] point2 (array_like): The second vector.

    @return (double) Chebyshev distance between two vectors.

    @see euclidean_distance_square, euclidean_distance, minkowski_distance


return numpy.max(numpy.absolute(object1 - object2), axis=<NUM_LIT:1>).T<EOL>

!
    @brief Calculate Chebyshev distance between two objects using numpy.

    @param[in] object1 (array_like): The first array_like object.
    @param[in] object2 (array_like): The second array_like object.

    @return (double) Chebyshev distance between two objects.


def minkowski_distance(point1, point2, degree=<NUM_LIT:2>):

distance = <NUM_LIT:0.0><EOL>for i in range(len(point1)):<EOL><INDENT>distance += (point1[i] - point2[i]) ** degree<EOL><DEDENT>return distance ** (<NUM_LIT:1.0> / degree)<EOL>

!
    @brief Calculate Minkowski distance between two vectors.

    \f[
    dist(a, b) = \sqrt[p]{ \sum_{i=0}^{N}\left(a_{i} - b_{i}\right)^{p} };
    \f]

    @param[in] point1 (array_like): The first vector.
    @param[in] point2 (array_like): The second vector.
    @param[in] degree (numeric): Degree of that is used for Minkowski distance.

    @return (double) Minkowski distance between two vectors.

    @see euclidean_distance


def minkowski_distance_numpy(object1, object2, degree=<NUM_LIT:2>):

return numpy.sum(numpy.power(numpy.power(object1 - object2, degree), <NUM_LIT:1>/degree), axis=<NUM_LIT:1>).T<EOL>

!
    @brief Calculate Minkowski distance between objects using numpy.

    @param[in] object1 (array_like): The first array_like object.
    @param[in] object2 (array_like): The second array_like object.
    @param[in] degree (numeric): Degree of that is used for Minkowski distance.

    @return (double) Minkowski distance between two object.


distance = <NUM_LIT:0.0><EOL>for i in range(len(point1)):<EOL><INDENT>divider = abs(point1[i]) + abs(point2[i])<EOL>if divider == <NUM_LIT:0.0>:<EOL><INDENT>continue<EOL><DEDENT>distance += abs(point1[i] - point2[i]) / divider<EOL><DEDENT>return distance<EOL>

!
    @brief Calculate Canberra distance between two vectors.

    \f[
    dist(a, b) = \sum_{i=0}^{N}\frac{\left | a_{i} - b_{i} \right |}{\left | a_{i} \right | + \left | b_{i} \right |};
    \f]

    @param[in] point1 (array_like): The first vector.
    @param[in] point2 (array_like): The second vector.

    @return (float) Canberra distance between two objects.


with numpy.errstate(divide='<STR_LIT:ignore>', invalid='<STR_LIT:ignore>'):<EOL><INDENT>result = numpy.divide(numpy.abs(object1 - object2), numpy.abs(object1) + numpy.abs(object2))<EOL><DEDENT>if len(result.shape) > <NUM_LIT:1>:<EOL><INDENT>return numpy.sum(numpy.nan_to_num(result), axis=<NUM_LIT:1>).T<EOL><DEDENT>else:<EOL><INDENT>return numpy.sum(numpy.nan_to_num(result))<EOL><DEDENT>

!
    @brief Calculate Canberra distance between two objects using numpy.

    @param[in] object1 (array_like): The first vector.
    @param[in] object2 (array_like): The second vector.

    @return (float) Canberra distance between two objects.


distance = <NUM_LIT:0.0><EOL>for i in range(len(point1)):<EOL><INDENT>divider = abs(point1[i]) + abs(point2[i])<EOL>if divider == <NUM_LIT:0.0>:<EOL><INDENT>continue<EOL><DEDENT>distance += ((point1[i] - point2[i]) ** <NUM_LIT>) / divider<EOL><DEDENT>return distance<EOL>

!
    @brief Calculate Chi square distance between two vectors.

    \f[
    dist(a, b) = \sum_{i=0}^{N}\frac{\left ( a_{i} - b_{i} \right )^{2}}{\left | a_{i} \right | + \left | b_{i} \right |};
    \f]

    @param[in] point1 (array_like): The first vector.
    @param[in] point2 (array_like): The second vector.

    @return (float) Chi square distance between two objects.


with numpy.errstate(divide='<STR_LIT:ignore>', invalid='<STR_LIT:ignore>'):<EOL><INDENT>result = numpy.divide(numpy.power(object1 - object2, <NUM_LIT:2>), numpy.abs(object1) + numpy.abs(object2))<EOL><DEDENT>if len(result.shape) > <NUM_LIT:1>:<EOL><INDENT>return numpy.sum(numpy.nan_to_num(result), axis=<NUM_LIT:1>).T<EOL><DEDENT>else:<EOL><INDENT>return numpy.sum(numpy.nan_to_num(result))<EOL><DEDENT>

!
    @brief Calculate Chi square distance between two vectors using numpy.

    @param[in] object1 (array_like): The first vector.
    @param[in] object2 (array_like): The second vector.

    @return (float) Chi square distance between two objects.


def __init__(self, metric_type, **kwargs):

self.__type = metric_type<EOL>self.__args = kwargs<EOL>self.__func = self.__args.get('<STR_LIT>', None)<EOL>self.__numpy = self.__args.get('<STR_LIT>', False)<EOL>self.__calculator = self.__create_distance_calculator()<EOL>

!
        @brief Creates distance metric instance for calculation distance between two points.

        @param[in] metric_type (type_metric):
        @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'numpy_usage' 'func' and corresponding additional argument for
                    for specific metric types).

        Keyword Args:

            - func (callable): Callable object with two arguments (point #1 and point #2) or (object #1 and object #2) in case of numpy usage.
                                This argument is used only if metric is 'type_metric.USER_DEFINED'.
            - degree (numeric): Only for 'type_metric.MINKOWSKI' - degree of Minkowski equation.
            - numpy_usage (bool): If True then numpy is used for calculation (by default is False).


return self.__calculator(point1, point2)<EOL>

!
        @brief Calculates distance between two points.

        @param[in] point1 (list): The first point.
        @param[in] point2 (list): The second point.

        @return (double) Distance between two points.


return self.__type<EOL>

!
        @brief Return type of distance metric that is used.

        @return (type_metric) Type of distance metric.


return self.__args<EOL>

!
        @brief Return additional arguments that are used by distance metric.

        @return (dict) Additional arguments.


return self.__func<EOL>

!
        @brief Return user-defined function for calculation distance metric.

        @return (callable): User-defined distance metric function.


self.__numpy = True<EOL>if self.__type != type_metric.USER_DEFINED:<EOL><INDENT>self.__calculator = self.__create_distance_calculator()<EOL><DEDENT>

!
        @brief Start numpy for distance calculation.
        @details Useful in case matrices to increase performance. No effect in case of type_metric.USER_DEFINED type.


self.__numpy = False<EOL>self.__calculator = self.__create_distance_calculator()<EOL>

!
        @brief Stop using numpy for distance calculation.
        @details Useful in case of big amount of small data portion when numpy call is longer than calculation itself.
                  No effect in case of type_metric.USER_DEFINED type.


if self.__numpy is True:<EOL><INDENT>return self.__create_distance_calculator_numpy()<EOL><DEDENT>return self.__create_distance_calculator_basic()<EOL>

!
        @brief Creates distance metric calculator.

        @return (callable) Callable object of distance metric calculator.


if self.__type == type_metric.EUCLIDEAN:<EOL><INDENT>return euclidean_distance<EOL><DEDENT>elif self.__type == type_metric.EUCLIDEAN_SQUARE:<EOL><INDENT>return euclidean_distance_square<EOL><DEDENT>elif self.__type == type_metric.MANHATTAN:<EOL><INDENT>return manhattan_distance<EOL><DEDENT>elif self.__type == type_metric.CHEBYSHEV:<EOL><INDENT>return chebyshev_distance<EOL><DEDENT>elif self.__type == type_metric.MINKOWSKI:<EOL><INDENT>return lambda point1, point2: minkowski_distance(point1, point2, self.__args.get('<STR_LIT>', <NUM_LIT:2>))<EOL><DEDENT>elif self.__type == type_metric.CANBERRA:<EOL><INDENT>return canberra_distance<EOL><DEDENT>elif self.__type == type_metric.CHI_SQUARE:<EOL><INDENT>return chi_square_distance<EOL><DEDENT>elif self.__type == type_metric.USER_DEFINED:<EOL><INDENT>return self.__func<EOL><DEDENT>else:<EOL><INDENT>raise ValueError("<STR_LIT>", self.__type)<EOL><DEDENT>

!
        @brief Creates distance metric calculator that does not use numpy.

        @return (callable) Callable object of distance metric calculator.


if self.__type == type_metric.EUCLIDEAN:<EOL><INDENT>return euclidean_distance_numpy<EOL><DEDENT>elif self.__type == type_metric.EUCLIDEAN_SQUARE:<EOL><INDENT>return euclidean_distance_square_numpy<EOL><DEDENT>elif self.__type == type_metric.MANHATTAN:<EOL><INDENT>return manhattan_distance_numpy<EOL><DEDENT>elif self.__type == type_metric.CHEBYSHEV:<EOL><INDENT>return chebyshev_distance_numpy<EOL><DEDENT>elif self.__type == type_metric.MINKOWSKI:<EOL><INDENT>return lambda object1, object2: minkowski_distance_numpy(object1, object2, self.__args.get('<STR_LIT>', <NUM_LIT:2>))<EOL><DEDENT>elif self.__type == type_metric.CANBERRA:<EOL><INDENT>return canberra_distance_numpy<EOL><DEDENT>elif self.__type == type_metric.CHI_SQUARE:<EOL><INDENT>return chi_square_distance_numpy<EOL><DEDENT>elif self.__type == type_metric.USER_DEFINED:<EOL><INDENT>return self.__func<EOL><DEDENT>else:<EOL><INDENT>raise ValueError("<STR_LIT>", self.__type)<EOL><DEDENT>

!
        @brief Creates distance metric calculator that uses numpy.

        @return (callable) Callable object of distance metric calculator.


file = open(filename, '<STR_LIT:r>');<EOL>comments = "<STR_LIT>";<EOL>space_descr = [];<EOL>data = [];<EOL>data_type = None;<EOL>map_data_repr = dict();   <EOL>for line in file:<EOL><INDENT>if (line[<NUM_LIT:0>] == '<STR_LIT:c>' or line[<NUM_LIT:0>] == '<STR_LIT:p>'): <EOL><INDENT>comments += line[<NUM_LIT:1>:]; <EOL><DEDENT>elif (line[<NUM_LIT:0>] == '<STR_LIT:r>'): <EOL><INDENT>node_coordinates = [float(val) for val in line[<NUM_LIT:1>:].split()];<EOL>if (len(node_coordinates) != <NUM_LIT:2>):<EOL><INDENT>raise NameError('<STR_LIT>');<EOL><DEDENT>space_descr.append( [float(val) for val in line[<NUM_LIT:1>:].split()] );<EOL><DEDENT>elif (line[<NUM_LIT:0>] == '<STR_LIT:m>'):<EOL><INDENT>if ( (data_type is not None) and (data_type != '<STR_LIT:m>') ):<EOL><INDENT>raise NameError('<STR_LIT>');<EOL><DEDENT>data_type = '<STR_LIT:m>';<EOL>data.append( [float(val) for val in line[<NUM_LIT:1>:].split()] );<EOL><DEDENT>elif (line[<NUM_LIT:0>] == '<STR_LIT:v>'):<EOL><INDENT>if ( (data_type is not None) and (data_type != '<STR_LIT:v>') ):<EOL><INDENT>raise NameError('<STR_LIT>');<EOL><DEDENT>data_type = '<STR_LIT:v>';<EOL>data.append( [float(val) for val in line[<NUM_LIT:1>:].split()] );<EOL><DEDENT>elif (line[<NUM_LIT:0>] == '<STR_LIT:e>'):<EOL><INDENT>if ( (data_type is not None) and (data_type != '<STR_LIT:e>') ):<EOL><INDENT>raise NameError('<STR_LIT>');<EOL><DEDENT>data_type = '<STR_LIT:e>';<EOL>vertices = [int(val) for val in line[<NUM_LIT:1>:].split()];<EOL>if (vertices[<NUM_LIT:0>] not in map_data_repr):<EOL><INDENT>map_data_repr[ vertices[<NUM_LIT:0>] ] = [ vertices[<NUM_LIT:1>] ];<EOL><DEDENT>else:<EOL><INDENT>map_data_repr[ vertices[<NUM_LIT:0>] ].append(vertices[<NUM_LIT:1>])<EOL><DEDENT>if (vertices[<NUM_LIT:1>] not in map_data_repr):<EOL><INDENT>map_data_repr[ vertices[<NUM_LIT:1>] ] = [ vertices[<NUM_LIT:0>] ];<EOL><DEDENT>else:<EOL><INDENT>map_data_repr[ vertices[<NUM_LIT:1>] ].append(vertices[<NUM_LIT:0>]);<EOL><DEDENT><DEDENT>elif (len(line.strip()) == <NUM_LIT:0>): continue;<EOL>else: <EOL><INDENT>print(line);<EOL>raise NameError('<STR_LIT>');<EOL><DEDENT><DEDENT>if (data_type == '<STR_LIT:e>'):<EOL><INDENT>for index in range(len(map_data_repr)):<EOL><INDENT>data.append([<NUM_LIT:0>] * len(map_data_repr));<EOL>for index_neighbour in map_data_repr[index + <NUM_LIT:1>]:<EOL><INDENT>data[index][index_neighbour - <NUM_LIT:1>] = <NUM_LIT:1>;<EOL><DEDENT><DEDENT><DEDENT>file.close();<EOL>graph_descr = None;<EOL>if (data_type == '<STR_LIT:m>'): graph_descr = type_graph_descr.GRAPH_MATRIX_DESCR;<EOL>elif (data_type == '<STR_LIT:v>'): graph_descr = type_graph_descr.GRAPH_VECTOR_DESCR;<EOL>elif (data_type == '<STR_LIT:e>'): graph_descr = type_graph_descr.GRAPH_MATRIX_DESCR;<EOL>else:<EOL><INDENT>raise NameError('<STR_LIT>');<EOL><DEDENT>if (space_descr != []):<EOL><INDENT>if (len(data) != len(space_descr)):<EOL><INDENT>raise NameError("<STR_LIT>");<EOL><DEDENT><DEDENT>return graph(data, graph_descr, space_descr, comments)<EOL>

!
    @brief Read graph from file in GRPR format.

    @param[in] filename (string): Path to file with graph in GRPR format.

    @return (graph) Graph that is read from file.


def draw_graph(graph_instance, map_coloring = None):

if (graph_instance.space_description is None):<EOL><INDENT>raise NameError("<STR_LIT>");<EOL><DEDENT>if (map_coloring is not None):<EOL><INDENT>if (len(graph_instance) != len(map_coloring)):<EOL><INDENT>raise NameError("<STR_LIT>");<EOL><DEDENT><DEDENT>fig = plt.figure();<EOL>axes = fig.add_subplot(<NUM_LIT>);<EOL>available_colors = ['<STR_LIT>', '<STR_LIT>', '<STR_LIT>',<EOL>'<STR_LIT>', '<STR_LIT>', '<STR_LIT>',<EOL>'<STR_LIT>', '<STR_LIT>', '<STR_LIT>',<EOL>'<STR_LIT>', '<STR_LIT>', '<STR_LIT>',<EOL>'<STR_LIT>', '<STR_LIT>', '<STR_LIT>',<EOL>'<STR_LIT>', '<STR_LIT>', '<STR_LIT>',<EOL>'<STR_LIT>', '<STR_LIT>'];<EOL>if (map_coloring is not None):<EOL><INDENT>if (len(map_coloring) > len(available_colors)):<EOL><INDENT>raise NameError('<STR_LIT>');<EOL><DEDENT><DEDENT>x_maximum = -float('<STR_LIT>');<EOL>x_minimum = float('<STR_LIT>');<EOL>y_maximum = -float('<STR_LIT>');<EOL>y_minimum = float('<STR_LIT>');<EOL>for i in range(<NUM_LIT:0>, len(graph_instance.space_description), <NUM_LIT:1>):<EOL><INDENT>if (graph_instance.type_graph_descr == type_graph_descr.GRAPH_MATRIX_DESCR):<EOL><INDENT>for j in range(i, len(graph_instance.space_description), <NUM_LIT:1>):    <EOL><INDENT>if (graph_instance.data[i][j] == <NUM_LIT:1>):<EOL><INDENT>axes.plot([graph_instance.space_description[i][<NUM_LIT:0>], graph_instance.space_description[j][<NUM_LIT:0>]], [graph_instance.space_description[i][<NUM_LIT:1>], graph_instance.space_description[j][<NUM_LIT:1>]], '<STR_LIT>', linewidth = <NUM_LIT>);<EOL><DEDENT><DEDENT><DEDENT>elif (graph_instance.type_graph_descr == type_graph_descr.GRAPH_VECTOR_DESCR):<EOL><INDENT>for j in graph_instance.data[i]:<EOL><INDENT>if (i > j):     <EOL><INDENT>axes.plot([graph_instance.space_description[i][<NUM_LIT:0>], graph_instance.space_description[j][<NUM_LIT:0>]], [graph_instance.space_description[i][<NUM_LIT:1>], graph_instance.space_description[j][<NUM_LIT:1>]], '<STR_LIT>', linewidth = <NUM_LIT>);   <EOL><DEDENT><DEDENT><DEDENT>color_node = '<STR_LIT:b>';<EOL>if (map_coloring is not None):<EOL><INDENT>color_node = colors.hex2color(available_colors[map_coloring[i]]);<EOL><DEDENT>axes.plot(graph_instance.space_description[i][<NUM_LIT:0>], graph_instance.space_description[i][<NUM_LIT:1>], color = color_node, marker = '<STR_LIT:o>', markersize = <NUM_LIT:20>);<EOL>if (x_maximum < graph_instance.space_description[i][<NUM_LIT:0>]): x_maximum = graph_instance.space_description[i][<NUM_LIT:0>];<EOL>if (x_minimum > graph_instance.space_description[i][<NUM_LIT:0>]): x_minimum = graph_instance.space_description[i][<NUM_LIT:0>];  <EOL>if (y_maximum < graph_instance.space_description[i][<NUM_LIT:1>]): y_maximum = graph_instance.space_description[i][<NUM_LIT:1>]; <EOL>if (y_minimum > graph_instance.space_description[i][<NUM_LIT:1>]): y_minimum = graph_instance.space_description[i][<NUM_LIT:1>];<EOL><DEDENT>plt.xlim(x_minimum - <NUM_LIT:0.5>, x_maximum + <NUM_LIT:0.5>);<EOL>plt.ylim(y_minimum - <NUM_LIT:0.5>, y_maximum + <NUM_LIT:0.5>);<EOL>plt.show()<EOL>

!
    @brief Draw graph.

    @param[in] graph_instance (graph): Graph that should be drawn.
    @param[in] map_coloring (list): List of color indexes for each vertex. Size of this list should be equal to size of graph (number of vertices).
                                    If it's not specified (None) than graph without coloring will be dwarn.

    @warning Graph can be represented if there is space representation for it.


def __init__(self, data, type_graph = None, space_descr = None, comments = None):

self.__data = data;<EOL>self.__space_descr = space_descr;<EOL>self.__comments = comments;<EOL>if (type_graph is not None):<EOL><INDENT>self.__type_graph = type_graph;<EOL><DEDENT>else:<EOL><INDENT>self.__type_graph = type_graph_descr.GRAPH_MATRIX_DESCR;<EOL>for row in self.__data:<EOL><INDENT>if (len(row) != len(self.__data)):<EOL><INDENT>self.__type_graph = type_graph_descr.GRAPH_VECTOR_DESCR;<EOL>break;<EOL><DEDENT>for element in row:<EOL><INDENT>if ( (element != <NUM_LIT:0>) or (element != <NUM_LIT:1>) ):<EOL><INDENT>self.__type_graph = type_graph_descr.GRAPH_VECTOR_DESCR;<EOL><DEDENT><DEDENT><DEDENT><DEDENT>

!
        @brief Constructor of graph.

        @param[in] data (list): Representation of graph. Considered as matrix if 'type_graph' is not specified.
        @param[in] type_graph (type_graph_descr): Type of graph representation in 'data'.
        @param[in] space_descr (list): Coordinates of each vertex that are used for graph drawing (can be omitted).
        @param[in] comments (string): Comments related to graph.


return len(self.__data)<EOL>

!
        @return (uint) Size of graph defined by number of vertices.


return self.__data<EOL>

!
        @return (list) Graph representation.


if (self.__space_descr == [] or self.__space_descr is None):<EOL><INDENT>return None;<EOL><DEDENT>return self.__space_descr<EOL>

!
        @return (list) Space description.


return self.__comments<EOL>


return self.__type_graph<EOL>

!
        @return (type_graph_descr) Type of graph representation.


return color.TITLES[sequential_index % len(color.TITLES)]<EOL>

!
        @brief Returns color using round robin to avoid out of range exception.

        @param[in] sequential_index (uint): Index that should be converted to valid color index.

        @return (uint) Color from list color.TITLES.


def __init__(self, phase, time, pointer_sync_analyser):

super().__init__(phase, time, pointer_sync_analyser)<EOL>

!
        @brief Constructor of the analyser.

        @param[in] phase (list): Output dynamic of the oscillatory network, where one iteration consists of all phases of oscillators.
        @param[in] time (list): Simulation time.
        @param[in] pointer_sync_analyser (POINTER): Pointer to CCORE analyser, if specified then other arguments can be omitted.


def allocate_color_clusters(self, tolerance = <NUM_LIT:0.1>):

return self.allocate_sync_ensembles(tolerance)<EOL>

!
        @brief Allocates clusters, when one cluster defines only one color.

        @param[in] tolerance (double): Defines maximum deviation between phases.

        @return (list) Clusters [vertices with color 1], [vertices with color 2], ..., [vertices with color n].


def allocate_map_coloring(self, tolerance = <NUM_LIT:0.1>):

clusters = self.allocate_color_clusters(tolerance);<EOL>number_oscillators = len(self._dynamic[<NUM_LIT:0>]);<EOL>coloring_map = [<NUM_LIT:0>] * number_oscillators;<EOL>for color_index in range(len(clusters)):<EOL><INDENT>for node_index in clusters[color_index]:<EOL><INDENT>coloring_map[node_index] = color_index;<EOL><DEDENT><DEDENT>return coloring_map<EOL>

!
        @brief Allocates coloring map for graph that has been processed.

        @param[in] tolerance (double): Defines maximum deviation between phases.

        @return (list) Colors for each node (index of node in graph), for example [color1, color2, color2, ...].


def __init__(self, graph_matrix, positive_weight, negative_weight, reduction = None):

number_oscillators = len(graph_matrix);<EOL>super().__init__(number_oscillators, type_conn = conn_type.DYNAMIC, ccore = False);<EOL>if (reduction == None):<EOL><INDENT>self._reduction = self._num_osc;<EOL><DEDENT>else:<EOL><INDENT>self._reduction = reduction;<EOL><DEDENT>self._positive_weight = positive_weight;<EOL>self._negative_weight = negative_weight;<EOL>self._create_connections(graph_matrix)<EOL>

!
        @brief Constructor of the oscillatory network syncgcolor for graph coloring problem.

        @param[in] graph_matrix (list): Graph represented by matrix.
        @param[in] positive_weight (double): Value of weight of positive connections.
        @param[in] negative_weight (double): Value of weight of negative connections.
        @param[in] reduction (bool): Inverse degree of the processed graph.


for row in range(<NUM_LIT:0>, len(graph_matrix)):<EOL><INDENT>for column in range (<NUM_LIT:0>, len(graph_matrix[row])):<EOL><INDENT>if (graph_matrix[row][column] > <NUM_LIT:0>):<EOL><INDENT>self.set_connection(row, column);<EOL><DEDENT><DEDENT><DEDENT>

!
        @brief Creates connection in the network in line with graph.

        @param[in] graph_matrix (list): Matrix representation of the graph.


def _phase_kuramoto(self, teta, t, argv):

index = argv;<EOL>phase = <NUM_LIT:0>;<EOL>for k in range(<NUM_LIT:0>, self._num_osc):<EOL><INDENT>if (self.has_connection(index, k) == True):<EOL><INDENT>phase += self._negative_weight * math.sin(self._phases[k] - teta);<EOL><DEDENT>else:<EOL><INDENT>phase += self._positive_weight * math.sin(self._phases[k] - teta);<EOL><DEDENT><DEDENT>return ( phase / self._reduction )<EOL>

!
        @brief Returns result of phase calculation for oscillator in the network.

        @param[in] teta (double): Value of phase of the oscillator with index argv in the network.
        @param[in] t (double): Unused, can be ignored.
        @param[in] argv (uint): Index of the oscillator in the network.

        @return (double) New value of phase for oscillator with index argv.


def process(self, order = <NUM_LIT>, solution = solve_type.FAST, collect_dynamic = False):

analyser = self.simulate_dynamic(order, solution, collect_dynamic);<EOL>return syncgcolor_analyser(analyser.output, analyser.time, None)<EOL>

!
        @brief Performs simulation of the network (performs solving of graph coloring problem).

        @param[in] order (double): Defines when process of synchronization in the network is over, range from 0 to 1.
        @param[in] solution (solve_type): defines type (method) of solving diff. equation.
        @param[in] collect_dynamic (bool): If True - return full dynamic of the network, otherwise - last state of phases.

        @return (syncnet_analyser) Returns analyser of results of coloring.


super().__init__(amplitudes, time)<EOL>

!
        @brief Constructor of the analyser.

        @param[in] amplitudes (list): Output dynamic of the hysteresis oscillatory network, where one iteration consists of all amplitudes of oscillators.
        @param[in] time (list): Simulation time (timestamps of simulation steps) when amplitudes are stored.


def allocate_clusters(self, tolerance=<NUM_LIT:0.1>, threshold_steps=<NUM_LIT:10>):

return self.allocate_sync_ensembles(tolerance, threshold_steps=threshold_steps)<EOL>

!
        @brief Returns list of clusters in line with state of ocillators (phases).

        @param[in] tolerance (double): Maximum error for allocation of synchronous ensemble oscillators.
        @param[in] threshold_steps (uint): Number of steps from the end of simulation that should be analysed for ensemble allocation.
                    If amount of simulation steps has been less than threshold steps than amount of steps will be reduced to amount
                    of simulation steps.

        @remark Results can be obtained only after network simulation (graph processing by the network).

        @return (list) List of clusters, for example [ [cluster1], [cluster2], ... ].

        @see allocate_map_coloring()


def allocate_map_coloring(self, tolerance, threshold_steps = <NUM_LIT:10>):

clusters = self.allocate_clusters(tolerance, threshold_steps)<EOL>coloring_map = [<NUM_LIT:0>] * len(self._dynamic[<NUM_LIT:0>])<EOL>for color_index in range(len(clusters)):<EOL><INDENT>for node_index in clusters[color_index]:<EOL><INDENT>coloring_map[node_index] = color_index<EOL><DEDENT><DEDENT>return coloring_map<EOL>

!
        @brief Returns list of color indexes that are assigned to each object from input data space accordingly.

        @param[in] tolerance (double): Tolerance level that define maximal difference between outputs of oscillators in one synchronous ensemble.
        @param[in] threshold_steps (uint): Number of steps from the end of simulation that should be analysed for ensemble allocation.
                    If amount of simulation steps has been less than threshold steps than amount of steps will be reduced to amount
                    of simulation steps.

        @remark Results can be obtained only after network simulation (graph processing by the network).

        @return (list) Color indexes that are assigned to each object from input data space accordingly.

        @see allocate_clusters()


def __init__(self, graph_matrix, alpha, eps):

number_oscillators = len(graph_matrix)<EOL>super().__init__(number_oscillators)<EOL>self._states = [<NUM_LIT:0>] * self._num_osc<EOL>for i in range(<NUM_LIT:0>, self._num_osc):<EOL><INDENT>self._states[i] = <NUM_LIT:1> - (<NUM_LIT:2> / self._num_osc) * i<EOL><DEDENT>self._outputs = [-<NUM_LIT:1>] * self._num_osc<EOL>self._outputs_buffer = [-<NUM_LIT:1>] * self._num_osc<EOL>self._time_contant = <NUM_LIT:1><EOL>self._weight = []<EOL>for row in range(<NUM_LIT:0>, self._num_osc):<EOL><INDENT>self._weight.append([<NUM_LIT:0>] * self._num_osc)<EOL>for col in range(<NUM_LIT:0>, self._num_osc):<EOL><INDENT>if (row != col):<EOL><INDENT>self._weight[row][col] = -alpha * (graph_matrix[row][col]) / sum(graph_matrix[row])<EOL><DEDENT>else:<EOL><INDENT>self._weight[row][col] = -alpha - eps<EOL><DEDENT><DEDENT><DEDENT>

!
        @brief Constructor of hysteresis oscillatory network for graph coloring.

        @param[in] graph_matrix (list): Matrix representation of a graph.
        @param[in] alpha (double): Positive constant (affect weight between two oscillators w[i][j]).
        @param[in] eps (double): Positive constant (affect feedback to itself (i = j) of each oscillator w[i][j] = -alpha - eps).


def process(self, steps, time, collect_dynamic=True):

output_dynamic = super().simulate(steps, time, collect_dynamic=collect_dynamic)<EOL>return hysteresis_analyser(output_dynamic.output, output_dynamic.time)<EOL>

!
        @brief Peforms graph coloring analysis using simulation of the oscillatory network.

        @param[in] steps (uint): Number steps of simulations during simulation.
        @param[in] time (double): Time of simulation.
        @param[in] collect_dynamic (bool): Specified requirement to collect whole dynamic of the network.

        @return (hysteresis_analyser) Returns analyser of results of clustering.


template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_SIMPLE1, <NUM_LIT>, <NUM_LIT>, <NUM_LIT>, <NUM_LIT:20>)<EOL>


template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_LINE, <NUM_LIT>, <NUM_LIT>, <NUM_LIT>, <NUM_LIT:20>)<EOL>


template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_CROSSROAD, <NUM_LIT>, <NUM_LIT>, <NUM_LIT>, <NUM_LIT:20>)<EOL>


template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_TWO_CROSSROADS, <NUM_LIT>, <NUM_LIT>, <NUM_LIT>, <NUM_LIT:20>)<EOL>


template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_FULL1, <NUM_LIT>, <NUM_LIT>, <NUM_LIT>, <NUM_LIT:20>, tolerance = <NUM_LIT>)<EOL>

Bad result - two vertices colored by the same color


template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_FULL2, <NUM_LIT>, <NUM_LIT>, <NUM_LIT>, <NUM_LIT:20>, tolerance = <NUM_LIT>)<EOL>


template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_FIVE_POINTED_FRAME_STAR, <NUM_LIT>, <NUM_LIT>, <NUM_LIT>, <NUM_LIT:30>)<EOL>


if (len(data[<NUM_LIT:0>]) != len(data)):<EOL><INDENT>raise NameError('<STR_LIT>');<EOL><DEDENT>self.__data_pointer = data;<EOL>self.__colors = [];<EOL>self.__coloring = None<EOL>

!
        @brief Constructor of DSATUR algorithm.

        @param[in] data (list): Matrix graph representation.


color_counter = <NUM_LIT:1>;<EOL>degrees = list();<EOL>saturation_degrees = [<NUM_LIT:0>] * len(self.__data_pointer);<EOL>self.__coloring = [<NUM_LIT:0>] * len(self.__data_pointer);<EOL>uncolored_vertices = set(range(len(self.__data_pointer)));<EOL>index_maximum_degree = <NUM_LIT:0>;<EOL>maximum_degree = <NUM_LIT:0>;<EOL>for index_node in range(len(self.__data_pointer)):<EOL><INDENT>degrees.append( ( sum(self.__data_pointer[index_node]), index_node ) );<EOL>if (degrees[index_node][<NUM_LIT:0>] > maximum_degree):<EOL><INDENT>(maximum_degree, node_index) = degrees[index_node];<EOL>index_maximum_degree = index_node;<EOL><DEDENT><DEDENT>neighbors = self.__get_neighbors(index_maximum_degree);<EOL>for index_neighbor in neighbors:<EOL><INDENT>saturation_degrees[index_neighbor] += <NUM_LIT:1>;<EOL><DEDENT>self.__coloring[index_maximum_degree] = color_counter;<EOL>uncolored_vertices.remove(index_maximum_degree);<EOL>while(len(uncolored_vertices) > <NUM_LIT:0>):<EOL><INDENT>maximum_satur_degree = -<NUM_LIT:1>;<EOL>for index in uncolored_vertices:<EOL><INDENT>if (saturation_degrees[index] > maximum_satur_degree):<EOL><INDENT>maximum_satur_degree = saturation_degrees[index];<EOL><DEDENT><DEDENT>indexes_maximum_satur_degree = [index for index in uncolored_vertices if saturation_degrees[index] == maximum_satur_degree];           <EOL>coloring_index = indexes_maximum_satur_degree[<NUM_LIT:0>];<EOL>if (len(indexes_maximum_satur_degree) > <NUM_LIT:1>): <EOL><INDENT>maximum_degree = -<NUM_LIT:1>;<EOL>for index in indexes_maximum_satur_degree:<EOL><INDENT>(degree, node_index) = degrees[index];<EOL>if (degree > maximum_degree):<EOL><INDENT>coloring_index = node_index;<EOL>maximum_degree = degree;<EOL><DEDENT><DEDENT><DEDENT>node_index_neighbors = self.__get_neighbors(coloring_index);<EOL>for number_color in range(<NUM_LIT:1>, color_counter + <NUM_LIT:1>, <NUM_LIT:1>):<EOL><INDENT>if (self.__get_amount_color(node_index_neighbors, number_color) == <NUM_LIT:0>):<EOL><INDENT>self.__coloring[coloring_index] = number_color;<EOL>break;<EOL><DEDENT><DEDENT>if (self.__coloring[coloring_index] == <NUM_LIT:0>):<EOL><INDENT>color_counter += <NUM_LIT:1>;     <EOL>self.__coloring[coloring_index] = color_counter;<EOL><DEDENT>uncolored_vertices.remove(coloring_index);<EOL>for index_neighbor in node_index_neighbors:<EOL><INDENT>subneighbors = self.__get_neighbors(index_neighbor);<EOL>if (self.__get_amount_color(subneighbors, self.__coloring[coloring_index]) == <NUM_LIT:1>):<EOL><INDENT>saturation_degrees[index_neighbor] += <NUM_LIT:1>;<EOL><DEDENT><DEDENT><DEDENT>

!
        @brief Perform graph coloring using DSATUR algorithm.

        @see get_colors()


return self.__coloring<EOL>

!
        @brief Returns results of graph coloring.

        @return (list) list with assigned colors where each element corresponds
                to node in the graph, for example [1, 2, 2, 1, 3, 4, 1].

        @see process()


def __get_amount_color(self, node_indexes, color_number):

color_counter = <NUM_LIT:0>;  <EOL>for index in node_indexes:<EOL><INDENT>if (self.__coloring[index] == color_number):<EOL><INDENT>color_counter += <NUM_LIT:1>;<EOL><DEDENT><DEDENT>return color_counter<EOL>

!
        @brief Countes how many nodes has color 'color_number'.

        @param[in] node_indexes (list): Indexes of graph nodes for checking.
        @param[in] color_number (uint): Number of color that is searched in nodes.

        @return (uint) Number found nodes with the specified color 'color_number'.


return [ index for index in range(len(self.__data_pointer[node_index])) if self.__data_pointer[node_index][index] != <NUM_LIT:0> ]<EOL>

!
        @brief Returns indexes of neighbors of the specified node.

        @param[in] node_index (uint):

        @return (list) Neighbors of the specified node.


return self.__number_points<EOL>

!
        @brief Returns number of points that are encoded.

        @return (uint) Number of encoded points.


return self.__linear_sum<EOL>

!
        @brief Returns linear sum.

        @return (list) Linear sum.


return self.__square_sum<EOL>

!
        @brief Returns square sum.

        @return (double) Square sum.


def __init__(self, number_points, linear_sum, square_sum):

self.__number_points = number_points;<EOL>self.__linear_sum = linear_sum;<EOL>self.__square_sum = square_sum;<EOL>self.__centroid = None;<EOL>self.__radius = None;<EOL>self.__diameter = None<EOL>

!
        @brief CF-entry constructor.

        @param[in] number_points (uint): Number of objects that is represented by the entry.
        @param[in] linear_sum (list): Linear sum of values that represent objects in each dimension.
        @param[in] square_sum (double): Square sum of values that represent objects.


return cfentry(self.__number_points, self.__linear_sum, self.__square_sum)<EOL>

!
        @returns (cfentry) Makes copy of the cfentry instance.


return '<STR_LIT>' % ( self.number_points, self.linear_sum, self.__square_sum, hex(id(self)) )<EOL>

!
        @return (string) Default cfentry representation.


return self.__repr__()<EOL>

!
        @brief Default cfentry string representation.


number_points = self.number_points + entry.number_points;<EOL>result_linear_sum = list_math_addition(self.linear_sum, entry.linear_sum);<EOL>result_square_sum = self.square_sum + entry.square_sum;  <EOL>return cfentry(number_points, result_linear_sum, result_square_sum)<EOL>

!
        @brief Overloaded operator add. Performs addition of two clustering features.

        @param[in] entry (cfentry): Entry that is added to the current.

        @return (cfentry) Result of addition of two clustering features.


number_points = self.number_points - entry.number_points;<EOL>result_linear_sum = list_math_subtraction(self.linear_sum, entry.linear_sum);<EOL>result_square_sum = self.square_sum - entry.square_sum;<EOL>if ( (number_points < <NUM_LIT:0>) or (result_square_sum < <NUM_LIT:0>) ):<EOL><INDENT>raise NameError("<STR_LIT>");<EOL><DEDENT>return cfentry(number_points, result_linear_sum, result_square_sum)<EOL>

!
        @brief Overloaded operator sub. Performs substraction of two clustering features.
        @details Substraction can't be performed with clustering feature whose description is less then substractor.

        @param[in] entry (cfentry): Entry that is substracted from the current.

        @return (cfentry) Result of substraction of two clustering features.


tolerance = <NUM_LIT>;<EOL>result = (self.__number_points == entry.number_points);<EOL>result &= ( (self.square_sum + tolerance > entry.square_sum) and (self.square_sum - tolerance < entry.square_sum) );<EOL>for index_dimension in range(<NUM_LIT:0>, len(self.linear_sum)):<EOL><INDENT>result &= ( (self.linear_sum[index_dimension] + tolerance > entry.linear_sum[index_dimension]) and (self.linear_sum[index_dimension] - tolerance < entry.linear_sum[index_dimension]) );<EOL><DEDENT>return result<EOL>

!
        @brief Overloaded operator eq.
        @details Performs comparison of two clustering features.

        @param[in] entry (cfentry): Entry that is used for comparison with current.

        @return (bool) True is both clustering features are equals in line with tolerance, otherwise False.


def get_distance(self, entry, type_measurement):

if (type_measurement is measurement_type.CENTROID_EUCLIDEAN_DISTANCE):<EOL><INDENT>return euclidean_distance_square(entry.get_centroid(), self.get_centroid());<EOL><DEDENT>elif (type_measurement is measurement_type.CENTROID_MANHATTAN_DISTANCE):<EOL><INDENT>return manhattan_distance(entry.get_centroid(), self.get_centroid());<EOL><DEDENT>elif (type_measurement is measurement_type.AVERAGE_INTER_CLUSTER_DISTANCE):<EOL><INDENT>return self.__get_average_inter_cluster_distance(entry);<EOL><DEDENT>elif (type_measurement is measurement_type.AVERAGE_INTRA_CLUSTER_DISTANCE):<EOL><INDENT>return self.__get_average_intra_cluster_distance(entry);<EOL><DEDENT>elif (type_measurement is measurement_type.VARIANCE_INCREASE_DISTANCE):<EOL><INDENT>return self.__get_variance_increase_distance(entry);<EOL><DEDENT>else:<EOL><INDENT>assert <NUM_LIT:0>;<EOL><DEDENT>

!
        @brief Calculates distance between two clusters in line with measurement type.

        @details In case of usage CENTROID_EUCLIDIAN_DISTANCE square euclidian distance will be returned.
                 Square root should be taken from the result for obtaining real euclidian distance between
                 entries.

        @param[in] entry (cfentry): Clustering feature to which distance should be obtained.
        @param[in] type_measurement (measurement_type): Distance measurement algorithm between two clusters.

        @return (double) Distance between two clusters.


if (self.__centroid is not None):<EOL><INDENT>return self.__centroid;<EOL><DEDENT>self.__centroid = [<NUM_LIT:0>] * len(self.linear_sum);<EOL>for index_dimension in range(<NUM_LIT:0>, len(self.linear_sum)):<EOL><INDENT>self.__centroid[index_dimension] = self.linear_sum[index_dimension] / self.number_points;<EOL><DEDENT>return self.__centroid<EOL>

!
        @brief Calculates centroid of cluster that is represented by the entry.
        @details It's calculated once when it's requested after the last changes.

        @return (list) Centroid of cluster that is represented by the entry.


if (self.__radius is not None):<EOL><INDENT>return self.__radius;<EOL><DEDENT>centroid = self.get_centroid();<EOL>radius_part_1 = self.square_sum;<EOL>radius_part_2 = <NUM_LIT:0.0>;<EOL>radius_part_3 = <NUM_LIT:0.0>;<EOL>if (type(centroid) == list):<EOL><INDENT>radius_part_2 = <NUM_LIT> * sum(list_math_multiplication(self.linear_sum, centroid));<EOL>radius_part_3 = self.number_points * sum(list_math_multiplication(centroid, centroid));<EOL><DEDENT>else:<EOL><INDENT>radius_part_2 = <NUM_LIT> * self.linear_sum * centroid;<EOL>radius_part_3 = self.number_points * centroid * centroid;<EOL><DEDENT>self.__radius = ( (<NUM_LIT:1.0> / self.number_points) * (radius_part_1 - radius_part_2 + radius_part_3) ) ** <NUM_LIT:0.5>;<EOL>return self.__radius<EOL>

!
        @brief Calculates radius of cluster that is represented by the entry.
        @details It's calculated once when it's requested after the last changes.

        @return (double) Radius of cluster that is represented by the entry.


if (self.__diameter is not None):<EOL><INDENT>return self.__diameter;<EOL><DEDENT>diameter_part = <NUM_LIT:0.0>;<EOL>if (type(self.linear_sum) == list):<EOL><INDENT>diameter_part = self.square_sum * self.number_points - <NUM_LIT> * sum(list_math_multiplication(self.linear_sum, self.linear_sum)) + self.square_sum * self.number_points;<EOL><DEDENT>else:<EOL><INDENT>diameter_part = self.square_sum * self.number_points - <NUM_LIT> * self.linear_sum * self.linear_sum + self.square_sum * self.number_points;<EOL><DEDENT>self.__diameter = ( diameter_part / (self.number_points * (self.number_points - <NUM_LIT:1>)) ) ** <NUM_LIT:0.5>;<EOL>return self.__diameter<EOL>

!
        @brief Calculates diameter of cluster that is represented by the entry.
        @details It's calculated once when it's requested after the last changes.

        @return (double) Diameter of cluster that is represented by the entry.


linear_part_distance = sum(list_math_multiplication(self.linear_sum, entry.linear_sum));<EOL>return ( (entry.number_points * self.square_sum - <NUM_LIT> * linear_part_distance + self.number_points * entry.square_sum) / (self.number_points * entry.number_points) ) ** <NUM_LIT:0.5><EOL>

!
        @brief Calculates average inter cluster distance between current and specified clusters.

        @param[in] entry (cfentry): Clustering feature to which distance should be obtained.

        @return (double) Average inter cluster distance.


linear_part_first = list_math_addition(self.linear_sum, entry.linear_sum);<EOL>linear_part_second = linear_part_first;<EOL>linear_part_distance = sum(list_math_multiplication(linear_part_first, linear_part_second));<EOL>general_part_distance = <NUM_LIT> * (self.number_points + entry.number_points) * (self.square_sum + entry.square_sum) - <NUM_LIT> * linear_part_distance;<EOL>return (general_part_distance / ( (self.number_points + entry.number_points) * (self.number_points + entry.number_points - <NUM_LIT:1.0>) )) ** <NUM_LIT:0.5><EOL>

!
        @brief Calculates average intra cluster distance between current and specified clusters.

        @param[in] entry (cfentry): Clustering feature to which distance should be obtained.

        @return (double) Average intra cluster distance.


linear_part_12 = list_math_addition(self.linear_sum, entry.linear_sum);<EOL>variance_part_first = (self.square_sum + entry.square_sum) -<NUM_LIT> * sum(list_math_multiplication(linear_part_12, linear_part_12)) / (self.number_points + entry.number_points) +(self.number_points + entry.number_points) * sum(list_math_multiplication(linear_part_12, linear_part_12)) / (self.number_points + entry.number_points)**<NUM_LIT>;<EOL>linear_part_11 = sum(list_math_multiplication(self.linear_sum, self.linear_sum));<EOL>variance_part_second = -( self.square_sum - (<NUM_LIT> * linear_part_11 / self.number_points) + (linear_part_11 / self.number_points) );<EOL>linear_part_22 = sum(list_math_multiplication(entry.linear_sum, entry.linear_sum));<EOL>variance_part_third = -( entry.square_sum - (<NUM_LIT> / entry.number_points) * linear_part_22 + entry.number_points * (<NUM_LIT:1.0> / entry.number_points ** <NUM_LIT>) * linear_part_22 );<EOL>return (variance_part_first + variance_part_second + variance_part_third)<EOL>

!
        @brief Calculates variance increase distance between current and specified clusters.

        @param[in] entry (cfentry): Clustering feature to which distance should be obtained.

        @return (double) Variance increase distance.


def __init__(self, feature, parent, payload):

<EOL>self.feature = copy(feature);<EOL>self.parent = parent;<EOL>self.type = cfnode_type.CFNODE_DUMMY;<EOL>self.payload = payload<EOL>

!
        @brief Constructor of abstract CF node.

        @param[in] feature (cfentry): Clustering feature of the created node.
        @param[in] parent (cfnode): Parent of the created node.
        @param[in] payload (*): Data that is stored by the node.


return '<STR_LIT>' % ( hex(id(self)), self.parent, self.feature )<EOL>

!
        @return (string) Default representation of CF node.


return self.__repr__()<EOL>

!
        @return (string) String representation of CF node.


def get_distance(self, node, type_measurement):

return self.feature.get_distance(node.feature, type_measurement)<EOL>

!
        @brief Calculates distance between nodes in line with specified type measurement.

        @param[in] node (cfnode): CF-node that is used for calculation distance to the current node.
        @param[in] type_measurement (measurement_type): Measurement type that is used for calculation distance.

        @return (double) Distance between two nodes.


return self.__successors<EOL>

!
        @return (list) List of successors of the node.


def __init__(self, feature, parent, successors, payload):

super().__init__(feature, parent, payload);<EOL>self.type = cfnode_type.CFNODE_NONLEAF;<EOL>self.__successors = successors<EOL>

!
        @brief Create CF Non-leaf node.

        @param[in] feature (cfentry): Clustering feature of the created node.
        @param[in] parent (non_leaf_node): Parent of the created node.
        @param[in] successors (list): List of successors of the node.
        @param[in] payload (*): Data that is stored by the node.


return '<STR_LIT>' % ( hex(id(self)), self.parent, self.feature, len(self.successors) )<EOL>

!
        @return (string) Representation of non-leaf node representation.


return self.__repr__()<EOL>

!
        @return (string) String non-leaf representation.


self.feature += successor.feature;<EOL>self.successors.append(successor);<EOL>successor.parent = self<EOL>

!
        @brief Insert successor to the node.

        @param[in] successor (cfnode): Successor for adding.


self.feature -= successor.feature;<EOL>self.successors.append(successor);<EOL>successor.parent = self<EOL>

!
        @brief Remove successor from the node.

        @param[in] successor (cfnode): Successor for removing.


self.feature += node.feature;<EOL>for child in node.successors:<EOL><INDENT>child.parent = self;<EOL>self.successors.append(child);<EOL><DEDENT>

!
        @brief Merge non-leaf node to the current.

        @param[in] node (non_leaf_node): Non-leaf node that should be merged with current.


farthest_node1 = None;<EOL>farthest_node2 = None;<EOL>farthest_distance = <NUM_LIT:0>;<EOL>for i in range(<NUM_LIT:0>, len(self.successors)):<EOL><INDENT>candidate1 = self.successors[i];<EOL>for j in range(i + <NUM_LIT:1>, len(self.successors)):<EOL><INDENT>candidate2 = self.successors[j];<EOL>candidate_distance = candidate1.get_distance(candidate2, type_measurement);<EOL>if (candidate_distance > farthest_distance):<EOL><INDENT>farthest_distance = candidate_distance;<EOL>farthest_node1 = candidate1;<EOL>farthest_node2 = candidate2;        <EOL>return [farthest_node1, farthest_node2];<EOL><DEDENT><DEDENT><DEDENT>

!
        @brief Find pair of farthest successors of the node in line with measurement type.

        @param[in] type_measurement (measurement_type): Measurement type that is used for obtaining farthest successors.

        @return (list) Pair of farthest successors represented by list [cfnode1, cfnode2].


nearest_node1 = None;<EOL>nearest_node2 = None;<EOL>nearest_distance = float("<STR_LIT>");<EOL>for i in range(<NUM_LIT:0>, len(self.successors)):<EOL><INDENT>candidate1 = self.successors[i];<EOL>for j in range(i + <NUM_LIT:1>, len(self.successors)):<EOL><INDENT>candidate2 = self.successors[j];<EOL>candidate_distance = candidate1.get_distance(candidate2, type_measurement);<EOL>if (candidate_distance < nearest_distance):<EOL><INDENT>nearest_distance = candidate_distance;<EOL>nearest_node1 = candidate1;<EOL>nearest_node2 = candidate2;<EOL><DEDENT><DEDENT><DEDENT>return [nearest_node1, nearest_node2]<EOL>

!
        @brief Find pair of nearest successors of the node in line with measurement type.

        @param[in] type_measurement (measurement_type): Measurement type that is used for obtaining nearest successors.

        @return (list) Pair of nearest successors represented by list.


return self.__entries<EOL>

!
        @return (list) List of leaf nodes.


def __init__(self, feature, parent, entries, payload):

super().__init__(feature, parent, payload);<EOL>self.type = cfnode_type.CFNODE_LEAF;<EOL>self.__entries = entries<EOL>

!
        @brief Create CF Leaf node.

        @param[in] feature (cfentry): Clustering feature of the created node.
        @param[in] parent (non_leaf_node): Parent of the created node.
        @param[in] entries (list): List of entries of the node.
        @param[in] payload (*): Data that is stored by the node.


text_entries = "<STR_LIT:\n>";<EOL>for entry in self.entries:<EOL><INDENT>text_entries += "<STR_LIT:\t>" + str(entry) + "<STR_LIT:\n>";<EOL><DEDENT>return '<STR_LIT>' % ( hex(id(self)), self.parent, self.feature, len(self.entries), text_entries )<EOL>

!
        @return (string) Default leaf node represenation.


return self.__repr__()<EOL>

!
        @return (string) String leaf node representation.


self.feature += entry;<EOL>self.entries.append(entry)<EOL>

!
        @brief Insert new clustering feature to the leaf node.

        @param[in] entry (cfentry): Clustering feature.


self.feature -= entry;<EOL>self.entries.remove(entry)<EOL>

!
        @brief Remove clustering feature from the leaf node.

        @param[in] entry (cfentry): Clustering feature.


self.feature += node.feature;<EOL>for entry in node.entries:<EOL><INDENT>self.entries.append(entry);<EOL><DEDENT>

!
        @brief Merge leaf node to the current.

        @param[in] node (leaf_node): Leaf node that should be merged with current.


farthest_entity1 = None;<EOL>farthest_entity2 = None;<EOL>farthest_distance = <NUM_LIT:0>;<EOL>for i in range(<NUM_LIT:0>, len(self.entries)):<EOL><INDENT>candidate1 = self.entries[i];<EOL>for j in range(i + <NUM_LIT:1>, len(self.entries)):<EOL><INDENT>candidate2 = self.entries[j];<EOL>candidate_distance = candidate1.get_distance(candidate2, type_measurement);<EOL>if (candidate_distance > farthest_distance):<EOL><INDENT>farthest_distance = candidate_distance;<EOL>farthest_entity1 = candidate1;<EOL>farthest_entity2 = candidate2;<EOL><DEDENT><DEDENT><DEDENT>return [farthest_entity1, farthest_entity2]<EOL>

!
        @brief Find pair of farthest entries of the node.

        @param[in] type_measurement (measurement_type): Measurement type that is used for obtaining farthest entries.

        @return (list) Pair of farthest entries of the node that are represented by list.


def get_nearest_index_entry(self, entry, type_measurement):

minimum_distance = float('<STR_LIT>');<EOL>nearest_index = <NUM_LIT:0>;<EOL>for candidate_index in range(<NUM_LIT:0>, len(self.entries)):<EOL><INDENT>candidate_distance = self.entries[candidate_index].get_distance(entry, type_measurement);<EOL>if (candidate_distance < minimum_distance):<EOL><INDENT>nearest_index = candidate_index;<EOL><DEDENT><DEDENT>return nearest_index<EOL>

!
        @brief Find nearest index of nearest entry of node for the specified entry.

        @param[in] entry (cfentry): Entry that is used for calculation distance.
        @param[in] type_measurement (measurement_type): Measurement type that is used for obtaining nearest entry to the specified.

        @return (uint) Index of nearest entry of node for the specified entry.


def get_nearest_entry(self, entry, type_measurement):

min_key = lambda cur_entity: cur_entity.get_distance(entry, type_measurement);<EOL>return min(self.__entries, key = min_key)<EOL>

!
        @brief Find nearest entry of node for the specified entry.

        @param[in] entry (cfentry): Entry that is used for calculation distance.
        @param[in] type_measurement (measurement_type): Measurement type that is used for obtaining nearest entry to the specified.

        @return (cfentry) Nearest entry of node for the specified entry.


return self.__root<EOL>

!
        @return (cfnode) Root of the tree.


return self.__leafes<EOL>

!
        @return (list) List of all non-leaf nodes in the tree.


return self.__amount_nodes<EOL>

!
        @return (unit) Number of nodes (leaf and non-leaf) in the tree.


return self.__amount_entries<EOL>

!
        @return (uint) Number of entries in the tree.


return self.__height<EOL>

!
        @return (uint) Height of the tree.


return self.__branch_factor<EOL>

!
        @return (uint) Branching factor of the tree.
        @details Branching factor defines maximum number of successors in each non-leaf node.


return self.__threshold<EOL>

!
        @return (double) Threshold of the tree that represents maximum diameter of sub-clusters that is formed by leaf node entries.


return self.__max_entries<EOL>

!
        @return (uint) Maximum number of entries in each leaf node.


return self.__type_measurement<EOL>

!
        @return (measurement_type) Type that is used for measuring.


def __init__(self, branch_factor, max_entries, threshold, type_measurement = measurement_type.CENTROID_EUCLIDEAN_DISTANCE):

self.__root = None;<EOL>self.__branch_factor = branch_factor; <EOL>if (self.__branch_factor < <NUM_LIT:2>):<EOL><INDENT>self.__branch_factor = <NUM_LIT:2>;<EOL><DEDENT>self.__threshold = threshold;         <EOL>self.__max_entries = max_entries;<EOL>self.__leafes = [];<EOL>self.__type_measurement = type_measurement;<EOL>self.__amount_nodes = <NUM_LIT:0>;    <EOL>self.__amount_entries = <NUM_LIT:0>;<EOL>self.__height = <NUM_LIT:0>;          <EOL>

!
        @brief Create CF-tree.

        @param[in] branch_factor (uint): Maximum number of children for non-leaf nodes.
        @param[in] max_entries (uint): Maximum number of entries for leaf nodes.
        @param[in] threshold (double): Maximum diameter of feature clustering for each leaf node.
        @param[in] type_measurement (measurement_type): Measurement type that is used for calculation distance metrics.


level_nodes = [];<EOL>if (level < self.__height):<EOL><INDENT>level_nodes = self.__recursive_get_level_nodes(level, self.__root);<EOL><DEDENT>return level_nodes<EOL>

!
        @brief Traverses CF-tree to obtain nodes at the specified level.

        @param[in] level (uint): CF-tree level from that nodes should be returned.

        @return (list) List of CF-nodes that are located on the specified level of the CF-tree.


def __recursive_get_level_nodes(self, level, node):

level_nodes = [];<EOL>if (level is <NUM_LIT:0>):<EOL><INDENT>level_nodes.append(node);<EOL><DEDENT>else:<EOL><INDENT>for sucessor in node.successors:<EOL><INDENT>level_nodes += self.__recursive_get_level_nodes(level - <NUM_LIT:1>, sucessor);<EOL><DEDENT><DEDENT>return level_nodes<EOL>

!
        @brief Traverses CF-tree to obtain nodes at the specified level recursively.

        @param[in] level (uint): Current CF-tree level.
        @param[in] node (cfnode): CF-node from that traversing is performed.

        @return (list) List of CF-nodes that are located on the specified level of the CF-tree.


entry = cfentry(len(cluster), linear_sum(cluster), square_sum(cluster));<EOL>self.insert(entry)<EOL>

!
        @brief Insert cluster that is represented as list of points where each point is represented by list of coordinates.
        @details Clustering feature is created for that cluster and inserted to the tree.

        @param[in] cluster (list): Cluster that is represented by list of points that should be inserted to the tree.


if (self.__root is None):<EOL><INDENT>node = leaf_node(entry, None, [ entry ], None);<EOL>self.__root = node;<EOL>self.__leafes.append(node);<EOL>self.__amount_entries += <NUM_LIT:1>;<EOL>self.__amount_nodes += <NUM_LIT:1>;<EOL>self.__height += <NUM_LIT:1>;             <EOL><DEDENT>else:<EOL><INDENT>child_node_updation = self.__recursive_insert(entry, self.__root);<EOL>if (child_node_updation is True):<EOL><INDENT>if (self.__merge_nearest_successors(self.__root) is True):<EOL><INDENT>self.__amount_nodes -= <NUM_LIT:1>;<EOL><DEDENT><DEDENT><DEDENT>

!
        @brief Insert clustering feature to the tree.

        @param[in] entry (cfentry): Clustering feature that should be inserted.


def find_nearest_leaf(self, entry, search_node = None):

if (search_node is None):<EOL><INDENT>search_node = self.__root;<EOL><DEDENT>nearest_node = search_node;<EOL>if (search_node.type == cfnode_type.CFNODE_NONLEAF):<EOL><INDENT>min_key = lambda child_node: child_node.feature.get_distance(entry, self.__type_measurement);<EOL>nearest_child_node = min(search_node.successors, key = min_key);<EOL>nearest_node = self.find_nearest_leaf(entry, nearest_child_node);<EOL><DEDENT>return nearest_node<EOL>

!
        @brief Search nearest leaf to the specified clustering feature.

        @param[in] entry (cfentry): Clustering feature.
        @param[in] search_node (cfnode): Node from that searching should be started, if None then search process will be started for the root.

        @return (leaf_node) Nearest node to the specified clustering feature.


def __recursive_insert(self, entry, search_node):

<EOL>if (search_node.type == cfnode_type.CFNODE_NONLEAF):<EOL><INDENT>return self.__insert_for_noneleaf_node(entry, search_node);<EOL><DEDENT>else:<EOL><INDENT>return self.__insert_for_leaf_node(entry, search_node);<EOL><DEDENT>

!
        @brief Recursive insert of the entry to the tree.
        @details It performs all required procedures during insertion such as splitting, merging.

        @param[in] entry (cfentry): Clustering feature.
        @param[in] search_node (cfnode): Node from that insertion should be started.

        @return (bool) True if number of nodes at the below level is changed, otherwise False.


def __insert_for_leaf_node(self, entry, search_node):

node_amount_updation = False;<EOL>index_nearest_entry = search_node.get_nearest_index_entry(entry, self.__type_measurement);<EOL>merged_entry = search_node.entries[index_nearest_entry] + entry;<EOL>if (merged_entry.get_diameter() > self.__threshold):<EOL><INDENT>search_node.insert_entry(entry);<EOL>if (len(search_node.entries) > self.__max_entries):<EOL><INDENT>self.__split_procedure(search_node);<EOL>node_amount_updation = True;<EOL><DEDENT>self.__amount_entries += <NUM_LIT:1>;<EOL><DEDENT>else:<EOL><INDENT>search_node.entries[index_nearest_entry] = merged_entry;<EOL>search_node.feature += entry;<EOL><DEDENT>return node_amount_updation<EOL>

!
        @brief Recursive insert entry from leaf node to the tree.

        @param[in] entry (cfentry): Clustering feature.
        @param[in] search_node (cfnode): None-leaf node from that insertion should be started.

        @return (bool) True if number of nodes at the below level is changed, otherwise False.


def __insert_for_noneleaf_node(self, entry, search_node):

node_amount_updation = False;<EOL>min_key = lambda child_node: child_node.get_distance(search_node, self.__type_measurement);<EOL>nearest_child_node = min(search_node.successors, key = min_key);<EOL>child_node_updation = self.__recursive_insert(entry, nearest_child_node);<EOL>search_node.feature += entry;<EOL>if (len(search_node.successors) > self.__branch_factor):<EOL><INDENT>if (search_node is self.__root):<EOL><INDENT>self.__root = non_leaf_node(search_node.feature, None, [ search_node ], None);<EOL>search_node.parent = self.__root;<EOL>self.__amount_nodes += <NUM_LIT:1>;<EOL>self.__height += <NUM_LIT:1>;<EOL><DEDENT>[new_node1, new_node2] = self.__split_nonleaf_node(search_node);<EOL>parent = search_node.parent;<EOL>parent.successors.remove(search_node);<EOL>parent.successors.append(new_node1);<EOL>parent.successors.append(new_node2);<EOL>self.__amount_nodes += <NUM_LIT:1>;<EOL>node_amount_updation = True;<EOL><DEDENT>elif (child_node_updation is True):<EOL><INDENT>if (self.__merge_nearest_successors(search_node) is True):<EOL><INDENT>self.__amount_nodes -= <NUM_LIT:1>;<EOL><DEDENT><DEDENT>return node_amount_updation<EOL>

!
        @brief Recursive insert entry from none-leaf node to the tree.

        @param[in] entry (cfentry): Clustering feature.
        @param[in] search_node (cfnode): None-leaf node from that insertion should be started.

        @return (bool) True if number of nodes at the below level is changed, otherwise False.


merging_result = False;<EOL>if (node.successors[<NUM_LIT:0>].type == cfnode_type.CFNODE_NONLEAF):<EOL><INDENT>[nearest_child_node1, nearest_child_node2] = node.get_nearest_successors(self.__type_measurement);<EOL>if (len(nearest_child_node1.successors) + len(nearest_child_node2.successors) <= self.__branch_factor):<EOL><INDENT>node.successors.remove(nearest_child_node2);<EOL>if (nearest_child_node2.type == cfnode_type.CFNODE_LEAF):<EOL><INDENT>self.__leafes.remove(nearest_child_node2);<EOL><DEDENT>nearest_child_node1.merge(nearest_child_node2);<EOL>merging_result = True;<EOL><DEDENT><DEDENT>return merging_result<EOL>

!
        @brief Find nearest sucessors and merge them.

        @param[in] node (non_leaf_node): Node whose two nearest successors should be merged.

        @return (bool): True if merging has been successfully performed, otherwise False.


if (split_node is self.__root):<EOL><INDENT>self.__root = non_leaf_node(split_node.feature, None, [ split_node ], None);<EOL>split_node.parent = self.__root;<EOL>self.__amount_nodes += <NUM_LIT:1>;<EOL>self.__height += <NUM_LIT:1>;<EOL><DEDENT>[new_node1, new_node2] = self.__split_leaf_node(split_node);<EOL>self.__leafes.remove(split_node);<EOL>self.__leafes.append(new_node1);<EOL>self.__leafes.append(new_node2);<EOL>parent = split_node.parent;<EOL>parent.successors.remove(split_node);<EOL>parent.successors.append(new_node1);<EOL>parent.successors.append(new_node2);<EOL>self.__amount_nodes += <NUM_LIT:1><EOL>

!
        @brief Starts node splitting procedure in the CF-tree from the specify node.

        @param[in] split_node (cfnode): CF-tree node that should be splitted.


[farthest_node1, farthest_node2] = node.get_farthest_successors(self.__type_measurement);<EOL>new_node1 = non_leaf_node(farthest_node1.feature, node.parent, [ farthest_node1 ], None);<EOL>new_node2 = non_leaf_node(farthest_node2.feature, node.parent, [ farthest_node2 ], None);<EOL>farthest_node1.parent = new_node1;<EOL>farthest_node2.parent = new_node2;<EOL>for successor in node.successors:<EOL><INDENT>if ( (successor is not farthest_node1) and (successor is not farthest_node2) ):<EOL><INDENT>distance1 = new_node1.get_distance(successor, self.__type_measurement);<EOL>distance2 = new_node2.get_distance(successor, self.__type_measurement);<EOL>if (distance1 < distance2):<EOL><INDENT>new_node1.insert_successor(successor);<EOL><DEDENT>else:<EOL><INDENT>new_node2.insert_successor(successor);<EOL><DEDENT><DEDENT><DEDENT>return [new_node1, new_node2]<EOL>

!
        @brief Performs splitting of the specified non-leaf node.

        @param[in] node (non_leaf_node): Non-leaf node that should be splitted.

        @return (list) New pair of non-leaf nodes [non_leaf_node1, non_leaf_node2].


<EOL>[farthest_entity1, farthest_entity2] = node.get_farthest_entries(self.__type_measurement);<EOL>new_node1 = leaf_node(farthest_entity1, node.parent, [ farthest_entity1 ], None);<EOL>new_node2 = leaf_node(farthest_entity2, node.parent, [ farthest_entity2 ], None);<EOL>for entity in node.entries:<EOL><INDENT>if ( (entity is not farthest_entity1) and (entity is not farthest_entity2) ):<EOL><INDENT>distance1 = new_node1.feature.get_distance(entity, self.__type_measurement);<EOL>distance2 = new_node2.feature.get_distance(entity, self.__type_measurement);<EOL>if (distance1 < distance2):<EOL><INDENT>new_node1.insert_entry(entity);<EOL><DEDENT>else:<EOL><INDENT>new_node2.insert_entry(entity);<EOL><DEDENT><DEDENT><DEDENT>return [new_node1, new_node2]<EOL>

!
        @brief Performs splitting of the specified leaf node.

        @param[in] node (leaf_node): Leaf node that should be splitted.

        @return (list) New pair of leaf nodes [leaf_node1, leaf_node2].

        @warning Splitted node is transformed to non_leaf.


def show_feature_destibution(self, data = None):

visualizer = cluster_visualizer();<EOL>print("<STR_LIT>", self.__amount_nodes);<EOL>if (data is not None):<EOL><INDENT>visualizer.append_cluster(data, marker = '<STR_LIT:x>');<EOL><DEDENT>for level in range(<NUM_LIT:0>, self.height):<EOL><INDENT>level_nodes = self.get_level_nodes(level);<EOL>centers = [ node.feature.get_centroid() for node in level_nodes ];<EOL>visualizer.append_cluster(centers, None, markersize = (self.height - level + <NUM_LIT:1>) * <NUM_LIT:5>);<EOL><DEDENT>visualizer.show()<EOL>

!
        @brief Shows feature distribution.
        @details Only features in 1D, 2D, 3D space can be visualized.

        @param[in] data (list): List of points that will be used for visualization, if it not specified than feature will be displayed only.


self.__kdtree_instance = kdtree_instance<EOL>self.__tree_level_text  = "<STR_LIT>"<EOL>self.__tree_text        = "<STR_LIT>"<EOL>

!
        @brief Initialize KD-tree text visualizer.

        @param[in] kdtree_instance (kdtree): Instance of KD-Tree that should be visualized.