diff --git a/evrouting/T.py b/evrouting/T.py
index 7a1e1a91ee1268b6e56c1ce1e3b852ee09f42077..e95dbd259a2e81b808ad5844072e165ad02020fa 100644
--- a/evrouting/T.py
+++ b/evrouting/T.py
@@ -1,5 +1,12 @@
-from typing import NewType, Tuple
+from typing import Tuple, Union, NewType
+from math import inf
 
-Node = NewType('Node', int)
-Edge = NewType('Edge', Tuple[Node, Node])
-SoC = NewType('SoC', float)
\ No newline at end of file
+Node = int
+Edge = Tuple[Node, Node]
+
+Wh = NewType('Wh', Union[float, int])
+SoC = NewType('SoC', Union[-inf, Wh])
+
+ChargingCoefficient = float
+
+Time = Union[float, int]
diff --git a/evrouting/charge/T.py b/evrouting/charge/T.py
index 25cd02828d0e4b7f9662a44e2ed9d75de5729bb1..069c6cf6cf6f101f7fe62297f09b1d0eb61c9b3b 100644
--- a/evrouting/charge/T.py
+++ b/evrouting/charge/T.py
@@ -1,5 +1,59 @@
-from typing import NewType, Callable
+from copy import copy
+from collections import namedtuple
+from math import inf
 
-from evrouting.T import SoC
+import networkx as nx
 
-SoCProfile = NewType('SoCProfile', Callable[[SoC], SoC])
+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 ChargingFunction:
+
+    def __init__(self, G: nx.Graph, l: Label):
+        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.c_u: ChargingCoefficient = charging_cofficient(G, l.u)
+
+    def __call__(self, t) -> SoC:
+        if t < self.t_trip:
+            return -inf
+
+        return self.beta_u(self.beta_u + self.c_u * (t - self.t_trip))
+
+    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.c_u + self.t_trip)
+
+
+class SoCProfile:
+    """
+    Describe SoC profile with two parameters:
+        - cost: Cost of going from u to v.
+        - out: Maximal SoC after passing the path from u to v.
+    """
+
+    def __init__(self, G: nx.Graph, U: SoC, u: Node, v: Node = None):
+        if v is None:
+            self.cost: Wh = 0
+            self.out: Wh = U
+        else:
+            self.cost: Wh = consumption(G, u, v)
+            self.out: Wh = U - self.cost
+
+    def __call__(self, beta) -> SoC:
+        if beta < self.cost:
+            return -inf
+        return beta - self.cost
+
+    def __add__(self, other: 'SoCProfile') -> 'SoCProfile':
+        new = copy(self)
+        new.cost = self.cost + other.cost
+        new.out = self.out - other.cost
+
+        return new
diff --git a/evrouting/charge/routing.py b/evrouting/charge/routing.py
index e9a2deff9cc73a29588ffe1b7305b5d38630a5df..c4809decc5c98620a6ea217a1cc0b06ac7bf96b4 100644
--- a/evrouting/charge/routing.py
+++ b/evrouting/charge/routing.py
@@ -1,16 +1,84 @@
+from typing import List
+from math import inf
+
 import networkx as nx
+from evrouting.T import Node, SoC, Time, ChargingCoefficient
+from evrouting.utils import PriorityQueue
+
+from .T import SoCProfile, ChargingFunction, Label
 
 
-def shortest_path(G: nx.Graph, s, t, b_0: float, b_t: float, U: float):
+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.
 
     :param G: Input Graph
     :param s: Start Node identifier
     :param t: End Node identifier
-    :param b_0: Start SoC
-    :param b_t: End SoC
+    :param beta_s: Start SoC
+    :param beta_t: End SoC
     :param U: Capacity
     :return:
     """
+    q = PriorityQueue()
+    l_set = {v: set() for v in G}
+    l_uns = {v: PriorityQueue() for v in G}
+
+    # Dummy vertex without incident edges that is (temporarily) added to G
+    v_0: Node = Node(len(G.nodes))
+    G.add_node(v_0)
+
+    S.add(v_0)
+
+    cf_v_0 = [(0, beta_s)]
+    l_uns[s] = PriorityQueue()
+
+    l = Label(0, beta_s, v_0, SoCProfile(G, U, s))
+    l_uns[s].insert(item=l, priority=key(l))
+
+    q.insert(s, 0)
+
+    # run main loop
+    while True:
+        try:
+            v = q.peak_min()
+        except KeyError:
+            # empty queue
+            break
+
+        l = l_uns[v].delete_min()
+        l_set[v].add(l)
+
+        if v == t:
+            return ChargingFunction(G, l).get_minimum()
+
+        # 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??
+
+        # update priority queue
+        if l_uns[v]:
+            l_new = l_uns[v].peak_min()
+            q.insert(v, key(l_new))
+        else:
+            q.delete_min()
+
+        # 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)
+                l_uns[y].insert(l_new)
+                if l_new == l_uns[y].peak_min():
+                    q.insert(y, key(l_new))
+
+
+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 65f9053df0818c64db0f95ef21186bd4c382d2e2..2d92456f5e345e5a71db7150276a60d74f32347e 100644
--- a/evrouting/graph_tools.py
+++ b/evrouting/graph_tools.py
@@ -1,12 +1,30 @@
+from typing import Dict, Tuple
 from collections import namedtuple
 
-Street = namedtuple('Street', ['u', 'v', 'distance', 'consumption'])
-Node = namedtuple('Node', ['label', 'charging_coeff'], defaults=(None, None))
+import networkx as nx
+from evrouting.T import Wh, ChargingCoefficient
 
+TemplateEdge = namedtuple('Edge', ['u', 'v', 'distance', 'consumption'])
+TemplateNode = namedtuple('Node', ['label', 'charging_coeff'], defaults=(None, None))
 
-def node_convert(n: Node) -> dict:
+NodeData = Dict
+EdgeData = Dict
+
+Node = int
+Edge = Tuple[int, int]
+
+
+def node_convert(n: TemplateNode) -> NodeData:
     return {'label': n.label, 'c': n.charging_coeff}
 
 
-def street_convert(s: Street) -> dict:
-    return {'weight': s.distance, 'c': s.consumption}
+def edge_convert(e: TemplateEdge) -> EdgeData:
+    return {'weight': e.distance, 'c': e.consumption}
+
+
+def consumption(G: nx.Graph, u: Node, v: Node) -> Wh:
+    return G.edges[u, v]['c']
+
+
+def charging_cofficient(G: nx.Graph, n: Node) -> ChargingCoefficient:
+    return G.nodes[n]['c']
diff --git a/evrouting/utils.py b/evrouting/utils.py
index e19100959ef999434fae2a3236fb73ef678827fe..8aa001fc41dee4cc845c37141a8aa834d71e47c1 100644
--- a/evrouting/utils.py
+++ b/evrouting/utils.py
@@ -1,4 +1,5 @@
 import itertools
+from typing import Any
 from heapq import *
 
 
@@ -10,7 +11,7 @@ class PriorityQueue:
         self.entry_finder = {}  # mapping of tasks to entries
         self.counter = itertools.count()  # unique sequence count as tie break
 
-    def insert(self, item, priority=0):
+    def insert(self, item: Any, priority=0):
         """Add a new task or update the priority of an existing task"""
         if item in self.entry_finder:
             self.remove_item(item)
@@ -19,12 +20,12 @@ class PriorityQueue:
         self.entry_finder[item] = entry
         heappush(self.pq, entry)
 
-    def remove_item(self, item):
+    def remove_item(self, item: Any):
         """Mark an existing task as REMOVED.  Raise KeyError if not found."""
         entry = self.entry_finder.pop(item)
         entry[-1] = self.REMOVED
 
-    def delete_min(self):
+    def delete_min(self) -> Any:
         """Remove and return the lowest priority task. Raise KeyError if empty."""
         while self.pq:
             priority, count, item = heappop(self.pq)
@@ -33,7 +34,7 @@ class PriorityQueue:
                 return item
         raise KeyError('pop from an empty priority queue')
 
-    def peak_min(self):
+    def peak_min(self) -> Any:
         """Return minimum item without removing it from the queue."""
         while self.pq:
             priority, count, item = self.pq[0]
diff --git a/tests/config.py b/tests/config.py
index b0a4fc2500923127697f3b1666d093694cdcad1e..7c0461a01009a6bc360fa4981c2f5129b1883cb7 100644
--- a/tests/config.py
+++ b/tests/config.py
@@ -1,6 +1,8 @@
 import networkx as nx
 
-from evrouting.graph_tools import Node, Street, node_convert, street_convert
+from evrouting.graph_tools import node_convert, edge_convert
+from evrouting.graph_tools import TemplateEdge as Edge
+from evrouting.graph_tools import TemplateNode as Node
 
 # List of configs
 config_list = ['edge_case']
@@ -17,9 +19,9 @@ edge_case = {
         Node('t'),
     ],
     'edges': [
-        Street(0, 1, distance=1, consumption=1),
-        Street(0, 2, distance=1, consumption=4),
-        Street(1, 2, distance=1, consumption=1),
+        Edge(0, 1, distance=1, consumption=1),
+        Edge(0, 2, distance=1, consumption=4),
+        Edge(1, 2, distance=1, consumption=1),
     ]
 }
 
@@ -31,6 +33,6 @@ def get_graph(config):
         G.add_node(node_id, **node_convert(node))
 
     for edge in config['edges']:
-        G.add_edge(edge.u, edge.v, **street_convert(edge))
+        G.add_edge(edge.u, edge.v, **edge_convert(edge))
 
     return G