Skip to content
This repository has been archived by the owner on Oct 21, 2021. It is now read-only.

Commit

Permalink
Merge pull request #153 from yeesian/master
Browse files Browse the repository at this point in the history
implement enumerate_paths
  • Loading branch information
pozorvlak committed Jan 12, 2015
2 parents c9b4317 + a6bdd0c commit d018f24
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 26 deletions.
33 changes: 28 additions & 5 deletions doc/source/algorithms.rst
Original file line number Diff line number Diff line change
Expand Up @@ -184,12 +184,35 @@ The user can (optionally) provide a visitor that perform operations along with t
Invoked when a vertex is closed (all its neighbors have been examined).
.. py:function:: dijkstra_shortest_paths_explicit(graph, edge_dists, source[, visitor])
Returns the explicit paths using ``dijkstra_shortest_paths()`` as an array of
vectors of vertices from the source to each target. Empty vectors are used to
indicate vertices that are unreachable from the source. Parameters are the same
as described in ``dijkstra_shortest_paths()``.
.. py:function:: enumerate_paths(result[, dest])
Returns an array of vectors (containing vertices), whose ``i``-th element corresponds to the path from a source to vertex ``dest[i]``. Empty vectors indicate vertices that are unreachable from the source. ``dest`` can be a subset of vertices, or left unspecified (in which case, all the vertices in the graph will be considered). If ``dest`` is a single vertex, then the result is just an array of vertices, corresponding to the path from a source to ``dest``.
**Remark**: ``enumerate_paths`` is applicable to both ``DijkstraStates`` and ``BellmanFordStates``.
The following is an example that shows how to use this function:
.. code-block:: python
julia> using Graphs
julia> g3 = simple_graph(4)
julia> add_edge!(g3,1,2); add_edge!(g3,1,3); add_edge!(g3,2,3); add_edge!(g3,3,4);
julia> s3 = dijkstra_shortest_paths(g3,2)
julia> sps = enumerate_paths(s3) # dest: all vertices
4-element Array{Array{Int64,1},1}:
[]
[2]
[2,3]
[2,3,4]
julia> sps = enumerate_paths(s3, [2,4]) # dest: subset of vertices
2-element Array{Array{Int64,1},1}:
[2]
[2,3,4]
julia> sps = enumerate_paths(s3, 4) # dest: single vertex
3-element Array{Int64,1}:
2
3
4
Bellman Ford Algorithm
~~~~~~~~~~~~~~~~~~~~
Expand Down
2 changes: 1 addition & 1 deletion src/Graphs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ module Graphs
DijkstraStates, create_dijkstra_states, AbstractDijkstraVisitor,
dijkstra_shortest_paths!, dijkstra_shortest_paths,
dijkstra_shortest_paths_withlog,
dijkstra_shortest_paths_explicit,
enumerate_paths,

# bellmanford
BellmanFordStates, create_bellman_ford_states, NegativeCycleError,
Expand Down
30 changes: 29 additions & 1 deletion src/bellmanford.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ type NegativeCycleError <: Exception end

type BellmanFordStates{V,D<:Number}
parents::Vector{V}
hasparent::Vector{Bool}
dists::Vector{D}
end

Expand All @@ -18,9 +19,10 @@ end
function create_bellman_ford_states{V,D<:Number}(g::AbstractGraph{V}, ::Type{D})
n = num_vertices(g)
parents = Array(V, n)
hasparent = fill(false, n)
dists = fill(typemax(D), n)

BellmanFordStates(parents, dists)
BellmanFordStates(parents,hasparent, dists)
end

function bellman_ford_shortest_paths!{V,D}(
Expand Down Expand Up @@ -53,6 +55,7 @@ function bellman_ford_shortest_paths!{V,D}(
if state.dists[vind] > state.dists[uind] + edist
state.dists[vind] = state.dists[uind] + edist
state.parents[vind] = u
state.hasparent[vind] = true
no_changes = false
push!(new_active, v)
end
Expand Down Expand Up @@ -105,3 +108,28 @@ function has_negative_edge_cycle{V, D}(
edge_inspector = VectorEdgePropertyInspector{D}(edge_dists)
has_negative_edge_cycle(graph, edge_inspector)
end

function enumerate_paths{V,D<:Number}(state::BellmanFordStates{V,D}, dest::Vector{V})
parents = state.parents
hasparent = state.hasparent

num_dest = length(dest)
all_paths = Array(Vector{V},num_dest)
for i=1:num_dest
all_paths[i] = V[]
index = dest[i]
if hasparent[index] || parents[index] == index
while hasparent[index]
push!(all_paths[i], index)
index = parents[index]
end
push!(all_paths[i], index)
reverse!(all_paths[i])
end
end
all_paths
end

enumerate_paths{V,D<:Number}(state::BellmanFordStates{V,D}, dest) = enumerate_paths(state, [dest])[1]
enumerate_paths{V,D<:Number}(state::BellmanFordStates{V,D}) = enumerate_paths(state, [1:length(state.parents)])

30 changes: 15 additions & 15 deletions src/dijkstra_spath.jl
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ end
function set_source!{V,D}(state::DijkstraStates{V,D}, g::AbstractGraph{V}, s::V)
i = vertex_index(s, g)
state.parents[i] = s
state.hasparent[i] = true
state.hasparent[i] = false
state.dists[i] = 0
state.colormap[i] = 2
end
Expand Down Expand Up @@ -252,28 +252,28 @@ end

dijkstra_shortest_paths{V}(
graph::AbstractGraph{V}, s::V
) = dijkstra_shortest_paths(graph, ones(num_edges(graph)), s)
) = dijkstra_shortest_paths(graph, ones(num_vertices(graph)), s)

function dijkstra_shortest_paths_explicit{V}(g::AbstractGraph{V},source::V, all...)
state = dijkstra_shortest_paths(g, source, all...)
function enumerate_paths{V,D,Heap,H}(state::DijkstraStates{V,D,Heap,H}, dest::Vector{V})
parents = state.parents
hasparent = state.hasparent

nstates = length(parents)
all_paths = Array(Vector{V},nstates)
for i in 1:nstates
num_dest = length(dest)
all_paths = Array(Vector{V},num_dest)
for i=1:num_dest
all_paths[i] = V[]
child_index = i
if hasparent[child_index]
parent_index = parents[child_index]
while child_index != parent_index
push!(all_paths[i], child_index)
child_index = parent_index
parent_index = parents[child_index]
index = dest[i]
if hasparent[index] || parents[index] == index
while hasparent[index]
push!(all_paths[i], index)
index = parents[index]
end
push!(all_paths[i], child_index)
push!(all_paths[i], index)
reverse!(all_paths[i])
end
end
all_paths
end

enumerate_paths{V,D,Heap,H}(state::DijkstraStates{V,D,Heap,H}, dest::V) = enumerate_paths(state, V[dest])[1]
enumerate_paths{V,D,Heap,H}(state::DijkstraStates{V,D,Heap,H}) = enumerate_paths(state, [1:length(state.parents)])
37 changes: 37 additions & 0 deletions test/bellman_test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,48 @@ end
@assert num_vertices(g1) == 5
@assert num_edges(g1) == 10

# Single Source

s1 = bellman_ford_shortest_paths(g1, eweights1, [1])

@test s1.parents == [1, 3, 1, 2, 3]
@test s1.dists == [0., 8., 5., 9., 7.]
@test s1.hasparent == [false, true, true, true, true]

## all destinations
sps = enumerate_paths(s1)
@test length(sps) == 5
@test sps[1] == [1]
@test sps[2] == [1,3,2]
@test sps[3] == [1,3]
@test sps[4] == [1,3,2,4]
@test sps[5] == [1,3,5]

## multiple destinations
sps = enumerate_paths(s1, [2,4])
@test length(sps) == 2
@test sps[1] == [1,3,2]
@test sps[2] == [1,3,2,4]

## single destination
sps = enumerate_paths(s1, 2)
@test sps == [1,3,2]
@test sps == enumerate_paths(s1, [2])[1]

# Multiple Sources

s1 = bellman_ford_shortest_paths(g1, eweights1, [1, 2])
@test s1.parents == [1, 2, 2, 2, 3]
@test s1.dists == [0., 0., 2., 1., 4.]
@test s1.hasparent == [false, false, true, true, true]

sps = enumerate_paths(s1)
@test sps[1] == [1]
@test sps[2] == [2]
@test sps[3] == [2,3]
@test sps[4] == [2,4]
@test sps[5] == [2,3,5]

@test !has_negative_edge_cycle(g1, eweights1)

immutable MyEdge{V}
Expand Down
21 changes: 17 additions & 4 deletions test/dijkstra.jl
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,20 @@ s2 = dijkstra_shortest_paths(g2, eweights2, [1])
@test s2.colormap == [2, 2, 2, 2, 2, 2]

g3 = simple_graph(4)
add_edge!(g3,1,2); add_edge!(g3,1,3); add_edge!(g3,2,3); add_edge!(g3,3,4); add_edge!(g3,4,3); add_edge!(g3,3,1)
sps = dijkstra_shortest_paths_explicit(g3,2)
@test length(sps[1]) == 3
@test sps[4][2] == 3
add_edge!(g3,1,2); add_edge!(g3,1,3); add_edge!(g3,2,3); add_edge!(g3,3,4)

s3 = dijkstra_shortest_paths(g3,2)
sps = enumerate_paths(s3)
@test length(sps) == 4
@test sps[1] == []
@test sps[2] == [2]
@test sps[3] == [2, 3]
@test sps[4] == [2, 3, 4]

sps = enumerate_paths(s3, [2,4])
@test length(sps) == 2
@test sps[1] == [2]
@test sps[2] == [2, 3, 4]

sps = enumerate_paths(s3, 4)
@test sps == [2, 3, 4]

0 comments on commit d018f24

Please sign in to comment.