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