Skip to main content

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