From 312f8ce5d8e858ed7a5c443d7774023d93b4ea07 Mon Sep 17 00:00:00 2001
From: "niehues.mark@gmail.com" <niehues.mark@gmail.com>
Date: Mon, 16 Mar 2020 16:50:29 +0100
Subject: [PATCH] wip

---
 evrouting/charge/T.py        | 20 ++++++++++++-------
 evrouting/charge/__init__.py |  2 +-
 evrouting/charge/routing.py  | 38 ++++++++++++++++++++++--------------
 evrouting/graph_tools.py     | 16 ++++++++++-----
 4 files changed, 48 insertions(+), 28 deletions(-)

diff --git a/evrouting/charge/T.py b/evrouting/charge/T.py
index d65d7bc..4d8c308 100644
--- a/evrouting/charge/T.py
+++ b/evrouting/charge/T.py
@@ -1,3 +1,4 @@
+from typing import Tuple
 from copy import copy
 from collections import namedtuple
 from math import inf
@@ -7,7 +8,12 @@ import networkx as nx
 from evrouting.T import SoC, Wh, ChargingCoefficient, Time, Node
 from evrouting.graph_tools import charging_cofficient, consumption
 
-Label = namedtuple('Label', ['t_trip', 'beta_u', 'u', 'SoCProfile_u_v'])
+
+class Label(namedtuple):
+    t_trip: Time
+    beta_u: SoC
+    u: Node
+    SoCProfile: SoCProfile
 
 
 class ChargingFunction:
@@ -19,8 +25,7 @@ class ChargingFunction:
     def __call__(self, t: Time, beta: SoC = 0) -> SoC:
         beta += self.c * t
 
-        if beta > self.U:
-            return self.U
+        return beta if beta < self.U else self.U
 
 
 class SoCFunction:
@@ -29,10 +34,10 @@ class SoCFunction:
         self.t_trip: Time = l.t_trip
         self.beta_u: SoC = l.beta_u
         self.u: Node = l.u
-        self.b_u_v: SoCProfile = l.SoCProfile_u_v
+        self.b_u_v: SoCProfile = l.SoCProfile
         self.cf: ChargingFunction = ChargingFunction(G, l.u, U)
 
-    def __call__(self, t) -> SoC:
+    def __call__(self, t: Time) -> SoC:
         if t < self.t_trip:
             return -inf
 
@@ -41,7 +46,8 @@ class SoCFunction:
     def get_minimum(self) -> Time:
         """TODO: Explain."""
         cost_p = self.b_u_v.cost
-        return max(self.t_trip, (cost_p - self.beta_u) / self.cf.c + self.t_trip)
+        return max(self.t_trip, (cost_p - self.beta_u) /
+                   self.cf.c + self.t_trip)
 
 
 class SoCProfile:
@@ -59,7 +65,7 @@ class SoCProfile:
             self.cost: Wh = consumption(G, u, v)
             self.out: Wh = U - self.cost
 
-    def __call__(self, beta) -> SoC:
+    def __call__(self, beta: SoC) -> SoC:
         if beta < self.cost:
             return -inf
         return beta - self.cost
diff --git a/evrouting/charge/__init__.py b/evrouting/charge/__init__.py
index 0e1bcfd..3133abe 100644
--- a/evrouting/charge/__init__.py
+++ b/evrouting/charge/__init__.py
@@ -1 +1 @@
-from .routing import shortest_path
\ No newline at end of file
+from .routing import shortest_path
diff --git a/evrouting/charge/routing.py b/evrouting/charge/routing.py
index 2dd2beb..2d3778c 100644
--- a/evrouting/charge/routing.py
+++ b/evrouting/charge/routing.py
@@ -1,14 +1,16 @@
-from typing import List
+from typing import Dict
 from math import inf
 
 import networkx as nx
-from evrouting.T import Node, SoC, Time, ChargingCoefficient
+from evrouting.T import Node, SoC, Time
 from evrouting.utils import PriorityQueue
 
-from .T import SoCProfile, SoCFunction, Label
+from .T import SoCProfile, SoCFunction, Label, ChargingFunction
+from ..graph_tools import distance
 
 
-def shortest_path(G: nx.Graph, S: set, s: Node, t: Node, beta_s: SoC, beta_t: SoC, U: SoC):
+def shortest_path(G: nx.Graph, S: set, s: Node, t: Node,
+                  beta_s: SoC, beta_t: SoC, U: SoC):
     """
     Calculates shortest path using the CHarge algorithm.
 
@@ -21,13 +23,12 @@ def shortest_path(G: nx.Graph, S: set, s: Node, t: Node, beta_s: SoC, beta_t: So
     :return:
     """
     q = PriorityQueue()
-    l_set = {v: set() for v in G}
-    l_uns = {v: PriorityQueue() for v in G}
+    l_set: Dict[int, set] = {v: set() for v in G}
+    l_uns: Dict[int, PriorityQueue] = {v: PriorityQueue() for v in G}
 
     # Dummy vertex without incident edges that is (temporarily) added to G
     v_0: Node = len(G.nodes)
     G.add_node(v_0)
-
     S.add(v_0)
 
     cf_v_0 = [(0, beta_s)]
@@ -55,9 +56,19 @@ def shortest_path(G: nx.Graph, S: set, s: Node, t: Node, beta_s: SoC, beta_t: So
         # handle charging stations
         t_trip, beta_u, u, b_u_v = l
         if v in S and not v == u:
-            # TODO !!!
-            for t_charge in t_breaks(l):
-                l_uns[v].insert(new_label(l), priority=)  # prio??
+            cf_u = ChargingFunction(G, u, U)  # Last charging station
+            cf_v = ChargingFunction(G, v, U)  # Current charging station
+
+            if cf_v.c > cf_u.c:
+                f_l = SoCFunction(G, l, U)
+                t_charge = f_l.get_minimum()
+                l_new = Label(
+                    t_trip=t_trip + t_charge,
+                    beta_u=beta_u,
+                    u=v,
+                    SoCProfile=SoCProfile(G, U, v)
+                )
+                l_uns[v].insert(l_new, priority=key(l_new))
 
         # update priority queue
         if l_uns[v]:
@@ -69,8 +80,8 @@ def shortest_path(G: nx.Graph, S: set, s: Node, t: Node, beta_s: SoC, beta_t: So
         # scan outgoing arcs
         for x, y in G[v]:
             b_x_y = b_u_v + SoCProfile(G, U, x, y)
-            if not b_x_y(beta_max_u) == -inf:
-                l_new = (t_trip + G.edges[x, y]['weight'], beta_u, u, b_x_y)
+            if not b_x_y(U) == -inf:
+                l_new = Label(t_trip + distance(G, x, y), beta_u, u, b_x_y)
                 l_uns[y].insert(l_new)
                 if l_new == l_uns[y].peak_min():
                     q.insert(y, key(l_new))
@@ -79,6 +90,3 @@ def shortest_path(G: nx.Graph, S: set, s: Node, t: Node, beta_s: SoC, beta_t: So
 def key(l: Label) -> Time:
     return l.t_trip
 
-
-def t_breaks(c_old: ChargingCoefficient, c_new: ChargingCoefficient) -> List[Time]:
-    pass
diff --git a/evrouting/graph_tools.py b/evrouting/graph_tools.py
index 2d92456..e08c119 100644
--- a/evrouting/graph_tools.py
+++ b/evrouting/graph_tools.py
@@ -1,14 +1,16 @@
-from typing import Dict, Tuple
+from typing import Dict, Tuple, Any
 from collections import namedtuple
 
 import networkx as nx
-from evrouting.T import Wh, ChargingCoefficient
+from evrouting.T import Wh, ChargingCoefficient, Time
 
 TemplateEdge = namedtuple('Edge', ['u', 'v', 'distance', 'consumption'])
-TemplateNode = namedtuple('Node', ['label', 'charging_coeff'], defaults=(None, None))
+TemplateNode = namedtuple(
+    'Node', ['label', 'charging_coeff'], defaults=(None, None)
+)
 
-NodeData = Dict
-EdgeData = Dict
+NodeData = Dict[str, Any]
+EdgeData = Dict[str, Any]
 
 Node = int
 Edge = Tuple[int, int]
@@ -26,5 +28,9 @@ def consumption(G: nx.Graph, u: Node, v: Node) -> Wh:
     return G.edges[u, v]['c']
 
 
+def distance(G: nx.Graph, u: Node, v: Node) -> Time:
+    return G.edges[u, v]['weight']
+
+
 def charging_cofficient(G: nx.Graph, n: Node) -> ChargingCoefficient:
     return G.nodes[n]['c']
-- 
GitLab