Skip to content

Cleanup and bugfix #23

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

Merged
merged 12 commits into from
Aug 19, 2024
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
/docs/build/
scripts
.vscode
debug.jl
7 changes: 4 additions & 3 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ version = "0.3.0"

[deps]
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
PiecewiseLinearFunctions = "08f3856d-0b18-48ce-8d4b-10c3630068d6"
SimpleTraits = "699a6c99-e7fa-54fc-8d76-47d257e15c1d"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"

[compat]
DataStructures = "0.18"
DocStringExtensions = "0.9"
Graphs = "1"
PiecewiseLinearFunctions = "0.1"
SimpleTraits = "0.9"
SparseArrays = "<0.0.1,1"
Statistics = "<0.0.1,1"
julia = "1.10"
Expand All @@ -30,8 +30,9 @@ JuliaFormatter = "98e50ef6-434e-11e9-1051-2b60c6c9e899"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228"

[targets]
test = ["Aqua", "GLPK", "Graphs", "JET", "JuMP", "JuliaFormatter", "Plots", "Random", "SparseArrays", "Test", "UnicodePlots"]
test = ["Aqua", "GLPK", "Graphs", "JET", "JuMP", "JuliaFormatter", "Plots", "Random", "SparseArrays", "StableRNGs", "Test", "UnicodePlots"]
38 changes: 23 additions & 15 deletions docs/Manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,16 @@ uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0"
version = "1.0.8+1"

[[deps.CodecBzip2]]
deps = ["Bzip2_jll", "Libdl", "TranscodingStreams"]
git-tree-sha1 = "f8889d1770addf59d0a015c49a473fa2bdb9f809"
deps = ["Bzip2_jll", "TranscodingStreams"]
git-tree-sha1 = "e7c529cc31bb85b97631b922fa2e6baf246f5905"
uuid = "523fee87-0ab8-5b00-afb7-3ecf72e48cfd"
version = "0.8.3"
version = "0.8.4"

[[deps.CodecZlib]]
deps = ["TranscodingStreams", "Zlib_jll"]
git-tree-sha1 = "b8fe8546d52ca154ac556809e10c75e6e7430ac8"
git-tree-sha1 = "bce6804e5e6044c6daab27bb533d1295e4a2e759"
uuid = "944b1d66-785c-5afd-91f1-9de20f533193"
version = "0.7.5"
version = "0.7.6"

[[deps.CommonSubexpressions]]
deps = ["MacroTools", "Test"]
Expand All @@ -76,10 +76,10 @@ uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae"
version = "1.1.1+0"

[[deps.ConstrainedShortestPaths]]
deps = ["DataStructures", "Graphs", "SimpleTraits", "SparseArrays", "Statistics"]
deps = ["DataStructures", "Graphs", "PiecewiseLinearFunctions", "SimpleTraits", "SparseArrays", "Statistics"]
path = ".."
uuid = "b3798467-87dc-4d99-943d-35a1bd39e395"
version = "0.2.1"
version = "0.3.0"

[[deps.DataStructures]]
deps = ["Compat", "InteractiveUtils", "OrderedCollections"]
Expand Down Expand Up @@ -212,9 +212,9 @@ version = "0.21.4"

[[deps.JuMP]]
deps = ["LinearAlgebra", "MacroTools", "MathOptInterface", "MutableArithmetics", "OrderedCollections", "PrecompileTools", "Printf", "SparseArrays"]
git-tree-sha1 = "7e10a0d8b534f2d8e9f712b33488584254624fb1"
git-tree-sha1 = "1171edaad5873df2c93808fb13fd6f87de6510fd"
uuid = "4076af6c-e467-56ae-b986-b466b2749572"
version = "1.22.2"
version = "1.23.0"

[deps.JuMP.extensions]
JuMPDimensionalDataExt = "DimensionalData"
Expand Down Expand Up @@ -377,6 +377,18 @@ git-tree-sha1 = "8489905bcdbcfac64d1daa51ca07c0d8f0283821"
uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
version = "2.8.1"

[[deps.PiecewiseLinearFunctions]]
deps = ["DocStringExtensions"]
git-tree-sha1 = "354fc89a695fa5e635210d611bcc10d3ed8dffcb"
uuid = "08f3856d-0b18-48ce-8d4b-10c3630068d6"
version = "0.1.0"

[deps.PiecewiseLinearFunctions.extensions]
PiecewiseLinearFunctionsPlotExt = "Plots"

[deps.PiecewiseLinearFunctions.weakdeps]
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"

[[deps.Pkg]]
deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"]
uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
Expand Down Expand Up @@ -497,13 +509,9 @@ deps = ["InteractiveUtils", "Logging", "Random", "Serialization"]
uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[[deps.TranscodingStreams]]
git-tree-sha1 = "96612ac5365777520c3c5396314c8cf7408f436a"
git-tree-sha1 = "e84b3a11b9bece70d14cce63406bbc79ed3464d2"
uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa"
version = "0.11.1"
weakdeps = ["Random", "Test"]

[deps.TranscodingStreams.extensions]
TestExt = ["Test", "Random"]
version = "0.11.2"

[[deps.UUIDs]]
deps = ["Random", "SHA"]
Expand Down
9 changes: 5 additions & 4 deletions docs/src/literate/custom.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ but simplified with only one constraint.

using ConstrainedShortestPaths
using Graphs, SparseArrays
import Base: <=, minimum

#=
## Resources
Expand All @@ -43,12 +42,14 @@ end

# `Base.<=` and `Base.minimum`

function <=(r1::Resource, r2::Resource)
function Base.:<=(r1::Resource, r2::Resource)
return r1.c <= r2.c && r1.w <= r2.w
end

function minimum(R::Vector{Resource})
return Resource(minimum(r.c for r in R), minimum(r.w for r in R))
function Base.min(r₁::Resource, r₂::Resource)
new_c = min(r₁.c, r₂.c)
new_w = min(r₁.w, r₂.w)
return Resource(new_c, new_w)
end

#=
Expand Down
10 changes: 5 additions & 5 deletions src/ConstrainedShortestPaths.jl
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
module ConstrainedShortestPaths

using DataStructures
using Graphs
using DataStructures: PriorityQueue, enqueue!, dequeue!, isempty
using DocStringExtensions: TYPEDEF, TYPEDFIELDS, TYPEDSIGNATURES
using Graphs:
AbstractGraph, is_directed, is_cyclic, nv, weights, src, dst, edges, outneighbors
using PiecewiseLinearFunctions: PiecewiseLinearFunction
using SimpleTraits
using SparseArrays
using SparseArrays: sparse
using Statistics: mean
import Base: <=, minimum, +

include("utils/utils.jl")
include("algorithms.jl")
Expand Down
98 changes: 64 additions & 34 deletions src/algorithms.jl
Original file line number Diff line number Diff line change
@@ -1,48 +1,75 @@
"""
CSPInstance{G,FR,BR,C,FF,BF}
$TYPEDEF

# Attributes

- `graph`
- `origin_forward_resource`
- `destination_backward_resource`
- `cost_function`
- `forward_functions`
- `backward_functions`
# Fields
$TYPEDFIELDS
"""
Base.@kwdef struct CSPInstance{
T,G<:AbstractGraph{T},FR,BR,C,FF<:AbstractMatrix,BF<:AbstractMatrix
}
graph::G # assumption : node 1 is origin, last node is destination
struct CSPInstance{T,G<:AbstractGraph{T},FR,BR,C,FF<:AbstractMatrix,BF<:AbstractMatrix}
"acyclic digraph in which to compute the shortest path"
graph::G
"origin vertex of path"
origin_vertex::T
"destination vertex of path"
destination_vertex::T
"forward resource at the origin vertex"
origin_forward_resource::FR
"backward resource at the destination vertex"
destination_backward_resource::BR
"cost function"
cost_function::C
"forward functions along edges"
forward_functions::FF
"backward functions along edges"
backward_functions::BF
end

"""
compute_bounds(instance)
$TYPEDSIGNATURES

Constructor for [`CSPInstance`](@ref).
"""
function CSPInstance(;
graph,
origin_vertex,
destination_vertex,
origin_forward_resource,
destination_backward_resource,
cost_function,
forward_functions,
backward_functions,
)
@assert is_directed(graph) "`graph` must be a directed graph"
@assert !is_cyclic(graph) "`graph` must be acyclic"
return CSPInstance(
graph,
origin_vertex,
destination_vertex,
origin_forward_resource,
destination_backward_resource,
cost_function,
forward_functions,
backward_functions,
)
end

"""
$TYPEDSIGNATURES

Compute backward bounds of instance (see [Computing bounds](@ref)).
"""
@traitfn function compute_bounds(
instance::CSPInstance{T,G}; kwargs...
) where {T,G<:AbstractGraph{T};IsDirected{G}}
function compute_bounds(instance::CSPInstance{T,G}; kwargs...) where {T,G<:AbstractGraph{T}}
(; graph, origin_vertex, destination_vertex) = instance
nb_vertices = nv(instance.graph)

vertices_order = topological_order(graph, origin_vertex, destination_vertex)

bounds = Vector{typeof(instance.destination_backward_resource)}(undef, nb_vertices)
bounds = Dict{Int,typeof(instance.destination_backward_resource)}()
# bounds = Vector{typeof(instance.destination_backward_resource)}(undef, nb_vertices)
bounds[destination_vertex] = instance.destination_backward_resource

for vertex in vertices_order[2:end]
vector = [
instance.backward_functions[vertex, neighbor](bounds[neighbor]; kwargs...) for
neighbor in outneighbors(graph, vertex)
neighbor in outneighbors(graph, vertex) if haskey(bounds, neighbor)
]
bounds[vertex] = minimum(vector)
end
Expand All @@ -51,14 +78,14 @@ Compute backward bounds of instance (see [Computing bounds](@ref)).
end

"""
generalized_a_star(instance, s, t, bounds)
$TYPEDSIGNATURES

Perform generalized A star algorithm on instnace using bounds
(see [Generalized `A^\\star`](@ref)).
"""
@traitfn function generalized_a_star(
instance::CSPInstance{T,G}, bounds::AbstractVector; kwargs...
) where {T,G<:AbstractGraph{T};IsDirected{G}}
function generalized_a_star(
instance::CSPInstance{T,G}, bounds::AbstractDict; kwargs...
) where {T,G<:AbstractGraph{T}}
(; graph, origin_vertex, destination_vertex) = instance
nb_vertices = nv(graph)

Expand All @@ -80,6 +107,9 @@ Perform generalized A star algorithm on instnace using bounds
p = dequeue!(L)
v = p[end]
for w in outneighbors(graph, v)
if !haskey(bounds, w)
continue
end
q = copy(p)
push!(q, w)
rp = forward_resources[p]
Expand All @@ -105,13 +135,13 @@ Perform generalized A star algorithm on instnace using bounds
end

"""
generalized_a_star_with_threshold(instance, bounds, threshold)
$TYPEDSIGNATURES

Compute all paths below threshold.
"""
@traitfn function generalized_a_star_with_threshold(
instance::CSPInstance{T,G}, bounds::AbstractVector, threshold::Float64; kwargs...
) where {T,G<:AbstractGraph;IsDirected{G}}
function generalized_a_star_with_threshold(
instance::CSPInstance{T,G}, bounds::AbstractDict, threshold::Float64; kwargs...
) where {T,G<:AbstractGraph}
(; graph, origin_vertex, destination_vertex) = instance

empty_path = [origin_vertex]
Expand Down Expand Up @@ -153,25 +183,25 @@ Compute all paths below threshold.
end

"""
generalized_constrained_shortest_path(instance, s, t)
$TYPEDSIGNATURES

Compute the shortest path of `instance`.
"""
@traitfn function generalized_constrained_shortest_path(
function generalized_constrained_shortest_path(
instance::CSPInstance{T,G}; kwargs...
) where {T,G<:AbstractGraph{T};IsDirected{G}}
) where {T,G<:AbstractGraph{T}}
bounds = compute_bounds(instance; kwargs...)
return generalized_a_star(instance, bounds; kwargs...)
end

"""
generalized_constrained_shortest_path(instance)
$TYPEDSIGNATURES

Compute shortest path between first and last nodes of `instance`
"""
@traitfn function generalized_constrained_shortest_path_with_threshold(
function generalized_constrained_shortest_path_with_threshold(
instance::CSPInstance{T,G}, threshold::Float64; kwargs...
) where {T,G<:AbstractGraph;IsDirected{G}}
) where {T,G<:AbstractGraph}
bounds = compute_bounds(instance; kwargs...)
return generalized_a_star_with_threshold(instance, bounds, threshold; kwargs...)
end
8 changes: 4 additions & 4 deletions src/examples/basic_shortest_path.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ end
# Wrapper

"""
basic_shortest_path(graph, distmx=weights(graph), s, t)
$TYPEDSIGNATURES

Compute shortest path between vertices `s` and `t` of graph `graph`.

Expand All @@ -41,9 +41,9 @@ Compute shortest path between vertices `s` and `t` of graph `graph`.
- `p_star::Vector{Int}`: optimal path found.
- `c_star::Float64`: length of path `p_star`.
"""
@traitfn function basic_shortest_path(
graph::G, s::T, t::T, distmx::AbstractMatrix=weights(graph)
) where {T,G<:AbstractGraph{T};IsDirected{G}}
function basic_shortest_path(
graph::AbstractGraph{T}, s::T, t::T, distmx::AbstractMatrix=weights(graph)
) where {T}
# origin forward resource and backward forward resource set to 0
resource = 0.0

Expand Down
Loading
Loading