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