Skip to content
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

Unitful support for shortestpath distance matrices #416

Merged
merged 1 commit into from
Jan 27, 2025
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
3 changes: 2 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"

[targets]
test = ["Aqua", "Base64", "DelimitedFiles", "Documenter", "JET", "JuliaFormatter", "LinearAlgebra", "Pkg", "Random", "SparseArrays", "StableRNGs", "Statistics", "Test"]
test = ["Aqua", "Base64", "DelimitedFiles", "Documenter", "JET", "JuliaFormatter", "LinearAlgebra", "Pkg", "Random", "SparseArrays", "StableRNGs", "Statistics", "Test", "Unitful"]
2 changes: 1 addition & 1 deletion src/Parallel/distance.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

function eccentricity(
g::AbstractGraph, vs=vertices(g), distmx::AbstractMatrix{T}=weights(g)
) where {T<:Real}
) where {T<:Number}
vlen = length(vs)
eccs = SharedVector{T}(vlen)
@sync @distributed for i in 1:vlen
Expand Down
6 changes: 3 additions & 3 deletions src/Parallel/shortestpaths/bellman-ford.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ function bellman_ford_shortest_paths(
g::AbstractGraph{U},
sources::AbstractVector{<:Integer},
distmx::AbstractMatrix{T}=weights(g),
) where {T<:Real} where {U<:Integer}
) where {T<:Number} where {U<:Integer}
nvg = nv(g)
active = Set{U}()
sizehint!(active, nv(g))
Expand Down Expand Up @@ -30,7 +30,7 @@ function _loop_body!(
dists::Vector{T},
parents::Vector{U},
active::Set{U},
) where {T<:Real} where {U<:Integer}
) where {T<:Number} where {U<:Integer}
prev_dists = deepcopy(dists)

tmp_active = collect(active)
Expand Down Expand Up @@ -58,7 +58,7 @@ end

function has_negative_edge_cycle(
g::AbstractGraph{U}, distmx::AbstractMatrix{T}
) where {T<:Real} where {U<:Integer}
) where {T<:Number} where {U<:Integer}
try
Parallel.bellman_ford_shortest_paths(g, vertices(g), distmx)
catch e
Expand Down
4 changes: 2 additions & 2 deletions src/Parallel/shortestpaths/dijkstra.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

An [`AbstractPathState`](@ref) designed for Parallel.dijkstra_shortest_paths calculation.
"""
struct MultipleDijkstraState{T<:Real,U<:Integer} <: AbstractPathState
struct MultipleDijkstraState{T<:Number,U<:Integer} <: AbstractPathState
dists::Matrix{T}
parents::Matrix{U}
end
Expand All @@ -18,7 +18,7 @@ traversal information.
"""
function dijkstra_shortest_paths(
g::AbstractGraph{U}, sources=vertices(g), distmx::AbstractMatrix{T}=weights(g)
) where {T<:Real} where {U}
) where {T<:Number} where {U}
n_v = nv(g)
r_v = length(sources)

Expand Down
4 changes: 2 additions & 2 deletions src/Parallel/shortestpaths/floyd-warshall.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Helper function used due to performance bug in @threads.
function _loopbody!(
pivot::U, nvg::U, dists::Matrix{T}, parents::Matrix{U}
) where {T<:Real} where {U<:Integer}
) where {T<:Number} where {U<:Integer}
# Relax dists[u, v] = min(dists[u, v], dists[u, pivot]+dists[pivot, v]) for all u, v
@inbounds @threads for v in one(U):nvg
d = dists[pivot, v]
Expand All @@ -26,7 +26,7 @@ end

function floyd_warshall_shortest_paths(
g::AbstractGraph{U}, distmx::AbstractMatrix{T}=weights(g)
) where {T<:Real} where {U<:Integer}
) where {T<:Number} where {U<:Integer}
nvg = nv(g)
dists = fill(typemax(T), (Int(nvg), Int(nvg)))
parents = zeros(U, (Int(nvg), Int(nvg)))
Expand Down
2 changes: 1 addition & 1 deletion src/Parallel/shortestpaths/johnson.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ using Compat

function johnson_shortest_paths(
g::AbstractGraph{U}, distmx::AbstractMatrix{T}=weights(g)
) where {T<:Real} where {U<:Integer}
) where {T<:Number} where {U<:Integer}
nvg = nv(g)
type_distmx = typeof(distmx)
# Change when parallel implementation of Bellman Ford available
Expand Down
2 changes: 1 addition & 1 deletion src/cycles/karp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# Discrete Mathematics, 1978, 23, 309 - 311
function _karp_minimum_cycle_mean(
g::AbstractGraph, distmx::AbstractMatrix{T}, component::Vector{U}
) where {T<:Real} where {U<:Integer}
) where {T<:Number} where {U<:Integer}
v2j = Dict{U,Int}()
for (j, v) in enumerate(component)
v2j[v] = j
Expand Down
2 changes: 1 addition & 1 deletion src/distance.jl
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ julia> eccentricity(g, [1; 2], [0 2 0; 0.5 0 0.5; 0 2 0])
"""
function eccentricity(
g::AbstractGraph, v::Integer, distmx::AbstractMatrix{T}=weights(g)
) where {T<:Real}
) where {T<:Number}
e = maximum(dijkstra_shortest_paths(g, v, distmx).dists)
e == typemax(T) && @warn("Infinite path length detected for vertex $v")

Expand Down
2 changes: 1 addition & 1 deletion src/graphcut/normalized_cut.jl
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,6 @@ function normalized_cut(
thres::Real,
W::AbstractMatrix{T}=adjacency_matrix(g),
num_cuts::Int=10,
) where {T<:Real}
) where {T<:Number}
return _recursive_normalized_cut(W, thres, num_cuts)
end
2 changes: 1 addition & 1 deletion src/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ end
# """Provides multiplication of a graph `g` by a vector `v` such that spectral
# graph functions in [GraphMatrices.jl](https://github.com/jpfairbanks/GraphMatrices.jl) can utilize Graphs natively.
# """
function *(g::AbstractGraph, v::Vector{T}) where {T<:Real}
function *(g::AbstractGraph, v::Vector{T}) where {T<:Number}
length(v) == nv(g) || throw(ArgumentError("Vector size must equal number of vertices"))
y = zeros(T, nv(g))
for e in edges(g)
Expand Down
8 changes: 4 additions & 4 deletions src/shortestpaths/bellman-ford.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ An `AbstractPathState` designed for Bellman-Ford shortest-paths calculations.
- `parents::Vector{U}`: `parents[v]` is the predecessor of vertex `v` on the shortest path from the source to `v`
- `dists::Vector{T}`: `dists[v]` is the length of the shortest path from the source to `v`
"""
struct BellmanFordState{T<:Real,U<:Integer} <: AbstractPathState
struct BellmanFordState{T<:Number,U<:Integer} <: AbstractPathState
parents::Vector{U}
dists::Vector{T}
end
Expand All @@ -40,7 +40,7 @@ function bellman_ford_shortest_paths(
graph::AbstractGraph{U},
sources::AbstractVector{<:Integer},
distmx::AbstractMatrix{T}=weights(graph),
) where {T<:Real} where {U<:Integer}
) where {T<:Number} where {U<:Integer}
nvg = nv(graph)
active = falses(nvg)
active[sources] .= true
Expand Down Expand Up @@ -76,15 +76,15 @@ end

function bellman_ford_shortest_paths(
graph::AbstractGraph{U}, v::Integer, distmx::AbstractMatrix{T}=weights(graph);
) where {T<:Real} where {U<:Integer}
) where {T<:Number} where {U<:Integer}
return bellman_ford_shortest_paths(graph, [v], distmx)
end

has_negative_edge_cycle(g::AbstractGraph) = false

function has_negative_edge_cycle(
g::AbstractGraph{U}, distmx::AbstractMatrix{T}
) where {T<:Real} where {U<:Integer}
) where {T<:Number} where {U<:Integer}
try
bellman_ford_shortest_paths(g, collect_if_not_vector(vertices(g)), distmx)
catch e
Expand Down
4 changes: 2 additions & 2 deletions src/shortestpaths/desopo-pape.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ An [`AbstractPathState`](@ref) designed for D`Esopo-Pape shortest-path calculati
- `parents::Vector{U}`: `parents[v]` is the predecessor of vertex `v` on the shortest path from the source to `v`
- `dists::Vector{T}`: `dists[v]` is the length of the shortest path from the source to `v`
"""
struct DEsopoPapeState{T<:Real,U<:Integer} <: AbstractPathState
struct DEsopoPapeState{T<:Number,U<:Integer} <: AbstractPathState
parents::Vector{U}
dists::Vector{T}
end
Expand Down Expand Up @@ -47,7 +47,7 @@ julia> ds.dists
"""
function desopo_pape_shortest_paths(
g::AbstractGraph, src::Integer, distmx::AbstractMatrix{T}=weights(g)
) where {T<:Real}
) where {T<:Number}
U = eltype(g)
nvg = nv(g)
(src in 1:nvg) || throw(DomainError(src, "src should be in between 1 and $nvg"))
Expand Down
4 changes: 2 additions & 2 deletions src/shortestpaths/dijkstra.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ An [`AbstractPathState`](@ref) designed for Dijkstra shortest-paths calculations
- `pathcounts::Vector{Float64}`: a vector, indexed by vertex, of the number of shortest paths from the source to that vertex. The path count of a source vertex is always `1.0`. The path count of an unreached vertex is always `0.0`.
- `closest_vertices::Vector{U}`: a vector of all vertices in the graph ordered from closest to farthest.
"""
struct DijkstraState{T<:Real,U<:Integer} <: AbstractPathState
struct DijkstraState{T<:Number,U<:Integer} <: AbstractPathState
parents::Vector{U}
dists::Vector{T}
predecessors::Vector{Vector{U}}
Expand Down Expand Up @@ -73,7 +73,7 @@ function dijkstra_shortest_paths(
allpaths=false,
trackvertices=false,
maxdist=typemax(T),
) where {T<:Real} where {U<:Integer}
) where {T<:Number} where {U<:Integer}
nvg = nv(g)
dists = fill(typemax(T), nvg)
parents = zeros(U, nvg)
Expand Down
2 changes: 1 addition & 1 deletion src/shortestpaths/floyd-warshall.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ 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<:Real} where {U<:Integer}
) 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))
Expand Down
6 changes: 3 additions & 3 deletions src/shortestpaths/johnson.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ An [`AbstractPathState`](@ref) designed for Johnson shortest-paths calculations.
- `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 JohnsonState{T<:Real,U<:Integer} <: AbstractPathState
struct JohnsonState{T<:Number,U<:Integer} <: AbstractPathState
dists::Matrix{T}
parents::Matrix{U}
end
Expand All @@ -29,7 +29,7 @@ Complexity: `O(|V|*|E|)`
"""
function johnson_shortest_paths(
g::AbstractGraph{U}, distmx::AbstractMatrix{T}=weights(g)
) where {T<:Real} where {U<:Integer}
) where {T<:Number} where {U<:Integer}
nvg = nv(g)
type_distmx = typeof(distmx)
# Change when parallel implementation of Bellman Ford available
Expand Down Expand Up @@ -71,7 +71,7 @@ end

function enumerate_paths(
s::JohnsonState{T,U}, v::Integer
) where {T<:Real} where {U<:Integer}
) where {T<:Number} where {U<:Integer}
pathinfo = s.parents[v, :]
paths = Vector{Vector{U}}()
for i in 1:length(pathinfo)
Expand Down
4 changes: 2 additions & 2 deletions src/shortestpaths/spfa.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ ERROR: Graphs.NegativeCycleError()
"""
function spfa_shortest_paths(
graph::AbstractGraph{U}, source::Integer, distmx::AbstractMatrix{T}=weights(graph)
) where {T<:Real} where {U<:Integer}
) where {T<:Number} where {U<:Integer}
nvg = nv(graph)

(source in 1:nvg) ||
Expand Down Expand Up @@ -115,7 +115,7 @@ false
"""
function has_negative_edge_cycle_spfa(
g::AbstractGraph{U}, distmx::AbstractMatrix{T}
) where {T<:Real} where {U<:Integer}
) where {T<:Number} where {U<:Integer}
try
spfa_shortest_paths(g, 1, distmx)
catch e
Expand Down
2 changes: 1 addition & 1 deletion src/shortestpaths/yen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function yen_k_shortest_paths(
distmx::AbstractMatrix{T}=weights(g),
K::Int=1;
maxdist=typemax(T),
) where {T<:Real} where {U<:Integer}
) where {T<:Number} where {U<:Integer}
source == target && return YenState{T,U}([U(0)], [[source]])

dj = dijkstra_shortest_paths(g, source, distmx; maxdist)
Expand Down
2 changes: 1 addition & 1 deletion src/spanningtrees/boruvka.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function boruvka_mst end

@traitfn function boruvka_mst(
g::AG::(!IsDirected), distmx::AbstractMatrix{T}=weights(g); minimize=true
) where {T<:Real,U,AG<:AbstractGraph{U}}
) where {T<:Number,U,AG<:AbstractGraph{U}}
djset = IntDisjointSets(nv(g))
# maximizing Z is the same as minimizing -Z
# mode will indicate the need for the -1 multiplication
Expand Down
2 changes: 1 addition & 1 deletion src/spanningtrees/kruskal.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ function kruskal_mst end
# see https://github.com/mauro3/SimpleTraits.jl/issues/47#issuecomment-327880153 for syntax
@traitfn function kruskal_mst(
g::AG::(!IsDirected), distmx::AbstractMatrix{T}=weights(g); minimize=true
) where {T<:Real,U,AG<:AbstractGraph{U}}
) where {T<:Number,U,AG<:AbstractGraph{U}}
connected_vs = IntDisjointSets(nv(g))

mst = Vector{edgetype(g)}()
Expand Down
2 changes: 1 addition & 1 deletion src/spanningtrees/prim.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Return a vector of edges.
function prim_mst end
@traitfn function prim_mst(
g::AG::(!IsDirected), distmx::AbstractMatrix{T}=weights(g)
) where {T<:Real,U,AG<:AbstractGraph{U}}
) where {T<:Number,U,AG<:AbstractGraph{U}}
nvg = nv(g)

pq = PriorityQueue{U,T}()
Expand Down
4 changes: 2 additions & 2 deletions src/traversals/maxadjvisit.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ assumed to be 1.
"""
@traitfn function mincut(
g::::(!IsDirected), distmx::AbstractMatrix{T}=weights(g)
) where {T<:Real}
) where {T<:Number}
nvg = nv(g)
U = eltype(g)

Expand Down Expand Up @@ -140,7 +140,7 @@ function maximum_adjacency_visit(
log::Bool=false,
io::IO=stdout,
s::U=one(U),
) where {U,T<:Real}
) where {U,T<:Number}
pq = PriorityQueue{U,T}(Base.Order.Reverse)
vertices_order = Vector{U}()
has_key = ones(Bool, nv(g))
Expand Down
2 changes: 2 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ using Random
using Statistics: mean, std
using StableRNGs
using Pkg
using Unitful

const testdir = dirname(@__FILE__)
const KMf = typeof(u"1.0km")

function get_pkg_version(name::AbstractString)
for dep in values(Pkg.dependencies())
Expand Down
14 changes: 14 additions & 0 deletions test/shortestpaths/yen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,20 @@
1.0 0.0 3.0 0.0
]

w_km = KMf.(w)
for g in testgraphs(G)
ds = @inferred(yen_k_shortest_paths(g, 2, 4, w_km))
@test ds.paths == [[2, 1, 4]]
ds = @inferred(yen_k_shortest_paths(g, 2, 1, w_km))
@test ds.paths == [[2, 1]]
ds = @inferred(yen_k_shortest_paths(g, 2, 3, w_km))
@test ds.paths == [[2, 3]]

# Test with multiple paths
ds = @inferred(yen_k_shortest_paths(g, 2, 4, w_km, 2))
@test ds.paths == [[2, 1, 4], [2, 3, 4]]
end

for g in testgraphs(G)
ds = @inferred(yen_k_shortest_paths(g, 2, 4, w))
@test ds.paths == [[2, 1, 4]]
Expand Down
Loading