pathfinding/matrix.rs
1//! Matrix of an arbitrary type and utilities to rotate, transpose, etc.
2
3use crate::directed::bfs::bfs_reach;
4use crate::directed::dfs::dfs_reach;
5use crate::utils::{constrain, in_direction, move_in_direction, uint_sqrt};
6use deprecate_until::deprecate_until;
7use num_traits::Signed;
8use std::collections::BTreeSet;
9use std::iter::FusedIterator;
10use std::ops::{Deref, DerefMut, Index, IndexMut, Neg, Range};
11use std::slice::{Iter, IterMut};
12use thiserror::Error;
13
14/// Matrix of an arbitrary type. Data are stored consecutively in
15/// memory, by rows. Raw data can be accessed using `as_ref()`
16/// or `as_mut()`.
17///
18/// Coordinates within the matrix are represented as (row, column) tuples
19#[derive(Clone, Debug, Eq, Hash, PartialEq)]
20pub struct Matrix<C> {
21 /// Rows
22 pub rows: usize,
23 /// Columns
24 pub columns: usize,
25 data: Vec<C>,
26}
27
28impl<C: Clone> Matrix<C> {
29 /// Create new matrix with an initial value.
30 ///
31 /// # Panics
32 ///
33 /// This function panics if the number of rows is greater than 0
34 /// and the number of columns is 0. If you need to build a matrix
35 /// column by column, build it row by row and call transposition
36 /// or rotation functions on it.
37 pub fn new(rows: usize, columns: usize, value: C) -> Self {
38 assert!(
39 rows == 0 || columns > 0,
40 "unable to create a matrix with empty rows"
41 );
42 Self {
43 rows,
44 columns,
45 data: vec![value; rows * columns],
46 }
47 }
48
49 /// Create new matrix with each cell's initial value given by a
50 /// function of its position.
51 ///
52 /// # Panics
53 ///
54 /// This function panics if the number of rows is greater than 0
55 /// and the number of columns is 0. If you need to build a matrix
56 /// column by column, build it row by row and call transposition
57 /// or rotation functions on it.
58 pub fn from_fn(rows: usize, columns: usize, cb: impl FnMut((usize, usize)) -> C) -> Self {
59 assert!(
60 rows == 0 || columns > 0,
61 "unable to create a matrix with empty rows"
62 );
63 Self {
64 rows,
65 columns,
66 data: (0..rows)
67 .flat_map(move |row| (0..columns).map(move |column| (row, column)))
68 .map(cb)
69 .collect(),
70 }
71 }
72
73 /// Create new square matrix with initial value.
74 pub fn new_square(size: usize, value: C) -> Self {
75 Self::new(size, size, value)
76 }
77
78 /// Fill with a known value.
79 pub fn fill(&mut self, value: C) {
80 self.data.fill(value);
81 }
82
83 /// Return a copy of a sub-matrix.
84 ///
85 /// # Errors
86 ///
87 /// [`MatrixFormatError::WrongIndex`] if the ranges
88 /// are outside the original matrix.
89 pub fn slice(
90 &self,
91 rows: Range<usize>,
92 columns: Range<usize>,
93 ) -> Result<Self, MatrixFormatError> {
94 if rows.end > self.rows || columns.end > self.columns {
95 return Err(MatrixFormatError::WrongIndex);
96 }
97 let height = rows.end - rows.start;
98 let width = columns.end - columns.start;
99 let mut v = Vec::with_capacity(height * width);
100 for r in rows {
101 v.extend(
102 self.data[r * self.columns + columns.start..r * self.columns + columns.end]
103 .iter()
104 .cloned(),
105 );
106 }
107 Self::from_vec(height, width, v)
108 }
109
110 /// Return a copy of a matrix rotated clock-wise
111 /// a number of times.
112 #[must_use]
113 pub fn rotated_cw(&self, times: usize) -> Self {
114 if self.is_square() {
115 let mut copy = self.clone();
116 copy.rotate_cw(times);
117 copy
118 } else {
119 match times % 4 {
120 0 => self.clone(),
121 1 => {
122 let mut copy = self.transposed();
123 copy.flip_lr();
124 copy
125 }
126 2 => {
127 let mut copy = self.clone();
128 copy.data.reverse();
129 copy
130 }
131 _ => {
132 let mut copy = self.transposed();
133 copy.flip_ud();
134 copy
135 }
136 }
137 }
138 }
139
140 /// Return a copy of a matrix rotated counter-clock-wise
141 /// a number of times.
142 #[must_use]
143 pub fn rotated_ccw(&self, times: usize) -> Self {
144 self.rotated_cw(4 - (times % 4))
145 }
146
147 /// Return a copy of the matrix flipped along the vertical axis.
148 #[must_use]
149 pub fn flipped_lr(&self) -> Self {
150 let mut copy = self.clone();
151 copy.flip_lr();
152 copy
153 }
154
155 /// Return a copy of the matrix flipped along the horizontal axis.
156 #[must_use]
157 pub fn flipped_ud(&self) -> Self {
158 let mut copy = self.clone();
159 copy.flip_ud();
160 copy
161 }
162
163 /// Return a copy of the matrix after transposition.
164 ///
165 /// # Panics
166 ///
167 /// This function will panic if the transposed matrix would end
168 /// up with empty rows.
169 #[must_use]
170 pub fn transposed(&self) -> Self {
171 assert!(
172 self.rows != 0 || self.columns == 0,
173 "this operation would create a matrix with empty rows"
174 );
175 Self {
176 rows: self.columns,
177 columns: self.rows,
178 data: (0..self.columns)
179 .flat_map(|c| (0..self.rows).map(move |r| self.data[r * self.columns + c].clone()))
180 .collect(),
181 }
182 }
183
184 /// Extend the matrix in place by adding one full row.
185 ///
186 /// # Errors
187 ///
188 /// - [`MatrixFormatError::WrongLength`] if the row does not have
189 /// the expected number of elements.
190 /// - [`MatrixFormatError::EmptyRow`] if an empty row is passed.
191 pub fn extend(&mut self, row: &[C]) -> Result<(), MatrixFormatError> {
192 if row.is_empty() {
193 return Err(MatrixFormatError::EmptyRow);
194 }
195 if self.columns != row.len() {
196 return Err(MatrixFormatError::WrongLength);
197 }
198 self.rows += 1;
199 for e in row {
200 self.data.push(e.clone());
201 }
202 Ok(())
203 }
204
205 /// Swap two elements of the matrix.
206 ///
207 /// If `a` equals to `b`, it's guaranteed that elements won't change value.
208 ///
209 /// # Panics
210 ///
211 /// Panics if `a` or `b` are out of bounds.
212 ///
213 /// # Example
214 ///
215 /// ```
216 /// use pathfinding::matrix::*;
217 ///
218 /// let mut matrix = Matrix::square_from_vec(vec![1, 2, 10, 20]).unwrap();
219 /// matrix.swap((0, 0), (0, 1));
220 /// assert_eq!(matrix, Matrix::square_from_vec(vec![2, 1, 10, 20]).unwrap());
221 /// ```
222 pub fn swap(&mut self, a: (usize, usize), b: (usize, usize)) {
223 let (a, b) = (self.idx(a), self.idx(b));
224 self.data.swap(a, b);
225 }
226
227 /// Transform the matrix into another matrix with the same shape
228 /// after applying a transforming function to every elements.
229 pub fn map<O, F>(self, transform: F) -> Matrix<O>
230 where
231 F: FnMut(C) -> O,
232 {
233 Matrix {
234 rows: self.rows,
235 columns: self.columns,
236 data: self.data.into_iter().map(transform).collect(),
237 }
238 }
239}
240
241impl<C: Copy> Matrix<C> {
242 /// Replace a slice of the current matrix with the content of another one.
243 /// Only the relevant cells will be extracted if the slice goes outside the
244 /// original matrix.
245 pub fn set_slice(&mut self, pos: (usize, usize), slice: &Self) {
246 let (row, column) = pos;
247 let height = (self.rows - row).min(slice.rows);
248 let width = (self.columns - column).min(slice.columns);
249 for r in 0..height {
250 self.data[(row + r) * self.columns + column..(row + r) * self.columns + column + width]
251 .copy_from_slice(&slice.data[r * slice.columns..r * slice.columns + width]);
252 }
253 }
254}
255
256impl<C: Clone + Signed> Neg for Matrix<C> {
257 type Output = Self;
258
259 #[must_use]
260 fn neg(self) -> Self {
261 Self {
262 rows: self.rows,
263 columns: self.columns,
264 data: self.data.iter().map(|x| -x.clone()).collect::<Vec<_>>(),
265 }
266 }
267}
268
269impl<C> Matrix<C> {
270 /// Create new matrix from vector values. The first value
271 /// will be assigned to index (0, 0), the second one to index (0, 1),
272 /// and so on.
273 ///
274 /// # Errors
275 ///
276 /// - [`MatrixFormatError::WrongLength`] if the data length does not
277 /// correspond to the announced size
278 /// - [`MatrixFormatError::EmptyRow`] if the matrix would contain
279 /// an empty row
280 pub fn from_vec(
281 rows: usize,
282 columns: usize,
283 values: Vec<C>,
284 ) -> Result<Self, MatrixFormatError> {
285 if rows * columns != values.len() {
286 return Err(MatrixFormatError::WrongLength);
287 }
288 if rows != 0 && columns == 0 {
289 return Err(MatrixFormatError::EmptyRow);
290 }
291 Ok(Self {
292 rows,
293 columns,
294 data: values,
295 })
296 }
297
298 /// Create new square matrix from vector values. The first value
299 /// will be assigned to index (0, 0), the second one to index (0, 1),
300 /// and so on.
301 ///
302 /// # Errors
303 ///
304 /// [`MatrixFormatError::WrongLength`] if the number of values is not a
305 /// square number or if `values` is empty.
306 pub fn square_from_vec(values: Vec<C>) -> Result<Self, MatrixFormatError> {
307 let Some(size) = uint_sqrt(values.len()) else {
308 return Err(MatrixFormatError::WrongLength);
309 };
310 Self::from_vec(size, size, values)
311 }
312
313 /// Create new empty matrix with a predefined number of columns.
314 /// This is useful to gradually build the matrix and extend it
315 /// later using [`extend`](Matrix::extend) and does not require
316 /// a filler element compared to [`Matrix::new`].
317 #[must_use]
318 pub const fn new_empty(columns: usize) -> Self {
319 Self {
320 rows: 0,
321 columns,
322 data: vec![],
323 }
324 }
325
326 /// Check if the matrix is empty.
327 #[must_use]
328 pub const fn is_empty(&self) -> bool {
329 self.rows == 0
330 }
331
332 /// Create a matrix from something convertible to an iterator on rows,
333 /// each row being convertible to an iterator on columns.
334 ///
335 /// # Errors
336 ///
337 /// [`MatrixFormatError::WrongLength`] if length of rows differ or
338 /// the rows are empty.
339 ///
340 /// # Example
341 ///
342 /// ```
343 /// use pathfinding::matrix::*;
344 ///
345 /// let input = "abc\ndef";
346 /// let matrix = Matrix::from_rows(input.lines().map(|l| l.chars()))?;
347 /// assert_eq!(matrix.rows, 2);
348 /// assert_eq!(matrix.columns, 3);
349 /// assert_eq!(matrix[(1, 1)], 'e');
350 /// # Ok::<_, MatrixFormatError>(())
351 /// ```
352 pub fn from_rows<IR, IC>(rows: IR) -> Result<Self, MatrixFormatError>
353 where
354 IR: IntoIterator<Item = IC>,
355 IC: IntoIterator<Item = C>,
356 {
357 let mut rows = rows.into_iter();
358 if let Some(first_row) = rows.next() {
359 let mut data = first_row.into_iter().collect::<Vec<_>>();
360 let number_of_columns = data.len();
361 let mut number_of_rows = 1;
362 for row in rows {
363 number_of_rows += 1;
364 data.extend(row);
365 if number_of_rows * number_of_columns != data.len() {
366 return Err(MatrixFormatError::WrongLength);
367 }
368 }
369 Self::from_vec(number_of_rows, number_of_columns, data)
370 } else {
371 Ok(Self::new_empty(0))
372 }
373 }
374
375 /// Check if a matrix is a square one.
376 #[must_use]
377 pub const fn is_square(&self) -> bool {
378 self.rows == self.columns
379 }
380
381 /// Index in raw data of a given position.
382 ///
383 /// # Safety
384 ///
385 /// This function returns a meaningless result if the
386 /// coordinates do not designate a cell.
387 #[must_use]
388 pub const unsafe fn idx_unchecked(&self, i: (usize, usize)) -> usize {
389 i.0 * self.columns + i.1
390 }
391
392 /// Index in raw data of a given position.
393 ///
394 /// # Panics
395 ///
396 /// This function panics if the coordinates do not designate a cell.
397 #[must_use]
398 pub fn idx(&self, i: (usize, usize)) -> usize {
399 assert!(
400 i.0 < self.rows,
401 "trying to access row {} (max {})",
402 i.0,
403 self.rows - 1
404 );
405 assert!(
406 i.1 < self.columns,
407 "trying to access column {} (max {})",
408 i.1,
409 self.columns - 1
410 );
411 unsafe { self.idx_unchecked(i) }
412 }
413
414 /// Constrain a wrapped-around index so that it falls inside the
415 /// matrix.
416 ///
417 /// # Examples
418 ///
419 /// ```rust
420 /// use pathfinding::matrix::Matrix;
421 ///
422 /// let matrix = Matrix::new(3, 5, 0);
423 /// assert_eq!(matrix.constrain((1, 2)), (1, 2));
424 /// assert_eq!(matrix.constrain((10, -53)), (1, 2));
425 /// ```
426 #[must_use]
427 pub const fn constrain(&self, (row, column): (isize, isize)) -> (usize, usize) {
428 (constrain(row, self.rows), constrain(column, self.columns))
429 }
430
431 /// Check if the coordinates designate a matrix cell.
432 #[must_use]
433 pub const fn within_bounds(&self, (row, column): (usize, usize)) -> bool {
434 row < self.rows && column < self.columns
435 }
436
437 /// Access an element if the coordinates designate a matrix cell.
438 #[must_use]
439 pub fn get(&self, i: (usize, usize)) -> Option<&C> {
440 self.within_bounds(i)
441 .then(|| &self.data[unsafe { self.idx_unchecked(i) }])
442 }
443
444 /// Mutably access an element if the coordinates designate a matrix cell.
445 #[must_use]
446 pub fn get_mut(&mut self, i: (usize, usize)) -> Option<&mut C> {
447 self.within_bounds(i).then(|| {
448 let idx = unsafe { self.idx_unchecked(i) };
449 &mut self.data[idx]
450 })
451 }
452
453 /// Flip the matrix around the vertical axis.
454 pub fn flip_lr(&mut self) {
455 for r in 0..self.rows {
456 self.data[r * self.columns..(r + 1) * self.columns].reverse();
457 }
458 }
459
460 /// Flip the matrix around the horizontal axis.
461 pub fn flip_ud(&mut self) {
462 for r in 0..self.rows / 2 {
463 for c in 0..self.columns {
464 self.data
465 .swap(r * self.columns + c, (self.rows - 1 - r) * self.columns + c);
466 }
467 }
468 }
469
470 /// Rotate a square matrix clock-wise a number of times.
471 ///
472 /// # Panics
473 ///
474 /// This function panics if the matrix is not square.
475 pub fn rotate_cw(&mut self, times: usize) {
476 assert!(
477 self.rows == self.columns,
478 "attempt to rotate a non-square matrix"
479 );
480 match times % 4 {
481 0 => (),
482 2 => self.data.reverse(),
483 n => {
484 for r in 0..self.rows / 2 {
485 for c in 0..(self.columns + 1) / 2 {
486 // i1 … i2
487 // … … …
488 // i4 … i3
489 let i1 = r * self.columns + c;
490 let i2 = c * self.columns + self.columns - 1 - r;
491 let i3 = (self.rows - 1 - r) * self.columns + self.columns - 1 - c;
492 let i4 = (self.rows - 1 - c) * self.columns + r;
493 if n == 1 {
494 // i1 … i2 i4 … i1
495 // … … … => … … …
496 // i4 … i3 i3 … i2
497 self.data.swap(i1, i2);
498 self.data.swap(i1, i4);
499 self.data.swap(i3, i4);
500 } else {
501 // i1 … i2 i2 … i3
502 // … … … => … … …
503 // i4 … i3 i1 … i4
504 self.data.swap(i3, i4);
505 self.data.swap(i1, i4);
506 self.data.swap(i1, i2);
507 }
508 }
509 }
510 }
511 }
512 }
513
514 /// Rotate a square matrix counter-clock-wise a number of times.
515 ///
516 /// # Panics
517 ///
518 /// This function panics if the matrix is not square.
519 pub fn rotate_ccw(&mut self, times: usize) {
520 self.rotate_cw(4 - (times % 4));
521 }
522
523 /// Return an iterator on neighbours of a given matrix cell, with or
524 /// without considering diagonals. The neighbours list is determined
525 /// at the time of calling this method and will not change even if new
526 /// rows are added between the method call and the iterator consumption.
527 ///
528 /// This function returns an empty iterator if the reference position does
529 /// not correspond to an existing matrix element.
530 pub fn neighbours(
531 &self,
532 (r, c): (usize, usize),
533 diagonals: bool,
534 ) -> impl Iterator<Item = (usize, usize)> {
535 let (row_range, col_range) = if r < self.rows && c < self.columns {
536 (
537 r.saturating_sub(1)..(self.rows).min(r + 2),
538 c.saturating_sub(1)..(self.columns).min(c + 2),
539 )
540 } else {
541 (0..0, 0..0)
542 };
543 row_range
544 .flat_map(move |r| col_range.clone().map(move |c| (r, c)))
545 .filter(move |&(rr, cc)| (rr != r || cc != c) && (diagonals || rr == r || cc == c))
546 }
547
548 /// Return the next cells in a given direction starting from
549 /// a given cell. Any direction (including with values greater than 1) can be
550 /// given. `(0, 0)` is not a valid direction.
551 ///
552 /// # Examples
553 ///
554 /// Starting from square `(1, 1)` in a 8×8 chessboard, move like a knight
555 /// by steps of two rows down and one column right:
556 ///
557 /// ```
558 /// use pathfinding::prelude::Matrix;
559 /// let m = Matrix::new_square(8, '.');
560 /// assert_eq!(m.move_in_direction((1, 1), (2, 1)), Some((3, 2)));
561 /// ```
562 #[must_use]
563 pub fn move_in_direction(
564 &self,
565 start: (usize, usize),
566 direction: (isize, isize),
567 ) -> Option<(usize, usize)> {
568 move_in_direction(start, direction, (self.rows, self.columns))
569 }
570
571 /// Return an iterator of cells in a given direction starting from
572 /// a given cell. Any direction (including with values greater than 1) can be
573 /// given. The starting cell is not included in the results.
574 ///
575 /// # Examples
576 ///
577 /// Starting from square `(1, 1)` in a 8×8 chessboard, move like a knight
578 /// by steps of two rows down and one column right:
579 ///
580 /// ```
581 /// use pathfinding::prelude::Matrix;
582 /// let m = Matrix::new_square(8, '.');
583 /// assert_eq!(m.in_direction((1, 1), (2, 1)).collect::<Vec<_>>(),
584 /// vec![(3, 2), (5, 3), (7, 4)]);
585 /// ```
586 ///
587 /// Starting from square `(3, 2)` in the same chessboard, move diagonally in
588 /// the North-West direction:
589 ///
590 /// ```
591 /// use pathfinding::prelude::{Matrix, directions};
592 /// let m = Matrix::new_square(8, '.');
593 /// assert_eq!(m.in_direction((3, 2), directions::NW).collect::<Vec<_>>(),
594 /// vec![(2, 1), (1, 0)]);
595 /// ```
596 pub fn in_direction(
597 &self,
598 start: (usize, usize),
599 direction: (isize, isize),
600 ) -> impl Iterator<Item = (usize, usize)> {
601 in_direction(start, direction, (self.rows, self.columns))
602 }
603
604 /// Return an iterator on rows of the matrix.
605 #[must_use]
606 pub fn iter(&self) -> RowIterator<'_, C> {
607 self.into_iter()
608 }
609
610 /// Return an iterator on content of columns of the matrix.
611 ///
612 /// This operation is more costly than using a row iterator, as it
613 /// requires building vectors of column data which are not stored
614 /// consecutively in memory.
615 #[must_use]
616 pub const fn column_iter(&self) -> ColumnIterator<'_, C> {
617 ColumnIterator {
618 matrix: self,
619 column: 0,
620 }
621 }
622
623 /// Return an iterator on the Matrix indices, first row first. The values are
624 /// computed when this method is called and will not change even if new rows are
625 /// added before the iterator is consumed.
626 #[deprecate_until(
627 note = "use the .keys() method instead",
628 since = "4.1.0",
629 remove = "> 4.x"
630 )]
631 pub fn indices(&self) -> impl Iterator<Item = (usize, usize)> {
632 self.keys()
633 }
634
635 /// Return an iterator on the Matrix indices, first row first. The values are
636 /// computed when this method is called and will not change even if new rows are
637 /// added before the iterator is consumed.
638 pub fn keys(&self) -> impl Iterator<Item = (usize, usize)> {
639 let columns = self.columns;
640 (0..self.rows).flat_map(move |r| (0..columns).map(move |c| (r, c)))
641 }
642
643 /// Return an iterator on values, first row first.
644 pub fn values(&self) -> Iter<C> {
645 self.data.iter()
646 }
647
648 /// Return a mutable iterator on values, first row first.
649 pub fn values_mut(&mut self) -> IterMut<C> {
650 self.data.iter_mut()
651 }
652
653 /// Return an iterator on the Matrix coordinates and values, first row first.
654 pub fn items(&self) -> impl Iterator<Item = ((usize, usize), &C)> {
655 self.keys().zip(self.values())
656 }
657
658 /// Return an iterator on the Matrix coordinates and mutable values,
659 /// first row first.
660 pub fn items_mut(&mut self) -> impl Iterator<Item = ((usize, usize), &mut C)> {
661 self.keys().zip(self.values_mut())
662 }
663
664 /// Return a set of the indices reachable from a candidate starting point
665 /// and for which the given predicate is valid. This can be used for example
666 /// to implement a flood-filling algorithm. Since the indices are collected
667 /// into a collection, they can later be used without keeping a reference on the
668 /// matrix itself, e.g., to modify the matrix.
669 ///
670 /// The search is done using a breadth first search (BFS) algorithm.
671 ///
672 /// # See also
673 ///
674 /// The [`dfs_reachable()`](`Self::dfs_reachable`) method performs a DFS search instead.
675 pub fn bfs_reachable<P>(
676 &self,
677 start: (usize, usize),
678 diagonals: bool,
679 mut predicate: P,
680 ) -> BTreeSet<(usize, usize)>
681 where
682 P: FnMut((usize, usize)) -> bool,
683 {
684 bfs_reach(start, |&n| {
685 self.neighbours(n, diagonals)
686 .filter(|&n| predicate(n))
687 .collect::<Vec<_>>()
688 })
689 .collect()
690 }
691
692 /// Return a set of the indices reachable from a candidate starting point
693 /// and for which the given predicate is valid. This can be used for example
694 /// to implement a flood-filling algorithm. Since the indices are collected
695 /// into a vector, they can later be used without keeping a reference on the
696 /// matrix itself, e.g., to modify the matrix.
697 ///
698 /// The search is done using a depth first search (DFS) algorithm.
699 ///
700 /// # See also
701 ///
702 /// The [`bfs_reachable()`](`Self::bfs_reachable`) method performs a BFS search instead.
703 pub fn dfs_reachable<P>(
704 &self,
705 start: (usize, usize),
706 diagonals: bool,
707 mut predicate: P,
708 ) -> BTreeSet<(usize, usize)>
709 where
710 P: FnMut((usize, usize)) -> bool,
711 {
712 dfs_reach(start, |&n| {
713 self.neighbours(n, diagonals)
714 .filter(|&n| predicate(n))
715 .collect::<Vec<_>>()
716 })
717 .collect()
718 }
719
720 /// Transposes any matrix in place.
721 fn transpose_in_place_non_square(&mut self) {
722 let m = self.columns;
723 let n = self.rows;
724
725 // Adjusted cycle length excluding the fixed point at 0, 0
726 let mn1 = m * n - 1;
727
728 // Scratch array for recording visited locations
729 let mut visited = vec![0u8; (m * n + 7).div_ceil(8)];
730
731 for s in 1..self.data.len() {
732 if visited[s / 8] & (1 << (s % 8)) != 0 {
733 continue;
734 }
735
736 // Identified an unvisited start point in a cycle
737 let mut x = s;
738 loop {
739 // Calculate the next position 'x' for the element to be moved.
740 // If it is in the last position, then there is nothing to do.
741 // Otherwise, calculate the new position using the formula (n * x) % mn1.
742 // This will ensure we visit all positions in a way that eventually visits
743 // and transposes every element, without exceeding the matrix's bounds.
744 if x != mn1 {
745 x = (n * x) % mn1;
746 }
747 self.data.swap(x, s);
748 visited[x / 8] |= 1 << (x % 8);
749
750 // Stop when we're back at the start of the cycle
751 if x == s {
752 break;
753 }
754 }
755 }
756
757 // The matrix is now transposed, so we can swap the rows and columns
758 self.rows = m;
759 self.columns = n;
760 }
761
762 /// Transpose a matrix in place.
763 ///
764 /// For more information refer to
765 /// [In-place matrix transposition](https://en.wikipedia.org/wiki/In-place_matrix_transposition).
766 pub fn transpose(&mut self) {
767 // Transposing square matrices in place is significantly more efficient than non-
768 // square matrices, so we handle that special case separately.
769 if self.rows == self.columns {
770 for r in 0..self.rows {
771 for c in r + 1..self.columns {
772 self.data.swap(r * self.columns + c, c * self.columns + r);
773 }
774 }
775 } else {
776 self.transpose_in_place_non_square();
777 }
778 }
779}
780
781impl<C> Index<(usize, usize)> for Matrix<C> {
782 type Output = C;
783
784 #[must_use]
785 fn index(&self, index: (usize, usize)) -> &C {
786 &self.data[self.idx(index)]
787 }
788}
789
790impl<C> Index<&(usize, usize)> for Matrix<C> {
791 type Output = C;
792
793 #[must_use]
794 fn index(&self, index: &(usize, usize)) -> &C {
795 &self[*index]
796 }
797}
798
799impl<C> IndexMut<(usize, usize)> for Matrix<C> {
800 fn index_mut(&mut self, index: (usize, usize)) -> &mut C {
801 let i = self.idx(index);
802 &mut self.data[i]
803 }
804}
805
806impl<C> IndexMut<&(usize, usize)> for Matrix<C> {
807 fn index_mut(&mut self, index: &(usize, usize)) -> &mut C {
808 &mut self[*index]
809 }
810}
811
812impl<C> Deref for Matrix<C> {
813 type Target = [C];
814
815 #[must_use]
816 fn deref(&self) -> &[C] {
817 &self.data
818 }
819}
820
821impl<C> DerefMut for Matrix<C> {
822 fn deref_mut(&mut self) -> &mut [C] {
823 &mut self.data
824 }
825}
826
827impl<C, IC> FromIterator<IC> for Matrix<C>
828where
829 IC: IntoIterator<Item = C>,
830{
831 fn from_iter<T: IntoIterator<Item = IC>>(iter: T) -> Self {
832 match Self::from_rows(iter) {
833 Ok(matrix) => matrix,
834 Err(e) => panic!("{e}"),
835 }
836 }
837}
838
839/// The matrix! macro allows the declaration of a Matrix from static data.
840/// All rows must have the same number of columns. The data will be copied
841/// into the matrix. There exist two forms:
842///
843/// - `matrix![(row1, row2, …, rowN)]`, each row being an array
844/// - `matrix![r1c1, r1c2, …, r1cN; r2c1, …,r2cN; …; rNc1, …, rNcN]`
845/// - `matrix![]` creates an empty matrix with a column size of 0
846///
847/// # Panics
848///
849/// This macro panics if the rows have an inconsistent number of columns.
850///
851/// # Example
852///
853/// ```
854/// use pathfinding::matrix;
855///
856/// let m1 = matrix![[10, 20, 30], [40, 50, 60]];
857/// assert_eq!(m1.columns, 3);
858/// assert_eq!(m1.rows, 2);
859///
860/// let m2 = matrix![10, 20, 30; 40, 50, 60];
861/// assert_eq!(m1, m2);
862/// ```
863#[macro_export]
864macro_rules! matrix {
865 () => {
866 pathfinding::matrix::Matrix::new_empty(0)
867 };
868 ($a:expr $(, $b: expr)*$(,)?) => {{
869 let mut m = pathfinding::matrix::Matrix::new_empty($a.len());
870 m.extend(&$a).unwrap();
871 $(
872 match m.extend(&$b) {
873 Ok(row) => row,
874 Err(_) => panic!("all rows must have the same width"),
875 }
876 )*
877 m
878 }};
879 ($($($a:expr),+$(,)?);+$(;)?) => {
880 matrix![$([$($a),+]),+]
881 };
882}
883
884/// Format error encountered while attempting to build a Matrix.
885#[derive(Debug, Error)]
886pub enum MatrixFormatError {
887 /// Attempt to build a matrix containing an empty row
888 #[error("matrix rows cannot be empty")]
889 EmptyRow,
890 /// Attempt to access elements not inside the matrix
891 #[error("index does not point to data inside the matrix")]
892 WrongIndex,
893 /// Attempt to build a matrix or a row from data with the wrong length
894 #[error("provided data does not correspond to the expected length")]
895 WrongLength,
896}
897
898/// Row iterator returned by `iter()` on a matrix.
899pub struct RowIterator<'a, C> {
900 matrix: &'a Matrix<C>,
901 row: usize,
902}
903
904impl<'a, C> Iterator for RowIterator<'a, C> {
905 type Item = &'a [C];
906
907 fn next(&mut self) -> Option<Self::Item> {
908 (self.row < self.matrix.rows).then(|| {
909 self.row += 1;
910 &self.matrix.data[(self.row - 1) * self.matrix.columns..self.row * self.matrix.columns]
911 })
912 }
913}
914
915impl<C> DoubleEndedIterator for RowIterator<'_, C> {
916 fn next_back(&mut self) -> Option<Self::Item> {
917 (self.row < self.matrix.rows).then(|| {
918 let row = self.matrix.rows - self.row;
919 self.row += 1;
920 &self.matrix.data[(row - 1) * self.matrix.columns..row * self.matrix.columns]
921 })
922 }
923}
924
925impl<C> FusedIterator for RowIterator<'_, C> {}
926
927impl<'a, C> IntoIterator for &'a Matrix<C> {
928 type IntoIter = RowIterator<'a, C>;
929 type Item = &'a [C];
930
931 #[must_use]
932 fn into_iter(self) -> RowIterator<'a, C> {
933 RowIterator {
934 matrix: self,
935 row: 0,
936 }
937 }
938}
939
940/// Column iterator returned by `column_iter()` on a matrix.
941pub struct ColumnIterator<'a, C> {
942 matrix: &'a Matrix<C>,
943 column: usize,
944}
945
946impl<'a, C> Iterator for ColumnIterator<'a, C> {
947 type Item = Vec<&'a C>;
948
949 fn next(&mut self) -> Option<Self::Item> {
950 (self.column < self.matrix.columns).then(|| {
951 self.column += 1;
952 (0..self.matrix.rows)
953 .map(|r| &self.matrix[(r, self.column - 1)])
954 .collect()
955 })
956 }
957}
958
959impl<C> DoubleEndedIterator for ColumnIterator<'_, C> {
960 fn next_back(&mut self) -> Option<Self::Item> {
961 (self.column < self.matrix.columns).then(|| {
962 self.column += 1;
963 let column = self.matrix.columns - self.column;
964 (0..self.matrix.rows)
965 .map(|r| &self.matrix[(r, column)])
966 .collect()
967 })
968 }
969}
970
971impl<C> FusedIterator for ColumnIterator<'_, C> {}
972
973/// Directions usable for [`Matrix::in_direction()`] second argument.
974pub mod directions {
975 /// East
976 pub const E: (isize, isize) = (0, 1);
977
978 /// South
979 pub const S: (isize, isize) = (1, 0);
980
981 /// West
982 pub const W: (isize, isize) = (0, -1);
983
984 /// North
985 pub const N: (isize, isize) = (-1, 0);
986
987 /// North-East
988 pub const NE: (isize, isize) = (-1, 1);
989
990 /// South-East
991 pub const SE: (isize, isize) = (1, 1);
992
993 /// North-West
994 pub const NW: (isize, isize) = (-1, -1);
995
996 /// South-West
997 pub const SW: (isize, isize) = (1, -1);
998
999 /// Four main directions
1000 pub const DIRECTIONS_4: [(isize, isize); 4] = [E, S, W, N];
1001
1002 /// Eight main directions with diagonals
1003 pub const DIRECTIONS_8: [(isize, isize); 8] = [NE, E, SE, S, SW, W, NW, N];
1004}