faer/mat/
mod.rs

1use crate::{Shape, Stride, Unbind};
2use core::marker::PhantomData;
3use core::ptr::NonNull;
4use faer_traits::{ComplexField, Conjugate};
5use reborrow::*;
6
7pub(crate) struct MatView<T: ?Sized, Rows, Cols, RStride, CStride> {
8	ptr: NonNull<T>,
9	nrows: Rows,
10	ncols: Cols,
11	row_stride: RStride,
12	col_stride: CStride,
13}
14
15/// represents a type that can be used to slice a matrix, such as an index or a range of indices
16pub trait MatIndex<RowRange, ColRange> {
17	/// sliced view type
18	type Target;
19
20	/// slice `this` using `row` and `col`
21	fn get(this: Self, row: RowRange, col: ColRange) -> Self::Target;
22
23	/// slice `this` using `row` and `col` without bound checks
24	unsafe fn get_unchecked(this: Self, row: RowRange, col: ColRange) -> Self::Target;
25}
26
27impl<T: ?Sized, Rows: Copy, Cols: Copy, RStride: Copy, CStride: Copy> Copy for MatView<T, Rows, Cols, RStride, CStride> {}
28impl<T: ?Sized, Rows: Copy, Cols: Copy, RStride: Copy, CStride: Copy> Clone for MatView<T, Rows, Cols, RStride, CStride> {
29	#[inline]
30	fn clone(&self) -> Self {
31		*self
32	}
33}
34
35#[inline]
36#[track_caller]
37fn from_slice_assert(nrows: usize, ncols: usize, len: usize) {
38	let size = usize::checked_mul(nrows, ncols);
39	assert!(size == Some(len));
40}
41
42mod mat_index;
43
44pub(crate) mod matmut;
45pub(crate) mod matown;
46pub(crate) mod matref;
47
48pub use matmut::Mut;
49pub use matown::Own;
50pub use matref::Ref;
51
52/// heap allocated resizable matrix, similar to a 2d [`alloc::vec::Vec`]
53///
54/// # note
55///
56/// the memory layout of `Own` is guaranteed to be column-major, meaning that it has a row stride
57/// of `1`, and an unspecified column stride that can be queried with [`Mat::col_stride`]
58///
59/// this implies that while each individual column is stored contiguously in memory, the matrix as
60/// a whole may not necessarily be contiguous. the implementation may add padding at the end of
61/// each column when overaligning each column can provide a performance gain
62///
63/// let us consider a 3×4 matrix
64///
65/// ```notcode
66///  0 │ 3 │ 6 │  9
67/// ───┼───┼───┼───
68///  1 │ 4 │ 7 │ 10
69/// ───┼───┼───┼───
70///  2 │ 5 │ 8 │ 11
71/// ```
72/// the memory representation of the data held by such a matrix could look like the following:
73///
74/// ```notcode
75/// [0, 1, 2, x, 3, 4, 5, x, 6, 7, 8, x, 9, 10, 11, x]
76/// ```
77///
78/// where `x` represents padding elements
79pub type Mat<T, Rows = usize, Cols = usize> = generic::Mat<Own<T, Rows, Cols>>;
80
81/// immutable view over a matrix, similar to an immutable reference to a 2d strided [prim@slice]
82///
83/// # Note
84///
85/// unlike a slice, the data pointed to by `MatRef<'_, T>` is allowed to be partially or fully
86/// uninitialized under certain conditions. in this case, care must be taken to not perform any
87/// operations that read the uninitialized values, either directly or indirectly through any of the
88/// numerical library routines, unless it is explicitly permitted
89pub type MatRef<'a, T, Rows = usize, Cols = usize, RStride = isize, CStride = isize> = generic::Mat<Ref<'a, T, Rows, Cols, RStride, CStride>>;
90
91/// mutable view over a matrix, similar to a mutable reference to a 2d strided [prim@slice]
92///
93/// # note
94///
95/// unlike a slice, the data pointed to by `MatMut<'_, T>` is allowed to be partially or fully
96/// uninitialized under certain conditions. In this case, care must be taken to not perform any
97/// operations that read the uninitialized values, either directly or indirectly through any of the
98/// numerical library routines, unless it is explicitly permitted
99///
100/// # move semantics
101/// since `MatMut` mutably borrows data, it cannot be [`Copy`]. this means that if we pass a
102/// `MatMut` to a function that takes it by value, or use a method that consumes `self` like
103/// [`MatMut::transpose_mut`], this renders the original variable unusable
104///
105/// ```compile_fail
106/// use faer::{Mat, MatMut};
107///
108/// fn takes_matmut(view: MatMut<'_, f64>) {}
109///
110/// let mut matrix = Mat::new();
111/// let view = matrix.as_mut();
112///
113/// takes_matmut(view); // `view` is moved (passed by value)
114/// takes_matmut(view); // this fails to compile since `view` was moved
115/// ```
116/// the way to get around it is to use the [`reborrow::ReborrowMut`] trait, which allows us to
117/// mutably borrow a `MatMut` to obtain another `MatMut` for the lifetime of the borrow.
118/// it's also similarly possible to immutably borrow a `MatMut` to obtain a `MatRef` for the
119/// lifetime of the borrow, using [`reborrow::Reborrow`]
120/// ```
121/// use faer::{Mat, MatMut, MatRef};
122/// use reborrow::*;
123///
124/// fn takes_matmut(view: MatMut<'_, f64>) {}
125/// fn takes_matref(view: MatRef<'_, f64>) {}
126///
127/// let mut matrix = Mat::new();
128/// let mut view = matrix.as_mut();
129///
130/// takes_matmut(view.rb_mut());
131/// takes_matmut(view.rb_mut());
132/// takes_matref(view.rb());
133/// // view is still usable here
134/// ```
135pub type MatMut<'a, T, Rows = usize, Cols = usize, RStride = isize, CStride = isize> = generic::Mat<Mut<'a, T, Rows, Cols, RStride, CStride>>;
136
137/// generic `Mat` wrapper
138pub mod generic {
139	use crate::{Idx, Shape, Stride};
140	use core::fmt::Debug;
141	use core::ops::{Index, IndexMut};
142	use reborrow::*;
143
144	/// generic `Mat` wrapper
145	#[derive(Copy, Clone)]
146	#[repr(transparent)]
147	pub struct Mat<Inner>(pub Inner);
148
149	impl<Inner: Debug> Debug for Mat<Inner> {
150		#[inline(always)]
151		fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
152			self.0.fmt(f)
153		}
154	}
155
156	impl<Inner> Mat<Inner> {
157		/// wrap by reference
158		#[inline(always)]
159		pub fn from_inner_ref(inner: &Inner) -> &Self {
160			unsafe { &*(inner as *const Inner as *const Self) }
161		}
162
163		/// wrap by mutable reference
164		#[inline(always)]
165		pub fn from_inner_mut(inner: &mut Inner) -> &mut Self {
166			unsafe { &mut *(inner as *mut Inner as *mut Self) }
167		}
168	}
169
170	impl<Inner> core::ops::Deref for Mat<Inner> {
171		type Target = Inner;
172
173		#[inline(always)]
174		fn deref(&self) -> &Self::Target {
175			&self.0
176		}
177	}
178
179	impl<Inner> core::ops::DerefMut for Mat<Inner> {
180		#[inline(always)]
181		fn deref_mut(&mut self) -> &mut Self::Target {
182			&mut self.0
183		}
184	}
185
186	impl<'short, Inner: Reborrow<'short>> Reborrow<'short> for Mat<Inner> {
187		type Target = Mat<Inner::Target>;
188
189		#[inline(always)]
190		fn rb(&'short self) -> Self::Target {
191			Mat(self.0.rb())
192		}
193	}
194
195	impl<'short, Inner: ReborrowMut<'short>> ReborrowMut<'short> for Mat<Inner> {
196		type Target = Mat<Inner::Target>;
197
198		#[inline(always)]
199		fn rb_mut(&'short mut self) -> Self::Target {
200			Mat(self.0.rb_mut())
201		}
202	}
203
204	impl<Inner: IntoConst> IntoConst for Mat<Inner> {
205		type Target = Mat<Inner::Target>;
206
207		#[inline(always)]
208		fn into_const(self) -> Self::Target {
209			Mat(self.0.into_const())
210		}
211	}
212
213	impl<
214		T,
215		Rows: Shape,
216		Cols: Shape,
217		RStride: Stride,
218		CStride: Stride,
219		Inner: for<'short> Reborrow<'short, Target = super::Ref<'short, T, Rows, Cols, RStride, CStride>>,
220	> Index<(Idx<Rows>, Idx<Cols>)> for Mat<Inner>
221	{
222		type Output = T;
223
224		#[inline]
225		#[track_caller]
226		fn index(&self, (row, col): (Idx<Rows>, Idx<Cols>)) -> &Self::Output {
227			self.rb().at(row, col)
228		}
229	}
230
231	impl<
232		T,
233		Rows: Shape,
234		Cols: Shape,
235		RStride: Stride,
236		CStride: Stride,
237		Inner: for<'short> Reborrow<'short, Target = super::Ref<'short, T, Rows, Cols, RStride, CStride>>
238			+ for<'short> ReborrowMut<'short, Target = super::Mut<'short, T, Rows, Cols, RStride, CStride>>,
239	> IndexMut<(Idx<Rows>, Idx<Cols>)> for Mat<Inner>
240	{
241		#[inline]
242		#[track_caller]
243		fn index_mut(&mut self, (row, col): (Idx<Rows>, Idx<Cols>)) -> &mut Self::Output {
244			self.rb_mut().at_mut(row, col)
245		}
246	}
247}
248
249/// trait for types that can be converted to a matrix view
250pub trait AsMatRef {
251	/// scalar type
252	type T;
253	/// row dimension type
254	type Rows: Shape;
255	/// column dimension type
256	type Cols: Shape;
257	/// owned matrix type
258	type Owned: AsMat<Self::T, T = Self::T, Rows = Self::Rows, Cols = Self::Cols, Owned = Self::Owned>;
259
260	/// returns a view over `self`
261	fn as_mat_ref(&self) -> MatRef<Self::T, Self::Rows, Self::Cols>;
262}
263
264/// trait for types that can be converted to a matrix view
265pub trait AsMatMut: AsMatRef {
266	/// returns a view over `self`
267	fn as_mat_mut(&mut self) -> MatMut<Self::T, Self::Rows, Self::Cols>;
268}
269
270/// trait for owning matrix types
271pub trait AsMat<T>: AsMatMut {
272	/// returns a matrix with dimensions `(rows, cols)` filled with zeros
273	fn zeros(rows: Self::Rows, cols: Self::Cols) -> Self
274	where
275		T: ComplexField;
276
277	/// returns a matrix with dimensions `(rows, cols)` filled with zeros
278	fn truncate(&mut self, rows: Self::Rows, cols: Self::Cols);
279}
280
281impl<M: AsMatRef> AsMatRef for &M {
282	type Cols = M::Cols;
283	type Owned = M::Owned;
284	type Rows = M::Rows;
285	type T = M::T;
286
287	#[inline]
288	fn as_mat_ref(&self) -> MatRef<Self::T, Self::Rows, Self::Cols> {
289		(**self).as_mat_ref()
290	}
291}
292impl<M: AsMatRef> AsMatRef for &mut M {
293	type Cols = M::Cols;
294	type Owned = M::Owned;
295	type Rows = M::Rows;
296	type T = M::T;
297
298	#[inline]
299	fn as_mat_ref(&self) -> MatRef<Self::T, Self::Rows, Self::Cols> {
300		(**self).as_mat_ref()
301	}
302}
303impl<M: AsMatMut> AsMatMut for &mut M {
304	#[inline]
305	fn as_mat_mut(&mut self) -> MatMut<Self::T, Self::Rows, Self::Cols> {
306		(**self).as_mat_mut()
307	}
308}
309
310impl<T, Rows: Shape, Cols: Shape, RStride: Stride, CStride: Stride> AsMatRef for MatRef<'_, T, Rows, Cols, RStride, CStride> {
311	type Cols = Cols;
312	type Owned = Mat<T, Rows, Cols>;
313	type Rows = Rows;
314	type T = T;
315
316	#[inline]
317	fn as_mat_ref(&self) -> MatRef<T, Rows, Cols> {
318		self.as_dyn_stride()
319	}
320}
321
322impl<T, Rows: Shape, Cols: Shape, RStride: Stride, CStride: Stride> AsMatRef for MatMut<'_, T, Rows, Cols, RStride, CStride> {
323	type Cols = Cols;
324	type Owned = Mat<T, Rows, Cols>;
325	type Rows = Rows;
326	type T = T;
327
328	#[inline]
329	fn as_mat_ref(&self) -> MatRef<T, Rows, Cols> {
330		self.rb().as_dyn_stride()
331	}
332}
333
334impl<T, Rows: Shape, Cols: Shape, RStride: Stride, CStride: Stride> AsMatMut for MatMut<'_, T, Rows, Cols, RStride, CStride> {
335	#[inline]
336	fn as_mat_mut(&mut self) -> MatMut<T, Rows, Cols> {
337		self.rb_mut().as_dyn_stride_mut()
338	}
339}
340
341impl<T, Rows: Shape, Cols: Shape> AsMatRef for Mat<T, Rows, Cols> {
342	type Cols = Cols;
343	type Owned = Mat<T, Rows, Cols>;
344	type Rows = Rows;
345	type T = T;
346
347	#[inline]
348	fn as_mat_ref(&self) -> MatRef<T, Rows, Cols> {
349		self.as_dyn_stride()
350	}
351}
352
353impl<T, Rows: Shape, Cols: Shape> AsMat<T> for Mat<T, Rows, Cols> {
354	#[inline]
355	fn zeros(rows: Rows, cols: Cols) -> Self
356	where
357		T: ComplexField,
358	{
359		Mat::zeros(rows, cols)
360	}
361
362	#[track_caller]
363	#[inline]
364	fn truncate(&mut self, rows: Self::Rows, cols: Self::Cols) {
365		self.truncate(rows, cols)
366	}
367}
368
369impl<T, Rows: Shape, Cols: Shape> AsMatMut for Mat<T, Rows, Cols> {
370	#[inline]
371	fn as_mat_mut(&mut self) -> MatMut<T, Rows, Cols> {
372		self.as_dyn_stride_mut()
373	}
374}
375
376#[cfg(test)]
377mod tests {
378	use super::*;
379	use crate::prelude::*;
380
381	#[test]
382	fn test_mat() {
383		let _x = crate::mat![[0.0, 1.0]];
384		let mat = Mat::from_fn(3, 4, |i, j| i as f64 + j as f64);
385
386		let mat = mat.as_ref().cloned();
387		let mat = mat.as_ref();
388
389		for i in 0..3 {
390			for j in 0..4 {
391				zip!(&mat).map(|x| x).as_ref().at(i, j);
392			}
393		}
394	}
395
396	#[test]
397	fn test_mat_complex() {
398		let _x = mat![[c64::new(0.0, 0.0), c64::new(1.0, 0.0)]];
399		let mat = Mat::from_fn(3, 4, |i, j| c64::new(i as f64 + j as f64, 0.0));
400		{
401			let _conj = mat.as_ref().conjugate();
402		}
403
404		let mat = mat.as_ref().cloned();
405		let mat = mat.as_ref();
406
407		for i in 0..3 {
408			for j in 0..4 {
409				zip!(&mat).map(|x| x).as_ref().at(i, j);
410			}
411		}
412	}
413}