Skip to content

Commit 48c7a21

Browse files
committed
implement DVSP under the new interface
1 parent fe9482f commit 48c7a21

30 files changed

+589
-633
lines changed

Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ authors = ["Members of JuliaDecisionFocusedLearning"]
44
version = "0.2.2"
55

66
[deps]
7+
CommonRLInterface = "d842c3ba-07a1-494f-bbec-f5741b0a3e98"
78
ConstrainedShortestPaths = "b3798467-87dc-4d99-943d-35a1bd39e395"
89
DataDeps = "124859b0-ceae-595e-8997-d05f6a7a8dfe"
910
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
@@ -30,6 +31,7 @@ Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
3031
StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
3132

3233
[compat]
34+
CommonRLInterface = "0.3.3"
3335
ConstrainedShortestPaths = "0.6.0"
3436
DataDeps = "0.7"
3537
Distributions = "0.25"

src/DecisionFocusedLearningBenchmarks.jl

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ function __init__()
3232

3333
register(
3434
DataDep(
35-
"euro-neurips-2022",
36-
"EURO-NeurIPs challenge 2022 dataset",
35+
"dvrptw",
36+
"EURO-NeurIPS challenge 2022 dataset for the dynamic vehicle routing problem with time windows",
3737
"https://github.com/ortec/euro-neurips-vrp-2022-quickstart/archive/refs/heads/main.zip";
3838
post_fetch_method=_euro_neurips_unpack,
3939
),
@@ -54,7 +54,7 @@ include("Warcraft/Warcraft.jl")
5454
include("FixedSizeShortestPath/FixedSizeShortestPath.jl")
5555
include("PortfolioOptimization/PortfolioOptimization.jl")
5656
include("StochasticVehicleScheduling/StochasticVehicleScheduling.jl")
57-
# include("DynamicVehicleScheduling/DynamicVehicleScheduling.jl")
57+
include("DynamicVehicleScheduling/DynamicVehicleScheduling.jl")
5858

5959
using .Utils
6060
using .Argmax
@@ -64,11 +64,11 @@ using .Warcraft
6464
using .FixedSizeShortestPath
6565
using .PortfolioOptimization
6666
using .StochasticVehicleScheduling
67-
# using .DynamicVehicleScheduling
67+
using .DynamicVehicleScheduling
6868

6969
# Interface
7070
export AbstractBenchmark, AbstractStochasticBenchmark, AbstractDynamicBenchmark, DataSample
71-
export generate_dataset
71+
export generate_sample, generate_dataset, generate_scenario
7272
export generate_statistical_model
7373
export generate_maximizer, maximizer_kwargs
7474
export objective_value
@@ -83,5 +83,6 @@ export WarcraftBenchmark
8383
export FixedSizeShortestPathBenchmark
8484
export PortfolioOptimizationBenchmark
8585
export StochasticVehicleSchedulingBenchmark
86+
export DVSPBenchmark
8687

8788
end # module DecisionFocusedLearningBenchmarks

src/DynamicVehicleScheduling/DynamicVSP/algorithms/anticipative_solver.jl

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ $TYPEDSIGNATURES
44
Retrieve anticipative routes solution from the given MIP solution `y`.
55
Outputs a set of routes per epoch.
66
"""
7-
function retrieve_routes_anticipative(y::AbstractArray, dvspenv::DVSPEnv)
8-
nb_tasks = length(dvspenv.customer_index)
9-
(; first_epoch, last_epoch) = dvspenv.config
7+
function retrieve_routes_anticipative(y::AbstractArray, dvspenv::DVSPEnv, customer_index)
8+
nb_tasks = length(customer_index)
9+
first_epoch = 1
10+
(; last_epoch) = dvspenv.instance
1011
job_indices = 2:(nb_tasks)
1112
epoch_indices = first_epoch:last_epoch
1213

13-
routes = [Vector{Int}[] for t in epoch_indices]
14+
routes = [Vector{Int}[] for _ in epoch_indices]
1415
for t in epoch_indices
1516
start = [i for i in job_indices if y[1, i, t] 1]
1617
for task in start
@@ -39,13 +40,21 @@ $TYPEDSIGNATURES
3940
Solve the anticipative VSP problem for environment `env`.
4041
For this, it uses the current environment history, so make sure that the environment is terminated before calling this method.
4142
"""
42-
function anticipative_solver(env::DVSPEnv; model_builder=highs_model, draw_epochs=true)
43-
draw_epochs && draw_all_epochs!(env)
44-
(; customer_index, service_time, start_time, request_epoch) = env
45-
duration = env.config.static_instance.duration[customer_index, customer_index]
46-
(; first_epoch, last_epoch, epoch_duration, Δ_dispatch) = env.config
43+
function anticipative_solver(
44+
env::DVSPEnv, scenario=env.scenario; model_builder=highs_model, reset_env=false
45+
)
46+
reset_env && reset!(env)
47+
request_epoch = [0]
48+
for (epoch, indices) in enumerate(scenario.indices)
49+
request_epoch = vcat(request_epoch, fill(epoch, length(indices)))
50+
end
51+
customer_index = vcat(1, scenario.indices...)
52+
service_time = vcat(0.0, scenario.service_time...)
53+
start_time = vcat(0.0, scenario.start_time...)
4754

48-
@assert first_epoch == 1
55+
duration = env.instance.static_instance.duration[customer_index, customer_index]
56+
first_epoch = 1
57+
(; last_epoch, epoch_duration, Δ_dispatch) = env.instance
4958

5059
model = model_builder()
5160
set_silent(model)
@@ -80,7 +89,7 @@ function anticipative_solver(env::DVSPEnv; model_builder=highs_model, draw_epoch
8089
sum(y[j, i, t] for j in 1:nb_nodes, t in epoch_indices) == 1
8190
)
8291

83-
# a trip from i can be planned only after request appeared
92+
# a trip from i can be planned only after request appeared (release times)
8493
for i in job_indices, t in epoch_indices, j in 1:nb_nodes
8594
if t < request_epoch[i]
8695
@constraint(model, y[i, j, t] <= 0)
@@ -107,5 +116,6 @@ function anticipative_solver(env::DVSPEnv; model_builder=highs_model, draw_epoch
107116

108117
optimize!(model)
109118

110-
return retrieve_routes_anticipative(value.(y), env)
119+
return JuMP.objective_value(model),
120+
retrieve_routes_anticipative(value.(y), env, customer_index)
111121
end

src/DynamicVehicleScheduling/DynamicVSP/algorithms/prize_collecting_vsp.jl

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ $TYPEDSIGNATURES
33
44
Create the acyclic digraph associated with the given VSP `instance`.
55
"""
6-
function create_graph(instance::VSPInstance)
6+
function create_graph(instance::StaticInstance)
77
(; duration, start_time, service_time) = instance
88
# Initialize directed graph
9-
nb_vertices = nb_locations(instance)
9+
nb_vertices = location_count(instance)
1010
graph = SimpleDiGraph(nb_vertices)
1111

1212
depot = 1 # depot is always index 1
@@ -42,8 +42,8 @@ $TYPEDSIGNATURES
4242
4343
Create the acyclic digraph associated with the given VSP `state`.
4444
"""
45-
function create_graph(state::VSPState)
46-
return create_graph(state.instance)
45+
function create_graph(state::DVSPState)
46+
return create_graph(state.state_instance)
4747
end
4848

4949
"""
@@ -82,9 +82,9 @@ $TYPEDSIGNATURES
8282
Solve the Prize Collecting Vehicle Scheduling Problem defined by `instance` and prize vector `θ`.
8383
"""
8484
function prize_collecting_vsp(
85-
θ::AbstractVector; instance::VSPState, model_builder=highs_model, kwargs...
85+
θ::AbstractVector; instance::DVSPState, model_builder=highs_model, kwargs...
8686
)
87-
(; duration) = instance.instance
87+
(; duration) = instance.state_instance
8888
graph = create_graph(instance)
8989

9090
model = model_builder()
@@ -95,7 +95,7 @@ function prize_collecting_vsp(
9595

9696
@variable(model, y[i=1:nb_nodes, j=1:nb_nodes; has_edge(graph, i, j)] >= 0)
9797

98-
θ_ext = fill(0.0, nb_locations(instance)) # no prize for must dispatch requests, only hard constraints
98+
θ_ext = fill(0.0, location_count(instance)) # no prize for must dispatch requests, only hard constraints
9999
θ_ext[instance.is_postponable] .= θ
100100

101101
@objective(
@@ -131,7 +131,7 @@ end
131131
function prize_collecting_vsp_Q(
132132
θ::AbstractVector,
133133
vals::AbstractVector;
134-
instance::VSPState,
134+
instance::DVSPState,
135135
model_builder=highs_model,
136136
kwargs...,
137137
)
@@ -142,7 +142,7 @@ function prize_collecting_vsp_Q(
142142
nb_nodes = nv(graph)
143143
job_indices = 2:(nb_nodes)
144144
@variable(model, y[i=1:nb_nodes, j=1:nb_nodes; has_edge(graph, i, j)] >= 0)
145-
θ_ext = fill(0.0, nb_locations(instance.instance)) # no prize for must dispatch requests, only hard constraints
145+
θ_ext = fill(0.0, location_count(instance.instance)) # no prize for must dispatch requests, only hard constraints
146146
θ_ext[instance.is_postponable] .= θ
147147
# v_ext = fill(0.0, nb_locations(instance.instance)) # no prize for must dispatch requests, only hard constraints
148148
# v_ext[instance.is_postponable] .= vals
@@ -176,7 +176,7 @@ end
176176
function my_objective_value(θ, routes; instance)
177177
(; duration) = instance.instance
178178
total = 0.0
179-
θ_ext = fill(0.0, nb_locations(instance))
179+
θ_ext = fill(0.0, location_count(instance))
180180
θ_ext[instance.is_postponable] .= θ
181181
for route in routes
182182
for (u, v) in partition(vcat(1, route), 2, 1)
@@ -189,7 +189,7 @@ end
189189
function _objective_value(θ, routes; instance)
190190
(; duration) = instance.instance
191191
total = 0.0
192-
θ_ext = fill(0.0, nb_locations(instance))
192+
θ_ext = fill(0.0, location_count(instance))
193193
θ_ext[instance.is_postponable] .= θ
194194
mapping = cumsum(instance.is_postponable)
195195
g = falses(length(θ))

0 commit comments

Comments
 (0)