"""!

@brief Examples of usage and demonstration of abilities of Oscillatory Neural Network based on Kuramoto model.

@authors Andrei Novikov (pyclustering@yandex.ru)
@date 2014-2020
@copyright BSD-3-Clause

"""


from pyclustering.nnet import solve_type, conn_type;
from pyclustering.nnet.sync import sync_network, sync_visualizer;


def template_dynamic_sync(num_osc, k = 1, sim_arg = None, conn = conn_type.ALL_TO_ALL, type_solution = solve_type.FAST, collect_dyn = True, ccore_flag = False):
    network = sync_network(num_osc, k, type_conn = conn, ccore = ccore_flag);

    if (sim_arg is not None):
        sync_output_dynamic = network.simulate(sim_arg[0], sim_arg[1], solution = type_solution, collect_dynamic = collect_dyn);
    else:
        sync_output_dynamic = network.simulate_dynamic(collect_dynamic = collect_dyn, solution = type_solution);

    sync_visualizer.show_output_dynamic(sync_output_dynamic);
    sync_visualizer.show_order_parameter(sync_output_dynamic);
    sync_visualizer.animate_output_dynamic(sync_output_dynamic);
    sync_visualizer.animate_correlation_matrix(sync_output_dynamic);

    return network;


# Positive connections
def trivial_dynamic_sync():
    template_dynamic_sync(100, 1, sim_arg = [50, 10]);
    template_dynamic_sync(100, 1, sim_arg = [50, 10], ccore_flag = True);

def weight_5_dynamic_sync():
    template_dynamic_sync(10, 10, sim_arg = [100, 10], type_solution = solve_type.RK4);

def bidir_struct_dynamic_sync():
    template_dynamic_sync(10, 100, sim_arg = [100, 10], conn = conn_type.LIST_BIDIR, type_solution = solve_type.RK4);    
    
def grid_four_struct_dynamic_sync():
    template_dynamic_sync(25, 50, sim_arg = [50, 10], conn = conn_type.GRID_FOUR, type_solution = solve_type.RK4);


def dynamic_simulation_all_to_all_structure():
    template_dynamic_sync(25, 1, conn = conn_type.ALL_TO_ALL, ccore_flag = True);

def dynamic_simulation_grid_four_structure():
    template_dynamic_sync(25, 1, conn = conn_type.GRID_FOUR, ccore_flag = True);

def dynamic_simulation_bidir_list_structure():
    template_dynamic_sync(25, 1, conn = conn_type.LIST_BIDIR, ccore_flag = True);

# Negative connections        
def negative_connection_5_oscillators():
    template_dynamic_sync(5, -1); 
    template_dynamic_sync(5, -1, ccore_flag = True);
    
def negative_connection_10_oscillators():
    "Comment: It is not full desynchronization"
    template_dynamic_sync(10, -3);
    
def negative_connection_9_grid_struct():
    "Comment: Right coloring"
    _ = template_dynamic_sync(9, -2, conn = conn_type.GRID_FOUR);
    
    
def negative_connection_16_grid_struct():
    "Comment: Wrong coloring"
    _ = template_dynamic_sync(16, -3, conn = conn_type.GRID_FOUR);


def template_animate_output_dynamic(title, amount_oscillators, coupling_stregth, frequency, order):
    network = sync_network(amount_oscillators, coupling_stregth, frequency, ccore = True);
    sync_output_dynamic = network.simulate_dynamic(order, solution = solve_type.RK4, collect_dynamic = True);
    
    sync_visualizer.animate(sync_output_dynamic, title);
    #sync_visualizer.animate(sync_output_dynamic, title);

def animate_phase_locking():
    template_animate_output_dynamic("Phase locking", 300, 1.0, 1.0, 0.995);

def animate_global_synchronization():
    template_animate_output_dynamic("Global synchronization", 300, 0.5, 0.0, 0.9999);


def template_animate_phase_matrix(num_osc, strength = 1.0, steps = None, time = None, conn = conn_type.ALL_TO_ALL, type_solution = solve_type.FAST, ccore_flag = True):
    network = sync_network(num_osc, strength, type_conn = conn, ccore = ccore_flag);

    if ( (steps is not None) and (time is not None) ):
        sync_output_dynamic = network.simulate(steps, time, solution = type_solution, collect_dynamic = True);
    else:
        sync_output_dynamic = network.simulate_dynamic(collect_dynamic = True, order = 0.999, solution = type_solution);

    sync_visualizer.animate_phase_matrix(sync_output_dynamic);
    return network;

def animate_phase_matrix_400_all_to_all():
    template_animate_phase_matrix(400, 0.4, None, None, conn = conn_type.ALL_TO_ALL, type_solution = solve_type.FAST);

def animate_phase_matrix_400_grid_four():
    template_animate_phase_matrix(400, 2.0, conn = conn_type.GRID_FOUR);

def animate_phase_matrix_400_grid_eight():
    template_animate_phase_matrix(400, 1.0, conn = conn_type.GRID_EIGHT);

# Examples of global synchronization.
trivial_dynamic_sync();
weight_5_dynamic_sync();
bidir_struct_dynamic_sync();
grid_four_struct_dynamic_sync();

# Examples of global synchronization for various network structures
dynamic_simulation_all_to_all_structure();
dynamic_simulation_grid_four_structure();
dynamic_simulation_bidir_list_structure();

# Examples with negative connection
negative_connection_5_oscillators();        # Almost full desynchronization
negative_connection_10_oscillators();       # It's not full desynchronization
negative_connection_9_grid_struct();        # Right coloring
negative_connection_16_grid_struct();       # Wrong coloring
   
   
animate_phase_locking();
animate_global_synchronization();

animate_phase_matrix_400_all_to_all();
animate_phase_matrix_400_grid_four();
animate_phase_matrix_400_grid_eight();