1use std::collections::HashSet;
2use std::error::Error;
3use std::f64::consts::PI;
4use std::fs;
5use std::mem;
6
7#[derive(Clone, Debug)]
8pub enum InstanceType {
10 Tsp,
12 Atsp,
14 Sop,
16 Hcp,
18 Cvrp,
20 Tours,
22 Other(String),
24}
25
26#[derive(Clone, Copy, Debug)]
27pub enum EdgeWeightType {
29 Explicit,
31 Euc2d,
33 Euc3d,
35 Max2d,
37 Max3d,
39 Man2d,
41 Man3d,
43 Ceil2d,
45 Geo,
47 Att,
49 Xray1,
51 Xray2,
53 Special,
55}
56
57#[derive(Clone, Copy, Debug)]
58pub enum EdgeWeightFormat {
60 Function,
62 FullMatrix,
64 UpperRow,
66 LowerRow,
68 UpperDiagRow,
70 LowerDiagRow,
72 UpperCol,
74 LowerCol,
76 UpperDiagCol,
78 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)]
102pub enum NodeCoords {
104 Twod(Vec<(usize, f64, f64)>),
107 Threed(Vec<(usize, f64, f64, f64)>),
110}
111
112#[derive(Clone, Debug)]
113pub enum EdgeData {
115 EdgeList(Vec<(usize, usize)>),
117 AdjList(Vec<(usize, Vec<usize>)>),
120}
121
122#[derive(Clone, Debug)]
123pub enum DisplayData {
125 CoordDisplay,
127 TwodDisplay(Vec<(usize, f64, f64)>),
130}
131
132#[derive(Clone, Debug)]
133pub struct Instance {
135 pub name: String,
137 pub instance_type: InstanceType,
139 pub comment: String,
141 pub dimension: usize,
145 pub capacity: Option<i32>,
147 pub edge_weight_type: EdgeWeightType,
149 pub edge_weight_format: Option<EdgeWeightFormat>,
151 pub distance: Option<f64>,
153 pub service_time: Option<f64>,
155 pub demand_dimension: Option<usize>,
157 pub node_coords: Option<NodeCoords>,
160 pub depots: Option<Vec<usize>>,
162 pub demands: Option<Vec<(usize, Vec<i32>)>>,
165 pub edge_data: Option<EdgeData>,
167 pub fixed_edges: Option<Vec<(usize, usize)>>,
169 pub display_data: Option<DisplayData>,
171 pub tours: Option<Vec<Vec<usize>>>,
173 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 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 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 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}