1use nalgebra::DMatrix;
8
9#[derive(Debug, Clone, PartialEq)]
39pub struct FdMatrix {
40 data: Vec<f64>,
41 nrows: usize,
42 ncols: usize,
43}
44
45impl FdMatrix {
46 pub fn from_column_major(
50 data: Vec<f64>,
51 nrows: usize,
52 ncols: usize,
53 ) -> Result<Self, crate::FdarError> {
54 if data.len() != nrows * ncols {
55 return Err(crate::FdarError::InvalidDimension {
56 parameter: "data",
57 expected: format!("{}", nrows * ncols),
58 actual: format!("{}", data.len()),
59 });
60 }
61 Ok(Self { data, nrows, ncols })
62 }
63
64 pub fn from_slice(data: &[f64], nrows: usize, ncols: usize) -> Result<Self, crate::FdarError> {
68 if data.len() != nrows * ncols {
69 return Err(crate::FdarError::InvalidDimension {
70 parameter: "data",
71 expected: format!("{}", nrows * ncols),
72 actual: format!("{}", data.len()),
73 });
74 }
75 Ok(Self {
76 data: data.to_vec(),
77 nrows,
78 ncols,
79 })
80 }
81
82 pub fn zeros(nrows: usize, ncols: usize) -> Self {
84 Self {
85 data: vec![0.0; nrows * ncols],
86 nrows,
87 ncols,
88 }
89 }
90
91 #[inline]
93 pub fn nrows(&self) -> usize {
94 self.nrows
95 }
96
97 #[inline]
99 pub fn ncols(&self) -> usize {
100 self.ncols
101 }
102
103 #[inline]
105 pub fn shape(&self) -> (usize, usize) {
106 (self.nrows, self.ncols)
107 }
108
109 #[inline]
111 pub fn len(&self) -> usize {
112 self.data.len()
113 }
114
115 #[inline]
117 pub fn is_empty(&self) -> bool {
118 self.data.is_empty()
119 }
120
121 #[inline]
126 pub fn column(&self, col: usize) -> &[f64] {
127 let start = col * self.nrows;
128 &self.data[start..start + self.nrows]
129 }
130
131 #[inline]
136 pub fn column_mut(&mut self, col: usize) -> &mut [f64] {
137 let start = col * self.nrows;
138 &mut self.data[start..start + self.nrows]
139 }
140
141 pub fn row(&self, row: usize) -> Vec<f64> {
146 (0..self.ncols)
147 .map(|j| self.data[row + j * self.nrows])
148 .collect()
149 }
150
151 #[inline]
156 pub fn row_to_buf(&self, row: usize, buf: &mut [f64]) {
157 debug_assert!(
158 row < self.nrows,
159 "row {row} out of bounds for {} rows",
160 self.nrows
161 );
162 debug_assert!(
163 buf.len() >= self.ncols,
164 "buffer len {} < ncols {}",
165 buf.len(),
166 self.ncols
167 );
168 let n = self.nrows;
169 for j in 0..self.ncols {
170 buf[j] = self.data[row + j * n];
171 }
172 }
173
174 #[inline]
182 pub fn row_dot(&self, row_a: usize, other: &FdMatrix, row_b: usize) -> f64 {
183 debug_assert_eq!(self.ncols, other.ncols, "ncols mismatch in row_dot");
184 let na = self.nrows;
185 let nb = other.nrows;
186 let mut sum = 0.0;
187 for j in 0..self.ncols {
188 sum += self.data[row_a + j * na] * other.data[row_b + j * nb];
189 }
190 sum
191 }
192
193 #[inline]
202 pub fn row_l2_sq(&self, row_a: usize, other: &FdMatrix, row_b: usize) -> f64 {
203 debug_assert_eq!(self.ncols, other.ncols, "ncols mismatch in row_l2_sq");
204 let na = self.nrows;
205 let nb = other.nrows;
206 let mut sum = 0.0;
207 for j in 0..self.ncols {
208 let d = self.data[row_a + j * na] - other.data[row_b + j * nb];
209 sum += d * d;
210 }
211 sum
212 }
213
214 pub fn iter_rows(&self) -> impl Iterator<Item = Vec<f64>> + '_ {
240 (0..self.nrows).map(move |i| self.row(i))
241 }
242
243 pub fn iter_columns(&self) -> impl Iterator<Item = &[f64]> {
263 (0..self.ncols).map(move |j| self.column(j))
264 }
265
266 pub fn rows(&self) -> Vec<Vec<f64>> {
270 (0..self.nrows).map(|i| self.row(i)).collect()
271 }
272
273 pub fn to_row_major(&self) -> Vec<f64> {
279 let mut buf = vec![0.0; self.nrows * self.ncols];
280 for i in 0..self.nrows {
281 for j in 0..self.ncols {
282 buf[i * self.ncols + j] = self.data[i + j * self.nrows];
283 }
284 }
285 buf
286 }
287
288 #[inline]
290 pub fn as_slice(&self) -> &[f64] {
291 &self.data
292 }
293
294 #[inline]
296 pub fn as_mut_slice(&mut self) -> &mut [f64] {
297 &mut self.data
298 }
299
300 pub fn into_vec(self) -> Vec<f64> {
302 self.data
303 }
304
305 pub fn to_dmatrix(&self) -> DMatrix<f64> {
310 DMatrix::from_column_slice(self.nrows, self.ncols, &self.data)
311 }
312
313 pub fn from_dmatrix(mat: &DMatrix<f64>) -> Self {
317 let (nrows, ncols) = mat.shape();
318 Self {
319 data: mat.as_slice().to_vec(),
320 nrows,
321 ncols,
322 }
323 }
324
325 #[inline]
327 pub fn get(&self, row: usize, col: usize) -> Option<f64> {
328 if row < self.nrows && col < self.ncols {
329 Some(self.data[row + col * self.nrows])
330 } else {
331 None
332 }
333 }
334
335 #[inline]
337 pub fn set(&mut self, row: usize, col: usize, value: f64) -> bool {
338 if row < self.nrows && col < self.ncols {
339 self.data[row + col * self.nrows] = value;
340 true
341 } else {
342 false
343 }
344 }
345}
346
347impl std::ops::Index<(usize, usize)> for FdMatrix {
348 type Output = f64;
349
350 #[inline]
351 fn index(&self, (row, col): (usize, usize)) -> &f64 {
352 debug_assert!(
353 row < self.nrows && col < self.ncols,
354 "FdMatrix index ({}, {}) out of bounds for {}x{} matrix",
355 row,
356 col,
357 self.nrows,
358 self.ncols
359 );
360 &self.data[row + col * self.nrows]
361 }
362}
363
364impl std::ops::IndexMut<(usize, usize)> for FdMatrix {
365 #[inline]
366 fn index_mut(&mut self, (row, col): (usize, usize)) -> &mut f64 {
367 debug_assert!(
368 row < self.nrows && col < self.ncols,
369 "FdMatrix index ({}, {}) out of bounds for {}x{} matrix",
370 row,
371 col,
372 self.nrows,
373 self.ncols
374 );
375 &mut self.data[row + col * self.nrows]
376 }
377}
378
379impl std::fmt::Display for FdMatrix {
380 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
381 write!(f, "FdMatrix({}x{})", self.nrows, self.ncols)
382 }
383}
384
385#[derive(Debug, Clone, PartialEq)]
390pub struct FdCurveSet {
391 pub dims: Vec<FdMatrix>,
393}
394
395impl FdCurveSet {
396 pub fn ndim(&self) -> usize {
398 self.dims.len()
399 }
400
401 pub fn ncurves(&self) -> usize {
403 if self.dims.is_empty() {
404 0
405 } else {
406 self.dims[0].nrows()
407 }
408 }
409
410 pub fn npoints(&self) -> usize {
412 if self.dims.is_empty() {
413 0
414 } else {
415 self.dims[0].ncols()
416 }
417 }
418
419 pub fn from_1d(data: FdMatrix) -> Self {
421 Self { dims: vec![data] }
422 }
423
424 pub fn from_dims(dims: Vec<FdMatrix>) -> Result<Self, crate::FdarError> {
428 if dims.is_empty() {
429 return Err(crate::FdarError::InvalidDimension {
430 parameter: "dims",
431 expected: "non-empty".to_string(),
432 actual: "empty".to_string(),
433 });
434 }
435 let (n, m) = dims[0].shape();
436 if dims.iter().any(|d| d.shape() != (n, m)) {
437 return Err(crate::FdarError::InvalidDimension {
438 parameter: "dims",
439 expected: format!("all ({n}, {m})"),
440 actual: "inconsistent shapes".to_string(),
441 });
442 }
443 Ok(Self { dims })
444 }
445
446 pub fn point(&self, curve: usize, time_idx: usize) -> Vec<f64> {
448 self.dims.iter().map(|d| d[(curve, time_idx)]).collect()
449 }
450}
451
452impl std::fmt::Display for FdCurveSet {
453 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
454 write!(
455 f,
456 "FdCurveSet(d={}, n={}, m={})",
457 self.ndim(),
458 self.ncurves(),
459 self.npoints()
460 )
461 }
462}
463
464#[cfg(test)]
465mod tests {
466 use super::*;
467
468 fn sample_3x4() -> FdMatrix {
469 let data = vec![
471 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, ];
476 FdMatrix::from_column_major(data, 3, 4).unwrap()
477 }
478
479 #[test]
480 fn test_from_column_major_valid() {
481 let mat = sample_3x4();
482 assert_eq!(mat.nrows(), 3);
483 assert_eq!(mat.ncols(), 4);
484 assert_eq!(mat.shape(), (3, 4));
485 assert_eq!(mat.len(), 12);
486 assert!(!mat.is_empty());
487 }
488
489 #[test]
490 fn test_from_column_major_invalid() {
491 assert!(FdMatrix::from_column_major(vec![1.0, 2.0], 3, 4).is_err());
492 }
493
494 #[test]
495 fn test_from_slice() {
496 let data = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0];
497 let mat = FdMatrix::from_slice(&data, 2, 3).unwrap();
498 assert_eq!(mat[(0, 0)], 1.0);
499 assert_eq!(mat[(1, 0)], 2.0);
500 assert_eq!(mat[(0, 1)], 3.0);
501 }
502
503 #[test]
504 fn test_from_slice_invalid() {
505 assert!(FdMatrix::from_slice(&[1.0, 2.0], 3, 3).is_err());
506 }
507
508 #[test]
509 fn test_zeros() {
510 let mat = FdMatrix::zeros(2, 3);
511 assert_eq!(mat.nrows(), 2);
512 assert_eq!(mat.ncols(), 3);
513 for j in 0..3 {
514 for i in 0..2 {
515 assert_eq!(mat[(i, j)], 0.0);
516 }
517 }
518 }
519
520 #[test]
521 fn test_index() {
522 let mat = sample_3x4();
523 assert_eq!(mat[(0, 0)], 1.0);
524 assert_eq!(mat[(1, 0)], 2.0);
525 assert_eq!(mat[(2, 0)], 3.0);
526 assert_eq!(mat[(0, 1)], 4.0);
527 assert_eq!(mat[(1, 1)], 5.0);
528 assert_eq!(mat[(2, 3)], 12.0);
529 }
530
531 #[test]
532 fn test_index_mut() {
533 let mut mat = sample_3x4();
534 mat[(1, 2)] = 99.0;
535 assert_eq!(mat[(1, 2)], 99.0);
536 }
537
538 #[test]
539 fn test_column() {
540 let mat = sample_3x4();
541 assert_eq!(mat.column(0), &[1.0, 2.0, 3.0]);
542 assert_eq!(mat.column(1), &[4.0, 5.0, 6.0]);
543 assert_eq!(mat.column(3), &[10.0, 11.0, 12.0]);
544 }
545
546 #[test]
547 fn test_column_mut() {
548 let mut mat = sample_3x4();
549 mat.column_mut(1)[0] = 99.0;
550 assert_eq!(mat[(0, 1)], 99.0);
551 }
552
553 #[test]
554 fn test_row() {
555 let mat = sample_3x4();
556 assert_eq!(mat.row(0), vec![1.0, 4.0, 7.0, 10.0]);
557 assert_eq!(mat.row(1), vec![2.0, 5.0, 8.0, 11.0]);
558 assert_eq!(mat.row(2), vec![3.0, 6.0, 9.0, 12.0]);
559 }
560
561 #[test]
562 fn test_rows() {
563 let mat = sample_3x4();
564 let rows = mat.rows();
565 assert_eq!(rows.len(), 3);
566 assert_eq!(rows[0], vec![1.0, 4.0, 7.0, 10.0]);
567 assert_eq!(rows[2], vec![3.0, 6.0, 9.0, 12.0]);
568 }
569
570 #[test]
571 fn test_as_slice() {
572 let mat = sample_3x4();
573 let expected = vec![
574 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0,
575 ];
576 assert_eq!(mat.as_slice(), expected.as_slice());
577 }
578
579 #[test]
580 fn test_into_vec() {
581 let mat = sample_3x4();
582 let v = mat.into_vec();
583 assert_eq!(v.len(), 12);
584 assert_eq!(v[0], 1.0);
585 }
586
587 #[test]
588 fn test_get_bounds_check() {
589 let mat = sample_3x4();
590 assert_eq!(mat.get(0, 0), Some(1.0));
591 assert_eq!(mat.get(2, 3), Some(12.0));
592 assert_eq!(mat.get(3, 0), None); assert_eq!(mat.get(0, 4), None); }
595
596 #[test]
597 fn test_set_bounds_check() {
598 let mut mat = sample_3x4();
599 assert!(mat.set(1, 1, 99.0));
600 assert_eq!(mat[(1, 1)], 99.0);
601 assert!(!mat.set(5, 0, 99.0)); }
603
604 #[test]
605 fn test_nalgebra_roundtrip() {
606 let mat = sample_3x4();
607 let dmat = mat.to_dmatrix();
608 assert_eq!(dmat.nrows(), 3);
609 assert_eq!(dmat.ncols(), 4);
610 assert_eq!(dmat[(0, 0)], 1.0);
611 assert_eq!(dmat[(1, 2)], 8.0);
612
613 let back = FdMatrix::from_dmatrix(&dmat);
614 assert_eq!(mat, back);
615 }
616
617 #[test]
618 fn test_empty() {
619 let mat = FdMatrix::zeros(0, 0);
620 assert!(mat.is_empty());
621 assert_eq!(mat.len(), 0);
622 }
623
624 #[test]
625 fn test_single_element() {
626 let mat = FdMatrix::from_column_major(vec![42.0], 1, 1).unwrap();
627 assert_eq!(mat[(0, 0)], 42.0);
628 assert_eq!(mat.column(0), &[42.0]);
629 assert_eq!(mat.row(0), vec![42.0]);
630 }
631
632 #[test]
633 fn test_display() {
634 let mat = sample_3x4();
635 assert_eq!(format!("{}", mat), "FdMatrix(3x4)");
636 }
637
638 #[test]
639 fn test_clone() {
640 let mat = sample_3x4();
641 let cloned = mat.clone();
642 assert_eq!(mat, cloned);
643 }
644
645 #[test]
646 fn test_as_mut_slice() {
647 let mut mat = FdMatrix::zeros(2, 2);
648 let s = mat.as_mut_slice();
649 s[0] = 1.0;
650 s[1] = 2.0;
651 s[2] = 3.0;
652 s[3] = 4.0;
653 assert_eq!(mat[(0, 0)], 1.0);
654 assert_eq!(mat[(1, 0)], 2.0);
655 assert_eq!(mat[(0, 1)], 3.0);
656 assert_eq!(mat[(1, 1)], 4.0);
657 }
658
659 #[test]
660 fn test_fd_curve_set_empty() {
661 assert!(FdCurveSet::from_dims(vec![]).is_err());
662 let cs = FdCurveSet::from_dims(vec![]).unwrap_or(FdCurveSet { dims: vec![] });
663 assert_eq!(cs.ndim(), 0);
664 assert_eq!(cs.ncurves(), 0);
665 assert_eq!(cs.npoints(), 0);
666 assert_eq!(format!("{}", cs), "FdCurveSet(d=0, n=0, m=0)");
667 }
668
669 #[test]
670 fn test_fd_curve_set_from_1d() {
671 let mat = sample_3x4();
672 let cs = FdCurveSet::from_1d(mat.clone());
673 assert_eq!(cs.ndim(), 1);
674 assert_eq!(cs.ncurves(), 3);
675 assert_eq!(cs.npoints(), 4);
676 assert_eq!(cs.point(0, 0), vec![1.0]);
677 assert_eq!(cs.point(1, 2), vec![8.0]);
678 }
679
680 #[test]
681 fn test_fd_curve_set_from_dims_consistent() {
682 let m1 = FdMatrix::from_column_major(vec![1.0, 2.0, 3.0, 4.0], 2, 2).unwrap();
683 let m2 = FdMatrix::from_column_major(vec![5.0, 6.0, 7.0, 8.0], 2, 2).unwrap();
684 let cs = FdCurveSet::from_dims(vec![m1, m2]).unwrap();
685 assert_eq!(cs.ndim(), 2);
686 assert_eq!(cs.point(0, 0), vec![1.0, 5.0]);
687 assert_eq!(cs.point(1, 1), vec![4.0, 8.0]);
688 assert_eq!(format!("{}", cs), "FdCurveSet(d=2, n=2, m=2)");
689 }
690
691 #[test]
692 fn test_fd_curve_set_from_dims_inconsistent() {
693 let m1 = FdMatrix::from_column_major(vec![1.0, 2.0], 2, 1).unwrap();
694 let m2 = FdMatrix::from_column_major(vec![1.0, 2.0, 3.0], 3, 1).unwrap();
695 assert!(FdCurveSet::from_dims(vec![m1, m2]).is_err());
696 }
697
698 #[test]
699 fn test_to_row_major() {
700 let mat = sample_3x4();
701 let rm = mat.to_row_major();
702 assert_eq!(
704 rm,
705 vec![1.0, 4.0, 7.0, 10.0, 2.0, 5.0, 8.0, 11.0, 3.0, 6.0, 9.0, 12.0]
706 );
707 }
708
709 #[test]
710 fn test_row_to_buf() {
711 let mat = sample_3x4();
712 let mut buf = vec![0.0; 4];
713 mat.row_to_buf(0, &mut buf);
714 assert_eq!(buf, vec![1.0, 4.0, 7.0, 10.0]);
715 mat.row_to_buf(1, &mut buf);
716 assert_eq!(buf, vec![2.0, 5.0, 8.0, 11.0]);
717 mat.row_to_buf(2, &mut buf);
718 assert_eq!(buf, vec![3.0, 6.0, 9.0, 12.0]);
719 }
720
721 #[test]
722 fn test_row_to_buf_larger_buffer() {
723 let mat = sample_3x4();
724 let mut buf = vec![99.0; 6]; mat.row_to_buf(0, &mut buf);
726 assert_eq!(&buf[..4], &[1.0, 4.0, 7.0, 10.0]);
727 assert_eq!(buf[4], 99.0);
729 }
730
731 #[test]
732 fn test_row_dot_same_matrix() {
733 let mat = sample_3x4();
734 assert_eq!(mat.row_dot(0, &mat, 1), 188.0);
737 assert_eq!(mat.row_dot(0, &mat, 0), 166.0);
739 }
740
741 #[test]
742 fn test_row_dot_different_matrices() {
743 let mat1 = sample_3x4();
744 let data2 = vec![
745 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 110.0, 120.0, ];
750 let mat2 = FdMatrix::from_column_major(data2, 3, 4).unwrap();
751 assert_eq!(mat1.row_dot(0, &mat2, 0), 1660.0);
754 }
755
756 #[test]
757 fn test_row_l2_sq_identical() {
758 let mat = sample_3x4();
759 assert_eq!(mat.row_l2_sq(0, &mat, 0), 0.0);
760 assert_eq!(mat.row_l2_sq(1, &mat, 1), 0.0);
761 }
762
763 #[test]
764 fn test_row_l2_sq_different() {
765 let mat = sample_3x4();
766 assert_eq!(mat.row_l2_sq(0, &mat, 1), 4.0);
769 }
770
771 #[test]
772 fn test_row_l2_sq_cross_matrix() {
773 let mat1 = FdMatrix::from_column_major(vec![0.0, 0.0], 1, 2).unwrap();
774 let mat2 = FdMatrix::from_column_major(vec![3.0, 4.0], 1, 2).unwrap();
775 assert_eq!(mat1.row_l2_sq(0, &mat2, 0), 25.0);
777 }
778
779 #[test]
780 fn test_column_major_layout_matches_manual() {
781 let n = 5;
783 let m = 7;
784 let data: Vec<f64> = (0..n * m).map(|x| x as f64).collect();
785 let mat = FdMatrix::from_column_major(data.clone(), n, m).unwrap();
786
787 for j in 0..m {
788 for i in 0..n {
789 assert_eq!(mat[(i, j)], data[i + j * n]);
790 }
791 }
792 }
793
794 #[test]
795 fn test_iter_rows() {
796 let mat = sample_3x4();
797 let rows: Vec<Vec<f64>> = mat.iter_rows().collect();
798 assert_eq!(rows.len(), 3);
799 assert_eq!(rows[0], vec![1.0, 4.0, 7.0, 10.0]);
800 assert_eq!(rows[1], vec![2.0, 5.0, 8.0, 11.0]);
801 assert_eq!(rows[2], vec![3.0, 6.0, 9.0, 12.0]);
802 }
803
804 #[test]
805 fn test_iter_rows_matches_rows() {
806 let mat = sample_3x4();
807 let from_iter: Vec<Vec<f64>> = mat.iter_rows().collect();
808 let from_rows = mat.rows();
809 assert_eq!(from_iter, from_rows);
810 }
811
812 #[test]
813 fn test_iter_rows_partial() {
814 let mat = sample_3x4();
816 let first_two: Vec<Vec<f64>> = mat.iter_rows().take(2).collect();
817 assert_eq!(first_two.len(), 2);
818 assert_eq!(first_two[0], vec![1.0, 4.0, 7.0, 10.0]);
819 assert_eq!(first_two[1], vec![2.0, 5.0, 8.0, 11.0]);
820 }
821
822 #[test]
823 fn test_iter_rows_empty() {
824 let mat = FdMatrix::zeros(0, 0);
825 let rows: Vec<Vec<f64>> = mat.iter_rows().collect();
826 assert!(rows.is_empty());
827 }
828
829 #[test]
830 fn test_iter_rows_single_row() {
831 let mat = FdMatrix::from_column_major(vec![1.0, 2.0, 3.0], 1, 3).unwrap();
832 let rows: Vec<Vec<f64>> = mat.iter_rows().collect();
833 assert_eq!(rows, vec![vec![1.0, 2.0, 3.0]]);
834 }
835
836 #[test]
837 fn test_iter_rows_single_column() {
838 let mat = FdMatrix::from_column_major(vec![1.0, 2.0, 3.0], 3, 1).unwrap();
839 let rows: Vec<Vec<f64>> = mat.iter_rows().collect();
840 assert_eq!(rows, vec![vec![1.0], vec![2.0], vec![3.0]]);
841 }
842
843 #[test]
844 fn test_iter_columns() {
845 let mat = sample_3x4();
846 let cols: Vec<&[f64]> = mat.iter_columns().collect();
847 assert_eq!(cols.len(), 4);
848 assert_eq!(cols[0], &[1.0, 2.0, 3.0]);
849 assert_eq!(cols[1], &[4.0, 5.0, 6.0]);
850 assert_eq!(cols[2], &[7.0, 8.0, 9.0]);
851 assert_eq!(cols[3], &[10.0, 11.0, 12.0]);
852 }
853
854 #[test]
855 fn test_iter_columns_partial() {
856 let mat = sample_3x4();
857 let first_two: Vec<&[f64]> = mat.iter_columns().take(2).collect();
858 assert_eq!(first_two.len(), 2);
859 assert_eq!(first_two[0], &[1.0, 2.0, 3.0]);
860 assert_eq!(first_two[1], &[4.0, 5.0, 6.0]);
861 }
862
863 #[test]
864 fn test_iter_columns_empty() {
865 let mat = FdMatrix::zeros(0, 0);
866 let cols: Vec<&[f64]> = mat.iter_columns().collect();
867 assert!(cols.is_empty());
868 }
869
870 #[test]
871 fn test_iter_columns_single_column() {
872 let mat = FdMatrix::from_column_major(vec![1.0, 2.0, 3.0], 3, 1).unwrap();
873 let cols: Vec<&[f64]> = mat.iter_columns().collect();
874 assert_eq!(cols, vec![&[1.0, 2.0, 3.0]]);
875 }
876
877 #[test]
878 fn test_iter_columns_single_row() {
879 let mat = FdMatrix::from_column_major(vec![1.0, 2.0, 3.0], 1, 3).unwrap();
880 let cols: Vec<&[f64]> = mat.iter_columns().collect();
881 assert_eq!(cols, vec![&[1.0_f64] as &[f64], &[2.0], &[3.0]]);
882 }
883
884 #[test]
885 fn test_iter_rows_enumerate() {
886 let mat = sample_3x4();
887 for (i, row) in mat.iter_rows().enumerate() {
888 assert_eq!(row, mat.row(i));
889 }
890 }
891
892 #[test]
893 fn test_iter_columns_enumerate() {
894 let mat = sample_3x4();
895 for (j, col) in mat.iter_columns().enumerate() {
896 assert_eq!(col, mat.column(j));
897 }
898 }
899}