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
65 changes: 39 additions & 26 deletions docs/src/benchmarks/dvsp.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ The Dynamic Vehicle Scheduling Problem (DVSP) is a sequential decision-making pr

### Overview

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.
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.
The goal is to serve all customers by the end of the planning horizon while minimizing total travel time.

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.
Expand All @@ -24,18 +24,18 @@ The dynamic vehicle scheduling problem can be formulated as a finite-horizon Mar
s_t = (R_t, D_t, t)
```
where:
- ``R_t`` are the pending customer requests (not yet served), where each request ``r_i \in R_t`` contains:
- ``R_t`` are the pending customer (not yet served), where each customer ``r_i \in R_t`` contains:
- ``x_i, y_i``: 2d spatial coordinates of the customer location
- ``\tau_i``: start time when the customer needs to be served
- ``s_i``: service time required to serve the customer
- ``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)
- ``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)
- ``t \in \{1, 2, \ldots, T\}`` is the current time step

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

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

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

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

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

The main benchmark configuration with the following parameters:

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

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

### Features

The benchmark provides two feature representations:

**Full Features** (14-dimensional):
- Start times for postponable requests
- End times (start + service time)
- Travel time from depot to request
- Travel time from request to depot
- Slack time until next time step
- Quantile-based travel times to other requests (9 quantiles)
The benchmark provides two feature matrix representations, containing one column per postponable customer in the state:

**Full Features** (27-dimensional):
- Start times for postponable customers (1)
- End times (start + service time) (2)
- Travel time from depot to customer (3)
- Travel time from customer to depot (4)
- Slack time until next time step (5)
- % of must-dispatch customers that can reach this customer on time (6)
- % of customers reachable from this customer on time (7)
- % of customers that can reach this customer on time (8)
- % of customers reachable or that can reach this customer on time (9)
- Quantile-based travel times to other customers (9 quantiles) (10-18)
- Quantiles of % of reachable new customers (9 quantiles) (19-27)

**2D Features** (simplified):
- Travel time from depot to request
- Mean travel time to other requests
- Travel time from depot to customer (1)
- Mean travel time to other customers (2)

## Benchmark Policies

### Lazy Policy

The lazy policy postpones all possible requests, serving only those that must be dispatched.
The lazy policy postpones all possible customers, serving only those that must be dispatched.

### Greedy Policy

The greedy policy serves all pending requests as soon as they arrive, without considering future consequences.
The greedy policy serves all pending customers as soon as they arrive, without considering future consequences.

## Decision-Focused Learning Policy

```math
\xrightarrow[\text{State}]{s_t}
\fbox{Neural network $\varphi_w$}
\xrightarrow[\text{Priorities}]{\theta}
\xrightarrow[\text{Prizes}]{\theta}
\fbox{Prize-collecting VSP}
\xrightarrow[\text{Routes}]{a_t}
```

**Components**:

1. **Neural Network** ``\varphi_w``: Takes current state features as input and predicts customer priorities ``\theta = (\theta_1, \ldots, \theta_n)``
2. **Optimization Layer**: Solves the prize-collecting vehicle scheduling problem to determine optimal routes given the predicted priorities
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.
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:
```math
\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)
```
This can be modeled as a flow linear program on a directed acyclic graph (DAG) and is solved using standard LP solvers.

The neural network architecture adapts to the feature dimensionality:
- **2D features**: `Dense(2 => 1)` followed by vectorization
- **Full features**: `Dense(14 => 1)` followed by vectorization
- **2D features**: `Dense(2 => 1)`, applied in parallel to each postponable customer
- **Full features**: `Dense(27 => 1)` applied in parallel to each postponable customer

**Note:** one can also use more complex architectures such as a deeper MLP or a graph neural network for better performance.
48 changes: 47 additions & 1 deletion src/DynamicVehicleScheduling/DynamicVehicleScheduling.jl
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ $TYPEDFIELDS
two_dimensional_features::Bool = false
end

"""
$TYPEDSIGNATURES

Generate a dataset for the dynamic vehicle scheduling benchmark.
Returns a vector of [`DataSample`](@ref) objects, each containing an [`Instance`](@ref).
The dataset is generated from pre-existing DVRPTW files.
"""
function Utils.generate_dataset(b::DynamicVehicleSchedulingBenchmark, dataset_size::Int=1)
(; max_requests_per_epoch, Δ_dispatch, epoch_duration, two_dimensional_features) = b
files = readdir(datadep"dvrptw"; join=true)
Expand All @@ -74,21 +81,45 @@ function Utils.generate_dataset(b::DynamicVehicleSchedulingBenchmark, dataset_si
]
end

"""
$TYPEDSIGNATURES

Creates an environment from an [`Instance`](@ref) of the dynamic vehicle scheduling benchmark.
The seed of the environment is randomly generated using the provided random number generator.
"""
function Utils.generate_environment(
::DynamicVehicleSchedulingBenchmark, instance::Instance, rng::AbstractRNG; kwargs...
)
seed = rand(rng, 1:typemax(Int))
return DVSPEnv(instance; seed)
end

"""
$TYPEDSIGNATURES

Returns a linear maximizer for the dynamic vehicle scheduling benchmark, of the form:
θ ↦ argmax_{y} θᵀg(y) + h(y)
"""
function Utils.generate_maximizer(::DynamicVehicleSchedulingBenchmark)
return LinearMaximizer(oracle; g, h)
end

"""
$TYPEDSIGNATURES

Generate a scenario for the dynamic vehicle scheduling benchmark.
This is a wrapper around the generic scenario generation function.
"""
function Utils.generate_scenario(b::DynamicVehicleSchedulingBenchmark, args...; kwargs...)
return Utils.generate_scenario(args...; kwargs...)
end

"""
$TYPEDSIGNATURES

Generate an anticipative solution for the dynamic vehicle scheduling benchmark.
The solution is computed using the anticipative solver with the benchmark's feature configuration.
"""
function Utils.generate_anticipative_solution(
b::DynamicVehicleSchedulingBenchmark, args...; kwargs...
)
Expand All @@ -97,6 +128,14 @@ function Utils.generate_anticipative_solution(
)
end

"""
$TYPEDSIGNATURES

Generate baseline policies for the dynamic vehicle scheduling benchmark.
Returns a tuple containing:
- `lazy`: A policy that dispatches vehicles only when they are ready
- `greedy`: A policy that dispatches vehicles to the nearest customer
"""
function Utils.generate_policies(b::DynamicVehicleSchedulingBenchmark)
lazy = Policy(
"Lazy",
Expand All @@ -111,11 +150,18 @@ function Utils.generate_policies(b::DynamicVehicleSchedulingBenchmark)
return (lazy, greedy)
end

"""
$TYPEDSIGNATURES

Generate a statistical model for the dynamic vehicle scheduling benchmark.
The model is a simple linear chain with a single dense layer that maps features to a scalar output.
The input dimension depends on whether two-dimensional features are used (2 features) or not (27 features).
"""
function Utils.generate_statistical_model(
b::DynamicVehicleSchedulingBenchmark; seed=nothing
)
Random.seed!(seed)
return Chain(Dense((b.two_dimensional_features ? 2 : 14) => 1), vec)
return Chain(Dense((b.two_dimensional_features ? 2 : 27) => 1), vec)
end

export DynamicVehicleSchedulingBenchmark
Expand Down
Loading