tsplib_parser/
lib.rs

1use std::collections::HashSet;
2use std::error::Error;
3use std::f64::consts::PI;
4use std::fs;
5use std::mem;
6
7#[derive(Clone, Debug)]
8/// Type of the data.
9pub enum InstanceType {
10    /// Data for a symmetric traveling salesperson problem.
11    Tsp,
12    /// Data for an asymmetric traveling salesperson problem.
13    Atsp,
14    /// Data for a sequential ordering problem.
15    Sop,
16    /// Hamiltonian cycle problem data.
17    Hcp,
18    /// Capacitated vehicle routing problem data.
19    Cvrp,
20    /// A collection of torus.
21    Tours,
22    /// Other problem data.
23    Other(String),
24}
25
26#[derive(Clone, Copy, Debug)]
27/// How the edge weights (or distances) are given.
28pub enum EdgeWeightType {
29    /// Weights are listed explicitly.
30    Explicit,
31    /// Weights are Euclidean distances in 2-D.
32    Euc2d,
33    /// Weights are Euclidean distances in 3-D.
34    Euc3d,
35    /// Weights are maximum distances in 2-D.
36    Max2d,
37    /// Weights are maximum distances in 3-D.
38    Max3d,
39    /// Weights are manhattan distances in 2-D.
40    Man2d,
41    /// Weights are manhattan distances in 3-D.
42    Man3d,
43    /// Weights are Euclidean distances in 2-D rounded up.
44    Ceil2d,
45    /// Weights are geographical distances.
46    Geo,
47    /// Special distance function for problems att48 and att532.
48    Att,
49    /// Special distance function for crystallography problems (Version 1).
50    Xray1,
51    /// Special distance function for crystallography problems (Version 2).
52    Xray2,
53    /// There is a special distance function documented elsewhere.
54    Special,
55}
56
57#[derive(Clone, Copy, Debug)]
58/// Describes the format of the edge weights.
59pub enum EdgeWeightFormat {
60    /// Weights are given by a function.
61    Function,
62    /// Weights are given by a full matrix.
63    FullMatrix,
64    /// Upper triangular matrix (row-wise without diagonal entries).
65    UpperRow,
66    /// Lower triangular matrix (row-wise without diagonal entries).
67    LowerRow,
68    /// Upper triangular matrix (row-wise including diagonal entries).
69    UpperDiagRow,
70    /// Lower triangular matrix (row-wise including diagonal entries).
71    LowerDiagRow,
72    /// Upper triangular matrix (column-wise without diagonal entries).
73    UpperCol,
74    /// Lower triangular matrix (column-wise without diagonal entries).
75    LowerCol,
76    /// Upper triangular matrix (column-wise including diagonal entries).
77    UpperDiagCol,
78    /// Lower triangular matrix (column-wise including diagonal entries).
79    LowerDiagCol,
80}
81
82#[derive(Clone, Copy)]
83enum EdgeDataFormat {
84    EdgeList,
85    AdjList,
86}
87
88#[derive(Clone, Copy)]
89enum NodeCoordType {
90    TwodCoords,
91    ThreedCoords,
92}
93
94#[derive(PartialEq)]
95enum DisplayDataType {
96    Coord,
97    Twod,
98    No,
99}
100
101#[derive(Clone, Debug)]
102/// Node coordinates.
103pub enum NodeCoords {
104    /// Nodes are specified by coordinates in 2-D.
105    /// The first element of each tuple is the node number, the second and third elements are the x and y coordinates.
106    Twod(Vec<(usize, f64, f64)>),
107    /// Nodes are specified by coordinates in 3-D.
108    /// The first element of each tuple is the node number, the second, third and fourth elements are the x, y, and z coordinates.
109    Threed(Vec<(usize, f64, f64, f64)>),
110}
111
112#[derive(Clone, Debug)]
113/// Edges of a graph.
114pub enum EdgeData {
115    /// Edges are given by a list of node pairs.
116    EdgeList(Vec<(usize, usize)>),
117    /// Edges are given by adjacency lists.
118    /// The first element of each tuple is the node number, the second element is a list of adjacent nodes.
119    AdjList(Vec<(usize, Vec<usize>)>),
120}
121
122#[derive(Clone, Debug)]
123/// How a graphical display of the nodes can be obtained.
124pub enum DisplayData {
125    /// Display is generated from the node coordinates.
126    CoordDisplay,
127    /// Explicit coordinates in 2-D.
128    /// The first element of each tuple is the node number, the second and third elements are the x and y coordinates.
129    TwodDisplay(Vec<(usize, f64, f64)>),
130}
131
132#[derive(Clone, Debug)]
133/// An instance of a TSP or related problem.
134pub struct Instance {
135    /// Name of the instance.
136    pub name: String,
137    /// Type of the data.
138    pub instance_type: InstanceType,
139    /// Additional comments.
140    pub comment: String,
141    /// For a TSP or ATSP, the dimension is the number of its nodes.
142    /// For a CVRP, it is the total number of nodes and depots.
143    /// For a TOUR file, it is the dimension of the corresponding problem.
144    pub dimension: usize,
145    /// The truck capacity.
146    pub capacity: Option<i32>,
147    /// How the edge weights (or distances) are given.
148    pub edge_weight_type: EdgeWeightType,
149    /// Describes the format of the edge weights if they are given explicitly.
150    pub edge_weight_format: Option<EdgeWeightFormat>,
151    /// Maximum route duration.
152    pub distance: Option<f64>,
153    /// Service time.
154    pub service_time: Option<f64>,
155    /// The number of commodities at each node.
156    pub demand_dimension: Option<usize>,
157    /// Node coordinates.
158    /// (which, for example may be used for either graphical display or for computing the edge weights).
159    pub node_coords: Option<NodeCoords>,
160    /// A list of possible alternate depot nodes.
161    pub depots: Option<Vec<usize>>,
162    /// The demands of all nodes.
163    /// The first element of each tuple is the node number, the second element is a list of possibly multi-dimensional demands.
164    pub demands: Option<Vec<(usize, Vec<i32>)>>,
165    /// Edges of a graph, if the graph is not complete.
166    pub edge_data: Option<EdgeData>,
167    /// Edges required to appear in each solution to the problem.
168    pub fixed_edges: Option<Vec<(usize, usize)>>,
169    /// How a graphical display of the nodes can be obtained.
170    pub display_data: Option<DisplayData>,
171    /// A collection of tours.
172    pub tours: Option<Vec<Vec<usize>>>,
173    /// Edge weights in a matrix format specified by `edge_weight_format`.
174    pub edge_weights: Option<Vec<Vec<i32>>>,
175}
176
177fn parse_instance_type(value: &str) -> InstanceType {
178    match value {
179        "TSP" => InstanceType::Tsp,
180        "ATSP" => InstanceType::Atsp,
181        "SOP" => InstanceType::Sop,
182        "HCP" => InstanceType::Hcp,
183        "CVRP" => InstanceType::Cvrp,
184        "TOUR" => InstanceType::Tours,
185        other => InstanceType::Other(other.to_string()),
186    }
187}
188
189fn parse_edge_weight_type(value: &str) -> Result<EdgeWeightType, Box<dyn Error>> {
190    match value {
191        "EXPLICIT" => Ok(EdgeWeightType::Explicit),
192        "EUC_2D" => Ok(EdgeWeightType::Euc2d),
193        "EUC_3D" => Ok(EdgeWeightType::Euc3d),
194        "MAX_2D" => Ok(EdgeWeightType::Max2d),
195        "MAX_3D" => Ok(EdgeWeightType::Max3d),
196        "MAN_2D" => Ok(EdgeWeightType::Man2d),
197        "MAN_3D" => Ok(EdgeWeightType::Man3d),
198        "CEIL_2D" => Ok(EdgeWeightType::Ceil2d),
199        "GEO" => Ok(EdgeWeightType::Geo),
200        "ATT" => Ok(EdgeWeightType::Att),
201        "XRAY1" => Ok(EdgeWeightType::Xray1),
202        "XRAY2" => Ok(EdgeWeightType::Xray2),
203        "SPECIAL" => Ok(EdgeWeightType::Special),
204        _ => Err(format!("Unsupported edge weight type: {}", value).into()),
205    }
206}
207
208fn parse_edge_weight_format(value: &str) -> Result<EdgeWeightFormat, Box<dyn Error>> {
209    match value {
210        "FUNCTION" => Ok(EdgeWeightFormat::Function),
211        "FULL_MATRIX" => Ok(EdgeWeightFormat::FullMatrix),
212        "UPPER_ROW" => Ok(EdgeWeightFormat::UpperRow),
213        "LOWER_ROW" => Ok(EdgeWeightFormat::LowerRow),
214        "UPPER_DIAG_ROW" => Ok(EdgeWeightFormat::UpperDiagRow),
215        "LOWER_DIAG_ROW" => Ok(EdgeWeightFormat::LowerDiagRow),
216        "UPPER_COL" => Ok(EdgeWeightFormat::UpperCol),
217        "LOWER_COL" => Ok(EdgeWeightFormat::LowerCol),
218        "UPPER_DIAG_COL" => Ok(EdgeWeightFormat::UpperDiagCol),
219        "LOWER_DIAG_COL" => Ok(EdgeWeightFormat::LowerDiagCol),
220        _ => Err(format!("Unsupported edge weight format: {}", value).into()),
221    }
222}
223
224fn parse_edge_data_format(value: &str) -> Result<EdgeDataFormat, Box<dyn Error>> {
225    match value {
226        "EDGE_LIST" => Ok(EdgeDataFormat::EdgeList),
227        "ADJ_LIST" => Ok(EdgeDataFormat::AdjList),
228        _ => Err(format!("Unsupported edge data format: {}", value).into()),
229    }
230}
231
232fn parse_node_coord_type(value: &str) -> Result<NodeCoordType, Box<dyn Error>> {
233    match value {
234        "TWOD_COORDS" => Ok(NodeCoordType::TwodCoords),
235        "THREED_COORDS" => Ok(NodeCoordType::ThreedCoords),
236        _ => Err(format!("Unsupported node coordinate type: {}", value).into()),
237    }
238}
239
240fn parse_display_data_type(value: &str) -> Result<DisplayDataType, Box<dyn Error>> {
241    match value {
242        "COORD_DISPLAY" => Ok(DisplayDataType::Coord),
243        "TWOD_DISPLAY" => Ok(DisplayDataType::Twod),
244        "NO_DISPLAY" => Ok(DisplayDataType::No),
245        _ => Err(format!("Unsupported display data type: {}", value).into()),
246    }
247}
248
249type TwodCoords = Vec<(usize, f64, f64)>;
250
251fn parse_2d_coords(
252    lines: &mut impl Iterator<Item = String>,
253    dimension: usize,
254    line_number: &mut usize,
255    section_name: &str,
256) -> Result<TwodCoords, Box<dyn Error>> {
257    let mut coords = Vec::with_capacity(dimension);
258    let mut processed = HashSet::new();
259
260    for _ in 0..dimension {
261        let line = lines
262            .next()
263            .ok_or(format!("Unexpected EOF while parsing {}", section_name))?;
264        *line_number += 1;
265
266        let mut parts = line.split_whitespace();
267        let node = parts
268            .next()
269            .ok_or(format!(
270                "Missing node number in line {} ({})",
271                line_number, section_name,
272            ))?
273            .parse()?;
274        let x = parts
275            .next()
276            .ok_or(format!(
277                "Missing x-coordinate in line {} of ({})",
278                line_number, section_name
279            ))?
280            .parse()?;
281        let y = parts
282            .next()
283            .ok_or(format!(
284                "Missing y-coordinate in line {} of ({})",
285                line_number, section_name
286            ))?
287            .parse()?;
288
289        if processed.contains(&node) {
290            return Err(format!(
291                "Duplicate node number: {} in line {} (NODE_COORD_SECTION)",
292                node, line_number
293            )
294            .into());
295        }
296
297        processed.insert(node);
298        coords.push((node, x, y));
299    }
300
301    Ok(coords)
302}
303
304type ThreedCoords = Vec<(usize, f64, f64, f64)>;
305
306fn parse_3d_coords(
307    lines: &mut impl Iterator<Item = String>,
308    dimension: usize,
309    line_number: &mut usize,
310) -> Result<ThreedCoords, Box<dyn Error>> {
311    let mut coords = Vec::with_capacity(dimension);
312    let mut processed = HashSet::new();
313
314    for _ in 0..dimension {
315        let line = lines
316            .next()
317            .ok_or("Unexpected EOF while parsing NODE_COORD_SECTION")?;
318        *line_number += 1;
319
320        let mut parts = line.split_whitespace();
321        let node = parts
322            .next()
323            .ok_or(format!(
324                "Missing node number in line {} of NODE_COORD_SECTION",
325                line_number,
326            ))?
327            .parse()?;
328        let x = parts
329            .next()
330            .ok_or(format!(
331                "Missing x-coordinate in line {} of NODE_COORD_SECTION",
332                line_number,
333            ))?
334            .parse()?;
335        let y = parts
336            .next()
337            .ok_or(format!(
338                "Missing y-coordinate in line {} of NODE_COORD_SECTION",
339                line_number,
340            ))?
341            .parse()?;
342        let z = parts
343            .next()
344            .ok_or(format!(
345                "Missing z-coordinate in line {} of NODE_COORD_SECTION",
346                line_number,
347            ))?
348            .parse()?;
349
350        if processed.contains(&node) {
351            return Err(format!(
352                "Duplicate node number: {} in line {} (NODE_COORD_SECTION)",
353                node, line_number
354            )
355            .into());
356        }
357
358        processed.insert(node);
359        coords.push((node, x, y, z));
360    }
361
362    Ok(coords)
363}
364
365fn parse_node_coords(
366    lines: &mut impl Iterator<Item = String>,
367    node_coord_type: NodeCoordType,
368    dimension: usize,
369    line_number: &mut usize,
370) -> Result<NodeCoords, Box<dyn Error>> {
371    match node_coord_type {
372        NodeCoordType::TwodCoords => Ok(NodeCoords::Twod(parse_2d_coords(
373            lines,
374            dimension,
375            line_number,
376            "NODE_COORD_SECTION",
377        )?)),
378        NodeCoordType::ThreedCoords => Ok(NodeCoords::Threed(parse_3d_coords(
379            lines,
380            dimension,
381            line_number,
382        )?)),
383    }
384}
385
386fn parse_depots(
387    lines: &mut impl Iterator<Item = String>,
388    line_number: &mut usize,
389) -> Result<Vec<usize>, Box<dyn Error>> {
390    let mut depots = Vec::new();
391
392    for line in lines {
393        *line_number += 1;
394
395        let mut iter = line.split_whitespace();
396
397        while let Some(digit) = iter.next() {
398            if digit == "-1" {
399                if let Some(text) = iter.next() {
400                    return Err(
401                        format!("Unexpected text {} after -1 in DEPOT_SECTION", text).into(),
402                    );
403                }
404
405                return Ok(depots);
406            }
407
408            let depot = digit.parse()?;
409            depots.push(depot);
410        }
411    }
412
413    Err("Unexpected EOF while parsing DEPOT_SECTION".into())
414}
415
416type Demands = Vec<(usize, Vec<i32>)>;
417
418fn parse_demands(
419    lines: &mut impl Iterator<Item = String>,
420    dimension: usize,
421    demand_dimension: usize,
422    line_number: &mut usize,
423) -> Result<Demands, Box<dyn Error>> {
424    let mut demands = Vec::with_capacity(dimension);
425    let mut processed = HashSet::new();
426
427    for _ in 0..dimension {
428        let line = lines
429            .next()
430            .ok_or("Unexpected EOF while parsing DEMAND_SECTION")?;
431        *line_number += 1;
432
433        let mut iter = line.split_whitespace();
434        let node = iter
435            .next()
436            .ok_or(format!(
437                "Missing node number in line {} (DEMAND_SECTION)",
438                line_number
439            ))?
440            .parse::<usize>()?;
441
442        let mut node_demands = Vec::with_capacity(demand_dimension);
443
444        for j in 0..demand_dimension {
445            let demand = iter
446                .next()
447                .ok_or(format!(
448                    "Missing {}-th demand in line {} (DEMAND_SECTION)",
449                    j + 1,
450                    line_number
451                ))?
452                .parse::<i32>()?;
453
454            node_demands.push(demand);
455        }
456
457        if processed.contains(&node) {
458            return Err(format!(
459                "Duplicate node number: {} in line {} (DEMAND_SECTION)",
460                node, line_number
461            )
462            .into());
463        }
464
465        processed.insert(node);
466        demands.push((node, node_demands));
467    }
468
469    Ok(demands)
470}
471
472fn parse_edge_list(
473    lines: &mut impl Iterator<Item = String>,
474    line_number: &mut usize,
475) -> Result<Vec<(usize, usize)>, Box<dyn Error>> {
476    let mut edge_list = Vec::new();
477
478    for line in lines {
479        *line_number += 1;
480
481        if line.trim() == "-1" {
482            return Ok(edge_list);
483        }
484
485        let mut parts = line.split_whitespace();
486        let from = parts
487            .next()
488            .ok_or(format!(
489                "Missing from node in line {} (EDGE_DATA_SECTION)",
490                line_number
491            ))?
492            .parse()?;
493        let to = parts
494            .next()
495            .ok_or(format!(
496                "Missing to node in line {} (EDGE_DATA_SECTION)",
497                line_number
498            ))?
499            .parse()?;
500
501        edge_list.push((from, to));
502    }
503
504    Err("Unexpected EOF while parsing EDGE_DATA_SECTION".into())
505}
506
507type AdjList = Vec<(usize, Vec<usize>)>;
508
509fn parse_adj_list(
510    lines: &mut impl Iterator<Item = String>,
511    line_number: &mut usize,
512) -> Result<AdjList, Box<dyn Error>> {
513    let mut adj_list = Vec::new();
514    let mut from_node = None;
515    let mut to_nodes = Vec::new();
516    let mut processed = HashSet::new();
517
518    for line in lines {
519        *line_number += 1;
520        let mut iter = line.split_whitespace();
521
522        while let Some(digit) = iter.next() {
523            if let Some(node) = from_node {
524                if digit == "-1" {
525                    if processed.contains(&node) {
526                        return Err(format!(
527                            "Duplicate node number: {} in line {} (EDGE_DATA_SECTION)",
528                            node, line_number
529                        )
530                        .into());
531                    }
532
533                    processed.insert(node);
534                    let mut tmp_nodes = Vec::new();
535                    mem::swap(&mut tmp_nodes, &mut to_nodes);
536                    adj_list.push((node, tmp_nodes));
537                    from_node = None;
538                } else {
539                    to_nodes.push(digit.parse()?);
540                }
541            } else if digit == "-1" {
542                if let Some(text) = iter.next() {
543                    return Err(
544                        format!("Unexpected text {} after -1 in EDGE_DATA_SECTION", text).into(),
545                    );
546                }
547
548                return Ok(adj_list);
549            } else {
550                from_node = Some(digit.parse()?);
551            }
552        }
553    }
554
555    Err("Unexpected EOF while parsing EDGE_DATA_SECTION".into())
556}
557
558fn parse_edge_data(
559    lines: &mut impl Iterator<Item = String>,
560    edge_data_type: EdgeDataFormat,
561    line_number: &mut usize,
562) -> Result<EdgeData, Box<dyn Error>> {
563    match edge_data_type {
564        EdgeDataFormat::EdgeList => Ok(EdgeData::EdgeList(parse_edge_list(lines, line_number)?)),
565        EdgeDataFormat::AdjList => Ok(EdgeData::AdjList(parse_adj_list(lines, line_number)?)),
566    }
567}
568
569fn parse_tours(
570    lines: &mut impl Iterator<Item = String>,
571    line_number: &mut usize,
572) -> Result<Vec<Vec<usize>>, Box<dyn Error>> {
573    let mut tours = Vec::new();
574    let mut current_tour = Vec::new();
575
576    for line in lines {
577        *line_number += 1;
578        let mut iter = line.split_whitespace();
579
580        while let Some(digit) = iter.next() {
581            if digit == "-1" {
582                if current_tour.is_empty() {
583                    if let Some(text) = iter.next() {
584                        return Err(
585                            format!("Unexpected text {} after -1 in TOUR_SECTION", text).into()
586                        );
587                    }
588
589                    return Ok(tours);
590                } else {
591                    let mut tmp_tour = Vec::new();
592                    mem::swap(&mut tmp_tour, &mut current_tour);
593                    tours.push(tmp_tour);
594                }
595            }
596
597            let node = digit.parse()?;
598            current_tour.push(node);
599        }
600    }
601
602    Err("Unexpected EOF while parsing TOUR_SECTION".into())
603}
604
605fn adjust_full_matrix(matrix: &mut [Vec<i32>], last_element: i32) -> i32 {
606    let mut last_element = last_element;
607
608    for row in matrix.iter_mut().rev() {
609        let first_element = row.remove(0);
610        row.push(last_element);
611        last_element = first_element;
612    }
613
614    last_element
615}
616
617fn parse_full_matrix(
618    lines: &mut impl Iterator<Item = String>,
619    dimension: usize,
620    line_number: &mut usize,
621) -> Result<Vec<Vec<i32>>, Box<dyn Error>> {
622    let mut matrix = Vec::with_capacity(dimension);
623
624    if dimension == 0 {
625        return Ok(matrix);
626    }
627
628    let mut row = Vec::with_capacity(dimension);
629    let mut i = 0;
630    let mut j = 0;
631
632    for line in lines {
633        *line_number += 1;
634        let mut iter = line.split_whitespace();
635
636        while let Some(weight) = iter.next() {
637            let weight = weight.parse::<i32>()?;
638            row.push(weight);
639            j += 1;
640
641            if j == dimension {
642                let mut tmp_row = Vec::with_capacity(dimension);
643                mem::swap(&mut tmp_row, &mut row);
644                matrix.push(tmp_row);
645                i += 1;
646                j = 0;
647
648                if i == dimension {
649                    if let Some(text) = iter.next() {
650                        if let Some(text) = iter.next() {
651                            return Err(format!(
652                                "Unexpected text {} after full matrix in EDGE_WEIGHT_SECTION",
653                                text,
654                            )
655                            .into());
656                        }
657
658                        let last_element = text.parse::<i32>()?;
659                        let first_element = adjust_full_matrix(&mut matrix, last_element) as usize;
660
661                        if first_element == dimension {
662                            return Ok(matrix);
663                        } else {
664                            return Err(format!(
665                                    "The first element {} is different from dimension {} for full matrix in EDGE_WEIGHT_SECTION",
666                                    first_element, dimension
667                                )
668                                .into());
669                        }
670                    }
671
672                    return Ok(matrix);
673                }
674            }
675        }
676    }
677
678    Err(format!(
679        "EDGE_WEIGHT_SECTION contains only {} < {} values",
680        matrix.into_iter().flatten().count() + row.len(),
681        dimension * dimension
682    )
683    .into())
684}
685
686fn parse_upper_row(
687    lines: &mut impl Iterator<Item = String>,
688    dimension: usize,
689    line_number: &mut usize,
690) -> Result<Vec<Vec<i32>>, Box<dyn Error>> {
691    let mut matrix = Vec::with_capacity(dimension);
692
693    if dimension == 0 {
694        return Ok(matrix);
695    }
696
697    let mut n_columns = dimension - 1;
698
699    let mut row = Vec::with_capacity(n_columns);
700
701    if n_columns == 0 {
702        matrix.push(row);
703
704        return Ok(matrix);
705    }
706
707    let mut i = 1;
708    let mut j = 0;
709
710    for line in lines {
711        *line_number += 1;
712        let mut iter = line.split_whitespace();
713
714        while let Some(weight) = iter.next() {
715            let weight = weight.parse::<i32>()?;
716            row.push(weight);
717            j += 1;
718
719            if j == n_columns {
720                let mut tmp_row = Vec::with_capacity(n_columns);
721                mem::swap(&mut tmp_row, &mut row);
722                matrix.push(tmp_row);
723                i += 1;
724                j = 0;
725                n_columns -= 1;
726
727                if i == dimension {
728                    if let Some(test) = iter.next() {
729                        return Err(format!(
730                            "Unexpected text {} after upper row in EDGE_WEIGHT_SECTION",
731                            test
732                        )
733                        .into());
734                    }
735
736                    return Ok(matrix);
737                }
738            }
739        }
740    }
741
742    Err(format!(
743        "EDGE_WEIGHT_SECTION contains only {} < {} values",
744        matrix.into_iter().flatten().count() + row.len(),
745        dimension * (dimension - 1) / 2
746    )
747    .into())
748}
749
750fn parse_lower_row(
751    lines: &mut impl Iterator<Item = String>,
752    dimension: usize,
753    line_number: &mut usize,
754) -> Result<Vec<Vec<i32>>, Box<dyn Error>> {
755    let mut matrix = Vec::with_capacity(dimension);
756
757    if dimension == 0 {
758        return Ok(matrix);
759    }
760
761    matrix.push(Vec::new());
762
763    if dimension == 1 {
764        return Ok(matrix);
765    }
766
767    let mut n_columns = 1;
768    let mut row = Vec::with_capacity(n_columns);
769    let mut i = 1;
770    let mut j = 0;
771
772    for line in lines {
773        *line_number += 1;
774        let mut iter = line.split_whitespace();
775
776        while let Some(weight) = iter.next() {
777            let weight = weight.parse::<i32>()?;
778            row.push(weight);
779            j += 1;
780
781            if j == n_columns {
782                let mut tmp_row = Vec::with_capacity(n_columns);
783                mem::swap(&mut tmp_row, &mut row);
784                matrix.push(tmp_row);
785                i += 1;
786                j = 0;
787                n_columns += 1;
788
789                if i == dimension {
790                    if let Some(test) = iter.next() {
791                        return Err(format!(
792                            "Unexpected text {} after lower row in EDGE_WEIGHT_SECTION",
793                            test
794                        )
795                        .into());
796                    }
797
798                    return Ok(matrix);
799                }
800            }
801        }
802    }
803
804    Err(format!(
805        "EDGE_WEIGHT_SECTION contains only {} < {} values",
806        matrix.into_iter().flatten().count() + row.len(),
807        dimension * (dimension - 1) / 2
808    )
809    .into())
810}
811
812fn parse_upper_diag_row(
813    lines: &mut impl Iterator<Item = String>,
814    dimension: usize,
815    line_number: &mut usize,
816) -> Result<Vec<Vec<i32>>, Box<dyn Error>> {
817    let mut matrix = Vec::with_capacity(dimension);
818
819    if dimension == 0 {
820        return Ok(matrix);
821    }
822
823    let mut n_columns = dimension;
824    let mut row = Vec::with_capacity(n_columns);
825    let mut i = 0;
826    let mut j = 0;
827
828    for line in lines {
829        *line_number += 1;
830        let mut iter = line.split_whitespace();
831
832        while let Some(weight) = iter.next() {
833            let weight = weight.parse::<i32>()?;
834            row.push(weight);
835            j += 1;
836
837            if j == n_columns {
838                let mut tmp_row = Vec::with_capacity(n_columns);
839                mem::swap(&mut tmp_row, &mut row);
840                matrix.push(tmp_row);
841                i += 1;
842                j = 0;
843                n_columns -= 1;
844
845                if i == dimension {
846                    if let Some(test) = iter.next() {
847                        return Err(format!(
848                            "Unexpected text {} after upper diag row in EDGE_WEIGHT_SECTION",
849                            test
850                        )
851                        .into());
852                    }
853
854                    return Ok(matrix);
855                }
856            }
857        }
858    }
859
860    Err(format!(
861        "EDGE_WEIGHT_SECTION contains only {} < {} values",
862        matrix.into_iter().flatten().count() + row.len(),
863        dimension * (dimension + 1) / 2
864    )
865    .into())
866}
867
868fn parse_lower_diag_row(
869    lines: &mut impl Iterator<Item = String>,
870    dimension: usize,
871    line_number: &mut usize,
872) -> Result<Vec<Vec<i32>>, Box<dyn Error>> {
873    let mut matrix = Vec::with_capacity(dimension);
874
875    if dimension == 0 {
876        return Ok(matrix);
877    }
878
879    let mut n_columns = 1;
880    let mut row = Vec::with_capacity(n_columns);
881    let mut i = 0;
882    let mut j = 0;
883
884    for line in lines {
885        *line_number += 1;
886        let mut iter = line.split_whitespace();
887
888        while let Some(weight) = iter.next() {
889            let weight = weight.parse::<i32>()?;
890            row.push(weight);
891            j += 1;
892
893            if j == n_columns {
894                let mut tmp_row = Vec::with_capacity(n_columns);
895                mem::swap(&mut tmp_row, &mut row);
896                matrix.push(tmp_row);
897                i += 1;
898                j = 0;
899                n_columns += 1;
900
901                if i == dimension {
902                    if let Some(test) = iter.next() {
903                        return Err(format!(
904                            "Unexpected text {} after lower diag row in EDGE_WEIGHT_SECTION",
905                            test
906                        )
907                        .into());
908                    }
909
910                    return Ok(matrix);
911                }
912            }
913        }
914    }
915
916    Err(format!(
917        "EDGE_WEIGHT_SECTION contains only {} < {} values",
918        matrix.into_iter().flatten().count() + row.len(),
919        dimension * (dimension + 1) / 2
920    )
921    .into())
922}
923
924fn parse_edge_weights(
925    lines: &mut impl Iterator<Item = String>,
926    edge_weight_format: EdgeWeightFormat,
927    dimension: usize,
928    line_number: &mut usize,
929) -> Result<Vec<Vec<i32>>, Box<dyn Error>> {
930    match edge_weight_format {
931        EdgeWeightFormat::FullMatrix => parse_full_matrix(lines, dimension, line_number),
932        EdgeWeightFormat::UpperRow | EdgeWeightFormat::LowerCol => {
933            parse_upper_row(lines, dimension, line_number)
934        }
935        EdgeWeightFormat::LowerRow | EdgeWeightFormat::UpperCol => {
936            parse_lower_row(lines, dimension, line_number)
937        }
938        EdgeWeightFormat::UpperDiagRow | EdgeWeightFormat::LowerDiagCol => {
939            parse_upper_diag_row(lines, dimension, line_number)
940        }
941        EdgeWeightFormat::LowerDiagRow | EdgeWeightFormat::UpperDiagCol => {
942            parse_lower_diag_row(lines, dimension, line_number)
943        }
944        other => Err(format!(
945            "Edge weight format {:?} does not support EDGE_WEIGHT_SECTION",
946            other
947        )
948        .into()),
949    }
950}
951
952impl Instance {
953    fn read_from_lines(
954        lines: &mut impl Iterator<Item = String>,
955    ) -> Result<Instance, Box<dyn Error>> {
956        let mut name = String::from("");
957        let mut instance_type = InstanceType::Other("".to_string());
958        let mut comment = String::from("");
959        let mut dimension = None;
960        let mut capacity = None;
961        let mut edge_weight_type = None;
962        let mut edge_weight_format = None;
963        let mut edge_data_format = None;
964        let mut node_coord_type = None;
965        let mut display_data_type = None;
966        let mut distance = None;
967        let mut service_time = None;
968        let mut demand_dimension = None;
969
970        let mut node_coords = None;
971        let mut depots = None;
972        let mut demands = None;
973        let mut edge_data = None;
974        let mut fixed_edges = None;
975        let mut display_data = None;
976        let mut tours = None;
977        let mut edge_weights = None;
978
979        let mut processed_keys = HashSet::new();
980
981        let mut line_number = 0;
982
983        while let Some(line) = lines.next() {
984            line_number += 1;
985            let trimmed = line.trim();
986
987            if trimmed.is_empty() {
988                continue;
989            }
990
991            if trimmed == "EOF" {
992                break;
993            }
994
995            if let Some((key, value)) = trimmed.split_once(":") {
996                let value = value.trim();
997                let key = key.trim();
998
999                if processed_keys.contains(key) {
1000                    return Err(format!("Duplicate key: {}", key).into());
1001                }
1002
1003                match key {
1004                    "NAME" => {
1005                        name = value.to_string();
1006                        processed_keys.insert("NAME");
1007                        continue;
1008                    }
1009                    "TYPE" => {
1010                        instance_type = parse_instance_type(value);
1011                        processed_keys.insert("TYPE");
1012                        continue;
1013                    }
1014                    "COMMENT" => {
1015                        comment = value.to_string();
1016                        processed_keys.insert("COMMENT");
1017                        continue;
1018                    }
1019                    "DIMENSION" => {
1020                        dimension = Some(value.parse()?);
1021                        processed_keys.insert("DIMENSION");
1022                        continue;
1023                    }
1024                    "CAPACITY" => {
1025                        capacity = Some(value.parse()?);
1026                        processed_keys.insert("CAPACITY");
1027                        continue;
1028                    }
1029                    "EDGE_WEIGHT_TYPE" => {
1030                        edge_weight_type = Some(parse_edge_weight_type(value)?);
1031                        processed_keys.insert("EDGE_WEIGHT_TYPE");
1032                        continue;
1033                    }
1034                    "EDGE_WEIGHT_FORMAT" => {
1035                        edge_weight_format = Some(parse_edge_weight_format(value)?);
1036                        processed_keys.insert("EDGE_WEIGHT_FORMAT");
1037                        continue;
1038                    }
1039                    "EDGE_DATA_FORMAT" => {
1040                        edge_data_format = Some(parse_edge_data_format(value)?);
1041                        processed_keys.insert("EDGE_DATA_FORMAT");
1042                        continue;
1043                    }
1044                    "NODE_COORD_TYPE" => {
1045                        node_coord_type = Some(parse_node_coord_type(value)?);
1046                        processed_keys.insert("NODE_COORD_TYPE");
1047                        continue;
1048                    }
1049                    "DISPLAY_DATA_TYPE" => {
1050                        display_data_type = Some(parse_display_data_type(value)?);
1051                        processed_keys.insert("DISPLAY_DATA_TYPE");
1052                        continue;
1053                    }
1054                    "DISTANCE" => {
1055                        distance = Some(value.parse()?);
1056                        processed_keys.insert("DISTANCE");
1057                        continue;
1058                    }
1059                    "SERVICE_TIME" => {
1060                        service_time = Some(value.parse()?);
1061                        processed_keys.insert("SERVICE_TIME");
1062                        continue;
1063                    }
1064                    "DEMAND_DIMENSION" => {
1065                        demand_dimension = Some(value.parse()?);
1066                        processed_keys.insert("DEMAND_DIMENSION");
1067                        continue;
1068                    }
1069                    _ => {}
1070                }
1071            }
1072
1073            let section_key_result = line.split(":").collect::<Vec<_>>();
1074
1075            if section_key_result.len() == 1
1076                || section_key_result.len() == 2 && section_key_result[1].is_empty()
1077            {
1078                let key = section_key_result[0].trim();
1079
1080                if processed_keys.contains(key) {
1081                    return Err(format!("Duplicate key: {}", key).into());
1082                }
1083
1084                match key {
1085                    "NODE_COORD_SECTION" => match (node_coord_type, dimension) {
1086                        (_, None) => {
1087                            return Err(
1088                                "DIMENSION must be specified before NODE_COORD_SECTION".into()
1089                            );
1090                        }
1091                        (Some(node_coord_type), Some(dimension)) => {
1092                            node_coords = Some(parse_node_coords(
1093                                lines,
1094                                node_coord_type,
1095                                dimension,
1096                                &mut line_number,
1097                            )?);
1098                            processed_keys.insert("NODE_COORD_SECTION");
1099                            continue;
1100                        }
1101                        (None, Some(dimension)) => {
1102                            let result = parse_2d_coords(
1103                                lines,
1104                                dimension,
1105                                &mut line_number,
1106                                "NODE_COORD_SECTION",
1107                            );
1108
1109                            if result.is_ok() {
1110                                node_coords = Some(NodeCoords::Twod(result?));
1111                                processed_keys.insert("NODE_COORD_SECTION");
1112                                continue;
1113                            }
1114
1115                            let result = parse_3d_coords(lines, dimension, &mut line_number);
1116
1117                            if result.is_ok() {
1118                                node_coords = Some(NodeCoords::Threed(result?));
1119                                processed_keys.insert("NODE_COORD_SECTION");
1120                                continue;
1121                            }
1122
1123                            return Err("Failed to parse NODE_COORD_SECTION".into());
1124                        }
1125                    },
1126                    "DEPOT_SECTION" => {
1127                        depots = Some(parse_depots(lines, &mut line_number)?);
1128                        processed_keys.insert("DEPOT_SECTION");
1129                        continue;
1130                    }
1131                    "DEMAND_SECTION" => {
1132                        if let Some(dimension) = dimension {
1133                            if demand_dimension.is_none() {
1134                                demand_dimension = Some(1);
1135                            }
1136
1137                            demands = Some(parse_demands(
1138                                lines,
1139                                dimension,
1140                                demand_dimension.unwrap(),
1141                                &mut line_number,
1142                            )?);
1143                            processed_keys.insert("DEMAND_SECTION");
1144                            continue;
1145                        } else {
1146                            return Err("DIMENSION must be specified before DEMAND_SECTION".into());
1147                        }
1148                    }
1149                    "EDGE_DATA_SECTION" => match edge_data_format {
1150                        Some(edge_data_format) => {
1151                            edge_data =
1152                                Some(parse_edge_data(lines, edge_data_format, &mut line_number)?);
1153                            processed_keys.insert("EDGE_DATA_SECTION");
1154                            continue;
1155                        }
1156                        None => {
1157                            return Err(
1158                                "EDGE_DATA_FORMAT must be specified before EDGE_DATA_SECTION"
1159                                    .into(),
1160                            );
1161                        }
1162                    },
1163                    "FIXED_EDGES_SECTION" => {
1164                        fixed_edges = Some(parse_edge_list(lines, &mut line_number)?);
1165                        processed_keys.insert("FIXED_EDGES_SECTION");
1166                        continue;
1167                    }
1168                    "DISPLAY_DATA_SECTION" => {
1169                        if display_data_type != Some(DisplayDataType::Twod) {
1170                            return Err("DISPLAY_DATA_TYPE must be TWOD_DISPLAY when DISPLAY_DATA_SECTION is used".into());
1171                        }
1172
1173                        if let Some(dimension) = dimension {
1174                            display_data = Some(DisplayData::TwodDisplay(parse_2d_coords(
1175                                lines,
1176                                dimension,
1177                                &mut line_number,
1178                                "DISPLAY_DATA_SECTION",
1179                            )?));
1180                            processed_keys.insert("DISPLAY_DATA_SECTION");
1181                            continue;
1182                        } else {
1183                            return Err(
1184                                "DIMENSION must be specified before DISPLAY_DATA_SECTION".into()
1185                            );
1186                        }
1187                    }
1188                    "TOUR_SECTION" => {
1189                        tours = Some(parse_tours(lines, &mut line_number)?);
1190                        processed_keys.insert("TOUR_SECTION");
1191                        continue;
1192                    }
1193                    "EDGE_WEIGHT_SECTION" => {
1194                        if let Some(edge_weight_format) = edge_weight_format {
1195                            if let Some(dimension) = dimension {
1196                                edge_weights = Some(parse_edge_weights(
1197                                    lines,
1198                                    edge_weight_format,
1199                                    dimension,
1200                                    &mut line_number,
1201                                )?);
1202                                processed_keys.insert("EDGE_WEIGHT_SECTION");
1203                                continue;
1204                            } else {
1205                                return Err(
1206                                    "DIMENSION must be specified before EDGE_WEIGHT_SECTION".into(),
1207                                );
1208                            }
1209                        } else {
1210                            return Err(
1211                                "EDGE_WEIGHT_FORMAT must be specified before EDGE_WEIGHT_SECTION"
1212                                    .into(),
1213                            );
1214                        }
1215                    }
1216                    _ => {}
1217                }
1218            }
1219
1220            return Err(format!("Failed to parse line {}: {}", line_number, line).into());
1221        }
1222
1223        if dimension.is_none() {
1224            return Err("Missing dimension".into());
1225        }
1226
1227        if edge_weight_type.is_none() {
1228            return Err("Missing edge weight type".into());
1229        }
1230
1231        if display_data_type == Some(DisplayDataType::Coord) && node_coord_type.is_none() {
1232            return Err(
1233                "NODE_COORD_TYPE must be specified when DISPLAY_DATA_TYPE is COORD_DISPLAY".into(),
1234            );
1235        }
1236
1237        if display_data_type.is_none() && node_coord_type.is_some() {
1238            display_data = Some(DisplayData::CoordDisplay);
1239        }
1240
1241        Ok(Instance {
1242            name,
1243            instance_type,
1244            comment,
1245            dimension: dimension.unwrap(),
1246            capacity,
1247            edge_weight_type: edge_weight_type.unwrap(),
1248            edge_weight_format,
1249            distance,
1250            service_time,
1251            demand_dimension,
1252            node_coords,
1253            depots,
1254            demands,
1255            edge_data,
1256            fixed_edges,
1257            display_data,
1258            tours,
1259            edge_weights,
1260        })
1261    }
1262
1263    /// Parses an instance from a string.
1264    pub fn parse(input: &str) -> Result<Instance, Box<dyn Error>> {
1265        let mut lines = input.lines().map(|line| line.to_string());
1266
1267        Instance::read_from_lines(&mut lines)
1268    }
1269
1270    /// Loads an instance from a file.
1271    pub fn load(filename: &str) -> Result<Instance, Box<dyn Error>> {
1272        let content = fs::read_to_string(filename)?;
1273
1274        Instance::parse(&content)
1275    }
1276}
1277
1278fn round(x: f64) -> i32 {
1279    (x + 0.5).trunc() as i32
1280}
1281
1282fn euiclidean_distance_2d(x1: f64, y1: f64, x2: f64, y2: f64) -> i32 {
1283    let dx = x1 - x2;
1284    let dy = y1 - y2;
1285
1286    round((dx * dx + dy * dy).sqrt())
1287}
1288
1289fn euclidean_distance_3d(x1: f64, y1: f64, z1: f64, x2: f64, y2: f64, z2: f64) -> i32 {
1290    let dx = x1 - x2;
1291    let dy = y1 - y2;
1292    let dz = z1 - z2;
1293
1294    round((dx * dx + dy * dy + dz * dz).sqrt())
1295}
1296
1297fn manhattan_distance_2d(x1: f64, y1: f64, x2: f64, y2: f64) -> i32 {
1298    let dx = x1 - x2;
1299    let dy = y1 - y2;
1300
1301    round(dx.abs() + dy.abs())
1302}
1303
1304fn manhattan_distance_3d(x1: f64, y1: f64, z1: f64, x2: f64, y2: f64, z2: f64) -> i32 {
1305    let dx = x1 - x2;
1306    let dy = y1 - y2;
1307    let dz = z1 - z2;
1308
1309    round(dx.abs() + dy.abs() + dz.abs())
1310}
1311
1312fn maximum_distance_2d(x1: f64, y1: f64, x2: f64, y2: f64) -> i32 {
1313    let dx = x1 - x2;
1314    let dy = y1 - y2;
1315
1316    round(dx.abs().max(dy.abs()))
1317}
1318
1319fn maximum_distance_3d(x1: f64, y1: f64, z1: f64, x2: f64, y2: f64, z2: f64) -> i32 {
1320    let dx = x1 - x2;
1321    let dy = y1 - y2;
1322    let dz = z1 - z2;
1323
1324    round(dx.abs().max(dy.abs()).max(dz.abs()))
1325}
1326
1327fn radian(v: f64) -> f64 {
1328    let deg = round(v) as f64;
1329    let min = v - deg;
1330
1331    PI * (deg + 5.0 * min / 3.0) / 180.0
1332}
1333
1334fn geographical_distance(x1: f64, y1: f64, x2: f64, y2: f64) -> i32 {
1335    const RRR: f64 = 6378.388;
1336
1337    let latitude1 = radian(x1);
1338    let longitude1 = radian(y1);
1339    let latitude2 = radian(x2);
1340    let longitude2 = radian(y2);
1341
1342    let q1 = (longitude1 - longitude2).cos();
1343    let q2 = (latitude1 - latitude2).cos();
1344    let q3 = (latitude1 + latitude2).cos();
1345
1346    (RRR * (0.5 * (1.0 + q1) * q2 - (1.0 - q1) * q3).acos() + 1.0).trunc() as i32
1347}
1348
1349fn pseudo_euclidean_distance(x1: f64, y1: f64, x2: f64, y2: f64) -> i32 {
1350    let xd = x1 - x2;
1351    let yd = y1 - y2;
1352    let rij = ((xd * xd + yd * yd) / 10.0).sqrt();
1353    let tij = round(rij);
1354
1355    if (tij as f64) < rij {
1356        tij + 1
1357    } else {
1358        tij
1359    }
1360}
1361
1362fn ceiling_euclidean_distance_2d(x1: f64, y1: f64, x2: f64, y2: f64) -> i32 {
1363    let dx = x1 - x2;
1364    let dy = y1 - y2;
1365
1366    (dx * dx + dy * dy).sqrt().ceil() as i32
1367}
1368
1369fn xray1(x1: f64, y1: f64, z1: f64, x2: f64, y2: f64, z3: f64) -> i32 {
1370    let dx = (x1 - x2).abs();
1371    let dx_minus = (dx - 360.0).abs();
1372    let dx = if dx < dx_minus { dx } else { dx_minus };
1373
1374    let dy = (y1 - y2).abs();
1375    let dz = (z1 - z3).abs();
1376
1377    let distance = if dx > dy && dx > dz {
1378        dx
1379    } else if dy > dz {
1380        dy
1381    } else {
1382        dz
1383    };
1384
1385    round(100.0 * distance)
1386}
1387
1388fn xray2(x1: f64, y1: f64, z1: f64, x2: f64, y2: f64, z3: f64) -> i32 {
1389    const SX: f64 = 1.25;
1390    const SY: f64 = 1.5;
1391    const SZ: f64 = 1.15;
1392
1393    let dx = (x1 - x2).abs();
1394    let dx_minus = (dx - 360.0).abs();
1395    let dx = if dx < dx_minus { dx } else { dx_minus };
1396    let dx = dx / SX;
1397
1398    let dy = (y1 - y2).abs() / SY;
1399    let dz = (z1 - z3).abs() / SZ;
1400
1401    let distance = if dx > dy && dx > dz {
1402        dx
1403    } else if dy > dz {
1404        dy
1405    } else {
1406        dz
1407    };
1408
1409    round(100.0 * distance)
1410}
1411
1412fn from_2d_coords_to_full_matrix<F>(coords: &[(usize, f64, f64)], f: F) -> Vec<Vec<i32>>
1413where
1414    F: Fn(f64, f64, f64, f64) -> i32,
1415{
1416    let dimension = coords.len();
1417    let mut matrix = vec![vec![0; dimension]; dimension];
1418    let mut coords = coords.to_vec();
1419    coords.sort_by_key(|(node, _, _)| *node);
1420
1421    for i in 0..dimension {
1422        for j in 0..dimension {
1423            matrix[i][j] = f(coords[i].1, coords[i].2, coords[j].1, coords[j].2);
1424        }
1425    }
1426
1427    matrix
1428}
1429
1430fn from_3d_coords_to_full_matrix<F>(coords: &[(usize, f64, f64, f64)], f: F) -> Vec<Vec<i32>>
1431where
1432    F: Fn(f64, f64, f64, f64, f64, f64) -> i32,
1433{
1434    let dimension = coords.len();
1435    let mut matrix = vec![vec![0; dimension]; dimension];
1436    let mut coords = coords.to_vec();
1437    coords.sort_by_key(|(node, _, _, _)| *node);
1438
1439    for i in 0..dimension {
1440        for j in 0..dimension {
1441            matrix[i][j] = f(
1442                coords[i].1,
1443                coords[i].2,
1444                coords[i].3,
1445                coords[j].1,
1446                coords[j].2,
1447                coords[j].3,
1448            );
1449        }
1450    }
1451
1452    matrix
1453}
1454
1455fn from_upper_row_to_full_matrix(matrix: &[Vec<i32>]) -> Vec<Vec<i32>> {
1456    let dimension = matrix.len();
1457    let mut full_matrix = vec![vec![0; dimension]; dimension];
1458
1459    for i in 0..dimension {
1460        let n_columns = dimension - i - 1;
1461
1462        for k in 0..n_columns {
1463            let j = i + 1 + k;
1464
1465            full_matrix[i][j] = matrix[i][k];
1466            full_matrix[j][i] = matrix[i][k];
1467        }
1468    }
1469
1470    full_matrix
1471}
1472
1473fn from_lower_row_to_full_matrix(matrix: &[Vec<i32>]) -> Vec<Vec<i32>> {
1474    let dimension = matrix.len();
1475    let mut full_matrix = vec![vec![0; dimension]; dimension];
1476
1477    for i in 0..dimension {
1478        for j in 0..i {
1479            full_matrix[i][j] = matrix[i][j];
1480            full_matrix[j][i] = matrix[i][j];
1481        }
1482    }
1483
1484    full_matrix
1485}
1486
1487fn from_upper_diag_row_to_full_matrix(matrix: &[Vec<i32>]) -> Vec<Vec<i32>> {
1488    let dimension = matrix.len();
1489    let mut full_matrix = vec![vec![0; dimension]; dimension];
1490
1491    for i in 0..dimension {
1492        let n_columns = dimension - i;
1493
1494        for k in 0..n_columns {
1495            let j = i + k;
1496
1497            full_matrix[i][j] = matrix[i][k];
1498            full_matrix[j][i] = matrix[i][k];
1499        }
1500    }
1501
1502    full_matrix
1503}
1504
1505fn from_lower_diag_row_to_full_matrix(matrix: &[Vec<i32>]) -> Vec<Vec<i32>> {
1506    let dimension = matrix.len();
1507    let mut full_matrix = vec![vec![0; dimension]; dimension];
1508
1509    for i in 0..dimension {
1510        for j in 0..=i {
1511            full_matrix[i][j] = matrix[i][j];
1512            full_matrix[j][i] = matrix[i][j];
1513        }
1514    }
1515
1516    full_matrix
1517}
1518
1519fn from_explicit_to_full_matrix(
1520    weights: &[Vec<i32>],
1521    format: &EdgeWeightFormat,
1522) -> Result<Vec<Vec<i32>>, Box<dyn Error>> {
1523    match format {
1524        EdgeWeightFormat::FullMatrix => Ok(weights.to_vec()),
1525        EdgeWeightFormat::UpperRow => Ok(from_upper_row_to_full_matrix(weights)),
1526        EdgeWeightFormat::LowerRow => Ok(from_lower_row_to_full_matrix(weights)),
1527        EdgeWeightFormat::UpperDiagRow => Ok(from_upper_diag_row_to_full_matrix(weights)),
1528        EdgeWeightFormat::LowerDiagRow => Ok(from_lower_diag_row_to_full_matrix(weights)),
1529        _ => Err(format!("Unsupported edge weight format: {:?}", format).into()),
1530    }
1531}
1532
1533impl Instance {
1534    /// Returns the full distance matrix of the instance.
1535    pub fn get_full_distance_matrix(&self) -> Result<Vec<Vec<i32>>, Box<dyn Error>> {
1536        match self.edge_weight_type {
1537            EdgeWeightType::Special => Err("SPECIAL edge weight type is not supported".into()),
1538            EdgeWeightType::Explicit => {
1539                if let Some(format) = self.edge_weight_format {
1540                    if let Some(weights) = &self.edge_weights {
1541                        from_explicit_to_full_matrix(weights, &format)
1542                    } else {
1543                        Err(
1544                        "EDGE_WEIGHT_SECTION must be specified when EDGE_WEIGHT_TYPE is EXPLICIT"
1545                            .into(),
1546                    )
1547                    }
1548                } else {
1549                    Err(
1550                        "EDGE_WEIGHT_FORMAT must be specified when EDGE_WEIGHT_TYPE is EXPLICIT"
1551                            .into(),
1552                    )
1553                }
1554            }
1555            EdgeWeightType::Euc2d => {
1556                if let Some(NodeCoords::Twod(coords)) = &self.node_coords {
1557                    Ok(from_2d_coords_to_full_matrix(
1558                        coords,
1559                        euiclidean_distance_2d,
1560                    ))
1561                } else {
1562                    Err(
1563                        "NODE_COORD_SECTION must be TWOD_COORDS when EDGE_WEIGHT_TYPE is EUC_2D"
1564                            .into(),
1565                    )
1566                }
1567            }
1568            EdgeWeightType::Euc3d => {
1569                if let Some(NodeCoords::Threed(coords)) = &self.node_coords {
1570                    Ok(from_3d_coords_to_full_matrix(coords, euclidean_distance_3d))
1571                } else {
1572                    Err(
1573                        "NODE_COORD_SECTION must be THREED_COORDS when EDGE_WEIGHT_TYPE is EUC_3D"
1574                            .into(),
1575                    )
1576                }
1577            }
1578            EdgeWeightType::Max2d => {
1579                if let Some(NodeCoords::Twod(coords)) = &self.node_coords {
1580                    Ok(from_2d_coords_to_full_matrix(coords, maximum_distance_2d))
1581                } else {
1582                    Err(
1583                        "NODE_COORD_SECTION must be TWOD_COORDS when EDGE_WEIGHT_TYPE is MAX_2D"
1584                            .into(),
1585                    )
1586                }
1587            }
1588            EdgeWeightType::Max3d => {
1589                if let Some(NodeCoords::Threed(coords)) = &self.node_coords {
1590                    Ok(from_3d_coords_to_full_matrix(coords, maximum_distance_3d))
1591                } else {
1592                    Err(
1593                        "NODE_COORD_SECTION must be THREED_COORDS when EDGE_WEIGHT_TYPE is MAX_3D"
1594                            .into(),
1595                    )
1596                }
1597            }
1598            EdgeWeightType::Man2d => {
1599                if let Some(NodeCoords::Twod(coords)) = &self.node_coords {
1600                    Ok(from_2d_coords_to_full_matrix(coords, manhattan_distance_2d))
1601                } else {
1602                    Err(
1603                        "NODE_COORD_SECTION must be TWOD_COORDS when EDGE_WEIGHT_TYPE is MAN_2D"
1604                            .into(),
1605                    )
1606                }
1607            }
1608            EdgeWeightType::Man3d => {
1609                if let Some(NodeCoords::Threed(coords)) = &self.node_coords {
1610                    Ok(from_3d_coords_to_full_matrix(coords, manhattan_distance_3d))
1611                } else {
1612                    Err(
1613                        "NODE_COORD_SECTION must be THREED_COORDS when EDGE_WEIGHT_TYPE is MAN_3D"
1614                            .into(),
1615                    )
1616                }
1617            }
1618            EdgeWeightType::Ceil2d => {
1619                if let Some(NodeCoords::Twod(coords)) = &self.node_coords {
1620                    Ok(from_2d_coords_to_full_matrix(
1621                        coords,
1622                        ceiling_euclidean_distance_2d,
1623                    ))
1624                } else {
1625                    Err(
1626                        "NODE_COORD_SECTION must be TWOD_COORDS when EDGE_WEIGHT_TYPE is CEIL_2D"
1627                            .into(),
1628                    )
1629                }
1630            }
1631            EdgeWeightType::Geo => {
1632                if let Some(NodeCoords::Twod(coords)) = &self.node_coords {
1633                    Ok(from_2d_coords_to_full_matrix(coords, geographical_distance))
1634                } else {
1635                    Err(
1636                        "NODE_COORD_SECTION must be TWOD_COORDS when EDGE_WEIGHT_TYPE is GEO"
1637                            .into(),
1638                    )
1639                }
1640            }
1641            EdgeWeightType::Att => {
1642                if let Some(NodeCoords::Twod(coords)) = &self.node_coords {
1643                    Ok(from_2d_coords_to_full_matrix(
1644                        coords,
1645                        pseudo_euclidean_distance,
1646                    ))
1647                } else {
1648                    Err(
1649                        "NODE_COORD_SECTION must be TWOD_COORDS when EDGE_WEIGHT_TYPE is ATT"
1650                            .into(),
1651                    )
1652                }
1653            }
1654            EdgeWeightType::Xray1 => {
1655                if let Some(NodeCoords::Threed(coords)) = &self.node_coords {
1656                    Ok(from_3d_coords_to_full_matrix(coords, xray1))
1657                } else {
1658                    Err(
1659                        "NODE_COORD_SECTION must be THREED_COORDS when EDGE_WEIGHT_TYPE is XRAY1"
1660                            .into(),
1661                    )
1662                }
1663            }
1664            EdgeWeightType::Xray2 => {
1665                if let Some(NodeCoords::Threed(coords)) = &self.node_coords {
1666                    Ok(from_3d_coords_to_full_matrix(coords, xray2))
1667                } else {
1668                    Err(
1669                        "NODE_COORD_SECTION must be THREED_COORDS when EDGE_WEIGHT_TYPE is XRAY2"
1670                            .into(),
1671                    )
1672                }
1673            }
1674        }
1675    }
1676}