#!/usr/bin/env python3 """Benchmark the neighbor search in graphs. Initially written as part of `Issue #90 `__ to determine whether a faster implementation is needed. That issue also contains a draft which *might* make it faster if that is required in the future. Examples: These are the benchmark results when run on a `Lenovo ThinkPad T560 laptop `__ with an `Intel(R) Core(TM) i5-6300U CPU @ 2.40GHz `__ and 16GB RAM (at commit ``9a8177326dc0d82d0aea4559e6c85071ceebf56f``): .. code-block:: bash ./scripts/benchmark_graph_neighbor_search.py --iterations 100 frequency = 2 for distance 5000 km generated graph in 0.018192768096923828 seconds number of nodes = 42, number of edges = 120 non-empty entries in neighbor table = 240 computation time = 0.0003081770000221695 (avg. over 100 samples) frequency = 8 for distance 1000 km generated graph in 0.0327601432800293 seconds number of nodes = 642, number of edges = 1920 non-empty entries in neighbor table = 3840 computation time = 0.0033796210000218707 (avg. over 100 samples) frequency = 71 for distance 100 km generated graph in 1.8711962699890137 seconds number of nodes = 50412, number of edges = 151230 non-empty entries in neighbor table = 302460 computation time = 0.30925760600001695 (avg. over 100 samples) frequency = 142 for distance 50 km generated graph in 7.630561828613281 seconds number of nodes = 201642, number of edges = 604920 non-empty entries in neighbor table = 1209840 computation time = 1.1302456550000102 (avg. over 100 samples) frequency = 706 for distance 10 km generated graph in 260.7689461708069 seconds number of nodes = 4984362, number of edges = 14953080 non-empty entries in neighbor table = 29906160 computation time = 27.382845137000004 (avg. over 100 samples) """ # Standard library from argparse import ArgumentDefaultsHelpFormatter from argparse import ArgumentParser from time import time from timeit import timeit # Scientific import numpy # Graph from pyrate.plan.graph.generate import create_earth_graph from pyrate.plan.graph.generate import min_required_frequency from pyrate.plan.graph import NavigationGraph def _main() -> None: """The main function.""" parser = ArgumentParser( description="Benchmark the neighbor search in graphs.", formatter_class=ArgumentDefaultsHelpFormatter ) parser.add_argument( "--iterations", type=int, default=100, help="the number of timing samples to collect per graph size" ) args = parser.parse_args() for distance_km in [5000, 1000, 100, 50, 10]: frequency = min_required_frequency(distance_km * 1000, in_meters=True) print(f"frequency = {frequency} for distance {distance_km} km") time_before_generation = time() graph = create_earth_graph(frequency, print_status=False) print(f"generated graph in {time() - time_before_generation} seconds") print(f"number of nodes = {len(graph)}, number of edges = {graph.num_edges}") def setup(local_graph: NavigationGraph = graph) -> None: local_graph._neighbors = None # pylint: disable=protected-access def statement(local_graph: NavigationGraph = graph) -> None: _ = local_graph.neighbors avg_time = timeit(setup=setup, stmt=statement, number=args.iterations) print(f"non-empty entries in neighbor table = {numpy.count_nonzero(graph.neighbors != -1)}") print(f"computation time = {avg_time} (avg. over {args.iterations} samples)") print() # empty line between distances if __name__ == "__main__": _main()