easy_ml/matrices/mod.rs
1/*!
2 * Generic matrix type.
3 *
4 * Matrices are generic over some type `T`. If `T` is [Numeric](super::numeric) then
5 * the matrix can be used in a mathematical way.
6 */
7
8#[cfg(feature = "serde")]
9use serde::Serialize;
10
11mod errors;
12pub mod iterators;
13pub mod operations;
14pub mod slices;
15pub mod views;
16
17pub use errors::ScalarConversionError;
18
19use crate::linear_algebra;
20use crate::matrices::iterators::*;
21use crate::matrices::slices::Slice2D;
22use crate::matrices::views::{
23 IndexRange, MatrixMask, MatrixPart, MatrixQuadrants, MatrixRange, MatrixReverse, MatrixView,
24 Reverse,
25};
26use crate::numeric::extra::{Real, RealRef};
27use crate::numeric::{Numeric, NumericRef};
28
29use std::num::NonZeroUsize;
30
31/**
32 * A general purpose matrix of some type. This type may implement
33 * no traits, in which case the matrix will be rather useless. If the
34 * type implements [`Clone`] most storage and accessor methods are defined and if the type
35 * implements [`Numeric`](super::numeric) then the matrix can be used in
36 * a mathematical way.
37 *
38 * When doing numeric operations with Matrices you should be careful to not
39 * consume a matrix by accidentally using it by value. All the operations are
40 * also defined on references to matrices so you should favor `&x * &y` style
41 * notation for matrices you intend to continue using. There are also convenience
42 * operations defined for a matrix and a scalar.
43 *
44 * # Matrix size invariants
45 *
46 * Matrices must always be at least 1x1. You cannot construct a matrix with no rows or
47 * no columns, and any function that resizes matrices will error if you try to use it
48 * in a way that would construct a 0x1, 1x0, or 0x0 matrix. The maximum size of a matrix
49 * is dependent on the platform's `std::isize::MAX` value. Matrices with dimensions NxM
50 * such that N * M < `std::isize::MAX` should not cause any errors in this library, but
51 * attempting to expand their size further may cause panics and or errors. At the time of
52 * writing it is no longer possible to construct or use matrices where the product of their
53 * number of rows and columns exceed `std::isize::MAX`, but some constructor methods may be used
54 * to attempt this. Concerned readers should note that on a 64 bit computer this maximum
55 * value is 9,223,372,036,854,775,807 so running out of memory is likely to occur first.
56 *
57 * # Matrix layout and iterator performance
58 *
59 * [See iterators submodule for Matrix layout and iterator performance](iterators#matrix-layout-and-iterator-performance)
60 *
61 * # Matrix operations
62 *
63 * [See operations submodule](operations)
64 */
65#[derive(Debug)]
66#[cfg_attr(feature = "serde", derive(Serialize))]
67pub struct Matrix<T> {
68 data: Vec<T>,
69 rows: Row,
70 columns: Column,
71}
72
73/// The maximum row and column lengths are usize, due to the internal storage being backed by Vec
74pub type Row = usize;
75/// The maximum row and column lengths are usize, due to the internal storage being backed by Vec
76pub type Column = usize;
77
78/**
79 * Methods for matrices of any type, including non numerical types such as bool.
80 */
81impl<T> Matrix<T> {
82 /**
83 * Creates a 1x1 matrix from some scalar
84 */
85 pub fn from_scalar(value: T) -> Matrix<T> {
86 Matrix {
87 data: vec![value],
88 rows: 1,
89 columns: 1,
90 }
91 }
92
93 /**
94 * Creates a row vector (1xN) from a list
95 *
96 * # Panics
97 *
98 * Panics if no values are provided. Note: this method erroneously did not validate its inputs
99 * in Easy ML versions up to and including 1.7.0
100 */
101 #[track_caller]
102 pub fn row(values: Vec<T>) -> Matrix<T> {
103 assert!(!values.is_empty(), "No values provided");
104 Matrix {
105 columns: values.len(),
106 data: values,
107 rows: 1,
108 }
109 }
110
111 /**
112 * Creates a column vector (Nx1) from a list
113 *
114 * # Panics
115 *
116 * Panics if no values are provided. Note: this method erroneously did not validate its inputs
117 * in Easy ML versions up to and including 1.7.0
118 */
119 #[track_caller]
120 pub fn column(values: Vec<T>) -> Matrix<T> {
121 assert!(!values.is_empty(), "No values provided");
122 Matrix {
123 rows: values.len(),
124 data: values,
125 columns: 1,
126 }
127 }
128
129 /**
130 * Creates a matrix from a nested array of values, each inner vector
131 * being a row, and hence the outer vector containing all rows in sequence, the
132 * same way as when writing matrices in mathematics.
133 *
134 * Example of a 2 x 3 matrix in both notations:
135 * ```ignore
136 * [
137 * 1, 2, 4
138 * 8, 9, 3
139 * ]
140 * ```
141 * ```
142 * use easy_ml::matrices::Matrix;
143 * Matrix::from(vec![
144 * vec![ 1, 2, 4 ],
145 * vec![ 8, 9, 3 ]
146 * ]);
147 * ```
148 *
149 * # Panics
150 *
151 * Panics if the input is jagged or rows or column length is 0.
152 */
153 #[track_caller]
154 pub fn from(mut values: Vec<Vec<T>>) -> Matrix<T> {
155 assert!(!values.is_empty(), "No rows defined");
156 // check length of first row is > 1
157 assert!(!values[0].is_empty(), "No column defined");
158 // check length of each row is the same
159 assert!(
160 values.iter().map(|x| x.len()).all(|x| x == values[0].len()),
161 "Inconsistent size"
162 );
163 // flatten the data into a row major layout
164 let rows = values.len();
165 let columns = values[0].len();
166 let mut data = Vec::with_capacity(rows * columns);
167 let mut value_stream = values.drain(..);
168 for _ in 0..rows {
169 let mut value_row_stream = value_stream.next().unwrap();
170 let mut row_of_values = value_row_stream.drain(..);
171 for _ in 0..columns {
172 data.push(row_of_values.next().unwrap());
173 }
174 }
175 Matrix {
176 data,
177 rows,
178 columns,
179 }
180 }
181
182 /**
183 * Creates a matrix with the specified size from a row major vec of data.
184 * The length of the vec must match the size of the matrix or the constructor
185 * will panic.
186 *
187 * Example of a 2 x 3 matrix in both notations:
188 * ```ignore
189 * [
190 * 1, 2, 4
191 * 8, 9, 3
192 * ]
193 * ```
194 * ```
195 * use easy_ml::matrices::Matrix;
196 * Matrix::from_flat_row_major((2, 3), vec![
197 * 1, 2, 4,
198 * 8, 9, 3
199 * ]);
200 * ```
201 *
202 * This method is more efficient than [`Matrix::from`](Matrix::from())
203 * but requires specifying the size explicitly and manually keeping track of where rows
204 * start and stop.
205 *
206 * # Panics
207 *
208 * Panics if the length of the vec does not match the size of the matrix, or no values are
209 * provided. Note: this method erroneously did not validate its inputs were not empty in
210 * Easy ML versions up to and including 1.7.0
211 */
212 #[track_caller]
213 pub fn from_flat_row_major(size: (Row, Column), values: Vec<T>) -> Matrix<T> {
214 assert!(
215 size.0 * size.1 == values.len(),
216 "Inconsistent size, attempted to construct a {}x{} matrix but provided with {} elements.",
217 size.0,
218 size.1,
219 values.len()
220 );
221 assert!(!values.is_empty(), "No values provided");
222 Matrix {
223 data: values,
224 rows: size.0,
225 columns: size.1,
226 }
227 }
228
229 /**
230 * Creates a matrix with the specified size initalised from a function.
231 *
232 * ```
233 * use easy_ml::matrices::Matrix;
234 * let matrix = Matrix::from_fn((4, 4), |(r, c)| r * c);
235 * assert_eq!(
236 * matrix,
237 * Matrix::from(vec![
238 * vec![ 0, 0, 0, 0 ],
239 * vec![ 0, 1, 2, 3 ],
240 * vec![ 0, 2, 4, 6 ],
241 * vec![ 0, 3, 6, 9 ],
242 * ])
243 * );
244 * ```
245 *
246 * # Panics
247 *
248 * Panics if the size has 0 rows or columns.
249 */
250 #[track_caller]
251 pub fn from_fn<F>(size: (Row, Column), mut producer: F) -> Matrix<T>
252 where
253 F: FnMut((Row, Column)) -> T,
254 {
255 use crate::tensors::indexing::ShapeIterator;
256 let length = size.0 * size.1;
257 let mut data = Vec::with_capacity(length);
258 let iterator = ShapeIterator::from([("row", size.0), ("column", size.1)]);
259 for [r, c] in iterator {
260 data.push(producer((r, c)));
261 }
262 Matrix::from_flat_row_major(size, data)
263 }
264
265 #[deprecated(
266 since = "1.1.0",
267 note = "Incorrect use of terminology, a unit matrix is another term for an identity matrix, please use `from_scalar` instead"
268 )]
269 pub fn unit(value: T) -> Matrix<T> {
270 Matrix::from_scalar(value)
271 }
272
273 /**
274 * Returns the dimensionality of this matrix in Row, Column format
275 */
276 pub fn size(&self) -> (Row, Column) {
277 (self.rows, self.columns)
278 }
279
280 /**
281 * Gets the number of rows in this matrix.
282 */
283 pub fn rows(&self) -> Row {
284 self.rows
285 }
286
287 /**
288 * Gets the number of columns in this matrix.
289 */
290 pub fn columns(&self) -> Column {
291 self.columns
292 }
293
294 /**
295 * Matrix data is stored as row major, so each row is stored as
296 * adjacent items going through the different columns. Therefore,
297 * to index this flattened representation we jump down in row sized
298 * blocks to reach the correct row, and then jump further equal to
299 * the column. The confusing thing is that the number of columns
300 * this matrix has is the length of each of the rows in this matrix,
301 * and vice versa.
302 */
303 fn get_index(&self, row: Row, column: Column) -> usize {
304 column + (row * self.columns())
305 }
306
307 /**
308 * The reverse of [get_index], converts from the flattened storage
309 * in memory into the row and column to index at this position.
310 *
311 * Matrix data is stored as row major, so each multiple of the number
312 * of columns starts a new row, and each index modulo the columns
313 * gives the column.
314 */
315 #[allow(dead_code)]
316 fn get_row_column(&self, index: usize) -> (Row, Column) {
317 (index / self.columns(), index % self.columns())
318 }
319
320 /**
321 * Gets a reference to the value at this row and column. Rows and Columns are 0 indexed.
322 *
323 * # Panics
324 *
325 * Panics if the index is out of range.
326 */
327 #[track_caller]
328 pub fn get_reference(&self, row: Row, column: Column) -> &T {
329 assert!(row < self.rows(), "Row out of index");
330 assert!(column < self.columns(), "Column out of index");
331 &self.data[self.get_index(row, column)]
332 }
333
334 /**
335 * Gets a mutable reference to the value at this row and column.
336 * Rows and Columns are 0 indexed.
337 *
338 * # Panics
339 *
340 * Panics if the index is out of range.
341 */
342 #[track_caller]
343 pub fn get_reference_mut(&mut self, row: Row, column: Column) -> &mut T {
344 assert!(row < self.rows(), "Row out of index");
345 assert!(column < self.columns(), "Column out of index");
346 let index = self.get_index(row, column);
347 // borrow for get_index ends
348 &mut self.data[index]
349 }
350
351 /**
352 * Not public API because don't want to name clash with the method on MatrixRef
353 * that calls this.
354 */
355 pub(crate) fn _try_get_reference(&self, row: Row, column: Column) -> Option<&T> {
356 if row < self.rows() && column < self.columns() {
357 Some(&self.data[self.get_index(row, column)])
358 } else {
359 None
360 }
361 }
362
363 /**
364 * Not public API because don't want to name clash with the method on MatrixRef
365 * that calls this.
366 */
367 pub(crate) unsafe fn _get_reference_unchecked(&self, row: Row, column: Column) -> &T {
368 unsafe { self.data.get_unchecked(self.get_index(row, column)) }
369 }
370
371 /**
372 * Sets a new value to this row and column. Rows and Columns are 0 indexed.
373 *
374 * # Panics
375 *
376 * Panics if the index is out of range.
377 */
378 #[track_caller]
379 pub fn set(&mut self, row: Row, column: Column, value: T) {
380 assert!(row < self.rows(), "Row out of index");
381 assert!(column < self.columns(), "Column out of index");
382 let index = self.get_index(row, column);
383 // borrow for get_index ends
384 self.data[index] = value;
385 }
386
387 /**
388 * Not public API because don't want to name clash with the method on MatrixMut
389 * that calls this.
390 */
391 pub(crate) fn _try_get_reference_mut(&mut self, row: Row, column: Column) -> Option<&mut T> {
392 if row < self.rows() && column < self.columns() {
393 let index = self.get_index(row, column);
394 // borrow for get_index ends
395 Some(&mut self.data[index])
396 } else {
397 None
398 }
399 }
400
401 /**
402 * Not public API because don't want to name clash with the method on MatrixMut
403 * that calls this.
404 */
405 pub(crate) unsafe fn _get_reference_unchecked_mut(
406 &mut self,
407 row: Row,
408 column: Column,
409 ) -> &mut T {
410 unsafe {
411 let index = self.get_index(row, column);
412 // borrow for get_index ends
413 self.data.get_unchecked_mut(index)
414 }
415 }
416
417 /**
418 * Removes a row from this Matrix, shifting all other rows to the left.
419 * Rows are 0 indexed.
420 *
421 * # Panics
422 *
423 * This will panic if the row does not exist or the matrix only has one row.
424 */
425 #[track_caller]
426 pub fn remove_row(&mut self, row: Row) {
427 assert!(self.rows() > 1);
428 let mut r = 0;
429 let mut c = 0;
430 // drop the values at the specified row
431 let columns = self.columns();
432 self.data.retain(|_| {
433 let keep = r != row;
434 if c < (columns - 1) {
435 c += 1;
436 } else {
437 r += 1;
438 c = 0;
439 }
440 keep
441 });
442 self.rows -= 1;
443 }
444
445 /**
446 * Removes a column from this Matrix, shifting all other columns to the left.
447 * Columns are 0 indexed.
448 *
449 * # Panics
450 *
451 * This will panic if the column does not exist or the matrix only has one column.
452 */
453 #[track_caller]
454 pub fn remove_column(&mut self, column: Column) {
455 assert!(self.columns() > 1);
456 let mut r = 0;
457 let mut c = 0;
458 // drop the values at the specified column
459 let columns = self.columns();
460 self.data.retain(|_| {
461 let keep = c != column;
462 if c < (columns - 1) {
463 c += 1;
464 } else {
465 r += 1;
466 c = 0;
467 }
468 keep
469 });
470 self.columns -= 1;
471 }
472
473 /**
474 * Returns an iterator over references to a column vector in this matrix.
475 * Columns are 0 indexed.
476 *
477 * # Panics
478 *
479 * Panics if the column does not exist in this matrix.
480 */
481 #[track_caller]
482 pub fn column_reference_iter(&self, column: Column) -> ColumnReferenceIterator<'_, T> {
483 ColumnReferenceIterator::new(self, column)
484 }
485
486 /**
487 * Returns an iterator over references to a row vector in this matrix.
488 * Rows are 0 indexed.
489 *
490 * # Panics
491 *
492 * Panics if the row does not exist in this matrix.
493 */
494 #[track_caller]
495 pub fn row_reference_iter(&self, row: Row) -> RowReferenceIterator<'_, T> {
496 RowReferenceIterator::new(self, row)
497 }
498
499 /**
500 * Returns an iterator over mutable references to a column vector in this matrix.
501 * Columns are 0 indexed.
502 *
503 * # Panics
504 *
505 * Panics if the column does not exist in this matrix.
506 */
507 #[track_caller]
508 pub fn column_reference_mut_iter(
509 &mut self,
510 column: Column,
511 ) -> ColumnReferenceMutIterator<'_, T> {
512 ColumnReferenceMutIterator::new(self, column)
513 }
514
515 /**
516 * Returns an iterator over mutable references to a row vector in this matrix.
517 * Rows are 0 indexed.
518 *
519 * # Panics
520 *
521 * Panics if the row does not exist in this matrix.
522 */
523 #[track_caller]
524 pub fn row_reference_mut_iter(&mut self, row: Row) -> RowReferenceMutIterator<'_, T> {
525 RowReferenceMutIterator::new(self, row)
526 }
527
528 /**
529 * Returns a column major iterator over references to all values in this matrix,
530 * proceeding through each column in order.
531 */
532 pub fn column_major_reference_iter(&self) -> ColumnMajorReferenceIterator<'_, T> {
533 ColumnMajorReferenceIterator::new(self)
534 }
535
536 /**
537 * Returns a row major iterator over references to all values in this matrix,
538 * proceeding through each row in order.
539 */
540 pub fn row_major_reference_iter(&self) -> RowMajorReferenceIterator<'_, T> {
541 RowMajorReferenceIterator::new(self)
542 }
543
544 // Non public row major reference iterator since we don't want to expose our implementation
545 // details to public API since then we could never change them.
546 pub(crate) fn direct_row_major_reference_iter(&self) -> std::slice::Iter<'_, T> {
547 self.data.iter()
548 }
549
550 // Non public row major reference iterator since we don't want to expose our implementation
551 // details to public API since then we could never change them.
552 pub(crate) fn direct_row_major_reference_iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
553 self.data.iter_mut()
554 }
555
556 /**
557 * Returns a column major iterator over mutable references to all values in this matrix,
558 * proceeding through each column in order.
559 */
560 pub fn column_major_reference_mut_iter(&mut self) -> ColumnMajorReferenceMutIterator<'_, T> {
561 ColumnMajorReferenceMutIterator::new(self)
562 }
563
564 /**
565 * Returns a row major iterator over mutable references to all values in this matrix,
566 * proceeding through each row in order.
567 */
568 pub fn row_major_reference_mut_iter(&mut self) -> RowMajorReferenceMutIterator<'_, T> {
569 RowMajorReferenceMutIterator::new(self)
570 }
571
572 /**
573 * Creates a column major iterator over all values in this matrix,
574 * proceeding through each column in order.
575 */
576 pub fn column_major_owned_iter(self) -> ColumnMajorOwnedIterator<T>
577 where
578 T: Default,
579 {
580 ColumnMajorOwnedIterator::new(self)
581 }
582
583 /**
584 * Creates a row major iterator over all values in this matrix,
585 * proceeding through each row in order.
586 */
587 pub fn row_major_owned_iter(self) -> RowMajorOwnedIterator<T>
588 where
589 T: Default,
590 {
591 RowMajorOwnedIterator::new(self)
592 }
593
594 /**
595 * Returns an iterator over references to the main diagonal in this matrix.
596 */
597 pub fn diagonal_reference_iter(&self) -> DiagonalReferenceIterator<'_, T> {
598 DiagonalReferenceIterator::new(self)
599 }
600
601 /**
602 * Returns an iterator over mutable references to the main diagonal in this matrix.
603 */
604 pub fn diagonal_reference_mut_iter(&mut self) -> DiagonalReferenceMutIterator<'_, T> {
605 DiagonalReferenceMutIterator::new(self)
606 }
607
608 /**
609 * Shrinks this matrix down from its current MxN size down to
610 * some new size OxP where O and P are determined by the kind of
611 * slice given and 1 <= O <= M and 1 <= P <= N.
612 *
613 * Only rows and columns specified by the slice will be retained, so for
614 * instance if the Slice is constructed by
615 * `Slice2D::new().rows(Slice::Range(0..2)).columns(Slice::Range(0..3))` then the
616 * modified matrix will be no bigger than 2x3 and contain up to the first two
617 * rows and first three columns that it previously had.
618 *
619 * See [Slice](slices::Slice) for constructing slices.
620 *
621 * # Panics
622 *
623 * This function will panic if the slice would delete all rows or all columns
624 * from this matrix, ie the resulting matrix must be at least 1x1.
625 */
626 #[track_caller]
627 pub fn retain_mut(&mut self, slice: Slice2D) {
628 let mut r = 0;
629 let mut c = 0;
630 // drop the values rejected by the slice
631 let columns = self.columns();
632 self.data.retain(|_| {
633 let keep = slice.accepts(r, c);
634 if c < (columns - 1) {
635 c += 1;
636 } else {
637 r += 1;
638 c = 0;
639 }
640 keep
641 });
642 // work out the resulting size of this matrix by using the non
643 // public fields of the Slice2D to handle each row and column
644 // seperately.
645 let remaining_rows = {
646 let mut accepted = 0;
647 for i in 0..self.rows() {
648 if slice.rows.accepts(i) {
649 accepted += 1;
650 }
651 }
652 accepted
653 };
654 let remaining_columns = {
655 let mut accepted = 0;
656 for i in 0..self.columns() {
657 if slice.columns.accepts(i) {
658 accepted += 1;
659 }
660 }
661 accepted
662 };
663 assert!(
664 remaining_rows > 0,
665 "Provided slice must leave at least 1 row in the retained matrix"
666 );
667 assert!(
668 remaining_columns > 0,
669 "Provided slice must leave at least 1 column in the retained matrix"
670 );
671 assert!(
672 !self.data.is_empty(),
673 "Provided slice must leave at least 1 row and 1 column in the retained matrix"
674 );
675 self.rows = remaining_rows;
676 self.columns = remaining_columns
677 // By construction jagged slices should be impossible, if this
678 // invariant later changes by accident it would be possible to break the
679 // rectangle shape invariant on a matrix object
680 // As Slice2D should prevent the construction of jagged slices no
681 // check is here to detect if all rows are still the same length
682 }
683
684 /**
685 * Consumes a 1x1 matrix and converts it into a scalar without copying the data.
686 *
687 * # Example
688 *
689 * ```
690 * use easy_ml::matrices::Matrix;
691 * # fn main() -> Result<(), Box<dyn std::error::Error>> {
692 * let x = Matrix::column(vec![ 1.0, 2.0, 3.0 ]);
693 * let sum_of_squares: f64 = (x.transpose() * x).try_into_scalar()?;
694 * # Ok(())
695 * # }
696 * ```
697 */
698 pub fn try_into_scalar(self) -> Result<T, ScalarConversionError> {
699 if self.size() == (1, 1) {
700 Ok(self.data.into_iter().next().unwrap())
701 } else {
702 Err(ScalarConversionError {})
703 }
704 }
705
706 /**
707 * Partition a matrix into an arbitary number of non overlapping parts.
708 *
709 * **This function is much like a hammer you should be careful to not overuse. If you don't need
710 * to mutate the parts of the matrix data individually it will be much easier and less error
711 * prone to create immutable views into the matrix using [MatrixRange] instead.**
712 *
713 * Parts are returned in row major order, forming a grid of slices into the Matrix data that
714 * can be mutated independently.
715 *
716 * # Panics
717 *
718 * Panics if any row or column index is greater than the number of rows or columns in the
719 * matrix. Each list of row partitions and column partitions must also be in ascending order.
720 *
721 * # Further Info
722 *
723 * The partitions form the boundries between each slice of matrix data. Hence, for each
724 * dimension, each partition may range between 0 and the length of the dimension inclusive.
725 *
726 * For one dimension of length 5, you can supply 0 up to 6 partitions,
727 * `[0,1,2,3,4,5]` would split that dimension into 7, 0 to 0, 0 to 1, 1 to 2,
728 * 2 to 3, 3 to 4, 4 to 5 and 5 to 5. 0 to 0 and 5 to 5 would of course be empty and the
729 * 5 parts in between would each be of length 1 along that dimension.
730 * `[2,4]` would instead split that dimension into three parts of 0 to 2, 2 to 4, and 4 to 5.
731 * `[]` would not split that dimension at all, and give a single part of 0 to 5.
732 *
733 * `partition` does this along both dimensions, and returns the parts in row major order, so
734 * you will receive a list of R+1 * C+1 length where R is the length of the row partitions
735 * provided and C is the length of the column partitions provided. If you just want to split
736 * a matrix into a 2x2 grid see [`partition_quadrants`](Matrix::partition_quadrants) which
737 * provides a dedicated API with more ergonomics for extracting the parts.
738 */
739 #[track_caller]
740 pub fn partition(
741 &mut self,
742 row_partitions: &[Row],
743 column_partitions: &[Column],
744 ) -> Vec<MatrixView<T, MatrixPart<'_, T>>> {
745 let rows = self.rows();
746 let columns = self.columns();
747 fn check_axis(partitions: &[usize], length: usize) {
748 let mut previous: Option<usize> = None;
749 for &index in partitions {
750 assert!(index <= length);
751 previous = match previous {
752 None => Some(index),
753 Some(i) => {
754 assert!(index > i, "{:?} must be ascending", partitions);
755 Some(i)
756 }
757 }
758 }
759 }
760 check_axis(row_partitions, rows);
761 check_axis(column_partitions, columns);
762
763 // There will be one more slice than partitions, since partitions are the boundries
764 // between slices.
765 let row_slices = row_partitions.len() + 1;
766 let column_slices = column_partitions.len() + 1;
767 let total_slices = row_slices * column_slices;
768 let mut slices: Vec<Vec<&mut [T]>> = Vec::with_capacity(total_slices);
769 let (_, mut data) = self.data.split_at_mut(0);
770
771 let mut index = 0;
772 for r in 0..row_slices {
773 let row_index = row_partitions.get(r).cloned().unwrap_or(rows);
774 // Determine how many rows of our matrix we need for the next set of row slices
775 let rows_included = row_index - index;
776 for _ in 0..column_slices {
777 slices.push(Vec::with_capacity(rows_included));
778 }
779 index = row_index;
780
781 for _ in 0..rows_included {
782 // Partition the next row of our matrix along the columns
783 let mut index = 0;
784 for c in 0..column_slices {
785 let column_index = column_partitions.get(c).cloned().unwrap_or(columns);
786 let columns_included = column_index - index;
787 index = column_index;
788 // Split off as many elements as included in this column slice
789 let (slice, rest) = data.split_at_mut(columns_included);
790 // Insert the slice into the slices, we'll push `rows_included` times into
791 // each slice Vec.
792 slices[(r * column_slices) + c].push(slice);
793 data = rest;
794 }
795 }
796 }
797 // rest is now empty, so we can ignore it.
798
799 slices
800 .into_iter()
801 .map(|slices| {
802 let rows = slices.len();
803 let columns = slices.first().map(|columns| columns.len()).unwrap_or(0);
804 if columns == 0 {
805 // We may have allocated N rows but if each column in that row has no size
806 // our actual size is 0x0
807 MatrixView::from(MatrixPart::new(slices, 0, 0))
808 } else {
809 MatrixView::from(MatrixPart::new(slices, rows, columns))
810 }
811 })
812 .collect()
813 }
814
815 /**
816 * Partition a matrix into 4 non overlapping quadrants. Top left starts at 0,0 until
817 * exclusive of row and column, bottom right starts at row and column to the end of the matrix.
818 *
819 * # Panics
820 *
821 * Panics if the row or column are greater than the number of rows or columns in the matrix.
822 *
823 * # Examples
824 *
825 * ```
826 * use easy_ml::matrices::Matrix;
827 * let mut matrix = Matrix::from(vec![
828 * vec![ 0, 1, 2 ],
829 * vec![ 3, 4, 5 ],
830 * vec![ 6, 7, 8 ]
831 * ]);
832 * // Split the matrix at the second row and first column giving 2x1, 2x2, 1x1 and 2x1
833 * // quadrants.
834 * // 0 | 1 2
835 * // 3 | 4 5
836 * // -------
837 * // 6 | 7 8
838 * let mut parts = matrix.partition_quadrants(2, 1);
839 * assert_eq!(parts.top_left, Matrix::column(vec![ 0, 3 ]));
840 * assert_eq!(parts.top_right, Matrix::from(vec![vec![ 1, 2 ], vec![ 4, 5 ]]));
841 * assert_eq!(parts.bottom_left, Matrix::column(vec![ 6 ]));
842 * assert_eq!(parts.bottom_right, Matrix::row(vec![ 7, 8 ]));
843 * // Modify the matrix data independently without worrying about the borrow checker
844 * parts.top_right.map_mut(|x| x + 10);
845 * parts.bottom_left.map_mut(|x| x - 10);
846 * // Drop MatrixQuadrants so we can use the matrix directly again
847 * std::mem::drop(parts);
848 * assert_eq!(matrix, Matrix::from(vec![
849 * vec![ 0, 11, 12 ],
850 * vec![ 3, 14, 15 ],
851 * vec![ -4, 7, 8 ]
852 * ]));
853 * ```
854 */
855 #[track_caller]
856 #[allow(clippy::needless_lifetimes)] // false positive?
857 pub fn partition_quadrants<'a>(
858 &'a mut self,
859 row: Row,
860 column: Column,
861 ) -> MatrixQuadrants<'a, T> {
862 let mut parts = self.partition(&[row], &[column]).into_iter();
863 // We know there will be exactly 4 parts returned by the partition since we provided
864 // 1 row and 1 column to partition ourself into 4 with.
865 MatrixQuadrants {
866 top_left: parts.next().unwrap(),
867 top_right: parts.next().unwrap(),
868 bottom_left: parts.next().unwrap(),
869 bottom_right: parts.next().unwrap(),
870 }
871 }
872
873 /**
874 * Returns a MatrixView giving a view of only the data within the row and column
875 * [IndexRange]s.
876 *
877 * This is a shorthand for constructing the MatrixView from this Matrix.
878 *
879 * ```
880 * use easy_ml::matrices::Matrix;
881 * use easy_ml::matrices::views::{MatrixView, MatrixRange, IndexRange};
882 * let ab = Matrix::from(vec![
883 * vec![ 0, 1, 2, 0 ],
884 * vec![ 3, 4, 5, 1 ]
885 * ]);
886 * let shorter = ab.range(0..2, 1..3);
887 * assert_eq!(
888 * shorter,
889 * Matrix::from(vec![
890 * vec![ 1, 2 ],
891 * vec![ 4, 5 ]
892 * ])
893 * );
894 * ```
895 */
896 pub fn range<R>(&self, rows: R, columns: R) -> MatrixView<T, MatrixRange<T, &Matrix<T>>>
897 where
898 R: Into<IndexRange>,
899 {
900 MatrixView::from(MatrixRange::from(self, rows, columns))
901 }
902
903 /**
904 * Returns a MatrixView giving a view of only the data within the row and column
905 * [IndexRange]s. The MatrixRange mutably borrows this Matrix, and can
906 * therefore mutate it.
907 *
908 * This is a shorthand for constructing the MatrixView from this Matrix.
909 */
910 pub fn range_mut<R>(
911 &mut self,
912 rows: R,
913 columns: R,
914 ) -> MatrixView<T, MatrixRange<T, &mut Matrix<T>>>
915 where
916 R: Into<IndexRange>,
917 {
918 MatrixView::from(MatrixRange::from(self, rows, columns))
919 }
920
921 /**
922 * Returns a MatrixView giving a view of only the data within the row and column
923 * [IndexRange]s. The MatrixRange takes ownership of this Matrix, and can
924 * therefore mutate it.
925 *
926 * This is a shorthand for constructing the MatrixView from this Matrix.
927 */
928 pub fn range_owned<R>(self, rows: R, columns: R) -> MatrixView<T, MatrixRange<T, Matrix<T>>>
929 where
930 R: Into<IndexRange>,
931 {
932 MatrixView::from(MatrixRange::from(self, rows, columns))
933 }
934
935 /**
936 * Returns a MatrixView giving a view of only the data outside the row and column
937 * [IndexRange]s.
938 *
939 * This is a shorthand for constructing the MatrixView from this Matrix.
940 *
941 * ```
942 * use easy_ml::matrices::Matrix;
943 * use easy_ml::matrices::views::{MatrixView, MatrixMask, IndexRange};
944 * let ab = Matrix::from(vec![
945 * vec![ 0, 1, 2, 0 ],
946 * vec![ 3, 4, 5, 1 ]
947 * ]);
948 * let shorter = ab.mask(0..1, 1..3);
949 * assert_eq!(
950 * shorter,
951 * Matrix::from(vec![
952 * vec![ 3, 1 ]
953 * ])
954 * );
955 * ```
956 */
957 pub fn mask<R>(&self, rows: R, columns: R) -> MatrixView<T, MatrixMask<T, &Matrix<T>>>
958 where
959 R: Into<IndexRange>,
960 {
961 MatrixView::from(MatrixMask::from(self, rows, columns))
962 }
963
964 /**
965 * Returns a MatrixView giving a view of only the data outside the row and column
966 * [IndexRange]s. The MatrixMask mutably borrows this Matrix, and can
967 * therefore mutate it.
968 *
969 * This is a shorthand for constructing the MatrixView from this Matrix.
970 */
971 pub fn mask_mut<R>(
972 &mut self,
973 rows: R,
974 columns: R,
975 ) -> MatrixView<T, MatrixMask<T, &mut Matrix<T>>>
976 where
977 R: Into<IndexRange>,
978 {
979 MatrixView::from(MatrixMask::from(self, rows, columns))
980 }
981
982 /**
983 * Returns a MatrixView giving a view of only the data outside the row and column
984 * [IndexRange]s. The MatrixMask takes ownership of this Matrix, and can
985 * therefore mutate it.
986 *
987 * This is a shorthand for constructing the MatrixView from this Matrix.
988 */
989 pub fn mask_owned<R>(self, rows: R, columns: R) -> MatrixView<T, MatrixMask<T, Matrix<T>>>
990 where
991 R: Into<IndexRange>,
992 {
993 MatrixView::from(MatrixMask::from(self, rows, columns))
994 }
995
996 /**
997 * Returns a MatrixView giving a view of only the data within the provided
998 * number of elements to retain at the start and end of the rows in the
999 * matrix.
1000 *
1001 * This is a shorthand for constructing the MatrixView from this Matrix.
1002 *
1003 * ```
1004 * use easy_ml::matrices::Matrix;
1005 * use easy_ml::matrices::views::{MatrixView, MatrixMask};
1006 * let ab = Matrix::from(vec![
1007 * vec![ 0, 1, 2, 0 ],
1008 * vec![ 3, 4, 5, 1 ],
1009 * vec![ 9, 2, 0, 2 ]
1010 * ]);
1011 * let shorter = ab.start_and_end_of_rows(1);
1012 * assert_eq!(
1013 * shorter,
1014 * Matrix::from(vec![
1015 * vec![ 0, 1, 2, 0 ],
1016 * vec![ 9, 2, 0, 2 ]
1017 * ])
1018 * );
1019 * ```
1020 *
1021 * # Panics
1022 *
1023 * - If the number of elements to retain at the start and end are 0
1024 */
1025 #[track_caller]
1026 pub fn start_and_end_of_rows(&self, retain: usize) -> MatrixView<T, MatrixMask<T, &Matrix<T>>> {
1027 match NonZeroUsize::new(retain) {
1028 None => panic!(
1029 "Number of rows to retain at start and end of matrix must be at least 1, 0 rows retained would remove all elements"
1030 ),
1031 Some(retain) => MatrixView::from(MatrixMask::start_and_end_of_rows(self, Some(retain))),
1032 }
1033 }
1034
1035 /**
1036 * Returns a MatrixView giving a view of only the data within the provided
1037 * number of elements to retain at the start and end of the rows in the
1038 * matrix. The MatrixMask mutably borrows this Matrix, and can
1039 * therefore mutate it.
1040 *
1041 * This is a shorthand for constructing the MatrixView from this Matrix.
1042 *
1043 * # Panics
1044 *
1045 * - If the number of elements to retain at the start and end are 0
1046 */
1047 #[track_caller]
1048 pub fn start_and_end_of_rows_mut(
1049 &mut self,
1050 retain: usize,
1051 ) -> MatrixView<T, MatrixMask<T, &mut Matrix<T>>> {
1052 match NonZeroUsize::new(retain) {
1053 None => panic!(
1054 "Number of rows to retain at start and end of matrix must be at least 1, 0 rows retained would remove all elements"
1055 ),
1056 Some(retain) => MatrixView::from(MatrixMask::start_and_end_of_rows(self, Some(retain))),
1057 }
1058 }
1059
1060 /**
1061 * Returns a MatrixView giving a view of only the data within the provided
1062 * number of elements to retain at the start and end of the rows in the
1063 * matrix. The MatrixMask takes ownership of this Matrix, and can
1064 * therefore mutate it.
1065 *
1066 * This is a shorthand for constructing the MatrixView from this Matrix.
1067 *
1068 * # Panics
1069 *
1070 * - If the number of elements to retain at the start and end are 0
1071 */
1072 #[track_caller]
1073 pub fn start_and_end_of_rows_owned(
1074 self,
1075 retain: usize,
1076 ) -> MatrixView<T, MatrixMask<T, Matrix<T>>> {
1077 match NonZeroUsize::new(retain) {
1078 None => panic!(
1079 "Number of rows to retain at start and end of matrix must be at least 1, 0 rows retained would remove all elements"
1080 ),
1081 Some(retain) => MatrixView::from(MatrixMask::start_and_end_of_rows(self, Some(retain))),
1082 }
1083 }
1084
1085 /**
1086 * Returns a MatrixView giving a view of only the data within the provided
1087 * number of elements to retain at the start and end of the columns in the
1088 * matrix.
1089 *
1090 * This is a shorthand for constructing the MatrixView from this Matrix.
1091 *
1092 * ```
1093 * use easy_ml::matrices::Matrix;
1094 * use easy_ml::matrices::views::{MatrixView, MatrixMask};
1095 * let ab = Matrix::from(vec![
1096 * vec![ 0, 1, 2, 0 ],
1097 * vec![ 3, 4, 5, 1 ],
1098 * vec![ 9, 2, 0, 2 ]
1099 * ]);
1100 * let shorter = ab.start_and_end_of_columns(1);
1101 * assert_eq!(
1102 * shorter,
1103 * Matrix::from(vec![
1104 * vec![ 0, 0 ],
1105 * vec![ 3, 1 ],
1106 * vec![ 9, 2 ]
1107 * ])
1108 * );
1109 * ```
1110 *
1111 * # Panics
1112 *
1113 * - If the number of elements to retain at the start and end are 0
1114 */
1115 #[track_caller]
1116 pub fn start_and_end_of_columns(
1117 &self,
1118 retain: usize,
1119 ) -> MatrixView<T, MatrixMask<T, &Matrix<T>>> {
1120 match NonZeroUsize::new(retain) {
1121 None => panic!(
1122 "Number of columns to retain at start and end of matrix must be at least 1, 0 columns retained would remove all elements"
1123 ),
1124 Some(retain) => {
1125 MatrixView::from(MatrixMask::start_and_end_of_columns(self, Some(retain)))
1126 }
1127 }
1128 }
1129
1130 /**
1131 * Returns a MatrixView giving a view of only the data within the provided
1132 * number of elements to retain at the start and end of the columns in the
1133 * matrix. The MatrixMask mutably borrows this Matrix, and can
1134 * therefore mutate it.
1135 *
1136 * This is a shorthand for constructing the MatrixView from this Matrix.
1137 *
1138 * # Panics
1139 *
1140 * - If the number of elements to retain at the start and end are 0
1141 */
1142 #[track_caller]
1143 pub fn start_and_end_of_columns_mut(
1144 &mut self,
1145 retain: usize,
1146 ) -> MatrixView<T, MatrixMask<T, &mut Matrix<T>>> {
1147 match NonZeroUsize::new(retain) {
1148 None => panic!(
1149 "Number of columns to retain at start and end of matrix must be at least 1, 0 columns retained would remove all elements"
1150 ),
1151 Some(retain) => {
1152 MatrixView::from(MatrixMask::start_and_end_of_columns(self, Some(retain)))
1153 }
1154 }
1155 }
1156
1157 /**
1158 * Returns a MatrixView giving a view of only the data within the provided
1159 * number of elements to retain at the start and end of the columns in the
1160 * matrix. The MatrixMask takes ownership of this Matrix, and can
1161 * therefore mutate it.
1162 *
1163 * This is a shorthand for constructing the MatrixView from this Matrix.
1164 *
1165 * # Panics
1166 *
1167 * - If the number of elements to retain at the start and end are 0
1168 */
1169 #[track_caller]
1170 pub fn start_and_end_of_columns_owned(
1171 self,
1172 retain: usize,
1173 ) -> MatrixView<T, MatrixMask<T, Matrix<T>>> {
1174 match NonZeroUsize::new(retain) {
1175 None => panic!(
1176 "Number of columns to retain at start and end of matrix must be at least 1, 0 columns retained would remove all elements"
1177 ),
1178 Some(retain) => {
1179 MatrixView::from(MatrixMask::start_and_end_of_columns(self, Some(retain)))
1180 }
1181 }
1182 }
1183
1184 /**
1185 * Returns a MatrixView with the rows and columns specified reversed in iteration
1186 * order. The data of this matrix and the dimension lengths remain unchanged.
1187 *
1188 * This is a shorthand for constructing the MatrixView from this Matrix.
1189 *
1190 * ```
1191 * use easy_ml::matrices::Matrix;
1192 * use easy_ml::matrices::views::{MatrixView, MatrixReverse, Reverse};
1193 * let ab = Matrix::from(vec![
1194 * vec![ 0, 1, 2 ],
1195 * vec![ 3, 4, 5 ]
1196 * ]);
1197 * let reversed = ab.reverse(Reverse { rows: true, ..Default::default() });
1198 * let also_reversed = MatrixView::from(
1199 * MatrixReverse::from(&ab, Reverse { rows: true, columns: false })
1200 * );
1201 * assert_eq!(reversed, also_reversed);
1202 * assert_eq!(
1203 * reversed,
1204 * Matrix::from(vec![
1205 * vec![ 3, 4, 5 ],
1206 * vec![ 0, 1, 2 ]
1207 * ])
1208 * );
1209 * ```
1210 */
1211 pub fn reverse(&self, reverse: Reverse) -> MatrixView<T, MatrixReverse<T, &Matrix<T>>> {
1212 MatrixView::from(MatrixReverse::from(self, reverse))
1213 }
1214
1215 /**
1216 * Returns a MatrixView with the rows and columns specified reversed in iteration
1217 * order. The data of this matrix and the dimension lengths remain unchanged. The MatrixReverse
1218 * mutably borrows this Matrix, and can therefore mutate it
1219 *
1220 * This is a shorthand for constructing the MatrixView from this Matrix.
1221 */
1222 pub fn reverse_mut(
1223 &mut self,
1224 reverse: Reverse,
1225 ) -> MatrixView<T, MatrixReverse<T, &mut Matrix<T>>> {
1226 MatrixView::from(MatrixReverse::from(self, reverse))
1227 }
1228
1229 /**
1230 * Returns a MatrixView with the rows and columns specified reversed in iteration
1231 * order. The data of this matrix and the dimension lengths remain unchanged. The MatrixReverse
1232 * takes ownership of this Matrix, and can therefore mutate it
1233 *
1234 * This is a shorthand for constructing the MatrixView from this Matrix.
1235 */
1236 pub fn reverse_owned(self, reverse: Reverse) -> MatrixView<T, MatrixReverse<T, Matrix<T>>> {
1237 MatrixView::from(MatrixReverse::from(self, reverse))
1238 }
1239
1240 /**
1241 * Converts this Matrix into a 2 dimensional Tensor with the provided dimension names.
1242 *
1243 * This is a wrapper around the `TryFrom<(Matrix<T>, [Dimension; 2])>` implementation.
1244 *
1245 * The Tensor will have the data in the same order, a shape with lengths of `self.rows()` then
1246 * `self.columns()` and the provided dimension names respectively.
1247 *
1248 * Result::Err is returned if the `rows` and `columns` dimension names are the same.
1249 */
1250 pub fn into_tensor(
1251 self,
1252 rows: crate::tensors::Dimension,
1253 columns: crate::tensors::Dimension,
1254 ) -> Result<crate::tensors::Tensor<T, 2>, crate::tensors::InvalidShapeError<2>> {
1255 (self, [rows, columns]).try_into()
1256 }
1257}
1258
1259/**
1260 * Methods for matrices with types that can be copied, but still not neccessarily numerical.
1261 */
1262impl<T: Clone> Matrix<T> {
1263 /**
1264 * Computes and returns the transpose of this matrix
1265 *
1266 * ```
1267 * use easy_ml::matrices::Matrix;
1268 * let x = Matrix::from(vec![
1269 * vec![ 1, 2 ],
1270 * vec![ 3, 4 ]]);
1271 * let y = Matrix::from(vec![
1272 * vec![ 1, 3 ],
1273 * vec![ 2, 4 ]]);
1274 * assert_eq!(x.transpose(), y);
1275 * ```
1276 */
1277 pub fn transpose(&self) -> Matrix<T> {
1278 Matrix::from_fn((self.columns(), self.rows()), |(column, row)| {
1279 self.get(row, column)
1280 })
1281 }
1282
1283 /**
1284 * Transposes the matrix in place (if it is square).
1285 *
1286 * ```
1287 * use easy_ml::matrices::Matrix;
1288 * let mut x = Matrix::from(vec![
1289 * vec![ 1, 2 ],
1290 * vec![ 3, 4 ]]);
1291 * x.transpose_mut();
1292 * let y = Matrix::from(vec![
1293 * vec![ 1, 3 ],
1294 * vec![ 2, 4 ]]);
1295 * assert_eq!(x, y);
1296 * ```
1297 *
1298 * Note: None square matrices were erroneously not supported in previous versions (<=1.8.0) and
1299 * could be incorrectly mutated. This method will now correctly transpose non square matrices
1300 * by not attempting to transpose them in place.
1301 */
1302 pub fn transpose_mut(&mut self) {
1303 if self.rows() != self.columns() {
1304 let transposed = self.transpose();
1305 self.data = transposed.data;
1306 self.rows = transposed.rows;
1307 self.columns = transposed.columns;
1308 } else {
1309 for i in 0..self.rows() {
1310 for j in 0..self.columns() {
1311 if i > j {
1312 continue;
1313 }
1314 let temp = self.get(i, j);
1315 self.set(i, j, self.get(j, i));
1316 self.set(j, i, temp);
1317 }
1318 }
1319 }
1320 }
1321
1322 /**
1323 * Returns an iterator over a column vector in this matrix. Columns are 0 indexed.
1324 *
1325 * If you have a matrix such as:
1326 * ```ignore
1327 * [
1328 * 1, 2, 3
1329 * 4, 5, 6
1330 * 7, 8, 9
1331 * ]
1332 * ```
1333 * then a column of 0, 1, and 2 will yield [1, 4, 7], [2, 5, 8] and [3, 6, 9]
1334 * respectively. If you do not need to copy the elements use
1335 * [`column_reference_iter`](Matrix::column_reference_iter) instead.
1336 *
1337 * # Panics
1338 *
1339 * Panics if the column does not exist in this matrix.
1340 */
1341 #[track_caller]
1342 pub fn column_iter(&self, column: Column) -> ColumnIterator<'_, T> {
1343 ColumnIterator::new(self, column)
1344 }
1345
1346 /**
1347 * Returns an iterator over a row vector in this matrix. Rows are 0 indexed.
1348 *
1349 * If you have a matrix such as:
1350 * ```ignore
1351 * [
1352 * 1, 2, 3
1353 * 4, 5, 6
1354 * 7, 8, 9
1355 * ]
1356 * ```
1357 * then a row of 0, 1, and 2 will yield [1, 2, 3], [4, 5, 6] and [7, 8, 9]
1358 * respectively. If you do not need to copy the elements use
1359 * [`row_reference_iter`](Matrix::row_reference_iter) instead.
1360 *
1361 * # Panics
1362 *
1363 * Panics if the row does not exist in this matrix.
1364 */
1365 #[track_caller]
1366 pub fn row_iter(&self, row: Row) -> RowIterator<'_, T> {
1367 RowIterator::new(self, row)
1368 }
1369
1370 /**
1371 * Returns a column major iterator over all values in this matrix, proceeding through each
1372 * column in order.
1373 *
1374 * If you have a matrix such as:
1375 * ```ignore
1376 * [
1377 * 1, 2
1378 * 3, 4
1379 * ]
1380 * ```
1381 * then the iterator will yield [1, 3, 2, 4]. If you do not need to copy the
1382 * elements use [`column_major_reference_iter`](Matrix::column_major_reference_iter) instead.
1383 */
1384 pub fn column_major_iter(&self) -> ColumnMajorIterator<'_, T> {
1385 ColumnMajorIterator::new(self)
1386 }
1387
1388 /**
1389 * Returns a row major iterator over all values in this matrix, proceeding through each
1390 * row in order.
1391 *
1392 * If you have a matrix such as:
1393 * ```ignore
1394 * [
1395 * 1, 2
1396 * 3, 4
1397 * ]
1398 * ```
1399 * then the iterator will yield [1, 2, 3, 4]. If you do not need to copy the
1400 * elements use [`row_major_reference_iter`](Matrix::row_major_reference_iter) instead.
1401 */
1402 pub fn row_major_iter(&self) -> RowMajorIterator<'_, T> {
1403 RowMajorIterator::new(self)
1404 }
1405
1406 /**
1407 * Returns a iterator over the main diagonal of this matrix.
1408 *
1409 * If you have a matrix such as:
1410 * ```ignore
1411 * [
1412 * 1, 2
1413 * 3, 4
1414 * ]
1415 * ```
1416 * then the iterator will yield [1, 4]. If you do not need to copy the
1417 * elements use [`diagonal_reference_iter`](Matrix::diagonal_reference_iter) instead.
1418 *
1419 * # Examples
1420 *
1421 * Computing a [trace](https://en.wikipedia.org/wiki/Trace_(linear_algebra))
1422 * ```
1423 * use easy_ml::matrices::Matrix;
1424 * let matrix = Matrix::from(vec![
1425 * vec![ 1, 2, 3 ],
1426 * vec![ 4, 5, 6 ],
1427 * vec![ 7, 8, 9 ],
1428 * ]);
1429 * let trace: i32 = matrix.diagonal_iter().sum();
1430 * assert_eq!(trace, 1 + 5 + 9);
1431 * ```
1432 */
1433 pub fn diagonal_iter(&self) -> DiagonalIterator<'_, T> {
1434 DiagonalIterator::new(self)
1435 }
1436
1437 /**
1438 * Creates a matrix of the provided size with all elements initialised to the provided value
1439 *
1440 * # Panics
1441 *
1442 * Panics if no values are provided. Note: this method erroneously did not validate its inputs
1443 * in Easy ML versions up to and including 1.7.0
1444 */
1445 #[track_caller]
1446 pub fn empty(value: T, size: (Row, Column)) -> Matrix<T> {
1447 assert!(size.0 > 0 && size.1 > 0, "Size must be at least 1x1");
1448 Matrix {
1449 data: vec![value; size.0 * size.1],
1450 rows: size.0,
1451 columns: size.1,
1452 }
1453 }
1454
1455 /**
1456 * Gets a copy of the value at this row and column. Rows and Columns are 0 indexed.
1457 *
1458 * # Panics
1459 *
1460 * Panics if the index is out of range.
1461 */
1462 #[track_caller]
1463 pub fn get(&self, row: Row, column: Column) -> T {
1464 assert!(
1465 row < self.rows(),
1466 "Row out of index, only have {} rows",
1467 self.rows()
1468 );
1469 assert!(
1470 column < self.columns(),
1471 "Column out of index, only have {} columns",
1472 self.columns()
1473 );
1474 self.data[self.get_index(row, column)].clone()
1475 }
1476
1477 /**
1478 * Similar to matrix.get(0, 0) in that this returns the element in the first
1479 * row and first column, except that this method will panic if the matrix is
1480 * not 1x1.
1481 *
1482 * This is provided as a convenience function when you want to convert a unit matrix
1483 * to a scalar, such as after taking a dot product of two vectors.
1484 *
1485 * # Example
1486 *
1487 * ```
1488 * use easy_ml::matrices::Matrix;
1489 * let x = Matrix::column(vec![ 1.0, 2.0, 3.0 ]);
1490 * let sum_of_squares: f64 = (x.transpose() * x).scalar();
1491 * ```
1492 *
1493 * # Panics
1494 *
1495 * Panics if the matrix is not 1x1
1496 */
1497 #[track_caller]
1498 pub fn scalar(&self) -> T {
1499 assert!(
1500 self.rows() == 1,
1501 "Cannot treat matrix as scalar as it has more than one row"
1502 );
1503 assert!(
1504 self.columns() == 1,
1505 "Cannot treat matrix as scalar as it has more than one column"
1506 );
1507 self.get(0, 0)
1508 }
1509
1510 /**
1511 * Applies a function to all values in the matrix, modifying
1512 * the matrix in place.
1513 */
1514 pub fn map_mut(&mut self, mapping_function: impl Fn(T) -> T) {
1515 for value in self.data.iter_mut() {
1516 *value = mapping_function(value.clone());
1517 }
1518 }
1519
1520 /**
1521 * Applies a function to all values and each value's index in the
1522 * matrix, modifying the matrix in place.
1523 */
1524 pub fn map_mut_with_index(&mut self, mapping_function: impl Fn(T, Row, Column) -> T) {
1525 self.row_major_reference_mut_iter()
1526 .with_index()
1527 .for_each(|((i, j), x)| {
1528 *x = mapping_function(x.clone(), i, j);
1529 });
1530 }
1531
1532 /**
1533 * Creates and returns a new matrix with all values from the original with the
1534 * function applied to each. This can be used to change the type of the matrix
1535 * such as creating a mask:
1536 * ```
1537 * use easy_ml::matrices::Matrix;
1538 * let x = Matrix::from(vec![
1539 * vec![ 0.0, 1.2 ],
1540 * vec![ 5.8, 6.9 ]]);
1541 * let y = x.map(|element| element > 2.0);
1542 * let result = Matrix::from(vec![
1543 * vec![ false, false ],
1544 * vec![ true, true ]]);
1545 * assert_eq!(&y, &result);
1546 * ```
1547 */
1548 pub fn map<U>(&self, mapping_function: impl Fn(T) -> U) -> Matrix<U>
1549 where
1550 U: Clone,
1551 {
1552 let mapped = self
1553 .data
1554 .iter()
1555 .map(|x| mapping_function(x.clone()))
1556 .collect();
1557 Matrix::from_flat_row_major(self.size(), mapped)
1558 }
1559
1560 /**
1561 * Creates and returns a new matrix with all values from the original
1562 * and the index of each value mapped by a function. This can be used
1563 * to perform elementwise operations that are not defined on the
1564 * Matrix type itself.
1565 *
1566 * # Exmples
1567 *
1568 * Matrix elementwise division:
1569 *
1570 * ```
1571 * use easy_ml::matrices::Matrix;
1572 * let x = Matrix::from(vec![
1573 * vec![ 9.0, 2.0 ],
1574 * vec![ 4.0, 3.0 ]]);
1575 * let y = Matrix::from(vec![
1576 * vec![ 3.0, 2.0 ],
1577 * vec![ 1.0, 3.0 ]]);
1578 * let z = x.map_with_index(|x, row, column| x / y.get(row, column));
1579 * let result = Matrix::from(vec![
1580 * vec![ 3.0, 1.0 ],
1581 * vec![ 4.0, 1.0 ]]);
1582 * assert_eq!(&z, &result);
1583 * ```
1584 */
1585 pub fn map_with_index<U>(&self, mapping_function: impl Fn(T, Row, Column) -> U) -> Matrix<U>
1586 where
1587 U: Clone,
1588 {
1589 let mapped = self
1590 .row_major_iter()
1591 .with_index()
1592 .map(|((i, j), x)| mapping_function(x, i, j))
1593 .collect();
1594 Matrix::from_flat_row_major(self.size(), mapped)
1595 }
1596
1597 /**
1598 * Inserts a new row into the Matrix at the provided index,
1599 * shifting other rows to the right and filling all entries with the
1600 * provided value. Rows are 0 indexed.
1601 *
1602 * # Panics
1603 *
1604 * This will panic if the row is greater than the number of rows in the matrix.
1605 */
1606 #[track_caller]
1607 pub fn insert_row(&mut self, row: Row, value: T) {
1608 assert!(
1609 row <= self.rows(),
1610 "Row to insert must be <= to {}",
1611 self.rows()
1612 );
1613 for column in 0..self.columns() {
1614 self.data.insert(self.get_index(row, column), value.clone());
1615 }
1616 self.rows += 1;
1617 }
1618
1619 /**
1620 * Inserts a new row into the Matrix at the provided index, shifting other rows
1621 * to the right and filling all entries with the values from the iterator in sequence.
1622 * Rows are 0 indexed.
1623 *
1624 * # Panics
1625 *
1626 * This will panic if the row is greater than the number of rows in the matrix,
1627 * or if the iterator has fewer elements than `self.columns()`.
1628 *
1629 * Example of duplicating a row:
1630 * ```
1631 * use easy_ml::matrices::Matrix;
1632 * let x: Matrix<u8> = Matrix::row(vec![ 1, 2, 3 ]);
1633 * let mut y = x.clone();
1634 * // duplicate the first row as the second row
1635 * y.insert_row_with(1, x.row_iter(0));
1636 * assert_eq!((2, 3), y.size());
1637 * let mut values = y.column_major_iter();
1638 * assert_eq!(Some(1), values.next());
1639 * assert_eq!(Some(1), values.next());
1640 * assert_eq!(Some(2), values.next());
1641 * assert_eq!(Some(2), values.next());
1642 * assert_eq!(Some(3), values.next());
1643 * assert_eq!(Some(3), values.next());
1644 * assert_eq!(None, values.next());
1645 * ```
1646 */
1647 #[track_caller]
1648 pub fn insert_row_with<I>(&mut self, row: Row, mut values: I)
1649 where
1650 I: Iterator<Item = T>,
1651 {
1652 assert!(
1653 row <= self.rows(),
1654 "Row to insert must be <= to {}",
1655 self.rows()
1656 );
1657 for column in 0..self.columns() {
1658 self.data.insert(
1659 self.get_index(row, column),
1660 values.next().unwrap_or_else(|| {
1661 panic!("At least {} values must be provided", self.columns())
1662 }),
1663 );
1664 }
1665 self.rows += 1;
1666 }
1667
1668 /**
1669 * Inserts a new column into the Matrix at the provided index, shifting other
1670 * columns to the right and filling all entries with the provided value.
1671 * Columns are 0 indexed.
1672 *
1673 * # Panics
1674 *
1675 * This will panic if the column is greater than the number of columns in the matrix.
1676 */
1677 #[track_caller]
1678 pub fn insert_column(&mut self, column: Column, value: T) {
1679 assert!(
1680 column <= self.columns(),
1681 "Column to insert must be <= to {}",
1682 self.columns()
1683 );
1684 for row in (0..self.rows()).rev() {
1685 self.data.insert(self.get_index(row, column), value.clone());
1686 }
1687 self.columns += 1;
1688 }
1689
1690 /**
1691 * Inserts a new column into the Matrix at the provided index, shifting other columns
1692 * to the right and filling all entries with the values from the iterator in sequence.
1693 * Columns are 0 indexed.
1694 *
1695 * # Panics
1696 *
1697 * This will panic if the column is greater than the number of columns in the matrix,
1698 * or if the iterator has fewer elements than `self.rows()`.
1699 *
1700 * Example of duplicating a column:
1701 * ```
1702 * use easy_ml::matrices::Matrix;
1703 * let x: Matrix<u8> = Matrix::column(vec![ 1, 2, 3 ]);
1704 * let mut y = x.clone();
1705 * // duplicate the first column as the second column
1706 * y.insert_column_with(1, x.column_iter(0));
1707 * assert_eq!((3, 2), y.size());
1708 * let mut values = y.column_major_iter();
1709 * assert_eq!(Some(1), values.next());
1710 * assert_eq!(Some(2), values.next());
1711 * assert_eq!(Some(3), values.next());
1712 * assert_eq!(Some(1), values.next());
1713 * assert_eq!(Some(2), values.next());
1714 * assert_eq!(Some(3), values.next());
1715 * assert_eq!(None, values.next());
1716 * ```
1717 */
1718 #[track_caller]
1719 pub fn insert_column_with<I>(&mut self, column: Column, values: I)
1720 where
1721 I: Iterator<Item = T>,
1722 {
1723 assert!(
1724 column <= self.columns(),
1725 "Column to insert must be <= to {}",
1726 self.columns()
1727 );
1728 let mut array_values = values.collect::<Vec<T>>();
1729 assert!(
1730 array_values.len() >= self.rows(),
1731 "At least {} values must be provided",
1732 self.rows()
1733 );
1734 for row in (0..self.rows()).rev() {
1735 self.data
1736 .insert(self.get_index(row, column), array_values.pop().unwrap());
1737 }
1738 self.columns += 1;
1739 }
1740
1741 /**
1742 * Makes a copy of this matrix shrunk down in size according to the slice. See
1743 * [retain_mut](Matrix::retain_mut()).
1744 */
1745 pub fn retain(&self, slice: Slice2D) -> Matrix<T> {
1746 let mut retained = self.clone();
1747 retained.retain_mut(slice);
1748 retained
1749 }
1750}
1751
1752/**
1753 * Any matrix of a Cloneable type implements Clone.
1754 */
1755impl<T: Clone> Clone for Matrix<T> {
1756 fn clone(&self) -> Self {
1757 self.map(|element| element)
1758 }
1759}
1760
1761/**
1762 * Any matrix of a Displayable type implements Display
1763 *
1764 * You can control the precision of the formatting using format arguments, i.e.
1765 * `format!("{:.3}", matrix)`
1766 */
1767impl<T: std::fmt::Display> std::fmt::Display for Matrix<T> {
1768 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1769 crate::matrices::views::format_view(self, f)
1770 }
1771}
1772
1773/**
1774 * Any matrix and two different dimension names can be converted to a 2 dimensional tensor with
1775 * the same number of rows and columns.
1776 *
1777 * Conversion will fail if the dimension names for `self.rows()` and `self.columns()` respectively
1778 * are the same.
1779 */
1780impl<T> TryFrom<(Matrix<T>, [crate::tensors::Dimension; 2])> for crate::tensors::Tensor<T, 2> {
1781 type Error = crate::tensors::InvalidShapeError<2>;
1782
1783 fn try_from(value: (Matrix<T>, [crate::tensors::Dimension; 2])) -> Result<Self, Self::Error> {
1784 let (matrix, [row_name, column_name]) = value;
1785 let shape = [(row_name, matrix.rows), (column_name, matrix.columns)];
1786 let check = crate::tensors::InvalidShapeError::new(shape);
1787 if !check.is_valid() {
1788 return Err(check);
1789 }
1790 // Now we know the shape is valid, we can call the standard Tensor constructor knowing
1791 // it won't fail since our data length will match the size of our shape.
1792 Ok(crate::tensors::Tensor::from(shape, matrix.data))
1793 }
1794}
1795
1796/**
1797 * Methods for matrices with numerical types, such as f32 or f64.
1798 *
1799 * Note that unsigned integers are not Numeric because they do not
1800 * implement [Neg](std::ops::Neg). You must first
1801 * wrap unsigned integers via [Wrapping](std::num::Wrapping) or [Saturating](std::num::Saturating).
1802 *
1803 * While these methods will all be defined on signed integer types as well, such as i16 or i32,
1804 * in many cases integers cannot be used sensibly in these computations. If you
1805 * have a matrix of type i8 for example, you should consider mapping it into a floating
1806 * type before doing heavy linear algebra maths on it.
1807 *
1808 * Determinants can be computed without loss of precision using sufficiently large signed
1809 * integers because the only operations performed on the elements are addition, subtraction
1810 * and mulitplication. However the inverse of a matrix such as
1811 *
1812 * ```ignore
1813 * [
1814 * 4, 7
1815 * 2, 8
1816 * ]
1817 * ```
1818 *
1819 * is
1820 *
1821 * ```ignore
1822 * [
1823 * 0.6, -0.7,
1824 * -0.2, 0.4
1825 * ]
1826 * ```
1827 *
1828 * which requires a type that supports decimals to accurately represent.
1829 *
1830 * Mapping matrix type example:
1831 * ```
1832 * use easy_ml::matrices::Matrix;
1833 * use std::num::Wrapping;
1834 *
1835 * let matrix: Matrix<u8> = Matrix::from(vec![
1836 * vec![ 2, 3 ],
1837 * vec![ 6, 0 ]
1838 * ]);
1839 * // determinant is not defined on this matrix because u8 is not Numeric
1840 * // println!("{:?}", matrix.determinant()); // won't compile
1841 * // however Wrapping<u8> is numeric
1842 * let matrix = matrix.map(|element| Wrapping(element));
1843 * println!("{:?}", matrix.determinant()); // -> 238 (overflow)
1844 * println!("{:?}", matrix.map(|element| element.0 as i16).determinant()); // -> -18
1845 * println!("{:?}", matrix.map(|element| element.0 as f32).determinant()); // -> -18.0
1846 * ```
1847 */
1848impl<T: Numeric> Matrix<T>
1849where
1850 for<'a> &'a T: NumericRef<T>,
1851{
1852 /**
1853 * Returns the determinant of this square matrix, or None if the matrix
1854 * does not have a determinant. See [`linear_algebra`](super::linear_algebra::determinant())
1855 */
1856 pub fn determinant(&self) -> Option<T> {
1857 linear_algebra::determinant::<T>(self)
1858 }
1859
1860 /**
1861 * Computes the inverse of a matrix provided that it exists. To have an inverse a
1862 * matrix must be square (same number of rows and columns) and it must also have a
1863 * non zero determinant. See [`linear_algebra`](super::linear_algebra::inverse())
1864 */
1865 pub fn inverse(&self) -> Option<Matrix<T>> {
1866 linear_algebra::inverse::<T>(self)
1867 }
1868
1869 /**
1870 * Computes the covariance matrix for this NxM feature matrix, in which
1871 * each N'th row has M features to find the covariance and variance of. See
1872 * [`linear_algebra`](super::linear_algebra::covariance_column_features())
1873 */
1874 pub fn covariance_column_features(&self) -> Matrix<T> {
1875 linear_algebra::covariance_column_features::<T>(self)
1876 }
1877
1878 /**
1879 * Computes the covariance matrix for this NxM feature matrix, in which
1880 * each M'th column has N features to find the covariance and variance of. See
1881 * [`linear_algebra`](super::linear_algebra::covariance_row_features())
1882 */
1883 pub fn covariance_row_features(&self) -> Matrix<T> {
1884 linear_algebra::covariance_row_features::<T>(self)
1885 }
1886}
1887
1888/**
1889 * Methods for matrices with numerical real valued types, such as f32 or f64.
1890 *
1891 * This excludes signed and unsigned integers as they do not support decimal
1892 * precision and hence can't be used for operations like square roots.
1893 *
1894 * Third party fixed precision and infinite precision decimal types should
1895 * be able to implement all of the methods for [Real] and then utilise these functions.
1896 */
1897impl<T: Real> Matrix<T>
1898where
1899 for<'a> &'a T: RealRef<T>,
1900{
1901 /**
1902 * Computes the [L2 norm](https://en.wikipedia.org/wiki/Euclidean_vector#Length)
1903 * of this row or column vector, also referred to as the length or magnitude,
1904 * and written as ||x||, or sometimes |x|.
1905 *
1906 * ||**a**|| = sqrt(a<sub>1</sub><sup>2</sup> + a<sub>2</sub><sup>2</sup> + a<sub>3</sub><sup>2</sup>...) = sqrt(**a**<sup>T</sup> * **a**)
1907 *
1908 * This is a shorthand for `(x.transpose() * x).scalar().sqrt()` for
1909 * column vectors and `(x * x.transpose()).scalar().sqrt()` for row vectors, ie
1910 * the square root of the dot product of a vector with itself.
1911 *
1912 * The euclidean length can be used to compute a
1913 * [unit vector](https://en.wikipedia.org/wiki/Unit_vector), that is, a
1914 * vector with length of 1. This should not be confused with a unit matrix,
1915 * which is another name for an identity matrix.
1916 *
1917 * ```
1918 * use easy_ml::matrices::Matrix;
1919 * let a = Matrix::column(vec![ 1.0, 2.0, 3.0 ]);
1920 * let length = a.euclidean_length(); // (1^2 + 2^2 + 3^2)^0.5
1921 * let unit = a / length;
1922 * assert_eq!(unit.euclidean_length(), 1.0);
1923 * ```
1924 *
1925 * # Panics
1926 *
1927 * If the matrix is not a vector, ie if it has more than one row and more than one
1928 * column.
1929 */
1930 #[track_caller]
1931 pub fn euclidean_length(&self) -> T {
1932 if self.columns() == 1 {
1933 // column vector
1934 (self.transpose() * self).scalar().sqrt()
1935 } else if self.rows() == 1 {
1936 // row vector
1937 (self * self.transpose()).scalar().sqrt()
1938 } else {
1939 panic!(
1940 "Cannot compute unit vector of a non vector, rows: {}, columns: {}",
1941 self.rows(),
1942 self.columns()
1943 );
1944 }
1945 }
1946}
1947
1948// FIXME: want this to be callable in the main numeric impl block
1949impl<T: Numeric> Matrix<T> {
1950 /**
1951 * Creates a diagonal matrix of the provided size with the diagonal elements
1952 * set to the provided value and all other elements in the matrix set to 0.
1953 * A diagonal matrix is always square.
1954 *
1955 * The size is still taken as a tuple to facilitate creating a diagonal matrix
1956 * from the dimensionality of an existing one. If the provided value is 1 then
1957 * this will create an identity matrix.
1958 *
1959 * A 3 x 3 identity matrix:
1960 * ```ignore
1961 * [
1962 * 1, 0, 0
1963 * 0, 1, 0
1964 * 0, 0, 1
1965 * ]
1966 * ```
1967 *
1968 * # Panics
1969 *
1970 * If the provided size is not square.
1971 */
1972 #[track_caller]
1973 pub fn diagonal(value: T, size: (Row, Column)) -> Matrix<T> {
1974 assert!(size.0 == size.1);
1975 let mut matrix = Matrix::empty(T::zero(), size);
1976 for i in 0..size.0 {
1977 matrix.set(i, i, value.clone());
1978 }
1979 matrix
1980 }
1981
1982 /**
1983 * Creates a diagonal matrix with the elements along the diagonal set to the
1984 * provided values and all other elements in the matrix set to 0.
1985 * A diagonal matrix is always square.
1986 *
1987 * Examples
1988 *
1989 * ```
1990 * use easy_ml::matrices::Matrix;
1991 * let matrix = Matrix::from_diagonal(vec![ 1, 1, 1 ]);
1992 * assert_eq!(matrix.size(), (3, 3));
1993 * let copy = Matrix::from_diagonal(matrix.diagonal_iter().collect());
1994 * assert_eq!(matrix, copy);
1995 * assert_eq!(matrix, Matrix::from(vec![
1996 * vec![ 1, 0, 0 ],
1997 * vec![ 0, 1, 0 ],
1998 * vec![ 0, 0, 1 ],
1999 * ]))
2000 * ```
2001 */
2002 pub fn from_diagonal(values: Vec<T>) -> Matrix<T> {
2003 let mut matrix = Matrix::empty(T::zero(), (values.len(), values.len()));
2004 for (i, element) in values.into_iter().enumerate() {
2005 matrix.set(i, i, element);
2006 }
2007 matrix
2008 }
2009}
2010
2011/**
2012 * PartialEq is implemented as two matrices are equal if and only if all their elements
2013 * are equal and they have the same size.
2014 */
2015impl<T: PartialEq> PartialEq for Matrix<T> {
2016 #[inline]
2017 fn eq(&self, other: &Self) -> bool {
2018 if self.rows() != other.rows() {
2019 return false;
2020 }
2021 if self.columns() != other.columns() {
2022 return false;
2023 }
2024 // perform elementwise check, return true only if every element in
2025 // each matrix is the same
2026 self.data.iter().zip(other.data.iter()).all(|(x, y)| x == y)
2027 }
2028}
2029
2030#[test]
2031fn test_sync() {
2032 fn assert_sync<T: Sync>() {}
2033 assert_sync::<Matrix<f64>>();
2034}
2035
2036#[test]
2037fn test_send() {
2038 fn assert_send<T: Send>() {}
2039 assert_send::<Matrix<f64>>();
2040}
2041
2042#[cfg(feature = "serde")]
2043mod serde_impls {
2044 use crate::matrices::{Column, Matrix, Row};
2045 use serde::{Deserialize, Deserializer};
2046
2047 #[derive(Deserialize)]
2048 #[serde(rename = "Matrix")]
2049 struct MatrixDeserialize<T> {
2050 data: Vec<T>,
2051 rows: Row,
2052 columns: Column,
2053 }
2054
2055 impl<'de, T> Deserialize<'de> for Matrix<T>
2056 where
2057 T: Deserialize<'de>,
2058 {
2059 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2060 where
2061 D: Deserializer<'de>,
2062 {
2063 MatrixDeserialize::<T>::deserialize(deserializer).map(|d| {
2064 // Safety: Use the no copy constructor that performs validation to prevent invalid
2065 // serialized data being created as a Matrix, which would then break all the
2066 // code that's relying on these invariants.
2067 Matrix::from_flat_row_major((d.rows, d.columns), d.data)
2068 })
2069 }
2070 }
2071}
2072
2073#[cfg(feature = "serde")]
2074#[test]
2075fn test_serialize() {
2076 fn assert_serialize<T: Serialize>() {}
2077 assert_serialize::<Matrix<f64>>();
2078}
2079
2080#[cfg(feature = "serde")]
2081#[test]
2082fn test_deserialize() {
2083 use serde::Deserialize;
2084 fn assert_deserialize<'de, T: Deserialize<'de>>() {}
2085 assert_deserialize::<Matrix<f64>>();
2086}
2087
2088#[cfg(feature = "serde")]
2089#[test]
2090fn test_serialization_deserialization_loop() {
2091 #[rustfmt::skip]
2092 let matrix = Matrix::from(vec![
2093 vec![1, 2, 3, 4],
2094 vec![5, 6, 7, 8],
2095 vec![9, 10, 11, 12],
2096 ]);
2097 let encoded = toml::to_string(&matrix).unwrap();
2098 assert_eq!(
2099 encoded,
2100 r#"data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
2101rows = 3
2102columns = 4
2103"#,
2104 );
2105 let parsed: Result<Matrix<i32>, _> = toml::from_str(&encoded);
2106 assert!(parsed.is_ok());
2107 assert_eq!(matrix, parsed.unwrap())
2108}
2109
2110#[cfg(feature = "serde")]
2111#[test]
2112#[should_panic]
2113fn test_deserialization_validation() {
2114 let _result: Result<Matrix<i32>, _> = toml::from_str(
2115 r#"data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
2116rows = 3
2117columns = 3
2118"#,
2119 );
2120}
2121
2122#[test]
2123fn test_indexing() {
2124 let a = Matrix::from(vec![vec![1, 2], vec![3, 4]]);
2125 assert_eq!(a.get_index(0, 1), 1);
2126 assert_eq!(a.get_row_column(1), (0, 1));
2127 assert_eq!(a.get(0, 1), 2);
2128 let b = Matrix::from(vec![vec![1, 2, 3], vec![5, 6, 7]]);
2129 assert_eq!(b.get_index(1, 2), 5);
2130 assert_eq!(b.get_row_column(5), (1, 2));
2131 assert_eq!(b.get(1, 2), 7);
2132 assert_eq!(
2133 Matrix::from(vec![vec![0, 0], vec![0, 0], vec![0, 0]])
2134 .map_with_index(|_, r, c| format!("{:?}x{:?}", r, c)),
2135 Matrix::from(vec![
2136 vec!["0x0", "0x1"],
2137 vec!["1x0", "1x1"],
2138 vec!["2x0", "2x1"]
2139 ])
2140 .map(|x| x.to_owned())
2141 );
2142}