| |
| |
| |
| |
| |
|
|
| use std::collections::HashMap; |
| use std::sync::Arc; |
|
|
| use serde::{Deserialize, Serialize}; |
| use solverforge::cvrp::ProblemData; |
| use solverforge::prelude::*; |
|
|
| |
| use super::route_metrics::preview_for_plan; |
| use super::{Delivery, PlanViewState, RoutingMode, Vehicle}; |
| |
|
|
| #[planning_solution( |
| constraints = "crate::constraints::create_constraints", |
| solver_toml = "../../solver.toml" |
| )] |
| #[shadow_variable_updates( |
| list_owner = "vehicles", |
| post_update_listener = "refresh_vehicle_route_shadows" |
| )] |
| #[derive(Serialize, Deserialize)] |
| #[serde(rename_all = "camelCase")] |
| pub struct Plan { |
| pub name: String, |
| #[serde(default)] |
| pub routing_mode: RoutingMode, |
| #[serde(default)] |
| pub view_state: PlanViewState, |
| |
| #[problem_fact_collection] |
| pub deliveries: Vec<Delivery>, |
| #[planning_entity_collection] |
| pub vehicles: Vec<Vehicle>, |
| |
| #[planning_score] |
| pub score: Option<HardSoftScore>, |
| |
| |
| |
| |
| #[serde(skip, default)] |
| pub prepared_problem_data: Vec<Arc<ProblemData>>, |
| } |
|
|
| impl Plan { |
| |
| pub fn new(name: impl Into<String>, deliveries: Vec<Delivery>, vehicles: Vec<Vehicle>) -> Self { |
| let mut plan = Self { |
| name: name.into(), |
| routing_mode: RoutingMode::default(), |
| view_state: PlanViewState::default(), |
| deliveries, |
| vehicles, |
| score: None, |
| prepared_problem_data: Vec::new(), |
| }; |
| plan.normalize(); |
| plan |
| } |
|
|
| |
| |
| |
| |
| |
| pub fn normalize(&mut self) { |
| let delivery_id_map: HashMap<usize, usize> = self |
| .deliveries |
| .iter() |
| .enumerate() |
| .map(|(idx, delivery)| (delivery.id, idx)) |
| .collect(); |
|
|
| for (idx, delivery) in self.deliveries.iter_mut().enumerate() { |
| delivery.id = idx; |
| } |
|
|
| for (idx, vehicle) in self.vehicles.iter_mut().enumerate() { |
| vehicle.id = idx; |
| vehicle.prepared_routing = None; |
| vehicle.delivery_order = vehicle |
| .delivery_order |
| .iter() |
| .filter_map(|old_id| delivery_id_map.get(old_id).copied()) |
| .collect(); |
| vehicle.refresh_route_shadows(); |
| } |
| self.prepared_problem_data.clear(); |
| } |
|
|
| |
| pub fn remove_delivery_assignments(&mut self, delivery_id: usize) { |
| for vehicle in &mut self.vehicles { |
| vehicle |
| .delivery_order |
| .retain(|assigned| *assigned != delivery_id); |
| } |
| } |
|
|
| |
| pub fn refresh_vehicle_route_shadows(&mut self, vehicle_idx: usize) { |
| if let Some(vehicle) = self.vehicles.get_mut(vehicle_idx) { |
| vehicle.refresh_route_shadows(); |
| } |
| } |
|
|
| |
| pub fn refreshed_for_transport(&self) -> Self { |
| let mut plan = self.clone(); |
| plan.view_state.preview = Some(preview_for_plan(&plan)); |
| plan |
| } |
| } |
|
|
| impl solverforge::cvrp::VrpSolution for Plan { |
| |
| fn vehicle_data_ptr(&self, entity_idx: usize) -> *const ProblemData { |
| self.vehicles[entity_idx] |
| .prepared_routing |
| .as_ref() |
| .and_then(|prepared| self.prepared_problem_data.get(prepared.problem_data_index)) |
| .map(Arc::as_ptr) |
| .unwrap_or(std::ptr::null()) |
| } |
|
|
| |
| fn vehicle_visits(&self, entity_idx: usize) -> &[usize] { |
| &self.vehicles[entity_idx].delivery_order |
| } |
|
|
| |
| fn vehicle_visits_mut(&mut self, entity_idx: usize) -> &mut Vec<usize> { |
| &mut self.vehicles[entity_idx].delivery_order |
| } |
|
|
| |
| fn vehicle_count(&self) -> usize { |
| self.vehicles.len() |
| } |
| } |
|
|
| #[cfg(test)] |
| impl Plan { |
| pub(crate) fn test_has_list_variable() -> bool { |
| Self::__solverforge_has_list_variable() |
| } |
|
|
| pub(crate) fn test_total_list_entities(plan: &Self) -> usize { |
| Self::__solverforge_total_list_entities(plan) |
| } |
|
|
| pub(crate) fn test_total_list_elements(plan: &Self) -> usize { |
| Self::__solverforge_total_list_elements(plan) |
| } |
|
|
| pub(crate) fn test_is_trivial(plan: &Self) -> bool { |
| Self::__solverforge_is_trivial(plan) |
| } |
|
|
| pub(crate) fn test_phase_count(config: &solverforge::SolverConfig) -> usize { |
| Self::__solverforge_build_phases(config).phases().len() |
| } |
| } |
|
|