1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use crate::construction::heuristics::UnassignmentInfo;
use crate::models::common::Cost;
use crate::models::problem::*;
use crate::models::solution::{Registry, Route};
use crate::models::*;
use rosomaxa::evolution::TelemetryMetrics;
use rosomaxa::prelude::*;
use std::fmt::{Debug, Formatter};
use std::sync::Arc;

/// Defines VRP problem.
pub struct Problem {
    /// Specifies used fleet.
    pub fleet: Arc<Fleet>,

    /// Specifies all jobs.
    pub jobs: Arc<Jobs>,

    /// Specifies jobs which preassigned to specific vehicles and/or drivers.
    pub locks: Vec<Arc<Lock>>,

    /// Specifies optimization goal with the corresponding global/local objectives and invariants.
    pub goal: Arc<GoalContext>,

    /// Specifies activity costs.
    pub activity: Arc<dyn ActivityCost + Send + Sync>,

    /// Specifies transport costs.
    pub transport: Arc<dyn TransportCost + Send + Sync>,

    /// Specifies index for storing extra parameters of arbitrary type.
    pub extras: Arc<Extras>,
}

impl Debug for Problem {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        f.debug_struct(short_type_name::<Self>())
            .field("fleet", &self.fleet)
            .field("jobs", &self.jobs.size())
            .field("locks", &self.locks.len())
            .field("goal", self.goal.as_ref())
            .finish_non_exhaustive()
    }
}

/// Represents a VRP solution.
pub struct Solution {
    /// A total solution cost.
    /// Definition of the cost depends on VRP variant.
    pub cost: Cost,

    /// Actor's registry.
    pub registry: Registry,

    /// List of assigned routes.
    pub routes: Vec<Route>,

    /// List of unassigned jobs within reason code.
    pub unassigned: Vec<(Job, UnassignmentInfo)>,

    /// An optional telemetry metrics if available.
    pub telemetry: Option<TelemetryMetrics>,
}

/// An enumeration which specifies how jobs should be ordered in tour.
pub enum LockOrder {
    /// Jobs can be reshuffled in any order.
    Any,
    /// Jobs cannot be reshuffled, but new job can be inserted in between.
    Sequence,
    /// Jobs cannot be reshuffled and no jobs can be inserted in between.
    Strict,
}

/// An enumeration which specifies how other jobs can be inserted in tour.
#[derive(Clone)]
pub enum LockPosition {
    /// No specific position.
    Any,
    /// First job follows departure.
    Departure,
    /// Last job is before arrival.
    Arrival,
    /// First and last jobs should be between departure and arrival.
    Fixed,
}

/// Specifies lock details.
pub struct LockDetail {
    /// Lock order.
    pub order: LockOrder,
    /// Lock position.
    pub position: LockPosition,
    /// Jobs affected by the lock.
    pub jobs: Vec<Job>,
}

/// Contains information about jobs locked to specific actors.
pub struct Lock {
    /// Specifies condition when locked jobs can be assigned to specific actor
    pub condition_fn: Arc<dyn Fn(&Actor) -> bool + Sync + Send>,
    /// Specifies lock details.
    pub details: Vec<LockDetail>,
    /// Specifies whether route is created or not in solution from beginning.
    /// True means that route is not created till evaluation.
    pub is_lazy: bool,
}

impl LockDetail {
    /// Creates a new instance of `LockDetail`.
    pub fn new(order: LockOrder, position: LockPosition, jobs: Vec<Job>) -> Self {
        Self { order, position, jobs }
    }
}

impl Lock {
    /// Creates a new instance of `Lock`.
    pub fn new(condition: Arc<dyn Fn(&Actor) -> bool + Sync + Send>, details: Vec<LockDetail>, is_lazy: bool) -> Self {
        Self { condition_fn: condition, details, is_lazy }
    }
}