Skip to content

Commit 2ccbcc7

Browse files
authored
Merge pull request #48 from JuliaDecisionFocusedLearning/better-dvsp
Improve DVSP benchmark: additional features, + more variety in start …
2 parents 14bc0f1 + 862a4ef commit 2ccbcc7

File tree

8 files changed

+294
-46
lines changed

8 files changed

+294
-46
lines changed

docs/src/benchmarks/dvsp.md

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ The Dynamic Vehicle Scheduling Problem (DVSP) is a sequential decision-making pr
66

77
### Overview
88

9-
In the dynamic vehicle scheduling problem, a fleet operator must decide at each time step which customer requests to serve immediately and which to postpone to future time steps.
9+
In the dynamic vehicle scheduling problem, a fleet operator must decide at each time step which customer to serve immediately and which to postpone to future time steps.
1010
The goal is to serve all customers by the end of the planning horizon while minimizing total travel time.
1111

1212
This is a simplified version of the more complex Dynamic Vehicle Routing Problem with Time Windows (DVRPTW), focusing on the core sequential decision-making aspects without capacity or time window constraints.
@@ -24,18 +24,18 @@ The dynamic vehicle scheduling problem can be formulated as a finite-horizon Mar
2424
s_t = (R_t, D_t, t)
2525
```
2626
where:
27-
- ``R_t`` are the pending customer requests (not yet served), where each request ``r_i \in R_t`` contains:
27+
- ``R_t`` are the pending customer (not yet served), where each customer ``r_i \in R_t`` contains:
2828
- ``x_i, y_i``: 2d spatial coordinates of the customer location
2929
- ``\tau_i``: start time when the customer needs to be served
3030
- ``s_i``: service time required to serve the customer
31-
- ``D_t`` indicates which requests must be dispatched this time step (i.e. that cannot be postponed further, otherwise they will be infeasible at the next time step because of their start time)
31+
- ``D_t`` indicates which customers must be dispatched this time step (i.e. that cannot be postponed further, otherwise they will be infeasible at the next time step because of their start time)
3232
- ``t \in \{1, 2, \ldots, T\}`` is the current time step
3333

3434
The state also implicitly includes (constant over time):
3535
- Travel duration matrix ``d_{ij}``: time to travel from location ``i`` to location ``j``
3636
- Depot location
3737

38-
**Action Space** ``\mathcal{A}``: The action at time step ``t`` is a set of vehicle routes:
38+
**Action Space** ``\mathcal{A}(s_t)``: The action at time step ``t`` is a set of vehicle routes:
3939
```math
4040
a_t = \{r_1, r_2, \ldots, r_k\}
4141
```
@@ -47,7 +47,7 @@ A route is feasible if:
4747

4848
**Transition Dynamics** ``\mathcal{P}(s_{t+1} | s_t, a_t)``: After executing routes ``a_t``:
4949

50-
1. **Remove served customers** from the pending request set
50+
1. **Remove served customers** from the pending customer set
5151
2. **Generate new customer arrivals** according to the underlying exogenous distribution
5252
3. **Update must-dispatch set** based on postponement rules
5353

@@ -70,7 +70,7 @@ where ``d_{ij}`` is the travel duration from location ``i`` to location ``j``, a
7070

7171
The main benchmark configuration with the following parameters:
7272

73-
- `max_requests_per_epoch`: Maximum number of new customer requests per time step (default: 10)
73+
- `max_requests_per_epoch`: Maximum number of new customers per time step (default: 10)
7474
- `Δ_dispatch`: Time delay between decision and vehicle dispatch (default: 1.0)
7575
- `epoch_duration`: Duration of each decision time step (default: 1.0)
7676
- `two_dimensional_features`: Whether to use simplified 2D features instead of full feature set (default: false)
@@ -82,51 +82,64 @@ Problem instances are generated from static vehicle routing datasets and include
8282
- **Customer locations**: Spatial coordinates for pickup/delivery points
8383
- **Depot location**: Central starting and ending point for all routes
8484
- **Travel times**: Distance/duration matrix between all location pairs
85-
- **Service requirements**: Time needed to serve each customer
85+
- **Service times**: Service time each customer
8686

87-
The dynamic version samples new customer arrivals from the static instance, drawing new customers by independently sampling their locations and service times.
87+
The dynamic version samples new customer arrivals from the static instance, drawing new customers by independently sampling:
88+
- their locations from the set of static customer locations
89+
- service times, uniformly from the range of service times in the static instance
8890

8991
### Features
9092

91-
The benchmark provides two feature representations:
92-
93-
**Full Features** (14-dimensional):
94-
- Start times for postponable requests
95-
- End times (start + service time)
96-
- Travel time from depot to request
97-
- Travel time from request to depot
98-
- Slack time until next time step
99-
- Quantile-based travel times to other requests (9 quantiles)
93+
The benchmark provides two feature matrix representations, containing one column per postponable customer in the state:
94+
95+
**Full Features** (27-dimensional):
96+
- Start times for postponable customers (1)
97+
- End times (start + service time) (2)
98+
- Travel time from depot to customer (3)
99+
- Travel time from customer to depot (4)
100+
- Slack time until next time step (5)
101+
- % of must-dispatch customers that can reach this customer on time (6)
102+
- % of customers reachable from this customer on time (7)
103+
- % of customers that can reach this customer on time (8)
104+
- % of customers reachable or that can reach this customer on time (9)
105+
- Quantile-based travel times to other customers (9 quantiles) (10-18)
106+
- Quantiles of % of reachable new customers (9 quantiles) (19-27)
100107

101108
**2D Features** (simplified):
102-
- Travel time from depot to request
103-
- Mean travel time to other requests
109+
- Travel time from depot to customer (1)
110+
- Mean travel time to other customers (2)
104111

105112
## Benchmark Policies
106113

107114
### Lazy Policy
108115

109-
The lazy policy postpones all possible requests, serving only those that must be dispatched.
116+
The lazy policy postpones all possible customers, serving only those that must be dispatched.
110117

111118
### Greedy Policy
112119

113-
The greedy policy serves all pending requests as soon as they arrive, without considering future consequences.
120+
The greedy policy serves all pending customers as soon as they arrive, without considering future consequences.
114121

115122
## Decision-Focused Learning Policy
116123

117124
```math
118125
\xrightarrow[\text{State}]{s_t}
119126
\fbox{Neural network $\varphi_w$}
120-
\xrightarrow[\text{Priorities}]{\theta}
127+
\xrightarrow[\text{Prizes}]{\theta}
121128
\fbox{Prize-collecting VSP}
122129
\xrightarrow[\text{Routes}]{a_t}
123130
```
124131

125132
**Components**:
126133

127-
1. **Neural Network** ``\varphi_w``: Takes current state features as input and predicts customer priorities ``\theta = (\theta_1, \ldots, \theta_n)``
128-
2. **Optimization Layer**: Solves the prize-collecting vehicle scheduling problem to determine optimal routes given the predicted priorities
134+
1. **Neural Network** ``\varphi_w``: Takes current state features as input and predicts customer prizes ``\theta = (\theta_1, \ldots, \theta_n)``, one value per postponable customer.
135+
2. **Optimization Layer**: Solves the prize-collecting vehicle scheduling problem to determine optimal routes given the predicted prizes, by maximizing total collected prizes minus travel costs:
136+
```math
137+
\max_{a_t\in \mathcal{A}(s_t)} \sum_{r \in a_t} \left( \sum_{i \in r} \theta_i - \sum_{(i,j) \in r} d_{ij} \right)
138+
```
139+
This can be modeled as a flow linear program on a directed acyclic graph (DAG) and is solved using standard LP solvers.
129140
130141
The neural network architecture adapts to the feature dimensionality:
131-
- **2D features**: `Dense(2 => 1)` followed by vectorization
132-
- **Full features**: `Dense(14 => 1)` followed by vectorization
142+
- **2D features**: `Dense(2 => 1)`, applied in parallel to each postponable customer
143+
- **Full features**: `Dense(27 => 1)` applied in parallel to each postponable customer
144+
145+
**Note:** one can also use more complex architectures such as a deeper MLP or a graph neural network for better performance.

src/DynamicVehicleScheduling/DynamicVehicleScheduling.jl

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,13 @@ $TYPEDFIELDS
5757
two_dimensional_features::Bool = false
5858
end
5959

60+
"""
61+
$TYPEDSIGNATURES
62+
63+
Generate a dataset for the dynamic vehicle scheduling benchmark.
64+
Returns a vector of [`DataSample`](@ref) objects, each containing an [`Instance`](@ref).
65+
The dataset is generated from pre-existing DVRPTW files.
66+
"""
6067
function Utils.generate_dataset(b::DynamicVehicleSchedulingBenchmark, dataset_size::Int=1)
6168
(; max_requests_per_epoch, Δ_dispatch, epoch_duration, two_dimensional_features) = b
6269
files = readdir(datadep"dvrptw"; join=true)
@@ -74,21 +81,45 @@ function Utils.generate_dataset(b::DynamicVehicleSchedulingBenchmark, dataset_si
7481
]
7582
end
7683

84+
"""
85+
$TYPEDSIGNATURES
86+
87+
Creates an environment from an [`Instance`](@ref) of the dynamic vehicle scheduling benchmark.
88+
The seed of the environment is randomly generated using the provided random number generator.
89+
"""
7790
function Utils.generate_environment(
7891
::DynamicVehicleSchedulingBenchmark, instance::Instance, rng::AbstractRNG; kwargs...
7992
)
8093
seed = rand(rng, 1:typemax(Int))
8194
return DVSPEnv(instance; seed)
8295
end
8396

97+
"""
98+
$TYPEDSIGNATURES
99+
100+
Returns a linear maximizer for the dynamic vehicle scheduling benchmark, of the form:
101+
θ ↦ argmax_{y} θᵀg(y) + h(y)
102+
"""
84103
function Utils.generate_maximizer(::DynamicVehicleSchedulingBenchmark)
85104
return LinearMaximizer(oracle; g, h)
86105
end
87106

107+
"""
108+
$TYPEDSIGNATURES
109+
110+
Generate a scenario for the dynamic vehicle scheduling benchmark.
111+
This is a wrapper around the generic scenario generation function.
112+
"""
88113
function Utils.generate_scenario(b::DynamicVehicleSchedulingBenchmark, args...; kwargs...)
89114
return Utils.generate_scenario(args...; kwargs...)
90115
end
91116

117+
"""
118+
$TYPEDSIGNATURES
119+
120+
Generate an anticipative solution for the dynamic vehicle scheduling benchmark.
121+
The solution is computed using the anticipative solver with the benchmark's feature configuration.
122+
"""
92123
function Utils.generate_anticipative_solution(
93124
b::DynamicVehicleSchedulingBenchmark, args...; kwargs...
94125
)
@@ -97,6 +128,14 @@ function Utils.generate_anticipative_solution(
97128
)
98129
end
99130

131+
"""
132+
$TYPEDSIGNATURES
133+
134+
Generate baseline policies for the dynamic vehicle scheduling benchmark.
135+
Returns a tuple containing:
136+
- `lazy`: A policy that dispatches vehicles only when they are ready
137+
- `greedy`: A policy that dispatches vehicles to the nearest customer
138+
"""
100139
function Utils.generate_policies(b::DynamicVehicleSchedulingBenchmark)
101140
lazy = Policy(
102141
"Lazy",
@@ -111,11 +150,18 @@ function Utils.generate_policies(b::DynamicVehicleSchedulingBenchmark)
111150
return (lazy, greedy)
112151
end
113152

153+
"""
154+
$TYPEDSIGNATURES
155+
156+
Generate a statistical model for the dynamic vehicle scheduling benchmark.
157+
The model is a simple linear chain with a single dense layer that maps features to a scalar output.
158+
The input dimension depends on whether two-dimensional features are used (2 features) or not (27 features).
159+
"""
114160
function Utils.generate_statistical_model(
115161
b::DynamicVehicleSchedulingBenchmark; seed=nothing
116162
)
117163
Random.seed!(seed)
118-
return Chain(Dense((b.two_dimensional_features ? 2 : 14) => 1), vec)
164+
return Chain(Dense((b.two_dimensional_features ? 2 : 27) => 1), vec)
119165
end
120166

121167
export DynamicVehicleSchedulingBenchmark

0 commit comments

Comments
 (0)