orx_v/matrices/v2/v2_as_matrix.rs
1use super::{v2_col_major::V2MatrixColMajor, v2_row_major::V2MatrixRowMajor};
2use crate::{NVec, NVecMut, D2};
3
4/// Creates matrix views of a rectangular `D2` vector.
5pub trait V2AsMatrix<T> {
6 /// Converts the rectangular `D2` vector into a row-major matrix.
7 ///
8 /// Say i represents row-index and j represents col-index.
9 /// In a row-major matrix:
10 /// * it is more efficient to iterate first over i, and then over j,
11 /// * [`row(i)`] often (1) returns a vector over a contagious memory location.
12 ///
13 /// *(1) When the data is represented by a complete allocation; however, recall that
14 /// it is possible to use a function or a sparse vector backed up with a lookup as
15 /// the underlying vector of the matrix.*
16 ///
17 /// # Panics
18 ///
19 /// Panics if the `D2` vector is not rectangular; i.e.,
20 /// [`is_rectangular`] is false.
21 ///
22 /// [`is_rectangular`]: crate::NVec::is_rectangular
23 ///
24 /// # Examples
25 ///
26 /// ```
27 /// use orx_v::*;
28 ///
29 /// let v2 = vec![
30 /// vec![1, 2, 3],
31 /// vec![4, 5, 6],
32 /// vec![7, 8, 9],
33 /// vec![10, 11, 12],
34 /// ];
35 ///
36 /// let mat = v2.into_matrix();
37 ///
38 /// assert_eq!(mat.num_rows(), 4);
39 /// assert_eq!(mat.num_cols(), 3);
40 ///
41 /// for row in mat.rows() {
42 /// assert_eq!(row.card([]), 3);
43 /// }
44 ///
45 /// let row = mat.row(2);
46 /// assert_eq!(row.equality(&[7, 8, 9]), Equality::Equal); // rows are contagious
47 ///
48 /// assert_eq!(mat.at([2, 1]), 8);
49 ///
50 /// assert_eq!(mat.all().count(), 12);
51 /// ```
52 ///
53 /// Notice that any vector of `D2` can be viewed as a matrix.
54 /// This allows for efficient representations.
55 ///
56 /// For instance, zeros or ones matrices do not require any allocation.
57 /// Similarly, a unit diagonal matrix can be represented by a function.
58 /// A general diagonal matrix can be represented with a `D1` vector and
59 /// a function.
60 ///
61 /// ```
62 /// use orx_v::*;
63 ///
64 /// let v2 = V.d2().constant(0).with_rectangular_bounds([2, 3]);
65 /// let zeros = v2.into_matrix();
66 ///
67 /// let v2 = V.d2().constant(1).with_rectangular_bounds([2, 3]);
68 /// let ones = v2.into_matrix();
69 ///
70 /// let n = 5;
71 ///
72 /// let v2 = V
73 /// .d2()
74 /// .fun(|[i, j]| match i == j {
75 /// true => 1,
76 /// false => 0,
77 /// })
78 /// .with_rectangular_bounds([n, n]);
79 /// let diagonal = v2.into_matrix();
80 ///
81 /// for i in 0..diagonal.num_rows() {
82 /// for j in 0..diagonal.num_cols() {
83 /// if i == j {
84 /// assert_eq!(diagonal.at([i, j]), 1);
85 /// } else {
86 /// assert_eq!(diagonal.at([i, j]), 0);
87 /// }
88 /// }
89 /// }
90 ///
91 /// let diagonal_entries = [7, 3, 5, 2, 1];
92 /// let v2 = V
93 /// .d2()
94 /// .fun(|[i, j]| match i == j {
95 /// true => diagonal_entries[i],
96 /// false => 0,
97 /// })
98 /// .with_rectangular_bounds([n, n]);
99 /// let diagonal = v2.into_matrix();
100 ///
101 /// for i in 0..diagonal.num_rows() {
102 /// for j in 0..diagonal.num_cols() {
103 /// if i == j {
104 /// assert_eq!(diagonal.at([i, j]), diagonal_entries[i]);
105 /// } else {
106 /// assert_eq!(diagonal.at([i, j]), 0);
107 /// }
108 /// }
109 /// }
110 /// ```
111 ///
112 /// More general approach to take benefit of sparsity is to use sparse vectors as the
113 /// underlying storage of the matrix.
114 ///
115 /// ```
116 /// use orx_v::*;
117 ///
118 /// let n = 3;
119 /// let m = 4;
120 ///
121 /// let mut v2 = V.d2().sparse(0).with_rectangular_bounds([n, m]);
122 /// let mut matrix = v2.as_matrix_mut();
123 ///
124 /// for row in matrix.rows() {
125 /// assert_eq!(row.equality(&[0, 0, 0, 0]), Equality::Equal);
126 /// }
127 ///
128 /// matrix.set([0, 1], 3);
129 /// *matrix.at_mut([2, 1]) = 7;
130 ///
131 /// assert_eq!(
132 /// matrix.equality(&[[0, 3, 0, 0], [0, 0, 0, 0], [0, 7, 0, 0]].as_matrix()),
133 /// Equality::Equal
134 /// );
135 /// ```
136 fn into_matrix(self) -> V2MatrixRowMajor<T, Self>
137 where
138 Self: NVec<D2, T>,
139 {
140 V2MatrixRowMajor::new(self)
141 }
142
143 /// Creates a row-major matrix view over the rectangular `D2` vector.
144 ///
145 /// Say i represents row-index and j represents col-index.
146 /// In a row-major matrix:
147 /// * it is more efficient to iterate first over i, and then over j,
148 /// * [`row(i)`] often (1) returns a vector over a contagious memory location.
149 ///
150 /// *(1) When the data is represented by a complete allocation; however, recall that
151 /// it is possible to use a function or a sparse vector backed up with a lookup as
152 /// the underlying vector of the matrix.*
153 ///
154 /// # Panics
155 ///
156 /// Panics if the `D2` vector is not rectangular; i.e.,
157 /// [`is_rectangular`] is false.
158 ///
159 /// [`is_rectangular`]: crate::NVec::is_rectangular
160 ///
161 /// # Examples
162 ///
163 /// ```
164 /// use orx_v::*;
165 ///
166 /// let v2 = vec![
167 /// vec![1, 2, 3],
168 /// vec![4, 5, 6],
169 /// vec![7, 8, 9],
170 /// vec![10, 11, 12],
171 /// ];
172 ///
173 /// let mat = v2.as_matrix();
174 ///
175 /// assert_eq!(mat.num_rows(), 4);
176 /// assert_eq!(mat.num_cols(), 3);
177 ///
178 /// for row in mat.rows() {
179 /// assert_eq!(row.card([]), 3);
180 /// }
181 ///
182 /// let row = mat.row(2);
183 /// assert_eq!(row.equality(&[7, 8, 9]), Equality::Equal); // rows are contagious
184 ///
185 /// assert_eq!(mat.at([2, 1]), 8);
186 ///
187 /// assert_eq!(mat.all().count(), 12);
188 /// ```
189 ///
190 /// Notice that any vector of `D2` can be viewed as a matrix.
191 /// This allows for efficient representations.
192 ///
193 /// For instance, zeros or ones matrices do not require any allocation.
194 /// Similarly, a unit diagonal matrix can be represented by a function.
195 /// A general diagonal matrix can be represented with a `D1` vector and
196 /// a function.
197 ///
198 /// ```
199 /// use orx_v::*;
200 ///
201 /// let v2 = V.d2().constant(0).with_rectangular_bounds([2, 3]);
202 /// let zeros = v2.as_matrix();
203 ///
204 /// let v2 = V.d2().constant(1).with_rectangular_bounds([2, 3]);
205 /// let ones = v2.as_matrix();
206 ///
207 /// let n = 5;
208 ///
209 /// let v2 = V
210 /// .d2()
211 /// .fun(|[i, j]| match i == j {
212 /// true => 1,
213 /// false => 0,
214 /// })
215 /// .with_rectangular_bounds([n, n]);
216 /// let diagonal = v2.as_matrix();
217 ///
218 /// for i in 0..diagonal.num_rows() {
219 /// for j in 0..diagonal.num_cols() {
220 /// if i == j {
221 /// assert_eq!(diagonal.at([i, j]), 1);
222 /// } else {
223 /// assert_eq!(diagonal.at([i, j]), 0);
224 /// }
225 /// }
226 /// }
227 ///
228 /// let diagonal_entries = [7, 3, 5, 2, 1];
229 /// let v2 = V
230 /// .d2()
231 /// .fun(|[i, j]| match i == j {
232 /// true => diagonal_entries[i],
233 /// false => 0,
234 /// })
235 /// .with_rectangular_bounds([n, n]);
236 /// let diagonal = v2.as_matrix();
237 ///
238 /// for i in 0..diagonal.num_rows() {
239 /// for j in 0..diagonal.num_cols() {
240 /// if i == j {
241 /// assert_eq!(diagonal.at([i, j]), diagonal_entries[i]);
242 /// } else {
243 /// assert_eq!(diagonal.at([i, j]), 0);
244 /// }
245 /// }
246 /// }
247 /// ```
248 ///
249 /// More general approach to take benefit of sparsity is to use sparse vectors as the
250 /// underlying storage of the matrix.
251 ///
252 /// ```
253 /// use orx_v::*;
254 ///
255 /// let n = 3;
256 /// let m = 4;
257 ///
258 /// let mut v2 = V.d2().sparse(0).with_rectangular_bounds([n, m]);
259 /// let mut matrix = v2.as_matrix_mut();
260 ///
261 /// for row in matrix.rows() {
262 /// assert_eq!(row.equality(&[0, 0, 0, 0]), Equality::Equal);
263 /// }
264 ///
265 /// matrix.set([0, 1], 3);
266 /// *matrix.at_mut([2, 1]) = 7;
267 ///
268 /// assert_eq!(
269 /// matrix.equality(&[[0, 3, 0, 0], [0, 0, 0, 0], [0, 7, 0, 0]].as_matrix()),
270 /// Equality::Equal
271 /// );
272 /// ```
273 fn as_matrix(&self) -> V2MatrixRowMajor<T, &Self>
274 where
275 Self: NVec<D2, T>,
276 {
277 V2MatrixRowMajor::new(self)
278 }
279
280 /// Creates a mutable row-major matrix view over the rectangular `D2` vector.
281 ///
282 /// Say i represents row-index and j represents col-index.
283 /// In a row-major matrix:
284 /// * it is more efficient to iterate first over i, and then over j,
285 /// * [`row(i)`] often (1) returns a vector over a contagious memory location.
286 ///
287 /// *(1) When the data is represented by a complete allocation; however, recall that
288 /// it is possible to use a function or a sparse vector backed up with a lookup as
289 /// the underlying vector of the matrix.*
290 ///
291 /// [`row(i)`]: crate::MatrixRowMajor::row
292 ///
293 /// # Panics
294 ///
295 /// Panics if the `D2` vector is not rectangular; i.e.,
296 /// [`is_rectangular`] is false.
297 ///
298 /// [`is_rectangular`]: crate::NVec::is_rectangular
299 ///
300 /// # Examples
301 ///
302 /// ```
303 /// use orx_v::*;
304 ///
305 /// let mut v2 = vec![
306 /// vec![1, 2, 3],
307 /// vec![4, 5, 6],
308 /// vec![7, 8, 9],
309 /// vec![10, 11, 12],
310 /// ];
311 ///
312 /// let mut mat = v2.as_matrix_mut();
313 ///
314 /// assert_eq!(mat.num_rows(), 4);
315 /// assert_eq!(mat.num_cols(), 3);
316 ///
317 /// *mat.at_mut([0, 1]) = 22;
318 ///
319 /// mat.row_mut(1).mut_all(|x| *x *= 10);
320 ///
321 /// assert_eq!(mat.row(0).equality(&[1, 22, 3]), Equality::Equal);
322 /// assert_eq!(mat.row(1).equality(&[40, 50, 60]), Equality::Equal);
323 /// ```
324 fn as_matrix_mut(&mut self) -> V2MatrixRowMajor<T, &mut Self>
325 where
326 Self: NVecMut<D2, T>,
327 {
328 V2MatrixRowMajor::new(self)
329 }
330
331 /// Converts the rectangular `D2` vector into a column-major matrix.
332 ///
333 /// Note that since default `D2` vector layout is row-major, this method
334 /// provides a transposed view of the original vector.
335 ///
336 /// Say i represents row-index and j represents col-index.
337 /// In a column-major matrix:
338 /// * it is more efficient to iterate first over j, and then over i,
339 /// * [`col(j)`] often (1) returns a vector over a contagious memory location.
340 ///
341 /// *(1) When the data is represented by a complete allocation; however, recall that
342 /// it is possible to use a function or a sparse vector backed up with a lookup as
343 /// the underlying vector of the matrix.*
344 ///
345 /// [`col(j)`]: crate::MatrixColMajor::col
346 ///
347 /// # Panics
348 ///
349 /// Panics if the `D2` vector is not rectangular; i.e.,
350 /// [`is_rectangular`] is false.
351 ///
352 /// [`is_rectangular`]: crate::NVec::is_rectangular
353 ///
354 /// # Examples
355 ///
356 /// ```
357 /// use orx_v::*;
358 ///
359 /// let v2 = vec![vec![0, 1], vec![2, 3], vec![4, 5], vec![6, 7]];
360 /// let mat = v2.into_matrix_col_major();
361 ///
362 /// assert_eq!(mat.num_rows(), 2);
363 /// assert_eq!(mat.num_cols(), 4);
364 ///
365 /// assert_eq!(
366 /// mat.equality(&[[0, 2, 4, 6], [1, 3, 5, 7]].as_matrix()),
367 /// Equality::Equal
368 /// );
369 ///
370 /// let col = mat.col(2);
371 /// assert_eq!(col.equality(&[4, 5]), Equality::Equal); // columns are contagious
372 /// ```
373 fn into_matrix_col_major(self) -> V2MatrixColMajor<T, Self>
374 where
375 Self: NVec<D2, T>,
376 {
377 V2MatrixColMajor::new(self)
378 }
379
380 /// Creates a column-major matrix view over the rectangular `D2` vector.
381 ///
382 /// Note that since default `D2` vector layout is row-major, this method
383 /// provides a transposed view of the original vector.
384 ///
385 /// Say i represents row-index and j represents col-index.
386 /// In a column-major matrix:
387 /// * it is more efficient to iterate first over j, and then over i,
388 /// * [`col(j)`] often (1) returns a vector over a contagious memory location.
389 ///
390 /// *(1) When the data is represented by a complete allocation; however, recall that
391 /// it is possible to use a function or a sparse vector backed up with a lookup as
392 /// the underlying vector of the matrix.*
393 ///
394 /// [`col(j)`]: crate::MatrixColMajor::col
395 ///
396 /// # Panics
397 ///
398 /// Panics if the `D2` vector is not rectangular; i.e.,
399 /// [`is_rectangular`] is false.
400 ///
401 /// [`is_rectangular`]: crate::NVec::is_rectangular
402 ///
403 /// # Examples
404 ///
405 /// ```
406 /// use orx_v::*;
407 ///
408 /// let v2 = vec![vec![0, 1], vec![2, 3], vec![4, 5], vec![6, 7]];
409 /// let mat = v2.as_matrix_col_major();
410 ///
411 /// assert_eq!(mat.num_rows(), 2);
412 /// assert_eq!(mat.num_cols(), 4);
413 ///
414 /// assert_eq!(
415 /// mat.equality(&[[0, 2, 4, 6], [1, 3, 5, 7]].as_matrix()),
416 /// Equality::Equal
417 /// );
418 ///
419 /// let col = mat.col(2);
420 /// assert_eq!(col.equality(&[4, 5]), Equality::Equal); // columns are contagious
421 /// ```
422 fn as_matrix_col_major(&self) -> V2MatrixColMajor<T, &Self>
423 where
424 Self: NVec<D2, T>,
425 {
426 V2MatrixColMajor::new(self)
427 }
428
429 /// Creates a mutable column-major matrix view over the rectangular `D2` vector.
430 ///
431 /// Note that since default `D2` vector layout is row-major, this method
432 /// provides a transposed view of the original vector.
433 ///
434 /// Say i represents row-index and j represents col-index.
435 /// In a column-major matrix:
436 /// * it is more efficient to iterate first over j, and then over i,
437 /// * [`col(j)`] often (1) returns a vector over a contagious memory location.
438 ///
439 /// *(1) When the data is represented by a complete allocation; however, recall that
440 /// it is possible to use a function or a sparse vector backed up with a lookup as
441 /// the underlying vector of the matrix.*
442 ///
443 /// [`col(j)`]: crate::MatrixColMajor::col
444 ///
445 /// # Panics
446 ///
447 /// Panics if the `D2` vector is not rectangular; i.e.,
448 /// [`is_rectangular`] is false.
449 ///
450 /// [`is_rectangular`]: crate::NVec::is_rectangular
451 ///
452 /// # Examples
453 ///
454 /// ```
455 /// use orx_v::*;
456 ///
457 /// let mut v2 = vec![vec![0, 10], vec![1, 11], vec![2, 12], vec![3, 13]];
458 /// let mut mat = v2.as_matrix_col_major_mut();
459 ///
460 /// assert_eq!(mat.num_rows(), 2);
461 /// assert_eq!(mat.num_cols(), 4);
462 ///
463 /// *mat.at_mut([1, 3]) = 33;
464 ///
465 /// {
466 /// let mut c1 = mat.col_mut(2);
467 /// c1.set(1, 22);
468 /// assert_eq!(c1.equality(&[2, 22]), Equality::Equal);
469 /// }
470 ///
471 /// assert_eq!(
472 /// mat.equality(&[[0, 1, 2, 3], [10, 11, 22, 33]].as_matrix()),
473 /// Equality::Equal
474 /// );
475 /// ```
476 fn as_matrix_col_major_mut(&mut self) -> V2MatrixColMajor<T, &mut Self>
477 where
478 Self: NVecMut<D2, T>,
479 {
480 V2MatrixColMajor::new(self)
481 }
482}
483
484impl<T, V> V2AsMatrix<T> for V where V: NVec<D2, T> {}