From 12d20b1fbf26b6fe2e80d511fe27675f65029a4c Mon Sep 17 00:00:00 2001
From: "niehues.mark@gmail.com" <niehues.mark@gmail.com>
Date: Mon, 30 Mar 2020 11:50:36 +0200
Subject: [PATCH] gv u added

---
 evrouting/gasstation/routing.py             | 39 +++++++--
 tests/gasstation/test_gasstation_routing.py | 97 ++++++++++++++++++++-
 2 files changed, 127 insertions(+), 9 deletions(-)

diff --git a/evrouting/gasstation/routing.py b/evrouting/gasstation/routing.py
index cac1765..576fd95 100644
--- a/evrouting/gasstation/routing.py
+++ b/evrouting/gasstation/routing.py
@@ -1,9 +1,14 @@
-from typing import Set, Callable, List, Any
+from typing import Set, Callable, List, Any, Dict
 
 import networkx as nx
 from evrouting.T import Node, SoC
 from evrouting.graph_tools import (
-    CONSUMPTION_KEY, DISTANCE_KEY, CHARGING_COEFFICIENT_KEY)
+    CONSUMPTION_KEY,
+    DISTANCE_KEY,
+    CHARGING_COEFFICIENT_KEY,
+    consumption,
+    charging_cofficient
+)
 
 Path = List[Node]
 DistFunction = Callable[[nx.Graph, Node, Node], Path]
@@ -72,7 +77,26 @@ def contract_graph(G: nx.Graph, charging_stations: Set[Node], capacity: SoC,
     return H
 
 
-def extract_graph(G: nx.Graph, capacity: SoC) -> nx.Graph:
+def get_possible_arriving_soc(G: nx.Graph, u: Node, capacity: SoC) -> List[SoC]:
+    """
+    :returns: All possible SoC  when arriving at node u, according to
+        the optimal fuelling strategy.
+    """
+    possible_arriving_soc: Set[SoC] = {0}
+    c_u = charging_cofficient(G, u)
+
+    for n in G.neighbors(u):
+        arriving_soc = capacity - consumption(G, u, n)
+        if arriving_soc >= 0 and charging_cofficient(G, n) < c_u and \
+                arriving_soc not in possible_arriving_soc:
+            possible_arriving_soc.add(arriving_soc)
+
+    return list(possible_arriving_soc)
+
+
+def state_graph(G: nx.Graph, capacity: SoC) -> nx.Graph:
+    node = None
+    get_possible_arriving_soc(G, node, capacity)
     pass
 
 
@@ -93,11 +117,12 @@ def shortest_path(G: nx.Graph, charging_stations: Set[Node], s: Node, t: Node,
     :param U: Capacity
     :return:
     """
-    H: nx.Graph = contract_graph(G, charging_stations, capacity)
+    S: nx.Graph = contract_graph(G, charging_stations, capacity)
+    H = state_graph(S, capacity)
+
     insert_temp_node(s, G, H, capacity, initial_soc)
     insert_temp_node(t, G, H, capacity, final_soc)
 
-    extracted_graph = extract_graph(H, capacity)
-    path: Path = dijkstra(extract_graph(H, capacity), (s, 0), (t, 0))
+    path: Path = dijkstra(H, (s, 0), (t, 0))
 
-    return compose_result(extracted_graph, path)
+    return compose_result(H, path)
diff --git a/tests/gasstation/test_gasstation_routing.py b/tests/gasstation/test_gasstation_routing.py
index 51d83a7..8cfa66c 100644
--- a/tests/gasstation/test_gasstation_routing.py
+++ b/tests/gasstation/test_gasstation_routing.py
@@ -2,8 +2,18 @@ import networkx as nx
 
 import pytest
 from evrouting.gasstation.routing import (
-    shortest_path, contract_graph, dijkstra, fold_path)
-from evrouting.graph_tools import label, CONSUMPTION_KEY, DISTANCE_KEY
+    shortest_path,
+    contract_graph,
+    dijkstra,
+    fold_path,
+    get_possible_arriving_soc
+)
+from evrouting.graph_tools import (
+    label,
+    CONSUMPTION_KEY,
+    DISTANCE_KEY,
+    CHARGING_COEFFICIENT_KEY
+)
 from tests.config import edge_case, get_graph, gasstation, init_config
 
 
@@ -73,6 +83,89 @@ class TestContraction:
             assert H.edges[edge][weight] == value
 
 
+class TestPossibleArrivingSoC:
+    U = 4
+    w_lower = 3
+    w_greater = 5
+
+    @pytest.fixture
+    def graph_w_below_U(self):
+        G = nx.Graph()
+        G.add_edge(0, 1, **{CONSUMPTION_KEY: self.w_lower, DISTANCE_KEY: 2 * self.w_lower})
+        yield G
+        del G
+
+    @pytest.fixture
+    def graph_w_gt_U(self):
+        G = nx.Graph()
+        G.add_edge(0, 1, **{CONSUMPTION_KEY: self.w_greater, DISTANCE_KEY: 2 * self.w_greater})
+        yield G
+        del G
+
+    @pytest.fixture
+    def graph_w_eq_U(self):
+        G = nx.Graph()
+        G.add_edge(0, 1, **{CONSUMPTION_KEY: self.U, DISTANCE_KEY: 2 * self.U})
+        yield G
+        del G
+
+    def test_unequal_charging_coeff_w_eq_U(self, graph_w_eq_U):
+        G = graph_w_eq_U
+        G.add_node(0, **{CHARGING_COEFFICIENT_KEY: 1})
+        G.add_node(1, **{CHARGING_COEFFICIENT_KEY: 2})
+
+        gv_lower = get_possible_arriving_soc(G, 0, self.U)
+        assert gv_lower == [0]
+
+        gv_higher = get_possible_arriving_soc(G, 1, self.U)
+        assert gv_higher == [0]
+
+    def test_equal_charging_coeff_w_lt_U(self, graph_w_below_U):
+        G = graph_w_below_U
+        G.add_node(0, **{CHARGING_COEFFICIENT_KEY: 1})
+        G.add_node(1, **{CHARGING_COEFFICIENT_KEY: 1})
+
+        gv_lower = get_possible_arriving_soc(G, 0, self.U)
+        assert gv_lower == [0]
+
+        gv_higher = get_possible_arriving_soc(G, 1, self.U)
+        assert gv_higher == [0]
+
+    def test_unequal_charging_coeff_w_lt_U(self, graph_w_below_U):
+        G = graph_w_below_U
+        G.add_node(0, **{CHARGING_COEFFICIENT_KEY: 1})
+        G.add_node(1, **{CHARGING_COEFFICIENT_KEY: 2})
+
+        gv_lower = get_possible_arriving_soc(G, 0, self.U)
+        assert gv_lower == [0]
+
+        gv_higher = get_possible_arriving_soc(G, 1, self.U)
+        assert gv_higher == [0, self.U - self.w_lower]
+
+    def test_equal_charging_coeff_w_eq_U(self, graph_w_eq_U):
+        G = graph_w_eq_U
+        G.add_node(0, **{CHARGING_COEFFICIENT_KEY: 1})
+        G.add_node(1, **{CHARGING_COEFFICIENT_KEY: 1})
+
+        gv_lower = get_possible_arriving_soc(G, 0, self.U)
+        assert gv_lower == [0]
+
+        gv_higher = get_possible_arriving_soc(G, 1, self.U)
+        assert gv_higher == [0]
+
+    @pytest.mark.parametrize('c_0,c_1', [(1, 2), (1, 1)])
+    def test_equal_unreachable(self, graph_w_gt_U, c_0, c_1):
+        G: nx.Graph = graph_w_gt_U
+        G.add_node(0, **{CHARGING_COEFFICIENT_KEY: c_0})
+        G.add_node(1, **{CHARGING_COEFFICIENT_KEY: c_1})
+
+        gv_lower = get_possible_arriving_soc(G, 0, self.U)
+        assert gv_lower == [0]
+
+        gv_higher = get_possible_arriving_soc(G, 1, self.U)
+        assert gv_higher == [0]
+
+
 class TestRouting:
     def test_shortest_path(self):
         G = get_graph(edge_case)
-- 
GitLab