Skip to content

Commit e117b38

Browse files
committed
plot instance and plot solution
1 parent 7e26cc0 commit e117b38

File tree

6 files changed

+118
-6
lines changed

6 files changed

+118
-6
lines changed

src/DecisionFocusedLearningBenchmarks.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export AbstractBenchmark, DataSample
4646
export generate_dataset
4747
export generate_statistical_model
4848
export generate_maximizer
49-
export plot_data
49+
export plot_data, plot_instance, plot_solution
5050
export compute_gap
5151

5252
# Export all benchmarks

src/StochasticVehicleScheduling/StochasticVehicleScheduling.jl

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ using JuMP:
2828
objective_value,
2929
set_silent,
3030
dual
31+
using Plots: Plots, plot, plot!, scatter!, annotate!, text
3132
using Printf: @printf
3233
using Random: Random, AbstractRNG, MersenneTwister
3334
using SparseArrays: sparse
@@ -72,6 +73,7 @@ Note that computing solutions can be time-consuming, especially for large instan
7273
You can also use instead `compact_mip` or `compact_linearized_mip` as the algorithm to compute solutions.
7374
If you want to provide a custom algorithm to compute solutions, you can pass it as the `algorithm` keyword argument.
7475
If `algorithm` takes keyword arguments, you can pass them as well directly in `kwargs...`.
76+
If `store_city=false`, the coordinates and unnecessary information about instances will not be stored in the dataset.
7577
"""
7678
function Utils.generate_dataset(
7779
benchmark::StochasticVehicleSchedulingBenchmark,
@@ -80,11 +82,14 @@ function Utils.generate_dataset(
8082
seed=nothing,
8183
rng=MersenneTwister(0),
8284
algorithm=column_generation_algorithm,
85+
store_city=true,
8386
kwargs...,
8487
)
8588
(; nb_tasks, nb_scenarios) = benchmark
8689
Random.seed!(rng, seed)
87-
instances = [Instance(; nb_tasks, nb_scenarios, rng=rng) for _ in 1:dataset_size]
90+
instances = [
91+
Instance(; nb_tasks, nb_scenarios, rng, store_city) for _ in 1:dataset_size
92+
]
8893
features = get_features.(instances)
8994
if compute_solutions
9095
solutions = [algorithm(instance; kwargs...) for instance in instances]
@@ -114,8 +119,96 @@ function Utils.generate_statistical_model(bench::StochasticVehicleSchedulingBenc
114119
return Chain(Dense(20 => 1; bias=false), vec)
115120
end
116121

122+
function plot_instance(
123+
::StochasticVehicleSchedulingBenchmark,
124+
sample::DataSample{<:Instance{City}};
125+
color_scheme=:lightrainbow,
126+
kwargs...,
127+
)
128+
(; tasks, district_width, width) = sample.instance.city
129+
ticks = 0:district_width:width
130+
max_time = maximum(t.end_time for t in sample.instance.city.tasks[1:(end - 1)])
131+
pp = floor(Int, max(max_time))
132+
palette = Plots.palette(color_scheme, pp)
133+
fig = plot(;
134+
xlabel="x",
135+
ylabel="y",
136+
legend=false,
137+
gridlinewidth=3,
138+
aspect_ratio=:equal,
139+
size=(500, 500),
140+
xticks=ticks,
141+
yticks=ticks,
142+
xlims=(-1, width + 1),
143+
ylims=(-1, width + 1),
144+
)
145+
for (i_task, task) in enumerate(tasks[1:(end - 1)])
146+
(; start_point, end_point) = task
147+
points = [(start_point.x, start_point.y), (end_point.x, end_point.y)]
148+
plot!(fig, points; color=:black)
149+
scatter!(
150+
fig,
151+
points[1];
152+
markersize=10,
153+
marker=:rect,
154+
color=palette[max(floor(Int, task.start_time), 1)],
155+
)
156+
scatter!(
157+
fig,
158+
points[2];
159+
markersize=10,
160+
marker=:rect,
161+
color=palette[max(floor(Int, task.end_time), 1)],
162+
)
163+
annotate!(fig, (points[1]..., text("$(i_task-1)", 10)))
164+
end
165+
p2 = Plots.heatmap(
166+
rand(2, 2); clims=(0, pp), framestyle=:none, c=palette, cbar=true, lims=(-1, -1)
167+
)
168+
l = Plots.@layout [a{0.99w} b]
169+
return plot(fig, p2; layout=l)
170+
end
171+
172+
function plot_solution(
173+
::StochasticVehicleSchedulingBenchmark, sample::DataSample{<:Instance{City}}; kwargs...
174+
)
175+
(; tasks, district_width, width) = sample.instance.city
176+
ticks = 0:district_width:width
177+
path_list = compute_path_list(sample.y_true)
178+
fig = plot(;
179+
xlabel="x",
180+
ylabel="y",
181+
legend=false,
182+
gridlinewidth=3,
183+
aspect_ratio=:equal,
184+
size=(500, 500),
185+
xticks=ticks,
186+
yticks=ticks,
187+
xlims=(-1, width + 1),
188+
ylims=(-1, width + 1),
189+
)
190+
for path in path_list
191+
X = Float64[]
192+
Y = Float64[]
193+
(; start_point, end_point) = tasks[path[1]]
194+
(; x, y) = end_point
195+
push!(X, x)
196+
push!(Y, y)
197+
for task in path[2:end]
198+
(; start_point, end_point) = tasks[task]
199+
push!(X, start_point.x)
200+
push!(Y, start_point.y)
201+
push!(X, end_point.x)
202+
push!(Y, end_point.y)
203+
end
204+
plot!(fig, X, Y; marker=:circle)
205+
end
206+
return fig
207+
end
208+
117209
export StochasticVehicleSchedulingBenchmark
118210
export generate_dataset, generate_maximizer, generate_statistical_model
211+
export plot_instance, plot_solution
119212
export compact_linearized_mip,
120213
compact_mip, column_generation_algorithm, evaluate_solution, is_feasible
121214

src/StochasticVehicleScheduling/instance/instance.jl

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Instance of the stochastic VSP problem.
66
# Fields
77
$TYPEDFIELDS
88
"""
9-
struct Instance{G<:AbstractGraph,M1<:AbstractMatrix,M2<:AbstractMatrix,F,C}
9+
struct Instance{CC,G<:AbstractGraph,M1<:AbstractMatrix,M2<:AbstractMatrix,F,C}
1010
"graph computed from `city` with the `create_VSP_graph(city::City)` method"
1111
graph::G
1212
"features matrix computed from `city`"
@@ -19,6 +19,8 @@ struct Instance{G<:AbstractGraph,M1<:AbstractMatrix,M2<:AbstractMatrix,F,C}
1919
vehicle_cost::C
2020
"cost of one minute delay"
2121
delay_cost::C
22+
"associated city"
23+
city::CC
2224
end
2325

2426
"""
@@ -69,15 +71,25 @@ Constructor for [`Instance`](@ref).
6971
Build an `Instance` for the stochatsic vehicle scheduling problem, with `nb_tasks` tasks and `nb_scenarios` scenarios.
7072
"""
7173
function Instance(;
72-
nb_tasks::Int, nb_scenarios::Int, rng::AbstractRNG=Random.default_rng(), kwargs...
74+
nb_tasks::Int,
75+
nb_scenarios::Int,
76+
rng::AbstractRNG=Random.default_rng(),
77+
store_city=true,
78+
kwargs...,
7379
)
7480
city = create_random_city(; rng=rng, nb_tasks, nb_scenarios, kwargs...)
7581
graph = create_VSP_graph(city)
7682
features = compute_features(city)
7783
slacks = compute_slacks(city, graph)
7884
intrinsic_delays = compute_delays(city)
7985
return Instance(
80-
graph, features, slacks, intrinsic_delays, city.vehicle_cost, city.delay_cost
86+
graph,
87+
features,
88+
slacks,
89+
intrinsic_delays,
90+
city.vehicle_cost,
91+
city.delay_cost,
92+
store_city ? city : nothing,
8193
)
8294
end
8395

src/Utils/data_sample.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Data sample data structure.
66
# Fields
77
$TYPEDFIELDS
88
"""
9-
@kwdef struct DataSample{F,S,C,I}
9+
@kwdef struct DataSample{I,F,S,C}
1010
"features"
1111
x::F
1212
"target cost parameters (optional)"

src/Utils/interface.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ Plot a data sample from the dataset created by [`generate_dataset`](@ref).
4646
Check the specific benchmark documentation of `plot_data` for more details on the arguments.
4747
"""
4848
function plot_data end
49+
function plot_instance end
50+
function plot_solution end
4951

5052
"""
5153
compute_gap(::AbstractBenchmark, dataset::Vector{<:DataSample}, statistical_model, maximizer) -> Float64

test/vsp.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515
)
1616
@test length(dataset) == N
1717

18+
figure_1 = plot_instance(b, dataset[1])
19+
@test figure_1 isa Plots.Plot
20+
figure_2 = plot_solution(b, dataset[1])
21+
@test figure_2 isa Plots.Plot
22+
1823
maximizer = generate_maximizer(b)
1924
model = generate_statistical_model(b)
2025

0 commit comments

Comments
 (0)