From 3ce94a16dbb373dc3de4d3b67d3f90caf2e7da04 Mon Sep 17 00:00:00 2001 From: "niehues.mark@gmail.com" <niehues.mark@gmail.com> Date: Thu, 26 Mar 2020 11:55:07 +0100 Subject: [PATCH] dijkstra --- evrouting/gasstation/routing.py | 16 +++++++ evrouting/graph_tools.py | 18 +++++-- tests/config.py | 28 ++++++++++- tests/gasstation/test_gasstation_routing.py | 53 ++++++++++++++++----- 4 files changed, 96 insertions(+), 19 deletions(-) diff --git a/evrouting/gasstation/routing.py b/evrouting/gasstation/routing.py index 55049b6..b9462fc 100644 --- a/evrouting/gasstation/routing.py +++ b/evrouting/gasstation/routing.py @@ -1,4 +1,9 @@ +from typing import Set, Union, Callable, List + import networkx as nx +from evrouting.T import Node, SoC + +DistFunction = Callable[[nx.Graph, Node, Node], Union[int, float]] def shortest_path(G: nx.Graph, s, t, b_0: float, b_t: float, U: float): @@ -14,3 +19,14 @@ def shortest_path(G: nx.Graph, s, t, b_0: float, b_t: float, U: float): :return: """ pass + + +def dijkstra(G: nx.Graph, u: Node, v: Node, weight: str = 'weight') -> Union[int, float]: + path: List[Node] = nx.algorithms.shortest_path(G, u, v, weight=weight) + + return sum([G.edges[path[i], path[i + 1]][weight] for i in range(len(path) - 1)]) + + +def contract_graph(G: nx.Graph, S: Set[Node], U: SoC, + f_dist: DistFunction = dijkstra) -> nx.Graph: + pass diff --git a/evrouting/graph_tools.py b/evrouting/graph_tools.py index 11338e3..1d457c6 100644 --- a/evrouting/graph_tools.py +++ b/evrouting/graph_tools.py @@ -8,23 +8,31 @@ TemplateNode = namedtuple( 'Node', ['label', 'charging_coeff'], defaults=(None, None) ) +LABEL_KEY = 'label' +CHARGING_COEFFICIENT_KEY = 'c' +DISTANCE_KEY = 'weight' +CONSUMPTION_KEY = 'c' + def node_convert(n: TemplateNode) -> NodeData: - return {'label': n.label, 'c': n.charging_coeff} + return {LABEL_KEY: n.label, CHARGING_COEFFICIENT_KEY: n.charging_coeff} def edge_convert(e: TemplateEdge) -> EdgeData: - return {'weight': e.distance, 'c': e.consumption} + return {DISTANCE_KEY: e.distance, CONSUMPTION_KEY: e.consumption} def consumption(G: nx.Graph, u: Node, v: Node) -> Wh: - return G.edges[u, v]['c'] + return G.edges[u, v][CONSUMPTION_KEY] def distance(G: nx.Graph, u: Node, v: Node) -> Time: - return G.edges[u, v]['weight'] + return G.edges[u, v][DISTANCE_KEY] def charging_cofficient(G: nx.Graph, n: Node) -> ChargingCoefficient: - return G.nodes[n]['c'] + return G.nodes[n][CHARGING_COEFFICIENT_KEY] + +def label(G: nx.Graph, u: Node) -> str: + return G.nodes[u][LABEL_KEY] diff --git a/tests/config.py b/tests/config.py index 63877f8..a28ee96 100644 --- a/tests/config.py +++ b/tests/config.py @@ -10,7 +10,8 @@ from evrouting.graph_tools import ( config_list = [ 'edge_case', 'edge_case_start_node_no_cs', - 'edge_case_a_slow' + 'edge_case_a_slow', + 'gasstation' ] edge_case = { @@ -31,6 +32,31 @@ edge_case = { ] } +gasstation = { + 'beta_s': 0, + 'beta_t': 0, + 'U': 2, + 's': 0, + 't': 2, + 'nodes': [ + TemplateNode('s', charging_coeff=1), + TemplateNode('a', charging_coeff=1), # <U + TemplateNode('f', charging_coeff=1), # >U + TemplateNode('b'), + TemplateNode('c', charging_coeff=1), # <U via non cs + TemplateNode('d'), + TemplateNode('e', charging_coeff=1), # >U via non cs + ], + 'edges': [ + TemplateEdge(0, 1, distance=1, consumption=1), + TemplateEdge(0, 2, distance=1, consumption=3), + TemplateEdge(0, 3, distance=1, consumption=1), + TemplateEdge(3, 4, distance=1, consumption=1), + TemplateEdge(0, 5, distance=1, consumption=1), + TemplateEdge(5, 6, distance=1, consumption=2), + ] +} + edge_case_a_slow = { 'beta_s': 0, 'beta_t': 0, diff --git a/tests/gasstation/test_gasstation_routing.py b/tests/gasstation/test_gasstation_routing.py index 1586502..c92e04a 100644 --- a/tests/gasstation/test_gasstation_routing.py +++ b/tests/gasstation/test_gasstation_routing.py @@ -1,18 +1,45 @@ -from evrouting.gasstation import shortest_path +import networkx as nx -from .config import edge_case, get_graph +import pytest +from evrouting.gasstation.routing import contract_graph, dijkstra +from evrouting.graph_tools import label, CONSUMPTION_KEY +from tests.config import edge_case, get_graph, gasstation, init_config -def test_shortest_path(): - G = get_graph(edge_case) +class TestDjikstra: + @pytest.mark.parametrize("u,v,min_len", [(0, 1, 1), (0, 2, 3), (0, 4, 2), (0, 6, 3)]) + def test_djikstra(self, u, v, min_len): + conf: dict = init_config(gasstation) + assert dijkstra(conf['G'], u, v, CONSUMPTION_KEY) == min_len - path = shortest_path( - G, - s=edge_case['s'], - t=edge_case['t'], - b_0=edge_case['b_0'], - b_t=edge_case['b_t'], - U=edge_case['U'] - ) + def test_djikstra_via_node(self): + conf: dict = init_config(edge_case) - assert path == [(0, 4), (2, 0)] + assert dijkstra(conf['G'], 0, 2, CONSUMPTION_KEY) == 2 + + +class TestContraction: + def test_contraction(self): + conf: dict = init_config(gasstation) + G: nx.Graph = conf['G'] + H: nx.Graph = contract_graph(G, conf['charging_stations'], conf['U']) + + # Check available gas stations + nodes = set(label(H, n) for n in H.nodes) + assert nodes == {'s', 'a', 'c'} + + +class TestRouting: + def test_shortest_path(self): + G = get_graph(edge_case) + + path = shortest_path( + G, + s=edge_case['s'], + t=edge_case['t'], + b_0=edge_case['b_0'], + b_t=edge_case['b_t'], + U=edge_case['U'] + ) + + assert path == [(0, 4), (2, 0)] -- GitLab