Skip to content

Commit

Permalink
dijkstra for directed
Browse files Browse the repository at this point in the history
  • Loading branch information
tscizzle committed Nov 9, 2016
1 parent 078e169 commit cd6b4c4
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 5 deletions.
60 changes: 59 additions & 1 deletion graphpy/graph.py
Expand Up @@ -663,4 +663,62 @@ def dijkstra(self, start_val, goal_val=None, return_distances=False,
raise ValueError(str(e) + " must have a weight")
if edge_weight < 0:
raise ValueError(str(e) + " must have a non-negative weight")
raise NotImplementedError
start = self.get_vertex(start_val)
goal = self.get_vertex(goal_val)

distances = {v: float('inf') for v in self}
predecessors = {v: -1 for v in self}
cloud_so_far = set([start])

distances[start] = 0
predecessors[start] = None

# relax edges until there are no vertices left not in the cloud
vertex_queue = priority_queue(data=[(distances[v], v) for v in self])
while vertex_queue:
# move the closest vertex that's not in the cloud into the cloud
_, current_vertex = vertex_queue.pop_min()
cloud_so_far.add(current_vertex)

# if searching for a specific vertex, check if this is it
if current_vertex == goal:
break

# conditionally relax each of that vertex's edges
current_distance = distances[current_vertex]
eligible_outs = [n for n in current_vertex.outs
if n not in cloud_so_far]
for out in eligible_outs:
current_out_distance = distances[out]
e = self.get_edge((current_vertex.val, out.val))
new_out_distance = current_distance + e.get('weight')
if new_out_distance < current_out_distance:
distances[out] = new_out_distance
predecessors[out] = current_vertex
vertex_queue.decrease_key(out, new_out_distance)

# with the algorithm complete, prepare the output

namify_keys = lambda dic: {v.val: d for v, d in dic.items()}
namify_values = lambda dic: {k: v.val if hasattr(v, 'val') else v
for k, v in dic.items()}
namified_distances = namify_keys(distances)
namified_predecessors = namify_values(namify_keys(predecessors))

def backtrack(target_val):
""" Use our predecessor map to get the shortest path from our start
to some target """
if namified_predecessors[target_val] == -1:
return None
path = [target_val]
while namified_predecessors[path[-1]] is not None:
path.append(namified_predecessors[path[-1]])
path.reverse()
return path

if goal_val is not None:
return (namified_distances[goal_val] if return_distances
else backtrack(goal_val))
else:
return (namified_distances if return_distances
else keydefaultdict(backtrack))
4 changes: 0 additions & 4 deletions tests/test_graph.py
Expand Up @@ -934,10 +934,6 @@ def test_directed_graph_search(self):
def test_directed_graph_dijkstra(self):
""" Perform Dijkstra's algorithm on a directed graph """

## TODO: design directed graphs for regular (including non-reachable),
## and negative values, including a check that direction of edges
## matters

""" 1_ E 1_ E
| / | /
| < | <
Expand Down

0 comments on commit cd6b4c4

Please sign in to comment.