Skip to content
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
2 changes: 1 addition & 1 deletion .github/workflows/Test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
julia-version: ['1']
julia-version: ['1.10', '1']

steps:
- uses: actions/checkout@v5
Expand Down
28 changes: 6 additions & 22 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ uuid = "2fbe496a-299b-4c81-bab5-c44dfc55cf20"
authors = ["Members of JuliaDecisionFocusedLearning"]
version = "0.3.0"

[workspace]
projects = ["docs", "test"]

[deps]
Colors = "5ae59095-9a9b-59fe-a467-6f913c188581"
Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa"
Expand Down Expand Up @@ -56,31 +59,12 @@ LinearAlgebra = "1"
Metalhead = "0.9.4"
NPZ = "0.4"
Plots = "1"
Printf = "1.11.0"
Printf = "1"
Random = "1"
Requires = "1.3.0"
SCIP = "0.12"
SimpleWeightedGraphs = "1.4"
SparseArrays = "1"
Statistics = "1.11.1"
Statistics = "1"
StatsBase = "0.34.4"
julia = "1.6"

[extras]
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
Flux = "587475ba-b771-5e3f-ad9e-33799f191a9c"
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b"
JuliaFormatter = "98e50ef6-434e-11e9-1051-2b60c6c9e899"
ProgressMeter = "92933f4c-e287-5a05-a399-4b506db050ca"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
TestItemRunner = "f8b46487-2199-4994-9208-9a1283c18c0a"
UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228"
Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f"

[targets]
test = ["Aqua", "Documenter", "Flux", "Graphs", "JET", "JuliaFormatter", "Random", "ProgressMeter", "StableRNGs", "Statistics", "Test", "TestItemRunner", "UnicodePlots", "Zygote"]
julia = "1.10"
16 changes: 10 additions & 6 deletions src/Argmax2D/Argmax2D.jl
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ function Utils.generate_sample(bench::Argmax2DBenchmark, rng::AbstractRNG)
θ_true ./= 2 * norm(θ_true)
instance = build_polytope(rand(rng, polytope_vertex_range); shift=rand(rng))
y_true = maximizer(θ_true; instance)
return DataSample(; x=x, θ=θ_true, y=y_true, info=instance)
return DataSample(; x=x, θ=θ_true, y=y_true, instance=instance)
end

"""
Expand All @@ -88,11 +88,11 @@ function Utils.generate_statistical_model(
return model
end

function Utils.plot_data(::Argmax2DBenchmark; info, θ, kwargs...)
function Utils.plot_data(::Argmax2DBenchmark; instance, θ, kwargs...)
pl = init_plot()
plot_polytope!(pl, info)
plot_polytope!(pl, instance)
plot_objective!(pl, θ)
return plot_maximizer!(pl, θ, info, maximizer)
return plot_maximizer!(pl, θ, instance, maximizer)
end

"""
Expand All @@ -101,9 +101,13 @@ $TYPEDSIGNATURES
Plot the data sample for the [`Argmax2DBenchmark`](@ref).
"""
function Utils.plot_data(
bench::Argmax2DBenchmark, sample::DataSample; info=sample.info, θ=sample.θ, kwargs...
bench::Argmax2DBenchmark,
sample::DataSample;
instance=sample.instance,
θ=sample.θ,
kwargs...,
)
return Utils.plot_data(bench; info, θ, kwargs...)
return Utils.plot_data(bench; instance, θ, kwargs...)
end

export Argmax2DBenchmark
Expand Down
2 changes: 1 addition & 1 deletion src/DecisionFocusedLearningBenchmarks.jl
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export generate_sample, generate_dataset, generate_environments, generate_enviro
export generate_scenario
export generate_policies
export generate_statistical_model
export generate_maximizer, maximizer_kwargs
export generate_maximizer
export generate_anticipative_solution
export is_exogenous, is_endogenous

Expand Down
2 changes: 1 addition & 1 deletion src/DynamicAssortment/DynamicAssortment.jl
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ Outputs a data sample containing an [`Instance`](@ref).
function Utils.generate_sample(
b::DynamicAssortmentBenchmark, rng::AbstractRNG=MersenneTwister(0)
)
return DataSample(; info=Instance(b, rng))
return DataSample(; instance=Instance(b, rng))
end

"""
Expand Down
2 changes: 1 addition & 1 deletion src/DynamicVehicleScheduling/DynamicVehicleScheduling.jl
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ function Utils.generate_dataset(b::DynamicVehicleSchedulingBenchmark, dataset_si
dataset_size = min(dataset_size, length(files))
return [
DataSample(;
info=Instance(
instance=Instance(
read_vsp_instance(files[i]);
max_requests_per_epoch,
Δ_dispatch,
Expand Down
28 changes: 15 additions & 13 deletions src/DynamicVehicleScheduling/anticipative_solver.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,14 @@ function retrieve_routes_anticipative(
current_task = task
while current_task != 1 # < nb_tasks
push!(route, current_task)
local next_task
next_task = -1
for i in 1:nb_tasks
if isapprox(y[current_task, i, t], 1; atol=0.1)
next_task = i
break
end
end
@assert next_task != -1 "No next task found from task $current_task at epoch $t"
current_task = next_task
end
push!(routes[i], route)
Expand Down Expand Up @@ -92,14 +93,14 @@ function anticipative_solver(
job_indices = 2:nb_nodes
epoch_indices = T

@variable(model, y[i = 1:nb_nodes, j = 1:nb_nodes, t = epoch_indices]; binary=true)
@variable(model, y[i=1:nb_nodes, j=1:nb_nodes, t=epoch_indices]; binary=true)

@objective(
model,
Max,
sum(
-duration[i, j] * y[i, j, t] for
i in 1:nb_nodes, j in 1:nb_nodes, t in epoch_indices
-duration[i, j] * y[i, j, t] for i in 1:nb_nodes, j in 1:nb_nodes,
t in epoch_indices
)
)

Expand Down Expand Up @@ -171,12 +172,14 @@ function anticipative_solver(
routes = epoch_routes[i]
epoch_customers = epoch_indices[i]

y_true = VSPSolution(
Vector{Int}[
map(idx -> findfirst(==(idx), epoch_customers), route) for route in routes
];
max_index=length(epoch_customers),
).edge_matrix
y_true =
VSPSolution(
Vector{Int}[
map(idx -> findfirst(==(idx), epoch_customers), route) for
route in routes
];
max_index=length(epoch_customers),
).edge_matrix

location_indices = customer_index[epoch_customers]
new_coordinates = env.instance.static_instance.coordinate[location_indices]
Expand All @@ -200,8 +203,7 @@ function anticipative_solver(
is_must_dispatch[2:end] .= true
else
is_must_dispatch[2:end] .=
planning_start_time .+ epoch_duration .+ @view(new_duration[1, 2:end]) .>
new_start_time[2:end]
planning_start_time .+ epoch_duration .+ @view(new_duration[1, 2:end]) .> new_start_time[2:end]
end
is_postponable[2:end] .= .!is_must_dispatch[2:end]
# TODO: avoid code duplication with add_new_customers!
Expand All @@ -222,7 +224,7 @@ function anticipative_solver(
compute_features(state, env.instance)
end

return DataSample(; info=(; state, reward), y=y_true, x)
return DataSample(; y=y_true, x, state, reward)
end

return obj, dataset
Expand Down
9 changes: 6 additions & 3 deletions src/DynamicVehicleScheduling/maximizer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,14 @@ function retrieve_routes(y::AbstractArray, graph::AbstractGraph)
current_task = task
while current_task != 1 # < nb_tasks
push!(route, current_task)
local next_task
next_task = -1
for i in outneighbors(graph, current_task)
if isapprox(y[current_task, i], 1; atol=0.1)
next_task = i
break
end
end
@assert next_task != -1 "No next task found from task $current_task"
current_task = next_task
end
push!(routes, route)
Expand All @@ -93,7 +94,7 @@ function prize_collecting_vsp(
nb_nodes = nv(graph)
job_indices = 2:(nb_nodes)

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

θ_ext = fill(0.0, location_count(instance)) # no prize for must dispatch requests, only hard constraints
θ_ext[instance.is_postponable] .= θ
Expand Down Expand Up @@ -129,7 +130,9 @@ end

function oracle(θ; instance::DVSPState, kwargs...)
routes = prize_collecting_vsp(θ; instance=instance, kwargs...)
return VSPSolution(routes; max_index=location_count(instance.state_instance)).edge_matrix
return VSPSolution(
routes; max_index=location_count(instance.state_instance)
).edge_matrix
end

function g(y; instance, kwargs...)
Expand Down
12 changes: 6 additions & 6 deletions src/DynamicVehicleScheduling/static_vsp/parsing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ Normalize all time values by the `normalization` parameter.
function read_vsp_instance(filepath::String; normalization=3600.0, digits=2)
type = Float64 #rounded ? Int : Float64
mode = ""
local edge_weight_type
local edge_weight_format
edge_weight_type = ""
edge_weight_format = ""
duration_matrix = Vector{type}[]
nb_locations = 0
local demand
local service_time
local coordinates
local start_time
demand = type[]
service_time = type[]
coordinates = Matrix{type}(undef, 0, 2)
start_time = type[]

file = open(filepath, "r")
for line in eachline(file)
Expand Down
18 changes: 10 additions & 8 deletions src/StochasticVehicleScheduling/StochasticVehicleScheduling.jl
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ end
function Utils.objective_value(
::StochasticVehicleSchedulingBenchmark, sample::DataSample, y::BitVector
)
return evaluate_solution(y, sample.info)
return evaluate_solution(y, sample.instance)
end

"""
Expand Down Expand Up @@ -98,7 +98,7 @@ function Utils.generate_sample(
else
nothing
end
return DataSample(; x, info=instance, y=y_true)
return DataSample(; x, instance, y=y_true)
end

"""
Expand Down Expand Up @@ -145,11 +145,12 @@ end
$TYPEDSIGNATURES
"""
function plot_instance(
::StochasticVehicleSchedulingBenchmark, sample::DataSample{<:Instance{City}}; kwargs...
::StochasticVehicleSchedulingBenchmark, sample::DataSample; kwargs...
)
(; tasks, district_width, width) = sample.info.city
@assert hasproperty(sample.instance, :city) "Sample does not contain city information."
(; tasks, district_width, width) = sample.instance.city
ticks = 0:district_width:width
max_time = maximum(t.end_time for t in sample.info.city.tasks[1:(end - 1)])
max_time = maximum(t.end_time for t in sample.instance.city.tasks[1:(end - 1)])
fig = plot(;
xlabel="x",
ylabel="y",
Expand Down Expand Up @@ -204,11 +205,12 @@ end
$TYPEDSIGNATURES
"""
function plot_solution(
::StochasticVehicleSchedulingBenchmark, sample::DataSample{<:Instance{City}}; kwargs...
::StochasticVehicleSchedulingBenchmark, sample::DataSample; kwargs...
)
(; tasks, district_width, width) = sample.info.city
@assert hasproperty(sample.instance, :city) "Sample does not contain city information."
(; tasks, district_width, width) = sample.instance.city
ticks = 0:district_width:width
solution = Solution(sample.y, sample.info)
solution = Solution(sample.y, sample.instance)
path_list = compute_path_list(solution)
fig = plot(;
xlabel="x",
Expand Down
4 changes: 2 additions & 2 deletions src/StochasticVehicleScheduling/instance/instance.jl
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ function create_VSP_graph(city::City)
job_tasks = 2:(city.nb_tasks + 1)

travel_times = [
distance(task1.end_point, task2.start_point) for
task1 in city.tasks, task2 in city.tasks
distance(task1.end_point, task2.start_point) for task1 in city.tasks,
task2 in city.tasks
]

# Create existing edges
Expand Down
2 changes: 1 addition & 1 deletion src/StochasticVehicleScheduling/maximizer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function vsp_maximizer(
nb_nodes = nv(graph)
job_indices = 2:(nb_nodes - 1)

@variable(model, y[i = 1:nb_nodes, j = 1:nb_nodes; has_edge(graph, i, j)], Bin)
@variable(model, y[i=1:nb_nodes, j=1:nb_nodes; has_edge(graph, i, j)], Bin)

@objective(
model,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ function solve_deterministic_VSP(
(; city, graph) = instance

travel_times = [
distance(task1.end_point, task2.start_point) for
task1 in city.tasks, task2 in city.tasks
distance(task1.end_point, task2.start_point) for task1 in city.tasks,
task2 in city.tasks
]

model = model_builder()
Expand All @@ -21,7 +21,7 @@ function solve_deterministic_VSP(
nb_nodes = nv(graph)
job_indices = 2:(nb_nodes - 1)

@variable(model, x[i = 1:nb_nodes, j = 1:nb_nodes; has_edge(graph, i, j)], Bin)
@variable(model, x[i=1:nb_nodes, j=1:nb_nodes; has_edge(graph, i, j)], Bin)

@objective(
model,
Expand Down
1 change: 0 additions & 1 deletion src/Utils/Utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ export generate_policies
export generate_anticipative_solution

export plot_data, compute_gap
export maximizer_kwargs
export grid_graph, get_path, path_to_matrix
export neg_tensor, squeeze_last_dims, average_tensor
export scip_model, highs_model
Expand Down
Loading