diff --git a/Project.toml b/Project.toml index f2bc82e..d9500c6 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "DecisionFocusedLearningBenchmarks" uuid = "2fbe496a-299b-4c81-bab5-c44dfc55cf20" authors = ["Members of JuliaDecisionFocusedLearning"] -version = "0.2.1" +version = "0.2.2" [deps] ConstrainedShortestPaths = "b3798467-87dc-4d99-943d-35a1bd39e395" diff --git a/src/StochasticVehicleScheduling/StochasticVehicleScheduling.jl b/src/StochasticVehicleScheduling/StochasticVehicleScheduling.jl index d6d2558..150f147 100644 --- a/src/StochasticVehicleScheduling/StochasticVehicleScheduling.jl +++ b/src/StochasticVehicleScheduling/StochasticVehicleScheduling.jl @@ -3,7 +3,8 @@ module StochasticVehicleScheduling export StochasticVehicleSchedulingBenchmark export generate_dataset, generate_maximizer, generate_statistical_model export plot_instance, plot_solution -export compact_linearized_mip, compact_mip, column_generation_algorithm, local_search +export compact_linearized_mip, + compact_mip, column_generation_algorithm, local_search, deterministic_mip export evaluate_solution, is_feasible using ..Utils @@ -44,6 +45,7 @@ include("solution/solution.jl") include("solution/algorithms/mip.jl") include("solution/algorithms/column_generation.jl") include("solution/algorithms/local_search.jl") +include("solution/algorithms/deterministic_mip.jl") include("maximizer.jl") diff --git a/src/StochasticVehicleScheduling/solution/algorithms/deterministic_mip.jl b/src/StochasticVehicleScheduling/solution/algorithms/deterministic_mip.jl new file mode 100644 index 0000000..5f68190 --- /dev/null +++ b/src/StochasticVehicleScheduling/solution/algorithms/deterministic_mip.jl @@ -0,0 +1,45 @@ +""" +$TYPEDSIGNATURES + +Solves the deterministic version of the vehicle scheduling problem using a MIP model. +Does not take into account the stochastic nature of the problem. +""" +function deterministic_mip(instance::Instance; model_builder=highs_model, silent=true) + (; graph, vehicle_cost) = instance + nb_nodes = nv(graph) + job_indices = 2:(nb_nodes - 1) + nodes = 1:nb_nodes + + # Model definition + model = model_builder() + silent && set_silent(model) + + # Variables and objective function + @variable(model, y[u in nodes, v in nodes; has_edge(graph, u, v)], Bin) + + @objective( + model, + Min, + vehicle_cost * sum(y[1, v] for v in job_indices) # nb_vehicles + ) + + # Flow contraints + @constraint( + model, + flow[i in job_indices], + sum(y[j, i] for j in inneighbors(graph, i)) == + sum(y[i, j] for j in outneighbors(graph, i)) + ) + @constraint( + model, + unit_demand[i in job_indices], + sum(y[j, i] for j in inneighbors(graph, i)) == 1 + ) + + # Solve model + optimize!(model) + solution = value.(y) + + sol = solution_from_JuMP_array(solution, graph) + return sol +end diff --git a/test/vsp.jl b/test/vsp.jl index 595b38c..1c3b5fd 100644 --- a/test/vsp.jl +++ b/test/vsp.jl @@ -3,14 +3,22 @@ using DecisionFocusedLearningBenchmarks.StochasticVehicleScheduling using Graphs using Plots + using StableRNGs: StableRNG b = StochasticVehicleSchedulingBenchmark(; nb_tasks=25, nb_scenarios=10) N = 5 - dataset = generate_dataset(b, N; seed=0) - mip_dataset = generate_dataset(b, N; seed=0, algorithm=compact_mip) - mipl_dataset = generate_dataset(b, N; seed=0, algorithm=compact_linearized_mip) - local_search_dataset = generate_dataset(b, N; seed=0, algorithm=local_search) + dataset = generate_dataset(b, N; seed=0, rng=StableRNG(0)) + mip_dataset = generate_dataset(b, N; seed=0, rng=StableRNG(0), algorithm=compact_mip) + mipl_dataset = generate_dataset( + b, N; seed=0, rng=StableRNG(0), algorithm=compact_linearized_mip + ) + local_search_dataset = generate_dataset( + b, N; seed=0, rng=StableRNG(0), algorithm=local_search + ) + deterministic_dataset = generate_dataset( + b, N; seed=0, rng=StableRNG(0), algorithm=deterministic_mip + ) @test length(dataset) == N figure_1 = plot_instance(b, dataset[1]) @@ -25,11 +33,12 @@ gap_mip = compute_gap(b, mip_dataset, model, maximizer) gap_mipl = compute_gap(b, mipl_dataset, model, maximizer) gap_local_search = compute_gap(b, local_search_dataset, model, maximizer) + gap_deterministic = compute_gap(b, deterministic_dataset, model, maximizer) - @test gap >= 0 && gap_mip >= 0 && gap_mipl >= 0 && gap_local_search >= 0 @test gap_mip ≈ gap_mipl rtol = 1e-2 @test gap_mip >= gap_local_search @test gap_mip >= gap + @test gap_local_search >= gap_deterministic for sample in dataset x = sample.x