if (self.__amount <= <NUM_LIT:0>) or (self.__amount > len(self.__data)):<EOL><INDENT>raise AttributeError("<STR_LIT>" + str(self.__amount) + "<STR_LIT>"<EOL>"<STR_LIT>")<EOL><DEDENT>if self.__candidates != kmeans_plusplus_initializer.FARTHEST_CENTER_CANDIDATE:<EOL><INDENT>if (self.__candidates <= <NUM_LIT:0>) or (self.__candidates > len(self.__data)):<EOL><INDENT>raise AttributeError("<STR_LIT>" + str(self.__candidates) + "<STR_LIT>"<EOL>"<STR_LIT>")<EOL><DEDENT><DEDENT>if len(self.__data) == <NUM_LIT:0>:<EOL><INDENT>raise AttributeError("<STR_LIT>")<EOL><DEDENT>

!
        @brief Checks input parameters of the algorithm and if something wrong then corresponding exception is thrown.


def __get_next_center(self, centers, return_index):

distances = self.__calculate_shortest_distances(self.__data, centers, return_index)<EOL>if self.__candidates == kmeans_plusplus_initializer.FARTHEST_CENTER_CANDIDATE:<EOL><INDENT>center_index = numpy.nanargmax(distances)<EOL><DEDENT>else:<EOL><INDENT>probabilities = self.__calculate_probabilities(distances)<EOL>center_index = self.__get_probable_center(distances, probabilities)<EOL><DEDENT>if return_index:<EOL><INDENT>return center_index<EOL><DEDENT>return self.__data[center_index]<EOL>

!
        @brief Calculates the next center for the data.

        @param[in] centers (array_like): Current initialized centers.
        @param[in] return_index (bool): If True then return center's index instead of point.

        @return (array_like) Next initialized center.<br>
                (uint) Index of next initialized center if return_index is True.


index_center = random.randint(<NUM_LIT:0>, len(self.__data) - <NUM_LIT:1>)<EOL>if return_index:<EOL><INDENT>return index_center<EOL><DEDENT>return self.__data[index_center]<EOL>

!
        @brief Choose randomly first center.

        @param[in] return_index (bool): If True then return center's index instead of point.

        @return (array_like) First center.<br>
                (uint) Index of first center.


total_distance = numpy.sum(distances)<EOL>if total_distance != <NUM_LIT:0.0>:<EOL><INDENT>probabilities = distances / total_distance<EOL>return numpy.cumsum(probabilities)<EOL><DEDENT>else:<EOL><INDENT>return numpy.zeros(len(distances))<EOL><DEDENT>

!
        @brief Calculates cumulative probabilities of being center of each point.

        @param[in] distances (array_like): Distances from each point to closest center.

        @return (array_like) Cumulative probabilities of being center of each point.


def __get_probable_center(self, distances, probabilities):

index_best_candidate = -<NUM_LIT:1><EOL>for _ in range(self.__candidates):<EOL><INDENT>candidate_probability = random.random()<EOL>index_candidate = <NUM_LIT:0><EOL>for index_object in range(len(probabilities)):<EOL><INDENT>if candidate_probability < probabilities[index_object]:<EOL><INDENT>index_candidate = index_object<EOL>break<EOL><DEDENT><DEDENT>if index_best_candidate == -<NUM_LIT:1>:<EOL><INDENT>index_best_candidate = next(iter(self.__free_indexes))<EOL><DEDENT>elif distances[index_best_candidate] < distances[index_candidate]:<EOL><INDENT>index_best_candidate = index_candidate<EOL><DEDENT><DEDENT>return index_best_candidate<EOL>

!
        @brief Calculates the next probable center considering amount candidates.

        @param[in] distances (array_like): Distances from each point to closest center.
        @param[in] probabilities (array_like): Cumulative probabilities of being center of each point.

        @return (uint) Index point that is next initialized center.


return_index = kwargs.get('<STR_LIT>', False)<EOL>index_point = self.__get_initial_center(True)<EOL>centers = [index_point]<EOL>self.__free_indexes.remove(index_point)<EOL>for _ in range(<NUM_LIT:1>, self.__amount):<EOL><INDENT>index_point = self.__get_next_center(centers, True)<EOL>centers.append(index_point)<EOL>self.__free_indexes.remove(index_point)<EOL><DEDENT>if not return_index:<EOL><INDENT>centers = [self.__data[index] for index in centers]<EOL><DEDENT>return centers<EOL>

!
        @brief Calculates initial centers using K-Means++ method.

        @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'return_index').

        Keyword Args:

            - return_index (bool): If True then returns indexes of points from input data instead of points itself.

        @return (list) List of initialized initial centers.
                  If argument 'return_index' is False then returns list of points.
                  If argument 'return_index' is True then returns list of indexes.


dimension = cells[<NUM_LIT:0>].dimensions<EOL>amount_canvases = <NUM_LIT:1><EOL>if dimension > <NUM_LIT:1>:<EOL><INDENT>amount_canvases = int(dimension * (dimension - <NUM_LIT:1>) / <NUM_LIT:2>)<EOL><DEDENT>figure = plt.figure()<EOL>grid_spec = gridspec.GridSpec(<NUM_LIT:1>, amount_canvases)<EOL>pairs = list(itertools.combinations(range(dimension), <NUM_LIT:2>))<EOL>if len(pairs) == <NUM_LIT:0>: pairs = [(<NUM_LIT:0>, <NUM_LIT:0>)]<EOL>for index in range(amount_canvases):<EOL><INDENT>ax = figure.add_subplot(grid_spec[index])<EOL>clique_visualizer.__draw_cells(ax, cells, pairs[index])<EOL>clique_visualizer.__draw_two_dimension_data(ax, data, pairs[index])<EOL><DEDENT>plt.show()<EOL>

!
        @brief Show CLIQUE blocks as a grid in data space.
        @details Each block contains points and according to this density is displayed. CLIQUE grid helps to visualize
                  grid that was used for clustering process.

        @param[in] cells (list): List of cells that is produced by CLIQUE algorithm.
        @param[in] data (array_like): Input data that was used for clustering process.


@staticmethod<EOL><INDENT>def show_clusters(data, clusters, noise=None):<DEDENT>

visualizer = cluster_visualizer()<EOL>visualizer.append_clusters(clusters, data)<EOL>visualizer.append_cluster(noise or [], data, marker='<STR_LIT:x>')<EOL>visualizer.show()<EOL>

!
        @brief Display CLIQUE clustering results.

        @param[in] data (list): Data that was used for clustering.
        @param[in] clusters (array_like): Clusters that were allocated by the algorithm.
        @param[in] noise (array_like): Noise that were allocated by the algorithm.


@staticmethod<EOL><INDENT>def __draw_two_dimension_data(ax, data, pair):<DEDENT>

ax.set_xlabel("<STR_LIT>" % pair[<NUM_LIT:0>])<EOL>ax.set_ylabel("<STR_LIT>" % pair[<NUM_LIT:1>])<EOL>for point in data:<EOL><INDENT>if len(data[<NUM_LIT:0>]) > <NUM_LIT:1>:<EOL><INDENT>ax.plot(point[pair[<NUM_LIT:0>]], point[pair[<NUM_LIT:1>]], color='<STR_LIT>', marker='<STR_LIT:.>')<EOL><DEDENT>else:<EOL><INDENT>ax.plot(point[pair[<NUM_LIT:0>]], <NUM_LIT:0>, color='<STR_LIT>', marker='<STR_LIT:.>')<EOL>ax.yaxis.set_ticklabels([])<EOL><DEDENT><DEDENT>

!
        @brief Display data in two-dimensional canvas.

        @param[in] ax (Axis): Canvas where data should be displayed.
        @param[in] data (list): Data points that should be displayed.
        @param[in] pair (tuple): Pair of dimension indexes.


def __init__(self, max_corner, min_corner):

self.__max_corner = max_corner<EOL>self.__min_corner = min_corner<EOL>

!
        @brief Creates spatial block in data space.

        @param[in] max_corner (array_like): Maximum corner coordinates of the block.
        @param[in] min_corner (array_like): Minimal corner coordinates of the block.


return "<STR_LIT>" % (self.__max_corner, self.__min_corner)<EOL>

!
        @brief Returns string block description.

        @return String representation of the block.


for i in range(len(point)):<EOL><INDENT>if point[i] < self.__min_corner[i] or point[i] > self.__max_corner[i]:<EOL><INDENT>return False<EOL><DEDENT><DEDENT>return True<EOL>

!
        @brief Point is considered as contained if it lies in block (belong to it).

        @return (bool) True if point is in block, otherwise False.


return self.__max_corner, self.__min_corner<EOL>

!
        @brief Return spatial description of current block.

        @return (tuple) Pair of maximum and minimum corners (max_corner, min_corner).


def __init__(self, logical_location=None, spatial_location=None, points=None, visited=False):

self.__logical_location = logical_location or []<EOL>self.__spatial_location = spatial_location<EOL>self.__points = points or []<EOL>self.__visited = visited<EOL>

!
        @brief Initializes CLIQUE block.

        @param[in] logical_location (list): Logical location of the block in CLIQUE grid.
        @param[in] spatial_location (spatial_block): Spatial location in data space.
        @param[in] points (array_like): Points that belong to this block (can be obtained by method 'capture_points',
                    this parameter is used by CLIQUE in case of processing by C++ implementation when clustering
                    result are passed back to Python code.
        @param[in] visited (bool): Marks if block is visited during clustering process.


return str(self.__logical_location)<EOL>

!
        @brief Returns string representation of the block using its logical location in CLIQUE grid.


return self.__logical_location<EOL>

!
        @brief Logical location is represented by coordinates in CLIQUE grid, for example, in case of 2x2 grid blocks
                may have following coordinates: [0, 0], [0, 1], [1, 0], [1, 1].
        @return (list) Logical location of the block in CLIQUE grid.


self.__logical_location = location<EOL>

!
        @brief Assign logical location to CLIQUE block.

        @param[in] location (list): New logical location of the block in CLIQUE grid.


return self.__spatial_location<EOL>

!
        @brief Spatial location is represented by real data space coordinates.
        @return (spatial_block) Spatial block that describes location in data space.


self.__spatial_location = location<EOL>

!
        @brief Assign spatial location to CLIQUE block.

        @param[in] location (spatial_block): New spatial location of the block.


return len(self.__logical_location)<EOL>

!
        @brief Amount of dimensions where CLIQUE block is located.
        @return (uint) Amount of dimensions where CLIQUE block is located.


return self.__points<EOL>

!
        @brief Points that belong to the CLIQUE block.
        @details Points are represented by indexes that correspond to points in input data space.

        @return (array_like) Points that belong to the CLIQUE block.

        @see capture_points


return self.__visited<EOL>

!
        @brief Defines whether block is visited during cluster analysis.
        @details If cluster analysis has not been performed then value will False.

        @return (bool) True if block has been visited during processing, False otherwise.


self.__visited = visited<EOL>

!
        @brief Marks or unmarks block as a visited.
        @details This setter is used by CLIQUE algorithm.

        @param[in] visited (bool): New visited state for the CLIQUE block.


def capture_points(self, data, point_availability):

for index_point in range(len(data)):<EOL><INDENT>if (point_availability[index_point] is True) and (data[index_point] in self.__spatial_location):<EOL><INDENT>self.__points.append(index_point)<EOL>point_availability[index_point] = False<EOL><DEDENT><DEDENT>

!
        @brief Finds points that belong to this block using availability map to reduce computational complexity by
                checking whether the point belongs to the block.
        @details Algorithm complexity of this method is O(n).

        @param[in] data (array_like): Data where points are represented as coordinates.
        @param[in] point_availability (array_like): Contains boolean values that denote whether point is already belong
                    to another CLIQUE block.


neighbors = []<EOL>for index_dimension in range(len(self.__logical_location)):<EOL><INDENT>if self.__logical_location[index_dimension] + <NUM_LIT:1> < edge:<EOL><INDENT>position = self.__logical_location[:]<EOL>position[index_dimension] += <NUM_LIT:1><EOL>neighbors.append(position)<EOL><DEDENT>if self.__logical_location[index_dimension] - <NUM_LIT:1> >= <NUM_LIT:0>:<EOL><INDENT>position = self.__logical_location[:]<EOL>position[index_dimension] -= <NUM_LIT:1><EOL>neighbors.append(position)<EOL><DEDENT><DEDENT>return neighbors<EOL>

!
        @brief Forms list of logical location of each neighbor for this particular CLIQUE block.

        @param[in] edge (uint): Amount of intervals in each dimension that is used for clustering process.

        @return (list) Logical location of each neighbor for this particular CLIQUE block.


def __init__(self, dimension, intervals):

self.__intervals = intervals<EOL>self.__dimension = dimension<EOL>self.__coordiate = [<NUM_LIT:0>] * dimension<EOL>

!
        @brief Initializes coordinate iterator for CLIQUE algorithm.

        @param[in] dimension (uint): Amount of dimensions in input data space.
        @param[in] intervals (uint): Amount of intervals in each dimension.


return self.__coordiate<EOL>

!
        @brief Returns current block coordinate.


for index_dimension in range(self.__dimension):<EOL><INDENT>if self.__coordiate[index_dimension] + <NUM_LIT:1> < self.__intervals:<EOL><INDENT>self.__coordiate[index_dimension] += <NUM_LIT:1><EOL>return<EOL><DEDENT>else:<EOL><INDENT>self.__coordiate[index_dimension] = <NUM_LIT:0><EOL><DEDENT><DEDENT>self.__coordiate = None<EOL>

!
        @brief Forms logical location for next block.


def __init__(self, data, amount_intervals, density_threshold, **kwargs):

self.__data = data<EOL>self.__amount_intervals = amount_intervals<EOL>self.__density_threshold = density_threshold<EOL>self.__ccore = kwargs.get('<STR_LIT>', True)<EOL>if self.__ccore:<EOL><INDENT>self.__ccore = ccore_library.workable()<EOL><DEDENT>self.__clusters = []<EOL>self.__noise = []<EOL>self.__cells = []<EOL>self.__cells_map = {}<EOL>self.__validate_arguments()<EOL>

!
        @brief Create CLIQUE clustering algorithm.

        @param[in] data (list): Input data (list of points) that should be clustered.
        @param[in] amount_intervals (uint): Amount of intervals in each dimension that defines amount of CLIQUE block
                    as \f[N_{blocks} = intervals^{dimensions}\f].
        @param[in] density_threshold (uint): Minimum number of points that should contain CLIQUE block to consider its
                    points as non-outliers.
        @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'ccore').

        Keyword Args:

            - ccore (bool): By default is True. If True then C++ implementation is used for cluster analysis, otherwise
               Python implementation is used.


if self.__ccore:<EOL><INDENT>self.__process_by_ccore()<EOL><DEDENT>else:<EOL><INDENT>self.__process_by_python()<EOL><DEDENT>return self<EOL>

!
        @brief Performs clustering process in line with rules of CLIQUE clustering algorithm.

        @return (clique) Returns itself (CLIQUE instance).

        @see get_clusters()
        @see get_noise()
        @see get_cells()


return self.__clusters<EOL>

!
        @brief Returns allocated clusters.

        @remark Allocated clusters are returned only after data processing (method process()). Otherwise empty list is returned.

        @return (list) List of allocated clusters, each cluster contains indexes of objects in list of data.

        @see process()
        @see get_noise()


return self.__noise<EOL>

!
        @brief Returns allocated noise.

        @remark Allocated noise is returned only after data processing (method process()). Otherwise empty list is returned.

        @return (list) List of indexes that are marked as a noise.

        @see process()
        @see get_clusters()


return self.__cells<EOL>

!
        @brief Returns CLIQUE blocks that are formed during clustering process.
        @details CLIQUE blocks can be used for visualization purposes. Each CLIQUE block contain its logical location
                  in grid, spatial location in data space and points that belong to block.

        @return (list) List of CLIQUE blocks.


return type_encoding.CLUSTER_INDEX_LIST_SEPARATION<EOL>

!
        @brief Returns clustering result representation type that indicate how clusters are encoded.

        @return (type_encoding) Clustering result representation.

        @see get_clusters()


(self.__clusters, self.__noise, block_logical_locations, block_max_corners, block_min_corners, block_points) =wrapper.clique(self.__data, self.__amount_intervals, self.__density_threshold)<EOL>amount_cells = len(block_logical_locations)<EOL>for i in range(amount_cells):<EOL><INDENT>self.__cells.append(clique_block(block_logical_locations[i],<EOL>spatial_block(block_max_corners[i], block_min_corners[i]),<EOL>block_points[i],<EOL>True))<EOL><DEDENT>

!
        @brief Performs cluster analysis using C++ implementation of CLIQUE algorithm that is used by default if
                user's target platform is supported.


self.__create_grid()<EOL>self.__allocate_clusters()<EOL>self.__cells_map.clear()<EOL>

!
        @brief Performs cluster analysis using Python implementation of CLIQUE algorithm.


if len(self.__data) == <NUM_LIT:0>:<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>if self.__amount_intervals <= <NUM_LIT:0>:<EOL><INDENT>raise ValueError("<STR_LIT>" % self.__amount_intervals)<EOL><DEDENT>if self.__density_threshold < <NUM_LIT:0>:<EOL><INDENT>raise ValueError("<STR_LIT>" % self.__density_threshold)<EOL><DEDENT>

!
        @brief Check input arguments of CLIQUE algorithm and if one of them is not correct then appropriate exception
                is thrown.


for cell in self.__cells:<EOL><INDENT>if cell.visited is False:<EOL><INDENT>self.__expand_cluster(cell)<EOL><DEDENT><DEDENT>

!
        @brief Performs cluster analysis using formed CLIQUE blocks.


cell.visited = True<EOL>if len(cell.points) <= self.__density_threshold:<EOL><INDENT>if len(cell.points) > <NUM_LIT:0>:<EOL><INDENT>self.__noise.extend(cell.points)<EOL><DEDENT>return<EOL><DEDENT>cluster = cell.points[:]<EOL>neighbors = self.__get_neighbors(cell)<EOL>for neighbor in neighbors:<EOL><INDENT>if len(neighbor.points) > self.__density_threshold:<EOL><INDENT>cluster.extend(neighbor.points)<EOL>neighbors += self.__get_neighbors(neighbor)<EOL><DEDENT>elif len(neighbor.points) > <NUM_LIT:0>:<EOL><INDENT>self.__noise.extend(neighbor.points)<EOL><DEDENT><DEDENT>self.__clusters.append(cluster)<EOL>

!
        @brief Tries to expand cluster from specified cell.
        @details During expanding points are marked as noise or append to new cluster.

        @param[in] cell (clique_block): CLIQUE block from that cluster should be expanded.


neighbors = []<EOL>location_neighbors = cell.get_location_neighbors(self.__amount_intervals)<EOL>for i in range(len(location_neighbors)):<EOL><INDENT>key = self.__location_to_key(location_neighbors[i])<EOL>candidate_neighbor = self.__cell_map[key]<EOL>if not candidate_neighbor.visited:<EOL><INDENT>candidate_neighbor.visited = True<EOL>neighbors.append(candidate_neighbor)<EOL><DEDENT><DEDENT>return neighbors<EOL>

!
        @brief Returns neighbors for specified CLIQUE block as clique_block objects.

        @return (list) Neighbors as clique_block objects.


data_sizes, min_corner, max_corner = self.__get_data_size_derscription()<EOL>dimension = len(self.__data[<NUM_LIT:0>])<EOL>cell_sizes = [dimension_length / self.__amount_intervals for dimension_length in data_sizes]<EOL>self.__cells = [clique_block() for _ in range(pow(self.__amount_intervals, dimension))]<EOL>iterator = coordinate_iterator(dimension, self.__amount_intervals)<EOL>point_availability = [True] * len(self.__data)<EOL>self.__cell_map = {}<EOL>for index_cell in range(len(self.__cells)):<EOL><INDENT>logical_location = iterator.get_coordinate()<EOL>iterator.increment()<EOL>self.__cells[index_cell].logical_location = logical_location[:]<EOL>cur_max_corner, cur_min_corner = self.__get_spatial_location(logical_location, min_corner, max_corner, cell_sizes)<EOL>self.__cells[index_cell].spatial_location = spatial_block(cur_max_corner, cur_min_corner)<EOL>self.__cells[index_cell].capture_points(self.__data, point_availability)<EOL>self.__cell_map[self.__location_to_key(logical_location)] = self.__cells[index_cell]<EOL><DEDENT>

!
        @brief Creates CLIQUE grid that consists of CLIQUE blocks for clustering process.


return '<STR_LIT>'.join(str(e) + '<STR_LIT:.>' for e in location)<EOL>

!
        @brief Forms key using logical location of a CLIQUE block.

        @return (string) Key for CLIQUE block map.


def __get_spatial_location(self, logical_location, min_corner, max_corner, cell_sizes):

cur_min_corner = min_corner[:]<EOL>cur_max_corner = min_corner[:]<EOL>dimension = len(self.__data[<NUM_LIT:0>])<EOL>for index_dimension in range(dimension):<EOL><INDENT>cur_min_corner[index_dimension] += cell_sizes[index_dimension] * logical_location[index_dimension]<EOL>if logical_location[index_dimension] == self.__amount_intervals - <NUM_LIT:1>:<EOL><INDENT>cur_max_corner[index_dimension] = max_corner[index_dimension]<EOL><DEDENT>else:<EOL><INDENT>cur_max_corner[index_dimension] = cur_min_corner[index_dimension] + cell_sizes[index_dimension]<EOL><DEDENT><DEDENT>return cur_max_corner, cur_min_corner<EOL>

!
        @brief Calculates spatial location for CLIQUE block with logical coordinates defined by logical_location.

        @param[in] logical_location (list): Logical location of CLIQUE block for that spatial location should be calculated.
        @param[in] min_corner (list): Minimum corner of an input data.
        @param[in] max_corner (list): Maximum corner of an input data.
        @param[in] cell_sizes (list): Size of CLIQUE block in each dimension.

        @return (list, list): Maximum and minimum corners for the specified CLIQUE block.


min_corner = self.__data[<NUM_LIT:0>][:]<EOL>max_corner = self.__data[<NUM_LIT:0>][:]<EOL>dimension = len(self.__data[<NUM_LIT:0>])<EOL>for index_point in range(<NUM_LIT:1>, len(self.__data)):<EOL><INDENT>for index_dimension in range(dimension):<EOL><INDENT>coordinate = self.__data[index_point][index_dimension]<EOL>if coordinate > max_corner[index_dimension]:<EOL><INDENT>max_corner[index_dimension] = coordinate<EOL><DEDENT>if coordinate < min_corner[index_dimension]:<EOL><INDENT>min_corner[index_dimension] = coordinate<EOL><DEDENT><DEDENT><DEDENT>data_sizes = [<NUM_LIT:0.0>] * dimension<EOL>for index_dimension in range(dimension):<EOL><INDENT>data_sizes[index_dimension] = max_corner[index_dimension] - min_corner[index_dimension]<EOL><DEDENT>return data_sizes, min_corner, max_corner<EOL>

!
        @brief Calculates input data description that is required to create CLIQUE grid.

        @return (list, list, list): Data size in each dimension, minimum and maximum corners.


def __init__(self, data, number_clusters, numlocal, maxneighbor):

self.__pointer_data = data<EOL>self.__numlocal = numlocal<EOL>self.__maxneighbor = maxneighbor<EOL>self.__number_clusters = number_clusters<EOL>self.__clusters = []<EOL>self.__current = []<EOL>self.__belong = []<EOL>self.__optimal_medoids = []<EOL>self.__optimal_estimation = float('<STR_LIT>')<EOL>

!
        @brief Constructor of clustering algorithm CLARANS.
        @details The higher the value of maxneighbor, the closer is CLARANS to K-Medoids, and the longer is each search of a local minima.

        @param[in] data (list): Input data that is presented as list of points (objects), each point should be represented by list or tuple.
        @param[in] number_clusters (uint): amount of clusters that should be allocated.
        @param[in] numlocal (uint): the number of local minima obtained (amount of iterations for solving the problem).
        @param[in] maxneighbor (uint): the maximum number of neighbors examined.


random.seed()<EOL>for _ in range(<NUM_LIT:0>, self.__numlocal):<EOL><INDENT>self.__current = random.sample(range(<NUM_LIT:0>, len(self.__pointer_data)), self.__number_clusters)<EOL>self.__update_clusters(self.__current)<EOL>self.__optimize_configuration()<EOL>estimation = self.__calculate_estimation()<EOL>if estimation < self.__optimal_estimation:<EOL><INDENT>self.__optimal_medoids = self.__current[:]<EOL>self.__optimal_estimation = estimation<EOL><DEDENT><DEDENT>self.__update_clusters(self.__optimal_medoids)<EOL>

!
        @brief Performs cluster analysis in line with rules of CLARANS algorithm.

        @see get_clusters()
        @see get_medoids()


return self.__clusters<EOL>

!
        @brief Returns allocated clusters by the algorithm.

        @remark Allocated clusters can be returned only after data processing (use method process()), otherwise empty list is returned.

        @return (list) List of allocated clusters, each cluster contains indexes of objects in list of data.

        @see process()
        @see get_medoids()


return self.__optimal_medoids<EOL>

!
        @brief Returns list of medoids of allocated clusters.

        @see process()
        @see get_clusters()


self.__belong = [<NUM_LIT:0>] * len(self.__pointer_data)<EOL>self.__clusters = [[] for i in range(len(medoids))]<EOL>for index_point in range(len(self.__pointer_data)):<EOL><INDENT>index_optim = -<NUM_LIT:1><EOL>dist_optim = <NUM_LIT:0.0><EOL>for index in range(len(medoids)):<EOL><INDENT>dist = euclidean_distance_square(self.__pointer_data[index_point], self.__pointer_data[medoids[index]])<EOL>if (dist < dist_optim) or (index is <NUM_LIT:0>):<EOL><INDENT>index_optim = index<EOL>dist_optim = dist<EOL><DEDENT><DEDENT>self.__clusters[index_optim].append(index_point)<EOL>self.__belong[index_point] = index_optim<EOL><DEDENT>self.__clusters = [cluster for cluster in self.__clusters if len(cluster) > <NUM_LIT:0>]<EOL>

!
        @brief Forms cluster in line with specified medoids by calculation distance from each point to medoids.


index_neighbor = <NUM_LIT:0><EOL>while (index_neighbor < self.__maxneighbor):<EOL><INDENT>current_medoid_index = self.__current[random.randint(<NUM_LIT:0>, self.__number_clusters - <NUM_LIT:1>)]<EOL>current_medoid_cluster_index = self.__belong[current_medoid_index]<EOL>candidate_medoid_index = random.randint(<NUM_LIT:0>, len(self.__pointer_data) - <NUM_LIT:1>)<EOL>while candidate_medoid_index in self.__current:<EOL><INDENT>candidate_medoid_index = random.randint(<NUM_LIT:0>, len(self.__pointer_data) - <NUM_LIT:1>)<EOL><DEDENT>candidate_cost = <NUM_LIT:0.0><EOL>for point_index in range(<NUM_LIT:0>, len(self.__pointer_data)):<EOL><INDENT>if point_index not in self.__current:<EOL><INDENT>point_cluster_index = self.__belong[point_index]<EOL>point_medoid_index = self.__current[point_cluster_index]<EOL>other_medoid_index = self.__find_another_nearest_medoid(point_index, current_medoid_index)<EOL>other_medoid_cluster_index = self.__belong[other_medoid_index]<EOL>distance_current = euclidean_distance_square(self.__pointer_data[point_index], self.__pointer_data[current_medoid_index])<EOL>distance_candidate = euclidean_distance_square(self.__pointer_data[point_index], self.__pointer_data[candidate_medoid_index])<EOL>distance_nearest = float('<STR_LIT>')<EOL>if ( (point_medoid_index != candidate_medoid_index) and (point_medoid_index != current_medoid_cluster_index) ):<EOL><INDENT>distance_nearest = euclidean_distance_square(self.__pointer_data[point_index], self.__pointer_data[point_medoid_index])<EOL><DEDENT>if (point_cluster_index == current_medoid_cluster_index):<EOL><INDENT>if (distance_candidate >= distance_nearest):<EOL><INDENT>candidate_cost += distance_nearest - distance_current<EOL><DEDENT>else:<EOL><INDENT>candidate_cost += distance_candidate - distance_current<EOL><DEDENT><DEDENT>elif (point_cluster_index == other_medoid_cluster_index):<EOL><INDENT>if (distance_candidate > distance_nearest):<EOL><INDENT>pass;<EOL><DEDENT>else:<EOL><INDENT>candidate_cost += distance_candidate - distance_nearest<EOL><DEDENT><DEDENT><DEDENT><DEDENT>if (candidate_cost < <NUM_LIT:0>):<EOL><INDENT>self.__current[current_medoid_cluster_index] = candidate_medoid_index<EOL>self.__update_clusters(self.__current)<EOL>index_neighbor = <NUM_LIT:0><EOL><DEDENT>else:<EOL><INDENT>index_neighbor += <NUM_LIT:1><EOL><DEDENT><DEDENT>

!
        @brief Finds quasi-optimal medoids and updates in line with them clusters in line with algorithm's rules.


def __find_another_nearest_medoid(self, point_index, current_medoid_index):

other_medoid_index = -<NUM_LIT:1><EOL>other_distance_nearest = float('<STR_LIT>')<EOL>for index_medoid in self.__current:<EOL><INDENT>if (index_medoid != current_medoid_index):<EOL><INDENT>other_distance_candidate = euclidean_distance_square(self.__pointer_data[point_index], self.__pointer_data[current_medoid_index])<EOL>if other_distance_candidate < other_distance_nearest:<EOL><INDENT>other_distance_nearest = other_distance_candidate<EOL>other_medoid_index = index_medoid<EOL><DEDENT><DEDENT><DEDENT>return other_medoid_index<EOL>

!
        @brief Finds the another nearest medoid for the specified point that is differ from the specified medoid.

        @param[in] point_index: index of point in dataspace for that searching of medoid in current list of medoids is perfomed.
        @param[in] current_medoid_index: index of medoid that shouldn't be considered as a nearest.

        @return (uint) index of the another nearest medoid for the point.


estimation = <NUM_LIT:0.0><EOL>for index_cluster in range(<NUM_LIT:0>, len(self.__clusters)):<EOL><INDENT>cluster = self.__clusters[index_cluster]<EOL>index_medoid = self.__current[index_cluster]<EOL>for index_point in cluster:<EOL><INDENT>estimation += euclidean_distance_square(self.__pointer_data[index_point], self.__pointer_data[index_medoid])<EOL><DEDENT><DEDENT>return estimation<EOL>

!
        @brief Calculates estimation (cost) of the current clusters. The lower the estimation,
               the more optimally configuration of clusters.

        @return (double) estimation of current clusters.


def __init__(self, data, number_clusters, branching_factor = <NUM_LIT:5>, max_node_entries = <NUM_LIT:5>, initial_diameter = <NUM_LIT:0.1>, type_measurement = measurement_type.CENTROID_EUCLIDEAN_DISTANCE, entry_size_limit = <NUM_LIT:200>, diameter_multiplier = <NUM_LIT>, ccore = True):

self.__pointer_data = data;<EOL>self.__number_clusters = number_clusters;<EOL>self.__measurement_type = type_measurement;<EOL>self.__entry_size_limit = entry_size_limit;<EOL>self.__diameter_multiplier = diameter_multiplier;<EOL>self.__ccore = ccore;<EOL>self.__features = None;<EOL>self.__tree = cftree(branching_factor, max_node_entries, initial_diameter, type_measurement);<EOL>self.__clusters = [];<EOL>self.__noise = []<EOL>

!
        @brief Constructor of clustering algorithm BIRCH.

        @param[in] data (list): Input data presented as list of points (objects), where each point should be represented by list or tuple.
        @param[in] number_clusters (uint): Number of clusters that should be allocated.
        @param[in] branching_factor (uint): Maximum number of successor that might be contained by each non-leaf node in CF-Tree.
        @param[in] max_node_entries (uint): Maximum number of entries that might be contained by each leaf node in CF-Tree.
        @param[in] initial_diameter (double): Initial diameter that used for CF-Tree construction, it can be increase if entry_size_limit is exceeded.
        @param[in] type_measurement (measurement_type): Type measurement used for calculation distance metrics.
        @param[in] entry_size_limit (uint): Maximum number of entries that can be stored in CF-Tree, if it is exceeded during creation then diameter is increased and CF-Tree is rebuilt.
        @param[in] diameter_multiplier (double): Multiplier that is used for increasing diameter when entry_size_limit is exceeded.
        @param[in] ccore (bool): If True than DLL CCORE (C++ solution) will be used for solving the problem.

        @remark Despite eight arguments only the first two is mandatory, others can be ommitted. In this case default values are used for instance creation.


self.__insert_data();<EOL>self.__extract_features();<EOL>current_number_clusters = len(self.__features);<EOL>while (current_number_clusters > self.__number_clusters):<EOL><INDENT>indexes = self.__find_nearest_cluster_features();<EOL>self.__features[indexes[<NUM_LIT:0>]] += self.__features[indexes[<NUM_LIT:1>]];<EOL>self.__features.pop(indexes[<NUM_LIT:1>]);<EOL>current_number_clusters = len(self.__features);<EOL><DEDENT>self.__decode_data()<EOL>

!
        @brief Performs cluster analysis in line with rules of BIRCH algorithm.

        @remark Results of clustering can be obtained using corresponding gets methods.

        @see get_clusters()


return self.__clusters<EOL>

!
        @brief Returns list of allocated clusters, each cluster contains indexes of objects in list of data.

        @remark Allocated noise can be returned only after data processing (use method process() before). Otherwise empty list is returned.

        @return (list) List of allocated clusters.

        @see process()
        @see get_noise()


return type_encoding.CLUSTER_INDEX_LIST_SEPARATION<EOL>

!
        @brief Returns clustering result representation type that indicate how clusters are encoded.

        @return (type_encoding) Clustering result representation.

        @see get_clusters()


self.__features = [];<EOL>if (len(self.__tree.leafes) == <NUM_LIT:1>):<EOL><INDENT>for entry in self.__tree.leafes[<NUM_LIT:0>].entries:<EOL><INDENT>self.__features.append(entry);<EOL><DEDENT><DEDENT>else:<EOL><INDENT>for node in self.__tree.leafes:<EOL><INDENT>self.__features.append(node.feature);<EOL><DEDENT><DEDENT>

!
        @brief Extracts features from CF-tree cluster.


self.__clusters = [ [] for _ in range(self.__number_clusters) ];<EOL>self.__noise = [];<EOL>for index_point in range(<NUM_LIT:0>, len(self.__pointer_data)):<EOL><INDENT>(_, cluster_index) = self.__get_nearest_feature(self.__pointer_data[index_point], self.__features);<EOL>self.__clusters[cluster_index].append(index_point);<EOL><DEDENT>

!
        @brief Decodes data from CF-tree features.


for index_point in range(<NUM_LIT:0>, len(self.__pointer_data)):<EOL><INDENT>point = self.__pointer_data[index_point];<EOL>self.__tree.insert_cluster( [ point ] );<EOL>if (self.__tree.amount_entries > self.__entry_size_limit):<EOL><INDENT>self.__tree = self.__rebuild_tree(index_point);<EOL><DEDENT><DEDENT>

!
        @brief Inserts input data to the tree.

        @remark If number of maximum number of entries is exceeded than diameter is increased and tree is rebuilt.


rebuild_result = False;<EOL>increased_diameter = self.__tree.threshold * self.__diameter_multiplier;<EOL>tree = None;<EOL>while(rebuild_result is False):<EOL><INDENT>if (increased_diameter == <NUM_LIT:0.0>):<EOL><INDENT>increased_diameter = <NUM_LIT:1.0>;<EOL><DEDENT>tree = cftree(self.__tree.branch_factor, self.__tree.max_entries, increased_diameter, self.__tree.type_measurement);<EOL>for index_point in range(<NUM_LIT:0>, index_point + <NUM_LIT:1>):<EOL><INDENT>point = self.__pointer_data[index_point];<EOL>tree.insert_cluster([point]);<EOL>if (tree.amount_entries > self.__entry_size_limit):<EOL><INDENT>increased_diameter *= self.__diameter_multiplier;<EOL>continue;<EOL><DEDENT><DEDENT>rebuild_result = True;<EOL><DEDENT>return tree<EOL>

!
        @brief Rebuilt tree in case of maxumum number of entries is exceeded.

        @param[in] index_point (uint): Index of point that is used as end point of re-building.

        @return (cftree) Rebuilt tree with encoded points till specified point from input data space.


minimum_distance = float("<STR_LIT>");<EOL>index1 = <NUM_LIT:0>;<EOL>index2 = <NUM_LIT:0>;<EOL>for index_candidate1 in range(<NUM_LIT:0>, len(self.__features)):<EOL><INDENT>feature1 = self.__features[index_candidate1];<EOL>for index_candidate2 in range(index_candidate1 + <NUM_LIT:1>, len(self.__features)):<EOL><INDENT>feature2 = self.__features[index_candidate2];<EOL>distance = feature1.get_distance(feature2, self.__measurement_type);<EOL>if (distance < minimum_distance):<EOL><INDENT>minimum_distance = distance;<EOL>index1 = index_candidate1;<EOL>index2 = index_candidate2;<EOL><DEDENT><DEDENT><DEDENT>return [index1, index2]<EOL>

!
        @brief Find pair of nearest CF entries.

        @return (list) List of two nearest enties that are represented by list [index_point1, index_point2].


def __get_nearest_feature(self, point, feature_collection):

minimum_distance = float("<STR_LIT>");<EOL>index_nearest_feature = -<NUM_LIT:1>;<EOL>for index_entry in range(<NUM_LIT:0>, len(feature_collection)):<EOL><INDENT>point_entry = cfentry(<NUM_LIT:1>, linear_sum([ point ]), square_sum([ point ]));<EOL>distance = feature_collection[index_entry].get_distance(point_entry, self.__measurement_type);<EOL>if (distance < minimum_distance):<EOL><INDENT>minimum_distance = distance;<EOL>index_nearest_feature = index_entry;<EOL><DEDENT><DEDENT>return (minimum_distance, index_nearest_feature)<EOL>

!
        @brief Find nearest entry for specified point.

        @param[in] point (list): Pointer to point from input dataset.
        @param[in] feature_collection (list): Feature collection that is used for obtaining nearest feature for the specified point.

        @return (double, uint) Tuple of distance to nearest entry to the specified point and index of that entry.


<EOL>self.points = [ ]<EOL>self.indexes = -<NUM_LIT:1><EOL>self.mean = None<EOL>self.rep = [ ]<EOL>if point is not None:<EOL><INDENT>self.points = [ point ]<EOL>self.indexes = [ index ]<EOL>self.mean = point<EOL>self.rep = [ point ]<EOL><DEDENT>self.closest = None<EOL>self.distance = float('<STR_LIT>')<EOL>

!
        @brief Constructor of CURE cluster.

        @param[in] point (list): Point represented by list of coordinates.
        @param[in] index (uint): Index point in dataset.


return "<STR_LIT>" % (self.distance, self.points)<EOL>

!
        @brief Displays distance to closest cluster and points that are contained by current cluster.


def __init__(self, data, number_cluster, number_represent_points = <NUM_LIT:5>, compression = <NUM_LIT:0.5>, ccore = True):

self.__pointer_data = self.__prepare_data_points(data)<EOL>self.__clusters = None<EOL>self.__representors = None<EOL>self.__means = None<EOL>self.__number_cluster = number_cluster<EOL>self.__number_represent_points = number_represent_points<EOL>self.__compression = compression<EOL>self.__ccore = ccore<EOL>if self.__ccore:<EOL><INDENT>self.__ccore = ccore_library.workable()<EOL><DEDENT>self.__validate_arguments()<EOL>

!
        @brief Constructor of clustering algorithm CURE.

        @param[in] data (array_like): Input data that should be processed.
        @param[in] number_cluster (uint): Number of clusters that should be allocated.
        @param[in] number_represent_points (uint): Number of representative points for each cluster.
        @param[in] compression (double): Coefficient defines level of shrinking of representation points toward the mean of the new created cluster after merging on each step. Usually it destributed from 0 to 1.
        @param[in] ccore (bool): If True then CCORE (C++ solution) will be used for solving.


if self.__ccore is True:<EOL><INDENT>self.__process_by_ccore()<EOL><DEDENT>else:<EOL><INDENT>self.__process_by_python()<EOL><DEDENT>

!
        @brief Performs cluster analysis in line with rules of CURE algorithm.

        @remark Results of clustering can be obtained using corresponding get methods.

        @see get_clusters()


cure_data_pointer = wrapper.cure_algorithm(self.__pointer_data, self.__number_cluster,<EOL>self.__number_represent_points, self.__compression)<EOL>self.__clusters = wrapper.cure_get_clusters(cure_data_pointer)<EOL>self.__representors = wrapper.cure_get_representors(cure_data_pointer)<EOL>self.__means = wrapper.cure_get_means(cure_data_pointer)<EOL>wrapper.cure_data_destroy(cure_data_pointer)<EOL>

!
        @brief Performs cluster analysis using CCORE (C/C++ part of pyclustering library).


self.__create_queue()  <EOL>self.__create_kdtree()  <EOL>while len(self.__queue) > self.__number_cluster:<EOL><INDENT>cluster1 = self.__queue[<NUM_LIT:0>]  <EOL>cluster2 = cluster1.closest  <EOL>self.__queue.remove(cluster1)<EOL>self.__queue.remove(cluster2)<EOL>self.__delete_represented_points(cluster1)<EOL>self.__delete_represented_points(cluster2)<EOL>merged_cluster = self.__merge_clusters(cluster1, cluster2)<EOL>self.__insert_represented_points(merged_cluster)<EOL>cluster_relocation_requests = []<EOL>if len(self.__queue) > <NUM_LIT:0>:<EOL><INDENT>merged_cluster.closest = self.__queue[<NUM_LIT:0>]  <EOL>merged_cluster.distance = self.__cluster_distance(merged_cluster, merged_cluster.closest)<EOL>for item in self.__queue:<EOL><INDENT>distance = self.__cluster_distance(merged_cluster, item)<EOL>if distance < merged_cluster.distance:<EOL><INDENT>merged_cluster.closest = item<EOL>merged_cluster.distance = distance<EOL><DEDENT>if (item.closest is cluster1) or (item.closest is cluster2):<EOL><INDENT>if item.distance < distance:<EOL><INDENT>(item.closest, item.distance) = self.__closest_cluster(item, distance)<EOL>if item.closest is None:<EOL><INDENT>item.closest = merged_cluster<EOL>item.distance = distance<EOL><DEDENT><DEDENT>else:<EOL><INDENT>item.closest = merged_cluster<EOL>item.distance = distance<EOL><DEDENT>cluster_relocation_requests.append(item)<EOL><DEDENT><DEDENT><DEDENT>self.__insert_cluster(merged_cluster)<EOL>for item in cluster_relocation_requests:<EOL><INDENT>self.__relocate_cluster(item)<EOL><DEDENT><DEDENT>self.__clusters = [cure_cluster_unit.indexes for cure_cluster_unit in self.__queue]<EOL>self.__representors = [cure_cluster_unit.rep for cure_cluster_unit in self.__queue]<EOL>self.__means = [cure_cluster_unit.mean for cure_cluster_unit in self.__queue]<EOL>

!
        @brief Performs cluster analysis using python code.


return self.__clusters<EOL>

!
        @brief Returns list of allocated clusters, each cluster contains indexes of objects in list of data.

        @return (list) List of allocated clusters.

        @see process()
        @see get_representors()
        @see get_means()


return self.__representors<EOL>

!
        @brief Returns list of point-representors of each cluster.
        @details Cluster index should be used for navigation between lists of point-representors.

        @return (list) List of point-representors of each cluster.

        @see get_clusters()
        @see get_means()


return self.__means<EOL>

!
        @brief Returns list of mean values of each cluster.
        @details Cluster index should be used for navigation between mean values.

        @return (list) List of mean values of each cluster.

        @see get_clusters()
        @see get_representors()


if isinstance(sample, numpy.ndarray):<EOL><INDENT>return sample.tolist()<EOL><DEDENT>return sample<EOL>

!
        @brief Prepare data points for clustering.
        @details In case of numpy.array there are a lot of overloaded basic operators, such as __contains__, __eq__.

        @return (list) Returns sample in list format.


if len(self.__pointer_data) == <NUM_LIT:0>:<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>if self.__number_cluster <= <NUM_LIT:0>:<EOL><INDENT>raise ValueError("<STR_LIT>" % self.__number_cluster)<EOL><DEDENT>if self.__compression < <NUM_LIT:0>:<EOL><INDENT>raise ValueError("<STR_LIT>" % self.__compression)<EOL><DEDENT>if self.__number_represent_points <= <NUM_LIT:0>:<EOL><INDENT>raise ValueError("<STR_LIT>" % self.__number_cluster)<EOL><DEDENT>

!
        @brief Check input arguments of BANG algorithm and if one of them is not correct then appropriate exception
                is thrown.


for index in range(len(self.__queue)):<EOL><INDENT>if cluster.distance < self.__queue[index].distance:<EOL><INDENT>self.__queue.insert(index, cluster)<EOL>return<EOL><DEDENT><DEDENT>self.__queue.append(cluster)<EOL>

!
        @brief Insert cluster to the list (sorted queue) in line with sequence order (distance).

        @param[in] cluster (cure_cluster): Cluster that should be inserted.


self.__queue.remove(cluster)<EOL>self.__insert_cluster(cluster)<EOL>

!
        @brief Relocate cluster in list in line with distance order.

        @param[in] cluster (cure_cluster): Cluster that should be relocated in line with order.


def __closest_cluster(self, cluster, distance):

nearest_cluster = None<EOL>nearest_distance = float('<STR_LIT>')<EOL>real_euclidean_distance = distance ** <NUM_LIT:0.5><EOL>for point in cluster.rep:<EOL><INDENT>nearest_nodes = self.__tree.find_nearest_dist_nodes(point, real_euclidean_distance)<EOL>for (candidate_distance, kdtree_node) in nearest_nodes:<EOL><INDENT>if (candidate_distance < nearest_distance) and (kdtree_node is not None) and (kdtree_node.payload is not cluster):<EOL><INDENT>nearest_distance = candidate_distance<EOL>nearest_cluster = kdtree_node.payload<EOL><DEDENT><DEDENT><DEDENT>return (nearest_cluster, nearest_distance)<EOL>

!
        @brief Find closest cluster to the specified cluster in line with distance.

        @param[in] cluster (cure_cluster): Cluster for which nearest cluster should be found.
        @param[in] distance (double): Closest distance to the previous cluster.

        @return (tuple) Pair (nearest CURE cluster, nearest distance) if the nearest cluster has been found, otherwise None is returned.


for point in cluster.rep:<EOL><INDENT>self.__tree.insert(point, cluster)<EOL><DEDENT>

!
        @brief Insert representation points to the k-d tree.

        @param[in] cluster (cure_cluster): Cluster whose representation points should be inserted.


for point in cluster.rep:<EOL><INDENT>self.__tree.remove(point, payload=cluster)<EOL><DEDENT>

!
        @brief Remove representation points of clusters from the k-d tree

        @param[in] cluster (cure_cluster): Cluster whose representation points should be removed.


def __merge_clusters(self, cluster1, cluster2):

merged_cluster = cure_cluster(None, None)<EOL>merged_cluster.points = cluster1.points + cluster2.points<EOL>merged_cluster.indexes = cluster1.indexes + cluster2.indexes<EOL>dimension = len(cluster1.mean)<EOL>merged_cluster.mean = [<NUM_LIT:0>] * dimension<EOL>if merged_cluster.points[<NUM_LIT:1>:] == merged_cluster.points[:-<NUM_LIT:1>]:<EOL><INDENT>merged_cluster.mean = merged_cluster.points[<NUM_LIT:0>]<EOL><DEDENT>else:<EOL><INDENT>for index in range(dimension):<EOL><INDENT>merged_cluster.mean[index] = ( len(cluster1.points) * cluster1.mean[index] + len(cluster2.points) * cluster2.mean[index] ) / ( len(cluster1.points) + len(cluster2.points) );<EOL><DEDENT><DEDENT>temporary = list()<EOL>for index in range(self.__number_represent_points):<EOL><INDENT>maximal_distance = <NUM_LIT:0><EOL>maximal_point = None<EOL>for point in merged_cluster.points:<EOL><INDENT>minimal_distance = <NUM_LIT:0><EOL>if index == <NUM_LIT:0>:<EOL><INDENT>minimal_distance = euclidean_distance_square(point, merged_cluster.mean)<EOL><DEDENT>else:<EOL><INDENT>minimal_distance = min([euclidean_distance_square(point, p) for p in temporary])<EOL><DEDENT>if minimal_distance >= maximal_distance:<EOL><INDENT>maximal_distance = minimal_distance<EOL>maximal_point = point<EOL><DEDENT><DEDENT>if maximal_point not in temporary:<EOL><INDENT>temporary.append(maximal_point)<EOL><DEDENT><DEDENT>for point in temporary:<EOL><INDENT>representative_point = [<NUM_LIT:0>] * dimension<EOL>for index in range(dimension):<EOL><INDENT>representative_point[index] = point[index] + self.__compression * (merged_cluster.mean[index] - point[index])<EOL><DEDENT>merged_cluster.rep.append(representative_point)<EOL><DEDENT>return merged_cluster<EOL>

!
        @brief Merges two clusters and returns new merged cluster. Representation points and mean points are calculated for the new cluster.

        @param[in] cluster1 (cure_cluster): Cluster that should be merged.
        @param[in] cluster2 (cure_cluster): Cluster that should be merged.

        @return (cure_cluster) New merged CURE cluster.


self.__queue = [cure_cluster(self.__pointer_data[index_point], index_point) for index_point in range(len(self.__pointer_data))]<EOL>for i in range(<NUM_LIT:0>, len(self.__queue)):<EOL><INDENT>minimal_distance = float('<STR_LIT>')<EOL>closest_index_cluster = -<NUM_LIT:1><EOL>for k in range(<NUM_LIT:0>, len(self.__queue)):<EOL><INDENT>if i != k:<EOL><INDENT>dist = self.__cluster_distance(self.__queue[i], self.__queue[k])<EOL>if dist < minimal_distance:<EOL><INDENT>minimal_distance = dist<EOL>closest_index_cluster = k<EOL><DEDENT><DEDENT><DEDENT>self.__queue[i].closest = self.__queue[closest_index_cluster]<EOL>self.__queue[i].distance = minimal_distance<EOL><DEDENT>self.__queue.sort(key = lambda x: x.distance, reverse = False)<EOL>

!
        @brief Create queue of sorted clusters by distance between them, where first cluster has the nearest neighbor. At the first iteration each cluster contains only one point.

        @param[in] data (list): Input data that is presented as list of points (objects), each point should be represented by list or tuple.

        @return (list) Create queue of sorted clusters by distance between them.


self.__tree = kdtree()<EOL>for current_cluster in self.__queue:<EOL><INDENT>for representative_point in current_cluster.rep:<EOL><INDENT>self.__tree.insert(representative_point, current_cluster)<EOL><DEDENT><DEDENT>

!
        @brief Create k-d tree in line with created clusters. At the first iteration contains all points from the input data set.

        @return (kdtree) k-d tree that consist of representative points of CURE clusters.


def __cluster_distance(self, cluster1, cluster2):

distance = float('<STR_LIT>')<EOL>for i in range(<NUM_LIT:0>, len(cluster1.rep)):<EOL><INDENT>for k in range(<NUM_LIT:0>, len(cluster2.rep)):<EOL><INDENT>dist = euclidean_distance_square(cluster1.rep[i], cluster2.rep[k]);   <EOL>if dist < distance:<EOL><INDENT>distance = dist<EOL><DEDENT><DEDENT><DEDENT>return distance<EOL>

!
        @brief Calculate minimal distance between clusters using representative points.

        @param[in] cluster1 (cure_cluster): The first cluster.
        @param[in] cluster2 (cure_cluster): The second cluster.

        @return (double) Euclidean distance between two clusters that is defined by minimum distance between representation points of two clusters.


@staticmethod<EOL><INDENT>def show_ordering_diagram(analyser, amount_clusters = None):<DEDENT>

ordering = analyser.cluster_ordering<EOL>axis = plt.subplot(<NUM_LIT>)<EOL>if amount_clusters is not None:<EOL><INDENT>radius, borders = analyser.calculate_connvectivity_radius(amount_clusters)<EOL>left_index_border = <NUM_LIT:0><EOL>current_index_border = <NUM_LIT:0><EOL>for index_border in range(len(borders)):<EOL><INDENT>right_index_border = borders[index_border]<EOL>axis.bar(range(left_index_border, right_index_border), ordering[left_index_border:right_index_border], width = <NUM_LIT:1.0>, color = color_list.TITLES[index_border])<EOL>left_index_border = right_index_border<EOL>current_index_border = index_border<EOL><DEDENT>axis.bar(range(left_index_border, len(ordering)), ordering[left_index_border:len(ordering)], width = <NUM_LIT:1.0>, color = color_list.TITLES[current_index_border + <NUM_LIT:1>])<EOL>plt.xlim([<NUM_LIT:0>, len(ordering)])<EOL>plt.axhline(y = radius, linewidth = <NUM_LIT:2>, color = '<STR_LIT>')<EOL>plt.text(<NUM_LIT:0>, radius + radius * <NUM_LIT>, "<STR_LIT>" + str(round(radius, <NUM_LIT:4>)) + "<STR_LIT>" + str(amount_clusters), color = '<STR_LIT:b>', fontsize = <NUM_LIT:10>)<EOL><DEDENT>else:<EOL><INDENT>axis.bar(range(<NUM_LIT:0>, len(ordering)), ordering[<NUM_LIT:0>:len(ordering)], width = <NUM_LIT:1.0>, color = '<STR_LIT>')<EOL>plt.xlim([<NUM_LIT:0>, len(ordering)])<EOL><DEDENT>plt.show()<EOL>

!
        @brief Display cluster-ordering (reachability-plot) diagram.

        @param[in] analyser (ordering_analyser): cluster-ordering analyser whose ordering diagram should be displayed.
        @param[in] amount_clusters (uint): if it is not 'None' then it displays connectivity radius line that can used for allocation of specified amount of clusters
                    and colorize diagram by corresponding cluster colors.

        Example demonstrates general abilities of 'ordering_visualizer' class:
        @code
            # Display cluster-ordering diagram with connectivity radius is used for allocation of three clusters.
            ordering_visualizer.show_ordering_diagram(analyser, 3);

            # Display cluster-ordering diagram without radius.
            ordering_visualizer.show_ordering_diagram(analyser);
        @endcode


return self.__ordering<EOL>

!
        @brief (list) Returns values of dataset cluster ordering.


self.__ordering = ordering_diagram<EOL>

!
        @brief Analyser of ordering diagram that is based on reachability-distances.

        @see calculate_connvectivity_radius


return len(self.__ordering)<EOL>

!
        @brief Returns length of clustering-ordering diagram.


def calculate_connvectivity_radius(self, amount_clusters, maximum_iterations = <NUM_LIT:100>):

maximum_distance = max(self.__ordering)<EOL>upper_distance = maximum_distance<EOL>lower_distance = <NUM_LIT:0.0><EOL>result = None<EOL>amount, borders = self.extract_cluster_amount(maximum_distance)<EOL>if amount <= amount_clusters:<EOL><INDENT>for _ in range(maximum_iterations):<EOL><INDENT>radius = (lower_distance + upper_distance) / <NUM_LIT><EOL>amount, borders = self.extract_cluster_amount(radius)<EOL>if amount == amount_clusters:<EOL><INDENT>result = radius<EOL>break<EOL><DEDENT>elif amount == <NUM_LIT:0>:<EOL><INDENT>break<EOL><DEDENT>elif amount > amount_clusters:<EOL><INDENT>lower_distance = radius<EOL><DEDENT>elif amount < amount_clusters:<EOL><INDENT>upper_distance = radius<EOL><DEDENT><DEDENT><DEDENT>return result, borders<EOL>

!
        @brief Calculates connectivity radius of allocation specified amount of clusters using ordering diagram and marks borders of clusters using indexes of values of ordering diagram.
        @details Parameter 'maximum_iterations' is used to protect from hanging when it is impossible to allocate specified number of clusters.

        @param[in] amount_clusters (uint): amount of clusters that should be allocated by calculated connectivity radius.
        @param[in] maximum_iterations (uint): maximum number of iteration for searching connectivity radius to allocated specified amount of clusters (by default it is restricted by 100 iterations).

        @return (double, list) Value of connectivity radius and borders of clusters like (radius, borders), radius may be 'None' as well as borders may be '[]'
                                if connectivity radius hasn't been found for the specified amount of iterations.


amount_clusters = <NUM_LIT:1><EOL>cluster_start = False<EOL>cluster_pick = False<EOL>total_similarity = True<EOL>previous_cluster_distance = None<EOL>previous_distance = None<EOL>cluster_borders = []<EOL>for index_ordering in range(len(self.__ordering)):<EOL><INDENT>distance = self.__ordering[index_ordering]<EOL>if distance >= radius:<EOL><INDENT>if cluster_start is False:<EOL><INDENT>cluster_start = True<EOL>amount_clusters += <NUM_LIT:1><EOL>if index_ordering != <NUM_LIT:0>:<EOL><INDENT>cluster_borders.append(index_ordering)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if (distance < previous_cluster_distance) and (cluster_pick is False):<EOL><INDENT>cluster_pick = True<EOL><DEDENT>elif (distance > previous_cluster_distance) and (cluster_pick is True):<EOL><INDENT>cluster_pick = False<EOL>amount_clusters += <NUM_LIT:1><EOL>if index_ordering != <NUM_LIT:0>:<EOL><INDENT>cluster_borders.append(index_ordering)<EOL><DEDENT><DEDENT><DEDENT>previous_cluster_distance = distance<EOL><DEDENT>else:<EOL><INDENT>cluster_start = False<EOL>cluster_pick = False<EOL><DEDENT>if (previous_distance is not None) and (distance != previous_distance):<EOL><INDENT>total_similarity = False<EOL><DEDENT>previous_distance = distance<EOL><DEDENT>if (total_similarity is True) and (previous_distance > radius):<EOL><INDENT>amount_clusters = <NUM_LIT:0><EOL><DEDENT>return amount_clusters, cluster_borders<EOL>

!
        @brief Obtains amount of clustering that can be allocated by using specified radius for ordering diagram and borders between them.
        @details When growth of reachability-distances is detected than it is considered as a start point of cluster,
                 than pick is detected and after that recession is observed until new growth (that means end of the
                 current cluster and start of a new one) or end of diagram.

        @param[in] radius (double): connectivity radius that is used for cluster allocation.

        @return (unit, list) Amount of clusters that can be allocated by the connectivity radius on ordering diagram and borders between them using indexes
                 from ordering diagram (amount_clusters, border_clusters).


def __init__(self, index, core_distance = None, reachability_distance = None):

<EOL>self.index_object = index<EOL>self.core_distance = core_distance<EOL>self.reachability_distance = reachability_distance<EOL>self.processed = False<EOL>

!
        @brief Constructor of object description in optics terms.

        @param[in] index (uint): Index of the object in the data set.
        @param[in] core_distance (double): Core distance that is minimum distance to specified number of neighbors.
        @param[in] reachability_distance (double): Reachability distance to this object.


return '<STR_LIT>' % (self.index_object, self.core_distance, self.reachability_distance)<EOL>

!
        @brief Returns string representation of the optics descriptor.


def __init__(self, sample, eps, minpts, amount_clusters = None, ccore = True, **kwargs):

self.__sample_pointer = sample      <EOL>self.__eps = eps                    <EOL>self.__minpts = minpts              <EOL>self.__amount_clusters = amount_clusters<EOL>self.__ordering = None<EOL>self.__clusters = None<EOL>self.__noise = None<EOL>self.__optics_objects = None<EOL>self.__data_type = kwargs.get('<STR_LIT>', '<STR_LIT>')<EOL>self.__kdtree = None<EOL>self.__ccore = ccore<EOL>self.__neighbor_searcher = self.__create_neighbor_searcher(self.__data_type)<EOL>if self.__ccore:<EOL><INDENT>self.__ccore = ccore_library.workable()<EOL><DEDENT>

!
        @brief Constructor of clustering algorithm OPTICS.

        @param[in] sample (list): Input data that is presented as a list of points (objects), where each point is represented by list or tuple.
        @param[in] eps (double): Connectivity radius between points, points may be connected if distance between them less than the radius.
        @param[in] minpts (uint): Minimum number of shared neighbors that is required for establishing links between points.
        @param[in] amount_clusters (uint): Optional parameter where amount of clusters that should be allocated is specified.
                    In case of usage 'amount_clusters' connectivity radius can be greater than real, in other words, there is place for mistake
                    in connectivity radius usage.
        @param[in] ccore (bool): if True than DLL CCORE (C++ solution) will be used for solving the problem.
        @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'data_type').

        Keyword Args:

            - data_type (string): Data type of input sample 'data' that is processed by the algorithm ('points', 'distance_matrix').


if self.__ccore is True:<EOL><INDENT>self.__process_by_ccore()<EOL><DEDENT>else:<EOL><INDENT>self.__process_by_python()<EOL><DEDENT>

!
        @brief Performs cluster analysis in line with rules of OPTICS algorithm.

        @remark Results of clustering can be obtained using corresponding gets methods.

        @see get_clusters()
        @see get_noise()
        @see get_ordering()


(self.__clusters, self.__noise, self.__ordering, self.__eps,<EOL>objects_indexes, objects_core_distances, objects_reachability_distances) =wrapper.optics(self.__sample_pointer, self.__eps, self.__minpts, self.__amount_clusters, self.__data_type)<EOL>self.__optics_objects = []<EOL>for i in range(len(objects_indexes)):<EOL><INDENT>if objects_core_distances[i] < <NUM_LIT:0.0>:<EOL><INDENT>objects_core_distances[i] = None<EOL><DEDENT>if objects_reachability_distances[i] < <NUM_LIT:0.0>:<EOL><INDENT>objects_reachability_distances[i] = None<EOL><DEDENT>optics_object = optics_descriptor(objects_indexes[i], objects_core_distances[i], objects_reachability_distances[i])<EOL>optics_object.processed = True<EOL>self.__optics_objects.append(optics_object)<EOL><DEDENT>

!
        @brief Performs cluster analysis using CCORE (C/C++ part of pyclustering library).


if self.__data_type == '<STR_LIT>':<EOL><INDENT>self.__kdtree = kdtree(self.__sample_pointer, range(len(self.__sample_pointer)))<EOL><DEDENT>self.__allocate_clusters()<EOL>if (self.__amount_clusters is not None) and (self.__amount_clusters != len(self.get_clusters())):<EOL><INDENT>analyser = ordering_analyser(self.get_ordering())<EOL>radius, _ = analyser.calculate_connvectivity_radius(self.__amount_clusters)<EOL>if radius is not None:<EOL><INDENT>self.__eps = radius<EOL>self.__allocate_clusters()<EOL><DEDENT><DEDENT>

!
        @brief Performs cluster analysis using python code.


self.__processed = [False] * len(sample)<EOL>self.__optics_objects = [optics_descriptor(i) for i in range(len(sample))]      <EOL>self.__ordered_database = []        <EOL>self.__clusters = None      <EOL>self.__noise = None         <EOL>

!
        @brief Initializes internal states and resets clustering results in line with input sample.


self.__initialize(self.__sample_pointer)<EOL>for optic_object in self.__optics_objects:<EOL><INDENT>if optic_object.processed is False:<EOL><INDENT>self.__expand_cluster_order(optic_object)<EOL><DEDENT><DEDENT>self.__extract_clusters()<EOL>

!
        @brief Performs cluster allocation and builds ordering diagram that is based on reachability-distances.


return self.__clusters<EOL>

!
        @brief Returns list of allocated clusters, where each cluster contains indexes of objects and each cluster is represented by list.

        @return (list) List of allocated clusters.

        @see process()
        @see get_noise()
        @see get_ordering()
        @see get_radius()


return self.__noise<EOL>

!
        @brief Returns list of noise that contains indexes of objects that corresponds to input data.

        @return (list) List of allocated noise objects.

        @see process()
        @see get_clusters()
        @see get_ordering()
        @see get_radius()


if self.__ordering is None:<EOL><INDENT>self.__ordering = []<EOL>for cluster in self.__clusters:<EOL><INDENT>for index_object in cluster:<EOL><INDENT>optics_object = self.__optics_objects[index_object]<EOL>if optics_object.reachability_distance is not None:<EOL><INDENT>self.__ordering.append(optics_object.reachability_distance)<EOL><DEDENT><DEDENT><DEDENT><DEDENT>return self.__ordering<EOL>

!
        @brief Returns clustering ordering information about the input data set.
        @details Clustering ordering of data-set contains the information about the internal clustering structure in line with connectivity radius.

        @return (ordering_analyser) Analyser of clustering ordering.

        @see process()
        @see get_clusters()
        @see get_noise()
        @see get_radius()
        @see get_optics_objects()


return self.__optics_objects<EOL>

!
        @brief Returns OPTICS objects where each object contains information about index of point from processed data,
                core distance and reachability distance.

        @return (list) OPTICS objects.

        @see get_ordering()
        @see get_clusters()
        @see get_noise()
        @see optics_descriptor


return self.__eps<EOL>

!
        @brief Returns connectivity radius that is calculated and used for clustering by the algorithm.
        @details Connectivity radius may be changed only in case of usage additional parameter of the algorithm - amount of clusters for allocation.

        @return (double) Connectivity radius.

        @see get_ordering()
        @see get_clusters()
        @see get_noise()
        @see get_optics_objects()


return type_encoding.CLUSTER_INDEX_LIST_SEPARATION<EOL>

!
        @brief Returns clustering result representation type that indicate how clusters are encoded.

        @return (type_encoding) Clustering result representation.

        @see get_clusters()


if data_type == '<STR_LIT>':<EOL><INDENT>return self.__neighbor_indexes_points<EOL><DEDENT>elif data_type == '<STR_LIT>':<EOL><INDENT>return self.__neighbor_indexes_distance_matrix<EOL><DEDENT>else:<EOL><INDENT>raise TypeError("<STR_LIT>" % data_type)<EOL><DEDENT>

!
        @brief Returns neighbor searcher in line with data type.

        @param[in] data_type (string): Data type (points or distance matrix).


optics_object.processed = True<EOL>neighbors_descriptor = self.__neighbor_searcher(optics_object)<EOL>optics_object.reachability_distance = None<EOL>self.__ordered_database.append(optics_object)<EOL>if len(neighbors_descriptor) >= self.__minpts:<EOL><INDENT>neighbors_descriptor.sort(key = lambda obj: obj[<NUM_LIT:1>])<EOL>optics_object.core_distance = neighbors_descriptor[self.__minpts - <NUM_LIT:1>][<NUM_LIT:1>]<EOL>order_seed = list()<EOL>self.__update_order_seed(optics_object, neighbors_descriptor, order_seed)<EOL>while len(order_seed) > <NUM_LIT:0>:<EOL><INDENT>optic_descriptor = order_seed[<NUM_LIT:0>]<EOL>order_seed.remove(optic_descriptor)<EOL>neighbors_descriptor = self.__neighbor_searcher(optic_descriptor)<EOL>optic_descriptor.processed = True<EOL>self.__ordered_database.append(optic_descriptor)<EOL>if len(neighbors_descriptor) >= self.__minpts:<EOL><INDENT>neighbors_descriptor.sort(key = lambda obj: obj[<NUM_LIT:1>])<EOL>optic_descriptor.core_distance = neighbors_descriptor[self.__minpts - <NUM_LIT:1>][<NUM_LIT:1>]<EOL>self.__update_order_seed(optic_descriptor, neighbors_descriptor, order_seed)<EOL><DEDENT>else:<EOL><INDENT>optic_descriptor.core_distance = None<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>optics_object.core_distance = None<EOL><DEDENT>

!
        @brief Expand cluster order from not processed optic-object that corresponds to object from input data.
               Traverse procedure is performed until objects are reachable from core-objects in line with connectivity radius.
               Order database is updated during expanding.

        @param[in] optics_object (optics_descriptor): Object that hasn't been processed.


self.__clusters = []<EOL>self.__noise = []<EOL>current_cluster = self.__noise<EOL>for optics_object in self.__ordered_database:<EOL><INDENT>if (optics_object.reachability_distance is None) or (optics_object.reachability_distance > self.__eps):<EOL><INDENT>if (optics_object.core_distance is not None) and (optics_object.core_distance <= self.__eps):<EOL><INDENT>self.__clusters.append([ optics_object.index_object ])<EOL>current_cluster = self.__clusters[-<NUM_LIT:1>]<EOL><DEDENT>else:<EOL><INDENT>self.__noise.append(optics_object.index_object)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>current_cluster.append(optics_object.index_object)<EOL><DEDENT><DEDENT>

!
        @brief Extract clusters and noise from order database.


def __update_order_seed(self, optic_descriptor, neighbors_descriptors, order_seed):

for neighbor_descriptor in neighbors_descriptors:<EOL><INDENT>index_neighbor = neighbor_descriptor[<NUM_LIT:0>]<EOL>current_reachable_distance = neighbor_descriptor[<NUM_LIT:1>]<EOL>if self.__optics_objects[index_neighbor].processed is not True:<EOL><INDENT>reachable_distance = max(current_reachable_distance, optic_descriptor.core_distance)<EOL>if self.__optics_objects[index_neighbor].reachability_distance is None:<EOL><INDENT>self.__optics_objects[index_neighbor].reachability_distance = reachable_distance<EOL>index_insertion = len(order_seed)<EOL>for index_seed in range(<NUM_LIT:0>, len(order_seed)):<EOL><INDENT>if reachable_distance < order_seed[index_seed].reachability_distance:<EOL><INDENT>index_insertion = index_seed<EOL>break<EOL><DEDENT><DEDENT>order_seed.insert(index_insertion, self.__optics_objects[index_neighbor])<EOL><DEDENT>else:<EOL><INDENT>if reachable_distance < self.__optics_objects[index_neighbor].reachability_distance:<EOL><INDENT>self.__optics_objects[index_neighbor].reachability_distance = reachable_distance<EOL>order_seed.sort(key = lambda obj: obj.reachability_distance)<EOL><DEDENT><DEDENT><DEDENT><DEDENT>

!
        @brief Update sorted list of reachable objects (from core-object) that should be processed using neighbors of core-object.

        @param[in] optic_descriptor (optics_descriptor): Core-object whose neighbors should be analysed.
        @param[in] neighbors_descriptors (list): List of neighbors of core-object.
        @param[in|out] order_seed (list): List of sorted object in line with reachable distance.


kdnodes = self.__kdtree.find_nearest_dist_nodes(self.__sample_pointer[optic_object.index_object], self.__eps)<EOL>return [[node_tuple[<NUM_LIT:1>].payload, math.sqrt(node_tuple[<NUM_LIT:0>])] for node_tuple in kdnodes if<EOL>node_tuple[<NUM_LIT:1>].payload != optic_object.index_object]<EOL>

!
        @brief Return neighbors of the specified object in case of sequence of points.

        @param[in] optic_object (optics_descriptor): Object for which neighbors should be returned in line with connectivity radius.

        @return (list) List of indexes of neighbors in line the connectivity radius.


distances = self.__sample_pointer[optic_object.index_object]<EOL>return [[index_neighbor, distances[index_neighbor]] for index_neighbor in range(len(distances))<EOL>if ((distances[index_neighbor] <= self.__eps) and (index_neighbor != optic_object.index_object))]<EOL>

!
        @brief Return neighbors of the specified object in case of distance matrix.

        @param[in] optic_object (optics_descriptor): Object for which neighbors should be returned in line with connectivity radius.

        @return (list) List of indexes of neighbors in line the connectivity radius.


def __init__(self, encoding, clusters, data):

self.__type_representation = encoding;<EOL>self.__clusters = clusters;<EOL>self.__data = data<EOL>

!
        @brief Constructor of clustering result representor.

        @param[in] encoding (type_encoding): Type of clusters representation (index list, object list or labels).
        @param[in] clusters (list): Current clusters representation.
        @param[in] data (list): Data that corresponds to clusters.


return self.__type_representation<EOL>

!
        @brief Returns current cluster representation.


return self.__clusters<EOL>

!
        @brief Returns clusters representation.


return self.__data<EOL>

!
        @brief Returns data that corresponds to clusters.


if(encoding == self.__type_representation):<EOL><INDENT>return;<EOL><DEDENT>if (self.__type_representation == type_encoding.CLUSTER_INDEX_LABELING):<EOL><INDENT>if (encoding == type_encoding.CLUSTER_INDEX_LIST_SEPARATION):<EOL><INDENT>self.__clusters = self.__convert_label_to_index();<EOL><DEDENT>else:<EOL><INDENT>self.__clusters = self.__convert_label_to_object();<EOL><DEDENT><DEDENT>elif (self.__type_representation == type_encoding.CLUSTER_INDEX_LIST_SEPARATION):<EOL><INDENT>if (encoding == type_encoding.CLUSTER_INDEX_LABELING):<EOL><INDENT>self.__clusters = self.__convert_index_to_label();<EOL><DEDENT>else:<EOL><INDENT>self.__clusters = self.__convert_index_to_object();<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if (encoding == type_encoding.CLUSTER_INDEX_LABELING):<EOL><INDENT>self.__clusters = self.__convert_object_to_label();<EOL><DEDENT>else:<EOL><INDENT>self.__clusters = self.__convert_object_to_index();<EOL><DEDENT><DEDENT>self.__type_representation = encoding<EOL>

!
        @brief Change clusters encoding to specified type (index list, object list, labeling).

        @param[in] encoding (type_encoding): New type of clusters representation.


if count_clusters is None:<EOL><INDENT>count_clusters = ga_math.calc_count_centers(chromosome)<EOL><DEDENT>clusters = [[] for _ in range(count_clusters)]<EOL>for _idx_data in range(len(chromosome)):<EOL><INDENT>clusters[chromosome[_idx_data]].append(_idx_data)<EOL><DEDENT>return clusters<EOL>

Convert chromosome to cluster representation:
                chromosome : [0, 1, 1, 0, 2, 3, 3]
                clusters: [[0, 3], [1, 2], [4], [5, 6]]


@staticmethod<EOL><INDENT>def get_centres(chromosomes, data, count_clusters):<DEDENT>

centres = ga_math.calc_centers(chromosomes, data, count_clusters)<EOL>return centres<EOL>


@staticmethod<EOL><INDENT>def calc_centers(chromosomes, data, count_clusters=None):<DEDENT>

if count_clusters is None:<EOL><INDENT>count_clusters = ga_math.calc_count_centers(chromosomes[<NUM_LIT:0>])<EOL><DEDENT>centers = np.zeros(shape=(len(chromosomes), count_clusters, len(data[<NUM_LIT:0>])))<EOL>for _idx_chromosome in range(len(chromosomes)):<EOL><INDENT>count_data_in_cluster = np.zeros(count_clusters)<EOL>for _idx in range(len(chromosomes[_idx_chromosome])):<EOL><INDENT>cluster_num = chromosomes[_idx_chromosome][_idx]<EOL>centers[_idx_chromosome][cluster_num] += data[_idx]<EOL>count_data_in_cluster[cluster_num] += <NUM_LIT:1><EOL><DEDENT>for _idx_cluster in range(count_clusters):<EOL><INDENT>if count_data_in_cluster[_idx_cluster] != <NUM_LIT:0>:<EOL><INDENT>centers[_idx_chromosome][_idx_cluster] /= count_data_in_cluster[_idx_cluster]<EOL><DEDENT><DEDENT><DEDENT>return centers<EOL>


if len(fitness) == <NUM_LIT:0>:<EOL><INDENT>raise AttributeError("<STR_LIT>")<EOL><DEDENT>inv_fitness = np.zeros(len(fitness))<EOL>for _idx in range(len(inv_fitness)):<EOL><INDENT>if fitness[_idx] != <NUM_LIT:0.0>:<EOL><INDENT>inv_fitness[_idx] = <NUM_LIT:1.0> / fitness[_idx]<EOL><DEDENT>else:<EOL><INDENT>inv_fitness[_idx] = <NUM_LIT:0.0><EOL><DEDENT><DEDENT>prob = np.zeros(len(fitness))<EOL>prob[<NUM_LIT:0>] = inv_fitness[<NUM_LIT:0>]<EOL>for _idx in range(<NUM_LIT:1>, len(inv_fitness)):<EOL><INDENT>prob[_idx] = prob[_idx - <NUM_LIT:1>] + inv_fitness[_idx]<EOL><DEDENT>prob /= prob[-<NUM_LIT:1>]<EOL>ga_math.set_last_value_to_one(prob)<EOL>return prob<EOL>


<EOL>back_idx = - <NUM_LIT:1><EOL>last_val = probabilities[back_idx]<EOL>for _ in range(-<NUM_LIT:1>, -len(probabilities) - <NUM_LIT:1>):<EOL><INDENT>if probabilities[back_idx] == last_val:<EOL><INDENT>probabilities[back_idx] = <NUM_LIT:1><EOL><DEDENT>else:<EOL><INDENT>break<EOL><DEDENT><DEDENT>

!
        @brief Update the last same probabilities to one.
        @details All values of probability list equals to the last element are set to 1.


<EOL>res_idx = None<EOL>random_num = np.random.rand()<EOL>for _idx in range(len(probabilities)):<EOL><INDENT>if random_num < probabilities[_idx]:<EOL><INDENT>res_idx = _idx<EOL>break<EOL><DEDENT><DEDENT>if res_idx is None:<EOL><INDENT>print('<STR_LIT>', probabilities)<EOL>raise AttributeError("<STR_LIT>")<EOL><DEDENT>return res_idx<EOL>

!
        @brief Returns index in probabilities.

        @param[in] probabilities (list): List with segments in increasing sequence with val in [0, 1],
                   for example, [0 0.1 0.2 0.3 1.0].


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.


if (self._ccore_sync_dynamic_pointer is not None):<EOL><INDENT>syncnet_analyser_destroy(self._ccore_sync_dynamic_pointer);<EOL>self._ccore_sync_dynamic_pointer = None;<EOL><DEDENT>

!
        @brief Desctructor of the analyser.


def allocate_clusters(self, eps = <NUM_LIT>, indexes = None, iteration = None):

return self.allocate_sync_ensembles(eps, indexes, iteration)<EOL>

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

        @param[in] eps (double): Tolerance level that define maximal difference between phases of oscillators in one cluster.
        @param[in] indexes (list): List of real object indexes and it should be equal to amount of oscillators (in case of 'None' - indexes are in range [0; amount_oscillators]).
        @param[in] iteration (uint): Iteration of simulation that should be used for allocation.

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


return type_encoding.CLUSTER_INDEX_LIST_SEPARATION<EOL>

!
        @brief Returns clustering result representation type that indicate how clusters are encoded.

        @return (type_encoding) Clustering result representation.

        @see get_clusters()


@staticmethod<EOL><INDENT>def animate_cluster_allocation(dataset, analyser, animation_velocity = <NUM_LIT>, tolerance = <NUM_LIT:0.1>, save_movie = None, title = None):<DEDENT>

figure = plt.figure();<EOL>def init_frame():<EOL><INDENT>return frame_generation(<NUM_LIT:0>);<EOL><DEDENT>def frame_generation(index_dynamic):<EOL><INDENT>figure.clf();<EOL>if (title is not None):<EOL><INDENT>figure.suptitle(title, fontsize = <NUM_LIT>, fontweight = '<STR_LIT>');<EOL><DEDENT>ax1 = figure.add_subplot(<NUM_LIT>, projection='<STR_LIT>');<EOL>clusters = analyser.allocate_clusters(eps = tolerance, iteration = index_dynamic);<EOL>dynamic = analyser.output[index_dynamic];<EOL>visualizer = cluster_visualizer(size_row = <NUM_LIT:2>);<EOL>visualizer.append_clusters(clusters, dataset);<EOL>artist1, = ax1.plot(dynamic, [<NUM_LIT:1.0>] * len(dynamic), marker = '<STR_LIT:o>', color = '<STR_LIT>', ls = '<STR_LIT>');<EOL>visualizer.show(figure, display = False);<EOL>artist2 = figure.gca();<EOL>return [ artist1, artist2 ];<EOL><DEDENT>cluster_animation = animation.FuncAnimation(figure, frame_generation, len(analyser), interval = animation_velocity, init_func = init_frame, repeat_delay = <NUM_LIT>);<EOL>if (save_movie is not None):<EOL><INDENT>plt.rcParams['<STR_LIT>'] = '<STR_LIT>';<EOL>ffmpeg_writer = animation.FFMpegWriter(fps = <NUM_LIT:15>);<EOL>cluster_animation.save(save_movie, writer = ffmpeg_writer);<EOL>

!
        @brief Shows animation of output dynamic (output of each oscillator) during simulation on a circle from [0; 2pi].

        @param[in] dataset (list): Input data that was used for processing by the network.
        @param[in] analyser (syncnet_analyser): Output dynamic analyser of the Sync network.
        @param[in] animation_velocity (uint): Interval between frames in milliseconds.
        @param[in] tolerance (double): Tolerance level that define maximal difference between phases of oscillators in one cluster.
        @param[in] save_movie (string): If it is specified then animation will be stored to file that is specified in this parameter.
        @param[in] title (string): If it is specified then title will be displayed on the animation plot.


def __init__(self, sample, radius, conn_repr = conn_represent.MATRIX, initial_phases = initial_type.RANDOM_GAUSSIAN, enable_conn_weight = False, ccore = True):

self._ccore_network_pointer = None;<EOL>self._osc_loc = sample;<EOL>self._num_osc = len(sample);<EOL>if ( (ccore is True) and ccore_library.workable() ):<EOL><INDENT>self._ccore_network_pointer = syncnet_create_network(sample, radius, initial_phases, enable_conn_weight);<EOL>self._conn_represent = conn_represent.MATRIX;<EOL><DEDENT>else:<EOL><INDENT>super().__init__(len(sample), <NUM_LIT:1>, <NUM_LIT:0>, conn_type.DYNAMIC, conn_repr, initial_phases, False);<EOL>self._conn_weight = None;<EOL>self._ena_conn_weight = enable_conn_weight;<EOL>if (radius is not None):<EOL><INDENT>self._create_connections(radius);<EOL><DEDENT><DEDENT>

!
        @brief Contructor of the oscillatory network SYNC for cluster analysis.

        @param[in] sample (list): Input data that is presented as list of points (objects), each point should be represented by list or tuple.
        @param[in] radius (double): Connectivity radius between points, points should be connected if distance between them less then the radius.
        @param[in] conn_repr (conn_represent): Internal representation of connection in the network: matrix or list. Ignored in case of usage of CCORE library.
        @param[in] initial_phases (initial_type): Type of initialization of initial phases of oscillators (random, uniformly distributed, etc.).
        @param[in] enable_conn_weight (bool): If True - enable mode when strength between oscillators depends on distance between two oscillators.
              If False - all connection between oscillators have the same strength that equals to 1 (True).
        @param[in] ccore (bool): Defines should be CCORE C++ library used instead of Python code or not.


if (self._ccore_network_pointer is not None):<EOL><INDENT>syncnet_destroy_network(self._ccore_network_pointer);<EOL>self._ccore_network_pointer = None;<EOL><DEDENT>

!
        @brief Destructor of oscillatory network is based on Kuramoto model.


if (self._ena_conn_weight is True):<EOL><INDENT>self._conn_weight = [[<NUM_LIT:0>] * self._num_osc for _ in range(<NUM_LIT:0>, self._num_osc, <NUM_LIT:1>)];<EOL><DEDENT>maximum_distance = <NUM_LIT:0>;<EOL>minimum_distance = float('<STR_LIT>');<EOL>for i in range(<NUM_LIT:0>, self._num_osc, <NUM_LIT:1>):<EOL><INDENT>for j in range(i + <NUM_LIT:1>, self._num_osc, <NUM_LIT:1>):<EOL><INDENT>dist = euclidean_distance(self._osc_loc[i], self._osc_loc[j]);<EOL>if (self._ena_conn_weight is True):<EOL><INDENT>self._conn_weight[i][j] = dist;<EOL>self._conn_weight[j][i] = dist;<EOL>if (dist > maximum_distance): maximum_distance = dist;<EOL>if (dist < minimum_distance): minimum_distance = dist;<EOL><DEDENT>if (dist <= radius):<EOL><INDENT>self.set_connection(i, j);<EOL><DEDENT><DEDENT><DEDENT>if (self._ena_conn_weight is True):<EOL><INDENT>multiplier = <NUM_LIT:1>; <EOL>subtractor = <NUM_LIT:0>;<EOL>if (maximum_distance != minimum_distance):<EOL><INDENT>multiplier = (maximum_distance - minimum_distance);<EOL>subtractor = minimum_distance;<EOL><DEDENT>for i in range(<NUM_LIT:0>, self._num_osc, <NUM_LIT:1>):<EOL><INDENT>for j in range(i + <NUM_LIT:1>, self._num_osc, <NUM_LIT:1>):<EOL><INDENT>value_conn_weight = (self._conn_weight[i][j] - subtractor) / multiplier;<EOL>self._conn_weight[i][j] = value_conn_weight;<EOL>self._conn_weight[j][i] = value_conn_weight;<EOL><DEDENT><DEDENT><DEDENT>

!
        @brief Create connections between oscillators in line with input radius of connectivity.

        @param[in] radius (double): Connectivity radius between oscillators.


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

if (self._ccore_network_pointer is not None):<EOL><INDENT>pointer_output_dynamic = syncnet_process(self._ccore_network_pointer, order, solution, collect_dynamic);<EOL>return syncnet_analyser(None, None, pointer_output_dynamic);<EOL><DEDENT>else:<EOL><INDENT>output_sync_dynamic = self.simulate_dynamic(order, solution, collect_dynamic);<EOL>return syncnet_analyser(output_sync_dynamic.output, output_sync_dynamic.time, None);<EOL><DEDENT>

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

        @param[in] order (double): Order of synchronization that is used as indication for stopping processing.
        @param[in] solution (solve_type): Specified type of solving diff. equation.
        @param[in] collect_dynamic (bool): Specified requirement to collect whole dynamic of the network.

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


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

index = argv;   <EOL>phase = <NUM_LIT:0.0>;      <EOL>neighbors = self.get_neighbors(index);<EOL>for k in neighbors:<EOL><INDENT>conn_weight = <NUM_LIT:1.0>;<EOL>if (self._ena_conn_weight is True):<EOL><INDENT>conn_weight = self._conn_weight[index][k];<EOL><DEDENT>phase += conn_weight * self._weight * math.sin(self._phases[k] - teta);<EOL><DEDENT>divider = len(neighbors);<EOL>if (divider == <NUM_LIT:0>):<EOL><INDENT>divider = <NUM_LIT:1.0>;<EOL><DEDENT>return ( self._freq[index] + (phase / divider) )<EOL>

!
        @brief Overrided method for calculation of oscillator phase.

        @param[in] teta (double): Current value of phase.
        @param[in] t (double): Time (can be ignored).
        @param[in] argv (uint): Index of oscillator whose phase represented by argument teta.

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


if ( (self._ccore_network_pointer is not None) and (self._osc_conn is None) ):<EOL><INDENT>self._osc_conn = sync_connectivity_matrix(self._ccore_network_pointer);<EOL><DEDENT>dimension = len(self._osc_loc[<NUM_LIT:0>]);<EOL>if ( (dimension != <NUM_LIT:3>) and (dimension != <NUM_LIT:2>) ):<EOL><INDENT>raise NameError('<STR_LIT>');<EOL><DEDENT>from matplotlib.font_manager import FontProperties;<EOL>from matplotlib import rcParams;<EOL>rcParams['<STR_LIT>'] = ['<STR_LIT>'];<EOL>rcParams['<STR_LIT>'] = <NUM_LIT:12>;<EOL>fig = plt.figure();<EOL>axes = None;<EOL>if (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>surface_font = FontProperties();<EOL>surface_font.set_name('<STR_LIT>');<EOL>surface_font.set_size('<STR_LIT>');<EOL>for i in range(<NUM_LIT:0>, self._num_osc, <NUM_LIT:1>):<EOL><INDENT>if (dimension == <NUM_LIT:2>):<EOL><INDENT>axes.plot(self._osc_loc[i][<NUM_LIT:0>], self._osc_loc[i][<NUM_LIT:1>], '<STR_LIT>');  <EOL>if (self._conn_represent == conn_represent.MATRIX):<EOL><INDENT>for j in range(i, self._num_osc, <NUM_LIT:1>):    <EOL><INDENT>if (self.has_connection(i, j) == True):<EOL><INDENT>axes.plot([self._osc_loc[i][<NUM_LIT:0>], self._osc_loc[j][<NUM_LIT:0>]], [self._osc_loc[i][<NUM_LIT:1>], self._osc_loc[j][<NUM_LIT:1>]], '<STR_LIT>', linewidth = <NUM_LIT:0.5>);<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>for j in self.get_neighbors(i):<EOL><INDENT>if ( (self.has_connection(i, j) == True) and (i > j) ):     <EOL><INDENT>axes.plot([self._osc_loc[i][<NUM_LIT:0>], self._osc_loc[j][<NUM_LIT:0>]], [self._osc_loc[i][<NUM_LIT:1>], self._osc_loc[j][<NUM_LIT:1>]], '<STR_LIT>', linewidth = <NUM_LIT:0.5>);<EOL><DEDENT><DEDENT><DEDENT><DEDENT>elif (dimension == <NUM_LIT:3>):<EOL><INDENT>axes.scatter(self._osc_loc[i][<NUM_LIT:0>], self._osc_loc[i][<NUM_LIT:1>], self._osc_loc[i][<NUM_LIT:2>], c = '<STR_LIT:b>', marker = '<STR_LIT:o>');<EOL>if (self._conn_represent == conn_represent.MATRIX):<EOL><INDENT>for j in range(i, self._num_osc, <NUM_LIT:1>):    <EOL><INDENT>if (self.has_connection(i, j) == True):<EOL><INDENT>axes.plot([self._osc_loc[i][<NUM_LIT:0>], self._osc_loc[j][<NUM_LIT:0>]], [self._osc_loc[i][<NUM_LIT:1>], self._osc_loc[j][<NUM_LIT:1>]], [self._osc_loc[i][<NUM_LIT:2>], self._osc_loc[j][<NUM_LIT:2>]], '<STR_LIT>', linewidth = <NUM_LIT:0.5>);<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>for j in self.get_neighbors(i):<EOL><INDENT>if ( (self.has_connection(i, j) == True) and (i > j) ):     <EOL><INDENT>axes.plot([self._osc_loc[i][<NUM_LIT:0>], self._osc_loc[j][<NUM_LIT:0>]], [self._osc_loc[i][<NUM_LIT:1>], self._osc_loc[j][<NUM_LIT:1>]], [self._osc_loc[i][<NUM_LIT:2>], self._osc_loc[j][<NUM_LIT:2>]], '<STR_LIT>', linewidth = <NUM_LIT:0.5>);<EOL><DEDENT><DEDENT><DEDENT><DEDENT><DEDENT>plt.grid();<EOL>plt.show()<EOL>

!
        @brief Shows connections in the network. It supports only 2-d and 3-d representation.


def __init__(self, data, eps, number_clusters, threshold = <NUM_LIT:0.5>, ccore = True):

self.__pointer_data = data;<EOL>self.__eps = eps;<EOL>self.__number_clusters = number_clusters;<EOL>self.__threshold = threshold;<EOL>self.__clusters = None;<EOL>self.__ccore = ccore;<EOL>if (self.__ccore):<EOL><INDENT>self.__ccore = ccore_library.workable();<EOL><DEDENT>self.__degree_normalization = <NUM_LIT:1.0> + <NUM_LIT> * ( (<NUM_LIT:1.0> - threshold) / (<NUM_LIT:1.0> + threshold) );<EOL>self.__adjacency_matrix = None;<EOL>self.__create_adjacency_matrix()<EOL>

!
        @brief Constructor of clustering algorithm ROCK.

        @param[in] data (list): Input data - list of points where each point is represented by list of coordinates.
        @param[in] eps (double): Connectivity radius (similarity threshold), points are neighbors if distance between them is less than connectivity radius.
        @param[in] number_clusters (uint): Defines number of clusters that should be allocated from the input data set.
        @param[in] threshold (double): Value that defines degree of normalization that influences on choice of clusters for merging during processing.
        @param[in] ccore (bool): Defines should be CCORE (C++ pyclustering library) used instead of Python code or not.


<EOL>if (self.__ccore is True):<EOL><INDENT>self.__clusters = wrapper.rock(self.__pointer_data, self.__eps, self.__number_clusters, self.__threshold);<EOL><DEDENT>else:  <EOL><INDENT>self.__clusters = [[index] for index in range(len(self.__pointer_data))];<EOL>while (len(self.__clusters) > self.__number_clusters):<EOL><INDENT>indexes = self.__find_pair_clusters(self.__clusters);<EOL>if (indexes != [-<NUM_LIT:1>, -<NUM_LIT:1>]):<EOL><INDENT>self.__clusters[indexes[<NUM_LIT:0>]] += self.__clusters[indexes[<NUM_LIT:1>]];<EOL>self.__clusters.pop(indexes[<NUM_LIT:1>]);   <EOL><DEDENT>else:<EOL><INDENT>break;<EOL><DEDENT><DEDENT><DEDENT>

!
        @brief Performs cluster analysis in line with rules of ROCK algorithm.

        @remark Results of clustering can be obtained using corresponding get methods.

        @see get_clusters()


return self.__clusters<EOL>

!
        @brief Returns list of allocated clusters, each cluster contains indexes of objects in list of data.

        @return (list) List of allocated clusters, each cluster contains indexes of objects in list of data.

        @see process()


maximum_goodness = <NUM_LIT:0.0>;<EOL>cluster_indexes = [-<NUM_LIT:1>, -<NUM_LIT:1>];<EOL>for i in range(<NUM_LIT:0>, len(clusters)):<EOL><INDENT>for j in range(i + <NUM_LIT:1>, len(clusters)):<EOL><INDENT>goodness = self.__calculate_goodness(clusters[i], clusters[j]);<EOL>if (goodness > maximum_goodness):<EOL><INDENT>maximum_goodness = goodness;<EOL>cluster_indexes = [i, j];<EOL><DEDENT><DEDENT><DEDENT>return cluster_indexes<EOL>

!
        @brief Returns pair of clusters that are best candidates for merging in line with goodness measure.
               The pair of clusters for which the above goodness measure is maximum is the best pair of clusters to be merged.

        @param[in] clusters (list): List of clusters that have been allocated during processing, each cluster is represented by list of indexes of points from the input data set.

        @return (list) List that contains two indexes of clusters (from list 'clusters') that should be merged on this step.
                It can be equals to [-1, -1] when no links between clusters.


def __calculate_links(self, cluster1, cluster2):

number_links = <NUM_LIT:0>;<EOL>for index1 in cluster1:<EOL><INDENT>for index2 in cluster2:<EOL><INDENT>number_links += self.__adjacency_matrix[index1][index2];<EOL><DEDENT><DEDENT>return number_links<EOL>

!
        @brief Returns number of link between two clusters.
        @details Link between objects (points) exists only if distance between them less than connectivity radius.

        @param[in] cluster1 (list): The first cluster.
        @param[in] cluster2 (list): The second cluster.

        @return (uint) Number of links between two clusters.


size_data = len(self.__pointer_data);<EOL>self.__adjacency_matrix = [ [ <NUM_LIT:0> for i in range(size_data) ] for j in range(size_data) ];<EOL>for i in range(<NUM_LIT:0>, size_data):<EOL><INDENT>for j in range(i + <NUM_LIT:1>, size_data):<EOL><INDENT>distance = euclidean_distance(self.__pointer_data[i], self.__pointer_data[j]);<EOL>if (distance <= self.__eps):<EOL><INDENT>self.__adjacency_matrix[i][j] = <NUM_LIT:1>;<EOL>self.__adjacency_matrix[j][i] = <NUM_LIT:1>;<EOL><DEDENT><DEDENT><DEDENT>

!
        @brief Creates 2D adjacency matrix (list of lists) where each element described existence of link between points (means that points are neighbors).


def __calculate_goodness(self, cluster1, cluster2):

number_links = self.__calculate_links(cluster1, cluster2);<EOL>devider = (len(cluster1) + len(cluster2)) ** self.__degree_normalization - len(cluster1) ** self.__degree_normalization - len(cluster2) ** self.__degree_normalization;<EOL>return (number_links / devider)<EOL>

!
        @brief Calculates coefficient 'goodness measurement' between two clusters. The coefficient defines level of suitability of clusters for merging.

        @param[in] cluster1 (list): The first cluster.
        @param[in] cluster2 (list): The second cluster.

        @return Goodness measure between two clusters.


def __init__(self, data, kmin, kmax, **kwargs):

if kmax - kmin < <NUM_LIT:3>:<EOL><INDENT>raise ValueError("<STR_LIT>" + str(kmax - kmin) + "<STR_LIT>"<EOL>"<STR_LIT>")<EOL><DEDENT>if len(data) < kmax:<EOL><INDENT>raise ValueError("<STR_LIT>" % (kmax, len(data)))<EOL><DEDENT>self.__initializer = kwargs.get('<STR_LIT>', kmeans_plusplus_initializer)<EOL>self.__ccore = kwargs.get('<STR_LIT>', True) orisinstance(self.__initializer, kmeans_plusplus_initializer) orisinstance(self.__initializer, random_center_initializer)<EOL>if self.__ccore:<EOL><INDENT>self.__ccore = ccore_library.workable()<EOL><DEDENT>self.__data = data<EOL>self.__kmin = kmin<EOL>self.__kmax = kmax<EOL>self.__wce = []<EOL>self.__elbows = []<EOL>self.__kvalue = -<NUM_LIT:1><EOL>

!
        @brief Construct Elbow method.

        @param[in] data (array_like): Input data that is presented as array of points (objects), each point should be represented by array_like data structure.
        @param[in] kmin (int): Minimum amount of clusters that should be considered.
        @param[in] kmax (int): Maximum amount of clusters that should be considered.
        @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'ccore', 'initializer').

        Keyword Args:

            - ccore (bool): If True then CCORE (C++ implementation of pyclustering library) is used (by default True).
            - initializer (callable): Center initializer that is used by K-Means algorithm (by default K-Means++).


if self.__ccore:<EOL><INDENT>self.__process_by_ccore()<EOL><DEDENT>else:<EOL><INDENT>self.__process_by_python()<EOL><DEDENT>return self<EOL>

!
        @brief Performs analysis to find out appropriate amount of clusters.

        @return


if isinstance(self.__initializer, kmeans_plusplus_initializer):<EOL><INDENT>initializer = wrapper.elbow_center_initializer.KMEANS_PLUS_PLUS<EOL><DEDENT>else:<EOL><INDENT>initializer = wrapper.elbow_center_initializer.RANDOM<EOL><DEDENT>result = wrapper.elbow(self.__data, self.__kmin, self.__kmax, initializer)<EOL>self.__kvalue = result[<NUM_LIT:0>]<EOL>self.__wce = result[<NUM_LIT:1>]<EOL>

!
        @brief Performs processing using C++ implementation.


for amount in range(self.__kmin, self.__kmax):<EOL><INDENT>centers = self.__initializer(self.__data, amount).initialize()<EOL>instance = kmeans(self.__data, centers, ccore=True)<EOL>instance.process()<EOL>self.__wce.append(instance.get_total_wce())<EOL><DEDENT>self.__calculate_elbows()<EOL>self.__find_optimal_kvalue()<EOL>

!
        @brief Performs processing using python implementation.


return self.__kvalue<EOL>

!
        @brief Returns appropriate amount of clusters.


return self.__wce<EOL>

!
        @brief Returns list of total within cluster errors for each K-value (kmin, kmin + 1, ..., kmax - 1).


x0, y0 = <NUM_LIT:0.0>, self.__wce[<NUM_LIT:0>]<EOL>x1, y1 = float(len(self.__wce)), self.__wce[-<NUM_LIT:1>]<EOL>for index_elbow in range(<NUM_LIT:1>, len(self.__wce) - <NUM_LIT:1>):<EOL><INDENT>x, y = float(index_elbow), self.__wce[index_elbow]<EOL>segment = abs((y0 - y1) * x + (x1 - x0) * y + (x0 * y1 - x1 * y0))<EOL>norm = math.sqrt((x1 - x0) ** <NUM_LIT:2> + (y1 - y0) ** <NUM_LIT:2>)<EOL>distance = segment / norm<EOL>self.__elbows.append(distance)<EOL><DEDENT>

!
        @brief Calculates potential elbows.
        @details Elbow is calculated as a distance from each point (x, y) to segment from kmin-point (x0, y0) to kmax-point (x1, y1).


optimal_elbow_value = max(self.__elbows)<EOL>self.__kvalue = self.__elbows.index(optimal_elbow_value) + <NUM_LIT:1> + self.__kmin<EOL>

!
        @brief Finds elbow and returns corresponding K-value.


def __init__(self, data, amount_clusters, epouch = <NUM_LIT:100>, ccore = True):

self.__data_pointer = data;<EOL>self.__amount_clusters = amount_clusters;<EOL>self.__epouch = epouch;<EOL>self.__ccore = ccore;<EOL>self.__network = None<EOL>

!
        @brief Creates SOM-SC (Self Organized Map for Simple Clustering) algorithm for clustering analysis.

        @param[in] data (list): List of points that are used for processing.
        @param[in] amount_clusters (uint): Amount of clusters that should be allocated.
        @param[in] epouch (uint): Number of epochs for training of SOM.
        @param[in] ccore (bool): If it is True then CCORE implementation will be used for clustering analysis.


self.__network = som(<NUM_LIT:1>, self.__amount_clusters, type_conn.grid_four, None, self.__ccore);<EOL>self.__network.train(self.__data_pointer, self.__epouch, True)<EOL>

!
        @brief Performs cluster analysis by competition between neurons of SOM.

        @remark Results of clustering can be obtained using corresponding get methods.

        @see get_clusters()


return self.__network.capture_objects<EOL>

!
        @brief Returns list of allocated clusters, each cluster contains indexes of objects in list of data.

        @see process()


return type_encoding.CLUSTER_INDEX_LIST_SEPARATION<EOL>

!
        @brief Returns clustering result representation type that indicate how clusters are encoded.

        @return (type_encoding) Clustering result representation.

        @see get_clusters()


def __init__(self, data, eps, neighbors, ccore = True, **kwargs):

self.__pointer_data = data<EOL>self.__kdtree = None<EOL>self.__eps = eps<EOL>self.__sqrt_eps = eps * eps<EOL>self.__neighbors = neighbors<EOL>self.__visited = [False] * len(self.__pointer_data)<EOL>self.__belong = [False] * len(self.__pointer_data)<EOL>self.__data_type = kwargs.get('<STR_LIT>', '<STR_LIT>')<EOL>self.__clusters = []<EOL>self.__noise = []<EOL>self.__neighbor_searcher = self.__create_neighbor_searcher(self.__data_type)<EOL>self.__ccore = ccore<EOL>if self.__ccore:<EOL><INDENT>self.__ccore = ccore_library.workable()<EOL><DEDENT>

!
        @brief Constructor of clustering algorithm DBSCAN.

        @param[in] data (list): Input data that is presented as list of points (objects), each point should be represented by list or tuple.
        @param[in] eps (double): Connectivity radius between points, points may be connected if distance between them less then the radius.
        @param[in] neighbors (uint): minimum number of shared neighbors that is required for establish links between points.
        @param[in] ccore (bool): if True than DLL CCORE (C++ solution) will be used for solving the problem.
        @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'data_type').

        Keyword Args:

            - data_type (string): Data type of input sample 'data' that is processed by the algorithm ('points', 'distance_matrix').