Skip to content

Commit a232588

Browse files
committed
mip algorithms
1 parent 649c94e commit a232588

File tree

9 files changed

+623
-7
lines changed

9 files changed

+623
-7
lines changed

Project.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ NPZ = "15e1cf62-19b3-5cfa-8e77-841668bca605"
2020
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
2121
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
2222
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
23+
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
24+
SCIP = "82193955-e24f-5292-bf16-6f2c5261a85f"
2325
SimpleWeightedGraphs = "47aef6b3-ad0c-573a-a1e2-d07658019622"
2426
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
2527
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
@@ -41,6 +43,8 @@ NPZ = "0.4"
4143
Plots = "1"
4244
Printf = "1.11.0"
4345
Random = "1"
46+
Requires = "1.3.0"
47+
SCIP = "0.11.6"
4448
SimpleWeightedGraphs = "1.4"
4549
SparseArrays = "1"
4650
Statistics = "1.11.1"

src/DecisionFocusedLearningBenchmarks.jl

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
module DecisionFocusedLearningBenchmarks
22

33
using DataDeps
4-
using HiGHS
5-
using InferOpt
4+
using Requires: @require
65

76
function __init__()
7+
# Register the Warcraft dataset
88
ENV["DATADEPS_ALWAYS_ACCEPT"] = "true"
99
register(
1010
DataDep(
@@ -14,6 +14,10 @@ function __init__()
1414
post_fetch_method=unpack,
1515
),
1616
)
17+
18+
# Gurobi setup
19+
@info "If you have Gurobi installed and want to use it, make sure to `using Gurobi` in order to enable it."
20+
@require Gurobi = "2e9cd046-0924-5485-92f1-d5272153d98b" include("gurobi_setup.jl")
1721
return nothing
1822
end
1923

src/StochasticVehicleScheduling/StochasticVehicleScheduling.jl

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,20 @@ module StochasticVehicleScheduling
33
using ..Utils
44
using DocStringExtensions: TYPEDEF, TYPEDFIELDS, TYPEDSIGNATURES
55
using Distributions: Distribution, LogNormal, Uniform
6-
using Graphs: AbstractGraph, SimpleDiGraph, add_edge!, nv, ne, edges, src, dst
6+
using Graphs:
7+
AbstractGraph,
8+
SimpleDiGraph,
9+
add_edge!,
10+
nv,
11+
ne,
12+
edges,
13+
src,
14+
dst,
15+
has_edge,
16+
inneighbors,
17+
outneighbors
18+
using JuMP:
19+
Model, @variable, @objective, @constraint, optimize!, value, objective_value, set_silent
720
using Printf: @printf
821
using Random: Random, AbstractRNG, MersenneTwister
922
using SparseArrays: sparse
@@ -17,6 +30,9 @@ include("instance/city.jl")
1730
include("instance/features.jl")
1831
include("instance/instance.jl")
1932

33+
include("solution/solution.jl")
34+
include("solution/exact_algorithms/mip.jl")
35+
2036
"""
2137
$TYPEDFIELDS
2238
@@ -58,6 +74,6 @@ function Utils.generate_statistical_model(bench::StochasticVehicleSchedulingBenc
5874

5975
export StochasticVehicleSchedulingBenchmark
6076

61-
export create_random_city, compute_features, Instance
77+
export compact_linearized_mip, compact_mip
6278

6379
end

src/StochasticVehicleScheduling/instance/instance.jl

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ struct Instance{G<:AbstractGraph,M1<:AbstractMatrix,M2<:AbstractMatrix,F,C}
1414
"slack matrix"
1515
slacks::M1
1616
"intrinsic delays scenario matrix"
17-
delays::M2
17+
intrinsic_delays::M2
1818
"cost of a vehicle"
1919
vehicle_cost::C
2020
"cost of one minute delay"
@@ -75,8 +75,10 @@ function Instance(;
7575
graph = create_VSP_graph(city)
7676
features = compute_features(city)
7777
slacks = compute_slacks(city, graph)
78-
delays = compute_delays(city)
79-
return Instance(graph, features, slacks, delays, city.vehicle_cost, city.delay_cost)
78+
intrinsic_delays = compute_delays(city)
79+
return Instance(
80+
graph, features, slacks, intrinsic_delays, city.vehicle_cost, city.delay_cost
81+
)
8082
end
8183

8284
"""
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
"""
2+
$TYPEDSIGNATURES
3+
4+
Returns the optimal solution of the Stochastic VSP instance, by solving the associated compact MIP.
5+
Quadratic constraints are linearized using Mc Cormick linearization.
6+
Note: If you have Gurobi, use `grb_model` as `model_builder` instead of `highs_model`.
7+
"""
8+
function compact_linearized_mip(instance::Instance; model_builder=scip_model, silent=true)
9+
(; graph, slacks, intrinsic_delays, vehicle_cost, delay_cost) = instance
10+
nb_nodes = nv(graph)
11+
job_indices = 2:(nb_nodes - 1)
12+
nodes = 1:nb_nodes
13+
14+
# Pre-processing
15+
ε = intrinsic_delays
16+
Rmax = maximum(sum(ε; dims=1))
17+
nb_scenarios = size(ε, 2)
18+
Ω = 1:nb_scenarios
19+
20+
# Model definition
21+
model = model_builder()
22+
silent && set_silent(model)
23+
24+
# Variables and objective function
25+
@variable(model, y[u in nodes, v in nodes; has_edge(graph, u, v)], Bin)
26+
@variable(model, R[v in nodes, ω in Ω] >= 0) # propagated delay of job v
27+
@variable(model, yR[u in nodes, v in nodes, ω in Ω; has_edge(graph, u, v)] >= 0) # yR[u, v] = y[u, v] * R[u, ω]
28+
29+
@objective(
30+
model,
31+
Min,
32+
delay_cost * sum(sum(R[v, ω] for v in job_indices) for ω in Ω) / nb_scenarios # average total delay
33+
+
34+
vehicle_cost * sum(y[1, v] for v in job_indices) # nb_vehicles
35+
)
36+
37+
# Flow contraints
38+
@constraint(
39+
model,
40+
flow[i in job_indices],
41+
sum(y[j, i] for j in inneighbors(graph, i)) ==
42+
sum(y[i, j] for j in outneighbors(graph, i))
43+
)
44+
@constraint(
45+
model,
46+
unit_demand[i in job_indices],
47+
sum(y[j, i] for j in inneighbors(graph, i)) == 1
48+
)
49+
50+
# Delay propagation constraints
51+
@constraint(model, [ω in Ω], R[1, ω] == ε[1, ω])
52+
@constraint(model, R_delay_1[v in job_indices, ω in Ω], R[v, ω] >= ε[v, ω])
53+
@constraint(
54+
model,
55+
R_delay_2[v in job_indices, ω in Ω],
56+
R[v, ω] >=
57+
ε[v, ω] + sum(
58+
yR[u, v, ω] - y[u, v] * slacks[u, v][ω] for u in nodes if has_edge(graph, u, v)
59+
)
60+
)
61+
62+
# Mc Cormick linearization constraints
63+
@constraint(
64+
model,
65+
R_McCormick_1[u in nodes, v in nodes, ω in Ω; has_edge(graph, u, v)],
66+
yR[u, v, ω] >= R[u, ω] + Rmax * (y[u, v] - 1)
67+
)
68+
@constraint(
69+
model,
70+
R_McCormick_2[u in nodes, v in nodes, ω in Ω; has_edge(graph, u, v)],
71+
yR[u, v, ω] <= Rmax * y[u, v]
72+
)
73+
74+
# Solve model
75+
optimize!(model)
76+
solution = value.(y)
77+
78+
sol = solution_from_JuMP_array(solution, graph)
79+
return objective_value(model), sol
80+
end
81+
82+
"""
83+
$TYPEDSIGNATURES
84+
85+
Returns the optimal solution of the Stochastic VSP instance, by solving the associated compact quadratic MIP.
86+
Note: If you have Gurobi, use `grb_model` as `model_builder` instead of `highs_model`.
87+
88+
!!! warning
89+
You need to use a solver that supports quadratic constraints to use this method.
90+
"""
91+
function compact_mip(instance::Instance; model_builder=scip_model, silent=true)
92+
(; graph, slacks, intrinsic_delays, vehicle_cost, delay_cost) = instance
93+
nb_nodes = nv(graph)
94+
job_indices = 2:(nb_nodes - 1)
95+
nodes = 1:nb_nodes
96+
97+
# Pre-processing
98+
ε = intrinsic_delays
99+
nb_scenarios = size(ε, 2)
100+
Ω = 1:nb_scenarios
101+
102+
# Model definition
103+
model = model_builder()
104+
silent && set_silent(model)
105+
106+
# Variables and objective function
107+
@variable(model, y[u in nodes, v in nodes; has_edge(graph, u, v)], Bin)
108+
@variable(model, R[v in nodes, ω in Ω] >= 0) # propagated delay of job v
109+
@variable(model, yR[u in nodes, v in nodes, ω in Ω; has_edge(graph, u, v)] >= 0) # yR[u, v] = y[u, v] * R[u, ω]
110+
111+
@objective(
112+
model,
113+
Min,
114+
delay_cost * sum(sum(R[v, ω] for v in job_indices) for ω in Ω) / nb_scenarios # average total delay
115+
+
116+
vehicle_cost * sum(y[1, v] for v in job_indices) # nb_vehicles
117+
)
118+
119+
# Flow contraints
120+
@constraint(
121+
model,
122+
flow[i in job_indices],
123+
sum(y[j, i] for j in inneighbors(graph, i)) ==
124+
sum(y[i, j] for j in outneighbors(graph, i))
125+
)
126+
@constraint(
127+
model,
128+
unit_demand[i in job_indices],
129+
sum(y[j, i] for j in inneighbors(graph, i)) == 1
130+
)
131+
132+
# Delay propagation constraints
133+
@constraint(model, [ω in Ω], R[1, ω] == ε[1, ω])
134+
@constraint(model, R_delay_1[v in job_indices, ω in Ω], R[v, ω] >= ε[v, ω])
135+
@constraint(
136+
model,
137+
R_delay_2[v in job_indices, ω in Ω],
138+
R[v, ω] >=
139+
ε[v, ω] +
140+
sum(y[u, v] * (R[u, ω] - slacks[u, v][ω]) for u in nodes if has_edge(graph, u, v))
141+
)
142+
143+
# Solve model
144+
optimize!(model)
145+
solution = value.(y)
146+
147+
sol = solution_from_JuMP_array(solution, graph)
148+
return objective_value(model), sol
149+
end

0 commit comments

Comments
 (0)