signature:
def animate_cluster_allocation ( data , observer , animation_velocity = 500 , movie_fps = 1 , save_movie = None ) :
    """@ brief Animates clustering process that is performed by K - Means algorithm .
 @ param [ in ] data ( list ) : Dataset that is used for clustering .
 @ param [ in ] observer ( kmeans _ 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 ( "K-Means algorithm (iteration: " + str ( index_iteration ) + ")" , fontsize = 18 , fontweight = 'bold' )
    clusters = observer . get_clusters ( index_iteration )
    centers = observer . get_centers ( index_iteration )
    kmeans_visualizer . show_clusters ( data , clusters , centers , None , figure = figure , display = 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 = 3000 )
else :
    plt . show ( )


signature:
def process ( self ) :
    """@ brief Performs cluster analysis in line with rules of K - Means algorithm .
 @ return ( kmeans ) Returns itself ( K - Means instance ) .
 @ remark Results of clustering can be obtained using corresponding get methods .
 @ see get _ clusters ( )
 @ see get _ centers ( )"""

implementation:
if len ( self . __pointer_data [ 0 ] ) != len ( self . __centers [ 0 ] ) :
    raise ValueError ( "Dimension of the input data and dimension of the initial cluster centers must be equal." )
if self . __ccore is True :
    self . __process_by_ccore ( )
else :
    self . __process_by_python ( )
return self


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

implementation:
ccore_metric = metric_wrapper . create_instance ( self . __metric )
results = wrapper . kmeans ( self . __pointer_data , self . __centers , self . __tolerance , self . __itermax , ( self . __observer is not None ) , ccore_metric . get_pointer ( ) )
self . __clusters = results [ 0 ]
self . __centers = results [ 1 ]
if self . __observer is not None :
    self . __observer . set_evolution_clusters ( results [ 2 ] )
    self . __observer . set_evolution_centers ( results [ 3 ] )
self . __total_wce = results [ 4 ] [ 0 ]


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

implementation:
maximum_change = float ( 'inf' )
iteration = 0
if self . __observer is not None :
    initial_clusters = self . __update_clusters ( )
    self . __observer . notify ( initial_clusters , self . __centers . tolist ( ) )
while maximum_change > self . __tolerance and iteration < self . __itermax :
    self . __clusters = self . __update_clusters ( )
    updated_centers = self . __update_centers ( )
    # changes should be calculated before assignment
    if self . __observer is not None :
        self . __observer . notify ( self . __clusters , updated_centers . tolist ( ) )
    maximum_change = self . __calculate_changes ( updated_centers )
    self . __centers = updated_centers
    # assign center after change calculation
    iteration += 1
self . __calculate_total_wce ( )


signature:
def get_centers ( self ) :
    """@ brief Returns list of centers of allocated clusters .
 @ see process ( )
 @ see get _ clusters ( )"""

implementation:
if isinstance ( self . __centers , list ) :
    return self . __centers
return self . __centers . tolist ( )


signature:
def __update_clusters ( self ) :
    """@ brief Calculate distance ( in line with specified metric ) to each point from the each cluster . 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 ( self . __centers ) ) ]
dataset_differences = self . __calculate_dataset_difference ( len ( clusters ) )
optimum_indexes = numpy . argmin ( dataset_differences , axis = 0 )
for index_point in range ( len ( optimum_indexes ) ) :
    index_cluster = optimum_indexes [ index_point ]
    clusters [ index_cluster ] . append ( index_point )
clusters = [ cluster for cluster in clusters if len ( cluster ) > 0 ]
return clusters


signature:
def __update_centers ( self ) :
    """@ brief Calculate centers of clusters in line with contained objects .
 @ return ( numpy . array ) Updated centers ."""

implementation:
dimension = self . __pointer_data . shape [ 1 ]
centers = numpy . zeros ( ( len ( self . __clusters ) , dimension ) )
for index in range ( len ( self . __clusters ) ) :
    cluster_points = self . __pointer_data [ self . __clusters [ index ] , : ]
    centers [ index ] = cluster_points . mean ( axis = 0 )
return numpy . array ( centers )


signature:
def __calculate_total_wce ( self ) :
    """@ brief Calculate total within cluster errors that is depend on metric that was chosen for K - Means algorithm ."""

implementation:
dataset_differences = self . __calculate_dataset_difference ( len ( self . __clusters ) )
self . __total_wce = 0
for index_cluster in range ( len ( self . __clusters ) ) :
    for index_point in self . __clusters [ index_cluster ] :
        self . __total_wce += dataset_differences [ index_cluster ] [ index_point ]


signature:
def __calculate_dataset_difference ( self , amount_clusters ) :
    """@ brief Calculate distance from each point to each cluster center ."""

implementation:
dataset_differences = numpy . zeros ( ( amount_clusters , len ( self . __pointer_data ) ) )
for index_center in range ( amount_clusters ) :
    if self . __metric . get_type ( ) != type_metric . USER_DEFINED :
        dataset_differences [ index_center ] = self . __metric ( self . __pointer_data , self . __centers [ index_center ] )
    else :
        dataset_differences [ index_center ] = [ self . __metric ( point , self . __centers [ index_center ] ) for point in self . __pointer_data ]
return dataset_differences


signature:
def __calculate_changes ( self , updated_centers ) :
    """@ brief Calculates changes estimation between previous and current iteration using centers for that purpose .
 @ param [ in ] updated _ centers ( array _ like ) : New cluster centers .
 @ return ( float ) Maximum changes between centers ."""

implementation:
if len ( self . __centers ) != len ( updated_centers ) :
    maximum_change = float ( 'inf' )
else :
    changes = self . __metric ( self . __centers , updated_centers )
    maximum_change = numpy . max ( changes )
return maximum_change


signature:
def initialize ( self , ** kwargs ) :
    """@ brief Generates random centers in line with input parameters .
 @ param [ in ] * * kwargs : Arbitrary keyword arguments ( available arguments : ' return _ index ' ) .
 < b > Keyword Args : < / b > < br >
 - return _ index ( bool ) : If True then returns indexes of points from input data instead of points itself .
 @ return ( list ) List of initialized initial centers .
 If argument ' return _ index ' is False then returns list of points .
 If argument ' return _ index ' is True then returns list of indexes ."""

implementation:
return_index = kwargs . get ( 'return_index' , False )
if self . __amount == len ( self . __data ) :
    if return_index :
        return list ( range ( len ( self . __data ) ) )
    return self . __data [ : ]
return [ self . __create_center ( return_index ) for _ in range ( self . __amount ) ]


signature:
def __create_center ( self , return_index ) :
    """@ brief Generates and returns random center .
 @ param [ in ] return _ index ( bool ) : If True then returns index of point from input data instead of point itself ."""

implementation:
random_index_point = random . randint ( 0 , len ( self . __data [ 0 ] ) )
if random_index_point not in self . __available_indexes :
    random_index_point = self . __available_indexes . pop ( )
else :
    self . __available_indexes . remove ( random_index_point )
if return_index :
    return random_index_point
return self . __data [ random_index_point ]


signature:
def __check_parameters ( self ) :
    """@ brief Checks input parameters of the algorithm and if something wrong then corresponding exception is thrown ."""

implementation:
if ( self . __amount <= 0 ) or ( self . __amount > len ( self . __data ) ) :
    raise AttributeError ( "Amount of cluster centers '" + str ( self . __amount ) + "' should be at least 1 and " "should be less or equal to amount of points in data." )
if self . __candidates != kmeans_plusplus_initializer . FARTHEST_CENTER_CANDIDATE :
    if ( self . __candidates <= 0 ) or ( self . __candidates > len ( self . __data ) ) :
        raise AttributeError ( "Amount of center candidates '" + str ( self . __candidates ) + "' should be at least 1 " "and should be less or equal to amount of points in data." )
if len ( self . __data ) == 0 :
    raise AttributeError ( "Data is empty." )


signature:
def __get_next_center ( self , centers , return_index ) :
    """@ brief Calculates the next center for the data .
 @ param [ in ] centers ( array _ like ) : Current initialized centers .
 @ param [ in ] return _ index ( bool ) : If True then return center ' s index instead of point .
 @ return ( array _ like ) Next initialized center . < br >
 ( uint ) Index of next initialized center if return _ index is True ."""

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


signature:
def __get_initial_center ( self , return_index ) :
    """@ brief Choose randomly first center .
 @ param [ in ] return _ index ( bool ) : If True then return center ' s index instead of point .
 @ return ( array _ like ) First center . < br >
 ( uint ) Index of first center ."""

implementation:
index_center = random . randint ( 0 , len ( self . __data ) - 1 )
if return_index :
    return index_center
return self . __data [ index_center ]


signature:
def __calculate_probabilities ( self , distances ) :
    """@ brief Calculates cumulative probabilities of being center of each point .
 @ param [ in ] distances ( array _ like ) : Distances from each point to closest center .
 @ return ( array _ like ) Cumulative probabilities of being center of each point ."""

implementation:
total_distance = numpy . sum ( distances )
if total_distance != 0.0 :
    probabilities = distances / total_distance
    return numpy . cumsum ( probabilities )
else :
    return numpy . zeros ( len ( distances ) )


signature:
def __get_probable_center ( self , distances , probabilities ) :
    """@ brief Calculates the next probable center considering amount candidates .
 @ param [ in ] distances ( array _ like ) : Distances from each point to closest center .
 @ param [ in ] probabilities ( array _ like ) : Cumulative probabilities of being center of each point .
 @ return ( uint ) Index point that is next initialized center ."""

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


signature:
def initialize ( self , ** kwargs ) :
    """@ brief Calculates initial centers using K - Means + + method .
 @ param [ in ] * * kwargs : Arbitrary keyword arguments ( available arguments : ' return _ index ' ) .
 < b > Keyword Args : < / b > < br >
 - return _ index ( bool ) : If True then returns indexes of points from input data instead of points itself .
 @ return ( list ) List of initialized initial centers .
 If argument ' return _ index ' is False then returns list of points .
 If argument ' return _ index ' is True then returns list of indexes ."""

implementation:
return_index = kwargs . get ( 'return_index' , False )
index_point = self . __get_initial_center ( True )
centers = [ index_point ]
self . __free_indexes . remove ( index_point )
# For each next center
for _ in range ( 1 , self . __amount ) :
    index_point = self . __get_next_center ( centers , True )
    centers . append ( index_point )
    self . __free_indexes . remove ( index_point )
if not return_index :
    centers = [ self . __data [ index ] for index in centers ]
return centers


signature:
def hundred_neurons_mix_stimulated ( ) :
    "Allocate several clusters : the first contains borders ( indexes of oscillators ) and the second objects ( indexes of oscillators )"


signature:
def __get_canonical_separate ( self , input_separate ) :
    """@ brief Return unified representation of separation value .
 @ details It represents list whose size is equal to amount of dynamics , where index of dynamic will show
 where it should be displayed .
 @ param [ in ] input _ separate ( bool | list ) : Input separate representation that should transformed .
 @ return ( list ) Indexes where each dynamic should be displayed ."""

implementation:
if ( isinstance ( input_separate , list ) ) :
    separate = [ 0 ] * len ( self . dynamics [ 0 ] ) ;
    for canvas_index in range ( len ( input_separate ) ) :
        dynamic_indexes = input_separate [ canvas_index ] ;
        for dynamic_index in dynamic_indexes :
            separate [ dynamic_index ] = canvas_index ;
    return separate ;
elif ( input_separate is False ) :
    if ( isinstance ( self . dynamics [ 0 ] , list ) is True ) :
        return [ self . canvas ] * len ( self . dynamics [ 0 ] ) ;
    else :
        return [ self . canvas ] ;
elif ( input_separate is True ) :
    if ( isinstance ( self . dynamics [ 0 ] , list ) is True ) :
        return range ( self . canvas , self . canvas + len ( self . dynamics [ 0 ] ) ) ;
    else :
        return [ self . canvas ] ;
else :
    raise Exception ( "Incorrect type of argument 'separate' '%s'." % type ( input_separate ) ) ;


signature:
def set_canvas_properties ( self , canvas , x_title = None , y_title = None , x_lim = None , y_lim = None , x_labels = True , y_labels = True ) :
    """@ brief Set properties for specified canvas .
 @ param [ in ] canvas ( uint ) : Index of canvas whose properties should changed .
 @ param [ in ] x _ title ( string ) : Title for X axis , if ' None ' , then nothing is displayed .
 @ param [ in ] y _ title ( string ) : Title for Y axis , if ' None ' , then nothing is displayed .
 @ param [ in ] x _ lim ( list ) : Defines borders of X axis like [ from , to ] , for example [ 0 , 3.14 ] , if ' None ' then
 borders are calculated automatically .
 @ param [ in ] y _ lim ( list ) : Defines borders of Y axis like [ from , to ] , if ' None ' then borders are calculated
 automatically .
 @ param [ in ] x _ labels ( bool ) : If True then labels of X axis are displayed .
 @ param [ in ] y _ labels ( bool ) : If True then labels of Y axis are displayed ."""

implementation: self . __canvases [ canvas ] = canvas_descr ( x_title , y_title , x_lim , y_lim , x_labels , y_labels ) ;


signature:
def append_dynamic ( self , t , dynamic , canvas = 0 , color = 'blue' ) :
    """@ brief Append single dynamic to specified canvas ( by default to the first with index ' 0 ' ) .
 @ param [ in ] t ( list ) : Time points that corresponds to dynamic values and considered on a X axis .
 @ param [ in ] dynamic ( list ) : Value points of dynamic that are considered on an Y axis .
 @ param [ in ] canvas ( uint ) : Canvas where dynamic should be displayed .
 @ param [ in ] color ( string ) : Color that is used for drawing dynamic on the canvas ."""

implementation:
description = dynamic_descr ( canvas , t , dynamic , False , color ) ;
self . __dynamic_storage . append ( description ) ;
self . __update_canvas_xlim ( description . time , description . separate ) ;


signature:
def append_dynamics ( self , t , dynamics , canvas = 0 , separate = False , color = 'blue' ) :
    """@ brief Append several dynamics to canvas or canvases ( defined by ' canvas ' and ' separate ' arguments ) .
 @ param [ in ] t ( list ) : Time points that corresponds to dynamic values and considered on a X axis .
 @ param [ in ] dynamics ( list ) : Dynamics where each of them is considered on Y axis .
 @ param [ in ] canvas ( uint ) : Index of canvas where dynamic should be displayed , in case of ' separate '
 representation this argument is considered as a first canvas from that displaying should be done .
 @ param [ in ] separate ( bool | list ) : If ' True ' then each dynamic is displayed on separate canvas , if it is defined
 by list , for example , [ [ 1 , 2 ] , [ 3 , 4 ] ] , then the first and the second dynamics are displayed on
 the canvas with index ' canvas ' and the third and forth are displayed on the next ' canvas + 1'
 canvas .
 @ param [ in ] color ( string ) : Color that is used to display output dynamic ( s ) ."""

implementation:
description = dynamic_descr ( canvas , t , dynamics , separate , color ) ;
self . __dynamic_storage . append ( description ) ;
self . __update_canvas_xlim ( description . time , description . separate ) ;


signature:
def show ( self , axis = None , display = True ) :
    """@ brief Draw and show output dynamics .
 @ param [ in ] axis ( axis ) : If is not ' None ' then user specified axis is used to display output dynamic .
 @ param [ in ] display ( bool ) : Whether output dynamic should be displayed or not , if not , then user
 should call ' plt . show ( ) ' by himself ."""

implementation:
if ( not axis ) :
    ( _ , axis ) = plt . subplots ( self . __size , 1 ) ;
self . __format_canvases ( axis ) ;
for dynamic in self . __dynamic_storage :
    self . __display_dynamic ( axis , dynamic ) ;
if ( display ) :
    plt . show ( ) ;


signature:
def output ( self ) :
    """@ brief ( list ) Returns oscillato outputs during simulation ."""

implementation:
if self . __ccore_pcnn_dynamic_pointer is not None :
    return wrapper . pcnn_dynamic_get_output ( self . __ccore_pcnn_dynamic_pointer )
return self . __dynamic


signature:
def time ( self ) :
    """@ brief ( list ) Returns sampling times when dynamic is measured during simulation ."""

implementation:
if self . __ccore_pcnn_dynamic_pointer is not None :
    return wrapper . pcnn_dynamic_get_time ( self . __ccore_pcnn_dynamic_pointer )
return list ( range ( len ( self ) ) )


signature:
def allocate_sync_ensembles ( self ) :
    """@ brief Allocate clusters in line with ensembles of synchronous oscillators where each
 synchronous ensemble corresponds to only one cluster .
 @ return ( list ) Grours ( lists ) of indexes of synchronous oscillators .
 For example , [ [ index _ osc1 , index _ osc3 ] , [ index _ osc2 ] , [ index _ osc4 , index _ osc5 ] ] ."""

implementation:
if self . __ccore_pcnn_dynamic_pointer is not None :
    return wrapper . pcnn_dynamic_allocate_sync_ensembles ( self . __ccore_pcnn_dynamic_pointer )
sync_ensembles = [ ]
traverse_oscillators = set ( )
number_oscillators = len ( self . __dynamic [ 0 ] )
for t in range ( len ( self . __dynamic ) - 1 , 0 , - 1 ) :
    sync_ensemble = [ ]
    for i in range ( number_oscillators ) :
        if self . __dynamic [ t ] [ i ] == self . __OUTPUT_TRUE :
            if i not in traverse_oscillators :
                sync_ensemble . append ( i )
                traverse_oscillators . add ( i )
    if sync_ensemble != [ ] :
        sync_ensembles . append ( sync_ensemble )
return sync_ensembles


signature:
def allocate_spike_ensembles ( self ) :
    """@ brief Analyses output dynamic of network and allocates spikes on each iteration as a list of indexes of oscillators .
 @ details Each allocated spike ensemble represents list of indexes of oscillators whose output is active .
 @ return ( list ) Spike ensembles of oscillators ."""

implementation:
if self . __ccore_pcnn_dynamic_pointer is not None :
    return wrapper . pcnn_dynamic_allocate_spike_ensembles ( self . __ccore_pcnn_dynamic_pointer )
spike_ensembles = [ ]
number_oscillators = len ( self . __dynamic [ 0 ] )
for t in range ( len ( self . __dynamic ) ) :
    spike_ensemble = [ ]
    for index in range ( number_oscillators ) :
        if self . __dynamic [ t ] [ index ] == self . __OUTPUT_TRUE :
            spike_ensemble . append ( index )
    if len ( spike_ensemble ) > 0 :
        spike_ensembles . append ( spike_ensemble )
return spike_ensembles


signature:
def allocate_time_signal ( self ) :
    """@ brief Analyses output dynamic and calculates time signal ( signal vector information ) of network output .
 @ return ( list ) Time signal of network output ."""

implementation:
if self . __ccore_pcnn_dynamic_pointer is not None :
    return wrapper . pcnn_dynamic_allocate_time_signal ( self . __ccore_pcnn_dynamic_pointer )
signal_vector_information = [ ]
for t in range ( 0 , len ( self . __dynamic ) ) :
    signal_vector_information . append ( sum ( self . __dynamic [ t ] ) )
return signal_vector_information


signature:
def show_time_signal ( pcnn_output_dynamic ) :
    """@ brief Shows time signal ( signal vector information ) using network dynamic during simulation .
 @ param [ in ] pcnn _ output _ dynamic ( pcnn _ dynamic ) : Output dynamic of the pulse - coupled neural network ."""

implementation:
time_signal = pcnn_output_dynamic . allocate_time_signal ( )
time_axis = range ( len ( time_signal ) )
plt . subplot ( 1 , 1 , 1 )
plt . plot ( time_axis , time_signal , '-' )
plt . ylabel ( "G (time signal)" )
plt . xlabel ( "t (iteration)" )
plt . grid ( True )
plt . show ( )


signature:
def show_output_dynamic ( pcnn_output_dynamic , separate_representation = False ) :
    """@ brief Shows output dynamic ( output of each oscillator ) during simulation .
 @ param [ in ] pcnn _ output _ dynamic ( pcnn _ dynamic ) : Output dynamic of the pulse - coupled neural network .
 @ param [ in ] separate _ representation ( list ) : Consists of lists of oscillators where each such list consists of oscillator indexes that will be shown on separated stage ."""

implementation: draw_dynamics ( pcnn_output_dynamic . time , pcnn_output_dynamic . output , x_title = "t" , y_title = "y(t)" , separate = separate_representation )


signature:
def animate_spike_ensembles ( pcnn_output_dynamic , image_size ) :
    """@ brief Shows animation of output dynamic ( output of each oscillator ) during simulation .
 @ param [ in ] pcnn _ output _ dynamic ( pcnn _ dynamic ) : Output dynamic of the pulse - coupled neural network .
 @ param [ in ] image _ size ( tuple ) : Image size represented as ( height , width ) ."""

implementation:
figure = plt . figure ( )
time_signal = pcnn_output_dynamic . allocate_time_signal ( )
spike_ensembles = pcnn_output_dynamic . allocate_spike_ensembles ( )
spike_animation = [ ]
ensemble_index = 0
for t in range ( len ( time_signal ) ) :
    image_color_segments = [ ( 255 , 255 , 255 ) ] * ( image_size [ 0 ] * image_size [ 1 ] )
    if time_signal [ t ] > 0 :
        for index_pixel in spike_ensembles [ ensemble_index ] :
            image_color_segments [ index_pixel ] = ( 0 , 0 , 0 )
        ensemble_index += 1
    stage = numpy . array ( image_color_segments , numpy . uint8 )
    stage = numpy . reshape ( stage , image_size + ( ( 3 ) , ) )
    # ( ( 3 ) , ) it ' s size of RGB - third dimension .
    image_cluster = Image . fromarray ( stage , 'RGB' )
    spike_animation . append ( [ plt . imshow ( image_cluster , interpolation = 'none' ) ] )
im_ani = animation . ArtistAnimation ( figure , spike_animation , interval = 75 , repeat_delay = 3000 , blit = True )
plt . show ( )


signature:
def simulate ( self , steps , stimulus ) :
    """@ brief Performs static simulation of pulse coupled neural network using .
 @ param [ in ] steps ( uint ) : Number steps of simulations during simulation .
 @ param [ in ] stimulus ( list ) : Stimulus for oscillators , number of stimulus should be equal to number of oscillators .
 @ return ( pcnn _ dynamic ) Dynamic of oscillatory network - output of each oscillator on each step of simulation ."""

implementation:
if len ( stimulus ) != len ( self ) :
    raise NameError ( 'Number of stimulus should be equal to number of oscillators. Each stimulus corresponds to only one oscillators.' )
if self . __ccore_pcnn_pointer is not None :
    ccore_instance_dynamic = wrapper . pcnn_simulate ( self . __ccore_pcnn_pointer , steps , stimulus )
    return pcnn_dynamic ( None , ccore_instance_dynamic )
dynamic = [ ]
dynamic . append ( self . _outputs )
for step in range ( 1 , steps , 1 ) :
    self . _outputs = self . _calculate_states ( stimulus )
    dynamic . append ( self . _outputs )
return pcnn_dynamic ( dynamic )


signature:
def _calculate_states ( self , stimulus ) :
    """@ brief Calculates states of oscillators in the network for current step and stored them except outputs of oscillators .
 @ param [ in ] stimulus ( list ) : Stimulus for oscillators , number of stimulus should be equal to number of oscillators .
 @ return ( list ) New outputs for oscillators ( do not stored it ) ."""

implementation:
feeding = [ 0.0 ] * self . _num_osc
linking = [ 0.0 ] * self . _num_osc
outputs = [ 0.0 ] * self . _num_osc
threshold = [ 0.0 ] * self . _num_osc
for index in range ( 0 , self . _num_osc , 1 ) :
    neighbors = self . get_neighbors ( index )
    feeding_influence = 0.0
    linking_influence = 0.0
    for index_neighbour in neighbors :
        feeding_influence += self . _outputs [ index_neighbour ] * self . _params . M
        linking_influence += self . _outputs [ index_neighbour ] * self . _params . W
    feeding_influence *= self . _params . VF
    linking_influence *= self . _params . VL
    feeding [ index ] = self . _params . AF * self . _feeding [ index ] + stimulus [ index ] + feeding_influence
    linking [ index ] = self . _params . AL * self . _linking [ index ] + linking_influence
    # calculate internal activity
    internal_activity = feeding [ index ] * ( 1.0 + self . _params . B * linking [ index ] )
    # calculate output of the oscillator
    if internal_activity > self . _threshold [ index ] :
        outputs [ index ] = self . __OUTPUT_TRUE
    else :
        outputs [ index ] = self . __OUTPUT_FALSE
    # In case of Fast Linking we should calculate threshold until output is changed .
    if self . _params . FAST_LINKING is not True :
        threshold [ index ] = self . _params . AT * self . _threshold [ index ] + self . _params . VT * outputs [ index ]
# In case of Fast Linking we need to wait until output is changed .
if self . _params . FAST_LINKING is True :
    output_change = True
    # Set it True for the for the first iteration .
    previous_outputs = outputs [ : ]
    while output_change is True :
        current_output_change = False
        for index in range ( 0 , self . _num_osc , 1 ) :
            linking_influence = 0.0
            neighbors = self . get_neighbors ( index )
            for index_neighbour in neighbors :
                linking_influence += previous_outputs [ index_neighbour ] * self . _params . W
            linking_influence *= self . _params . VL
            linking [ index ] = linking_influence
            internal_activity = feeding [ index ] * ( 1.0 + self . _params . B * linking [ index ] )
            # calculate output of the oscillator
            if internal_activity > self . _threshold [ index ] :
                outputs [ index ] = self . __OUTPUT_TRUE
            else :
                outputs [ index ] = self . __OUTPUT_FALSE
            current_output_change |= ( outputs [ index ] != previous_outputs [ index ] )
        output_change = current_output_change
        if output_change is True :
            previous_outputs = outputs [ : ]
# In case of Fast Linking threshold should be calculated after fast linking .
if self . _params . FAST_LINKING is True :
    for index in range ( 0 , self . _num_osc , 1 ) :
        threshold [ index ] = self . _params . AT * self . _threshold [ index ] + self . _params . VT * outputs [ index ]
self . _feeding = feeding [ : ]
self . _linking = linking [ : ]
self . _threshold = threshold [ : ]
return outputs


signature:
def size ( self ) :
    """@ brief Return size of self - organized map that is defined by total number of neurons .
 @ return ( uint ) Size of self - organized map ( number of neurons ) ."""

implementation:
if self . __ccore_som_pointer is not None :
    self . _size = wrapper . som_get_size ( self . __ccore_som_pointer )
return self . _size


signature:
def weights ( self ) :
    """@ brief Return weight of each neuron .
 @ return ( list ) Weights of each neuron ."""

implementation:
if self . __ccore_som_pointer is not None :
    self . _weights = wrapper . som_get_weights ( self . __ccore_som_pointer )
return self . _weights


signature:
def awards ( self ) :
    """@ brief Return amount of captured objects by each neuron after training .
 @ return ( list ) Amount of captured objects by each neuron .
 @ see train ( )"""

implementation:
if self . __ccore_som_pointer is not None :
    self . _award = wrapper . som_get_awards ( self . __ccore_som_pointer )
return self . _award


signature:
def capture_objects ( self ) :
    """@ brief Returns indexes of captured objects by each neuron .
 @ details For example , network with size 2x2 has been trained on 5 sample , we neuron # 1 has won one object with
 index ' 1 ' , neuron # 2 - objects with indexes ' 0 ' , ' 3 ' , ' 4 ' , neuron # 3 - nothing , neuron # 4 - object
 with index ' 2 ' . Thus , output is [ [ 1 ] , [ 0 , 3 , 4 ] , [ ] , [ 2 ] ] .
 @ return ( list ) Indexes of captured objects by each neuron ."""

implementation:
if self . __ccore_som_pointer is not None :
    self . _capture_objects = wrapper . som_get_capture_objects ( self . __ccore_som_pointer )
return self . _capture_objects


signature:
def __initialize_locations ( self , rows , cols ) :
    """@ brief Initialize locations ( coordinates in SOM grid ) of each neurons in the map .
 @ param [ in ] rows ( uint ) : Number of neurons in the column ( number of rows ) .
 @ param [ in ] cols ( uint ) : Number of neurons in the row ( number of columns ) .
 @ return ( list ) List of coordinates of each neuron in map ."""

implementation:
location = list ( )
for i in range ( rows ) :
    for j in range ( cols ) :
        location . append ( [ float ( i ) , float ( j ) ] )
return location


signature:
def __initialize_distances ( self , size , location ) :
    """@ brief Initialize distance matrix in SOM grid .
 @ param [ in ] size ( uint ) : Amount of neurons in the network .
 @ param [ in ] location ( list ) : List of coordinates of each neuron in the network .
 @ return ( list ) Distance matrix between neurons in the network ."""

implementation:
sqrt_distances = [ [ [ ] for i in range ( size ) ] for j in range ( size ) ]
for i in range ( size ) :
    for j in range ( i , size , 1 ) :
        dist = euclidean_distance_square ( location [ i ] , location [ j ] )
        sqrt_distances [ i ] [ j ] = dist
        sqrt_distances [ j ] [ i ] = dist
return sqrt_distances


signature:
def _create_initial_weights ( self , init_type ) :
    """@ brief Creates initial weights for neurons in line with the specified initialization .
 @ param [ in ] init _ type ( type _ init ) : Type of initialization of initial neuron weights ( random , random in center of the input data , random distributed in data , ditributed in line with uniform grid ) ."""

implementation:
dim_info = dimension_info ( self . _data )
step_x = dim_info . get_center ( ) [ 0 ]
if self . _rows > 1 :
    step_x = dim_info . get_width ( ) [ 0 ] / ( self . _rows - 1 ) ;
step_y = 0.0
if dim_info . get_dimensions ( ) > 1 :
    step_y = dim_info . get_center ( ) [ 1 ]
    if self . _cols > 1 :
        step_y = dim_info . get_width ( ) [ 1 ] / ( self . _cols - 1 ) ;
# generate weights ( topological coordinates )
random . seed ( )
# Uniform grid .
if init_type == type_init . uniform_grid : # Predefined weights in line with input data .
    self . _weights = [ [ [ ] for i in range ( dim_info . get_dimensions ( ) ) ] for j in range ( self . _size ) ]
    for i in range ( self . _size ) :
        location = self . _location [ i ]
        for dim in range ( dim_info . get_dimensions ( ) ) :
            if dim == 0 :
                if self . _rows > 1 :
                    self . _weights [ i ] [ dim ] = dim_info . get_minimum_coordinate ( ) [ dim ] + step_x * location [ dim ]
                else :
                    self . _weights [ i ] [ dim ] = dim_info . get_center ( ) [ dim ]
            elif dim == 1 :
                if self . _cols > 1 :
                    self . _weights [ i ] [ dim ] = dim_info . get_minimum_coordinate ( ) [ dim ] + step_y * location [ dim ]
                else :
                    self . _weights [ i ] [ dim ] = dim_info . get_center ( ) [ dim ]
            else :
                self . _weights [ i ] [ dim ] = dim_info . get_center ( ) [ dim ]
elif init_type == type_init . random_surface : # Random weights at the full surface .
    self . _weights = [ [ random . uniform ( dim_info . get_minimum_coordinate ( ) [ i ] , dim_info . get_maximum_coordinate ( ) [ i ] ) for i in range ( dim_info . get_dimensions ( ) ) ] for _ in range ( self . _size ) ]
elif init_type == type_init . random_centroid : # Random weights at the center of input data .
    self . _weights = [ [ ( random . random ( ) + dim_info . get_center ( ) [ i ] ) for i in range ( dim_info . get_dimensions ( ) ) ] for _ in range ( self . _size ) ]
else : # Random weights of input data .
    self . _weights = [ [ random . random ( ) for i in range ( dim_info . get_dimensions ( ) ) ] for _ in range ( self . _size ) ]


signature:
def _create_connections ( self , conn_type ) :
    """@ brief Create connections in line with input rule ( grid four , grid eight , honeycomb , function neighbour ) .
 @ param [ in ] conn _ type ( type _ conn ) : Type of connection between oscillators in the network ."""

implementation:
self . _neighbors = [ [ ] for index in range ( self . _size ) ]
for index in range ( 0 , self . _size , 1 ) :
    upper_index = index - self . _cols
    upper_left_index = index - self . _cols - 1
    upper_right_index = index - self . _cols + 1
    lower_index = index + self . _cols
    lower_left_index = index + self . _cols - 1
    lower_right_index = index + self . _cols + 1
    left_index = index - 1
    right_index = index + 1
    node_row_index = math . floor ( index / self . _cols )
    upper_row_index = node_row_index - 1
    lower_row_index = node_row_index + 1
    if ( conn_type == type_conn . grid_eight ) or ( conn_type == type_conn . grid_four ) :
        if upper_index >= 0 :
            self . _neighbors [ index ] . append ( upper_index )
        if lower_index < self . _size :
            self . _neighbors [ index ] . append ( lower_index )
    if ( conn_type == type_conn . grid_eight ) or ( conn_type == type_conn . grid_four ) or ( conn_type == type_conn . honeycomb ) :
        if ( left_index >= 0 ) and ( math . floor ( left_index / self . _cols ) == node_row_index ) :
            self . _neighbors [ index ] . append ( left_index )
        if ( right_index < self . _size ) and ( math . floor ( right_index / self . _cols ) == node_row_index ) :
            self . _neighbors [ index ] . append ( right_index )
    if conn_type == type_conn . grid_eight :
        if ( upper_left_index >= 0 ) and ( math . floor ( upper_left_index / self . _cols ) == upper_row_index ) :
            self . _neighbors [ index ] . append ( upper_left_index )
        if ( upper_right_index >= 0 ) and ( math . floor ( upper_right_index / self . _cols ) == upper_row_index ) :
            self . _neighbors [ index ] . append ( upper_right_index )
        if ( lower_left_index < self . _size ) and ( math . floor ( lower_left_index / self . _cols ) == lower_row_index ) :
            self . _neighbors [ index ] . append ( lower_left_index )
        if ( lower_right_index < self . _size ) and ( math . floor ( lower_right_index / self . _cols ) == lower_row_index ) :
            self . _neighbors [ index ] . append ( lower_right_index )
    if conn_type == type_conn . honeycomb :
        if ( node_row_index % 2 ) == 0 :
            upper_left_index = index - self . _cols
            upper_right_index = index - self . _cols + 1
            lower_left_index = index + self . _cols
            lower_right_index = index + self . _cols + 1
        else :
            upper_left_index = index - self . _cols - 1
            upper_right_index = index - self . _cols
            lower_left_index = index + self . _cols - 1
            lower_right_index = index + self . _cols
        if ( upper_left_index >= 0 ) and ( math . floor ( upper_left_index / self . _cols ) == upper_row_index ) :
            self . _neighbors [ index ] . append ( upper_left_index )
        if ( upper_right_index >= 0 ) and ( math . floor ( upper_right_index / self . _cols ) == upper_row_index ) :
            self . _neighbors [ index ] . append ( upper_right_index )
        if ( lower_left_index < self . _size ) and ( math . floor ( lower_left_index / self . _cols ) == lower_row_index ) :
            self . _neighbors [ index ] . append ( lower_left_index )
        if ( lower_right_index < self . _size ) and ( math . floor ( lower_right_index / self . _cols ) == lower_row_index ) :
            self . _neighbors [ index ] . append ( lower_right_index )


signature:
def _competition ( self , x ) :
    """@ brief Calculates neuron winner ( distance , neuron index ) .
 @ param [ in ] x ( list ) : Input pattern from the input data set , for example it can be coordinates of point .
 @ return ( uint ) Returns index of neuron that is winner ."""

implementation:
index = 0
minimum = euclidean_distance_square ( self . _weights [ 0 ] , x )
for i in range ( 1 , self . _size , 1 ) :
    candidate = euclidean_distance_square ( self . _weights [ i ] , x )
    if candidate < minimum :
        index = i
        minimum = candidate
return index


signature:
def _adaptation ( self , index , x ) :
    """@ brief Change weight of neurons in line with won neuron .
 @ param [ in ] index ( uint ) : Index of neuron - winner .
 @ param [ in ] x ( list ) : Input pattern from the input data set ."""

implementation:
dimension = len ( self . _weights [ 0 ] )
if self . _conn_type == type_conn . func_neighbor :
    for neuron_index in range ( self . _size ) :
        distance = self . _sqrt_distances [ index ] [ neuron_index ]
        if distance < self . _local_radius :
            influence = math . exp ( - ( distance / ( 2.0 * self . _local_radius ) ) )
            for i in range ( dimension ) :
                self . _weights [ neuron_index ] [ i ] = self . _weights [ neuron_index ] [ i ] + self . _learn_rate * influence * ( x [ i ] - self . _weights [ neuron_index ] [ i ] )
else :
    for i in range ( dimension ) :
        self . _weights [ index ] [ i ] = self . _weights [ index ] [ i ] + self . _learn_rate * ( x [ i ] - self . _weights [ index ] [ i ] )
    for neighbor_index in self . _neighbors [ index ] :
        distance = self . _sqrt_distances [ index ] [ neighbor_index ]
        if distance < self . _local_radius :
            influence = math . exp ( - ( distance / ( 2.0 * self . _local_radius ) ) )
            for i in range ( dimension ) :
                self . _weights [ neighbor_index ] [ i ] = self . _weights [ neighbor_index ] [ i ] + self . _learn_rate * influence * ( x [ i ] - self . _weights [ neighbor_index ] [ i ] )


signature:
def train ( self , data , epochs , autostop = False ) :
    """@ brief Trains self - organized feature map ( SOM ) .
 @ param [ in ] data ( list ) : Input data - list of points where each point is represented by list of features , for example coordinates .
 @ param [ in ] epochs ( uint ) : Number of epochs for training .
 @ param [ in ] autostop ( bool ) : Automatic termination of learining process when adaptation is not occurred .
 @ return ( uint ) Number of learining iterations ."""

implementation:
self . _data = data
if self . __ccore_som_pointer is not None :
    return wrapper . som_train ( self . __ccore_som_pointer , data , epochs , autostop )
self . _sqrt_distances = self . __initialize_distances ( self . _size , self . _location )
for i in range ( self . _size ) :
    self . _award [ i ] = 0
    self . _capture_objects [ i ] . clear ( )
# weights
self . _create_initial_weights ( self . _params . init_type )
previous_weights = None
for epoch in range ( 1 , epochs + 1 ) : # Depression term of coupling
    self . _local_radius = ( self . _params . init_radius * math . exp ( - ( epoch / epochs ) ) ) ** 2
    self . _learn_rate = self . _params . init_learn_rate * math . exp ( - ( epoch / epochs ) )
    # Clear statistics
    if autostop :
        for i in range ( self . _size ) :
            self . _award [ i ] = 0
            self . _capture_objects [ i ] . clear ( )
    for i in range ( len ( self . _data ) ) : # Step 1 : Competition :
        index = self . _competition ( self . _data [ i ] )
        # Step 2 : Adaptation :
        self . _adaptation ( index , self . _data [ i ] )
        # Update statistics
        if ( autostop == True ) or ( epoch == epochs ) :
            self . _award [ index ] += 1
            self . _capture_objects [ index ] . append ( i )
    # Check requirement of stopping
    if autostop :
        if previous_weights is not None :
            maximal_adaptation = self . _get_maximal_adaptation ( previous_weights )
            if maximal_adaptation < self . _params . adaptation_threshold :
                return epoch
        previous_weights = [ item [ : ] for item in self . _weights ]
return epochs


signature:
def simulate ( self , input_pattern ) :
    """@ brief Processes input pattern ( no learining ) and returns index of neuron - winner .
 Using index of neuron winner catched object can be obtained using property capture _ objects .
 @ param [ in ] input _ pattern ( list ) : Input pattern .
 @ return ( uint ) Returns index of neuron - winner .
 @ see capture _ objects"""

implementation:
if self . __ccore_som_pointer is not None :
    return wrapper . som_simulate ( self . __ccore_som_pointer , input_pattern )
return self . _competition ( input_pattern )


signature:
def _get_maximal_adaptation ( self , previous_weights ) :
    """@ brief Calculates maximum changes of weight in line with comparison between previous weights and current weights .
 @ param [ in ] previous _ weights ( list ) : Weights from the previous step of learning process .
 @ return ( double ) Value that represents maximum changes of weight after adaptation process ."""

implementation:
dimension = len ( self . _data [ 0 ] )
maximal_adaptation = 0.0
for neuron_index in range ( self . _size ) :
    for dim in range ( dimension ) :
        current_adaptation = previous_weights [ neuron_index ] [ dim ] - self . _weights [ neuron_index ] [ dim ]
        if current_adaptation < 0 :
            current_adaptation = - current_adaptation
        if maximal_adaptation < current_adaptation :
            maximal_adaptation = current_adaptation
return maximal_adaptation


signature:
def get_winner_number ( self ) :
    """@ brief Calculates number of winner at the last step of learning process .
 @ return ( uint ) Number of winner ."""

implementation:
if self . __ccore_som_pointer is not None :
    self . _award = wrapper . som_get_awards ( self . __ccore_som_pointer )
winner_number = 0
for i in range ( self . _size ) :
    if self . _award [ i ] > 0 :
        winner_number += 1
return winner_number


signature:
def show_distance_matrix ( self ) :
    """@ brief Shows gray visualization of U - matrix ( distance matrix ) .
 @ see get _ distance _ matrix ( )"""

implementation:
distance_matrix = self . get_distance_matrix ( )
plt . imshow ( distance_matrix , cmap = plt . get_cmap ( 'hot' ) , interpolation = 'kaiser' )
plt . title ( "U-Matrix" )
plt . colorbar ( )
plt . show ( )


signature:
def get_distance_matrix ( self ) :
    """@ brief Calculates distance matrix ( U - matrix ) .
 @ details The U - Matrix visualizes based on the distance in input space between a weight vector and its neighbors on map .
 @ return ( list ) Distance matrix ( U - matrix ) .
 @ see show _ distance _ matrix ( )
 @ see get _ density _ matrix ( )"""

implementation:
if self . __ccore_som_pointer is not None :
    self . _weights = wrapper . som_get_weights ( self . __ccore_som_pointer )
    if self . _conn_type != type_conn . func_neighbor :
        self . _neighbors = wrapper . som_get_neighbors ( self . __ccore_som_pointer )
distance_matrix = [ [ 0.0 ] * self . _cols for i in range ( self . _rows ) ]
for i in range ( self . _rows ) :
    for j in range ( self . _cols ) :
        neuron_index = i * self . _cols + j
        if self . _conn_type == type_conn . func_neighbor :
            self . _create_connections ( type_conn . grid_eight )
        for neighbor_index in self . _neighbors [ neuron_index ] :
            distance_matrix [ i ] [ j ] += euclidean_distance_square ( self . _weights [ neuron_index ] , self . _weights [ neighbor_index ] )
        distance_matrix [ i ] [ j ] /= len ( self . _neighbors [ neuron_index ] )
return distance_matrix


signature:
def show_density_matrix ( self , surface_divider = 20.0 ) :
    """@ brief Show density matrix ( P - matrix ) using kernel density estimation .
 @ param [ in ] surface _ divider ( double ) : Divider in each dimension that affect radius for density measurement .
 @ see show _ distance _ matrix ( )"""

implementation:
density_matrix = self . get_density_matrix ( surface_divider )
plt . imshow ( density_matrix , cmap = plt . get_cmap ( 'hot' ) , interpolation = 'kaiser' )
plt . title ( "P-Matrix" )
plt . colorbar ( )
plt . show ( )


signature:
def get_density_matrix ( self , surface_divider = 20.0 ) :
    """@ brief Calculates density matrix ( P - Matrix ) .
 @ param [ in ] surface _ divider ( double ) : Divider in each dimension that affect radius for density measurement .
 @ return ( list ) Density matrix ( P - Matrix ) .
 @ see get _ distance _ matrix ( )"""

implementation:
if self . __ccore_som_pointer is not None :
    self . _weights = wrapper . som_get_weights ( self . __ccore_som_pointer )
density_matrix = [ [ 0 ] * self . _cols for i in range ( self . _rows ) ]
dimension = len ( self . _weights [ 0 ] )
dim_max = [ float ( '-Inf' ) ] * dimension
dim_min = [ float ( 'Inf' ) ] * dimension
for weight in self . _weights :
    for index_dim in range ( dimension ) :
        if weight [ index_dim ] > dim_max [ index_dim ] :
            dim_max [ index_dim ] = weight [ index_dim ]
        if weight [ index_dim ] < dim_min [ index_dim ] :
            dim_min [ index_dim ] = weight [ index_dim ]
radius = [ 0.0 ] * len ( self . _weights [ 0 ] )
for index_dim in range ( dimension ) :
    radius [ index_dim ] = ( dim_max [ index_dim ] - dim_min [ index_dim ] ) / surface_divider
# # TODO : do not use data
for point in self . _data :
    for index_neuron in range ( len ( self ) ) :
        point_covered = True
        for index_dim in range ( dimension ) :
            if abs ( point [ index_dim ] - self . _weights [ index_neuron ] [ index_dim ] ) > radius [ index_dim ] :
                point_covered = False
                break
        row = int ( math . floor ( index_neuron / self . _cols ) )
        col = index_neuron - row * self . _cols
        if point_covered is True :
            density_matrix [ row ] [ col ] += 1
return density_matrix


signature:
def show_winner_matrix ( self ) :
    """@ brief Show winner matrix where each element corresponds to neuron and value represents
 amount of won objects from input dataspace at the last training iteration .
 @ see show _ distance _ matrix ( )"""

implementation:
if self . __ccore_som_pointer is not None :
    self . _award = wrapper . som_get_awards ( self . __ccore_som_pointer )
( fig , ax ) = plt . subplots ( )
winner_matrix = [ [ 0 ] * self . _cols for i in range ( self . _rows ) ]
for i in range ( self . _rows ) :
    for j in range ( self . _cols ) :
        neuron_index = i * self . _cols + j
        winner_matrix [ i ] [ j ] = self . _award [ neuron_index ]
        ax . text ( i , j , str ( winner_matrix [ i ] [ j ] ) , va = 'center' , ha = 'center' )
ax . imshow ( winner_matrix , cmap = plt . get_cmap ( 'cool' ) , interpolation = 'none' )
ax . grid ( True )
plt . title ( "Winner Matrix" )
plt . show ( )


signature:
def show_network ( self , awards = False , belongs = False , coupling = True , dataset = True , marker_type = 'o' ) :
    """@ brief Shows neurons in the dimension of data .
 @ param [ in ] awards ( bool ) : If True - displays how many objects won each neuron .
 @ param [ in ] belongs ( bool ) : If True - marks each won object by according index of neuron - winner ( only when dataset is displayed too ) .
 @ param [ in ] coupling ( bool ) : If True - displays connections between neurons ( except case when function neighbor is used ) .
 @ param [ in ] dataset ( bool ) : If True - displays inputs data set .
 @ param [ in ] marker _ type ( string ) : Defines marker that is used for dispaying neurons in the network ."""

implementation:
if self . __ccore_som_pointer is not None :
    self . _size = wrapper . som_get_size ( self . __ccore_som_pointer )
    self . _weights = wrapper . som_get_weights ( self . __ccore_som_pointer )
    self . _neighbors = wrapper . som_get_neighbors ( self . __ccore_som_pointer )
    self . _award = wrapper . som_get_awards ( self . __ccore_som_pointer )
dimension = len ( self . _weights [ 0 ] )
fig = plt . figure ( )
# Check for dimensions
if ( dimension == 1 ) or ( dimension == 2 ) :
    axes = fig . add_subplot ( 111 )
elif dimension == 3 :
    axes = fig . gca ( projection = '3d' )
else :
    raise NotImplementedError ( 'Impossible to show network in data-space that is differ from 1D, 2D or 3D.' )
if ( self . _data is not None ) and ( dataset is True ) :
    for x in self . _data :
        if dimension == 1 :
            axes . plot ( x [ 0 ] , 0.0 , 'b|' , ms = 30 )
        elif dimension == 2 :
            axes . plot ( x [ 0 ] , x [ 1 ] , 'b.' )
        elif dimension == 3 :
            axes . scatter ( x [ 0 ] , x [ 1 ] , x [ 2 ] , c = 'b' , marker = '.' )
# Show neurons
for index in range ( self . _size ) :
    color = 'g'
    if self . _award [ index ] == 0 :
        color = 'y'
    if dimension == 1 :
        axes . plot ( self . _weights [ index ] [ 0 ] , 0.0 , color + marker_type )
        if awards :
            location = '{0}' . format ( self . _award [ index ] )
            axes . text ( self . _weights [ index ] [ 0 ] , 0.0 , location , color = 'black' , fontsize = 10 )
        if belongs and self . _data is not None :
            location = '{0}' . format ( index )
            axes . text ( self . _weights [ index ] [ 0 ] , 0.0 , location , color = 'black' , fontsize = 12 )
            for k in range ( len ( self . _capture_objects [ index ] ) ) :
                point = self . _data [ self . _capture_objects [ index ] [ k ] ]
                axes . text ( point [ 0 ] , 0.0 , location , color = 'blue' , fontsize = 10 )
    if dimension == 2 :
        axes . plot ( self . _weights [ index ] [ 0 ] , self . _weights [ index ] [ 1 ] , color + marker_type )
        if awards :
            location = '{0}' . format ( self . _award [ index ] )
            axes . text ( self . _weights [ index ] [ 0 ] , self . _weights [ index ] [ 1 ] , location , color = 'black' , fontsize = 10 )
        if belongs and self . _data is not None :
            location = '{0}' . format ( index )
            axes . text ( self . _weights [ index ] [ 0 ] , self . _weights [ index ] [ 1 ] , location , color = 'black' , fontsize = 12 )
            for k in range ( len ( self . _capture_objects [ index ] ) ) :
                point = self . _data [ self . _capture_objects [ index ] [ k ] ]
                axes . text ( point [ 0 ] , point [ 1 ] , location , color = 'blue' , fontsize = 10 )
        if ( self . _conn_type != type_conn . func_neighbor ) and ( coupling != False ) :
            for neighbor in self . _neighbors [ index ] :
                if neighbor > index :
                    axes . plot ( [ self . _weights [ index ] [ 0 ] , self . _weights [ neighbor ] [ 0 ] ] , [ self . _weights [ index ] [ 1 ] , self . _weights [ neighbor ] [ 1 ] ] , 'g' , linewidth = 0.5 )
    elif dimension == 3 :
        axes . scatter ( self . _weights [ index ] [ 0 ] , self . _weights [ index ] [ 1 ] , self . _weights [ index ] [ 2 ] , c = color , marker = marker_type )
        if ( self . _conn_type != type_conn . func_neighbor ) and ( coupling != False ) :
            for neighbor in self . _neighbors [ index ] :
                if neighbor > index :
                    axes . plot ( [ self . _weights [ index ] [ 0 ] , self . _weights [ neighbor ] [ 0 ] ] , [ self . _weights [ index ] [ 1 ] , self . _weights [ neighbor ] [ 1 ] ] , [ self . _weights [ index ] [ 2 ] , self . _weights [ neighbor ] [ 2 ] ] , 'g-' , linewidth = 0.5 )
plt . title ( "Network Structure" )
plt . grid ( )
plt . show ( )


signature:
def calculate_sync_order ( oscillator_phases ) :
    """@ brief Calculates level of global synchronization ( order parameter ) for input phases .
 @ details This parameter is tend 1.0 when the oscillatory network close to global synchronization and it tend to 0.0 when
 desynchronization is observed in the network .
 @ param [ in ] oscillator _ phases ( list ) : List of oscillator phases that are used for level of global synchronization .
 @ return ( double ) Level of global synchronization ( order parameter ) .
 @ see calculate _ order _ parameter ( )"""

implementation:
exp_amount = 0.0 ;
average_phase = 0.0 ;
for phase in oscillator_phases :
    exp_amount += math . expm1 ( abs ( 1j * phase ) ) ;
    average_phase += phase ;
exp_amount /= len ( oscillator_phases ) ;
average_phase = math . expm1 ( abs ( 1j * ( average_phase / len ( oscillator_phases ) ) ) ) ;
return abs ( average_phase ) / abs ( exp_amount ) ;


signature:
def calculate_local_sync_order ( oscillator_phases , oscillatory_network ) :
    """@ brief Calculates level of local synchorization ( local order parameter ) for input phases for the specified network .
 @ details This parameter is tend 1.0 when the oscillatory network close to local synchronization and it tend to 0.0 when
 desynchronization is observed in the network .
 @ param [ in ] oscillator _ phases ( list ) : List of oscillator phases that are used for level of local ( partial ) synchronization .
 @ param [ in ] oscillatory _ network ( sync ) : Instance of oscillatory network whose connections are required for calculation .
 @ return ( double ) Level of local synchronization ( local order parameter ) ."""

implementation:
exp_amount = 0.0 ;
num_neigh = 0.0 ;
for i in range ( 0 , len ( oscillatory_network ) , 1 ) :
    for j in range ( 0 , len ( oscillatory_network ) , 1 ) :
        if ( oscillatory_network . has_connection ( i , j ) == True ) :
            exp_amount += math . exp ( - abs ( oscillator_phases [ j ] - oscillator_phases [ i ] ) ) ;
            num_neigh += 1.0 ;
if ( num_neigh == 0 ) :
    num_neigh = 1.0 ;
return exp_amount / num_neigh ;


signature:
def output ( self ) :
    """@ brief ( list ) Returns output dynamic of the Sync network ( phase coordinates of each oscillator in the network ) during simulation ."""

implementation:
if ( ( self . _ccore_sync_dynamic_pointer is not None ) and ( ( self . _dynamic is None ) or ( len ( self . _dynamic ) == 0 ) ) ) :
    self . _dynamic = wrapper . sync_dynamic_get_output ( self . _ccore_sync_dynamic_pointer ) ;
return self . _dynamic ;


signature:
def time ( self ) :
    """@ brief ( list ) Returns sampling times when dynamic is measured during simulation ."""

implementation:
if ( ( self . _ccore_sync_dynamic_pointer is not None ) and ( ( self . _time is None ) or ( len ( self . _time ) == 0 ) ) ) :
    self . _time = wrapper . sync_dynamic_get_time ( self . _ccore_sync_dynamic_pointer ) ;
return self . _time ;


signature:
def allocate_sync_ensembles ( self , tolerance = 0.01 , indexes = None , iteration = None ) :
    """@ brief Allocate clusters in line with ensembles of synchronous oscillators where each synchronous ensemble corresponds to only one cluster .
 @ param [ in ] tolerance ( double ) : Maximum error for allocation of synchronous ensemble oscillators .
 @ param [ in ] indexes ( list ) : List of real object indexes and it should be equal to amount of oscillators ( in case of ' None ' - indexes are in range [ 0 ; amount _ oscillators ] ) .
 @ param [ in ] iteration ( uint ) : Iteration of simulation that should be used for allocation .
 @ return ( list ) Grours ( lists ) of indexes of synchronous oscillators .
 For example [ [ index _ osc1 , index _ osc3 ] , [ index _ osc2 ] , [ index _ osc4 , index _ osc5 ] ] ."""

implementation:
if ( self . _ccore_sync_dynamic_pointer is not None ) :
    ensembles = wrapper . sync_dynamic_allocate_sync_ensembles ( self . _ccore_sync_dynamic_pointer , tolerance , iteration ) ;
    if ( indexes is not None ) :
        for ensemble in ensembles :
            for index in range ( len ( ensemble ) ) :
                ensemble [ index ] = indexes [ ensemble [ index ] ] ;
    return ensembles ;
if ( ( self . _dynamic is None ) or ( len ( self . _dynamic ) == 0 ) ) :
    return [ ] ;
number_oscillators = len ( self . _dynamic [ 0 ] ) ;
last_state = None ;
if ( iteration is None ) :
    last_state = self . _dynamic [ len ( self . _dynamic ) - 1 ] ;
else :
    last_state = self . _dynamic [ iteration ] ;
clusters = [ ] ;
if ( number_oscillators > 0 ) :
    clusters . append ( [ 0 ] ) ;
for i in range ( 1 , number_oscillators , 1 ) :
    cluster_allocated = False ;
    for cluster in clusters :
        for neuron_index in cluster :
            last_state_shifted = abs ( last_state [ i ] - 2 * pi ) ;
            if ( ( ( last_state [ i ] < ( last_state [ neuron_index ] + tolerance ) ) and ( last_state [ i ] > ( last_state [ neuron_index ] - tolerance ) ) ) or ( ( last_state_shifted < ( last_state [ neuron_index ] + tolerance ) ) and ( last_state_shifted > ( last_state [ neuron_index ] - tolerance ) ) ) ) :
                cluster_allocated = True ;
                real_index = i ;
                if ( indexes is not None ) :
                    real_index = indexes [ i ] ;
                cluster . append ( real_index ) ;
                break ;
        if ( cluster_allocated == True ) :
            break ;
    if ( cluster_allocated == False ) :
        clusters . append ( [ i ] ) ;
return clusters ;


signature:
def allocate_phase_matrix ( self , grid_width = None , grid_height = None , iteration = None ) :
    """@ brief Returns 2D matrix of phase values of oscillators at the specified iteration of simulation .
 @ details User should ensure correct matrix sizes in line with following expression grid _ width x grid _ height that should be equal to
 amount of oscillators otherwise exception is thrown . If grid _ width or grid _ height are not specified than phase matrix size
 will by calculated automatically by square root .
 @ param [ in ] grid _ width ( uint ) : Width of the allocated matrix .
 @ param [ in ] grid _ height ( uint ) : Height of the allocated matrix .
 @ param [ in ] iteration ( uint ) : Number of iteration of simulation for which correlation matrix should be allocated .
 If iternation number is not specified , the last step of simulation is used for the matrix allocation .
 @ return ( list ) Phase value matrix of oscillators with size [ number _ oscillators x number _ oscillators ] ."""

implementation:
output_dynamic = self . output ;
if ( ( output_dynamic is None ) or ( len ( output_dynamic ) == 0 ) ) :
    return [ ] ;
current_dynamic = output_dynamic [ len ( output_dynamic ) - 1 ] ;
if ( iteration is not None ) :
    current_dynamic = output_dynamic [ iteration ] ;
width_matrix = grid_width ;
height_matrix = grid_height ;
number_oscillators = len ( current_dynamic ) ;
if ( ( width_matrix is None ) or ( height_matrix is None ) ) :
    width_matrix = int ( math . ceil ( math . sqrt ( number_oscillators ) ) ) ;
    height_matrix = width_matrix ;
if ( number_oscillators != width_matrix * height_matrix ) :
    raise NameError ( "Impossible to allocate phase matrix with specified sizes, amout of neurons should be equal to grid_width * grid_height." ) ;
phase_matrix = [ [ 0.0 for i in range ( width_matrix ) ] for j in range ( height_matrix ) ] ;
for i in range ( height_matrix ) :
    for j in range ( width_matrix ) :
        phase_matrix [ i ] [ j ] = current_dynamic [ j + i * width_matrix ] ;
return phase_matrix ;


signature:
def allocate_correlation_matrix ( self , iteration = None ) :
    """@ brief Allocate correlation matrix between oscillators at the specified step of simulation .
 @ param [ in ] iteration ( uint ) : Number of iteration of simulation for which correlation matrix should be allocated .
 If iternation number is not specified , the last step of simulation is used for the matrix allocation .
 @ return ( list ) Correlation matrix between oscillators with size [ number _ oscillators x number _ oscillators ] ."""

implementation:
if ( self . _ccore_sync_dynamic_pointer is not None ) :
    return wrapper . sync_dynamic_allocate_correlation_matrix ( self . _ccore_sync_dynamic_pointer , iteration ) ;
if ( ( self . _dynamic is None ) or ( len ( self . _dynamic ) == 0 ) ) :
    return [ ] ;
dynamic = self . _dynamic ;
current_dynamic = dynamic [ len ( dynamic ) - 1 ] ;
if ( iteration is not None ) :
    current_dynamic = dynamic [ iteration ] ;
number_oscillators = len ( dynamic [ 0 ] ) ;
affinity_matrix = [ [ 0.0 for i in range ( number_oscillators ) ] for j in range ( number_oscillators ) ] ;
for i in range ( number_oscillators ) :
    for j in range ( number_oscillators ) :
        phase1 = current_dynamic [ i ] ;
        phase2 = current_dynamic [ j ] ;
        affinity_matrix [ i ] [ j ] = abs ( math . sin ( phase1 - phase2 ) ) ;
return affinity_matrix ;


signature:
def calculate_order_parameter ( self , start_iteration = None , stop_iteration = None ) :
    """@ brief Calculates level of global synchorization ( order parameter ) .
 @ details This parameter is tend 1.0 when the oscillatory network close to global synchronization and it tend to 0.0 when
 desynchronization is observed in the network . Order parameter is calculated using following equation :
 r _ { c } = \f rac { 1 } { Ne ^ { i \v arphi } } \ sum _ { j = 0 } ^ { N } e ^ { i \t heta _ { j } } ;
 where \f $ \v arphi \f $ is a average phase coordinate in the network , \f $ N \f $ is an amount of oscillators in the network .
 @ param [ in ] start _ iteration ( uint ) : The first iteration that is used for calculation , if ' None ' then the last iteration is used .
 @ param [ in ] stop _ iteration ( uint ) : The last iteration that is used for calculation , if ' None ' then ' start _ iteration ' + 1 is used .
 Example :
 @ code
 oscillatory _ network = sync ( 16 , type _ conn = conn _ type . ALL _ TO _ ALL ) ;
 output _ dynamic = oscillatory _ network . simulate _ static ( 100 , 10 ) ;
 print ( " Order parameter at the last step : " , output _ dynamic . calculate _ order _ parameter ( ) ) ;
 print ( " Order parameter at the first step : " , output _ dynamic . calculate _ order _ parameter ( 0 ) ) ;
 print ( " Order parameter evolution between 40 and 50 steps : " , output _ dynamic . calculate _ order _ parameter ( 40 , 50 ) ) ;
 @ endcode
 @ return ( list ) List of levels of global synchronization ( order parameter evolution ) .
 @ see order _ estimator"""

implementation:
( start_iteration , stop_iteration ) = self . __get_start_stop_iterations ( start_iteration , stop_iteration ) ;
if ( self . _ccore_sync_dynamic_pointer is not None ) :
    return wrapper . sync_dynamic_calculate_order ( self . _ccore_sync_dynamic_pointer , start_iteration , stop_iteration ) ;
sequence_order = [ ] ;
for index in range ( start_iteration , stop_iteration ) :
    sequence_order . append ( order_estimator . calculate_sync_order ( self . output [ index ] ) ) ;
return sequence_order ;


signature:
def calculate_local_order_parameter ( self , oscillatory_network , start_iteration = None , stop_iteration = None ) :
    """@ brief Calculates local order parameter .
 @ details Local order parameter or so - called level of local or partial synchronization is calculated by following expression :
 r _ { c } = \ left | \ sum _ { i = 0 } ^ { N } \f rac { 1 } { N _ { i } } \ sum _ { j = 0 } e ^ { \t heta _ { j } - \t heta _ { i } } \r ight | ;
 where N - total amount of oscillators in the network and \f $ N _ { i } \f $ - amount of neighbors of oscillator with index \f $ i \f $ .
 @ param [ in ] oscillatory _ network ( sync ) : Sync oscillatory network whose structure of connections is required for calculation .
 @ param [ in ] start _ iteration ( uint ) : The first iteration that is used for calculation , if ' None ' then the last iteration is used .
 @ param [ in ] stop _ iteration ( uint ) : The last iteration that is used for calculation , if ' None ' then ' start _ iteration ' + 1 is used .
 @ return ( list ) List of levels of local ( partial ) synchronization ( local order parameter evolution ) ."""

implementation:
( start_iteration , stop_iteration ) = self . __get_start_stop_iterations ( start_iteration , stop_iteration ) ;
if ( self . _ccore_sync_dynamic_pointer is not None ) :
    network_pointer = oscillatory_network . _ccore_network_pointer ;
    return wrapper . sync_dynamic_calculate_local_order ( self . _ccore_sync_dynamic_pointer , network_pointer , start_iteration , stop_iteration ) ;
sequence_local_order = [ ] ;
for index in range ( start_iteration , stop_iteration ) :
    sequence_local_order . append ( order_estimator . calculate_local_sync_order ( self . output [ index ] , oscillatory_network ) ) ;
return sequence_local_order ;


signature:
def __get_start_stop_iterations ( self , start_iteration , stop_iteration ) :
    """@ brief Aplly rules for start _ iteration and stop _ iteration parameters .
 @ param [ in ] start _ iteration ( uint ) : The first iteration that is used for calculation .
 @ param [ in ] stop _ iteration ( uint ) : The last iteration that is used for calculation .
 @ return ( tuple ) New the first iteration and the last ."""

implementation:
if ( start_iteration is None ) :
    start_iteration = len ( self ) - 1 ;
if ( stop_iteration is None ) :
    stop_iteration = start_iteration + 1 ;
return ( start_iteration , stop_iteration ) ;


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

implementation: draw_dynamics ( sync_output_dynamic . time , sync_output_dynamic . output , x_title = "t" , y_title = "phase" , y_lim = [ 0 , 2 * 3.14 ] ) ;


signature:
def show_correlation_matrix ( sync_output_dynamic , iteration = None ) :
    """@ brief Shows correlation matrix between oscillators at the specified iteration .
 @ param [ in ] sync _ output _ dynamic ( sync _ dynamic ) : Output dynamic of the Sync network .
 @ param [ in ] iteration ( uint ) : Number of interation of simulation for which correlation matrix should be allocated .
 If iternation number is not specified , the last step of simulation is used for the matrix allocation ."""

implementation:
_ = plt . figure ( ) ;
correlation_matrix = sync_output_dynamic . allocate_correlation_matrix ( iteration ) ;
plt . imshow ( correlation_matrix , cmap = plt . get_cmap ( 'cool' ) , interpolation = 'kaiser' , vmin = 0.0 , vmax = 1.0 ) ;
plt . show ( ) ;


signature:
def show_phase_matrix ( sync_output_dynamic , grid_width = None , grid_height = None , iteration = None ) :
    """@ brief Shows 2D matrix of phase values of oscillators at the specified iteration .
 @ details User should ensure correct matrix sizes in line with following expression grid _ width x grid _ height that should be equal to
 amount of oscillators otherwise exception is thrown . If grid _ width or grid _ height are not specified than phase matrix size
 will by calculated automatically by square root .
 @ param [ in ] sync _ output _ dynamic ( sync _ dynamic ) : Output dynamic of the Sync network whose phase matrix should be shown .
 @ param [ in ] grid _ width ( uint ) : Width of the phase matrix .
 @ param [ in ] grid _ height ( uint ) : Height of the phase matrix .
 @ param [ in ] iteration ( uint ) : Number of iteration of simulation for which correlation matrix should be allocated .
 If iternation number is not specified , the last step of simulation is used for the matrix allocation ."""

implementation:
_ = plt . figure ( ) ;
phase_matrix = sync_output_dynamic . allocate_phase_matrix ( grid_width , grid_height , iteration ) ;
plt . imshow ( phase_matrix , cmap = plt . get_cmap ( 'jet' ) , interpolation = 'kaiser' , vmin = 0.0 , vmax = 2.0 * math . pi ) ;
plt . show ( ) ;


signature:
def show_order_parameter ( sync_output_dynamic , start_iteration = None , stop_iteration = None ) :
    """@ brief Shows evolution of order parameter ( level of global synchronization in the network ) .
 @ param [ in ] sync _ output _ dynamic ( sync _ dynamic ) : Output dynamic of the Sync network whose evolution of global synchronization should be visualized .
 @ param [ in ] start _ iteration ( uint ) : The first iteration that is used for calculation , if ' None ' then the first is used
 @ param [ in ] stop _ iteration ( uint ) : The last iteration that is used for calculation , if ' None ' then the last is used ."""

implementation:
( start_iteration , stop_iteration ) = sync_visualizer . __get_start_stop_iterations ( sync_output_dynamic , start_iteration , stop_iteration ) ;
order_parameter = sync_output_dynamic . calculate_order_parameter ( start_iteration , stop_iteration ) ;
axis = plt . subplot ( 111 ) ;
plt . plot ( sync_output_dynamic . time [ start_iteration : stop_iteration ] , order_parameter , 'b-' , linewidth = 2.0 ) ;
set_ax_param ( axis , "t" , "R (order parameter)" , None , [ 0.0 , 1.05 ] ) ;
plt . show ( ) ;


signature:
def show_local_order_parameter ( sync_output_dynamic , oscillatory_network , start_iteration = None , stop_iteration = None ) :
    """@ brief Shows evolution of local order parameter ( level of local synchronization in the network ) .
 @ param [ in ] sync _ output _ dynamic ( sync _ dynamic ) : Output dynamic of the Sync network whose evolution of global synchronization should be visualized .
 @ param [ in ] oscillatory _ network ( sync ) : Sync oscillatory network whose structure of connections is required for calculation .
 @ param [ in ] start _ iteration ( uint ) : The first iteration that is used for calculation , if ' None ' then the first is used
 @ param [ in ] stop _ iteration ( uint ) : The last iteration that is used for calculation , if ' None ' then the last is used ."""

implementation:
( start_iteration , stop_iteration ) = sync_visualizer . __get_start_stop_iterations ( sync_output_dynamic , start_iteration , stop_iteration ) ;
order_parameter = sync_output_dynamic . calculate_local_order_parameter ( oscillatory_network , start_iteration , stop_iteration ) ;
axis = plt . subplot ( 111 ) ;
plt . plot ( sync_output_dynamic . time [ start_iteration : stop_iteration ] , order_parameter , 'b-' , linewidth = 2.0 ) ;
set_ax_param ( axis , "t" , "R (local order parameter)" , None , [ 0.0 , 1.05 ] ) ;
plt . show ( ) ;


signature:
def animate_output_dynamic ( sync_output_dynamic , animation_velocity = 75 , save_movie = None ) :
    """@ brief Shows animation of output dynamic ( output of each oscillator ) during simulation on a circle from [ 0 ; 2pi ] .
 @ param [ in ] sync _ output _ dynamic ( sync _ dynamic ) : Output dynamic of the Sync network .
 @ param [ in ] animation _ velocity ( uint ) : Interval between frames in milliseconds .
 @ 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 ( ) ;
dynamic = sync_output_dynamic . output [ 0 ] ;
artist , = plt . polar ( dynamic , [ 1.0 ] * len ( dynamic ) , 'o' , color = 'blue' ) ;
def init_frame ( ) :
    return [ artist ] ;
def frame_generation ( index_dynamic ) :
    dynamic = sync_output_dynamic . output [ index_dynamic ] ;
    artist . set_data ( dynamic , [ 1.0 ] * len ( dynamic ) ) ;
    return [ artist ] ;
phase_animation = animation . FuncAnimation ( figure , frame_generation , len ( sync_output_dynamic ) , interval = animation_velocity , init_func = init_frame , repeat_delay = 5000 ) ;
if ( save_movie is not None ) :
    phase_animation . save ( save_movie , writer = 'ffmpeg' , fps = 15 , bitrate = 1500 ) ;
else :
    plt . show ( ) ;


signature:
def animate_correlation_matrix ( sync_output_dynamic , animation_velocity = 75 , colormap = 'cool' , save_movie = None ) :
    """@ brief Shows animation of correlation matrix between oscillators during simulation .
 @ param [ in ] sync _ output _ dynamic ( sync _ dynamic ) : Output dynamic of the Sync network .
 @ param [ in ] animation _ velocity ( uint ) : Interval between frames in milliseconds .
 @ param [ in ] colormap ( string ) : Name of colormap that is used by matplotlib ( ' gray ' , ' pink ' , ' cool ' , spring ' , etc . ) .
 @ 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 ( )
correlation_matrix = sync_output_dynamic . allocate_correlation_matrix ( 0 )
artist = plt . imshow ( correlation_matrix , cmap = plt . get_cmap ( colormap ) , interpolation = 'kaiser' , vmin = 0.0 , vmax = 1.0 )
def init_frame ( ) :
    return [ artist ]
def frame_generation ( index_dynamic ) :
    correlation_matrix = sync_output_dynamic . allocate_correlation_matrix ( index_dynamic )
    artist . set_data ( correlation_matrix )
    return [ artist ]
correlation_animation = animation . FuncAnimation ( figure , frame_generation , len ( sync_output_dynamic ) , init_func = init_frame , interval = animation_velocity , repeat_delay = 1000 , blit = True )
if ( save_movie is not None ) :
    correlation_animation . save ( save_movie , writer = 'ffmpeg' , fps = 15 , bitrate = 1500 )
else :
    plt . show ( )


signature:
def animate_phase_matrix ( sync_output_dynamic , grid_width = None , grid_height = None , animation_velocity = 75 , colormap = 'jet' , save_movie = None ) :
    """@ brief Shows animation of phase matrix between oscillators during simulation on 2D stage .
 @ details If grid _ width or grid _ height are not specified than phase matrix size will by calculated automatically by square root .
 @ param [ in ] sync _ output _ dynamic ( sync _ dynamic ) : Output dynamic of the Sync network .
 @ param [ in ] grid _ width ( uint ) : Width of the phase matrix .
 @ param [ in ] grid _ height ( uint ) : Height of the phase matrix .
 @ param [ in ] animation _ velocity ( uint ) : Interval between frames in milliseconds .
 @ param [ in ] colormap ( string ) : Name of colormap that is used by matplotlib ( ' gray ' , ' pink ' , ' cool ' , spring ' , etc . ) .
 @ 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_dynamic ) :
    figure . clf ( ) ;
    axis = figure . add_subplot ( 111 ) ;
    phase_matrix = sync_output_dynamic . allocate_phase_matrix ( grid_width , grid_height , index_dynamic ) ;
    axis . imshow ( phase_matrix , cmap = plt . get_cmap ( colormap ) , interpolation = 'kaiser' , vmin = 0.0 , vmax = 2.0 * math . pi ) ;
    artist = figure . gca ( ) ;
    return [ artist ] ;
phase_animation = animation . FuncAnimation ( figure , frame_generation , len ( sync_output_dynamic ) , init_func = init_frame , interval = animation_velocity , repeat_delay = 1000 ) ;
if ( save_movie is not None ) :
    phase_animation . save ( save_movie , writer = 'ffmpeg' , fps = 15 , bitrate = 1500 ) ;
else :
    plt . show ( ) ;


signature:
def __get_start_stop_iterations ( sync_output_dynamic , start_iteration , stop_iteration ) :
    """@ brief Apply rule of preparation for start iteration and stop iteration values .
 @ param [ in ] sync _ output _ dynamic ( sync _ dynamic ) : Output dynamic of the Sync network .
 @ param [ in ] start _ iteration ( uint ) : The first iteration that is used for calculation .
 @ param [ in ] stop _ iteration ( uint ) : The last iteration that is used for calculation .
 @ return ( tuple ) New values of start and stop iterations ."""

implementation:
if ( start_iteration is None ) :
    start_iteration = 0 ;
if ( stop_iteration is None ) :
    stop_iteration = len ( sync_output_dynamic ) ;
return ( start_iteration , stop_iteration ) ;


signature:
def animate ( sync_output_dynamic , title = None , save_movie = None ) :
    """@ brief Shows animation of phase coordinates and animation of correlation matrix together for the Sync dynamic output on the same figure .
 @ param [ in ] sync _ output _ dynamic ( sync _ dynamic ) : Output dynamic of the Sync network .
 @ param [ in ] title ( string ) : Title of the animation that is displayed on a figure if it is specified .
 @ param [ in ] save _ movie ( string ) : If it is specified then animation will be stored to file that is specified in this parameter ."""

implementation:
dynamic = sync_output_dynamic . output [ 0 ] ;
correlation_matrix = sync_output_dynamic . allocate_correlation_matrix ( 0 ) ;
figure = plt . figure ( 1 ) ;
if ( title is not None ) :
    figure . suptitle ( title , fontsize = 26 , fontweight = 'bold' )
ax1 = figure . add_subplot ( 121 , projection = 'polar' ) ;
ax2 = figure . add_subplot ( 122 ) ;
artist1 , = ax1 . plot ( dynamic , [ 1.0 ] * len ( dynamic ) , marker = 'o' , color = 'blue' , ls = '' ) ;
artist2 = ax2 . imshow ( correlation_matrix , cmap = plt . get_cmap ( 'Accent' ) , interpolation = 'kaiser' ) ;
def init_frame ( ) :
    return [ artist1 , artist2 ] ;
def frame_generation ( index_dynamic ) :
    dynamic = sync_output_dynamic . output [ index_dynamic ] ;
    artist1 . set_data ( dynamic , [ 1.0 ] * len ( dynamic ) ) ;
    correlation_matrix = sync_output_dynamic . allocate_correlation_matrix ( index_dynamic ) ;
    artist2 . set_data ( correlation_matrix ) ;
    return [ artist1 , artist2 ] ;
dynamic_animation = animation . FuncAnimation ( figure , frame_generation , len ( sync_output_dynamic ) , interval = 75 , init_func = init_frame , repeat_delay = 5000 ) ;
if ( save_movie is not None ) :
    dynamic_animation . save ( save_movie , writer = 'ffmpeg' , fps = 15 , bitrate = 1500 ) ;
else :
    plt . show ( ) ;


signature:
def sync_order ( self ) :
    """@ brief Calculates current level of global synchorization ( order parameter ) in the network .
 @ details This parameter is tend 1.0 when the oscillatory network close to global synchronization and it tend to 0.0 when
 desynchronization is observed in the network . Order parameter is calculated using following equation :
 r _ { c } = \f rac { 1 } { Ne ^ { i \v arphi } } \ sum _ { j = 0 } ^ { N } e ^ { i \t heta _ { j } } ;
 where \f $ \v arphi \f $ is a average phase coordinate in the network , \f $ N \f $ is an amount of oscillators in the network .
 Example :
 @ code
 oscillatory _ network = sync ( 16 , type _ conn = conn _ type . ALL _ TO _ ALL ) ;
 output _ dynamic = oscillatory _ network . simulate _ static ( 100 , 10 ) ;
 if ( oscillatory _ network . sync _ order ( ) < 0.9 ) : print ( " Global synchronization is not reached yet . " ) ;
 else : print ( " Global synchronization is reached . " ) ;
 @ endcode
 @ return ( double ) Level of global synchronization ( order parameter ) .
 @ see sync _ local _ order ( )"""

implementation:
if ( self . _ccore_network_pointer is not None ) :
    return wrapper . sync_order ( self . _ccore_network_pointer ) ;
return order_estimator . calculate_sync_order ( self . _phases ) ;


signature:
def sync_local_order ( self ) :
    """@ brief Calculates current level of local ( partial ) synchronization in the network .
 @ return ( double ) Level of local ( partial ) synchronization .
 @ see sync _ order ( )"""

implementation:
if ( self . _ccore_network_pointer is not None ) :
    return wrapper . sync_local_order ( self . _ccore_network_pointer ) ;
return order_estimator . calculate_local_sync_order ( self . _phases , self ) ;


signature:
def _phase_kuramoto ( self , teta , t , argv ) :
    """@ brief Returns result of phase calculation for specified oscillator in the network .
 @ param [ in ] teta ( double ) : Phase of the oscillator that is differentiated .
 @ param [ in ] t ( double ) : Current time of simulation .
 @ param [ in ] argv ( tuple ) : Index of the oscillator in the list .
 @ return ( double ) New phase for specified oscillator ( don ' t assign here ) ."""

implementation:
index = argv ;
phase = 0 ;
for k in range ( 0 , self . _num_osc ) :
    if ( self . has_connection ( index , k ) == True ) :
        phase += math . sin ( self . _phases [ k ] - teta ) ;
return ( self . _freq [ index ] + ( phase * self . _weight / self . _num_osc ) ) ;


signature:
def simulate ( self , steps , time , solution = solve_type . FAST , collect_dynamic = True ) :
    """@ brief Performs static simulation of Sync oscillatory network .
 @ param [ in ] steps ( uint ) : Number steps of simulations during simulation .
 @ param [ in ] time ( double ) : Time of simulation .
 @ param [ in ] solution ( solve _ type ) : Type of solution ( solving ) .
 @ 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 ' = True , than return dynamic for the whole simulation time ,
 otherwise returns only last values ( last step of simulation ) of dynamic .
 @ see simulate _ dynamic ( )
 @ see simulate _ static ( )"""

implementation: return self . simulate_static ( steps , time , solution , collect_dynamic ) ;


signature:
def simulate_dynamic ( self , order = 0.998 , solution = solve_type . FAST , collect_dynamic = False , step = 0.1 , int_step = 0.01 , threshold_changes = 0.0000001 ) :
    """@ brief Performs dynamic simulation of the network until stop condition is not reached . Stop condition is defined by input argument ' order ' .
 @ param [ in ] order ( double ) : Order of process synchronization , distributed 0 . . 1.
 @ param [ in ] solution ( solve _ type ) : Type of solution .
 @ param [ in ] collect _ dynamic ( bool ) : If True - returns whole dynamic of oscillatory network , otherwise returns only last values of dynamics .
 @ param [ in ] step ( double ) : Time step of one iteration of simulation .
 @ param [ in ] int _ step ( double ) : Integration step , should be less than step .
 @ param [ in ] threshold _ changes ( double ) : Additional stop condition that helps prevent infinite simulation , defines limit of changes of oscillators between current and previous steps .
 @ return ( list ) Dynamic of oscillatory network . If argument ' collect _ dynamic ' = True , than return dynamic for the whole simulation time ,
 otherwise returns only last values ( last step of simulation ) of dynamic .
 @ see simulate ( )
 @ see simulate _ static ( )"""

implementation:
if ( self . _ccore_network_pointer is not None ) :
    ccore_instance_dynamic = wrapper . sync_simulate_dynamic ( self . _ccore_network_pointer , order , solution , collect_dynamic , step , int_step , threshold_changes ) ;
    return sync_dynamic ( None , None , ccore_instance_dynamic ) ;
# For statistics and integration
time_counter = 0 ;
# Prevent infinite loop . It ' s possible when required state cannot be reached .
previous_order = 0 ;
current_order = self . sync_local_order ( ) ;
# If requested input dynamics
dyn_phase = [ ] ;
dyn_time = [ ] ;
if ( collect_dynamic == True ) :
    dyn_phase . append ( self . _phases ) ;
    dyn_time . append ( 0 ) ;
# Execute until sync state will be reached
while ( current_order < order ) : # update states of oscillators
    self . _phases = self . _calculate_phases ( solution , time_counter , step , int_step ) ;
    # update time
    time_counter += step ;
    # if requested input dynamic
    if ( collect_dynamic == True ) :
        dyn_phase . append ( self . _phases ) ;
        dyn_time . append ( time_counter ) ;
    # update orders
    previous_order = current_order ;
    current_order = self . sync_local_order ( ) ;
    # hang prevention
    if ( abs ( current_order - previous_order ) < threshold_changes ) : # print ( " Warning : sync _ network : : simulate _ dynamic - simulation is aborted due to low level of convergence rate ( order = " + str ( current _ order ) + " ) . " ) ;
        break ;
if ( collect_dynamic != True ) :
    dyn_phase . append ( self . _phases ) ;
    dyn_time . append ( time_counter ) ;
output_sync_dynamic = sync_dynamic ( dyn_phase , dyn_time , None ) ;
return output_sync_dynamic ;


signature:
def simulate_static ( self , steps , time , solution = solve_type . FAST , collect_dynamic = False ) :
    """@ brief Performs static simulation of oscillatory network .
 @ param [ in ] steps ( uint ) : Number steps of simulations during simulation .
 @ param [ in ] time ( double ) : Time of simulation .
 @ param [ in ] solution ( solve _ type ) : Type of solution .
 @ 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 ' = True , than return dynamic for the whole simulation time ,
 otherwise returns only last values ( last step of simulation ) of dynamic .
 @ see simulate ( )
 @ see simulate _ dynamic ( )"""

implementation:
if ( self . _ccore_network_pointer is not None ) :
    ccore_instance_dynamic = wrapper . sync_simulate_static ( self . _ccore_network_pointer , steps , time , solution , collect_dynamic ) ;
    return sync_dynamic ( None , None , ccore_instance_dynamic ) ;
dyn_phase = [ ] ;
dyn_time = [ ] ;
if ( collect_dynamic == True ) :
    dyn_phase . append ( self . _phases ) ;
    dyn_time . append ( 0 ) ;
step = time / steps ;
int_step = step / 10.0 ;
for t in numpy . arange ( step , time + step , step ) : # update states of oscillators
    self . _phases = self . _calculate_phases ( solution , t , step , int_step ) ;
    # update states of oscillators
    if ( collect_dynamic == True ) :
        dyn_phase . append ( self . _phases ) ;
        dyn_time . append ( t ) ;
if ( collect_dynamic != True ) :
    dyn_phase . append ( self . _phases ) ;
    dyn_time . append ( time ) ;
output_sync_dynamic = sync_dynamic ( dyn_phase , dyn_time ) ;
return output_sync_dynamic ;


signature:
def _calculate_phases ( self , solution , t , step , int_step ) :
    """@ brief Calculates new phases for oscillators in the network in line with current step .
 @ param [ in ] solution ( solve _ type ) : Type solver of the differential equation .
 @ 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_phases = [ 0.0 ] * self . _num_osc ;
# new oscillator _ phases
for index in range ( 0 , self . _num_osc , 1 ) :
    if ( solution == solve_type . FAST ) :
        result = self . _phases [ index ] + self . _phase_kuramoto ( self . _phases [ index ] , 0 , index ) ;
        next_phases [ index ] = self . _phase_normalization ( result ) ;
    elif ( ( solution == solve_type . RK4 ) or ( solution == solve_type . RKF45 ) ) :
        result = odeint ( self . _phase_kuramoto , self . _phases [ index ] , numpy . arange ( t - step , t , int_step ) , ( index , ) ) ;
        next_phases [ index ] = self . _phase_normalization ( result [ len ( result ) - 1 ] [ 0 ] ) ;
    else :
        raise NameError ( "Solver '" + str ( solution ) + "' is not supported" ) ;
return next_phases ;


signature:
def _phase_normalization ( self , teta ) :
    """@ brief Normalization of phase of oscillator that should be placed between [ 0 ; 2 * pi ] .
 @ param [ in ] teta ( double ) : phase of oscillator .
 @ return ( double ) Normalized phase ."""

implementation:
norm_teta = teta ;
while ( norm_teta > ( 2.0 * pi ) ) or ( norm_teta < 0 ) :
    if ( norm_teta > ( 2.0 * pi ) ) :
        norm_teta -= 2.0 * pi ;
    else :
        norm_teta += 2.0 * pi ;
return norm_teta ;


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 . _ccore_network_pointer is not None ) and ( self . _osc_conn is None ) ) :
    self . _osc_conn = wrapper . sync_connectivity_matrix ( self . _ccore_network_pointer ) ;
return super ( ) . get_neighbors ( index ) ;


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 . _ccore_network_pointer is not None ) and ( self . _osc_conn is None ) ) :
    self . _osc_conn = wrapper . sync_connectivity_matrix ( self . _ccore_network_pointer ) ;
return super ( ) . has_connection ( i , j ) ;


signature:
def process ( self ) :
    """@ brief Performs cluster analysis in line with rules of K - Medoids algorithm .
 @ return ( kmedoids ) Returns itself ( K - Medoids instance ) .
 @ remark Results of clustering can be obtained using corresponding get methods .
 @ see get _ clusters ( )
 @ see get _ medoids ( )"""

implementation:
if self . __ccore is True :
    ccore_metric = metric_wrapper . create_instance ( self . __metric )
    self . __clusters , self . __medoid_indexes = wrapper . kmedoids ( self . __pointer_data , self . __medoid_indexes , self . __tolerance , self . __itermax , ccore_metric . get_pointer ( ) , self . __data_type )
else :
    changes = float ( 'inf' )
    iterations = 0
    while changes > self . __tolerance and iterations < self . __itermax :
        self . __clusters = self . __update_clusters ( )
        update_medoid_indexes = self . __update_medoids ( )
        changes = max ( [ self . __distance_calculator ( self . __medoid_indexes [ index ] , update_medoid_indexes [ index ] ) for index in range ( len ( update_medoid_indexes ) ) ] )
        self . __medoid_indexes = update_medoid_indexes
        iterations += 1
return self


signature:
def __create_distance_calculator ( self ) :
    """@ brief Creates distance calculator in line with algorithms parameters .
 @ return ( callable ) Distance calculator ."""

implementation:
if self . __data_type == 'points' :
    return lambda index1 , index2 : self . __metric ( self . __pointer_data [ index1 ] , self . __pointer_data [ index2 ] )
elif self . __data_type == 'distance_matrix' :
    if isinstance ( self . __pointer_data , numpy . matrix ) :
        return lambda index1 , index2 : self . __pointer_data . item ( ( index1 , index2 ) )
    return lambda index1 , index2 : self . __pointer_data [ index1 ] [ index2 ]
else :
    raise TypeError ( "Unknown type of data is specified '%s'" % self . __data_type )


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

implementation:
clusters = [ [ self . __medoid_indexes [ i ] ] for i in range ( len ( self . __medoid_indexes ) ) ]
for index_point in range ( len ( self . __pointer_data ) ) :
    if index_point in self . __medoid_indexes :
        continue
    index_optim = - 1
    dist_optim = float ( 'Inf' )
    for index in range ( len ( self . __medoid_indexes ) ) :
        dist = self . __distance_calculator ( index_point , self . __medoid_indexes [ index ] )
        if dist < dist_optim :
            index_optim = index
            dist_optim = dist
    clusters [ index_optim ] . append ( index_point )
return clusters


signature:
def __update_medoids ( self ) :
    """@ brief Find medoids of clusters in line with contained objects .
 @ return ( list ) list of medoids for current number of clusters ."""

implementation:
medoid_indexes = [ - 1 ] * len ( self . __clusters )
for index in range ( len ( self . __clusters ) ) :
    medoid_index = medoid ( self . __pointer_data , self . __clusters [ index ] , metric = self . __metric , data_type = self . __data_type )
    medoid_indexes [ index ] = medoid_index
return medoid_indexes


signature:
def process ( self , collect_dynamic = False , order = 0.999 ) :
    """@ brief Performs simulation of the oscillatory network .
 @ param [ in ] collect _ dynamic ( bool ) : If True - returns whole dynamic of oscillatory network , otherwise returns only last values of dynamics .
 @ param [ in ] order ( double ) : Order of process synchronization that should be considered as end of clustering , destributed 0 . . 1.
 @ return ( tuple ) Dynamic of oscillatory network . If argument ' collect _ dynamic ' = True , than return dynamic for the whole simulation time ,
 otherwise returns only last values ( last step of simulation ) of dynamic .
 @ see get _ som _ clusters ( )
 @ see get _ clusters ( )"""

implementation:
# train self - organization map .
self . _som . train ( self . _data , 100 ) ;
# prepare to build list .
weights = list ( ) ;
self . _som_osc_table . clear ( ) ;
# must be cleared , if it ' s used before .
for i in range ( self . _som . size ) :
    if ( self . _som . awards [ i ] > 0 ) :
        weights . append ( self . _som . weights [ i ] ) ;
        self . _som_osc_table . append ( i ) ;
# create oscillatory neural network .
self . _sync = self . __create_sync_layer ( weights ) ;
self . _analyser = self . _sync . process ( order , collect_dynamic = collect_dynamic ) ;
return ( self . _analyser . time , self . _analyser . output ) ;


signature:
def __create_sync_layer ( self , weights ) :
    """@ brief Creates second layer of the network .
 @ param [ in ] weights ( list ) : List of weights of SOM neurons .
 @ return ( syncnet ) Second layer of the network ."""

implementation:
sync_layer = syncnet ( weights , 0.0 , initial_phases = initial_type . RANDOM_GAUSSIAN , ccore = False ) ;
for oscillator_index1 in range ( 0 , len ( sync_layer ) ) :
    for oscillator_index2 in range ( oscillator_index1 + 1 , len ( sync_layer ) ) :
        if ( self . __has_object_connection ( oscillator_index1 , oscillator_index2 ) ) :
            sync_layer . set_connection ( oscillator_index1 , oscillator_index2 ) ;
return sync_layer ;


signature:
def __has_object_connection ( self , oscillator_index1 , oscillator_index2 ) :
    """@ brief Searches for pair of objects that are encoded by specified neurons and that are connected in line with connectivity radius .
 @ param [ in ] oscillator _ index1 ( uint ) : Index of the first oscillator in the second layer .
 @ param [ in ] oscillator _ index2 ( uint ) : Index of the second oscillator in the second layer .
 @ return ( bool ) True - if there is pair of connected objects encoded by specified oscillators ."""

implementation:
som_neuron_index1 = self . _som_osc_table [ oscillator_index1 ] ;
som_neuron_index2 = self . _som_osc_table [ oscillator_index2 ] ;
for index_object1 in self . _som . capture_objects [ som_neuron_index1 ] :
    for index_object2 in self . _som . capture_objects [ som_neuron_index2 ] :
        distance = euclidean_distance_square ( self . _data [ index_object1 ] , self . _data [ index_object2 ] ) ;
        if ( distance <= self . _radius ) :
            return True ;
return False ;


signature:
def get_som_clusters ( self ) :
    """@ brief Returns clusters with SOM neurons that encode input features in line with result of synchronization in the second ( Sync ) layer .
 @ return ( list ) List of clusters that are represented by lists of indexes of neurons that encode input data .
 @ see process ( )
 @ see get _ clusters ( )"""

implementation:
sync_clusters = self . _analyser . allocate_clusters ( ) ;
# Decode it to indexes of SOM neurons
som_clusters = list ( ) ;
for oscillators in sync_clusters :
    cluster = list ( ) ;
    for index_oscillator in oscillators :
        index_neuron = self . _som_osc_table [ index_oscillator ] ;
        cluster . append ( index_neuron ) ;
    som_clusters . append ( cluster ) ;
return som_clusters ;


signature:
def get_clusters ( self , eps = 0.1 ) :
    """@ brief Returns clusters in line with ensembles of synchronous oscillators where each synchronous ensemble corresponds to only one cluster .
 @ param [ in ] eps ( double ) : Maximum error for allocation of synchronous ensemble oscillators .
 @ return ( list ) List of grours ( lists ) of indexes of synchronous oscillators that corresponds to index of objects .
 @ see process ( )
 @ see get _ som _ clusters ( )"""

implementation:
sync_clusters = self . _analyser . allocate_clusters ( eps )
# it isn ' t indexes of SOM neurons
clusters = list ( )
for oscillators in sync_clusters :
    cluster = list ( )
    for index_oscillator in oscillators :
        index_neuron = self . _som_osc_table [ index_oscillator ]
        cluster += self . _som . capture_objects [ index_neuron ]
    clusters . append ( cluster )
return clusters