lightmatrix/
matrix_slice.rs

1use core::ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive};
2use num_traits::NumAssign;
3use paste::paste;
4
5use crate::matrix::*;
6
7#[derive(Debug, Clone)]
8pub(crate) enum RangeType {
9    Range(Range<usize>),
10    RangeFrom(RangeFrom<usize>),
11    RangeFull(RangeFull),
12    RangeInclusive(RangeInclusive<usize>),
13    RangeTo(RangeTo<usize>),
14    RangeToInclusive(RangeToInclusive<usize>),
15}
16
17#[derive(Debug)]
18pub struct MatrixSliceMut<'a, T: NumAssign + Copy + Default, const ROW: usize, const COL: usize> {
19    pub matrix: &'a mut Matrix<T, ROW, COL>,
20    range: (RangeType, RangeType),
21}
22
23#[derive(Debug)]
24pub struct MatrixSlice<'a, T: NumAssign + Copy + Default, const ROW: usize, const COL: usize> {
25    pub matrix: &'a Matrix<T, ROW, COL>,
26    range: (RangeType, RangeType),
27}
28
29impl<'a, T: NumAssign + Copy + Default, const ROW: usize, const COL: usize> Clone
30    for MatrixSlice<'a, T, ROW, COL>
31{
32    fn clone(&self) -> Self {
33        Self {
34            matrix: self.matrix,
35            range: self.range.clone(),
36        }
37    }
38}
39
40impl<'a, T: NumAssign + Copy + Default, const ROW: usize, const COL: usize>
41    From<MatrixSliceMut<'a, T, ROW, COL>> for MatrixSlice<'a, T, ROW, COL>
42{
43    fn from(m: MatrixSliceMut<'a, T, ROW, COL>) -> Self {
44        Self {
45            matrix: m.matrix,
46            range: m.range,
47        }
48    }
49}
50
51macro_rules! impl_matrix_slice_mut {
52    ($type_range_rows:ty, $type_range_cols:ty, $enum_range_rows:ty,  $enum_range_cols:ty) => {
53        paste! {
54            /// get a mutable slice of the input matrix
55            impl<'a, T: 'a + NumAssign + Copy + Default, const ROW: usize, const COL: usize>
56                From<(
57                    &'a mut Matrix<T, ROW, COL>,
58                    ($type_range_rows, $type_range_cols),
59                )> for MatrixSliceMut<'a, T, ROW, COL>
60            {
61                fn from(
62                    (m, (range_rows, range_cols)): (
63                        &'a mut Matrix<T, ROW, COL>,
64                        ($type_range_rows, $type_range_cols),
65                    ),
66                ) -> Self {
67                    Self {
68                        matrix: m,
69                        range: ($enum_range_rows(range_rows), $enum_range_cols(range_cols)),
70                    }
71                }
72            }
73            /// Get a slice of the input matrix
74            /// # Example
75            /// ```
76            /// use lightmatrix::{matrix::*,matrix_slice::*};
77            /// let (m1, mut m2) = (
78            ///     Matrix::<f64, 15, 10>::default(),
79            ///     Matrix::<f64, 15, 15>::default(),
80            /// );
81            /// let src = MatrixSlice::from((&m1, ((2..5), (3..6))));
82            /// let mut dest = MatrixSliceMut::from((&mut m2, ((5..8), (7..10))));
83            /// dest.assign(src);
84            /// ```
85            ///
86            /// # Example of failure
87            /// ```compile_fail
88            /// use lightmatrix::{matrix::*,matrix_slice::*};
89            /// let (m1, mut m2) = (
90            ///     Matrix::<f64, 15, 10>::default(),
91            ///     Matrix::<f64, 15, 15>::default(),
92            /// );
93            /// let src = MatrixSlice::from((&m1, ((2..15), (3..15))));
94            /// let mut dest = MatrixSliceMut::from((&mut m2, ((5..8), (7..10))));
95            /// drop(m2);
96            /// dest.assign(src);
97            impl<'a, T: 'a + NumAssign + Copy + Default, const ROW: usize, const COL: usize>
98                From<(
99                    &'a Matrix<T, ROW, COL>,
100                    ($type_range_rows, $type_range_cols),
101                )> for MatrixSlice<'a, T, ROW, COL>
102            {
103                fn from(
104                    (m, (range_rows, range_cols)): (
105                        &'a Matrix<T, ROW, COL>,
106                        ($type_range_rows, $type_range_cols),
107                    ),
108                ) -> Self {
109                    Self {
110                        matrix: m,
111                        range: ($enum_range_rows(range_rows), $enum_range_cols(range_cols)),
112                    }
113                }
114            }
115        }
116    };
117}
118
119macro_rules! impl_matrix_slice_outer {
120    ($type_range_rows:ty, $enum_range_rows:ty) => {
121        impl_matrix_slice_mut!(
122            $type_range_rows,
123            Range<usize>,
124            $enum_range_rows,
125            RangeType::Range
126        );
127        impl_matrix_slice_mut!(
128            $type_range_rows,
129            RangeFrom<usize>,
130            $enum_range_rows,
131            RangeType::RangeFrom
132        );
133        impl_matrix_slice_mut!(
134            $type_range_rows,
135            RangeFull,
136            $enum_range_rows,
137            RangeType::RangeFull
138        );
139        impl_matrix_slice_mut!(
140            $type_range_rows,
141            RangeTo<usize>,
142            $enum_range_rows,
143            RangeType::RangeTo
144        );
145        impl_matrix_slice_mut!(
146            $type_range_rows,
147            RangeToInclusive<usize>,
148            $enum_range_rows,
149            RangeType::RangeToInclusive
150        );
151        impl_matrix_slice_mut!(
152            $type_range_rows,
153            RangeInclusive<usize>,
154            $enum_range_rows,
155            RangeType::RangeInclusive
156        );
157    };
158}
159
160impl_matrix_slice_outer!(Range<usize>, RangeType::Range);
161impl_matrix_slice_outer!(RangeFull, RangeType::RangeFull);
162impl_matrix_slice_outer!(RangeFrom<usize>, RangeType::RangeFrom);
163impl_matrix_slice_outer!(RangeTo<usize>, RangeType::RangeTo);
164impl_matrix_slice_outer!(RangeToInclusive<usize>, RangeType::RangeToInclusive);
165impl_matrix_slice_outer!(RangeInclusive<usize>, RangeType::RangeInclusive);
166
167#[derive(Default)]
168pub(crate) struct RangeInfo {
169    pub start: usize,
170    pub count: usize,
171}
172
173/// convert a matrix slice to an owned matrix
174impl<
175        'a,
176        T: NumAssign + Copy + Default,
177        const ROW_DEST: usize,
178        const COL_DEST: usize,
179        const ROW: usize,
180        const COL: usize,
181    > From<&'a MatrixSliceMut<'a, T, ROW, COL>> for Matrix<T, ROW_DEST, COL_DEST>
182{
183    fn from(m: &MatrixSliceMut<'a, T, ROW, COL>) -> Self {
184        let mut ret = Self::default();
185
186        let (range_rows, range_cols) = m.get_range();
187        let src_range_rows_count = range_rows.count;
188        let src_range_cols_count = range_cols.count;
189        let src_rows_start = range_rows.start;
190        let src_cols_start = range_cols.start;
191
192        assert_eq!(src_range_rows_count, ret.rows());
193        assert_eq!(src_range_cols_count, ret.cols());
194
195        for i in 0..src_range_rows_count {
196            for j in 0..src_range_cols_count {
197                ret[[i, j]] = m.matrix[[src_rows_start + i, src_cols_start + j]];
198            }
199        }
200        ret
201    }
202}
203
204/// convert a matrix slice to an owned matrix
205impl<
206        'a,
207        T: NumAssign + Copy + Default,
208        const ROW: usize,
209        const COL: usize,
210        const ROW_DEST: usize,
211        const COL_DEST: usize,
212    > From<&'a MatrixSlice<'a, T, ROW, COL>> for Matrix<T, ROW_DEST, COL_DEST>
213{
214    fn from(m: &MatrixSlice<'a, T, ROW, COL>) -> Self {
215        let mut ret = Self::default();
216
217        let (range_rows, range_cols) = m.get_range();
218        let src_range_rows_count = range_rows.count;
219        let src_range_cols_count = range_cols.count;
220        let src_rows_start = range_rows.start;
221        let src_cols_start = range_cols.start;
222
223        assert_eq!(src_range_rows_count, ret.rows());
224        assert_eq!(src_range_cols_count, ret.cols());
225
226        for i in 0..src_range_rows_count {
227            for j in 0..src_range_cols_count {
228                ret[[i, j]] = m.matrix[[src_rows_start + i, src_cols_start + j]];
229            }
230        }
231        ret
232    }
233}
234
235/// # Copy values from one slice to another.
236/// # Example
237/// ```
238/// use lightmatrix::{matrix::*,matrix_slice::*};
239/// let (mut m1, mut m2) = (
240///     Matrix::<f64, 15, 10>::default(),
241///     Matrix::<f64, 15, 15>::default(),
242/// );
243///
244/// //fill matrices with values...
245///
246/// let src = MatrixSlice::from((&m1, ((2..15), (3..15))));
247/// let mut dest = MatrixSliceMut::from((&mut m2, ((5..8), (7..10))));
248/// dest.assign(src);
249/// ```
250impl<'a, T: NumAssign + Copy + Default, const ROW: usize, const COL: usize>
251    MatrixSliceMut<'a, T, ROW, COL>
252{
253    pub fn assign<const ROW_OTHER: usize, const COL_OTHER: usize>(
254        &mut self,
255        other: MatrixSlice<'a, T, ROW_OTHER, COL_OTHER>,
256    ) {
257        let (range_rows, range_cols) = self.get_range();
258        let dest_range_rows_count = range_rows.count;
259        let dest_range_cols_count = range_cols.count;
260        let dest_rows_start = range_rows.start;
261        let dest_cols_start = range_cols.start;
262
263        let (range_rows, range_cols) = other.get_range();
264        let src_range_rows_count = range_rows.count;
265        let src_range_cols_count = range_cols.count;
266        let src_rows_start = range_rows.start;
267        let src_cols_start = range_cols.start;
268
269        assert!(dest_range_rows_count <= src_range_rows_count);
270
271        assert!(dest_range_cols_count <= src_range_cols_count);
272
273        for i in 0..dest_range_rows_count {
274            for j in 0..dest_range_cols_count {
275                self.matrix[[dest_rows_start + i, dest_cols_start + j]] =
276                    other.matrix[[src_rows_start + i, src_cols_start + j]];
277            }
278        }
279    }
280    pub(crate) fn get_range(&'a self) -> (RangeInfo, RangeInfo) {
281        let mut ranges: [RangeInfo; 2] = Default::default();
282        for (idx, r) in (&[&self.range.0, &self.range.1]).iter().enumerate() {
283            let range_count: usize;
284            let range_start: usize;
285            match r {
286                RangeType::Range(Range { start, end }) => {
287                    range_count = end - start;
288                    range_start = *start;
289                }
290                RangeType::RangeInclusive(ref range_inclusive) => {
291                    let (&start, &end) = (range_inclusive.start(), range_inclusive.end());
292                    range_count = end - start + 1;
293                    range_start = start;
294                }
295                RangeType::RangeFull(_) => {
296                    if idx == 0 {
297                        range_count = self.matrix.rows();
298                    } else {
299                        range_count = self.matrix.cols();
300                    }
301                    range_start = 0;
302                }
303                RangeType::RangeFrom(RangeFrom { start }) => {
304                    if idx == 0 {
305                        range_count = self.matrix.rows();
306                    } else {
307                        range_count = self.matrix.cols();
308                    }
309                    range_start = *start;
310                }
311                RangeType::RangeTo(RangeTo { end }) => {
312                    range_count = *end;
313                    range_start = 0;
314                }
315                RangeType::RangeToInclusive(RangeToInclusive { end }) => {
316                    range_count = end + 1;
317                    range_start = 0;
318                }
319            }
320            ranges[idx].start = range_start;
321            ranges[idx].count = range_count;
322        }
323        let [range_rows, range_cols] = ranges;
324        (range_rows, range_cols)
325    }
326}
327
328impl<'a, T: NumAssign + Copy + Default, const ROW: usize, const COL: usize>
329    MatrixSlice<'a, T, ROW, COL>
330{
331    pub(crate) fn get_range(&'a self) -> (RangeInfo, RangeInfo) {
332        let mut ranges: [RangeInfo; 2] = Default::default();
333        for (idx, r) in (&[&self.range.0, &self.range.1]).iter().enumerate() {
334            let range_count: usize;
335            let range_start: usize;
336            match r {
337                RangeType::Range(Range { start, end }) => {
338                    range_count = end - start;
339                    range_start = *start;
340                }
341                RangeType::RangeInclusive(ref range_inclusive) => {
342                    let (&start, &end) = (range_inclusive.start(), range_inclusive.end());
343                    range_count = end - start + 1;
344                    range_start = start;
345                }
346                RangeType::RangeFull(_) => {
347                    if idx == 0 {
348                        range_count = self.matrix.rows();
349                    } else {
350                        range_count = self.matrix.cols();
351                    }
352                    range_start = 0;
353                }
354                RangeType::RangeFrom(RangeFrom { start }) => {
355                    if idx == 0 {
356                        range_count = self.matrix.rows();
357                    } else {
358                        range_count = self.matrix.cols();
359                    }
360                    range_start = *start;
361                }
362                RangeType::RangeTo(RangeTo { end }) => {
363                    range_count = *end;
364                    range_start = 0;
365                }
366                RangeType::RangeToInclusive(RangeToInclusive { end }) => {
367                    range_count = end + 1;
368                    range_start = 0;
369                }
370            }
371            ranges[idx].start = range_start;
372            ranges[idx].count = range_count;
373        }
374        let [range_rows, range_cols] = ranges;
375        (range_rows, range_cols)
376    }
377}
378
379#[cfg(test)]
380#[quickcheck]
381fn matrix_slice_assign((m1, mut m2): (Matrix<f64, 15, 10>, Matrix<f64, 15, 10>)) -> bool {
382    let src = MatrixSlice::<f64, 15, 10>::from((&m1, ((2..5), (3..6))));
383    let mut dest = MatrixSliceMut::<f64, 15, 10>::from((&mut m2, ((5..8), (7..10))));
384    dest.assign(src);
385    let mut check = true;
386    for (i_idx, i) in (5..8).enumerate() {
387        for (j_idx, j) in (7..10).enumerate() {
388            check &= m2[[i, j]] == m1[[2 + i_idx, 3 + j_idx]];
389        }
390    }
391    check
392}
393
394#[cfg(test)]
395#[quickcheck]
396fn matrix_slice_assign_from_larget_region(
397    (m1, mut m2): (Matrix<f64, 15, 10>, Matrix<f64, 15, 15>),
398) -> bool {
399    let src = MatrixSlice::from((&m1, ((2..15), (3..15))));
400    let mut dest = MatrixSliceMut::from((&mut m2, ((5..8), (7..10))));
401    dest.assign(src);
402    let mut check = true;
403    for (i_idx, i) in (5..8).enumerate() {
404        for (j_idx, j) in (7..10).enumerate() {
405            check &= m2[[i, j]] == m1[[2 + i_idx, 3 + j_idx]];
406        }
407    }
408    check
409}
410
411#[test]
412fn matrix_slice_assign_dest_shape_too_big() {
413    use std::panic;
414    let result = panic::catch_unwind(|| {
415        let (m1, mut m2) = (
416            Matrix::<f64, 15, 10>::default(),
417            Matrix::<f64, 15, 15>::default(),
418        );
419        let src = MatrixSlice::from((&m1, ((2..5), (3..6))));
420        let mut dest = MatrixSliceMut::from((&mut m2, ((5..9), (7..10))));
421        dest.assign(src)
422    });
423    assert!(result.is_err());
424}
425
426#[cfg(test)]
427#[quickcheck]
428fn matrix_slice_assign_range_full((m1, mut m2): (Matrix<f64, 15, 10>, Matrix<f64, 3, 3>)) -> bool {
429    let src = MatrixSlice::<f64, 15, 10>::from((&m1, ((2..5), (3..6))));
430    let mut dest = MatrixSliceMut::from((&mut m2, ((..), (..))));
431    dest.assign(src);
432    let mut check = true;
433    for (i_idx, i) in (0..3).enumerate() {
434        for (j_idx, j) in (0..3).enumerate() {
435            check &= m2[[i, j]] == m1[[2 + i_idx, 3 + j_idx]];
436        }
437    }
438    check
439}
440
441#[cfg(test)]
442#[quickcheck]
443fn matrix_slice_assign_range_inclusive(
444    (m1, mut m2): (Matrix<f64, 15, 10>, Matrix<f64, 4, 4>),
445) -> bool {
446    let src = MatrixSlice::<f64, 15, 10>::from((&m1, ((2..=5), (3..=6))));
447    let mut dest = MatrixSliceMut::from((&mut m2, ((..), (..))));
448    dest.assign(src);
449    let mut check = true;
450    for (i_idx, i) in (0..4).enumerate() {
451        for (j_idx, j) in (0..4).enumerate() {
452            check &= m2[[i, j]] == m1[[2 + i_idx, 3 + j_idx]];
453        }
454    }
455    check
456}
457
458#[cfg(test)]
459#[quickcheck]
460fn matrix_slice_combo_range_and_range_inclusive(
461    (m1, mut m2): (Matrix<f64, 15, 10>, Matrix<f64, 4, 4>),
462) -> bool {
463    let src = MatrixSlice::<f64, 15, 10>::from((&m1, ((2..6), (3..=6))));
464    let mut dest = MatrixSliceMut::from((&mut m2, ((..), (..))));
465    dest.assign(src);
466    let mut check = true;
467    for (i_idx, i) in (0..4).enumerate() {
468        for (j_idx, j) in (0..4).enumerate() {
469            check &= m2[[i, j]] == m1[[2 + i_idx, 3 + j_idx]];
470        }
471    }
472    check
473}
474
475#[cfg(test)]
476#[quickcheck]
477fn matrix_slice_combo_range_and_range_to(
478    (m1, mut m2): (Matrix<f64, 15, 10>, Matrix<f64, 4, 4>),
479) -> bool {
480    let src = MatrixSlice::<f64, 15, 10>::from((&m1, ((..4), (3..7))));
481    let mut dest = MatrixSliceMut::from((&mut m2, ((..), (..))));
482    dest.assign(src);
483    let mut check = true;
484    for (i_idx, i) in (0..4).enumerate() {
485        for (j_idx, j) in (0..4).enumerate() {
486            check &= m2[[i, j]] == m1[[0 + i_idx, 3 + j_idx]];
487        }
488    }
489    check
490}
491
492#[cfg(test)]
493#[quickcheck]
494fn matrix_slice_combo_range_and_range_from(
495    (m1, mut m2): (Matrix<f64, 15, 10>, Matrix<f64, 4, 4>),
496) -> bool {
497    let src = MatrixSlice::<f64, 15, 10>::from((&m1, ((11..), (3..7))));
498    let mut dest = MatrixSliceMut::from((&mut m2, ((..), (..))));
499    dest.assign(src);
500    let mut check = true;
501    for (i_idx, i) in (0..4).enumerate() {
502        for (j_idx, j) in (0..4).enumerate() {
503            check &= m2[[i, j]] == m1[[11 + i_idx, 3 + j_idx]];
504        }
505    }
506    check
507}
508
509#[cfg(test)]
510#[quickcheck]
511fn matrix_slice_combo_range_from_and_range_to_inclusive(
512    (m1, mut m2): (Matrix<f64, 15, 10>, Matrix<f64, 4, 4>),
513) -> bool {
514    let src = MatrixSlice::<f64, 15, 10>::from((&m1, ((11..), (..=3))));
515    let mut dest = MatrixSliceMut::from((&mut m2, ((..), (..))));
516    dest.assign(src);
517    let mut check = true;
518    for (i_idx, i) in (0..4).enumerate() {
519        for (j_idx, j) in (0..4).enumerate() {
520            check &= m2[[i, j]] == m1[[11 + i_idx, 0 + j_idx]];
521        }
522    }
523    check
524}
525
526#[cfg(test)]
527#[quickcheck]
528fn matrix_slice_combo_range_inclusive_and_range_to_inclusive(
529    (m1, mut m2): (Matrix<f64, 15, 10>, Matrix<f64, 4, 4>),
530) -> bool {
531    let src = MatrixSlice::<f64, 15, 10>::from((&m1, ((11..15), (0..4))));
532    let mut dest = MatrixSliceMut::from((&mut m2, ((0..=3), (..=3))));
533    dest.assign(src);
534    let mut check = true;
535    for (i_idx, i) in (0..4).enumerate() {
536        for (j_idx, j) in (0..4).enumerate() {
537            check &= m2[[i, j]] == m1[[11 + i_idx, 0 + j_idx]];
538        }
539    }
540    check
541}
542
543#[cfg(test)]
544#[quickcheck]
545fn matrix_slice_to_owned_matrix(m1: Matrix<i64, 15, 15>) -> bool {
546    let slice = MatrixSlice::from((&m1, ((0..10), (0..10))));
547    let owned: Matrix<i64, 10, 10> = Matrix::from(&slice);
548    let mut check = true;
549    for i in 0..10 {
550        for j in 0..10 {
551            check &= m1[[i, j]] == owned[[i, j]];
552        }
553    }
554    check
555}
556
557#[test]
558fn matrix_slice_unmatched_shape() {
559    let m = Matrix::<i64, 4, 1>::default();
560    use std::panic;
561    let result = panic::catch_unwind(|| {
562        let slice = MatrixSlice::from((&m, ((0..4), (0..1))));
563        let _owned: Matrix<i64, 4, 3> = Matrix::from(&slice);
564    });
565    assert!(result.is_err());
566}
567
568#[cfg(test)]
569#[quickcheck]
570fn matrix_slice_clone(mut m1: Matrix<i64, 15, 15>) -> bool {
571    let view = {
572        let slice = MatrixSliceMut::from((&mut m1, ((0..10), (0..10))));
573        MatrixSlice::from(slice)
574    };
575    let mut check = true;
576    let copy = Matrix::<i64, 10, 10>::from(&view);
577    for i in 0..10 {
578        for j in 0..10 {
579            check &= m1[[i, j]] == copy[[i, j]];
580        }
581    }
582    m1 *= 2;
583    for i in 0..10 {
584        for j in 0..10 {
585            check &= m1[[i, j]] == 2 * copy[[i, j]];
586        }
587    }
588    check
589}