easy_ml/matrices/
views.rs

1/*!
2 * Generic views into a matrix.
3 *
4 * The concept of a view into a matrix is built from the low level [MatrixRef] and
5 * [MatrixMut] traits which define having read and read/write access to Matrix data
6 * respectively, and the high level API implemented on the [MatrixView] struct.
7 *
8 * Since a Matrix is itself a MatrixRef, the APIs for the traits are purposefully verbose to
9 * avoid name clashes with methods defined on the Matrix and MatrixView types. You should
10 * typically use MatrixRef and MatrixMut implementations via the MatrixView struct which provides
11 * an API closely resembling Matrix.
12 *
13 * # Examples
14 *
15 * [Using trait objects with MatrixViews](erased)
16 */
17
18use std::marker::PhantomData;
19
20use crate::matrices::iterators::*;
21use crate::matrices::{Column, Matrix, Row};
22
23pub mod erased;
24mod map;
25mod partitions;
26mod ranges;
27mod reverse;
28pub mod traits;
29
30pub(crate) use map::*;
31pub use partitions::*;
32pub use ranges::*;
33pub use reverse::*;
34
35/**
36* A shared/immutable reference to a matrix (or a portion of it) of some type.
37*
38* # Indexing
39*
40* Valid indexes into a MatrixRef range from 0 inclusive to `view_rows` exclusive for rows and
41* from 0 inclusive to `view_columns` exclusive for columns. Even if a 4x4 matrix creates some
42* 2x2 MatrixRef that can view only its center, the indexes used on the MatrixRef would be
43* 0,0 to 1,1, not 1,1 to 2,2 as corresponding on the matrix. If the view_rows or view_columns are
44* 0 then the MatrixRef has no valid indexes.
45*
46* # Safety
47*
48* In order to support returning references without bounds checking in a useful way, the
49* implementing type is required to uphold several invariants.
50*
51* 1 - Any valid index as described in Indexing will yield a safe reference when calling
52* `get_reference_unchecked` and `get_reference_unchecked_mut`.
53*
54* 2 - The `view_rows`/`view_columns` that define which indexes are valid may not
55* be changed by a shared reference to the MatrixRef implementation. ie, the matrix may
56* not be resized while a mutable reference is held to it, except by that reference.
57*
58* **NB: Version 2 of Easy ML makes NoInteriorMutability a supertrait of MatrixRef.** It is
59* no longer possible to implement MatrixRef with interior mutability, which matches the
60* 1.x TensorRef trait requirements. In a future major version, NoInteriorMutability will be removed
61* and folded into the documentation on MatrixRef.
62*
63* Essentially, interior mutability causes problems, since code looping through the range of valid
64* indexes in a MatrixRef needs to be able to rely on that range of valid indexes not changing.
65* This is trivially the case by default since a [Matrix] does not have any form of
66* interior mutability, and therefore an iterator holding a shared reference to a Matrix prevents
67* that matrix being resized. However, a type *wrongly* implementing MatrixRef could introduce
68* interior mutability by putting the Matrix in an `Arc<Mutex<>>` which would allow another thread
69* to resize a matrix while an iterator was looping through previously valid indexes on a different
70* thread.
71*
72* Note that it is okay to be able to resize any MatrixRef implementation if that always requires
73* an exclusive reference to the MatrixRef/Matrix, since the exclusivity prevents the above
74* scenario.
75*/
76pub unsafe trait MatrixRef<T>: NoInteriorMutability {
77    /**
78     * Gets a reference to the value at the index if the index is in range. Otherwise returns None.
79     */
80    fn try_get_reference(&self, row: Row, column: Column) -> Option<&T>;
81
82    /**
83     * The number of rows that this reference can view. This may be less than the actual number of
84     * rows of data stored in the matrix implementation, and could be 0.
85     */
86    fn view_rows(&self) -> Row;
87
88    /**
89     * The number of columns that this reference can view. This may be less than the actual number
90     * of columns of data stored in the matrix implementation, and could be 0.
91     */
92    fn view_columns(&self) -> Column;
93
94    /**
95     * Gets a reference to the value at the index without doing any bounds checking. For a safe
96     * alternative see [try_get_reference](MatrixRef::try_get_reference).
97     *
98     * # Safety
99     *
100     * Calling this method with an out-of-bounds index is *[undefined behavior]* even if the
101     * resulting reference is not used. Valid indexes are defined as in [MatrixRef].
102     *
103     * [undefined behavior]: <https://doc.rust-lang.org/reference/behavior-considered-undefined.html>
104     * [MatrixRef]: MatrixRef
105     */
106    #[allow(clippy::missing_safety_doc)] // it's not missing
107    unsafe fn get_reference_unchecked(&self, row: Row, column: Column) -> &T;
108
109    /**
110     * A hint for the data layout this MatrixView uses to store its data.
111     *
112     * See [Matrix layout and iterator performance](crate::matrices::iterators#matrix-layout-and-iterator-performance)
113     */
114    fn data_layout(&self) -> DataLayout;
115}
116
117/**
118 * A unique/mutable reference to a matrix (or a portion of it) of some type.
119 *
120 * # Safety
121 *
122 * See [MatrixRef].
123 */
124pub unsafe trait MatrixMut<T>: MatrixRef<T> {
125    /**
126     * Gets a mutable reference to the value at the index, if the index is in range. Otherwise
127     * returns None.
128     */
129    fn try_get_reference_mut(&mut self, row: Row, column: Column) -> Option<&mut T>;
130
131    /**
132     * Gets a mutable reference to the value at the index without doing any bounds checking.
133     * For a safe alternative see [try_get_reference_mut](MatrixMut::try_get_reference_mut).
134     *
135     * # Safety
136     *
137     * Calling this method with an out-of-bounds index is *[undefined behavior]* even if the
138     * resulting reference is not used. Valid indexes are defined as in [MatrixRef].
139     *
140     * [undefined behavior]: <https://doc.rust-lang.org/reference/behavior-considered-undefined.html>
141     * [MatrixRef]: MatrixRef
142     */
143    #[allow(clippy::missing_safety_doc)] // it's not missing
144    unsafe fn get_reference_unchecked_mut(&mut self, row: Row, column: Column) -> &mut T;
145}
146
147/**
148 * A marker trait that promises that the implementing type does not permit interior mutability.
149 *
150 * When combined with [MatrixRef] or [MatrixMut], other code can rely on
151 * the type not being resizable or otherwise mutated through a shared reference.
152 *
153 * NB: This requirement is mandatory from Easy ML 2.0 to implement MatrixView.
154 *
155 * # Safety
156 *
157 * Implementing types must ensure that their internal state cannot be changed through a shared
158 * reference to them.
159 */
160pub unsafe trait NoInteriorMutability {}
161
162/**
163 * The [data layout] used for storing the 2 dimensional data of a MatrixView.
164 *
165 * [data layout]: https://en.wikipedia.org/wiki/Row-_and_column-major_order
166 */
167#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
168pub enum DataLayout {
169    RowMajor,
170    ColumnMajor,
171    Other,
172}
173
174/**
175 * A view into some or all of a matrix.
176 *
177 * A MatrixView has a similar relationship to a [`Matrix`] as a
178 * `&str` has to a `String`, or an array slice to an array. A MatrixView cannot resize
179 * its source, and may span only a portion of the source Matrix in each dimension.
180 *
181 * However a MatrixView is generic not only over the type of the data in the Matrix,
182 * but also over the way the Matrix is 'sliced' and the two are orthogonal to each other.
183 *
184 * MatrixView closely mirrors the API of Matrix, minus resizing methods which are not available.
185 * Methods that create a new matrix do not return a MatrixView, they return a Matrix.
186 */
187#[derive(Clone, Debug)]
188pub struct MatrixView<T, S> {
189    source: S,
190    _type: PhantomData<T>,
191}
192
193// TODO linear_algebra numeric functions, transpositions
194
195/**
196 * MatrixView methods which require only read access via a [MatrixRef] source.
197 */
198impl<T, S> MatrixView<T, S>
199where
200    S: MatrixRef<T>,
201{
202    /**
203     * Creates a MatrixView from a source of some type.
204     *
205     * The lifetime of the source determines the lifetime of the MatrixView created. If the
206     * MatrixView is created from a reference to a Matrix, then the MatrixView cannot live
207     * longer than the Matrix referenced.
208     */
209    pub fn from(source: S) -> MatrixView<T, S> {
210        MatrixView {
211            source,
212            _type: PhantomData,
213        }
214    }
215
216    /**
217     * Consumes the matrix view, yielding the source it was created from.
218     */
219    pub fn source(self) -> S {
220        self.source
221    }
222
223    /**
224     * Gives a reference to the matrix view's source. This should typically not be needed
225     * since Easy ML APIs which take [MatrixRef]s as inputs like iterators are
226     * already wrapped for you as methods on MatrixView.
227     */
228    pub fn source_ref(&self) -> &S {
229        &self.source
230    }
231
232    /**
233     * Gives a mutable reference to the matrix view's source. This should typically not be needed
234     * since Easy ML APIs which take [MatrixRef]s as inputs like iterators are
235     * already wrapped for you as methods on MatrixView.
236     */
237    pub fn source_ref_mut(&mut self) -> &mut S {
238        &mut self.source
239    }
240
241    /**
242     * Returns the dimensionality of this matrix view in Row, Column format
243     */
244    pub fn size(&self) -> (Row, Column) {
245        (self.rows(), self.columns())
246    }
247
248    /**
249     * Gets the number of rows visible to this matrix view.
250     */
251    pub fn rows(&self) -> Row {
252        self.source.view_rows()
253    }
254
255    /**
256     * Gets the number of columns visible to this matrix view.
257     */
258    pub fn columns(&self) -> Column {
259        self.source.view_columns()
260    }
261
262    /**
263     * Gets the data layout this MatrixView's source uses to store its data.
264     *
265     * See [Matrix layout and iterator performance](crate::matrices::iterators#matrix-layout-and-iterator-performance)
266     */
267    pub fn data_layout(&self) -> DataLayout {
268        self.source.data_layout()
269    }
270
271    /**
272     * Gets a reference to the value at this row and column. Rows and Columns are 0 indexed.
273     *
274     * # Panics
275     *
276     * Panics if the index is out of range.
277     */
278    #[track_caller]
279    pub fn get_reference(&self, row: Row, column: Column) -> &T {
280        match self.source.try_get_reference(row, column) {
281            Some(reference) => reference,
282            None => panic!(
283                "Index ({},{}) not in range, MatrixView range is (0,0) to ({},{}).",
284                row,
285                column,
286                self.rows(),
287                self.columns()
288            ),
289        }
290    }
291
292    /**
293     * Gets a reference to the value at the row and column if the index is in range.
294     * Otherwise returns None.
295     */
296    pub fn try_get_reference(&self, row: Row, column: Column) -> Option<&T> {
297        self.source.try_get_reference(row, column)
298    }
299
300    /**
301     * Gets a reference to the value at the index without doing any bounds checking. For a safe
302     * alternative see [try_get_reference](MatrixView::try_get_reference).
303     *
304     * # Safety
305     *
306     * Calling this method with an out-of-bounds index is *[undefined behavior]* even if the
307     * resulting reference is not used. Valid indexes are defined as in [MatrixRef].
308     *
309     * [undefined behavior]: <https://doc.rust-lang.org/reference/behavior-considered-undefined.html>
310     * [MatrixRef]: MatrixRef
311     */
312    #[allow(clippy::missing_safety_doc)] // it's not missing
313    pub unsafe fn get_reference_unchecked(&self, row: Row, column: Column) -> &T {
314        unsafe { self.source.get_reference_unchecked(row, column) }
315    }
316
317    /**
318     * Returns an iterator over references to a column vector in this matrix view.
319     * Columns are 0 indexed.
320     *
321     * # Panics
322     *
323     * Panics if the column is not visible to this view.
324     */
325    #[track_caller]
326    pub fn column_reference_iter(&self, column: Column) -> ColumnReferenceIterator<T, S> {
327        ColumnReferenceIterator::from(&self.source, column)
328    }
329
330    /**
331     * Returns an iterator over references to a row vector in this matrix view.
332     * Rows are 0 indexed.
333     *
334     * # Panics
335     *
336     * Panics if the row is not visible to this view.
337     */
338    #[track_caller]
339    pub fn row_reference_iter(&self, row: Row) -> RowReferenceIterator<T, S> {
340        RowReferenceIterator::from(&self.source, row)
341    }
342
343    /**
344     * Returns a column major iterator over references to all values in this matrix view,
345     * proceeding through each column in order.
346     */
347    pub fn column_major_reference_iter(&self) -> ColumnMajorReferenceIterator<T, S> {
348        ColumnMajorReferenceIterator::from(&self.source)
349    }
350
351    /**
352     * Returns a row major iterator over references to all values in this matrix view,
353     * proceeding through each row in order.
354     */
355    pub fn row_major_reference_iter(&self) -> RowMajorReferenceIterator<T, S> {
356        RowMajorReferenceIterator::from(&self.source)
357    }
358
359    /**
360     * Returns an iterator over references to the main diagonal in this matrix view.
361     */
362    pub fn diagonal_reference_iter(&self) -> DiagonalReferenceIterator<T, S> {
363        DiagonalReferenceIterator::from(&self.source)
364    }
365
366    /**
367     * Returns a MatrixView giving a view of only the data within the row and column
368     * [IndexRange]s.
369     *
370     * This is a shorthand for constructing the MatrixView from this MatrixView. See
371     * [`Matrix::range`](Matrix::range).
372     */
373    pub fn range<R>(&self, rows: R, columns: R) -> MatrixView<T, MatrixRange<T, &S>>
374    where
375        R: Into<IndexRange>,
376    {
377        MatrixView::from(MatrixRange::from(&self.source, rows, columns))
378    }
379
380    /**
381     * Returns a MatrixView giving a view of only the data within the row and column
382     * [IndexRange]s. The MatrixRange mutably borrows the source, and can therefore
383     * mutate it.
384     *
385     * This is a shorthand for constructing the MatrixView from this MatrixView. See
386     * [`Matrix::range`](Matrix::range).
387     */
388    pub fn range_mut<R>(&mut self, rows: R, columns: R) -> MatrixView<T, MatrixRange<T, &mut S>>
389    where
390        R: Into<IndexRange>,
391    {
392        MatrixView::from(MatrixRange::from(&mut self.source, rows, columns))
393    }
394
395    /**
396     * Returns a MatrixView giving a view of only the data within the row and column
397     * [IndexRange]s. The MatrixRange takes ownership of the source, and
398     * can therefore mutate it
399     *
400     * This is a shorthand for constructing the MatrixView from this MatrixView. See
401     * [`Matrix::range`](Matrix::range).
402     */
403    pub fn range_owned<R>(self, rows: R, columns: R) -> MatrixView<T, MatrixRange<T, S>>
404    where
405        R: Into<IndexRange>,
406    {
407        MatrixView::from(MatrixRange::from(self.source, rows, columns))
408    }
409
410    /**
411     * Returns a MatrixView giving a view of only the data outside the row and column
412     * [IndexRange]s.
413     *
414     * This is a shorthand for constructing the MatrixView from this MatrixView. See
415     * [`Matrix::mask`](Matrix::mask).
416     */
417    pub fn mask<R>(&self, rows: R, columns: R) -> MatrixView<T, MatrixMask<T, &S>>
418    where
419        R: Into<IndexRange>,
420    {
421        MatrixView::from(MatrixMask::from(&self.source, rows, columns))
422    }
423
424    /**
425     * Returns a MatrixView giving a view of only the data outside the row and column
426     * [IndexRange]s. The MatrixMask mutably borrows the source, and can therefore
427     * mutate it.
428     *
429     * This is a shorthand for constructing the MatrixView from this MatrixView. See
430     * [`Matrix::mask`](Matrix::mask).
431     */
432    pub fn mask_mut<R>(&mut self, rows: R, columns: R) -> MatrixView<T, MatrixMask<T, &mut S>>
433    where
434        R: Into<IndexRange>,
435    {
436        MatrixView::from(MatrixMask::from(&mut self.source, rows, columns))
437    }
438
439    /**
440     * Returns a MatrixView giving a view of only the data outside the row and column
441     * [IndexRange]s. The MatrixMask takes ownership of the source, and
442     * can therefore mutate it
443     *
444     * This is a shorthand for constructing the MatrixView from this MatrixView. See
445     * [`Matrix::mask`](Matrix::mask).
446     */
447    pub fn mask_owned<R>(self, rows: R, columns: R) -> MatrixView<T, MatrixMask<T, S>>
448    where
449        R: Into<IndexRange>,
450    {
451        MatrixView::from(MatrixMask::from(self.source, rows, columns))
452    }
453
454    /**
455     * Returns a MatrixView with the rows and columns specified reversed in iteration
456     * order. The data of this matrix and the dimension lengths remain unchanged.
457     *
458     * This is a shorthand for constructing the MatrixView from this matrix. See
459     * [`Matrix::reverse`](Matrix::reverse).
460     */
461    pub fn reverse(&self, reverse: Reverse) -> MatrixView<T, MatrixReverse<T, &S>> {
462        MatrixView::from(MatrixReverse::from(&self.source, reverse))
463    }
464
465    /**
466     * Returns a MatrixView with the rows and columns specified reversed in iteration
467     * order. The data of this matrix and the dimension lengths remain unchanged. The MatrixReverse
468     * mutably borrows the source, and can therefore mutate it
469     *
470     * This is a shorthand for constructing the MatrixView from this MatrixView. See
471     * [`Matrix::reverse`](Matrix::reverse).
472     */
473    pub fn reverse_mut(&mut self, reverse: Reverse) -> MatrixView<T, MatrixReverse<T, &mut S>> {
474        MatrixView::from(MatrixReverse::from(&mut self.source, reverse))
475    }
476
477    /**
478     * Returns a MatrixView with the rows and columns specified reversed in iteration
479     * order. The data of this matrix and the dimension lengths remain unchanged. The MatrixReverse
480     * takes ownership of the source, and can therefore mutate it
481     *
482     * This is a shorthand for constructing the MatrixView from this MatrixView. See
483     * [`Matrix::reverse`](Matrix::reverse).
484     */
485    pub fn reverse_owned(self, reverse: Reverse) -> MatrixView<T, MatrixReverse<T, S>> {
486        MatrixView::from(MatrixReverse::from(self.source, reverse))
487    }
488}
489
490/**
491 * MatrixView methods which require only read access via a [MatrixRef] source
492 * and a clonable type.
493 */
494impl<T, S> MatrixView<T, S>
495where
496    T: Clone,
497    S: MatrixRef<T>,
498{
499    /**
500     * Gets a copy of the value at this row and column. Rows and Columns are 0 indexed.
501     *
502     * # Panics
503     *
504     * Panics if the index is out of range.
505     */
506    #[track_caller]
507    pub fn get(&self, row: Row, column: Column) -> T {
508        match self.source.try_get_reference(row, column) {
509            Some(reference) => reference.clone(),
510            None => panic!(
511                "Index ({},{}) not in range, MatrixView range is (0,0) to ({},{}).",
512                row,
513                column,
514                self.rows(),
515                self.columns()
516            ),
517        }
518    }
519
520    /**
521     * Computes and returns the transpose of this matrix
522     *
523     * ```
524     * use easy_ml::matrices::Matrix;
525     * use easy_ml::matrices::views::MatrixView;
526     * let x = MatrixView::from(Matrix::from(vec![
527     *    vec![ 1, 2 ],
528     *    vec![ 3, 4 ]]));
529     * let y = Matrix::from(vec![
530     *    vec![ 1, 3 ],
531     *    vec![ 2, 4 ]]);
532     * assert_eq!(x.transpose(), y);
533     * ```
534     */
535    pub fn transpose(&self) -> Matrix<T> {
536        Matrix::from_fn((self.columns(), self.rows()), |(column, row)| {
537            self.get(row, column)
538        })
539    }
540
541    /**
542     * Returns an iterator over a column vector in this matrix view. Columns are 0 indexed.
543     *
544     * If you have a matrix such as:
545     * ```ignore
546     * [
547     *    1, 2, 3
548     *    4, 5, 6
549     *    7, 8, 9
550     * ]
551     * ```
552     * then a column of 0, 1, and 2 will yield [1, 4, 7], [2, 5, 8] and [3, 6, 9]
553     * respectively. If you do not need to copy the elements use
554     * [`column_reference_iter`](MatrixView::column_reference_iter) instead.
555     *
556     * # Panics
557     *
558     * Panics if the column does not exist in this matrix.
559     */
560    #[track_caller]
561    pub fn column_iter(&self, column: Column) -> ColumnIterator<T, S> {
562        ColumnIterator::from(&self.source, column)
563    }
564
565    /**
566     * Returns an iterator over a row vector in this matrix view. Rows are 0 indexed.
567     *
568     * If you have a matrix such as:
569     * ```ignore
570     * [
571     *    1, 2, 3
572     *    4, 5, 6
573     *    7, 8, 9
574     * ]
575     * ```
576     * then a row of 0, 1, and 2 will yield [1, 2, 3], [4, 5, 6] and [7, 8, 9]
577     * respectively. If you do not need to copy the elements use
578     * [`row_reference_iter`](MatrixView::row_reference_iter) instead.
579     *
580     * # Panics
581     *
582     * Panics if the row does not exist in this matrix.
583     */
584    #[track_caller]
585    pub fn row_iter(&self, row: Row) -> RowIterator<T, S> {
586        RowIterator::from(&self.source, row)
587    }
588
589    /**
590     * Returns a column major iterator over all values in this matrix view, proceeding through each
591     * column in order.
592     *
593     * If you have a matrix such as:
594     * ```ignore
595     * [
596     *    1, 2
597     *    3, 4
598     * ]
599     * ```
600     * then the iterator will yield [1, 3, 2, 4]. If you do not need to copy the
601     * elements use [`column_major_reference_iter`](MatrixView::column_major_reference_iter)
602     * instead.
603     */
604    pub fn column_major_iter(&self) -> ColumnMajorIterator<T, S> {
605        ColumnMajorIterator::from(&self.source)
606    }
607
608    /**
609     * Returns a row major iterator over all values in this matrix view, proceeding through each
610     * row in order.
611     *
612     * If you have a matrix such as:
613     * ```ignore
614     * [
615     *    1, 2
616     *    3, 4
617     * ]
618     * ```
619     * then the iterator will yield [1, 2, 3, 4]. If you do not need to copy the
620     * elements use [`row_major_reference_iter`](MatrixView::row_major_reference_iter) instead.
621     */
622    pub fn row_major_iter(&self) -> RowMajorIterator<T, S> {
623        RowMajorIterator::from(&self.source)
624    }
625
626    /**
627     * Returns a iterator over the main diagonal of this matrix view.
628     *
629     * If you have a matrix such as:
630     * ```ignore
631     * [
632     *    1, 2
633     *    3, 4
634     * ]
635     * ```
636     * then the iterator will yield [1, 4]. If you do not need to copy the
637     * elements use [`diagonal_reference_iter`](MatrixView::diagonal_reference_iter) instead.
638     *
639     * # Examples
640     *
641     * Computing a [trace](https://en.wikipedia.org/wiki/Trace_(linear_algebra))
642     * ```
643     * use easy_ml::matrices::Matrix;
644     * use easy_ml::matrices::views::MatrixView;
645     * let view = MatrixView::from(Matrix::from(vec![
646     *     vec![ 1, 2, 3 ],
647     *     vec![ 4, 5, 6 ],
648     *     vec![ 7, 8, 9 ],
649     * ]));
650     * let trace: i32 = view.diagonal_iter().sum();
651     * assert_eq!(trace, 1 + 5 + 9);
652     * ```
653     */
654    pub fn diagonal_iter(&self) -> DiagonalIterator<T, S> {
655        DiagonalIterator::from(&self.source)
656    }
657
658    /**
659     * Creates and returns a new matrix with all values from the original with the
660     * function applied to each.
661     *
662     * # Exmples
663     * ```
664     * use easy_ml::matrices::Matrix;
665     * use easy_ml::matrices::views::MatrixView;
666     * let x = MatrixView::from(Matrix::from(vec![
667     *    vec![ 0.0, 1.2 ],
668     *    vec![ 5.8, 6.9 ]]));
669     * let y = x.map(|element| element > 2.0);
670     * let result = Matrix::from(vec![
671     *    vec![ false, false ],
672     *    vec![ true, true ]]);
673     * assert_eq!(&y, &result);
674     * ```
675     */
676    pub fn map<U>(&self, mapping_function: impl Fn(T) -> U) -> Matrix<U>
677    where
678        U: Clone,
679    {
680        let mapped = self.row_major_iter().map(mapping_function).collect();
681        Matrix::from_flat_row_major(self.size(), mapped)
682    }
683
684    /**
685     * Creates and returns a new matrix with all values from the original
686     * and the index of each value mapped by a function. This can be used
687     * to perform elementwise operations that are not defined on the
688     * Matrix type itself.
689     */
690    pub fn map_with_index<U>(&self, mapping_function: impl Fn(T, Row, Column) -> U) -> Matrix<U>
691    where
692        U: Clone,
693    {
694        let mapped = self
695            .row_major_iter()
696            .with_index()
697            .map(|((i, j), x)| mapping_function(x, i, j))
698            .collect();
699        Matrix::from_flat_row_major(self.size(), mapped)
700    }
701}
702
703/**
704 * MatrixView methods which require mutable access via a [MatrixMut] source.
705 */
706impl<T, S> MatrixView<T, S>
707where
708    S: MatrixMut<T>,
709{
710    /**
711     * Gets a mutable reference to the value at this row and column.
712     * Rows and Columns are 0 indexed.
713     *
714     * # Panics
715     *
716     * Panics if the index is out of range.
717     */
718    #[track_caller]
719    pub fn get_reference_mut(&mut self, row: Row, column: Column) -> &mut T {
720        let size = self.size();
721        // borrow for size ends
722        match self.source.try_get_reference_mut(row, column) {
723            Some(reference) => reference,
724            None => panic!(
725                "Index ({},{}) not in range, MatrixView range is (0,0) to ({},{}).",
726                row, column, size.0, size.1
727            ),
728        }
729    }
730
731    /**
732     * Sets a new value to this row and column. Rows and Columns are 0 indexed.
733     *
734     * # Panics
735     *
736     * Panics if the index is out of range.
737     */
738    #[track_caller]
739    pub fn set(&mut self, row: Row, column: Column, value: T) {
740        match self.source.try_get_reference_mut(row, column) {
741            Some(reference) => *reference = value,
742            None => panic!(
743                "Index ({},{}) not in range, MatrixView range is (0,0) to ({},{}).",
744                row,
745                column,
746                self.rows(),
747                self.columns()
748            ),
749        }
750    }
751
752    /**
753     * Gets a mutable reference to the value at the row and column if the index is in range.
754     * Otherwise returns None.
755     */
756    pub fn try_get_reference_mut(&mut self, row: Row, column: Column) -> Option<&mut T> {
757        self.source.try_get_reference_mut(row, column)
758    }
759
760    /**
761     * Gets a mutable reference to the value at the index without doing any bounds checking.
762     * For a safe alternative see [try_get_reference_mut](MatrixView::try_get_reference_mut).
763     *
764     * # Safety
765     *
766     * Calling this method with an out-of-bounds index is *[undefined behavior]* even if the
767     * resulting reference is not used. Valid indexes are defined as in [MatrixRef].
768     *
769     * [undefined behavior]: <https://doc.rust-lang.org/reference/behavior-considered-undefined.html>
770     * [MatrixRef]: MatrixRef
771     */
772    #[allow(clippy::missing_safety_doc)] // it's not missing
773    pub unsafe fn get_reference_unchecked_mut(&mut self, row: Row, column: Column) -> &mut T {
774        unsafe { self.source.get_reference_unchecked_mut(row, column) }
775    }
776}
777
778/**
779 * MatrixView methods which require mutable access via a [MatrixMut] source and
780 * no interior mutability.
781 */
782impl<T, S> MatrixView<T, S>
783where
784    S: MatrixMut<T> + NoInteriorMutability,
785{
786    /**
787     * Returns an iterator over mutable references to a column vector in this matrix view.
788     * Columns are 0 indexed.
789     *
790     * # Panics
791     *
792     * Panics if the column is not visible to this view.
793     */
794    #[track_caller]
795    pub fn column_reference_mut_iter(
796        &mut self,
797        column: Column,
798    ) -> ColumnReferenceMutIterator<T, S> {
799        ColumnReferenceMutIterator::from(&mut self.source, column)
800    }
801
802    /**
803     * Returns an iterator over mutable references to a row vector in this matrix view.
804     * Rows are 0 indexed.
805     *
806     * # Panics
807     *
808     * Panics if the row is not visible to this view.
809     */
810    #[track_caller]
811    pub fn row_reference_mut_iter(&mut self, row: Row) -> RowReferenceMutIterator<T, S> {
812        RowReferenceMutIterator::from(&mut self.source, row)
813    }
814
815    /**
816     * Returns a column major iterator over mutable references to all values in this matrix view,
817     * proceeding through each column in order.
818     */
819    pub fn column_major_reference_mut_iter(&mut self) -> ColumnMajorReferenceMutIterator<T, S> {
820        ColumnMajorReferenceMutIterator::from(&mut self.source)
821    }
822
823    /**
824     * Returns a row major iterator over mutable references to all values in this matrix view,
825     * proceeding through each row in order.
826     */
827    pub fn row_major_reference_mut_iter(&mut self) -> RowMajorReferenceMutIterator<T, S> {
828        RowMajorReferenceMutIterator::from(&mut self.source)
829    }
830
831    /**
832     * Returns an iterator over mutable references to the main diagonal in this matrix view.
833     */
834    pub fn diagonal_reference_mut_iter(&mut self) -> DiagonalReferenceMutIterator<T, S> {
835        DiagonalReferenceMutIterator::from(&mut self.source)
836    }
837}
838
839/**
840 * MatrixView methods which require mutable access via a [MatrixMut] source
841 * and a clonable type.
842 */
843impl<T, S> MatrixView<T, S>
844where
845    T: Clone,
846    S: MatrixMut<T>,
847{
848    /**
849     * Applies a function to all values in the matrix view, modifying the source in place.
850     *
851     * # Examples
852     *
853     * ```
854     * use easy_ml::matrices::Matrix;
855     * use easy_ml::matrices::views::MatrixView;
856     * let mut matrix = Matrix::from(vec![
857     *    vec![ 0.0, 1.2 ],
858     *    vec![ 5.8, 6.9 ]]);
859     * {
860     *    let mut view = MatrixView::from(&mut matrix);
861     *    view.map_mut(|x| x + 1.0);
862     * }
863     * let result = Matrix::from(vec![
864     *    vec![ 1.0, 2.2 ],
865     *    vec![ 6.8, 7.9 ]]);
866     * assert_eq!(result, matrix);
867     */
868    pub fn map_mut(&mut self, mapping_function: impl Fn(T) -> T) {
869        self.map_mut_with_index(|x, _, _| mapping_function(x))
870    }
871
872    /**
873     * Applies a function to all values and each value's index in the matrix view,
874     * modifying the source in place.
875     */
876    pub fn map_mut_with_index(&mut self, mapping_function: impl Fn(T, Row, Column) -> T) {
877        match self.data_layout() {
878            DataLayout::ColumnMajor => {
879                self.column_major_reference_mut_iter()
880                    .with_index()
881                    .for_each(|((i, j), x)| {
882                        *x = mapping_function(x.clone(), i, j);
883                    });
884            }
885            _ => {
886                self.row_major_reference_mut_iter()
887                    .with_index()
888                    .for_each(|((i, j), x)| {
889                        *x = mapping_function(x.clone(), i, j);
890                    });
891            }
892        }
893    }
894}
895
896// Common formatting logic used for Matrix and MatrixView Display implementations
897pub(crate) fn format_view<T, S>(view: &S, f: &mut std::fmt::Formatter) -> std::fmt::Result
898where
899    T: std::fmt::Display,
900    S: MatrixRef<T>,
901{
902    let rows = view.view_rows();
903    let columns = view.view_columns();
904    // It would be nice to default to some precision for f32 and f64 but I can't
905    // work out how to easily check if T matches. If we use precision for all T
906    // then strings get truncated which is even worse for debugging.
907    write!(f, "[ ")?;
908    for row in 0..rows {
909        if row > 0 {
910            write!(f, "  ")?;
911        }
912        for column in 0..columns {
913            let value = match view.try_get_reference(row, column) {
914                Some(x) => x,
915                None => panic!(
916                    "Expected ({},{}) to be in range of (0,0) to ({},{})",
917                    row, column, rows, columns
918                ),
919            };
920            match f.precision() {
921                Some(precision) => write!(f, "{:.*}", precision, value)?,
922                None => write!(f, "{}", value)?,
923            };
924            if column < columns - 1 {
925                write!(f, ", ")?;
926            }
927        }
928        if row < rows - 1 {
929            writeln!(f)?;
930        }
931    }
932    write!(f, " ]")
933}
934
935/**
936 * Any matrix view of a Displayable type implements Display
937 *
938 * You can control the precision of the formatting using format arguments, i.e.
939 * `format!("{:.3}", matrix)`
940 */
941impl<T, S> std::fmt::Display for MatrixView<T, S>
942where
943    T: std::fmt::Display,
944    S: MatrixRef<T>,
945{
946    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
947        format_view(&self.source, f)
948    }
949}
950
951#[test]
952fn printing_matrices() {
953    use crate::matrices::Matrix;
954    let view = MatrixView::from(Matrix::from(vec![vec![1.0, 2.0], vec![3.0, 4.0]]));
955    let formatted = format!("{:.3}", view);
956    assert_eq!("[ 1.000, 2.000\n  3.000, 4.000 ]", formatted);
957    assert_eq!("[ 1, 2\n  3, 4 ]", view.to_string());
958}
959
960// Common matrix equality definition
961#[inline]
962pub(crate) fn matrix_equality<T, S1, S2>(left: &S1, right: &S2) -> bool
963where
964    T: PartialEq,
965    S1: MatrixRef<T>,
966    S2: MatrixRef<T>,
967{
968    if left.view_rows() != right.view_rows() {
969        return false;
970    }
971    if left.view_columns() != right.view_columns() {
972        return false;
973    }
974    // perform elementwise check, return true only if every element in
975    // each matrix is the same
976    match (left.data_layout(), right.data_layout()) {
977        (DataLayout::ColumnMajor, DataLayout::ColumnMajor) => {
978            ColumnMajorReferenceIterator::from(left)
979                .zip(ColumnMajorReferenceIterator::from(right))
980                .all(|(x, y)| x == y)
981        }
982        _ => RowMajorReferenceIterator::from(left)
983            .zip(RowMajorReferenceIterator::from(right))
984            .all(|(x, y)| x == y),
985    }
986}
987
988/**
989 * PartialEq is implemented as two matrix views are equal if and only if all their elements
990 * are equal and they have the same size. Differences in their source types are ignored.
991 */
992impl<T, S1, S2> PartialEq<MatrixView<T, S2>> for MatrixView<T, S1>
993where
994    T: PartialEq,
995    S1: MatrixRef<T>,
996    S2: MatrixRef<T>,
997{
998    #[inline]
999    fn eq(&self, other: &MatrixView<T, S2>) -> bool {
1000        matrix_equality(&self.source, &other.source)
1001    }
1002}
1003
1004/**
1005 * A MatrixView and a Matrix can be compared for equality. PartialEq is implemented as they are
1006 * equal if and only if all their elements are equal and they have the same size.
1007 */
1008impl<T, S> PartialEq<Matrix<T>> for MatrixView<T, S>
1009where
1010    T: PartialEq,
1011    S: MatrixRef<T>,
1012{
1013    #[inline]
1014    fn eq(&self, other: &Matrix<T>) -> bool {
1015        matrix_equality(&self.source, &other)
1016    }
1017}
1018
1019/**
1020 * A Matrix and a MatrixView can be compared for equality. PartialEq is implemented as they are
1021 * equal if and only if all their elements are equal and they have the same size.
1022 */
1023impl<T, S> PartialEq<MatrixView<T, S>> for Matrix<T>
1024where
1025    T: PartialEq,
1026    S: MatrixRef<T>,
1027{
1028    #[inline]
1029    fn eq(&self, other: &MatrixView<T, S>) -> bool {
1030        matrix_equality(&self, &other.source)
1031    }
1032}
1033
1034#[test]
1035fn creating_matrix_views_erased() {
1036    let matrix = Matrix::from(vec![vec![1.0]]);
1037    let boxed: Box<dyn MatrixMut<f32>> = Box::new(matrix);
1038    let mut view = MatrixView::from(boxed);
1039    view.set(0, 0, view.get(0, 0) + 1.0);
1040    assert_eq!(2.0, view.get(0, 0));
1041}