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}