Skip to main content

faer/
lib.rs

1//! `faer` is a general-purpose linear algebra library for rust, with a focus on
2//! high performance for algebraic operations on medium/large matrices, as well
3//! as matrix decompositions
4//!
5//! most of the high-level functionality in this library is provided through
6//! associated functions in its vocabulary types: [`Mat`]/[`MatRef`]/[`MatMut`]
7//!
8//! `faer` is recommended for applications that handle medium to large dense
9//! matrices, and its design is not well suited for applications that operate
10//! mostly on low dimensional vectors and matrices such as computer graphics or
11//! game development. for such applications, `nalgebra` and `cgmath` may be
12//! better suited
13//!
14//! # basic usage
15//!
16//! [`Mat`] is a resizable matrix type with dynamic capacity, which can be
17//! created using [`Mat::new`] to produce an empty $0\times 0$ matrix,
18//! [`Mat::zeros`] to create a rectangular matrix filled with zeros,
19//! [`Mat::identity`] to create an identity matrix, or [`Mat::from_fn`]
20//! for the more general case
21//!
22//! Given a `&Mat<T>` (resp. `&mut Mat<T>`), a [`MatRef<'_, T>`](MatRef) (resp.
23//! [`MatMut<'_, T>`](MatMut)) can be created by calling [`Mat::as_ref`] (resp.
24//! [`Mat::as_mut`]), which allow for more flexibility than `Mat` in that they
25//! allow slicing ([`MatRef::get`]) and splitting ([`MatRef::split_at`])
26//!
27//! `MatRef` and `MatMut` are lightweight view objects. the former can be copied
28//! freely while the latter has move and reborrow semantics, as described in its
29//! documentation
30//!
31//! most of the matrix operations can be used through the corresponding math
32//! operators: `+` for matrix addition, `-` for subtraction, `*` for either
33//! scalar or matrix multiplication depending on the types of the operands.
34//!
35//! ## example
36//! ```
37//! use faer::{Mat, Scale, mat};
38//! let a = mat![
39//! 	[1.0, 5.0, 9.0], //
40//! 	[2.0, 6.0, 10.0],
41//! 	[3.0, 7.0, 11.0],
42//! 	[4.0, 8.0, 12.0f64],
43//! ];
44//! let b = Mat::from_fn(4, 3, |i, j| (i + j) as f64);
45//! let add = &a + &b;
46//! let sub = &a - &b;
47//! let scale = Scale(3.0) * &a;
48//! let mul = &a * b.transpose();
49//! let a00 = a[(0, 0)];
50//! ```
51//!
52//! # matrix decompositions
53//! `faer` provides a variety of matrix factorizations, each with its own
54//! advantages and drawbacks:
55//!
56//! ## $LL^\top$ decomposition
57//! [`Mat::llt`] decomposes a self-adjoint positive definite matrix $A$ such
58//! that $$A = LL^H,$$
59//! where $L$ is a lower triangular matrix. this decomposition is highly
60//! efficient and has good stability properties
61//!
62//! [an implementation for sparse matrices is also
63//! available](sparse::linalg::solvers::Llt)
64//!
65//! ## $LBL^\top$ decomposition
66//! [`Mat::lblt`] decomposes a self-adjoint (possibly indefinite) matrix $A$
67//! such that $$P A P^\top = LBL^H,$$
68//! where $P$ is a permutation matrix, $L$ is a lower triangular matrix, and $B$
69//! is a block diagonal matrix, with $1 \times 1$ or $2 \times 2$ diagonal
70//! blocks. this decomposition is efficient and has good stability properties
71//!
72//! ## $LU$ decomposition with partial pivoting
73//! [`Mat::partial_piv_lu`] decomposes a square invertible matrix $A$ into a
74//! lower triangular matrix $L$, a unit upper triangular matrix $U$, and a
75//! permutation matrix $P$, such that $$PA = LU$$
76//! it is used by default for computing the determinant, and is generally the
77//! recommended method for solving a square linear system or computing the
78//! inverse of a matrix (although we generally recommend using a
79//! [`faer::linalg::solvers::Solve`](crate::linalg::solvers::Solve) instead of
80//! computing the inverse explicitly)
81//!
82//! [an implementation for sparse matrices is also
83//! available](sparse::linalg::solvers::Lu)
84//!
85//! ## $LU$ decomposition with full pivoting
86//! [`Mat::full_piv_lu`] decomposes a generic rectangular matrix $A$ into a
87//! lower triangular matrix $L$, a unit upper triangular matrix $U$, and
88//! permutation matrices $P$ and $Q$, such that $$PAQ^\top = LU$$
89//! it can be more stable than the LU decomposition with partial pivoting, in
90//! exchange for being more computationally expensive
91//!
92//! ## $QR$ decomposition
93//! [`Mat::qr`] decomposes a matrix $A$ into the product $$A = QR,$$
94//! where $Q$ is a unitary matrix, and $R$ is an upper trapezoidal matrix. it is
95//! often used for solving least squares problems
96//!
97//! [an implementation for sparse matrices is also
98//! available](sparse::linalg::solvers::Qr)
99//!
100//! ## $QR$ decomposition with column pivoting
101//! ([`Mat::col_piv_qr`]) decomposes a matrix $A$ into the product $$AP^\top =
102//! QR,$$ where $P$ is a permutation matrix, $Q$ is a unitary matrix, and $R$ is
103//! an upper trapezoidal matrix
104//!
105//! it is slower than the version with no pivoting, in exchange for being more
106//! numerically stable for rank-deficient matrices
107//!
108//! ## singular value decomposition
109//! the SVD of a matrix $A$ of shape $(m, n)$ is a decomposition into three
110//! components $U$, $S$, and $V$, such that:
111//!
112//! - $U$ has shape $(m, m)$ and is a unitary matrix,
113//! - $V$ has shape $(n, n)$ and is a unitary matrix,
114//! - $S$ has shape $(m, n)$ and is zero everywhere except the main diagonal,
115//!   with nonnegative
116//! diagonal values in nonincreasing order,
117//! - and finally:
118//!
119//! $$A = U S V^H$$
120//!
121//! the SVD is provided in two forms: either the full matrices $U$ and $V$ are
122//! computed, using [`Mat::svd`], or only their first $\min(m, n)$ columns are
123//! computed, using [`Mat::thin_svd`]
124//!
125//! if only the singular values (elements of $S$) are desired, they can be
126//! obtained in nonincreasing order using [`Mat::singular_values`]
127//!
128//! ## eigendecomposition
129//! **note**: the order of the eigenvalues is currently unspecified and may be
130//! changed in a future release
131//!
132//! the eigenvalue decomposition of a square matrix $A$ of shape $(n, n)$ is a
133//! decomposition into two components $U$, $S$:
134//!
135//! - $U$ has shape $(n, n)$ and is invertible,
136//! - $S$ has shape $(n, n)$ and is a diagonal matrix,
137//! - and finally:
138//!
139//! $$A = U S U^{-1}$$
140//!
141//! if $A$ is self-adjoint, then $U$ can be made unitary ($U^{-1} = U^H$), and
142//! $S$ is real valued. additionally, the eigenvalues are sorted in
143//! nondecreasing order
144//!
145//! Depending on the domain of the input matrix and whether it is self-adjoint,
146//! multiple methods are provided to compute the eigendecomposition:
147//! * [`Mat::self_adjoint_eigen`] can be used with either real or complex
148//!   matrices,
149//! producing an eigendecomposition of the same type,
150//! * [`Mat::eigen`] can be used with real or complex matrices, but always
151//!   produces complex values.
152//!
153//! if only the eigenvalues (elements of $S$) are desired, they can be obtained
154//! using [`Mat::self_adjoint_eigenvalues`] (nondecreasing order),
155//! [`Mat::eigenvalues`] with the same conditions described above.
156//!
157//! # crate features
158//!
159//! - `std`: enabled by default. links with the standard library to enable
160//!   additional features such as cpu feature detection at runtime
161//! - `rayon`: enabled by default. enables the `rayon` parallel backend and
162//!   enables global parallelism by default
163//! - `npy`: enables conversions to/from numpy's matrix file format
164//! - `perf-warn`: produces performance warnings when matrix operations are
165//!   called with suboptimal
166//! data layout
167//! - `nightly`: requires the nightly compiler. enables experimental simd
168//!   features such as avx512
169#![cfg_attr(not(feature = "std"), no_std)]
170#![allow(non_snake_case)]
171#![warn(rustdoc::broken_intra_doc_links)]
172extern crate alloc;
173#[cfg(feature = "std")]
174extern crate std;
175/// see: [`generativity::make_guard`]
176#[macro_export]
177macro_rules! make_guard {
178    ($($name:ident),* $(,)?) => {
179        $(#[allow(unused_unsafe)] let $name = unsafe { $crate::generativity::Id::new() };
180        #[allow(unused, unused_unsafe)] let lifetime_brand = unsafe {
181        $crate::generativity::LifetimeBrand::new(&$name) }; #[allow(unused_unsafe)] let
182        $name = unsafe { $crate::generativity::Guard::new($name) };)*
183    };
184}
185macro_rules! repeat_n {
186	($e:expr, $n:expr) => {
187		iter::repeat_n($e, $n)
188	};
189}
190use core::num::NonZeroUsize;
191use core::sync::atomic::AtomicUsize;
192use equator::{assert, debug_assert};
193use faer_traits::*;
194/// shorthand for `<_ as Auto::<T>>::auto()`
195#[macro_export]
196macro_rules! auto {
197	($ty:ty $(,)?) => {
198		$crate::Auto::<$ty>::auto()
199	};
200}
201macro_rules! dispatch {
202	($imp:expr, $ty:ident, $T:ty $(,)?) => {
203		if const { <$T>::IS_NATIVE_C32 } {
204			unsafe {
205				transmute(
206					<ComplexImpl<f32> as ComplexField>::Arch::default()
207						.dispatch(transmute::<_, $ty<ComplexImpl<f32>>>($imp)),
208				)
209			}
210		} else if const { <$T>::IS_NATIVE_C64 } {
211			unsafe {
212				transmute(
213					<ComplexImpl<f64> as ComplexField>::Arch::default()
214						.dispatch(transmute::<_, $ty<ComplexImpl<f64>>>($imp)),
215				)
216			}
217		} else {
218			<$T>::Arch::default().dispatch($imp)
219		}
220	};
221}
222macro_rules! stack_mat {
223	($name:ident, $m:expr, $n:expr, $A:expr, $N:expr, $T:ty $(,)?) => {
224		let mut __tmp = {
225			#[repr(align(64))]
226			struct __Col<T, const A: usize>([T; A]);
227			struct __Mat<T, const A: usize, const N: usize>([__Col<T, A>; N]);
228			core::mem::MaybeUninit::<__Mat<$T, $A, $N>>::uninit()
229		};
230		let __stack = MemStack::new_any(core::slice::from_mut(&mut __tmp));
231		let mut $name =
232			$crate::linalg::temp_mat_zeroed::<$T, _, _>($m, $n, __stack).0;
233		let mut $name = $crate::mat::AsMatMut::as_mat_mut(&mut $name);
234	};
235	($name:ident, $m:expr, $n:expr, $T:ty $(,)?) => {
236		stack_mat!($name, $m, $n, $m, $n, $T)
237	};
238}
239#[macro_export]
240#[doc(hidden)]
241macro_rules! __dbg {
242    () => {
243        std::eprintln!("[{}:{}:{}]", std::file!(), std::line!(), std::column!())
244    };
245    ($val:expr $(,)?) => {
246        match $val { tmp => { std::eprintln!("[{}:{}:{}] {} = {:20?}", std::file!(),
247        std::line!(), std::column!(), std::stringify!($val), & tmp); tmp } }
248    };
249    ($($val:expr),+ $(,)?) => {
250        ($($crate::__dbg!($val)),+,)
251    };
252}
253#[cfg(feature = "perf-warn")]
254#[macro_export]
255#[doc(hidden)]
256macro_rules! __perf_warn {
257	($name:ident) => {{
258		#[inline(always)]
259		#[allow(non_snake_case)]
260		fn $name() -> &'static ::core::sync::atomic::AtomicBool {
261			static $name: ::core::sync::atomic::AtomicBool =
262				::core::sync::atomic::AtomicBool::new(false);
263			&$name
264		}
265		::core::matches!(
266			$name().compare_exchange(
267				false,
268				true,
269				::core::sync::atomic::Ordering::Relaxed,
270				::core::sync::atomic::Ordering::Relaxed,
271			),
272			Ok(_)
273		)
274	}};
275}
276#[doc(hidden)]
277#[macro_export]
278macro_rules! with_dim {
279    ($name:ident, $value:expr $(,)?) => {
280        let __val__ = $value; $crate::make_guard!($name); let $name =
281        $crate::utils::bound::Dim::new(__val__, $name);
282    };
283    ({ $(let $name:ident = $value:expr;)* }) => {
284        $(let __val__ = $value; $crate::make_guard!($name); let $name =
285        $crate::utils::bound::Dim::new(__val__, $name);)*
286    };
287}
288/// zips together matrix of the same size, so that coefficient-wise operations
289/// can be performed on their elements.
290///
291/// # note
292/// the order in which the matrix elements are traversed is unspecified.
293///
294/// # example
295/// ```
296/// use faer::{Mat, mat, unzip, zip};
297/// let nrows = 2;
298/// let ncols = 3;
299/// let a = mat![[1.0, 3.0, 5.0], [2.0, 4.0, 6.0]];
300/// let b = mat![[7.0, 9.0, 11.0], [8.0, 10.0, 12.0]];
301/// let mut sum = Mat::<f64>::zeros(nrows, ncols);
302/// zip!(&mut sum, &a, &b).for_each(|unzip!(sum, a, b)| {
303/// 	*sum = a + b;
304/// });
305/// for i in 0..nrows {
306/// 	for j in 0..ncols {
307/// 		assert_eq!(sum[(i, j)], a[(i, j)] + b[(i, j)]);
308/// 	}
309/// }
310/// ```
311#[macro_export]
312macro_rules! zip {
313    ($head:expr $(,)?) => {
314        $crate::linalg::zip::LastEq($crate::linalg::zip::IntoView::into_view($head),
315        ::core::marker::PhantomData)
316    };
317    ($head:expr, $($tail:expr),* $(,)?) => {
318        $crate::linalg::zip::ZipEq::new($crate::linalg::zip::IntoView::into_view($head),
319        $crate::zip!($($tail,)*))
320    };
321}
322/// expands to the type of zipped items.
323///
324/// # example
325/// ```
326/// use faer::{Mat, Zip, mat, unzip, zip};
327/// let nrows = 2;
328/// let ncols = 3;
329/// let a = mat![[1.0, 3.0, 5.0], [2.0, 4.0, 6.0]];
330/// let b = mat![[7.0, 9.0, 11.0], [8.0, 10.0, 12.0]];
331/// let mut sum = Mat::<f64>::zeros(nrows, ncols);
332/// zip!(&mut sum, &a, &b).for_each(
333/// 	|unzip!(sum, a, b): Zip!(&mut f64, &f64, &f64)| {
334/// 		*sum = a + b;
335/// 	},
336/// );
337/// for i in 0..nrows {
338/// 	for j in 0..ncols {
339/// 		assert_eq!(sum[(i, j)], a[(i, j)] + b[(i, j)]);
340/// 	}
341/// }
342/// ```
343#[macro_export]
344macro_rules! Zip {
345    (..$(,)?) => {
346        _
347    };
348    ($head:ty $(,)?) => {
349        $crate::linalg::zip::Last::<$head >
350    };
351    ($head:ty, $($tail:tt)*) => {
352        $crate::linalg::zip::Zip::<$head, $crate::Zip!($($tail)*) >
353    };
354}
355/// used to undo the zipping by the [`zip!`] macro.
356///
357/// # example
358/// ```
359/// use faer::{Mat, mat, unzip, zip};
360/// let nrows = 2;
361/// let ncols = 3;
362/// let a = mat![[1.0, 3.0, 5.0], [2.0, 4.0, 6.0]];
363/// let b = mat![[7.0, 9.0, 11.0], [8.0, 10.0, 12.0]];
364/// let mut sum = Mat::<f64>::zeros(nrows, ncols);
365/// zip!(&mut sum, &a, &b).for_each(|unzip!(sum, a, b)| {
366/// 	*sum = a + b;
367/// });
368/// for i in 0..nrows {
369/// 	for j in 0..ncols {
370/// 		assert_eq!(sum[(i, j)], a[(i, j)] + b[(i, j)]);
371/// 	}
372/// }
373/// ```
374#[macro_export]
375macro_rules! unzip {
376    (..$(,)?) => {
377        _
378    };
379    ($head:pat $(,)?) => {
380        $crate::linalg::zip::Last($head)
381    };
382    ($head:pat, $($tail:tt)*) => {
383        $crate::linalg::zip::Zip($head, $crate::unzip!($($tail)*))
384    };
385}
386#[macro_export]
387#[doc(hidden)]
388macro_rules! __transpose_impl {
389    ([$([$($col:expr),*])*] $($v:expr;)*) => {
390        [$([$($col,)*],)* [$($v,)*]]
391    };
392    ([$([$($col:expr),*])*] $($v0:expr, $($v:expr),*;)*) => {
393        $crate::__transpose_impl!([$([$($col),*])* [$($v0),*]] $($($v),*;)*)
394    };
395}
396/// creates a [`Mat`] containing the arguments.
397///
398/// ```
399/// use faer::mat;
400/// let matrix = mat![
401/// 	[1.0, 5.0, 9.0], //
402/// 	[2.0, 6.0, 10.0],
403/// 	[3.0, 7.0, 11.0],
404/// 	[4.0, 8.0, 12.0f64],
405/// ];
406/// assert_eq!(matrix[(0, 0)], 1.0);
407/// assert_eq!(matrix[(1, 0)], 2.0);
408/// assert_eq!(matrix[(2, 0)], 3.0);
409/// assert_eq!(matrix[(3, 0)], 4.0);
410/// assert_eq!(matrix[(0, 1)], 5.0);
411/// assert_eq!(matrix[(1, 1)], 6.0);
412/// assert_eq!(matrix[(2, 1)], 7.0);
413/// assert_eq!(matrix[(3, 1)], 8.0);
414/// assert_eq!(matrix[(0, 2)], 9.0);
415/// assert_eq!(matrix[(1, 2)], 10.0);
416/// assert_eq!(matrix[(2, 2)], 11.0);
417/// assert_eq!(matrix[(3, 2)], 12.0);
418/// ```
419#[macro_export]
420macro_rules! mat {
421    () => {
422        { compile_error!("number of columns in the matrix is ambiguous"); }
423    };
424    ($([$($v:expr),* $(,)?]),* $(,)?) => {
425        { let __data = ::core::mem::ManuallyDrop::new($crate::__transpose_impl!([]
426        $($($v),*;)*)); let __data = &* __data; let __ncols = __data.len(); let __nrows =
427        (* __data.get(0).unwrap()).len(); #[allow(unused_unsafe)] unsafe {
428        $crate::mat::Mat::from_fn(__nrows, __ncols, | i, j | ::core::ptr::from_ref(&
429        __data[j] [i]).read()) } }
430    };
431    (
432        @ alloc $($unsafe:ident)? ($stack:ident) ($var:pat) (uninit::<$ty:ty >, $($arg:expr),+
433        $(,)?)
434    ) => {
435        let (mut __mat__, $stack) = $($unsafe)? { $crate::linalg::temp_mat_uninit::<$ty, _, _
436        > ($($arg,)* $stack,) }; let $var = $crate::mat::AsMatMut::as_mat_mut(&mut __mat__);
437    };
438    (
439        @ alloc $($unsafe:ident)? ($stack:ident) ($var:pat) (zero::<$ty:ty >, $($arg:expr),+
440        $(,)?)
441    ) => {
442        let (mut __mat__, $stack) = $($unsafe)? { $crate::linalg::temp_mat_zeroed::<$ty, _, _
443        > ($($arg,)* $stack,) }; let $var = $crate::mat::AsMatMut::as_mat_mut(&mut __mat__);
444    };
445}
446/// creates a [`col::Col`] containing the arguments
447///
448/// ```
449/// use faer::col;
450/// let col_vec = col![3.0, 5.0, 7.0, 9.0];
451/// assert_eq!(col_vec[0], 3.0);
452/// assert_eq!(col_vec[1], 5.0);
453/// assert_eq!(col_vec[2], 7.0);
454/// assert_eq!(col_vec[3], 9.0);
455/// ```
456#[macro_export]
457macro_rules! col {
458    ($($v:expr),* $(,)?) => {
459        { let __data = ::core::mem::ManuallyDrop::new([$($v,)*]); let __data = &* __data;
460        let __len = __data.len(); #[allow(unused_unsafe)] unsafe {
461        $crate::col::Col::from_fn(__len, | i | ::core::ptr::from_ref(& __data[i]).read())
462        } }
463    };
464    (
465        @ alloc $($unsafe:ident)? ($stack:ident) ($var:pat) (uninit::<$ty:ty >, $($arg:expr),+
466        $(,)?)
467    ) => {
468        let (mut __mat__, $stack) = $($unsafe)? { $crate::linalg::temp_mat_uninit::<$ty, _, _
469        > ($($arg,)* 1, $stack,) }; let $var = $crate::mat::AsMatMut::as_mat_mut(&mut __mat__).col_mut(0);
470    };
471
472    (
473        @ alloc $($unsafe:ident)? ($stack:ident) ($var:pat) (zero::<$ty:ty >, $($arg:expr),+
474        $(,)?)
475    ) => {
476        let (mut __mat__, $stack) = $($unsafe)? { $crate::linalg::temp_mat_zeroed::<$ty, _, _
477        > ($($arg,)* 1, $stack,) }; let $var = $crate::mat::AsMatMut::as_mat_mut(&mut __mat__).col_mut(0);
478    };
479}
480/// creates a [`row::Row`] containing the arguments
481///
482/// ```
483/// use faer::row;
484/// let row_vec = row![3.0, 5.0, 7.0, 9.0];
485/// assert_eq!(row_vec[0], 3.0);
486/// assert_eq!(row_vec[1], 5.0);
487/// assert_eq!(row_vec[2], 7.0);
488/// assert_eq!(row_vec[3], 9.0);
489/// ```
490#[macro_export]
491macro_rules! row {
492    ($($v:expr),* $(,)?) => {
493        { let __data = ::core::mem::ManuallyDrop::new([$($v,)*]); let __data = &* __data;
494        let __len = __data.len(); #[allow(unused_unsafe)] unsafe {
495        $crate::row::Row::from_fn(__len, | i | ::core::ptr::from_ref(& __data[i]).read())
496        } }
497    };
498    (
499        @ alloc $($unsafe:ident)? ($stack:ident) ($var:pat) (uninit::<$ty:ty >, $($arg:expr),+
500        $(,)?)
501    ) => {
502        let (mut __mat__, $stack) = $($unsafe)? { $crate::linalg::temp_mat_uninit::<$ty, _, _
503        > ($($arg,)* 1, $stack,) }; let $var = $crate::mat::AsMatMut::as_mat_mut(&mut __mat__).col_mut(0).transpose_mut();
504    };
505
506    (
507        @ alloc $($unsafe:ident)? ($stack:ident) ($var:pat) (zero::<$ty:ty >, $($arg:expr),+
508        $(,)?)
509    ) => {
510        let (mut __mat__, $stack) = $($unsafe)? { $crate::linalg::temp_mat_zeroed::<$ty, _, _
511        > ($($arg,)* 1, $stack,) }; let $var = $crate::mat::AsMatMut::as_mat_mut(&mut __mat__).col_mut(0).transpose_mut();
512    };
513}
514/// convenience function to concatenate a nested list of matrices into a single
515/// big ['Mat']. concatonation pattern follows the numpy.block convention that
516/// each sub-list must have an equal number of columns (net) but the boundaries
517/// do not need to align. in other words, this sort of thing:
518/// ```notcode
519///   AAAbb
520///   AAAbb
521///   cDDDD
522/// ```
523/// is perfectly acceptable
524#[doc(hidden)]
525#[track_caller]
526pub fn concat_impl<T: ComplexField>(
527	blocks: &[&[(mat::MatRef<'_, T>, Conj)]],
528) -> mat::Mat<T> {
529	#[inline(always)]
530	fn count_total_columns<T: ComplexField>(
531		block_row: &[(mat::MatRef<'_, T>, Conj)],
532	) -> usize {
533		let mut out: usize = 0;
534		for (elem, _) in block_row.iter() {
535			out += elem.ncols();
536		}
537		out
538	}
539	#[inline(always)]
540	#[track_caller]
541	fn count_rows<T: ComplexField>(
542		block_row: &[(mat::MatRef<'_, T>, Conj)],
543	) -> usize {
544		let mut out: usize = 0;
545		for (i, (e, _)) in block_row.iter().enumerate() {
546			if i == 0 {
547				out = e.nrows();
548			} else {
549				assert!(e.nrows() == out);
550			}
551		}
552		out
553	}
554	let mut n: usize = 0;
555	let mut m: usize = 0;
556	for row in blocks.iter() {
557		n += count_rows(row);
558	}
559	for (i, row) in blocks.iter().enumerate() {
560		let cols = count_total_columns(row);
561		if i == 0 {
562			m = cols;
563		} else {
564			assert!(cols == m);
565		}
566	}
567	let mut mat = mat::Mat::<T>::zeros(n, m);
568	let mut ni: usize = 0;
569	let mut mj: usize;
570	for row in blocks.iter() {
571		mj = 0;
572		for (elem, conj) in row.iter() {
573			let mut dst =
574				mat.as_mut()
575					.submatrix_mut(ni, mj, elem.nrows(), elem.ncols());
576			if *conj == Conj::No {
577				dst.copy_from(elem);
578			} else {
579				dst.copy_from(elem.conjugate());
580			}
581			mj += elem.ncols();
582		}
583		ni += row[0].0.nrows();
584	}
585	mat
586}
587/// concatenates the matrices in each row horizontally,
588/// then concatenates the results vertically
589///
590/// `concat![[a0, a1, a2], [b1, b2]]` results in the matrix
591/// ```notcode
592/// [a0 | a1 | a2][b0 | b1]
593/// ```
594#[macro_export]
595macro_rules! concat {
596    () => {
597        { compile_error!("number of columns in the matrix is ambiguous"); }
598    };
599    ($([$($v:expr),* $(,)?]),* $(,)?) => {
600        { $crate::concat_impl(& [$(& [$(($v).as_ref().__canonicalize(),)*],)*]) }
601    };
602}
603/// column vector
604pub mod col;
605/// diagonal matrix
606pub mod diag;
607/// de-serialization from common matrix file formats
608#[cfg(feature = "std")]
609pub mod io;
610pub mod linalg;
611/// rectangular matrix
612pub mod mat;
613#[path = "./operator/mod.rs"]
614pub mod matrix_free;
615/// permutation matrix
616pub mod perm;
617/// row vector
618pub mod row;
619pub mod sparse;
620/// helper utilities
621pub mod utils;
622/// native unsigned integer type
623pub trait Index: traits::IndexCore + traits::Index + seal::Seal {}
624impl<T: faer_traits::Index<Signed: seal::Seal> + seal::Seal> Index for T {}
625mod seal {
626	pub trait Seal {}
627	impl<T: faer_traits::Seal> Seal for T {}
628	impl Seal for crate::utils::bound::Dim<'_> {}
629	impl<I: crate::Index> Seal for crate::utils::bound::Idx<'_, I> {}
630	impl<I: crate::Index> Seal for crate::utils::bound::IdxInc<'_, I> {}
631	impl<I: crate::Index> Seal for crate::utils::bound::MaybeIdx<'_, I> {}
632	impl<I: crate::Index> Seal for crate::utils::bound::IdxIncOne<I> {}
633	impl<I: crate::Index> Seal for crate::utils::bound::MaybeIdxOne<I> {}
634	impl Seal for crate::utils::bound::One {}
635	impl Seal for crate::utils::bound::Zero {}
636	impl Seal for crate::ContiguousFwd {}
637	impl Seal for crate::ContiguousBwd {}
638}
639/// sealed trait for types that can be created from "unbound" values, as long as
640/// their struct preconditions are upheld
641pub trait Unbind<I = usize>:
642	Send + Sync + Copy + core::fmt::Debug + seal::Seal
643{
644	/// creates new value
645	/// # safety
646	/// safety invariants must be upheld
647	unsafe fn new_unbound(idx: I) -> Self;
648	/// returns the unbound value, unconstrained by safety invariants
649	fn unbound(self) -> I;
650}
651/// type that can be used to index into a range
652pub type Idx<Dim, I = usize> = <Dim as ShapeIdx>::Idx<I>;
653/// type that can be used to partition a range
654pub type IdxInc<Dim, I = usize> = <Dim as ShapeIdx>::IdxInc<I>;
655/// either an index or a negative value
656pub type MaybeIdx<Dim, I = usize> = <Dim as ShapeIdx>::MaybeIdx<I>;
657/// base trait for [`Shape`]
658pub trait ShapeIdx {
659	/// type that can be used to index into a range
660	type Idx<I: Index>: Unbind<I> + Ord + Eq;
661	/// type that can be used to partition a range
662	type IdxInc<I: Index>: Unbind<I> + Ord + Eq + From<Idx<Self, I>>;
663	/// either an index or a negative value
664	type MaybeIdx<I: Index>: Unbind<I::Signed> + Ord + Eq;
665}
666/// matrix dimension
667pub trait Shape:
668	Unbind
669	+ Ord
670	+ ShapeIdx<
671		Idx<usize>: Ord + Eq + PartialOrd<Self>,
672		IdxInc<usize>: Ord + Eq + PartialOrd<Self>,
673	>
674{
675	/// whether the types involved have any safety invariants
676	const IS_BOUND: bool = true;
677	/// bind the current value using a invariant lifetime guard
678	#[inline]
679	fn bind<'n>(self, guard: generativity::Guard<'n>) -> utils::bound::Dim<'n> {
680		utils::bound::Dim::new(self.unbound(), guard)
681	}
682	/// cast a slice of bound values to unbound values
683	#[inline]
684	fn cast_idx_slice<I: Index>(slice: &[Idx<Self, I>]) -> &[I] {
685		unsafe { core::slice::from_raw_parts(slice.as_ptr() as _, slice.len()) }
686	}
687	/// cast a slice of bound values to unbound values
688	#[inline]
689	fn cast_idx_inc_slice<I: Index>(slice: &[IdxInc<Self, I>]) -> &[I] {
690		unsafe { core::slice::from_raw_parts(slice.as_ptr() as _, slice.len()) }
691	}
692	/// returns the index `0`, which is always valid
693	#[inline(always)]
694	fn start() -> IdxInc<Self> {
695		unsafe { IdxInc::<Self>::new_unbound(0) }
696	}
697	/// returns the incremented value, as an inclusive index
698	#[inline(always)]
699	fn next(idx: Idx<Self>) -> IdxInc<Self> {
700		unsafe { IdxInc::<Self>::new_unbound(idx.unbound() + 1) }
701	}
702	/// returns the last value, equal to the dimension
703	#[inline(always)]
704	fn end(self) -> IdxInc<Self> {
705		unsafe { IdxInc::<Self>::new_unbound(self.unbound()) }
706	}
707	/// checks if the index is valid, returning `Some(_)` in that case
708	#[inline(always)]
709	fn idx(self, idx: usize) -> Option<Idx<Self>> {
710		if idx < self.unbound() {
711			Some(unsafe { Idx::<Self>::new_unbound(idx) })
712		} else {
713			None
714		}
715	}
716	/// checks if the index is valid, returning `Some(_)` in that case
717	#[inline(always)]
718	fn idx_inc(self, idx: usize) -> Option<IdxInc<Self>> {
719		if idx <= self.unbound() {
720			Some(unsafe { IdxInc::<Self>::new_unbound(idx) })
721		} else {
722			None
723		}
724	}
725	/// checks if the index is valid, and panics otherwise
726	#[inline(always)]
727	fn checked_idx(self, idx: usize) -> Idx<Self> {
728		equator::assert!(idx < self.unbound());
729		unsafe { Idx::<Self>::new_unbound(idx) }
730	}
731	/// checks if the index is valid, and panics otherwise
732	#[inline(always)]
733	fn checked_idx_inc(self, idx: usize) -> IdxInc<Self> {
734		equator::assert!(idx <= self.unbound());
735		unsafe { IdxInc::<Self>::new_unbound(idx) }
736	}
737	/// assumes the index is valid
738	/// # safety
739	/// the index must be valid
740	#[inline(always)]
741	unsafe fn unchecked_idx(self, idx: usize) -> Idx<Self> {
742		equator::debug_assert!(idx < self.unbound());
743		unsafe { Idx::<Self>::new_unbound(idx) }
744	}
745	/// assumes the index is valid
746	/// # safety
747	/// the index must be valid
748	#[inline(always)]
749	unsafe fn unchecked_idx_inc(self, idx: usize) -> IdxInc<Self> {
750		equator::debug_assert!(idx <= self.unbound());
751		unsafe { IdxInc::<Self>::new_unbound(idx) }
752	}
753	/// returns an iterator over the indices between `from` and `to`
754	#[inline(always)]
755	fn indices(
756		from: IdxInc<Self>,
757		to: IdxInc<Self>,
758	) -> impl Clone + ExactSizeIterator + DoubleEndedIterator<Item = Idx<Self>>
759	{
760		(from.unbound()..to.unbound()).map(
761			#[inline(always)]
762			|i| unsafe { Idx::<Self>::new_unbound(i) },
763		)
764	}
765}
766impl<T: Send + Sync + Copy + core::fmt::Debug + faer_traits::Seal> Unbind<T>
767	for T
768{
769	#[inline(always)]
770	unsafe fn new_unbound(idx: T) -> Self {
771		idx
772	}
773
774	#[inline(always)]
775	fn unbound(self) -> T {
776		self
777	}
778}
779impl ShapeIdx for usize {
780	type Idx<I: Index> = I;
781	type IdxInc<I: Index> = I;
782	type MaybeIdx<I: Index> = I::Signed;
783}
784impl Shape for usize {
785	const IS_BOUND: bool = false;
786}
787/// stride distance between two consecutive elements along a given dimension
788pub trait Stride:
789	seal::Seal + core::fmt::Debug + Copy + Send + Sync + 'static
790{
791	/// the reversed stride type
792	type Rev: Stride<Rev = Self>;
793	/// returns the reversed stride
794	fn rev(self) -> Self::Rev;
795	/// returns the stride in elements
796	fn element_stride(self) -> isize;
797}
798impl Stride for isize {
799	type Rev = Self;
800
801	#[inline(always)]
802	fn rev(self) -> Self::Rev {
803		-self
804	}
805
806	#[inline(always)]
807	fn element_stride(self) -> isize {
808		self
809	}
810}
811/// contiguous stride equal to `+1`
812#[derive(Copy, Clone, Debug)]
813pub struct ContiguousFwd;
814/// contiguous stride equal to `-1`
815#[derive(Copy, Clone, Debug)]
816pub struct ContiguousBwd;
817impl Stride for ContiguousFwd {
818	type Rev = ContiguousBwd;
819
820	#[inline(always)]
821	fn rev(self) -> Self::Rev {
822		ContiguousBwd
823	}
824
825	#[inline(always)]
826	fn element_stride(self) -> isize {
827		1
828	}
829}
830impl Stride for ContiguousBwd {
831	type Rev = ContiguousFwd;
832
833	#[inline(always)]
834	fn rev(self) -> Self::Rev {
835		ContiguousFwd
836	}
837
838	#[inline(always)]
839	fn element_stride(self) -> isize {
840		-1
841	}
842}
843/// memory allocation error
844#[derive(Copy, Clone, Debug, PartialEq, Eq)]
845pub enum TryReserveError {
846	///rRequired allocation does not fit within `isize` bytes
847	CapacityOverflow,
848	/// allocator could not provide an allocation with the requested layout
849	AllocError {
850		/// requested layout
851		layout: core::alloc::Layout,
852	},
853}
854/// determines whether the input should be implicitly conjugated or not
855#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
856pub enum Conj {
857	/// no implicit conjugation
858	No,
859	/// implicit conjugation
860	Yes,
861}
862#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
863pub(crate) enum DiagStatus {
864	Unit,
865	Generic,
866}
867/// determines whether to replace or add to the result of a matmul operatio
868#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
869pub enum Accum {
870	/// overwrites the output buffer
871	Replace,
872	/// adds the result to the output buffer
873	Add,
874}
875/// determines which side of a self-adjoint matrix should be accessed
876#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
877pub enum Side {
878	/// lower triangular half
879	Lower,
880	/// upper triangular half
881	Upper,
882}
883impl Conj {
884	/// returns `self == Conj::Yes`
885	#[inline]
886	pub const fn is_conj(self) -> bool {
887		matches!(self, Conj::Yes)
888	}
889
890	/// returns the composition of `self` and `other`
891	#[inline]
892	pub const fn compose(self, other: Self) -> Self {
893		match (self, other) {
894			(Conj::No, Conj::No) => Conj::No,
895			(Conj::Yes, Conj::Yes) => Conj::No,
896			(Conj::No, Conj::Yes) => Conj::Yes,
897			(Conj::Yes, Conj::No) => Conj::Yes,
898		}
899	}
900
901	/// returns `Conj::No` if `T` is the canonical representation, otherwise
902	/// `Conj::Yes`
903	#[inline]
904	pub const fn get<T: Conjugate>() -> Self {
905		if T::IS_CANONICAL { Self::No } else { Self::Yes }
906	}
907
908	#[inline]
909	pub(crate) fn apply<T: Conjugate>(value: &T) -> T::Canonical {
910		let value = unsafe { &*(value as *const T as *const T::Canonical) };
911		if const { matches!(Self::get::<T>(), Conj::Yes) } {
912			T::Canonical::conj_impl(value)
913		} else {
914			T::Canonical::copy_impl(value)
915		}
916	}
917
918	#[inline]
919	pub(crate) fn apply_rt<T: ComplexField>(self, value: &T) -> T {
920		if self.is_conj() {
921			T::conj_impl(value)
922		} else {
923			T::copy_impl(value)
924		}
925	}
926}
927/// determines the parallelization configuration
928#[derive(Copy, Clone, Debug, PartialEq, Eq)]
929pub enum Par {
930	/// sequential, non portable across different platforms
931	Seq,
932	/// parallelized using the global rayon threadpool, non portable across
933	/// different platforms
934	#[cfg(feature = "rayon")]
935	Rayon(NonZeroUsize),
936}
937impl Par {
938	/// returns `Par::Rayon(nthreads)` if `nthreads` is non-zero, or
939	/// `Par::Rayon(rayon::current_num_threads())` otherwise
940	#[inline]
941	#[cfg(feature = "rayon")]
942	pub fn rayon(nthreads: usize) -> Self {
943		if nthreads == 0 {
944			Self::Rayon(
945				NonZeroUsize::new(rayon::current_num_threads()).unwrap(),
946			)
947		} else {
948			Self::Rayon(NonZeroUsize::new(nthreads).unwrap())
949		}
950	}
951
952	/// the number of threads that should ideally execute an operation with the
953	/// given parallelism
954	#[inline]
955	pub fn degree(&self) -> usize {
956		utils::thread::parallelism_degree(*self)
957	}
958}
959#[allow(non_camel_case_types)]
960/// `Complex<f32>`
961pub type c32 = traits::c32;
962#[allow(non_camel_case_types)]
963/// `Complex<f64>`
964pub type c64 = traits::c64;
965#[allow(non_camel_case_types)]
966/// `Complex<f64>`
967pub type cx128 = traits::cx128;
968#[allow(non_camel_case_types)]
969/// `Complex<f64>`
970pub type fx128 = traits::fx128;
971pub use col::{Col, ColMut, ColRef};
972pub use mat::{Mat, MatMut, MatRef};
973pub use row::{Row, RowMut, RowRef};
974#[allow(unused_imports, dead_code)]
975mod internal_prelude {
976	pub use crate::simd_iter;
977
978	pub trait DivCeil: Sized {
979		fn msrv_div_ceil(self, rhs: Self) -> Self;
980		fn msrv_next_multiple_of(self, rhs: Self) -> Self;
981		fn msrv_checked_next_multiple_of(self, rhs: Self) -> Option<Self>;
982	}
983	impl DivCeil for usize {
984		#[inline]
985		fn msrv_div_ceil(self, rhs: Self) -> Self {
986			let d = self / rhs;
987			let r = self % rhs;
988			if r > 0 { d + 1 } else { d }
989		}
990
991		#[inline]
992		fn msrv_next_multiple_of(self, rhs: Self) -> Self {
993			match self % rhs {
994				0 => self,
995				r => self + (rhs - r),
996			}
997		}
998
999		#[inline]
1000		fn msrv_checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
1001			{
1002				match self.checked_rem(rhs)? {
1003					0 => Some(self),
1004					r => self.checked_add(rhs - r),
1005				}
1006			}
1007		}
1008	}
1009	pub(crate) use crate::col::{Col, ColMut, ColRef};
1010	pub(crate) use crate::diag::{Diag, DiagMut, DiagRef};
1011	pub(crate) use crate::hacks::transmute;
1012	pub(crate) use crate::linalg::{
1013		self, temp_mat_scratch, temp_mat_uninit, temp_mat_zeroed,
1014	};
1015	pub(crate) use crate::mat::{
1016		AsMat, AsMatMut, AsMatRef, Mat, MatMut, MatRef,
1017	};
1018	pub(crate) use crate::perm::{Perm, PermRef};
1019	pub(crate) use crate::prelude::*;
1020	pub(crate) use crate::row::{AsRowMut, AsRowRef, Row, RowMut, RowRef};
1021	pub(crate) use crate::utils::bound::{Array, Dim, Idx, IdxInc, MaybeIdx};
1022	pub(crate) use crate::utils::simd::SimdCtx;
1023	pub(crate) use crate::{Auto, NonExhaustive, Side, Spec};
1024	pub use faer_traits::ext::*;
1025	pub use faer_traits::math_utils::*;
1026	pub use faer_traits::{
1027		ComplexField, ComplexImpl, ComplexImplConj, Conjugate, Index,
1028		IndexCore, Real, RealField, SignedIndex, SimdArch, Symbolic,
1029	};
1030	pub use num_complex::Complex;
1031	#[cfg(test)]
1032	pub(crate) use std::dbg;
1033	#[cfg(test)]
1034	pub(crate) use {alloc::boxed::Box, alloc::vec, alloc::vec::Vec};
1035	#[inline]
1036	pub fn simd_align(i: usize) -> usize {
1037		i.wrapping_neg()
1038	}
1039	pub(crate) use self::{unzip as uz, zip as z};
1040	pub(crate) use crate::{
1041		Accum, Conj, ContiguousBwd, ContiguousFwd, DiagStatus, Par, Shape,
1042		Stride, Unbind, make_guard, unzip, zip,
1043	};
1044	pub use dyn_stack::{MemStack, StackReq, alloc as alloca};
1045	pub use equator::{
1046		assert, assert as Assert, debug_assert, debug_assert as DebugAssert,
1047	};
1048	pub use reborrow::*;
1049}
1050#[allow(unused_imports)]
1051pub(crate) mod internal_prelude_sp {
1052	pub(crate) use crate::internal_prelude::*;
1053	pub(crate) use crate::sparse::{
1054		FaerError, NONE, Pair, SparseColMat, SparseColMatMut, SparseColMatRef,
1055		SparseRowMat, SparseRowMatMut, SparseRowMatRef, SymbolicSparseColMat,
1056		SymbolicSparseColMatRef, SymbolicSparseRowMat, SymbolicSparseRowMatRef,
1057		Triplet, csc_numeric, csc_symbolic, csr_numeric, csr_symbolic,
1058		linalg as linalg_sp, try_collect, try_zeroed, windows2,
1059	};
1060	pub(crate) use core::cell::Cell;
1061	pub(crate) use core::iter;
1062	pub(crate) use dyn_stack::MemBuffer;
1063}
1064/// useful imports for general usage of the library
1065pub mod prelude {
1066	#[cfg(feature = "linalg")]
1067	pub use super::linalg::solvers::{DenseSolve, Solve, SolveLstsq};
1068	#[cfg(feature = "sparse")]
1069	pub use super::prelude_sp::*;
1070	pub use super::{Par, Scale, c32, c64, col, mat, row, unzip, zip};
1071	pub use col::{Col, ColMut, ColRef};
1072	pub use mat::{Mat, MatMut, MatRef};
1073	pub use reborrow::{IntoConst, Reborrow, ReborrowMut};
1074	pub use row::{Row, RowMut, RowRef};
1075	/// see [`Default`]
1076	#[inline]
1077	pub fn default<T: Default>() -> T {
1078		Default::default()
1079	}
1080}
1081#[cfg(feature = "sparse")]
1082mod prelude_sp {
1083	use crate::sparse;
1084	pub use sparse::{
1085		SparseColMat, SparseColMatMut, SparseColMatRef, SparseRowMat,
1086		SparseRowMatMut, SparseRowMatRef,
1087	};
1088}
1089/// scaling factor for multiplying matrices.
1090#[derive(Copy, Clone, Debug)]
1091#[repr(transparent)]
1092pub struct Scale<T>(pub T);
1093impl<T> Scale<T> {
1094	/// create a reference to a scaling factor from a reference to a value.
1095	#[inline(always)]
1096	pub fn from_ref(value: &T) -> &Self {
1097		unsafe { &*(value as *const T as *const Self) }
1098	}
1099
1100	/// create a mutable reference to a scaling factor from a mutable reference
1101	/// to a value.
1102	#[inline(always)]
1103	pub fn from_mut(value: &mut T) -> &mut Self {
1104		unsafe { &mut *(value as *mut T as *mut Self) }
1105	}
1106}
1107/// 0: disabled
1108/// 1: `Seq`
1109/// n >= 2: `Rayon(n - 2)`
1110///
1111/// default: `Rayon(0)`
1112static GLOBAL_PARALLELISM: AtomicUsize = {
1113	#[cfg(all(not(miri), feature = "rayon"))]
1114	{
1115		AtomicUsize::new(2)
1116	}
1117	#[cfg(not(all(not(miri), feature = "rayon")))]
1118	{
1119		AtomicUsize::new(1)
1120	}
1121};
1122/// causes functions that access global parallelism settings to panic.
1123pub fn disable_global_parallelism() {
1124	GLOBAL_PARALLELISM.store(0, core::sync::atomic::Ordering::Relaxed);
1125}
1126/// sets the global parallelism settings.
1127pub fn set_global_parallelism(par: Par) {
1128	let value = match par {
1129		Par::Seq => 1,
1130		#[cfg(feature = "rayon")]
1131		Par::Rayon(n) => n.get().saturating_add(2),
1132	};
1133	GLOBAL_PARALLELISM.store(value, core::sync::atomic::Ordering::Relaxed);
1134}
1135/// gets the global parallelism settings.
1136///
1137/// # panics
1138/// panics if global parallelism is disabled.
1139#[track_caller]
1140pub fn get_global_parallelism() -> Par {
1141	let value = GLOBAL_PARALLELISM.load(core::sync::atomic::Ordering::Relaxed);
1142	match value {
1143		0 => panic!("Global parallelism is disabled."),
1144		1 => Par::Seq,
1145		#[cfg(feature = "rayon")]
1146		n => Par::rayon(n - 2),
1147		#[cfg(not(feature = "rayon"))]
1148		_ => unreachable!(),
1149	}
1150}
1151#[doc(hidden)]
1152pub mod hacks;
1153/// statistics and randomness functionality
1154pub mod stats;
1155mod non_exhaustive {
1156	#[doc(hidden)]
1157	#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1158	#[repr(transparent)]
1159	pub struct NonExhaustive(pub(crate) ());
1160}
1161pub(crate) use non_exhaustive::NonExhaustive;
1162/// like `Default`, but with an extra type parameter so that algorithm
1163/// hyperparameters can be tuned per scalar type.
1164pub trait Auto<T> {
1165	/// returns the default value for the type `T`
1166	fn auto() -> Self;
1167}
1168/// implements [`Default`] based on `Config`'s [`Auto`] implementation for the
1169/// type `T`.
1170pub struct Spec<Config, T> {
1171	/// wrapped config value
1172	pub config: Config,
1173	__marker: core::marker::PhantomData<fn() -> T>,
1174}
1175impl<Config, T> core::ops::Deref for Spec<Config, T> {
1176	type Target = Config;
1177
1178	#[inline]
1179	fn deref(&self) -> &Self::Target {
1180		&self.config
1181	}
1182}
1183impl<Config, T> core::ops::DerefMut for Spec<Config, T> {
1184	#[inline]
1185	fn deref_mut(&mut self) -> &mut Self::Target {
1186		&mut self.config
1187	}
1188}
1189impl<Config: Copy, T> Copy for Spec<Config, T> {}
1190impl<Config: Clone, T> Clone for Spec<Config, T> {
1191	#[inline]
1192	fn clone(&self) -> Self {
1193		Self::new(self.config.clone())
1194	}
1195}
1196impl<Config: core::fmt::Debug, T> core::fmt::Debug for Spec<Config, T> {
1197	#[inline]
1198	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1199		self.config.fmt(f)
1200	}
1201}
1202impl<Config, T> Spec<Config, T> {
1203	/// wraps the given config value
1204	#[inline]
1205	pub fn new(config: Config) -> Self {
1206		Spec {
1207			config,
1208			__marker: core::marker::PhantomData,
1209		}
1210	}
1211}
1212impl<T, Config> From<Config> for Spec<Config, T> {
1213	#[inline]
1214	fn from(config: Config) -> Self {
1215		Spec {
1216			config,
1217			__marker: core::marker::PhantomData,
1218		}
1219	}
1220}
1221impl<T, Config: Auto<T>> Default for Spec<Config, T> {
1222	#[inline]
1223	fn default() -> Self {
1224		Spec {
1225			config: Auto::<T>::auto(),
1226			__marker: core::marker::PhantomData,
1227		}
1228	}
1229}
1230mod into_range {
1231	use super::*;
1232	pub trait IntoRange<I> {
1233		type Len<N: Shape>: Shape;
1234		fn into_range(self, min: I, max: I) -> core::ops::Range<I>;
1235	}
1236	impl<I> IntoRange<I> for core::ops::Range<I> {
1237		type Len<N: Shape> = usize;
1238
1239		#[inline]
1240		fn into_range(self, _: I, _: I) -> core::ops::Range<I> {
1241			self
1242		}
1243	}
1244	impl<I> IntoRange<I> for core::ops::RangeFrom<I> {
1245		type Len<N: Shape> = usize;
1246
1247		#[inline]
1248		fn into_range(self, _: I, max: I) -> core::ops::Range<I> {
1249			self.start..max
1250		}
1251	}
1252	impl<I> IntoRange<I> for core::ops::RangeTo<I> {
1253		type Len<N: Shape> = usize;
1254
1255		#[inline]
1256		fn into_range(self, min: I, _: I) -> core::ops::Range<I> {
1257			min..self.end
1258		}
1259	}
1260	impl<I> IntoRange<I> for core::ops::RangeFull {
1261		type Len<N: Shape> = N;
1262
1263		#[inline]
1264		fn into_range(self, min: I, max: I) -> core::ops::Range<I> {
1265			min..max
1266		}
1267	}
1268}
1269mod sort;
1270pub extern crate dyn_stack;
1271pub extern crate faer_traits as traits;
1272#[doc(hidden)]
1273pub extern crate generativity;
1274pub extern crate num_complex as complex;
1275#[cfg(feature = "rand")]
1276#[cfg_attr(docs_rs, doc(cfg(feature = "rand")))]
1277pub extern crate rand;
1278pub extern crate reborrow;
1279
1280extern crate self as faer;
1281
1282#[macro_export]
1283#[doc(hidden)]
1284macro_rules! simd_iter {
1285	(for ($batch_id:tt, $i:pat $(,)?) in [$indices:expr; $batch_size:expr] $b:block $(,)?) => {#[allow(non_upper_case_globals, unconditional_panic)] 'out:{
1286		let (__head__, __body_batch__, __body_item__, __tail__) = &$indices;
1287		let __body_batch__ = __body_batch__.clone();
1288		let mut __body_item__ = __body_item__.clone();
1289		const {
1290			::core::assert!($batch_size > 0);
1291			::core::assert!($batch_size <= 8);
1292		}
1293		{
1294		if const { $batch_size == 1 } {if $batch_size == 1 { const $batch_id: usize = 0; if let &Some($i) = __head__ $b; }}
1295		if const { $batch_size == 2 } {if $batch_size == 2 { const $batch_id: usize = 1; if let &Some($i) = __head__ $b; }}
1296		if const { $batch_size == 3 } {if $batch_size == 3 { const $batch_id: usize = 2; if let &Some($i) = __head__ $b; }}
1297		if const { $batch_size == 4 } {if $batch_size == 4 { const $batch_id: usize = 3; if let &Some($i) = __head__ $b; }}
1298		if const { $batch_size == 5 } {if $batch_size == 5 { const $batch_id: usize = 4; if let &Some($i) = __head__ $b; }}
1299		if const { $batch_size == 6 } {if $batch_size == 6 { const $batch_id: usize = 5; if let &Some($i) = __head__ $b; }}
1300		if const { $batch_size == 7 } {if $batch_size == 7 { const $batch_id: usize = 6; if let &Some($i) = __head__ $b; }}
1301		if const { $batch_size == 8 } {if $batch_size == 8 { const $batch_id: usize = 7; if let &Some($i) = __head__ $b; }}
1302		}
1303		for __i__ in __body_batch__ {
1304			let __i__: [_; $batch_size] = __i__;
1305			let __i__ = __i__.as_slice();
1306			::core::assert!(__i__.len() == $batch_size);
1307
1308			{
1309			if const { $batch_size > 0 } {if __i__.len() > 0 { const $batch_id: usize = 0; let $i = __i__[0]; $b }}
1310			if const { $batch_size > 1 } {if __i__.len() > 1 { const $batch_id: usize = 1; let $i = __i__[1]; $b }}
1311			if const { $batch_size > 2 } {if __i__.len() > 2 { const $batch_id: usize = 2; let $i = __i__[2]; $b }}
1312			if const { $batch_size > 3 } {if __i__.len() > 3 { const $batch_id: usize = 3; let $i = __i__[3]; $b }}
1313			if const { $batch_size > 4 } {if __i__.len() > 4 { const $batch_id: usize = 4; let $i = __i__[4]; $b }}
1314			if const { $batch_size > 5 } {if __i__.len() > 5 { const $batch_id: usize = 5; let $i = __i__[5]; $b }}
1315			if const { $batch_size > 6 } {if __i__.len() > 6 { const $batch_id: usize = 6; let $i = __i__[6]; $b }}
1316			if const { $batch_size > 7 } {if __i__.len() > 7 { const $batch_id: usize = 7; let $i = __i__[7]; $b }}
1317			}
1318		};
1319
1320		{
1321		if const { $batch_size > 0 } { if $batch_size > 0 { const $batch_id: usize = 0; if let Some($i) = __body_item__.next() $b else { if let &Some($i) = __tail__ $b; break 'out; } } }
1322		if const { $batch_size > 1 } { if $batch_size > 1 { const $batch_id: usize = 1; if let Some($i) = __body_item__.next() $b else { if let &Some($i) = __tail__ $b; break 'out; } } }
1323		if const { $batch_size > 2 } { if $batch_size > 2 { const $batch_id: usize = 2; if let Some($i) = __body_item__.next() $b else { if let &Some($i) = __tail__ $b; break 'out; } } }
1324		if const { $batch_size > 3 } { if $batch_size > 3 { const $batch_id: usize = 3; if let Some($i) = __body_item__.next() $b else { if let &Some($i) = __tail__ $b; break 'out; } } }
1325		if const { $batch_size > 4 } { if $batch_size > 4 { const $batch_id: usize = 4; if let Some($i) = __body_item__.next() $b else { if let &Some($i) = __tail__ $b; break 'out; } } }
1326		if const { $batch_size > 5 } { if $batch_size > 5 { const $batch_id: usize = 5; if let Some($i) = __body_item__.next() $b else { if let &Some($i) = __tail__ $b; break 'out; } } }
1327		if const { $batch_size > 6 } { if $batch_size > 6 { const $batch_id: usize = 6; if let Some($i) = __body_item__.next() $b else { if let &Some($i) = __tail__ $b; break 'out; } } }
1328		if const { $batch_size > 7 } { if $batch_size > 7 { const $batch_id: usize = 7; if let Some($i) = __body_item__.next() $b else { if let &Some($i) = __tail__ $b; break 'out; } } }
1329		}
1330	}};
1331	(for $i:pat in [$indices:expr] $b:block $(,)?) => {#[allow(non_upper_case_globals)]{
1332		let (__head__, __body__, __tail__) = &$indices;
1333		if let &Some($i) = __head__ $b;
1334		for $i in __body__.clone() $b;
1335		if let &Some($i) = __tail__ $b;
1336	}};
1337}