-
Notifications
You must be signed in to change notification settings - Fork 96
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
two sided dijkstra #268
base: master
Are you sure you want to change the base?
two sided dijkstra #268
Changes from 17 commits
9b43737
b37aefd
779b167
a2d65d4
d28db69
515091c
e3bede8
20b5bb8
2abd6b7
7504b6d
806593d
0de4e92
cb9eebe
e9aecef
40bb78a
22670f3
3b2d21a
313c464
08d696a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -83,7 +83,7 @@ function dijkstra_shortest_paths( | |
parents = zeros(U, nvg) | ||
visited = zeros(Bool, nvg) | ||
|
||
pathcounts = zeros(nvg) | ||
pathcounts = zeros(Int, nvg) | ||
preds = fill(Vector{U}(), nvg) | ||
H = PriorityQueue{U,T}() | ||
# fill creates only one array. | ||
|
@@ -110,33 +110,11 @@ function dijkstra_shortest_paths( | |
alt = d + distmx[u, v] | ||
|
||
alt > maxdist && continue | ||
|
||
if !visited[v] | ||
visited[v] = true | ||
dists[v] = alt | ||
parents[v] = u | ||
|
||
pathcounts[v] += pathcounts[u] | ||
if allpaths | ||
preds[v] = [u;] | ||
end | ||
H[v] = alt | ||
elseif alt < dists[v] | ||
dists[v] = alt | ||
parents[v] = u | ||
#615 | ||
pathcounts[v] = pathcounts[u] | ||
if allpaths | ||
resize!(preds[v], 1) | ||
preds[v][1] = u | ||
end | ||
H[v] = alt | ||
elseif alt == dists[v] | ||
pathcounts[v] += pathcounts[u] | ||
if allpaths | ||
push!(preds[v], u) | ||
end | ||
end | ||
relax(u,v,distmx,dists,parents,visited,H; | ||
allpaths=allpaths, | ||
pathcounts=pathcounts, | ||
preds=preds | ||
) | ||
end | ||
end | ||
|
||
|
@@ -169,3 +147,132 @@ function dijkstra_shortest_paths( | |
g, [src;], distmx; allpaths=allpaths, trackvertices=trackvertices, maxdist=maxdist | ||
) | ||
end | ||
|
||
function relax(u, | ||
v, | ||
distmx::AbstractMatrix{T}, | ||
dists::Vector{T}, | ||
parents::Vector{U}, | ||
visited::Vector{Bool}, | ||
Q::PriorityQueue{U,T}; | ||
allpaths=false, | ||
pathcounts=nothing, | ||
preds=nothing, | ||
forward=true | ||
) where {T<:Real} where {U<:Integer} | ||
alt = dists[u] + (forward ? distmx[u, v] : distmx[v, u]) | ||
|
||
if !visited[v] | ||
visited[v] = true | ||
dists[v] = alt | ||
parents[v] = u | ||
|
||
if !isnothing(pathcounts) | ||
pathcounts[v] += pathcounts[u] | ||
end | ||
if allpaths | ||
preds[v] = [u;] | ||
end | ||
Q[v] = alt | ||
elseif alt < dists[v] | ||
dists[v] = alt | ||
parents[v] = u | ||
#615 | ||
if !isnothing(pathcounts) | ||
pathcounts[v] = pathcounts[u] | ||
end | ||
if allpaths | ||
resize!(preds[v], 1) | ||
preds[v][1] = u | ||
end | ||
Q[v] = alt | ||
elseif alt == dists[v] | ||
if !isnothing(pathcounts) | ||
pathcounts[v] += pathcounts[u] | ||
end | ||
if allpaths | ||
push!(preds[v], u) | ||
end | ||
end | ||
end | ||
|
||
""" | ||
bidijkstra_shortest_paths(g, src, dst, distmx=weights(g)); | ||
|
||
Perform [Bidirectional Dijkstra's algorithm](https://www.homepages.ucl.ac.uk/~ucahmto/math/2020/05/30/bidirectional-dijkstra.html) | ||
on a graph, computing the shortest path between `src` and `dst`. | ||
|
||
# Examples | ||
```jldoctest | ||
julia> using Graphs | ||
|
||
julia> bidijkstra_shortest_path(cycle_graph(5), 1, 4) | ||
3-element Vector{Int64}: | ||
1 | ||
5 | ||
4 | ||
|
||
julia> bidijkstra_shortest_path(path_graph(5), 1, 4) | ||
4-element Vector{Int64}: | ||
1 | ||
2 | ||
3 | ||
4 | ||
``` | ||
""" | ||
function bidijkstra_shortest_path( | ||
g::AbstractGraph, | ||
src::U, | ||
dst::U, | ||
distmx::AbstractMatrix{T}=weights(g) | ||
) where {T<:Real} where {U<:Integer} | ||
if src == dst | ||
return Int[] | ||
end | ||
# keep weight of the best seen path and the midpoint vertex | ||
μ, mid_v = typemax(T), -1 | ||
nvg = nv(g) | ||
dists_f, dists_b= fill(typemax(T), nvg), fill(typemax(T), nvg) | ||
parents_f, parents_b= zeros(U, nvg), zeros(U, nvg) | ||
visited_f, visited_b = zeros(Bool, nvg),zeros(Bool, nvg) | ||
preds_f, preds_b = fill(Vector{U}(), nvg), fill(Vector{U}(), nvg) | ||
Qf, Qb = PriorityQueue{U,T}(), PriorityQueue{U,T}() | ||
|
||
dists_f[src], dists_b[dst]= zero(T), zero(T) | ||
visited_f[src], visited_b[dst]= true, true | ||
Qf[src], Qb[dst] = zero(T), zero(T) | ||
|
||
while !isempty(Qf) && !isempty(Qb) | ||
uf, ub = dequeue!(Qf), dequeue!(Qb) | ||
|
||
for v in outneighbors(g, uf) | ||
relax(uf, v, distmx, dists_f, parents_f, visited_f, Qf) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This relax function clarifies things, would it be hard to add it to the original There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was hoping you would notice =p I'll make the changes There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have a new version of the |
||
if visited_b[v] && (dists_f[uf]+distmx[uf,v]+dists_b[v]) < μ | ||
# we have found an edge between the forward and backward exploration | ||
μ = dists_f[uf]+distmx[uf,v]+dists_b[v] | ||
mid_v = v | ||
end | ||
end | ||
|
||
for v in inneighbors(g, ub) | ||
relax(ub, v, distmx, dists_b, parents_b, visited_b, Qb; forward=false) | ||
if visited_f[v] && (dists_f[v]+distmx[v,ub]+dists_b[ub]) < μ | ||
# we have found an edge between the forward and backward exploration | ||
μ = dists_f[v]+distmx[v,ub]+dists_b[ub] | ||
mid_v = v | ||
end | ||
end | ||
if dists_f[uf]+dists_b[ub] >= μ | ||
break | ||
end | ||
end | ||
if mid_v == -1 | ||
# no path exists between source and destination | ||
return Int[] | ||
end | ||
ds_f = DijkstraState{T,U}(parents_f, dists_f, preds_f, zeros(nvg), Vector{U}()) | ||
ds_b = DijkstraState{T,U}(parents_b, dists_b, preds_b, zeros(nvg), Vector{U}()) | ||
path = vcat(enumerate_paths(ds_f, mid_v), reverse(enumerate_paths(ds_b, mid_v)[1:end-1])) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if there are several paths? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure how to deal with such situations, as far as I can tell multiple paths with the same cost can be detected if the condition There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Given that |
||
return path | ||
end | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
@testset "Bidijkstra" begin | ||
g3 = path_graph(5) | ||
g4 = path_digraph(5) | ||
|
||
d1 = float([0 1 2 3 4; 5 0 6 7 8; 9 10 0 11 12; 13 14 15 0 16; 17 18 19 20 0]) | ||
d2 = sparse(float([0 1 2 3 4; 5 0 6 7 8; 9 10 0 11 12; 13 14 15 0 16; 17 18 19 20 0])) | ||
for g in testgraphs(g3), dg in testdigraphs(g4) | ||
@test @inferred(bidijkstra_shortest_path(g, 1, 4, d1)) == | ||
@inferred(bidijkstra_shortest_path(dg, 1, 4, d1)) == | ||
@inferred(bidijkstra_shortest_path(g, 1, 4, d2)) | ||
@test isempty(@inferred(bidijkstra_shortest_path(dg, 4, 1))) | ||
end | ||
|
||
# test for #1258 | ||
g = complete_graph(4) | ||
w = float([1 1 1 4; 1 1 1 1; 1 1 1 1; 4 1 1 1]) | ||
ds = dijkstra_shortest_paths(g, 1, w) | ||
@test length(bidijkstra_shortest_path(g, 1, 4, w)) == 3 # path is a sequence of vertices | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We probably should not change this, it might overflow.