-
Notifications
You must be signed in to change notification settings - Fork 97
/
Copy pathfloyd-warshall.jl
103 lines (90 loc) · 3.29 KB
/
floyd-warshall.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# Parts of this code were taken / derived from Graphs.jl. See LICENSE for
# licensing details.
"""
struct FloydWarshallState{T, U}
An [`AbstractPathState`](@ref) designed for Floyd-Warshall shortest-paths calculations.
# Fields
- `dists::Matrix{T}`: `dists[u, v]` is the length of the shortest path from `u` to `v`
- `parents::Matrix{U}`: `parents[u, v]` is the predecessor of vertex `v` on the shortest path from `u` to `v`
"""
struct FloydWarshallState{T,U<:Integer} <: AbstractPathState
dists::Matrix{T}
parents::Matrix{U}
end
@doc """
floyd_warshall_shortest_paths(g, distmx=weights(g))
Use the [Floyd-Warshall algorithm](http://en.wikipedia.org/wiki/Floyd–Warshall_algorithm)
to compute the shortest paths between all pairs of vertices in graph `g` using an
optional distance matrix `distmx`. Return a [`Graphs.FloydWarshallState`](@ref) with relevant traversal information (try querying `state.parents` or `state.dists`).
### Performance
Space complexity is on the order of `O(|V|^2)`.
"""
function floyd_warshall_shortest_paths(
g::AbstractGraph{U}, distmx::AbstractMatrix{T}=weights(g)
) where {T<:Number} where {U<:Integer}
nvg = nv(g)
# if we do checkbounds here, we can use @inbounds later
checkbounds(distmx, Base.OneTo(nvg), Base.OneTo(nvg))
dists = fill(typemax(T), (Int(nvg), Int(nvg)))
parents = zeros(U, (Int(nvg), Int(nvg)))
@inbounds for v in vertices(g)
dists[v, v] = zero(T)
end
undirected = !is_directed(g)
@inbounds for e in edges(g)
u = src(e)
v = dst(e)
d = distmx[u, v]
dists[u, v] = min(d, dists[u, v])
parents[u, v] = u
if undirected
dists[v, u] = min(d, dists[v, u])
parents[v, u] = v
end
end
@inbounds for pivot in vertices(g)
# Relax dists[u, v] = min(dists[u, v], dists[u, pivot]+dists[pivot, v]) for all u, v
for v in vertices(g)
d = dists[pivot, v]
d == typemax(T) && continue
p = parents[pivot, v]
for u in vertices(g)
ans = (dists[u, pivot] == typemax(T) ? typemax(T) : dists[u, pivot] + d)
if dists[u, v] > ans
dists[u, v] = ans
parents[u, v] = p
end
end
end
end
fws = FloydWarshallState(dists, parents)
return fws
end
function enumerate_paths(
s::FloydWarshallState{T,U}, v::Integer
) where {T} where {U<:Integer}
pathinfo = s.parents[v, :]
paths = Vector{Vector{U}}()
for i in 1:length(pathinfo)
if (i == v) || (s.dists[v, i] == typemax(T))
push!(paths, Vector{U}())
else
path = Vector{U}()
currpathindex = U(i)
while currpathindex != 0
push!(path, currpathindex)
if pathinfo[currpathindex] == currpathindex
currpathindex = zero(currpathindex)
else
currpathindex = pathinfo[currpathindex]
end
end
push!(paths, reverse(path))
end
end
return paths
end
function enumerate_paths(s::FloydWarshallState)
return [enumerate_paths(s, v) for v in 1:size(s.parents, 1)]
end
enumerate_paths(st::FloydWarshallState, s::Integer, d::Integer) = enumerate_paths(st, s)[d]