File size: 2,405 Bytes
2574e86
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
//! Planning solution for the field-service routing problem.
//!
//! `FieldServicePlan` is both the input to SolverForge and the domain value
//! converted to JSON snapshots after solving. Facts stay read-only; technician
//! routes carry the mutable visit list.

use serde::{Deserialize, Serialize};
use solverforge::prelude::*;

// @solverforge:begin solution-imports
use super::Location;
use super::ServiceVisit;
use super::TechnicianRoute;
use super::TravelLeg;
// @solverforge:end solution-imports

/// Full planning solution passed to the SolverForge runtime and HTTP API.
///
/// The first three collections are read-only facts. `technician_routes` is the
/// planning entity collection because each route owns the mutable visit list.
#[planning_solution(
    constraints = "crate::constraints::create_constraints",
    solver_toml = "../../solver.toml"
)]
#[derive(Serialize, Deserialize)]
pub struct FieldServicePlan {
    // @solverforge:begin solution-collections
    /// All depots and customer sites, addressed by vector index from visits and
    /// route endpoints.
    #[problem_fact_collection]
    pub locations: Vec<Location>,
    /// Customer jobs that must be inserted into technician routes.
    #[problem_fact_collection]
    pub service_visits: Vec<ServiceVisit>,
    /// Directed travel matrix used by constraints and route geometry.
    #[problem_fact_collection]
    pub travel_legs: Vec<TravelLeg>,
    /// Route entities whose `visits` lists are changed by the solver.
    #[planning_entity_collection]
    pub technician_routes: Vec<TechnicianRoute>,
    // @solverforge:end solution-collections
    #[planning_score]
    pub score: Option<HardSoftScore>,
}

impl FieldServicePlan {
    /// Builds a plan from immutable facts and initially empty route entities.
    #[rustfmt::skip]
    pub fn new(
        // @solverforge:begin solution-constructor-params
        locations: Vec<Location>,
        service_visits: Vec<ServiceVisit>,
        travel_legs: Vec<TravelLeg>,
        technician_routes: Vec<TechnicianRoute>,
        // @solverforge:end solution-constructor-params
    ) -> Self {
        Self {
            // @solverforge:begin solution-constructor-init
            locations,
            service_visits,
            travel_legs,
            technician_routes,
            // @solverforge:end solution-constructor-init
            score: None,
        }
    }
}