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

fix enumerate_paths #159

Merged
merged 1 commit into from
Jan 30, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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]