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> {}