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 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 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
173impl<
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
204impl<
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
235impl<'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}