def extract_arguments_for_run_round(number_of_source_destination_pairs: int,
                                    samples: int,
                                    algorithm_arguments=None):
    """
    Execute the simulation for a specific number of source and destination pairs multiple times

    Parameters
    ----------
    number_of_source_destination_pairs: int
        Specifies the number of demands that need to be generated.

    samples: int
        The number of times the simulation will be repeated.

    algorithm_arguments: dict
        Dictionary containing the arguments needed for the algorithm.
    """

    # Extracting the arguments for the algorithm
    algorithm = extract_argument(algorithm_arguments, 'algorithm',
                                 routing_algorithms.initial_knowledge_init)
    graph_edges = extract_argument(algorithm_arguments, 'graph_edges', None)
    distance_threshold = extract_argument(algorithm_arguments,
                                          'distance_threshold', 16)

    # If the algorithm is the local knowledge algorithm
    propagation_radius = extract_argument(algorithm_arguments,
                                          'propagation_radius', None)

    link_prediction = extract_argument(algorithm_arguments, 'link_prediction',
                                       False)
    exponential_scale = extract_argument(algorithm_arguments,
                                         'exponential_scale', False)

    # Running the simulation for the specific source and destination pairs
    results_for_source_destination, link_length_dictionary =\
        run_for_specific_source_destination_pair(number_of_source_destination_pairs, samples, algorithm, graph_edges,
                                                 distance_threshold, propagation_radius,
                                                 exponential_scale, link_prediction)

    return helper.map_tuple_gen(np.mean, zip(*results_for_source_destination)),\
           helper.map_tuple_gen(compute_mean_with_confidence, zip(*results_for_source_destination)),\
           link_length_dictionary
def local_knowledge_algorithm(graph_edges: list, number_of_source_destination_pairs: int, propagation_radius: int = 0,
                              exponential_scale: bool = True):
    """
    Runs the local knowledge algorithm specified by a propagation radius.
    The local knowledge of nodes about the virtual links used within a path is updated within
    a specified propagation radius.

    Parameters
    ----------
    graph_edges: list
        The graph edges to be added as local knowledge to the vertices of the graph.

    number_of_source_destination_pairs: int
        Specifies the number of demands that need to be generated.

    propagation_radius: int
        Index of the end vertex, towards which we are looking for the shortest path.

    exponential_scale: bool
        Specifies whether long link creation scales exponentially or polynomially with time.
    """

    # Generate the specific graph object
    main_graph = create_graph_with_local_knowledge(graph_edges)

    result_for_source_destination = []
    for x in range(1, number_of_source_destination_pairs + 1):

        temp_result: tuple = ()

        simulation_settings = routing_simulation.Settings()

        source = random.randint(1, simulation_settings.number_of_nodes)
        dest = random.randint(1, simulation_settings.number_of_nodes)

        while source == dest:
            dest = random.randint(1, simulation_settings.number_of_nodes)

        # Initialize path
        # Determine shortest path based on local knowledge
        current_path = shortest_path.dijkstra(main_graph.vertices[source].local_knowledge, source, dest)
        current_distance = len(current_path)-1

        temp_result += (distribute_entanglement(main_graph, current_path, exponential_scale),)

        # Update local knowledge of the nodes that are along the current path
        update_local_knowledge(main_graph, current_path, propagation_radius)

        temp_result += (main_graph.get_sum_of_link_capacities(),)
        temp_result += (main_graph.get_available_link_count(),)
        temp_result += (current_distance,)
        result_for_source_destination.append(temp_result)
    return helper.map_tuple_gen(np.mean, zip(*result_for_source_destination))
def initial_knowledge_init(graph_edges: list, number_of_source_destination_pairs: int, time_window_size: int = 1,
                           link_prediction: bool = False, exponential_scale: bool = True):
    """
    Initializes the initial knowledge algorithm.
    Create paths for the specified number of source and destination pairs, then send the packets along a specific path
    and store the waiting time and the distance

    Parameters
    ----------
    graph_edges: list
        The graph in which we want to assign weight in.

    number_of_source_destination_pairs: int
        Specifies the number of demands that need to be generated.

    time_window_size: int
        Specifies the size of the time window used.

    link_prediction: bool
        Value determining whether or not link prediction is used.

    exponential_scale: bool
        Specifies whether long link creation scales exponentially or polynomially with time.
    """

    number_of_measures = 4
    final_results = tuple([] for x in range(number_of_measures))
    main_graph = graph.Graph(graph_edges, link_prediction=link_prediction)

    if link_prediction:
        k = 1
        while k < number_of_source_destination_pairs + 1:
            initial_knowledge_step(main_graph, k, time_window_size, number_of_source_destination_pairs,
                                   final_results, link_prediction)
            k += 1
    else:
        final_results = initial_knowledge_algorithm(main_graph, number_of_source_destination_pairs,
                                                    link_prediction=link_prediction,
                                                    exponential_scale=exponential_scale)

    return helper.map_tuple_gen(helper.mean, final_results)
def global_knowledge_init(graph_edges: list, number_of_source_destination_pairs: int,
                          exponential_scale: bool = True) -> tuple:
    """
    Initiates the global knowledge approach in graph.

    Parameters
    ----------
    graph_edges : list of tuple
        List of edges that specifies the edges of the graph to be created.

    number_of_source_destination_pairs: bool
        Specifies the number of demands that need to be generated.

    exponential_scale: bool
        Specifies whether long link creation scales exponentially or polynomially with time.

    """
    main_graph = graph.Graph(graph_edges)

    result_for_source_destination = global_knowledge_algorithm(main_graph, number_of_source_destination_pairs,
                                                               exponential_scale)
    return helper.map_tuple_gen(np.mean, zip(*result_for_source_destination))
 # is constant (additional edges are added for the case when the dth is not equal to max dth
 initial_knowledge_results = []
 initial_knowledge_errors = []
 samples = 2
 max_dth = 16
 start = time.time()
 for dth in range(1, 5):
     threshold = 2**dth
     power_law_results = []
     for sampling_power_law in range(10):
         factory = graph_edge_factory.VirtualEdgeFactory(
             distance_threshold=threshold, max_distance_threshold=max_dth)
         graph_edges = factory.generate_random_power_law_graph_edges()
         arguments = {
             'algorithm': routing_algorithms.initial_knowledge_init,
             'graph_edges': graph_edges,
             'link_prediction': False,
             'exponential_scale': True
         }
         local_result, errors, length = routing_simulation.run_algorithm_for_graphs(
             50, samples, arguments)
         power_law_results.append(local_result)
     temp = [list(zip(*item)) for item in list(zip(*power_law_results))]
     topology_result = [helper.map_tuple_gen(np.mean, x) for x in temp]
     initial_knowledge_results.append(topology_result)
     initial_knowledge_errors.append(errors)
 end = time.time()
 plot.plot_results(initial_knowledge_results,
                   'initial_knowledge_random_k1_graph_dth_' + str(max_dth) +
                   str(end - start),
                   save_tikz=False)