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