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}