Skip to content

Commit d1081b0

Browse files
matheusdiogenesandradeMatheus Diógenes Andradegdalle
authored
Algorithm for finding the longest path of a DAG (#209)
* Algorithm for finding the longest path of a DAG * Automated test issue * Including longest path test * Test fix * Simplify * Fix JET warning * Fixing doctest * Adjustments * Simplify --------- Co-authored-by: Matheus Diógenes Andrade <matheusdiogenesandrade@pop-os.localdomain> Co-authored-by: Guillaume Dalle <22795598+gdalle@users.noreply.github.com>
1 parent 7133460 commit d1081b0

File tree

7 files changed

+83
-2
lines changed

7 files changed

+83
-2
lines changed

docs/src/algorithms/shortestpaths.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Shortest paths
22

3-
*Graphs.jl* includes standard algorithms for [shortest paths](https://en.wikipedia.org/wiki/Shortest_path_problem).
3+
*Graphs.jl* includes standard algorithms for [shortest paths](https://en.wikipedia.org/wiki/Shortest_path_problem) and longest paths.
44

55
## Index
66

@@ -19,6 +19,7 @@ Pages = [
1919
"shortestpaths/dijkstra.jl",
2020
"shortestpaths/floyd-warshall.jl",
2121
"shortestpaths/johnson.jl",
22+
"shortestpaths/longest_path.jl",
2223
"shortestpaths/spfa.jl",
2324
"shortestpaths/yen.jl",
2425
]

src/Graphs.jl

+6-1
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,10 @@ export
426426
independent_set,
427427

428428
# vertexcover
429-
vertex_cover
429+
vertex_cover,
430+
431+
# longestpaths
432+
dag_longest_path
430433

431434
"""
432435
Graphs
@@ -496,6 +499,7 @@ include("traversals/eulerian.jl")
496499
include("connectivity.jl")
497500
include("distance.jl")
498501
include("editdist.jl")
502+
include("shortestpaths/utils.jl")
499503
include("shortestpaths/astar.jl")
500504
include("shortestpaths/bellman-ford.jl")
501505
include("shortestpaths/dijkstra.jl")
@@ -504,6 +508,7 @@ include("shortestpaths/desopo-pape.jl")
504508
include("shortestpaths/floyd-warshall.jl")
505509
include("shortestpaths/yen.jl")
506510
include("shortestpaths/spfa.jl")
511+
include("shortestpaths/longest_path.jl")
507512
include("linalg/LinAlg.jl")
508513
include("operators.jl")
509514
include("persistence/common.jl")

src/shortestpaths/longest_path.jl

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"""
2+
dag_longest_path(g, distmx=weights(g); topological_order=topological_sort_by_dfs(g))
3+
4+
Return a longest path within the directed acyclic graph `g`, with distance matrix `distmx` and using `topological_order` to iterate on vertices.
5+
"""
6+
function dag_longest_path end
7+
8+
@traitfn function dag_longest_path(
9+
g::::IsDirected,
10+
distmx::AbstractMatrix=weights(g);
11+
topological_order=topological_sort_by_dfs(g),
12+
)
13+
U = eltype(g)
14+
T = eltype(distmx)
15+
16+
dists = zeros(T, nv(g))
17+
parents = zeros(U, nv(g))
18+
19+
for v in topological_order
20+
for u in inneighbors(g, v)
21+
newdist = dists[u] + distmx[u, v]
22+
if newdist > dists[v]
23+
dists[v] = newdist
24+
parents[v] = u
25+
end
26+
end
27+
end
28+
29+
if isempty(dists)
30+
return U[]
31+
else
32+
v = argmax(dists)
33+
return path_from_parents(v, parents)
34+
end
35+
end

src/shortestpaths/utils.jl

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
function path_from_parents(target::Integer, parents::AbstractVector)
2+
v = target
3+
path = [v]
4+
while parents[v] != v && parents[v] != zero(v)
5+
v = parents[v]
6+
pushfirst!(path, v)
7+
end
8+
return path
9+
end

test/runtests.jl

+2
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ tests = [
9191
"edit_distance",
9292
"connectivity",
9393
"persistence/persistence",
94+
"shortestpaths/utils",
9495
"shortestpaths/astar",
9596
"shortestpaths/bellman-ford",
9697
"shortestpaths/desopo-pape",
@@ -99,6 +100,7 @@ tests = [
99100
"shortestpaths/floyd-warshall",
100101
"shortestpaths/yen",
101102
"shortestpaths/spfa",
103+
"shortestpaths/longest_path",
102104
"traversals/bfs",
103105
"traversals/bipartition",
104106
"traversals/greedy_color",

test/shortestpaths/longest_path.jl

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
@testset "Longest path" begin
2+
# empty DAG
3+
g = DiGraph()
4+
@test dag_longest_path(g) == Int[]
5+
6+
# unweighted DAG
7+
g = SimpleDiGraphFromIterator(Edge.([(1, 2), (2, 3), (2, 4), (3, 5), (5, 6), (3, 7)]))
8+
@test dag_longest_path(g) == [1, 2, 3, 5, 6]
9+
10+
# weighted DAG
11+
n = 6
12+
g = DiGraph(n)
13+
A = [(1, 2, -5), (2, 3, 1), (3, 4, 1), (4, 5, 0), (3, 5, 4), (1, 6, 2)]
14+
distmx = fill(NaN, n, n)
15+
for (i, j, dist) in A
16+
add_edge!(g, (i, j))
17+
distmx[i, j] = dist
18+
end
19+
@test dag_longest_path(g, distmx) == [2, 3, 5]
20+
end

test/shortestpaths/utils.jl

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
@testset "Path from parents" begin
2+
using Graphs: path_from_parents
3+
parents = [3, 0, 2, 5, 5]
4+
@test path_from_parents(1, parents) == [2, 3, 1]
5+
@test path_from_parents(2, parents) == [2]
6+
@test path_from_parents(3, parents) == [2, 3]
7+
@test path_from_parents(4, parents) == [5, 4]
8+
@test path_from_parents(5, parents) == [5]
9+
end

0 commit comments

Comments
 (0)