Skip to main content

ferrox/vrptw/
problem.rs

1use serde::{Deserialize, Serialize};
2
3/// A customer to be visited by the vehicle.
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct Customer {
6    pub id: usize,
7    pub name: String,
8    pub x: f64,
9    pub y: f64,
10    /// Earliest arrival time.
11    pub window_open: i64,
12    /// Latest arrival time (must arrive by this time).
13    pub window_close: i64,
14    /// Service duration at this customer.
15    pub service_time: i64,
16}
17
18impl Customer {
19    pub fn travel_to(&self, other: &Customer) -> f64 {
20        let dx = self.x - other.x;
21        let dy = self.y - other.y;
22        (dx * dx + dy * dy).sqrt()
23    }
24}
25
26/// The depot — vehicle starts and ends here.
27#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct Depot {
29    pub x: f64,
30    pub y: f64,
31    pub ready_time: i64,
32    pub due_time: i64,
33}
34
35impl Depot {
36    pub fn travel_to_customer(&self, c: &Customer) -> f64 {
37        let dx = self.x - c.x;
38        let dy = self.y - c.y;
39        (dx * dx + dy * dy).sqrt()
40    }
41}
42
43/// Seeded into `ContextKey::Seeds` with id prefix `"vrptw-request:"`.
44///
45/// Models a single-vehicle TSP with Time Windows (TSPTW).
46/// Customers are optional: the objective is to maximise customers visited
47/// while respecting time windows and the vehicle's return deadline.
48#[derive(Debug, Clone, Serialize, Deserialize)]
49pub struct VrptwRequest {
50    pub id: String,
51    pub depot: Depot,
52    pub customers: Vec<Customer>,
53    #[serde(default = "default_time_limit")]
54    pub time_limit_seconds: f64,
55}
56
57fn default_time_limit() -> f64 {
58    30.0
59}
60
61/// One stop in the vehicle's route.
62#[derive(Debug, Clone, Serialize, Deserialize)]
63pub struct RouteStop {
64    pub customer_id: usize,
65    pub customer_name: String,
66    pub arrival: i64,
67    pub departure: i64,
68}
69
70/// Written to `ContextKey::Strategies` with id prefix `"vrptw-plan-<solver>:"`.
71#[derive(Debug, Clone, Serialize, Deserialize)]
72pub struct VrptwPlan {
73    pub request_id: String,
74    /// Ordered stops (depot → customers → depot is implied).
75    pub route: Vec<RouteStop>,
76    pub customers_total: usize,
77    pub customers_visited: usize,
78    /// Total travel distance (unscaled, Euclidean).
79    pub total_distance: f64,
80    /// Time the vehicle returns to depot.
81    pub return_time: i64,
82    pub solver: String,
83    pub status: String,
84    pub wall_time_seconds: f64,
85}
86
87impl VrptwPlan {
88    pub fn visit_ratio(&self) -> f64 {
89        if self.customers_total == 0 {
90            return 0.0;
91        }
92        self.customers_visited as f64 / self.customers_total as f64
93    }
94}