Skip to content

Commit 9fe5e86

Browse files
committed
now anticipative solver sirectly creates an epoch dataset
1 parent 7f9d322 commit 9fe5e86

File tree

8 files changed

+176
-109
lines changed

8 files changed

+176
-109
lines changed

src/DynamicVehicleScheduling/DynamicVSP/learning/2d_features.jl

Lines changed: 0 additions & 13 deletions
This file was deleted.

src/DynamicVehicleScheduling/DynamicVehicleScheduling.jl

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,12 @@ include("environment/scenario.jl")
3636
include("environment/environment.jl")
3737
include("environment/plot.jl")
3838

39-
include("DynamicVSP/algorithms/prize_collecting_vsp.jl")
40-
include("DynamicVSP/algorithms/anticipative_solver.jl")
39+
include("algorithms/prize_collecting_vsp.jl")
40+
include("algorithms/anticipative_solver.jl")
4141

42-
include("DynamicVSP/learning/features.jl")
43-
include("DynamicVSP/learning/2d_features.jl")
44-
include("DynamicVSP/learning/dataset.jl")
42+
include("learning/features.jl")
43+
include("learning/2d_features.jl")
44+
include("learning/dataset.jl")
4545

4646
include("policy/abstract_vsp_policy.jl")
4747
include("policy/greedy_policy.jl")
@@ -62,14 +62,18 @@ function Utils.generate_scenario_generator(::DVSPBenchmark)
6262
end
6363

6464
function Utils.generate_anticipative_solver(::DVSPBenchmark; kwargs...)
65-
return AnticipativeVSPPolicy(; kwargs...)
65+
return anticipative_solver
6666
end
6767

6868
function Utils.generate_environment(::DVSPBenchmark, instance::Instance; kwargs...)
6969
return DVSPEnv(instance; kwargs...)
7070
end
7171

72-
export DVSPBenchmark, generate_environment # , generate_sample, generate_anticipative_solver
72+
function Utils.generate_maximizer(::DVSPBenchmark)
73+
return prize_collecting_vsp
74+
end
75+
76+
export DVSPBenchmark #, generate_environment # , generate_sample, generate_anticipative_solver
7377
export run_policy!,
7478
GreedyVSPPolicy, LazyVSPPolicy, KleopatraVSPPolicy, AnticipativeVSPPolicy
7579

src/DynamicVehicleScheduling/DynamicVSP/algorithms/anticipative_solver.jl renamed to src/DynamicVehicleScheduling/algorithms/anticipative_solver.jl

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,76 @@ function anticipative_solver(
116116

117117
optimize!(model)
118118

119-
return JuMP.objective_value(model),
120-
retrieve_routes_anticipative(value.(y), env, customer_index)
119+
obj = JuMP.objective_value(model)
120+
epoch_routes = retrieve_routes_anticipative(value.(y), env, customer_index)
121+
122+
epoch_indices = Vector{Int}[]
123+
N = 1
124+
indices = [1]
125+
for epoch in 1:last_epoch
126+
M = length(scenario.indices[epoch])
127+
indices = vcat(indices, (N + 1):(N + M))
128+
push!(epoch_indices, copy(indices))
129+
N = N + M
130+
epoch_routes[epoch]
131+
dispatched = vcat(epoch_routes[epoch]...)
132+
indices = setdiff(indices, dispatched)
133+
end
134+
135+
indices = vcat(1, scenario.indices...)
136+
start_time = vcat(0.0, scenario.start_time...)
137+
service_time = vcat(0.0, scenario.service_time...)
138+
139+
dataset = map(1:last_epoch) do epoch
140+
routes = epoch_routes[epoch]
141+
epoch_customers = epoch_indices[epoch]
142+
# y_true = [
143+
# map(idx -> findfirst(==(idx), epoch_customers), route) for route in routes
144+
# ]
145+
146+
y_true =
147+
VSPSolution(
148+
Vector{Int}[
149+
map(idx -> findfirst(==(idx), epoch_customers), route) for
150+
route in routes
151+
];
152+
max_index=length(epoch_customers),
153+
).edge_matrix
154+
155+
location_indices = indices[epoch_customers]
156+
new_coordinates = env.instance.static_instance.coordinate[location_indices]
157+
new_start_time = start_time[epoch_customers]
158+
new_service_time = service_time[epoch_customers]
159+
new_duration = env.instance.static_instance.duration[
160+
location_indices, location_indices
161+
]
162+
static_instance = StaticInstance(
163+
new_coordinates, new_service_time, new_start_time, new_duration
164+
)
165+
166+
is_must_dispatch = falses(length(location_indices))
167+
is_postponable = falses(length(location_indices))
168+
169+
epoch_duration = env.instance.epoch_duration
170+
Δ_dispatch = env.instance.Δ_dispatch
171+
planning_start_time = (epoch - 1) * epoch_duration + Δ_dispatch
172+
is_must_dispatch[2:end] .=
173+
planning_start_time .+ epoch_duration .+ @view(new_duration[1, 2:end]) .>
174+
new_start_time[2:end]
175+
is_postponable[2:end] .= .!is_must_dispatch[2:end]
176+
177+
state = DVSPState(;
178+
state_instance=static_instance,
179+
is_must_dispatch,
180+
is_postponable,
181+
location_indices,
182+
current_epoch=epoch,
183+
)
184+
185+
x = compute_2D_features(state, env.instance)
186+
187+
return DataSample(; instance=state, y_true, x)
188+
end
189+
190+
return obj, dataset
121191
end

src/DynamicVehicleScheduling/DynamicVSP/algorithms/prize_collecting_vsp.jl renamed to src/DynamicVehicleScheduling/algorithms/prize_collecting_vsp.jl

Lines changed: 75 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -127,83 +127,83 @@ function prize_collecting_vsp(
127127
return retrieve_routes(value.(y), graph)
128128
end
129129

130-
# ?
131-
function prize_collecting_vsp_Q(
132-
θ::AbstractVector,
133-
vals::AbstractVector;
134-
instance::DVSPState,
135-
model_builder=highs_model,
136-
kwargs...,
137-
)
138-
(; duration) = instance.instance
139-
graph = create_graph(instance)
140-
model = model_builder()
141-
set_silent(model)
142-
nb_nodes = nv(graph)
143-
job_indices = 2:(nb_nodes)
144-
@variable(model, y[i=1:nb_nodes, j=1:nb_nodes; has_edge(graph, i, j)] >= 0)
145-
θ_ext = fill(0.0, location_count(instance.instance)) # no prize for must dispatch requests, only hard constraints
146-
θ_ext[instance.is_postponable] .= θ
147-
# v_ext = fill(0.0, nb_locations(instance.instance)) # no prize for must dispatch requests, only hard constraints
148-
# v_ext[instance.is_postponable] .= vals
149-
@objective(
150-
model,
151-
Max,
152-
sum(
153-
(θ_ext[dst(edge)] + vals[dst(edge)] - duration[src(edge), dst(edge)]) *
154-
y[src(edge), dst(edge)] for edge in edges(graph)
155-
)
156-
)
157-
@constraint(
158-
model,
159-
flow[i in 2:nb_nodes],
160-
sum(y[j, i] for j in inneighbors(graph, i)) ==
161-
sum(y[i, j] for j in outneighbors(graph, i))
162-
)
163-
@constraint(
164-
model, demand[i in job_indices], sum(y[j, i] for j in inneighbors(graph, i)) <= 1
165-
)
166-
# must dispatch constraints
167-
@constraint(
168-
model,
169-
demand_must_dispatch[i in job_indices; instance.is_must_dispatch[i]],
170-
sum(y[j, i] for j in inneighbors(graph, i)) == 1
171-
)
172-
optimize!(model)
173-
return retrieve_routes(value.(y), graph)
174-
end
130+
# # ?
131+
# function prize_collecting_vsp_Q(
132+
# θ::AbstractVector,
133+
# vals::AbstractVector;
134+
# instance::DVSPState,
135+
# model_builder=highs_model,
136+
# kwargs...,
137+
# )
138+
# (; duration) = instance.instance
139+
# graph = create_graph(instance)
140+
# model = model_builder()
141+
# set_silent(model)
142+
# nb_nodes = nv(graph)
143+
# job_indices = 2:(nb_nodes)
144+
# @variable(model, y[i=1:nb_nodes, j=1:nb_nodes; has_edge(graph, i, j)] >= 0)
145+
# θ_ext = fill(0.0, location_count(instance.instance)) # no prize for must dispatch requests, only hard constraints
146+
# θ_ext[instance.is_postponable] .= θ
147+
# # v_ext = fill(0.0, nb_locations(instance.instance)) # no prize for must dispatch requests, only hard constraints
148+
# # v_ext[instance.is_postponable] .= vals
149+
# @objective(
150+
# model,
151+
# Max,
152+
# sum(
153+
# (θ_ext[dst(edge)] + vals[dst(edge)] - duration[src(edge), dst(edge)]) *
154+
# y[src(edge), dst(edge)] for edge in edges(graph)
155+
# )
156+
# )
157+
# @constraint(
158+
# model,
159+
# flow[i in 2:nb_nodes],
160+
# sum(y[j, i] for j in inneighbors(graph, i)) ==
161+
# sum(y[i, j] for j in outneighbors(graph, i))
162+
# )
163+
# @constraint(
164+
# model, demand[i in job_indices], sum(y[j, i] for j in inneighbors(graph, i)) <= 1
165+
# )
166+
# # must dispatch constraints
167+
# @constraint(
168+
# model,
169+
# demand_must_dispatch[i in job_indices; instance.is_must_dispatch[i]],
170+
# sum(y[j, i] for j in inneighbors(graph, i)) == 1
171+
# )
172+
# optimize!(model)
173+
# return retrieve_routes(value.(y), graph)
174+
# end
175175

176-
function my_objective_value(θ, routes; instance)
177-
(; duration) = instance.instance
178-
total = 0.0
179-
θ_ext = fill(0.0, location_count(instance))
180-
θ_ext[instance.is_postponable] .= θ
181-
for route in routes
182-
for (u, v) in partition(vcat(1, route), 2, 1)
183-
total += θ_ext[v] - duration[u, v]
184-
end
185-
end
186-
return -total
187-
end
176+
# function my_objective_value(θ, routes; instance)
177+
# (; duration) = instance.instance
178+
# total = 0.0
179+
# θ_ext = fill(0.0, location_count(instance))
180+
# θ_ext[instance.is_postponable] .= θ
181+
# for route in routes
182+
# for (u, v) in partition(vcat(1, route), 2, 1)
183+
# total += θ_ext[v] - duration[u, v]
184+
# end
185+
# end
186+
# return -total
187+
# end
188188

189-
function _objective_value(θ, routes; instance)
190-
(; duration) = instance.instance
191-
total = 0.0
192-
θ_ext = fill(0.0, location_count(instance))
193-
θ_ext[instance.is_postponable] .= θ
194-
mapping = cumsum(instance.is_postponable)
195-
g = falses(length(θ))
196-
for route in routes
197-
for (u, v) in partition(vcat(1, route), 2, 1)
198-
total -= duration[u, v]
199-
if instance.is_postponable[v]
200-
total += θ_ext[v]
201-
g[mapping[v]] = 1
202-
end
203-
end
204-
end
205-
return -total, g
206-
end
189+
# function _objective_value(θ, routes; instance)
190+
# (; duration) = instance.instance
191+
# total = 0.0
192+
# θ_ext = fill(0.0, location_count(instance))
193+
# θ_ext[instance.is_postponable] .= θ
194+
# mapping = cumsum(instance.is_postponable)
195+
# g = falses(length(θ))
196+
# for route in routes
197+
# for (u, v) in partition(vcat(1, route), 2, 1)
198+
# total -= duration[u, v]
199+
# if instance.is_postponable[v]
200+
# total += θ_ext[v]
201+
# g[mapping[v]] = 1
202+
# end
203+
# end
204+
# end
205+
# return -total, g
206+
# end
207207

208208
# function ChainRulesCore.rrule(::typeof(my_objective_value), θ, routes; instance)
209209
# total, g = _objective_value(θ, routes; instance)

src/DynamicVehicleScheduling/environment/environment.jl

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,6 @@ Check if the episode is terminated, i.e. if the current epoch is the last one.
5252
"""
5353
CommonRLInterface.terminated(env::DVSPEnv) = current_epoch(env) >= last_epoch(env)
5454

55-
"""
56-
draw new customers in scenario
57-
"""
58-
function draw_next_epoch!(env::DVSPEnv, scenario=env.scenario)
59-
env.state.current_epoch += 1
60-
61-
return nothing
62-
end
63-
6455
"""
6556
$TYPEDSIGNATURES
6657
@@ -78,10 +69,9 @@ remove dispatched customers, advance time, and add new requests to the environme
7869
function CommonRLInterface.act!(env::DVSPEnv, routes, scenario=env.scenario)
7970
reward = -apply_routes!(env.state, routes)
8071
env.state.current_epoch += 1
81-
if current_epoch(env) > last_epoch(env)
82-
return nothing
72+
if current_epoch(env) <= last_epoch(env)
73+
add_new_customers!(env.state, env.instance; scenario[current_epoch(env)]...)
8374
end
84-
add_new_customers!(env.state, env.instance; scenario[current_epoch(env)]...)
8575
return reward
8676
end
8777

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
function get_features_meanTimeToRequests(state::DVSPState, instance::Instance)
2+
quantiles = [0.5]
3+
a = instance.static_instance.duration[state.location_indices, 2:end]
4+
quantileTimeToRequests = mapslices(x -> quantile(x, quantiles), a; dims=2)
5+
return quantileTimeToRequests
6+
end
7+
8+
function compute_2D_features(state::DVSPState, instance::Instance)
9+
timeDepotRequest = state.state_instance.duration[:, 1][state.is_postponable]
10+
quantileTimeToRequests = get_features_meanTimeToRequests(state, instance)[state.is_postponable]
11+
return hcat(timeDepotRequest, quantileTimeToRequests)'
12+
end
13+
14+
function compute_2D_features(env::DVSPEnv)
15+
return compute_2D_features(env.state, env.instance)
16+
end

0 commit comments

Comments
 (0)