easy_ml/matrices/views/ranges.rs
1use crate::matrices::views::{DataLayout, MatrixMut, MatrixRef, NoInteriorMutability};
2use crate::matrices::{Column, Row};
3
4use std::marker::PhantomData;
5use std::ops::Range;
6
7/**
8 * A 2 dimensional range over a matrix, hiding the values **outside** the range from view.
9 *
10 * The entire source is still owned by the MatrixRange however, so this does not permit
11 * creating multiple mutable ranges into a single matrix even if they wouldn't overlap.
12 *
13 * For non overlapping mutable ranges into a single matrix see
14 * [`partition`](crate::matrices::Matrix::partition).
15 *
16 * See also: [MatrixMask](MatrixMask)
17 */
18#[derive(Clone, Debug)]
19pub struct MatrixRange<T, S> {
20 source: S,
21 rows: IndexRange,
22 columns: IndexRange,
23 _type: PhantomData<T>,
24}
25
26/**
27 * A 2 dimensional mask over a matrix, hiding the values **inside** the range from view.
28 *
29 * The entire source is still owned by the MatrixMask however, so this does not permit
30 * creating multiple mutable masks into a single matrix even if they wouldn't overlap.
31 *
32 * See also: [MatrixRange](MatrixRange)
33 */
34#[derive(Clone, Debug)]
35pub struct MatrixMask<T, S> {
36 source: S,
37 rows: IndexRange,
38 columns: IndexRange,
39 _type: PhantomData<T>,
40}
41
42impl<T, S> MatrixRange<T, S>
43where
44 S: MatrixRef<T>,
45{
46 /**
47 * Creates a new MatrixRange giving a view of only the data within the row and column
48 * [IndexRange](IndexRange)s.
49 *
50 * # Examples
51 *
52 * Creating a view and manipulating a matrix from it.
53 * ```
54 * use easy_ml::matrices::Matrix;
55 * use easy_ml::matrices::views::{MatrixView, MatrixRange};
56 * let mut matrix = Matrix::from(vec![
57 * vec![ 2, 3, 4 ],
58 * vec![ 5, 1, 8 ]]);
59 * {
60 * let mut view = MatrixView::from(MatrixRange::from(&mut matrix, 0..1, 1..3));
61 * assert_eq!(vec![3, 4], view.row_major_iter().collect::<Vec<_>>());
62 * view.map_mut(|x| x + 10);
63 * }
64 * assert_eq!(matrix, Matrix::from(vec![
65 * vec![ 2, 13, 14 ],
66 * vec![ 5, 1, 8 ]]));
67 * ```
68 *
69 * Various ways to construct a MatrixRange
70 * ```
71 * use easy_ml::matrices::Matrix;
72 * use easy_ml::matrices::views::{IndexRange, MatrixRange};
73 * let matrix = Matrix::from(vec![vec![1]]);
74 * let index_range = MatrixRange::from(&matrix, IndexRange::new(0, 4), IndexRange::new(1, 3));
75 * let tuple = MatrixRange::from(&matrix, (0, 4), (1, 3));
76 * let array = MatrixRange::from(&matrix, [0, 4], [1, 3]);
77 * // Note std::ops::Range is start..end not start and length!
78 * let range = MatrixRange::from(&matrix, 0..4, 1..4);
79 * ```
80 *
81 * NOTE: In previous versions (<=1.8.1), this erroneously did not clip the IndexRange input to
82 * not exceed the rows and columns of the source, which led to the possibility to create
83 * MatrixRanges that reported a greater number of rows and columns in their shape than their
84 * actual data. This function will now correctly clip any ranges that exceed their sources.
85 */
86 pub fn from<R>(source: S, rows: R, columns: R) -> MatrixRange<T, S>
87 where
88 R: Into<IndexRange>,
89 {
90 let max_rows = source.view_rows();
91 let max_columns = source.view_columns();
92 MatrixRange {
93 source,
94 rows: {
95 let mut rows = rows.into();
96 rows.clip(max_rows);
97 rows
98 },
99 columns: {
100 let mut columns = columns.into();
101 columns.clip(max_columns);
102 columns
103 },
104 _type: PhantomData,
105 }
106 }
107
108 /**
109 * Consumes the MatrixRange, yielding the source it was created from.
110 */
111 #[allow(dead_code)]
112 pub fn source(self) -> S {
113 self.source
114 }
115
116 /**
117 * Gives a reference to the MatrixRange's source (in which the data is not clipped).
118 */
119 // # Safety
120 //
121 // Giving out a mutable reference to our source could allow it to be changed out from under us
122 // and make our range checks invalid. However, since the source implements MatrixRef
123 // interior mutability is not allowed, so we can give out shared references without breaking
124 // our own integrity.
125 #[allow(dead_code)]
126 pub fn source_ref(&self) -> &S {
127 &self.source
128 }
129}
130
131impl<T, S> MatrixMask<T, S>
132where
133 S: MatrixRef<T>,
134{
135 /**
136 * Creates a new MatrixMask giving a view of only the data outside the row and column
137 * [IndexRange](IndexRange)s. If the index range given for rows or columns exceeds the
138 * size of the matrix, they will be clipped to fit the actual size without an error.
139 *
140 * # Examples
141 *
142 * Creating a view and manipulating a matrix from it.
143 * ```
144 * use easy_ml::matrices::Matrix;
145 * use easy_ml::matrices::views::{MatrixView, MatrixMask};
146 * let mut matrix = Matrix::from(vec![
147 * vec![ 2, 3, 4 ],
148 * vec![ 5, 1, 8 ]]);
149 * {
150 * let mut view = MatrixView::from(MatrixMask::from(&mut matrix, 0..1, 2..3));
151 * assert_eq!(vec![5, 1], view.row_major_iter().collect::<Vec<_>>());
152 * view.map_mut(|x| x + 10);
153 * }
154 * assert_eq!(matrix, Matrix::from(vec![
155 * vec![ 2, 3, 4 ],
156 * vec![ 15, 11, 8 ]]));
157 * ```
158 *
159 * Various ways to construct a MatrixMask
160 * ```
161 * use easy_ml::matrices::Matrix;
162 * use easy_ml::matrices::views::{IndexRange, MatrixMask};
163 * let matrix = Matrix::from(vec![vec![1]]);
164 * let index_range = MatrixMask::from(&matrix, IndexRange::new(0, 4), IndexRange::new(1, 3));
165 * let tuple = MatrixMask::from(&matrix, (0, 4), (1, 3));
166 * let array = MatrixMask::from(&matrix, [0, 4], [1, 3]);
167 * // Note std::ops::Range is start..end not start and length!
168 * let range = MatrixMask::from(&matrix, 0..4, 1..4);
169 * ```
170 */
171 pub fn from<R>(source: S, rows: R, columns: R) -> MatrixMask<T, S>
172 where
173 R: Into<IndexRange>,
174 {
175 let max_rows = source.view_rows();
176 let max_columns = source.view_columns();
177 MatrixMask {
178 source,
179 rows: {
180 let mut rows = rows.into();
181 rows.clip(max_rows);
182 rows
183 },
184 columns: {
185 let mut columns = columns.into();
186 columns.clip(max_columns);
187 columns
188 },
189 _type: PhantomData,
190 }
191 }
192
193 /**
194 * Consumes the MatrixMask, yielding the source it was created from.
195 */
196 #[allow(dead_code)]
197 pub fn source(self) -> S {
198 self.source
199 }
200
201 /**
202 * Gives a reference to the MatrixMask's source (in which the data is not masked).
203 */
204 // # Safety
205 //
206 // Giving out a mutable reference to our source could allow it to be changed out from under us
207 // and make our mask checks invalid. However, since the source implements MatrixRef
208 // interior mutability is not allowed, so we can give out shared references without breaking
209 // our own integrity.
210 #[allow(dead_code)]
211 pub fn source_ref(&self) -> &S {
212 &self.source
213 }
214}
215
216/**
217 * A range bounded between `start` inclusive and `start + length` exclusive.
218 *
219 * # Examples
220 *
221 * Converting between [Range](std::ops::Range) and IndexRange.
222 * ```
223 * use std::ops::Range;
224 * use easy_ml::matrices::views::IndexRange;
225 * assert_eq!(IndexRange::new(3, 2), (3..5).into());
226 * assert_eq!(IndexRange::new(1, 5), (1..6).into());
227 * assert_eq!(IndexRange::new(0, 4), (0..4).into());
228 * ```
229 *
230 * Creating a Range
231 *
232 * ```
233 * use easy_ml::matrices::views::IndexRange;
234 * let range = IndexRange::new(3, 2);
235 * let also_range: IndexRange = (3, 2).into();
236 * let also_also_range: IndexRange = [3, 2].into();
237 * ```
238 *
239 * NB: You can construct an IndexRange where start+length exceeds isize::MAX or even
240 * usize::MAX, however matrices and tensors themselves cannot contain more than isize::MAX
241 * elements. Concerned readers should note that on a 64 bit computer this maximum
242 * value is 9,223,372,036,854,775,807 so running out of memory is likely to occur first.
243 */
244#[derive(Clone, Debug, Eq, PartialEq)]
245pub struct IndexRange {
246 pub(crate) start: usize,
247 pub(crate) length: usize,
248}
249
250impl IndexRange {
251 pub fn new(start: usize, length: usize) -> IndexRange {
252 IndexRange { start, length }
253 }
254
255 // TODO: If we make these public we need to disambiguate Range from Mask behaviour better
256 /**
257 * Maps from a coordinate space of the ith index accessible by this range to the actual index
258 * into the entire dimension's data.
259 */
260 #[inline]
261 pub(crate) fn map(&self, index: usize) -> Option<usize> {
262 if index < self.length {
263 Some(index + self.start)
264 } else {
265 None
266 }
267 }
268
269 // NOTE: This doesn't perform bounds checks, adding the length of the mask could push
270 // the index out of the valid bounds of the dimension it is for, but if we performed
271 // bounds checks here they would be redundant since performing the get with the masked index
272 // will bounds check if required
273 #[inline]
274 pub(crate) fn mask(&self, index: usize) -> usize {
275 if index < self.start {
276 index
277 } else {
278 index + self.length
279 }
280 }
281
282 // Clips the range or mask to not exceed an index. Note, this may yield 0 length ranges
283 // that have non zero starting positions, however map and mask will still calculate correctly.
284 pub(crate) fn clip(&mut self, max_index: usize) {
285 let end = self.start + self.length;
286 let end = std::cmp::min(end, max_index);
287 let length = end.saturating_sub(self.start);
288 self.length = length;
289 }
290}
291
292/**
293 * Converts from a range of start..end to an IndexRange of start and length
294 *
295 * NOTE: In previous versions (<=1.8.1) this did not saturate when attempting to subtract the
296 * start of the range from the end to calculate the length. It will now correctly produce an
297 * IndexRange with a length of 0 if the end is before or equal to the start.
298 */
299impl From<Range<usize>> for IndexRange {
300 fn from(range: Range<usize>) -> IndexRange {
301 IndexRange::new(range.start, range.end.saturating_sub(range.start))
302 }
303}
304
305/** Converts from an IndexRange of start and length to a range of start..end */
306impl From<IndexRange> for Range<usize> {
307 fn from(range: IndexRange) -> Range<usize> {
308 Range {
309 start: range.start,
310 end: range.start + range.length,
311 }
312 }
313}
314
315/**
316 * Converts from a tuple of start and length to an IndexRange
317 *
318 * NOTE: In previous versions (<=1.8.1), this was erroneously implemented as conversion from a
319 * tuple of start and end, not start and length as documented.
320 */
321impl From<(usize, usize)> for IndexRange {
322 fn from(range: (usize, usize)) -> IndexRange {
323 let (start, length) = range;
324 IndexRange::new(start, length)
325 }
326}
327
328/**
329 * Converts from an array of start and length to an IndexRange
330 *
331 * NOTE: In previous versions (<=1.8.1), this was erroneously implemented as conversion from an
332 * array of start and end, not start and length as documented.
333 */
334impl From<[usize; 2]> for IndexRange {
335 fn from(range: [usize; 2]) -> IndexRange {
336 let [start, length] = range;
337 IndexRange::new(start, length)
338 }
339}
340
341#[test]
342fn test_index_range_clipping() {
343 let mut range: IndexRange = (0..6).into();
344 range.clip(4);
345 assert_eq!(range, (0..4).into());
346 let mut range: IndexRange = (1..4).into();
347 range.clip(5);
348 assert_eq!(range, (1..4).into());
349 range.clip(2);
350 assert_eq!(range, (1..2).into());
351 let mut range: IndexRange = (3..5).into();
352 range.clip(2);
353 assert_eq!(range, (3..2).into());
354 assert_eq!(range.map(0), None);
355 assert_eq!(range.map(1), None);
356 assert_eq!(range.mask(0), 0);
357 assert_eq!(range.mask(1), 1);
358}
359
360// # Safety
361//
362// Since the MatrixRef we own must implement MatrixRef correctly, so do we by delegating to it,
363// as we don't introduce any interior mutability.
364/**
365 * A MatrixRange of a MatrixRef type implements MatrixRef.
366 */
367unsafe impl<T, S> MatrixRef<T> for MatrixRange<T, S>
368where
369 S: MatrixRef<T>,
370{
371 fn try_get_reference(&self, row: Row, column: Column) -> Option<&T> {
372 let row = self.rows.map(row)?;
373 let column = self.columns.map(column)?;
374 self.source.try_get_reference(row, column)
375 }
376
377 fn view_rows(&self) -> Row {
378 self.rows.length
379 }
380
381 fn view_columns(&self) -> Column {
382 self.columns.length
383 }
384
385 unsafe fn get_reference_unchecked(&self, row: Row, column: Column) -> &T {
386 unsafe {
387 // It is the caller's responsibiltiy to always call with row/column indexes in range,
388 // therefore the unwrap() case should never happen because on an arbitary MatrixRef
389 // it would be undefined behavior.
390 let row = self.rows.map(row).unwrap();
391 let column = self.columns.map(column).unwrap();
392 self.source.get_reference_unchecked(row, column)
393 }
394 }
395
396 fn data_layout(&self) -> DataLayout {
397 self.source.data_layout()
398 }
399}
400
401// # Safety
402//
403// Since the MatrixMut we own must implement MatrixMut correctly, so do we by delegating to it,
404// as we don't introduce any interior mutability.
405/**
406 * A MatrixRange of a MatrixMut type implements MatrixMut.
407 */
408unsafe impl<T, S> MatrixMut<T> for MatrixRange<T, S>
409where
410 S: MatrixMut<T>,
411{
412 fn try_get_reference_mut(&mut self, row: Row, column: Column) -> Option<&mut T> {
413 let row = self.rows.map(row)?;
414 let column = self.columns.map(column)?;
415 self.source.try_get_reference_mut(row, column)
416 }
417
418 unsafe fn get_reference_unchecked_mut(&mut self, row: Row, column: Column) -> &mut T {
419 unsafe {
420 // It is the caller's responsibility to always call with row/column indexes in range,
421 // therefore the unwrap() case should never happen because on an arbitary MatrixRef
422 // it would be undefined behavior.
423 let row = self.rows.map(row).unwrap();
424 let column = self.columns.map(column).unwrap();
425 self.source.get_reference_unchecked_mut(row, column)
426 }
427 }
428}
429
430// # Safety
431//
432// Since the NoInteriorMutability we own must implement NoInteriorMutability correctly, so
433// do we by delegating to it, as we don't introduce any interior mutability.
434/**
435 * A MatrixRange of a NoInteriorMutability type implements NoInteriorMutability.
436 */
437unsafe impl<T, S> NoInteriorMutability for MatrixRange<T, S> where S: NoInteriorMutability {}
438
439#[test]
440fn test_matrix_range_shape_clips() {
441 use crate::matrices::Matrix;
442 let matrix = Matrix::from(vec![vec![1, 2, 3], vec![4, 5, 6]]);
443 let range = MatrixRange::from(&matrix, 0..7, 1..4);
444 assert_eq!(2, range.view_rows());
445 assert_eq!(2, range.view_columns());
446 assert_eq!(2, range.rows.length);
447 assert_eq!(2, range.columns.length);
448}
449
450// # Safety
451//
452// Since the MatrixRef we own must implement MatrixRef correctly, so do we by delegating to it,
453// as we don't introduce any interior mutability.
454/**
455 * A MatrixMask of a MatrixRef type implements MatrixRef.
456 */
457unsafe impl<T, S> MatrixRef<T> for MatrixMask<T, S>
458where
459 S: MatrixRef<T>,
460{
461 fn try_get_reference(&self, row: Row, column: Column) -> Option<&T> {
462 let row = self.rows.mask(row);
463 let column = self.columns.mask(column);
464 self.source.try_get_reference(row, column)
465 }
466
467 fn view_rows(&self) -> Row {
468 // We enforce in the constructor that the mask is clipped to the size of our actual
469 // matrix, hence the mask cannot be longer than our data in either dimension. If the
470 // mask is the same length as our data, we'd return 0 which for MatrixRef is allowed.
471 self.source.view_rows() - self.rows.length
472 }
473
474 fn view_columns(&self) -> Column {
475 // We enforce in the constructor that the mask is clipped to the size of our actual
476 // matrix, hence the mask cannot be longer than our data in either dimension. If the
477 // mask is the same length as our data, we'd return 0 which for MatrixRef is allowed.
478 self.source.view_columns() - self.columns.length
479 }
480
481 unsafe fn get_reference_unchecked(&self, row: Row, column: Column) -> &T {
482 unsafe {
483 // It is the caller's responsibility to always call with row/column indexes in range,
484 // therefore calling get_reference_unchecked with indexes beyond the size of the matrix
485 // should never happen because on an arbitary MatrixRef it would be undefined behavior.
486 let row = self.rows.mask(row);
487 let column = self.columns.mask(column);
488 self.source.get_reference_unchecked(row, column)
489 }
490 }
491
492 fn data_layout(&self) -> DataLayout {
493 self.source.data_layout()
494 }
495}
496
497// # Safety
498//
499// Since the MatrixMut we own must implement MatrixMut correctly, so do we by delegating to it,
500// as we don't introduce any interior mutability.
501/**
502 * A MatrixMask of a MatrixMut type implements MatrixMut.
503 */
504unsafe impl<T, S> MatrixMut<T> for MatrixMask<T, S>
505where
506 S: MatrixMut<T>,
507{
508 fn try_get_reference_mut(&mut self, row: Row, column: Column) -> Option<&mut T> {
509 let row = self.rows.mask(row);
510 let column = self.columns.mask(column);
511 self.source.try_get_reference_mut(row, column)
512 }
513
514 unsafe fn get_reference_unchecked_mut(&mut self, row: Row, column: Column) -> &mut T {
515 unsafe {
516 // It is the caller's responsibility to always call with row/column indexes in range,
517 // therefore calling get_reference_unchecked with indexes beyond the size of the matrix
518 // should never happen because on an arbitary MatrixRef it would be undefined behavior.
519 let row = self.rows.mask(row);
520 let column = self.columns.mask(column);
521 self.source.get_reference_unchecked_mut(row, column)
522 }
523 }
524}
525
526// # Safety
527//
528// Since the NoInteriorMutability we own must implement NoInteriorMutability correctly, so
529// do we by delegating to it, as we don't introduce any interior mutability.
530/**
531 * A MatrixMask of a NoInteriorMutability type implements NoInteriorMutability.
532 */
533unsafe impl<T, S> NoInteriorMutability for MatrixMask<T, S> where S: NoInteriorMutability {}