signature:
def linear_sum ( list_vector ) :
    """@ brief Calculates linear sum of vector that is represented by list , each element can be represented by list - multidimensional elements .
 @ param [ in ] list _ vector ( list ) : Input vector .
 @ return ( list | double ) Linear sum of vector that can be represented by list in case of multidimensional elements ."""

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


signature:
def square_sum ( list_vector ) :
    """@ brief Calculates square sum of vector that is represented by list , each element can be represented by list - multidimensional elements .
 @ param [ in ] list _ vector ( list ) : Input vector .
 @ return ( double ) Square sum of vector ."""

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


signature:
def list_math_subtraction ( a , b ) :
    """@ brief Calculates subtraction of two lists .
 @ details Each element from list ' a ' is subtracted by element from list ' b ' accordingly .
 @ param [ in ] a ( list ) : List of elements that supports mathematical subtraction .
 @ param [ in ] b ( list ) : List of elements that supports mathematical subtraction .
 @ return ( list ) Results of subtraction of two lists ."""

implementation: return [ a [ i ] - b [ i ] for i in range ( len ( a ) ) ] ;


signature:
def list_math_substraction_number ( a , b ) :
    """@ brief Calculates subtraction between list and number .
 @ details Each element from list ' a ' is subtracted by number ' b ' .
 @ param [ in ] a ( list ) : List of elements that supports mathematical subtraction .
 @ param [ in ] b ( list ) : Value that supports mathematical subtraction .
 @ return ( list ) Results of subtraction between list and number ."""

implementation: return [ a [ i ] - b for i in range ( len ( a ) ) ] ;


signature:
def list_math_addition ( a , b ) :
    """@ brief Addition of two lists .
 @ details Each element from list ' a ' is added to element from list ' b ' accordingly .
 @ param [ in ] a ( list ) : List of elements that supports mathematic addition . .
 @ param [ in ] b ( list ) : List of elements that supports mathematic addition . .
 @ return ( list ) Results of addtion of two lists ."""

implementation: return [ a [ i ] + b [ i ] for i in range ( len ( a ) ) ] ;


signature:
def list_math_addition_number ( a , b ) :
    """@ brief Addition between list and number .
 @ details Each element from list ' a ' is added to number ' b ' .
 @ param [ in ] a ( list ) : List of elements that supports mathematic addition .
 @ param [ in ] b ( double ) : Value that supports mathematic addition .
 @ return ( list ) Result of addtion of two lists ."""

implementation: return [ a [ i ] + b for i in range ( len ( a ) ) ] ;


signature:
def list_math_division_number ( a , b ) :
    """@ brief Division between list and number .
 @ details Each element from list ' a ' is divided by number ' b ' .
 @ param [ in ] a ( list ) : List of elements that supports mathematic division .
 @ param [ in ] b ( double ) : Value that supports mathematic division .
 @ return ( list ) Result of division between list and number ."""

implementation: return [ a [ i ] / b for i in range ( len ( a ) ) ] ;


signature:
def list_math_division ( a , b ) :
    """@ brief Division of two lists .
 @ details Each element from list ' a ' is divided by element from list ' b ' accordingly .
 @ param [ in ] a ( list ) : List of elements that supports mathematic division .
 @ param [ in ] b ( list ) : List of elements that supports mathematic division .
 @ return ( list ) Result of division of two lists ."""

implementation: return [ a [ i ] / b [ i ] for i in range ( len ( a ) ) ] ;


signature:
def list_math_multiplication_number ( a , b ) :
    """@ brief Multiplication between list and number .
 @ details Each element from list ' a ' is multiplied by number ' b ' .
 @ param [ in ] a ( list ) : List of elements that supports mathematic division .
 @ param [ in ] b ( double ) : Number that supports mathematic division .
 @ return ( list ) Result of division between list and number ."""

implementation: return [ a [ i ] * b for i in range ( len ( a ) ) ] ;


signature:
def list_math_multiplication ( a , b ) :
    """@ brief Multiplication of two lists .
 @ details Each element from list ' a ' is multiplied by element from list ' b ' accordingly .
 @ param [ in ] a ( list ) : List of elements that supports mathematic multiplication .
 @ param [ in ] b ( list ) : List of elements that supports mathematic multiplication .
 @ return ( list ) Result of multiplication of elements in two lists ."""

implementation: return [ a [ i ] * b [ i ] for i in range ( len ( a ) ) ] ;


signature:
def __create_all_to_all_connections ( self ) :
    """@ brief Creates connections between all oscillators ."""

implementation:
if ( self . _conn_represent == conn_represent . MATRIX ) :
    for index in range ( 0 , self . _num_osc , 1 ) :
        self . _osc_conn . append ( [ True ] * self . _num_osc ) ;
        self . _osc_conn [ index ] [ index ] = False ;
elif ( self . _conn_represent == conn_represent . LIST ) :
    for index in range ( 0 , self . _num_osc , 1 ) :
        self . _osc_conn . append ( [ neigh for neigh in range ( 0 , self . _num_osc , 1 ) if index != neigh ] ) ;


signature:
def __create_grid_four_connections ( self ) :
    """@ brief Creates network with connections that make up four grid structure .
 @ details Each oscillator may be connected with four neighbors in line with ' grid ' structure : right , upper , left , lower ."""

implementation:
side_size = self . __width ;
if ( self . _conn_represent == conn_represent . MATRIX ) :
    self . _osc_conn = [ [ 0 ] * self . _num_osc for index in range ( 0 , self . _num_osc , 1 ) ] ;
elif ( self . _conn_represent == conn_represent . LIST ) :
    self . _osc_conn = [ [ ] for index in range ( 0 , self . _num_osc , 1 ) ] ;
else :
    raise NameError ( "Unknown type of representation of connections" ) ;
for index in range ( 0 , self . _num_osc , 1 ) :
    upper_index = index - side_size ;
    lower_index = index + side_size ;
    left_index = index - 1 ;
    right_index = index + 1 ;
    node_row_index = math . ceil ( index / side_size ) ;
    if ( upper_index >= 0 ) :
        self . __create_connection ( index , upper_index ) ;
    if ( lower_index < self . _num_osc ) :
        self . __create_connection ( index , lower_index ) ;
    if ( ( left_index >= 0 ) and ( math . ceil ( left_index / side_size ) == node_row_index ) ) :
        self . __create_connection ( index , left_index ) ;
    if ( ( right_index < self . _num_osc ) and ( math . ceil ( right_index / side_size ) == node_row_index ) ) :
        self . __create_connection ( index , right_index ) ;


signature:
def __create_grid_eight_connections ( self ) :
    """@ brief Creates network with connections that make up eight grid structure .
 @ details Each oscillator may be connected with eight neighbors in line with grid structure : right , right - upper , upper , upper - left , left , left - lower , lower , lower - right ."""

implementation:
self . __create_grid_four_connections ( ) ;
# create connection with right , upper , left , lower .
side_size = self . __width ;
for index in range ( 0 , self . _num_osc , 1 ) :
    upper_left_index = index - side_size - 1 ;
    upper_right_index = index - side_size + 1 ;
    lower_left_index = index + side_size - 1 ;
    lower_right_index = index + side_size + 1 ;
    node_row_index = math . floor ( index / side_size ) ;
    upper_row_index = node_row_index - 1 ;
    lower_row_index = node_row_index + 1 ;
    if ( ( upper_left_index >= 0 ) and ( math . floor ( upper_left_index / side_size ) == upper_row_index ) ) :
        self . __create_connection ( index , upper_left_index ) ;
    if ( ( upper_right_index >= 0 ) and ( math . floor ( upper_right_index / side_size ) == upper_row_index ) ) :
        self . __create_connection ( index , upper_right_index ) ;
    if ( ( lower_left_index < self . _num_osc ) and ( math . floor ( lower_left_index / side_size ) == lower_row_index ) ) :
        self . __create_connection ( index , lower_left_index ) ;
    if ( ( lower_right_index < self . _num_osc ) and ( math . floor ( lower_right_index / side_size ) == lower_row_index ) ) :
        self . __create_connection ( index , lower_right_index ) ;


signature:
def __create_list_bidir_connections ( self ) :
    """@ brief Creates network as bidirectional list .
 @ details Each oscillator may be conneted with two neighbors in line with classical list structure : right , left ."""

implementation:
if ( self . _conn_represent == conn_represent . MATRIX ) :
    for index in range ( 0 , self . _num_osc , 1 ) :
        self . _osc_conn . append ( [ 0 ] * self . _num_osc ) ;
        self . _osc_conn [ index ] [ index ] = False ;
        if ( index > 0 ) :
            self . _osc_conn [ index ] [ index - 1 ] = True ;
        if ( index < ( self . _num_osc - 1 ) ) :
            self . _osc_conn [ index ] [ index + 1 ] = True ;
elif ( self . _conn_represent == conn_represent . LIST ) :
    for index in range ( self . _num_osc ) :
        self . _osc_conn . append ( [ ] ) ;
        if ( index > 0 ) :
            self . _osc_conn [ index ] . append ( index - 1 ) ;
        if ( index < ( self . _num_osc - 1 ) ) :
            self . _osc_conn [ index ] . append ( index + 1 ) ;


signature:
def __create_none_connections ( self ) :
    """@ brief Creates network without connections ."""

implementation:
if ( self . _conn_represent == conn_represent . MATRIX ) :
    for _ in range ( 0 , self . _num_osc , 1 ) :
        self . _osc_conn . append ( [ False ] * self . _num_osc ) ;
elif ( self . _conn_represent == conn_represent . LIST ) :
    self . _osc_conn = [ [ ] for _ in range ( 0 , self . _num_osc , 1 ) ] ;


signature:
def _create_structure ( self , type_conn = conn_type . ALL_TO_ALL ) :
    """@ brief Creates connection in line with representation of matrix connections [ NunOsc x NumOsc ] .
 @ param [ in ] type _ conn ( conn _ type ) : Connection type ( all - to - all , bidirectional list , grid structure , etc . ) that is used by the network ."""

implementation:
self . _osc_conn = list ( ) ;
if ( type_conn == conn_type . NONE ) :
    self . __create_none_connections ( ) ;
elif ( type_conn == conn_type . ALL_TO_ALL ) :
    self . __create_all_to_all_connections ( ) ;
elif ( type_conn == conn_type . GRID_FOUR ) :
    self . __create_grid_four_connections ( ) ;
elif ( type_conn == conn_type . GRID_EIGHT ) :
    self . __create_grid_eight_connections ( ) ;
elif ( type_conn == conn_type . LIST_BIDIR ) :
    self . __create_list_bidir_connections ( ) ;
elif ( type_conn == conn_type . DYNAMIC ) :
    self . __create_dynamic_connection ( ) ;
else :
    raise NameError ( 'The unknown type of connections' ) ;


signature:
def has_connection ( self , i , j ) :
    """@ brief Returns True if there is connection between i and j oscillators and False - if connection doesn ' t exist .
 @ param [ in ] i ( uint ) : index of an oscillator in the network .
 @ param [ in ] j ( uint ) : index of an oscillator in the network ."""

implementation:
if ( self . _conn_represent == conn_represent . MATRIX ) :
    return ( self . _osc_conn [ i ] [ j ] ) ;
elif ( self . _conn_represent == conn_represent . LIST ) :
    for neigh_index in range ( 0 , len ( self . _osc_conn [ i ] ) , 1 ) :
        if ( self . _osc_conn [ i ] [ neigh_index ] == j ) :
            return True ;
    return False ;
else :
    raise NameError ( "Unknown type of representation of coupling" ) ;


signature:
def set_connection ( self , i , j ) :
    """@ brief Couples two specified oscillators in the network with dynamic connections .
 @ param [ in ] i ( uint ) : index of an oscillator that should be coupled with oscillator ' j ' in the network .
 @ param [ in ] j ( uint ) : index of an oscillator that should be coupled with oscillator ' i ' in the network .
 @ note This method can be used only in case of DYNAMIC connections , otherwise it throws expection ."""

implementation:
if ( self . structure != conn_type . DYNAMIC ) :
    raise NameError ( "Connection between oscillators can be changed only in case of dynamic type." ) ;
if ( self . _conn_represent == conn_represent . MATRIX ) :
    self . _osc_conn [ i ] [ j ] = True ;
    self . _osc_conn [ j ] [ i ] = True ;
else :
    self . _osc_conn [ i ] . append ( j ) ;
    self . _osc_conn [ j ] . append ( i ) ;


signature:
def get_neighbors ( self , index ) :
    """@ brief Finds neighbors of the oscillator with specified index .
 @ param [ in ] index ( uint ) : index of oscillator for which neighbors should be found in the network .
 @ return ( list ) Indexes of neighbors of the specified oscillator ."""

implementation:
if ( self . _conn_represent == conn_represent . LIST ) :
    return self . _osc_conn [ index ] ;
    # connections are represented by list .
elif ( self . _conn_represent == conn_represent . MATRIX ) :
    return [ neigh_index for neigh_index in range ( self . _num_osc ) if self . _osc_conn [ index ] [ neigh_index ] == True ] ;
else :
    raise NameError ( "Unknown type of representation of connections" ) ;


signature:
def process ( self ) :
    """@ brief Performs cluster analysis in line with rules of CLARANS algorithm .
 @ see get _ clusters ( )
 @ see get _ medoids ( )"""

implementation:
random . seed ( )
for _ in range ( 0 , self . __numlocal ) : # set ( current ) random medoids
    self . __current = random . sample ( range ( 0 , len ( self . __pointer_data ) ) , self . __number_clusters )
    # update clusters in line with random allocated medoids
    self . __update_clusters ( self . __current )
    # optimize configuration
    self . __optimize_configuration ( )
    # obtain cost of current cluster configuration and compare it with the best obtained
    estimation = self . __calculate_estimation ( )
    if estimation < self . __optimal_estimation :
        self . __optimal_medoids = self . __current [ : ]
        self . __optimal_estimation = estimation
self . __update_clusters ( self . __optimal_medoids )


signature:
def __update_clusters ( self , medoids ) :
    """@ brief Forms cluster in line with specified medoids by calculation distance from each point to medoids ."""

implementation:
self . __belong = [ 0 ] * len ( self . __pointer_data )
self . __clusters = [ [ ] for i in range ( len ( medoids ) ) ]
for index_point in range ( len ( self . __pointer_data ) ) :
    index_optim = - 1
    dist_optim = 0.0
    for index in range ( len ( medoids ) ) :
        dist = euclidean_distance_square ( self . __pointer_data [ index_point ] , self . __pointer_data [ medoids [ index ] ] )
        if ( dist < dist_optim ) or ( index is 0 ) :
            index_optim = index
            dist_optim = dist
    self . __clusters [ index_optim ] . append ( index_point )
    self . __belong [ index_point ] = index_optim
# If cluster is not able to capture object it should be removed
self . __clusters = [ cluster for cluster in self . __clusters if len ( cluster ) > 0 ]


signature:
def __optimize_configuration ( self ) :
    """@ brief Finds quasi - optimal medoids and updates in line with them clusters in line with algorithm ' s rules ."""

implementation:
index_neighbor = 0
while ( index_neighbor < self . __maxneighbor ) : # get random current medoid that is to be replaced
    current_medoid_index = self . __current [ random . randint ( 0 , self . __number_clusters - 1 ) ]
    current_medoid_cluster_index = self . __belong [ current_medoid_index ]
    # get new candidate to be medoid
    candidate_medoid_index = random . randint ( 0 , len ( self . __pointer_data ) - 1 )
    while candidate_medoid_index in self . __current :
        candidate_medoid_index = random . randint ( 0 , len ( self . __pointer_data ) - 1 )
    candidate_cost = 0.0
    for point_index in range ( 0 , len ( self . __pointer_data ) ) :
        if point_index not in self . __current : # get non - medoid point and its medoid
            point_cluster_index = self . __belong [ point_index ]
            point_medoid_index = self . __current [ point_cluster_index ]
            # get other medoid that is nearest to the point ( except current and candidate )
            other_medoid_index = self . __find_another_nearest_medoid ( point_index , current_medoid_index )
            other_medoid_cluster_index = self . __belong [ other_medoid_index ]
            # for optimization calculate all required distances
            # from the point to current medoid
            distance_current = euclidean_distance_square ( self . __pointer_data [ point_index ] , self . __pointer_data [ current_medoid_index ] )
            # from the point to candidate median
            distance_candidate = euclidean_distance_square ( self . __pointer_data [ point_index ] , self . __pointer_data [ candidate_medoid_index ] )
            # from the point to nearest ( own ) medoid
            distance_nearest = float ( 'inf' )
            if ( ( point_medoid_index != candidate_medoid_index ) and ( point_medoid_index != current_medoid_cluster_index ) ) :
                distance_nearest = euclidean_distance_square ( self . __pointer_data [ point_index ] , self . __pointer_data [ point_medoid_index ] )
            # apply rules for cost calculation
            if ( point_cluster_index == current_medoid_cluster_index ) : # case 1:
                if ( distance_candidate >= distance_nearest ) :
                    candidate_cost += distance_nearest - distance_current
                # case 2:
                else :
                    candidate_cost += distance_candidate - distance_current
            elif ( point_cluster_index == other_medoid_cluster_index ) : # case 3 ( ' nearest medoid ' is the representative object of that cluster and object is more similar to ' nearest ' than to ' candidate ' ) :
                if ( distance_candidate > distance_nearest ) :
                    pass ;
                # case 4:
                else :
                    candidate_cost += distance_candidate - distance_nearest
    if ( candidate_cost < 0 ) : # set candidate that has won
        self . __current [ current_medoid_cluster_index ] = candidate_medoid_index
        # recalculate clusters
        self . __update_clusters ( self . __current )
        # reset iterations and starts investigation from the begining
        index_neighbor = 0
    else :
        index_neighbor += 1


signature:
def __find_another_nearest_medoid ( self , point_index , current_medoid_index ) :
    """@ 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 ."""

implementation:
other_medoid_index = - 1
other_distance_nearest = float ( 'inf' )
for index_medoid in self . __current :
    if ( index_medoid != current_medoid_index ) :
        other_distance_candidate = euclidean_distance_square ( self . __pointer_data [ point_index ] , self . __pointer_data [ current_medoid_index ] )
        if other_distance_candidate < other_distance_nearest :
            other_distance_nearest = other_distance_candidate
            other_medoid_index = index_medoid
return other_medoid_index


signature:
def __calculate_estimation ( self ) :
    """@ brief Calculates estimation ( cost ) of the current clusters . The lower the estimation ,
 the more optimally configuration of clusters .
 @ return ( double ) estimation of current clusters ."""

implementation:
estimation = 0.0
for index_cluster in range ( 0 , len ( self . __clusters ) ) :
    cluster = self . __clusters [ index_cluster ]
    index_medoid = self . __current [ index_cluster ]
    for index_point in cluster :
        estimation += euclidean_distance_square ( self . __pointer_data [ index_point ] , self . __pointer_data [ index_medoid ] )
return estimation


signature:
def sixteen_oscillator_two_stimulated_ensembles_grid ( ) :
    "Not accurate false due to spikes are observed"

implementation:
parameters = legion_parameters ( ) ;
parameters . teta_x = - 1.1 ;
template_dynamic_legion ( 16 , 2000 , 1500 , conn_type = conn_type . GRID_FOUR , params = parameters , stimulus = [ 1 , 1 , 1 , 0 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 1 , 1 ] ) ;


signature:
def simple_segmentation_example ( ) :
    "Perfect results !"


signature:
def visualize ( self , display = True ) :
    """@ brief Display KD - tree to console .
 @ param [ in ] display ( bool ) : If ' True ' then tree will be shown in console .
 @ return ( string ) Text representation of the KD - tree ."""

implementation:
kdnodes = self . __get_nodes ( )
level = kdnodes [ 0 ]
for kdnode in kdnodes :
    self . __print_node ( level , kdnode )
self . __tree_text += self . __tree_level_text
if display is True :
    print ( self . __tree_text )
return self . __tree_text


signature:
def insert ( self , point , payload ) :
    """@ brief Insert new point with payload to kd - tree .
 @ param [ in ] point ( list ) : Coordinates of the point of inserted node .
 @ param [ in ] payload ( any - type ) : Payload of inserted node . It can be identificator of the node or
 some useful payload that belongs to the point .
 @ return ( node ) Inserted node to the kd - tree ."""

implementation:
if self . __root is None :
    self . __dimension = len ( point )
    self . __root = node ( point , payload , None , None , 0 )
    self . __point_comparator = self . __create_point_comparator ( type ( point ) )
    return self . __root
cur_node = self . __root
while True :
    if cur_node . data [ cur_node . disc ] <= point [ cur_node . disc ] : # If new node is greater or equal than current node then check right leaf
        if cur_node . right is None :
            discriminator = cur_node . disc + 1
            if discriminator >= self . __dimension :
                discriminator = 0
            cur_node . right = node ( point , payload , None , None , discriminator , cur_node )
            return cur_node . right
        else :
            cur_node = cur_node . right
    else : # If new node is less than current then check left leaf
        if cur_node . left is None :
            discriminator = cur_node . disc + 1
            if discriminator >= self . __dimension :
                discriminator = 0
            cur_node . left = node ( point , payload , None , None , discriminator , cur_node )
            return cur_node . left
        else :
            cur_node = cur_node . left


signature:
def remove ( self , point , ** kwargs ) :
    """@ brief Remove specified point from kd - tree .
 @ details It removes the first found node that satisfy to the input parameters . Make sure that
 pair ( point , payload ) is unique for each node , othewise the first found is removed .
 @ param [ in ] point ( list ) : Coordinates of the point of removed node .
 @ param [ in ] * * kwargs : Arbitrary keyword arguments ( available arguments : ' payload ' ) .
 < b > Keyword Args : < / b > < br >
 - payload ( any ) : Payload of the node that should be removed .
 @ return ( node ) Root if node has been successfully removed , otherwise None ."""

implementation:
# Get required node
node_for_remove = None
if 'payload' in kwargs :
    node_for_remove = self . find_node_with_payload ( point , kwargs [ 'payload' ] , None )
else :
    node_for_remove = self . find_node ( point , None )
if node_for_remove is None :
    return None
parent = node_for_remove . parent
minimal_node = self . __recursive_remove ( node_for_remove )
if parent is None :
    self . __root = minimal_node
    # If all k - d tree was destroyed
    if minimal_node is not None :
        minimal_node . parent = None
else :
    if parent . left is node_for_remove :
        parent . left = minimal_node
    elif parent . right is node_for_remove :
        parent . right = minimal_node
return self . __root


signature:
def __recursive_remove ( self , node_removed ) :
    """@ brief Delete node and return root of subtree .
 @ param [ in ] node _ removed ( node ) : Node that should be removed .
 @ return ( node ) Minimal node in line with coordinate that is defined by descriminator ."""

implementation:
# Check if it is leaf
if ( node_removed . right is None ) and ( node_removed . left is None ) :
    return None
discriminator = node_removed . disc
# Check if only left branch exist
if node_removed . right is None :
    node_removed . right = node_removed . left
    node_removed . left = None
# Find minimal node in line with coordinate that is defined by discriminator
minimal_node = self . find_minimal_node ( node_removed . right , discriminator )
parent = minimal_node . parent
if parent . left is minimal_node :
    parent . left = self . __recursive_remove ( minimal_node )
elif parent . right is minimal_node :
    parent . right = self . __recursive_remove ( minimal_node )
minimal_node . parent = node_removed . parent
minimal_node . disc = node_removed . disc
minimal_node . right = node_removed . right
minimal_node . left = node_removed . left
# Update parent for successors of previous parent .
if minimal_node . right is not None :
    minimal_node . right . parent = minimal_node
if minimal_node . left is not None :
    minimal_node . left . parent = minimal_node
return minimal_node


signature:
def find_minimal_node ( self , node_head , discriminator ) :
    """@ brief Find minimal node in line with coordinate that is defined by discriminator .
 @ param [ in ] node _ head ( node ) : Node of KD tree from that search should be started .
 @ param [ in ] discriminator ( uint ) : Coordinate number that is used for comparison .
 @ return ( node ) Minimal node in line with descriminator from the specified node ."""

implementation:
min_key = lambda cur_node : cur_node . data [ discriminator ]
stack = [ ]
candidates = [ ]
isFinished = False
while isFinished is False :
    if node_head is not None :
        stack . append ( node_head )
        node_head = node_head . left
    else :
        if len ( stack ) != 0 :
            node_head = stack . pop ( )
            candidates . append ( node_head )
            node_head = node_head . right
        else :
            isFinished = True
return min ( candidates , key = min_key )


signature:
def __fill_tree ( self , data_list , payload_list ) :
    """@ brief Fill KD - tree by specified data and create point comparator in line with data type .
 @ param [ in ] data _ list ( array _ like ) : Data points that should be inserted to the tree .
 @ param [ in ] payload _ list ( array _ like ) : Data point payloads that follows data points inserted to the tree ."""

implementation:
if data_list is None or len ( data_list ) == 0 :
    return
# Just return from here , tree can be filled by insert method later
if payload_list is None : # Case when payload is not specified .
    for index in range ( 0 , len ( data_list ) ) :
        self . insert ( data_list [ index ] , None )
else : # Case when payload is specified .
    for index in range ( 0 , len ( data_list ) ) :
        self . insert ( data_list [ index ] , payload_list [ index ] )
self . __point_comparator = self . __create_point_comparator ( type ( self . __root . data ) )


signature:
def __create_point_comparator ( self , type_point ) :
    """@ brief Create point comparator .
 @ details In case of numpy . array specific comparator is required .
 @ param [ in ] type _ point ( data _ type ) : Type of point that is stored in KD - node .
 @ return ( callable ) Callable point comparator to compare to points ."""

implementation:
if type_point == numpy . ndarray :
    return lambda obj1 , obj2 : numpy . array_equal ( obj1 , obj2 )
return lambda obj1 , obj2 : obj1 == obj2


signature:
def __find_node_by_rule ( self , point , search_rule , cur_node ) :
    """@ brief Search node that satisfy to parameters in search rule .
 @ details If node with specified parameters does not exist then None will be returned ,
 otherwise required node will be returned .
 @ param [ in ] point ( list ) : Coordinates of the point whose node should be found .
 @ param [ in ] search _ rule ( lambda ) : Rule that is called to check whether node satisfies to search parameter .
 @ param [ in ] cur _ node ( node ) : Node from which search should be started .
 @ return ( node ) Node if it satisfies to input parameters , otherwise it return None ."""

implementation:
req_node = None
if cur_node is None :
    cur_node = self . __root
while cur_node :
    if cur_node . data [ cur_node . disc ] <= point [ cur_node . disc ] : # Check if it ' s required node
        if search_rule ( cur_node ) :
            req_node = cur_node
            break
        cur_node = cur_node . right
    else :
        cur_node = cur_node . left
return req_node


signature:
def find_node_with_payload ( self , point , point_payload , cur_node = None ) :
    """@ brief Find node with specified coordinates and payload .
 @ details If node with specified parameters does not exist then None will be returned ,
 otherwise required node will be returned .
 @ param [ in ] point ( list ) : Coordinates of the point whose node should be found .
 @ param [ in ] point _ payload ( any ) : Payload of the node that is searched in the tree .
 @ param [ in ] cur _ node ( node ) : Node from which search should be started .
 @ return ( node ) Node if it satisfies to input parameters , otherwise it return None ."""

implementation:
rule_search = lambda node , point = point , payload = point_payload : self . __point_comparator ( node . data , point ) and node . payload == payload
return self . __find_node_by_rule ( point , rule_search , cur_node )


signature:
def find_node ( self , point , cur_node = None ) :
    """@ brief Find node with coordinates that are defined by specified point .
 @ details If node with specified parameters does not exist then None will be returned ,
 otherwise required node will be returned .
 @ param [ in ] point ( list ) : Coordinates of the point whose node should be found .
 @ param [ in ] cur _ node ( node ) : Node from which search should be started .
 @ return ( node ) Node if it satisfies to input parameters , otherwise it return None ."""

implementation:
rule_search = lambda node , point = point : self . __point_comparator ( node . data , point )
return self . __find_node_by_rule ( point , rule_search , cur_node )


signature:
def find_nearest_dist_node ( self , point , distance , retdistance = False ) :
    """@ brief Find nearest neighbor in area with radius = distance .
 @ param [ in ] point ( list ) : Maximum distance where neighbors are searched .
 @ param [ in ] distance ( double ) : Maximum distance where neighbors are searched .
 @ param [ in ] retdistance ( bool ) : If True - returns neighbors with distances to them , otherwise only neighbors is returned .
 @ return ( node | list ) Nearest neighbor if ' retdistance ' is False and list with two elements [ node , distance ] if ' retdistance ' is True ,
 where the first element is pointer to node and the second element is distance to it ."""

implementation:
best_nodes = self . find_nearest_dist_nodes ( point , distance )
if best_nodes == [ ] :
    return None
nearest = min ( best_nodes , key = lambda item : item [ 0 ] )
if retdistance is True :
    return nearest
else :
    return nearest [ 1 ]


signature:
def find_nearest_dist_nodes ( self , point , distance ) :
    """@ brief Find neighbors that are located in area that is covered by specified distance .
 @ param [ in ] point ( list ) : Coordinates that is considered as centroind for searching .
 @ param [ in ] distance ( double ) : Distance from the center where seaching is performed .
 @ return ( list ) Neighbors in area that is specified by point ( center ) and distance ( radius ) ."""

implementation:
best_nodes = [ ]
if self . __root is not None :
    self . __recursive_nearest_nodes ( point , distance , distance * distance , self . __root , best_nodes )
return best_nodes


signature:
def __recursive_nearest_nodes ( self , point , distance , sqrt_distance , node_head , best_nodes ) :
    """@ brief Returns list of neighbors such as tuple ( distance , node ) that is located in area that is covered by distance .
 @ param [ in ] point ( list ) : Coordinates that is considered as centroind for searching
 @ param [ in ] distance ( double ) : Distance from the center where seaching is performed .
 @ param [ in ] sqrt _ distance ( double ) : Square distance from the center where searching is performed .
 @ param [ in ] node _ head ( node ) : Node from that searching is performed .
 @ param [ in | out ] best _ nodes ( list ) : List of founded nodes ."""

implementation:
if node_head . right is not None :
    minimum = node_head . data [ node_head . disc ] - distance
    if point [ node_head . disc ] >= minimum :
        self . __recursive_nearest_nodes ( point , distance , sqrt_distance , node_head . right , best_nodes )
if node_head . left is not None :
    maximum = node_head . data [ node_head . disc ] + distance
    if point [ node_head . disc ] < maximum :
        self . __recursive_nearest_nodes ( point , distance , sqrt_distance , node_head . left , best_nodes )
candidate_distance = euclidean_distance_square ( point , node_head . data )
if candidate_distance <= sqrt_distance :
    best_nodes . append ( ( candidate_distance , node_head ) )


signature:
def children ( self , node_parent ) :
    """@ brief Returns list of children of node .
 @ param [ in ] node _ parent ( node ) : Node whose children are required .
 @ return ( list ) Children of node . If node haven ' t got any child then None is returned ."""

implementation:
if node_parent . left is not None :
    yield node_parent . left
if node_parent . right is not None :
    yield node_parent . right


signature:
def traverse ( self , start_node = None , level = None ) :
    """@ brief Traverses all nodes of subtree that is defined by node specified in input parameter .
 @ param [ in ] start _ node ( node ) : Node from that travering of subtree is performed .
 @ param [ in , out ] level ( uint ) : Should be ignored by application .
 @ return ( list ) All nodes of the subtree ."""

implementation:
if start_node is None :
    start_node = self . __root
    level = 0
if start_node is None :
    return [ ]
items = [ ( level , start_node ) ]
for child in self . children ( start_node ) :
    if child is not None :
        items += self . traverse ( child , level + 1 )
return items


signature:
def __process_by_ccore ( self ) :
    """@ brief Performs processing using C + + implementation ."""

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


signature:
def __process_by_python ( self ) :
    """@ brief Performs processing using python implementation ."""

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


signature:
def __calculate_elbows ( self ) :
    """@ 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 ) ."""

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


signature:
def __find_optimal_kvalue ( self ) :
    """@ brief Finds elbow and returns corresponding K - value ."""

implementation:
optimal_elbow_value = max ( self . __elbows )
self . __kvalue = self . __elbows . index ( optimal_elbow_value ) + 1 + self . __kmin


signature:
def show_ordering_diagram ( analyser , amount_clusters = None ) :
    """@ 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"""

implementation:
ordering = analyser . cluster_ordering
axis = plt . subplot ( 111 )
if amount_clusters is not None :
    radius , borders = analyser . calculate_connvectivity_radius ( amount_clusters )
    # divide into cluster groups to visualize by colors
    left_index_border = 0
    current_index_border = 0
    for index_border in range ( len ( borders ) ) :
        right_index_border = borders [ index_border ]
        axis . bar ( range ( left_index_border , right_index_border ) , ordering [ left_index_border : right_index_border ] , width = 1.0 , color = color_list . TITLES [ index_border ] )
        left_index_border = right_index_border
        current_index_border = index_border
    axis . bar ( range ( left_index_border , len ( ordering ) ) , ordering [ left_index_border : len ( ordering ) ] , width = 1.0 , color = color_list . TITLES [ current_index_border + 1 ] )
    plt . xlim ( [ 0 , len ( ordering ) ] )
    plt . axhline ( y = radius , linewidth = 2 , color = 'black' )
    plt . text ( 0 , radius + radius * 0.03 , " Radius:   " + str ( round ( radius , 4 ) ) + ";\n Clusters: " + str ( amount_clusters ) , color = 'b' , fontsize = 10 )
else :
    axis . bar ( range ( 0 , len ( ordering ) ) , ordering [ 0 : len ( ordering ) ] , width = 1.0 , color = 'black' )
    plt . xlim ( [ 0 , len ( ordering ) ] )
plt . show ( )


signature:
def calculate_connvectivity_radius ( self , amount_clusters , maximum_iterations = 100 ) :
    """@ 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 ."""

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


signature:
def extract_cluster_amount ( self , radius ) :
    """@ 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 ) ."""

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


signature:
def __process_by_ccore ( self ) :
    """@ brief Performs cluster analysis using CCORE ( C / C + + part of pyclustering library ) ."""

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


signature:
def __process_by_python ( self ) :
    """@ brief Performs cluster analysis using python code ."""

implementation:
if self . __data_type == 'points' :
    self . __kdtree = kdtree ( self . __sample_pointer , range ( len ( self . __sample_pointer ) ) )
self . __allocate_clusters ( )
if ( self . __amount_clusters is not None ) and ( self . __amount_clusters != len ( self . get_clusters ( ) ) ) :
    analyser = ordering_analyser ( self . get_ordering ( ) )
    radius , _ = analyser . calculate_connvectivity_radius ( self . __amount_clusters )
    if radius is not None :
        self . __eps = radius
        self . __allocate_clusters ( )


signature:
def __initialize ( self , sample ) :
    """@ brief Initializes internal states and resets clustering results in line with input sample ."""

implementation:
self . __processed = [ False ] * len ( sample )
self . __optics_objects = [ optics_descriptor ( i ) for i in range ( len ( sample ) ) ]
# List of OPTICS objects that corresponds to objects from input sample .
self . __ordered_database = [ ]
# List of OPTICS objects in traverse order .
self . __clusters = None
# Result of clustering ( list of clusters where each cluster contains indexes of objects from input data ) .
self . __noise = None


signature:
def __allocate_clusters ( self ) :
    """@ brief Performs cluster allocation and builds ordering diagram that is based on reachability - distances ."""

implementation:
self . __initialize ( self . __sample_pointer )
for optic_object in self . __optics_objects :
    if optic_object . processed is False :
        self . __expand_cluster_order ( optic_object )
self . __extract_clusters ( )


signature:
def get_ordering ( self ) :
    """@ 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 ( )"""

implementation:
if self . __ordering is None :
    self . __ordering = [ ]
    for cluster in self . __clusters :
        for index_object in cluster :
            optics_object = self . __optics_objects [ index_object ]
            if optics_object . reachability_distance is not None :
                self . __ordering . append ( optics_object . reachability_distance )
return self . __ordering


signature:
def __create_neighbor_searcher ( self , data_type ) :
    """@ brief Returns neighbor searcher in line with data type .
 @ param [ in ] data _ type ( string ) : Data type ( points or distance matrix ) ."""

implementation:
if data_type == 'points' :
    return self . __neighbor_indexes_points
elif data_type == 'distance_matrix' :
    return self . __neighbor_indexes_distance_matrix
else :
    raise TypeError ( "Unknown type of data is specified '%s'" % data_type )


signature:
def __expand_cluster_order ( self , optics_object ) :
    """@ 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 ."""

implementation:
optics_object . processed = True
neighbors_descriptor = self . __neighbor_searcher ( optics_object )
optics_object . reachability_distance = None
self . __ordered_database . append ( optics_object )
# Check core distance
if len ( neighbors_descriptor ) >= self . __minpts :
    neighbors_descriptor . sort ( key = lambda obj : obj [ 1 ] )
    optics_object . core_distance = neighbors_descriptor [ self . __minpts - 1 ] [ 1 ]
    # Continue processing
    order_seed = list ( )
    self . __update_order_seed ( optics_object , neighbors_descriptor , order_seed )
    while len ( order_seed ) > 0 :
        optic_descriptor = order_seed [ 0 ]
        order_seed . remove ( optic_descriptor )
        neighbors_descriptor = self . __neighbor_searcher ( optic_descriptor )
        optic_descriptor . processed = True
        self . __ordered_database . append ( optic_descriptor )
        if len ( neighbors_descriptor ) >= self . __minpts :
            neighbors_descriptor . sort ( key = lambda obj : obj [ 1 ] )
            optic_descriptor . core_distance = neighbors_descriptor [ self . __minpts - 1 ] [ 1 ]
            self . __update_order_seed ( optic_descriptor , neighbors_descriptor , order_seed )
        else :
            optic_descriptor . core_distance = None
else :
    optics_object . core_distance = None


signature:
def __extract_clusters ( self ) :
    """@ brief Extract clusters and noise from order database ."""

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


signature:
def __update_order_seed ( self , optic_descriptor , neighbors_descriptors , order_seed ) :
    """@ 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 ."""

implementation:
for neighbor_descriptor in neighbors_descriptors :
    index_neighbor = neighbor_descriptor [ 0 ]
    current_reachable_distance = neighbor_descriptor [ 1 ]
    if self . __optics_objects [ index_neighbor ] . processed is not True :
        reachable_distance = max ( current_reachable_distance , optic_descriptor . core_distance )
        if self . __optics_objects [ index_neighbor ] . reachability_distance is None :
            self . __optics_objects [ index_neighbor ] . reachability_distance = reachable_distance
            # insert element in queue O ( n ) - worst case .
            index_insertion = len ( order_seed )
            for index_seed in range ( 0 , len ( order_seed ) ) :
                if reachable_distance < order_seed [ index_seed ] . reachability_distance :
                    index_insertion = index_seed
                    break
            order_seed . insert ( index_insertion , self . __optics_objects [ index_neighbor ] )
        else :
            if reachable_distance < self . __optics_objects [ index_neighbor ] . reachability_distance :
                self . __optics_objects [ index_neighbor ] . reachability_distance = reachable_distance
                order_seed . sort ( key = lambda obj : obj . reachability_distance )


signature:
def __neighbor_indexes_points ( self , optic_object ) :
    """@ 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 ."""

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


signature:
def __neighbor_indexes_distance_matrix ( self , optic_object ) :
    """@ 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 ."""

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


signature:
def process ( self ) :
    """@ 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 ( )"""

implementation:
self . __insert_data ( ) ;
self . __extract_features ( ) ;
# in line with specification modify hierarchical algorithm should be used for further clustering
current_number_clusters = len ( self . __features ) ;
while ( current_number_clusters > self . __number_clusters ) :
    indexes = self . __find_nearest_cluster_features ( ) ;
    self . __features [ indexes [ 0 ] ] += self . __features [ indexes [ 1 ] ] ;
    self . __features . pop ( indexes [ 1 ] ) ;
    current_number_clusters = len ( self . __features ) ;
# decode data
self . __decode_data ( ) ;


signature:
def __extract_features ( self ) :
    """@ brief Extracts features from CF - tree cluster ."""

implementation:
self . __features = [ ] ;
if ( len ( self . __tree . leafes ) == 1 ) : # parameters are too general , copy all entries
    for entry in self . __tree . leafes [ 0 ] . entries :
        self . __features . append ( entry ) ;
else : # copy all leaf clustering features
    for node in self . __tree . leafes :
        self . __features . append ( node . feature ) ;


signature:
def __decode_data ( self ) :
    """@ brief Decodes data from CF - tree features ."""

implementation:
self . __clusters = [ [ ] for _ in range ( self . __number_clusters ) ] ;
self . __noise = [ ] ;
for index_point in range ( 0 , len ( self . __pointer_data ) ) :
    ( _ , cluster_index ) = self . __get_nearest_feature ( self . __pointer_data [ index_point ] , self . __features ) ;
    self . __clusters [ cluster_index ] . append ( index_point ) ;


signature:
def __insert_data ( self ) :
    """@ 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 ."""

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


signature:
def __rebuild_tree ( self , index_point ) :
    """@ 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 ."""

implementation:
rebuild_result = False ;
increased_diameter = self . __tree . threshold * self . __diameter_multiplier ;
tree = None ;
while ( rebuild_result is False ) : # increase diameter and rebuild tree
    if ( increased_diameter == 0.0 ) :
        increased_diameter = 1.0 ;
    # build tree with update parameters
    tree = cftree ( self . __tree . branch_factor , self . __tree . max_entries , increased_diameter , self . __tree . type_measurement ) ;
    for index_point in range ( 0 , index_point + 1 ) :
        point = self . __pointer_data [ index_point ] ;
        tree . insert_cluster ( [ point ] ) ;
        if ( tree . amount_entries > self . __entry_size_limit ) :
            increased_diameter *= self . __diameter_multiplier ;
            continue ;
    # Re - build is successful .
    rebuild_result = True ;
return tree ;


signature:
def __find_nearest_cluster_features ( self ) :
    """@ brief Find pair of nearest CF entries .
 @ return ( list ) List of two nearest enties that are represented by list [ index _ point1 , index _ point2 ] ."""

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


signature:
def __get_nearest_feature ( self , point , feature_collection ) :
    """@ 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 ."""

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


signature:
def __read_answer_from_line ( self , index_point , line ) :
    """@ brief Read information about point from the specific line and place it to cluster or noise in line with that
 information .
 @ param [ in ] index _ point ( uint ) : Index point that should be placed to cluster or noise .
 @ param [ in ] line ( string ) : Line where information about point should be read ."""

implementation:
if line [ 0 ] == 'n' :
    self . __noise . append ( index_point )
else :
    index_cluster = int ( line )
    if index_cluster >= len ( self . __clusters ) :
        self . __clusters . append ( [ index_point ] )
    else :
        self . __clusters [ index_cluster ] . append ( index_point )


signature:
def __read_answer ( self ) :
    """@ brief Read information about proper clusters and noises from the file ."""

implementation:
if self . __clusters is not None :
    return
file = open ( self . __answer_path , 'r' )
self . __clusters , self . __noise = [ ] , [ ]
index_point = 0
for line in file :
    self . __read_answer_from_line ( index_point , line )
    index_point += 1
file . close ( )


signature:
def append_cluster ( self , cluster , data = None , marker = '.' , markersize = None , color = None ) :
    """@ brief Appends cluster for visualization .
 @ param [ in ] cluster ( list ) : cluster that may consist of indexes of objects from the data or object itself .
 @ param [ in ] data ( list ) : If defines that each element of cluster is considered as a index of object from the data .
 @ param [ in ] marker ( string ) : Marker that is used for displaying objects from cluster on the canvas .
 @ param [ in ] markersize ( uint ) : Size of marker .
 @ param [ in ] color ( string ) : Color of marker .
 @ return Returns index of cluster descriptor on the canvas ."""

implementation:
if len ( cluster ) == 0 :
    raise ValueError ( "Empty cluster is provided." )
markersize = markersize or 5
if color is None :
    index_color = len ( self . __clusters ) % len ( color_list . TITLES )
    color = color_list . TITLES [ index_color ]
cluster_descriptor = canvas_cluster_descr ( cluster , data , marker , markersize , color )
self . __clusters . append ( cluster_descriptor )


signature:
def append_clusters ( self , clusters , data = None , marker = '.' , markersize = None ) :
    """@ brief Appends list of cluster for visualization .
 @ param [ in ] clusters ( list ) : List of clusters where each cluster may consist of indexes of objects from the data or object itself .
 @ param [ in ] data ( list ) : If defines that each element of cluster is considered as a index of object from the data .
 @ param [ in ] marker ( string ) : Marker that is used for displaying objects from clusters on the canvas .
 @ param [ in ] markersize ( uint ) : Size of marker ."""

implementation:
for cluster in clusters :
    self . append_cluster ( cluster , data , marker , markersize )


signature:
def show ( self , pair_filter = None , ** kwargs ) :
    """@ brief Shows clusters ( visualize ) in multi - dimensional space .
 @ param [ in ] pair _ filter ( list ) : List of coordinate pairs that should be displayed . This argument is used as a filter .
 @ param [ in ] * * kwargs : Arbitrary keyword arguments ( available arguments : ' visible _ axis ' ' visible _ labels ' , ' visible _ grid ' , ' row _ size ' ) .
 < b > Keyword Args : < / b > < br >
 - visible _ axis ( bool ) : Defines visibility of axes on each canvas , if True - axes are visible .
 By default axis of each canvas are not displayed .
 - visible _ labels ( bool ) : Defines visibility of labels on each canvas , if True - labels is displayed .
 By default labels of each canvas are displayed .
 - visible _ grid ( bool ) : Defines visibility of grid on each canvas , if True - grid is displayed .
 By default grid of each canvas is displayed .
 - max _ row _ size ( uint ) : Maximum number of canvases on one row ."""

implementation:
if not len ( self . __clusters ) > 0 :
    raise ValueError ( "There is no non-empty clusters for visualization." )
cluster_data = self . __clusters [ 0 ] . data or self . __clusters [ 0 ] . cluster
dimension = len ( cluster_data [ 0 ] )
acceptable_pairs = pair_filter or [ ]
pairs = [ ]
amount_axis = 1
axis_storage = [ ]
if dimension > 1 :
    pairs = self . __create_pairs ( dimension , acceptable_pairs )
    amount_axis = len ( pairs )
self . __figure = plt . figure ( )
self . __grid_spec = self . __create_grid_spec ( amount_axis , kwargs . get ( 'max_row_size' , 4 ) )
for index in range ( amount_axis ) :
    ax = self . __create_canvas ( dimension , pairs , index , ** kwargs )
    axis_storage . append ( ax )
for cluster_descr in self . __clusters :
    self . __draw_canvas_cluster ( axis_storage , cluster_descr , pairs )
plt . show ( )


signature:
def __create_grid_spec ( self , amount_axis , max_row_size ) :
    """@ brief Create grid specification for figure to place canvases .
 @ param [ in ] amount _ axis ( uint ) : Amount of canvases that should be organized by the created grid specification .
 @ param [ in ] max _ row _ size ( max _ row _ size ) : Maximum number of canvases on one row .
 @ return ( gridspec . GridSpec ) Grid specification to place canvases on figure ."""

implementation:
row_size = amount_axis
if row_size > max_row_size :
    row_size = max_row_size
col_size = math . ceil ( amount_axis / row_size )
return gridspec . GridSpec ( col_size , row_size )


signature:
def __create_pairs ( self , dimension , acceptable_pairs ) :
    """@ brief Create coordinate pairs that should be displayed .
 @ param [ in ] dimension ( uint ) : Data - space dimension .
 @ param [ in ] acceptable _ pairs ( list ) : List of coordinate pairs that should be displayed .
 @ return ( list ) List of coordinate pairs that should be displayed ."""

implementation:
if len ( acceptable_pairs ) > 0 :
    return acceptable_pairs
return list ( itertools . combinations ( range ( dimension ) , 2 ) )


signature:
def __create_canvas ( self , dimension , pairs , position , ** kwargs ) :
    """@ brief Create new canvas with user defined parameters to display cluster or chunk of cluster on it .
 @ param [ in ] dimension ( uint ) : Data - space dimension .
 @ param [ in ] pairs ( list ) : Pair of coordinates that will be displayed on the canvas . If empty than label will not
 be displayed on the canvas .
 @ param [ in ] position ( uint ) : Index position of canvas on a grid .
 @ param [ in ] * * kwargs : Arbitrary keyword arguments ( available arguments : ' visible _ axis ' ' visible _ labels ' , ' visible _ grid ' ) .
 < b > Keyword Args : < / b > < br >
 - visible _ axis ( bool ) : Defines visibility of axes on each canvas , if True - axes are visible .
 By default axis are not displayed .
 - visible _ labels ( bool ) : Defines visibility of labels on each canvas , if True - labels is displayed .
 By default labels are displayed .
 - visible _ grid ( bool ) : Defines visibility of grid on each canvas , if True - grid is displayed .
 By default grid is displayed .
 @ return ( matplotlib . Axis ) Canvas to display cluster of chuck of cluster ."""

implementation:
visible_grid = kwargs . get ( 'visible_grid' , True )
visible_labels = kwargs . get ( 'visible_labels' , True )
visible_axis = kwargs . get ( 'visible_axis' , False )
ax = self . __figure . add_subplot ( self . __grid_spec [ position ] )
if dimension > 1 :
    if visible_labels :
        ax . set_xlabel ( "x%d" % pairs [ position ] [ 0 ] )
        ax . set_ylabel ( "x%d" % pairs [ position ] [ 1 ] )
else :
    ax . set_ylim ( - 0.5 , 0.5 )
    ax . set_yticklabels ( [ ] )
if visible_grid :
    ax . grid ( True )
if not visible_axis :
    ax . set_yticklabels ( [ ] )
    ax . set_xticklabels ( [ ] )
return ax


signature:
def __draw_canvas_cluster ( self , axis_storage , cluster_descr , pairs ) :
    """@ brief Draw clusters .
 @ param [ in ] axis _ storage ( list ) : List of matplotlib axis where cluster dimensional chunks are displayed .
 @ param [ in ] cluster _ descr ( canvas _ cluster _ descr ) : Canvas cluster descriptor that should be displayed .
 @ param [ in ] pairs ( list ) : List of coordinates that should be displayed ."""

implementation:
for index_axis in range ( len ( axis_storage ) ) :
    for item in cluster_descr . cluster :
        if len ( pairs ) > 0 :
            self . __draw_cluster_item_multi_dimension ( axis_storage [ index_axis ] , pairs [ index_axis ] , item , cluster_descr )
        else :
            self . __draw_cluster_item_one_dimension ( axis_storage [ index_axis ] , item , cluster_descr )


signature:
def __draw_cluster_item_multi_dimension ( self , ax , pair , item , cluster_descr ) :
    """@ brief Draw cluster chunk defined by pair coordinates in data space with dimension greater than 1.
 @ param [ in ] ax ( axis ) : Matplotlib axis that is used to display chunk of cluster point .
 @ param [ in ] pair ( list ) : Coordinate of the point that should be displayed .
 @ param [ in ] item ( list ) : Data point or index of data point .
 @ param [ in ] cluster _ descr ( canvas _ cluster _ descr ) : Cluster description whose point is visualized ."""

implementation:
index_dimension1 = pair [ 0 ]
index_dimension2 = pair [ 1 ]
if cluster_descr . data is None :
    ax . plot ( item [ index_dimension1 ] , item [ index_dimension2 ] , color = cluster_descr . color , marker = cluster_descr . marker , markersize = cluster_descr . markersize )
else :
    ax . plot ( cluster_descr . data [ item ] [ index_dimension1 ] , cluster_descr . data [ item ] [ index_dimension2 ] , color = cluster_descr . color , marker = cluster_descr . marker , markersize = cluster_descr . markersize )


signature:
def __draw_cluster_item_one_dimension ( self , ax , item , cluster_descr ) :
    """@ brief Draw cluster point in one dimensional data space . .
 @ param [ in ] ax ( axis ) : Matplotlib axis that is used to display chunk of cluster point .
 @ param [ in ] item ( list ) : Data point or index of data point .
 @ param [ in ] cluster _ descr ( canvas _ cluster _ descr ) : Cluster description whose point is visualized ."""

implementation:
if cluster_descr . data is None :
    ax . plot ( item [ 0 ] , 0.0 , color = cluster_descr . color , marker = cluster_descr . marker , markersize = cluster_descr . markersize )
else :
    ax . plot ( cluster_descr . data [ item ] [ 0 ] , 0.0 , color = cluster_descr . color , marker = cluster_descr . marker , markersize = cluster_descr . markersize )


signature:
def append_cluster ( self , cluster , data = None , canvas = 0 , marker = '.' , markersize = None , color = None ) :
    """@ brief Appends cluster to canvas for drawing .
 @ param [ in ] cluster ( list ) : cluster that may consist of indexes of objects from the data or object itself .
 @ param [ in ] data ( list ) : If defines that each element of cluster is considered as a index of object from the data .
 @ param [ in ] canvas ( uint ) : Number of canvas that should be used for displaying cluster .
 @ param [ in ] marker ( string ) : Marker that is used for displaying objects from cluster on the canvas .
 @ param [ in ] markersize ( uint ) : Size of marker .
 @ param [ in ] color ( string ) : Color of marker .
 @ return Returns index of cluster descriptor on the canvas ."""

implementation:
if len ( cluster ) == 0 :
    return
if canvas > self . __number_canvases or canvas < 0 :
    raise ValueError ( "Canvas index '%d' is out of range [0; %d]." % self . __number_canvases or canvas )
if color is None :
    index_color = len ( self . __canvas_clusters [ canvas ] ) % len ( color_list . TITLES )
    color = color_list . TITLES [ index_color ]
added_canvas_descriptor = canvas_cluster_descr ( cluster , data , marker , markersize , color )
self . __canvas_clusters [ canvas ] . append ( added_canvas_descriptor )
if data is None :
    dimension = len ( cluster [ 0 ] )
    if self . __canvas_dimensions [ canvas ] is None :
        self . __canvas_dimensions [ canvas ] = dimension
    elif self . __canvas_dimensions [ canvas ] != dimension :
        raise ValueError ( "Only clusters with the same dimension of objects can be displayed on canvas." )
else :
    dimension = len ( data [ 0 ] )
    if self . __canvas_dimensions [ canvas ] is None :
        self . __canvas_dimensions [ canvas ] = dimension
    elif self . __canvas_dimensions [ canvas ] != dimension :
        raise ValueError ( "Only clusters with the same dimension of objects can be displayed on canvas." )
if ( dimension < 1 ) or ( dimension > 3 ) :
    raise ValueError ( "Only objects with size dimension 1 (1D plot), 2 (2D plot) or 3 (3D plot) " "can be displayed. For multi-dimensional data use 'cluster_visualizer_multidim'." )
if markersize is None :
    if ( dimension == 1 ) or ( dimension == 2 ) :
        added_canvas_descriptor . markersize = self . __default_2d_marker_size
    elif dimension == 3 :
        added_canvas_descriptor . markersize = self . __default_3d_marker_size
return len ( self . __canvas_clusters [ canvas ] ) - 1


signature:
def append_cluster_attribute ( self , index_canvas , index_cluster , data , marker = None , markersize = None ) :
    """@ brief Append cluster attribure for cluster on specific canvas .
 @ details Attribute it is data that is visualized for specific cluster using its color , marker and markersize if last two is not specified .
 @ param [ in ] index _ canvas ( uint ) : Index canvas where cluster is located .
 @ param [ in ] index _ cluster ( uint ) : Index cluster whose attribute should be added .
 @ param [ in ] data ( list ) : List of points ( data ) that represents attribute .
 @ param [ in ] marker ( string ) : Marker that is used for displaying objects from cluster on the canvas .
 @ param [ in ] markersize ( uint ) : Size of marker ."""

implementation:
cluster_descr = self . __canvas_clusters [ index_canvas ] [ index_cluster ]
attribute_marker = marker
if attribute_marker is None :
    attribute_marker = cluster_descr . marker
attribure_markersize = markersize
if attribure_markersize is None :
    attribure_markersize = cluster_descr . markersize
attribute_color = cluster_descr . color
added_attribute_cluster_descriptor = canvas_cluster_descr ( data , None , attribute_marker , attribure_markersize , attribute_color )
self . __canvas_clusters [ index_canvas ] [ index_cluster ] . attributes . append ( added_attribute_cluster_descriptor )


signature:
def set_canvas_title ( self , text , canvas = 0 ) :
    """@ brief Set title for specified canvas .
 @ param [ in ] text ( string ) : Title for canvas .
 @ param [ in ] canvas ( uint ) : Index of canvas where title should be displayed ."""

implementation:
if canvas > self . __number_canvases :
    raise NameError ( 'Canvas does ' + canvas + ' not exists.' )
self . __canvas_titles [ canvas ] = text


signature:
def show ( self , figure = None , invisible_axis = True , visible_grid = True , display = True , shift = None ) :
    """@ brief Shows clusters ( visualize ) .
 @ param [ in ] figure ( fig ) : Defines requirement to use specified figure , if None - new figure is created for drawing clusters .
 @ param [ in ] invisible _ axis ( bool ) : Defines visibility of axes on each canvas , if True - axes are invisible .
 @ param [ in ] visible _ grid ( bool ) : Defines visibility of grid on each canvas , if True - grid is displayed .
 @ param [ in ] display ( bool ) : Defines requirement to display clusters on a stage , if True - clusters are displayed ,
 if False - plt . show ( ) should be called by user . "
 @ param [ in ] shift ( uint ) : Force canvas shift value - defines canvas index from which custers should be visualized .
 @ return ( fig ) Figure where clusters are shown ."""

implementation:
canvas_shift = shift
if canvas_shift is None :
    if figure is not None :
        canvas_shift = len ( figure . get_axes ( ) )
    else :
        canvas_shift = 0
if figure is not None :
    cluster_figure = figure
else :
    cluster_figure = plt . figure ( )
maximum_cols = self . __size_row
maximum_rows = math . ceil ( ( self . __number_canvases + canvas_shift ) / maximum_cols )
grid_spec = gridspec . GridSpec ( maximum_rows , maximum_cols )
for index_canvas in range ( len ( self . __canvas_clusters ) ) :
    canvas_data = self . __canvas_clusters [ index_canvas ]
    if len ( canvas_data ) == 0 :
        continue
    dimension = self . __canvas_dimensions [ index_canvas ]
    # ax = axes [ real _ index ] ;
    if ( dimension == 1 ) or ( dimension == 2 ) :
        ax = cluster_figure . add_subplot ( grid_spec [ index_canvas + canvas_shift ] )
    else :
        ax = cluster_figure . add_subplot ( grid_spec [ index_canvas + canvas_shift ] , projection = '3d' )
    if len ( canvas_data ) == 0 :
        plt . setp ( ax , visible = False )
    for cluster_descr in canvas_data :
        self . __draw_canvas_cluster ( ax , dimension , cluster_descr )
        for attribute_descr in cluster_descr . attributes :
            self . __draw_canvas_cluster ( ax , dimension , attribute_descr )
    if invisible_axis is True :
        ax . xaxis . set_ticklabels ( [ ] )
        ax . yaxis . set_ticklabels ( [ ] )
        if ( dimension == 3 ) :
            ax . zaxis . set_ticklabels ( [ ] )
    if self . __canvas_titles [ index_canvas ] is not None :
        ax . set_title ( self . __canvas_titles [ index_canvas ] )
    ax . grid ( visible_grid )
if display is True :
    plt . show ( )
return cluster_figure


signature:
def __draw_canvas_cluster ( self , ax , dimension , cluster_descr ) :
    """@ brief Draw canvas cluster descriptor .
 @ param [ in ] ax ( Axis ) : Axis of the canvas where canvas cluster descriptor should be displayed .
 @ param [ in ] dimension ( uint ) : Canvas dimension .
 @ param [ in ] cluster _ descr ( canvas _ cluster _ descr ) : Canvas cluster descriptor that should be displayed .
 @ return ( fig ) Figure where clusters are shown ."""

implementation:
cluster = cluster_descr . cluster
data = cluster_descr . data
marker = cluster_descr . marker
markersize = cluster_descr . markersize
color = cluster_descr . color
for item in cluster :
    if dimension == 1 :
        if data is None :
            ax . plot ( item [ 0 ] , 0.0 , color = color , marker = marker , markersize = markersize )
        else :
            ax . plot ( data [ item ] [ 0 ] , 0.0 , color = color , marker = marker , markersize = markersize )
    elif dimension == 2 :
        if data is None :
            ax . plot ( item [ 0 ] , item [ 1 ] , color = color , marker = marker , markersize = markersize )
        else :
            ax . plot ( data [ item ] [ 0 ] , data [ item ] [ 1 ] , color = color , marker = marker , markersize = markersize )
    elif dimension == 3 :
        if data is None :
            ax . scatter ( item [ 0 ] , item [ 1 ] , item [ 2 ] , c = color , marker = marker , s = markersize )
        else :
            ax . scatter ( data [ item ] [ 0 ] , data [ item ] [ 1 ] , data [ item ] [ 2 ] , c = color , marker = marker , s = markersize )


signature:
def gaussian ( data , mean , covariance ) :
    """@ brief Calculates gaussian for dataset using specified mean ( mathematical expectation ) and variance or covariance in case
 multi - dimensional data .
 @ param [ in ] data ( list ) : Data that is used for gaussian calculation .
 @ param [ in ] mean ( float | numpy . array ) : Mathematical expectation used for calculation .
 @ param [ in ] covariance ( float | numpy . array ) : Variance or covariance matrix for calculation .
 @ return ( list ) Value of gaussian function for each point in dataset ."""

implementation:
dimension = float ( len ( data [ 0 ] ) )
if dimension != 1.0 :
    inv_variance = numpy . linalg . pinv ( covariance )
else :
    inv_variance = 1.0 / covariance
divider = ( pi * 2.0 ) ** ( dimension / 2.0 ) * numpy . sqrt ( numpy . linalg . norm ( covariance ) )
if divider != 0.0 :
    right_const = 1.0 / divider
else :
    right_const = float ( 'inf' )
result = [ ]
for point in data :
    mean_delta = point - mean
    point_gaussian = right_const * numpy . exp ( - 0.5 * mean_delta . dot ( inv_variance ) . dot ( numpy . transpose ( mean_delta ) ) )
    result . append ( point_gaussian )
return result


signature:
def initialize ( self , init_type = ema_init_type . KMEANS_INITIALIZATION ) :
    """@ brief Calculates initial parameters for EM algorithm : means and covariances using
 specified strategy .
 @ param [ in ] init _ type ( ema _ init _ type ) : Strategy for initialization .
 @ return ( float | list , float | numpy . array ) Initial means and variance ( covariance matrix in case multi - dimensional data ) ."""

implementation:
if init_type == ema_init_type . KMEANS_INITIALIZATION :
    return self . __initialize_kmeans ( )
elif init_type == ema_init_type . RANDOM_INITIALIZATION :
    return self . __initialize_random ( )
raise NameError ( "Unknown type of EM algorithm initialization is specified." )


signature:
def __calculate_initial_clusters ( self , centers ) :
    """@ brief Calculate Euclidean distance to each point from the each cluster .
 @ brief Nearest points are captured by according clusters and as a result clusters are updated .
 @ return ( list ) updated clusters as list of clusters . Each cluster contains indexes of objects from data ."""

implementation:
clusters = [ [ ] for _ in range ( len ( centers ) ) ]
for index_point in range ( len ( self . __sample ) ) :
    index_optim , dist_optim = - 1 , 0.0
    for index in range ( len ( centers ) ) :
        dist = euclidean_distance_square ( self . __sample [ index_point ] , centers [ index ] )
        if ( dist < dist_optim ) or ( index is 0 ) :
            index_optim , dist_optim = index , dist
    clusters [ index_optim ] . append ( index_point )
return clusters


signature:
def notify ( self , means , covariances , clusters ) :
    """@ brief This method is used by the algorithm to notify observer about changes where the algorithm
 should provide new values : means , covariances and allocated clusters .
 @ param [ in ] means ( list ) : Mean of each cluster on currect step .
 @ param [ in ] covariances ( list ) : Covariances of each cluster on current step .
 @ param [ in ] clusters ( list ) : Allocated cluster on current step ."""

implementation:
self . __means_evolution . append ( means )
self . __covariances_evolution . append ( covariances )
self . __clusters_evolution . append ( clusters )


signature:
def show_clusters ( clusters , sample , covariances , means , figure = None , display = True ) :
    """@ brief Draws clusters and in case of two - dimensional dataset draws their ellipses .
 @ param [ in ] clusters ( list ) : Clusters that were allocated by the algorithm .
 @ param [ in ] sample ( list ) : Dataset that were used for clustering .
 @ param [ in ] covariances ( list ) : Covariances of the clusters .
 @ param [ in ] means ( list ) : Means of the clusters .
 @ param [ in ] figure ( figure ) : If ' None ' then new is figure is creater , otherwise specified figure is used
 for visualization .
 @ param [ in ] display ( bool ) : If ' True ' then figure will be shown by the method , otherwise it should be
 shown manually using matplotlib function ' plt . show ( ) ' .
 @ return ( figure ) Figure where clusters were drawn ."""

implementation:
visualizer = cluster_visualizer ( )
visualizer . append_clusters ( clusters , sample )
if figure is None :
    figure = visualizer . show ( display = False )
else :
    visualizer . show ( figure = figure , display = False )
if len ( sample [ 0 ] ) == 2 :
    ema_visualizer . __draw_ellipses ( figure , visualizer , clusters , covariances , means )
if display is True :
    plt . show ( )
return figure


signature:
def animate_cluster_allocation ( data , observer , animation_velocity = 75 , movie_fps = 1 , save_movie = None ) :
    """@ brief Animates clustering process that is performed by EM algorithm .
 @ param [ in ] data ( list ) : Dataset that is used for clustering .
 @ param [ in ] observer ( ema _ observer ) : EM observer that was used for collection information about clustering process .
 @ param [ in ] animation _ velocity ( uint ) : Interval between frames in milliseconds ( for run - time animation only ) .
 @ param [ in ] movie _ fps ( uint ) : Defines frames per second ( for rendering movie only ) .
 @ param [ in ] save _ movie ( string ) : If it is specified then animation will be stored to file that is specified in this parameter ."""

implementation:
figure = plt . figure ( )
def init_frame ( ) :
    return frame_generation ( 0 )
def frame_generation ( index_iteration ) :
    figure . clf ( )
    figure . suptitle ( "EM algorithm (iteration: " + str ( index_iteration ) + ")" , fontsize = 18 , fontweight = 'bold' )
    clusters = observer . get_evolution_clusters ( ) [ index_iteration ]
    covariances = observer . get_evolution_covariances ( ) [ index_iteration ]
    means = observer . get_evolution_means ( ) [ index_iteration ]
    ema_visualizer . show_clusters ( clusters , data , covariances , means , figure , False )
    figure . subplots_adjust ( top = 0.85 )
    return [ figure . gca ( ) ]
iterations = len ( observer )
cluster_animation = animation . FuncAnimation ( figure , frame_generation , iterations , interval = animation_velocity , init_func = init_frame , repeat_delay = 5000 )
if save_movie is not None :
    cluster_animation . save ( save_movie , writer = 'ffmpeg' , fps = movie_fps , bitrate = 1500 )
else :
    plt . show ( )


signature:
def process ( self ) :
    """@ brief Run clustering process of the algorithm .
 @ details This method should be called before call ' get _ clusters ( ) ' ."""

implementation:
previous_likelihood = - 200000
current_likelihood = - 100000
current_iteration = 0
while ( self . __stop is False ) and ( abs ( previous_likelihood - current_likelihood ) > self . __tolerance ) and ( current_iteration < self . __iterations ) :
    self . __expectation_step ( )
    self . __maximization_step ( )
    current_iteration += 1
    self . __extract_clusters ( )
    self . __notify ( )
    previous_likelihood = current_likelihood
    current_likelihood = self . __log_likelihood ( )
    self . __stop = self . __get_stop_condition ( )
self . __normalize_probabilities ( )


signature:
def euclidean_distance_numpy ( object1 , object2 ) :
    """@ brief Calculate Euclidean distance between two objects using numpy .
 @ param [ in ] object1 ( array _ like ) : The first array _ like object .
 @ param [ in ] object2 ( array _ like ) : The second array _ like object .
 @ return ( double ) Euclidean distance between two objects ."""

implementation: return numpy . sum ( numpy . sqrt ( numpy . square ( object1 - object2 ) ) , axis = 1 ) . T


signature:
def euclidean_distance_square ( point1 , point2 ) :
    """@ brief Calculate square Euclidean distance between two vectors .
 dist ( a , b ) = \ sum _ { i = 0 } ^ { N } ( a _ { i } - b _ { i } ) ^ { 2 } ;
 @ param [ in ] point1 ( array _ like ) : The first vector .
 @ param [ in ] point2 ( array _ like ) : The second vector .
 @ return ( double ) Square Euclidean distance between two vectors .
 @ see euclidean _ distance , manhattan _ distance , chebyshev _ distance"""

implementation:
distance = 0.0
for i in range ( len ( point1 ) ) :
    distance += ( point1 [ i ] - point2 [ i ] ) ** 2.0
return distance


signature:
def euclidean_distance_square_numpy ( object1 , object2 ) :
    """@ brief Calculate square Euclidean distance between two objects using numpy .
 @ param [ in ] object1 ( array _ like ) : The first array _ like object .
 @ param [ in ] object2 ( array _ like ) : The second array _ like object .
 @ return ( double ) Square Euclidean distance between two objects ."""

implementation: return numpy . sum ( numpy . square ( object1 - object2 ) , axis = 1 ) . T


signature:
def manhattan_distance ( point1 , point2 ) :
    """@ brief Calculate Manhattan distance between between two vectors .
 dist ( a , b ) = \ sum _ { i = 0 } ^ { N } \ left | a _ { i } - b _ { i } \r ight | ;
 @ param [ in ] point1 ( array _ like ) : The first vector .
 @ param [ in ] point2 ( array _ like ) : The second vector .
 @ return ( double ) Manhattan distance between two vectors .
 @ see euclidean _ distance _ square , euclidean _ distance , chebyshev _ distance"""

implementation:
distance = 0.0
dimension = len ( point1 )
for i in range ( dimension ) :
    distance += abs ( point1 [ i ] - point2 [ i ] )
return distance


signature:
def manhattan_distance_numpy ( object1 , object2 ) :
    """@ brief Calculate Manhattan distance between two objects using numpy .
 @ param [ in ] object1 ( array _ like ) : The first array _ like object .
 @ param [ in ] object2 ( array _ like ) : The second array _ like object .
 @ return ( double ) Manhattan distance between two objects ."""

implementation: return numpy . sum ( numpy . absolute ( object1 - object2 ) , axis = 1 ) . T


signature:
def chebyshev_distance ( point1 , point2 ) :
    """@ brief Calculate Chebyshev distance between between two vectors .
 dist ( a , b ) = \ max _ { } i \ left ( \ left | a _ { i } - b _ { i } \r ight | \r ight ) ;
 @ param [ in ] point1 ( array _ like ) : The first vector .
 @ param [ in ] point2 ( array _ like ) : The second vector .
 @ return ( double ) Chebyshev distance between two vectors .
 @ see euclidean _ distance _ square , euclidean _ distance , minkowski _ distance"""

implementation:
distance = 0.0
dimension = len ( point1 )
for i in range ( dimension ) :
    distance = max ( distance , abs ( point1 [ i ] - point2 [ i ] ) )
return distance


signature:
def chebyshev_distance_numpy ( object1 , object2 ) :
    """@ brief Calculate Chebyshev distance between two objects using numpy .
 @ param [ in ] object1 ( array _ like ) : The first array _ like object .
 @ param [ in ] object2 ( array _ like ) : The second array _ like object .
 @ return ( double ) Chebyshev distance between two objects ."""

implementation: return numpy . max ( numpy . absolute ( object1 - object2 ) , axis = 1 ) . T


signature:
def minkowski_distance ( point1 , point2 , degree = 2 ) :
    """@ brief Calculate Minkowski distance between two vectors .
 dist ( a , b ) = \ sqrt [ p ] { \ sum _ { i = 0 } ^ { N } \ left ( a _ { i } - b _ { i } \r ight ) ^ { p } } ;
 @ param [ in ] point1 ( array _ like ) : The first vector .
 @ param [ in ] point2 ( array _ like ) : The second vector .
 @ param [ in ] degree ( numeric ) : Degree of that is used for Minkowski distance .
 @ return ( double ) Minkowski distance between two vectors .
 @ see euclidean _ distance"""

implementation:
distance = 0.0
for i in range ( len ( point1 ) ) :
    distance += ( point1 [ i ] - point2 [ i ] ) ** degree
return distance ** ( 1.0 / degree )


signature:
def minkowski_distance_numpy ( object1 , object2 , degree = 2 ) :
    """@ brief Calculate Minkowski distance between objects using numpy .
 @ param [ in ] object1 ( array _ like ) : The first array _ like object .
 @ param [ in ] object2 ( array _ like ) : The second array _ like object .
 @ param [ in ] degree ( numeric ) : Degree of that is used for Minkowski distance .
 @ return ( double ) Minkowski distance between two object ."""

implementation: return numpy . sum ( numpy . power ( numpy . power ( object1 - object2 , degree ) , 1 / degree ) , axis = 1 ) . T


signature:
def canberra_distance_numpy ( object1 , object2 ) :
    """@ brief Calculate Canberra distance between two objects using numpy .
 @ param [ in ] object1 ( array _ like ) : The first vector .
 @ param [ in ] object2 ( array _ like ) : The second vector .
 @ return ( float ) Canberra distance between two objects ."""

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


signature:
def chi_square_distance ( point1 , point2 ) :
    """@ brief Calculate Chi square distance between two vectors .
 dist ( a , b ) = \ sum _ { i = 0 } ^ { N } \f rac { \ left ( a _ { i } - b _ { i } \r ight ) ^ { 2 } } { \ left | a _ { i } \r ight | + \ left | b _ { i } \r ight | } ;
 @ param [ in ] point1 ( array _ like ) : The first vector .
 @ param [ in ] point2 ( array _ like ) : The second vector .
 @ return ( float ) Chi square distance between two objects ."""

implementation:
distance = 0.0
for i in range ( len ( point1 ) ) :
    divider = abs ( point1 [ i ] ) + abs ( point2 [ i ] )
    if divider == 0.0 :
        continue
    distance += ( ( point1 [ i ] - point2 [ i ] ) ** 2.0 ) / divider
return distance


signature:
def enable_numpy_usage ( self ) :
    """@ brief Start numpy for distance calculation .
 @ details Useful in case matrices to increase performance . No effect in case of type _ metric . USER _ DEFINED type ."""

implementation:
self . __numpy = True
if self . __type != type_metric . USER_DEFINED :
    self . __calculator = self . __create_distance_calculator ( )


signature:
def __create_distance_calculator_basic ( self ) :
    """@ brief Creates distance metric calculator that does not use numpy .
 @ return ( callable ) Callable object of distance metric calculator ."""

implementation:
if self . __type == type_metric . EUCLIDEAN :
    return euclidean_distance
elif self . __type == type_metric . EUCLIDEAN_SQUARE :
    return euclidean_distance_square
elif self . __type == type_metric . MANHATTAN :
    return manhattan_distance
elif self . __type == type_metric . CHEBYSHEV :
    return chebyshev_distance
elif self . __type == type_metric . MINKOWSKI :
    return lambda point1 , point2 : minkowski_distance ( point1 , point2 , self . __args . get ( 'degree' , 2 ) )
elif self . __type == type_metric . CANBERRA :
    return canberra_distance
elif self . __type == type_metric . CHI_SQUARE :
    return chi_square_distance
elif self . __type == type_metric . USER_DEFINED :
    return self . __func
else :
    raise ValueError ( "Unknown type of metric: '%d'" , self . __type )


signature:
def __create_distance_calculator_numpy ( self ) :
    """@ brief Creates distance metric calculator that uses numpy .
 @ return ( callable ) Callable object of distance metric calculator ."""

implementation:
if self . __type == type_metric . EUCLIDEAN :
    return euclidean_distance_numpy
elif self . __type == type_metric . EUCLIDEAN_SQUARE :
    return euclidean_distance_square_numpy
elif self . __type == type_metric . MANHATTAN :
    return manhattan_distance_numpy
elif self . __type == type_metric . CHEBYSHEV :
    return chebyshev_distance_numpy
elif self . __type == type_metric . MINKOWSKI :
    return lambda object1 , object2 : minkowski_distance_numpy ( object1 , object2 , self . __args . get ( 'degree' , 2 ) )
elif self . __type == type_metric . CANBERRA :
    return canberra_distance_numpy
elif self . __type == type_metric . CHI_SQUARE :
    return chi_square_distance_numpy
elif self . __type == type_metric . USER_DEFINED :
    return self . __func
else :
    raise ValueError ( "Unknown type of metric: '%d'" , self . __type )


signature:
def extract_number_oscillations ( self , index , amplitude_threshold ) :
    """@ brief Extracts number of oscillations of specified oscillator .
 @ param [ in ] index ( uint ) : Index of oscillator whose dynamic is considered .
 @ param [ in ] amplitude _ threshold ( double ) : Amplitude threshold when oscillation is taken into account , for example ,
 when oscillator amplitude is greater than threshold then oscillation is incremented .
 @ return ( uint ) Number of oscillations of specified oscillator ."""

implementation: return pyclustering . utils . extract_number_oscillations ( self . __amplitude , index , amplitude_threshold ) ;


signature:
def show_output_dynamic ( fsync_output_dynamic ) :
    """@ brief Shows output dynamic ( output of each oscillator ) during simulation .
 @ param [ in ] fsync _ output _ dynamic ( fsync _ dynamic ) : Output dynamic of the fSync network .
 @ see show _ output _ dynamics"""

implementation: pyclustering . utils . draw_dynamics ( fsync_output_dynamic . time , fsync_output_dynamic . output , x_title = "t" , y_title = "amplitude" ) ;


signature:
def simulate ( self , steps , time , collect_dynamic = False ) :
    """@ brief Performs static simulation of oscillatory network .
 @ param [ in ] steps ( uint ) : Number simulation steps .
 @ param [ in ] time ( double ) : Time of simulation .
 @ param [ in ] collect _ dynamic ( bool ) : If True - returns whole dynamic of oscillatory network , otherwise returns only last values of dynamics .
 @ return ( list ) Dynamic of oscillatory network . If argument ' collect _ dynamic ' is True , than return dynamic for the whole simulation time ,
 otherwise returns only last values ( last step of simulation ) of output dynamic .
 @ see simulate ( )
 @ see simulate _ dynamic ( )"""

implementation:
dynamic_amplitude , dynamic_time = ( [ ] , [ ] ) if collect_dynamic is False else ( [ self . __amplitude ] , [ 0 ] ) ;
step = time / steps ;
int_step = step / 10.0 ;
for t in numpy . arange ( step , time + step , step ) :
    self . __amplitude = self . __calculate ( t , step , int_step ) ;
    if collect_dynamic is True :
        dynamic_amplitude . append ( [ numpy . real ( amplitude ) [ 0 ] for amplitude in self . __amplitude ] ) ;
        dynamic_time . append ( t ) ;
if collect_dynamic is False :
    dynamic_amplitude . append ( [ numpy . real ( amplitude ) [ 0 ] for amplitude in self . __amplitude ] ) ;
    dynamic_time . append ( time ) ;
output_sync_dynamic = fsync_dynamic ( dynamic_amplitude , dynamic_time ) ;
return output_sync_dynamic ;


signature:
def __calculate ( self , t , step , int_step ) :
    """@ brief Calculates new amplitudes for oscillators in the network in line with current step .
 @ param [ in ] t ( double ) : Time of simulation .
 @ param [ in ] step ( double ) : Step of solution at the end of which states of oscillators should be calculated .
 @ param [ in ] int _ step ( double ) : Step differentiation that is used for solving differential equation .
 @ return ( list ) New states ( phases ) for oscillators ."""

implementation:
next_amplitudes = [ 0.0 ] * self . _num_osc ;
for index in range ( 0 , self . _num_osc , 1 ) :
    z = numpy . array ( self . __amplitude [ index ] , dtype = numpy . complex128 , ndmin = 1 ) ;
    result = odeint ( self . __calculate_amplitude , z . view ( numpy . float64 ) , numpy . arange ( t - step , t , int_step ) , ( index , ) ) ;
    next_amplitudes [ index ] = ( result [ len ( result ) - 1 ] ) . view ( numpy . complex128 ) ;
return next_amplitudes ;


signature:
def __oscillator_property ( self , index ) :
    """@ brief Calculate Landau - Stuart oscillator constant property that is based on frequency and radius .
 @ param [ in ] index ( uint ) : Oscillator index whose property is calculated .
 @ return ( double ) Oscillator property ."""

implementation: return numpy . array ( 1j * self . __frequency [ index ] + self . __radius [ index ] ** 2 , dtype = numpy . complex128 , ndmin = 1 ) ;


signature:
def __landau_stuart ( self , amplitude , index ) :
    """@ brief Calculate Landau - Stuart state .
 @ param [ in ] amplitude ( double ) : Current amplitude of oscillator .
 @ param [ in ] index ( uint ) : Oscillator index whose state is calculated .
 @ return ( double ) Landau - Stuart state ."""

implementation: return ( self . __properties [ index ] - numpy . absolute ( amplitude ) ** 2 ) * amplitude ;


signature:
def __synchronization_mechanism ( self , amplitude , index ) :
    """@ brief Calculate synchronization part using Kuramoto synchronization mechanism .
 @ param [ in ] amplitude ( double ) : Current amplitude of oscillator .
 @ param [ in ] index ( uint ) : Oscillator index whose synchronization influence is calculated .
 @ return ( double ) Synchronization influence for the specified oscillator ."""

implementation:
sync_influence = 0.0 ;
for k in range ( self . _num_osc ) :
    if self . has_connection ( index , k ) is True :
        amplitude_neighbor = numpy . array ( self . __amplitude [ k ] , dtype = numpy . complex128 , ndmin = 1 ) ;
        sync_influence += amplitude_neighbor - amplitude ;
return sync_influence * self . __coupling_strength / self . _num_osc ;


signature:
def __calculate_amplitude ( self , amplitude , t , argv ) :
    """@ brief Returns new amplitude value for particular oscillator that is defined by index that is in ' argv ' argument .
 @ details The method is used for differential calculation .
 @ param [ in ] amplitude ( double ) : Current amplitude of oscillator .
 @ param [ in ] t ( double ) : Current time of simulation .
 @ param [ in ] argv ( uint ) : Index of the current oscillator .
 @ return ( double ) New amplitude of the oscillator ."""

implementation:
z = amplitude . view ( numpy . complex ) ;
dzdt = self . __landau_stuart ( z , argv ) + self . __synchronization_mechanism ( z , argv ) ;
return dzdt . view ( numpy . float64 ) ;