Skip to main content

vrp_scientific/solomon/
reader.rs

1#[cfg(test)]
2#[path = "../../tests/unit/solomon/reader_test.rs"]
3mod reader_test;
4
5use crate::common::*;
6use std::io::{BufReader, Read};
7use std::sync::Arc;
8use vrp_core::construction::features::JobDemandDimension;
9use vrp_core::models::common::*;
10use vrp_core::models::problem::*;
11use vrp_core::models::*;
12use vrp_core::models::{Extras, Problem};
13use vrp_core::prelude::GenericError;
14use vrp_core::utils::Float;
15
16/// A trait read write solomon problem.
17pub trait SolomonProblem {
18    /// Reads solomon problem.
19    fn read_solomon(self, is_rounded: bool) -> Result<Problem, GenericError>;
20}
21
22impl<R: Read> SolomonProblem for BufReader<R> {
23    fn read_solomon(self, is_rounded: bool) -> Result<Problem, GenericError> {
24        read_solomon_format(self, is_rounded)
25    }
26}
27
28impl SolomonProblem for String {
29    fn read_solomon(self, is_rounded: bool) -> Result<Problem, GenericError> {
30        read_solomon_format(BufReader::new(self.as_bytes()), is_rounded)
31    }
32}
33
34fn read_solomon_format<R: Read>(reader: BufReader<R>, is_rounded: bool) -> Result<Problem, GenericError> {
35    SolomonReader { buffer: String::new(), reader, coord_index: CoordIndex::default() }.read_problem(is_rounded)
36}
37
38struct VehicleLine {
39    number: usize,
40    capacity: usize,
41}
42
43struct JobLine {
44    id: usize,
45    location: (i32, i32),
46    demand: usize,
47    tw: TimeWindow,
48    service: usize,
49}
50
51struct SolomonReader<R: Read> {
52    buffer: String,
53    reader: BufReader<R>,
54    coord_index: CoordIndex,
55}
56
57impl<R: Read> TextReader for SolomonReader<R> {
58    fn create_goal_context(
59        &self,
60        activity: Arc<SimpleActivityCost>,
61        transport: Arc<dyn TransportCost>,
62    ) -> Result<GoalContext, GenericError> {
63        let is_time_constrained = true;
64        create_goal_context_prefer_min_tours(activity, transport, is_time_constrained)
65    }
66
67    fn read_definitions(&mut self) -> Result<(Vec<Job>, Fleet), GenericError> {
68        let fleet = self.read_fleet()?;
69        let jobs = self.read_jobs()?;
70
71        Ok((jobs, fleet))
72    }
73
74    fn create_transport(&self, is_rounded: bool) -> Result<Arc<dyn TransportCost>, GenericError> {
75        self.coord_index.create_transport(is_rounded, &self.get_logger())
76    }
77
78    fn create_extras(&self) -> Extras {
79        get_extras(self.coord_index.clone())
80    }
81}
82
83impl<R: Read> SolomonReader<R> {
84    fn read_fleet(&mut self) -> Result<Fleet, GenericError> {
85        self.skip_lines(4)?;
86        let vehicle = self.read_vehicle()?;
87        self.skip_lines(4)?;
88        let depot = self.read_customer()?;
89        Ok(create_fleet_with_distance_costs(
90            vehicle.number,
91            vehicle.capacity,
92            self.coord_index.collect(depot.location),
93            depot.tw,
94        ))
95    }
96
97    fn read_jobs(&mut self) -> Result<Vec<Job>, GenericError> {
98        let mut jobs: Vec<Job> = Default::default();
99        loop {
100            match self.read_customer() {
101                Ok(customer) => {
102                    let mut dimens = Dimensions::default();
103                    dimens.set_job_id(customer.id.to_string()).set_job_demand(Demand::<SingleDimLoad> {
104                        pickup: (SingleDimLoad::default(), SingleDimLoad::default()),
105                        delivery: (SingleDimLoad::new(customer.demand as i32), SingleDimLoad::default()),
106                    });
107                    jobs.push(Job::Single(Arc::new(Single {
108                        places: vec![Place {
109                            location: Some(self.coord_index.collect(customer.location)),
110                            duration: customer.service as Float,
111                            times: vec![TimeSpan::Window(customer.tw.clone())],
112                        }],
113                        dimens,
114                    })));
115                }
116                Err(error) => {
117                    if self.buffer.is_empty() {
118                        break;
119                    } else {
120                        return Err(error);
121                    }
122                }
123            }
124        }
125
126        Ok(jobs)
127    }
128
129    fn read_vehicle(&mut self) -> Result<VehicleLine, GenericError> {
130        read_line(&mut self.reader, &mut self.buffer)?;
131        let (number, capacity) = self
132            .buffer
133            .split_whitespace()
134            .map(|line| line.parse::<usize>().unwrap())
135            .try_collect_tuple()
136            .ok_or_else(|| "cannot parse vehicle number or/and capacity".to_string())?;
137
138        Ok(VehicleLine { number, capacity })
139    }
140
141    fn read_customer(&mut self) -> Result<JobLine, GenericError> {
142        read_line(&mut self.reader, &mut self.buffer)?;
143        let (id, x, y, demand, start, end, service) = self
144            .buffer
145            .split_whitespace()
146            .map(|line| line.parse::<i32>().unwrap())
147            .try_collect_tuple()
148            .ok_or_else(|| "cannot read customer line".to_string())?;
149        Ok(JobLine {
150            id: id as usize,
151            location: (x, y),
152            demand: demand as usize,
153            tw: TimeWindow::new(start as Float, end as Float),
154            service: service as usize,
155        })
156    }
157
158    fn skip_lines(&mut self, count: usize) -> Result<(), GenericError> {
159        skip_lines(count, &mut self.reader, &mut self.buffer)
160    }
161}