floyd_warshall/matrices.rs
1use std::fmt;
2use std::fmt::Debug;
3
4/// This represents a sequence of nodes. The length is also saved, and when ```exists = false```, this means "there is no path".
5#[derive(Clone, Debug)]
6pub struct Path<T> {
7 v: Vec<T>,
8 len: usize,
9 exists: bool,
10}
11
12impl<T> Path<T> {
13 pub(crate) fn set_vector(&mut self, t: Vec<T>) {
14 self.v = t
15 }
16
17 /// Returns the intermediate nodes on this path as a slice.
18 pub fn get_slice<'a>(&'a self) -> &'a [T] {
19 &self.v
20 }
21
22 /// Returns an iterator of the intermediat enodes on this path.
23 pub fn iter<'a>(&'a self) -> impl DoubleEndedIterator<Item = &'a T> {
24 self.v.iter()
25 }
26
27 /// Returns the length of this path.
28 pub fn len(&self) -> usize {
29 assert!(self.exists);
30 self.len
31 }
32
33 /// Updates the length of this path. Also removes the "there is not path here"-flag.
34 pub(crate) fn set_len(&mut self, v: usize) {
35 self.len = v;
36 self.exists = true;
37 }
38
39 /// Has this path finite length?
40 pub fn exists(&self) -> bool {
41 self.exists
42 }
43}
44
45impl<T> AsRef<Vec<T>> for Path<T> {
46 fn as_ref(&self) -> &Vec<T> {
47 &self.v
48 }
49}
50
51impl<T> Default for Path<T> {
52 fn default() -> Self {
53 use std::usize::MAX;
54 Path {
55 v: Vec::new(),
56 len: MAX,
57 exists: false,
58 }
59 }
60}
61
62/// This matrix is a solution to the APSP problem, calculated by the Floyd-Warshall algorithm.
63/// It contains the intermediate nodes on the shortest path between every two nodes.
64#[derive(Debug)]
65pub struct PathMatrix<T> {
66 m: Box<[Path<T>]>,
67 n: usize,
68}
69
70impl<T> PathMatrix<T> {
71 /// Creates a new ```PathMatrix``` with the given dimension (n * n), where no paths were found yet.
72 /// That means, no nodes are yet connected in this matrix.
73 pub fn new(n: usize) -> PathMatrix<T> {
74 let mut m = vec![];
75 let n_elems = 1 + n * (n - 1) / 2;
76
77 for _ in 0..n_elems {
78 m.push(Path::default());
79 }
80
81 let m = m.into();
82
83 PathMatrix { m, n }
84 }
85
86 /// This method computes the "inner index" into the ```Vec``` by using the given X-Y-coordinates into the matrix.
87 fn idx(&self, mut i: usize, mut j: usize) -> usize {
88 // Because we're only supporting undirected graphs and we only fill one half of the matrix,
89 // we can swap the two indices, so that i <= j.
90 if i > j {
91 ::std::mem::swap(&mut i, &mut j);
92 }
93 assert!(i <= j);
94
95 if i == j {
96 0
97 } else {
98 // i + self.n * j // This is for the old n x n matrix.
99 // j + k + i
100 if j < 3 {
101 j + i
102 } else {
103 let k = j - 1;
104 self.idx(0, j - 1) + k + i
105 }
106 }
107 }
108
109 /// This method returns the value at the given position.
110 pub fn get_path_len(&self, i: usize, j: usize) -> usize {
111 let idx = self.idx(i, j);
112 self.m[idx].len()
113 }
114
115 /// This method returns the shortest path possible between i and i.
116 pub fn get_path(&self, i: usize, j: usize) -> &Path<T> {
117 let idx = self.idx(i, j);
118 &self.m[idx]
119 }
120
121 /// This method returns the shortest path possible between i and i as an iterator.
122 pub fn get_path_iter<'a>(
123 &'a self,
124 i: usize,
125 j: usize,
126 ) -> impl DoubleEndedIterator<Item = &'a T> {
127 let idx = self.idx(i, j);
128 self.m[idx].iter()
129 }
130
131 /// If the matrix contains a path between i and j (which means, it has a set length), this returns true.
132 pub fn does_path_exist(&self, i: usize, j: usize) -> bool {
133 let idx = self.idx(i, j);
134 self.m[idx].exists()
135 }
136
137 /// Returns a mutable reference to the path object for the two given nodes.
138 pub(crate) fn get_path_mut(&mut self, i: usize, j: usize) -> &mut Path<T> {
139 let idx = self.idx(i, j);
140 &mut self.m[idx]
141 }
142
143 /// This method updates the value at the given position.
144 pub fn set_path_len(&mut self, i: usize, j: usize, v: usize) {
145 let idx = self.idx(i, j);
146 self.m[idx].set_len(v);
147 }
148}
149
150// impl<T> Debug for PathMatrix<T>
151// where
152// T: Debug,
153// {
154// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
155// use std::result::Result;
156
157// for j in 0..self.n {
158// let from = j * self.n;
159// let to = j * self.n + j + 1;
160// writeln!(f, "{:?}", &self.m[from..to])?
161// }
162
163// Result::Ok(())
164// }
165// }
166
167// /// This matrix is a solution to the APSP problem, calculated by the Floyd-Warshall algorithm. It contains the length of the shortest path for every pair of nodes in a given graph.
168// pub struct DistanceMatrix {
169// m: Box<[usize]>,
170// n: usize,
171// }
172
173// impl DistanceMatrix {
174// /// Creates a new ```DistanceMatrix``` with the given dimension (n * n).
175// pub(crate) fn new(n: usize) -> DistanceMatrix {
176// use std::usize::MAX;
177// let m = vec![MAX; n * n].into();
178// DistanceMatrix { m, n }
179// }
180
181// /// This method computes the "inner index" into the ```Vec``` by using the given X-Y-coordinates into the matrix.
182// fn idx(&self, mut i: usize, mut j: usize) -> usize {
183// // We only fill one half of the matrix.
184// if i > j {
185// ::std::mem::swap(&mut i, &mut j);
186// }
187// assert!(i <= j);
188
189// i + self.n * j
190// }
191
192// /// This method returns the value at the given position.
193// pub fn get(&self, i: usize, j: usize) -> usize {
194// let idx = self.idx(i, j);
195// self.m[idx]
196// }
197
198// /// This method updates the value at the given position.
199// pub fn set(&mut self, i: usize, j: usize, v: usize) {
200// let idx = self.idx(i, j);
201// self.m[idx] = v;
202// }
203// }
204
205// impl fmt::Debug for DistanceMatrix {
206// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
207// use std::result::Result;
208
209// for j in 0..self.n {
210// let from = j * self.n;
211// let to = j * self.n + j + 1;
212// writeln!(f, "{:?}", &self.m[from..to])?
213// }
214
215// Result::Ok(())
216// }
217// }