Skip to content

Commit

Permalink
fix enumerate_paths
Browse files Browse the repository at this point in the history
see discussion in JuliaAttic#150
  • Loading branch information
yeesian authored and ggggggggg committed Mar 17, 2015
1 parent e8bca27 commit a902e95
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 70 deletions.
43 changes: 33 additions & 10 deletions doc/source/algorithms.rst
Original file line number Diff line number Diff line change
Expand Up @@ -184,36 +184,59 @@ 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:: enumerate_paths(result[, dest])
.. py:function:: enumerate_paths(vertices, parent_indices[, 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``.
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 indices, or left unspecified (in which case, all the indices will be considered). If ``dest`` is a single index, 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``.
.. py:function:: enumerate_indices(parent_indices[, dest])
Returns an array of indices corresponding to the vertices returned by `enumerate_paths(vertices, parent_indices[, dest])`
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
julia> g4 = Graphs.inclist([4,5,6,7],is_directed=true)
julia> add_edge!(g4,4,5); add_edge!(g4,4,6); add_edge!(g4,5,6); add_edge!(g4,6,7)
julia> s4 = dijkstra_shortest_paths(g4,5)
julia> sps = enumerate_indices(s4.parent_indices) # dest: all indices
4-element Array{Array{Int64,1},1}:
[]
[2]
[2,3]
[2,3,4]
julia> sps = enumerate_paths(s3, [2,4]) # dest: subset of vertices
julia> enumerate_indices(s4.parent_indices, [2,4]) # dest: subset of indices
2-element Array{Array{Int64,1},1}:
[2]
[2,3,4]
julia> sps = enumerate_paths(s3, 4) # dest: single vertex
julia> enumerate_indices(s4.parent_indices, 4) # dest: single index
3-element Array{Int64,1}:
2
3
4
julia> enumerate_paths(vertices(g4), s4.parent_indices) # dest: all vertices
4-element Array{Array{Int64,1},1}:
[]
[5]
[5,6]
[5,6,7]
julia> enumerate_paths(vertices(g4), s4.parent_indices, [2,4]) # dest: subset of vertices
2-element Array{Array{Int64,1},1}:
[5]
[5,6,7]
julia> enumerate_paths(vertices(g4), s4.parent_indices, 4) # dest: single vertex
3-element Array{Int64,1}:
5
6
7
**Remark**: ``enumerate_paths`` and ``enumerate_indices`` are applicable to the results from both ``dijkstra_shortest_paths`` and ``bellman_ford_shortest_paths``.
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,
enumerate_paths,
enumerate_paths, enumerate_indices,

# bellmanford
BellmanFordStates, create_bellman_ford_states, NegativeCycleError,
Expand Down
33 changes: 5 additions & 28 deletions src/bellmanford.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type NegativeCycleError <: Exception end

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

Expand All @@ -19,10 +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)
parent_indices = zeros(Int, n)
dists = fill(typemax(D), n)

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

function bellman_ford_shortest_paths!{V,D}(
Expand All @@ -40,6 +40,7 @@ function bellman_ford_shortest_paths!{V,D}(
i = vertex_index(v, graph)
state.dists[i] = 0
state.parents[i] = v
state.parent_indices[i] = i
push!(active, v)
end
no_changes = false
Expand All @@ -55,7 +56,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
state.parent_indices[vind] = vertex_index(u, graph)
no_changes = false
push!(new_active, v)
end
Expand Down Expand Up @@ -109,27 +110,3 @@ function has_negative_edge_cycle{V, D}(
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)])

40 changes: 20 additions & 20 deletions src/dijkstra_spath.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

type DijkstraStates{V,D<:Number,Heap,H}
parents::Vector{V}
hasparent::Vector{Bool}
parent_indices::Vector{Int}
dists::Vector{D}
colormap::Vector{Int}
heap::Heap
Expand All @@ -27,13 +27,13 @@ end
function create_dijkstra_states{V,D<:Number}(g::AbstractGraph{V}, ::Type{D})
n = num_vertices(g)
parents = Array(V, n)
hasparent = fill(false, n)
parent_indices = zeros(Int, n)
dists = fill(typemax(D), n)
colormap = zeros(Int, n)
heap = mutable_binary_minheap(DijkstraHEntry{V,D})
hmap = zeros(Int, n)

DijkstraStates(parents, hasparent, dists, colormap, heap, hmap)
DijkstraStates(parents, parent_indices, dists, colormap, heap, hmap)
end

###################################################################
Expand Down 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] = false
state.parent_indices[i] = i
state.dists[i] = 0
state.colormap[i] = 2
end
Expand All @@ -111,7 +111,7 @@ function process_neighbors!{V,D,Heap,H}(

dists::Vector{D} = state.dists
parents::Vector{V} = state.parents
hasparent::Vector{Bool} = state.hasparent
parent_indices::Vector{Int} = state.parent_indices
colormap::Vector{Int} = state.colormap
heap::Heap = state.heap
hmap::Vector{H} = state.hmap
Expand All @@ -125,7 +125,7 @@ function process_neighbors!{V,D,Heap,H}(
if v_color == 0
dists[iv] = dv = du + edge_property(edge_dists, e, graph)
parents[iv] = u
hasparent[iv] = true
parent_indices[iv] = vertex_index(u, graph)
colormap[iv] = 1
discover_vertex!(visitor, u, v, dv)

Expand All @@ -137,7 +137,7 @@ function process_neighbors!{V,D,Heap,H}(
if dv < dists[iv]
dists[iv] = dv
parents[iv] = u
hasparent[iv] = true
parent_indices[iv] = vertex_index(u, graph)

# update the value on the heap
update_vertex!(visitor, u, v, dv)
Expand Down Expand Up @@ -254,19 +254,16 @@ dijkstra_shortest_paths{V}(
graph::AbstractGraph{V}, s::V
) = dijkstra_shortest_paths(graph, ones(num_vertices(graph)), s)

function enumerate_paths{V,D,Heap,H}(state::DijkstraStates{V,D,Heap,H}, dest::Vector{V})
parents = state.parents
hasparent = state.hasparent

num_dest = length(dest)
all_paths = Array(Vector{V},num_dest)
function enumerate_indices(parent_indices::Vector{Int}, dest_indices::Vector{Int})
num_dest = length(dest_indices)
all_paths = Array(Vector{Int},num_dest)
for i=1:num_dest
all_paths[i] = V[]
index = dest[i]
if hasparent[index] || parents[index] == index
while hasparent[index]
all_paths[i] = Int[]
index = dest_indices[i]
if parent_indices[index] != 0
while parent_indices[index] != index
push!(all_paths[i], index)
index = parents[index]
index = parent_indices[index]
end
push!(all_paths[i], index)
reverse!(all_paths[i])
Expand All @@ -275,5 +272,8 @@ function enumerate_paths{V,D,Heap,H}(state::DijkstraStates{V,D,Heap,H}, dest::Ve
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)])
enumerate_indices(parent_indices::Vector{Int}, dest_index::Int) = enumerate_indices(parent_indices, Int[dest_index])[1]
enumerate_indices(parent_indices::Vector{Int}) = enumerate_indices(parent_indices, [1:length(parent_indices)])
enumerate_paths(vertices, parent_indices::Vector{Int}, dest_indices::Vector{Int}) = [vertices[i] for i in enumerate_indices(parent_indices, dest_indices)]
enumerate_paths(vertices, parent_indices::Vector{Int}, dest_index::Int) = enumerate_paths(vertices, parent_indices, [dest_index])[1]
enumerate_paths(vertices, parent_indices::Vector{Int}) = enumerate_paths(vertices, parent_indices, [1:length(parent_indices)])
12 changes: 5 additions & 7 deletions test/bellman_test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,9 @@ 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)
sps = enumerate_paths(vertices(g1), s1.parent_indices)
@test length(sps) == 5
@test sps[1] == [1]
@test sps[2] == [1,3,2]
Expand All @@ -47,24 +46,23 @@ sps = enumerate_paths(s1)
@test sps[5] == [1,3,5]

## multiple destinations
sps = enumerate_paths(s1, [2,4])
sps = enumerate_paths(vertices(g1), s1.parent_indices, [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)
sps = enumerate_paths(vertices(g1), s1.parent_indices, 2)
@test sps == [1,3,2]
@test sps == enumerate_paths(s1, [2])[1]
@test sps == enumerate_paths(vertices(g1), s1.parent_indices, [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)
sps = enumerate_paths(vertices(g1), s1.parent_indices)
@test sps[1] == [1]
@test sps[2] == [2]
@test sps[3] == [2,3]
Expand Down
42 changes: 38 additions & 4 deletions test/dijkstra.jl
Original file line number Diff line number Diff line change
Expand Up @@ -115,17 +115,51 @@ g3 = simple_graph(4)
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)
sps = enumerate_paths(vertices(g3), s3.parent_indices)
@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])
sps = enumerate_paths(vertices(g3), s3.parent_indices, [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]
sps = enumerate_paths(vertices(g3), s3.parent_indices, 4)
@test sps == [2, 3, 4]

g4 = Graphs.inclist([4,5,6,7],is_directed=true)
add_edge!(g4,4,5); add_edge!(g4,4,6); add_edge!(g4,5,6); add_edge!(g4,6,7)

s4 = dijkstra_shortest_paths(g4,5)
sps = enumerate_indices(s4.parent_indices)
@test length(sps) == 4
@test sps[1] == []
@test sps[2] == [2]
@test sps[3] == [2, 3]
@test sps[4] == [2, 3, 4]

sps = enumerate_indices(s4.parent_indices, [2,4])
@test length(sps) == 2
@test sps[1] == [2]
@test sps[2] == [2, 3, 4]

sps = enumerate_indices(s4.parent_indices, 4)
@test sps == [2, 3, 4]

sps = enumerate_paths(vertices(g4), s4.parent_indices)
@test length(sps) == 4
@test sps[1] == []
@test sps[2] == [5]
@test sps[3] == [5, 6]
@test sps[4] == [5, 6, 7]

sps = enumerate_paths(vertices(g4), s4.parent_indices, [2,4])
@test length(sps) == 2
@test sps[1] == [5]
@test sps[2] == [5, 6, 7]

sps = enumerate_paths(vertices(g4), s4.parent_indices, 4)
@test sps == [5, 6, 7]

0 comments on commit a902e95

Please sign in to comment.