vector_victor/
lib.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
5extern crate core;
6
7use index::MatrixIndex;
8use itertools::Itertools;
9use num_traits::{Bounded, One, Zero};
10use std::cmp::min;
11use std::fmt::Debug;
12use std::iter::{zip, Flatten};
13use std::ops::{Index, IndexMut};
14
15pub mod decompose;
16pub mod index;
17mod math;
18mod ops;
19
20mod swizzle;
21mod util;
22
23/** A 2D array of values which can be operated upon.
24
25Matrices have a fixed size known at compile time */
26#[derive(Debug, Copy, Clone, PartialEq)]
27pub struct Matrix<T, const M: usize, const N: usize>
28where
29    T: Copy,
30{
31    data: [[T; N]; M], // Row-Major order
32}
33
34/// An alias for a [Matrix] with a single column
35pub type Vector<T, const N: usize> = Matrix<T, N, 1>;
36
37// CONSTRUCTORS
38
39// Default
40impl<T: Copy + Default, const M: usize, const N: usize> Default for Matrix<T, M, N> {
41    fn default() -> Self {
42        Matrix::fill(T::default())
43    }
44}
45
46// Zero
47impl<T: Copy + Zero, const M: usize, const N: usize> Zero for Matrix<T, M, N> {
48    fn zero() -> Self {
49        Matrix::fill(T::zero())
50    }
51
52    fn is_zero(&self) -> bool {
53        self.elements().all(|e| e.is_zero())
54    }
55}
56
57// One
58impl<T: Copy + One, const M: usize, const N: usize> One for Matrix<T, M, N> {
59    fn one() -> Self {
60        Matrix::fill(T::one())
61    }
62}
63
64// min_value and max_value
65// LowerBounded and UpperBounded are automatically implemented from this
66impl<T: Copy + Bounded, const N: usize, const M: usize> Bounded for Matrix<T, N, M> {
67    fn min_value() -> Self {
68        Self::fill(T::min_value())
69    }
70
71    fn max_value() -> Self {
72        Self::fill(T::max_value())
73    }
74}
75
76// Identity
77impl<T: Copy + Zero + One, const N: usize> Matrix<T, N, N> {
78    /** Create an identity matrix, a square matrix where the diagonals are 1 and
79    all other elements are 0.
80
81    for example,
82
83    $bbI = \[\[1,0,0],\[0,1,0],\[0,0,1]]$
84
85    Matrix multiplication between a matrix and the identity matrix always results in itself
86
87    $bbA xx bbI = bbA$
88
89    # Examples
90    ```
91    # use vector_victor::Matrix;
92    let i = Matrix::<i32,3,3>::identity();
93    assert_eq!(i, Matrix::mat([[1, 0, 0],
94                               [0, 1, 0],
95                               [0, 0, 1]]))
96    ```
97
98    Note that the identity only exists for matrices that are square, so this doesnt work:
99    ```compile_fail
100    # use vector_victor::Matrix;
101    let i = Matrix::<i32,4,2>::identity();
102    ``` */
103    #[must_use]
104    pub fn identity() -> Self {
105        let mut result = Self::zero();
106        for i in 0..N {
107            result[(i, i)] = T::one();
108        }
109        return result;
110    }
111}
112
113// Matrix constructors
114impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> {
115    /** Generate a new matrix from a 2D Array
116
117    # Arguments
118
119    * `data`: A 2D array of elements to copy into the new matrix
120
121    # Examples
122
123    ```
124    # use vector_victor::Matrix;
125    let a = Matrix::mat([[1,2,3,4];4]);
126    ``` */
127    #[must_use]
128    pub fn mat(data: [[T; N]; M]) -> Self {
129        assert!(M > 0, "Matrix must have at least 1 row");
130        assert!(N > 0, "Matrix must have at least 1 column");
131        Matrix::<T, M, N> { data }
132    }
133
134    /** Generate a new matrix from a single scalar
135
136    # Arguments
137
138    * `scalar`: Scalar value to copy into the new matrix.
139
140    # Examples
141
142    ```
143    # use vector_victor::Matrix;
144    // these are equivalent
145    assert_eq!(Matrix::<i32,4,4>::fill(5), Matrix::mat([[5;4];4]))
146    ``` */
147    #[must_use]
148    pub fn fill(scalar: T) -> Matrix<T, M, N> {
149        assert!(M > 0, "Matrix must have at least 1 row");
150        assert!(N > 0, "Matrix must have at least 1 column");
151        Matrix::<T, M, N> {
152            data: [[scalar; N]; M],
153        }
154    }
155
156    /** Create a matrix from an iterator of vectors
157
158    # Arguments
159
160    * `iter`: iterator of vectors to copy into rows
161
162    # Examples
163
164    The following is another way of performing [`Matrix::transpose()`]
165    ```
166    # use vector_victor::Matrix;
167    let my_matrix = Matrix::mat([[1, 2, 3],
168                                 [4, 5, 6]]);
169
170    let transpose : Matrix<_,3,2>= Matrix::from_rows(my_matrix.cols());
171
172    assert_eq!(transpose, Matrix::mat([[1, 4],
173                                       [2, 5],
174                                       [3, 6]]))
175    ``` */
176    #[must_use]
177    pub fn from_rows<I>(iter: I) -> Self
178    where
179        I: IntoIterator<Item = Vector<T, N>>,
180        Self: Default,
181    {
182        let mut result = Self::default();
183        for (m, row) in iter.into_iter().enumerate().take(M) {
184            result.set_row(m, &row)
185        }
186        result
187    }
188
189    /** Create a matrix from an iterator of vectors
190
191    # Arguments
192
193    * `iter`: iterator of vectors to copy into columns
194
195    # Examples
196
197    The following is another way of performing [`Matrix::transpose()`]
198    ```
199    # use vector_victor::Matrix;
200    let my_matrix = Matrix::mat([[1, 2, 3],
201                                 [4, 5, 6]]);
202
203    let transpose : Matrix<_,3,2>= Matrix::from_cols(my_matrix.rows());
204
205    assert_eq!(transpose, Matrix::mat([[1, 4],
206                                       [2, 5],
207                                       [3, 6]]))
208    ``` */
209    #[must_use]
210    pub fn from_cols<I>(iter: I) -> Self
211    where
212        I: IntoIterator<Item = Vector<T, M>>,
213        Self: Default,
214    {
215        let mut result = Self::default();
216        for (n, col) in iter.into_iter().enumerate().take(N) {
217            result.set_col(n, &col)
218        }
219        result
220    }
221}
222
223// Vector constructor
224impl<T: Copy, const N: usize> Vector<T, N> {
225    /** Create a vector from a 1D array.
226    Note that vectors are always column vectors unless explicitly instantiated as row vectors
227
228    # Examples
229    ```
230    # use vector_victor::{Matrix, Vector};
231    // these are equivalent
232    assert_eq!(Vector::vec([1,2,3,4]), Matrix::mat([[1],[2],[3],[4]]));
233    ``` */
234    pub fn vec(data: [T; N]) -> Self {
235        assert!(N > 0, "Vector must have at least 1 element");
236        return Vector::<T, N> {
237            data: data.map(|e| [e]),
238        };
239    }
240}
241
242// ACCESSORS AND MUTATORS
243impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> {
244    /** Returns an iterator over the elements of the matrix in row-major order.
245
246    This is identical to the behavior of [`IntoIterator`](#associatedtype.IntoIter)
247
248    # Examples
249    ```
250    # use vector_victor::Matrix;
251    let my_matrix = Matrix::mat([[1, 2],
252                                 [3, 4]]);
253
254    itertools::assert_equal(my_matrix.elements(), [1,2,3,4].iter())
255    ``` */
256    #[must_use]
257    pub fn elements<'s>(&'s self) -> impl Iterator<Item = &'s T> + 's {
258        self.data.iter().flatten()
259    }
260
261    /** Returns a mutable iterator over the elements of the matrix in row-major order.
262
263    # Examples
264    ```
265    # use vector_victor::Matrix;
266    let mut my_matrix = Matrix::mat([[1, 2],
267                                     [3, 4]]);
268
269    for elem in my_matrix.elements_mut() {*elem += 2;}
270    itertools::assert_equal(my_matrix.elements(), [3,4,5,6].iter())
271    ``` */
272    #[must_use]
273    pub fn elements_mut<'s>(&'s mut self) -> impl Iterator<Item = &'s mut T> + 's {
274        self.data.iter_mut().flatten()
275    }
276
277    /** returns an iterator over the elements along the diagonal of a matrix
278
279    # Examples
280    ```
281    # use vector_victor::Matrix;
282    let my_matrix = Matrix::mat([[1, 2, 3],
283                                 [4, 5, 6],
284                                 [7, 8, 9],
285                                 [10,11,12]]);
286
287    itertools::assert_equal(my_matrix.diagonals(), [1,5,9].iter())
288    ``` */
289    #[must_use]
290    pub fn diagonals<'s>(&'s self) -> impl Iterator<Item = &'s T> + 's {
291        (0..min(N, M)).map(|n| &self[(n, n)])
292    }
293
294    /** Returns an iterator over the elements directly below the diagonal of a matrix
295
296    # Examples
297    ```
298    # use vector_victor::Matrix;
299    let my_matrix = Matrix::mat([[1, 2, 3],
300                                 [4, 5, 6],
301                                 [7, 8, 9],
302                                 [10,11,12]]);
303
304    itertools::assert_equal(my_matrix.subdiagonals(), [4,8,12].iter());
305    ``` */
306    #[must_use]
307    pub fn subdiagonals<'s>(&'s self) -> impl Iterator<Item = &'s T> + 's {
308        (0..min(N, M - 1)).map(|n| &self[(n + 1, n)])
309    }
310
311    /** Returns a reference to the element at that position in the matrix, or `None` if out of bounds.
312
313    [`Index`](#impl-Index%3CI%3E-for-Matrix%3CT,+M,+N%3E) behaves similarly,
314    but will panic if the index is out of bounds instead of returning an option
315
316    # Arguments
317
318    * `index`: a 1D or 2D index into the matrix. See [MatrixIndex] for more information on matrix indexing.
319
320    # Examples
321
322    ```
323    # use vector_victor::Matrix;
324    let my_matrix = Matrix::mat([[1, 2],
325                                 [3, 4]]);
326
327    // element at index 2 is the same as the element at row 1, column 0.
328    assert_eq!(my_matrix.get(2), my_matrix.get((1,0)));
329
330    // my_matrix.get() is equivalent to my_matrix[],
331    // but returns an Option instead of panicking
332    assert_eq!(my_matrix.get(2), Some(&my_matrix[2]));
333
334    // index 4 is out of range, so get(4) returns None.
335    assert_eq!(my_matrix.get(4), None);
336    ``` */
337    #[inline]
338    #[must_use]
339    pub fn get(&self, index: impl MatrixIndex) -> Option<&T> {
340        let (m, n) = index.to_2d(M, N)?;
341        Some(&self.data[m][n])
342    }
343
344    /** Returns a mutable reference to the element at that position in the matrix,
345    or `None` if out of bounds.
346
347    [`IndexMut`](#impl-IndexMut%3CI%3E-for-Matrix%3CT,+M,+N%3E) behaves similarly,
348    but will panic if the index is out of bounds instead of returning an option
349
350    # Arguments
351
352    * `index`: a 1D or 2D index into the matrix. See [MatrixIndex] for more information
353    on matrix indexing.
354
355    # Examples
356
357    ```
358    # use vector_victor::Matrix;
359    let mut my_matrix = Matrix::mat([[1, 2],
360                                     [3, 4]]);
361
362    match my_matrix.get_mut(2) {
363        Some(t) => *t = 5,
364        None => panic!()};
365    assert_eq!(my_matrix, Matrix::mat([[1,2],[5,4]]))
366    ``` */
367    #[inline]
368    #[must_use]
369    pub fn get_mut(&mut self, index: impl MatrixIndex) -> Option<&mut T> {
370        let (m, n) = index.to_2d(M, N)?;
371        Some(&mut self.data[m][n])
372    }
373
374    /** Returns a row of the matrix.
375
376    # Panics
377
378    Panics if row index `m` is out of bounds.
379
380    # Examples
381
382    ```
383    # use vector_victor::{Matrix, Vector};
384    let my_matrix = Matrix::mat([[1, 2],
385                                 [3, 4]]);
386
387    // row at index 1
388    assert_eq!(my_matrix.row(1), Vector::vec([3,4]));
389    ``` */
390    #[inline]
391    #[must_use]
392    pub fn row(&self, m: usize) -> Vector<T, N> {
393        assert!(
394            m < M,
395            "Row index {} out of bounds for {}×{} matrix",
396            m,
397            M,
398            N
399        );
400        Vector::<T, N>::vec(self.data[m])
401    }
402
403    /** Sets a row of the matrix.
404
405    # Panics
406
407    Panics if row index `m` is out of bounds.
408
409    # Examples
410
411    ```
412    # use vector_victor::{Matrix, Vector};
413    let mut my_matrix = Matrix::mat([[1, 2],
414                                     [3, 4]]);
415    // row at index 1
416    my_matrix.set_row(1, &Vector::vec([5,6]));
417    assert_eq!(my_matrix, Matrix::mat([[1,2],[5,6]]));
418    ``` */
419    #[inline]
420    pub fn set_row(&mut self, m: usize, val: &Vector<T, N>) {
421        assert!(
422            m < M,
423            "Row index {} out of bounds for {}×{} matrix",
424            m,
425            M,
426            N
427        );
428        for n in 0..N {
429            self.data[m][n] = val.data[n][0];
430        }
431    }
432
433    /** Returns a column of the matrix.
434
435    # Panics
436
437    Panics if column index `n` is out of bounds.
438
439    # Examples
440
441    ```
442    # use vector_victor::{Matrix, Vector};
443    let my_matrix = Matrix::mat([[1, 2],
444                                 [3, 4]]);
445
446    // column at index 1
447    assert_eq!(my_matrix.col(1), Vector::vec([2,4]));
448    ``` */
449    #[inline]
450    #[must_use]
451    pub fn col(&self, n: usize) -> Vector<T, M> {
452        assert!(
453            n < N,
454            "Column index {} out of bounds for {}×{} matrix",
455            n,
456            M,
457            N
458        );
459        Vector::<T, M>::vec(self.data.map(|r| r[n]))
460    }
461
462    /** Sets a column of the matrix.
463
464    # Panics
465
466    Panics if column index `n` is out of bounds.
467
468    # Examples
469
470    ```
471    # use vector_victor::{Matrix, Vector};
472    let mut my_matrix = Matrix::mat([[1, 2],
473                                     [3, 4]]);
474    // column at index 1
475    my_matrix.set_col(1, &Vector::vec([5,6]));
476    assert_eq!(my_matrix, Matrix::mat([[1,5],[3,6]]));
477    ``` */
478    #[inline]
479    pub fn set_col(&mut self, n: usize, val: &Vector<T, M>) {
480        assert!(
481            n < N,
482            "Column index {} out of bounds for {}×{} matrix",
483            n,
484            M,
485            N
486        );
487
488        for m in 0..M {
489            self.data[m][n] = val.data[m][0];
490        }
491    }
492
493    /// Returns an iterator over the rows of the matrix, returning them as column vectors.
494    #[must_use]
495    pub fn rows<'a>(&'a self) -> impl Iterator<Item = Vector<T, N>> + 'a {
496        (0..M).map(|m| self.row(m))
497    }
498
499    /// Returns an iterator over the columns of the matrix, returning them as column vectors.
500    #[must_use]
501    pub fn cols<'a>(&'a self) -> impl Iterator<Item = Vector<T, M>> + 'a {
502        (0..N).map(|n| self.col(n))
503    }
504
505    /** Interchange two rows
506
507    # Panics
508
509    Panics if row index `m1` or `m2` are out of bounds */
510    pub fn pivot_row(&mut self, m1: usize, m2: usize) {
511        let tmp = self.row(m2);
512        self.set_row(m2, &self.row(m1));
513        self.set_row(m1, &tmp);
514    }
515
516    /** Interchange two columns
517
518    # Panics
519
520    Panics if column index `n1` or `n2` are out of bounds */
521    pub fn pivot_col(&mut self, n1: usize, n2: usize) {
522        let tmp = self.col(n2);
523        self.set_col(n2, &self.col(n1));
524        self.set_col(n1, &tmp);
525    }
526
527    /** Apply a permutation matrix to the rows of a matrix
528
529    # Arguments
530
531    * `ms`: a [`Vector`] of [`usize`] of length P. Each entry is the index of the row that will
532    appear in the result
533
534    Returns: a P×N matrix
535
536    # Panics
537
538    Panics if any of the row indices in `ms` is out of bounds
539
540    # Examples
541
542    ```
543    # use vector_victor::{Matrix, Vector};
544    let my_matrix = Matrix::mat([[1, 2, 3],
545                                 [4, 5, 6],
546                                 [7, 8, 9]]);
547
548    let permuted = my_matrix.permute_rows(&Vector::vec([1, 0, 2]));
549    assert_eq!(permuted, Matrix::mat([[4, 5, 6],
550                                      [1, 2, 3],
551                                      [7, 8, 9]]))
552    ``` */
553    #[must_use]
554    pub fn permute_rows<const P: usize>(&self, ms: &Vector<usize, P>) -> Matrix<T, P, N>
555    where
556        T: Default,
557    {
558        Matrix::<T, P, N>::from_rows(ms.elements().map(|&m| self.row(m)))
559    }
560
561    /** Apply a permutation matrix to the columns of a matrix
562
563    # Arguments
564
565    * `ns`: a [`Vector`] of [`usize`] of length P. Each entry is the index of the column that will
566    appear in the result
567
568    Returns: a P×N matrix
569
570    # Panics
571
572    Panics if any of the column indices in `ns` is out of bounds */
573    #[must_use]
574    pub fn permute_cols<const P: usize>(&self, ns: &Vector<usize, P>) -> Matrix<T, M, P>
575    where
576        T: Default,
577    {
578        Matrix::<T, M, P>::from_cols(ns.elements().map(|&n| self.col(n)))
579    }
580
581    /** Returns the transpose $M^T$ of the matrix, or the matrix flipped across its diagonal.
582
583    # Examples
584    ```
585    # use vector_victor::Matrix;
586    let my_matrix = Matrix::mat([[1, 2, 3],
587                                 [4, 5, 6]]);
588
589    assert_eq!(
590        my_matrix.transpose(),
591        Matrix::mat([[1, 4],
592                     [2, 5],
593                     [3, 6]]))
594    ``` */
595    pub fn transpose(&self) -> Matrix<T, N, M>
596    where
597        Matrix<T, N, M>: Default,
598    {
599        Matrix::<T, N, M>::from_rows(self.cols())
600    }
601}
602
603// Index
604impl<I, T, const M: usize, const N: usize> Index<I> for Matrix<T, M, N>
605where
606    I: MatrixIndex,
607    T: Copy,
608{
609    type Output = T;
610
611    #[inline(always)]
612    fn index(&self, index: I) -> &Self::Output {
613        self.get(index).expect(&*format!(
614            "index {:?} out of range for {}×{} Matrix",
615            index, M, N
616        ))
617    }
618}
619
620// IndexMut
621impl<I, T, const M: usize, const N: usize> IndexMut<I> for Matrix<T, M, N>
622where
623    I: MatrixIndex,
624    T: Copy,
625{
626    #[inline(always)]
627    fn index_mut(&mut self, index: I) -> &mut Self::Output {
628        self.get_mut(index).expect(&*format!(
629            "index {:?} out of range for {}×{} Matrix",
630            index, M, N
631        ))
632    }
633}
634
635// CONVERSIONS
636
637// Convert from 2D Array (equivalent to new)
638impl<T: Copy, const M: usize, const N: usize> From<[[T; N]; M]> for Matrix<T, M, N> {
639    fn from(data: [[T; N]; M]) -> Self {
640        Self::mat(data)
641    }
642}
643
644// Convert from 1D Array (equivalent to vec)
645impl<T: Copy, const M: usize> From<[T; M]> for Vector<T, M> {
646    fn from(data: [T; M]) -> Self {
647        Self::vec(data)
648    }
649}
650
651// Convert from scalar (equivalent to fill)
652impl<T: Copy, const M: usize, const N: usize> From<T> for Matrix<T, M, N> {
653    fn from(scalar: T) -> Self {
654        Self::fill(scalar)
655    }
656}
657
658// Convert to 2D Array
659impl<T: Copy + Debug, const M: usize, const N: usize> Into<[[T; N]; M]> for Matrix<T, M, N> {
660    fn into(self) -> [[T; N]; M] {
661        self.rows()
662            .map(|row| row.into())
663            .collect_vec()
664            .try_into()
665            .unwrap()
666    }
667}
668
669// convert to 1D Array
670impl<T: Copy + Debug, const M: usize> Into<[T; M]> for Vector<T, M> {
671    fn into(self) -> [T; M] {
672        self.elements().cloned().collect_vec().try_into().unwrap()
673    }
674}
675
676// IntoIter
677impl<T: Copy, const M: usize, const N: usize> IntoIterator for Matrix<T, M, N> {
678    type Item = T;
679    type IntoIter = Flatten<std::array::IntoIter<[T; N], M>>;
680
681    fn into_iter(self) -> Self::IntoIter {
682        self.data.into_iter().flatten()
683    }
684}
685
686// FromIterator
687impl<T: Copy, const M: usize, const N: usize> FromIterator<T> for Matrix<T, M, N>
688where
689    Self: Default,
690{
691    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
692        let mut result: Self = Default::default();
693        for (l, r) in zip(result.elements_mut(), iter) {
694            *l = r;
695        }
696        result
697    }
698}