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, a valid index for MatrixView range is (0,0) to ({},{}).",
285 row,
286 column,
287 self.rows() - 1,
288 self.columns() - 1,
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, a valid index for MatrixView range is (0,0) to ({},{}).",
672 row,
673 column,
674 self.rows() - 1,
675 self.columns() - 1,
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, a valid index for MatrixView range is (0,0) to ({},{}).",
886 row,
887 column,
888 size.0 - 1,
889 size.1 - 1,
890 ),
891 }
892 }
893
894 /**
895 * Sets a new value to this row and column. Rows and Columns are 0 indexed.
896 *
897 * # Panics
898 *
899 * Panics if the index is out of range.
900 */
901 #[track_caller]
902 pub fn set(&mut self, row: Row, column: Column, value: T) {
903 match self.source.try_get_reference_mut(row, column) {
904 Some(reference) => *reference = value,
905 None => panic!(
906 "Index ({},{}) not in range, a valid index for MatrixView range is (0,0) to ({},{}).",
907 row,
908 column,
909 self.rows() - 1,
910 self.columns() - 1,
911 ),
912 }
913 }
914
915 /**
916 * Gets a mutable reference to the value at the row and column if the index is in range.
917 * Otherwise returns None.
918 */
919 pub fn try_get_reference_mut(&mut self, row: Row, column: Column) -> Option<&mut T> {
920 self.source.try_get_reference_mut(row, column)
921 }
922
923 /**
924 * Gets a mutable reference to the value at the index without doing any bounds checking.
925 * For a safe alternative see [try_get_reference_mut](MatrixView::try_get_reference_mut).
926 *
927 * # Safety
928 *
929 * Calling this method with an out-of-bounds index is *[undefined behavior]* even if the
930 * resulting reference is not used. Valid indexes are defined as in [MatrixRef].
931 *
932 * [undefined behavior]: <https://doc.rust-lang.org/reference/behavior-considered-undefined.html>
933 * [MatrixRef]: MatrixRef
934 */
935 #[allow(clippy::missing_safety_doc)] // it's not missing
936 pub unsafe fn get_reference_unchecked_mut(&mut self, row: Row, column: Column) -> &mut T {
937 unsafe { self.source.get_reference_unchecked_mut(row, column) }
938 }
939}
940
941/**
942 * MatrixView methods which require mutable access via a [MatrixMut] source and
943 * no interior mutability.
944 */
945impl<T, S> MatrixView<T, S>
946where
947 S: MatrixMut<T> + NoInteriorMutability,
948{
949 /**
950 * Returns an iterator over mutable references to a column vector in this matrix view.
951 * Columns are 0 indexed.
952 *
953 * # Panics
954 *
955 * Panics if the column is not visible to this view.
956 */
957 #[track_caller]
958 pub fn column_reference_mut_iter(
959 &mut self,
960 column: Column,
961 ) -> ColumnReferenceMutIterator<'_, T, S> {
962 ColumnReferenceMutIterator::from(&mut self.source, column)
963 }
964
965 /**
966 * Returns an iterator over mutable references to a row vector in this matrix view.
967 * Rows are 0 indexed.
968 *
969 * # Panics
970 *
971 * Panics if the row is not visible to this view.
972 */
973 #[track_caller]
974 pub fn row_reference_mut_iter(&mut self, row: Row) -> RowReferenceMutIterator<'_, T, S> {
975 RowReferenceMutIterator::from(&mut self.source, row)
976 }
977
978 /**
979 * Returns a column major iterator over mutable references to all values in this matrix view,
980 * proceeding through each column in order.
981 */
982 pub fn column_major_reference_mut_iter(&mut self) -> ColumnMajorReferenceMutIterator<'_, T, S> {
983 ColumnMajorReferenceMutIterator::from(&mut self.source)
984 }
985
986 /**
987 * Returns a row major iterator over mutable references to all values in this matrix view,
988 * proceeding through each row in order.
989 */
990 pub fn row_major_reference_mut_iter(&mut self) -> RowMajorReferenceMutIterator<'_, T, S> {
991 RowMajorReferenceMutIterator::from(&mut self.source)
992 }
993
994 /**
995 * Returns an iterator over mutable references to the main diagonal in this matrix view.
996 */
997 pub fn diagonal_reference_mut_iter(&mut self) -> DiagonalReferenceMutIterator<'_, T, S> {
998 DiagonalReferenceMutIterator::from(&mut self.source)
999 }
1000}
1001
1002/**
1003 * MatrixView methods which require mutable access via a [MatrixMut] source
1004 * and a clonable type.
1005 */
1006impl<T, S> MatrixView<T, S>
1007where
1008 T: Clone,
1009 S: MatrixMut<T>,
1010{
1011 /**
1012 * Applies a function to all values in the matrix view, modifying the source in place.
1013 *
1014 * # Examples
1015 *
1016 * ```
1017 * use easy_ml::matrices::Matrix;
1018 * use easy_ml::matrices::views::MatrixView;
1019 * let mut matrix = Matrix::from(vec![
1020 * vec![ 0.0, 1.2 ],
1021 * vec![ 5.8, 6.9 ]]);
1022 * {
1023 * let mut view = MatrixView::from(&mut matrix);
1024 * view.map_mut(|x| x + 1.0);
1025 * }
1026 * let result = Matrix::from(vec![
1027 * vec![ 1.0, 2.2 ],
1028 * vec![ 6.8, 7.9 ]]);
1029 * assert_eq!(result, matrix);
1030 */
1031 pub fn map_mut(&mut self, mapping_function: impl Fn(T) -> T) {
1032 self.map_mut_with_index(|x, _, _| mapping_function(x))
1033 }
1034
1035 /**
1036 * Applies a function to all values and each value's index in the matrix view,
1037 * modifying the source in place.
1038 */
1039 pub fn map_mut_with_index(&mut self, mapping_function: impl Fn(T, Row, Column) -> T) {
1040 match self.data_layout() {
1041 DataLayout::ColumnMajor => {
1042 self.column_major_reference_mut_iter()
1043 .with_index()
1044 .for_each(|((i, j), x)| {
1045 *x = mapping_function(x.clone(), i, j);
1046 });
1047 }
1048 _ => {
1049 self.row_major_reference_mut_iter()
1050 .with_index()
1051 .for_each(|((i, j), x)| {
1052 *x = mapping_function(x.clone(), i, j);
1053 });
1054 }
1055 }
1056 }
1057}
1058
1059// Common formatting logic used for Matrix and MatrixView Display implementations
1060pub(crate) fn format_view<T, S>(view: &S, f: &mut std::fmt::Formatter) -> std::fmt::Result
1061where
1062 T: std::fmt::Display,
1063 S: MatrixRef<T>,
1064{
1065 let rows = view.view_rows();
1066 let columns = view.view_columns();
1067 // It would be nice to default to some precision for f32 and f64 but I can't
1068 // work out how to easily check if T matches. If we use precision for all T
1069 // then strings get truncated which is even worse for debugging.
1070 write!(f, "[ ")?;
1071 for row in 0..rows {
1072 if row > 0 {
1073 write!(f, " ")?;
1074 }
1075 for column in 0..columns {
1076 let value = match view.try_get_reference(row, column) {
1077 Some(x) => x,
1078 None => panic!(
1079 "Expected ({},{}) to be a valid index in range of (0,0) to ({},{})",
1080 row, column, rows - 1, columns - 1
1081 ),
1082 };
1083 match f.precision() {
1084 Some(precision) => write!(f, "{:.*}", precision, value)?,
1085 None => write!(f, "{}", value)?,
1086 };
1087 if column < columns - 1 {
1088 write!(f, ", ")?;
1089 }
1090 }
1091 if row < rows - 1 {
1092 writeln!(f)?;
1093 }
1094 }
1095 write!(f, " ]")
1096}
1097
1098/**
1099 * Any matrix view of a Displayable type implements Display
1100 *
1101 * You can control the precision of the formatting using format arguments, i.e.
1102 * `format!("{:.3}", matrix)`
1103 */
1104impl<T, S> std::fmt::Display for MatrixView<T, S>
1105where
1106 T: std::fmt::Display,
1107 S: MatrixRef<T>,
1108{
1109 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1110 format_view(&self.source, f)
1111 }
1112}
1113
1114#[test]
1115fn printing_matrices() {
1116 use crate::matrices::Matrix;
1117 let view = MatrixView::from(Matrix::from(vec![vec![1.0, 2.0], vec![3.0, 4.0]]));
1118 let formatted = format!("{:.3}", view);
1119 assert_eq!("[ 1.000, 2.000\n 3.000, 4.000 ]", formatted);
1120 assert_eq!("[ 1, 2\n 3, 4 ]", view.to_string());
1121}
1122
1123// Common matrix equality definition
1124#[inline]
1125pub(crate) fn matrix_equality<T, S1, S2>(left: &S1, right: &S2) -> bool
1126where
1127 T: PartialEq,
1128 S1: MatrixRef<T>,
1129 S2: MatrixRef<T>,
1130{
1131 if left.view_rows() != right.view_rows() {
1132 return false;
1133 }
1134 if left.view_columns() != right.view_columns() {
1135 return false;
1136 }
1137 // perform elementwise check, return true only if every element in
1138 // each matrix is the same
1139 match (left.data_layout(), right.data_layout()) {
1140 (DataLayout::ColumnMajor, DataLayout::ColumnMajor) => {
1141 ColumnMajorReferenceIterator::from(left)
1142 .zip(ColumnMajorReferenceIterator::from(right))
1143 .all(|(x, y)| x == y)
1144 }
1145 _ => RowMajorReferenceIterator::from(left)
1146 .zip(RowMajorReferenceIterator::from(right))
1147 .all(|(x, y)| x == y),
1148 }
1149}
1150
1151/**
1152 * PartialEq is implemented as two matrix views are equal if and only if all their elements
1153 * are equal and they have the same size. Differences in their source types are ignored.
1154 */
1155impl<T, S1, S2> PartialEq<MatrixView<T, S2>> for MatrixView<T, S1>
1156where
1157 T: PartialEq,
1158 S1: MatrixRef<T>,
1159 S2: MatrixRef<T>,
1160{
1161 #[inline]
1162 fn eq(&self, other: &MatrixView<T, S2>) -> bool {
1163 matrix_equality(&self.source, &other.source)
1164 }
1165}
1166
1167/**
1168 * A MatrixView and a Matrix can be compared for equality. PartialEq is implemented as they are
1169 * equal if and only if all their elements are equal and they have the same size.
1170 */
1171impl<T, S> PartialEq<Matrix<T>> for MatrixView<T, S>
1172where
1173 T: PartialEq,
1174 S: MatrixRef<T>,
1175{
1176 #[inline]
1177 fn eq(&self, other: &Matrix<T>) -> bool {
1178 matrix_equality(&self.source, &other)
1179 }
1180}
1181
1182/**
1183 * A Matrix and a MatrixView can be compared for equality. PartialEq is implemented as they are
1184 * equal if and only if all their elements are equal and they have the same size.
1185 */
1186impl<T, S> PartialEq<MatrixView<T, S>> for Matrix<T>
1187where
1188 T: PartialEq,
1189 S: MatrixRef<T>,
1190{
1191 #[inline]
1192 fn eq(&self, other: &MatrixView<T, S>) -> bool {
1193 matrix_equality(&self, &other.source)
1194 }
1195}
1196
1197#[test]
1198fn creating_matrix_views_erased() {
1199 let matrix = Matrix::from(vec![vec![1.0]]);
1200 let boxed: Box<dyn MatrixMut<f32>> = Box::new(matrix);
1201 let mut view = MatrixView::from(boxed);
1202 view.set(0, 0, view.get(0, 0) + 1.0);
1203 assert_eq!(2.0, view.get(0, 0));
1204}