	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
	fn neg(self) -> Self::Output {
	fn neg(self) -> Self::Output {
	fn add(self, rhs: Self) -> fx128 {
	fn add_assign(&mut self, rhs: Self) {
	fn sub_assign(&mut self, rhs: Self) {
	fn mul_assign(&mut self, rhs: Self) {
	fn div_assign(&mut self, rhs: Self) {
	fn rem_assign(&mut self, rhs: Self) {
	fn sub(self, rhs: Self) -> fx128 {
	fn mul(self, rhs: Self) -> fx128 {
	fn div(self, rhs: Self) -> fx128 {
	fn rem(self, rhs: Self) -> fx128 {
	fn add(self, rhs: Self) -> fx128 {
	fn sub(self, rhs: Self) -> fx128 {
	fn mul(self, rhs: Self) -> fx128 {
	fn div(self, rhs: Self) -> fx128 {
	fn rem(self, rhs: Self) -> fx128 {
	fn zero() -> Self {
	fn is_zero(&self) -> bool {
	fn one() -> Self {
	fn is_one(&self) -> bool {
	fn from_str_radix(_: &str, _: u32) -> Result<Self, Self::FromStrRadixErr> {
	fn zero_impl() -> Self {
	fn one_impl() -> Self {
	fn nan_impl() -> Self {
	fn infinity_impl() -> Self {
	fn from_real_impl(real: &Self::Real) -> Self {
	fn from_f64_impl(real: f64) -> Self {
	fn real_part_impl(value: &Self) -> Self::Real {
	fn imag_part_impl(value: &Self) -> Self::Real {
	fn copy_impl(value: &Self) -> Self {
	fn conj_impl(value: &Self) -> Self {
	fn recip_impl(value: &Self) -> Self {
	fn sqrt_impl(value: &Self) -> Self {
	fn abs_impl(value: &Self) -> Self::Real {
	fn abs1_impl(value: &Self) -> Self::Real {
	fn abs2_impl(value: &Self) -> Self::Real {
	fn mul_real_impl(lhs: &Self, rhs: &Self::Real) -> Self {
	fn mul_pow2_impl(lhs: &Self, rhs: &Self::Real) -> Self {
	fn is_finite_impl(value: &Self) -> bool {
	fn simd_ctx<S: pulp::Simd>(simd: S) -> Self::SimdCtx<S> {
	fn ctx_from_simd<S: pulp::Simd>(ctx: &Self::SimdCtx<S>) -> S {
	fn simd_mask_between<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, start: Self::Index, end: Self::Index) -> Self::SimdMask<S> {
	fn simd_mem_mask_between<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, start: Self::Index, end: Self::Index) -> Self::SimdMemMask<S> {
	unsafe fn simd_mask_load_raw<S: pulp::Simd>(
		ctx: &Self::SimdCtx<S>,
		mask: Self::SimdMemMask<S>,
		ptr: *const Self::SimdVec<S>,
	) -> Self::SimdVec<S> {
	unsafe fn simd_mask_store_raw<S: pulp::Simd>(
		ctx: &Self::SimdCtx<S>,
		mask: Self::SimdMemMask<S>,
		ptr: *mut Self::SimdVec<S>,
		values: Self::SimdVec<S>,
	) {
	fn simd_splat<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, value: &Self) -> Self::SimdVec<S> {
	fn simd_splat_real<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, value: &Self::Real) -> Self::SimdVec<S> {
	fn simd_add<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, lhs: Self::SimdVec<S>, rhs: Self::SimdVec<S>) -> Self::SimdVec<S> {
	fn simd_sub<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, lhs: Self::SimdVec<S>, rhs: Self::SimdVec<S>) -> Self::SimdVec<S> {
	fn simd_neg<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, value: Self::SimdVec<S>) -> Self::SimdVec<S> {
	fn simd_conj<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, value: Self::SimdVec<S>) -> Self::SimdVec<S> {
	fn simd_abs1<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, value: Self::SimdVec<S>) -> Self::SimdVec<S> {
	fn simd_abs_max<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, value: Self::SimdVec<S>) -> Self::SimdVec<S> {
	fn simd_mul_real<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, lhs: Self::SimdVec<S>, real_rhs: Self::SimdVec<S>) -> Self::SimdVec<S> {
	fn simd_mul_pow2<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, lhs: Self::SimdVec<S>, real_rhs: Self::SimdVec<S>) -> Self::SimdVec<S> {
	fn simd_mul<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, lhs: Self::SimdVec<S>, rhs: Self::SimdVec<S>) -> Self::SimdVec<S> {
	fn simd_conj_mul<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, lhs: Self::SimdVec<S>, rhs: Self::SimdVec<S>) -> Self::SimdVec<S> {
	fn simd_mul_add<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, lhs: Self::SimdVec<S>, rhs: Self::SimdVec<S>, acc: Self::SimdVec<S>) -> Self::SimdVec<S> {
	fn simd_conj_mul_add<S: pulp::Simd>(
		ctx: &Self::SimdCtx<S>,
		lhs: Self::SimdVec<S>,
		rhs: Self::SimdVec<S>,
		acc: Self::SimdVec<S>,
	) -> Self::SimdVec<S> {
	fn simd_abs2<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, value: Self::SimdVec<S>) -> Self::SimdVec<S> {
	fn simd_abs2_add<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, value: Self::SimdVec<S>, acc: Self::SimdVec<S>) -> Self::SimdVec<S> {
	fn simd_reduce_sum<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, value: Self::SimdVec<S>) -> Self {
	fn simd_reduce_max<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, value: Self::SimdVec<S>) -> Self {
	fn simd_equal<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, real_lhs: Self::SimdVec<S>, real_rhs: Self::SimdVec<S>) -> Self::SimdMask<S> {
	fn simd_less_than<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, real_lhs: Self::SimdVec<S>, real_rhs: Self::SimdVec<S>) -> Self::SimdMask<S> {
	fn simd_less_than_or_equal<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, real_lhs: Self::SimdVec<S>, real_rhs: Self::SimdVec<S>) -> Self::SimdMask<S> {
	fn simd_greater_than<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, real_lhs: Self::SimdVec<S>, real_rhs: Self::SimdVec<S>) -> Self::SimdMask<S> {
	fn simd_greater_than_or_equal<S: pulp::Simd>(
		ctx: &Self::SimdCtx<S>,
		real_lhs: Self::SimdVec<S>,
		real_rhs: Self::SimdVec<S>,
	) -> Self::SimdMask<S> {
	fn simd_select<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, mask: Self::SimdMask<S>, lhs: Self::SimdVec<S>, rhs: Self::SimdVec<S>) -> Self::SimdVec<S> {
	fn simd_index_select<S: pulp::Simd>(
		ctx: &Self::SimdCtx<S>,
		mask: Self::SimdMask<S>,
		lhs: Self::SimdIndex<S>,
		rhs: Self::SimdIndex<S>,
	) -> Self::SimdIndex<S> {
	fn simd_index_splat<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, value: Self::Index) -> Self::SimdIndex<S> {
	fn simd_index_add<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, lhs: Self::SimdIndex<S>, rhs: Self::SimdIndex<S>) -> Self::SimdIndex<S> {
	fn simd_index_less_than<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, lhs: Self::SimdIndex<S>, rhs: Self::SimdIndex<S>) -> Self::SimdMask<S> {
	fn simd_and_mask<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, lhs: Self::SimdMask<S>, rhs: Self::SimdMask<S>) -> Self::SimdMask<S> {
	fn simd_or_mask<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, lhs: Self::SimdMask<S>, rhs: Self::SimdMask<S>) -> Self::SimdMask<S> {
	fn simd_not_mask<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, mask: Self::SimdMask<S>) -> Self::SimdMask<S> {
	fn simd_first_true_mask<S: pulp::Simd>(ctx: &Self::SimdCtx<S>, value: Self::SimdMask<S>) -> usize {
	fn epsilon_impl() -> Self {
	fn nbits_impl() -> usize {
	fn min_positive_impl() -> Self {
	fn max_positive_impl() -> Self {
	fn sqrt_min_positive_impl() -> Self {
	fn sqrt_max_positive_impl() -> Self {
	fn is_in_subset(&self) -> bool {
	fn to_subset(&self) -> Option<f32> {
	fn to_subset_unchecked(&self) -> f32 {
	fn from_subset(element: &f32) -> Self {
	fn is_in_subset(&self) -> bool {
	fn to_subset(&self) -> Option<f64> {
	fn to_subset_unchecked(&self) -> f64 {
	fn from_subset(element: &f64) -> Self {
	fn to_superset(&self) -> fx128 {
	fn from_superset(element: &fx128) -> Option<Self> {
	fn from_superset_unchecked(element: &fx128) -> Self {
	fn is_in_subset(_: &fx128) -> bool {
	fn from_i64(n: i64) -> Option<Self> {
	fn from_u64(n: u64) -> Option<Self> {
	fn splat(val: Self::Element) -> Self {
	fn extract(&self, _: usize) -> Self::Element {
	unsafe fn extract_unchecked(&self, _: usize) -> Self::Element {
	fn replace(&mut self, _: usize, val: Self::Element) {
	unsafe fn replace_unchecked(&mut self, _: usize, val: Self::Element) {
	fn select(self, cond: Self::SimdBool, other: Self) -> Self {
	fn map_lanes(self, f: impl Fn(Self::Element) -> Self::Element) -> Self
	where
		Self: Clone,
	{
	fn zip_map_lanes(self, b: Self, f: impl Fn(Self::Element, Self::Element) -> Self::Element) -> Self
	where
		Self: Clone,
	{
	fn default_epsilon() -> Self::Epsilon {
	fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
	fn default_max_ulps() -> u32 {
	fn ulps_eq(&self, other: &Self, _: Self::Epsilon, _: u32) -> bool {
	fn default_max_relative() -> Self::Epsilon {
	fn relative_eq(&self, other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon) -> bool {
// For when the numbers are really close together
// Use a relative difference comparison
	fn abs(&self) -> Self {
	fn abs_sub(&self, other: &Self) -> Self {
	fn is_negative(&self) -> bool {
	fn is_positive(&self) -> bool {
	fn signum(&self) -> Self {
/// Builds a pure-real complex number from the given value.
	fn from_real(re: Self::RealField) -> Self {
/// The real part of this complex number.
	fn real(self) -> Self::RealField {
/// The imaginary part of this complex number.
	fn imaginary(self) -> Self::RealField {
/// The modulus of this complex number.
	fn modulus(self) -> Self::RealField {
/// The squared modulus of this complex number.
	fn modulus_squared(self) -> Self::RealField {
/// The argument of this complex number.
	fn argument(self) -> Self::RealField {
/// The sum of the absolute value of this complex number's real and imaginary part.
	fn norm1(self) -> Self::RealField {
/// Multiplies this complex number by `factor`.
	fn scale(self, factor: Self::RealField) -> Self {
/// Divides this complex number by `factor`.
	fn unscale(self, factor: Self::RealField) -> Self {
	fn floor(self) -> Self {
	fn ceil(self) -> Self {
	fn round(self) -> Self {
	fn trunc(self) -> Self {
	fn fract(self) -> Self {
	fn mul_add(self, a: Self, b: Self) -> Self {
/// The absolute value of this complex number: `self / self.signum()`.
///
/// This is equivalent to `self.modulus()`.
	fn abs(self) -> Self::RealField {
/// Computes (self.conjugate() * self + other.conjugate() * other).sqrt()
	fn hypot(self, other: Self) -> Self::RealField {
	fn recip(self) -> Self {
	fn conjugate(self) -> Self {
	fn sin(self) -> Self {
	fn cos(self) -> Self {
	fn sin_cos(self) -> (Self, Self) {
	fn tan(self) -> Self {
	fn asin(self) -> Self {
	fn acos(self) -> Self {
	fn atan(self) -> Self {
	fn sinh(self) -> Self {
	fn cosh(self) -> Self {
	fn tanh(self) -> Self {
	fn asinh(self) -> Self {
	fn acosh(self) -> Self {
	fn atanh(self) -> Self {
	fn log(self, _: Self::RealField) -> Self {
	fn log2(self) -> Self {
	fn log10(self) -> Self {
	fn ln(self) -> Self {
	fn ln_1p(self) -> Self {
	fn sqrt(self) -> Self {
	fn exp(self) -> Self {
	fn exp2(self) -> Self {
	fn exp_m1(self) -> Self {
	fn powi(self, _: i32) -> Self {
	fn powf(self, _: Self::RealField) -> Self {
	fn powc(self, _: Self) -> Self {
	fn cbrt(self) -> Self {
	fn is_finite(&self) -> bool {
	fn try_sqrt(self) -> Option<Self> {
	fn is_sign_positive(&self) -> bool {
	fn is_sign_negative(&self) -> bool {
	fn copysign(self, sign: Self) -> Self {
	fn max(self, other: Self) -> Self {
	fn min(self, other: Self) -> Self {
	fn clamp(self, min: Self, max: Self) -> Self {
	fn atan2(self, _: Self) -> Self {
	fn min_value() -> Option<Self> {
	fn max_value() -> Option<Self> {
	fn pi() -> Self {
	fn two_pi() -> Self {
	fn frac_pi_2() -> Self {
	fn frac_pi_3() -> Self {
	fn frac_pi_4() -> Self {
	fn frac_pi_6() -> Self {
	fn frac_pi_8() -> Self {
	fn frac_1_pi() -> Self {
	fn frac_2_pi() -> Self {
	fn frac_2_sqrt_pi() -> Self {
	fn e() -> Self {
	fn log2_e() -> Self {
	fn log10_e() -> Self {
	fn ln_2() -> Self {
	fn ln_10() -> Self {
fn eigen_dtype<T: Scalar>() -> usize {
	fn openblas_set_num_threads(num: i32) -> c_void;
	fn goto_set_num_threads(num: i32) -> c_void;
	fn MKL_Set_Num_Threads(num: i32) -> c_void;
	fn bli_thread_set_num_threads(num: i64) -> c_void;
	fn omp_set_num_threads(num: i32) -> c_void;
	fn sgetc2_(n: *const c_int, A: *mut f32, lda: *const c_int, ipiv: *mut c_int, jpiv: *mut c_int, info: *mut c_int) -> c_void;
	fn dgetc2_(n: *const c_int, A: *mut f64, lda: *const c_int, ipiv: *mut c_int, jpiv: *mut c_int, info: *mut c_int) -> c_void;
	fn cgetc2_(n: *const c_int, A: *mut c32, lda: *const c_int, ipiv: *mut c_int, jpiv: *mut c_int, info: *mut c_int) -> c_void;
	fn zgetc2_(n: *const c_int, A: *mut c64, lda: *const c_int, ipiv: *mut c_int, jpiv: *mut c_int, info: *mut c_int) -> c_void;
fn lapack_set_num_threads(parallel: Par) {
	fn random(rng: &mut dyn RngCore, nrows: usize, ncols: usize) -> Mat<Self>;
	fn random(rng: &mut dyn RngCore, nrows: usize, ncols: usize) -> Mat<Self> {
	fn random(rng: &mut dyn RngCore, nrows: usize, ncols: usize) -> Mat<Self> {
	fn random(rng: &mut dyn RngCore, nrows: usize, ncols: usize) -> Mat<Self> {
	fn random(rng: &mut dyn RngCore, nrows: usize, ncols: usize) -> Mat<Self> {
	fn random(rng: &mut dyn RngCore, nrows: usize, ncols: usize) -> Mat<Self> {
	fn random(rng: &mut dyn RngCore, nrows: usize, ncols: usize) -> Mat<Self> {
fn bench_eigen<T: Scalar>(bencher: Bencher, decomp: usize, A: MatRef<'_, T>) {
fn llt<T: Scalar, Lib: self::Lib, Thd: self::Thread>(bencher: Bencher, PlotArg(n): PlotArg) {
	fn compute(&self, arg: PlotArg, time: diol::Picoseconds) -> f64 {
	fn monotonicity(&self) -> diol::traits::Monotonicity {
fn main() -> eyre::Result<()> {
fn eigen(bencher: Bencher, PlotArg(n): PlotArg) {
fn main() -> eyre::Result<()> {
fn download(name: &str, sym: bool) -> SparseColMat<usize, f64> {
fn suitesparse_llt(bencher: Bencher, name: String) {
fn faer_llt(bencher: Bencher, name: String) {
fn main() -> eyre::Result<()> {
fn foo_scratch(n: usize) -> StackReq {
// A <- A * B
fn foo(mut A: MatMut<'_, f64>, B: MatRef<'_, f64>, stack: &mut MemStack) {
fn main() {
//          stack
// [....................]
// let (mut stacks, mut stack) = stack.make_with(nthreads, |_| MemStack::new(&mut []));
// stacks    stack
// [...][.................]
// for i in 0..nthreads {
// 	let scratch = foo_scratch(n);
// 	let new;
// 	(new, stack) = stack.make_aligned_uninit(scratch.size_bytes(), scratch.align_bytes());
// 	// stacks foo_scratch  stack
// 	// [...][..][..][..][....]
// 	stacks[i] = MemStack::new(new);
// }
// stacks    foo_scratch
// [...][..][..][..][..][..]
// use rayon::prelude::*;
fn lapack(bencher: Bencher, PlotArg(n): PlotArg) {
	fn get(this: Self, row: RowRange) -> Self::Target {
	unsafe fn get_unchecked(this: Self, row: RowRange) -> Self::Target {
	fn get(this: Self, row: RowRange) -> Self::Target {
	unsafe fn get_unchecked(this: Self, row: RowRange) -> Self::Target {
            fn get(this: Self, row: Idx<$R>) -> Self::Target {
            unsafe fn get_unchecked(this: Self, row: Idx<$R>) -> Self::Target {
            fn get(this: Self, row: Idx<$R>) -> Self::Target {
            unsafe fn get_unchecked(this: Self, row: Idx<$R>) -> Self::Target {
/// see [`super::ColMut`]
	fn rb(&'short self) -> Self::Target {
	fn rb_mut(&'short mut self) -> Self::Target {
	fn into_const(self) -> Self::Target {
/// creates a column view over the given element
	pub fn from_mut(value: &'a mut T) -> Self {
/// creates a `ColMut` from slice views over the column vector data, the result has the same
/// number of rows as the length of the input slice
	pub fn from_slice_mut(slice: &'a mut [T]) -> Self {
/// creates a `ColMut` from pointers to the column vector data, number of rows, and row stride
///
/// # safety
/// this function has the same safety requirements as
/// [`MatMut::from_raw_parts(ptr, nrows, 1, row_stride, 0)`]
	pub const unsafe fn from_raw_parts_mut(ptr: *mut T, nrows: Rows, row_stride: RStride) -> Self {
/// returns a pointer to the column data
	pub fn as_ptr(&self) -> *const T {
/// returns the number of rows of the column
	pub fn nrows(&self) -> Rows {
/// returns the number of columns of the column (always `1`)
	pub fn ncols(&self) -> usize {
/// returns the number of rows and columns of the column
	pub fn shape(&self) -> (Rows, usize) {
/// returns the row stride of the column, specified in number of elements, not in bytes
	pub fn row_stride(&self) -> RStride {
/// returns a raw pointer to the element at the given index
	pub fn ptr_at(&self, row: IdxInc<Rows>) -> *const T {
/// returns a raw pointer to the element at the given index, assuming the provided index
/// is within the column bounds
///
/// # safety
/// the behavior is undefined if any of the following conditions are violated:
/// * `row < self.nrows()`
	pub unsafe fn ptr_inbounds_at(&self, row: Idx<Rows>) -> *const T {
/// see [`ColRef::split_at_row`]
	pub fn split_at_row(self, row: IdxInc<Rows>) -> (ColRef<'a, T, usize, RStride>, ColRef<'a, T, usize, RStride>) {
/// see [`ColRef::transpose`]
	pub fn transpose(self) -> RowRef<'a, T, Rows, RStride> {
/// see [`ColRef::conjugate`]
	pub fn conjugate(self) -> ColRef<'a, T::Conj, Rows, RStride>
	where
		T: Conjugate,
	{
/// see [`ColRef::canonical`]
	pub fn canonical(self) -> ColRef<'a, T::Canonical, Rows, RStride>
	where
		T: Conjugate,
	{
/// see [`ColRef::adjoint`]
	pub fn adjoint(self) -> RowRef<'a, T::Conj, Rows, RStride>
	where
		T: Conjugate,
	{
/// see [`ColRef::get`]
	pub fn get<RowRange>(self, row: RowRange) -> <ColRef<'a, T, Rows, RStride> as ColIndex<RowRange>>::Target
	where
		ColRef<'a, T, Rows, RStride>: ColIndex<RowRange>,
	{
/// see [`ColRef::get_unchecked`]
	pub unsafe fn get_unchecked<RowRange>(self, row: RowRange) -> <ColRef<'a, T, Rows, RStride> as ColIndex<RowRange>>::Target
	where
		ColRef<'a, T, Rows, RStride>: ColIndex<RowRange>,
	{
/// see [`ColRef::reverse_rows`]
	pub fn reverse_rows(self) -> ColRef<'a, T, Rows, RStride::Rev> {
/// see [`ColRef::subrows`]
	pub fn subrows<V: Shape>(self, row_start: IdxInc<Rows>, nrows: V) -> ColRef<'a, T, V, RStride> {
/// see [`ColRef::as_row_shape`]
	pub fn as_row_shape<V: Shape>(self, nrows: V) -> ColRef<'a, T, V, RStride> {
/// see [`ColRef::as_dyn_rows`]
	pub fn as_dyn_rows(self) -> ColRef<'a, T, usize, RStride> {
/// see [`ColRef::as_dyn_stride`]
	pub fn as_dyn_stride(self) -> ColRef<'a, T, Rows, isize> {
/// see [`ColRef::iter`]
	pub fn iter(self) -> impl 'a + ExactSizeIterator + DoubleEndedIterator<Item = &'a T>
	where
		Rows: 'a,
	{
/// see [`ColRef::par_iter`]
	pub fn par_iter(self) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = &'a T>
	where
		T: Sync,
		Rows: 'a,
	{
/// see [`ColRef::par_partition`]
	pub fn par_partition(self, count: usize) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = ColRef<'a, T, usize, RStride>>
	where
		T: Sync,
		Rows: 'a,
	{
/// see [`ColRef::try_as_col_major`]
	pub fn try_as_col_major(self) -> Option<ColRef<'a, T, Rows, ContiguousFwd>> {
/// see [`ColRef::try_as_col_major`]
	pub fn try_as_col_major_mut(self) -> Option<ColMut<'a, T, Rows, ContiguousFwd>> {
	pub unsafe fn const_cast(self) -> ColMut<'a, T, Rows, RStride> {
	pub fn bind_r<'N>(self, row: Guard<'N>) -> ColMut<'a, T, Dim<'N>, RStride> {
/// see [`ColRef::as_mat`]
	pub fn as_mat(self) -> MatRef<'a, T, Rows, usize, RStride, isize> {
/// see [`ColRef::as_mat`]
	pub fn as_mat_mut(self) -> MatMut<'a, T, Rows, usize, RStride, isize> {
/// see [`ColRef::as_diagonal`]
	pub fn as_diagonal(self) -> DiagRef<'a, T, Rows, RStride> {
/// copies `other` into `self`
	pub fn copy_from<RhsT: Conjugate<Canonical = T>>(&mut self, other: impl AsColRef<T = RhsT, Rows = Rows>)
	where
		T: ComplexField,
	{
		pub fn imp<'M, 'N, T: ComplexField>(this: ColMut<'_, T, Dim<'M>>, other: ColRef<'_, T, Dim<'M>>, conj_: Conj) {
/// fills all the elements of `self` with `value`
	pub fn fill(&mut self, value: T)
	where
		T: Clone,
	{
		fn cloner<T: Clone>(value: T) -> impl for<'a> FnMut(crate::linalg::zip::Last<&'a mut T>) {
/// returns a view over `self`
	pub fn as_mut(&mut self) -> ColMut<'_, T, Rows, RStride> {
/// see [`ColRef::as_ptr`]
	pub fn as_ptr_mut(&self) -> *mut T {
/// see [`ColRef::ptr_at`]
	pub fn ptr_at_mut(&self, row: IdxInc<Rows>) -> *mut T {
/// see [`ColRef::ptr_inbounds_at`]
	pub unsafe fn ptr_inbounds_at_mut(&self, row: Idx<Rows>) -> *mut T {
/// see [`ColRef::split_at_row`]
	pub fn split_at_row_mut(self, row: IdxInc<Rows>) -> (ColMut<'a, T, usize, RStride>, ColMut<'a, T, usize, RStride>) {
/// see [`ColRef::transpose`]
	pub fn transpose_mut(self) -> RowMut<'a, T, Rows, RStride> {
/// see [`ColRef::conjugate`]
	pub fn conjugate_mut(self) -> ColMut<'a, T::Conj, Rows, RStride>
	where
		T: Conjugate,
	{
/// see [`ColRef::canonical`]
	pub fn canonical_mut(self) -> ColMut<'a, T::Canonical, Rows, RStride>
	where
		T: Conjugate,
	{
/// see [`ColRef::adjoint`]
	pub fn adjoint_mut(self) -> RowMut<'a, T::Conj, Rows, RStride>
	where
		T: Conjugate,
	{
	pub(crate) fn at_mut(self, row: Idx<Rows>) -> &'a mut T {
	pub(crate) unsafe fn at_mut_unchecked(self, row: Idx<Rows>) -> &'a mut T {
/// see [`ColRef::get`]
	pub fn get_mut<RowRange>(self, row: RowRange) -> <ColMut<'a, T, Rows, RStride> as ColIndex<RowRange>>::Target
	where
		ColMut<'a, T, Rows, RStride>: ColIndex<RowRange>,
	{
/// see [`ColRef::get_unchecked`]
	pub unsafe fn get_mut_unchecked<RowRange>(self, row: RowRange) -> <ColMut<'a, T, Rows, RStride> as ColIndex<RowRange>>::Target
	where
		ColMut<'a, T, Rows, RStride>: ColIndex<RowRange>,
	{
/// see [`ColRef::reverse_rows`]
	pub fn reverse_rows_mut(self) -> ColMut<'a, T, Rows, RStride::Rev> {
/// see [`ColRef::subrows`]
	pub fn subrows_mut<V: Shape>(self, row_start: IdxInc<Rows>, nrows: V) -> ColMut<'a, T, V, RStride> {
/// see [`ColRef::as_row_shape`]
	pub fn as_row_shape_mut<V: Shape>(self, nrows: V) -> ColMut<'a, T, V, RStride> {
/// see [`ColRef::as_dyn_rows`]
	pub fn as_dyn_rows_mut(self) -> ColMut<'a, T, usize, RStride> {
/// see [`ColRef::as_dyn_stride`]
	pub fn as_dyn_stride_mut(self) -> ColMut<'a, T, Rows, isize> {
/// see [`ColRef::iter`]
	pub fn iter_mut(self) -> impl 'a + ExactSizeIterator + DoubleEndedIterator<Item = &'a mut T>
	where
		Rows: 'a,
	{
/// see [`ColRef::par_iter`]
	pub fn par_iter_mut(self) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = &'a mut T>
	where
		T: Send,
		Rows: 'a,
	{
/// see [`ColRef::par_partition`]
	pub fn par_partition_mut(self, count: usize) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = ColMut<'a, T, usize, RStride>>
	where
		T: Send,
		Rows: 'a,
	{
	pub(crate) unsafe fn as_type<U>(self) -> ColMut<'a, U, Rows, RStride> {
/// see [`ColRef::as_diagonal`]
	pub fn as_diagonal_mut(self) -> DiagMut<'a, T, Rows, RStride> {
	pub(crate) fn __at_mut(self, i: Idx<Rows>) -> &'a mut T {
/// returns a reference over the elements as a slice
	pub fn as_slice_mut(self) -> &'a mut [T] {
/// returns a reference over the elements as a lifetime-bound slice
	pub fn as_array_mut(self) -> &'a mut Array<'ROWS, T> {
	pub fn split_rows_with<'TOP, 'BOT>(
		self,
		row: Partition<'TOP, 'BOT, 'ROWS>,
	) -> (ColRef<'a, T, Dim<'TOP>, RStride>, ColRef<'a, T, Dim<'BOT>, RStride>) {
	pub fn split_rows_with_mut<'TOP, 'BOT>(
		self,
		row: Partition<'TOP, 'BOT, 'ROWS>,
	) -> (ColMut<'a, T, Dim<'TOP>, RStride>, ColMut<'a, T, Dim<'BOT>, RStride>) {
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
/// Returns the maximum element in the column, or `None` if the column is empty
	pub fn max(&self) -> Option<T> {
/// Returns the minimum element in the column, or `None` if the column is empty
	pub fn min(&self) -> Option<T> {
	fn test_col_min() {
	fn test_col_max() {
/// see [`super::Col`]
fn idx_to_pair<T, R>(f: impl FnMut(T) -> R) -> impl FnMut(T, usize) -> R {
/// returns a new column with dimension `nrows`, filled with the provided function
	pub fn from_fn(nrows: Rows, f: impl FnMut(Idx<Rows>) -> T) -> Self {
/// returns a new column with dimension `nrows`, filled with zeros
	pub fn zeros(nrows: Rows) -> Self
	where
		T: ComplexField,
	{
/// returns a new column with dimension `nrows`, filled with ones
	pub fn ones(nrows: Rows) -> Self
	where
		T: ComplexField,
	{
/// returns a new column with dimension `nrows`, filled with `value`
	pub fn full(nrows: Rows, value: T) -> Self
	where
		T: Clone,
	{
/// reserves the minimum capacity for `row_capacity` rows without reallocating, or returns an
/// error in case of failure. does nothing if the capacity is already sufficient
	pub fn try_reserve(&mut self, new_row_capacity: usize) -> Result<(), TryReserveError> {
/// reserves the minimum capacity for `row_capacity` rows without reallocating. does nothing if
/// the capacity is already sufficient
	pub fn reserve(&mut self, new_row_capacity: usize) {
/// resizes the column in-place so that the new dimension is `new_nrows`.
/// new elements are created with the given function `f`, so that elements at index `i`
/// are created by calling `f(i)`
	pub fn resize_with(&mut self, new_nrows: Rows, f: impl FnMut(Idx<Rows>) -> T) {
/// truncates the column so that its new dimensions are `new_nrows`.  
/// the new dimension must be smaller than or equal to the current dimension
///
/// # panics
/// the function panics if any of the following conditions are violated:
/// - `new_nrows > self.nrows()`
	pub fn truncate(&mut self, new_nrows: Rows) {
/// see [`ColRef::as_row_shape`]
	pub fn into_row_shape<V: Shape>(self, nrows: V) -> Col<T, V> {
/// see [`ColRef::as_diagonal`]
	pub fn into_diagonal(self) -> Diag<T, Rows> {
/// see [`ColRef::transpose`]
	pub fn into_transpose(self) -> Row<T, Rows> {
	pub(crate) fn from_iter_imp<I: Iterator<Item = T>>(iter: I) -> Self {
// optimization for exact len iterators
	fn from_iter<I>(iter: I) -> Self
	where
		I: IntoIterator<Item = T>,
	{
/// returns the number of rows of the column
	pub fn nrows(&self) -> Rows {
/// returns the number of columns of the column (always `1`)
	pub fn ncols(&self) -> usize {
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
/// see [`ColRef::as_ptr`]
	pub fn as_ptr(&self) -> *const T {
/// see [`ColRef::shape`]
	pub fn shape(&self) -> (Rows, usize) {
/// see [`ColRef::row_stride`]
	pub fn row_stride(&self) -> isize {
/// see [`ColRef::ptr_at`]
	pub fn ptr_at(&self, row: IdxInc<Rows>) -> *const T {
/// see [`ColRef::ptr_inbounds_at`]
	pub unsafe fn ptr_inbounds_at(&self, row: Idx<Rows>) -> *const T {
/// see [`ColRef::split_at_row`]
	pub fn split_at_row(&self, row: IdxInc<Rows>) -> (ColRef<'_, T, usize>, ColRef<'_, T, usize>) {
/// see [`ColRef::transpose`]
	pub fn transpose(&self) -> RowRef<'_, T, Rows> {
/// see [`ColRef::conjugate`]
	pub fn conjugate(&self) -> ColRef<'_, T::Conj, Rows>
	where
		T: Conjugate,
	{
/// see [`ColRef::canonical`]
	pub fn canonical(&self) -> ColRef<'_, T::Canonical, Rows>
	where
		T: Conjugate,
	{
/// see [`ColRef::adjoint`]
	pub fn adjoint(&self) -> RowRef<'_, T::Conj, Rows>
	where
		T: Conjugate,
	{
/// see [`ColRef::get`]
	pub fn get<RowRange>(&self, row: RowRange) -> <ColRef<'_, T, Rows> as ColIndex<RowRange>>::Target
	where
		for<'a> ColRef<'a, T, Rows>: ColIndex<RowRange>,
	{
/// see [`ColRef::get_unchecked`]
	pub unsafe fn get_unchecked<RowRange>(&self, row: RowRange) -> <ColRef<'_, T, Rows> as ColIndex<RowRange>>::Target
	where
		for<'a> ColRef<'a, T, Rows>: ColIndex<RowRange>,
	{
/// see [`ColRef::reverse_rows`]
	pub fn reverse_rows(&self) -> ColRef<'_, T, Rows> {
/// see [`ColRef::subrows`]
	pub fn subrows<V: Shape>(&self, row_start: IdxInc<Rows>, nrows: V) -> ColRef<'_, T, V> {
/// see [`ColRef::as_row_shape`]
	pub fn as_row_shape<V: Shape>(&self, nrows: V) -> ColRef<'_, T, V> {
/// see [`ColRef::as_dyn_rows`]
	pub fn as_dyn_rows(&self) -> ColRef<'_, T, usize> {
/// see [`ColRef::as_dyn_stride`]
	pub fn as_dyn_stride(&self) -> ColRef<'_, T, Rows, isize> {
/// see [`ColRef::iter`]
	pub fn iter(&self) -> impl '_ + ExactSizeIterator + DoubleEndedIterator<Item = &'_ T> {
/// see [`ColRef::par_iter`]
	pub fn par_iter(&self) -> impl '_ + rayon::iter::IndexedParallelIterator<Item = &'_ T>
	where
		T: Sync,
	{
/// see [`ColRef::par_partition`]
	pub fn par_partition(&self, count: usize) -> impl '_ + rayon::iter::IndexedParallelIterator<Item = ColRef<'_, T, usize>>
	where
		T: Sync,
	{
/// see [`ColRef::try_as_col_major`]
	pub fn try_as_col_major(&self) -> Option<ColRef<'_, T, Rows, ContiguousFwd>> {
/// see [`ColRef::try_as_col_major`]
	pub fn try_as_col_major_mut(&mut self) -> Option<ColMut<'_, T, Rows, ContiguousFwd>> {
/// see [`ColRef::as_mat`]
	pub fn as_mat(&self) -> MatRef<'_, T, Rows, usize, isize> {
/// see [`ColRef::as_mat`]
	pub fn as_mat_mut(&mut self) -> MatMut<'_, T, Rows, usize, isize> {
/// see [`ColRef::as_diagonal`]
	pub fn as_diagonal(&self) -> DiagRef<'_, T, Rows> {
/// see [`ColMut::as_ptr_mut`]
	pub fn as_ptr_mut(&mut self) -> *mut T {
/// see [`ColMut::ptr_at_mut`]
	pub fn ptr_at_mut(&mut self, row: IdxInc<Rows>) -> *mut T {
/// see [`ColMut::ptr_inbounds_at_mut`]
	pub unsafe fn ptr_inbounds_at_mut(&mut self, row: Idx<Rows>) -> *mut T {
/// see [`ColMut::split_at_row_mut`]
	pub fn split_at_row_mut(&mut self, row: IdxInc<Rows>) -> (ColMut<'_, T, usize>, ColMut<'_, T, usize>) {
/// see [`ColMut::transpose_mut`]
	pub fn transpose_mut(&mut self) -> RowMut<'_, T, Rows> {
/// see [`ColMut::conjugate_mut`]
	pub fn conjugate_mut(&mut self) -> ColMut<'_, T::Conj, Rows>
	where
		T: Conjugate,
	{
/// see [`ColMut::canonical_mut`]
	pub fn canonical_mut(&mut self) -> ColMut<'_, T::Canonical, Rows>
	where
		T: Conjugate,
	{
/// see [`ColMut::adjoint_mut`]
	pub fn adjoint_mut(&mut self) -> RowMut<'_, T::Conj, Rows>
	where
		T: Conjugate,
	{
/// see [`ColMut::get_mut`]
	pub fn get_mut<RowRange>(&mut self, row: RowRange) -> <ColMut<'_, T, Rows> as ColIndex<RowRange>>::Target
	where
		for<'a> ColMut<'a, T, Rows>: ColIndex<RowRange>,
	{
/// see [`ColMut::get_mut_unchecked`]
	pub unsafe fn get_mut_unchecked<RowRange>(&mut self, row: RowRange) -> <ColMut<'_, T, Rows> as ColIndex<RowRange>>::Target
	where
		for<'a> ColMut<'a, T, Rows>: ColIndex<RowRange>,
	{
/// see [`ColMut::reverse_rows_mut`]
	pub fn reverse_rows_mut(&mut self) -> ColMut<'_, T, Rows> {
/// see [`ColMut::subrows_mut`]
	pub fn subrows_mut<V: Shape>(&mut self, row_start: IdxInc<Rows>, nrows: V) -> ColMut<'_, T, V> {
/// see [`ColMut::as_row_shape_mut`]
	pub fn as_row_shape_mut<V: Shape>(&mut self, nrows: V) -> ColMut<'_, T, V> {
/// see [`ColMut::as_dyn_rows_mut`]
	pub fn as_dyn_rows_mut(&mut self) -> ColMut<'_, T, usize> {
/// see [`ColMut::as_dyn_stride_mut`]
	pub fn as_dyn_stride_mut(&mut self) -> ColMut<'_, T, Rows, isize> {
/// see [`ColMut::iter_mut`]
	pub fn iter_mut(&mut self) -> impl '_ + ExactSizeIterator + DoubleEndedIterator<Item = &'_ mut T> {
/// see [`ColMut::par_iter_mut`]
	pub fn par_iter_mut(&mut self) -> impl '_ + rayon::iter::IndexedParallelIterator<Item = &'_ mut T>
	where
		T: Send,
	{
/// see [`ColMut::par_partition_mut`]
	pub fn par_partition_mut(&mut self, count: usize) -> impl '_ + rayon::iter::IndexedParallelIterator<Item = ColMut<'_, T, usize>>
	where
		T: Send,
	{
/// see [`ColMut::as_diagonal_mut`]
	pub fn as_diagonal_mut(&mut self) -> DiagMut<'_, T, Rows> {
	fn rb(&'short self) -> Self::Target {
	fn rb_mut(&'short mut self) -> Self::Target {
/// Returns the maximum element in the column, or `None` if the column is empty
	pub fn max(&self) -> Option<T> {
/// Returns the minimum element in the column, or `None` if the column is empty
	pub fn min(&self) -> Option<T> {
	fn test_col_min() {
	fn test_col_max() {
	fn test_from_iter() {
/// see [`super::ColRef`]
	fn clone(&self) -> Self {
	fn rb(&'short self) -> Self::Target {
	fn rb_mut(&'short mut self) -> Self::Target {
	fn into_const(self) -> Self::Target {
/// creates a column view over the given element
	pub fn from_ref(value: &'a T) -> Self {
/// creates a `ColRef` from slice views over the column vector data, the result has the same
/// number of rows as the length of the input slice
	pub fn from_slice(slice: &'a [T]) -> Self {
/// creates a `ColRef` from pointers to the column vector data, number of rows, and row stride
///
/// # safety
/// this function has the same safety requirements as
/// [`MatRef::from_raw_parts(ptr, nrows, 1, row_stride, 0)`]
	pub const unsafe fn from_raw_parts(ptr: *const T, nrows: Rows, row_stride: RStride) -> Self {
/// returns a pointer to the column data
	pub fn as_ptr(&self) -> *const T {
/// returns the number of rows of the column
	pub fn nrows(&self) -> Rows {
/// returns the number of columns of the column (always `1`)
	pub fn ncols(&self) -> usize {
/// returns the number of rows and columns of the column
	pub fn shape(&self) -> (Rows, usize) {
/// returns the row stride of the column, specified in number of elements, not in bytes
	pub fn row_stride(&self) -> RStride {
/// returns a raw pointer to the element at the given index
	pub fn ptr_at(&self, row: IdxInc<Rows>) -> *const T {
/// returns a raw pointer to the element at the given index, assuming the provided index
/// is within the column bounds
///
/// # safety
/// the behavior is undefined if any of the following conditions are violated:
/// * `row < self.nrows()`
	pub unsafe fn ptr_inbounds_at(&self, row: Idx<Rows>) -> *const T {
/// splits the column horizontally at the given row into two parts and returns an array of
/// each submatrix, in the following order:
/// * top
/// * bottom
///
/// # panics
/// the function panics if the following condition is violated:
/// * `row <= self.nrows()`
	pub fn split_at_row(self, row: IdxInc<Rows>) -> (ColRef<'a, T, usize, RStride>, ColRef<'a, T, usize, RStride>) {
/// returns a view over the transpose of `self`
	pub fn transpose(self) -> RowRef<'a, T, Rows, RStride> {
/// returns a view over the conjugate of `self`
	pub fn conjugate(self) -> ColRef<'a, T::Conj, Rows, RStride>
	where
		T: Conjugate,
	{
/// returns an unconjugated view over `self`
	pub fn canonical(self) -> ColRef<'a, T::Canonical, Rows, RStride>
	where
		T: Conjugate,
	{
/// returns a view over the conjugate transpose of `self`
	pub fn adjoint(self) -> RowRef<'a, T::Conj, Rows, RStride>
	where
		T: Conjugate,
	{
	pub(crate) fn at(self, row: Idx<Rows>) -> &'a T {
	pub(crate) unsafe fn at_unchecked(self, row: Idx<Rows>) -> &'a T {
/// returns a reference to the element at the given index, or a subcolumn if `row` is a range
///
/// # panics
/// the function panics if any of the following conditions are violated:
/// * `row` must be contained in `[0, self.nrows())`
	pub fn get<RowRange>(self, row: RowRange) -> <ColRef<'a, T, Rows, RStride> as ColIndex<RowRange>>::Target
	where
		ColRef<'a, T, Rows, RStride>: ColIndex<RowRange>,
	{
/// returns a reference to the element at the given index, or a subcolumn if `row` is a range,
/// without bound checks
///
/// # safety
/// the behavior is undefined if any of the following conditions are violated:
/// * `row` must be contained in `[0, self.nrows())`
	pub unsafe fn get_unchecked<RowRange>(self, row: RowRange) -> <ColRef<'a, T, Rows, RStride> as ColIndex<RowRange>>::Target
	where
		ColRef<'a, T, Rows, RStride>: ColIndex<RowRange>,
	{
/// returns a view over the `self`, with the rows in reversed order
	pub fn reverse_rows(self) -> ColRef<'a, T, Rows, RStride::Rev> {
/// returns a view over the column starting at row `row_start`, and with number of rows
/// `nrows`
///
/// # panics
/// the function panics if any of the following conditions are violated:
/// * `row_start <= self.nrows()`
/// * `nrows <= self.nrows() - row_start`
	pub fn subrows<V: Shape>(self, row_start: IdxInc<Rows>, nrows: V) -> ColRef<'a, T, V, RStride> {
/// returns the input column with the given row shape after checking that it matches the
/// current row shape
	pub fn as_row_shape<V: Shape>(self, nrows: V) -> ColRef<'a, T, V, RStride> {
/// returns the input column with dynamic row shape
	pub fn as_dyn_rows(self) -> ColRef<'a, T, usize, RStride> {
/// returns the input column with dynamic stride
	pub fn as_dyn_stride(self) -> ColRef<'a, T, Rows, isize> {
/// returns an iterator over the elements of the column
	pub fn iter(self) -> impl 'a + ExactSizeIterator + DoubleEndedIterator<Item = &'a T>
	where
		Rows: 'a,
	{
/// returns a parallel iterator over the elements of the column
	pub fn par_iter(self) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = &'a T>
	where
		T: Sync,
		Rows: 'a,
	{
/// returns a parallel iterator that provides exactly `count` successive chunks of the elements
/// of this column
///
/// only available with the `rayon` feature
	pub fn par_partition(self, count: usize) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = ColRef<'a, T, usize, RStride>>
	where
		T: Sync,
		Rows: 'a,
	{
/// returns a view over the column with a static row stride equal to `+1`, or `None` otherwise
	pub fn try_as_col_major(self) -> Option<ColRef<'a, T, Rows, ContiguousFwd>> {
	pub unsafe fn const_cast(self) -> ColMut<'a, T, Rows, RStride> {
/// returns a matrix view over `self`
	pub fn as_mat(self) -> MatRef<'a, T, Rows, usize, RStride, isize> {
	pub fn bind_r<'N>(self, row: Guard<'N>) -> ColRef<'a, T, Dim<'N>, RStride> {
	pub(crate) fn read(&self, row: Idx<Rows>) -> T
	where
		T: Clone,
	{
	pub(crate) fn __at(self, i: Idx<Rows>) -> &'a T {
/// interprets the column as a diagonal matrix
	pub fn as_diagonal(self) -> DiagRef<'a, T, Rows, RStride> {
/// returns a newly allocated column holding the cloned values of `self`
	pub fn cloned(&self) -> Col<T, Rows>
	where
		T: Clone,
	{
		fn imp<'M, T: Clone, RStride: Stride>(this: ColRef<'_, T, Dim<'M>, RStride>) -> Col<T, Dim<'M>> {
/// returns a newly allocated column holding the (possibly conjugated) values of `self`
	pub fn to_owned(&self) -> Col<T::Canonical, Rows>
	where
		T: Conjugate,
	{
		fn imp<'M, T, RStride: Stride>(this: ColRef<'_, T, Dim<'M>, RStride>) -> Col<T::Canonical, Dim<'M>>
		where
			T: Conjugate,
		{
/// returns the maximum norm of `self`
	pub fn norm_max(&self) -> Real<T>
	where
		T: Conjugate,
	{
/// returns the l2 norm of `self`
	pub fn norm_l2(&self) -> Real<T>
	where
		T: Conjugate,
	{
/// returns the squared l2 norm of `self`
	pub fn squared_norm_l2(&self) -> Real<T>
	where
		T: Conjugate,
	{
/// returns the l1 norm of `self`
	pub fn norm_l1(&self) -> Real<T>
	where
		T: Conjugate,
	{
/// returns the sum of the elements of `self`
	pub fn sum(&self) -> T::Canonical
	where
		T: Conjugate,
	{
/// returns a view over `self`
	pub fn as_ref(&self) -> ColRef<'_, T, Rows, RStride> {
/// see [`Mat::kron`]
	pub fn kron(&self, rhs: impl AsMatRef<T: Conjugate<Canonical = T::Canonical>>) -> Mat<T::Canonical>
	where
		T: Conjugate,
	{
		fn imp<T: ComplexField>(lhs: MatRef<impl Conjugate<Canonical = T>>, rhs: MatRef<impl Conjugate<Canonical = T>>) -> Mat<T> {
/// returns `true` if all of the elements of `self` are finite.
/// otherwise returns `false`.
	pub fn is_all_finite(&self) -> bool
	where
		T: Conjugate,
	{
		fn imp<T: ComplexField>(A: ColRef<'_, T>) -> bool {
/// returns `true` if any of the elements of `self` is `NaN`.
/// otherwise returns `false`.
	pub fn has_nan(&self) -> bool
	where
		T: Conjugate,
	{
		fn imp<T: ComplexField>(A: ColRef<'_, T>) -> bool {
/// returns a reference over the elements as a slice
	pub fn as_slice(self) -> &'a [T] {
/// returns a reference over the elements as a lifetime-bound slice
	pub fn as_array(self) -> &'a Array<'ROWS, T> {
	pub fn split_rows_with<'TOP, 'BOT>(
		self,
		row: Partition<'TOP, 'BOT, 'ROWS>,
	) -> (ColRef<'a, T, Dim<'TOP>, RStride>, ColRef<'a, T, Dim<'BOT>, RStride>) {
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
	pub(crate) fn internal_max(self) -> Option<T> {
/// Returns the minimum element in the column, or `None` if the column is empty
	pub(crate) fn internal_min(self) -> Option<T> {
/// Returns the maximum element in the column, or `None` if the column is empty
	pub fn max(&self) -> Option<T> {
/// Returns the minimum element in the column, or `None` if the column is empty
	pub fn min(&self) -> Option<T> {
	fn test_col_min() {
	fn test_col_max() {
/// represents a type that can be used to slice a column, such as an index or a range of indices
/// sliced view type
/// slice `this` using `row`
	fn get(this: Self, row: RowRange) -> Self::Target;
/// slice `this` using `row`, without bound checks
	unsafe fn get_unchecked(this: Self, row: RowRange) -> Self::Target;
	fn clone(&self) -> Self {
/// immutable view over a column vector, similar to an immutable reference to a strided
/// [prim@slice]
///
/// # note
///
/// unlike a slice, the data pointed to by `ColRef<'_, T>` is allowed to be partially or fully
/// uninitialized under certain conditions. in this case, care must be taken to not perform any
/// operations that read the uninitialized values, or form references to them, either directly or
/// indirectly through any of the numerical library routines, unless it is explicitly permitted
/// mutable view over a column vector, similar to a mutable reference to a strided
/// [prim@slice]
///
/// # note
///
/// unlike a slice, the data pointed to by `ColMut<'_, T>` is allowed to be partially or fully
/// uninitialized under certain conditions. in this case, care must be taken to not perform any
/// operations that read the uninitialized values, or form references to them, either directly or
/// indirectly through any of the numerical library routines, unless it is explicitly permitted
/// heap allocated resizable column vector.
///
/// # note
///
/// the memory layout of `Col` is guaranteed to be column-major, meaning that it has a row stride
/// of `1`.
/// generic `Col` wrapper
/// generic `Col` wrapper
		fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
/// wrap by reference
		pub fn from_inner_ref(inner: &Inner) -> &Self {
/// wrap by mutable reference
		pub fn from_inner_mut(inner: &mut Inner) -> &mut Self {
		fn deref(&self) -> &Self::Target {
		fn deref_mut(&mut self) -> &mut Self::Target {
		fn rb(&'short self) -> Self::Target {
		fn rb_mut(&'short mut self) -> Self::Target {
		fn into_const(self) -> Self::Target {
		fn index(&self, row: Idx<Rows>) -> &Self::Output {
		fn index_mut(&mut self, row: Idx<Rows>) -> &mut Self::Output {
/// trait for types that can be converted to a column view
/// returns a view over `self`
	fn as_col_mut(&mut self) -> ColMut<'_, Self::T, Self::Rows>;
/// trait for types that can be converted to a column view
/// returns a view over `self`
	fn as_col_ref(&self) -> ColRef<'_, Self::T, Self::Rows>;
	fn as_col_ref(&self) -> ColRef<'_, Self::T, Self::Rows> {
	fn as_col_mut(&mut self) -> ColMut<'_, Self::T, Self::Rows> {
	fn as_mat_ref(&self) -> MatRef<'_, Self::T, Self::Rows, Self::Cols> {
	fn as_mat_ref(&self) -> MatRef<'_, Self::T, Self::Rows, Self::Cols> {
	fn as_mat_ref(&self) -> MatRef<'_, Self::T, Self::Rows, Self::Cols> {
	fn as_mat_mut(&mut self) -> MatMut<'_, Self::T, Self::Rows, Self::Cols> {
	fn as_mat_mut(&mut self) -> MatMut<'_, Self::T, Self::Rows, Self::Cols> {
	fn zeros(rows: Rows, _: One) -> Self
	where
		T: ComplexField,
	{
	fn truncate(&mut self, rows: Self::Rows, _: One) {
/// see [`super::DiagMut`]
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
/// creates a diagonal matrix view over the given element
	pub fn from_mut(value: &'a mut T) -> Self {
/// creates a `DiagMut` from slice views over the diagonal data, the result has the same
/// dimension as the length of the input slice
	pub fn from_slice_mut(slice: &'a mut [T]) -> Self {
/// creates a `DiagMut` from pointers to the diagonal data, dimension, and stride
///
/// # safety
/// this function has the same safety requirements as
/// [`MatMut::from_raw_parts_mut(ptr, dim, 1, stride, 0)`]
	pub const unsafe fn from_raw_parts_mut(ptr: *mut T, dim: Dim, stride: Stride) -> Self {
/// returns the stride of the diagonal, specified in number of elements, not in bytes
	pub fn stride(&self) -> Stride {
/// returns the diagonal as a column vector view
	pub fn column_vector(self) -> ColRef<'a, T, Dim, Stride> {
/// returns the diagonal as a mutable column vector view
	pub fn column_vector_mut(self) -> ColMut<'a, T, Dim, Stride> {
/// returns a view over `self`
	pub fn as_ref(&self) -> DiagRef<'_, T, Dim, Stride> {
/// returns a view over `self`
	pub fn as_mut(&mut self) -> DiagMut<'_, T, Dim, Stride> {
/// fills all the elements of `self` with `value`
	pub fn fill(&mut self, value: T)
	where
		T: Clone,
	{
/// see [`DiagRef::as_shape`]
	pub fn as_shape<D: Shape>(self, len: D) -> DiagRef<'a, T, D, Stride> {
/// see [`DiagRef::as_dyn`]
	pub fn as_dyn(self) -> DiagRef<'a, T, usize, Stride> {
/// see [`DiagRef::as_dyn_stride`]
	pub fn as_dyn_stride(self) -> DiagRef<'a, T, Dim> {
/// see [`DiagRef::conjugate`]
	pub fn conjugate(self) -> DiagRef<'a, T::Conj, Dim, Stride>
	where
		T: Conjugate,
	{
/// see [`DiagRef::canonical`]
	pub fn canonical(self) -> DiagRef<'a, T::Canonical, Dim, Stride>
	where
		T: Conjugate,
	{
/// see [`DiagRef::as_shape`]
	pub fn as_shape_mut<D: Shape>(self, len: D) -> DiagMut<'a, T, D, Stride> {
/// see [`DiagRef::as_dyn`]
	pub fn as_dyn_mut(self) -> DiagMut<'a, T, usize, Stride> {
/// see [`DiagRef::as_dyn_stride`]
	pub fn as_dyn_stride_mut(self) -> DiagMut<'a, T, Dim> {
/// see [`DiagRef::conjugate`]
	pub fn conjugate_mut(self) -> DiagMut<'a, T::Conj, Dim, Stride>
	where
		T: Conjugate,
	{
/// see [`DiagRef::canonical`]
	pub fn canonical_mut(self) -> DiagMut<'a, T::Canonical, Dim, Stride>
	where
		T: Conjugate,
	{
/// returns the dimension of `self`
	pub fn dim(&self) -> Dim {
/// copies `other` into `self`
	pub fn copy_from<RhsT: Conjugate<Canonical = T>>(&mut self, rhs: impl AsDiagRef<T = RhsT, Dim = Dim>)
	where
		T: ComplexField,
	{
	fn rb(&'short self) -> Self::Target {
	fn rb_mut(&'short mut self) -> Self::Target {
	fn into_const(self) -> Self::Target {
/// see [`super::Diag`]
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
/// returns the stride of the diagonal, specified in number of elements, not in bytes
	pub fn stride(&self) -> isize {
/// returns the diagonal as a column vector
	pub fn column_vector(&self) -> ColRef<'_, T, Dim> {
/// returns the diagonal as a column vector
	pub fn column_vector_mut(&mut self) -> ColMut<'_, T, Dim> {
/// returns the diagonal as a column vector
	pub fn into_column_vector(self) -> Col<T, Dim> {
/// returns a view over `self`
	pub fn as_ref(&self) -> DiagRef<'_, T, Dim> {
/// returns a view over `self`
	pub fn as_mut(&mut self) -> DiagMut<'_, T, Dim> {
/// see [`DiagRef::as_shape`]
	pub fn as_shape<D: Shape>(&self, len: D) -> DiagRef<'_, T, D> {
/// see [`DiagRef::as_dyn`]
	pub fn as_dyn(&self) -> DiagRef<'_, T> {
/// see [`DiagMut::as_dyn_mut`]
	pub fn as_dyn_mut(&mut self) -> DiagMut<'_, T> {
/// see [`DiagRef::conjugate`]
	pub fn conjugate(&self) -> DiagRef<'_, T::Conj, Dim>
	where
		T: Conjugate,
	{
/// see [`DiagRef::canonical`]
	pub fn canonical(&self) -> DiagRef<'_, T::Canonical, Dim>
	where
		T: Conjugate,
	{
/// see [`DiagMut::as_shape_mut`]
	pub fn as_shape_mut<D: Shape>(&mut self, len: D) -> DiagMut<'_, T, D> {
/// see [`DiagMut::conjugate_mut`]
	pub fn conjugate_mut(&mut self) -> DiagMut<'_, T::Conj, Dim>
	where
		T: Conjugate,
	{
/// see [`DiagMut::canonical_mut`]
	pub fn canonical_mut(&mut self) -> DiagMut<'_, T::Canonical, Dim>
	where
		T: Conjugate,
	{
/// returns the dimension of `self`
	pub fn dim(&self) -> Dim {
/// returns a new diagonal with dimension `dim`, filled with zeros
	pub fn zeros(dim: Dim) -> Self
	where
		T: ComplexField,
	{
/// returns a new diagonal with dimension `dim`, filled with ones
	pub fn ones(dim: Dim) -> Self
	where
		T: ComplexField,
	{
/// returns a new diagonal with dimension `dim`, filled with `value`
	pub fn full(dim: Dim, value: T) -> Self
	where
		T: Clone,
	{
/// copies `other` into `self`
	pub fn copy_from<RhsT: Conjugate<Canonical = T>>(&mut self, rhs: impl AsDiagRef<T = RhsT, Dim = Dim>)
	where
		T: ComplexField,
	{
	fn rb(&'short self) -> Self::Target {
	fn rb_mut(&'short mut self) -> Self::Target {
/// see [`super::DiagRef`]
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
	fn clone(&self) -> Self {
	fn rb(&'short self) -> Self::Target {
	fn rb_mut(&'short mut self) -> Self::Target {
	fn into_const(self) -> Self::Target {
/// creates a diagonal matrix view over the given element
	pub fn from_ref(value: &'a T) -> Self {
/// creates a `DiagRef` from slice views over the diagonal data, the result has the same
/// dimension as the length of the input slice
	pub fn from_slice(slice: &'a [T]) -> Self {
/// creates a `DiagRef` from pointers to the diagonal data, dimension, and stride
///
/// # safety
/// this function has the same safety requirements as
/// [`MatRef::from_raw_parts(ptr, dim, 1, stride, 0)`]
	pub const unsafe fn from_raw_parts(ptr: *const T, dim: Dim, stride: Stride) -> Self {
/// returns the stride of the diagonal, specified in number of elements, not in bytes
	pub fn stride(&self) -> Stride {
/// returns the diagonal as a column vector view.
	pub fn column_vector(self) -> ColRef<'a, T, Dim, Stride> {
/// returns a view over `self`
	pub fn as_ref(&self) -> DiagRef<'_, T, Dim, Stride> {
/// returns the input matrix with the given shape after checking that it matches the
/// current shape
	pub fn as_shape<D: Shape>(self, len: D) -> DiagRef<'a, T, D, Stride> {
/// returns the input matrix with dynamic shape
	pub fn as_dyn(self) -> DiagRef<'a, T, usize, Stride> {
/// returns the input matrix with dynamic stride
	pub fn as_dyn_stride(self) -> DiagRef<'a, T, Dim> {
/// returns a view over the conjugate of `self`
	pub fn conjugate(self) -> DiagRef<'a, T::Conj, Dim, Stride>
	where
		T: Conjugate,
	{
/// returns an unconjugated view over `self`
	pub fn canonical(self) -> DiagRef<'a, T::Canonical, Dim, Stride>
	where
		T: Conjugate,
	{
/// returns the dimension of `self`
	pub fn dim(&self) -> Dim {
/// returns `true` if all of the elements of `self` are finite.
/// otherwise returns `false`.
	pub fn is_all_finite(&self) -> bool
	where
		T: Conjugate,
	{
/// returns `true` if any of the elements of `self` is `NaN`.
/// otherwise returns `false`.
	pub fn has_nan(&self) -> bool
	where
		T: Conjugate,
	{
/// diagonal matrix view
/// diagonal mutable matrix view
/// diagonal matrix
/// generic `Diag` wrapper
/// generic `Diag` wrapper
		fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
/// wrap by reference
		pub fn from_inner_ref(inner: &Inner) -> &Self {
/// wrap by mutable reference
		pub fn from_inner_mut(inner: &mut Inner) -> &mut Self {
		fn deref(&self) -> &Self::Target {
		fn deref_mut(&mut self) -> &mut Self::Target {
		fn rb(&'short self) -> Self::Target {
		fn rb_mut(&'short mut self) -> Self::Target {
		fn into_const(self) -> Self::Target {
		fn index(&self, idx: Idx<Dim>) -> &Self::Output {
		fn index_mut(&mut self, idx: Idx<Dim>) -> &mut Self::Output {
/// trait for types that can be converted to a diagonal matrix view.
/// returns a view over `self`
	fn as_diag_mut(&mut self) -> DiagMut<'_, Self::T, Self::Dim>;
/// trait for types that can be converted to a diagonal matrix view.
/// scalar type
/// dimension type
/// returns a view over `self`
	fn as_diag_ref(&self) -> DiagRef<'_, Self::T, Self::Dim>;
	fn as_diag_ref(&self) -> DiagRef<'_, Self::T, Self::Dim> {
/// Obtain a TypeId for T without `T: 'static`
/// credit goes to: <https://github.com/thomcc>
pub fn nonstatic_typeid<T: ?Sized>() -> core::any::TypeId {
		fn type_id(&self) -> core::any::TypeId
		where
			Self: 'static;
		fn type_id(&self) -> core::any::TypeId
		where
			Self: 'static,
		{
// There is no excuse for the crimes we have done here, but what jury would convict us?
pub unsafe fn coerce<Src, Dst>(src: Src) -> Dst {
pub unsafe fn transmute<Src, Dst>(src: Src) -> Dst {
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
// don't pretty print
// don't pretty print
/// npy format conversions
/// memory view over a buffer in `npy` format
/// data type of an `npy` buffer
/// 32-bit floating point
/// 64-bit floating point
/// 32-bit complex floating point
/// 64-bit complex floating point
/// unknown type
/// trait implemented for native types that can be read from a `npy` buffer
/// data type of the buffer data
		fn parse_npyz(data: &[u8], npyz: npyz::NpyFile<&[u8]>) -> Result<(NpyDType, usize, usize, usize, bool), std::io::Error> {
/// parse a npy file from a memory buffer
		pub fn new(data: &'a [u8]) -> Result<Self, std::io::Error> {
/// returns the data type of the memory buffer
		pub fn dtype(&self) -> NpyDType {
/// checks if the memory buffer is aligned, in which case the data can be referenced
/// in-place
		pub fn is_aligned(&self) -> bool {
/// if the memory buffer is aligned, and the provided type matches the one stored in the
/// buffer, returns a matrix view over the data
		pub fn as_aligned_ref<T: FromNpy>(&self) -> MatRef<'_, T> {
/// if the provided type matches the one stored in the buffer, returns a matrix containing
/// the data
		pub fn to_mat<T: FromNpy>(&self) -> Mat<T> {
//! `faer` is a general-purpose linear algebra library for rust, with a focus on high performance
//! for algebraic operations on medium/large matrices, as well as matrix decompositions
//!
//! most of the high-level functionality in this library is provided through associated functions in
//! its vocabulary types: [`Mat`]/[`MatRef`]/[`MatMut`]
//!
//! `faer` is recommended for applications that handle medium to large dense matrices, and its
//! design is not well suited for applications that operate mostly on low dimensional vectors and
//! matrices such as computer graphics or game development. for such applications, `nalgebra` and
//! `cgmath` may be better suited
//!
//! # basic usage
//!
//! [`Mat`] is a resizable matrix type with dynamic capacity, which can be created using
//! [`Mat::new`] to produce an empty $0\times 0$ matrix, [`Mat::zeros`] to create a rectangular
//! matrix filled with zeros, [`Mat::identity`] to create an identity matrix, or [`Mat::from_fn`]
//! for the more general case
//!
//! Given a `&Mat<T>` (resp. `&mut Mat<T>`), a [`MatRef<'_, T>`](MatRef) (resp. [`MatMut<'_,
//! T>`](MatMut)) can be created by calling [`Mat::as_ref`] (resp. [`Mat::as_mut`]), which allow
//! for more flexibility than `Mat` in that they allow slicing ([`MatRef::get`]) and splitting
//! ([`MatRef::split_at`])
//!
//! `MatRef` and `MatMut` are lightweight view objects. the former can be copied freely while the
//! latter has move and reborrow semantics, as described in its documentation
//!
//! most of the matrix operations can be used through the corresponding math operators: `+` for
//! matrix addition, `-` for subtraction, `*` for either scalar or matrix multiplication depending
//! on the types of the operands.
//!
//! ## example
//! ```
//! use faer::{Mat, Scale, mat};
//!
//! let a = mat![
//! 	[1.0, 5.0, 9.0], //
//! 	[2.0, 6.0, 10.0],
//! 	[3.0, 7.0, 11.0],
//! 	[4.0, 8.0, 12.0f64],
//! ];
//!
//! let b = Mat::from_fn(4, 3, |i, j| (i + j) as f64);
//!
//! let add = &a + &b;
//! let sub = &a - &b;
//! let scale = Scale(3.0) * &a;
//! let mul = &a * b.transpose();
//!
//! let a00 = a[(0, 0)];
//! ```
//!
//! # matrix decompositions
//! `faer` provides a variety of matrix factorizations, each with its own advantages and drawbacks:
//!
//! ## $LL^\top$ decomposition
//! [`Mat::llt`] decomposes a self-adjoint positive definite matrix $A$ such that
//! $$A = LL^H,$$
//! where $L$ is a lower triangular matrix. this decomposition is highly efficient and has good
//! stability properties
//!
//! [an implementation for sparse matrices is also available](sparse::linalg::solvers::Llt)
//!
//! ## $LBL^\top$ decomposition
//! [`Mat::lblt`] decomposes a self-adjoint (possibly indefinite) matrix $A$ such that
//! $$P A P^\top = LBL^H,$$
//! where $P$ is a permutation matrix, $L$ is a lower triangular matrix, and $B$ is a block
//! diagonal matrix, with $1 \times 1$ or $2 \times 2$ diagonal blocks.
//! this decomposition is efficient and has good stability properties
//!
//! ## $LU$ decomposition with partial pivoting
//! [`Mat::partial_piv_lu`] decomposes a square invertible matrix $A$ into a lower triangular
//! matrix $L$, a unit upper triangular matrix $U$, and a permutation matrix $P$, such that
//! $$PA = LU$$
//! it is used by default for computing the determinant, and is generally the recommended method
//! for solving a square linear system or computing the inverse of a matrix (although we generally
//! recommend using a [`faer::linalg::solvers::Solve`](crate::linalg::solvers::Solve) instead of
//! computing the inverse explicitly)
//!
//! [an implementation for sparse matrices is also available](sparse::linalg::solvers::Lu)
//!
//! ## $LU$ decomposition with full pivoting
//! [`Mat::full_piv_lu`] decomposes a generic rectangular matrix $A$ into a lower triangular
//! matrix $L$, a unit upper triangular matrix $U$, and permutation matrices $P$ and $Q$, such that
//! $$PAQ^\top = LU$$
//! it can be more stable than the LU decomposition with partial pivoting, in exchange for being
//! more computationally expensive
//!
//! ## $QR$ decomposition
//! [`Mat::qr`] decomposes a matrix $A$ into the product $$A = QR,$$
//! where $Q$ is a unitary matrix, and $R$ is an upper trapezoidal matrix. it is often used for
//! solving least squares problems
//!
//! [an implementation for sparse matrices is also available](sparse::linalg::solvers::Qr)
//!
//! ## $QR$ decomposition with column pivoting
//! ([`Mat::col_piv_qr`]) decomposes a matrix $A$ into the product $$AP^\top = QR,$$
//! where $P$ is a permutation matrix, $Q$ is a unitary matrix, and $R$ is an upper trapezoidal
//! matrix
//!
//! it is slower than the version with no pivoting, in exchange for being more numerically stable
//! for rank-deficient matrices
//!
//! ## singular value decomposition
//! the SVD of a matrix $A$ of shape $(m, n)$ is a decomposition into three components $U$, $S$,
//! and $V$, such that:
//!
//! - $U$ has shape $(m, m)$ and is a unitary matrix,
//! - $V$ has shape $(n, n)$ and is a unitary matrix,
//! - $S$ has shape $(m, n)$ and is zero everywhere except the main diagonal, with nonnegative
//! diagonal values in nonincreasing order,
//! - and finally:
//!
//! $$A = U S V^H$$
//!
//! the SVD is provided in two forms: either the full matrices $U$ and $V$ are computed, using
//! [`Mat::svd`], or only their first $\min(m, n)$ columns are computed, using
//! [`Mat::thin_svd`]
//!
//! if only the singular values (elements of $S$) are desired, they can be obtained in
//! nonincreasing order using [`Mat::singular_values`]
//!
//! ## eigendecomposition
//! **note**: the order of the eigenvalues is currently unspecified and may be changed in a future
//! release
//!
//! the eigenvalue decomposition of a square matrix $A$ of shape $(n, n)$ is a decomposition into
//! two components $U$, $S$:
//!
//! - $U$ has shape $(n, n)$ and is invertible,
//! - $S$ has shape $(n, n)$ and is a diagonal matrix,
//! - and finally:
//!
//! $$A = U S U^{-1}$$
//!
//! if $A$ is self-adjoint, then $U$ can be made unitary ($U^{-1} = U^H$), and $S$ is real valued.
//! additionally, the eigenvalues are sorted in nondecreasing order
//!
//! Depending on the domain of the input matrix and whether it is self-adjoint, multiple methods
//! are provided to compute the eigendecomposition:
//! * [`Mat::self_adjoint_eigen`] can be used with either real or complex matrices,
//! producing an eigendecomposition of the same type,
//! * [`Mat::eigen`] can be used with real or complex matrices, but always produces complex values.
//!
//! if only the eigenvalues (elements of $S$) are desired, they can be obtained using
//! [`Mat::self_adjoint_eigenvalues`] (nondecreasing order), [`Mat::eigenvalues`]
//! with the same conditions described above.
//!
//! # crate features
//!
//! - `std`: enabled by default. links with the standard library to enable additional features such
//!   as cpu feature detection at runtime
//! - `rayon`: enabled by default. enables the `rayon` parallel backend and enables global
//!   parallelism by default
//! - `serde`: Enables serialization and deserialization of [`Mat`]
//! - `npy`: enables conversions to/from numpy's matrix file format
//! - `perf-warn`: produces performance warnings when matrix operations are called with suboptimal
//! data layout
//! - `nightly`: requires the nightly compiler. enables experimental simd features such as avx512
/// see: [`generativity::make_guard`]
/// shorthand for `<_ as Auto::<T>>::auto()`
/// zips together matrix of the same size, so that coefficient-wise operations can be performed on
/// their elements.
///
/// # note
/// the order in which the matrix elements are traversed is unspecified.
///
/// # example
/// ```
/// use faer::{Mat, mat, unzip, zip};
///
/// let nrows = 2;
/// let ncols = 3;
///
/// let a = mat![[1.0, 3.0, 5.0], [2.0, 4.0, 6.0]];
/// let b = mat![[7.0, 9.0, 11.0], [8.0, 10.0, 12.0]];
/// let mut sum = Mat::<f64>::zeros(nrows, ncols);
///
/// zip!(&mut sum, &a, &b).for_each(|unzip!(sum, a, b)| {
/// 	*sum = a + b;
/// });
///
/// for i in 0..nrows {
/// 	for j in 0..ncols {
/// 		assert_eq!(sum[(i, j)], a[(i, j)] + b[(i, j)]);
/// 	}
/// }
/// ```
/// expands to the type of zipped items.
///
/// # example
/// ```
/// use faer::{Mat, Zip, mat, unzip, zip};
///
/// let nrows = 2;
/// let ncols = 3;
///
/// let a = mat![[1.0, 3.0, 5.0], [2.0, 4.0, 6.0]];
/// let b = mat![[7.0, 9.0, 11.0], [8.0, 10.0, 12.0]];
/// let mut sum = Mat::<f64>::zeros(nrows, ncols);
///
/// zip!(&mut sum, &a, &b).for_each(|unzip!(sum, a, b): Zip!(&mut f64, &f64, &f64)| {
/// 	*sum = a + b;
/// });
///
/// for i in 0..nrows {
/// 	for j in 0..ncols {
/// 		assert_eq!(sum[(i, j)], a[(i, j)] + b[(i, j)]);
/// 	}
/// }
/// ```
/// used to undo the zipping by the [`zip!`] macro.
///
/// # example
/// ```
/// use faer::{Mat, mat, unzip, zip};
///
/// let nrows = 2;
/// let ncols = 3;
///
/// let a = mat![[1.0, 3.0, 5.0], [2.0, 4.0, 6.0]];
/// let b = mat![[7.0, 9.0, 11.0], [8.0, 10.0, 12.0]];
/// let mut sum = Mat::<f64>::zeros(nrows, ncols);
///
/// zip!(&mut sum, &a, &b).for_each(|unzip!(sum, a, b)| {
/// 	*sum = a + b;
/// });
///
/// for i in 0..nrows {
/// 	for j in 0..ncols {
/// 		assert_eq!(sum[(i, j)], a[(i, j)] + b[(i, j)]);
/// 	}
/// }
/// ```
/// creates a [`Mat`] containing the arguments.
///
/// ```
/// use faer::mat;
///
/// let matrix = mat![
/// 	[1.0, 5.0, 9.0], //
/// 	[2.0, 6.0, 10.0],
/// 	[3.0, 7.0, 11.0],
/// 	[4.0, 8.0, 12.0f64],
/// ];
///
/// assert_eq!(matrix[(0, 0)], 1.0);
/// assert_eq!(matrix[(1, 0)], 2.0);
/// assert_eq!(matrix[(2, 0)], 3.0);
/// assert_eq!(matrix[(3, 0)], 4.0);
///
/// assert_eq!(matrix[(0, 1)], 5.0);
/// assert_eq!(matrix[(1, 1)], 6.0);
/// assert_eq!(matrix[(2, 1)], 7.0);
/// assert_eq!(matrix[(3, 1)], 8.0);
///
/// assert_eq!(matrix[(0, 2)], 9.0);
/// assert_eq!(matrix[(1, 2)], 10.0);
/// assert_eq!(matrix[(2, 2)], 11.0);
/// assert_eq!(matrix[(3, 2)], 12.0);
/// ```
/// creates a [`col::Col`] containing the arguments
///
/// ```
/// use faer::col;
///
/// let col_vec = col![3.0, 5.0, 7.0, 9.0];
///
/// assert_eq!(col_vec[0], 3.0);
/// assert_eq!(col_vec[1], 5.0);
/// assert_eq!(col_vec[2], 7.0);
/// assert_eq!(col_vec[3], 9.0);
/// ```
/// creates a [`row::Row`] containing the arguments
///
/// ```
/// use faer::row;
///
/// let row_vec = row![3.0, 5.0, 7.0, 9.0];
///
/// assert_eq!(row_vec[0], 3.0);
/// assert_eq!(row_vec[1], 5.0);
/// assert_eq!(row_vec[2], 7.0);
/// assert_eq!(row_vec[3], 9.0);
/// ```
/// convenience function to concatenate a nested list of matrices into a single
/// big ['Mat']. concatonation pattern follows the numpy.block convention that
/// each sub-list must have an equal number of columns (net) but the boundaries
/// do not need to align. in other words, this sort of thing:
/// ```notcode
///   AAAbb
///   AAAbb
///   cDDDD
/// ```
/// is perfectly acceptable
pub fn concat_impl<T: ComplexField>(blocks: &[&[(mat::MatRef<'_, T>, Conj)]]) -> mat::Mat<T> {
	fn count_total_columns<T: ComplexField>(block_row: &[(mat::MatRef<'_, T>, Conj)]) -> usize {
	fn count_rows<T: ComplexField>(block_row: &[(mat::MatRef<'_, T>, Conj)]) -> usize {
// get size of result while doing checks
/// concatenates the matrices in each row horizontally,
/// then concatenates the results vertically
///
/// `concat![[a0, a1, a2], [b1, b2]]` results in the matrix
/// ```notcode
/// [a0 | a1 | a2][b0 | b1]
/// ```
/// helper utilities
/// diagonal matrix
/// rectangular matrix
/// permutation matrix
/// column vector
/// row vector
/// de-serialization from common matrix file formats
/// native unsigned integer type
/// sealed trait for types that can be created from "unbound" values, as long as their
/// struct preconditions are upheld
/// creates new value
/// # safety
/// safety invariants must be upheld
	unsafe fn new_unbound(idx: I) -> Self;
/// returns the unbound value, unconstrained by safety invariants
	fn unbound(self) -> I;
/// type that can be used to index into a range
/// type that can be used to partition a range
/// either an index or a negative value
/// base trait for [`Shape`]
/// type that can be used to index into a range
/// type that can be used to partition a range
/// either an index or a negative value
/// matrix dimension
/// whether the types involved have any safety invariants
/// bind the current value using a invariant lifetime guard
	fn bind<'n>(self, guard: generativity::Guard<'n>) -> utils::bound::Dim<'n> {
/// cast a slice of bound values to unbound values
	fn cast_idx_slice<I: Index>(slice: &[Idx<Self, I>]) -> &[I] {
/// cast a slice of bound values to unbound values
	fn cast_idx_inc_slice<I: Index>(slice: &[IdxInc<Self, I>]) -> &[I] {
/// returns the index `0`, which is always valid
	fn start() -> IdxInc<Self> {
/// returns the incremented value, as an inclusive index
	fn next(idx: Idx<Self>) -> IdxInc<Self> {
/// returns the last value, equal to the dimension
	fn end(self) -> IdxInc<Self> {
/// checks if the index is valid, returning `Some(_)` in that case
	fn idx(self, idx: usize) -> Option<Idx<Self>> {
/// checks if the index is valid, returning `Some(_)` in that case
	fn idx_inc(self, idx: usize) -> Option<IdxInc<Self>> {
/// checks if the index is valid, and panics otherwise
	fn checked_idx(self, idx: usize) -> Idx<Self> {
/// checks if the index is valid, and panics otherwise
	fn checked_idx_inc(self, idx: usize) -> IdxInc<Self> {
/// assumes the index is valid
/// # safety
/// the index must be valid
	unsafe fn unchecked_idx(self, idx: usize) -> Idx<Self> {
/// assumes the index is valid
/// # safety
/// the index must be valid
	unsafe fn unchecked_idx_inc(self, idx: usize) -> IdxInc<Self> {
/// returns an iterator over the indices between `from` and `to`
	fn indices(from: IdxInc<Self>, to: IdxInc<Self>) -> impl Clone + ExactSizeIterator + DoubleEndedIterator<Item = Idx<Self>> {
	unsafe fn new_unbound(idx: T) -> Self {
	fn unbound(self) -> T {
/// stride distance between two consecutive elements along a given dimension
/// the reversed stride type
/// returns the reversed stride
	fn rev(self) -> Self::Rev;
/// returns the stride in elements
	fn element_stride(self) -> isize;
	fn rev(self) -> Self::Rev {
	fn element_stride(self) -> isize {
/// contiguous stride equal to `+1`
/// contiguous stride equal to `-1`
	fn rev(self) -> Self::Rev {
	fn element_stride(self) -> isize {
	fn rev(self) -> Self::Rev {
	fn element_stride(self) -> isize {
/// memory allocation error
///rRequired allocation does not fit within `isize` bytes
/// allocator could not provide an allocation with the requested layout
/// requested layout
/// determines whether the input should be implicitly conjugated or not
/// no implicit conjugation
/// implicit conjugation
/// determines whether to replace or add to the result of a matmul operatio
/// overwrites the output buffer
/// adds the result to the output buffer
/// determines which side of a self-adjoint matrix should be accessed
/// lower triangular half
/// upper triangular half
/// returns `self == Conj::Yes`
	pub const fn is_conj(self) -> bool {
/// returns the composition of `self` and `other`
	pub const fn compose(self, other: Self) -> Self {
/// returns `Conj::No` if `T` is the canonical representation, otherwise `Conj::Yes`
	pub const fn get<T: Conjugate>() -> Self {
	pub(crate) fn apply<T: Conjugate>(value: &T) -> T::Canonical {
	pub(crate) fn apply_rt<T: ComplexField>(self, value: &T) -> T {
/// determines the parallelization configuration
/// sequential, non portable across different platforms
/// parallelized using the global rayon threadpool, non portable across different platforms
/// returns `Par::Rayon(nthreads)` if `nthreads` is non-zero, or
/// `Par::Rayon(rayon::current_num_threads())` otherwise
	pub fn rayon(nthreads: usize) -> Self {
/// the number of threads that should ideally execute an operation with the given parallelism
	pub fn degree(&self) -> usize {
/// `Complex<f32>`
/// `Complex<f64>`
/// `Complex<f64>`
/// `Complex<f64>`
		fn msrv_div_ceil(self, rhs: Self) -> Self;
		fn msrv_next_multiple_of(self, rhs: Self) -> Self;
		fn msrv_checked_next_multiple_of(self, rhs: Self) -> Option<Self>;
		fn msrv_div_ceil(self, rhs: Self) -> Self {
		fn msrv_next_multiple_of(self, rhs: Self) -> Self {
		fn msrv_checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
	pub fn simd_align(i: usize) -> usize {
/// useful imports for general usage of the library
/// see [`Default`]
	pub fn default<T: Default>() -> T {
/// scaling factor for multiplying matrices.
/// create a reference to a scaling factor from a reference to a value.
	pub fn from_ref(value: &T) -> &Self {
/// create a mutable reference to a scaling factor from a mutable reference to a value.
	pub fn from_mut(value: &mut T) -> &mut Self {
/// 0: disabled
/// 1: `Seq`
/// n >= 2: `Rayon(n - 2)`
///
/// default: `Rayon(0)`
/// causes functions that access global parallelism settings to panic.
pub fn disable_global_parallelism() {
/// sets the global parallelism settings.
pub fn set_global_parallelism(par: Par) {
/// gets the global parallelism settings.
///
/// # panics
/// panics if global parallelism is disabled.
pub fn get_global_parallelism() -> Par {
/// statistics and randomness functionality
/// like `Default`, but with an extra type parameter so that algorithm hyperparameters can be tuned
/// per scalar type.
/// returns the default value for the type `T`
	fn auto() -> Self;
/// implements [`Default`] based on `Config`'s [`Auto`] implementation for the type `T`.
/// wrapped config value
	fn deref(&self) -> &Self::Target {
	fn deref_mut(&mut self) -> &mut Self::Target {
	fn clone(&self) -> Self {
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
/// wraps the given config value
	pub fn new(config: Config) -> Self {
	fn from(config: Config) -> Self {
	fn default() -> Self {
		fn into_range(self, min: I, max: I) -> core::ops::Range<I>;
		fn into_range(self, _: I, _: I) -> core::ops::Range<I> {
		fn into_range(self, _: I, max: I) -> core::ops::Range<I> {
		fn into_range(self, min: I, _: I) -> core::ops::Range<I> {
		fn into_range(self, min: I, max: I) -> core::ops::Range<I> {
/// pivoting strategy for choosing the pivots
/// deprecated, corresponds to partial pivoting
/// searches for the k-th pivot in the k-th column
/// searches for the k-th pivot in the k-th column, as well as the tail of the diagonal of the
/// matrix
/// searches for pivots that are locally optimal
/// searches for pivots that are locally optimal, as well as the tail of the diagonal of the
/// matrix
/// searches for pivots that are globally optimal
/// tuning parameters for the decomposition
/// pivoting strategy
/// block size of the algorithm
/// threshold at which size parallelism should be disabled
fn swap_self_adjoint<T: ComplexField>(A: MatMut<'_, T>, i: usize, j: usize) {
fn rank_1_update_and_argmax_fallback<'M, 'N, T: ComplexField>(
	A: MatMut<'_, T, Dim<'N>, Dim<'N>>,
	L: ColRef<'_, T, Dim<'N>>,
	d: T::Real,
	start: IdxInc<'N>,
	end: IdxInc<'N>,
) -> (usize, usize, T::Real) {
fn rank_2_update_and_argmax_fallback<'N, T: ComplexField>(
	A: MatMut<'_, T, Dim<'N>, Dim<'N>>,
	L0: ColRef<'_, T, Dim<'N>>,
	L1: ColRef<'_, T, Dim<'N>>,
	d: T::Real,
	d00: T::Real,
	d11: T::Real,
	d10: T,
	start: IdxInc<'N>,
	end: IdxInc<'N>,
) -> (usize, usize, T::Real) {
fn rank_1_update_and_argmax_seq<'M, 'N, T: ComplexField>(
	A: MatMut<'_, T, Dim<'N>, Dim<'N>>,
	L: ColRef<'_, T, Dim<'N>>,
	d: T::Real,
	start: IdxInc<'N>,
	end: IdxInc<'N>,
) -> (usize, usize, T::Real) {
fn rank_2_update_and_argmax_seq<'N, T: ComplexField>(
	A: MatMut<'_, T, Dim<'N>, Dim<'N>>,
	L0: ColRef<'_, T, Dim<'N>>,
	L1: ColRef<'_, T, Dim<'N>>,
	d: T::Real,
	d00: T::Real,
	d11: T::Real,
	d10: T,
	start: IdxInc<'N>,
	end: IdxInc<'N>,
) -> (usize, usize, T::Real) {
fn rank_1_update_and_argmax<T: ComplexField>(A: MatMut<'_, T>, L: ColRef<'_, T>, d: T::Real, par: Par) -> (usize, usize, T::Real) {
// to check that integers can be represented exactly as floats
fn rank_2_update_and_argmax<'N, T: ComplexField>(
	A: MatMut<'_, T>,
	L0: ColRef<'_, T>,
	L1: ColRef<'_, T>,
	d: T::Real,
	d00: T::Real,
	d11: T::Real,
	d10: T,
	par: Par,
) -> (usize, usize, T::Real) {
// to check that integers can be represented exactly as floats
fn lblt_full_piv<T: ComplexField>(A: MatMut<'_, T>, subdiag: DiagMut<'_, T>, pivots: &mut [usize], par: Par, params: LbltParams) {
// swap pivots to first (and second) column
// t = (d00/|d10| * d11/|d10| - 1.0)
//         [ a00  a01 ]
// L_new * [ a10  a11 ] = L
fn l1_argmax<T: ComplexField>(col: ColRef<'_, T>) -> (Option<usize>, T::Real) {
fn offdiag_argmax<T: ComplexField>(A: MatRef<'_, T>, idx: usize) -> (Option<usize>, T::Real) {
fn update_and_offdiag_argmax<T: ComplexField>(
	mut dst: ColMut<'_, T>,
	Wl: MatRef<'_, T>,
	Al: MatRef<'_, T>,
	Ar: MatRef<'_, T>,
	i0: usize,
	par: Par,
) -> (Option<usize>, T::Real) {
fn lblt_blocked_step<T: ComplexField>(
	alpha: T::Real,
	W: MatMut<'_, T>,
	A_left: MatMut<'_, T>,
	A: MatMut<'_, T>,
	subdiag: DiagMut<'_, T>,
	pivots: &mut [usize],
	rook: bool,
	diagonal: bool,
	par: Par,
) -> usize {
// swap pivots to first (and second) column
// t = (d00/|d10| * d11/|d10| - 1.0)
//         [ a00  a01 ]
// L_new * [ a10  a11 ] = L
fn lblt_blocked<T: ComplexField>(
	A: MatMut<'_, T>,
	subdiag: DiagMut<'_, T>,
	pivots: &mut [usize],
	block_size: usize,
	rook: bool,
	diagonal: bool,
	par: Par,
	stack: &mut MemStack,
) {
fn lblt_unblocked<T: ComplexField>(
	alpha: T::Real,
	A_left: MatMut<'_, T>,
	A: MatMut<'_, T>,
	subdiag: DiagMut<'_, T>,
	pivots: &mut [usize],
	rook: bool,
	diagonal: bool,
	par: Par,
) {
// find the diagonal pivot candidate, if requested
// find the largest off-diagonal in the pivot's column
// pivot search
// swap pivots to first (and second) column
// rank downdate
// t = (d00/|d10| * d11/|d10| - 1.0)
//         [ a00  a01 ]
// L_new * [ a10  a11 ] = L
	fn auto() -> Self {
pub fn rank2_update<'a, T: ComplexField>(
	mut A: MatMut<'a, T>,
	mut L0: ColMut<'a, T>,
	mut L1: ColMut<'a, T>,
	d: T::Real,
	d00: T::Real,
	d10: T,
	d11: T::Real,
) {
pub fn rank2_update_simd<'a, T: ComplexField>(
	A: MatMut<'a, T, usize, usize, ContiguousFwd>,
	L0: ColMut<'a, T, usize, ContiguousFwd>,
	L1: ColMut<'a, T, usize, ContiguousFwd>,
	d: T::Real,
	d00: T::Real,
	d10: T,
	d11: T::Real,
) {
		fn with_simd<S: pulp::Simd>(self, simd: S) {
pub fn rank2_update_fallback<'a, T: ComplexField>(
	mut A: MatMut<'a, T>,
	mut L0: ColMut<'a, T>,
	mut L1: ColMut<'a, T>,
	d: T::Real,
	d00: T::Real,
	d10: T,
	d11: T::Real,
) {
pub fn rank1_update<'a, T: ComplexField>(mut A: MatMut<'a, T>, mut L0: ColMut<'a, T>, d: T::Real) {
pub fn rank1_update_simd<'a, T: ComplexField>(A: MatMut<'a, T, usize, usize, ContiguousFwd>, L0: ColMut<'a, T, usize, ContiguousFwd>, d: T::Real) {
		fn with_simd<S: pulp::Simd>(self, simd: S) {
pub fn rank1_update_fallback<'a, T: ComplexField>(mut A: MatMut<'a, T>, mut L0: ColMut<'a, T>, d: T::Real) {
/// computes the layout of required workspace for performing an $LBL^\top$
/// decomposition
pub fn cholesky_in_place_scratch<I: Index, T: ComplexField>(dim: usize, par: Par, params: Spec<LbltParams, T>) -> StackReq {
/// info about the result of the $LBL^\top$ factorization
/// number of pivoting transpositions
/// computes the $LBL^\top$ factorization of $A$ and stores the factorization in `matrix` and
/// `subdiag`
///
/// the diagonal of the block diagonal matrix is stored on the diagonal
/// of `matrix`, while the subdiagonal elements of the blocks are stored in `subdiag`
///
/// # panics
///
/// panics if the input matrix is not square
///
/// this can also panic if the provided memory in `stack` is insufficient (see
/// [`cholesky_in_place_scratch`]).
pub fn cholesky_in_place<'out, I: Index, T: ComplexField>(
	A: MatMut<'_, T>,
	subdiag: DiagMut<'_, T>,
	perm: &'out mut [I],
	perm_inv: &'out mut [I],
	par: Par,
	stack: &mut MemStack,
	params: Spec<LbltParams, T>,
) -> (LbltInfo, PermRef<'out, I>) {
pub fn inverse_scratch<I: Index, T: ComplexField>(dim: usize, par: Par) -> StackReq {
pub fn inverse<I: Index, T: ComplexField>(
	out: MatMut<'_, T>,
	L: MatRef<'_, T>,
	diagonal: DiagRef<'_, T>,
	subdiagonal: DiagRef<'_, T>,
	perm: PermRef<'_, I>,
	par: Par,
	stack: &mut MemStack,
) {
//! the $L B L^\top$ decomposition of a self-adjoint matrix $A$ is such that:
//! $$P A P^\top = LBL^H$$
//! where $P$ is a permutation matrix, $B$ is a block diagonal matrix, with $1\times 1$ or $2 \times
//! 2 $ diagonal blocks, and $L$ is a unit lower triangular matrix
	fn test_real() {
	fn test_cplx() {
pub fn reconstruct_scratch<I: Index, T: ComplexField>(dim: usize, par: Par) -> StackReq {
pub fn reconstruct<I: Index, T: ComplexField>(
	out: MatMut<'_, T>,
	L: MatRef<'_, T>,
	diagonal: DiagRef<'_, T>,
	subdiagonal: DiagRef<'_, T>,
	perm: PermRef<'_, I>,
	par: Par,
	stack: &mut MemStack,
) {
	fn test_reconstruct() {
/// computes the layout of required workspace for solving a linear system defined by
/// a matrix in place, given its bunch-kaufman decomposition
pub fn solve_in_place_scratch<I: Index, T: ComplexField>(dim: usize, rhs_ncols: usize, par: Par) -> StackReq {
/// given the bunch-kaufman factors of a matrix $a$ and a matrix $b$ stored in `rhs`, this
/// function computes the solution of the linear system $A x = b$, implicitly conjugating $A$ if
/// needed
///
/// the solution of the linear system is stored in `rhs`
///
/// # panics
///
/// - panics if `lb_factors` is not a square matrix
/// - panics if `subdiag` is not a column vector with the same number of rows as the dimension of
///   `lb_factors`
/// - panics if `rhs` doesn't have the same number of rows as the dimension of `lb_factors`
/// - panics if the provided memory in `stack` is insufficient (see [`solve_in_place_scratch`])
pub fn solve_in_place_with_conj<I: Index, T: ComplexField>(
	L: MatRef<'_, T>,
	diagonal: DiagRef<'_, T>,
	subdiagonal: DiagRef<'_, T>,
	conj_A: Conj,
	perm: PermRef<'_, I>,
	rhs: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
//
pub fn solve_in_place<I: Index, T: ComplexField, C: Conjugate<Canonical = T>>(
	L: MatRef<'_, C>,
	diagonal: DiagRef<'_, C>,
	subdiagonal: DiagRef<'_, C>,
	perm: PermRef<'_, I>,
	rhs: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
fn simd_cholesky_row_batch<'N, T: ComplexField, S: Simd>(
	simd: T::SimdCtx<S>,
	A: MatMut<'_, T, Dim<'N>, Dim<'N>, ContiguousFwd>,
	D: RowMut<'_, T, Dim<'N>>,

	start: IdxInc<'N>,

	is_llt: bool,
	regularize: bool,
	eps: T::Real,
	delta: T::Real,
	signs: Option<&Array<'N, i8>>,
) -> Result<usize, usize> {
fn simd_cholesky_matrix<T: ComplexField, S: Simd>(
	simd: T::SimdCtx<S>,
	A: MatMut<'_, T, usize, usize, ContiguousFwd>,
	D: RowMut<'_, T, usize>,

	is_llt: bool,
	regularize: bool,
	eps: T::Real,
	delta: T::Real,
	signs: Option<&[i8]>,
) -> Result<usize, usize> {
fn simd_cholesky<T: ComplexField>(
	A: MatMut<'_, T>,
	D: RowMut<'_, T>,
	is_llt: bool,
	regularize: bool,
	eps: T::Real,
	delta: T::Real,
	signs: Option<&[i8]>,
) -> Result<usize, usize> {
		fn with_simd<S: Simd>(self, simd: S) -> Self::Output {
fn cholesky_fallback<T: ComplexField>(
	A: MatMut<'_, T>,
	D: RowMut<'_, T>,
	is_llt: bool,
	regularize: bool,
	eps: T::Real,
	delta: T::Real,
	signs: Option<&[i8]>,
) -> Result<usize, usize> {
pub(crate) fn cholesky_recursion_right_looking<T: ComplexField>(
	A: MatMut<'_, T>,
	D: RowMut<'_, T>,

	recursion_threshold: usize,
	block_size: usize,
	is_llt: bool,
	regularize: bool,
	eps: &T::Real,
	delta: &T::Real,
	signs: Option<&[i8]>,
	par: Par,
) -> Result<usize, usize> {
pub(crate) fn cholesky_block_left_looking<T: ComplexField>(
	A: MatMut<'_, T>,
	D: RowMut<'_, T>,

	right_looking_threshold: usize,
	recursion_threshold: usize,
	block_size: usize,

	is_llt: bool,
	regularize: bool,
	eps: &T::Real,
	delta: &T::Real,
	signs: Option<&[i8]>,
	par: Par,
) -> Result<usize, usize> {
/// dynamic $LDL^\top$ regularization.
/// values below `epsilon` in absolute value, or with the wrong sign are set to `delta` with
/// their corrected sign.
/// expected signs for the diagonal at each step of the decomposition.
/// regularized value.
/// regularization threshold.
/// info about the result of the $LDL^\top$ factorization.
/// number of pivots whose value or sign had to be corrected.
/// error in the $LDL^\top$ factorization.
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
	fn default() -> Self {
	fn auto() -> Self {
pub fn cholesky_in_place_scratch<T: ComplexField>(dim: usize, par: Par, params: Spec<LdltParams, T>) -> StackReq {
pub fn cholesky_in_place<T: ComplexField>(
	A: MatMut<'_, T>,
	regularization: LdltRegularization<'_, T::Real>,
	par: Par,
	stack: &mut MemStack,
	params: Spec<LdltParams, T>,
) -> Result<LdltInfo, LdltError> {
	fn test_simd_cholesky() {
	fn test_cholesky() {
pub fn inverse_scratch<T: ComplexField>(dim: usize, par: Par) -> StackReq {
pub fn inverse<T: ComplexField>(out: MatMut<'_, T>, L: MatRef<'_, T>, D: DiagRef<'_, T>, par: Par, stack: &mut MemStack) {
// A = L D L.T
// A^-1 = L^-T D^-1 L^-1
	fn test_inverse() {
//! the $L D L^\top$ decomposition of a self-adjoint positive definite matrix $A$ is such that:
//! $$A = L D L^H$$
//! where $L$ is a unit lower triangular matrix, and $D$ is a diagonal matrix
pub fn reconstruct_scratch<T: ComplexField>(dim: usize, par: Par) -> StackReq {
pub fn reconstruct<T: ComplexField>(out: MatMut<'_, T>, L: MatRef<'_, T>, D: DiagRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn test_reconstruct() {
pub fn solve_in_place_scratch<T: ComplexField>(dim: usize, rhs_ncols: usize, par: Par) -> StackReq {
pub fn solve_in_place_with_conj<T: ComplexField>(
	L: MatRef<'_, T>,
	D: DiagRef<'_, T>,
	conj_lhs: Conj,
	rhs: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
pub fn solve_in_place<T: ComplexField, C: Conjugate<Canonical = T>>(
	L: MatRef<'_, C>,
	D: DiagRef<'_, C>,
	rhs: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
	fn test_solve() {
fn rank_update_step_simd<T: ComplexField>(
	L: ColMut<'_, T, usize, ContiguousFwd>,
	W: MatMut<'_, T, usize, usize, ContiguousFwd>,
	p: ColRef<'_, T>,
	beta: ColRef<'_, T>,
	align_offset: usize,
) {
		fn with_simd<S: Simd>(self, simd: S) {
fn rank_update_step_fallback<T: ComplexField>(L: ColMut<'_, T>, W: MatMut<'_, T>, p: ColRef<'_, T>, beta: ColRef<'_, T>) {
// On the Modification of LDLT Factorizations
// By R. Fletcher and M. J. D. Powell
// https://www.ams.org/journals/mcom/1974-28-128/S0025-5718-1974-0359297-1/S0025-5718-1974-0359297-1.pdf
	fn run(self) {
pub fn rank_r_update_clobber<T: ComplexField>(cholesky_factors: MatMut<'_, T>, w: MatMut<'_, T>, alpha: DiagMut<'_, T>) {
	fn test_rank_update() {
/// dynamic $LL^\top$ regularization.
///
/// values below `epsilon` in absolute value, or with the wrong sign are set to `delta` with
/// their corrected sign
/// regularized value
/// regularization threshold
/// info about the result of the $LL^\top$ factorization
/// number of pivots whose value or sign had to be corrected
/// error in the $LL^\top$ factorization
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
	fn default() -> Self {
	fn auto() -> Self {
pub fn cholesky_in_place_scratch<T: ComplexField>(dim: usize, par: Par, params: Spec<LltParams, T>) -> StackReq {
pub fn cholesky_in_place<T: ComplexField>(
	A: MatMut<'_, T>,
	regularization: LltRegularization<T::Real>,
	par: Par,
	stack: &mut MemStack,
	params: Spec<LltParams, T>,
) -> Result<LltInfo, LltError> {
pub fn inverse_scratch<T: ComplexField>(dim: usize, par: Par) -> StackReq {
pub fn inverse<T: ComplexField>(out: MatMut<'_, T>, L: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
// A = L L.T
// A^-1 = L^-T L^-1
	fn test_inverse() {
//! the $L L^\top$ decomposition of a self-adjoint positive definite matrix $A$ is such that:
//! $$A = L L^H$$
//! where $L$ is a lower triangular matrix
pub fn reconstruct_scratch<T: ComplexField>(dim: usize, par: Par) -> StackReq {
pub fn reconstruct<T: ComplexField>(out: MatMut<'_, T>, L: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn test_reconstruct() {
pub fn solve_in_place_scratch<T: ComplexField>(dim: usize, rhs_ncols: usize, par: Par) -> StackReq {
pub fn solve_in_place_with_conj<T: ComplexField>(L: MatRef<'_, T>, conj_lhs: Conj, rhs: MatMut<'_, T>, par: Par, stack: &mut MemStack) {
pub fn solve_in_place<T: ComplexField, C: Conjugate<Canonical = T>>(L: MatRef<'_, C>, rhs: MatMut<'_, T>, par: Par, stack: &mut MemStack) {
	fn test_solve() {
fn rank_update_step_simd<T: ComplexField>(
	L: ColMut<'_, T, usize, ContiguousFwd>,
	W: MatMut<'_, T, usize, usize, ContiguousFwd>,
	p: ColRef<'_, T>,
	beta: ColRef<'_, T>,
	gamma: ColRef<'_, T>,
	align_offset: usize,
) {
		fn with_simd<S: Simd>(self, simd: S) {
fn rank_update_step_fallback<T: ComplexField>(L: ColMut<'_, T>, W: MatMut<'_, T>, p: ColRef<'_, T>, beta: ColRef<'_, T>, gamma: ColRef<'_, T>) {
// On the Modification of LDLT Factorizations
// By R. Fletcher and M. J. D. Powell
// https://www.ams.org/journals/mcom/1974-28-128/S0025-5718-1974-0359297-1/S0025-5718-1974-0359297-1.pdf
	fn run(self) -> Result<(), LltError> {
pub fn rank_r_update_clobber<T: ComplexField>(cholesky_factors: MatMut<'_, T>, w: MatMut<'_, T>, alpha: DiagMut<'_, T>) -> Result<(), LltError> {
	fn test_rank_update() {
	fn default() -> Self {
/// numerical rank of the matrix
/// number of transpositions that make up the permutation
pub fn cholesky_in_place_scratch<I: Index, T: ComplexField>(dim: usize, par: Par, params: PivLltParams) -> StackReq {
pub fn cholesky_in_place<'out, I: Index, T: ComplexField>(
	a: MatMut<'_, T>,
	perm: &'out mut [I],
	perm_inv: &'out mut [I],
	par: Par,
	stack: &mut MemStack,
	params: PivLltParams,
) -> Result<(PivLltInfo, PermRef<'out, I>), LltError> {
pub fn inverse_scratch<I: Index, T: ComplexField>(dim: usize, par: Par) -> StackReq {
pub fn inverse<I: Index, T: ComplexField>(out: MatMut<'_, T>, L: MatRef<'_, T>, perm: PermRef<'_, I>, par: Par, stack: &mut MemStack) {
// A = L L.T
// A^-1 = L^-T L^-1
	fn test_inverse() {
//! the pivoted $L L^\top$ decomposition of a self-adjoint positive definite matrix $A$ is such
//! that: $$P A P^\top = L L^H$$
//! where $L$ is a unit lower triangular matrix and $P$ is a permutation matrix
pub fn reconstruct_scratch<I: Index, T: ComplexField>(dim: usize, par: Par) -> StackReq {
pub fn reconstruct<I: Index, T: ComplexField>(out: MatMut<'_, T>, L: MatRef<'_, T>, perm: PermRef<'_, I>, par: Par, stack: &mut MemStack) {
	fn test_reconstruct() {
pub fn solve_in_place_scratch<I: Index, T: ComplexField>(dim: usize, rhs_ncols: usize, par: Par) -> StackReq {
pub fn solve_in_place_with_conj<I: Index, T: ComplexField>(
	L: MatRef<'_, T>,
	perm: PermRef<'_, I>,
	conj_lhs: Conj,
	rhs: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
pub fn solve_in_place<I: Index, T: ComplexField, C: Conjugate<Canonical = T>>(
	L: MatRef<'_, C>,
	perm: PermRef<'_, I>,
	rhs: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
	fn test_solve() {
//! low level implementation of the various cholesky-like decompositions
/// hessenberg factorization tuning parameters
/// threshold at which parallelism should be disabled
/// threshold at which blocking should be disabled
	fn auto() -> Self {
/// computes the layout of the workspace required to compute a matrix's hessenberg
/// decomposition
pub fn hessenberg_in_place_scratch<T: ComplexField>(dim: usize, block_size: usize, par: Par, params: Spec<HessenbergParams, T>) -> StackReq {
fn hessenberg_fused_op_simd<T: ComplexField>(
	A: MatMut<'_, T, usize, usize, ContiguousFwd>,

	l_out: RowMut<'_, T, usize>,
	r_out: ColMut<'_, T, usize, ContiguousFwd>,
	l_in: RowRef<'_, T, usize, ContiguousFwd>,
	r_in: ColRef<'_, T, usize>,

	l0: ColRef<'_, T, usize, ContiguousFwd>,
	l1: ColRef<'_, T, usize, ContiguousFwd>,
	r0: RowRef<'_, T, usize>,
	r1: RowRef<'_, T, usize>,
	align: usize,
) {
		fn with_simd<S: pulp::Simd>(self, simd: S) -> Self::Output {
fn hessenberg_fused_op_fallback<T: ComplexField>(
	A: MatMut<'_, T>,

	l_out: RowMut<'_, T>,
	r_out: ColMut<'_, T>,
	l_in: RowRef<'_, T>,
	r_in: ColRef<'_, T>,

	l0: ColRef<'_, T>,
	l1: ColRef<'_, T>,
	r0: RowRef<'_, T>,
	r1: RowRef<'_, T>,
) {
fn hessenberg_fused_op<T: ComplexField>(
	A: MatMut<'_, T>,

	l_out: RowMut<'_, T>,
	r_out: ColMut<'_, T>,
	l_in: RowRef<'_, T>,
	r_in: ColRef<'_, T>,

	l0: ColRef<'_, T>,
	l1: ColRef<'_, T>,
	r0: RowRef<'_, T>,
	r1: RowRef<'_, T>,
	align: usize,
) {
fn hessenberg_rearranged_unblocked<T: ComplexField>(A: MatMut<'_, T>, H: MatMut<'_, T>, par: Par, stack: &mut MemStack, params: HessenbergParams) {
fn hessenberg_gqvdg_unblocked<T: ComplexField>(
	A: MatMut<'_, T>,
	Z: MatMut<'_, T>,
	H: MatMut<'_, T>,
	beta: ColMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
	params: HessenbergParams,
) {
/// computes a matrix $A$'s hessenberg decomposition such that $A = Q H Q^H$
///
/// $H$ is a hessenberg matrix stored in the upper triangular half of $A$ (plus the subdiagonal)
///
/// $Q$ is a sequence of householder reflections stored in the unit lower triangular half of $A$
/// (excluding the diagonal), with the householder coefficients being stored in `householder`
pub fn hessenberg_in_place<T: ComplexField>(
	A: MatMut<'_, T>,
	householder: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
	params: Spec<HessenbergParams, T>,
) {
fn hessenberg_gqvdg_blocked<T: ComplexField>(A: MatMut<'_, T>, H: MatMut<'_, T>, par: Par, stack: &mut MemStack, params: HessenbergParams) {
	fn test_hessenberg_real() {
	fn test_hessenberg_cplx() {
	fn test_hessenberg_cplx_gqvdg() {
//! low level implementation of the eigenvalue decomposition of a square diagonalizable matrix.
//!
//! the eigenvalue decomposition of a square matrix $A$ of shape $(n, n)$ is a decomposition into
//! two components $U$, $S$:
//!
//! - $U$ has shape $(n, n)$ and is invertible
//! - $S$ has shape $(n, n)$ and is a diagonal matrix
//! - and finally:
//!
//! $$A = U S U^{-1}$$
//!
//! if $A$ is self-adjoint, then $U$ can be made unitary ($U^{-1} = U^H$), and $S$ is real valued
/// hessenberg decomposition
/// self-adjoint tridiagonalization
/// eigendecomposition error
/// reached max iterations
/// schur to eigendecomposition conversion parameters
/// threshold at which the implementation should stop recursing
/// eigendecomposition tuning parameters
/// hessenberg parameters
/// schur from hessenberg conversion parameters
/// eigendecomposition from schur conversion parameters
/// self-adjoint eigendecomposition tuning parameters
/// tridiagonalization parameters
/// threshold at which the implementation should stop recursing
	fn auto() -> Self {
	fn auto() -> Self {
	fn auto() -> Self {
/// whether the eigenvectors should be computed
/// do not compute eigenvectors
/// compute eigenvectors
/// computes the layout of the workspace required to compute a self-adjoint matrix's
/// eigendecomposition
pub fn self_adjoint_evd_scratch<T: ComplexField>(
	dim: usize,
	compute_u: ComputeEigenvectors,
	par: Par,
	params: Spec<SelfAdjointEvdParams, T>,
) -> StackReq {
/// computes the matrix $A$'s eigendecomposition, assuming it is tridiagonal and self-adjoint
///
/// the eigenvalues are stored in $S$, and the eigenvectors in $U$ such that the eigenvalues are
/// sorted in nondecreasing order
pub fn tridiagonal_self_adjoint_evd<T: ComplexField>(
	diag: DiagRef<'_, T>,
	subdiag: DiagRef<'_, T>,
	s: DiagMut<'_, T>,
	u: Option<MatMut<'_, T>>,
	par: Par,
	stack: &mut MemStack,
	params: Spec<SelfAdjointEvdParams, T>,
) -> Result<(), EvdError> {
/// computes the matrix $A$'s eigendecomposition, assuming it is self-adjoint
///
/// the eigenvalues are stored in $S$, and the eigenvectors in $U$ such that the eigenvalues are
/// sorted in nondecreasing order
///
/// only the lower triangular half of $A$ is accessed
pub fn self_adjoint_evd<T: ComplexField>(
	A: MatRef<'_, T>,
	s: DiagMut<'_, T>,
	u: Option<MatMut<'_, T>>,
	par: Par,
	stack: &mut MemStack,
	params: Spec<SelfAdjointEvdParams, T>,
) -> Result<(), EvdError> {
/// computes the layout of the workspace required to compute a self-adjoint matrix's
/// pseudoinverse, given the eigendecomposition
pub fn pseudoinverse_from_self_adjoint_evd_scratch<T: ComplexField>(dim: usize, par: Par) -> StackReq {
/// computes a self-adjoint matrix's pseudoinverse, given the eigendecomposition factors $S$ and $U$
pub fn pseudoinverse_from_self_adjoint_evd<T: ComplexField>(
	pinv: MatMut<'_, T>,
	s: DiagRef<'_, T>,
	u: MatRef<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
/// computes a self-adjoint matrix's pseudoinverse, given the eigendecomposition factors $S$ and
/// $U$, and tolerance parameters for determining zero eigenvalues
pub fn pseudoinverse_from_self_adjoint_evd_with_tolerance<T: ComplexField>(
	pinv: MatMut<'_, T>,
	s: DiagRef<'_, T>,
	u: MatRef<'_, T>,
	abs_tol: T::Real,
	rel_tol: T::Real,
	par: Par,
	stack: &mut MemStack,
) {
fn dot2x1<T: RealField>(lhs0: RowRef<'_, T>, lhs1: RowRef<'_, T>, rhs: ColRef<'_, T>) -> (T, T) {
fn dot2x2<T: RealField>(lhs0: RowRef<'_, T>, lhs1: RowRef<'_, T>, rhs0: ColRef<'_, T>, rhs1: ColRef<'_, T>) -> (T, T, T, T) {
pub(crate) fn evd_from_real_schur_imp<T: RealField>(A: MatRef<'_, T>, V: MatMut<'_, T>, par: Par, params: EvdFromSchurParams) {
// real eigenvalue
// solve (A[:k, :k] - p I) X = -A[:k, k]
// form rhs
// complex eigenvalue pair
// solve (A[:k, :k] - (p + iq) I) X = rhs
// form rhs
pub(crate) fn evd_from_cplx_schur_imp<T: ComplexField>(A: MatRef<'_, T>, conj_A: Conj, V: MatMut<'_, T>, par: Par, params: EvdFromSchurParams) {
// solve (A[:k, :k] - p I) X = -A[:k, k]
// form rhs
fn solve_real_shifted_upper_quasi_triangular_system<T: RealField>(
	A: MatRef<'_, T>,
	p: T,
	x: ColMut<'_, T>,
	norm: T,
	par: Par,
	params: EvdFromSchurParams,
) {
// 1x1 block
// solve
// [a b] [x0]   [r0]
// [c a]×[x1] = [r1]
//
//  [x0]   [a  -b] [r0]
//  [x1] = [-c  a]×[r1] / det
fn solve_cplx_shifted_upper_quasi_triangular_system<T: RealField>(
	A: MatRef<'_, T>,
	p: T,
	q: T,
	x: MatMut<'_, T>,
	norm: T,
	par: Par,
	params: EvdFromSchurParams,
) {
// 1x1 block
fn solve_shifted_upper_triangular_system<T: ComplexField>(
	A: MatRef<'_, T>,
	conj_A: Conj,
	p: T,
	x: ColMut<'_, T>,
	norm: T::Real,
	par: Par,
	params: EvdFromSchurParams,
) {
// 1x1 block
/// computes the layout of the workspace required to compute a matrix's
/// eigendecomposition
pub fn evd_scratch<T: ComplexField>(
	dim: usize,
	eigen_left: ComputeEigenvectors,
	eigen_right: ComputeEigenvectors,
	par: Par,
	params: Spec<EvdParams, T>,
) -> StackReq {
fn evd_imp<T: ComplexField>(
	A: MatRef<'_, T>,
	s: ColMut<'_, T>,
	s_im: Option<ColMut<'_, T>>,
	u_left: Option<MatMut<'_, T>>,
	u_right: Option<MatMut<'_, T>>,
	par: Par,
	stack: &mut MemStack,
	params: EvdParams,
) -> Result<(), EvdError> {
/// computes the matrix $A$'s eigendecomposition
///
/// the eigenvalues are stored in $S$, the left eigenvectors in $U_L$, and the right eigenvectors in
/// $U_R$
pub fn evd_cplx<T: RealField>(
	A: MatRef<'_, Complex<T>>,
	s: DiagMut<'_, Complex<T>>,
	u_left: Option<MatMut<'_, Complex<T>>>,
	u_right: Option<MatMut<'_, Complex<T>>>,
	par: Par,
	stack: &mut MemStack,
	params: Spec<EvdParams, Complex<T>>,
) -> Result<(), EvdError> {
/// computes the matrix $A$'s eigendecomposition
///
/// the eigenvalues are stored in $S$, the left eigenvectors in $U_L$, and the right eigenvectors in
/// $U_R$
pub fn evd_real<T: RealField>(
	A: MatRef<'_, T>,
	s_re: DiagMut<'_, T>,
	s_im: DiagMut<'_, T>,
	u_left: Option<MatMut<'_, T>>,
	u_right: Option<MatMut<'_, T>>,
	par: Par,
	stack: &mut MemStack,
	params: Spec<EvdParams, T>,
) -> Result<(), EvdError> {
	fn test_cplx_evd(mat: MatRef<'_, c64>) {
	fn test_real_evd(mat: MatRef<'_, f64>) {
	fn test_cplx() {
	fn test_real() {
	fn test_self_adjoint_evd<T: ComplexField>(mat: MatRef<'_, T>) {
	fn test_real() {
	fn test_cplx() {
	fn test_special() {
	fn test_pinv() {
// adapted from <T>LAPACK implementation
//
// https://github.com/tlapack/tlapack
// https://github.com/tlapack/tlapack/blob/master/include/tlapack/lapack/lahqr.hpp
fn lahqr_eig22<T: ComplexField>(a00: T, a01: T, a10: T, a11: T) -> (T, T) {
fn lahqr<T: ComplexField>(want_t: bool, A: MatMut<'_, T>, Z: Option<MatMut<'_, T>>, w: ColMut<'_, T>, ilo: usize, ihi: usize) -> isize {
// k_defl counts the number of iterations since a deflation
// istop is the end of the active subblock.
// As more and more eigenvalues converge, it eventually
// becomes ilo+1 and the loop ends.
// istart is the start of the active subblock. Either
// istart = ilo, or H(istart, istart-1) = 0. This means
// that we can treat this subblock separately.
// The elementwise deflation test has passed
// The following performs second deflation test due
// to Ahues & Tisseur (LAWN 122, 1997). It has better
// mathematical foundation and improves accuracy in some
// examples.
//
// The test is |A(i,i-1)|*|A(i-1,i)| <=
// eps*|A(i,i)|*|A(i-1,i-1)| The multiplications might overflow
// so we do some scaling first.
// determine shift
// exceptional shift
// wilkinson shift
// We have already checked whether the subblock has split.
// If it has split, we can introduce any shift at the top of the new
// subblock. Now that we know the specific shift, we can also check
// whether we can introduce that shift somewhere else in the subblock.
//
fn lahqr_shiftcolumn<T: ComplexField>(h: MatRef<'_, T>, v: ColMut<'_, T>, s1: T, s2: T) {
fn aggressive_early_deflation<T: ComplexField>(
	want_t: bool,
	mut a: MatMut<'_, T>,
	mut z: Option<MatMut<'_, T>>,
	mut s: ColMut<'_, T>,
	ilo: usize,
	ihi: usize,
	nw: usize,
	par: Par,
	stack: &mut MemStack,
	params: SchurParams,
) -> (usize, usize) {
fn schur_move<T: ComplexField>(mut a: MatMut<'_, T>, mut q: Option<MatMut<'_, T>>, ifst: usize, ilst: &mut usize) -> isize {
// Quick return
// Size of the next eigenvalue block
// The swap failed, return with error
// Size of the next eigenvalue block
// The swap failed, return with error
pub(crate) fn schur_swap<T: ComplexField>(mut a: MatMut<'_, T>, q: Option<MatMut<'_, T>>, j0: usize) -> isize {
/// returns err code, number of aggressive early deflations, number of qr sweeps
pub fn multishift_qr<T: ComplexField>(
	want_t: bool,
	a: MatMut<'_, T>,
	z: Option<MatMut<'_, T>>,
	w: ColMut<'_, T>,
	ilo: usize,
	ihi: usize,
	par: Par,
	stack: &mut MemStack,
	params: SchurParams,
) -> (isize, usize, usize) {
fn move_bulge<T: ComplexField>(mut h: MatMut<'_, T>, mut v: ColMut<'_, T>, s1: T, s2: T) {
fn multishift_qr_sweep<T: ComplexField>(
	want_t: bool,
	a: MatMut<'_, T>,
	mut z: Option<MatMut<'_, T>>,
	s: ColMut<'_, T>,
	ilo: usize,
	ihi: usize,
	par: Par,
	stack: &mut MemStack,
) {
fn introduce_bulges<T: ComplexField>(
	ilo: usize,
	ihi: usize,
	n_block_desired: usize,
	n_bulges: usize,
	n_shifts: usize,
	want_t: bool,
	mut a: MatMut<'_, T>,
	mut z: Option<MatMut<'_, T>>,
	mut u: MatMut<'_, T>,
	mut v: MatMut<'_, T>,
	mut wh: MatMut<'_, T>,
	mut wv: MatMut<'_, T>,
	s: ColRef<'_, T>,
	i_pos_block: &mut usize,
	par: Par,
) {
fn move_bulges_down<T: ComplexField>(
	ilo: usize,
	ihi: usize,
	n_block_desired: usize,
	n_bulges: usize,
	n_shifts: usize,
	want_t: bool,
	mut a: MatMut<'_, T>,
	mut z: Option<MatMut<'_, T>>,
	mut u: MatMut<'_, T>,
	mut v: MatMut<'_, T>,
	mut wh: MatMut<'_, T>,
	mut wv: MatMut<'_, T>,
	s: ColRef<'_, T>,
	i_pos_block: &mut usize,
	par: Par,
) {
fn remove_bulges<T: ComplexField>(
	ilo: usize,
	ihi: usize,
	n_bulges: usize,
	n_shifts: usize,
	want_t: bool,
	mut a: MatMut<'_, T>,
	mut z: Option<MatMut<'_, T>>,
	mut u: MatMut<'_, T>,
	mut v: MatMut<'_, T>,
	mut wh: MatMut<'_, T>,
	mut wv: MatMut<'_, T>,
	s: ColRef<'_, T>,
	i_pos_block: &mut usize,
	par: Par,
) {
	fn test_3() {
	fn test_n() {
/// function that returns the number of shifts to use for a given matrix size
/// function that returns the deflation window to use for a given matrix size
/// threshold to switch between blocked and unblocked code
/// threshold of percent of aggressive-early-deflation window that must converge to skip a
/// sweep
	fn auto() -> Self {
pub fn multishift_qr_scratch<T: ComplexField>(n: usize, nh: usize, want_t: bool, want_z: bool, parallelism: Par, params: SchurParams) -> StackReq {
fn default_recommended_shift_count(dim: usize, _active_block_dim: usize) -> usize {
fn default_recommended_deflation_window(dim: usize, _active_block_dim: usize) -> usize {
// ret: (a b c d) (eig1_re eig1_im) (eig2_re eig2_im) (cs sn)
fn lahqr_eig22<T: RealField>(mut a00: T, mut a01: T, mut a10: T, mut a11: T) -> ((T, T), (T, T)) {
fn lasy2<T: RealField>(tl: MatRef<'_, T>, tr: MatRef<'_, T>, b: MatRef<'_, T>, x: MatMut<'_, T>) -> T {
// Do pivoting to get largest pivot element
fn lahqr_schur22<T: RealField>(mut a: T, mut b: T, mut c: T, mut d: T) -> ((T, T, T, T), (T, T), (T, T), (T, T)) {
fn lahqr_shiftcolumn<T: RealField>(h: MatRef<'_, T>, mut v: ColMut<'_, T>, s1: (T, T), s2: (T, T)) {
fn schur_move<T: RealField>(mut a: MatMut<T>, mut q: Option<MatMut<T>>, mut ifst: usize, ilst: &mut usize) -> isize {
pub(crate) fn schur_swap<T: RealField>(mut a: MatMut<T>, mut q: Option<MatMut<T>>, j0: usize, n1: usize, n2: usize) -> isize {
fn aggressive_early_deflation<T: RealField>(
	want_t: bool,
	mut a: MatMut<'_, T>,
	mut z: Option<MatMut<'_, T>>,
	mut s_re: ColMut<'_, T>,
	mut s_im: ColMut<'_, T>,
	ilo: usize,
	ihi: usize,
	nw: usize,
	par: Par,
	mut stack: &mut MemStack,
	params: SchurParams,
) -> (usize, usize) {
fn move_bulge<T: RealField>(mut h: MatMut<'_, T>, mut v: ColMut<'_, T>, s1: (T, T), s2: (T, T)) {
fn multishift_qr_sweep<T: RealField>(
	want_t: bool,
	a: MatMut<T>,
	mut z: Option<MatMut<T>>,
	s_re: ColMut<T>,
	s_im: ColMut<T>,
	ilo: usize,
	ihi: usize,
	par: Par,
	stack: &mut MemStack,
) {
fn introduce_bulges<T: RealField>(
	ilo: usize,
	ihi: usize,
	n_block_desired: usize,
	n_bulges: usize,
	n_shifts: usize,
	want_t: bool,
	mut a: MatMut<'_, T>,
	mut z: Option<MatMut<'_, T>>,
	mut u: MatMut<'_, T>,
	mut v: MatMut<'_, T>,
	mut wh: MatMut<'_, T>,
	mut wv: MatMut<'_, T>,
	s_re: ColRef<'_, T>,
	s_im: ColRef<'_, T>,
	i_pos_block: &mut usize,
	parallelism: Par,
) {
fn move_bulges_down<T: RealField>(
	ilo: usize,
	ihi: usize,
	n_block_desired: usize,
	n_bulges: usize,
	n_shifts: usize,
	want_t: bool,
	mut a: MatMut<'_, T>,
	mut z: Option<MatMut<'_, T>>,
	mut u: MatMut<'_, T>,
	mut v: MatMut<'_, T>,
	mut wh: MatMut<'_, T>,
	mut wv: MatMut<'_, T>,
	s_re: ColRef<'_, T>,
	s_im: ColRef<'_, T>,
	i_pos_block: &mut usize,
	parallelism: Par,
) {
fn remove_bulges<T: RealField>(
	ilo: usize,
	ihi: usize,
	n_bulges: usize,
	n_shifts: usize,
	want_t: bool,
	mut a: MatMut<'_, T>,
	mut z: Option<MatMut<'_, T>>,
	mut u: MatMut<'_, T>,
	mut v: MatMut<'_, T>,
	mut wh: MatMut<'_, T>,
	mut wv: MatMut<'_, T>,
	s_re: ColRef<'_, T>,
	s_im: ColRef<'_, T>,
	i_pos_block: &mut usize,
	parallelism: Par,
) {
pub fn multishift_qr<T: RealField>(
	want_t: bool,
	a: MatMut<'_, T>,
	z: Option<MatMut<'_, T>>,
	w_re: ColMut<'_, T>,
	w_im: ColMut<'_, T>,
	ilo: usize,
	ihi: usize,
	parallelism: Par,
	stack: &mut MemStack,
	params: SchurParams,
) -> (isize, usize, usize) {
pub fn lahqr<T: RealField>(
	want_t: bool,
	a: MatMut<'_, T>,
	z: Option<MatMut<'_, T>>,
	w_re: ColMut<'_, T>,
	w_im: ColMut<'_, T>,
	ilo: usize,
	ihi: usize,
) -> isize {
	fn test_5() {
	fn test_5_2() {
	fn test_n() {
/// tridiagonalization tuning parameters
/// threshold at which parallelism should be disabled
	fn auto() -> Self {
/// computes the layout of the workspace required to compute a self-adjoint matrix's
/// tridiagonalization
pub fn tridiag_in_place_scratch<T: ComplexField>(dim: usize, par: Par, params: Spec<TridiagParams, T>) -> StackReq {
fn tridiag_fused_op_simd<T: ComplexField>(
	A: MatMut<'_, T, usize, usize, ContiguousFwd>,
	y2: ColMut<'_, T, usize>,
	z2: ColMut<'_, T, usize, ContiguousFwd>,

	ry2: ColRef<'_, T, usize>,
	rz2: ColRef<'_, T, usize, ContiguousFwd>,

	u0: ColRef<'_, T, usize, ContiguousFwd>,
	u1: ColRef<'_, T, usize>,
	u2: ColRef<'_, T, usize>,
	v2: ColRef<'_, T, usize, ContiguousFwd>,

	f: T,
	align: usize,
) {
		fn with_simd<S: pulp::Simd>(self, simd: S) -> Self::Output {
fn tridiag_fused_op<T: ComplexField>(
	A: MatMut<'_, T>,
	y2: ColMut<'_, T>,
	z2: ColMut<'_, T>,

	ry2: ColRef<'_, T>,
	rz2: ColRef<'_, T>,

	u0: ColRef<'_, T>,
	u1: ColRef<'_, T>,
	u2: ColRef<'_, T>,
	v2: ColRef<'_, T>,

	f: T,
	align: usize,
) {
fn tridiag_fused_op_fallback<T: ComplexField>(
	A: MatMut<'_, T>,
	y2: ColMut<'_, T>,
	z2: ColMut<'_, T>,

	ry2: ColRef<'_, T>,
	rz2: ColRef<'_, T>,

	u0: ColRef<'_, T>,
	u1: ColRef<'_, T>,
	u2: ColRef<'_, T>,
	v2: ColRef<'_, T>,

	f: T,
) {
/// computes a self-adjoint matrix $A$'s tridiagonalization such that $A = Q T Q^H$
///
/// $T$ is a self-adjoint tridiagonal matrix stored in $A$'s diagonal and subdiagonal
///
/// $Q$ is a sequence of householder reflections stored in the unit lower triangular half of $A$
/// (excluding the diagonal), with the householder coefficients being stored in `householder`
pub fn tridiag_in_place<T: ComplexField>(
	A: MatMut<'_, T>,
	householder: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
	params: Spec<TridiagParams, T>,
) {
// to check that integers can be
// represented exactly as floats
	fn test_tridiag_real() {
	fn test_tridiag_cplx() {
// QR algorithm ported from Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
fn tridiag_to_mat<T: RealField>(diag: ColRef<'_, T, usize, ContiguousFwd>, offdiag: ColRef<'_, T, usize, ContiguousFwd>) -> Mat<T, usize, usize> {
pub(crate) fn qr_algorithm<T: RealField>(
	diag: ColMut<'_, T, usize, ContiguousFwd>,
	offdiag: ColMut<'_, T, usize, ContiguousFwd>,
	u: Option<MatMut<'_, T, usize, usize>>,
) -> Result<(), EvdError> {
// Wilkinson shift
// T = G' T G
fn secular_eq<T: RealField>(shift: T, mu: T, d: ColRef<'_, T, usize, ContiguousFwd>, z: ColRef<'_, T, usize, ContiguousFwd>, rho_recip: T) -> T {
fn batch_secular_eq<const N: usize, T: RealField>(
	shift: &[T;
fn compute_eigenvalues<T: RealField>(
	mut mus: ColMut<'_, T, usize, ContiguousFwd>,
	mut shifts: ColMut<'_, T, usize, ContiguousFwd>,
	d: ColRef<'_, T, usize, ContiguousFwd>,
	z: ColRef<'_, T, usize, ContiguousFwd>,
	rho: T,
	non_deflated: usize,
) {
fn divide_and_conquer_recurse<T: RealField>(
	mut diag: ColMut<'_, T, usize, ContiguousFwd>,
	mut offdiag: ColMut<'_, T, usize, ContiguousFwd>,
	mut u: MatMut<'_, T, usize, usize>,

	par: Par,

	pl_before: &mut [usize],
	pl_after: &mut [usize],
	pr: &mut [usize],
	run_info: &mut [usize],

	mut z: ColMut<'_, T, usize, ContiguousFwd>,
	mut permuted_diag: ColMut<'_, T, usize, ContiguousFwd>,
	mut permuted_z: ColMut<'_, T, usize, ContiguousFwd>,
	mut householder: ColMut<'_, T, usize, ContiguousFwd>,
	mut mus: ColMut<'_, T, usize, ContiguousFwd>,
	mut shifts: ColMut<'_, T, usize, ContiguousFwd>,
	mut repaired_u: MatMut<'_, T, usize, usize, ContiguousFwd>,
	mut tmp: MatMut<'_, T, usize, usize, ContiguousFwd>,
	qr_fallback_threshold: usize,
) -> Result<(), EvdError> {
//     [Q0   0] ([D0   0]            ) [Q0.T     0]
// T = [ 0  Q1]×([ 0  D1] + rho×z×z.T)×[   0  Q1.T]
//
// we compute the permutation Pl_before that sorts diag([D0 D1])
// we apply householder transformations to segments of permuted_z that correspond to
// consecutive almost-equal eigenvalues
// we compute the permutation Pl_after that places the deflated eigenvalues at the end
//
// we compute the EVD of:
// Pl_after × H × Pl_before × (diag([D0 D1]) + rho×z×z.T) × Pl_before.T × H.T × Pl_after.T =
// Q×W×Q.T
//
// we sort the eigenvalues in W
// Pr × W × Pr.T = E
//
// diag([D0 D1]) + rho×z×z.T = Pl_before^-1×H^-1×Pl_after^-1×Q×Pr × E × ...
// merge two sorted diagonals
// permuted_diag = Pl * diag * Pl.T
// permuted_z = Pl * diag
// fill uninitialized values of u with zeros
// apply Pl to u on the right
// copy permuted_diag to diag
// return
// move deflated eigenvalues to the end
// deflated value, store in diag
// perturb z and rho
// we don't actually need rho for computing the eigenvectors so we're not going to perturb it
// new_zi^2 = prod(wk - di) / prod_{k != i} (dk - di)
// NOTE: order of operations is crucial here
// reuse z to store computed eigenvalues, since it's not used anymore
// compute singular vectors
// multiply u by repaired_u (taking into account uninitialized values and sparsity structure)
//     [u0   0]
// u = [ 0  u1], u0 is n1×n1, u1 is (n-n1)×(n-n1)
// compute: u×repaired_u
// partition repaired_u
//
//              [u'_0]
// repaired_u = [u'_1], u'_0 is n1×n, u'_1 is (n-n1)×n
//
//                  [u0×u'_0]
// u × repaired_u = [u1×u'_1]
pub(crate) fn divide_and_conquer<T: RealField>(
	diag: ColMut<'_, T, usize, ContiguousFwd>,
	offdiag: ColMut<'_, T, usize, ContiguousFwd>,
	u: MatMut<'_, T, usize, usize>,

	par: Par,
	stack: &mut MemStack,
	qr_fallback_threshold: usize,
) -> Result<(), EvdError> {
pub(crate) fn divide_and_conquer_scratch<T: ComplexField>(n: usize, par: Par) -> StackReq {
	fn test_qr(diag: &[f64], offdiag: &[f64]) {
	fn test_dc(diag: &[f64], offdiag: &[f64]) {
	fn test_evd_2_0() {
	fn test_evd_2_1() {
	fn test_evd_3() {
	fn test_evd_5() {
	fn test_evd_wilkinson() {
	fn test_glued_wilkinson() {
// https://github.com/sarah-ek/faer-rs/issues/82
	fn test_gh_82() {
	fn test_gh_82_mini() {
/// computes the layout of the workspace required to compute a matrix pair's generalized
/// hessenberg decomposition
pub fn generalized_hessenberg_scratch<T: ComplexField>(n: usize, params: GeneralizedHessenbergParams) -> StackReq {
pub(crate) fn make_givens<T: ComplexField>(f: T, g: T) -> (T::Real, T, T) {
pub(crate) fn rot<T: ComplexField>(c: T::Real, s: T, x: RowMut<'_, T>, y: RowMut<'_, T>) {
/// generalized hessenberg factorization tuning parameters
/// algorithm blocking parameter
/// threshold at which blocking should be disabled
	fn auto() -> Self {
pub(crate) fn trot<T: ComplexField>(c: T::Real, s: T, x: ColMut<'_, T>, y: ColMut<'_, T>) {
fn generalized_hessenberg_unblocked<T: ComplexField>(
	A: MatMut<'_, T>,
	B: MatMut<'_, T>,
	Q: Option<MatMut<'_, T>>,
	Z: Option<MatMut<'_, T>>,
	Q_is_I: bool,
	Z_is_I: bool,
	par: Par,
	stack: &mut MemStack,
	params: GeneralizedHessenbergParams,
) {
// step 1: rotate rows jrow-1, jrow to kill A(jrow,jcol)
// step 2: rotate columns jrow, jrow-1 to kill B(jrow,jrow-1)
fn apply_U_from_the_right<T: ComplexField>(M: MatMut<'_, T>, U: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
/// computes a matrix pair $(A, B)$'s generalized hessenberg decomposition such that
/// - B is an upper triangular matrix
/// - $A = Q H Z^H, A = Q T Z^H$,
/// - $H$ is a hessenberg matrix stored in the upper triangular half of $A$ (plus the subdiagonal),
/// - $T$ is an upper triangular matrix,
/// - $Q$ and $Z$ are unitary matrices.
///
/// # warning
/// $B$ is assumed to be upper triangular on input.
///
/// $Q$ and $Z$ are postmultiplied into the input-output parameters `Q` and `Z`.
///
/// i.e.: $Q_{\text{out}} = Q_{\text{in}} * Q$ and $Z_{\text{out}} = Z_{\text{in}} * Z$.
///
/// if this behavior is not desired then $Q$ and $Z$ should be overwritten by the identity matrix
/// before calling this function.
pub fn generalized_hessenberg<T: ComplexField>(
	A: MatMut<'_, T>,
	B: MatMut<'_, T>,
	Q_inout: Option<MatMut<'_, T>>,
	Z_inout: Option<MatMut<'_, T>>,
	par: Par,
	stack: &mut MemStack,
	params: GeneralizedHessenbergParams,
) {
// update (j+1)th column of A by transformations from left.
// multiply with the trailing accumulated unitary
// matrix, which takes the form
//
//        [  U11  U12  ]
//    U = [            ],
//        [  U21  U22  ]
//
// where U21 is a len-by-len matrix and U12 is lower
// triangular.
// multiply with the other accumulated unitary
// matrices, which take the form
//
//        [  U11  U12   0  ]
//        [                ]
//    U = [  U21  U22   0  ],
//        [                ]
//        [   0    0    I  ]
//
// where I denotes the (nnb-len)-by-(nnb-len) identity
// matrix, U21 is a len-by-len upper triangular matrix
// and U12 is an nnb-by-nnb lower triangular matrix.
// Apply accumulated unitary matrices to Q.
// accumulate right givens rotations if required.
// initialize small unitary factors that will hold the
// accumulated givens rotations in workspace.
// apply accumulated unitary matrices to A and B.
// apply accumulated unitary matrices to Z.
	fn test_givens() {
	fn test_hessenberg() {
//! low level implementation of the generalized eigenvalue decomposition of a square matrix pair.
//!
//! the generalized eigenvalue decomposition of a matrix pair $(A, B)$ of shape $(n, n)$ is a
//! decomposition into components $S$, $U$ such that:
//!
//! - $U$ has shape $(n, n)$ and is invertible
//! - $S$ has shape $(n, n)$ and is a diagonal matrix
//! - and finally:
//!
//! $$A = B U S U^{-1}$$
//!
//! if $A$ is self-adjoint and $B$ is positive definite, then $U$ can be made unitary ($U^{-1} =
//! U^H$), and $S$ is real valued.
//!
//! the implementation can choose to compute the left and/or right generalized eigenvectors
//! separately, and the generalized eigenvalues (diagonal of $S$) are represented as a ratio $\alpha
//! / \beta$ to improve numerical stability.
/// eigendecomposition error
/// reached max iterations
/// eigendecomposition error
/// reached max iterations
/// B matrix not positive definite
/// generalized schur decomposition parameters
/// An estimate of the relative cost of flops within the near-the-diagonal shift chase compared
/// to flops within the matmul calls of a QZ sweep.
/// Function that returns the number of shifts to use for a given matrix size
/// Function that returns the deflation window to use for a given matrix size
/// Threshold to switch between blocked and unblocked code
/// Threshold of percent of aggressive-early-deflation window that must converge to skip a
/// sweep
/// schur to eigendecomposition conversion parameters
/// eigendecomposition tuning parameters
/// hessenberg parameters
/// schur from hessenberg conversion parameters
/// eigendecomposition from schur conversion parameters
fn default_relative_cost_estimate_of_shift_chase_to_matmul(n: usize, nh: usize) -> usize {
	fn auto() -> Self {
	fn auto() -> Self {
	fn auto() -> Self {
/// hessenberg decomposition
/// $QZ$ decomposition for complex matrices
/// $QZ$ decomposition for real matrices
fn compute_gevd_generic<T: ComplexField>(
	A: MatMut<'_, T>,
	B: MatMut<'_, T>,
	alpha_re: ColMut<'_, T>,
	alpha_im: ColMut<'_, T>,
	beta: ColMut<'_, T>,
	u_left: Option<MatMut<'_, T>>,
	u_right: Option<MatMut<'_, T>>,
	par: Par,
	stack: &mut MemStack,
	params: GevdParams,

	hessenberg_to_qz: fn(
		A: MatMut<'_, T>,
		B: MatMut<'_, T>,
		Q: Option<MatMut<'_, T>>,
		Z: Option<MatMut<'_, T>>,
		alphar: ColMut<'_, T>,
		alphai: ColMut<'_, T>,
		beta: ColMut<'_, T>,
		eigenvectors: ComputeEigenvectors,
		par: Par,
		params: GeneralizedSchurParams,
		stack: &mut MemStack,
	),
	qz_to_gevd: fn(A: MatRef<'_, T>, B: MatRef<'_, T>, Q: Option<MatMut<'_, T>>, Z: Option<MatMut<'_, T>>, par: Par, stack: &mut MemStack),
) -> Result<(), GevdError> {
fn solve_shifted_1x1<T: ComplexField>(smin: T::Real, ca: T::Real, A: T, d0: T, B: &mut T, w: T) {
// use smin * I
// w is real
fn solve_complex_shifted_1x1<T: RealField>(smin: T, ca: T, A: MatRef<'_, T>, d0: T, mut B: MatMut<'_, T>, wr: T, wi: T) {
// Compute the real part of  C = ca A - w D
// use smin * I
// w is real
// w is complex
fn solve_complex_shifted_2x2<T: RealField>(smin: T, ca: T, A: MatRef<'_, T>, d0: T, d1: T, mut B: MatMut<'_, T>, wr: T, wi: T, stack: &mut MemStack) {
// Compute the real part of  C = ca A - w D
// w is real
// use smin * I
// w is complex
// use smin * I
fn qz_to_gevd_real<T: RealField>(
	A: MatRef<'_, T>,
	B: MatRef<'_, T>,
	Q: Option<MatMut<'_, T>>,
	Z: Option<MatMut<'_, T>>,
	par: Par,
	stack: &mut MemStack,
) {
// left eigenvectors
// real eigenvalue
// scale to avoid underflow
// complex eigenvalue
// scale to avoid over/underflow
// compute first two components of eigenvector
// Compute dot products
//
//       j-1
// SUM = sum  conjg( a*S(k,j) - b*P(k,j) )*x(k)
//       k=je
//
// To reduce the op count, this is done as
//
// _        j-1                  _        j-1
// a*conjg( sum  S(k,j)*x(k) ) - b*conjg( sum  P(k,j)*x(k) )
//          k=je                          k=je
//
// which may cause underflow problems if A or B are close
// to underflow.  (T.g., less than SMALL.)
// Solve  ( a A - b B ).T  y = SUM(,)
// with scaling and perturbation of the denominator
// right eigenvectors
// real eigenvalue
// scale to avoid underflow
// complex eigenvalue
// scale to avoid over/underflow
// compute first two components of eigenvector
// Compute the contributions of the off-diagonals of
// column j (and j+1, if 2-by-2 block) of A and B to the
// sums.
fn qz_to_gevd_cplx<T: ComplexField>(
	A: MatRef<'_, T>,
	B: MatRef<'_, T>,
	Q: Option<MatMut<'_, T>>,
	Z: Option<MatMut<'_, T>>,
	par: Par,
	stack: &mut MemStack,
) {
// left eigenvectors
// real eigenvalue
// scale to avoid underflow
// Compute dot products
//
//       j-1
// SUM = sum  conjg( a*S(k,j) - b*P(k,j) )*x(k)
//       k=je
//
// To reduce the op count, this is done as
//
// _        j-1                  _        j-1
// a*conjg( sum  S(k,j)*x(k) ) - b*conjg( sum  P(k,j)*x(k) )
//          k=je                          k=je
//
// which may cause underflow problems if A or B are close
// to underflow.  (T.g., less than SMALL.)
// Solve  ( a A - b B ).T  y = SUM(,)
// with scaling and perturbation of the denominator
// right eigenvectors
// real eigenvalue
// scale to avoid underflow
// Compute the contributions of the off-diagonals of
// column j (and j+1, if 2-by-2 block) of A and B to the
// sums.
/// computes the layout of the workspace required to compute a matrix pair's
/// generalized eigendecomposition
pub fn gevd_scratch<T: ComplexField>(
	dim: usize,
	left: ComputeEigenvectors,
	right: ComputeEigenvectors,
	par: Par,
	params: Spec<GevdParams, T>,
) -> StackReq {
/// computes the real matrix pair $(A, B)$'s eigendecomposition
///
/// the eigenvalues are stored in $S$, the left eigenvectors in $U_L$, and the right eigenvectors in
/// $U_R$
///
/// the values in $A$ and $B$ after this function is called are unspecified.
pub fn gevd_real<T: RealField>(
	A: MatMut<'_, T>,
	B: MatMut<'_, T>,
	S_re: DiagMut<'_, T>,
	S_im: DiagMut<'_, T>,
	beta: DiagMut<'_, T>,
	U_left: Option<MatMut<'_, T>>,
	U_right: Option<MatMut<'_, T>>,
	par: Par,
	stack: &mut MemStack,
	params: Spec<GevdParams, T>,
) -> Result<(), GevdError> {
/// computes the complex matrix pair $(A, B)$'s eigendecomposition
///
/// the eigenvalues are stored in $S$, the left eigenvectors in $U_L$, and the right eigenvectors in
/// $U_R$
///
/// the values in $A$ and $B$ after this function is called are unspecified.
pub fn gevd_cplx<T: ComplexField>(
	A: MatMut<'_, T>,
	B: MatMut<'_, T>,
	S: DiagMut<'_, T>,
	beta: DiagMut<'_, T>,
	U_left: Option<MatMut<'_, T>>,
	U_right: Option<MatMut<'_, T>>,
	par: Par,
	stack: &mut MemStack,
	params: Spec<GevdParams, T>,
) -> Result<(), GevdError> {
	fn test_lishen_() {
	fn test_cplx() {
fn hessenberg_to_qz_unblocked<T: ComplexField>(
	ilo: usize,
	ihi: usize,
	A: MatMut<'_, T>,
	B: MatMut<'_, T>,
	Q: Option<MatMut<'_, T>>,
	Z: Option<MatMut<'_, T>>,
	alpha: ColMut<'_, T>,
	beta: ColMut<'_, T>,
	eigvals_only: bool,
) {
// set eigenvalues ihi+1:n
// initialize dynamic indices
//
// eigenvalues ilast+1:n have been found.
// column operations modify rows ifrstm:whatever
// row operations modify columns whatever:ilastm
//
// if only eigenvalues are being computed, then
// ifrstm is the row of the last splitting row above row ilast;
// this is always at least ilo.
// iiter counts iterations since the last eigenvalue was found,
// to tell when to use an extraordinary shift.
// maxit is the maximum number of QZ sweeps allowed.
// split the matrix if possible.
//
// two tests:
// 1: H(j,j-1)=0  or  j=ilo
// 2: T(j,j)=0
//
// special case: j=ilast
// test 1: for H(j,j-1)=0 or j=ilo
// test 2: for T(j,j)=0
// test 1a: check for 2 consecutive small subdiagonals in A
// if both tests pass (1 & 2), i.e., the leading diagonal
// element of B in the block is zero, split a 1x1 block off
// at the top. (i.e., at the j-th row/column) the leading
// diagonal element of the remainder can also be zero, so
// this may have to be done repeatedly.
// only test 2 passed -- chase the zero to T(ilast,ilast)
// then process as in the case T(ilast,ilast)=0
// only test 1 passed -- work on j:ilast
// neither test passed -- try next j
// goto50
// T(ilast,ilast)=0 -- clear H(ilast,ilast-1) to split off a 1x1 block.
// H(ilast,ilast-1)=0 -- standardize B, set alpha and beta
// goto60
// go to next block -- exit if finished.
// reset counters
// goto70
// QZ step
//
// this iteration only involves rows/columns ifirst:ilast.  we
// assume ifirst < ilast, and that the diagonal of B is non-zero.
// compute the shift.
//
// at this point, ifirst < ilast, and the diagonal elements of
// T(ifirst:ilast,ifirst,ilast) are larger than btol (in
// magnitude)
// the wilkinson shift (aep p.512), i.e., the eigenvalue of
// the bottom-right 2x2 block of A inv(B) which is nearest to
// the bottom-right element.
//
// we factor B as U*D, where U has unit diagonals, and
// compute (A*inv(D))*inv(U).
// exceptional shift.  chosen for no particularly good reason.
// now check for two consecutive small subdiagonals.
// do an implicit-shift QZ sweep.
//
// initial Q
// sweep
fn chase_bulge_1x1<T: ComplexField>(
	k: usize,
	istartm: usize,
	istopm: usize,
	ihi: usize,
	mut A: MatMut<'_, T>,
	mut B: MatMut<'_, T>,
	mut Q: Option<MatMut<'_, T>>,
	mut Z: Option<MatMut<'_, T>>,
	qstart: usize,
	zstart: usize,
) {
// * Shift is located on the edge of the matrix, remove it
// * Normal operation, move bulge down
// *
// *
// * Apply transformation from the right
// * Apply transformation from the left
fn multishift_sweep<T: ComplexField>(
	eigvals_only: bool,
	ilo: usize,
	ihi: usize,
	alpha: ColRef<'_, T>,
	beta: ColRef<'_, T>,
	mut A: MatMut<'_, T>,
	mut B: MatMut<'_, T>,
	mut Q: Option<MatMut<'_, T>>,
	mut Z: Option<MatMut<'_, T>>,
	mut QC: MatMut<'_, T>,
	mut ZC: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
// * The following block introduces the shifts and chases
// * them down one by one just enough to make space for
// * the other shifts. The near-the-diagonal block is
// * of size (ns+1) x ns.
// * Introduce the shift
// * Chase the shift down
// * Update the rest of the pencil
//
// * Update A(ilo:ilo+ns,ilo+ns:istopm) and B(ilo:ilo+ns,ilo+ns:istopm)
// * from the left with Qc(1:ns+1,1:ns+1)'
// * Update A(istartm:ilo-1,ilo:ilo+ns-1) and B(istartm:ilo-1,ilo:ilo+ns-1)
// * from the right with Zc(1:ns,1:ns),
// * The following block chases the shifts down to the bottom
// * right block. If possible, a shift is moved down npos
// * positions at a time
// Size of the near-the-diagonal block
// istartb points to the first row we will be updating
// istopb points to the last column we will be updating
// * Near the diagonal shift chase
// * Move down the block with index k+i+j, updating
// * the (ns+np x ns+np) block:
// * (k:k+ns+np,k:k+ns+np-1)
// * Update rest of the pencil
// * Update A(k+1:k+ns+np, k+ns+np:istopm) and
// * B(k+1:k+ns+np, k+ns+np:istopm)
// * from the left with Qc(1:ns+np,1:ns+np)'
// * Update A(istartm:k,k:k+ns+npos-1) and B(istartm:k,k:k+ns+npos-1)
// * from the right with Zc(1:ns+np,1:ns+np)
// * The following block removes the shifts from the bottom right corner
// * one by one. Updates are initially applied to A(ihi-ns+1:ihi,ihi-ns:ihi).
// * istartb points to the first row we will be updating
// * istopb points to the last column we will be updating
// * Chase the shift down to the bottom right corner
// * Update rest of the pencil
//
// * Update A(ihi-ns+1:ihi, ihi+1:istopm)
// * from the left with Qc(1:ns,1:ns)'
// * Update A(istartm:ihi-ns,ihi-ns:ihi)
// * from the right with Zc(1:ns+1,1:ns+1)
fn swap_qz<T: ComplexField>(mut A: MatMut<'_, T>, mut B: MatMut<'_, T>, mut Q: Option<MatMut<'_, T>>, mut Z: Option<MatMut<'_, T>>, j1: usize) {
fn reorder_qz<T: ComplexField>(
	mut A: MatMut<'_, T>,
	mut B: MatMut<'_, T>,
	mut Q: Option<MatMut<'_, T>>,
	mut Z: Option<MatMut<'_, T>>,
	ifst: usize,
	ilst: usize,
) {
fn aggressive_early_deflation<T: ComplexField>(
	eigvals_only: bool,
	ilo: usize,
	ihi: usize,
	nw: usize,
	mut A: MatMut<'_, T>,
	mut B: MatMut<'_, T>,
	mut Q: Option<MatMut<'_, T>>,
	mut Z: Option<MatMut<'_, T>>,
	mut alpha: ColMut<'_, T>,
	mut beta: ColMut<'_, T>,
	mut QC: MatMut<'_, T>,
	mut ZC: MatMut<'_, T>,
	par: Par,
	params: GeneralizedSchurParams,
	stack: &mut MemStack,
) -> (usize, usize) {
// * 1 by 1 deflation window, just try a regular deflation
// ns = 0;
// nd = 1;
// * Transform window to real schur form
// * Deflation detection loop
// * Try to deflate eigenvalue
// * Deflatable
// * Not deflatable, move out of the way
// * Store eigenvalues
// * Reflect spike back, this will create optimally packed bulges
// * Chase bulges down
// * Move bulge down and remove it
/// computes the layout of the workspace required to compute a complex matrix pair's QZ
/// decomposition, assuming the pair is already in generalized hessenberg form.
pub fn hessenberg_to_qz_scratch<T: ComplexField>(n: usize, par: Par, params: GeneralizedSchurParams) -> StackReq {
fn multishift_sweep_scratch<T: ComplexField>(n: usize, ns: usize) -> StackReq {
fn aed_scratch<T: ComplexField>(n: usize, nw: usize, par: Par, params: GeneralizedSchurParams) -> StackReq {
/// computes a complex matrix pair's QZ decomposition, assuming the pair is already in generalized
/// hessenberg form.  
/// the unitary transformations $Q$ and $Z$ resulting from the QZ decomposition are postmultiplied
/// into the input-output parameters `Q_inout` and `Z_inout`.
///
/// if both the generalized eigenvalues and eigenvectors are desired, then `eigenvectors` may be set
/// to `ComputeEigenvectors::Yes`. in this case the input matrices $A$ and $B$ are overwritten by
/// their QZ form $(S, T)$ such that $S$ and $T$ are upper triangular.
///
/// if only the generalized eigenvalues are desired, then `eigenvectors` may be set to
/// `ComputeEigenvectors::No`. note that in this case, the input matrices $A$ and $B$ are still
/// clobbered, and contain unspecified values on output.
pub fn hessenberg_to_qz<T: ComplexField>(
	A: MatMut<'_, T>,
	B: MatMut<'_, T>,
	Q: Option<MatMut<'_, T>>,
	Z: Option<MatMut<'_, T>>,
	alpha: ColMut<'_, T>,
	beta: ColMut<'_, T>,
	eigenvectors: linalg::evd::ComputeEigenvectors,
	par: Par,
	params: GeneralizedSchurParams,
	stack: &mut MemStack,
) {
fn hessenberg_to_qz_blocked<T: ComplexField>(
	ilo: usize,
	ihi: usize,
	A: MatMut<'_, T>,
	B: MatMut<'_, T>,
	Q: Option<MatMut<'_, T>>,
	Z: Option<MatMut<'_, T>>,
	alpha: ColMut<'_, T>,
	beta: ColMut<'_, T>,
	eigvals_only: bool,
	par: Par,
	params: GeneralizedSchurParams,
	stack: &mut MemStack,
) {
// * Check deflations at the end
// * Check deflations at the start
// * Check interior deflations
// * Check infinite eigenvalues, this is done without blocking so might
// * slow down the method when many infinite eigenvalues are present
// * A diagonal element of B is negligible, move it
// * to the top and deflate it
// * istart2 now points to the top of the bottom right
// * unreduced Hessenberg block
// * Setting nw to the size of the subblock will make AED deflate
// * all the eigenvalues. This is slightly more efficient than just
// * using qz_small because the off diagonal part gets updated via BLAS.
// * Time for AED
// * AED has uncovered many eigenvalues. Skip a QZ sweep and run
// * AED again.
// * Exceptional shift.  Chosen for no particularly good reason.
// * Time for a QZ sweep
// * Call ZHGEQZ to normalize the eigenvalue blocks and set the eigenvalues
// * If all the eigenvalues have been found, ZHGEQZ will not do any iterations
// * and only normalize the blocks. In case of a rare convergence failure,
// * the single shift might perform better.
	fn test_qz_cplx_unblocked() {
	fn test_qz_cplx_blocked() {
fn copy_sign<T: RealField>(a: T, b: T) -> T {
fn rot_rows<T: RealField>(c: T, s: T, A: MatMut<'_, T>, i: usize, j: usize) {
fn rot_cols<T: RealField>(c: T, s: T, A: MatMut<'_, T>, i: usize, j: usize) {
// solve A * R - L * B = C
// solve D * R - L * E = F
// (R, L) is stored in (C, F)
fn solve_sylvester_single_block<T: RealField>(
	A: MatRef<'_, T>,
	B: MatRef<'_, T>,
	mut C: MatMut<'_, T>,
	D: MatRef<'_, T>,
	E: MatRef<'_, T>,
	mut F: MatMut<'_, T>,
	stack: &mut MemStack,
) {
fn svd_triu_2x2<T: RealField>(f: T, g: T, h: T) -> (T, T, T, T, T, T) {
// * PMAX points to the maximum absolute element of matrix
// * PMAX = 1 if F largest in absolute values
// * PMAX = 2 if G largest in absolute values
// * PMAX = 3 if H largest in absolute values
// *
// * Now FA .ge. HA
// *
// * Diagonal matrix
// * Case of very large GA
// * Normal case
// *
// * Copes with infinite F or H
// *
// * Note that 0 .le. L .le. 1
// *
// *
// * Note that abs(M) .le. 1/macheps
// *
// *
// * Note that T .ge. 1
// *
// *
// * Note that 1 .le. S .le. 1 + 1/macheps
// *
// * Note that 0 .le. R .le. 1 + 1/macheps
// * Note that 1 .le. A .le. 1 + abs(M)
// * Note that M is very tiny
// *
// * Correct signs of SSMAX and SSMIN
// *
pub(super) fn generalized_eigval_2x2<T: RealField>((a11, a12, a21, a22): (T, T, T, T), (b11, b12, b21, b22): (T, T, T, T)) -> (T, T, T, T, T) {
// * Scale A
// * Perturb B if necessary to insure non-singularity
// * Scale B
// * Compute larger eigenvalue by method described by C. van Loan
// *
// * ( AS is A shifted by -SHIFT*B )
// * Note: the test of R in the following IF is to cover the case when
// * DISCR is small and negative and is flushed to zero during
// * the calculation of R.  On machines which have a consistent
// * flush-to-zero threshold and handle numbers above that
// * threshold correctly, it would not be necessary.
// * Compute smaller eigenvalue
// * Choose (real) eigenvalue closest to 2,2 element of A*B**(-1)
// * for WR1.
// * Further scaling to avoid underflow and overflow in computing
// * SCALE1 and overflow in computing w*B.
// *
// * This scale factor (WSCALE) is bounded from above using C1 and C2,
// * and from below using C3 and C4.
// * C1 implements the condition  s A  must never overflow.
// * C2 implements the condition  w B  must never overflow.
// * C3, with C2,
// * implement the condition that s A - w B must never overflow.
// * C4 implements the condition  s    should not underflow.
// * C5 implements the condition  max(s,|w|) should be at least 2.
// * Scale first eigenvalue
fn hessenberg_to_qz_unblocked<T: RealField>(
	ilo: usize,
	ihi: usize,
	A: MatMut<'_, T>,
	B: MatMut<'_, T>,
	Q: Option<MatMut<'_, T>>,
	Z: Option<MatMut<'_, T>>,
	alphar: ColMut<'_, T>,
	alphai: ColMut<'_, T>,
	beta: ColMut<'_, T>,
	eigvals_only: bool,
) {
// * Set Eigenvalues IHI+1:N
// * MAIN QZ ITERATION LOOP
// *
// * Initialize dynamic indices
// *
// * Eigenvalues ILAST+1:N have been found.
// * Column operations modify rows IFRSTM:whatever.
// * Row operations modify columns whatever:ILASTM.
// *
// * If only eigenvalues are being computed, then
// * IFRSTM is the row of the last splitting row above row ILAST;
// * this is always at least ILO.
// * IITER counts iterations since the last eigenvalue was found,
// * to tell when to use an extraordinary shift.
// * MAXIT is the maximum number of QZ sweeps allowed.
// * Split the matrix if possible.
// *
// * Two tests:
// * 1: H(j,j-1)=0  or  j=ILO
// * 2: T(j,j)=0
// * Special case: j=ILAST
// * General case: j<ILAST
// * Test 1: for H(j,j-1)=0 or j=ILO
// * Test 2: for T(j,j)=0
// * Test 1a: Check for 2 consecutive small subdiagonals in A
// * If both tests pass (1 & 2), i.e., the leading diagonal
// * element of B in the block is zero, split a 1x1 block off
// * at the top. (I.e., at the J-th row/column) The leading
// * diagonal element of the remainder can also be zero, so
// * this may have to be done repeatedly.
// * Only test 2 passed -- chase the zero to T(ILAST,ILAST)
// * Then process as in the case T(ILAST,ILAST)=0
// * Only test 1 passed -- work on J:ILAST
// * Neither test passed -- try next J
// * (Drop-through is "impossible")
// goto70
// * T(ILAST,ILAST)=0 -- clear H(ILAST,ILAST-1) to split off a
// * 1x1 block.
// goto80
// * H(ILAST,ILAST-1)=0 -- Standardize B, set ALPHAR, ALPHAI,
// * and BETA
// * Go to next block -- exit if finished.
// * Reset counters
// goto110
// * Compute single shifts.
// *
// * At this point, IFIRST < ILAST, and the diagonal elements of
// * T(IFIRST:ILAST,IFIRST,ILAST) are larger than BTOL (in
// * magnitude)
// * Exceptional shift.  Chosen for no particularly good reason.
// * (Single shift only.)
// * Shifts based on the generalized eigenvalues of the
// * bottom-right 2x2 block of A and B. The first eigenvalue
// * returned by DLAG2 is the Wilkinson shift (AEP p.512),
// temp = max(s1, safmin * max(one(), max(abs(wr), abs(wi))));
// * Fiddle with shift to avoid overflow
// * Now check for two consecutive small subdiagonals.
// goto130
// goto200
// * Use Francis double-shift
// *
// * Note: the Francis double-shift should work with real shifts,
// * but only if the block is at least 3x3.
// * This code may break if this point is reached with
// * a 2x2 block with real eigenvalues.
// * Special case -- 2x2 block with complex eigenvectors
// *
// * Step 1: Standardize, that is, rotate so that
// *
// * |   ( B11  0  )
// * B = (         )  with B11 non-negative.
// * |   (  0  B22 )
// * If B22 is negative, negate column ILAST
// * Step 2: Compute ALPHAR, ALPHAI, and BETA (see refs.)
// *
// * Recompute shift
// *f If standardization has perturbed the shift onto real line,
// * do another (real single-shift) QR step.
// * Do EISPACK (QZVAL) computation of alpha and beta
// *
// *
// * Compute complex Givens rotation on right
// * (Assume some element of C = (sA - wB) > unfl )
// * |                          __
// * |         (sA - wB) ( CZ   -SZ )
// * |                   ( SZ    CZ )
// *
// * Compute Givens rotation on left
// *
// * |         (  CQ   SQ )
// * |         (  __      )  A or B
// * |         ( -SQ   CQ )
// * Compute diagonal elements of QBZ
// *
// *
// * Normalize so beta > 0, and Im( alpha1 ) > 0
// *
// *
// * Step 3: Go to next block -- exit if finished.
// * Reset counters
// * Set Eigenvalues 1:ILO-1
fn double_shift_sweep<T: RealField>(
	ascale: T,
	ilast: usize,
	bscale: T,
	ifirst: usize,
	ilastm: usize,
	n: usize,
	ifrstm: usize,
	mut H: MatMut<'_, T>,
	mut T: MatMut<'_, T>,
	mut Q: Option<MatMut<'_, T>>,
	mut Z: Option<MatMut<'_, T>>,
) {
// * | Usual case: 3x3 or larger block, using Francis implicit
// * |             double-shift
// * |
// * |                          2
// * | Eigenvalue equation is  w  - c w + d = 0,
// * |
// * |                               -1 2        -1
// * | so compute 1st column of  (A B  )  - c A B   + d
// * | using the formula in QZIT (from EISPACK)
// * |
// * | We assume that the block is at least 3x3
// * Sweep
// * All but last elements: use 3x3 Householder transforms.
// *
// * Zero (j-1)st column of A
// * Zero j-th column of B (see DLAGBC for details)
// *
// * Swap rows to pivot
// * Swap columns if nec.
// * LU-factor
// w21 = zero();
// * Compute SCALE
// * Solve
// goto250
// * Compute Householder Vector
// * Apply transformations from the right.
// * Last elements: Use Givens rotations
// *
// * Rotations from the left
// * Rotations from the right.
fn single_shift_sweep<T: RealField>(
	s1: T,
	istart: usize,
	wr: T,
	ilast: usize,
	ilastm: usize,
	ifrstm: usize,
	mut H: MatMut<'_, T>,
	mut T: MatMut<'_, T>,
	mut Q: Option<MatMut<'_, T>>,
	mut Z: Option<MatMut<'_, T>>,
) {
// * Do an implicit single-shift QZ sweep.
// *
// * Initial Q
// * Sweep
/// computes the layout of the workspace required to compute a real matrix pair's QZ
/// decomposition, assuming the pair is already in generalized hessenberg form.
pub fn hessenberg_to_qz_scratch<T: RealField>(n: usize, par: Par, params: GeneralizedSchurParams) -> StackReq {
fn hessenberg_to_qz_blocked_scratch<T: RealField>(n: usize, par: Par, params: GeneralizedSchurParams) -> StackReq {
fn multishift_sweep_scratch<T: RealField>(n: usize, ns: usize) -> StackReq {
fn aed_scratch<T: RealField>(n: usize, nw: usize, par: Par, params: GeneralizedSchurParams) -> StackReq {
/// computes a real matrix pair's QZ decomposition, assuming the pair is already in generalized
/// hessenberg form.  
/// the unitary transformations $Q$ and $Z$ resulting from the QZ decomposition are postmultiplied
/// into the input-output parameters `Q_inout` and `Z_inout`.
///
/// if both the generalized eigenvalues and eigenvectors are desired, then `eigenvectors` may be set
/// to `ComputeEigenvectors::Yes`. in this case the input matrices $A$ and $B$ are overwritten by
/// their QZ form $(S, T)$ such that $S$ is upper quasi-triangular and $T$ is upper triangular.
///
/// if only the generalized eigenvalues are desired, then `eigenvectors` may be set to
/// `ComputeEigenvectors::No`. note that in this case, the input matrices $A$ and $B$ are still
/// clobbered, and contain unspecified values on output.
pub fn hessenberg_to_qz<T: RealField>(
	A: MatMut<'_, T>,
	B: MatMut<'_, T>,
	Q_inout: Option<MatMut<'_, T>>,
	Z_inout: Option<MatMut<'_, T>>,
	alphar: ColMut<'_, T>,
	alphai: ColMut<'_, T>,
	beta: ColMut<'_, T>,
	eigenvectors: linalg::evd::ComputeEigenvectors,
	par: Par,
	params: GeneralizedSchurParams,
	stack: &mut MemStack,
) {
fn hessenberg_to_qz_blocked<T: RealField>(
	ilo: usize,
	ihi: usize,
	mut A: MatMut<'_, T>,
	mut B: MatMut<'_, T>,
	mut Q: Option<MatMut<'_, T>>,
	mut Z: Option<MatMut<'_, T>>,
	mut alphar: ColMut<'_, T>,
	mut alphai: ColMut<'_, T>,
	mut beta: ColMut<'_, T>,
	eigvals_only: bool,
	par: Par,
	params: GeneralizedSchurParams,
	stack: &mut MemStack,
) {
// * Check deflations at the end
// * Check deflations at the start
// * Check interior deflations
// * Check infinite eigenvalues, this is done without blocking so might
// * slow down the method when many infinite eigenvalues are present
// * A diagonal element of B is negligible, move it
// * to the top and deflate it
// * istart2 now points to the top of the bottom right
// * unreduced Hessenberg block
// * Setting nw to the size of the subblock will make AED deflate
// * all the eigenvalues. This is slightly more efficient than just
// * using qz_small because the off diagonal part gets updated via BLAS.
// * Time for AED
// * AED has uncovered many eigenvalues. Skip a QZ sweep and run
// * AED again.
// * Shuffle shifts to put double shifts in front
// * This ensures that we don't split up a double shift
// * Exceptional shift.  Chosen for no particularly good reason.
// * Time for a QZ sweep
// * Call ZHGEQZ to normalize the eigenvalue blocks and set the eigenvalues
// * If all the eigenvalues have been found, ZHGEQZ will not do any iterations
// * and only normalize the blocks. In case of a rare convergence failure,
// * the single shift might perform better.
fn laqz1<T: RealField>(A: MatRef<'_, T>, B: MatRef<'_, T>, sr1: T, sr2: T, si: T, beta1: T, beta2: T, mut v: ColMut<'_, T>) {
// *
// * Solve linear system
// *
// *
// * Apply second shift
// *
// *
// * Account for imaginary part
// *
// *
// * Check for overflow
// *
fn chase_bulge_2x2<T: RealField>(
	k: usize,
	istartm: usize,
	istopm: usize,
	ihi: usize,
	mut A: MatMut<'_, T>,
	mut B: MatMut<'_, T>,
	qstart: usize,
	mut Q: Option<MatMut<'_, T>>,
	zstart: usize,
	mut Z: Option<MatMut<'_, T>>,
) {
// * Shift is located on the edge of the matrix, remove it
// * Make H upper triangular
// *
// * Normal operation, move bulge down
// *
// *
// * Make H upper triangular
// *
// * Make H upper triangular
// *
// * Calculate Z1 and Z2
// *
// *
// * Apply transformations from the right
// *
// *
// * Calculate Q1 and Q2
// *
// *
// * Apply transformations from the left
// *
fn aggressive_early_deflation<T: RealField>(
	eigvals_only: bool,
	ilo: usize,
	ihi: usize,
	nw: usize,
	mut A: MatMut<'_, T>,
	mut B: MatMut<'_, T>,
	mut Q: Option<MatMut<'_, T>>,
	mut Z: Option<MatMut<'_, T>>,
	mut alphar: ColMut<'_, T>,
	mut alphai: ColMut<'_, T>,
	mut beta: ColMut<'_, T>,
	mut QC: MatMut<'_, T>,
	mut ZC: MatMut<'_, T>,
	par: Par,
	params: GeneralizedSchurParams,
	stack: &mut MemStack,
) -> (usize, usize) {
// * 1 by 1 deflation window, just try a regular deflation
// ns = 1;
// nd = 0;
// ns = 0;
// nd = 1;
// * Transform window to real schur form
// * Deflation detection loop
// * Try to deflate complex conjugate eigenvalue pair
// * Deflatable
// * Not deflatable, move out of the way
// * Try to deflate eigenvalue
// * Deflatable
// * Not deflatable, move out of the way
// * Store eigenvalues
// * Reflect spike back, this will create optimally packed bulges
// * Chase bulges down
// * Move double pole block down and remove it
// * k points to single shift
// * Remove the shift
// * Apply Qc and Zc to rest of the matrix
fn swap_qz<T: RealField>(
	mut A: MatMut<'_, T>,
	mut B: MatMut<'_, T>,
	mut Q: Option<MatMut<'_, T>>,
	mut Z: Option<MatMut<'_, T>>,
	start: usize,
	n1: usize,
	n2: usize,
	stack: &mut MemStack,
) {
// * CASE 1: Swap 1-by-1 and 1-by-1 blocks.
// *
// * Compute orthogonal QL and RQ that swap 1-by-1 and 1-by-1 blocks
// * using Givens rotations and perform the swap tentatively.
// * CASE 2: Swap n1-by-n1 and n2-by-n2 blocks
// * Solve the generalized Sylvester equation
// * S11 * R - L * S22 = S12
// * T11 * R - L * T22 = T12
// * for R and L. Solutions in LI and IR.
// S12/T12 is n1-by-n2
// compute Q' s.t.
// [ L ]        [ TL ]
// [ I ] = Q' * [  0 ]
// compute Z' s.t.
// [ R.T.rev ]        [ TR ]
// [       I ] = Z' * [  0 ]
//
// i.e.
//               [ R.T.revrow ]   [ TR ]
// Z'.T.revcol * [   I.revrow ] = [  0 ]
//
// i.e.
//            [   I ]   [         0 ]
// Z'.T.rev * [ R.T ] = [ TR.revrow ]
//
// i.e.
// [ I  R ] * Z'.rev = [ 0  TR.revrow.T ]
// [ I  R ] * Z'.rev = [ 0  TR.revrow.T ]
// triangularize the B section
// B. Kagstrom; A Direct Method for Reordering Eigenvalues in the
// Generalized Real Schur Form of a Regular Matrix Pair (A, B), in
// M.S. Moonen et al (eds), Linear Algebra for Large Scale and
// Real-Time Applications, Kluwer Academic Publ. 1993, pp 195-218.
fn reorder_qz<T: RealField>(
	mut A: MatMut<'_, T>,
	mut B: MatMut<'_, T>,
	mut Q: Option<MatMut<'_, T>>,
	mut Z: Option<MatMut<'_, T>>,
	mut ifst: usize,
	mut ilst: usize,
	stack: &mut MemStack,
) {
// *
// * Determine the first row of the specified block and find out
// * if it is 1-by-1 or 2-by-2.
// *
// *
// * Determine the first row of the final block
// * and find out if it is 1-by-1 or 2-by-2.
// *
// * Swap with next one below.
// * Current block either 1-by-1 or 2-by-2.
// * Test if 2-by-2 block breaks into two 1-by-1 blocks.
// * Current block consists of two 1-by-1 blocks, each of which
// * must be swap individually.
// * Swap two 1-by-1 blocks.
// * Recompute NBNEXT in case of 2-by-2 split.
// * 2-by-2 block did not split.
// * 2-by-2 block did split.
// * Swap with next one below.
// * Current block either 1-by-1 or 2-by-2.
// * Test if 2-by-2 block breaks into two 1-by-1 blocks.
// * Current block consists of two 1-by-1 blocks, each of which
// * must be swap individually.
// * Swap two 1-by-1 blocks.
// * Recompute NBNEXT in case of 2-by-2 split.
// * 2-by-2 block did not split.
// * 2-by-2 block did split.
fn multishift_sweep<T: RealField>(
	ilo: usize,
	ihi: usize,
	mut sr: ColMut<'_, T>,
	mut si: ColMut<'_, T>,
	mut ss: ColMut<'_, T>,
	mut A: MatMut<'_, T>,
	mut B: MatMut<'_, T>,
	mut Q: Option<MatMut<'_, T>>,
	mut Z: Option<MatMut<'_, T>>,
	mut QC: MatMut<'_, T>,
	mut ZC: MatMut<'_, T>,
	eigvals_only: bool,
	par: Par,
	stack: &mut MemStack,
) {
// * Shuffle shifts into pairs of real shifts and pairs
// * of complex conjugate shifts assuming complex
// * conjugate shifts are already adjacent to one
// * another
// * NSHFTS is supposed to be even, but if it is odd,
// * then simply reduce it by one.  The shuffle above
// * ensures that the drop shift is real and that
// * the remaining shifts are paired.
// * Update the rest of the pencil
// * Update A[(ilo:ilo+ns,ilo+ns:istopm)] and B[(ilo:ilo+ns,ilo+ns:istopm)]
// * from the left with Qc(1:ns+1,1:ns+1)'
// * Update A[(istartm:ilo-1,ilo:ilo+ns-1)] and B[(istartm:ilo-1,ilo:ilo+ns-1)]
// * from the right with Zc(1:ns,1:ns),
// * The following block chases the shifts down to the bottom
// * right block. If possible, a shift is moved down npos
// * positions at a time
// Size of the near-the-diagonal block
// istartb points to the first row we will be updating
// istopb points to the last column we will be updating
// * Move down the block with index k+i+j-1, updating
// * the (ns+np x ns+np) block:
// * (k:k+ns+np,k:k+ns+np-1)
// * Update rest of the pencil
// * Update A[(k+1:k+ns+np, k+ns+np:istopm)] and
// * B[(k+1:k+ns+np, k+ns+np:istopm)]
// * from the left with Qc(1:ns+np,1:ns+np)'
// * Update A[(istartm:k,k:k+ns+npos-1)] and B[(istartm:k,k:k+ns+npos-1)]
// * from the right with Zc(1:ns+np,1:ns+np)
// * The following block removes the shifts from the bottom right corner
// * one by one. Updates are initially applied to A[(ihi-ns+1:ihi,ihi-ns:ihi)].
// * istartb points to the first row we will be updating
// * istopb points to the last column we will be updating
// * Chase the shift down to the bottom right corner
// * Update rest of the pencil
//
// * Update A[(ihi-ns+1:ihi, ihi+1:istopm)]
// * from the left with Qc(1:ns,1:ns)'
// * Update A[(istartm:ihi-ns,ihi-ns:ihi)]
// * from the right with Zc(1:ns+1,1:ns+1)
	fn make_pair(rng: &mut dyn RngCore, ns: &[usize]) -> (Mat<f64>, Mat<f64>) {
	fn geigval_2x2(A: MatRef<'_, f64>, B: MatRef<'_, f64>) -> (f64, f64, f64, f64) {
	fn geigval_1x1(A: MatRef<'_, f64>, B: MatRef<'_, f64>) -> f64 {
	fn test_swap_qz_random() {
	fn test_swap_qz_edge_case() {
	fn test_qz_real_unblocked() {
	fn test_qz_real_blocked() {
//! block householder transformations
//!
//! a householder reflection is linear transformation that describes a reflection about a
//! hyperplane that crosses the origin of the space
//!
//! let $v$ be a unit vector that is orthogonal to the hyperplane. then the corresponding
//! householder transformation in matrix form is $I - 2vv^H$, where $I$ is the identity matrix
//!
//! in practice, a non unit vector $v$ is used, so the transformation is written as
//! $$H = I - \frac{vv^H}{\tau}$$
//!
//! a block householder transformation is a sequence of such transformations
//! $H_0, H_1, \dots, H_{b -1 }$ applied one after the other, with the restriction that the first
//! $i$ components of the vector $v_i$ of the $i$-th transformation are zero, and the component at
//! index $i$ is one
//!
//! the matrix $V = [v_0\ v_1\ \dots\ v_{b-1}]$ is thus a lower trapezoidal matrix with unit
//! diagonal. we call it the householder basis
//!
//! there exists a unique upper triangular matrix $T$, that we call the householder factor, such
//! that $$H_0 \times \dots \times H_{b-1} = I - VT^{-1}V^H$$
//!
//! a block householder sequence is a sequence of such transformations, composed of two matrices:
//! - a lower trapezoidal matrix with unit diagonal, which is the horizontal concatenation of the
//! bases of each block householder transformation,
//! - a horizontal concatenation of the householder factors.
//!
//! examples on how to create and manipulate block householder sequences are provided in the
//! documentation of the $QR$ module.
/// Householder information
/// The tau value of the householder transformation
/// The reciprocal of head with beta added
/// The norm
/// computes the householder reflection $I - \frac{v v^H}{\tau}$ such that when multiplied by $x$
/// from the left, the result is $\beta e_0$. $\tau$ and $(\text{head} - \beta)^{-1}$ are returned
/// and $\tau$ is real-valued. $\beta$ is stored in `head`
///
/// $x$ is determined by $x_0$, contained in `head`, and $|x_{1\dots}|$, contained in `tail_norm`.
/// the vector $v$ is such that $v_0 = 1$ and $v_{1\dots}$ is stored in `essential` (when provided)
fn make_householder_imp<T: ComplexField>(head: &mut T, out: ColMut<'_, T>, input: Option<ColRef<'_, T>>) -> HouseholderInfo<T> {
/// computes the householder reflection $I - \frac{v v^H}{\tau}$ such that when multiplied by $x$
/// from the left, the result is $\beta e_0$. $\tau$ and $(\text{head} - \beta)^{-1}$ are returned
/// and $\tau$ is real-valued. $\beta$ is stored in `head`
///
/// $x$ is determined by $x_0$, contained in `head`, and $|x_{1\dots}|$, contained in `tail_norm`.
/// the vector $v$ is such that $v_0 = 1$ and $v_{1\dots}$ is stored in `essential` (when provided)
pub fn make_householder_in_place<T: ComplexField>(head: &mut T, tail: ColMut<'_, T>) -> HouseholderInfo<T> {
pub(crate) fn make_householder_out_of_place<T: ComplexField>(head: &mut T, out: ColMut<'_, T>, tail: ColRef<'_, T>) -> HouseholderInfo<T> {
pub fn upgrade_householder_factor<T: ComplexField>(
	householder_factor: MatMut<'_, T>,
	essentials: MatRef<'_, T>,
	block_size: usize,
	prev_block_size: usize,
	par: Par,
) {
// pretend that prev_block_size == 1, recompute whole top half of matrix
/// computes the layout of required workspace for applying a block householder
/// transformation to a right-hand-side matrix in place
pub fn apply_block_householder_on_the_left_in_place_scratch<T: ComplexField>(
	householder_basis_nrows: usize,
	block_size: usize,
	rhs_ncols: usize,
) -> StackReq {
/// computes the layout of required workspace for applying the transpose of a block
/// householder transformation to a right-hand-side matrix in place
pub fn apply_block_householder_transpose_on_the_left_in_place_scratch<T: ComplexField>(
	householder_basis_nrows: usize,
	block_size: usize,
	rhs_ncols: usize,
) -> StackReq {
/// computes the layout of required workspace for applying a block householder
/// transformation to a left-hand-side matrix in place
pub fn apply_block_householder_on_the_right_in_place_scratch<T: ComplexField>(
	householder_basis_nrows: usize,
	block_size: usize,
	lhs_nrows: usize,
) -> StackReq {
/// computes the layout of required workspace for applying the transpose of a block
/// householder transformation to a left-hand-side matrix in place
pub fn apply_block_householder_transpose_on_the_right_in_place_scratch<T: ComplexField>(
	householder_basis_nrows: usize,
	block_size: usize,
	lhs_nrows: usize,
) -> StackReq {
/// computes the layout of required workspace for applying the transpose of a sequence
/// of block householder transformations to a right-hand-side matrix in place
pub fn apply_block_householder_sequence_transpose_on_the_left_in_place_scratch<T: ComplexField>(
	householder_basis_nrows: usize,
	block_size: usize,
	rhs_ncols: usize,
) -> StackReq {
/// computes the layout of required workspace for applying a sequence of block
/// householder transformations to a right-hand-side matrix in place
pub fn apply_block_householder_sequence_on_the_left_in_place_scratch<T: ComplexField>(
	householder_basis_nrows: usize,
	block_size: usize,
	rhs_ncols: usize,
) -> StackReq {
/// computes the layout of required workspace for applying the transpose of a sequence
/// of block householder transformations to a left-hand-side matrix in place
pub fn apply_block_householder_sequence_transpose_on_the_right_in_place_scratch<T: ComplexField>(
	householder_basis_nrows: usize,
	block_size: usize,
	lhs_nrows: usize,
) -> StackReq {
/// computes the layout of required workspace for applying a sequence of block
/// householder transformations to a left-hand-side matrix in place
pub fn apply_block_householder_sequence_on_the_right_in_place_scratch<T: ComplexField>(
	householder_basis_nrows: usize,
	block_size: usize,
	lhs_nrows: usize,
) -> StackReq {
fn apply_block_householder_on_the_left_in_place_generic<'M, 'N, 'K, T: ComplexField>(
	householder_basis: MatRef<'_, T, Dim<'M>, Dim<'N>>,
	householder_factor: MatRef<'_, T, Dim<'N>, Dim<'N>>,
	conj_lhs: Conj,
	matrix: MatMut<'_, T, Dim<'M>, Dim<'K>>,
	forward: bool,
	par: Par,
	stack: &mut MemStack,
) {
			fn with_simd<S: pulp::Simd>(self, simd: S) -> Self::Output {
// essentials* × mat
// [T^-1|T^-*] × essentials* × tmp
// essentials × [T^-1|T^-*] × essentials* × tmp
/// computes the product of the matrix, multiplied by the given block householder transformation,
/// and stores the result in `matrix`
pub fn apply_block_householder_on_the_right_in_place_with_conj<T: ComplexField>(
	householder_basis: MatRef<'_, T>,
	householder_factor: MatRef<'_, T>,
	conj_rhs: Conj,
	matrix: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
/// computes the product of the matrix, multiplied by the transpose of the given block householder
/// transformation, and stores the result in `matrix`
pub fn apply_block_householder_transpose_on_the_right_in_place_with_conj<T: ComplexField>(
	householder_basis: MatRef<'_, T>,
	householder_factor: MatRef<'_, T>,
	conj_rhs: Conj,
	matrix: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
/// computes the product of the given block householder transformation, multiplied by `matrix`, and
/// stores the result in `matrix`
pub fn apply_block_householder_on_the_left_in_place_with_conj<T: ComplexField>(
	householder_basis: MatRef<'_, T>,
	householder_factor: MatRef<'_, T>,
	conj_lhs: Conj,
	matrix: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
/// computes the product of the transpose of the given block householder transformation, multiplied
/// by `matrix`, and stores the result in `matrix`
pub fn apply_block_householder_transpose_on_the_left_in_place_with_conj<T: ComplexField>(
	householder_basis: MatRef<'_, T>,
	householder_factor: MatRef<'_, T>,
	conj_lhs: Conj,
	matrix: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
/// computes the product of a sequence of block householder transformations given by
/// `householder_basis` and `householder_factor`, multiplied by `matrix`, and stores the result in
/// `matrix`
pub fn apply_block_householder_sequence_on_the_left_in_place_with_conj<T: ComplexField>(
	householder_basis: MatRef<'_, T>,
	householder_factor: MatRef<'_, T>,
	conj_lhs: Conj,
	matrix: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
/// computes the product of the transpose of a sequence block householder transformations given by
/// `householder_basis` and `householder_factor`, multiplied by `matrix`, and stores the result in
/// `matrix`
pub fn apply_block_householder_sequence_transpose_on_the_left_in_place_with_conj<T: ComplexField>(
	householder_basis: MatRef<'_, T>,
	householder_factor: MatRef<'_, T>,
	conj_lhs: Conj,
	matrix: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
/// computes the product of `matrix`, multiplied by a sequence of block householder transformations
/// given by `householder_basis` and `householder_factor`, and stores the result in `matrix`
pub fn apply_block_householder_sequence_on_the_right_in_place_with_conj<T: ComplexField>(
	householder_basis: MatRef<'_, T>,
	householder_factor: MatRef<'_, T>,
	conj_rhs: Conj,
	matrix: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
/// computes the product of `matrix`, multiplied by the transpose of a sequence of block householder
/// transformations given by `householder_basis` and `householder_factor`, and stores the result in
/// `matrix`
pub fn apply_block_householder_sequence_transpose_on_the_right_in_place_with_conj<T: ComplexField>(
	householder_basis: MatRef<'_, T>,
	householder_factor: MatRef<'_, T>,
	conj_rhs: Conj,
	matrix: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
/// jacobi rotation matrix
///
/// $$ \begin{bmatrix} c & -\bar s \\\\ s & c \end{bmatrix} $$
/// cosine
/// sine
	pub fn make_givens(p: T, q: T) -> Self
	where
		T: RealField,
	{
	pub fn rotg(p: T, q: T) -> (Self, T) {
// Use unscaled algorithm
// Use scaled algorithm
// Use unscaled algorithm
// Use scaled algorithm
// a is not well-scaled when scaled by g1.
// Otherwise use the same scaling for a and b.
/// apply to the given matrix from the left
///
/// $$ J \begin{bmatrix} m_{00} & m_{01} \\\\ m_{10} & m_{11} \end{bmatrix} $$
	pub fn apply_on_the_left_2x2(&self, m00: T, m01: T, m10: T, m11: T) -> (T, T, T, T) {
/// apply to the given matrix from the right
///
/// $$ \begin{bmatrix} m_{00} & m_{01} \\\\ m_{10} & m_{11} \end{bmatrix} J $$
	pub fn apply_on_the_right_2x2(&self, m00: T, m01: T, m10: T, m11: T) -> (T, T, T, T) {
	fn apply_on_the_left_in_place_impl<'N>(&self, (x, y): (RowMut<'_, T, Dim<'N>>, RowMut<'_, T, Dim<'N>>)) {
				fn with_simd<S: pulp::Simd>(self, simd: S) -> Self::Output {
/// apply from the left to $x$ and $y$
	pub fn apply_on_the_left_in_place<N: Shape>(&self, (x, y): (RowMut<'_, T, N>, RowMut<'_, T, N>)) {
/// apply from the right to $x$ and $y$
	pub fn apply_on_the_right_in_place<N: Shape>(&self, (x, y): (ColMut<'_, T, N>, ColMut<'_, T, N>)) {
	fn apply_on_the_left_in_place_fallback<'N>(&self, x: RowMut<'_, T, Dim<'N>>, y: RowMut<'_, T, Dim<'N>>) {
	pub(crate) fn apply_on_the_right_in_place_with_simd<'N, S: pulp::Simd>(
		&self,
		simd: SimdCtx<'N, T, S>,
		x: ColMut<'_, T, Dim<'N>, ContiguousFwd>,
		y: ColMut<'_, T, Dim<'N>, ContiguousFwd>,
	) {
	pub(crate) fn apply_on_the_left_in_place_with_simd<'N, S: pulp::Simd>(
		&self,
		simd: SimdCtx<'N, T, S>,
		x: RowMut<'_, T, Dim<'N>, ContiguousFwd>,
		y: RowMut<'_, T, Dim<'N>, ContiguousFwd>,
	) {
/// returns the adjoint of `self`
	pub fn adjoint(&self) -> Self {
/// returns the conjugate of `self`
	pub fn conjugate(&self) -> Self {
/// returns the transpose of `self`
	pub fn transpose(&self) -> Self {
/// kronecker product of two matrices
///
/// the kronecker product of two matrices $A$ and $B$ is a block matrix
/// $B$ with the following structure:
///
/// ```text
/// C = [ a[(0, 0)] * B    , a[(0, 1)] * B    , ... , a[(0, n-1)] * B    ]
///     [ a[(1, 0)] * B    , a[(1, 1)] * B    , ... , a[(1, n-1)] * B    ]
///     [ ...              , ...              , ... , ...              ]
///     [ a[(m-1, 0)] * B  , a[(m-1, 1)] * B  , ... , a[(m-1, n-1)] * B  ]
/// ```
///
/// # panics
///
/// panics if `dst` does not have the correct dimensions. the dimensions
/// of `dst` must be `A.nrows() * B.nrows()` by `A.ncols() * B.ncols()`.
///
/// # example
///
/// ```
/// use faer::linalg::kron::kron;
/// use faer::{Mat, mat};
///
/// let a = mat![[1.0, 2.0], [3.0, 4.0]];
/// let b = mat![[0.0, 5.0], [6.0, 7.0]];
/// let c = mat![
/// 	[0.0, 5.0, 0.0, 10.0],
/// 	[6.0, 7.0, 12.0, 14.0],
/// 	[0.0, 15.0, 0.0, 20.0],
/// 	[18.0, 21.0, 24.0, 28.0],
/// ];
/// let mut dst = Mat::zeros(4, 4);
/// kron(dst.as_mut(), a.as_ref(), b.as_ref());
/// assert_eq!(dst, c);
/// ```
pub fn kron<T: ComplexField>(dst: MatMut<'_, T>, lhs: MatRef<'_, impl Conjugate<Canonical = T>>, rhs: MatRef<'_, impl Conjugate<Canonical = T>>) {
// pull the lever kron
// SAFETY: Bounds have been checked.
// the other lever
	fn test_kron_ones() {
fn best_value<T: ComplexField, S: Simd>(
	simd: &SimdCtx<T, S>,
	best_value: RealReg<T::SimdVec<S>>,
	best_indices: T::SimdIndex<S>,
	value: T::SimdVec<S>,
	indices: T::SimdIndex<S>,
) -> (RealReg<T::SimdVec<S>>, T::SimdIndex<S>) {
fn best_score<T: ComplexField, S: Simd>(
	simd: &SimdCtx<T, S>,
	best_score: RealReg<T::SimdVec<S>>,
	best_indices: T::SimdIndex<S>,
	score: RealReg<T::SimdVec<S>>,
	indices: T::SimdIndex<S>,
) -> (RealReg<T::SimdVec<S>>, T::SimdIndex<S>) {
fn best_score_2d<T: ComplexField, S: Simd>(
	simd: &SimdCtx<T, S>,
	best_score: RealReg<T::SimdVec<S>>,
	best_row: T::SimdIndex<S>,
	best_col: T::SimdIndex<S>,
	score: RealReg<T::SimdVec<S>>,
	row: T::SimdIndex<S>,
	col: T::SimdIndex<S>,
) -> (RealReg<T::SimdVec<S>>, T::SimdIndex<S>, T::SimdIndex<S>) {
fn reduce_2d<T: ComplexField, S: Simd>(
	simd: &SimdCtx<T, S>,
	best_values: RealReg<T::SimdVec<S>>,
	best_row: T::SimdIndex<S>,
	best_col: T::SimdIndex<S>,
) -> (usize, usize, Real<T>) {
fn best_in_col_simd<'M, T: ComplexField, S: Simd>(
	simd: SimdCtx<'M, T, S>,
	data: ColRef<'_, T, Dim<'M>, ContiguousFwd>,
) -> (RealReg<T::SimdVec<S>>, T::SimdIndex<S>) {
fn update_and_best_in_col_simd<'M, T: ComplexField, S: Simd>(
	simd: SimdCtx<'M, T, S>,
	data: ColMut<'_, T, Dim<'M>, ContiguousFwd>,
	lhs: ColRef<'_, T, Dim<'M>, ContiguousFwd>,
	rhs: T,
) -> (RealReg<T::SimdVec<S>>, T::SimdIndex<S>) {
fn best_in_mat_simd<T: ComplexField>(data: MatRef<'_, T, usize, usize, ContiguousFwd>) -> (usize, usize, Real<T>) {
		fn with_simd<S: Simd>(self, simd: S) -> Self::Output {
fn update_and_best_in_mat_simd<T: ComplexField>(
	data: MatMut<'_, T, usize, usize, ContiguousFwd>,
	lhs: ColRef<'_, T, usize, ContiguousFwd>,
	rhs: RowRef<'_, T, usize>,
	align: usize,
) -> (usize, usize, Real<T>) {
		fn with_simd<S: Simd>(self, simd: S) -> Self::Output {
fn best_in_matrix_fallback<T: ComplexField>(data: MatRef<'_, T>) -> (usize, usize, Real<T>) {
fn best_in_matrix<T: ComplexField>(data: MatRef<'_, T>) -> (usize, usize, Real<T>) {
fn rank_one_update_and_best_in_matrix<T: ComplexField>(
	mut dst: MatMut<'_, T>,
	lhs: ColRef<'_, T>,
	rhs: RowRef<'_, T>,
	align: usize,
) -> (usize, usize, Real<T>) {
fn lu_in_place_unblocked<T: ComplexField>(
	A: MatMut<'_, T>,
	row_trans: &mut [usize],
	col_trans: &mut [usize],
	par: Par,
	transpose: bool,
	params: Spec<FullPivLuParams, T>,
) -> usize {
/// $LU$ factorization tuning parameters
/// threshold at which size parallelism should be disabled
	fn auto() -> Self {
pub fn lu_in_place_scratch<I: Index, T: ComplexField>(nrows: usize, ncols: usize, par: Par, params: Spec<FullPivLuParams, T>) -> StackReq {
pub fn lu_in_place<'out, I: Index, T: ComplexField>(
	mat: MatMut<'_, T>,
	row_perm: &'out mut [I],
	row_perm_inv: &'out mut [I],
	col_perm: &'out mut [I],
	col_perm_inv: &'out mut [I],
	par: Par,
	stack: &mut MemStack,
	params: Spec<FullPivLuParams, T>,
) -> (FullPivLuInfo, PermRef<'out, I>, PermRef<'out, I>) {
	fn test_flu() {
	fn test_gh238() {
pub fn inverse_scratch<I: Index, T: ComplexField>(dim: usize, par: Par) -> StackReq {
pub fn inverse<I: Index, T: ComplexField>(
	out: MatMut<'_, T>,
	L: MatRef<'_, T>,
	U: MatRef<'_, T>,
	row_perm: PermRef<'_, I>,
	col_perm: PermRef<'_, I>,
	par: Par,
	stack: &mut MemStack,
) {
// A = P^-1 L U Q
// A^-1 = Q^-1 U^-1 L^-1 P
	fn test_inverse() {
//! the full pivoting $LU$ decomposition is such that:
//! $$P A Q^\top = LU$$
//! where $P$ and $Q$ are permutation matrices, $L$ is a unit lower triangular matrix, and $U$ is
//! an upper triangular matrix.
pub fn reconstruct_scratch<I: Index, T: ComplexField>(nrows: usize, ncols: usize, par: Par) -> StackReq {
pub fn reconstruct<I: Index, T: ComplexField>(
	out: MatMut<'_, T>,
	L: MatRef<'_, T>,
	U: MatRef<'_, T>,
	row_perm: PermRef<'_, I>,
	col_perm: PermRef<'_, I>,
	par: Par,
	stack: &mut MemStack,
) {
	fn test_reconstruct() {
pub fn solve_in_place_scratch<I: Index, T: ComplexField>(LU_dim: usize, rhs_ncols: usize, par: Par) -> StackReq {
pub fn solve_transpose_in_place_scratch<I: Index, T: ComplexField>(LU_dim: usize, rhs_ncols: usize, par: Par) -> StackReq {
pub fn solve_in_place_with_conj<I: Index, T: ComplexField>(
	L: MatRef<'_, T>,
	U: MatRef<'_, T>,
	row_perm: PermRef<'_, I>,
	col_perm: PermRef<'_, I>,
	conj_LU: Conj,
	rhs: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
// LU = P A Q^-1
// P^-1 LU Q = A
// A^-1 = Q^-1 U^-1 L^-1 P
pub fn solve_transpose_in_place_with_conj<I: Index, T: ComplexField>(
	L: MatRef<'_, T>,
	U: MatRef<'_, T>,
	row_perm: PermRef<'_, I>,
	col_perm: PermRef<'_, I>,
	conj_LU: Conj,
	rhs: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
// LU = P A Q^-1
// A^-1 = Q^-1 U^-1 L^-1 P
// A^-T = P^-1 L^-T U^-T Q
pub fn solve_in_place<I: Index, T: ComplexField, C: Conjugate<Canonical = T>>(
	L: MatRef<'_, C>,
	U: MatRef<'_, C>,
	row_perm: PermRef<'_, I>,
	col_perm: PermRef<'_, I>,
	rhs: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
pub fn solve_transpose_in_place<I: Index, T: ComplexField, C: Conjugate<Canonical = T>>(
	L: MatRef<'_, C>,
	U: MatRef<'_, C>,
	row_perm: PermRef<'_, I>,
	col_perm: PermRef<'_, I>,
	rhs: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
	fn test_solve() {
//! low level implementation of the various $LU$ decompositions
pub(crate) fn swap_elems<T: ComplexField>(col: ColMut<'_, T>, i: usize, j: usize) {
fn lu_in_place_unblocked<I: Index, T: ComplexField>(matrix: MatMut<'_, T>, start: usize, end: usize, trans: &mut [I]) -> usize {
pub(crate) fn lu_in_place_recursion<I: Index, T: ComplexField>(
	A: MatMut<'_, T>,
	start: usize,
	end: usize,
	trans: &mut [I],
	par: Par,
	params: Spec<PartialPivLuParams, T>,
) -> usize {
/// $LU$ factorization tuning parameters
/// threshold at which the implementation should stop recursing
/// blocking variant step size
/// threshold at which size parallelism should be disabled
/// information about the resulting $LU$ factorization
/// number of transpositions that were performed, can be used to compute the determinant of
/// $P$
/// error in the $LU$ factorization
	fn auto() -> Self {
pub fn lu_in_place_scratch<I: Index, T: ComplexField>(nrows: usize, ncols: usize, par: Par, params: Spec<PartialPivLuParams, T>) -> StackReq {
pub fn lu_in_place<'out, I: Index, T: ComplexField>(
	A: MatMut<'_, T>,
	perm: &'out mut [I],
	perm_inv: &'out mut [I],
	par: Par,
	stack: &mut MemStack,
	params: Spec<PartialPivLuParams, T>,
) -> (PartialPivLuInfo, PermRef<'out, I>) {
	fn test_plu() {
pub fn inverse_scratch<I: Index, T: ComplexField>(dim: usize, par: Par) -> StackReq {
pub fn inverse<I: Index, T: ComplexField>(
	out: MatMut<'_, T>,
	L: MatRef<'_, T>,
	U: MatRef<'_, T>,
	row_perm: PermRef<'_, I>,
	par: Par,
	stack: &mut MemStack,
) {
// A = P^-1 L U
// A^-1 = U^-1 L^-1 P
	fn test_inverse() {
//! the partial pivoting $LU$ decomposition is such that:
//! $$PA = LU$$
//! where $P$ is a permutation matrix, $L$ is a unit lower triangular matrix, and $U$ is
//! an upper triangular matrix.
pub fn reconstruct_scratch<I: Index, T: ComplexField>(nrows: usize, ncols: usize, par: Par) -> StackReq {
pub fn reconstruct<I: Index, T: ComplexField>(
	out: MatMut<'_, T>,
	L: MatRef<'_, T>,
	U: MatRef<'_, T>,
	row_perm: PermRef<'_, I>,
	par: Par,
	stack: &mut MemStack,
) {
	fn test_reconstruct() {
pub fn solve_in_place_scratch<I: Index, T: ComplexField>(LU_dim: usize, rhs_ncols: usize, par: Par) -> StackReq {
pub fn solve_transpose_in_place_scratch<I: Index, T: ComplexField>(LU_dim: usize, rhs_ncols: usize, par: Par) -> StackReq {
pub fn solve_in_place_with_conj<I: Index, T: ComplexField>(
	L: MatRef<'_, T>,
	U: MatRef<'_, T>,
	row_perm: PermRef<'_, I>,
	conj_LU: Conj,
	rhs: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
// LU = PA
// P^-1 LU = A
// A^-1 = U^-1 L^-1 P
pub fn solve_transpose_in_place_with_conj<I: Index, T: ComplexField>(
	L: MatRef<'_, T>,
	U: MatRef<'_, T>,
	row_perm: PermRef<'_, I>,
	conj_LU: Conj,
	rhs: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
// LU = PA
// P^-1 LU = A
// A^-T = (U^-1 L^-1 P).T
// A^-T = P^-1 L^-T U^-T
pub fn solve_in_place<I: Index, T: ComplexField, C: Conjugate<Canonical = T>>(
	L: MatRef<'_, C>,
	U: MatRef<'_, C>,
	row_perm: PermRef<'_, I>,
	rhs: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
pub fn solve_transpose_in_place<I: Index, T: ComplexField, C: Conjugate<Canonical = T>>(
	L: MatRef<'_, C>,
	U: MatRef<'_, C>,
	row_perm: PermRef<'_, I>,
	rhs: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
	fn test_solve() {
	fn eq(&self, other: &mat::generic::Mat<R>) -> bool {
		fn imp<LT: PartialEq<RT>, RT>(l: MatRef<'_, LT>, r: MatRef<'_, RT>) -> bool {
	fn eq(&self, other: &col::generic::Col<R>) -> bool {
		fn imp<LT: PartialEq<RT>, RT>(l: ColRef<'_, LT>, r: ColRef<'_, RT>) -> bool {
	fn eq(&self, other: &row::generic::Row<R>) -> bool {
	fn eq(&self, other: &diag::generic::Diag<R>) -> bool {
	fn eq(&self, other: &perm::generic::Perm<R>) -> bool {
		fn sub_assign(&mut self, rhs: _) {
			fn imp<T: ComplexField, RT: Conjugate<Canonical = T>>(lhs: MatMut<'_, T>, rhs: MatRef<'_, RT>) {
		fn sub_assign(&mut self, rhs: _) {
			fn imp<T: ComplexField, RT: Conjugate<Canonical = T>>(lhs: ColMut<'_, T>, rhs: ColRef<'_, RT>) {
		fn sub_assign(&mut self, rhs: _) {
			fn imp<T: ComplexField, RT: Conjugate<Canonical = T>>(lhs: RowMut<'_, T>, rhs: RowRef<'_, RT>) {
		fn sub_assign(&mut self, rhs: _) {
			fn imp<T: ComplexField, RT: Conjugate<Canonical = T>>(lhs: ColMut<'_, T>, rhs: ColRef<'_, RT>) {
		fn add_assign(&mut self, rhs: _) {
			fn imp<T: ComplexField, RT: Conjugate<Canonical = T>>(lhs: MatMut<'_, T>, rhs: MatRef<'_, RT>) {
		fn add_assign(&mut self, rhs: _) {
			fn imp<T: ComplexField, RT: Conjugate<Canonical = T>>(lhs: ColMut<'_, T>, rhs: ColRef<'_, RT>) {
		fn add_assign(&mut self, rhs: _) {
			fn imp<T: ComplexField, RT: Conjugate<Canonical = T>>(lhs: RowMut<'_, T>, rhs: RowRef<'_, RT>) {
		fn add_assign(&mut self, rhs: _) {
			fn imp<T: ComplexField, RT: Conjugate<Canonical = T>>(lhs: ColMut<'_, T>, rhs: ColRef<'_, RT>) {
		fn add(self, rhs: _) {
			fn imp<T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(lhs: MatRef<'_, LT>, rhs: MatRef<'_, RT>) -> Mat<T> {
		fn add(self, rhs: _) {
			fn imp<T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(lhs: ColRef<'_, LT>, rhs: ColRef<'_, RT>) -> Col<T> {
		fn add(self, rhs: _) {
			fn imp<T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(lhs: RowRef<'_, LT>, rhs: RowRef<'_, RT>) -> Row<T> {
		fn add(self, rhs: _) {
			fn imp<T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(lhs: ColRef<'_, LT>, rhs: ColRef<'_, RT>) -> Col<T> {
		fn sub(self, rhs: _) {
			fn imp<T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(lhs: MatRef<'_, LT>, rhs: MatRef<'_, RT>) -> Mat<T> {
		fn sub(self, rhs: _) {
			fn imp<T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(lhs: ColRef<'_, LT>, rhs: ColRef<'_, RT>) -> Col<T> {
		fn sub(self, rhs: _) {
			fn imp<T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(lhs: RowRef<'_, LT>, rhs: RowRef<'_, RT>) -> Row<T> {
		fn sub(self, rhs: _) {
			fn imp<T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(lhs: ColRef<'_, LT>, rhs: ColRef<'_, RT>) -> Col<T> {
		fn neg(self) {
			fn imp<T: Conjugate>(A: MatRef<'_, T>) -> Mat<T::Canonical> {
		fn neg(self) {
			fn imp<T: Conjugate>(A: ColRef<'_, T>) -> Col<T::Canonical> {
		fn neg(self) {
			fn imp<T: Conjugate>(A: RowRef<'_, T>) -> Row<T::Canonical> {
		fn neg(self) {
			fn imp<T: Conjugate>(A: ColRef<'_, T>) -> Col<T::Canonical> {
fn add_fn<LhsT: Conjugate<Canonical: ComplexField>, RhsT: Conjugate<Canonical = LhsT::Canonical>>()
-> impl FnMut(linalg::zip::Zip<&LhsT, linalg::zip::Last<&RhsT>>) -> LhsT::Canonical {
fn sub_fn<LhsT: Conjugate<Canonical: ComplexField>, RhsT: Conjugate<Canonical = LhsT::Canonical>>()
-> impl FnMut(linalg::zip::Zip<&LhsT, linalg::zip::Last<&RhsT>>) -> LhsT::Canonical {
fn mul_fn<LhsT: Conjugate<Canonical: ComplexField>, RhsT: Conjugate<Canonical = LhsT::Canonical>>()
-> impl FnMut(linalg::zip::Zip<&LhsT, linalg::zip::Last<&RhsT>>) -> LhsT::Canonical {
fn neg_fn<LhsT: Conjugate<Canonical: ComplexField>>() -> impl FnMut(linalg::zip::Last<&LhsT>) -> LhsT::Canonical {
fn add_assign_fn<LhsT: ComplexField, RhsT: Conjugate<Canonical = LhsT>>() -> impl FnMut(linalg::zip::Zip<&mut LhsT, linalg::zip::Last<&RhsT>>) {
fn sub_assign_fn<LhsT: ComplexField, RhsT: Conjugate<Canonical = LhsT>>() -> impl FnMut(linalg::zip::Zip<&mut LhsT, linalg::zip::Last<&RhsT>>) {
			fn mul(self, rhs: _) {
				fn imp<T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(
					lhs: MatRef<'_, LT>,
					rhs: MatRef<'_, RT>,
				) -> Mat<T> {
			fn mul(self, rhs: _) {
				fn imp<T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(
					lhs: MatRef<'_, LT>,
					rhs: ColRef<'_, RT>,
				) -> Col<T> {
			fn mul(self, rhs: _) {
				fn imp<T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(
					lhs: RowRef<'_, LT>,
					rhs: MatRef<'_, RT>,
				) -> Row<T> {
			fn mul(self, rhs: _) {
				fn imp<T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(lhs: RowRef<'_, LT>, rhs: ColRef<'_, RT>) -> T {
			fn mul(self, rhs: _) {
				fn imp<T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(
					lhs: ColRef<'_, LT>,
					rhs: RowRef<'_, RT>,
				) -> Mat<T> {
			fn mul(self, rhs: _) {
				fn imp<T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(
					lhs: ColRef<'_, LT>,
					rhs: MatRef<'_, RT>,
				) -> Mat<T> {
			fn mul(self, rhs: _) {
				fn imp<T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(
					lhs: ColRef<'_, LT>,
					rhs: ColRef<'_, RT>,
				) -> Col<T> {
			fn mul(self, rhs: _) {
				fn imp<T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(
					lhs: MatRef<'_, LT>,
					rhs: ColRef<'_, RT>,
				) -> Mat<T> {
			fn mul(self, rhs: _) {
				fn imp<T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(
					lhs: RowRef<'_, LT>,
					rhs: ColRef<'_, RT>,
				) -> Row<T> {
			fn mul(self, rhs: _) {
				fn imp<T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(
					lhs: ColRef<'_, LT>,
					rhs: ColRef<'_, RT>,
				) -> Col<T> {
		fn mul(self, rhs: _) {
			fn imp<I: Index>(lhs: PermRef<'_, I>, rhs: PermRef<'_, I>) -> Perm<I> {
		fn mul(self, rhs: _) {
			fn imp<I: Index, T: ComplexField, RT: Conjugate<Canonical = T>>(lhs: PermRef<'_, I>, rhs: MatRef<'_, RT>) -> Mat<T> {
		fn mul(self, rhs: _) {
			fn imp<I: Index, T: ComplexField, RT: Conjugate<Canonical = T>>(lhs: PermRef<'_, I>, rhs: ColRef<'_, RT>) -> Col<T> {
		fn mul(self, rhs: _) {
			fn imp<I: Index, T: ComplexField, LT: Conjugate<Canonical = T>>(lhs: MatRef<'_, LT>, rhs: PermRef<'_, I>) -> Mat<T> {
		fn mul(self, rhs: _) {
			fn imp<I: Index, T: ComplexField, LT: Conjugate<Canonical = T>>(lhs: RowRef<'_, LT>, rhs: PermRef<'_, I>) -> Row<T> {
		fn mul(self, rhs: _) {
			fn imp<T: ComplexField, LT: Conjugate<Canonical = T>>(lhs: MatRef<'_, LT>, rhs: &T) -> Mat<T> {
		fn div(self, rhs: _) {
			fn imp<T: ComplexField, LT: Conjugate<Canonical = T>>(lhs: MatRef<'_, LT>, rhs: &T) -> Mat<T> {
		fn mul(self, rhs: _) {
			fn imp<T: ComplexField, RT: Conjugate<Canonical = T>>(lhs: &T, rhs: MatRef<'_, RT>) -> Mat<T> {
		fn mul(self, rhs: _) {
			fn imp<T: ComplexField, LT: Conjugate<Canonical = T>>(lhs: ColRef<'_, LT>, rhs: &T) -> Col<T> {
		fn div(self, rhs: _) {
			fn imp<T: ComplexField, LT: Conjugate<Canonical = T>>(lhs: ColRef<'_, LT>, rhs: &T) -> Col<T> {
		fn mul(self, rhs: _) {
			fn imp<T: ComplexField, RT: Conjugate<Canonical = T>>(lhs: &T, rhs: ColRef<'_, RT>) -> Col<T> {
		fn mul(self, rhs: _) {
			fn imp<T: ComplexField, LT: Conjugate<Canonical = T>>(lhs: RowRef<'_, LT>, rhs: &T) -> Row<T> {
		fn div(self, rhs: _) {
			fn imp<T: ComplexField, LT: Conjugate<Canonical = T>>(lhs: RowRef<'_, LT>, rhs: &T) -> Row<T> {
		fn mul(self, rhs: _) {
			fn imp<T: ComplexField, RT: Conjugate<Canonical = T>>(lhs: &T, rhs: RowRef<'_, RT>) -> Row<T> {
		fn mul(self, rhs: _) {
			fn imp<T: ComplexField, LT: Conjugate<Canonical = T>>(lhs: ColRef<'_, LT>, rhs: &T) -> Col<T> {
		fn div(self, rhs: _) {
			fn imp<T: ComplexField, LT: Conjugate<Canonical = T>>(lhs: ColRef<'_, LT>, rhs: &T) -> Col<T> {
		fn mul(self, rhs: _) {
			fn imp<T: ComplexField, RT: Conjugate<Canonical = T>>(lhs: &T, rhs: ColRef<'_, RT>) -> Col<T> {
		fn mul(self, rhs: _) {
			fn imp<T: ComplexField, LT: Conjugate<Canonical = T>>(lhs: MatRef<'_, LT>, rhs: &T) -> Mat<T> {
		fn div(self, rhs: _) {
			fn imp<T: ComplexField, LT: Conjugate<Canonical = T>>(lhs: MatRef<'_, LT>, rhs: &T) -> Mat<T> {
		fn mul(self, rhs: _) {
			fn imp<T: ComplexField, RT: Conjugate<Canonical = T>>(lhs: &T, rhs: MatRef<'_, RT>) -> Mat<T> {
		fn mul(self, rhs: _) {
			fn imp<T: ComplexField, LT: Conjugate<Canonical = T>>(lhs: ColRef<'_, LT>, rhs: &T) -> Col<T> {
		fn div(self, rhs: _) {
			fn imp<T: ComplexField, LT: Conjugate<Canonical = T>>(lhs: ColRef<'_, LT>, rhs: &T) -> Col<T> {
		fn mul(self, rhs: _) {
			fn imp<T: ComplexField, RT: Conjugate<Canonical = T>>(lhs: &T, rhs: ColRef<'_, RT>) -> Col<T> {
		fn mul(self, rhs: _) {
			fn imp<T: ComplexField, LT: Conjugate<Canonical = T>>(lhs: RowRef<'_, LT>, rhs: &T) -> Row<T> {
		fn div(self, rhs: _) {
			fn imp<T: ComplexField, LT: Conjugate<Canonical = T>>(lhs: RowRef<'_, LT>, rhs: &T) -> Row<T> {
		fn mul(self, rhs: _) {
			fn imp<T: ComplexField, RT: Conjugate<Canonical = T>>(lhs: &T, rhs: RowRef<'_, RT>) -> Row<T> {
		fn mul(self, rhs: _) {
			fn imp<T: ComplexField, LT: Conjugate<Canonical = T>>(lhs: ColRef<'_, LT>, rhs: &T) -> Col<T> {
		fn div(self, rhs: _) {
			fn imp<T: ComplexField, LT: Conjugate<Canonical = T>>(lhs: ColRef<'_, LT>, rhs: &T) -> Col<T> {
		fn mul(self, rhs: _) {
			fn imp<T: ComplexField, RT: Conjugate<Canonical = T>>(lhs: &T, rhs: ColRef<'_, RT>) -> Col<T> {
		fn mul_assign(&mut self, rhs: _) {
			fn imp<T: ComplexField>(lhs: MatMut<'_, T>, rhs: &T) {
		fn div_assign(&mut self, rhs: _) {
			fn imp<T: ComplexField>(mut lhs: MatMut<'_, T>, rhs: &T) {
		fn mul_assign(&mut self, rhs: _) {
			fn imp<T: ComplexField>(lhs: ColMut<'_, T>, rhs: &T) {
		fn div_assign(&mut self, rhs: _) {
			fn imp<T: ComplexField>(mut lhs: ColMut<'_, T>, rhs: &T) {
		fn mul_assign(&mut self, rhs: _) {
			fn imp<T: ComplexField>(lhs: RowMut<'_, T>, rhs: &T) {
		fn div_assign(&mut self, rhs: _) {
			fn imp<T: ComplexField>(mut lhs: RowMut<'_, T>, rhs: &T) {
		fn mul_assign(&mut self, rhs: _) {
			fn imp<T: ComplexField>(mut lhs: ColMut<'_, T>, rhs: &T) {
		fn div_assign(&mut self, rhs: _) {
			fn imp<T: ComplexField>(mut lhs: ColMut<'_, T>, rhs: &T) {
		fn mul_assign(&mut self, rhs: _) {
			fn imp<T: ComplexField>(lhs: MatMut<'_, T>, rhs: &T) {
		fn div_assign(&mut self, rhs: _) {
			fn imp<T: ComplexField>(mut lhs: MatMut<'_, T>, rhs: &T) {
		fn mul_assign(&mut self, rhs: _) {
			fn imp<T: ComplexField>(lhs: ColMut<'_, T>, rhs: &T) {
		fn div_assign(&mut self, rhs: _) {
			fn imp<T: ComplexField>(mut lhs: ColMut<'_, T>, rhs: &T) {
		fn mul_assign(&mut self, rhs: _) {
			fn imp<T: ComplexField>(lhs: RowMut<'_, T>, rhs: &T) {
		fn div_assign(&mut self, rhs: _) {
			fn imp<T: ComplexField>(mut lhs: RowMut<'_, T>, rhs: &T) {
		fn mul_assign(&mut self, rhs: _) {
			fn imp<T: ComplexField>(mut lhs: ColMut<'_, T>, rhs: &T) {
		fn div_assign(&mut self, rhs: _) {
			fn imp<T: ComplexField>(mut lhs: ColMut<'_, T>, rhs: &T) {
			fn mul(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, RT: Conjugate<Canonical = T>>(lhs: &T, rhs: SparseRowMatRef<'_, I, RT>) -> SparseRowMat<I, T> {
			fn mul(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, RT: Conjugate<Canonical = T>>(lhs: &T, rhs: SparseColMatRef<'_, I, RT>) -> SparseColMat<I, T> {
			fn mul(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, LT: Conjugate<Canonical = T>>(rhs: &T, lhs: SparseRowMatRef<'_, I, LT>) -> SparseRowMat<I, T> {
			fn mul(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, LT: Conjugate<Canonical = T>>(rhs: &T, lhs: SparseColMatRef<'_, I, LT>) -> SparseColMat<I, T> {
			fn div(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, LT: Conjugate<Canonical = T>>(rhs: &T, lhs: SparseRowMatRef<'_, I, LT>) -> SparseRowMat<I, T> {
			fn div(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, LT: Conjugate<Canonical = T>>(rhs: &T, lhs: SparseColMatRef<'_, I, LT>) -> SparseColMat<I, T> {
			fn mul_assign(&mut self, rhs: _) {
				fn imp<I: Index, T: ComplexField>(rhs: &T, lhs: SparseRowMatMut<'_, I, T>) {
			fn mul_assign(&mut self, rhs: _) {
				fn imp<I: Index, T: ComplexField>(rhs: &T, lhs: SparseColMatMut<'_, I, T>) {
			fn div_assign(&mut self, rhs: _) {
				fn imp<I: Index, T: ComplexField>(rhs: &T, lhs: SparseRowMatMut<'_, I, T>) {
			fn div_assign(&mut self, rhs: _) {
				fn imp<I: Index, T: ComplexField>(rhs: &T, lhs: SparseColMatMut<'_, I, T>) {
			fn mul(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, RT: Conjugate<Canonical = T>>(lhs: &T, rhs: SparseRowMatRef<'_, I, RT>) -> SparseRowMat<I, T> {
			fn mul(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, RT: Conjugate<Canonical = T>>(lhs: &T, rhs: SparseColMatRef<'_, I, RT>) -> SparseColMat<I, T> {
			fn mul(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, LT: Conjugate<Canonical = T>>(rhs: &T, lhs: SparseRowMatRef<'_, I, LT>) -> SparseRowMat<I, T> {
			fn mul(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, LT: Conjugate<Canonical = T>>(rhs: &T, lhs: SparseColMatRef<'_, I, LT>) -> SparseColMat<I, T> {
			fn div(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, LT: Conjugate<Canonical = T>>(rhs: &T, lhs: SparseRowMatRef<'_, I, LT>) -> SparseRowMat<I, T> {
			fn div(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, LT: Conjugate<Canonical = T>>(rhs: &T, lhs: SparseColMatRef<'_, I, LT>) -> SparseColMat<I, T> {
			fn mul_assign(&mut self, rhs: _) {
				fn imp<I: Index, T: ComplexField>(rhs: &T, lhs: SparseRowMatMut<'_, I, T>) {
			fn mul_assign(&mut self, rhs: _) {
				fn imp<I: Index, T: ComplexField>(rhs: &T, lhs: SparseColMatMut<'_, I, T>) {
			fn div_assign(&mut self, rhs: _) {
				fn imp<I: Index, T: ComplexField>(rhs: &T, lhs: SparseRowMatMut<'_, I, T>) {
			fn div_assign(&mut self, rhs: _) {
				fn imp<I: Index, T: ComplexField>(rhs: &T, lhs: SparseColMatMut<'_, I, T>) {
			fn neg(self) {
			fn neg(self) {
				fn imp<I: Index, T: Conjugate>(A: SparseColMatRef<'_, I, T>) -> SparseColMat<I, T::Canonical> {
			fn add_assign(&mut self, rhs: _) {
				fn imp<I: Index, T: ComplexField, RT: Conjugate<Canonical = T>>(lhs: SparseColMatMut<'_, I, T>, rhs: SparseColMatRef<'_, I, RT>) {
			fn sub_assign(&mut self, rhs: _) {
				fn imp<I: Index, T: ComplexField, RT: Conjugate<Canonical = T>>(lhs: SparseColMatMut<'_, I, T>, rhs: SparseColMatRef<'_, I, RT>) {
			fn add_assign(&mut self, rhs: _) {
				fn imp<I: Index, T: ComplexField, RT: Conjugate<Canonical = T>>(lhs: SparseRowMatMut<'_, I, T>, rhs: SparseRowMatRef<'_, I, RT>) {
			fn sub_assign(&mut self, rhs: _) {
				fn imp<I: Index, T: ComplexField, RT: Conjugate<Canonical = T>>(lhs: SparseRowMatMut<'_, I, T>, rhs: SparseRowMatRef<'_, I, RT>) {
			fn add(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(
					lhs: SparseColMatRef<'_, I, LT>,
					rhs: SparseColMatRef<'_, I, RT>,
				) -> SparseColMat<I, T> {
			fn sub(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(
					lhs: SparseColMatRef<'_, I, LT>,
					rhs: SparseColMatRef<'_, I, RT>,
				) -> SparseColMat<I, T> {
			fn add(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(
					lhs: SparseRowMatRef<'_, I, LT>,
					rhs: SparseRowMatRef<'_, I, RT>,
				) -> SparseRowMat<I, T> {
			fn sub(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(
					lhs: SparseRowMatRef<'_, I, LT>,
					rhs: SparseRowMatRef<'_, I, RT>,
				) -> SparseRowMat<I, T> {
			fn mul(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(
					lhs: SparseColMatRef<'_, I, LT>,
					rhs: SparseColMatRef<'_, I, RT>,
				) -> SparseColMat<I, T> {
			fn mul(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(
					lhs: SparseRowMatRef<'_, I, LT>,
					rhs: SparseRowMatRef<'_, I, RT>,
				) -> SparseRowMat<I, T> {
			fn mul(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(
					lhs: SparseColMatRef<'_, I, LT>,
					rhs: MatRef<'_, RT>,
				) -> Mat<T> {
			fn mul(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(
					lhs: SparseRowMatRef<'_, I, LT>,
					rhs: MatRef<'_, RT>,
				) -> Mat<T> {
			fn mul(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(
					lhs: SparseColMatRef<'_, I, LT>,
					rhs: ColRef<'_, RT>,
				) -> Col<T> {
			fn mul(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(
					lhs: SparseRowMatRef<'_, I, LT>,
					rhs: ColRef<'_, RT>,
				) -> Col<T> {
			fn mul(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(
					lhs: SparseColMatRef<'_, I, LT>,
					rhs: DiagRef<'_, RT>,
				) -> SparseColMat<I, T> {
			fn mul(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(
					lhs: SparseRowMatRef<'_, I, LT>,
					rhs: DiagRef<'_, RT>,
				) -> SparseRowMat<I, T> {
			fn mul(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, LT: Conjugate<Canonical = T>>(
					lhs: SparseColMatRef<'_, I, LT>,
					rhs: PermRef<'_, I>,
				) -> SparseColMat<I, T> {
			fn mul(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, LT: Conjugate<Canonical = T>>(
					lhs: SparseRowMatRef<'_, I, LT>,
					rhs: PermRef<'_, I>,
				) -> SparseRowMat<I, T> {
			fn mul(self, rhs: _) {
			fn mul(self, rhs: _) {
			fn mul(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(
					lhs: DiagRef<'_, LT>,
					rhs: SparseColMatRef<'_, I, RT>,
				) -> SparseColMat<I, T> {
			fn mul(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(
					lhs: DiagRef<'_, LT>,
					rhs: SparseRowMatRef<'_, I, RT>,
				) -> SparseRowMat<I, T> {
			fn mul(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(
					lhs: MatRef<'_, LT>,
					rhs: SparseColMatRef<'_, I, RT>,
				) -> Mat<T> {
			fn mul(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(
					lhs: MatRef<'_, LT>,
					rhs: SparseRowMatRef<'_, I, RT>,
				) -> Mat<T> {
			fn mul(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(
					lhs: RowRef<'_, LT>,
					rhs: SparseColMatRef<'_, I, RT>,
				) -> Row<T> {
			fn mul(self, rhs: _) {
				fn imp<I: Index, T: ComplexField, LT: Conjugate<Canonical = T>, RT: Conjugate<Canonical = T>>(
					lhs: RowRef<'_, LT>,
					rhs: SparseRowMatRef<'_, I, RT>,
				) -> Row<T> {
	fn add_fn<T: ComplexField, LhsT: Conjugate<Canonical = T>, RhsT: Conjugate<Canonical = T>>(lhs: Option<&LhsT>, rhs: Option<&RhsT>) -> T {
	fn sub_fn<T: ComplexField, LhsT: Conjugate<Canonical = T>, RhsT: Conjugate<Canonical = T>>(lhs: Option<&LhsT>, rhs: Option<&RhsT>) -> T {
	fn add_assign_fn<T: ComplexField, RhsT: Conjugate<Canonical = T>>(dst: &mut T, rhs: Option<&RhsT>) {
	fn sub_assign_fn<T: ComplexField, RhsT: Conjugate<Canonical = T>>(dst: &mut T, rhs: Option<&RhsT>) {
	fn matrices() -> (Mat<f64>, Mat<f64>) {
	fn rows() -> (Row<f64>, Row<f64>) {
	fn cols() -> (Col<f64>, Col<f64>) {
	fn test_adding_matrices_of_different_sizes_should_panic() {
	fn test_subtracting_two_matrices_of_different_sizes_should_panic() {
	fn test_matrix_add() {
	fn test_row_add() {
	fn test_col_add() {
	fn test_matrix_sub() {
	fn test_row_sub() {
	fn test_col_sub() {
	fn test_neg() {
	fn test_scalar_mul() {
	fn test_diag_mul() {
	fn test_perm_mul() {
	fn test_matmul_col_row() {
// outer product
// inner product
	fn assert_row_approx_eq(given: Row<f64>, expected: &Row<f64>) {
	fn assert_col_approx_eq(given: Col<f64>, expected: &Col<f64>) {
	fn assert_matrix_approx_eq(given: Mat<f64>, expected: &Mat<f64>) {
pub fn has_spicy_matmul<T: ComplexField>() -> bool {
pub fn spicy_matmul_scratch<T: ComplexField>(nrows: usize, ncols: usize, depth: usize, gather: bool, diag: bool) -> StackReq {
pub fn spicy_matmul<I: Index, T: ComplexField>(
	C: MatMut<'_, T>,
	C_block: BlockStructure,
	row_idx: Option<&[I]>,
	col_idx: Option<&[I]>,
	beta: Accum,

	A: MatRef<'_, T>,
	conj_A: Conj,

	B: MatRef<'_, T>,
	conj_B: Conj,

	D: Option<DiagRef<'_, T>>,
	alpha: T,

	par: Par,

	stack: &mut MemStack,
) {
//! matrix multiplication
/// triangular matrix multiplication module, where some of the operands are treated as triangular
/// matrices
		fn with_simd<S: Simd>(self, simd: S) -> Self::Output {
		fn with_simd<S: Simd>(self, simd: S) -> Self::Output {
	pub fn matmul_simd<'M, 'N, 'K, T: ComplexField>(
		dst: MatMut<'_, T, Dim<'M>, Dim<'N>, ContiguousFwd>,
		beta: Accum,
		lhs: MatRef<'_, T, Dim<'M>, Dim<'K>, ContiguousFwd>,
		conj_lhs: Conj,
		rhs: MatRef<'_, T, Dim<'K>, Dim<'N>>,
		conj_rhs: Conj,
		alpha: &T,
		par: Par,
	) {
		fn with_simd<S: Simd>(self, simd: S) -> Self::Output {
	pub fn matmul_simd<'M, 'N, 'K, T: ComplexField>(
		dst: MatMut<'_, T, Dim<'M>, Dim<'N>>,
		beta: Accum,
		lhs: MatRef<'_, T, Dim<'M>, Dim<'K>, isize, ContiguousFwd>,
		conj_lhs: Conj,
		rhs: MatRef<'_, T, Dim<'K>, Dim<'N>, ContiguousFwd, isize>,
		conj_rhs: Conj,
		alpha: &T,
		par: Par,
	) {
/// dot product
/// returns `lhs * rhs`, implicitly conjugating the operands if needed
	pub fn inner_prod<K: Shape, T: ComplexField>(lhs: RowRef<T, K>, conj_lhs: Conj, rhs: ColRef<T, K>, conj_rhs: Conj) -> T {
		pub fn imp<'K, T: ComplexField>(lhs: RowRef<T, Dim<'K>>, conj_lhs: Conj, rhs: ColRef<T, Dim<'K>>, conj_rhs: Conj) -> T {
	fn inner_prod_slice<'K, T: ComplexField>(
		len: Dim<'K>,
		lhs: ColRef<'_, T, Dim<'K>, ContiguousFwd>,
		conj_lhs: Conj,
		rhs: ColRef<'_, T, Dim<'K>, ContiguousFwd>,
		conj_rhs: Conj,
	) -> T {
			fn with_simd<S: Simd>(self, simd: S) -> Self::Output {
	pub(crate) fn inner_prod_no_conj_simd<'K, T: ComplexField, S: Simd>(
		simd: SimdCtx<'K, T, S>,
		lhs: ColRef<'_, T, Dim<'K>, ContiguousFwd>,
		rhs: ColRef<'_, T, Dim<'K>, ContiguousFwd>,
	) -> T {
	pub(crate) fn inner_prod_conj_lhs_simd<'K, T: ComplexField, S: Simd>(
		simd: SimdCtx<'K, T, S>,
		lhs: ColRef<'_, T, Dim<'K>, ContiguousFwd>,
		rhs: ColRef<'_, T, Dim<'K>, ContiguousFwd>,
	) -> T {
	pub(crate) fn inner_prod_schoolbook<'K, T: ComplexField>(
		lhs: RowRef<'_, T, Dim<'K>>,
		conj_lhs: Conj,
		rhs: ColRef<'_, T, Dim<'K>>,
		conj_rhs: Conj,
	) -> T {
	pub fn matvec<'M, 'K, T: ComplexField>(
		dst: ColMut<'_, T, Dim<'M>>,
		beta: Accum,
		lhs: MatRef<'_, T, Dim<'M>, Dim<'K>, isize, ContiguousFwd>,
		conj_lhs: Conj,
		rhs: ColRef<'_, T, Dim<'K>, ContiguousFwd>,
		conj_rhs: Conj,
		alpha: &T,
		par: Par,
	) {
					fn with_simd<S: Simd>(self, simd: S) -> Self::Output {
	pub fn matvec<'M, 'K, T: ComplexField>(
		dst: ColMut<'_, T, Dim<'M>, ContiguousFwd>,
		beta: Accum,
		lhs: MatRef<'_, T, Dim<'M>, Dim<'K>, ContiguousFwd, isize>,
		conj_lhs: Conj,
		rhs: ColRef<'_, T, Dim<'K>>,
		conj_rhs: Conj,
		alpha: &T,
		par: Par,
	) {
					fn with_simd<S: Simd>(self, simd: S) -> Self::Output {
	fn rank_update_imp<'M, 'N, T: ComplexField>(
		dst: MatMut<'_, T, Dim<'M>, Dim<'N>, ContiguousFwd>,
		beta: Accum,
		lhs: ColRef<'_, T, Dim<'M>, ContiguousFwd>,
		conj_lhs: Conj,
		rhs: RowRef<'_, T, Dim<'N>>,
		conj_rhs: Conj,
		alpha: &T,
	) {
			fn with_simd<S: Simd>(self, simd: S) -> Self::Output {
	pub fn rank_update<'M, 'N, T: ComplexField>(
		dst: MatMut<'_, T, Dim<'M>, Dim<'N>, ContiguousFwd>,
		beta: Accum,
		lhs: ColRef<'_, T, Dim<'M>, ContiguousFwd>,
		conj_lhs: Conj,
		rhs: RowRef<'_, T, Dim<'N>>,
		conj_rhs: Conj,
		alpha: &T,
		par: Par,
	) {
fn matmul_imp<'M, 'N, 'K, T: ComplexField>(
	dst: MatMut<'_, T, Dim<'M>, Dim<'N>>,
	beta: Accum,
	lhs: MatRef<'_, T, Dim<'M>, Dim<'K>>,
	conj_lhs: Conj,
	rhs: MatRef<'_, T, Dim<'K>, Dim<'N>>,
	conj_rhs: Conj,
	alpha: &T,
	par: Par,
) {
fn precondition<M: Shape, N: Shape, K: Shape>(dst_nrows: M, dst_ncols: N, lhs_nrows: M, lhs_ncols: K, rhs_nrows: K, rhs_ncols: N) {
/// computes the matrix product `[beta * acc] + alpha * lhs * rhs` and stores the result in `acc`
///
/// performs the operation:
/// - `acc = alpha * lhs * rhs` if `beta` is `Accum::Replace` (in this case, the preexisting
/// values in `acc` are not read)
/// - `acc = acc + alpha * lhs * rhs` if `beta` is `Accum::Add`
///
/// # panics
///
/// panics if the matrix dimensions are not compatible for matrix multiplication.
/// i.e.  
///  - `acc.nrows() == lhs.nrows()`
///  - `acc.ncols() == rhs.ncols()`
///  - `lhs.ncols() == rhs.nrows()`
///
/// # Example
///
/// ```
/// use faer::linalg::matmul::matmul;
/// use faer::{Accum, Conj, Mat, Par, mat, unzip, zip};
///
/// let lhs = mat![[0.0, 2.0], [1.0, 3.0]];
/// let rhs = mat![[4.0, 6.0], [5.0, 7.0]];
///
/// let mut acc = Mat::<f64>::zeros(2, 2);
/// let target = mat![
/// 	[
/// 		2.5 * (lhs[(0, 0)] * rhs[(0, 0)] + lhs[(0, 1)] * rhs[(1, 0)]),
/// 		2.5 * (lhs[(0, 0)] * rhs[(0, 1)] + lhs[(0, 1)] * rhs[(1, 1)]),
/// 	],
/// 	[
/// 		2.5 * (lhs[(1, 0)] * rhs[(0, 0)] + lhs[(1, 1)] * rhs[(1, 0)]),
/// 		2.5 * (lhs[(1, 0)] * rhs[(0, 1)] + lhs[(1, 1)] * rhs[(1, 1)]),
/// 	],
/// ];
///
/// matmul(&mut acc, Accum::Replace, &lhs, &rhs, 2.5, Par::Seq);
///
/// zip!(&acc, &target).for_each(|unzip!(acc, target)| assert!((acc - target).abs() < 1e-10));
/// ```
pub fn matmul<T: ComplexField, LhsT: Conjugate<Canonical = T>, RhsT: Conjugate<Canonical = T>, M: Shape, N: Shape, K: Shape>(
	dst: impl AsMatMut<T = T, Rows = M, Cols = N>,
	beta: Accum,
	lhs: impl AsMatRef<T = LhsT, Rows = M, Cols = K>,
	rhs: impl AsMatRef<T = RhsT, Rows = K, Cols = N>,
	alpha: T,
	par: Par,
) {
/// computes the matrix product `[beta * acc] + alpha * lhs * rhs` (implicitly conjugating the
/// operands if needed) and stores the result in `acc`
///
/// performs the operation:
/// - `acc = alpha * lhs * rhs` if `beta` is `Accum::Replace` (in this case, the preexisting
/// values in `acc` are not read)
/// - `acc = acc + alpha * lhs * rhs` if `beta` is `Accum::Add`
///
/// # panics
///
/// panics if the matrix dimensions are not compatible for matrix multiplication.
/// i.e.  
///  - `acc.nrows() == lhs.nrows()`
///  - `acc.ncols() == rhs.ncols()`
///  - `lhs.ncols() == rhs.nrows()`
///
/// # example
///
/// ```
/// use faer::linalg::matmul::matmul_with_conj;
/// use faer::{Accum, Conj, Mat, Par, mat, unzip, zip};
///
/// let lhs = mat![[0.0, 2.0], [1.0, 3.0]];
/// let rhs = mat![[4.0, 6.0], [5.0, 7.0]];
///
/// let mut acc = Mat::<f64>::zeros(2, 2);
/// let target = mat![
/// 	[
/// 		2.5 * (lhs[(0, 0)] * rhs[(0, 0)] + lhs[(0, 1)] * rhs[(1, 0)]),
/// 		2.5 * (lhs[(0, 0)] * rhs[(0, 1)] + lhs[(0, 1)] * rhs[(1, 1)]),
/// 	],
/// 	[
/// 		2.5 * (lhs[(1, 0)] * rhs[(0, 0)] + lhs[(1, 1)] * rhs[(1, 0)]),
/// 		2.5 * (lhs[(1, 0)] * rhs[(0, 1)] + lhs[(1, 1)] * rhs[(1, 1)]),
/// 	],
/// ];
///
/// matmul_with_conj(
/// 	&mut acc,
/// 	Accum::Replace,
/// 	&lhs,
/// 	Conj::No,
/// 	&rhs,
/// 	Conj::No,
/// 	2.5,
/// 	Par::Seq,
/// );
///
/// zip!(&acc, &target).for_each(|unzip!(acc, target)| assert!((acc - target).abs() < 1e-10));
/// ```
pub fn matmul_with_conj<T: ComplexField, M: Shape, N: Shape, K: Shape>(
	dst: impl AsMatMut<T = T, Rows = M, Cols = N>,
	beta: Accum,
	lhs: impl AsMatRef<T = T, Rows = M, Cols = K>,
	conj_lhs: Conj,
	rhs: impl AsMatRef<T = T, Rows = K, Cols = N>,
	conj_rhs: Conj,
	alpha: T,
	par: Par,
) {
	fn test_matmul() {
// too big for CI
	fn matmul_with_conj_fallback<T: Copy + ComplexField>(
		acc: MatMut<'_, T>,
		a: MatRef<'_, T>,
		conj_a: Conj,
		b: MatRef<'_, T>,
		conj_b: Conj,
		beta: Accum,
		alpha: T,
	) {
	fn test_matmul_impl(
		reverse_acc_cols: bool,
		reverse_acc_rows: bool,
		acc_colmajor: bool,
		m: usize,
		n: usize,
		conj_a: Conj,
		conj_b: Conj,
		par: Par,
		beta: Accum,
		alpha: c32,
		acc_init: MatMut<c32>,
		a: MatRef<c32>,
		b: MatRef<c32>,
	) {
	fn generate_structured_matrix(is_dst: bool, nrows: usize, ncols: usize, structure: BlockStructure) -> Mat<f64> {
	fn run_test_problem(m: usize, n: usize, k: usize, dst_structure: BlockStructure, lhs_structure: BlockStructure, rhs_structure: BlockStructure) {
	fn test_triangular() {
fn pointer_offset<T>(ptr: *const T) -> usize {
fn copy_lower<'N, T: ComplexField>(dst: MatMut<'_, T, Dim<'N>, Dim<'N>>, src: MatRef<'_, T, Dim<'N>, Dim<'N>>, src_diag: DiagonalKind) {
fn accum_lower<'N, T: ComplexField>(dst: MatMut<'_, T, Dim<'N>, Dim<'N>>, src: MatRef<'_, T, Dim<'N>, Dim<'N>>, skip_diag: bool, beta: Accum) {
fn copy_upper<'N, T: ComplexField>(dst: MatMut<'_, T, Dim<'N>, Dim<'N>>, src: MatRef<'_, T, Dim<'N>, Dim<'N>>, src_diag: DiagonalKind) {
fn mat_x_lower_impl_unchecked<'M, 'N, T: ComplexField>(
	dst: MatMut<'_, T, Dim<'M>, Dim<'N>>,
	beta: Accum,
	lhs: MatRef<'_, T, Dim<'M>, Dim<'N>>,
	rhs: MatRef<'_, T, Dim<'N>, Dim<'N>>,
	rhs_diag: DiagonalKind,
	alpha: &T,
	conj_lhs: Conj,
	conj_rhs: Conj,
	par: Par,
) {
// split rhs into 3 sections
// split lhs and dst into 2 sections
fn lower_x_lower_into_lower_impl_unchecked<'N, T: ComplexField>(
	dst: MatMut<'_, T, Dim<'N>, Dim<'N>>,
	beta: Accum,
	skip_diag: bool,
	lhs: MatRef<'_, T, Dim<'N>, Dim<'N>>,
	lhs_diag: DiagonalKind,
	rhs: MatRef<'_, T, Dim<'N>, Dim<'N>>,
	rhs_diag: DiagonalKind,
	alpha: &T,
	conj_lhs: Conj,
	conj_rhs: Conj,
	par: Par,
) {
// lhs_top_left  × rhs_top_left  => dst_top_left  | low × low => low |   X
// lhs_bot_left  × rhs_top_left  => dst_bot_left  | mat × low => mat | 1/2
// lhs_bot_right × rhs_bot_left  => dst_bot_left  | low × mat => mat | 1/2
// lhs_bot_right × rhs_bot_right => dst_bot_right | low × low => low |   X
fn upper_x_lower_impl_unchecked<'N, T: ComplexField>(
	dst: MatMut<'_, T, Dim<'N>, Dim<'N>>,
	beta: Accum,
	lhs: MatRef<'_, T, Dim<'N>, Dim<'N>>,
	lhs_diag: DiagonalKind,
	rhs: MatRef<'_, T, Dim<'N>, Dim<'N>>,
	rhs_diag: DiagonalKind,
	alpha: &T,
	conj_lhs: Conj,
	conj_rhs: Conj,
	par: Par,
) {
// lhs_top_right × rhs_bot_left  => dst_top_left  | mat × mat => mat |   1
// lhs_top_left  × rhs_top_left  => dst_top_left  | upp × low => mat |   X
//
// lhs_top_right × rhs_bot_right => dst_top_right | mat × low => mat | 1/2
// lhs_bot_right × rhs_bot_left  => dst_bot_left  | upp × mat => mat | 1/2
// lhs_bot_right × rhs_bot_right => dst_bot_right | upp × low => mat |   X
fn upper_x_lower_into_lower_impl_unchecked<'N, T: ComplexField>(
	dst: MatMut<'_, T, Dim<'N>, Dim<'N>>,
	beta: Accum,
	skip_diag: bool,
	lhs: MatRef<'_, T, Dim<'N>, Dim<'N>>,
	lhs_diag: DiagonalKind,
	rhs: MatRef<'_, T, Dim<'N>, Dim<'N>>,
	rhs_diag: DiagonalKind,
	alpha: &T,
	conj_lhs: Conj,
	conj_rhs: Conj,
	par: Par,
) {
// lhs_top_left  × rhs_top_left  => dst_top_left  | upp × low => low |   X
// lhs_top_right × rhs_bot_left  => dst_top_left  | mat × mat => low | 1/2
//
// lhs_bot_right × rhs_bot_left  => dst_bot_left  | upp × mat => mat | 1/2
// lhs_bot_right × rhs_bot_right => dst_bot_right | upp × low => low |   X
fn mat_x_mat_into_lower_impl_unchecked<'N, 'K, T: ComplexField>(
	dst: MatMut<'_, T, Dim<'N>, Dim<'N>>,
	beta: Accum,
	skip_diag: bool,
	lhs: MatRef<'_, T, Dim<'N>, Dim<'K>>,
	rhs: MatRef<'_, T, Dim<'K>, Dim<'N>>,
	alpha: &T,
	conj_lhs: Conj,
	conj_rhs: Conj,
	par: Par,
) {
fn mat_x_lower_into_lower_impl_unchecked<'N, T: ComplexField>(
	dst: MatMut<'_, T, Dim<'N>, Dim<'N>>,
	beta: Accum,
	skip_diag: bool,
	lhs: MatRef<'_, T, Dim<'N>, Dim<'N>>,
	rhs: MatRef<'_, T, Dim<'N>, Dim<'N>>,
	rhs_diag: DiagonalKind,
	alpha: &T,
	conj_lhs: Conj,
	conj_rhs: Conj,
	par: Par,
) {
// lhs_bot_right × rhs_bot_left  => dst_bot_left  | mat × mat => mat |   1
// lhs_bot_right × rhs_bot_right => dst_bot_right | mat × low => low |   X
//
// lhs_top_left  × rhs_top_left  => dst_top_left  | mat × low => low |   X
// lhs_top_right × rhs_bot_left  => dst_top_left  | mat × mat => low | 1/2
// lhs_bot_left  × rhs_top_left  => dst_bot_left  | mat × low => mat | 1/2
/// describes the parts of the matrix that must be accessed.
/// the full matrix is accessed.
/// the lower triangular half (including the diagonal) is accessed.
/// the lower triangular half (excluding the diagonal) is accessed.
/// the lower triangular half (excluding the diagonal, which is assumed to be equal to
/// `1.0`) is accessed.
/// the upper triangular half (including the diagonal) is accessed.
/// the upper triangular half (excluding the diagonal) is accessed.
/// the upper triangular half (excluding the diagonal, which is assumed to be equal to
/// `1.0`) is accessed.
/// checks if `self` is full.
	pub fn is_dense(self) -> bool {
/// checks if `self` is triangular lower (either inclusive or exclusive).
	pub fn is_lower(self) -> bool {
/// checks if `self` is triangular upper (either inclusive or exclusive).
	pub fn is_upper(self) -> bool {
/// returns the block structure corresponding to the transposed matrix.
	pub fn transpose(self) -> Self {
	pub(crate) fn diag_kind(self) -> DiagonalKind {
fn precondition<M: Shape, N: Shape, K: Shape>(
	dst_nrows: M,
	dst_ncols: N,
	dst_structure: BlockStructure,
	lhs_nrows: M,
	lhs_ncols: K,
	lhs_structure: BlockStructure,
	rhs_nrows: K,
	rhs_ncols: N,
	rhs_structure: BlockStructure,
) {
/// computes the matrix product `[beta * acc] + alpha * lhs * rhs` (implicitly conjugating the
/// operands if needed) and stores the result in `acc`
///
/// performs the operation:
/// - `acc = alpha * lhs * rhs` if `beta` is `accum::replace` (in this case, the preexisting
/// values in `acc` are not read)
/// - `acc = acc + alpha * lhs * rhs` if `beta` is `accum::add`
///
/// the left hand side and right hand side may be interpreted as triangular depending on the
/// given corresponding matrix structure.
///
/// for the destination matrix, the result is:
/// - fully computed if the structure is rectangular,
/// - only the triangular half (including the diagonal) is computed if the structure is
/// triangular
/// - only the strict triangular half (excluding the diagonal) is computed if the structure is
/// strictly triangular or unit triangular
///
/// # panics
///
/// panics if the matrix dimensions are not compatible for matrix multiplication.
/// i.e.  
///  - `acc.nrows() == lhs.nrows()`
///  - `acc.ncols() == rhs.ncols()`
///  - `lhs.ncols() == rhs.nrows()`
///
/// additionally, matrices that are marked as triangular must be square, i.e., they must have
/// the same number of rows and columns.
///
/// # example
///
/// ```
/// use faer::linalg::matmul::triangular::{BlockStructure, matmul_with_conj};
/// use faer::{Accum, Conj, Mat, Par, mat, unzip, zip};
///
/// let lhs = mat![[0.0, 2.0], [1.0, 3.0]];
/// let rhs = mat![[4.0, 6.0], [5.0, 7.0]];
///
/// let mut acc = Mat::<f64>::zeros(2, 2);
/// let target = mat![
/// 	[
/// 		2.5 * (lhs[(0, 0)] * rhs[(0, 0)] + lhs[(0, 1)] * rhs[(1, 0)]),
/// 		0.0,
/// 	],
/// 	[
/// 		2.5 * (lhs[(1, 0)] * rhs[(0, 0)] + lhs[(1, 1)] * rhs[(1, 0)]),
/// 		2.5 * (lhs[(1, 0)] * rhs[(0, 1)] + lhs[(1, 1)] * rhs[(1, 1)]),
/// 	],
/// ];
///
/// matmul_with_conj(
/// 	&mut acc,
/// 	BlockStructure::TriangularLower,
/// 	Accum::Replace,
/// 	&lhs,
/// 	BlockStructure::Rectangular,
/// 	Conj::No,
/// 	&rhs,
/// 	BlockStructure::Rectangular,
/// 	Conj::No,
/// 	2.5,
/// 	Par::Seq,
/// );
///
/// zip!(&acc, &target).for_each(|unzip!(acc, target)| assert!((acc - target).abs() < 1e-10));
/// ```
pub fn matmul_with_conj<T: ComplexField, M: Shape, N: Shape, K: Shape>(
	dst: impl AsMatMut<T = T, Rows = M, Cols = N>,
	dst_structure: BlockStructure,
	beta: Accum,
	lhs: impl AsMatRef<T = T, Rows = M, Cols = K>,
	lhs_structure: BlockStructure,
	conj_lhs: Conj,
	rhs: impl AsMatRef<T = T, Rows = K, Cols = N>,
	rhs_structure: BlockStructure,
	conj_rhs: Conj,
	alpha: T,
	par: Par,
) {
/// computes the matrix product `[beta * acc] + alpha * lhs * rhs` (implicitly conjugating the
/// operands if needed) and stores the result in `acc`
///
/// performs the operation:
/// - `acc = alpha * lhs * rhs` if `beta` is `accum::replace` (in this case, the preexisting
/// values in `acc` are not read)
/// - `acc = acc + alpha * lhs * rhs` if `beta` is `accum::add`
///
/// the left hand side and right hand side may be interpreted as triangular depending on the
/// given corresponding matrix structure.
///
/// for the destination matrix, the result is:
/// - fully computed if the structure is rectangular,
/// - only the triangular half (including the diagonal) is computed if the structure is
/// triangular
/// - only the strict triangular half (excluding the diagonal) is computed if the structure is
/// strictly triangular or unit triangular
///
/// # panics
///
/// panics if the matrix dimensions are not compatible for matrix multiplication.
/// i.e.  
///  - `acc.nrows() == lhs.nrows()`
///  - `acc.ncols() == rhs.ncols()`
///  - `lhs.ncols() == rhs.nrows()`
///
/// additionally, matrices that are marked as triangular must be square, i.e., they must have
/// the same number of rows and columns.
///
/// # example
///
/// ```
/// use faer::linalg::matmul::triangular::{BlockStructure, matmul};
/// use faer::{Accum, Conj, Mat, Par, mat, unzip, zip};
///
/// let lhs = mat![[0.0, 2.0], [1.0, 3.0]];
/// let rhs = mat![[4.0, 6.0], [5.0, 7.0]];
///
/// let mut acc = Mat::<f64>::zeros(2, 2);
/// let target = mat![
/// 	[
/// 		2.5 * (lhs[(0, 0)] * rhs[(0, 0)] + lhs[(0, 1)] * rhs[(1, 0)]),
/// 		0.0,
/// 	],
/// 	[
/// 		2.5 * (lhs[(1, 0)] * rhs[(0, 0)] + lhs[(1, 1)] * rhs[(1, 0)]),
/// 		2.5 * (lhs[(1, 0)] * rhs[(0, 1)] + lhs[(1, 1)] * rhs[(1, 1)]),
/// 	],
/// ];
///
/// matmul(
/// 	&mut acc,
/// 	BlockStructure::TriangularLower,
/// 	Accum::Replace,
/// 	&lhs,
/// 	BlockStructure::Rectangular,
/// 	&rhs,
/// 	BlockStructure::Rectangular,
/// 	2.5,
/// 	Par::Seq,
/// );
///
/// zip!(&acc, &target).for_each(|unzip!(acc, target)| assert!((acc - target).abs() < 1e-10));
/// ```
pub fn matmul<T: ComplexField, LhsT: Conjugate<Canonical = T>, RhsT: Conjugate<Canonical = T>, M: Shape, N: Shape, K: Shape>(
	dst: impl AsMatMut<T = T, Rows = M, Cols = N>,
	dst_structure: BlockStructure,
	beta: Accum,
	lhs: impl AsMatRef<T = LhsT, Rows = M, Cols = K>,
	lhs_structure: BlockStructure,
	rhs: impl AsMatRef<T = RhsT, Rows = K, Cols = N>,
	rhs_structure: BlockStructure,
	alpha: T,
	par: Par,
) {
fn matmul_imp<'M, 'N, 'K, T: ComplexField>(
	dst: MatMut<'_, T, Dim<'M>, Dim<'N>>,
	dst_structure: BlockStructure,
	beta: Accum,
	lhs: MatRef<'_, T, Dim<'M>, Dim<'K>>,
	lhs_structure: BlockStructure,
	conj_lhs: Conj,
	rhs: MatRef<'_, T, Dim<'K>, Dim<'N>>,
	rhs_structure: BlockStructure,
	conj_rhs: Conj,
	alpha: &T,
	par: Par,
) {
// if either the lhs or the rhs is triangular
// do nothing
// invert acc, lhs and rhs
// invert and transpose
// transpose
// do nothing
// lower part of lhs does not contribute to result
//! linear algebra module
//!
//! contains low level routines and the implementation of their corresponding high level
//! wrappers
//!
//! # memory allocation
//! since most `faer` crates aim to expose a low level api for optimal performance, most algorithms
//! try to defer memory allocation to the user
//!
//! however, since a lot of algorithms need some form of temporary space for intermediate
//! computations, they may ask for a slice of memory for that purpose, by taking a [`stack:
//! MemStack`](dyn_stack::MemStack) parameter. a [`MemStack`] is a thin wrapper over a slice of
//! memory bytes. this memory may come from any valid source (heap allocation, fixed-size array on
//! the stack, etc.). the functions taking a [`MemStack`] parameter have a corresponding function
//! with a similar name ending in `_scratch` that returns the memory requirements of the algorithm.
//! for example:
//! [`householder::apply_block_householder_on_the_left_in_place_with_conj`] and
//! [`householder::apply_block_householder_on_the_left_in_place_scratch`]
//!
//! the memory stack may be reused in user-code to avoid repeated allocations, and it is also
//! possible to compute the sum ([`dyn_stack::StackReq::all_of`]) or union
//! ([`dyn_stack::StackReq::any_of`]) of multiple scratch requirements, in order to optimally
//! combine them into a single allocation
//!
//! after computing a [`dyn_stack::StackReq`], one can query its layout to allocate the
//! required memory. the simplest way to do so is through [`dyn_stack::MemBuffer::new`]
/// returns the stack requirements for creating a temporary matrix with the given dimensions.
pub fn temp_mat_scratch<T: ComplexField>(nrows: usize, ncols: usize) -> StackReq {
	fn drop(&mut self) {
	fn as_mat_ref(&self) -> crate::mat::MatRef<'_, T, Rows, Cols> {
	fn as_mat_mut(&mut self) -> crate::mat::MatMut<'_, T, Rows, Cols> {
	fn drop(&mut self) {
/// creates a temporary matrix of uninit values, from the given memory stack.
pub unsafe fn temp_mat_uninit<'a, T: ComplexField + 'a, Rows: Shape + 'a, Cols: Shape + 'a>(
	nrows: Rows,
	ncols: Cols,
	stack: &'a mut MemStack,
) -> (impl 'a + AsMatMut<T = T, Rows = Rows, Cols = Cols>, &'a mut MemStack) {
/// creates a temporary matrix of zero values, from the given memory stack.
pub fn temp_mat_zeroed<'a, T: ComplexField + 'a, Rows: Shape + 'a, Cols: Shape + 'a>(
	nrows: Rows,
	ncols: Cols,
	stack: &'a mut MemStack,
) -> (impl 'a + AsMatMut<T = T, Rows = Rows, Cols = Cols>, &'a mut MemStack) {
/// triangular matrix inverse
/// triangular matrix solve
/// matrix zipping implementation
/// jacobi rotation matrix
/// kronecker product
/// high level solvers
// B11 += A10 * dot
// B01 += l * dot
// dot  = -tau_inv * (B01 + B10^H * B11)
// B01 += dot
// norm-= abs2(B01)
fn update_mat_and_dot_simd<T: ComplexField>(
	norm: RowMut<'_, T>,
	dot: RowMut<'_, T>,
	B01: RowMut<'_, T>,
	B11: MatMut<'_, T, usize, usize, ContiguousFwd>,
	A10: ColRef<'_, T, usize, ContiguousFwd>,
	B10: ColRef<'_, T, usize, ContiguousFwd>,
	l: T,
	tau_inv: T::Real,
	align: usize,
) {
		fn with_simd<S: Simd>(self, simd: S) -> Self::Output {
/// $QR$ factorization with column pivoting tuning parameters
/// threshold at which blocking algorithms should be disabled
/// threshold at which the parallelism should be disabled
	fn auto() -> Self {
fn qr_in_place_unblocked<'out, I: Index, T: ComplexField>(
	A: MatMut<'_, T>,
	H: RowMut<'_, T>,
	col_perm: &'out mut [I],
	col_perm_inv: &'out mut [I],
	par: Par,
	stack: &mut MemStack,
	params: Spec<ColPivQrParams, T>,
) -> (ColPivQrInfo, PermRef<'out, I>) {
/// computes the layout of required workspace for performing a qr decomposition
/// with column pivoting
pub fn qr_in_place_scratch<I: Index, T: ComplexField>(
	nrows: usize,
	ncols: usize,
	block_size: usize,
	par: Par,
	params: Spec<ColPivQrParams, T>,
) -> StackReq {
/// information about the resulting $QR$ factorization.
/// number of transpositions that were performed, can be used to compute the determinant of
/// $P$.
pub fn qr_in_place<'out, I: Index, T: ComplexField>(
	A: MatMut<'_, T>,
	Q_coeff: MatMut<'_, T>,
	col_perm: &'out mut [I],
	col_perm_inv: &'out mut [I],
	par: Par,
	stack: &mut MemStack,
	params: Spec<ColPivQrParams, T>,
) -> (ColPivQrInfo, PermRef<'out, I>) {
	fn test_unblocked_qr() {
pub fn inverse_scratch<I: Index, T: ComplexField>(dim: usize, block_size: usize, par: Par) -> StackReq {
pub fn inverse<I: Index, T: ComplexField>(
	out: MatMut<'_, T>,
	Q_basis: MatRef<'_, T>,
	Q_coeff: MatRef<'_, T>,
	R: MatRef<'_, T>,
	col_perm: PermRef<'_, I>,
	par: Par,
	stack: &mut MemStack,
) {
// A P^-1 = Q R
// A^-1 = P^-1 R^-1 Q^-1
	fn test_inverse() {
//! the $QR$ decomposition with column pivoting decomposes a matrix $A$ into the product
//! $$AP^T = QR$$
//! where $P$ is a permutation matrix, $Q$ is a unitary matrix (represented as a block householder
//! sequence), and $R$ is an upper trapezoidal matrix.
pub fn reconstruct_scratch<I: Index, T: ComplexField>(nrows: usize, ncols: usize, block_size: usize, par: Par) -> StackReq {
pub fn reconstruct<I: Index, T: ComplexField>(
	out: MatMut<'_, T>,
	Q_basis: MatRef<'_, T>,
	Q_coeff: MatRef<'_, T>,
	R: MatRef<'_, T>,
	col_perm: PermRef<'_, I>,
	par: Par,
	stack: &mut MemStack,
) {
	fn test_reconstruct() {
pub fn solve_lstsq_in_place_scratch<I: Index, T: ComplexField>(
	qr_nrows: usize,
	qr_ncols: usize,
	qr_block_size: usize,
	rhs_ncols: usize,
	par: Par,
) -> StackReq {
pub fn solve_in_place_scratch<I: Index, T: ComplexField>(qr_dim: usize, qr_block_size: usize, rhs_ncols: usize, par: Par) -> StackReq {
pub fn solve_transpose_in_place_scratch<I: Index, T: ComplexField>(qr_dim: usize, qr_block_size: usize, rhs_ncols: usize, par: Par) -> StackReq {
pub fn solve_lstsq_in_place_with_conj<I: Index, T: ComplexField>(
	Q_basis: MatRef<'_, T>,
	Q_coeff: MatRef<'_, T>,
	R: MatRef<'_, T>,
	col_perm: PermRef<'_, I>,
	conj_QR: Conj,
	rhs: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
pub fn solve_lstsq_in_place<I: Index, T: ComplexField, C: Conjugate<Canonical = T>>(
	Q_basis: MatRef<'_, C>,
	Q_coeff: MatRef<'_, C>,
	R: MatRef<'_, C>,
	col_perm: PermRef<'_, I>,
	rhs: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
pub fn solve_in_place_with_conj<I: Index, T: ComplexField>(
	Q_basis: MatRef<'_, T>,
	Q_coeff: MatRef<'_, T>,
	R: MatRef<'_, T>,
	col_perm: PermRef<'_, I>,
	conj_QR: Conj,
	rhs: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
pub fn solve_in_place<I: Index, T: ComplexField, C: Conjugate<Canonical = T>>(
	Q_basis: MatRef<'_, C>,
	Q_coeff: MatRef<'_, C>,
	R: MatRef<'_, C>,
	col_perm: PermRef<'_, I>,
	rhs: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
pub fn solve_transpose_in_place_with_conj<I: Index, T: ComplexField>(
	Q_basis: MatRef<'_, T>,
	Q_coeff: MatRef<'_, T>,
	R: MatRef<'_, T>,
	col_perm: PermRef<'_, I>,
	conj_QR: Conj,
	rhs: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
pub fn solve_transpose_in_place<I: Index, T: ComplexField, C: Conjugate<Canonical = T>>(
	Q_basis: MatRef<'_, C>,
	Q_coeff: MatRef<'_, C>,
	R: MatRef<'_, C>,
	col_perm: PermRef<'_, I>,
	rhs: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
	fn test_lstsq() {
	fn test_solve() {
//! `faer` provides utilities for computing and manipulating the $QR$ factorization with and
//! without pivoting. the $QR$ factorization decomposes a matrix into a product of a unitary matrix
//! $Q$ (represented using block householder sequences), and an upper trapezoidal matrix $R$, such
//! that their product is equal to the original matrix (or a column permutation of it in the case
//! where column pivoting is used)
//!
//! # example
//!
//! assume we have an overdetermined system $Ax = b$ with full rank, and that we wish to find the
//! solution that minimizes the 2-norm
//!
//! this is equivalent to computing a matrix $x$ that minimizes the value $||Ax - b||^2$,
//! which is given by the solution $$x = (A^H A)^{-1} A^H b$$
//!
//! if we compute the $QR$ decomposition of $A$, such that $A = QR = Q_{\text{thin}}
//! R_{\text{thin}}$, then we get $$x = R_{\text{thin}}^{-1} Q_{\text{thin}}^H b$$
//!
//! to translate this to code, we can proceed as follows:
//!
//! ```
//! use faer::dyn_stack::{MemBuffer, MemStack, StackReq};
//! use faer::reborrow::*;
//!
//! use faer::linalg::qr::no_pivoting::factor;
//! use faer::linalg::{householder, triangular_solve};
//!
//! use faer::{Conj, Mat, Par, mat};
//!
//! // we start by defining matrices A and B that define our least-squares problem.
//! let a = mat![
//! 	[-1.14920683, -1.67950492],
//! 	[-0.93009756, -0.03885086],
//! 	[1.22579735, 0.88489976],
//! 	[0.70698973, 0.38928314],
//! 	[-1.66293762, 0.38123281],
//! 	[0.27639595, -0.32559289],
//! 	[-0.37506387, -0.13180778],
//! 	[-1.20774962, -0.38635657],
//! 	[0.44373549, 0.84397648],
//! 	[-1.96779374, -1.42751757_f64],
//! ];
//!
//! let b = mat![
//! 	[-0.14689786, -0.52845138, -2.26975669],
//! 	[-1.00844774, -1.38550214, 0.50329459],
//! 	[1.07941646, 0.71514245, -0.73987761],
//! 	[0.1281168, -0.23999022, 1.58776697],
//! 	[-0.49385283, 1.17875407, 2.01019076],
//! 	[0.65117811, -0.60339895, 0.27217694],
//! 	[0.85599951, -0.00699227, 0.93607199],
//! 	[-0.12635444, 0.94945626, 0.86565968],
//! 	[0.02383305, 0.41515805, -1.2816278],
//! 	[0.34158312, -0.07552168, 0.56724015_f64],
//! ];
//!
//! // approximate solution computed with numpy
//! let expected_solution = mat![
//! 	[0.33960324, -0.33812452, -0.8458301], //
//! 	[-0.25718351, 0.6281214, 1.07071764_f64],
//! ];
//!
//! let rank = Ord::min(a.nrows(), a.ncols());
//!
//! // we choose the recommended block size for the householder factors of our problem.
//! let block_size = factor::recommended_block_size::<f64>(a.nrows(), a.ncols());
//!
//! // we allocate the memory for the operations that we perform
//! let mut mem =
//! 	MemBuffer::new(StackReq::any_of(&[
//! 		factor::qr_in_place_scratch::<f64>(
//! 			a.nrows(),
//! 			a.ncols(),
//! 			block_size,
//! 			Par::Seq,
//! 			Default::default(),
//! 		),
//! 		householder::apply_block_householder_sequence_transpose_on_the_left_in_place_scratch::<
//! 			f64,
//! 		>(a.nrows(), block_size, b.ncols()),
//! 	]));
//! let mut stack = MemStack::new(&mut mem);
//!
//! let mut qr = a;
//! let mut h_factor = Mat::zeros(block_size, rank);
//! factor::qr_in_place(
//! 	qr.as_mut(),
//! 	h_factor.as_mut(),
//! 	Par::Seq,
//! 	stack.rb_mut(),
//! 	Default::default(),
//! );
//!
//! // now the householder bases are in the strictly lower trapezoidal part of `a`, and the
//! // matrix R is in the upper triangular part of `a`.
//!
//! let mut solution = b.clone();
//!
//! // compute Q^H×B
//! householder::apply_block_householder_sequence_transpose_on_the_left_in_place_with_conj(
//! 	qr.as_ref(),
//! 	h_factor.as_ref(),
//! 	Conj::Yes,
//! 	solution.as_mut(),
//! 	Par::Seq,
//! 	stack.rb_mut(),
//! );
//!
//! solution.truncate(rank, b.ncols());
//!
//! // compute R_thin^{-1} Q_thin^H×B
//! triangular_solve::solve_upper_triangular_in_place(
//! 	qr.as_ref().split_at_row(rank).0,
//! 	solution.as_mut(),
//! 	Par::Seq,
//! );
//!
//! for i in 0..rank {
//! 	for j in 0..b.ncols() {
//! 		assert!((solution[(i, j)] - expected_solution[(i, j)]).abs() <= 1e-6);
//! 	}
//! }
//! ```
	fn test_example() {
// we start by defining matrices A and B that define our least-squares problem.
// approximate solution computed with numpy
//
// we choose the recommended block size for the householder factors of our problem.
// we allocate the memory for the operations that we perform
// now the householder bases are in the strictly lower trapezoidal part of `a`, and the
// matrix R is in the upper triangular part of `a`.
// compute Q^H×B
// compute R_thin^{-1} Q_thin^H×B
// R R R R|R R R | A A A
// H R R R|R R R | A A A
// H H 0 R|R R R | A A A
//        |------| A A A
// H H H 0|R R R | A A A
// H H H H|0 R R | A A A
/// information about the resulting $QR$ factorization.
/// estimated rank of the matrix.
fn qr_in_place_unblocked<T: ComplexField>(A: MatMut<'_, T>, H: RowMut<'_, T>, row_start: usize, col_start: usize) -> usize {
/// the recommended block size to use for a $QR$ decomposition of a matrix with the given shape.
pub fn recommended_block_size<T: ComplexField>(nrows: usize, ncols: usize) -> usize {
/// $QR$ factorization tuning parameters.
/// threshold at which blocking algorithms should be disabled
/// threshold at which the parallelism should be disabled
	fn auto() -> Self {
fn qr_in_place_blocked<T: ComplexField>(
	A: MatMut<'_, T>,
	H: MatMut<'_, T>,
	row_start: usize,
	col_start: usize,
	par: Par,
	stack: &mut MemStack,
	params: Spec<QrParams, T>,
) -> usize {
//
//  offset col_start
//       v v
// R R R R|A A|A A
// H 0 R R|A A|A A
// H H 0 R|A A|A A
// H H H 0|R A|A A
// H H H H|0 R|A A
// H H H H|H 0|A A
// householder coeffs
//
// H H H H H 0 0 0 ∞ 0 0 0
//   H H H   ∞ 0 0   ∞ 0 0
//     H H     ∞ 0     ∞ 0
//       H       ∞       ∞
pub fn qr_in_place<T: ComplexField>(A: MatMut<'_, T>, Q_coeff: MatMut<'_, T>, par: Par, stack: &mut MemStack, params: Spec<QrParams, T>) -> QrInfo {
/// computes the layout of required workspace for performing a qr
/// decomposition with no pivoting
pub fn qr_in_place_scratch<T: ComplexField>(nrows: usize, ncols: usize, block_size: usize, par: Par, params: Spec<QrParams, T>) -> StackReq {
	fn test_qr() {
	fn test_rank_deficient() {
pub fn inverse_scratch<T: ComplexField>(dim: usize, block_size: usize, par: Par) -> StackReq {
pub fn inverse<T: ComplexField>(
	out: MatMut<'_, T>,
	Q_basis: MatRef<'_, T>,
	Q_coeff: MatRef<'_, T>,
	R: MatRef<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
// A = Q R
// A^-1 = R^-1 Q^-1
	fn test_inverse() {
//! the $QR$ decomposition decomposes a matrix $A$ into the product
//! $$A = QR$$
//! where $Q$ is a unitary matrix (represented as a block householder sequence), and $R$ is an upper
//! trapezoidal matrix.
pub fn reconstruct_scratch<T: ComplexField>(nrows: usize, ncols: usize, block_size: usize, par: Par) -> StackReq {
pub fn reconstruct<T: ComplexField>(
	out: MatMut<'_, T>,
	Q_basis: MatRef<'_, T>,
	Q_coeff: MatRef<'_, T>,
	R: MatRef<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
	fn test_reconstruct() {
pub fn solve_lstsq_in_place_scratch<T: ComplexField>(qr_nrows: usize, qr_ncols: usize, qr_block_size: usize, rhs_ncols: usize, par: Par) -> StackReq {
pub fn solve_in_place_scratch<T: ComplexField>(qr_dim: usize, qr_block_size: usize, rhs_ncols: usize, par: Par) -> StackReq {
pub fn solve_transpose_in_place_scratch<T: ComplexField>(qr_dim: usize, qr_block_size: usize, rhs_ncols: usize, par: Par) -> StackReq {
pub fn solve_lstsq_in_place_with_conj<T: ComplexField>(
	Q_basis: MatRef<'_, T>,
	Q_coeff: MatRef<'_, T>,
	R: MatRef<'_, T>,
	conj_QR: Conj,
	rhs: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
pub fn solve_lstsq_in_place<T: ComplexField, C: Conjugate<Canonical = T>>(
	Q_basis: MatRef<'_, C>,
	Q_coeff: MatRef<'_, C>,
	R: MatRef<'_, C>,
	rhs: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
pub fn solve_in_place_with_conj<T: ComplexField>(
	Q_basis: MatRef<'_, T>,
	Q_coeff: MatRef<'_, T>,
	R: MatRef<'_, T>,
	conj_QR: Conj,
	rhs: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
pub fn solve_in_place<T: ComplexField, C: Conjugate<Canonical = T>>(
	Q_basis: MatRef<'_, C>,
	Q_coeff: MatRef<'_, C>,
	R: MatRef<'_, C>,
	rhs: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
pub fn solve_transpose_in_place_with_conj<T: ComplexField>(
	Q_basis: MatRef<'_, T>,
	Q_coeff: MatRef<'_, T>,
	R: MatRef<'_, T>,
	conj_QR: Conj,
	rhs: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
pub fn solve_transpose_in_place<T: ComplexField, C: Conjugate<Canonical = T>>(
	Q_basis: MatRef<'_, C>,
	Q_coeff: MatRef<'_, C>,
	R: MatRef<'_, C>,
	rhs: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
	fn test_lstsq() {
	fn test_solve() {
pub fn determinant<T: ComplexField>(mat: MatRef<'_, T>) -> T::Canonical {
fn norm_l1_simd<'N, T: ComplexField>(data: ColRef<'_, T, Dim<'N>, ContiguousFwd>) -> T::Real {
		fn with_simd<S: pulp::Simd>(self, simd: S) -> Self::Output {
fn norm_l1_simd_pairwise_rows<T: ComplexField>(data: ColRef<'_, T, usize, ContiguousFwd>) -> T::Real {
fn norm_l1_simd_pairwise_cols<T: ComplexField>(data: MatRef<'_, T, usize, usize, ContiguousFwd>) -> T::Real {
pub fn norm_l1<T: ComplexField>(mut mat: MatRef<'_, T>) -> T::Real {
	fn test_norm_l1() {
fn norm_l2_simd<'N, T: ComplexField>(data: ColRef<'_, T, Dim<'N>, ContiguousFwd>) -> [T::Real;
		fn with_simd<S: pulp::Simd>(self, simd: S) -> Self::Output {
fn norm_l2_simd_pairwise_rows<T: ComplexField>(data: ColRef<'_, T, usize, ContiguousFwd>) -> [T::Real;
fn norm_l2_simd_pairwise_cols<T: ComplexField>(data: MatRef<'_, T, usize, usize, ContiguousFwd>) -> [T::Real;
pub fn norm_l2_x3<T: ComplexField>(mut mat: MatRef<'_, T>) -> [T::Real;
pub fn norm_l2<T: ComplexField>(mat: MatRef<'_, T>) -> T::Real {
	fn test_norm_l2() {
	fn test_norm_l2_cplx() {
fn norm_l2_sqr_simd<'N, T: ComplexField>(data: ColRef<'_, T, Dim<'N>, ContiguousFwd>) -> T::Real {
		fn with_simd<S: pulp::Simd>(self, simd: S) -> Self::Output {
fn norm_l2_sqr_simd_pairwise_rows<T: ComplexField>(data: ColRef<'_, T, usize, ContiguousFwd>) -> T::Real {
fn norm_l2_sqr_simd_pairwise_cols<T: ComplexField>(data: MatRef<'_, T, usize, usize, ContiguousFwd>) -> T::Real {
pub fn norm_l2_sqr<T: ComplexField>(mut mat: MatRef<'_, T>) -> T::Real {
	fn test_norm_l2_sqr() {
fn norm_max_simd<'N, T: ComplexField>(data: ColRef<'_, T, Dim<'N>, ContiguousFwd>) -> T::Real {
		fn with_simd<S: pulp::Simd>(self, simd: S) -> Self::Output {
fn norm_max_simd_pairwise_rows<T: ComplexField>(data: ColRef<'_, T, usize, ContiguousFwd>) -> T::Real {
fn norm_max_simd_pairwise_cols<T: ComplexField>(data: MatRef<'_, T, usize, usize, ContiguousFwd>) -> T::Real {
pub fn norm_max<T: ComplexField>(mut mat: MatRef<'_, T>) -> T::Real {
	fn test_norm_max() {
fn sum_simd<'N, T: ComplexField>(data: ColRef<'_, T, Dim<'N>, ContiguousFwd>) -> T {
		fn with_simd<S: pulp::Simd>(self, simd: S) -> Self::Output {
fn sum_simd_pairwise_rows<T: ComplexField>(data: ColRef<'_, T, usize, ContiguousFwd>) -> T {
fn sum_simd_pairwise_cols<T: ComplexField>(data: MatRef<'_, T, usize, usize, ContiguousFwd>) -> T {
pub fn sum<T: ComplexField>(mut mat: MatRef<'_, T>) -> T {
	fn test_sum_real() {
	fn test_sum_cplx() {
/// shape info of a linear system solver
/// returns the number of rows of the matrix
	fn nrows(&self) -> usize;
/// returns the number of columns of the matrix
	fn ncols(&self) -> usize;
/// linear system solver implementation
/// solves the equation `self × x = rhs`, implicitly conjugating `self` if needed, and stores
/// the result in `rhs`
	fn solve_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>);
/// solves the equation `self.transpose() × x = rhs`, implicitly conjugating `self` if needed,
/// and stores the result in `rhs`
	fn solve_transpose_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>);
/// least squares linear system solver implementation
/// solves the equation `self × x = rhs` in the sense of least squares, implicitly conjugating
/// `self` if needed, and stores the result in the top rows of `rhs`
	fn solve_lstsq_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>);
/// dense linear system solver
/// returns an approximation of the matrix that was used to create the decomposition
	fn reconstruct(&self) -> Mat<T>;
/// returns an approximation of the inverse of the matrix that was used to create the
/// decomposition
	fn inverse(&self) -> Mat<T>;
	fn nrows(&self) -> usize {
	fn ncols(&self) -> usize {
	fn solve_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
	fn solve_transpose_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
	fn solve_lstsq_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
	fn reconstruct(&self) -> Mat<T> {
	fn inverse(&self) -> Mat<T> {
/// [`SolveCore`] extension trait
/// solves $A x = b$
	fn solve_in_place(&self, rhs: impl AsMatMut<T = T, Rows = usize>) {
/// solves $\bar A x = b$
	fn solve_conjugate_in_place(&self, rhs: impl AsMatMut<T = T, Rows = usize>) {
/// solves $A^\top x = b$
	fn solve_transpose_in_place(&self, rhs: impl AsMatMut<T = T, Rows = usize>) {
/// solves $A^H x = b$
	fn solve_adjoint_in_place(&self, rhs: impl AsMatMut<T = T, Rows = usize>) {
/// solves $x A = b$
	fn rsolve_in_place(&self, lhs: impl AsMatMut<T = T, Cols = usize>) {
/// solves $x \bar A = b$
	fn rsolve_conjugate_in_place(&self, lhs: impl AsMatMut<T = T, Cols = usize>) {
/// solves $x A^\top = b$
	fn rsolve_transpose_in_place(&self, lhs: impl AsMatMut<T = T, Cols = usize>) {
/// solves $x A^H = b$
	fn rsolve_adjoint_in_place(&self, lhs: impl AsMatMut<T = T, Cols = usize>) {
/// solves $A x = b$
	fn solve<Rhs: AsMatRef<T = T, Rows = usize>>(&self, rhs: Rhs) -> Rhs::Owned {
/// solves $\bar A x = b$
	fn solve_conjugate<Rhs: AsMatRef<T = T, Rows = usize>>(&self, rhs: Rhs) -> Rhs::Owned {
/// solves $A^\top x = b$
	fn solve_transpose<Rhs: AsMatRef<T = T, Rows = usize>>(&self, rhs: Rhs) -> Rhs::Owned {
/// solves $A^H x = b$
	fn solve_adjoint<Rhs: AsMatRef<T = T, Rows = usize>>(&self, rhs: Rhs) -> Rhs::Owned {
/// solves $x A = b$
	fn rsolve<Lhs: AsMatRef<T = T, Cols = usize>>(&self, lhs: Lhs) -> Lhs::Owned {
/// solves $x \bar A = b$
	fn rsolve_conjugate<Lhs: AsMatRef<T = T, Cols = usize>>(&self, lhs: Lhs) -> Lhs::Owned {
/// solves $x A^\top = b$
	fn rsolve_transpose<Lhs: AsMatRef<T = T, Cols = usize>>(&self, lhs: Lhs) -> Lhs::Owned {
/// solves $x A^H = b$
	fn rsolve_adjoint<Lhs: AsMatRef<T = T, Cols = usize>>(&self, lhs: Lhs) -> Lhs::Owned {
/// returns the $LU$ decomposition of `self` with partial (row) pivoting
	pub fn partial_piv_lu(&self) -> PartialPivLu<C::Canonical> {
/// returns the $LU$ decomposition of `self` with full pivoting
	pub fn full_piv_lu(&self) -> FullPivLu<C::Canonical> {
/// returns the $QR$ decomposition of `self`
	pub fn qr(&self) -> Qr<C::Canonical> {
/// returns the $QR$ decomposition of `self` with column pivoting
	pub fn col_piv_qr(&self) -> ColPivQr<C::Canonical> {
/// returns the svd of `self`
///
/// singular values are nonnegative and sorted in nonincreasing order
	pub fn svd(&self) -> Result<Svd<C::Canonical>, SvdError> {
/// returns the thin svd of `self`
///
/// singular values are nonnegative and sorted in nonincreasing order
	pub fn thin_svd(&self) -> Result<Svd<C::Canonical>, SvdError> {
/// returns the $L L^\top$ decomposition of `self`
	pub fn llt(&self, side: Side) -> Result<Llt<C::Canonical>, LltError> {
/// returns the $L D L^\top$ decomposition of `self`
	pub fn ldlt(&self, side: Side) -> Result<Ldlt<C::Canonical>, LdltError> {
/// returns the $LBL^\top$ decomposition of `self`
	pub fn lblt(&self, side: Side) -> Lblt<C::Canonical> {
/// returns the eigendecomposition of `self`, assuming it is self-adjoint
///
/// eigenvalues sorted in nondecreasing order
	pub fn self_adjoint_eigen(&self, side: Side) -> Result<SelfAdjointEigen<C::Canonical>, EvdError> {
/// returns the eigenvalues of `self`, assuming it is self-adjoint
///
/// eigenvalues sorted in nondecreasing order
	pub fn self_adjoint_eigenvalues(&self, side: Side) -> Result<Vec<Real<C>>, EvdError> {
		pub fn imp<T: ComplexField>(mut A: MatRef<'_, T>, side: Side) -> Result<Vec<T::Real>, EvdError> {
/// returns the singular values of `self`
///
/// singular values are nonnegative and sorted in nonincreasing order
	pub fn singular_values(&self) -> Result<Vec<Real<C>>, SvdError> {
		pub fn imp<T: ComplexField>(A: MatRef<'_, T>) -> Result<Vec<T::Real>, SvdError> {
	fn eigen_imp(&self) -> Result<Eigen<Real<C>>, EvdError> {
	fn gen_eigen_imp(&self, B: MatRef<'_, C>) -> Result<GeneralizedEigen<Real<C>>, GevdError> {
	fn eigenvalues_imp(&self) -> Result<Vec<Complex<Real<C>>>, EvdError> {
/// returns the generalized_eigendecomposition of `(self, B)`
	pub fn generalized_eigen(&self, B: impl AsMatRef<T = T, Rows = usize, Cols = usize>) -> Result<GeneralizedEigen<Real<T>>, GevdError> {
/// returns the eigendecomposition of `self`
	pub fn eigen(&self) -> Result<Eigen<Real<T>>, EvdError> {
/// returns the eigenvalues of `self`
	pub fn eigenvalues(&self) -> Result<Vec<Complex<Real<T>>>, EvdError> {
/// [`SolveLstsqCore`] extension trait
/// solves $A x = b$ in the sense of least squares.
	fn solve_lstsq_in_place(&self, rhs: impl AsMatMut<T = T, Rows = usize>) {
/// solves $\bar A x = b$ in the sense of least squares.
	fn solve_conjugate_lstsq_in_place(&self, rhs: impl AsMatMut<T = T, Rows = usize>) {
/// solves $A x = b$ in the sense of least squares.
	fn solve_lstsq<Rhs: AsMatRef<T = T, Rows = usize>>(&self, rhs: Rhs) -> Rhs::Owned {
/// solves $\bar A x = b$ in the sense of least squares.
	fn solve_conjugate_lstsq<Rhs: AsMatRef<T = T, Rows = usize>>(&self, rhs: Rhs) -> Rhs::Owned {
/// [`DenseSolveCore`] extension trait
/// $L L^\top$ decomposition
/// $L D L^\top$ decomposition
/// $LBL^\top$ decomposition
/// $LU$ decomposition with partial (row) pivoting
/// $LU$ decomposition with full pivoting
/// $QR$ decomposition
/// $QR$ decomposition with column pivoting
/// svd decomposition (either full or thin)
/// self-adjoint eigendecomposition
/// eigendecomposition
/// eigendecomposition
/// returns the $L L^\top$ decomposition of $A$
	pub fn new<C: Conjugate<Canonical = T>>(A: MatRef<'_, C>, side: Side) -> Result<Self, LltError> {
	fn new_imp(mut L: Mat<T>) -> Result<Self, LltError> {
/// returns the $L$ factor
	pub fn L(&self) -> MatRef<'_, T> {
/// returns the $L D L^\top$ decomposition of $A$
	pub fn new<C: Conjugate<Canonical = T>>(A: MatRef<'_, C>, side: Side) -> Result<Self, LdltError> {
	fn new_imp(mut L: Mat<T>) -> Result<Self, LdltError> {
/// returns the $L$ factor
	pub fn L(&self) -> MatRef<'_, T> {
/// returns the $D$ factor
	pub fn D(&self) -> DiagRef<'_, T> {
/// returns the $LBL^\top$ decomposition of $A$
	pub fn new<C: Conjugate<Canonical = T>>(A: MatRef<'_, C>, side: Side) -> Self {
	fn new_imp(mut L: Mat<T>) -> Self {
/// returns the $L$ factor
	pub fn L(&self) -> MatRef<'_, T> {
/// returns the diagonal of the $B$ factor
	pub fn B_diag(&self) -> DiagRef<'_, T> {
/// returns the subdiagonal of the $B$ factor
	pub fn B_subdiag(&self) -> DiagRef<'_, T> {
/// returns the pivoting permutation $P$
	pub fn P(&self) -> PermRef<'_, usize> {
fn split_LU<T: ComplexField>(LU: Mat<T>) -> (Mat<T>, Mat<T>) {
/// returns the $LU$ decomposition of $A$ with partial pivoting
	pub fn new<C: Conjugate<Canonical = T>>(A: MatRef<'_, C>) -> Self {
	fn new_imp(mut LU: Mat<T>) -> Self {
/// returns the $L$ factor
	pub fn L(&self) -> MatRef<'_, T> {
/// returns the $U$ factor
	pub fn U(&self) -> MatRef<'_, T> {
/// returns the row pivoting permutation $P$
	pub fn P(&self) -> PermRef<'_, usize> {
/// returns the $LU$ decomposition of $A$ with full pivoting
	pub fn new<C: Conjugate<Canonical = T>>(A: MatRef<'_, C>) -> Self {
	fn new_imp(mut LU: Mat<T>) -> Self {
/// returns the factor $L$
	pub fn L(&self) -> MatRef<'_, T> {
/// returns the factor $U$
	pub fn U(&self) -> MatRef<'_, T> {
/// returns the row pivoting permutation $P$
	pub fn P(&self) -> PermRef<'_, usize> {
/// returns the column pivoting permutation $P$
	pub fn Q(&self) -> PermRef<'_, usize> {
/// returns the $QR$ decomposition of $A$
	pub fn new<C: Conjugate<Canonical = T>>(A: MatRef<'_, C>) -> Self {
	fn new_imp(mut QR: Mat<T>) -> Self {
/// returns the householder basis of $Q$
	pub fn Q_basis(&self) -> MatRef<'_, T> {
/// returns the householder coefficients of $Q$
	pub fn Q_coeff(&self) -> MatRef<'_, T> {
/// returns the factor $R$
	pub fn R(&self) -> MatRef<'_, T> {
/// returns the upper trapezoidal part of $R$
	pub fn thin_R(&self) -> MatRef<'_, T> {
/// computes the factor $Q$
	pub fn compute_Q(&self) -> Mat<T> {
/// computes the first $\min(\text{nrows}, \text{ncols})$ columns of the factor $Q$
	pub fn compute_thin_Q(&self) -> Mat<T> {
/// returns the $QR$ decomposition of $A$ with column pivoting
	pub fn new<C: Conjugate<Canonical = T>>(A: MatRef<'_, C>) -> Self {
	fn new_imp(mut QR: Mat<T>) -> Self {
/// returns the householder basis of $Q$
	pub fn Q_basis(&self) -> MatRef<'_, T> {
/// returns the householder coefficients of $Q$
	pub fn Q_coeff(&self) -> MatRef<'_, T> {
/// returns the factor $R$
	pub fn R(&self) -> MatRef<'_, T> {
/// returns the upper trapezoidal part of $R$
	pub fn thin_R(&self) -> MatRef<'_, T> {
/// computes the factor $Q$
	pub fn compute_Q(&self) -> Mat<T> {
/// computes the first $\min(\text{nrows}, \text{ncols})$ columns of the factor $Q$
	pub fn compute_thin_Q(&self) -> Mat<T> {
/// returns the column pivoting permutation $P$
	pub fn P(&self) -> PermRef<'_, usize> {
/// returns the svd of $A$
	pub fn new<C: Conjugate<Canonical = T>>(A: MatRef<'_, C>) -> Result<Self, SvdError> {
/// returns the thin svd of $A$
	pub fn new_thin<C: Conjugate<Canonical = T>>(A: MatRef<'_, C>) -> Result<Self, SvdError> {
	fn new_imp(A: MatRef<'_, T>, conj: Conj, thin: bool) -> Result<Self, SvdError> {
/// returns the factor $U$
	pub fn U(&self) -> MatRef<'_, T> {
/// returns the factor $V$
	pub fn V(&self) -> MatRef<'_, T> {
/// returns the factor $S$
	pub fn S(&self) -> DiagRef<'_, T> {
/// returns the pseudoinverse of the original matrix $A$.
	pub fn pseudoinverse(&self) -> Mat<T> {
/// returns the eigendecomposition of $A$, assuming it is self-adjoint
	pub fn new<C: Conjugate<Canonical = T>>(A: MatRef<'_, C>, side: Side) -> Result<Self, EvdError> {
	fn new_imp(A: MatRef<'_, T>, conj: Conj) -> Result<Self, EvdError> {
/// returns the factor $U$
	pub fn U(&self) -> MatRef<'_, T> {
/// returns the factor $S$
	pub fn S(&self) -> DiagRef<'_, T> {
/// returns the pseudoinverse of the original matrix $A$.
	pub fn pseudoinverse(&self) -> Mat<T> {
fn real_to_cplx<T: RealField>(
	mut U: MatMut<'_, Complex<T>>,
	mut S: DiagMut<'_, Complex<T>>,
	U_real: MatRef<'_, T>,
	S_re: DiagRef<'_, T>,
	S_im: DiagRef<'_, T>,
) {
/// returns the eigendecomposition of $A$
	pub fn new<C: Conjugate<Canonical = Complex<T>>>(A: MatRef<'_, C>) -> Result<Self, EvdError> {
/// returns the eigendecomposition of $A$
	pub fn new_from_real(A: MatRef<'_, T>) -> Result<Self, EvdError> {
	fn new_imp(A: MatRef<'_, Complex<T>>, conj: Conj) -> Result<Self, EvdError> {
/// returns the factor $U$
	pub fn U(&self) -> MatRef<'_, Complex<T>> {
/// returns the factor $S$
	pub fn S(&self) -> DiagRef<'_, Complex<T>> {
/// returns the generalized eigendecomposition of $(A, B)$
	pub fn new<C: Conjugate<Canonical = Complex<T>>>(A: MatRef<'_, C>, B: MatRef<'_, C>) -> Result<Self, GevdError> {
/// returns the generalized eigendecomposition of $(A, B)$
	pub fn new_from_real(A: MatRef<'_, T>, B: MatRef<'_, T>) -> Result<Self, GevdError> {
	fn new_imp(A: MatRef<'_, Complex<T>>, B: MatRef<'_, Complex<T>>, conj: Conj) -> Result<Self, GevdError> {
/// returns the factor $U$
	pub fn U(&self) -> MatRef<'_, Complex<T>> {
/// returns the factor $S_a$
	pub fn S_a(&self) -> DiagRef<'_, Complex<T>> {
/// returns the factor $S_b$
	pub fn S_b(&self) -> DiagRef<'_, Complex<T>> {
	fn nrows(&self) -> usize {
	fn ncols(&self) -> usize {
	fn nrows(&self) -> usize {
	fn ncols(&self) -> usize {
	fn nrows(&self) -> usize {
	fn ncols(&self) -> usize {
	fn nrows(&self) -> usize {
	fn ncols(&self) -> usize {
	fn nrows(&self) -> usize {
	fn ncols(&self) -> usize {
	fn nrows(&self) -> usize {
	fn ncols(&self) -> usize {
	fn nrows(&self) -> usize {
	fn ncols(&self) -> usize {
	fn nrows(&self) -> usize {
	fn ncols(&self) -> usize {
	fn nrows(&self) -> usize {
	fn ncols(&self) -> usize {
	fn nrows(&self) -> usize {
	fn ncols(&self) -> usize {
	fn solve_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
	fn solve_transpose_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
fn make_self_adjoint<T: ComplexField>(mut A: MatMut<'_, T>) {
	fn reconstruct(&self) -> Mat<T> {
	fn inverse(&self) -> Mat<T> {
	fn solve_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
	fn solve_transpose_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
	fn reconstruct(&self) -> Mat<T> {
	fn inverse(&self) -> Mat<T> {
	fn solve_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
	fn solve_transpose_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
	fn reconstruct(&self) -> Mat<T> {
	fn inverse(&self) -> Mat<T> {
	fn solve_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
	fn solve_transpose_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
	fn reconstruct(&self) -> Mat<T> {
	fn inverse(&self) -> Mat<T> {
	fn solve_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
	fn solve_transpose_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
	fn reconstruct(&self) -> Mat<T> {
	fn inverse(&self) -> Mat<T> {
	fn solve_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
	fn solve_transpose_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
	fn solve_lstsq_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
	fn reconstruct(&self) -> Mat<T> {
	fn inverse(&self) -> Mat<T> {
	fn solve_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
	fn solve_transpose_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
	fn solve_lstsq_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
	fn reconstruct(&self) -> Mat<T> {
	fn inverse(&self) -> Mat<T> {
	fn solve_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
	fn solve_transpose_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
	fn solve_lstsq_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
	fn reconstruct(&self) -> Mat<T> {
	fn inverse(&self) -> Mat<T> {
	fn solve_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
	fn solve_transpose_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
	fn reconstruct(&self) -> Mat<T> {
	fn inverse(&self) -> Mat<T> {
	fn test_solver(A: MatRef<'_, c64>, A_dec: impl SolveCore<c64>) {
		fn test_solver_imp(A: MatRef<'_, c64>, A_dec: &dyn SolveCore<c64>) {
	fn test_all_solvers() {
	fn test_eigen_cplx() {
	fn test_geigen_cplx() {
	fn test_eigen_real() {
	fn test_geigen_real() {
	fn test_svd_solver_for_rectangular_matrix() {
/// computes the layout of the workspace required to compute a matrix's
/// bidiagonalization
pub fn bidiag_in_place_scratch<T: ComplexField>(nrows: usize, ncols: usize, par: Par, params: Spec<BidiagParams, T>) -> StackReq {
/// bidiagonalization tuning parameters.
/// threshold at which parallelism should be disabled
	fn auto() -> Self {
/// computes a matrix $A$'s bidiagonalization such that $A = U B V^H$
///
/// $B$ is a bidiagonal matrix stored in $A$'s diagonal and superdiagonal
///
/// $U$ is a sequence of householder reflections stored in the unit lower triangular half of $A$,
/// with the householder coefficients being stored in `H_left`
///
/// $V$ is a sequence of householder reflections stored in the unit upper triangular half of $A$
/// (excluding the diagonal), with the householder coefficients being stored in `H_right`
pub fn bidiag_in_place<T: ComplexField>(
	A: MatMut<'_, T>,
	H_left: MatMut<'_, T>,
	H_right: MatMut<'_, T>,
	par: Par,
	stack: &mut MemStack,
	params: Spec<BidiagParams, T>,
) {
fn bidiag_fused_op<T: ComplexField>(
	A22: MatMut<'_, T>,
	u: ColRef<'_, T>,
	up: ColRef<'_, T>,
	z: ColRef<'_, T>,
	y: RowMut<'_, T>,
	vp: RowRef<'_, T>,
	align: usize,
) {
fn bidiag_fused_op_fallback<T: ComplexField>(
	A22: MatMut<'_, T>,
	u: ColRef<'_, T>,
	up: ColRef<'_, T>,
	z: ColRef<'_, T>,
	y: RowMut<'_, T>,
	vp: RowRef<'_, T>,
) {
fn bidiag_fused_op_simd<'M, 'N, T: ComplexField>(
	A22: MatMut<'_, T, usize, usize, ContiguousFwd>,
	u: ColRef<'_, T, usize, ContiguousFwd>,
	up: ColRef<'_, T, usize, ContiguousFwd>,
	z: ColRef<'_, T, usize, ContiguousFwd>,

	y: RowMut<'_, T, usize>,
	vp: RowRef<'_, T, usize>,

	align: usize,
) {
		fn with_simd<S: pulp::Simd>(self, simd: S) -> Self::Output {
	fn test_bidiag_real() {
	fn test_bidiag_cplx() {
// Algorithm ported from Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2013 Gauthier Brun <brun.gauthier@gmail.com>
// Copyright (C) 2013 Nicolas Carre <nicolas.carre@ensimag.fr>
// Copyright (C) 2013 Jean Ceccato <jean.ceccato@ensimag.fr>
// Copyright (C) 2013 Pierre Zoppitelli <pierre.zoppitelli@ensimag.fr>
// Copyright (C) 2013 Jitse Niesen <jitse@maths.leeds.ac.uk>
// Copyright (C) 2014-2017 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
fn bidiag_to_mat<T: RealField>(diag: ColRef<'_, T, usize, ContiguousFwd>, subdiag: ColRef<'_, T, usize, ContiguousFwd>) -> Mat<T> {
fn bidiag_to_mat2<T: RealField>(diag: ColRef<'_, T, usize, ContiguousFwd>, subdiag: ColRef<'_, T, usize, ContiguousFwd>) -> Mat<T> {
fn arrow_to_mat<T: RealField>(diag: ColRef<'_, T, usize, ContiguousFwd>, col0: ColRef<'_, T, usize, ContiguousFwd>) -> Mat<T> {
/// secular eq must be increasing
pub(crate) fn secular_eq_root_finder<T: RealField>(
	secular_eq: &dyn Fn(T, T) -> T,
	batch_secular_eq: &dyn Fn(&[T;
// rational interpolation: fit a function of the form a / mu + b through
// the two previous iterates and use its
// zero to compute the next iterate
// find mu such that a / mu + b = -k * f_zero
// a / mu = -f_zero - b
// mu = -a / (f_zero + b)
// this will be our right candidate
// this will be our left candidate
// try to find non zero starting bounds
// try bisection just to get a good guess for secant
// try secant with the guess from bisection
// secant failed, use bisection again
pub(super) fn qr_algorithm<T: RealField>(
	diag: ColMut<'_, T, usize, ContiguousFwd>,
	subdiag: ColMut<'_, T, usize, ContiguousFwd>,
	u: Option<MatMut<'_, T>>,
	v: Option<MatMut<'_, T>>,
) -> Result<(), SvdError> {
fn compute_svd_of_m<T: RealField>(
	um: Option<MatMut<'_, T, usize, usize, ContiguousFwd>>,
	vm: Option<MatMut<'_, T, usize, usize, ContiguousFwd>>,
	diag: ColMut<'_, T, usize, ContiguousFwd>,
	col0: ColRef<'_, T, usize, ContiguousFwd>,
	outer_perm: &[usize],
	stack: &mut MemStack,
) {
fn compute_singular_vectors<'N, T: RealField>(
	mut um: Option<MatMut<T, usize, usize, ContiguousFwd>>,
	mut vm: Option<MatMut<T, Dim<'N>, Dim<'N>, ContiguousFwd>>,
	zhat: ColRef<T, Dim<'N>, ContiguousFwd>,
	diag: ColRef<'_, T, Dim<'N>, ContiguousFwd>,
	perm: &[Idx<'N>],
	outer_perm: &Array<'N, Idx<'N>>,
	col_perm_inv: &[usize],
	actual_n: usize,
	shifts: ColRef<T, Dim<'N>, ContiguousFwd>,
	mus: ColRef<T, Dim<'N>, ContiguousFwd>,
) {
fn perturb_col0<'N, T: RealField>(
	zhat: ColMut<'_, T, Dim<'N>, ContiguousFwd>,
	col0: ColRef<'_, T, Dim<'N>, ContiguousFwd>,
	diag: ColRef<'_, T, Dim<'N>, ContiguousFwd>,
	perm: &[Idx<'N>],
	s: ColRef<T, Dim<'N>, ContiguousFwd>,
	shifts: ColRef<T, Dim<'N>, ContiguousFwd>,
	mus: ColRef<T, Dim<'N>, ContiguousFwd>,
) {
// NOTE: the order of operations is crucial here
fn compute_singular_values<'N, 'O, T: RealField>(
	mut shifts: ColMut<T, Dim<'N>, ContiguousFwd>,
	mut mus: ColMut<T, Dim<'N>, ContiguousFwd>,
	mut s: ColMut<T, Dim<'N>, ContiguousFwd>,
	diag: ColRef<'_, T, Dim<'N>, ContiguousFwd>,
	diag_perm: ColRef<'_, T, Dim<'O>, ContiguousFwd>,
	col0: ColRef<'_, T, Dim<'N>, ContiguousFwd>,
	col0_perm: ColRef<'_, T, Dim<'O>, ContiguousFwd>,
) {
fn secular_eq<'N, T: RealField>(
	shift: T,
	mu: T,
	col0_perm: ColRef<'_, T, Dim<'N>, ContiguousFwd>,
	diag_perm: ColRef<'_, T, Dim<'N>, ContiguousFwd>,
) -> T {
fn batch_secular_eq<'N, const N: usize, T: RealField>(
	shift: &[T;
fn deflate<T: RealField>(
	diag: ColMut<'_, T, usize, ContiguousFwd>,
	col0: ColMut<'_, T, usize, ContiguousFwd>,
	jacobi_coeff: &mut [JacobiRotation<T>],
	jacobi_idx: &mut [usize],
	transpositions: &mut [usize],
	perm: &mut [usize],
	k: usize,
	stack: &mut MemStack,
) -> (usize, usize) {
// condition 4.1
// condition 4.2
// condition 4.3
// condition 4.4
fn deflation_43<T: RealField>(
	diag: ColMut<'_, T, usize, ContiguousFwd>,
	col0: ColMut<'_, T, usize, ContiguousFwd>,
	i: usize,
) -> Option<JacobiRotation<T>> {
fn deflation_44<T: RealField>(
	diag: ColMut<'_, T, usize, ContiguousFwd>,
	col0: ColMut<'_, T, usize, ContiguousFwd>,
	i: usize,
	j: usize,
) -> Option<JacobiRotation<T>> {
	fn rb_mut(&'short mut self) -> Self::Target {
pub(super) fn divide_and_conquer_scratch<T: ComplexField>(
	n: usize,
	qr_fallback_threshold: usize,
	compute_u: bool,
	compute_v: bool,
	par: Par,
) -> StackReq {
pub(super) fn divide_and_conquer<T: RealField>(
	diag: ColMut<'_, T, usize, ContiguousFwd>,
	subdiag: ColMut<'_, T, usize, ContiguousFwd>,
	u: MatU<'_, T>,
	v: Option<MatMut<'_, T>>,
	par: Par,
	stack: &mut MemStack,
	qr_fallback_threshold: usize,
) -> Result<(), SvdError> {
// make the last subdiag zero
// rotation of Q1, q1
// matrix matrix
// rank 1 update
// matrix matrix
// rank 1 update
	fn parse_bidiag(path: &Path) -> (Col<f64>, Col<f64>) {
	fn test_qr_algorithm() {
	fn test_divide_and_conquer() {
	fn test_josef() {
	fn test_deflation43() {
	fn test_deflation44() {
	fn test_both_deflation() {
//! low level implementation of the svd of a matrix
//!
//! the svd of a matrix $A$ of shape $(m, n)$ is a decomposition into three components $U$, $S$,
//! and $V$, such that:
//!
//! - $U$ has shape $(m, m)$ and is a unitary matrix
//! - $V$ has shape $(n, n)$ and is a unitary matrix
//! - $S$ has shape $(m, n)$ and is zero everywhere except the main diagonal
//! - and finally:
//!
//! $$A = U S V^H$$
/// bidiagonalization
/// whether the singular vectors should be computed
/// do not compute singular vectors
/// compute the first $\min(\text{nrows}, \text{ncols})$ singular vectors
/// compute singular vectors
/// svd error
/// reached max iterations
/// svd tuning parameters
/// bidiagonalization parameters
/// $QR$ parameters
/// threshold at which the implementation should stop recursing
/// threshold at which parallelism should be disabled
	fn auto() -> Self {
fn svd_imp_scratch<T: ComplexField>(
	m: usize,
	n: usize,
	compute_u: ComputeSvdVectors,
	compute_v: ComputeSvdVectors,

	bidiag_svd_scratch: fn(n: usize, compute_u: bool, compute_v: bool, par: Par, params: SvdParams) -> StackReq,

	params: SvdParams,

	par: Par,
) -> StackReq {
fn bidiag_cplx_svd_scratch<T: ComplexField>(n: usize, compute_u: bool, compute_v: bool, par: Par, params: SvdParams) -> StackReq {
fn bidiag_real_svd_scratch<T: RealField>(n: usize, compute_u: bool, compute_v: bool, par: Par, params: SvdParams) -> StackReq {
fn compute_bidiag_cplx_svd<T: ComplexField>(
	mut diag: ColMut<'_, T, usize, ContiguousFwd>,
	subdiag: ColMut<'_, T, usize, ContiguousFwd>,
	mut u: Option<MatMut<'_, T>>,
	mut v: Option<MatMut<'_, T>>,
	params: SvdParams,
	par: Par,
	stack: &mut MemStack,
) -> Result<(), SvdError> {
fn compute_bidiag_real_svd<T: RealField>(
	mut diag: ColMut<'_, T, usize, ContiguousFwd>,
	mut subdiag: ColMut<'_, T, usize, ContiguousFwd>,
	mut u: Option<MatMut<'_, T, usize, usize>>,
	mut v: Option<MatMut<'_, T, usize, usize>>,
	params: SvdParams,
	par: Par,
	stack: &mut MemStack,
) -> Result<(), SvdError> {
/// bidiag -> divide conquer svd / qr algo
fn svd_imp<T: ComplexField>(
	matrix: MatRef<'_, T>,
	s: ColMut<'_, T>,
	u: Option<MatMut<'_, T>>,
	v: Option<MatMut<'_, T>>,
	bidiag_svd: fn(
		diag: ColMut<'_, T, usize, ContiguousFwd>,
		subdiag: ColMut<'_, T, usize, ContiguousFwd>,
		u: Option<MatMut<'_, T, usize, usize>>,
		v: Option<MatMut<'_, T, usize, usize>>,
		params: SvdParams,
		par: Par,
		stack: &mut MemStack,
	) -> Result<(), SvdError>,
	par: Par,
	stack: &mut MemStack,
	params: SvdParams,
) -> Result<(), SvdError> {
fn compute_squareish_svd<T: ComplexField>(
	matrix: MatRef<'_, T>,
	s: ColMut<'_, T>,
	u: Option<MatMut<'_, T>>,
	v: Option<MatMut<'_, T>>,
	par: Par,
	stack: &mut MemStack,
	params: SvdParams,
) -> Result<(), SvdError> {
/// computes the layout of the workspace required to compute a matrix's svd
pub fn svd_scratch<T: ComplexField>(
	nrows: usize,
	ncols: usize,
	compute_u: ComputeSvdVectors,
	compute_v: ComputeSvdVectors,
	par: Par,
	params: Spec<SvdParams, T>,
) -> StackReq {
/// computes the svd of $A$, with the singular vectors being omitted, thin or full
///
/// the singular are stored in $S$, and the singular vectors in $U$ and $V$ such that the singular
/// values are sorted in nonincreasing order
pub fn svd<T: ComplexField>(
	A: MatRef<'_, T>,
	s: DiagMut<'_, T>,
	u: Option<MatMut<'_, T>>,
	v: Option<MatMut<'_, T>>,
	par: Par,
	stack: &mut MemStack,
	params: Spec<SvdParams, T>,
) -> Result<(), SvdError> {
// r = u s v
// matrix = q u s v
// conjugate u and v
/// computes the layout of the workspace required to compute a matrix's
/// pseudoinverse, given the svd
pub fn pseudoinverse_from_svd_scratch<T: ComplexField>(nrows: usize, ncols: usize, par: Par) -> StackReq {
/// computes a self-adjoint matrix's pseudoinverse, given the svd factors $S$, $U$ and $V$
pub fn pseudoinverse_from_svd<T: ComplexField>(
	pinv: MatMut<'_, T>,
	s: DiagRef<'_, T>,
	u: MatRef<'_, T>,
	v: MatRef<'_, T>,
	par: Par,
	stack: &mut MemStack,
) {
/// computes a self-adjoint matrix's pseudoinverse, given the svd factors $S$, $U$ and $V$, and
/// tolerance parameters for determining zero singular values
pub fn pseudoinverse_from_svd_with_tolerance<T: ComplexField>(
	pinv: MatMut<'_, T>,
	s: DiagRef<'_, T>,
	u: MatRef<'_, T>,
	v: MatRef<'_, T>,
	abs_tol: T::Real,
	rel_tol: T::Real,
	par: Par,
	stack: &mut MemStack,
) {
	fn test_svd<T: ComplexField>(mat: MatRef<'_, T>) {
	fn test_real() {
	fn test_cplx() {
	fn test_special() {
	fn test_zink() {
	fn test_pinv() {
	fn test_pinv2() {
fn invert_lower_triangular_impl_small<'N, T: ComplexField>(mut dst: MatMut<'_, T, Dim<'N>, Dim<'N>>, src: MatRef<'_, T, Dim<'N>, Dim<'N>>) {
fn invert_unit_lower_triangular_impl_small<'N, T: ComplexField>(mut dst: MatMut<'_, T, Dim<'N>, Dim<'N>>, src: MatRef<'_, T, Dim<'N>, Dim<'N>>) {
fn invert_lower_triangular_impl<'N, T: ComplexField>(dst: MatMut<'_, T, Dim<'N>, Dim<'N>>, src: MatRef<'_, T, Dim<'N>, Dim<'N>>, par: Par) {
// m must be equal to n
fn invert_unit_lower_triangular_impl<'N, T: ComplexField>(dst: MatMut<'_, T, Dim<'N>, Dim<'N>>, src: MatRef<'_, T, Dim<'N>, Dim<'N>>, par: Par) {
// m must be equal to n
/// computes the inverse of the lower triangular matrix `src` (with implicit unit
/// diagonal) and stores the strictly lower triangular part of the result to `dst`.
///
/// # panics
///
/// panics if `src` and `dst` have mismatching dimensions, or if they are not square.
pub fn invert_unit_lower_triangular<T: ComplexField>(dst: MatMut<'_, T>, src: MatRef<'_, T>, par: Par) {
/// computes the inverse of the lower triangular matrix `src` and stores the
/// lower triangular part of the result to `dst`.
///
/// # panics
///
/// panics if `src` and `dst` have mismatching dimensions, or if they are not square.
pub fn invert_lower_triangular<T: ComplexField>(dst: MatMut<'_, T>, src: MatRef<'_, T>, par: Par) {
/// computes the inverse of the upper triangular matrix `src` (with implicit unit
/// diagonal) and stores the strictly upper triangular part of the result to `dst`.
///
/// # panics
///
/// panics if `src` and `dst` have mismatching dimensions, or if they are not square.
pub fn invert_unit_upper_triangular<T: ComplexField>(dst: MatMut<'_, T>, src: MatRef<'_, T>, par: Par) {
/// computes the inverse of the upper triangular matrix `src` and stores the
/// upper triangular part of the result to `dst`.
///
/// # panics
///
/// panics if `src` and `dst` have mismatching dimensions, or if they are not square.
pub fn invert_upper_triangular<T: ComplexField>(dst: MatMut<'_, T>, src: MatRef<'_, T>, par: Par) {
	fn test_invert_lower() {
	fn test_invert_unit_lower() {
	fn test_invert_upper() {
	fn test_invert_unit_upper() {
//! Triangular solve module.
fn identity<T: ComplexField>(x: T) -> T {
fn conjugate<T: ComplexField>(x: T) -> T {
fn solve_unit_lower_triangular_in_place_base_case_generic_imp<'N, 'K, T: ComplexField>(
	tril: MatRef<'_, T, Dim<'N>, Dim<'N>>,
	rhs: MatMut<'_, T, Dim<'N>, Dim<'K>>,
	maybe_conj_lhs: impl Fn(T) -> T,
) {
fn solve_lower_triangular_in_place_base_case_generic_imp<'N, 'K, T: ComplexField>(
	tril: MatRef<'_, T, Dim<'N>, Dim<'N>>,
	rhs: MatMut<'_, T, Dim<'N>, Dim<'K>>,
	maybe_conj_lhs: impl Fn(T) -> T,
) {
fn block_size(n: usize) -> usize {
// we want remainder to be a multiple of register size
fn recursion_threshold() -> usize {
/// solves $L x = b$, implicitly conjugating $L$ if needed, and stores the result in `rhs`
pub fn solve_lower_triangular_in_place_with_conj<T: ComplexField, N: Shape, K: Shape>(
	triangular_lower: MatRef<'_, T, N, N, impl Stride, impl Stride>,
	conj_lhs: Conj,
	rhs: MatMut<'_, T, N, K, impl Stride, impl Stride>,
	par: Par,
) {
/// solves $L x = b$, implicitly conjugating $L$ if needed, and stores the result in `rhs`
pub fn solve_lower_triangular_in_place<T: ComplexField, LhsT: Conjugate<Canonical = T>, N: Shape, K: Shape>(
	triangular_lower: MatRef<'_, LhsT, N, N, impl Stride, impl Stride>,
	rhs: MatMut<'_, T, N, K, impl Stride, impl Stride>,
	par: Par,
) {
/// solves $L x = b$, replacing the diagonal of $L$ with ones, and implicitly conjugating $L$ if
/// needed, and stores the result in `rhs`
pub fn solve_unit_lower_triangular_in_place_with_conj<T: ComplexField, N: Shape, K: Shape>(
	triangular_unit_lower: MatRef<'_, T, N, N, impl Stride, impl Stride>,
	conj_lhs: Conj,
	rhs: MatMut<'_, T, N, K, impl Stride, impl Stride>,
	par: Par,
) {
/// solves $L x = b$, replacing the diagonal of $L$ with ones, and implicitly conjugating $L$ if
/// needed, and stores the result in `rhs`
pub fn solve_unit_lower_triangular_in_place<T: ComplexField, LhsT: Conjugate<Canonical = T>, N: Shape, K: Shape>(
	triangular_unit_lower: MatRef<'_, LhsT, N, N, impl Stride, impl Stride>,
	rhs: MatMut<'_, T, N, K, impl Stride, impl Stride>,
	par: Par,
) {
/// solves $U x = b$, implicitly conjugating $U$ if needed, and stores the result in `rhs`
pub fn solve_upper_triangular_in_place_with_conj<T: ComplexField, N: Shape, K: Shape>(
	triangular_upper: MatRef<'_, T, N, N, impl Stride, impl Stride>,
	conj_lhs: Conj,
	rhs: MatMut<'_, T, N, K, impl Stride, impl Stride>,
	par: Par,
) {
/// solves $U x = b$, implicitly conjugating $U$ if needed, and stores the result in `rhs`
pub fn solve_upper_triangular_in_place<T: ComplexField, LhsT: Conjugate<Canonical = T>, N: Shape, K: Shape>(
	triangular_upper: MatRef<'_, LhsT, N, N, impl Stride, impl Stride>,
	rhs: MatMut<'_, T, N, K, impl Stride, impl Stride>,
	par: Par,
) {
/// solves $U x = b$, replacing the diagonal of $U$ with ones, and implicitly conjugating $U$ if
/// needed, and stores the result in `rhs`
pub fn solve_unit_upper_triangular_in_place_with_conj<T: ComplexField, N: Shape, K: Shape>(
	triangular_unit_upper: MatRef<'_, T, N, N, impl Stride, impl Stride>,
	conj_lhs: Conj,
	rhs: MatMut<'_, T, N, K, impl Stride, impl Stride>,
	par: Par,
) {
/// solves $U x = b$, replacing the diagonal of $U$ with ones, and implicitly conjugating $U$ if
/// needed, and stores the result in `rhs`
pub fn solve_unit_upper_triangular_in_place<T: ComplexField, LhsT: Conjugate<Canonical = T>, N: Shape, K: Shape>(
	triangular_unit_upper: MatRef<'_, LhsT, N, N, impl Stride, impl Stride>,
	rhs: MatMut<'_, T, N, K, impl Stride, impl Stride>,
	par: Par,
) {
fn solve_unit_lower_triangular_in_place_imp<'N, 'K, T: ComplexField>(
	tril: MatRef<'_, T, Dim<'N>, Dim<'N>>,
	conj_lhs: Conj,
	rhs: MatMut<'_, T, Dim<'N>, Dim<'K>>,
	par: Par,
) {
//       (A00    )   X0         (B0)
// ConjA?(A10 A11)   X1 = ConjB?(B1)
//
//
// 1. ConjA?(A00) X0 = ConjB?(B0)
//
// 2. ConjA?(A10) X0 + ConjA?(A11) X1 = ConjB?(B1)
// => ConjA?(A11) X1 = ConjB?(B1) - ConjA?(A10) X0
fn solve_lower_triangular_in_place_imp<'N, 'K, T: ComplexField>(
	tril: MatRef<'_, T, Dim<'N>, Dim<'N>>,
	conj_lhs: Conj,
	rhs: MatMut<'_, T, Dim<'N>, Dim<'K>>,
	par: Par,
) {
//       (A00    )   X0         (B0)
// ConjA?(A10 A11)   X1 = ConjB?(B1)
//
//
// 1. ConjA?(A00) X0 = ConjB?(B0)
//
// 2. ConjA?(A10) X0 + ConjA?(A11) X1 = ConjB?(B1)
// => ConjA?(A11) X1 = ConjB?(B1) - ConjA?(A10) X0
fn solve_unit_upper_triangular_in_place_imp<'N, 'K, T: ComplexField>(
	triu: MatRef<'_, T, Dim<'N>, Dim<'N>>,
	conj_lhs: Conj,
	rhs: MatMut<'_, T, Dim<'N>, Dim<'K>>,
	par: Par,
) {
fn solve_upper_triangular_in_place_imp<'N, 'K, T: ComplexField>(
	triu: MatRef<'_, T, Dim<'N>, Dim<'N>>,
	conj_lhs: Conj,
	rhs: MatMut<'_, T, Dim<'N>, Dim<'K>>,
	par: Par,
) {
	fn into_view(self) -> Self::Target;
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
	fn into_view(self) -> Self::Target {
/// matrix layout transformation. used for zipping optimizations
/// matrix is used as-is
/// matrix rows are reversed
/// matrix is transposed
/// matrix is transposed, then rows are reversed
/// vector layout transformation. used for zipping optimizations
/// vector is used as-is
/// vector is reversed
/// type with a given matrix shape
/// type of rows
/// type of columns
/// returns the number of rows
	fn nrows(this: &Self) -> Self::Rows;
/// returns the number of columns
	fn ncols(this: &Self) -> Self::Cols;
/// indexing type
/// layout transformation type
/// item produced by the zip views
/// matrix type with type erased dimensions
/// returns slice at index of length `n_elems`
	unsafe fn get_slice_unchecked<'a>(this: &'a mut Self, idx: Self::Index, n_elems: usize) -> <Self::Slice as SliceFamily<'a, Self::Item>>::Slice;
/// converts a type erased index back to its original representation
	unsafe fn from_dyn_idx(idx: <Self::Dyn as MatIndex>::Index) -> Self::Index;
/// get the item at the given index, skipping bound checks
	unsafe fn get_unchecked(this: &mut Self, index: Self::Index) -> Self::Item;
/// get the item at the given slice position, skipping bound checks
	unsafe fn next_unchecked<'a>(slice: &mut <Self::Slice as SliceFamily<'a, Self::Item>>::Slice) -> Self::Item;
/// checks if the zip matrices are contiguous
	fn is_contiguous(this: &Self) -> bool;
/// computes the preferred iteration layout of the matrices
	fn preferred_layout(this: &Self) -> Self::LayoutTransform;
/// applies the layout transformation to the matrices
	fn with_layout(this: Self, layout: Self::LayoutTransform) -> Self::Dyn;
/// single matrix
/// single element
/// zipped matrices
/// zipped elements
/// single matrix view
/// creates a zip matrix, after asserting that the dimensions match
	pub fn new(head: Head, tail: Tail) -> Self {
/// creates a zip matrix, assuming that the dimensions match
	pub fn new_unchecked(head: Head, tail: Tail) -> Self {
	fn nrows(this: &Self) -> Self::Rows {
	fn ncols(this: &Self) -> Self::Cols {
	unsafe fn get_slice_unchecked<'a>(this: &'a mut Self, idx: Self::Index, n_elems: usize) -> <Self::Slice as SliceFamily<'a, Self::Item>>::Slice {
	unsafe fn from_dyn_idx(idx: <Self::Dyn as MatIndex>::Index) -> Self::Index {
	unsafe fn get_unchecked(this: &mut Self, index: Self::Index) -> Self::Item {
	unsafe fn next_unchecked<'a>(slice: &mut <Self::Slice as SliceFamily<'a, Self::Item>>::Slice) -> Self::Item {
	fn is_contiguous(this: &Self) -> bool {
	fn preferred_layout(this: &Self) -> Self::LayoutTransform {
	fn with_layout(this: Self, layout: Self::LayoutTransform) -> Self::Dyn {
	fn nrows(this: &Self) -> Self::Rows {
	fn ncols(this: &Self) -> Self::Cols {
	unsafe fn get_slice_unchecked<'a>(this: &'a mut Self, idx: Self::Index, n_elems: usize) -> <Self::Slice as SliceFamily<'a, Self::Item>>::Slice {
	unsafe fn from_dyn_idx(idx: <Self::Dyn as MatIndex>::Index) -> Self::Index {
	unsafe fn get_unchecked(this: &mut Self, index: Self::Index) -> Self::Item {
	unsafe fn next_unchecked<'a>(slice: &mut <Self::Slice as SliceFamily<'a, Self::Item>>::Slice) -> Self::Item {
	fn is_contiguous(this: &Self) -> bool {
	fn preferred_layout(this: &Self) -> Self::LayoutTransform {
	fn with_layout(this: Self, layout: Self::LayoutTransform) -> Self::Dyn {
	fn nrows(this: &Self) -> Self::Rows {
	fn ncols(this: &Self) -> Self::Cols {
	unsafe fn get_slice_unchecked<'a>(this: &'a mut Self, idx: Self::Index, n_elems: usize) -> <Self::Slice as SliceFamily<'a, Self::Item>>::Slice {
	unsafe fn from_dyn_idx(idx: <Self::Dyn as MatIndex>::Index) -> Self::Index {
	unsafe fn get_unchecked(this: &mut Self, (i, j): Self::Index) -> Self::Item {
	unsafe fn next_unchecked<'a>(slice: &mut <Self::Slice as SliceFamily<'a, Self::Item>>::Slice) -> Self::Item {
	fn is_contiguous(this: &Self) -> bool {
	fn preferred_layout(this: &Self) -> Self::LayoutTransform {
	fn with_layout(this: Self, layout: Self::LayoutTransform) -> Self::Dyn {
	fn nrows(this: &Self) -> Self::Rows {
	fn ncols(this: &Self) -> Self::Cols {
	unsafe fn get_slice_unchecked<'a>(this: &'a mut Self, idx: Self::Index, n_elems: usize) -> <Self::Slice as SliceFamily<'a, Self::Item>>::Slice {
	unsafe fn from_dyn_idx(idx: <Self::Dyn as MatIndex>::Index) -> Self::Index {
	unsafe fn get_unchecked(this: &mut Self, (i, j): Self::Index) -> Self::Item {
	unsafe fn next_unchecked<'a>(slice: &mut <Self::Slice as SliceFamily<'a, Self::Item>>::Slice) -> Self::Item {
	fn is_contiguous(this: &Self) -> bool {
	fn preferred_layout(this: &Self) -> Self::LayoutTransform {
	fn with_layout(this: Self, layout: Self::LayoutTransform) -> Self::Dyn {
	fn nrows(this: &Self) -> Self::Rows {
	fn ncols(_: &Self) -> Self::Cols {
	unsafe fn get_slice_unchecked<'a>(this: &'a mut Self, idx: Self::Index, n_elems: usize) -> <Self::Slice as SliceFamily<'a, Self::Item>>::Slice {
	unsafe fn from_dyn_idx(idx: <Self::Dyn as MatIndex>::Index) -> Self::Index {
	unsafe fn get_unchecked(this: &mut Self, i: Self::Index) -> Self::Item {
	unsafe fn next_unchecked<'a>(slice: &mut <Self::Slice as SliceFamily<'a, Self::Item>>::Slice) -> Self::Item {
	fn is_contiguous(this: &Self) -> bool {
	fn preferred_layout(this: &Self) -> Self::LayoutTransform {
	fn with_layout(this: Self, layout: Self::LayoutTransform) -> Self::Dyn {
	fn nrows(this: &Self) -> Self::Rows {
	fn ncols(this: &Self) -> Self::Cols {
	unsafe fn get_slice_unchecked<'a>(this: &'a mut Self, idx: Self::Index, n_elems: usize) -> <Self::Slice as SliceFamily<'a, Self::Item>>::Slice {
	unsafe fn from_dyn_idx(idx: <Self::Dyn as MatIndex>::Index) -> Self::Index {
	unsafe fn get_unchecked(this: &mut Self, i: Self::Index) -> Self::Item {
	unsafe fn next_unchecked<'a>(slice: &mut <Self::Slice as SliceFamily<'a, Self::Item>>::Slice) -> Self::Item {
	fn is_contiguous(this: &Self) -> bool {
	fn preferred_layout(this: &Self) -> Self::LayoutTransform {
	fn with_layout(this: Self, layout: Self::LayoutTransform) -> Self::Dyn {
	fn nrows(_: &Self) -> Self::Rows {
	fn ncols(this: &Self) -> Self::Cols {
	unsafe fn get_slice_unchecked<'a>(this: &'a mut Self, idx: Self::Index, n_elems: usize) -> <Self::Slice as SliceFamily<'a, Self::Item>>::Slice {
	unsafe fn from_dyn_idx(idx: <Self::Dyn as MatIndex>::Index) -> Self::Index {
	unsafe fn get_unchecked(this: &mut Self, i: Self::Index) -> Self::Item {
	unsafe fn next_unchecked<'a>(slice: &mut <Self::Slice as SliceFamily<'a, Self::Item>>::Slice) -> Self::Item {
	fn is_contiguous(this: &Self) -> bool {
	fn preferred_layout(this: &Self) -> Self::LayoutTransform {
	fn with_layout(this: Self, layout: Self::LayoutTransform) -> Self::Dyn {
	fn nrows(this: &Self) -> Self::Rows {
	fn ncols(_: &Self) -> Self::Cols {
	unsafe fn get_slice_unchecked<'a>(this: &'a mut Self, idx: Self::Index, n_elems: usize) -> <Self::Slice as SliceFamily<'a, Self::Item>>::Slice {
	unsafe fn from_dyn_idx(idx: <Self::Dyn as MatIndex>::Index) -> Self::Index {
	unsafe fn get_unchecked(this: &mut Self, i: Self::Index) -> Self::Item {
	unsafe fn next_unchecked<'a>(slice: &mut <Self::Slice as SliceFamily<'a, Self::Item>>::Slice) -> Self::Item {
	fn is_contiguous(this: &Self) -> bool {
	fn preferred_layout(this: &Self) -> Self::LayoutTransform {
	fn with_layout(this: Self, layout: Self::LayoutTransform) -> Self::Dyn {
	fn nrows(this: &Self) -> Self::Rows {
	fn ncols(this: &Self) -> Self::Cols {
	unsafe fn get_slice_unchecked<'a>(this: &'a mut Self, idx: Self::Index, n_elems: usize) -> <Self::Slice as SliceFamily<'a, Self::Item>>::Slice {
	unsafe fn from_dyn_idx(idx: <Self::Dyn as MatIndex>::Index) -> Self::Index {
	unsafe fn get_unchecked(this: &mut Self, i: Self::Index) -> Self::Item {
	unsafe fn next_unchecked<'a>(slice: &mut <Self::Slice as SliceFamily<'a, Self::Item>>::Slice) -> Self::Item {
	fn is_contiguous(this: &Self) -> bool {
	fn preferred_layout(this: &Self) -> Self::LayoutTransform {
	fn with_layout(this: Self, layout: Self::LayoutTransform) -> Self::Dyn {
	fn nrows(_: &Self) -> Self::Rows {
	fn ncols(this: &Self) -> Self::Cols {
	unsafe fn get_slice_unchecked<'a>(this: &'a mut Self, idx: Self::Index, n_elems: usize) -> <Self::Slice as SliceFamily<'a, Self::Item>>::Slice {
	unsafe fn from_dyn_idx(idx: <Self::Dyn as MatIndex>::Index) -> Self::Index {
	unsafe fn get_unchecked(this: &mut Self, i: Self::Index) -> Self::Item {
	unsafe fn next_unchecked<'a>(slice: &mut <Self::Slice as SliceFamily<'a, Self::Item>>::Slice) -> Self::Item {
	fn is_contiguous(this: &Self) -> bool {
	fn preferred_layout(this: &Self) -> Self::LayoutTransform {
	fn with_layout(this: Self, layout: Self::LayoutTransform) -> Self::Dyn {
fn annotate_noalias_mat<Z: MatIndex>(
	f: &mut impl FnMut(<Z as MatIndex>::Item),
	mut slice: <Z::Slice as SliceFamily<'_, Z::Item>>::Slice,
	i_begin: usize,
	i_end: usize,
	_j: usize,
) {
fn annotate_noalias_mat_with_index<Z: MatIndex<Index = (RowIdx, ColIdx)>, RowIdx, ColIdx>(
	f: &mut impl FnMut(RowIdx, ColIdx, <Z as MatIndex>::Item),
	mut slice: <Z::Slice as SliceFamily<'_, Z::Item>>::Slice,
	i_begin: usize,
	i_end: usize,
	j: usize,
	transpose: bool,
	reverse_rows: bool,
) where
	Z::Dyn: MatIndex<Index = (usize, usize)>,
{
fn annotate_noalias_col<Z: MatIndex>(
	f: &mut impl FnMut(<Z as MatIndex>::Item),
	mut slice: <Z::Slice as SliceFamily<'_, Z::Item>>::Slice,
	i_begin: usize,
	i_end: usize,
) {
fn annotate_noalias_col_with_index<Z: MatIndex<Index = Idx>, Idx>(
	f: &mut impl FnMut(Idx, <Z as MatIndex>::Item),
	mut slice: <Z::Slice as SliceFamily<'_, Z::Item>>::Slice,
	i_begin: usize,
	i_end: usize,
	reverse: bool,
) where
	Z::Dyn: MatIndex<Item = Z::Item, Index = usize>,
{
fn for_each_mat<Z: MatIndex>(z: Z, mut f: impl FnMut(<Z as MatIndex>::Item))
where
	Z::Dyn: MatIndex<Item = Z::Item, Slice = Z::Slice, Rows = usize, Cols = usize, Index = (usize, usize)>,
{
// TODO:
// - for_each_vec_with_index
fn for_each_mat_with_index<RowIdx, ColIdx, Z: MatIndex<Index = (RowIdx, ColIdx), LayoutTransform = MatLayoutTransform>>(
	z: Z,
	mut f: impl FnMut(RowIdx, ColIdx, <Z as MatIndex>::Item),
) where
	Z::Dyn: MatIndex<Rows = usize, Cols = usize, Index = (usize, usize), Slice = Z::Slice, Item = Z::Item>,
{
fn for_each_mat_triangular_lower_with_index<RowIdx, ColIdx, Z: MatIndex<Index = (RowIdx, ColIdx), LayoutTransform = MatLayoutTransform>>(
	z: Z,
	diag: Diag,
	mut f: impl FnMut(RowIdx, ColIdx, <Z as MatIndex>::Item),
) where
	Z::Dyn: MatIndex<Rows = usize, Cols = usize, Index = (usize, usize), Item = Z::Item, Slice = Z::Slice>,
{
fn for_each_mat_triangular_upper_with_index<RowIdx, ColIdx, Z: MatIndex<Index = (RowIdx, ColIdx), LayoutTransform = MatLayoutTransform>>(
	z: Z,
	diag: Diag,
	mut f: impl FnMut(RowIdx, ColIdx, <Z as MatIndex>::Item),
) where
	Z::Dyn: MatIndex<Rows = usize, Cols = usize, Index = (usize, usize), Item = Z::Item, Slice = Z::Slice>,
{
fn for_each_mat_triangular_lower<Z: MatIndex<LayoutTransform = MatLayoutTransform>>(
	z: Z,
	diag: Diag,
	transpose: bool,
	mut f: impl FnMut(<Z as MatIndex>::Item),
) where
	Z::Dyn: MatIndex<
			LayoutTransform = MatLayoutTransform,
			Item = Z::Item,
			Slice = Z::Slice,
			Rows = usize,
			Cols = usize,
			Index = (usize, usize),
			Dyn = Z::Dyn,
		>,
{
fn for_each_diag<Z: MatIndex>(z: Z, mut f: impl FnMut(<Z as MatIndex>::Item))
where
	Z::Dyn: MatIndex<Rows = usize, Cols = usize, Index = usize, Item = Z::Item, Slice = Z::Slice>,
{
fn for_each_diag_with_index<Idx, Z: MatIndex<LayoutTransform = VecLayoutTransform, Index = Idx>>(z: Z, mut f: impl FnMut(Idx, <Z as MatIndex>::Item))
where
	Z::Dyn: MatIndex<Rows = usize, Cols = usize, Index = usize, Item = Z::Item, Slice = Z::Slice>,
{
fn for_each_col<Z: MatIndex>(z: Z, mut f: impl FnMut(<Z as MatIndex>::Item))
where
	Z::Dyn: MatIndex<Rows = usize, Cols = (), Index = usize, Item = Z::Item, Slice = Z::Slice>,
{
fn for_each_col_with_index<Idx, Z: MatIndex<LayoutTransform = VecLayoutTransform, Index = Idx>>(z: Z, mut f: impl FnMut(Idx, <Z as MatIndex>::Item))
where
	Z::Dyn: MatIndex<Rows = usize, Cols = (), Index = usize, Item = Z::Item, Slice = Z::Slice>,
{
fn for_each_row_with_index<Idx, Z: MatIndex<LayoutTransform = VecLayoutTransform, Index = Idx>>(z: Z, mut f: impl FnMut(Idx, <Z as MatIndex>::Item))
where
	Z::Dyn: MatIndex<Rows = (), Cols = usize, Index = usize, Item = Z::Item, Slice = Z::Slice>,
{
fn for_each_row<Z: MatIndex>(z: Z, mut f: impl FnMut(<Z as MatIndex>::Item))
where
	Z::Dyn: MatIndex<Rows = (), Cols = usize, Index = usize, Item = Z::Item, Slice = Z::Slice>,
{
/// applies `f` to each element of `self`
	pub fn for_each(self, f: impl FnMut(<Self as MatIndex>::Item)) {
/// applies `f` to each element of `self`, while passing the indices of the position of the
/// current element
	pub fn for_each_with_index(self, f: impl FnMut(Idx<Rows>, Idx<Cols>, <Self as MatIndex>::Item)) {
/// applies `f` to each element of the lower triangular half of `self`, while passing the
/// indices of the position of the current element
///
/// `diag` specifies whether the diagonal should be included or excluded
	pub fn for_each_triangular_lower_with_index(self, diag: Diag, f: impl FnMut(Idx<Rows>, Idx<Cols>, <Self as MatIndex>::Item)) {
/// applies `f` to each element of the upper triangular half of `self`, while passing the
/// indices of the position of the current element
///
/// `diag` specifies whether the diagonal should be included or excluded
	pub fn for_each_triangular_upper_with_index(self, diag: Diag, f: impl FnMut(Idx<Rows>, Idx<Cols>, <Self as MatIndex>::Item)) {
/// applies `f` to each element of the lower triangular half of `self`
///
/// `diag` specifies whether the diagonal should be included or excluded
	pub fn for_each_triangular_lower(self, diag: Diag, f: impl FnMut(<Self as MatIndex>::Item)) {
/// applies `f` to each element of the upper triangular half of `self`
///
/// `diag` specifies whether the diagonal should be included or excluded
	pub fn for_each_triangular_upper(self, diag: Diag, f: impl FnMut(<Self as MatIndex>::Item)) {
/// applies `f` to each element of `self` and collect its result into a new matrix
	pub fn map<T>(self, f: impl FnMut(<Self as MatIndex>::Item) -> T) -> Mat<T, Rows, Cols> {
/// applies `f` to each element of `self` and collect its result into a new matrix
	pub fn map_with_index<T>(self, f: impl FnMut(Idx<Rows>, Idx<Cols>, <Self as MatIndex>::Item) -> T) -> Mat<T, Rows, Cols> {
/// applies `f` to each element of `self`
	pub fn for_each(self, f: impl FnMut(<Self as MatIndex>::Item)) {
/// applies `f` to each element of `self`, while passing the indices of the position of the
/// current element
	pub fn for_each_with_index(self, f: impl FnMut(Idx<Rows>, Idx<Cols>, <Self as MatIndex>::Item)) {
/// applies `f` to each element of the lower triangular half of `self`, while passing the
/// indices of the position of the current element
///
/// `diag` specifies whether the diagonal should be included or excluded
	pub fn for_each_triangular_lower_with_index(self, diag: Diag, f: impl FnMut(Idx<Rows>, Idx<Cols>, <Self as MatIndex>::Item)) {
/// applies `f` to each element of the upper triangular half of `self`, while passing the
/// indices of the position of the current element
///
/// `diag` specifies whether the diagonal should be included or excluded
	pub fn for_each_triangular_upper_with_index(self, diag: Diag, f: impl FnMut(Idx<Rows>, Idx<Cols>, <Self as MatIndex>::Item)) {
/// applies `f` to each element of the lower triangular half of `self`
///
/// `diag` specifies whether the diagonal should be included or excluded
	pub fn for_each_triangular_lower(self, diag: Diag, f: impl FnMut(<Self as MatIndex>::Item)) {
/// applies `f` to each element of the upper triangular half of `self`
///
/// `diag` specifies whether the diagonal should be included or excluded
	pub fn for_each_triangular_upper(self, diag: Diag, f: impl FnMut(<Self as MatIndex>::Item)) {
/// applies `f` to each element of `self` and collect its result into a new matrix
	pub fn map<T>(self, f: impl FnMut(<Self as MatIndex>::Item) -> T) -> Mat<T, Rows, Cols> {
/// applies `f` to each element of `self` and collect its result into a new matrix
	pub fn map_with_index<T>(self, f: impl FnMut(Idx<Rows>, Idx<Cols>, <Self as MatIndex>::Item) -> T) -> Mat<T, Rows, Cols> {
/// applies `f` to each element of `self`
	pub fn for_each(self, f: impl FnMut(<Self as MatIndex>::Item)) {
/// applies `f` to each element of `self`, while passing the indices of the position of the
/// current element
	pub fn for_each_with_index(self, f: impl FnMut(Idx<Rows>, <Self as MatIndex>::Item)) {
/// applies `f` to each element of `self` and collect its result into a new matrix
	pub fn map<T>(self, f: impl FnMut(<Self as MatIndex>::Item) -> T) -> Col<T, Rows> {
/// applies `f` to each element of `self` and collect its result into a new matrix
	pub fn map_with_index<T>(self, f: impl FnMut(Idx<Rows>, <Self as MatIndex>::Item) -> T) -> Col<T, Rows> {
/// applies `f` to each element of `self`
	pub fn for_each(self, f: impl FnMut(<Self as MatIndex>::Item)) {
/// applies `f` to each element of `self`, while passing the indices of the position of the
/// current element
	pub fn for_each_with_index(self, f: impl FnMut(Idx<Rows>, <Self as MatIndex>::Item)) {
/// applies `f` to each element of `self` and collect its result into a new matrix
	pub fn map<T>(self, f: impl FnMut(<Self as MatIndex>::Item) -> T) -> Col<T, Rows> {
/// applies `f` to each element of `self` and collect its result into a new matrix
	pub fn map_with_index<T>(self, f: impl FnMut(Idx<Rows>, <Self as MatIndex>::Item) -> T) -> Col<T, Rows> {
/// applies `f` to each element of `self`
	pub fn for_each(self, f: impl FnMut(<Self as MatIndex>::Item)) {
/// applies `f` to each element of `self`, while passing the indices of the position of the
/// current element
	pub fn for_each_with_index(self, f: impl FnMut(Idx<Dim>, <Self as MatIndex>::Item)) {
/// applies `f` to each element of `self` and collect its result into a new matrix
	pub fn map<T>(self, f: impl FnMut(<Self as MatIndex>::Item) -> T) -> diag::Diag<T, Dim> {
/// applies `f` to each element of `self` and collect its result into a new matrix
	pub fn map_with_index<T>(self, f: impl FnMut(Idx<Dim>, <Self as MatIndex>::Item) -> T) -> diag::Diag<T, Dim> {
/// applies `f` to each element of `self`
	pub fn for_each(self, f: impl FnMut(<Self as MatIndex>::Item)) {
/// applies `f` to each element of `self`, while passing the indices of the position of the
/// current element
	pub fn for_each_with_index(self, f: impl FnMut(Idx<Dim>, <Self as MatIndex>::Item)) {
/// applies `f` to each element of `self` and collect its result into a new matrix
	pub fn map<T>(self, f: impl FnMut(<Self as MatIndex>::Item) -> T) -> diag::Diag<T, Dim> {
/// applies `f` to each element of `self` and collect its result into a new matrix
	pub fn map_with_index<T>(self, f: impl FnMut(Idx<Dim>, <Self as MatIndex>::Item) -> T) -> diag::Diag<T, Dim> {
/// applies `f` to each element of `self`
	pub fn for_each(self, f: impl FnMut(<Self as MatIndex>::Item)) {
/// applies `f` to each element of `self`, while passing the indices of the position of the
/// current element
	pub fn for_each_with_index(self, f: impl FnMut(Idx<Cols>, <Self as MatIndex>::Item)) {
/// applies `f` to each element of `self` and collect its result into a new matrix
	pub fn map<T>(self, f: impl FnMut(<Self as MatIndex>::Item) -> T) -> Row<T, Cols> {
/// applies `f` to each element of `self` and collect its result into a new matrix
	pub fn map_with_index<T>(self, f: impl FnMut(Idx<Cols>, <Self as MatIndex>::Item) -> T) -> Row<T, Cols> {
/// applies `f` to each element of `self`
	pub fn for_each(self, f: impl FnMut(<Self as MatIndex>::Item)) {
/// applies `f` to each element of `self`, while passing the indices of the position of the
/// current element
	pub fn for_each_with_index(self, f: impl FnMut(Idx<Cols>, <Self as MatIndex>::Item)) {
/// applies `f` to each element of `self` and collect its result into a new matrix
	pub fn map<T>(self, f: impl FnMut(<Self as MatIndex>::Item) -> T) -> Row<T, Cols> {
/// applies `f` to each element of `self` and collect its result into a new matrix
	pub fn map_with_index<T>(self, f: impl FnMut(Idx<Cols>, <Self as MatIndex>::Item) -> T) -> Row<T, Cols> {
	fn get(this: Self, row: RowRange, col: ColRange) -> Self::Target {
	unsafe fn get_unchecked(this: Self, row: RowRange, col: ColRange) -> Self::Target {
	fn get(this: Self, row: RowRange, col: ColRange) -> Self::Target {
	unsafe fn get_unchecked(this: Self, row: RowRange, col: ColRange) -> Self::Target {
            fn get(this: Self, row: Idx<$R>, col: ColRange) -> Self::Target {
            unsafe fn get_unchecked(this: Self, row: Idx<$R>, col: ColRange) -> Self::Target {
            fn get(this: Self, row: Idx<$R>, col: ColRange) -> Self::Target {
            unsafe fn get_unchecked(this: Self, row: Idx<$R>, col: ColRange) -> Self::Target {
            fn get(this: Self, row: RowRange, col: Idx<$C>) -> Self::Target {
            unsafe fn get_unchecked(this: Self, row: RowRange, col: Idx<$C>) -> Self::Target {
            fn get(this: Self, row: RowRange, col: Idx<$C>) -> Self::Target {
            unsafe fn get_unchecked(this: Self, row: RowRange, col: Idx<$C>) -> Self::Target {
            fn get(this: Self, row: Idx<$R>, col: Idx<$C>) -> Self::Target {
            unsafe fn get_unchecked(this: Self, row: Idx<$R>, col: Idx<$C>) -> Self::Target {
            fn get(this: Self, row: Idx<$R>, col: Idx<$C>) -> Self::Target {
            unsafe fn get_unchecked(this: Self, row: Idx<$R>, col: Idx<$C>) -> Self::Target {
/// see [`super::MatMut`]
	fn rb(&'short self) -> Self::Target {
	fn rb_mut(&'short mut self) -> Self::Target {
	fn into_const(self) -> Self::Target {
/// equivalent to `MatMut::from_row_major_slice_mut(array.as_flattened_mut(), ROWS, COLS)`
	pub fn from_row_major_array_mut<const ROWS: usize, const COLS: usize>(array: &'a mut [[T;
/// equivalent to `MatMut::from_column_major_slice_mut(array.as_flattened_mut(), ROWS, COLS)`
	pub fn from_column_major_array_mut<const ROWS: usize, const COLS: usize>(array: &'a mut [[T;
/// creates a `MatMut` from a pointer to the matrix data, dimensions, and strides
///
/// the row (resp. column) stride is the offset from the memory address of a given matrix
/// element at index `(row: i, col: j)`, to the memory address of the matrix element at
/// index `(row: i + 1, col: 0)` (resp. `(row: 0, col: i + 1)`). this offset is specified in
/// number of elements, not in bytes
///
/// # safety
/// the behavior is undefined if any of the following conditions are violated:
/// * for each matrix unit, the entire memory region addressed by the matrix must be contained
/// within a single allocation, accessible in its entirety by the corresponding pointer in
/// `ptr`
/// * for each matrix unit, the corresponding pointer must be non null and properly aligned,
/// even for a zero-sized matrix.
/// * the values accessible by the matrix must be initialized at some point before they are
///   read, or
/// references to them are formed
/// * no aliasing (including self aliasing) is allowed. in other words, none of the elements
/// accessible by any matrix unit may be accessed for reads or writes by any other means for
/// the duration of the lifetime `'a`. no two elements within a single matrix unit may point to
/// the same address (such a thing can be achieved with a zero stride, for example), and no two
/// matrix units may point to the same address
///
/// # example
///
/// ```
/// use faer::{MatMut, mat};
///
/// // row major matrix with 2 rows, 3 columns, with a column at the end that we want to skip.
/// // the row stride is the pointer offset from the address of 1.0 to the address of 4.0,
/// // which is 4
/// // the column stride is the pointer offset from the address of 1.0 to the address of 2.0,
/// // which is 1
/// let mut data = [[1.0, 2.0, 3.0, f64::NAN], [4.0, 5.0, 6.0, f64::NAN]];
/// let mut matrix =
/// 	unsafe { MatMut::from_raw_parts_mut(data.as_mut_ptr() as *mut f64, 2, 3, 4, 1) };
///
/// let expected = mat![[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]];
/// assert_eq!(expected.as_ref(), matrix);
/// ```
	pub const unsafe fn from_raw_parts_mut(ptr: *mut T, nrows: Rows, ncols: Cols, row_stride: RStride, col_stride: CStride) -> Self {
/// returns a pointer to the matrix data
	pub fn as_ptr(&self) -> *const T {
/// returns the number of rows of the matrix
	pub fn nrows(&self) -> Rows {
/// returns the number of columns of the matrix
	pub fn ncols(&self) -> Cols {
/// returns the number of rows and columns of the matrix
	pub fn shape(&self) -> (Rows, Cols) {
/// returns the row stride of the matrix, specified in number of elements, not in bytes
	pub fn row_stride(&self) -> RStride {
/// returns the column stride of the matrix, specified in number of elements, not in bytes
	pub fn col_stride(&self) -> CStride {
/// returns a raw pointer to the element at the given index
	pub fn ptr_at(&self, row: IdxInc<Rows>, col: IdxInc<Cols>) -> *const T {
/// returns a raw pointer to the element at the given index, assuming the provided index
/// is within the matrix bounds
///
/// # safety
/// the behavior is undefined if any of the following conditions are violated:
/// * `row < self.nrows()`
/// * `col < self.ncols()`
	pub unsafe fn ptr_inbounds_at(&self, row: Idx<Rows>, col: Idx<Cols>) -> *const T {
/// see [`MatRef::split_at`]
	pub fn split_at(
		self,
		row: IdxInc<Rows>,
		col: IdxInc<Cols>,
	) -> (
		MatRef<'a, T, usize, usize, RStride, CStride>,
		MatRef<'a, T, usize, usize, RStride, CStride>,
		MatRef<'a, T, usize, usize, RStride, CStride>,
		MatRef<'a, T, usize, usize, RStride, CStride>,
	) {
/// see [`MatRef::split_at_row`]
	pub fn split_at_row(self, row: IdxInc<Rows>) -> (MatRef<'a, T, usize, Cols, RStride, CStride>, MatRef<'a, T, usize, Cols, RStride, CStride>) {
/// see [`MatRef::split_at_col`]
	pub fn split_at_col(self, col: IdxInc<Cols>) -> (MatRef<'a, T, Rows, usize, RStride, CStride>, MatRef<'a, T, Rows, usize, RStride, CStride>) {
/// see [`MatRef::transpose`]
	pub fn transpose(self) -> MatRef<'a, T, Cols, Rows, CStride, RStride> {
/// see [`MatRef::conjugate`]
	pub fn conjugate(self) -> MatRef<'a, T::Conj, Rows, Cols, RStride, CStride>
	where
		T: Conjugate,
	{
/// see [`MatRef::canonical`]
	pub fn canonical(self) -> MatRef<'a, T::Canonical, Rows, Cols, RStride, CStride>
	where
		T: Conjugate,
	{
/// see [`MatRef::adjoint`]
	pub fn adjoint(self) -> MatRef<'a, T::Conj, Cols, Rows, CStride, RStride>
	where
		T: Conjugate,
	{
/// see [`MatRef::reverse_rows`]
	pub fn reverse_rows(self) -> MatRef<'a, T, Rows, Cols, RStride::Rev, CStride> {
/// see [`MatRef::reverse_cols`]
	pub fn reverse_cols(self) -> MatRef<'a, T, Rows, Cols, RStride, CStride::Rev> {
/// see [`MatRef::reverse_rows_and_cols`]
	pub fn reverse_rows_and_cols(self) -> MatRef<'a, T, Rows, Cols, RStride::Rev, CStride::Rev> {
/// see [`MatRef::submatrix`]
	pub fn submatrix<V: Shape, H: Shape>(
		self,
		row_start: IdxInc<Rows>,
		col_start: IdxInc<Cols>,
		nrows: V,
		ncols: H,
	) -> MatRef<'a, T, V, H, RStride, CStride> {
/// see [`MatRef::subrows`]
	pub fn subrows<V: Shape>(self, row_start: IdxInc<Rows>, nrows: V) -> MatRef<'a, T, V, Cols, RStride, CStride> {
/// see [`MatRef::subcols`]
	pub fn subcols<H: Shape>(self, col_start: IdxInc<Cols>, ncols: H) -> MatRef<'a, T, Rows, H, RStride, CStride> {
/// see [`MatRef::as_shape`]
	pub fn as_shape<V: Shape, H: Shape>(self, nrows: V, ncols: H) -> MatRef<'a, T, V, H, RStride, CStride> {
/// see [`MatRef::as_row_shape`]
	pub fn as_row_shape<V: Shape>(self, nrows: V) -> MatRef<'a, T, V, Cols, RStride, CStride> {
/// see [`MatRef::as_col_shape`]
	pub fn as_col_shape<H: Shape>(self, ncols: H) -> MatRef<'a, T, Rows, H, RStride, CStride> {
/// see [`MatRef::as_dyn_stride`]
	pub fn as_dyn_stride(self) -> MatRef<'a, T, Rows, Cols, isize, isize> {
/// see [`MatRef::as_dyn`]
	pub fn as_dyn(self) -> MatRef<'a, T, usize, usize, RStride, CStride> {
/// see [`MatRef::as_dyn_rows`]
	pub fn as_dyn_rows(self) -> MatRef<'a, T, usize, Cols, RStride, CStride> {
/// see [`MatRef::as_dyn_cols`]
	pub fn as_dyn_cols(self) -> MatRef<'a, T, Rows, usize, RStride, CStride> {
/// see [`MatRef::row`]
	pub fn row(self, i: Idx<Rows>) -> RowRef<'a, T, Cols, CStride> {
/// see [`MatRef::col`]
	pub fn col(self, j: Idx<Cols>) -> ColRef<'a, T, Rows, RStride> {
/// see [`MatRef::col_iter`]
	pub fn col_iter(self) -> impl 'a + ExactSizeIterator + DoubleEndedIterator<Item = ColRef<'a, T, Rows, RStride>>
	where
		Rows: 'a,
		Cols: 'a,
	{
/// see [`MatRef::row_iter`]
	pub fn row_iter(self) -> impl 'a + ExactSizeIterator + DoubleEndedIterator<Item = RowRef<'a, T, Cols, CStride>>
	where
		Rows: 'a,
		Cols: 'a,
	{
/// see [`MatRef::par_col_iter`]
	pub fn par_col_iter(self) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = ColRef<'a, T, Rows, RStride>>
	where
		T: Sync,
		Rows: 'a,
		Cols: 'a,
	{
/// see [`MatRef::par_row_iter`]
	pub fn par_row_iter(self) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = RowRef<'a, T, Cols, CStride>>
	where
		T: Sync,
		Rows: 'a,
		Cols: 'a,
	{
/// see [`MatRef::par_col_chunks`]
	pub fn par_col_chunks(
		self,
		chunk_size: usize,
	) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = MatRef<'a, T, Rows, usize, RStride, CStride>>
	where
		T: Sync,
		Rows: 'a,
		Cols: 'a,
	{
/// see [`MatRef::par_col_partition`]
	pub fn par_col_partition(
		self,
		count: usize,
	) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = MatRef<'a, T, Rows, usize, RStride, CStride>>
	where
		T: Sync,
		Rows: 'a,
		Cols: 'a,
	{
/// see [`MatRef::par_row_chunks`]
	pub fn par_row_chunks(
		self,
		chunk_size: usize,
	) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = MatRef<'a, T, usize, Cols, RStride, CStride>>
	where
		T: Sync,
		Rows: 'a,
		Cols: 'a,
	{
/// see [`MatRef::par_row_partition`]
	pub fn par_row_partition(
		self,
		count: usize,
	) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = MatRef<'a, T, usize, Cols, RStride, CStride>>
	where
		T: Sync,
		Rows: 'a,
		Cols: 'a,
	{
/// see [`MatRef::try_as_col_major`]
	pub fn try_as_col_major(self) -> Option<MatRef<'a, T, Rows, Cols, ContiguousFwd, CStride>> {
/// see [`MatRef::try_as_row_major`]
	pub fn try_as_row_major(self) -> Option<MatRef<'a, T, Rows, Cols, RStride, ContiguousFwd>> {
	pub unsafe fn const_cast(self) -> MatMut<'a, T, Rows, Cols, RStride, CStride> {
/// see [`MatRef::)]`]	#[doc(hidden)]
	pub fn bind<'M, 'N>(self, row: Guard<'M>, col: Guard<'N>) -> MatMut<'a, T, Dim<'M>, Dim<'N>, RStride, CStride> {
	pub fn bind_r<'M>(self, row: Guard<'M>) -> MatMut<'a, T, Dim<'M>, Cols, RStride, CStride> {
	pub fn bind_c<'N>(self, col: Guard<'N>) -> MatMut<'a, T, Rows, Dim<'N>, RStride, CStride> {
/// see [`MatRef::get`]
	pub fn get<RowRange, ColRange>(
		self,
		row: RowRange,
		col: ColRange,
	) -> <MatRef<'a, T, Rows, Cols, RStride, CStride> as MatIndex<RowRange, ColRange>>::Target
	where
		MatRef<'a, T, Rows, Cols, RStride, CStride>: MatIndex<RowRange, ColRange>,
	{
/// see [`MatRef::get_unchecked`]
///
/// # safety
/// same as [`MatRef::get_unchecked`]
	pub unsafe fn get_unchecked<RowRange, ColRange>(
		self,
		row: RowRange,
		col: ColRange,
	) -> <MatRef<'a, T, Rows, Cols, RStride, CStride> as MatIndex<RowRange, ColRange>>::Target
	where
		MatRef<'a, T, Rows, Cols, RStride, CStride>: MatIndex<RowRange, ColRange>,
	{
/// see [`MatRef::get`]
	pub fn get_mut<RowRange, ColRange>(
		self,
		row: RowRange,
		col: ColRange,
	) -> <MatMut<'a, T, Rows, Cols, RStride, CStride> as MatIndex<RowRange, ColRange>>::Target
	where
		MatMut<'a, T, Rows, Cols, RStride, CStride>: MatIndex<RowRange, ColRange>,
	{
/// see [`MatRef::get_unchecked`]
///
/// # safety
/// same as [`MatRef::get_unchecked`]
	pub unsafe fn get_mut_unchecked<RowRange, ColRange>(
		self,
		row: RowRange,
		col: ColRange,
	) -> <MatMut<'a, T, Rows, Cols, RStride, CStride> as MatIndex<RowRange, ColRange>>::Target
	where
		MatMut<'a, T, Rows, Cols, RStride, CStride>: MatIndex<RowRange, ColRange>,
	{
/// returns a view over `self`
	pub fn as_mut(&mut self) -> MatMut<'_, T, Rows, Cols, RStride, CStride> {
/// copies the lower triangular half of `other`, including the diagonal, into `self`
	pub fn copy_from_triangular_lower<RhsT: Conjugate<Canonical = T>>(&mut self, other: impl AsMatRef<T = RhsT, Rows = Rows, Cols = Cols>)
	where
		T: ComplexField,
	{
		pub fn imp<'M, 'N, T: ComplexField>(this: MatMut<'_, T, Dim<'M>, Dim<'N>>, other: MatRef<'_, T, Dim<'M>, Dim<'N>>, conj_: Conj) {
/// copies the upper triangular half of `other`, including the diagonal, into `self`
	pub fn copy_from_triangular_upper<RhsT: Conjugate<Canonical = T>>(&mut self, other: impl AsMatRef<T = RhsT, Rows = Rows, Cols = Cols>)
	where
		T: ComplexField,
	{
/// copies `other` into `self`
	pub fn copy_from<RhsT: Conjugate<Canonical = T>>(&mut self, other: impl AsMatRef<T = RhsT, Rows = Rows, Cols = Cols>)
	where
		T: ComplexField,
	{
		pub fn imp<'M, 'N, T: ComplexField>(this: MatMut<'_, T, Dim<'M>, Dim<'N>>, other: MatRef<'_, T, Dim<'M>, Dim<'N>>, conj_: Conj) {
/// copies the lower triangular half of `other`, excluding the diagonal, into `self`
	pub fn copy_from_strict_triangular_lower<RhsT: Conjugate<Canonical = T>>(&mut self, other: impl AsMatRef<T = RhsT, Rows = Rows, Cols = Cols>)
	where
		T: ComplexField,
	{
		pub fn imp<'M, 'N, T: ComplexField>(this: MatMut<'_, T, Dim<'M>, Dim<'N>>, other: MatRef<'_, T, Dim<'M>, Dim<'N>>, conj_: Conj) {
/// copies the upper triangular half of `other`, excluding the diagonal, into `self`
	pub fn copy_from_strict_triangular_upper<RhsT: Conjugate<Canonical = T>>(&mut self, other: impl AsMatRef<T = RhsT, Rows = Rows, Cols = Cols>)
	where
		T: ComplexField,
	{
/// fills all the elements of `self` with `value`
	pub fn fill(&mut self, value: T)
	where
		T: Clone,
	{
		fn cloner<T: Clone>(value: T) -> impl for<'a> FnMut(Last<&'a mut T>) {
/// see [`MatRef::as_ptr`]
	pub fn as_ptr_mut(&self) -> *mut T {
/// see [`MatRef::ptr_at`]
	pub fn ptr_at_mut(&self, row: IdxInc<Rows>, col: IdxInc<Cols>) -> *mut T {
/// see [`MatRef::ptr_inbounds_at`]
	pub unsafe fn ptr_inbounds_at_mut(&self, row: Idx<Rows>, col: Idx<Cols>) -> *mut T {
/// see [`MatRef::split_at`]
	pub fn split_at_mut(
		self,
		row: IdxInc<Rows>,
		col: IdxInc<Cols>,
	) -> (
		MatMut<'a, T, usize, usize, RStride, CStride>,
		MatMut<'a, T, usize, usize, RStride, CStride>,
		MatMut<'a, T, usize, usize, RStride, CStride>,
		MatMut<'a, T, usize, usize, RStride, CStride>,
	) {
/// see [`MatRef::split_at_row`]
	pub fn split_at_row_mut(self, row: IdxInc<Rows>) -> (MatMut<'a, T, usize, Cols, RStride, CStride>, MatMut<'a, T, usize, Cols, RStride, CStride>) {
/// see [`MatRef::split_at_col`]
	pub fn split_at_col_mut(self, col: IdxInc<Cols>) -> (MatMut<'a, T, Rows, usize, RStride, CStride>, MatMut<'a, T, Rows, usize, RStride, CStride>) {
/// see [`MatRef::transpose`]
	pub fn transpose_mut(self) -> MatMut<'a, T, Cols, Rows, CStride, RStride> {
/// see [`MatRef::conjugate`]
	pub fn conjugate_mut(self) -> MatMut<'a, T::Conj, Rows, Cols, RStride, CStride>
	where
		T: Conjugate,
	{
/// see [`MatRef::canonical`]
	pub fn canonical_mut(self) -> MatMut<'a, T::Canonical, Rows, Cols, RStride, CStride>
	where
		T: Conjugate,
	{
/// see [`MatRef::adjoint`]
	pub fn adjoint_mut(self) -> MatMut<'a, T::Conj, Cols, Rows, CStride, RStride>
	where
		T: Conjugate,
	{
	pub(crate) fn at_mut(self, row: Idx<Rows>, col: Idx<Cols>) -> &'a mut T {
	pub(crate) unsafe fn at_mut_unchecked(self, row: Idx<Rows>, col: Idx<Cols>) -> &'a mut T {
/// see [`MatRef::reverse_rows`]
	pub fn reverse_rows_mut(self) -> MatMut<'a, T, Rows, Cols, RStride::Rev, CStride> {
/// see [`MatRef::reverse_cols`]
	pub fn reverse_cols_mut(self) -> MatMut<'a, T, Rows, Cols, RStride, CStride::Rev> {
/// see [`MatRef::reverse_rows_and_cols`]
	pub fn reverse_rows_and_cols_mut(self) -> MatMut<'a, T, Rows, Cols, RStride::Rev, CStride::Rev> {
/// see [`MatRef::submatrix`]
	pub fn submatrix_mut<V: Shape, H: Shape>(
		self,
		row_start: IdxInc<Rows>,
		col_start: IdxInc<Cols>,
		nrows: V,
		ncols: H,
	) -> MatMut<'a, T, V, H, RStride, CStride> {
/// see [`MatRef::subrows`]
	pub fn subrows_mut<V: Shape>(self, row_start: IdxInc<Rows>, nrows: V) -> MatMut<'a, T, V, Cols, RStride, CStride> {
/// see [`MatRef::subcols`]
	pub fn subcols_mut<H: Shape>(self, col_start: IdxInc<Cols>, ncols: H) -> MatMut<'a, T, Rows, H, RStride, CStride> {
/// see [`MatRef::as_shape`]
	pub fn as_shape_mut<V: Shape, H: Shape>(self, nrows: V, ncols: H) -> MatMut<'a, T, V, H, RStride, CStride> {
/// see [`MatRef::as_row_shape`]
	pub fn as_row_shape_mut<V: Shape>(self, nrows: V) -> MatMut<'a, T, V, Cols, RStride, CStride> {
/// see [`MatRef::as_col_shape`]
	pub fn as_col_shape_mut<H: Shape>(self, ncols: H) -> MatMut<'a, T, Rows, H, RStride, CStride> {
/// see [`MatRef::as_dyn_stride`]
	pub fn as_dyn_stride_mut(self) -> MatMut<'a, T, Rows, Cols, isize, isize> {
/// see [`MatRef::as_dyn`]
	pub fn as_dyn_mut(self) -> MatMut<'a, T, usize, usize, RStride, CStride> {
/// see [`MatRef::as_dyn_rows`]
	pub fn as_dyn_rows_mut(self) -> MatMut<'a, T, usize, Cols, RStride, CStride> {
/// see [`MatRef::as_dyn_cols`]
	pub fn as_dyn_cols_mut(self) -> MatMut<'a, T, Rows, usize, RStride, CStride> {
/// see [`MatRef::row`]
	pub fn row_mut(self, i: Idx<Rows>) -> RowMut<'a, T, Cols, CStride> {
/// see [`MatRef::col`]
	pub fn col_mut(self, j: Idx<Cols>) -> ColMut<'a, T, Rows, RStride> {
/// see [`MatRef::col_iter`]
	pub fn col_iter_mut(self) -> impl 'a + ExactSizeIterator + DoubleEndedIterator<Item = ColMut<'a, T, Rows, RStride>>
	where
		Rows: 'a,
		Cols: 'a,
	{
/// see [`MatRef::row_iter`]
	pub fn row_iter_mut(self) -> impl 'a + ExactSizeIterator + DoubleEndedIterator<Item = RowMut<'a, T, Cols, CStride>>
	where
		Rows: 'a,
		Cols: 'a,
	{
	pub(crate) unsafe fn as_type<U>(self) -> MatMut<'a, U, Rows, Cols, RStride, CStride> {
/// see [`MatRef::par_col_iter`]
	pub fn par_col_iter_mut(self) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = ColMut<'a, T, Rows, RStride>>
	where
		T: Send,
		Rows: 'a,
		Cols: 'a,
	{
/// see [`MatRef::par_row_iter`]
	pub fn par_row_iter_mut(self) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = RowMut<'a, T, Cols, CStride>>
	where
		T: Send,
		Rows: 'a,
		Cols: 'a,
	{
/// see [`MatRef::par_col_chunks`]
	pub fn par_col_chunks_mut(
		self,
		chunk_size: usize,
	) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = MatMut<'a, T, Rows, usize, RStride, CStride>>
	where
		T: Send,
		Rows: 'a,
		Cols: 'a,
	{
/// see [`MatRef::par_col_partition`]
	pub fn par_col_partition_mut(
		self,
		count: usize,
	) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = MatMut<'a, T, Rows, usize, RStride, CStride>>
	where
		T: Send,
		Rows: 'a,
		Cols: 'a,
	{
/// see [`MatRef::par_row_chunks`]
	pub fn par_row_chunks_mut(
		self,
		chunk_size: usize,
	) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = MatMut<'a, T, usize, Cols, RStride, CStride>>
	where
		T: Send,
		Rows: 'a,
		Cols: 'a,
	{
/// see [`MatRef::par_row_partition`]
	pub fn par_row_partition_mut(
		self,
		count: usize,
	) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = MatMut<'a, T, usize, Cols, RStride, CStride>>
	where
		T: Send,
		Rows: 'a,
		Cols: 'a,
	{
/// see [`MatRef::split_first_row`]
	pub fn split_first_row_mut(self) -> Option<(RowMut<'a, T, Cols, CStride>, MatMut<'a, T, usize, Cols, RStride, CStride>)> {
/// see [`MatRef::split_first_col`]
	pub fn split_first_col_mut(self) -> Option<(ColMut<'a, T, Rows, RStride>, MatMut<'a, T, Rows, usize, RStride, CStride>)> {
/// see [`MatRef::split_last_row`]
	pub fn split_last_row_mut(self) -> Option<(RowMut<'a, T, Cols, CStride>, MatMut<'a, T, usize, Cols, RStride, CStride>)> {
/// see [`MatRef::split_last_col`]
	pub fn split_last_col_mut(self) -> Option<(ColMut<'a, T, Rows, RStride>, MatMut<'a, T, Rows, usize, RStride, CStride>)> {
/// see [`MatRef::split_first_row`]
	pub fn split_first_row(self) -> Option<(RowRef<'a, T, Cols, CStride>, MatRef<'a, T, usize, Cols, RStride, CStride>)> {
/// see [`MatRef::split_first_col`]
	pub fn split_first_col(self) -> Option<(ColRef<'a, T, Rows, RStride>, MatRef<'a, T, Rows, usize, RStride, CStride>)> {
/// see [`MatRef::split_last_row`]
	pub fn split_last_row(self) -> Option<(RowRef<'a, T, Cols, CStride>, MatRef<'a, T, usize, Cols, RStride, CStride>)> {
/// see [`MatRef::split_last_col`]
	pub fn split_last_col(self) -> Option<(ColRef<'a, T, Rows, RStride>, MatRef<'a, T, Rows, usize, RStride, CStride>)> {
/// see [`MatRef::try_as_col_major`]
	pub fn try_as_col_major_mut(self) -> Option<MatMut<'a, T, Rows, Cols, ContiguousFwd, CStride>> {
/// see [`MatRef::try_as_row_major`]
	pub fn try_as_row_major_mut(self) -> Option<MatMut<'a, T, Rows, Cols, RStride, ContiguousFwd>> {
/// returns two views over the given columns
///
/// # panics
/// panics if `i0 == i1`
	pub fn two_cols_mut(self, i0: Idx<Cols>, i1: Idx<Cols>) -> (ColMut<'a, T, Rows, RStride>, ColMut<'a, T, Rows, RStride>) {
/// returns two views over the given rows
///
/// # panics
/// panics if `i0 == i1`
	pub fn two_rows_mut(self, i0: Idx<Rows>, i1: Idx<Rows>) -> (RowMut<'a, T, Cols, CStride>, RowMut<'a, T, Cols, CStride>) {
	pub(crate) fn write(&mut self, i: Idx<Rows>, j: Idx<Cols>, value: T) {
	pub(crate) fn __at_mut(self, (i, j): (Idx<Rows>, Idx<Cols>)) -> &'a mut T {
/// creates a `MatMut` from slice views over the matrix data, and the matrix dimensions.
/// the data is interpreted in a column-major format, so that the first chunk of `nrows`
/// values from the slices goes in the first column of the matrix, the second chunk of `nrows`
/// values goes in the second column, and so on
///
/// # panics
/// the function panics if any of the following conditions are violated:
/// * `nrows * ncols == slice.len()`
///
/// # example
/// ```
/// use faer::{MatMut, mat};
///
/// let mut slice = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0_f64];
/// let view = MatMut::from_column_major_slice_mut(&mut slice, 3, 2);
///
/// let expected = mat![[1.0, 4.0], [2.0, 5.0], [3.0, 6.0]];
/// assert_eq!(expected, view);
/// ```
	pub fn from_column_major_slice_mut(slice: &'a mut [T], nrows: Rows, ncols: Cols) -> Self
	where
		T: Sized,
	{
/// creates a `MatMut` from slice views over the matrix data, and the matrix dimensions.
/// the data is interpreted in a column-major format, where the beginnings of two consecutive
/// columns are separated by `col_stride` elements.
	pub fn from_column_major_slice_with_stride_mut(slice: &'a mut [T], nrows: Rows, ncols: Cols, col_stride: usize) -> Self
	where
		T: Sized,
	{
/// creates a `MatMut` from slice views over the matrix data, and the matrix dimensions.
/// the data is interpreted in a row-major format, so that the first chunk of `ncols`
/// values from the slices goes in the first column of the matrix, the second chunk of `ncols`
/// values goes in the second column, and so on
///
/// # panics
/// the function panics if any of the following conditions are violated:
/// * `nrows * ncols == slice.len()`
///
/// # example
/// ```
/// use faer::{MatMut, mat};
///
/// let mut slice = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0_f64];
/// let view = MatMut::from_row_major_slice_mut(&mut slice, 3, 2);
///
/// let expected = mat![[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]];
/// assert_eq!(expected, view);
/// ```
	pub fn from_row_major_slice_mut(slice: &'a mut [T], nrows: Rows, ncols: Cols) -> Self
	where
		T: Sized,
	{
/// creates a `MatMut` from slice views over the matrix data, and the matrix dimensions.
/// the data is interpreted in a row-major format, where the beginnings of two consecutive
/// rows are separated by `row_stride` elements.
	pub fn from_row_major_slice_with_stride_mut(slice: &'a mut [T], nrows: Rows, ncols: Cols, row_stride: usize) -> Self
	where
		T: Sized,
	{
	pub fn split_with_mut<'TOP, 'BOT, 'LEFT, 'RIGHT>(
		self,
		row: Partition<'TOP, 'BOT, 'ROWS>,
		col: Partition<'LEFT, 'RIGHT, 'COLS>,
	) -> (
		MatMut<'a, T, Dim<'TOP>, Dim<'LEFT>, RStride, CStride>,
		MatMut<'a, T, Dim<'TOP>, Dim<'RIGHT>, RStride, CStride>,
		MatMut<'a, T, Dim<'BOT>, Dim<'LEFT>, RStride, CStride>,
		MatMut<'a, T, Dim<'BOT>, Dim<'RIGHT>, RStride, CStride>,
	) {
	pub fn split_rows_with_mut<'TOP, 'BOT>(
		self,
		row: Partition<'TOP, 'BOT, 'ROWS>,
	) -> (
		MatMut<'a, T, Dim<'TOP>, Cols, RStride, CStride>,
		MatMut<'a, T, Dim<'BOT>, Cols, RStride, CStride>,
	) {
	pub fn split_cols_with_mut<'LEFT, 'RIGHT>(
		self,
		col: Partition<'LEFT, 'RIGHT, 'COLS>,
	) -> (
		MatMut<'a, T, Rows, Dim<'LEFT>, RStride, CStride>,
		MatMut<'a, T, Rows, Dim<'RIGHT>, RStride, CStride>,
	) {
	pub fn split_with<'TOP, 'BOT, 'LEFT, 'RIGHT>(
		self,
		row: Partition<'TOP, 'BOT, 'ROWS>,
		col: Partition<'LEFT, 'RIGHT, 'COLS>,
	) -> (
		MatRef<'a, T, Dim<'TOP>, Dim<'LEFT>, RStride, CStride>,
		MatRef<'a, T, Dim<'TOP>, Dim<'RIGHT>, RStride, CStride>,
		MatRef<'a, T, Dim<'BOT>, Dim<'LEFT>, RStride, CStride>,
		MatRef<'a, T, Dim<'BOT>, Dim<'RIGHT>, RStride, CStride>,
	) {
	pub fn split_rows_with<'TOP, 'BOT>(
		self,
		row: Partition<'TOP, 'BOT, 'ROWS>,
	) -> (
		MatRef<'a, T, Dim<'TOP>, Cols, RStride, CStride>,
		MatRef<'a, T, Dim<'BOT>, Cols, RStride, CStride>,
	) {
	pub fn split_cols_with<'LEFT, 'RIGHT>(
		self,
		col: Partition<'LEFT, 'RIGHT, 'COLS>,
	) -> (
		MatRef<'a, T, Rows, Dim<'LEFT>, RStride, CStride>,
		MatRef<'a, T, Rows, Dim<'RIGHT>, RStride, CStride>,
	) {
/// see [`MatRef::diagonal`]
	pub fn diagonal(self) -> DiagRef<'a, T, Dim, isize> {
/// see [`MatRef::diagonal`]
	pub fn diagonal_mut(self) -> DiagMut<'a, T, Dim, isize> {
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
/// see [MatRef::min]
	pub fn min(self) -> Option<T> {
/// see [MatRef::min]
	pub fn max(self) -> Option<T> {
fn from_strided_column_major_slice_mut_assert(nrows: usize, ncols: usize, col_stride: usize, len: usize) {
// we don't have to worry about size == usize::MAX == slice.len(), because the length of a
// slice can never exceed isize::MAX in bytes, unless the type is zero sized, in which case
// we don't care
fn from_strided_row_major_slice_mut_assert(nrows: usize, ncols: usize, row_stride: usize, len: usize) {
// we don't have to worry about size == usize::MAX == slice.len(), because the length of a
// slice can never exceed isize::MAX in bytes, unless the type is zero sized, in which case
// we don't care
	fn test_min() {
//
	fn test_max() {
//
pub(crate) fn align_for(size: usize, align: usize, needs_drop: bool) -> usize {
// CURSED: currently avoiding inlining to get noalias annotations in llvm
unsafe fn noalias_annotate<T, Rows: Shape, Cols: Shape>(
	iter: &mut [core::mem::MaybeUninit<T>],
	new_nrows: IdxInc<Rows>,
	old_nrows: IdxInc<Rows>,
	f: &mut impl FnMut(Idx<Rows>, Idx<Cols>) -> T,
	j: Idx<Cols>,
) {
	fn drop(&mut self) {
			fn drop(&mut self) {
	fn try_with_capacity(mut row_capacity: usize, col_capacity: usize) -> Result<Self, TryReserveError> {
	fn into_raw_parts(self) -> (NonNull<T>, usize, usize, StackReq) {
	fn drop(&mut self) {
	fn try_with_capacity(row_capacity: usize, col_capacity: usize) -> Result<Self, TryReserveError> {
	fn do_reserve_with(&mut self, nrows: usize, ncols: usize, new_row_capacity: usize, new_col_capacity: usize) -> Result<(), TryReserveError> {
		unsafe fn move_mat(mut new: *mut u8, mut old: *const u8, col_bytes: usize, ncols: usize, new_byte_stride: isize, old_byte_stride: isize) {
	fn try_reserve(&mut self, nrows: usize, ncols: usize, new_row_capacity: usize, new_col_capacity: usize) -> Result<(), TryReserveError> {
	fn drop(&mut self) {
/// see [`super::Mat`]
	fn drop(&mut self) {
	fn drop(&mut self) {
	fn drop(&mut self) {
/// returns an empty matrix of dimension `0×0`.
	pub const fn new() -> Self {
/// reserves the minimum capacity for `row_capacity` rows and `col_capacity`
/// columns without reallocating. does nothing if the capacity is already sufficient
	pub fn with_capacity(row_capacity: usize, col_capacity: usize) -> Self {
	unsafe fn init_with(
		ptr: *mut T,
		old_nrows: IdxInc<Rows>,
		old_ncols: IdxInc<Cols>,
		new_nrows: IdxInc<Rows>,
		new_ncols: IdxInc<Cols>,
		row_capacity: usize,
		f: &mut impl FnMut(Idx<Rows>, Idx<Cols>) -> T,
	) {
/// returns a new matrix with dimensions `(nrows, ncols)`, filled with the provided function
	pub fn from_fn(nrows: Rows, ncols: Cols, f: impl FnMut(Idx<Rows>, Idx<Cols>) -> T) -> Self {
/// returns a new matrix with dimensions `(nrows, ncols)`, filled with zeros
	pub fn zeros(nrows: Rows, ncols: Cols) -> Self
	where
		T: ComplexField,
	{
/// returns a new matrix with dimensions `(nrows, ncols)`, filled with ones
	pub fn ones(nrows: Rows, ncols: Cols) -> Self
	where
		T: ComplexField,
	{
/// returns a new identity matrix, with ones on the diagonal and zeros everywhere else
	pub fn identity(nrows: Rows, ncols: Cols) -> Self
	where
		T: ComplexField,
	{
/// returns a new matrix with dimensions `(nrows, ncols)`, filled with `value`
	pub fn full(nrows: Rows, ncols: Cols, value: T) -> Self
	where
		T: Clone,
	{
/// reserves the minimum capacity for `new_row_capacity` rows and `new_col_capacity`
/// columns without reallocating, or returns an error in case of failure. does nothing if the
/// capacity is already sufficient
	pub fn try_reserve(&mut self, new_row_capacity: usize, new_col_capacity: usize) -> Result<(), TryReserveError> {
/// reserves the minimum capacity for `new_row_capacity` rows and `new_col_capacity`
/// columns without reallocating. does nothing if the capacity is already sufficient
	pub fn reserve(&mut self, new_row_capacity: usize, new_col_capacity: usize) {
/// resizes the matrix in-place so that the new dimensions are `(new_nrows, new_ncols)`.
/// new elements are created with the given function `f`, so that elements at index `(i, j)`
/// are created by calling `f(i, j)`.
	pub fn resize_with(&mut self, new_nrows: Rows, new_ncols: Cols, f: impl FnMut(Idx<Rows>, Idx<Cols>) -> T) {
/// truncates the matrix so that its new dimensions are `new_nrows` and `new_ncols`.  
/// both of the new dimensions must be smaller than or equal to the current dimensions
///
/// # panics
/// the function panics if any of the following conditions are violated:
/// - `new_nrows > self.nrows()`
/// - `new_ncols > self.ncols()`
	pub fn truncate(&mut self, new_nrows: Rows, new_ncols: Cols) {
/// see [`MatRef::as_shape`]
	pub fn into_shape<V: Shape, H: Shape>(self, nrows: V, ncols: H) -> Mat<T, V, H> {
/// set the dimensions of the matrix.
///
/// # safety
/// the behavior is undefined if any of the following conditions are violated:
/// - `nrows < self.row_capacity()`
/// - `ncols < self.col_capacity()`
/// - the elements that were previously out of bounds but are now in bounds must be
/// initialized
	pub unsafe fn set_dims(&mut self, nrows: Rows, ncols: Cols) {
/// returns a reference to a slice over the column at the given index
	pub fn col_as_slice(&self, j: Idx<Cols>) -> &[T] {
/// returns a reference to a slice over the column at the given index
	pub fn col_as_slice_mut(&mut self, j: Idx<Cols>) -> &mut [T] {
/// returns the number of rows of the matrix
	pub fn nrows(&self) -> Rows {
/// returns the number of columns of the matrix
	pub fn ncols(&self) -> Cols {
	fn clone(&self) -> Self {
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
/// returns a pointer to the matrix data
	pub fn as_ptr(&self) -> *const T {
/// returns the number of rows and columns of the matrix
	pub fn shape(&self) -> (Rows, Cols) {
/// returns the row stride of the matrix, specified in number of elements, not in bytes
	pub fn row_stride(&self) -> isize {
/// returns the column stride of the matrix, specified in number of elements, not in bytes
	pub fn col_stride(&self) -> isize {
/// returns a raw pointer to the element at the given index
	pub fn ptr_at(&self, row: IdxInc<Rows>, col: IdxInc<Cols>) -> *const T {
/// returns a raw pointer to the element at the given index, assuming the provided index
/// is within the matrix bounds
///
/// # safety
/// the behavior is undefined if any of the following conditions are violated:
/// * `row < self.nrows()`
/// * `col < self.ncols()`
	pub unsafe fn ptr_inbounds_at(&self, row: Idx<Rows>, col: Idx<Cols>) -> *const T {
/// see [`MatRef::split_at`]
	pub fn split_at(
		&self,
		row: IdxInc<Rows>,
		col: IdxInc<Cols>,
	) -> (
		MatRef<'_, T, usize, usize>,
		MatRef<'_, T, usize, usize>,
		MatRef<'_, T, usize, usize>,
		MatRef<'_, T, usize, usize>,
	) {
/// see [`MatRef::split_at_row`]
	pub fn split_at_row(&self, row: IdxInc<Rows>) -> (MatRef<'_, T, usize, Cols>, MatRef<'_, T, usize, Cols>) {
/// see [`MatRef::split_at_col`]
	pub fn split_at_col(&self, col: IdxInc<Cols>) -> (MatRef<'_, T, Rows, usize>, MatRef<'_, T, Rows, usize>) {
/// see [`MatRef::transpose`]
	pub fn transpose(&self) -> MatRef<'_, T, Cols, Rows> {
/// see [`MatRef::conjugate`]
	pub fn conjugate(&self) -> MatRef<'_, T::Conj, Rows, Cols>
	where
		T: Conjugate,
	{
/// see [`MatRef::canonical`]
	pub fn canonical(&self) -> MatRef<'_, T::Canonical, Rows, Cols>
	where
		T: Conjugate,
	{
/// see [`MatRef::adjoint`]
	pub fn adjoint(&self) -> MatRef<'_, T::Conj, Cols, Rows>
	where
		T: Conjugate,
	{
/// see [`MatRef::reverse_rows`]
	pub fn reverse_rows(&self) -> MatRef<'_, T, Rows, Cols> {
/// see [`MatRef::reverse_cols`]
	pub fn reverse_cols(&self) -> MatRef<'_, T, Rows, Cols> {
/// see [`MatRef::reverse_rows_and_cols`]
	pub fn reverse_rows_and_cols(&self) -> MatRef<'_, T, Rows, Cols> {
/// see [`MatRef::submatrix`]
	pub fn submatrix<V: Shape, H: Shape>(&self, row_start: IdxInc<Rows>, col_start: IdxInc<Cols>, nrows: V, ncols: H) -> MatRef<'_, T, V, H> {
/// see [`MatRef::subrows`]
	pub fn subrows<V: Shape>(&self, row_start: IdxInc<Rows>, nrows: V) -> MatRef<'_, T, V, Cols> {
/// see [`MatRef::subcols`]
	pub fn subcols<H: Shape>(&self, col_start: IdxInc<Cols>, ncols: H) -> MatRef<'_, T, Rows, H> {
/// see [`MatRef::as_shape`]
	pub fn as_shape<V: Shape, H: Shape>(&self, nrows: V, ncols: H) -> MatRef<'_, T, V, H> {
/// see [`MatRef::as_row_shape`]
	pub fn as_row_shape<V: Shape>(&self, nrows: V) -> MatRef<'_, T, V, Cols> {
/// see [`MatRef::as_col_shape`]
	pub fn as_col_shape<H: Shape>(&self, ncols: H) -> MatRef<'_, T, Rows, H> {
/// see [`MatRef::as_dyn_stride`]
	pub fn as_dyn_stride(&self) -> MatRef<'_, T, Rows, Cols, isize, isize> {
/// see [`MatRef::as_dyn`]
	pub fn as_dyn(&self) -> MatRef<'_, T, usize, usize> {
/// see [`MatRef::as_dyn_rows`]
	pub fn as_dyn_rows(&self) -> MatRef<'_, T, usize, Cols> {
/// see [`MatRef::as_dyn_cols`]
	pub fn as_dyn_cols(&self) -> MatRef<'_, T, Rows, usize> {
/// see [`MatRef::row`]
	pub fn row(&self, i: Idx<Rows>) -> RowRef<'_, T, Cols> {
/// see [`MatRef::col`]
	pub fn col(&self, j: Idx<Cols>) -> ColRef<'_, T, Rows> {
/// see [`MatRef::col_iter`]
	pub fn col_iter(&self) -> impl '_ + ExactSizeIterator + DoubleEndedIterator<Item = ColRef<'_, T, Rows>> {
/// see [`MatRef::row_iter`]
	pub fn row_iter(&self) -> impl '_ + ExactSizeIterator + DoubleEndedIterator<Item = RowRef<'_, T, Cols>> {
/// see [`MatRef::par_col_iter`]
	pub fn par_col_iter(&self) -> impl '_ + rayon::iter::IndexedParallelIterator<Item = ColRef<'_, T, Rows>>
	where
		T: Sync,
	{
/// see [`MatRef::par_row_iter`]
	pub fn par_row_iter(&self) -> impl '_ + rayon::iter::IndexedParallelIterator<Item = RowRef<'_, T, Cols>>
	where
		T: Sync,
	{
/// see [`MatRef::par_col_chunks`]
	pub fn par_col_chunks(&self, chunk_size: usize) -> impl '_ + rayon::iter::IndexedParallelIterator<Item = MatRef<'_, T, Rows, usize>>
	where
		T: Sync,
	{
/// see [`MatRef::par_col_partition`]
	pub fn par_col_partition(&self, count: usize) -> impl '_ + rayon::iter::IndexedParallelIterator<Item = MatRef<'_, T, Rows, usize>>
	where
		T: Sync,
	{
/// see [`MatRef::par_row_chunks`]
	pub fn par_row_chunks(&self, chunk_size: usize) -> impl '_ + rayon::iter::IndexedParallelIterator<Item = MatRef<'_, T, usize, Cols>>
	where
		T: Sync,
	{
/// see [`MatRef::par_row_partition`]
	pub fn par_row_partition(&self, count: usize) -> impl '_ + rayon::iter::IndexedParallelIterator<Item = MatRef<'_, T, usize, Cols>>
	where
		T: Sync,
	{
/// see [`MatRef::try_as_col_major`]
	pub fn try_as_col_major(&self) -> Option<MatRef<'_, T, Rows, Cols, ContiguousFwd>> {
/// see [`MatRef::try_as_row_major`]
	pub fn try_as_row_major(&self) -> Option<MatRef<'_, T, Rows, Cols, isize, ContiguousFwd>> {
/// see [`MatRef::get`]
	pub fn get<RowRange, ColRange>(&self, row: RowRange, col: ColRange) -> <MatRef<'_, T, Rows, Cols> as MatIndex<RowRange, ColRange>>::Target
	where
		for<'a> MatRef<'a, T, Rows, Cols>: MatIndex<RowRange, ColRange>,
	{
/// see [`MatRef::get_unchecked`]
	pub unsafe fn get_unchecked<RowRange, ColRange>(
		&self,
		row: RowRange,
		col: ColRange,
	) -> <MatRef<'_, T, Rows, Cols> as MatIndex<RowRange, ColRange>>::Target
	where
		for<'a> MatRef<'a, T, Rows, Cols>: MatIndex<RowRange, ColRange>,
	{
/// see [`MatMut::get_mut`]
	pub fn get_mut<RowRange, ColRange>(&mut self, row: RowRange, col: ColRange) -> <MatMut<'_, T, Rows, Cols> as MatIndex<RowRange, ColRange>>::Target
	where
		for<'a> MatMut<'a, T, Rows, Cols>: MatIndex<RowRange, ColRange>,
	{
/// see [`MatMut::get_mut_unchecked`]
	pub unsafe fn get_mut_unchecked<RowRange, ColRange>(
		&mut self,
		row: RowRange,
		col: ColRange,
	) -> <MatMut<'_, T, Rows, Cols> as MatIndex<RowRange, ColRange>>::Target
	where
		for<'a> MatMut<'a, T, Rows, Cols>: MatIndex<RowRange, ColRange>,
	{
/// returns a pointer to the matrix data
	pub fn as_ptr_mut(&mut self) -> *mut T {
/// returns a raw pointer to the element at the given index
	pub fn ptr_at_mut(&mut self, row: IdxInc<Rows>, col: IdxInc<Cols>) -> *mut T {
/// returns a raw pointer to the element at the given index, assuming the provided index
/// is within the matrix bounds
///
/// # safety
/// the behavior is undefined if any of the following conditions are violated:
/// * `row < self.nrows()`
/// * `col < self.ncols()`
	pub unsafe fn ptr_inbounds_at_mut(&mut self, row: Idx<Rows>, col: Idx<Cols>) -> *mut T {
/// see [`MatMut::split_at_mut`]
	pub fn split_at_mut(
		&mut self,
		row: IdxInc<Rows>,
		col: IdxInc<Cols>,
	) -> (
		MatMut<'_, T, usize, usize>,
		MatMut<'_, T, usize, usize>,
		MatMut<'_, T, usize, usize>,
		MatMut<'_, T, usize, usize>,
	) {
/// see [`MatMut::split_at_row_mut`]
	pub fn split_at_row_mut(&mut self, row: IdxInc<Rows>) -> (MatMut<'_, T, usize, Cols>, MatMut<'_, T, usize, Cols>) {
/// see [`MatMut::split_at_col_mut`]
	pub fn split_at_col_mut(&mut self, col: IdxInc<Cols>) -> (MatMut<'_, T, Rows, usize>, MatMut<'_, T, Rows, usize>) {
/// see [`MatMut::transpose_mut`]
	pub fn transpose_mut(&mut self) -> MatMut<'_, T, Cols, Rows> {
/// see [`MatMut::conjugate_mut`]
	pub fn conjugate_mut(&mut self) -> MatMut<'_, T::Conj, Rows, Cols>
	where
		T: Conjugate,
	{
/// see [`MatMut::canonical_mut`]
	pub fn canonical_mut(&mut self) -> MatMut<'_, T::Canonical, Rows, Cols>
	where
		T: Conjugate,
	{
/// see [`MatMut::adjoint_mut`]
	pub fn adjoint_mut(&mut self) -> MatMut<'_, T::Conj, Cols, Rows>
	where
		T: Conjugate,
	{
/// see [`MatMut::reverse_rows_mut`]
	pub fn reverse_rows_mut(&mut self) -> MatMut<'_, T, Rows, Cols> {
/// see [`MatMut::reverse_cols_mut`]
	pub fn reverse_cols_mut(&mut self) -> MatMut<'_, T, Rows, Cols> {
/// see [`MatMut::reverse_rows_and_cols_mut`]
	pub fn reverse_rows_and_cols_mut(&mut self) -> MatMut<'_, T, Rows, Cols> {
/// see [`MatMut::submatrix_mut`]
	pub fn submatrix_mut<V: Shape, H: Shape>(&mut self, row_start: IdxInc<Rows>, col_start: IdxInc<Cols>, nrows: V, ncols: H) -> MatMut<'_, T, V, H> {
/// see [`MatMut::subrows_mut`]
	pub fn subrows_mut<V: Shape>(&mut self, row_start: IdxInc<Rows>, nrows: V) -> MatMut<'_, T, V, Cols> {
/// see [`MatMut::subcols_mut`]
	pub fn subcols_mut<H: Shape>(&mut self, col_start: IdxInc<Cols>, ncols: H) -> MatMut<'_, T, Rows, H> {
/// see [`MatMut::as_shape_mut`]
	pub fn as_shape_mut<V: Shape, H: Shape>(&mut self, nrows: V, ncols: H) -> MatMut<'_, T, V, H> {
/// see [`MatMut::as_row_shape_mut`]
	pub fn as_row_shape_mut<V: Shape>(&mut self, nrows: V) -> MatMut<'_, T, V, Cols> {
/// see [`MatMut::as_col_shape_mut`]
	pub fn as_col_shape_mut<H: Shape>(&mut self, ncols: H) -> MatMut<'_, T, Rows, H> {
/// see [`MatMut::as_dyn_stride_mut`]
	pub fn as_dyn_stride_mut(&mut self) -> MatMut<'_, T, Rows, Cols, isize, isize> {
/// see [`MatMut::as_dyn_mut`]
	pub fn as_dyn_mut(&mut self) -> MatMut<'_, T, usize, usize> {
/// see [`MatMut::as_dyn_rows_mut`]
	pub fn as_dyn_rows_mut(&mut self) -> MatMut<'_, T, usize, Cols> {
/// see [`MatMut::as_dyn_cols_mut`]
	pub fn as_dyn_cols_mut(&mut self) -> MatMut<'_, T, Rows, usize> {
/// see [`MatMut::row_mut`]
	pub fn row_mut(&mut self, i: Idx<Rows>) -> RowMut<'_, T, Cols> {
/// see [`MatMut::col_mut`]
	pub fn col_mut(&mut self, j: Idx<Cols>) -> ColMut<'_, T, Rows> {
/// see [`MatMut::col_iter_mut`]
	pub fn col_iter_mut(&mut self) -> impl '_ + ExactSizeIterator + DoubleEndedIterator<Item = ColMut<'_, T, Rows>> {
/// see [`MatMut::row_iter_mut`]
	pub fn row_iter_mut(&mut self) -> impl '_ + ExactSizeIterator + DoubleEndedIterator<Item = RowMut<'_, T, Cols>> {
/// see [`MatMut::par_col_iter_mut`]
	pub fn par_col_iter_mut(&mut self) -> impl '_ + rayon::iter::IndexedParallelIterator<Item = ColMut<'_, T, Rows>>
	where
		T: Send,
	{
/// see [`MatMut::par_row_iter_mut`]
	pub fn par_row_iter_mut(&mut self) -> impl '_ + rayon::iter::IndexedParallelIterator<Item = RowMut<'_, T, Cols>>
	where
		T: Send,
	{
/// see [`MatMut::par_col_chunks_mut`]
	pub fn par_col_chunks_mut(&mut self, chunk_size: usize) -> impl '_ + rayon::iter::IndexedParallelIterator<Item = MatMut<'_, T, Rows, usize>>
	where
		T: Send,
	{
/// see [`MatMut::par_col_partition_mut`]
	pub fn par_col_partition_mut(&mut self, count: usize) -> impl '_ + rayon::iter::IndexedParallelIterator<Item = MatMut<'_, T, Rows, usize>>
	where
		T: Send,
	{
/// see [`MatMut::par_row_chunks_mut`]
	pub fn par_row_chunks_mut(&mut self, chunk_size: usize) -> impl '_ + rayon::iter::IndexedParallelIterator<Item = MatMut<'_, T, usize, Cols>>
	where
		T: Send,
	{
/// see [`MatMut::par_row_partition_mut`]
	pub fn par_row_partition_mut(&mut self, count: usize) -> impl '_ + rayon::iter::IndexedParallelIterator<Item = MatMut<'_, T, usize, Cols>>
	where
		T: Send,
	{
/// see [`MatMut::split_first_row_mut`]
	pub fn split_first_row_mut(&mut self) -> Option<(RowMut<'_, T, Cols>, MatMut<'_, T, usize, Cols>)> {
/// see [`MatMut::try_as_col_major_mut`]
	pub fn try_as_col_major_mut(&mut self) -> Option<MatMut<'_, T, Rows, Cols, ContiguousFwd>> {
/// see [`MatMut::try_as_row_major_mut`]
	pub fn try_as_row_major_mut(&mut self) -> Option<MatMut<'_, T, Rows, Cols, isize, ContiguousFwd>> {
/// see [`MatMut::two_cols_mut`]
	pub fn two_cols_mut(&mut self, i0: Idx<Cols>, i1: Idx<Cols>) -> (ColMut<'_, T, Rows>, ColMut<'_, T, Rows>) {
/// see [`MatMut::two_rows_mut`]
	pub fn two_rows_mut(&mut self, i0: Idx<Rows>, i1: Idx<Rows>) -> (RowMut<'_, T, Cols>, RowMut<'_, T, Cols>) {
/// see [`MatRef::diagonal`]
	pub fn diagonal(&self) -> DiagRef<'_, T, Dim, isize> {
/// see [`MatMut::diagonal_mut`]
	pub fn diagonal_mut(&mut self) -> DiagMut<'_, T, Dim, isize> {
	fn rb(&'short self) -> Self::Target {
	fn rb_mut(&'short mut self) -> Self::Target {
/// inserts a row at the end of the matrix
/// # panics
/// The function panics if the number of columns in the row does not match the number of columns
/// in the matrix
	pub fn push_row(&mut self, row: RowRef<'_, T, Cols>)
	where
		T: Clone,
	{
/// inserts a col at the end of the matrix
/// # panics
/// The function panics if the number of rows in the col does not match the number of rows in
/// the matrix
	pub fn push_col(&mut self, col: ColRef<'_, T, Rows>)
	where
		T: Clone,
	{
/// see [MatRef::min]
	pub fn min(self) -> Option<T> {
/// see [MatRef::min]
	pub fn max(self) -> Option<T> {
	fn test_resize() {
// Create a matrix
//
//
	fn test_resize_5() {
// Create a matrix
//
//
//
//
//
//
	fn test_resize_5_1() {
// Create a matrix
//
//
//
//
//
//
	fn test_push_row() {
	fn test_push_row_panic() {
// row has one too many columns
	fn test_push_col() {
	fn test_push_col_panic() {
	fn test_min() {
//
	fn test_max() {
//
/// see [`super::MatRef`]
	fn clone(&self) -> Self {
	fn rb(&'short self) -> Self::Target {
	fn rb_mut(&'short mut self) -> Self::Target {
	fn into_const(self) -> Self::Target {
fn from_strided_column_major_slice_assert(nrows: usize, ncols: usize, col_stride: usize, len: usize) {
/// equivalent to `MatRef::from_row_major_slice(array.as_flattened(), ROWS, COLS)`
	pub fn from_row_major_array<const ROWS: usize, const COLS: usize>(array: &'a [[T;
/// equivalent to `MatRef::from_column_major_slice(array.as_flattened(), ROWS, COLS)`
	pub fn from_column_major_array<const ROWS: usize, const COLS: usize>(array: &'a [[T;
/// creates a `1×1` view over the given element
	pub fn from_ref(value: &'a T) -> Self {
/// creates a `MatRef` from a view over a single element, repeated `nrows×ncols` times
	pub fn from_repeated_ref(value: &'a T, nrows: Rows, ncols: Cols) -> Self {
/// creates a `MatRef` from slice views over the matrix data, and the matrix dimensions.
/// the data is interpreted in a column-major format, so that the first chunk of `nrows`
/// values from the slices goes in the first column of the matrix, the second chunk of `nrows`
/// values goes in the second column, and so on
///
/// # panics
/// the function panics if any of the following conditions are violated:
/// * `nrows * ncols == slice.len()`
///
/// # example
/// ```
/// use faer::{MatRef, mat};
///
/// let slice = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0_f64];
/// let view = MatRef::from_column_major_slice(&slice, 3, 2);
///
/// let expected = mat![[1.0, 4.0], [2.0, 5.0], [3.0, 6.0]];
/// assert_eq!(expected, view);
/// ```
	pub fn from_column_major_slice(slice: &'a [T], nrows: Rows, ncols: Cols) -> Self {
/// creates a `MatRef` from slice views over the matrix data, and the matrix dimensions.
/// the data is interpreted in a column-major format, where the beginnings of two consecutive
/// columns are separated by `col_stride` elements
	pub fn from_column_major_slice_with_stride(slice: &'a [T], nrows: Rows, ncols: Cols, col_stride: usize) -> Self {
/// creates a `MatRef` from slice views over the matrix data, and the matrix dimensions.
/// the data is interpreted in a row-major format, so that the first chunk of `ncols`
/// values from the slices goes in the first column of the matrix, the second chunk of `ncols`
/// values goes in the second column, and so on
///
/// # panics
/// the function panics if any of the following conditions are violated:
/// * `nrows * ncols == slice.len()`
///
/// # example
/// ```
/// use faer::{MatRef, mat};
///
/// let slice = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0_f64];
/// let view = MatRef::from_row_major_slice(&slice, 3, 2);
///
/// let expected = mat![[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]];
/// assert_eq!(expected, view);
/// ```
	pub fn from_row_major_slice(slice: &'a [T], nrows: Rows, ncols: Cols) -> Self {
/// creates a `MatRef` from slice views over the matrix data, and the matrix dimensions.
/// the data is interpreted in a row-major format, where the beginnings of two consecutive
/// rows are separated by `row_stride` elements
	pub fn from_row_major_slice_with_stride(slice: &'a [T], nrows: Rows, ncols: Cols, row_stride: usize) -> Self {
/// creates a `MatRef` from a pointer to the matrix data, dimensions, and strides
///
/// the row (resp. column) stride is the offset from the memory address of a given matrix
/// element at index `(row: i, col: j)`, to the memory address of the matrix element at
/// index `(row: i + 1, col: 0)` (resp. `(row: 0, col: i + 1)`). this offset is specified in
/// number of elements, not in bytes
///
/// # safety
/// the behavior is undefined if any of the following conditions are violated:
/// * for each matrix unit, the entire memory region addressed by the matrix must be contained
/// within a single allocation, accessible in its entirety by the corresponding pointer in
/// `ptr`
/// * for each matrix unit, the corresponding pointer must be properly aligned,
/// even for a zero-sized matrix
/// * the values accessible by the matrix must be initialized at some point before they are
/// read, or references to them are formed
/// * no mutable aliasing is allowed. in other words, none of the elements accessible by any
/// matrix unit may be accessed for writes by any other means for the duration of the lifetime
/// `'a`
///
/// # example
///
/// ```
/// use faer::{MatRef, mat};
///
/// // row major matrix with 2 rows, 3 columns, with a column at the end that we want to skip.
/// // the row stride is the pointer offset from the address of 1.0 to the address of 4.0,
/// // which is 4
/// // the column stride is the pointer offset from the address of 1.0 to the address of 2.0,
/// // which is 1
/// let data = [[1.0, 2.0, 3.0, f64::NAN], [4.0, 5.0, 6.0, f64::NAN]];
/// let matrix = unsafe { MatRef::from_raw_parts(data.as_ptr() as *const f64, 2, 3, 4, 1) };
///
/// let expected = mat![[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]];
/// assert_eq!(expected.as_ref(), matrix);
/// ```
	pub const unsafe fn from_raw_parts(ptr: *const T, nrows: Rows, ncols: Cols, row_stride: RStride, col_stride: CStride) -> Self {
/// returns a pointer to the matrix data
	pub fn as_ptr(&self) -> *const T {
/// returns the number of rows of the matrix
	pub fn nrows(&self) -> Rows {
/// returns the number of columns of the matrix
	pub fn ncols(&self) -> Cols {
/// returns the number of rows and columns of the matrix
	pub fn shape(&self) -> (Rows, Cols) {
/// returns the row stride of the matrix, specified in number of elements, not in bytes
	pub fn row_stride(&self) -> RStride {
/// returns the column stride of the matrix, specified in number of elements, not in bytes
	pub fn col_stride(&self) -> CStride {
/// returns a raw pointer to the element at the given index
	pub fn ptr_at(&self, row: IdxInc<Rows>, col: IdxInc<Cols>) -> *const T {
/// returns a raw pointer to the element at the given index, assuming the provided index
/// is within the matrix bounds
///
/// # safety
/// the behavior is undefined if any of the following conditions are violated:
/// * `row < self.nrows()`
/// * `col < self.ncols()`
	pub unsafe fn ptr_inbounds_at(&self, row: Idx<Rows>, col: Idx<Cols>) -> *const T {
/// splits the matrix horizontally and vertically at the given index into four corners and
/// returns an array of each submatrix, in the following order:
/// * top left
/// * top right
/// * bottom left
/// * bottom right
///
/// # safety
/// the function panics if any of the following conditions are violated:
/// * `row <= self.nrows()`
/// * `col <= self.ncols()`
	pub fn split_at(
		self,
		row: IdxInc<Rows>,
		col: IdxInc<Cols>,
	) -> (
		MatRef<'a, T, usize, usize, RStride, CStride>,
		MatRef<'a, T, usize, usize, RStride, CStride>,
		MatRef<'a, T, usize, usize, RStride, CStride>,
		MatRef<'a, T, usize, usize, RStride, CStride>,
	) {
/// splits the matrix horizontally at the given row into two parts and returns an array of
/// each submatrix, in the following order:
/// * top
/// * bottom
///
/// # panics
/// the function panics if the following condition is violated:
/// * `row <= self.nrows()`
	pub fn split_at_row(self, row: IdxInc<Rows>) -> (MatRef<'a, T, usize, Cols, RStride, CStride>, MatRef<'a, T, usize, Cols, RStride, CStride>) {
/// splits the matrix vertically at the given column into two parts and returns an array of
/// each submatrix, in the following order:
/// * left
/// * right
///
/// # panics
/// the function panics if the following condition is violated:
/// * `col <= self.ncols()`
	pub fn split_at_col(self, col: IdxInc<Cols>) -> (MatRef<'a, T, Rows, usize, RStride, CStride>, MatRef<'a, T, Rows, usize, RStride, CStride>) {
/// returns a view over the transpose of `self`
///
/// # example
/// ```
/// use faer::mat;
///
/// let matrix = mat![[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]];
/// let view = matrix.as_ref();
/// let transpose = view.transpose();
///
/// let expected = mat![[1.0, 4.0], [2.0, 5.0], [3.0, 6.0]];
/// assert_eq!(expected.as_ref(), transpose);
/// ```
	pub fn transpose(self) -> MatRef<'a, T, Cols, Rows, CStride, RStride> {
/// returns a view over the conjugate of `self`
	pub fn conjugate(self) -> MatRef<'a, T::Conj, Rows, Cols, RStride, CStride>
	where
		T: Conjugate,
	{
/// returns an unconjugated view over `self`
	pub fn canonical(self) -> MatRef<'a, T::Canonical, Rows, Cols, RStride, CStride>
	where
		T: Conjugate,
	{
	pub fn __canonicalize(self) -> (MatRef<'a, T::Canonical, Rows, Cols, RStride, CStride>, Conj)
	where
		T: Conjugate,
	{
/// returns a view over the conjugate transpose of `self`.
	pub fn adjoint(self) -> MatRef<'a, T::Conj, Cols, Rows, CStride, RStride>
	where
		T: Conjugate,
	{
	pub(crate) fn at(self, row: Idx<Rows>, col: Idx<Cols>) -> &'a T {
	pub(crate) unsafe fn at_unchecked(self, row: Idx<Rows>, col: Idx<Cols>) -> &'a T {
/// returns a view over the `self`, with the rows in reversed order
///
/// # example
/// ```
/// use faer::mat;
///
/// let matrix = mat![[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]];
/// let view = matrix.as_ref();
/// let reversed_rows = view.reverse_rows();
///
/// let expected = mat![[4.0, 5.0, 6.0], [1.0, 2.0, 3.0]];
/// assert_eq!(expected.as_ref(), reversed_rows);
/// ```
	pub fn reverse_rows(self) -> MatRef<'a, T, Rows, Cols, RStride::Rev, CStride> {
/// returns a view over the `self`, with the columns in reversed order
///
/// # example
/// ```
/// use faer::mat;
///
/// let matrix = mat![[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]];
/// let view = matrix.as_ref();
/// let reversed_cols = view.reverse_cols();
///
/// let expected = mat![[3.0, 2.0, 1.0], [6.0, 5.0, 4.0]];
/// assert_eq!(expected.as_ref(), reversed_cols);
/// ```
	pub fn reverse_cols(self) -> MatRef<'a, T, Rows, Cols, RStride, CStride::Rev> {
/// returns a view over the `self`, with the rows and the columns in reversed order
///
/// # example
/// ```
/// use faer::mat;
///
/// let matrix = mat![[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]];
/// let view = matrix.as_ref();
/// let reversed = view.reverse_rows_and_cols();
///
/// let expected = mat![[6.0, 5.0, 4.0], [3.0, 2.0, 1.0]];
/// assert_eq!(expected.as_ref(), reversed);
/// ```
	pub fn reverse_rows_and_cols(self) -> MatRef<'a, T, Rows, Cols, RStride::Rev, CStride::Rev> {
/// returns a view over the submatrix starting at index `(row_start, col_start)`, and with
/// dimensions `(nrows, ncols)`
///
/// # panics
/// the function panics if any of the following conditions are violated:
/// * `row_start <= self.nrows()`
/// * `col_start <= self.ncols()`
/// * `nrows <= self.nrows() - row_start`
/// * `ncols <= self.ncols() - col_start`
///
/// # example
/// ```
/// use faer::mat;
///
/// let matrix = mat![
/// 	[1.0, 5.0, 9.0], //
/// 	[2.0, 6.0, 10.0],
/// 	[3.0, 7.0, 11.0],
/// 	[4.0, 8.0, 12.0f64],
/// ];
///
/// let view = matrix.as_ref();
/// let submatrix = view.submatrix(
/// 	/* row_start: */ 2, /* col_start: */ 1, /* nrows: */ 2, /* ncols: */ 2,
/// );
///
/// let expected = mat![[7.0, 11.0], [8.0, 12.0f64]];
/// assert_eq!(expected.as_ref(), submatrix);
/// ```
	pub fn submatrix<V: Shape, H: Shape>(
		self,
		row_start: IdxInc<Rows>,
		col_start: IdxInc<Cols>,
		nrows: V,
		ncols: H,
	) -> MatRef<'a, T, V, H, RStride, CStride> {
/// returns a view over the submatrix starting at row `row_start`, and with number of rows
/// `nrows`
///
/// # panics
/// the function panics if any of the following conditions are violated:
/// * `row_start <= self.nrows()`
/// * `nrows <= self.nrows() - row_start`
///
/// # example
/// ```
/// use faer::mat;
///
/// let matrix = mat![
/// 	[1.0, 5.0, 9.0], //
/// 	[2.0, 6.0, 10.0],
/// 	[3.0, 7.0, 11.0],
/// 	[4.0, 8.0, 12.0f64],
/// ];
///
/// let view = matrix.as_ref();
/// let subrows = view.subrows(/* row_start: */ 1, /* nrows: */ 2);
///
/// let expected = mat![[2.0, 6.0, 10.0], [3.0, 7.0, 11.0],];
/// assert_eq!(expected.as_ref(), subrows);
/// ```
	pub fn subrows<V: Shape>(self, row_start: IdxInc<Rows>, nrows: V) -> MatRef<'a, T, V, Cols, RStride, CStride> {
/// returns a view over the submatrix starting at column `col_start`, and with number of
/// columns `ncols`
///
/// # panics
/// the function panics if any of the following conditions are violated:
/// * `col_start <= self.ncols()`
/// * `ncols <= self.ncols() - col_start`
///
/// # example
/// ```
/// use faer::mat;
///
/// let matrix = mat![
/// 	[1.0, 5.0, 9.0], //
/// 	[2.0, 6.0, 10.0],
/// 	[3.0, 7.0, 11.0],
/// 	[4.0, 8.0, 12.0f64],
/// ];
///
/// let view = matrix.as_ref();
/// let subcols = view.subcols(/* col_start: */ 2, /* ncols: */ 1);
///
/// let expected = mat![[9.0], [10.0], [11.0], [12.0f64]];
/// assert_eq!(expected.as_ref(), subcols);
/// ```
	pub fn subcols<H: Shape>(self, col_start: IdxInc<Cols>, ncols: H) -> MatRef<'a, T, Rows, H, RStride, CStride> {
/// returns the input matrix with the given shape after checking that it matches the
/// current shape
	pub fn as_shape<V: Shape, H: Shape>(self, nrows: V, ncols: H) -> MatRef<'a, T, V, H, RStride, CStride> {
/// returns the input matrix with the given row shape after checking that it matches the
/// current row shape
	pub fn as_row_shape<V: Shape>(self, nrows: V) -> MatRef<'a, T, V, Cols, RStride, CStride> {
/// returns the input matrix with the given column shape after checking that it matches the
/// current column shape
	pub fn as_col_shape<H: Shape>(self, ncols: H) -> MatRef<'a, T, Rows, H, RStride, CStride> {
/// returns the input matrix with dynamic stride
	pub fn as_dyn_stride(self) -> MatRef<'a, T, Rows, Cols, isize, isize> {
/// returns the input matrix with dynamic shape
	pub fn as_dyn(self) -> MatRef<'a, T, usize, usize, RStride, CStride> {
/// returns the input matrix with dynamic row shape
	pub fn as_dyn_rows(self) -> MatRef<'a, T, usize, Cols, RStride, CStride> {
/// returns the input matrix with dynamic column shape
	pub fn as_dyn_cols(self) -> MatRef<'a, T, Rows, usize, RStride, CStride> {
/// returns a view over the row at the given index
///
/// # panics
/// the function panics if any of the following conditions are violated:
/// * `row_idx < self.nrows()`
	pub fn row(self, i: Idx<Rows>) -> RowRef<'a, T, Cols, CStride> {
/// returns a view over the column at the given index
///
/// # panics
/// the function panics if any of the following conditions are violated:
/// * `col_idx < self.ncols()`
	pub fn col(self, j: Idx<Cols>) -> ColRef<'a, T, Rows, RStride> {
/// returns an iterator over the columns of the matrix
	pub fn col_iter(self) -> impl 'a + ExactSizeIterator + DoubleEndedIterator<Item = ColRef<'a, T, Rows, RStride>>
	where
		Rows: 'a,
		Cols: 'a,
	{
/// returns an iterator over the rows of the matrix
	pub fn row_iter(self) -> impl 'a + ExactSizeIterator + DoubleEndedIterator<Item = RowRef<'a, T, Cols, CStride>>
	where
		Rows: 'a,
		Cols: 'a,
	{
/// returns a parallel iterator over the columns of the matrix
	pub fn par_col_iter(self) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = ColRef<'a, T, Rows, RStride>>
	where
		T: Sync,
		Rows: 'a,
		Cols: 'a,
	{
		fn col_fn<T, Rows: Shape, RStride: Stride, CStride: Stride>(
			col: MatRef<'_, T, Rows, usize, RStride, CStride>,
		) -> ColRef<'_, T, Rows, RStride> {
/// returns a parallel iterator over the rows of the matrix
	pub fn par_row_iter(self) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = RowRef<'a, T, Cols, CStride>>
	where
		T: Sync,
		Rows: 'a,
		Cols: 'a,
	{
/// returns a parallel iterator that provides successive chunks of the columns of this
/// matrix, with each having at most `chunk_size` columns
///
/// if the number of columns is a multiple of `chunk_size`, then all chunks have
/// `chunk_size` columns
///
/// only available with the `rayon` feature
	pub fn par_col_chunks(
		self,
		chunk_size: usize,
	) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = MatRef<'a, T, Rows, usize, RStride, CStride>>
	where
		T: Sync,
		Rows: 'a,
		Cols: 'a,
	{
/// returns a parallel iterator that provides exactly `count` successive chunks of the columns
/// of this matrix
///
/// only available with the `rayon` feature
	pub fn par_col_partition(
		self,
		count: usize,
	) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = MatRef<'a, T, Rows, usize, RStride, CStride>>
	where
		T: Sync,
		Rows: 'a,
		Cols: 'a,
	{
/// returns a parallel iterator that provides successive chunks of the rows of this matrix,
/// with each having at most `chunk_size` rows
///
/// if the number of rows is a multiple of `chunk_size`, then all chunks have `chunk_size`
/// rows
///
/// only available with the `rayon` feature
	pub fn par_row_chunks(
		self,
		chunk_size: usize,
	) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = MatRef<'a, T, usize, Cols, RStride, CStride>>
	where
		T: Sync,
		Rows: 'a,
		Cols: 'a,
	{
/// returns a parallel iterator that provides exactly `count` successive chunks of the rows
/// of this matrix
///
/// only available with the `rayon` feature
	pub fn par_row_partition(
		self,
		count: usize,
	) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = MatRef<'a, T, usize, Cols, RStride, CStride>>
	where
		T: Sync,
		Rows: 'a,
		Cols: 'a,
	{
/// returns a reference to the first row and a view over the remaining ones if the matrix has
/// at least one row, otherwise `None`
	pub fn split_first_row(self) -> Option<(RowRef<'a, T, Cols, CStride>, MatRef<'a, T, usize, Cols, RStride, CStride>)> {
/// returns a reference to the first column and a view over the remaining ones if the matrix has
/// at least one column, otherwise `None`
	pub fn split_first_col(self) -> Option<(ColRef<'a, T, Rows, RStride>, MatRef<'a, T, Rows, usize, RStride, CStride>)> {
/// returns a reference to the last row and a view over the remaining ones if the matrix has
/// at least one row, otherwise `None`
	pub fn split_last_row(self) -> Option<(RowRef<'a, T, Cols, CStride>, MatRef<'a, T, usize, Cols, RStride, CStride>)> {
/// returns a reference to the last column and a view over the remaining ones if the matrix has
/// at least one column, otherwise `None`
	pub fn split_last_col(self) -> Option<(ColRef<'a, T, Rows, RStride>, MatRef<'a, T, Rows, usize, RStride, CStride>)> {
/// returns a view over the matrix with a static column stride equal to `+1`, or `None`
/// otherwise
	pub fn try_as_row_major(self) -> Option<MatRef<'a, T, Rows, Cols, RStride, ContiguousFwd>> {
	pub fn bind<'M, 'N>(self, row: Guard<'M>, col: Guard<'N>) -> MatRef<'a, T, Dim<'M>, Dim<'N>, RStride, CStride> {
	pub fn bind_r<'M>(self, row: Guard<'M>) -> MatRef<'a, T, Dim<'M>, Cols, RStride, CStride> {
	pub fn bind_c<'N>(self, col: Guard<'N>) -> MatRef<'a, T, Rows, Dim<'N>, RStride, CStride> {
	pub unsafe fn const_cast(self) -> MatMut<'a, T, Rows, Cols, RStride, CStride> {
/// returns a view over the matrix with a static row stride equal to `+1`, or `None` otherwise
	pub fn try_as_col_major(self) -> Option<MatRef<'a, T, Rows, Cols, ContiguousFwd, CStride>> {
/// returns references to the element at the given index, or submatrices if either `row`
/// or `col` is a range, with bound checks
///
/// # panics
/// the function panics if any of the following conditions are violated:
/// * `row` must be contained in `[0, self.nrows())`
/// * `col` must be contained in `[0, self.ncols())`
	pub fn get<RowRange, ColRange>(
		self,
		row: RowRange,
		col: ColRange,
	) -> <MatRef<'a, T, Rows, Cols, RStride, CStride> as MatIndex<RowRange, ColRange>>::Target
	where
		MatRef<'a, T, Rows, Cols, RStride, CStride>: MatIndex<RowRange, ColRange>,
	{
/// equivalent to `self.get(row, ..)`
	pub fn get_r<RowRange>(self, row: RowRange) -> <MatRef<'a, T, Rows, Cols, RStride, CStride> as MatIndex<RowRange, core::ops::RangeFull>>::Target
	where
		MatRef<'a, T, Rows, Cols, RStride, CStride>: MatIndex<RowRange, core::ops::RangeFull>,
	{
/// equivalent to `self.get(.., col)`
	pub fn get_c<ColRange>(self, col: ColRange) -> <MatRef<'a, T, Rows, Cols, RStride, CStride> as MatIndex<core::ops::RangeFull, ColRange>>::Target
	where
		MatRef<'a, T, Rows, Cols, RStride, CStride>: MatIndex<core::ops::RangeFull, ColRange>,
	{
/// returns references to the element at the given index, or submatrices if either `row`
/// or `col` is a range, without bound checks
///
/// # safety
/// the behavior is undefined if any of the following conditions are violated:
/// * `row` must be contained in `[0, self.nrows())`
/// * `col` must be contained in `[0, self.ncols())`
	pub unsafe fn get_unchecked<RowRange, ColRange>(
		self,
		row: RowRange,
		col: ColRange,
	) -> <MatRef<'a, T, Rows, Cols, RStride, CStride> as MatIndex<RowRange, ColRange>>::Target
	where
		MatRef<'a, T, Rows, Cols, RStride, CStride>: MatIndex<RowRange, ColRange>,
	{
	pub(crate) fn __at(self, (i, j): (Idx<Rows>, Idx<Cols>)) -> &'a T {
/// returns a view over `self`
	pub fn as_ref(&self) -> MatRef<'_, T, Rows, Cols, RStride, CStride> {
/// returns a newly allocated matrix holding the cloned values of `self`
	pub fn cloned(&self) -> Mat<T, Rows, Cols>
	where
		T: Clone,
	{
		fn imp<'M, 'N, T: Clone, RStride: Stride, CStride: Stride>(
			this: MatRef<'_, T, Dim<'M>, Dim<'N>, RStride, CStride>,
		) -> Mat<T, Dim<'M>, Dim<'N>> {
/// returns a newly allocated matrix holding the (possibly conjugated) values of `self`
	pub fn to_owned(&self) -> Mat<T::Canonical, Rows, Cols>
	where
		T: Conjugate,
	{
		fn imp<'M, 'N, T, RStride: Stride, CStride: Stride>(
			this: MatRef<'_, T, Dim<'M>, Dim<'N>, RStride, CStride>,
		) -> Mat<T::Canonical, Dim<'M>, Dim<'N>>
		where
			T: Conjugate,
		{
/// returns the maximum norm of `self`
	pub fn norm_max(&self) -> Real<T>
	where
		T: Conjugate,
	{
/// returns the l2 norm of `self`
	pub fn norm_l2(&self) -> Real<T>
	where
		T: Conjugate,
	{
/// returns the squared l2 norm of `self`
	pub fn squared_norm_l2(&self) -> Real<T>
	where
		T: Conjugate,
	{
/// returns the l1 norm of `self`
	pub fn norm_l1(&self) -> Real<T>
	where
		T: Conjugate,
	{
/// returns the sum of the elements of `self`
	pub fn sum(&self) -> T::Canonical
	where
		T: Conjugate,
	{
/// returns the determinant of `self`
	pub fn determinant(&self) -> T::Canonical
	where
		T: Conjugate,
	{
/// kronecker product of two matrices
///
/// the kronecker product of two matrices $A$ and $B$ is a block matrix
/// $B$ with the following structure:
///
/// ```text
/// C = [ a[(0, 0)] * B    , a[(0, 1)] * B    , ... , a[(0, n-1)] * B    ]
///     [ a[(1, 0)] * B    , a[(1, 1)] * B    , ... , a[(1, n-1)] * B    ]
///     [ ...              , ...              , ... , ...              ]
///     [ a[(m-1, 0)] * B  , a[(m-1, 1)] * B  , ... , a[(m-1, n-1)] * B  ]
/// ```
///
/// # panics
///
/// panics if `dst` does not have the correct dimensions. the dimensions
/// of `dst` must be `A.nrows() * B.nrows()` by `A.ncols() * B.ncols()`.
///
/// # example
///
/// ```
/// use faer::linalg::kron::kron;
/// use faer::{Mat, mat};
///
/// let a = mat![[1.0, 2.0], [3.0, 4.0]];
/// let b = mat![[0.0, 5.0], [6.0, 7.0]];
/// let c = mat![
/// 	[0.0, 5.0, 0.0, 10.0],
/// 	[6.0, 7.0, 12.0, 14.0],
/// 	[0.0, 15.0, 0.0, 20.0],
/// 	[18.0, 21.0, 24.0, 28.0],
/// ];
/// let mut dst = Mat::zeros(4, 4);
/// kron(dst.as_mut(), a.as_ref(), b.as_ref());
/// assert_eq!(dst, c);
/// ```
	pub fn kron(&self, rhs: impl AsMatRef<T: Conjugate<Canonical = T::Canonical>>) -> Mat<T::Canonical>
	where
		T: Conjugate,
	{
		fn imp<T: ComplexField>(lhs: MatRef<'_, impl Conjugate<Canonical = T>>, rhs: MatRef<'_, impl Conjugate<Canonical = T>>) -> Mat<T> {
/// returns `true` if all of the elements of `self` are finite.
/// otherwise returns `false`.
	pub fn is_all_finite(&self) -> bool
	where
		T: Conjugate,
	{
		fn imp<T: ComplexField>(A: MatRef<'_, T>) -> bool {
/// returns `true` if `self` is the identity matrix.
/// otherwise returns `false`.
	pub fn is_identity(&self) -> bool
	where
		T: Conjugate,
	{
		fn imp<T: ComplexField>(A: MatRef<'_, T>) -> bool {
/// returns `true` if any of the elements of `self` is `NaN`.
/// otherwise returns `false`.
	pub fn has_nan(&self) -> bool
	where
		T: Conjugate,
	{
		fn imp<T: ComplexField>(A: MatRef<'_, T>) -> bool {
/// returns the diagonal of the matrix
	pub fn diagonal(self) -> DiagRef<'a, T, Dim, isize> {
	pub fn split_with<'TOP, 'BOT, 'LEFT, 'RIGHT>(
		self,
		row: Partition<'TOP, 'BOT, 'ROWS>,
		col: Partition<'LEFT, 'RIGHT, 'COLS>,
	) -> (
		MatRef<'a, T, Dim<'TOP>, Dim<'LEFT>, RStride, CStride>,
		MatRef<'a, T, Dim<'TOP>, Dim<'RIGHT>, RStride, CStride>,
		MatRef<'a, T, Dim<'BOT>, Dim<'LEFT>, RStride, CStride>,
		MatRef<'a, T, Dim<'BOT>, Dim<'RIGHT>, RStride, CStride>,
	) {
	pub fn split_rows_with<'TOP, 'BOT>(
		self,
		row: Partition<'TOP, 'BOT, 'ROWS>,
	) -> (
		MatRef<'a, T, Dim<'TOP>, Cols, RStride, CStride>,
		MatRef<'a, T, Dim<'BOT>, Cols, RStride, CStride>,
	) {
	pub fn split_cols_with<'LEFT, 'RIGHT>(
		self,
		col: Partition<'LEFT, 'RIGHT, 'COLS>,
	) -> (
		MatRef<'a, T, Rows, Dim<'LEFT>, RStride, CStride>,
		MatRef<'a, T, Rows, Dim<'RIGHT>, RStride, CStride>,
	) {
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
		fn imp<'M, 'N, T: core::fmt::Debug>(this: MatRef<'_, T, Dim<'M>, Dim<'N>>, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
	pub(crate) fn internal_max(self) -> Option<T> {
	pub(crate) fn internal_min(self) -> Option<T> {
/// Returns the maximum element in the matrix
///
/// # Returns
///
/// * `Option<T>` - The maximum element in the matrix, or `None` if the matrix is empty
///
/// # Examples
///
/// ```
/// use faer::{Mat, mat};
///
/// let m = mat![[1.0, 5.0, 3.0], [4.0, 2.0, 9.0], [7.0, 8.0, 6.0],];
///
/// assert_eq!(m.max(), Some(9.0));
///
/// let empty: Mat<f64> = Mat::new();
/// assert_eq!(empty.max(), None);
/// ```
	pub fn max(self) -> Option<T> {
/// Returns the minimum element in the matrix
///
/// # Returns
///
/// * `Option<T>` - The minimum element in the matrix, or `None` if the matrix is empty
///
/// # Examples
///
/// ```
/// use faer::{Mat, mat};
///
/// let m = mat![[1.0, 5.0, 3.0], [4.0, 2.0, 9.0], [7.0, 8.0, 6.0],];
///
/// assert_eq!(m.min(), Some(1.0));
///
/// let empty: Mat<f64> = Mat::new();
/// assert_eq!(empty.min(), None);
/// ```
	pub fn min(self) -> Option<T> {
	fn test_min() {
//
	fn test_max() {
//
/// represents a type that can be used to slice a matrix, such as an index or a range of indices
/// sliced view type
/// slice `this` using `row` and `col`
	fn get(this: Self, row: RowRange, col: ColRange) -> Self::Target;
/// slice `this` using `row` and `col` without bound checks
	unsafe fn get_unchecked(this: Self, row: RowRange, col: ColRange) -> Self::Target;
	fn clone(&self) -> Self {
fn from_slice_assert(nrows: usize, ncols: usize, len: usize) {
/// heap allocated resizable matrix, similar to a 2d [`alloc::vec::Vec`]
///
/// # note
///
/// the memory layout of `Own` is guaranteed to be column-major, meaning that it has a row stride
/// of `1`, and an unspecified column stride that can be queried with [`Mat::col_stride`]
///
/// this implies that while each individual column is stored contiguously in memory, the matrix as
/// a whole may not necessarily be contiguous. the implementation may add padding at the end of
/// each column when overaligning each column can provide a performance gain
///
/// let us consider a 3×4 matrix
///
/// ```notcode
///  0 │ 3 │ 6 │  9
/// ───┼───┼───┼───
///  1 │ 4 │ 7 │ 10
/// ───┼───┼───┼───
///  2 │ 5 │ 8 │ 11
/// ```
/// the memory representation of the data held by such a matrix could look like the following:
///
/// ```notcode
/// [0, 1, 2, x, 3, 4, 5, x, 6, 7, 8, x, 9, 10, 11, x]
/// ```
///
/// where `x` represents padding elements
/// immutable view over a matrix, similar to an immutable reference to a 2d strided [prim@slice]
///
/// # Note
///
/// unlike a slice, the data pointed to by `MatRef<'_, T>` is allowed to be partially or fully
/// uninitialized under certain conditions. in this case, care must be taken to not perform any
/// operations that read the uninitialized values, either directly or indirectly through any of the
/// numerical library routines, unless it is explicitly permitted
/// mutable view over a matrix, similar to a mutable reference to a 2d strided [prim@slice]
///
/// # note
///
/// unlike a slice, the data pointed to by `MatMut<'_, T>` is allowed to be partially or fully
/// uninitialized under certain conditions. In this case, care must be taken to not perform any
/// operations that read the uninitialized values, either directly or indirectly through any of the
/// numerical library routines, unless it is explicitly permitted
///
/// # move semantics
/// since `MatMut` mutably borrows data, it cannot be [`Copy`]. this means that if we pass a
/// `MatMut` to a function that takes it by value, or use a method that consumes `self` like
/// [`MatMut::transpose_mut`], this renders the original variable unusable
///
/// ```compile_fail
/// use faer::{Mat, MatMut};
///
/// fn takes_matmut(view: MatMut<'_, f64>) {}
///
/// let mut matrix = Mat::new();
/// let view = matrix.as_mut();
///
/// takes_matmut(view); // `view` is moved (passed by value)
/// takes_matmut(view); // this fails to compile since `view` was moved
/// ```
/// the way to get around it is to use the [`reborrow::ReborrowMut`] trait, which allows us to
/// mutably borrow a `MatMut` to obtain another `MatMut` for the lifetime of the borrow.
/// it's also similarly possible to immutably borrow a `MatMut` to obtain a `MatRef` for the
/// lifetime of the borrow, using [`reborrow::Reborrow`]
/// ```
/// use faer::{Mat, MatMut, MatRef};
/// use reborrow::*;
///
/// fn takes_matmut(view: MatMut<'_, f64>) {}
/// fn takes_matref(view: MatRef<'_, f64>) {}
///
/// let mut matrix = Mat::new();
/// let mut view = matrix.as_mut();
///
/// takes_matmut(view.rb_mut());
/// takes_matmut(view.rb_mut());
/// takes_matref(view.rb());
/// // view is still usable here
/// ```
/// generic `Mat` wrapper
/// generic `Mat` wrapper
		fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
/// wrap by reference
		pub fn from_inner_ref(inner: &Inner) -> &Self {
/// wrap by mutable reference
		pub fn from_inner_mut(inner: &mut Inner) -> &mut Self {
		fn deref(&self) -> &Self::Target {
		fn deref_mut(&mut self) -> &mut Self::Target {
		fn rb(&'short self) -> Self::Target {
		fn rb_mut(&'short mut self) -> Self::Target {
		fn into_const(self) -> Self::Target {
		fn index(&self, (row, col): (Idx<Rows>, Idx<Cols>)) -> &Self::Output {
		fn index_mut(&mut self, (row, col): (Idx<Rows>, Idx<Cols>)) -> &mut Self::Output {
/// trait for types that can be converted to a matrix view
/// scalar type
/// row dimension type
/// column dimension type
/// owned matrix type
/// returns a view over `self`
	fn as_mat_ref(&self) -> MatRef<'_, Self::T, Self::Rows, Self::Cols>;
/// trait for types that can be converted to a matrix view
/// returns a view over `self`
	fn as_mat_mut(&mut self) -> MatMut<'_, Self::T, Self::Rows, Self::Cols>;
/// trait for owning matrix types
/// returns a matrix with dimensions `(rows, cols)` filled with zeros
	fn zeros(rows: Self::Rows, cols: Self::Cols) -> Self
	where
		T: ComplexField;
/// returns a matrix with dimensions `(rows, cols)` filled with zeros
	fn truncate(&mut self, rows: Self::Rows, cols: Self::Cols);
	fn as_mat_ref(&self) -> MatRef<'_, Self::T, Self::Rows, Self::Cols> {
	fn as_mat_ref(&self) -> MatRef<'_, Self::T, Self::Rows, Self::Cols> {
	fn as_mat_mut(&mut self) -> MatMut<'_, Self::T, Self::Rows, Self::Cols> {
	fn as_mat_ref(&self) -> MatRef<'_, T, Rows, Cols> {
	fn as_mat_ref(&self) -> MatRef<'_, T, Rows, Cols> {
	fn as_mat_mut(&mut self) -> MatMut<'_, T, Rows, Cols> {
	fn as_mat_ref(&self) -> MatRef<'_, T, Rows, Cols> {
	fn zeros(rows: Rows, cols: Cols) -> Self
	where
		T: ComplexField,
	{
	fn truncate(&mut self, rows: Self::Rows, cols: Self::Cols) {
	fn as_mat_mut(&mut self) -> MatMut<'_, T, Rows, Cols> {
	fn test_mat() {
	fn test_mat_complex() {
/// computes the layout of required workspace for executing the bicgstab algorithm
pub fn bicgstab_scratch<T: ComplexField>(
	left_precond: impl Precond<T>,
	right_precond: impl Precond<T>,
	mat: impl LinOp<T>,
	rhs_ncols: usize,
	par: Par,
) -> StackReq {
	fn implementation<T: ComplexField>(K1: &dyn Precond<T>, K2: &dyn Precond<T>, A: &dyn LinOp<T>, rhs_ncols: usize, par: Par) -> StackReq {
// row_perm
// row_perm_inv
// col_perm
// col_perm_inv
// rtv
// r
// p
// r_tilde
// v
// y
// s
// t
// z
// y0 | z0 | ks
// rtr | rtt
// temp
// rtr | rtt
/// algorithm parameters
/// whether the initial guess is implicitly zero or not
/// absolute tolerance for convergence testing
/// relative tolerance for convergence testing
/// maximum number of iterations
	fn default() -> Self {
/// algorithm result
/// absolute residual at the final step
/// relative residual at the final step
/// number of iterations executed by the algorithm
/// algorithm error
/// convergence failure
/// absolute residual at the final step
/// relative residual at the final step
/// executes bicgstab using the provided preconditioners
///
/// # note
/// this function is also optimized for a rhs with multiple columns
pub fn bicgstab<T: ComplexField>(
	out: MatMut<'_, T>,
	left_precond: impl Precond<T>,
	right_precond: impl Precond<T>,
	mat: impl LinOp<T>,
	rhs: MatRef<'_, T>,
	params: BicgParams<T::Real>,
	callback: impl FnMut(MatRef<'_, T>),
	par: Par,
	stack: &mut MemStack,
) -> Result<BicgInfo<T::Real>, BicgError<T::Real>> {
	fn implementation<T: ComplexField>(
		out: MatMut<'_, T>,
		left_precond: &dyn Precond<T>,
		right_precond: &dyn Precond<T>,
		mat: &dyn LinOp<T>,
		rhs: MatRef<'_, T>,
		params: BicgParams<T::Real>,
		callback: &mut dyn FnMut(MatRef<'_, T>),
		par: Par,
		stack: &mut MemStack,
	) -> Result<BicgInfo<T::Real>, BicgError<T::Real>> {
	fn test_bicgstab() {
/// algorithm parameters
/// whether the initial guess is implicitly zero or not
/// absolute tolerance for convergence testing
/// relative tolerance for convergence testing
/// maximum number of iterations
/// algorithm result
/// absolute residual at the final step
/// relative residual at the final step
/// number of iterations executed by the algorithm
/// algorithm error
/// operator was detected to not be positive definite
/// preconditioner was detected to not be positive definite
/// convergence failure
/// absolute residual at the final step
/// relative residual at the final step
	fn default() -> Self {
/// computes the layout of required workspace for executing the conjugate gradient
/// algorithm
pub fn conjugate_gradient_scratch<T: ComplexField>(precond: impl Precond<T>, mat: impl LinOp<T>, rhs_ncols: usize, par: Par) -> StackReq {
	fn implementation<T: ComplexField>(M: &dyn Precond<T>, A: &dyn LinOp<T>, rhs_ncols: usize, par: Par) -> StackReq {
// residual
// p
// z
// rtz
// perm
// perm_inv
// Ap
// ptAp | rtz_new
// ptAp | rtz
// alpha | beta
// alpha_perm | beta_perm
/// executes the conjugate gradient using the provided preconditioner
///
/// # note
/// this function is also optimized for a rhs with multiple columns
pub fn conjugate_gradient<T: ComplexField>(
	out: MatMut<'_, T>,
	precond: impl Precond<T>,
	mat: impl LinOp<T>,
	rhs: MatRef<'_, T>,
	params: CgParams<T::Real>,
	callback: impl FnMut(MatRef<'_, T>),
	par: Par,
	stack: &mut MemStack,
) -> Result<CgInfo<T::Real>, CgError<T::Real>> {
	fn implementation<T: ComplexField>(
		mut x: MatMut<'_, T>,
		M: &dyn Precond<T>,
		A: &dyn LinOp<T>,
		b: MatRef<'_, T>,

		params: CgParams<T::Real>,
		callback: &mut dyn FnMut(MatRef<'_, T>),
		par: Par,
		mut stack: &mut MemStack,
	) -> Result<CgInfo<T::Real>, CgError<T::Real>> {
	fn test_cg() {
	fn test_cg_breakdown() {
/// partial eigendecomposition tuning parameters.
/// minimum projection subspace dimension.
/// maximum projection subspace dimension.
/// maximum number of algorithm restarts.
/// partial eigendecomposition tuning parameters.
/// number of converged eigenvalues and eigenvectors.
	fn default() -> Self {
fn iterate_arnoldi<T: ComplexField>(A: &dyn LinOp<T>, H: MatMut<'_, T>, V: MatMut<'_, T>, start: usize, end: usize, par: Par, stack: &mut MemStack) {
fn schur_swap<T: ComplexField>(a: MatMut<T>, q: Option<MatMut<T>>, j0: usize, n1: usize, n2: usize) -> isize {
fn reorder_schur<T: ComplexField>(mut A: MatMut<'_, T>, mut Q: Option<MatMut<'_, T>>, mut ifst: usize, mut ilst: usize) {
// *
// * Determine the first row of the specified block and find out
// * if it is 1-by-1 or 2-by-2.
// *
// *
// * Determine the first row of the final block
// * and find out if it is 1-by-1 or 2-by-2.
// *
// * Swap with next one below.
// * Current block either 1-by-1 or 2-by-2.
// * Test if 2-by-2 block breaks into two 1-by-1 blocks.
// * Current block consists of two 1-by-1 blocks, each of which
// * must be swapped individually.
// * Swap two 1-by-1 blocks.
// * Recompute NBNEXT in case of 2-by-2 split.
// * 2-by-2 block did not split.
// * 2-by-2 block did split.
// * Swap with next one below.
// * Current block either 1-by-1 or 2-by-2.
// * Test if 2-by-2 block breaks into two 1-by-1 blocks.
// * Current block consists of two 1-by-1 blocks, each of which
// * must be swapped individually.
// * Swap two 1-by-1 blocks.
// * Recompute NBNEXT in case of 2-by-2 split.
// * 2-by-2 block did not split.
// * 2-by-2 block did split.
fn partial_schur_real_imp<T: RealField>(
	eigvecs: MatMut<'_, Complex<T>>,
	eigvals: &mut [Complex<T>],

	A: &dyn LinOp<T>,
	v0: ColRef<'_, T>,
	min_dim: usize,
	max_dim: usize,
	n_eigval: usize,
	tol: T,
	restarts: usize,
	par: Par,
	stack: &mut MemStack,
) -> usize {
// AV = VH
// x in span(V)
// Ax = AV y = (VH + f e*) y = k V y + f e* y = kx + f * y[-1]
fn partial_schur_cplx_imp<T: ComplexField>(
	eigvecs: MatMut<'_, Complex<T::Real>>,
	eigvals: &mut [Complex<T::Real>],

	A: &dyn LinOp<T>,
	v0: ColRef<'_, T>,
	min_dim: usize,
	max_dim: usize,
	n_eigval: usize,
	tol: T::Real,
	restarts: usize,
	par: Par,
	stack: &mut MemStack,
) -> usize {
// AV = VH
// x in span(V)
// Ax = AV y = (VH + f e*) y = k V y + f e* y = kx + f * y[-1]
/// computes the layout of required workspace for computing the `n_eigval` eigenvalues
/// (and corresponding eigenvectors) of $A$ with the largest magnitude.
pub fn partial_eigen_scratch<T: ComplexField>(A: &dyn LinOp<T>, n_eigval: usize, par: Par, params: PartialEigenParams) -> StackReq {
/// computes an estimate of the eigenvalues (and corresponding eigenvectors) of $A$ with the largest
/// magnitude until the provided outputs are full or the maximum number of algorithm restarts is
/// reached.
pub fn partial_eigen<T: ComplexField>(
	eigvecs: MatMut<'_, Complex<T::Real>>,
	eigvals: &mut [Complex<T::Real>],
	A: &dyn LinOp<T>,
	v0: ColRef<'_, T>,
	tolerance: T::Real,
	par: Par,
	stack: &mut MemStack,
	params: PartialEigenParams,
) -> PartialEigenInfo {
/// computes an estimate of the eigenvalues (and corresponding eigenvectors) of $A$ with the largest
/// magnitude, assuming $A$ is self-adjoint, until the provided outputs are full or the maximum
/// number of algorithm restarts is reached.
pub fn partial_self_adjoint_eigen<T: ComplexField>(
	eigvecs: MatMut<'_, T>,
	eigvals: &mut [T],
	A: &dyn LinOp<T>,
	v0: ColRef<'_, T>,
	tolerance: T::Real,
	par: Par,
	stack: &mut MemStack,
	params: PartialEigenParams,
) -> PartialEigenInfo {
/// computes an estimate of the singular values (and corresponding singular vectors) of $A$ with the
/// largest magnitude, until the provided outputs are full or the maximum number of algorithm
/// restarts is reached.
pub fn partial_svd<T: ComplexField>(
	left_singular_vecs: MatMut<'_, T>,
	right_singular_vecs: MatMut<'_, T>,
	singular_vals: &mut [T],
	A: &dyn BiLinOp<T>,
	v0: ColRef<'_, T>,
	tolerance: T::Real,
	par: Par,
	stack: &mut MemStack,
	params: PartialEigenParams,
) -> PartialEigenInfo {
	fn test_arnoldi_real() {
	fn test_arnoldi_cplx() {
	fn test_toeplitz() {
	fn test_small_real() {
	fn test_small_cplx() {
/// algorithm parameters
/// whether the initial guess is implicitly zero or not
/// absolute tolerance for convergence testing
/// relative tolerance for convergence testing
/// maximum number of iterations
	fn default() -> Self {
/// algorithm result
/// absolute residual at the final step
/// relative residual at the final step
/// number of iterations executed by the algorithm
/// algorithm error
/// convergence failure
/// absolute residual at the final step
/// relative residual at the final step
/// computes the layout of required workspace for executing the lsmr
/// algorithm
pub fn lsmr_scratch<T: ComplexField>(right_precond: impl BiPrecond<T>, mat: impl BiLinOp<T>, rhs_ncols: usize, par: Par) -> StackReq {
	fn implementation<T: ComplexField>(M: &dyn BiPrecond<T>, A: &dyn BiLinOp<T>, rhs_ncols: usize, par: Par) -> StackReq {
// u
// v
// beta
// alpha
// zetabar
// alphabar
// theta
// pbar_adjoint
// vold
// p_adjoint
// rho
// thetaold
// rhobar
// thetabar
// zeta
// zetabar
/// executes lsmr using the provided preconditioner
///
/// # note
/// this function is also optimized for a rhs with multiple columns
pub fn lsmr<T: ComplexField>(
	out: MatMut<'_, T>,
	right_precond: impl BiPrecond<T>,
	mat: impl BiLinOp<T>,
	rhs: MatRef<'_, T>,
	params: LsmrParams<T::Real>,
	callback: impl FnMut(MatRef<'_, T>),
	par: Par,
	stack: &mut MemStack,
) -> Result<LsmrInfo<T::Real>, LsmrError<T::Real>> {
	fn implementation<T: ComplexField>(
		mut x: MatMut<'_, T>,
		M: &impl BiPrecond<T>,
		A: &impl BiLinOp<T>,
		b: MatRef<'_, T>,
		params: LsmrParams<T::Real>,
		callback: &mut dyn FnMut(MatRef<'_, T>),
		par: Par,
		stack: &mut MemStack,
	) -> Result<LsmrInfo<T::Real>, LsmrError<T::Real>> {
		fn thin_qr<T: ComplexField>(mut Q: MatMut<'_, T>, mut R: MatMut<'_, T>, mut mat: MatMut<'_, T>, par: Par, stack: &mut MemStack) {
// pad to avoid last block slowing down the rest
// now contains M v_old
	fn test_lsmr() {
	fn test_breakdown() {
//! matrix-free linear operator traits and algorithms
/// biconjugate gradient stabilized method.
/// conjugate gradient method.
/// least squares minimal residual.
/// krylov-schur eigensolvers.
/// specifies whether the initial guess should be assumed to be zero or not
/// initial guess is already zeroed
/// initial guess may contain non-zero values
/// identity preconditioner, no-op for most operations
/// dimension of the preconditioner, equal to the dimension of the solution
/// linear operator from a finite-dimensional vector space
/// computes the workspace layout required to apply `self` or the conjugate o
/// `self` to a matrix with `rhs_ncols` columns
	fn apply_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq;
/// output dimension of the operator
	fn nrows(&self) -> usize;
/// input dimension of the operator
	fn ncols(&self) -> usize;
/// applies `self` to `rhs`, and stores the result in `out`
	fn apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack);
/// applies the conjugate of `self` to `rhs`, and stores the result in `out`
	fn conj_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack);
	fn apply_scratch(&self, _rhs_ncols: usize, _par: Par) -> StackReq {
	fn nrows(&self) -> usize {
	fn ncols(&self) -> usize {
	fn apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, _par: Par, _stack: &mut MemStack) {
	fn conj_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, _par: Par, _stack: &mut MemStack) {
	fn transpose_apply_scratch(&self, _rhs_ncols: usize, _par: Par) -> StackReq {
	fn transpose_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, _par: Par, _stack: &mut MemStack) {
	fn adjoint_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, _par: Par, _stack: &mut MemStack) {
	fn apply_in_place_scratch(&self, _rhs_ncols: usize, _par: Par) -> StackReq {
	fn apply_in_place(&self, _rhs: MatMut<'_, T>, _par: Par, _stack: &mut MemStack) {
	fn conj_apply_in_place(&self, _rhs: MatMut<'_, T>, _par: Par, _stack: &mut MemStack) {
	fn transpose_apply_in_place_scratch(&self, _rhs_ncols: usize, _par: Par) -> StackReq {
	fn transpose_apply_in_place(&self, _rhs: MatMut<'_, T>, _par: Par, _stack: &mut MemStack) {
	fn adjoint_apply_in_place(&self, _rhs: MatMut<'_, T>, _par: Par, _stack: &mut MemStack) {
/// linear operator that can be applied from either the right or the left side
/// computes the workspace layout required to apply the transpose or adjoint o
/// `self` to a matrix with `rhs_ncols` columns
	fn transpose_apply_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq;
/// applies the transpose of `self` to `rhs`, and stores the result in `out`
	fn transpose_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack);
/// applies the adjoint of `self` to `rhs`, and stores the result in `out`
	fn adjoint_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack);
/// preconditioner for a linear system
///
/// same as [`LinOp`] except that it can be applied in place
/// computes the workspace layout required to apply `self` or the conjugate of
/// `self` to a matrix with `rhs_ncols` columns in place
	fn apply_in_place_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
/// applies `self` to `rhs`, and stores the result in `rhs`
	fn apply_in_place(&self, rhs: MatMut<'_, T>, par: Par, stack: &mut MemStack) {
/// applies the conjugate of `self` to `rhs`, and stores the result in `rhs`
	fn conj_apply_in_place(&self, rhs: MatMut<'_, T>, par: Par, stack: &mut MemStack) {
/// preconditioner for a linear system that can bee applied from either the right or the left side
///
/// same as [`BiLinOp`] except that it can be applied in place.
/// computes the workspace layout required to apply the transpose or adjoint of
/// `self` to a matrix with `rhs_ncols` columns in place
	fn transpose_apply_in_place_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
/// applies the transpose of `self` to `rhs`, and stores the result in `rhs`
	fn transpose_apply_in_place(&self, rhs: MatMut<'_, T>, par: Par, stack: &mut MemStack) {
/// applies the adjoint of `self` to `rhs`, and stores the result in `rhs`
	fn adjoint_apply_in_place(&self, rhs: MatMut<'_, T>, par: Par, stack: &mut MemStack) {
	fn apply_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
	fn nrows(&self) -> usize {
	fn ncols(&self) -> usize {
	fn apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn conj_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn transpose_apply_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
	fn transpose_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn adjoint_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn apply_in_place_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
	fn apply_in_place(&self, rhs: MatMut<'_, T>, par: Par, stack: &mut MemStack) {
	fn conj_apply_in_place(&self, rhs: MatMut<'_, T>, par: Par, stack: &mut MemStack) {
	fn transpose_apply_in_place_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
	fn transpose_apply_in_place(&self, rhs: MatMut<'_, T>, par: Par, stack: &mut MemStack) {
	fn adjoint_apply_in_place(&self, rhs: MatMut<'_, T>, par: Par, stack: &mut MemStack) {
	fn nrows(&self) -> usize {
	fn ncols(&self) -> usize {
	fn apply_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
	fn apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn conj_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn transpose_apply_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
	fn transpose_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn adjoint_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn nrows(&self) -> usize {
	fn ncols(&self) -> usize {
	fn apply_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
	fn apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn conj_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn transpose_apply_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
	fn transpose_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn adjoint_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn nrows(&self) -> usize {
	fn ncols(&self) -> usize {
	fn apply_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
	fn apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn conj_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn transpose_apply_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
	fn transpose_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn adjoint_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn nrows(&self) -> usize {
	fn ncols(&self) -> usize {
	fn apply_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
	fn apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn conj_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn transpose_apply_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
	fn transpose_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn adjoint_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn nrows(&self) -> usize {
	fn ncols(&self) -> usize {
	fn apply_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
	fn apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn conj_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn transpose_apply_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
	fn transpose_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn adjoint_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn nrows(&self) -> usize {
	fn ncols(&self) -> usize {
	fn apply_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
	fn apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn conj_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn transpose_apply_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
	fn transpose_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn adjoint_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn nrows(&self) -> usize {
	fn ncols(&self) -> usize {
	fn apply_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
	fn apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn conj_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn transpose_apply_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
	fn transpose_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn adjoint_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn nrows(&self) -> usize {
	fn ncols(&self) -> usize {
	fn apply_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
	fn apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn conj_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn transpose_apply_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
	fn transpose_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn adjoint_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn apply_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
	fn nrows(&self) -> usize {
	fn ncols(&self) -> usize {
	fn apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn conj_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn transpose_apply_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
	fn transpose_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn adjoint_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn apply_in_place_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
	fn apply_in_place(&self, rhs: MatMut<'_, T>, par: Par, stack: &mut MemStack) {
	fn conj_apply_in_place(&self, rhs: MatMut<'_, T>, par: Par, stack: &mut MemStack) {
	fn transpose_apply_in_place_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
	fn transpose_apply_in_place(&self, rhs: MatMut<'_, T>, par: Par, stack: &mut MemStack) {
	fn adjoint_apply_in_place(&self, rhs: MatMut<'_, T>, par: Par, stack: &mut MemStack) {
	fn nrows(&self) -> usize {
	fn ncols(&self) -> usize {
	fn apply_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
	fn apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn conj_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn transpose_apply_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
	fn transpose_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn adjoint_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn nrows(&self) -> usize {
	fn ncols(&self) -> usize {
	fn apply_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
	fn apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn conj_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn transpose_apply_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
	fn transpose_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn adjoint_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn nrows(&self) -> usize {
	fn ncols(&self) -> usize {
	fn apply_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
	fn apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn conj_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn transpose_apply_scratch(&self, rhs_ncols: usize, par: Par) -> StackReq {
	fn transpose_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
	fn adjoint_apply(&self, out: MatMut<'_, T>, rhs: MatRef<'_, T>, par: Par, stack: &mut MemStack) {
fn iterate_lanczos<T: ComplexField>(A: &dyn LinOp<T>, H: MatMut<'_, T>, V: MatMut<'_, T>, start: usize, end: usize, par: Par, stack: &mut MemStack) {
pub fn partial_self_adjoint_eigen_imp<T: ComplexField>(
	eigvecs: MatMut<'_, T>,
	eigvals: &mut [T],

	A: &dyn LinOp<T>,
	v0: ColRef<'_, T>,
	min_dim: usize,
	max_dim: usize,
	n_eigval: usize,
	tol: T::Real,
	restarts: usize,
	par: Par,
	stack: &mut MemStack,
) -> usize {
	fn test_small_cplx() {
fn iterate_lanczos<T: ComplexField>(
	A: &dyn BiLinOp<T>,
	H: MatMut<'_, T>,
	Q: MatMut<'_, T>,
	P: MatMut<'_, T>,
	start: usize,
	end: usize,
	par: Par,
	stack: &mut MemStack,
) {
pub fn partial_svd_imp<T: ComplexField>(
	left_singular_vecs: MatMut<'_, T>,
	right_singular_vecs: MatMut<'_, T>,
	singular_vals: &mut [T],

	A: &dyn BiLinOp<T>,
	v0: ColRef<'_, T>,
	min_dim: usize,
	max_dim: usize,
	n_eigval: usize,
	tol: T::Real,
	restarts: usize,
	par: Par,
	stack: &mut MemStack,
) -> usize {
	fn test_small_cplx() {
/// swaps the values in the columns `a` and `b`
///
/// # panics
///
/// panics if `a` and `b` don't have the same number of columns
///
/// # example
///
/// ```
/// use faer::{mat, perm};
///
/// let mut m = mat![
/// 	[1.0, 2.0, 3.0], //
/// 	[4.0, 5.0, 6.0],
/// 	[7.0, 8.0, 9.0],
/// 	[10.0, 14.0, 12.0],
/// ];
///
/// let (a, b) = m.two_cols_mut(0, 2);
/// perm::swap_cols(a, b);
///
/// let swapped = mat![
/// 	[3.0, 2.0, 1.0], //
/// 	[6.0, 5.0, 4.0],
/// 	[9.0, 8.0, 7.0],
/// 	[12.0, 14.0, 10.0],
/// ];
///
/// assert_eq!(m, swapped);
/// ```
pub fn swap_cols<N: Shape, T>(a: ColMut<'_, T, N>, b: ColMut<'_, T, N>) {
	fn swap<T>() -> impl FnMut(Zip<&mut T, Last<&mut T>>) {
/// swaps the values in the rows `a` and `b`
///
/// # panics
///
/// panics if `a` and `b` don't have the same number of columns
///
/// # example
///
/// ```
/// use faer::{mat, perm};
///
/// let mut m = mat![
/// 	[1.0, 2.0, 3.0], //
/// 	[4.0, 5.0, 6.0],
/// 	[7.0, 8.0, 9.0],
/// 	[10.0, 14.0, 12.0],
/// ];
///
/// let (a, b) = m.two_rows_mut(0, 2);
/// perm::swap_rows(a, b);
///
/// let swapped = mat![
/// 	[7.0, 8.0, 9.0], //
/// 	[4.0, 5.0, 6.0],
/// 	[1.0, 2.0, 3.0],
/// 	[10.0, 14.0, 12.0],
/// ];
///
/// assert_eq!(m, swapped);
/// ```
pub fn swap_rows<N: Shape, T>(a: RowMut<'_, T, N>, b: RowMut<'_, T, N>) {
/// swaps the two rows at indices `a` and `b` in the given matrix
///
/// # panics
///
/// panics if either `a` or `b` is out of bounds
///
/// # example
///
/// ```
/// use faer::{mat, perm};
///
/// let mut m = mat![
/// 	[1.0, 2.0, 3.0], //
/// 	[4.0, 5.0, 6.0],
/// 	[7.0, 8.0, 9.0],
/// 	[10.0, 14.0, 12.0],
/// ];
///
/// perm::swap_rows_idx(m.as_mut(), 0, 2);
///
/// let swapped = mat![
/// 	[7.0, 8.0, 9.0], //
/// 	[4.0, 5.0, 6.0],
/// 	[1.0, 2.0, 3.0],
/// 	[10.0, 14.0, 12.0],
/// ];
///
/// assert_eq!(m, swapped);
/// ```
pub fn swap_rows_idx<M: Shape, N: Shape, T>(mat: MatMut<'_, T, M, N>, a: Idx<M>, b: Idx<M>) {
/// swaps the two columns at indices `a` and `b` in the given matrix
///
/// # panics
///
/// panics if either `a` or `b` is out of bounds
///
/// # example
///
/// ```
/// use faer::{mat, perm};
///
/// let mut m = mat![
/// 	[1.0, 2.0, 3.0], //
/// 	[4.0, 5.0, 6.0],
/// 	[7.0, 8.0, 9.0],
/// 	[10.0, 14.0, 12.0],
/// ];
///
/// perm::swap_cols_idx(m.as_mut(), 0, 2);
///
/// let swapped = mat![
/// 	[3.0, 2.0, 1.0], //
/// 	[6.0, 5.0, 4.0],
/// 	[9.0, 8.0, 7.0],
/// 	[12.0, 14.0, 10.0],
/// ];
///
/// assert_eq!(m, swapped);
/// ```
pub fn swap_cols_idx<M: Shape, N: Shape, T>(mat: MatMut<'_, T, M, N>, a: Idx<N>, b: Idx<N>) {
/// permutation matrix
/// immutable permutation matrix view
/// generic `Perm` wrapper
/// generic `Perm` wrapper
		fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
/// wrap by reference
		pub fn from_inner_ref(inner: &Inner) -> &Self {
/// wrap by mutable reference
		pub fn from_inner_mut(inner: &mut Inner) -> &mut Self {
		fn deref(&self) -> &Self::Target {
		fn deref_mut(&mut self) -> &mut Self::Target {
		fn rb(&'short self) -> Self::Target {
		fn rb_mut(&'short mut self) -> Self::Target {
		fn into_const(self) -> Self::Target {
/// computes a permutation of the columns of the source matrix using the given permutation, and
/// stores the result in the destination matrix
///
/// # panics
///
/// - panics if the matrices do not have the same shape
/// - panics if the size of the permutation doesn't match the number of columns of the matrices
pub fn permute_cols<I: Index, T: ComplexField>(dst: MatMut<'_, T>, src: MatRef<'_, T>, perm_indices: PermRef<'_, I>) {
/// computes a permutation of the rows of the source matrix using the given permutation, and
/// stores the result in the destination matrix
///
/// # panics
///
/// - panics if the matrices do not have the same shape
/// - panics if the size of the permutation doesn't match the number of rows of the matrices
pub fn permute_rows<I: Index, T: ComplexField>(dst: MatMut<'_, T>, src: MatRef<'_, T>, perm_indices: PermRef<'_, I>) {
	fn implementation<I: Index, T: ComplexField>(dst: MatMut<'_, T>, src: MatRef<'_, T>, perm_indices: PermRef<'_, I>) {
/// computes the layout of required workspace for applying a row permutation to a
/// matrix in place
pub fn permute_rows_in_place_scratch<I: Index, T: ComplexField>(nrows: usize, ncols: usize) -> StackReq {
/// computes the layout of required workspace for applying a column permutation to a
/// matrix in place
pub fn permute_cols_in_place_scratch<I: Index, T: ComplexField>(nrows: usize, ncols: usize) -> StackReq {
/// computes a permutation of the rows of the matrix using the given permutation, and
/// stores the result in the same matrix
///
/// # panics
///
/// - panics if the size of the permutation doesn't match the number of rows of the matrix
pub fn permute_rows_in_place<I: Index, T: ComplexField>(matrix: MatMut<'_, T>, perm_indices: PermRef<'_, I>, stack: &mut MemStack) {
	fn implementation<T: ComplexField, I: Index>(matrix: MatMut<'_, T>, perm_indices: PermRef<'_, I>, stack: &mut MemStack) {
/// computes a permutation of the columns of the matrix using the given permutation, and
/// stores the result in the same matrix.
///
/// # panics
///
/// - panics if the size of the permutation doesn't match the number of columns of the matrix
pub fn permute_cols_in_place<I: Index, T: ComplexField>(matrix: MatMut<'_, T>, perm_indices: PermRef<'_, I>, stack: &mut MemStack) {
	fn implementation<I: Index, T: ComplexField>(matrix: MatMut<'_, T>, perm_indices: PermRef<'_, I>, stack: &mut MemStack) {
/// see [`super::Perm`]
/// returns the input permutation with the given shape after checking that it matches the
/// current shape
	pub fn as_shape<M: Shape>(&self, dim: M) -> PermRef<'_, I, M> {
/// returns the input permutation with the given shape after checking that it matches the
/// current shape
	pub fn into_shape<M: Shape>(self, dim: M) -> Perm<I, M> {
/// creates a new permutation, by checking the validity of the inputs
///
/// # panics
///
/// the function panics if any of the following conditions are violated:
/// `forward` and `inverse` must have the same length which must be less than or equal to
/// `I::Signed::MAX`, be valid permutations, and be inverse permutations of each other
	pub fn new_checked(forward: alloc::boxed::Box<[Idx<N, I>]>, inverse: alloc::boxed::Box<[Idx<N, I>]>, dim: N) -> Self {
/// creates a new permutation reference, without checking the validity of the inputs
///
/// # safety
///
/// `forward` and `inverse` must have the same length which must be less than or equal to
/// `I::Signed::MAX`, be valid permutations, and be inverse permutations of each other
	pub unsafe fn new_unchecked(forward: alloc::boxed::Box<[Idx<N, I>]>, inverse: alloc::boxed::Box<[Idx<N, I>]>) -> Self {
/// returns the permutation as an array
	pub fn into_arrays(self) -> (alloc::boxed::Box<[Idx<N, I>]>, alloc::boxed::Box<[Idx<N, I>]>) {
/// returns the dimension of the permutation
	pub fn len(&self) -> N {
/// returns the inverse permutation
	pub fn into_inverse(self) -> Self {
	fn rb(&'short self) -> Self::Target {
/// see [`super::PermRef`]
	fn clone(&self) -> Self {
	fn rb(&'short self) -> Self::Target {
	fn rb_mut(&'short mut self) -> Self::Target {
	fn into_const(self) -> Self::Target {
/// convert `self` to a permutation view
	pub fn as_ref(&self) -> PermRef<'_, I, N> {
/// returns the input permutation with the given shape after checking that it matches the
/// current shape
	pub fn as_shape<M: Shape>(self, dim: M) -> PermRef<'a, I, M> {
/// creates a new permutation, by checking the validity of the inputs
///
/// # panics
///
/// the function panics if any of the following conditions are violated:
/// * `forward` and `inverse` must have the same length which must be less than or equal to
/// `I::Signed::MAX`, be valid permutations, and be inverse permutations of each other
	pub fn new_checked(forward: &'a [Idx<N, I>], inverse: &'a [Idx<N, I>], dim: N) -> Self {
		fn check<I: Index>(forward: &[I], inverse: &[I], n: usize) {
/// creates a new permutation reference, without checking the validity of the inputs
///
/// # safety
///
/// `forward` and `inverse` must have the same length which must be less than or equal to
/// `I::Signed::MAX`, be valid permutations, and be inverse permutations of each other
	pub unsafe fn new_unchecked(forward: &'a [Idx<N, I>], inverse: &'a [Idx<N, I>], dim: N) -> Self {
/// returns the permutation as an array
	pub fn arrays(self) -> (&'a [Idx<N, I>], &'a [Idx<N, I>]) {
/// returns the dimension of the permutation
	pub fn len(&self) -> N {
/// returns the inverse permutation
	pub fn inverse(self) -> Self {
/// cast the permutation to the fixed width index type
	pub fn canonicalized(self) -> PermRef<'a, I::FixedWidth, N> {
/// cast the permutation from the fixed width index type
	pub fn uncanonicalized<J: Index>(self) -> PermRef<'a, J, N> {
/// returns the permutation as an array
	pub fn bound_arrays(self) -> (&'a Array<'N, Idx<Dim<'N>, I>>, &'a Array<'N, Idx<Dim<'N>, I>>) {
/// represents a type that can be used to slice a row, such as an index or a range of indices
/// sliced view type
/// slice `this` using `col`
	fn get(this: Self, col: ColRange) -> Self::Target;
/// slice `this` using `col` without bound checks
	unsafe fn get_unchecked(this: Self, col: ColRange) -> Self::Target;
/// immutable view over a row vector, similar to an immutable reference to a strided
/// [prim@slice]
///
/// # note
///
/// unlike a slice, the data pointed to by `RowRef<'_, T>` is allowed to be partially or fully
/// uninitialized under certain conditions. in this case, care must be taken to not perform any
/// operations that read the uninitialized values, or form references to them, either directly or
/// indirectly through any of the numerical library routines, unless it is explicitly permitted
/// mutable view over a row vector, similar to a mutable reference to a strided
/// [prim@slice]
///
/// # note
///
/// unlike a slice, the data pointed to by `RowMut<'_, T>` is allowed to be partially or fully
/// uninitialized under certain conditions. in this case, care must be taken to not perform any
/// operations that read the uninitialized values, or form references to them, either directly or
/// indirectly through any of the numerical library routines, unless it is explicitly permitted
/// heap allocated resizable row vector.
///
/// # note
///
/// the memory layout of `Row` is guaranteed to be row-major, meaning that it has a column stride
/// of `1`.
/// generic `Row` wrapper
/// generic `Row` wrapper
		fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
/// wrap by reference
		pub fn from_inner_ref(inner: &Inner) -> &Self {
/// wrap by mutable reference
		pub fn from_inner_mut(inner: &mut Inner) -> &mut Self {
		fn deref(&self) -> &Self::Target {
		fn deref_mut(&mut self) -> &mut Self::Target {
		fn rb(&'short self) -> Self::Target {
		fn rb_mut(&'short mut self) -> Self::Target {
		fn into_const(self) -> Self::Target {
		fn index(&self, col: Idx<Cols>) -> &Self::Output {
		fn index_mut(&mut self, col: Idx<Cols>) -> &mut Self::Output {
/// trait for types that can be converted to a row view
/// returns a view over `self`
	fn as_row_mut(&mut self) -> RowMut<'_, Self::T, Self::Cols>;
/// trait for types that can be converted to a row view
/// returns a view over `self`
	fn as_row_ref(&self) -> RowRef<'_, Self::T, Self::Cols>;
	fn as_row_ref(&self) -> RowRef<'_, Self::T, Self::Cols> {
	fn as_row_mut(&mut self) -> RowMut<'_, Self::T, Self::Cols> {
	fn as_mat_ref(&self) -> MatRef<'_, Self::T, One, Self::Cols> {
	fn as_mat_ref(&self) -> MatRef<'_, Self::T, One, Self::Cols> {
	fn as_mat_ref(&self) -> MatRef<'_, Self::T, One, Self::Cols> {
	fn as_mat_mut(&mut self) -> MatMut<'_, Self::T, One, Self::Cols> {
	fn as_mat_mut(&mut self) -> MatMut<'_, Self::T, One, Self::Cols> {
	fn zeros(_: One, cols: Cols) -> Self
	where
		T: ComplexField,
	{
	fn truncate(&mut self, _: One, cols: Self::Cols) {
	fn get(this: Self, col: ColRange) -> Self::Target {
	unsafe fn get_unchecked(this: Self, col: ColRange) -> Self::Target {
	fn get(this: Self, col: ColRange) -> Self::Target {
	unsafe fn get_unchecked(this: Self, col: ColRange) -> Self::Target {
            fn get(this: Self, col: Idx<$C>) -> Self::Target {
            unsafe fn get_unchecked(this: Self, col: Idx<$C>) -> Self::Target {
            fn get(this: Self, col: Idx<$C>) -> Self::Target {
            unsafe fn get_unchecked(this: Self, col: Idx<$C>) -> Self::Target {
/// see [`super::RowMut`]
	fn rb(&'short self) -> Self::Target {
	fn rb_mut(&'short mut self) -> Self::Target {
	fn into_const(self) -> Self::Target {
/// creates a row view over the given element
	pub fn from_mut(value: &'a mut T) -> Self {
/// creates a `RowMut` from slice views over the row vector data, the result has the same
/// number of columns as the length of the input slice
	pub fn from_slice_mut(slice: &'a mut [T]) -> Self {
/// creates a `RowMut` from pointers to the column vector data, number of rows, and row stride
///
/// # safety
/// this function has the same safety requirements as
/// [`MatMut::from_raw_parts_mut(ptr, 1, ncols, 0, col_stride)`]
	pub const unsafe fn from_raw_parts_mut(ptr: *mut T, ncols: Cols, col_stride: CStride) -> Self {
/// returns a pointer to the row data
	pub fn as_ptr(&self) -> *const T {
/// returns the number of rows of the row (always 1)
	pub fn nrows(&self) -> usize {
/// returns the number of columns of the row
	pub fn ncols(&self) -> Cols {
/// returns the number of rows and columns of the row
	pub fn shape(&self) -> (usize, Cols) {
/// returns the column stride of the row
	pub fn col_stride(&self) -> CStride {
/// returns a raw pointer to the element at the given index
	pub fn ptr_at(&self, col: IdxInc<Cols>) -> *const T {
/// returns a raw pointer to the element at the given index, assuming the provided index
/// is within the row bounds
///
/// # safety
/// the behavior is undefined if any of the following conditions are violated:
/// * `col < self.ncols()`
	pub unsafe fn ptr_inbounds_at(&self, col: Idx<Cols>) -> *const T {
/// see [`RowRef::split_at_col`]
	pub fn split_at_col(self, col: IdxInc<Cols>) -> (RowRef<'a, T, usize, CStride>, RowRef<'a, T, usize, CStride>) {
/// see [`RowRef::transpose`]
	pub fn transpose(self) -> ColRef<'a, T, Cols, CStride> {
/// see [`RowRef::conjugate`]
	pub fn conjugate(self) -> RowRef<'a, T::Conj, Cols, CStride>
	where
		T: Conjugate,
	{
/// see [`RowRef::canonical`]
	pub fn canonical(self) -> RowRef<'a, T::Canonical, Cols, CStride>
	where
		T: Conjugate,
	{
/// see [`RowRef::adjoint`]
	pub fn adjoint(self) -> ColRef<'a, T::Conj, Cols, CStride>
	where
		T: Conjugate,
	{
/// see [`RowRef::get`]
	pub fn get<ColRange>(self, col: ColRange) -> <RowRef<'a, T, Cols, CStride> as RowIndex<ColRange>>::Target
	where
		RowRef<'a, T, Cols, CStride>: RowIndex<ColRange>,
	{
/// see [`RowRef::get_unchecked`]
	pub unsafe fn get_unchecked<ColRange>(self, col: ColRange) -> <RowRef<'a, T, Cols, CStride> as RowIndex<ColRange>>::Target
	where
		RowRef<'a, T, Cols, CStride>: RowIndex<ColRange>,
	{
/// see [`RowRef::reverse_cols`]
	pub fn reverse_cols(self) -> RowRef<'a, T, Cols, CStride::Rev> {
/// see [`RowRef::subcols`]
	pub fn subcols<V: Shape>(self, col_start: IdxInc<Cols>, ncols: V) -> RowRef<'a, T, V, CStride> {
/// see [`RowRef::as_col_shape`]
	pub fn as_col_shape<V: Shape>(self, ncols: V) -> RowRef<'a, T, V, CStride> {
/// see [`RowRef::as_dyn_cols`]
	pub fn as_dyn_cols(self) -> RowRef<'a, T, usize, CStride> {
/// see [`RowRef::as_dyn_stride`]
	pub fn as_dyn_stride(self) -> RowRef<'a, T, Cols, isize> {
/// see [`RowRef::iter`]
	pub fn iter(self) -> impl 'a + ExactSizeIterator + DoubleEndedIterator<Item = &'a T>
	where
		Cols: 'a,
	{
/// see [`RowRef::par_iter`]
	pub fn par_iter(self) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = &'a T>
	where
		T: Sync,
		Cols: 'a,
	{
/// see [`RowRef::try_as_row_major`]
	pub fn try_as_row_major(self) -> Option<RowRef<'a, T, Cols, ContiguousFwd>> {
/// see [`RowRef::as_diagonal`]
	pub fn as_diagonal(self) -> DiagRef<'a, T, Cols, CStride> {
	pub unsafe fn const_cast(self) -> RowMut<'a, T, Cols, CStride> {
/// see [`RowRef::as_mat`]
	pub fn as_mat(self) -> MatRef<'a, T, usize, Cols, isize, CStride> {
/// see [`RowRef::as_mat`]
	pub fn as_mat_mut(self) -> MatMut<'a, T, usize, Cols, isize, CStride> {
/// returns a view over `self`
	pub fn as_mut(&mut self) -> RowMut<'_, T, Cols, CStride> {
/// copies `other` into `self`
	pub fn copy_from<RhsT: Conjugate<Canonical = T>>(&mut self, other: impl AsRowRef<T = RhsT, Cols = Cols>)
	where
		T: ComplexField,
	{
/// fills all the elements of `self` with `value`
	pub fn fill(&mut self, value: T)
	where
		T: Clone,
	{
/// see [`RowRef::as_ptr`]
	pub fn as_ptr_mut(&self) -> *mut T {
/// see [`RowRef::ptr_at`]
	pub fn ptr_at_mut(&self, col: IdxInc<Cols>) -> *mut T {
/// see [`RowRef::ptr_inbounds_at`]
	pub unsafe fn ptr_inbounds_at_mut(&self, col: Idx<Cols>) -> *mut T {
/// see [`RowRef::split_at_col`]
	pub fn split_at_col_mut(self, col: IdxInc<Cols>) -> (RowMut<'a, T, usize, CStride>, RowMut<'a, T, usize, CStride>) {
/// see [`RowRef::transpose`]
	pub fn transpose_mut(self) -> ColMut<'a, T, Cols, CStride> {
/// see [`RowRef::conjugate`]
	pub fn conjugate_mut(self) -> RowMut<'a, T::Conj, Cols, CStride>
	where
		T: Conjugate,
	{
/// see [`RowRef::canonical`]
	pub fn canonical_mut(self) -> RowMut<'a, T::Canonical, Cols, CStride>
	where
		T: Conjugate,
	{
/// see [`RowRef::adjoint`]
	pub fn adjoint_mut(self) -> ColMut<'a, T::Conj, Cols, CStride>
	where
		T: Conjugate,
	{
	pub(crate) fn at_mut(self, col: Idx<Cols>) -> &'a mut T {
	pub(crate) unsafe fn at_mut_unchecked(self, col: Idx<Cols>) -> &'a mut T {
/// see [`RowRef::get`]
	pub fn get_mut<ColRange>(self, col: ColRange) -> <RowMut<'a, T, Cols, CStride> as RowIndex<ColRange>>::Target
	where
		RowMut<'a, T, Cols, CStride>: RowIndex<ColRange>,
	{
/// see [`RowRef::get`]
	pub unsafe fn get_mut_unchecked<ColRange>(self, col: ColRange) -> <RowMut<'a, T, Cols, CStride> as RowIndex<ColRange>>::Target
	where
		RowMut<'a, T, Cols, CStride>: RowIndex<ColRange>,
	{
/// see [`RowRef::reverse_cols`]
	pub fn reverse_cols_mut(self) -> RowMut<'a, T, Cols, CStride::Rev> {
/// see [`RowRef::subcols`]
	pub fn subcols_mut<V: Shape>(self, col_start: IdxInc<Cols>, ncols: V) -> RowMut<'a, T, V, CStride> {
/// see [`RowRef::as_col_shape`]
	pub fn as_col_shape_mut<V: Shape>(self, ncols: V) -> RowMut<'a, T, V, CStride> {
/// see [`RowRef::as_dyn_cols`]
	pub fn as_dyn_cols_mut(self) -> RowMut<'a, T, usize, CStride> {
/// see [`RowRef::as_dyn_stride`]
	pub fn as_dyn_stride_mut(self) -> RowMut<'a, T, Cols, isize> {
/// see [`RowRef::iter`]
	pub fn iter_mut(self) -> impl 'a + ExactSizeIterator + DoubleEndedIterator<Item = &'a mut T>
	where
		Cols: 'a,
	{
/// see [`RowRef::par_iter`]
	pub fn par_iter_mut(self) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = &'a mut T>
	where
		T: Send,
		Cols: 'a,
	{
/// see [`RowRef::par_partition`]
	pub fn par_partition(self, count: usize) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = RowRef<'a, T, usize, CStride>>
	where
		T: Sync,
		Cols: 'a,
	{
/// see [`RowRef::par_partition`]
	pub fn par_partition_mut(self, count: usize) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = RowMut<'a, T, usize, CStride>>
	where
		T: Send,
		Cols: 'a,
	{
	pub(crate) unsafe fn as_type<U>(self) -> RowMut<'a, U, Cols, CStride> {
/// see [`RowRef::try_as_row_major`]
	pub fn try_as_row_major_mut(self) -> Option<RowMut<'a, T, Cols, ContiguousFwd>> {
/// see [`RowRef::as_diagonal`]
	pub fn as_diagonal_mut(self) -> DiagMut<'a, T, Cols, CStride> {
	pub(crate) fn __at_mut(self, i: Idx<Cols>) -> &'a mut T {
/// returns a reference over the elements as a slice
	pub fn as_slice(self) -> &'a [T] {
/// returns a reference over the elements as a lifetime-bound slice
	pub fn as_array(self) -> &'a Array<'ROWS, T> {
/// returns a reference over the elements as a slice
	pub fn as_slice_mut(self) -> &'a mut [T] {
/// returns a reference over the elements as a lifetime-bound slice
	pub fn as_array_mut(self) -> &'a mut Array<'COLS, T> {
	pub fn split_cols_with<'LEFT, 'RIGHT>(
		self,
		col: Partition<'LEFT, 'RIGHT, 'COLS>,
	) -> (RowRef<'a, T, Dim<'LEFT>, CStride>, RowRef<'a, T, Dim<'RIGHT>, CStride>) {
	pub fn split_cols_with_mut<'LEFT, 'RIGHT>(
		self,
		col: Partition<'LEFT, 'RIGHT, 'COLS>,
	) -> (RowMut<'a, T, Dim<'LEFT>, CStride>, RowMut<'a, T, Dim<'RIGHT>, CStride>) {
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
/// Returns the maximum element in the row, or `None` if the row is empty
	pub fn max(&self) -> Option<T> {
/// Returns the minimum element in the row, or `None` if the row is empty
	pub fn min(&self) -> Option<T> {
	fn test_row_min() {
	fn test_row_max() {
/// see [`super::Row`]
/// returns a new row with dimension `ncols`, filled with the provided function
	pub fn from_fn(ncols: Cols, f: impl FnMut(Idx<Cols>) -> T) -> Self {
/// returns a new row with dimension `ncols`, filled with zeros
	pub fn zeros(ncols: Cols) -> Self
	where
		T: ComplexField,
	{
/// returns a new row with dimension `ncols`, filled with ones
	pub fn ones(ncols: Cols) -> Self
	where
		T: ComplexField,
	{
/// returns a new row with dimension `ncols`, filled with `value`
	pub fn full(ncols: Cols, value: T) -> Self
	where
		T: Clone,
	{
/// reserves the minimum capacity for `col_capacity` columns without reallocating, or returns an
/// error in case of failure. does nothing if the capacity is already sufficient
	pub fn try_reserve(&mut self, new_row_capacity: usize) -> Result<(), TryReserveError> {
/// reserves the minimum capacity for `col_capacity` columns without reallocating. does nothing
/// if the capacity is already sufficient
	pub fn reserve(&mut self, new_row_capacity: usize) {
/// resizes the row in-place so that the new dimension is `new_ncols`.
/// new elements are created with the given function `f`, so that elements at index `j`
/// are created by calling `f(j)`
	pub fn resize_with(&mut self, new_ncols: Cols, f: impl FnMut(Idx<Cols>) -> T) {
/// truncates the row so that its new dimensions are `new_ncols`.  
/// the new dimension must be smaller than or equal to the current dimension
///
/// # panics
/// the function panics if any of the following conditions are violated:
/// - `new_ncols > self.ncols()`
	pub fn truncate(&mut self, new_ncols: Cols) {
/// see [`RowRef::as_col_shape`]
	pub fn into_col_shape<V: Shape>(self, ncols: V) -> Row<T, V> {
/// see [`RowRef::as_diagonal`]
	pub fn into_diagonal(self) -> Diag<T, Cols> {
/// see [`RowRef::transpose`]
	pub fn into_transpose(self) -> Col<T, Cols> {
/// returns the number of rows of the row (always 1)
	pub fn nrows(&self) -> usize {
/// returns the number of columns of the row
	pub fn ncols(&self) -> Cols {
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
/// see [`RowRef::as_ptr`]
	pub fn as_ptr(&self) -> *const T {
/// see [`RowRef::shape`]
	pub fn shape(&self) -> (usize, Cols) {
/// see [`RowRef::col_stride`]
	pub fn col_stride(&self) -> isize {
/// see [`RowRef::ptr_at`]
	pub fn ptr_at(&self, col: IdxInc<Cols>) -> *const T {
/// see [`RowRef::ptr_inbounds_at`]
	pub unsafe fn ptr_inbounds_at(&self, col: Idx<Cols>) -> *const T {
/// see [`RowRef::split_at_col`]
	pub fn split_at_col(&self, col: IdxInc<Cols>) -> (RowRef<'_, T, usize>, RowRef<'_, T, usize>) {
/// see [`RowRef::transpose`]
	pub fn transpose(&self) -> ColRef<'_, T, Cols> {
/// see [`RowRef::conjugate`]
	pub fn conjugate(&self) -> RowRef<'_, T::Conj, Cols>
	where
		T: Conjugate,
	{
/// see [`RowRef::canonical`]
	pub fn canonical(&self) -> RowRef<'_, T::Canonical, Cols>
	where
		T: Conjugate,
	{
/// see [`RowRef::adjoint`]
	pub fn adjoint(&self) -> ColRef<'_, T::Conj, Cols>
	where
		T: Conjugate,
	{
/// see [`RowRef::get`]
	pub fn get<ColRange>(&self, col: ColRange) -> <RowRef<'_, T, Cols> as RowIndex<ColRange>>::Target
	where
		for<'a> RowRef<'a, T, Cols>: RowIndex<ColRange>,
	{
/// see [`RowRef::get_unchecked`]
	pub unsafe fn get_unchecked<ColRange>(&self, col: ColRange) -> <RowRef<'_, T, Cols> as RowIndex<ColRange>>::Target
	where
		for<'a> RowRef<'a, T, Cols>: RowIndex<ColRange>,
	{
/// see [`RowRef::reverse_cols`]
	pub fn reverse_cols(&self) -> RowRef<'_, T, Cols> {
/// see [`RowRef::subcols`]
	pub fn subcols<V: Shape>(&self, col_start: IdxInc<Cols>, ncols: V) -> RowRef<'_, T, V> {
/// see [`RowRef::as_col_shape`]
	pub fn as_col_shape<V: Shape>(&self, ncols: V) -> RowRef<'_, T, V> {
/// see [`RowRef::as_dyn_cols`]
	pub fn as_dyn_cols(&self) -> RowRef<'_, T, usize> {
/// see [`RowRef::as_dyn_stride`]
	pub fn as_dyn_stride(&self) -> RowRef<'_, T, Cols, isize> {
/// see [`RowRef::iter`]
	pub fn iter(&self) -> impl '_ + ExactSizeIterator + DoubleEndedIterator<Item = &'_ T> {
/// see [`RowRef::par_iter`]
	pub fn par_iter(&self) -> impl '_ + rayon::iter::IndexedParallelIterator<Item = &'_ T>
	where
		T: Sync,
	{
/// see [`RowRef::try_as_row_major`]
	pub fn try_as_row_major(&self) -> Option<RowRef<'_, T, Cols, ContiguousFwd>> {
/// see [`RowRef::as_diagonal`]
	pub fn as_diagonal(&self) -> DiagRef<'_, T, Cols> {
/// see [`RowRef::const_cast`]
	pub unsafe fn const_cast(&self) -> RowMut<'_, T, Cols> {
/// see [`RowRef::as_mat`]
	pub fn as_mat(&self) -> MatRef<'_, T, usize, Cols, isize> {
/// see [`RowRef::as_mat`]
	pub fn as_mat_mut(&mut self) -> MatMut<'_, T, usize, Cols, isize> {
/// see [`RowMut::as_ptr_mut`]
	pub fn as_ptr_mut(&mut self) -> *mut T {
/// see [`RowMut::ptr_at_mut`]
	pub fn ptr_at_mut(&mut self, col: IdxInc<Cols>) -> *mut T {
/// see [`RowMut::ptr_inbounds_at_mut`]
	pub unsafe fn ptr_inbounds_at_mut(&mut self, col: Idx<Cols>) -> *mut T {
/// see [`RowMut::split_at_col_mut`]
	pub fn split_at_col_mut(&mut self, col: IdxInc<Cols>) -> (RowMut<'_, T, usize>, RowMut<'_, T, usize>) {
/// see [`RowMut::transpose_mut`]
	pub fn transpose_mut(&mut self) -> ColMut<'_, T, Cols> {
/// see [`RowMut::conjugate_mut`]
	pub fn conjugate_mut(&mut self) -> RowMut<'_, T::Conj, Cols>
	where
		T: Conjugate,
	{
/// see [`RowMut::canonical_mut`]
	pub fn canonical_mut(&mut self) -> RowMut<'_, T::Canonical, Cols>
	where
		T: Conjugate,
	{
/// see [`RowMut::adjoint_mut`]
	pub fn adjoint_mut(&mut self) -> ColMut<'_, T::Conj, Cols>
	where
		T: Conjugate,
	{
/// see [`RowMut::get_mut`]
	pub fn get_mut<ColRange>(&mut self, col: ColRange) -> <RowMut<'_, T, Cols> as RowIndex<ColRange>>::Target
	where
		for<'a> RowMut<'a, T, Cols>: RowIndex<ColRange>,
	{
/// see [`RowMut::get_mut_unchecked`]
	pub unsafe fn get_mut_unchecked<ColRange>(&mut self, col: ColRange) -> <RowMut<'_, T, Cols> as RowIndex<ColRange>>::Target
	where
		for<'a> RowMut<'a, T, Cols>: RowIndex<ColRange>,
	{
/// see [`RowMut::reverse_cols_mut`]
	pub fn reverse_cols_mut(&mut self) -> RowMut<'_, T, Cols> {
/// see [`RowMut::subcols_mut`]
	pub fn subcols_mut<V: Shape>(&mut self, col_start: IdxInc<Cols>, ncols: V) -> RowMut<'_, T, V> {
/// see [`RowMut::as_col_shape_mut`]
	pub fn as_col_shape_mut<V: Shape>(&mut self, ncols: V) -> RowMut<'_, T, V> {
/// see [`RowMut::as_dyn_cols_mut`]
	pub fn as_dyn_cols_mut(&mut self) -> RowMut<'_, T, usize> {
/// see [`RowMut::as_dyn_stride_mut`]
	pub fn as_dyn_stride_mut(&mut self) -> RowMut<'_, T, Cols, isize> {
/// see [`RowMut::iter_mut`]
	pub fn iter_mut(&mut self) -> impl '_ + ExactSizeIterator + DoubleEndedIterator<Item = &'_ mut T> {
/// see [`RowMut::par_iter_mut`]
	pub fn par_iter_mut(&mut self) -> impl '_ + rayon::iter::IndexedParallelIterator<Item = &'_ mut T>
	where
		T: Send,
	{
/// see [`RowMut::try_as_row_major_mut`]
	pub fn try_as_row_major_mut(&mut self) -> Option<RowMut<'_, T, Cols, ContiguousFwd>> {
/// see [`RowMut::as_diagonal_mut`]
	pub fn as_diagonal_mut(&mut self) -> DiagMut<'_, T, Cols> {
	fn rb(&'short self) -> Self::Target {
	fn rb_mut(&'short mut self) -> Self::Target {
/// Returns the maximum element in the row, or `None` if the row is empty
	pub fn max(&self) -> Option<T> {
/// Returns the minimum element in the row, or `None` if the row is empty
	pub fn min(&self) -> Option<T> {
	fn from_iter<I>(iter: I) -> Self
	where
		I: IntoIterator<Item = T>,
	{
	fn test_row_min() {
	fn test_row_max() {
	fn test_from_iter() {
/// see [`super::RowRef`]
	fn clone(&self) -> Self {
	fn rb(&'short self) -> Self::Target {
	fn rb_mut(&'short mut self) -> Self::Target {
	fn into_const(self) -> Self::Target {
/// creates a row view over the given element
	pub fn from_ref(value: &'a T) -> Self {
/// creates a `RowRef` from slice views over the row vector data, the result has the same
/// number of columns as the length of the input slice
	pub fn from_slice(slice: &'a [T]) -> Self {
/// creates a `RowRef` from pointers to the column vector data, number of rows, and row stride
///
/// # safety
/// this function has the same safety requirements as
/// [`MatRef::from_raw_parts(ptr, 1, ncols, 0, col_stride)`]
	pub const unsafe fn from_raw_parts(ptr: *const T, ncols: Cols, col_stride: CStride) -> Self {
/// returns a pointer to the row data
	pub fn as_ptr(&self) -> *const T {
/// returns the number of rows of the row (always 1)
	pub fn nrows(&self) -> usize {
/// returns the number of columns of the row
	pub fn ncols(&self) -> Cols {
/// returns the number of rows and columns of the row
	pub fn shape(&self) -> (usize, Cols) {
/// returns the column stride of the row
	pub fn col_stride(&self) -> CStride {
/// returns a raw pointer to the element at the given index
	pub fn ptr_at(&self, col: IdxInc<Cols>) -> *const T {
/// returns a raw pointer to the element at the given index, assuming the provided index
/// is within the row bounds
///
/// # safety
/// the behavior is undefined if any of the following conditions are violated:
/// * `col < self.ncols()`
	pub unsafe fn ptr_inbounds_at(&self, col: Idx<Cols>) -> *const T {
/// splits the row vertically at the given column into two parts and returns an array of
/// each subrow, in the following order:
/// * left
/// * right
///
/// # panics
/// the function panics if the following condition is violated:
/// * `col <= self.ncols()`
	pub fn split_at_col(self, col: IdxInc<Cols>) -> (RowRef<'a, T, usize, CStride>, RowRef<'a, T, usize, CStride>) {
/// returns a view over the transpose of `self`
	pub fn transpose(self) -> ColRef<'a, T, Cols, CStride> {
/// returns a view over the conjugate of `self`
	pub fn conjugate(self) -> RowRef<'a, T::Conj, Cols, CStride>
	where
		T: Conjugate,
	{
/// returns an unconjugated view over `self`
	pub fn canonical(self) -> RowRef<'a, T::Canonical, Cols, CStride>
	where
		T: Conjugate,
	{
/// returns a view over the conjugate transpose of `self`
	pub fn adjoint(self) -> ColRef<'a, T::Conj, Cols, CStride>
	where
		T: Conjugate,
	{
	pub(crate) fn at(self, col: Idx<Cols>) -> &'a T {
	pub(crate) unsafe fn at_unchecked(self, col: Idx<Cols>) -> &'a T {
/// returns a reference to the element at the given index, or a subrow if
/// `col` is a range, with bound checks
///
/// # panics
/// the function panics if any of the following conditions are violated:
/// * `col` must be contained in `[0, self.ncols())`
	pub fn get<ColRange>(self, col: ColRange) -> <RowRef<'a, T, Cols, CStride> as RowIndex<ColRange>>::Target
	where
		RowRef<'a, T, Cols, CStride>: RowIndex<ColRange>,
	{
/// returns a reference to the element at the given index, or a subrow if
/// `col` is a range, without bound checks
///
/// # panics
/// the behavior is undefined if any of the following conditions are violated:
/// * `col` must be contained in `[0, self.ncols())`
	pub unsafe fn get_unchecked<ColRange>(self, col: ColRange) -> <RowRef<'a, T, Cols, CStride> as RowIndex<ColRange>>::Target
	where
		RowRef<'a, T, Cols, CStride>: RowIndex<ColRange>,
	{
/// returns a view over the `self`, with the columns in reversed order
	pub fn reverse_cols(self) -> RowRef<'a, T, Cols, CStride::Rev> {
/// returns a view over the subrow starting at column `col_start`, and with number of
/// columns `ncols`
///
/// # panics
/// the function panics if any of the following conditions are violated:
/// * `col_start <= self.ncols()`
/// * `ncols <= self.ncols() - col_start`
	pub fn subcols<V: Shape>(self, col_start: IdxInc<Cols>, ncols: V) -> RowRef<'a, T, V, CStride> {
/// returns the input row with the given column shape after checking that it matches the
/// current column shape
	pub fn as_col_shape<V: Shape>(self, ncols: V) -> RowRef<'a, T, V, CStride> {
/// returns the input row with dynamic column shape
	pub fn as_dyn_cols(self) -> RowRef<'a, T, usize, CStride> {
/// returns the input row with dynamic stride
	pub fn as_dyn_stride(self) -> RowRef<'a, T, Cols, isize> {
/// returns an iterator over the elements of the row
	pub fn iter(self) -> impl 'a + ExactSizeIterator + DoubleEndedIterator<Item = &'a T>
	where
		Cols: 'a,
	{
/// returns a parallel iterator over the elements of the row
	pub fn par_iter(self) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = &'a T>
	where
		T: Sync,
		Cols: 'a,
	{
/// returns a parallel iterator that provides exactly `count` successive chunks of the elements
/// of this row
///
/// only available with the `rayon` feature
	pub fn par_partition(self, count: usize) -> impl 'a + rayon::iter::IndexedParallelIterator<Item = RowRef<'a, T, usize, CStride>>
	where
		T: Sync,
		Cols: 'a,
	{
/// returns a view over the row with a static column stride equal to `+1`, or `None` otherwise
	pub fn try_as_row_major(self) -> Option<RowRef<'a, T, Cols, ContiguousFwd>> {
	pub unsafe fn const_cast(self) -> RowMut<'a, T, Cols, CStride> {
/// returns a matrix view over `self`
	pub fn as_mat(self) -> MatRef<'a, T, usize, Cols, isize, CStride> {
/// interprets the row as a diagonal matrix
	pub fn as_diagonal(self) -> DiagRef<'a, T, Cols, CStride> {
	pub(crate) fn __at(self, i: Idx<Cols>) -> &'a T {
/// returns a view over `self`
	pub fn as_ref(&self) -> RowRef<'_, T, Cols, CStride> {
/// returns the maximum norm of `self`
	pub fn norm_max(&self) -> Real<T>
	where
		T: Conjugate,
	{
/// returns the l2 norm of `self`
	pub fn norm_l2(&self) -> Real<T>
	where
		T: Conjugate,
	{
/// returns the squared l2 norm of `self`
	pub fn squared_norm_l2(&self) -> Real<T>
	where
		T: Conjugate,
	{
/// returns the l1 norm of `self`
	pub fn norm_l1(&self) -> Real<T>
	where
		T: Conjugate,
	{
/// returns the sum of the elements of `self`
	pub fn sum(&self) -> T::Canonical
	where
		T: Conjugate,
	{
/// see [`Mat::kron`]
	pub fn kron(&self, rhs: impl AsMatRef<T: Conjugate<Canonical = T::Canonical>>) -> Mat<T::Canonical>
	where
		T: Conjugate,
	{
		fn imp<T: ComplexField>(lhs: MatRef<impl Conjugate<Canonical = T>>, rhs: MatRef<impl Conjugate<Canonical = T>>) -> Mat<T> {
/// returns `true` if all of the elements of `self` are finite.
/// otherwise returns `false`.
	pub fn is_all_finite(&self) -> bool
	where
		T: Conjugate,
	{
/// returns `true` if any of the elements of `self` is `NaN`.
/// otherwise returns `false`.
	pub fn has_nan(&self) -> bool
	where
		T: Conjugate,
	{
/// returns a newly allocated row holding the cloned values of `self`
	pub fn cloned(&self) -> Row<T, Cols>
	where
		T: Clone,
	{
/// returns a newly allocated row holding the (possibly conjugated) values of `self`
	pub fn to_owned(&self) -> Row<T::Canonical, Cols>
	where
		T: Conjugate,
	{
/// returns a reference over the elements as a slice
	pub fn as_slice(self) -> &'a [T] {
/// returns a reference over the elements as a lifetime-bound slice
	pub fn as_array(self) -> &'a Array<'ROWS, T> {
	pub fn split_cols_with<'LEFT, 'RIGHT>(
		self,
		col: Partition<'LEFT, 'RIGHT, 'COLS>,
	) -> (RowRef<'a, T, Dim<'LEFT>, CStride>, RowRef<'a, T, Dim<'RIGHT>, CStride>) {
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
		fn imp<T: core::fmt::Debug>(f: &mut core::fmt::Formatter<'_>, this: RowRef<'_, T, Dim<'_>>) -> core::fmt::Result {
/// Returns the maximum element in the row, or `None` if the row is empty
	pub(crate) fn internal_max(self) -> Option<T> {
/// Returns the minimum element in the row, or `None` if the row is empty
	pub(crate) fn internal_min(self) -> Option<T> {
/// Returns the maximum element in the row, or `None` if the row is empty
	pub fn max(&self) -> Option<T> {
/// Returns the minimum element in the row, or `None` if the row is empty
	pub fn min(&self) -> Option<T> {
	fn test_row_min() {
	fn test_row_max() {
	fn serialize<S>(&self, s: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
	where
		S: Serializer,
	{
			fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
			where
				S: Serializer,
			{
	fn serialize<S>(&self, s: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
	where
		S: Serializer,
	{
	fn serialize<S>(&self, s: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
	where
		S: Serializer,
	{
	fn deserialize<D>(d: D) -> Result<Self, <D as serde::Deserializer<'a>>::Error>
	where
		D: serde::Deserializer<'a>,
	{
			fn into_mat(self, nrows: usize, ncols: usize) -> Mat<T> {
			fn new(nrows: Option<usize>, ncols: Option<usize>) -> Self {
			fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
			where
				D: serde::Deserializer<'a>,
			{
			fn expecting(&self, formatter: &mut alloc::fmt::Formatter) -> alloc::fmt::Result {
			fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
			where
				A: SeqAccess<'a>,
			{
			fn expecting(&self, formatter: &mut alloc::fmt::Formatter) -> alloc::fmt::Result {
			fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
			where
				A: SeqAccess<'a>,
			{
			fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
			where
				A: serde::de::MapAccess<'a>,
			{
	fn matrix_serialization_normal() {
	fn matrix_serialization_wide() {
	fn matrix_serialization_tall() {
	fn matrix_serialization_zero() {
	fn matrix_serialization_errors_too_small() {
	fn matrix_serialization_errors_too_large() {
// code taken from the rust standard library
	fn get_ptr(ptr: *mut Self::Item) -> Self;
	unsafe fn offset_from(self, origin: Self) -> isize;
	unsafe fn add(self, offset: usize) -> Self;
	unsafe fn sub(self, offset: usize) -> Self;
	unsafe fn read(self) -> Self::Item;
	unsafe fn write(self, item: Self::Item);
	unsafe fn copy_nonoverlapping(src: Self, dst: Self, len: usize);
	unsafe fn reverse(ptr: Self, len: usize);
	unsafe fn swap(a: Self, b: Self) {
	unsafe fn swap_idx(self, i: usize, j: usize) {
	fn get_ptr(ptr: *mut Self::Item) -> Self {
	unsafe fn offset_from(self, origin: Self) -> isize {
	unsafe fn add(self, offset: usize) -> Self {
	unsafe fn sub(self, offset: usize) -> Self {
	unsafe fn read(self) -> Self::Item {
	unsafe fn write(self, item: Self::Item) {
	unsafe fn copy_nonoverlapping(src: Self, dst: Self, len: usize) {
	unsafe fn reverse(ptr: Self, len: usize) {
	fn get_ptr(ptr: *mut Self::Item) -> Self {
	unsafe fn offset_from(self, origin: Self) -> isize {
	unsafe fn add(self, offset: usize) -> Self {
	unsafe fn sub(self, offset: usize) -> Self {
	unsafe fn read(self) -> Self::Item {
	unsafe fn write(self, item: Self::Item) {
	unsafe fn copy_nonoverlapping(src: Self, dst: Self, len: usize) {
	unsafe fn reverse(ptr: Self, len: usize) {
	fn drop(&mut self) {
// SAFETY: This is a helper class. Please refer to its usage for correctness. Namely, one
// must be sure that `src` and `dst` does not overlap as required by
// `ptr::copy_nonoverlapping` and are both valid for writes.
unsafe fn insert_tail<P: Ptr, F>(v: P, v_len: usize, is_less: &mut F)
where
	F: FnMut(P, P) -> bool,
{
// SAFETY: caller must ensure v is at least len 2.
// See insert_head which talks about why this approach is beneficial.
// It's important that we use i_ptr here. If this check is positive and we continue,
// We want to make sure that no other copy of the value was seen by is_less.
// Otherwise we would have to copy it back.
// It's important, that we use tmp for comparison from now on. As it is the value that
// will be copied back. And notionally we could have created a divergence if we copy
// back the wrong value.
// Intermediate state of the insertion process is always tracked by `hole`, which
// serves two purposes:
// 1. Protects integrity of `v` from panics in `is_less`.
// 2. Fills the remaining hole in `v` in the end.
//
// Panic safety:
//
// If `is_less` panics at any point during the process, `hole` will get dropped and
// fill the hole in `v` with `tmp`, thus ensuring that `v` still holds every object it
// initially held exactly once.
// SAFETY: We know i is at least 1.
// `hole` gets dropped and thus copies `tmp` into the remaining hole in `v`.
unsafe fn insert_head<P: Ptr, F>(v: P, v_len: usize, is_less: &mut F)
where
	F: FnMut(P, P) -> bool,
{
// SAFETY: caller must ensure v is at least len 2.
// There are three ways to implement insertion here:
//
// 1. Swap adjacent elements until the first one gets to its final destination. However, this way we
//    copy data around more than is necessary. If elements are big structures (costly to copy), this
//    method will be slow.
//
// 2. Iterate until the right place for the first element is found. Then shift the elements
//    succeeding it to make room for it and finally place it into the remaining hole. This is a good
//    method.
//
// 3. Copy the first element into a temporary variable. Iterate until the right place for it is
//    found. As we go along, copy every traversed element into the slot preceding it. Finally, copy
//    data from the temporary variable into the remaining hole. This method is very good. Benchmarks
//    demonstrated slightly better performance than with the 2nd method.
//
// All methods were benchmarked, and the 3rd showed best results. So we chose that one.
// Intermediate state of the insertion process is always tracked by `hole`, which
// serves two purposes:
// 1. Protects integrity of `v` from panics in `is_less`.
// 2. Fills the remaining hole in `v` in the end.
//
// Panic safety:
//
// If `is_less` panics at any point during the process, `hole` will get dropped and
// fill the hole in `v` with `tmp`, thus ensuring that `v` still holds every object it
// initially held exactly once.
// `hole` gets dropped and thus copies `tmp` into the remaining hole in `v`.
pub(super) fn insertion_sort_shift_left<P: Ptr, F: FnMut(P, P) -> bool>(v: P, v_len: usize, offset: usize, is_less: &mut F) {
// Using assert here improves performance.
// Shift each element of the unsorted region v[i..] as far left as is needed to make v sorted.
// SAFETY: we tested that `offset` must be at least 1, so this loop is only entered if len
// >= 2. The range is exclusive and we know `i` must be at least 1 so this slice has at
// >least len 2.
fn insertion_sort_shift_right<P: Ptr, F: FnMut(P, P) -> bool>(v: P, v_len: usize, offset: usize, is_less: &mut F) {
// Using assert here improves performance.
// Shift each element of the unsorted region v[..i] as far left as is needed to make v sorted.
// SAFETY: we tested that `offset` must be at least 1, so this loop is only entered if len
// >= 2.We ensured that the slice length is always at least 2 long. We know that start_found
// will be at least one less than end, and the range is exclusive. Which gives us i always
// <= (end - 2).
unsafe fn partial_insertion_sort<P: Ptr, F: FnMut(P, P) -> bool>(v: P, v_len: usize, is_less: &mut F) -> bool {
// Maximum number of adjacent out-of-order pairs that will get shifted.
// If the slice is shorter than this, don't shift any elements.
// SAFETY: We already explicitly did the bound checking with `i < len`.
// All our subsequent indexing is only in the range `0 <= index < len`
// Find the next pair of adjacent out-of-order elements.
// Are we done?
// Don't shift elements on short arrays, that has a performance cost.
// Swap the found pair of elements. This puts them in correct order.
// Shift the smaller element to the left.
// Shift the greater element to the right.
// Didn't manage to sort the slice in the limited number of steps.
pub unsafe fn heapsort<P: Ptr, F: FnMut(P, P) -> bool>(v: P, v_len: usize, mut is_less: F) {
// This binary heap respects the invariant `parent >= child`.
// Children of `node`.
// Choose the greater child.
// We need a branch to be sure not to out-of-bounds index,
// but it's highly predictable.  The comparison, however,
// is better done branchless, especially for primitives.
// Stop if the invariant holds at `node`.
// Swap `node` with the greater child, move one step down, and continue sifting.
// Build the heap in linear time.
// Pop maximal elements from the heap.
unsafe fn partition_in_blocks<P: Ptr, F: FnMut(P, P) -> bool>(v: P, v_len: usize, pivot: P, is_less: &mut F) -> usize {
// Number of elements in a typical block.
// The partitioning algorithm repeats the following steps until completion:
//
// 1. Trace a block from the left side to identify elements greater than or equal to the pivot.
// 2. Trace a block from the right side to identify elements smaller than the pivot.
// 3. Exchange the identified elements between the left and right side.
//
// We keep the following variables for a block of elements:
//
// 1. `block` - Number of elements in the block.
// 2. `start` - Start pointer into the `offsets` array.
// 3. `end` - End pointer into the `offsets` array.
// 4. `offsets` - Indices of out-of-order elements within the block.
// The current block on the left side (from `l` to `l.add(block_l)`).
// The current block on the right side (from `r.sub(block_r)` to `r`).
// SAFETY: The documentation for .add() specifically mention that `vec.as_ptr().add(vec.len())`
// is always safe
// FIXME: When we get VLAs, try creating one array of length `min(v.len(), 2 * BLOCK)` rather
// than two fixed-size arrays of length `BLOCK`. VLAs might be more cache-efficient.
// Returns the number of elements between pointers `l` (inclusive) and `r` (exclusive).
	unsafe fn width<P: Ptr>(l: P, r: P) -> usize {
// We are done with partitioning block-by-block when `l` and `r` get very close. Then we do
// some patch-up work in order to partition the remaining elements in between.
// Number of remaining elements (still not compared to the pivot).
// Adjust block sizes so that the left and right block don't overlap, but get perfectly
// aligned to cover the whole remaining gap.
// There were the same number of elements to switch on both blocks during the last
// iteration, so there are no remaining elements on either block. Cover the
// remaining items with roughly equally-sized blocks.
// Trace `block_l` elements from the left side.
// SAFETY: The unsafety operations below involve the usage of the `offset`.
//         According to the conditions required by the function, we satisfy them
// because:
//         1. `offsets_l` is stack-allocated, and thus considered separate allocated object.
//         2. The function `is_less` returns a `bool`. Casting a `bool` will never overflow `isize`.
//         3. We have guaranteed that `block_l` will be `<= BLOCK`. Plus, `end_l` was initially set
//            to the begin pointer of `offsets_` which was declared on the stack. Thus, we know that
//            even in the worst case (all invocations of `is_less` returns false) we will only be at
//            most 1 byte pass the end.
//        Another unsafety operation here is dereferencing `elem`.
//        However, `elem` was initially the begin pointer to the slice which is
// always valid.
// Branchless comparison.
// Trace `block_r` elements from the right side.
// SAFETY: The unsafety operations below involve the usage of the `offset`.
//         According to the conditions required by the function, we satisfy them
// because:
//         1. `offsets_r` is stack-allocated, and thus considered separate allocated object.
//         2. The function `is_less` returns a `bool`. Casting a `bool` will never overflow `isize`.
//         3. We have guaranteed that `block_r` will be `<= BLOCK`. Plus, `end_r` was initially set
//            to the begin pointer of `offsets_` which was declared on the stack. Thus, we know that
//            even in the worst case (all invocations of `is_less` returns true) we will only be at
//            most 1 byte pass the end.
//        Another unsafety operation here is dereferencing `elem`.
//        However, `elem` was initially `1 * sizeof(T)` past the end and we
// decrement it by `1 * sizeof(T)` before accessing it.        Plus,
// `block_r` was asserted to be less than `BLOCK` and `elem` will therefore at most
// be pointing to the beginning of the slice.
// Branchless comparison.
// Number of out-of-order elements to swap between the left and right side.
// Instead of swapping one pair at the time, it is more efficient to perform a cyclic
// permutation. This is not strictly equivalent to swapping, but produces a similar
// result using fewer memory operations.
// SAFETY: The use of `ptr::read` is valid because there is at least one element in
// both `offsets_l` and `offsets_r`, so `left!` is a valid pointer to read from.
//
// The uses of `left!` involve calls to `offset` on `l`, which points to the
// beginning of `v`. All the offsets pointed-to by `start_l` are at most `block_l`, so
// these `offset` calls are safe as all reads are within the block. The same argument
// applies for the uses of `right!`.
//
// The calls to `start_l.offset` are valid because there are at most `count-1` of them,
// plus the final one at the end of the unsafe block, where `count` is the minimum
// number of collected offsets in `offsets_l` and `offsets_r`, so there is
// no risk of there not being enough elements. The same reasoning applies to
// the calls to `start_r.offset`.
//
// The calls to `copy_nonoverlapping` are safe because `left!` and `right!` are
// guaranteed not to overlap, and are valid because of the reasoning above.
// core::mem::forget(tmp);
// All out-of-order elements in the left block were moved. Move to the next block.
// block-width-guarantee
// SAFETY: if `!is_done` then the slice width is guaranteed to be at least `2*BLOCK`
// wide. There are at most `BLOCK` elements in `offsets_l` because of its
// size, so the `offset` operation is safe. Otherwise, the debug assertions
// in the `is_done` case guarantee that `width(l, r) == block_l + block_r`,
// namely, that the block sizes have been adjusted to account
// for the smaller number of remaining elements.
// All out-of-order elements in the right block were moved. Move to the previous block.
// SAFETY: Same argument as [block-width-guarantee]. Either this is a full block
// `2*BLOCK`-wide, or `block_r` has been adjusted for the last handful of
// elements.
// All that remains now is at most one block (either the left or the right) with out-of-order
// elements that need to be moved. Such remaining elements can be simply shifted to the end
// within their block.
// The left block remains.
// Move its remaining out-of-order elements to the far right.
// remaining-elements-safety
// SAFETY: while the loop condition holds there are still elements in `offsets_l`, so it
// is safe to point `end_l` to the previous element.
//
// The `ptr::swap` is safe if both its arguments are valid for reads and writes:
//  - Per the debug assert above, the distance between `l` and `r` is `block_l` elements, so there
//    can be at most `block_l` remaining offsets between `start_l` and `end_l`. This means `r` will
//    be moved at most `block_l` steps back, which makes the `r.offset` calls valid (at that point
//    `l == r`).
//  - `offsets_l` contains valid offsets into `v` collected during the partitioning of the last
//    block, so the `l.offset` calls are valid.
// The right block remains.
// Move its remaining out-of-order elements to the far left.
// SAFETY: See the reasoning in [remaining-elements-safety].
// Nothing else to do, we're done.
pub(super) unsafe fn partition<P: Ptr, F>(v: P, v_len: usize, pivot: usize, is_less: &mut F) -> (usize, bool)
where
	F: FnMut(P, P) -> bool,
{
// Place the pivot at the beginning of slice.
// Read the pivot into a stack-allocated variable for efficiency. If a following comparison
// operation panics, the pivot will be automatically written back into the slice.
// SAFETY: `pivot` is a reference to the first element of `v`, so `ptr::read` is safe.
// Find the first pair of out-of-order elements.
// SAFETY: The unsafety below involves indexing an array.
// For the first one: We already do the bounds checking here with `l < r`.
// For the second one: We initially have `l == 0` and `r == v.len()` and we checked that `l
// < r` at every indexing operation.                     From here we know that `r`
// must be at least `r == l` which was shown to be valid from the first one.
// Find the first element greater than or equal to the pivot.
// Find the last element smaller that the pivot.
// `_pivot_guard` goes out of scope and writes the pivot (which is a stack-allocated
// variable) back into the slice where it originally was. This step is critical in ensuring
// safety!
// Place the pivot between the two partitions.
pub(super) unsafe fn partition_equal<P: Ptr, F>(v: P, v_len: usize, pivot: usize, is_less: &mut F) -> usize
where
	F: FnMut(P, P) -> bool,
{
// Place the pivot at the beginning of slice.
// Read the pivot into a stack-allocated variable for efficiency. If a following comparison
// operation panics, the pivot will be automatically written back into the slice.
// SAFETY: The pointer here is valid because it is obtained from a reference to a slice.
// Now partition the slice.
// SAFETY: The unsafety below involves indexing an array.
// For the first one: We already do the bounds checking here with `l < r`.
// For the second one: We initially have `l == 0` and `r == v.len()` and we checked that `l
// < r` at every indexing operation.                     From here we know that `r`
// must be at least `r == l` which was shown to be valid from the first one.
// Find the first element greater than the pivot.
// Find the last element equal to the pivot.
// Are we done?
// Swap the found pair of out-of-order elements.
// We found `l` elements equal to the pivot. Add 1 to account for the pivot itself.
// `_pivot_guard` goes out of scope and writes the pivot (which is a stack-allocated variable)
// back into the slice where it originally was. This step is critical in ensuring safety!
pub(super) unsafe fn break_patterns<P: Ptr>(v: P, v_len: usize) {
// Pseudorandom number generator from the "Xorshift RNGs" paper by George Marsaglia.
// Take random numbers modulo this number.
// The number fits into `usize` because `len` is not greater than `isize::MAX`.
// Some pivot candidates will be in the nearby of this index. Let's randomize them.
// Generate a random number modulo `len`. However, in order to avoid costly operations
// we first take it modulo a power of two, and then decrease by `len` until it fits
// into the range `[0, len - 1]`.
// `other` is guaranteed to be less than `2 * len`.
pub(super) unsafe fn choose_pivot<P: Ptr, F>(v: P, v_len: usize, is_less: &mut F) -> (usize, bool)
where
	F: FnMut(P, P) -> bool,
{
// Minimum length to choose the median-of-medians method.
// Shorter slices use the simple median-of-three method.
// Maximum number of swaps that can be performed in this function.
// Three indices near which we are going to choose a pivot.
// Counts the total number of swaps we are about to perform while sorting indices.
// Swaps indices so that `v[a] <= v[b]`.
// SAFETY: `len >= 8` so there are at least two elements in the neighborhoods of
// `a`, `b` and `c`. This means the three calls to `sort_adjacent` result in
// corresponding calls to `sort3` with valid 3-item neighborhoods around each
// pointer, which in turn means the calls to `sort2` are done with valid
// references. Thus the `v.get_unchecked` calls are safe, as is the `ptr::swap`
// call.
// Swaps indices so that `v[a] <= v[b] <= v[c]`.
// Finds the median of `v[a - 1], v[a], v[a + 1]` and stores the index into `a`.
// Find medians in the neighborhoods of `a`, `b`, and `c`.
// Find the median among `a`, `b`, and `c`.
// The maximum number of swaps was performed. Chances are the slice is descending or mostly
// descending, so reversing will probably help sort it faster.
/// sorts `v` using pattern-defeating quicksort, which is *O*(*n* \* log(*n*)) worst-case
pub unsafe fn quicksort<P: Ptr, F>(v: P, v_len: usize, mut is_less: F)
where
	F: FnMut(P, P) -> bool,
{
// Sorting has no meaningful behavior on zero-sized types.
// Limit the number of imbalanced partitions to `floor(log2(len)) + 1`.
unsafe fn recurse<P: Ptr, F: FnMut(P, P) -> bool>(mut v: P, mut v_len: usize, is_less: &mut F, mut pred: Option<P>, mut limit: u32) {
// Slices of up to this length get sorted using insertion sort.
// True if the last partitioning was reasonably balanced.
// True if the last partitioning didn't shuffle elements (the slice was already partitioned).
// Very short slices get sorted using insertion sort.
// If too many bad pivot choices were made, simply fall back to heapsort in order to
// guarantee `O(n * log(n))` worst-case.
// If the last partitioning was imbalanced, try breaking patterns in the slice by shuffling
// some elements around. Hopefully we'll choose a better pivot this time.
// Choose a pivot and try guessing whether the slice is already sorted.
// If the last partitioning was decently balanced and didn't shuffle elements, and if pivot
// selection predicts the slice is likely already sorted...
// Try identifying several out-of-order elements and shifting them to correct
// positions. If the slice ends up being completely sorted, we're done.
// If the chosen pivot is equal to the predecessor, then it's the smallest element in the
// slice. Partition the slice into elements equal to and elements greater than the pivot.
// This case is usually hit when the slice contains many duplicate elements.
// Continue sorting elements greater than the pivot.
// Partition the slice.
// Split the slice into `left`, `pivot`, and `right`.
// Recurse into the shorter side only in order to minimize the total number of recursive
// calls and consume less stack space. Then just continue with the longer side (this is
// akin to tail recursion).
pub unsafe fn sort_unstable_by<P: Ptr>(ptr: P, len: usize, compare: impl FnMut(P, P) -> core::cmp::Ordering) {
pub unsafe fn sort_indices<I: crate::Index, T>(indices: &mut [I], values: &mut [T]) {
	fn test_quicksort() {
	fn test_quicksort_big() {
/// implementation of symbolic representation
/// generic `SymbolicSparseColMat` wrapper
/// generic `SymbolicSparseColMat` wrapper
			fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
/// wrap by reference
			pub fn from_inner_ref(inner: &Inner) -> &Self {
/// wrap by mutable reference
			pub fn from_inner_mut(inner: &mut Inner) -> &mut Self {
			fn deref(&self) -> &Self::Target {
			fn deref_mut(&mut self) -> &mut Self::Target {
			fn rb(&'short self) -> Self::Target {
			fn rb_mut(&'short mut self) -> Self::Target {
			fn into_const(self) -> Self::Target {
/// see [`super::SymbolicSparseColMatRef`]
/// see [`super::SymbolicSparseColMat`]
/// implementation of numeric representation
/// generic `SparseColMat` wrapper
/// generic `SparseColMat` wrapper
			fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
/// wrap by reference
			pub fn from_inner_ref(inner: &Inner) -> &Self {
/// wrap by mutable reference
			pub fn from_inner_mut(inner: &mut Inner) -> &mut Self {
			fn rb(&'short self) -> Self::Target {
			fn rb_mut(&'short mut self) -> Self::Target {
			fn into_const(self) -> Self::Target {
/// see [`super::SparseColMatRef`]
/// see [`super::SparseColMatMut`]
/// see [`super::SparseColMat`]
/// symbolic view structure of sparse matrix in column format, either compressed or uncompressed
///
/// # invariants
/// - `nrows <= I::Signed::MAX` (always checked)
/// - `ncols <= I::Signed::MAX` (always checked)
/// - `col_ptrs` has length `ncols + 1` (always checked)
/// - `col_ptrs` is increasing
/// - `col_ptrs[0]..col_ptrs[ncols]` is a valid range in row_indices (always checked, assuming it's
///   increasing)
/// - if `nnz_per_col` is `none`, elements of `row_indices[col_ptrs[j]..col_ptrs[j + 1]]` are less
///   than `nrows`
///
/// - `nnz_per_col[j] <= col_ptrs[j+1] - col_ptrs[j]`
/// - if `nnz_per_col` is `some(_)`, elements of `row_indices[col_ptrs[j]..][..nnz_per_col[j]]` are
///   less than `nrows`
///
/// # soft invariants
/// - within each column, row indices are sorted in increasing order
///
/// # note
/// some algorithms allow working with matrices containing unsorted row indices per column
///
/// passing such a matrix to an algorithm that does not explicitly permit this is unspecified
/// (though not undefined) behavior
/// owning symbolic structure of sparse matrix in column format, either compressed or
/// uncompressed
///
/// see [`SymbolicSparseColMatRef`]
/// view over sparse column major matrix
///
/// see [`SymbolicSparseColMatRef`]
/// view over sparse column major matrix
///
/// see [`SymbolicSparseColMatRef`]
/// owning sparse column major matrix
///
/// see [`SymbolicSparseColMatRef`]
pub(crate) fn partition_by_lt<I: Index>(upper: I) -> impl Fn(&I) -> bool {
pub(crate) fn partition_by_le<I: Index>(upper: I) -> impl Fn(&I) -> bool {
	fn clone(&self) -> Self {
	fn clone(&self) -> Self {
	fn into_const(self) -> Self::Target {
	fn rb_mut(&'short mut self) -> Self::Target {
	fn rb(&'short self) -> Self::Target {
	fn into_const(self) -> Self::Target {
	fn rb_mut(&'short mut self) -> Self::Target {
	fn rb(&'short self) -> Self::Target {
	fn into_const(self) -> Self::Target {
	fn rb_mut(&'short mut self) -> Self::Target {
	fn rb(&'short self) -> Self::Target {
	fn rb_mut(&'short mut self) -> Self::Target {
	fn rb(&'short self) -> Self::Target {
	fn rb(&'short self) -> Self::Target {
fn assume_col_ptr<I: Index>(nrows: usize, ncols: usize, col_ptr: &[I], col_nnz: Option<&[I]>, row_idx: &[I]) {
fn check_col_ptr<I: Index>(nrows: usize, ncols: usize, col_ptr: &[I], col_nnz: Option<&[I]>, row_idx: &[I]) {
fn check_row_idx<I: Index>(nrows: usize, ncols: usize, col_ptr: &[I], col_nnz: Option<&[I]>, row_idx: &[I]) {
fn check_row_idx_unsorted<I: Index>(nrows: usize, ncols: usize, col_ptr: &[I], col_nnz: Option<&[I]>, row_idx: &[I]) {
/// creates a new symbolic matrix view without checking its invariants
///
/// # safety
/// see type level documentation.
	pub unsafe fn new_unchecked(nrows: Rows, ncols: Cols, col_ptr: &'a [I], col_nnz: Option<&'a [I]>, row_idx: &'a [I]) -> Self {
/// creates a new symbolic matrix view after checking its invariants
///
/// # safety
/// see type level documentation.
	pub fn new_checked(nrows: Rows, ncols: Cols, col_ptr: &'a [I], col_nnz: Option<&'a [I]>, row_idx: &'a [I]) -> Self {
/// creates a new symbolic matrix view after checking its invariants (excluding soft invariants)
///
/// # safety
/// see type level documentation.
	pub fn new_unsorted_checked(nrows: Rows, ncols: Cols, col_ptr: &'a [I], col_nnz: Option<&'a [I]>, row_idx: &'a [I]) -> Self {
/// returns the components of the sparse matrix
/// - number of rows
/// - number of columns
/// - column pointers
/// - column non-zero counts
/// - row indices
	pub fn parts(self) -> (Rows, Cols, &'a [I], Option<&'a [I]>, &'a [I]) {
/// returns the number of rows of the matrix
	pub fn nrows(&self) -> Rows {
/// returns the number of columns of the matrix
	pub fn ncols(&self) -> Cols {
/// returns the number of rows and columns of the matrix
	pub fn shape(&self) -> (Rows, Cols) {
/// returns a view over the transpose of `self`
	pub fn transpose(self) -> SymbolicSparseRowMatRef<'a, I, Cols, Rows> {
/// returns a newly allocated matrix holding the values of `self`
	pub fn to_owned(&self) -> Result<SymbolicSparseColMat<I, Rows, Cols>, FaerError> {
/// returns a newly allocated matrix holding the values of `self` in row major format
	pub fn to_row_major(&self) -> Result<SymbolicSparseRowMat<I, Rows, Cols>, FaerError> {
/// returns the number of non-zero elements in the matrix
	pub fn compute_nnz(&self) -> usize {
		fn imp<I: Index>(col_ptr: &[I], col_nnz: Option<&[I]>, ncols: usize) -> usize {
// can't overflow
/// returns the column pointers
	pub fn col_ptr(&self) -> &'a [I] {
/// returns the column non-zero counts
	pub fn col_nnz(&self) -> Option<&'a [I]> {
/// returns the row indices
	pub fn row_idx(&self) -> &'a [I] {
/// returns the range specifying the indices of column `j`
	pub fn col_range(&self, j: Idx<Cols>) -> Range<usize> {
/// returns the range specifying the indices of column `j`, without bound checks
	pub unsafe fn col_range_unchecked(&self, j: Idx<Cols>) -> Range<usize> {
/// returns the row indices of column `j`
	pub fn row_idx_of_col_raw(&self, j: Idx<Cols>) -> &'a [Idx<Rows, I>] {
/// returns the row indices of column `j`
	pub fn row_idx_of_col(&self, j: Idx<Cols>) -> impl 'a + Clone + ExactSizeIterator + DoubleEndedIterator<Item = Idx<Rows>>
	where
		Rows: 'a,
		Cols: 'a,
	{
/// returns the input matrix with the given shape after checking that it matches the
/// current shape
	pub fn as_shape<V: Shape, H: Shape>(self, nrows: V, ncols: H) -> SymbolicSparseColMatRef<'a, I, V, H> {
/// returns the input matrix with dynamic shape
	pub fn as_dyn(self) -> SymbolicSparseColMatRef<'a, I> {
/// Returns a view over the symbolic structure of `self`.
	pub fn as_ref(self) -> SymbolicSparseColMatRef<'a, I, Rows, Cols> {
/// creates a new symbolic matrix view without checking its invariants
///
/// # safety
/// see type level documentation.
	pub unsafe fn new_unchecked(
		nrows: Rows,
		ncols: Cols,
		col_ptr: alloc::vec::Vec<I>,
		col_nnz: Option<alloc::vec::Vec<I>>,
		row_idx: alloc::vec::Vec<I>,
	) -> Self {
/// creates a new symbolic matrix view after checking its invariants
///
/// # safety
/// see type level documentation.
	pub fn new_checked(
		nrows: Rows,
		ncols: Cols,
		col_ptr: alloc::vec::Vec<I>,
		col_nnz: Option<alloc::vec::Vec<I>>,
		row_idx: alloc::vec::Vec<I>,
	) -> Self {
/// creates a new symbolic matrix view after checking its invariants (excluding soft invariants)
///
/// # safety
/// see type level documentation.
	pub fn new_unsorted_checked(
		nrows: Rows,
		ncols: Cols,
		col_ptr: alloc::vec::Vec<I>,
		col_nnz: Option<alloc::vec::Vec<I>>,
		row_idx: alloc::vec::Vec<I>,
	) -> Self {
/// see [`SymbolicSparseColMatRef::parts`]
	pub fn parts(&self) -> (Rows, Cols, &'_ [I], Option<&'_ [I]>, &'_ [I]) {
/// see [`SymbolicSparseColMatRef::parts`]
	pub fn into_parts(self) -> (Rows, Cols, alloc::vec::Vec<I>, Option<alloc::vec::Vec<I>>, alloc::vec::Vec<I>) {
/// returns the number of rows of the matrix
	pub fn nrows(&self) -> Rows {
/// returns the number of columns of the matrix
	pub fn ncols(&self) -> Cols {
/// returns the number of rows and columns of the matrix
	pub fn shape(&self) -> (Rows, Cols) {
/// returns a view over the transpose of `self`
	pub fn transpose(&self) -> SymbolicSparseRowMatRef<'_, I, Cols, Rows> {
/// returns the transpose of `self`
	pub fn into_transpose(self) -> SymbolicSparseRowMat<I, Cols, Rows> {
/// see [`SymbolicSparseColMatRef::to_owned`]
	pub fn to_owned(&self) -> Result<SymbolicSparseColMat<I, Rows, Cols>, FaerError> {
/// see [`SymbolicSparseColMatRef::to_row_major`]
	pub fn to_row_major(&self) -> Result<SymbolicSparseRowMat<I, Rows, Cols>, FaerError> {
/// see [`SymbolicSparseColMatRef::compute_nnz`]
	pub fn compute_nnz(&self) -> usize {
/// see [`SymbolicSparseColMatRef::col_ptr`]
	pub fn col_ptr(&self) -> &'_ [I] {
/// see [`SymbolicSparseColMatRef::col_nnz`]
	pub fn col_nnz(&self) -> Option<&'_ [I]> {
/// see [`SymbolicSparseColMatRef::row_idx`]
	pub fn row_idx(&self) -> &'_ [I] {
/// see [`SymbolicSparseColMatRef::col_range`]
	pub fn col_range(&self, j: Idx<Cols>) -> Range<usize> {
/// see [`SymbolicSparseColMatRef::col_range_unchecked`]
	pub unsafe fn col_range_unchecked(&self, j: Idx<Cols>) -> Range<usize> {
/// see [`SymbolicSparseColMatRef::row_idx_of_col_raw`]
	pub fn row_idx_of_col_raw(&self, j: Idx<Cols>) -> &'_ [Idx<Rows, I>] {
/// see [`SymbolicSparseColMatRef::row_idx_of_col`]
	pub fn row_idx_of_col(&self, j: Idx<Cols>) -> impl '_ + Clone + ExactSizeIterator + DoubleEndedIterator<Item = Idx<Rows>> {
/// see [`SymbolicSparseColMatRef::as_shape`]
	pub fn as_shape<V: Shape, H: Shape>(&self, nrows: V, ncols: H) -> SymbolicSparseColMatRef<'_, I, V, H> {
/// see [`SymbolicSparseColMatRef::as_shape`]
	pub fn into_shape<V: Shape, H: Shape>(self, nrows: V, ncols: H) -> SymbolicSparseColMat<I, V, H> {
/// see [`SymbolicSparseColMatRef::as_dyn`]
	pub fn as_dyn(&self) -> SymbolicSparseColMatRef<'_, I> {
/// see [`SymbolicSparseColMatRef::as_dyn`]
	pub fn into_dyn(self) -> SymbolicSparseColMat<I> {
/// Returns a view over the symbolic structure of `self`.
	pub fn as_ref(&self) -> SymbolicSparseColMatRef<'_, I, Rows, Cols> {
	pub(crate) fn try_new_from_indices_impl(
		nrows: Rows,
		ncols: Cols,
		idx: impl Fn(usize) -> Pair<Idx<Rows, I>, Idx<Cols, I>>,
		ignore: impl Fn(Idx<Rows, I>, Idx<Cols, I>) -> bool,
		all_nnz: usize,
	) -> Result<(Self, Argsort<I>), CreationError> {
/// create a new symbolic structure, and the corresponding order for the numerical values
/// from pairs of indices
	pub fn try_new_from_indices(nrows: Rows, ncols: Cols, idx: &[Pair<Idx<Rows, I>, Idx<Cols, I>>]) -> Result<(Self, Argsort<I>), CreationError> {
/// create a new symbolic structure, and the corresponding order for the numerical values
/// from pairs of indices
///
/// negative indices are ignored
	pub fn try_new_from_nonnegative_indices(
		nrows: Rows,
		ncols: Cols,
		idx: &[Pair<MaybeIdx<Rows, I>, MaybeIdx<Cols, I>>],
	) -> Result<(Self, Argsort<I>), CreationError> {
/// creates a new sparse matrix view.
///
/// # panics
/// panics if the length of `values` is not equal to the length of
/// `symbolic.row_idx()`
	pub fn new(symbolic: SymbolicSparseColMatRef<'a, I, Rows, Cols>, val: &'a [T]) -> Self {
/// returns the symbolic and numeric components of the sparse matrix
	pub fn parts(self) -> (SymbolicSparseColMatRef<'a, I, Rows, Cols>, &'a [T]) {
/// returns the symbolic component of the sparse matrix
	pub fn symbolic(&self) -> SymbolicSparseColMatRef<'a, I, Rows, Cols> {
/// returns the numeric component of the sparse matrix
	pub fn val(self) -> &'a [T] {
/// returns a view over the values of column `j`
	pub fn val_of_col(self, j: Idx<Cols>) -> &'a [T] {
/// returns the input matrix with the given shape after checking that it matches the
/// current shape
	pub fn as_shape<V: Shape, H: Shape>(self, nrows: V, ncols: H) -> SparseColMatRef<'a, I, T, V, H> {
/// returns a reference to the value at the given index, or `None` if the symbolic structure
/// doesn't contain it, or contains multiple indices with the given index
///
/// # panics
/// - panics if `row >= self.nrows()`
/// - panics if `col >= self.ncols()`
	pub fn get(self, row: Idx<Rows>, col: Idx<Cols>) -> Option<&'a T> {
/// returns the input matrix with dynamic shape
	pub fn as_dyn(self) -> SparseColMatRef<'a, I, T> {
/// returns a view over `self`
	pub fn as_ref(self) -> SparseColMatRef<'a, I, T, Rows, Cols> {
/// returns a view over the transpose of `self`
	pub fn transpose(self) -> SparseRowMatRef<'a, I, T, Cols, Rows> {
/// returns a view over the conjugate of `self`
	pub fn conjugate(self) -> SparseColMatRef<'a, I, T::Conj, Rows, Cols>
	where
		T: Conjugate,
	{
/// returns a view over the adjoint of `self`
	pub fn adjoint(self) -> SparseRowMatRef<'a, I, T::Conj, Cols, Rows>
	where
		T: Conjugate,
	{
/// returns an unconjugated view over `self`
	pub fn canonical(self) -> SparseColMatRef<'a, I, T::Canonical, Rows, Cols>
	where
		T: Conjugate,
	{
/// returns a newly allocated matrix holding the (possibly conjugated) values of `self` in row
/// major format
	pub fn to_row_major(&self) -> Result<SparseRowMat<I, T::Canonical, Rows, Cols>, FaerError>
	where
		T: Conjugate,
	{
// O(1) since it's compressed
/// returns a newly allocated dense matrix holding the (possibly conjugated) values of `self`
	pub fn to_dense(&self) -> Mat<T::Canonical, Rows, Cols>
	where
		T: Conjugate,
	{
		fn imp<'ROWS, 'COLS, I: Index, T: Conjugate>(
			src: SparseColMatRef<'_, I, T, Dim<'ROWS>, Dim<'COLS>>,
		) -> Mat<T::Canonical, Dim<'ROWS>, Dim<'COLS>> {
/// returns an iterator over the entries of the matrix.
	pub fn triplet_iter(self) -> impl 'a + Iterator<Item = Triplet<Idx<Rows>, Idx<Cols>, &'a T>>
	where
		Rows: 'a,
		Cols: 'a,
	{
/// see [`SparseColMatRef::new`]
	pub fn new(symbolic: SymbolicSparseColMatRef<'a, I, Rows, Cols>, val: &'a mut [T]) -> Self {
/// see [`SparseColMatRef::parts`]
	pub fn parts(self) -> (SymbolicSparseColMatRef<'a, I, Rows, Cols>, &'a [T]) {
/// see [`SparseColMatRef::parts`]
	pub fn parts_mut(self) -> (SymbolicSparseColMatRef<'a, I, Rows, Cols>, &'a mut [T]) {
/// see [`SparseColMatRef::symbolic`]
	pub fn symbolic(&self) -> SymbolicSparseColMatRef<'a, I, Rows, Cols> {
/// see [`SparseColMatRef::val`]
	pub fn val(self) -> &'a [T] {
/// see [`SparseColMatRef::val`]
	pub fn val_mut(self) -> &'a mut [T] {
/// see [`SparseColMatRef::val_of_col`]
	pub fn val_of_col(self, j: Idx<Cols>) -> &'a [T] {
/// see [`SparseColMatRef::val_of_col`]
	pub fn val_of_col_mut(self, j: Idx<Cols>) -> &'a mut [T] {
/// see [`SymbolicSparseColMatRef::row_idx_of_col`] and [`SparseColMatRef::val_of_col`]
	pub fn idx_val_of_col_mut(self, j: Idx<Cols>) -> (impl 'a + Clone + ExactSizeIterator + DoubleEndedIterator<Item = Idx<Rows>>, &'a mut [T])
	where
		Rows: 'a,
		Cols: 'a,
	{
/// see [`SparseColMatRef::as_shape`]
	pub fn as_shape<V: Shape, H: Shape>(self, nrows: V, ncols: H) -> SparseColMatRef<'a, I, T, V, H> {
/// see [`SparseColMatRef::as_shape`]
	pub fn as_shape_mut<V: Shape, H: Shape>(self, nrows: V, ncols: H) -> SparseColMatMut<'a, I, T, V, H> {
/// see [`SparseColMatRef::as_dyn`]
	pub fn as_dyn(self) -> SparseColMatRef<'a, I, T> {
/// see [`SparseColMatRef::get`]
	pub fn get(self, row: Idx<Rows>, col: Idx<Cols>) -> Option<&'a T> {
/// see [`SparseColMatRef::get`]
	pub fn get_mut(self, row: Idx<Rows>, col: Idx<Cols>) -> Option<&'a mut T> {
/// see [`SparseColMatRef::as_dyn`]
	pub fn as_dyn_mut(self) -> SparseColMatMut<'a, I, T> {
/// see [`SparseColMatRef::transpose`]
	pub fn transpose(self) -> SparseRowMatRef<'a, I, T, Cols, Rows> {
/// see [`SparseColMatRef::transpose`]
	pub fn transpose_mut(self) -> SparseRowMatMut<'a, I, T, Cols, Rows> {
/// see [`SparseColMatRef::conjugate`]
	pub fn conjugate(self) -> SparseColMatRef<'a, I, T::Conj, Rows, Cols>
	where
		T: Conjugate,
	{
/// see [`SparseColMatRef::conjugate`]
	pub fn conjugate_mut(self) -> SparseColMatMut<'a, I, T::Conj, Rows, Cols>
	where
		T: Conjugate,
	{
/// see [`SparseColMatRef::adjoint`]
	pub fn adjoint(self) -> SparseRowMatRef<'a, I, T::Conj, Cols, Rows>
	where
		T: Conjugate,
	{
/// see [`SparseColMatRef::adjoint`]
	pub fn adjoint_mut(self) -> SparseRowMatMut<'a, I, T::Conj, Cols, Rows>
	where
		T: Conjugate,
	{
/// see [`SparseColMatRef::canonical`]
	pub fn canonical(self) -> SparseColMatRef<'a, I, T::Canonical, Rows, Cols>
	where
		T: Conjugate,
	{
/// see [`SparseColMatRef::canonical`]
	pub fn canonical_mut(self) -> SparseColMatMut<'a, I, T::Canonical, Rows, Cols>
	where
		T: Conjugate,
	{
/// see [`SparseColMatRef::to_row_major`]
	pub fn to_row_major(&self) -> Result<SparseRowMat<I, T::Canonical, Rows, Cols>, FaerError>
	where
		T: Conjugate,
	{
/// see [`SparseColMatRef::to_dense`]
	pub fn to_dense(&self) -> Mat<T::Canonical, Rows, Cols>
	where
		T: Conjugate,
	{
/// see [`SparseColMatRef::triplet_iter`]
	pub fn triplet_iter(self) -> impl 'a + Iterator<Item = Triplet<Idx<Rows>, Idx<Cols>, &'a T>>
	where
		Rows: 'a,
		Cols: 'a,
	{
/// see [`SparseColMatRef::new`]
	pub fn new(symbolic: SymbolicSparseColMat<I, Rows, Cols>, val: alloc::vec::Vec<T>) -> Self {
/// see [`SparseColMatRef::parts`]
	pub fn parts(&self) -> (SymbolicSparseColMatRef<'_, I, Rows, Cols>, &'_ [T]) {
/// see [`SparseColMatRef::parts`]
	pub fn parts_mut(&mut self) -> (SymbolicSparseColMatRef<'_, I, Rows, Cols>, &'_ mut [T]) {
/// see [`SparseColMatRef::parts`]
	pub fn into_parts(self) -> (SymbolicSparseColMat<I, Rows, Cols>, alloc::vec::Vec<T>) {
/// see [`SparseColMatRef::symbolic`]
	pub fn symbolic(&self) -> SymbolicSparseColMatRef<'_, I, Rows, Cols> {
/// see [`SparseColMatRef::val`]
	pub fn val(&self) -> &'_ [T] {
/// see [`SparseColMatRef::val`]
	pub fn val_mut(&mut self) -> &'_ mut [T] {
/// see [`SparseColMatRef::val_of_col`]
	pub fn val_of_col(&self, j: Idx<Cols>) -> &'_ [T] {
/// see [`SparseColMatRef::val_of_col`]
	pub fn val_of_col_mut(&mut self, j: Idx<Cols>) -> &'_ mut [T] {
/// see [`SparseColMatRef::as_shape`]
	pub fn as_shape<V: Shape, H: Shape>(&self, nrows: V, ncols: H) -> SparseColMatRef<'_, I, T, V, H> {
/// see [`SparseColMatRef::as_shape`]
	pub fn as_shape_mut<V: Shape, H: Shape>(&mut self, nrows: V, ncols: H) -> SparseColMatMut<'_, I, T, V, H> {
/// see [`SparseColMatRef::as_shape`]
	pub fn into_shape<V: Shape, H: Shape>(self, nrows: V, ncols: H) -> SparseColMat<I, T, V, H> {
/// see [`SparseColMatRef::as_dyn`]
	pub fn as_dyn(&self) -> SparseColMatRef<'_, I, T> {
/// see [`SparseColMatRef::as_dyn`]
	pub fn as_dyn_mut(&mut self) -> SparseColMatMut<'_, I, T> {
/// see [`SparseColMatRef::as_dyn`]
	pub fn into_dyn(self) -> SparseColMat<I, T> {
/// see [`SparseColMatRef::as_ref`]
	pub fn as_ref(&self) -> SparseColMatRef<'_, I, T, Rows, Cols> {
/// see [`SparseColMatRef::transpose`]
	pub fn transpose(&self) -> SparseRowMatRef<'_, I, T, Cols, Rows> {
/// see [`SparseColMatRef::transpose`]
	pub fn transpose_mut(&mut self) -> SparseRowMatMut<'_, I, T, Cols, Rows> {
/// see [`SparseColMatRef::transpose`]
	pub fn into_transpose(self) -> SparseRowMat<I, T, Cols, Rows> {
/// see [`SparseColMatRef::conjugate`]
	pub fn conjugate(&self) -> SparseColMatRef<'_, I, T::Conj, Rows, Cols>
	where
		T: Conjugate,
	{
/// see [`SparseColMatRef::conjugate`]
	pub fn conjugate_mut(&mut self) -> SparseColMatMut<'_, I, T::Conj, Rows, Cols>
	where
		T: Conjugate,
	{
/// see [`SparseColMatRef::conjugate`]
	pub fn into_conjugate(self) -> SparseColMat<I, T::Conj, Rows, Cols>
	where
		T: Conjugate,
	{
/// see [`SparseColMatRef::adjoint`]
	pub fn adjoint(&self) -> SparseRowMatRef<'_, I, T::Conj, Cols, Rows>
	where
		T: Conjugate,
	{
/// see [`SparseColMatRef::adjoint`]
	pub fn adjoint_mut(&mut self) -> SparseRowMatMut<'_, I, T::Conj, Cols, Rows>
	where
		T: Conjugate,
	{
/// see [`SparseColMatRef::adjoint`]
	pub fn into_adjoint(self) -> SparseRowMat<I, T::Conj, Cols, Rows>
	where
		T: Conjugate,
	{
/// see [`SparseColMatRef::canonical`]
	pub fn canonical(&self) -> SparseColMatRef<'_, I, T::Canonical, Rows, Cols>
	where
		T: Conjugate,
	{
/// see [`SparseColMatRef::canonical`]
	pub fn canonical_mut(&mut self) -> SparseColMatMut<'_, I, T::Canonical, Rows, Cols>
	where
		T: Conjugate,
	{
/// see [`SparseColMatRef::canonical`]
	pub fn into_canonical(self) -> SparseColMat<I, T::Canonical, Rows, Cols>
	where
		T: Conjugate,
	{
/// see [`SparseColMatRef::to_row_major`]
	pub fn to_row_major(&self) -> Result<SparseRowMat<I, T::Canonical, Rows, Cols>, FaerError>
	where
		T: Conjugate,
	{
/// see [`SparseColMatRef::to_dense`]
	pub fn to_dense(&self) -> Mat<T::Canonical, Rows, Cols>
	where
		T: Conjugate,
	{
	pub(crate) fn new_from_argsort_impl(
		symbolic: SymbolicSparseColMat<I, Rows, Cols>,
		argsort: &Argsort<I>,
		all_values: impl Fn(usize) -> T,
		values_len: usize,
	) -> Result<Self, FaerError>
	where
		T: ComplexField,
	{
/// create a new matrix from a previously created symbolic structure and value order
///
/// the provided values must correspond to the same indices that were provided in the
/// function call from which the order was created
	pub fn new_from_argsort(symbolic: SymbolicSparseColMat<I, Rows, Cols>, argsort: &Argsort<I>, val: &[T]) -> Result<Self, FaerError>
	where
		T: ComplexField,
	{
/// create a new matrix from triplets
	pub fn try_new_from_triplets(nrows: Rows, ncols: Cols, entries: &[Triplet<Idx<Rows, I>, Idx<Cols, I>, T>]) -> Result<Self, CreationError>
	where
		T: ComplexField,
	{
/// create a new matrix from triplets
///
/// negative indices are ignored
	pub fn try_new_from_nonnegative_triplets(
		nrows: Rows,
		ncols: Cols,
		entries: &[Triplet<MaybeIdx<Rows, I>, MaybeIdx<Cols, I>, T>],
	) -> Result<Self, CreationError>
	where
		T: ComplexField,
	{
/// see [`SparseColMatRef::get`]
	pub fn get(&self, row: Idx<Rows>, col: Idx<Cols>) -> Option<&T> {
/// see [`SparseColMatRef::get`]
	pub fn get_mut(&mut self, row: Idx<Rows>, col: Idx<Cols>) -> Option<&mut T> {
/// see [`SparseColMatRef::triplet_iter`]
	pub fn triplet_iter(&self) -> impl '_ + Iterator<Item = Triplet<Idx<Rows>, Idx<Cols>, &'_ T>> {
	fn deref(&self) -> &Self::Target {
	fn deref(&self) -> &Self::Target {
	fn deref(&self) -> &Self::Target {
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
		fn imp<'ROWS, 'COLS, I: Index>(mat: SymbolicSparseColMatRef<'_, I, Dim<'ROWS>, Dim<'COLS>>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
				fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
		fn imp<'ROWS, 'COLS, I: Index, T: fmt::Debug>(
			mat: SparseColMatRef<'_, I, T, Dim<'ROWS>, Dim<'COLS>>,
			f: &mut fmt::Formatter<'_>,
		) -> fmt::Result {
				fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// implementation of symbolic representation
/// generic `SymbolicSparseRowMat` wrapper
/// generic `SymbolicSparseRowMat` wrapper
			fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
/// wrap by reference
			pub fn from_inner_ref(inner: &Inner) -> &Self {
/// wrap by mutable reference
			pub fn from_inner_mut(inner: &mut Inner) -> &mut Self {
			fn deref(&self) -> &Self::Target {
			fn deref_mut(&mut self) -> &mut Self::Target {
			fn rb(&'short self) -> Self::Target {
			fn rb_mut(&'short mut self) -> Self::Target {
			fn into_const(self) -> Self::Target {
/// see [`super::SymbolicSparseRowMatRef`]
/// see [`super::SymbolicSparseRowMat`]
/// implementation of numeric representation
/// generic `SparseRowMat` wrapper
/// generic `SparseRowMat` wrapper
			fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
/// wrap by reference
			pub fn from_inner_ref(inner: &Inner) -> &Self {
/// wrap by mutable reference
			pub fn from_inner_mut(inner: &mut Inner) -> &mut Self {
			fn rb(&'short self) -> Self::Target {
			fn rb_mut(&'short mut self) -> Self::Target {
			fn into_const(self) -> Self::Target {
/// see [`super::SparseRowMatRef`]
/// see [`super::SparseRowMatMut`]
/// see [`super::SparseRowMat`]
/// symbolic view structure of sparse matrix in row format, either compressed or uncompressed
///
/// # invariants
/// - `nrows <= I::Signed::MAX` (always checked)
/// - `ncols <= I::Signed::MAX` (always checked)
/// - `row_ptrs` has length `nrows + 1` (always checked)
/// - `row_ptrs` is increasing
/// - `row_ptrs[0]..row_ptrs[nrows]` is a valid range in row_indices (always checked, assuming
///   increasing)
/// - if `nnz_per_row` is `none`, elements of `col_indices[row_ptrs[i]..row_ptrs[i + 1]]` are less
///   than `ncols`
///
/// - `nnz_per_row[i] <= row_ptrs[i+1] - row_ptrs[i]`
/// - if `nnz_per_row` is `some(_)`, elements of `col_indices[row_ptrs[i]..][..nnz_per_row[i]]` are
///   less than `ncols`
///
/// # soft invariants
/// - within each row, column indices are sorted in increasing order
///
/// # note
/// some algorithms allow working with matrices containing unsorted row indices per column
///
/// passing such a matrix to an algorithm that does not explicitly permit this is unspecified
/// (though not undefined) behavior
/// owning symbolic structure of sparse matrix in row format, either compressed or
/// uncompressed
///
/// see [`SymbolicSparseRowMatRef`]
/// view over sparse row major matrix
///
/// see [`SymbolicSparseRowMatRef`]
/// view over sparse row major matrix
///
/// see [`SymbolicSparseRowMatRef`]
/// owning sparse row major matrix
///
/// see [`SymbolicSparseRowMatRef`]
	fn clone(&self) -> Self {
	fn clone(&self) -> Self {
	fn into_const(self) -> Self::Target {
	fn rb_mut(&'short mut self) -> Self::Target {
	fn rb(&'short self) -> Self::Target {
	fn into_const(self) -> Self::Target {
	fn rb_mut(&'short mut self) -> Self::Target {
	fn rb(&'short self) -> Self::Target {
	fn into_const(self) -> Self::Target {
	fn rb_mut(&'short mut self) -> Self::Target {
	fn rb(&'short self) -> Self::Target {
	fn rb_mut(&'short mut self) -> Self::Target {
	fn rb(&'short self) -> Self::Target {
	fn rb(&'short self) -> Self::Target {
fn assume_row_ptr<I: Index>(nrows: usize, ncols: usize, row_ptr: &[I], row_nnz: Option<&[I]>, col_idx: &[I]) {
fn check_row_ptr<I: Index>(nrows: usize, ncols: usize, row_ptr: &[I], row_nnz: Option<&[I]>, col_idx: &[I]) {
fn check_col_idx<I: Index>(nrows: usize, ncols: usize, row_ptr: &[I], row_nnz: Option<&[I]>, col_idx: &[I]) {
fn check_col_idx_unsorted<I: Index>(nrows: usize, ncols: usize, row_ptr: &[I], row_nnz: Option<&[I]>, col_idx: &[I]) {
/// creates a new symbolic matrix view without checking its invariants
///
/// # safety
/// see type level documentation.
	pub unsafe fn new_unchecked(nrows: Rows, ncols: Cols, row_ptr: &'a [I], row_nnz: Option<&'a [I]>, col_idx: &'a [I]) -> Self {
/// creates a new symbolic matrix view after checking its invariants
///
/// # safety
/// see type level documentation.
	pub fn new_checked(nrows: Rows, ncols: Cols, row_ptr: &'a [I], row_nnz: Option<&'a [I]>, col_idx: &'a [I]) -> Self {
/// creates a new symbolic matrix view after checking its invariants (excluding soft invariants)
///
/// # safety
/// see type level documentation.
	pub fn new_unsorted_checked(nrows: Rows, ncols: Cols, row_ptr: &'a [I], row_nnz: Option<&'a [I]>, col_idx: &'a [I]) -> Self {
/// returns the components of the sparse matrix
/// - number of rows
/// - number of columns
/// - row pointers
/// - row non-zero counts
/// - column indices
	pub fn parts(self) -> (Rows, Cols, &'a [I], Option<&'a [I]>, &'a [I]) {
/// returns the number of rows of the matrix
	pub fn nrows(&self) -> Rows {
/// returns the number of columns of the matrix
	pub fn ncols(&self) -> Cols {
/// returns the number of rows and columns of the matrix
	pub fn shape(&self) -> (Rows, Cols) {
/// returns a view over the transpose of `self`
	pub fn transpose(self) -> SymbolicSparseColMatRef<'a, I, Cols, Rows> {
/// returns a newly allocated matrix holding the values of `self`
	pub fn to_owned(&self) -> Result<SymbolicSparseRowMat<I, Rows, Cols>, FaerError> {
/// returns a newly allocated matrix holding the values of `self` in column major format
	pub fn to_col_major(&self) -> Result<SymbolicSparseColMat<I, Rows, Cols>, FaerError> {
/// returns the number of non-zero elements in the matrix
	pub fn compute_nnz(&self) -> usize {
/// returns the row pointers
	pub fn row_ptr(&self) -> &'a [I] {
/// returns the row non-zero counts
	pub fn row_nnz(&self) -> Option<&'a [I]> {
/// returns the column indices
	pub fn col_idx(&self) -> &'a [I] {
/// returns the range specifying the indices of row `i`
	pub fn row_range(&self, i: Idx<Rows>) -> Range<usize> {
/// returns the range specifying the indices of row `i`, without bound checks
	pub unsafe fn row_range_unchecked(&self, i: Idx<Rows>) -> Range<usize> {
/// returns the column indices of row `i`
	pub fn col_idx_of_row_raw(&self, i: Idx<Rows>) -> &'a [Idx<Cols, I>] {
/// returns the column indices of row `i`
	pub fn col_idx_of_row(&self, i: Idx<Rows>) -> impl 'a + Clone + ExactSizeIterator + DoubleEndedIterator<Item = Idx<Cols>>
	where
		Rows: 'a,
		Cols: 'a,
	{
/// returns the input matrix with the given shape after checking that it matches the
/// current shape
	pub fn as_shape<V: Shape, H: Shape>(self, nrows: V, ncols: H) -> SymbolicSparseRowMatRef<'a, I, V, H> {
/// returns the input matrix with dynamic shape
	pub fn as_dyn(self) -> SymbolicSparseRowMatRef<'a, I> {
/// Returns a view over the symbolic structure of `self`.
	pub fn as_ref(self) -> SymbolicSparseRowMatRef<'a, I, Rows, Cols> {
/// see [`SymbolicSparseRowMatRef::new_unchecked`]
	pub unsafe fn new_unchecked(
		nrows: Rows,
		ncols: Cols,
		row_ptr: alloc::vec::Vec<I>,
		row_nnz: Option<alloc::vec::Vec<I>>,
		col_idx: alloc::vec::Vec<I>,
	) -> Self {
/// see [`SymbolicSparseRowMatRef::new_checked`]
	pub fn new_checked(
		nrows: Rows,
		ncols: Cols,
		row_ptr: alloc::vec::Vec<I>,
		row_nnz: Option<alloc::vec::Vec<I>>,
		col_idx: alloc::vec::Vec<I>,
	) -> Self {
/// see [`SymbolicSparseRowMatRef::new_unsorted_checked`]
	pub fn new_unsorted_checked(
		nrows: Rows,
		ncols: Cols,
		row_ptr: alloc::vec::Vec<I>,
		row_nnz: Option<alloc::vec::Vec<I>>,
		col_idx: alloc::vec::Vec<I>,
	) -> Self {
/// see [`SymbolicSparseRowMatRef::parts`]
	pub fn parts(&self) -> (Rows, Cols, &'_ [I], Option<&'_ [I]>, &'_ [I]) {
/// see [`SymbolicSparseRowMatRef::parts`]
	pub fn into_parts(self) -> (Rows, Cols, alloc::vec::Vec<I>, Option<alloc::vec::Vec<I>>, alloc::vec::Vec<I>) {
/// see [`SymbolicSparseRowMatRef::nrows`]
	pub fn nrows(&self) -> Rows {
/// see [`SymbolicSparseRowMatRef::ncols`]
	pub fn ncols(&self) -> Cols {
/// see [`SymbolicSparseRowMatRef::as_shape`]
	pub fn shape(&self) -> (Rows, Cols) {
/// see [`SymbolicSparseRowMatRef::transpose`]
	pub fn transpose(&self) -> SymbolicSparseColMatRef<'_, I, Cols, Rows> {
/// see [`SymbolicSparseRowMatRef::transpose`]
	pub fn into_transpose(self) -> SymbolicSparseColMat<I, Cols, Rows> {
/// see [`SymbolicSparseRowMatRef::to_owned`]
	pub fn to_owned(&self) -> Result<SymbolicSparseRowMat<I, Rows, Cols>, FaerError> {
/// see [`SymbolicSparseRowMatRef::to_col_major`]
	pub fn to_col_major(&self) -> Result<SymbolicSparseColMat<I, Rows, Cols>, FaerError> {
/// see [`SymbolicSparseRowMatRef::compute_nnz`]
	pub fn compute_nnz(&self) -> usize {
/// see [`SymbolicSparseRowMatRef::row_ptr`]
	pub fn row_ptr(&self) -> &'_ [I] {
/// see [`SymbolicSparseRowMatRef::row_nnz`]
	pub fn row_nnz(&self) -> Option<&'_ [I]> {
/// see [`SymbolicSparseRowMatRef::col_idx`]
	pub fn col_idx(&self) -> &'_ [I] {
/// see [`SymbolicSparseRowMatRef::row_range`]
	pub fn row_range(&self, i: Idx<Rows>) -> Range<usize> {
/// see [`SymbolicSparseRowMatRef::row_range_unchecked`]
	pub unsafe fn row_range_unchecked(&self, i: Idx<Rows>) -> Range<usize> {
/// see [`SymbolicSparseRowMatRef::col_idx_of_row_raw`]
	pub fn col_idx_of_row_raw(&self, i: Idx<Rows>) -> &'_ [Idx<Cols, I>] {
/// see [`SymbolicSparseRowMatRef::col_idx_of_row`]
	pub fn col_idx_of_row(&self, i: Idx<Rows>) -> impl '_ + Clone + ExactSizeIterator + DoubleEndedIterator<Item = Idx<Cols>> {
/// see [`SymbolicSparseRowMatRef::as_shape`]
	pub fn as_shape<V: Shape, H: Shape>(&self, nrows: V, ncols: H) -> SymbolicSparseRowMatRef<'_, I, V, H> {
/// see [`SymbolicSparseRowMatRef::as_shape`]
	pub fn into_shape<V: Shape, H: Shape>(self, nrows: V, ncols: H) -> SymbolicSparseRowMat<I, V, H> {
/// see [`SymbolicSparseRowMatRef::as_dyn`]
	pub fn as_dyn(&self) -> SymbolicSparseRowMatRef<'_, I> {
/// see [`SymbolicSparseRowMatRef::as_dyn`]
	pub fn into_dyn(self) -> SymbolicSparseRowMat<I> {
/// Returns a view over the symbolic structure of `self`.
	pub fn as_ref(&self) -> SymbolicSparseRowMatRef<'_, I, Rows, Cols> {
/// create a new symbolic structure, and the corresponding order for the numerical values
/// from pairs of indices
	pub fn try_new_from_indices(nrows: Rows, ncols: Cols, idx: &[Pair<Idx<Rows, I>, Idx<Cols, I>>]) -> Result<(Self, Argsort<I>), CreationError> {
/// create a new symbolic structure, and the corresponding order for the numerical values
/// from pairs of indices
///
/// negative indices are ignored
	pub fn try_new_from_nonnegative_indices(
		nrows: Rows,
		ncols: Cols,
		idx: &[Pair<MaybeIdx<Rows, I>, MaybeIdx<Cols, I>>],
	) -> Result<(Self, Argsort<I>), CreationError> {
/// creates a new sparse matrix view.
///
/// # panics
/// panics if the length of `values` is not equal to the length of
/// `symbolic.col_idx()`
	pub fn new(symbolic: SymbolicSparseRowMatRef<'a, I, Rows, Cols>, val: &'a [T]) -> Self {
/// returns the symbolic and numeric components of the sparse matrix
	pub fn parts(self) -> (SymbolicSparseRowMatRef<'a, I, Rows, Cols>, &'a [T]) {
/// returns the symbolic component of the sparse matrix
	pub fn symbolic(&self) -> SymbolicSparseRowMatRef<'a, I, Rows, Cols> {
/// returns the numeric component of the sparse matrix
	pub fn val(self) -> &'a [T] {
/// returns a view over the values of row `i`
	pub fn val_of_row(self, i: Idx<Rows>) -> &'a [T] {
/// returns the input matrix with the given shape after checking that it matches the
/// current shape
	pub fn as_shape<V: Shape, H: Shape>(self, nrows: V, ncols: H) -> SparseRowMatRef<'a, I, T, V, H> {
/// returns a reference to the value at the given index, or `None` if the symbolic structure
/// doesn't contain it, or contains multiple indices with the given index
///
/// # panics
/// - panics if `row >= self.nrows()`
/// - panics if `col >= self.ncols()`
	pub fn get(self, row: Idx<Rows>, col: Idx<Cols>) -> Option<&'a T> {
/// returns the input matrix with dynamic shape
	pub fn as_dyn(self) -> SparseRowMatRef<'a, I, T> {
/// returns a view over `self`
	pub fn as_ref(self) -> SparseRowMatRef<'a, I, T, Rows, Cols> {
/// returns a view over the transpose of `self`
	pub fn transpose(self) -> SparseColMatRef<'a, I, T, Cols, Rows> {
/// returns a view over the conjugate of `self`
	pub fn conjugate(self) -> SparseRowMatRef<'a, I, T::Conj, Rows, Cols>
	where
		T: Conjugate,
	{
/// returns a view over the adjoint of `self`
	pub fn adjoint(self) -> SparseColMatRef<'a, I, T::Conj, Cols, Rows>
	where
		T: Conjugate,
	{
/// returns an unconjugated view over `self`
	pub fn canonical(self) -> SparseRowMatRef<'a, I, T::Canonical, Rows, Cols>
	where
		T: Conjugate,
	{
/// returns a newly allocated matrix holding the (possibly conjugated) values of `self` in
/// column major format
	pub fn to_col_major(&self) -> Result<SparseColMat<I, T::Canonical, Rows, Cols>, FaerError>
	where
		T: Conjugate,
	{
/// returns a newly allocated dense matrix holding the (possibly conjugated) values of `self`
	pub fn to_dense(&self) -> Mat<T::Canonical, Rows, Cols>
	where
		T: Conjugate,
	{
		fn imp<'ROWS, 'COLS, I: Index, T: Conjugate>(
			src: SparseRowMatRef<'_, I, T, Dim<'ROWS>, Dim<'COLS>>,
		) -> Mat<T::Canonical, Dim<'ROWS>, Dim<'COLS>> {
/// returns an iterator over the entries of the matrix.
	pub fn triplet_iter(self) -> impl 'a + Iterator<Item = Triplet<Idx<Rows>, Idx<Cols>, &'a T>>
	where
		Rows: 'a,
		Cols: 'a,
	{
/// see [`SparseRowMatRef::new`]
	pub fn new(symbolic: SymbolicSparseRowMatRef<'a, I, Rows, Cols>, val: &'a mut [T]) -> Self {
/// see [`SparseRowMatRef::parts`]
	pub fn parts(self) -> (SymbolicSparseRowMatRef<'a, I, Rows, Cols>, &'a [T]) {
/// see [`SparseRowMatRef::parts`]
	pub fn parts_mut(self) -> (SymbolicSparseRowMatRef<'a, I, Rows, Cols>, &'a mut [T]) {
/// see [`SparseRowMatRef::symbolic`]
	pub fn symbolic(&self) -> SymbolicSparseRowMatRef<'a, I, Rows, Cols> {
/// see [`SparseRowMatRef::val`]
	pub fn val(self) -> &'a [T] {
/// see [`SparseRowMatRef::val`]
	pub fn val_mut(self) -> &'a mut [T] {
/// see [`SparseRowMatRef::val_of_row`]
	pub fn val_of_row(self, i: Idx<Rows>) -> &'a [T] {
/// see [`SparseRowMatRef::val_of_row`]
	pub fn val_of_row_mut(self, j: Idx<Rows>) -> &'a mut [T] {
/// see [`SparseRowMatRef::as_shape`]
	pub fn as_shape<V: Shape, H: Shape>(self, nrows: V, ncols: H) -> SparseRowMatRef<'a, I, T, V, H> {
/// see [`SparseRowMatRef::as_shape`]
	pub fn as_shape_mut<V: Shape, H: Shape>(self, nrows: V, ncols: H) -> SparseRowMatMut<'a, I, T, V, H> {
/// see [`SparseRowMatRef::get`]
	pub fn get(self, row: Idx<Rows>, col: Idx<Cols>) -> Option<&'a T> {
/// returns a reference to the value at the given index, or `None` if the symbolic structure
/// doesn't contain it, or contains multiple indices with the given index
///
/// # panics
/// - panics if `row >= self.nrows()`
/// - panics if `col >= self.ncols()`
/// see [`SparseRowMatRef::get`]
	pub fn get_mut(self, row: Idx<Rows>, col: Idx<Cols>) -> Option<&'a mut T> {
/// see [`SparseRowMatRef::as_dyn`]
	pub fn as_dyn(self) -> SparseRowMatRef<'a, I, T> {
/// see [`SparseRowMatRef::as_dyn`]
	pub fn as_dyn_mut(self) -> SparseRowMatMut<'a, I, T> {
/// see [`SparseRowMatRef::transpose`]
	pub fn transpose(self) -> SparseColMatRef<'a, I, T, Cols, Rows> {
/// see [`SparseRowMatRef::transpose`]
	pub fn transpose_mut(self) -> SparseColMatMut<'a, I, T, Cols, Rows> {
/// see [`SparseRowMatRef::conjugate`]
	pub fn conjugate(self) -> SparseRowMatRef<'a, I, T::Conj, Rows, Cols>
	where
		T: Conjugate,
	{
/// see [`SparseRowMatRef::conjugate`]
	pub fn conjugate_mut(self) -> SparseRowMatMut<'a, I, T::Conj, Rows, Cols>
	where
		T: Conjugate,
	{
/// see [`SparseRowMatRef::adjoint`]
	pub fn adjoint(self) -> SparseColMatRef<'a, I, T::Conj, Cols, Rows>
	where
		T: Conjugate,
	{
/// see [`SparseRowMatRef::adjoint`]
	pub fn adjoint_mut(self) -> SparseColMatMut<'a, I, T::Conj, Cols, Rows>
	where
		T: Conjugate,
	{
/// see [`SparseRowMatRef::canonical`]
	pub fn canonical(self) -> SparseRowMatRef<'a, I, T::Canonical, Rows, Cols>
	where
		T: Conjugate,
	{
/// see [`SparseRowMatRef::canonical`]
	pub fn canonical_mut(self) -> SparseRowMatMut<'a, I, T::Canonical, Rows, Cols>
	where
		T: Conjugate,
	{
/// see [`SparseRowMatRef::to_col_major`]
	pub fn to_col_major(&self) -> Result<SparseColMat<I, T::Canonical, Rows, Cols>, FaerError>
	where
		T: Conjugate,
	{
/// see [`SparseRowMatRef::to_dense`]
	pub fn to_dense(&self) -> Mat<T::Canonical, Rows, Cols>
	where
		T: Conjugate,
	{
/// see [`SparseRowMatRef::triplet_iter`]
	pub fn triplet_iter(self) -> impl 'a + Iterator<Item = Triplet<Idx<Rows>, Idx<Cols>, &'a T>>
	where
		Rows: 'a,
		Cols: 'a,
	{
/// see [`SparseRowMatRef::new`]
	pub fn new(symbolic: SymbolicSparseRowMat<I, Rows, Cols>, val: alloc::vec::Vec<T>) -> Self {
/// see [`SparseRowMatRef::parts`]
	pub fn parts(&self) -> (SymbolicSparseRowMatRef<'_, I, Rows, Cols>, &'_ [T]) {
/// see [`SparseRowMatRef::parts`]
	pub fn parts_mut(&mut self) -> (SymbolicSparseRowMatRef<'_, I, Rows, Cols>, &'_ mut [T]) {
/// see [`SparseRowMatRef::parts`]
	pub fn into_parts(self) -> (SymbolicSparseRowMat<I, Rows, Cols>, alloc::vec::Vec<T>) {
/// see [`SparseRowMatRef::symbolic`]
	pub fn symbolic(&self) -> SymbolicSparseRowMatRef<'_, I, Rows, Cols> {
/// see [`SparseRowMatRef::val`]
	pub fn val(&self) -> &'_ [T] {
/// see [`SparseRowMatRef::val`]
	pub fn val_mut(&mut self) -> &'_ mut [T] {
/// see [`SparseRowMatRef::val_of_row`]
	pub fn val_of_row(&self, j: Idx<Rows>) -> &'_ [T] {
/// see [`SparseRowMatRef::val_of_row`]
	pub fn val_of_row_mut(&mut self, j: Idx<Rows>) -> &'_ mut [T] {
/// see [`SparseRowMatRef::as_shape`]
	pub fn as_shape<V: Shape, H: Shape>(&self, nrows: V, ncols: H) -> SparseRowMatRef<'_, I, T, V, H> {
/// see [`SparseRowMatRef::as_shape`]
	pub fn as_shape_mut<V: Shape, H: Shape>(&mut self, nrows: V, ncols: H) -> SparseRowMatMut<'_, I, T, V, H> {
/// see [`SparseRowMatRef::as_shape`]
	pub fn into_shape<V: Shape, H: Shape>(self, nrows: V, ncols: H) -> SparseRowMat<I, T, V, H> {
/// see [`SparseRowMatRef::as_dyn`]
	pub fn as_dyn(&self) -> SparseRowMatRef<'_, I, T> {
/// see [`SparseRowMatRef::as_dyn`]
	pub fn as_dyn_mut(&mut self) -> SparseRowMatMut<'_, I, T> {
/// see [`SparseRowMatRef::as_dyn`]
	pub fn into_dyn(self) -> SparseRowMat<I, T> {
/// see [`SparseRowMatRef::as_ref`]
	pub fn as_ref(&self) -> SparseRowMatRef<'_, I, T, Rows, Cols> {
/// see [`SparseRowMatRef::transpose`]
	pub fn transpose(&self) -> SparseColMatRef<'_, I, T, Cols, Rows> {
/// see [`SparseRowMatRef::transpose`]
	pub fn transpose_mut(&mut self) -> SparseColMatMut<'_, I, T, Cols, Rows> {
/// see [`SparseRowMatRef::transpose`]
	pub fn into_transpose(self) -> SparseColMat<I, T, Cols, Rows> {
/// see [`SparseRowMatRef::conjugate`]
	pub fn conjugate(&self) -> SparseRowMatRef<'_, I, T::Conj, Rows, Cols>
	where
		T: Conjugate,
	{
/// see [`SparseRowMatRef::conjugate`]
	pub fn conjugate_mut(&mut self) -> SparseRowMatMut<'_, I, T::Conj, Rows, Cols>
	where
		T: Conjugate,
	{
/// see [`SparseRowMatRef::conjugate`]
	pub fn into_conjugate(self) -> SparseRowMat<I, T::Conj, Rows, Cols>
	where
		T: Conjugate,
	{
/// see [`SparseRowMatRef::adjoint`]
	pub fn adjoint(&self) -> SparseColMatRef<'_, I, T::Conj, Cols, Rows>
	where
		T: Conjugate,
	{
/// see [`SparseRowMatRef::adjoint`]
	pub fn adjoint_mut(&mut self) -> SparseColMatMut<'_, I, T::Conj, Cols, Rows>
	where
		T: Conjugate,
	{
/// see [`SparseRowMatRef::adjoint`]
	pub fn into_adjoint(self) -> SparseColMat<I, T::Conj, Cols, Rows>
	where
		T: Conjugate,
	{
/// see [`SparseRowMatRef::canonical`]
	pub fn canonical(&self) -> SparseRowMatRef<'_, I, T::Canonical, Rows, Cols>
	where
		T: Conjugate,
	{
/// see [`SparseRowMatRef::canonical`]
	pub fn canonical_mut(&mut self) -> SparseRowMatMut<'_, I, T::Canonical, Rows, Cols>
	where
		T: Conjugate,
	{
/// see [`SparseRowMatRef::canonical`]
	pub fn into_canonical(self) -> SparseRowMat<I, T::Canonical, Rows, Cols>
	where
		T: Conjugate,
	{
/// see [`SparseRowMatRef::to_col_major`]
	pub fn to_col_major(&self) -> Result<SparseColMat<I, T::Canonical, Rows, Cols>, FaerError>
	where
		T: Conjugate,
	{
/// see [`SparseRowMatRef::to_dense`]
	pub fn to_dense(&self) -> Mat<T::Canonical, Rows, Cols>
	where
		T: Conjugate,
	{
/// create a new matrix from a previously created symbolic structure and value order
///
/// the provided values must correspond to the same indices that were provided in the
/// function call from which the order was created
	pub fn new_from_argsort(symbolic: SymbolicSparseRowMat<I, Rows, Cols>, argsort: &Argsort<I>, val: &[T]) -> Result<Self, FaerError>
	where
		T: ComplexField,
	{
/// create a new matrix from triplets
	pub fn try_new_from_triplets(nrows: Rows, ncols: Cols, entries: &[Triplet<Idx<Rows, I>, Idx<Cols, I>, T>]) -> Result<Self, CreationError>
	where
		T: ComplexField,
	{
/// create a new matrix from triplets
///
/// negative indices are ignored
	pub fn try_new_from_nonnegative_triplets(
		nrows: Rows,
		ncols: Cols,
		entries: &[Triplet<MaybeIdx<Rows, I>, MaybeIdx<Cols, I>, T>],
	) -> Result<Self, CreationError>
	where
		T: ComplexField,
	{
/// see [`SparseRowMatRef::get`]
	pub fn get(&self, row: Idx<Rows>, col: Idx<Cols>) -> Option<&T> {
/// see [`SparseRowMatRef::get`]
	pub fn get_mut(&mut self, row: Idx<Rows>, col: Idx<Cols>) -> Option<&mut T> {
/// see [`SparseRowMatRef::triplet_iter`]
	pub fn triplet_iter(&self) -> impl '_ + Iterator<Item = Triplet<Idx<Rows>, Idx<Cols>, &'_ T>> {
	fn deref(&self) -> &Self::Target {
	fn deref(&self) -> &Self::Target {
	fn deref(&self) -> &Self::Target {
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
		fn imp<'ROWS, 'COLS, I: Index>(mat: SymbolicSparseRowMatRef<'_, I, Dim<'ROWS>, Dim<'COLS>>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
				fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
		fn imp<'ROWS, 'COLS, I: Index, T: fmt::Debug>(
			mat: SparseRowMatRef<'_, I, T, Dim<'ROWS>, Dim<'COLS>>,
			f: &mut fmt::Formatter<'_>,
		) -> fmt::Result {
				fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
//! approximate minimum degree ordering.
// AMD, Copyright (c), 1996-2022, Timothy A. Davis,
// Patrick R. Amestoy, and Iain S. Duff.  All Rights Reserved.
//
// Availability:
//
//     http://www.suitesparse.com
//
// -------------------------------------------------------------------------------
// AMD License: BSD 3-clause:
// -------------------------------------------------------------------------------
//
//     Redistribution and use in source and binary forms, with or without
//     modification, are permitted provided that the following conditions are met:
//         * Redistributions of source code must retain the above copyright notice, this list of
//           conditions and the following disclaimer.
//         * Redistributions in binary form must reproduce the above copyright notice, this list of
//           conditions and the following disclaimer in the documentation and/or other materials
//           provided with the distribution.
//         * Neither the name of the organizations to which the authors are affiliated, nor the
//           names of its contributors may be used to endorse or promote products derived from this
//           software without specific prior written permission.
//
//     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
//     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
//     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
//     ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
//     DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
//     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
//     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
//     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
//     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
//     OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
//     DAMAGE.
fn post_tree<'n, I: Index>(
	root: Idx<'n, usize>,
	k: usize,
	child: &mut Array<'n, MaybeIdx<'n, I>>,
	sibling: &Array<'n, MaybeIdx<'n, I>>,
	order: &mut Array<'n, I::Signed>,
	stack: &mut Array<'n, I::Signed>,
) -> usize {
fn postorder<'n, 'out, I: Index>(
	order: &'out mut Array<'n, I::Signed>,
	etree: &Array<'n, MaybeIdx<'n, I>>,
	nv: &Array<'n, I::Signed>,
	f_size: &Array<'n, I::Signed>,
	stack: &mut MemStack,
) {
fn flip<I: SignedIndex>(i: I) -> I {
fn clear_flag<I: SignedIndex>(wflg: I, wbig: I, w: &mut [I]) -> I {
fn amd_2<I: Index>(
	pe: &mut [I::Signed],  // input/output
	iw: &mut [I::Signed],  // input/modified (undefined on output)
	len: &mut [I::Signed], // input/modified (undefined on output)
	pfree: usize,
	next: &mut [I::Signed],
	last: &mut [I::Signed],
	control: Control,
	stack: &mut MemStack,
) -> FlopCount {
//assert!(pme2 >= zero);
fn amd_1<I: Index>(
	perm: &mut [I::Signed],
	perm_inv: &mut [I::Signed],
	A: SymbolicSparseColMatRef<'_, I>,
	len: &mut [I::Signed],
	iwlen: usize,
	control: Control,
	stack: &mut MemStack,
) -> FlopCount {
// Construct the pointers for A+A'.
// Note that this restriction on iwlen is slightly more restrictive than
// what is strictly required in amd_2. amd_2 can operate with no elbow
// room at all, but it will be very slow. For better performance, at
// least size-n elbow room is enforced.
// Construct A+A'.
// Entry A(j,k) in the strictly upper triangular part.
// Scan lower triangular part of A, in column j until reaching
// row k. Start where last scan left off.
// A (i,j) is only in the lower part, not in upper.
// Clean up, for remaining mismatched entries.
fn preprocess<'out, I: Index>(
	new_col_ptr: &'out mut [I],
	new_row_idx: &'out mut [I],
	A: SymbolicSparseColMatRef<'_, I>,
	stack: &mut MemStack,
) -> SymbolicSparseColMatRef<'out, I> {
fn aat<I: Index>(len: &mut [I::Signed], A: SymbolicSparseColMatRef<'_, I>, stack: &mut MemStack) -> Result<usize, FaerError> {
// local workspace
/// computes the layout of required workspace for computing the amd ordering of a sorted
/// matrix
pub fn order_scratch<I: Index>(n: usize, nnz_upper: usize) -> StackReq {
// len
// A+A.T plus elbow room
// p_e
// s_p
// i_w
// w
// nv
// elen
// child
// sibling
// stack
/// computes the layout of required workspace for computing the amd ordering of an
/// unsorted matrix
pub fn order_maybe_unsorted_scratch<I: Index>(n: usize, nnz_upper: usize) -> StackReq {
/// computes the approximate minimum degree ordering for reducing the fill-in during the sparse
/// cholesky factorization of a matrix with the sparsity pattern of $A + A^\top$
pub fn order<I: Index>(
	perm: &mut [I],
	perm_inv: &mut [I],
	A: SymbolicSparseColMatRef<'_, I>,
	control: Control,
	stack: &mut MemStack,
) -> Result<FlopCount, FaerError> {
/// computes the approximate minimum degree ordering for reducing the fill-in during the sparse
/// cholesky factorization of a matrix with the sparsity pattern of $A + A^\top$
///
/// # note
/// allows unsorted matrices
pub fn order_maybe_unsorted<I: Index>(
	perm: &mut [I],
	perm_inv: &mut [I],
	A: SymbolicSparseColMatRef<'_, I>,
	control: Control,
	stack: &mut MemStack,
) -> Result<FlopCount, FaerError> {
/// tuning parameters for the amd implementation
/// "dense" if degree > dense * sqrt(n)
/// do aggressive absorption
	fn default() -> Self {
/// flop count of the ldlt and lu factorizations if the provided ordering is used
/// number of division
/// number of multiplications and subtractions for the ldlt factorization
/// number of multiplications and subtractions for the lu factorization
//! computes the Cholesky decomposition (either $LL^\top$, $LTL^\top$, or $LBL^\top$) of a given
//! sparse matrix. see [`crate::linalg::cholesky`] for more info.
//!
//! the entry point in this module is [`SymbolicCholesky`] and [`factorize_symbolic_cholesky`].
//!
//! # note
//! the functions in this module accept unsorted input, producing a sorted decomposition factor
//! (simplicial).
//!
//! # example (low level api)
//! simplicial:
//! ```
//! fn simplicial_cholesky() -> Result<(), faer::sparse::FaerError> {
//! 	use faer::Par;
//! 	use faer::dyn_stack::{MemBuffer, MemStack, StackReq};
//! 	use faer::reborrow::*;
//!
//! 	use faer::linalg::cholesky::ldlt::factor::LdltRegularization;
//! 	use faer::linalg::cholesky::llt::factor::LltRegularization;
//!
//! 	use faer::sparse::linalg::amd;
//! 	use faer::sparse::linalg::cholesky::simplicial;
//! 	use faer::sparse::{CreationError, SparseColMat, SymbolicSparseColMat, Triplet};
//!
//! 	use rand::prelude::*;
//!
//! 	// the simplicial cholesky api takes an upper triangular matrix as input, to be
//! 	// interpreted as self-adjoint.
//! 	let dim = 4;
//! 	let A_upper = match SparseColMat::<usize, f64>::try_new_from_triplets(
//! 		dim,
//! 		dim,
//! 		&[
//! 			// diagonal entries
//! 			Triplet::new(0, 0, 10.0),
//! 			Triplet::new(1, 1, 11.0),
//! 			Triplet::new(2, 2, 12.0),
//! 			Triplet::new(3, 3, 13.0),
//! 			// non diagonal entries
//! 			Triplet::new(0, 1, 1.0),
//! 			Triplet::new(0, 3, 1.5),
//! 			Triplet::new(1, 3, -3.2),
//! 		],
//! 	) {
//! 		Ok(A) => Ok(A),
//! 		Err(CreationError::Generic(err)) => Err(err),
//! 		Err(CreationError::OutOfBounds { .. }) => panic!(),
//! 	}?;
//!
//! 	let mut A = faer::sparse::ops::add(A_upper.rb(), A_upper.to_row_major()?.rb().transpose())?;
//! 	for i in 0..dim {
//! 		A[(i, i)] /= 2.0;
//! 	}
//!
//! 	let A_nnz = A_upper.compute_nnz();
//! 	let mut rhs = Vec::new();
//! 	let mut rng = StdRng::seed_from_u64(0);
//! 	rhs.try_reserve_exact(dim)?;
//! 	rhs.resize_with(dim, || rng.random::<f64>());
//!
//! 	let mut sol = Vec::new();
//! 	sol.try_reserve_exact(dim)?;
//! 	sol.resize(dim, 0.0f64);
//!
//! 	let rhs = faer::MatRef::from_column_major_slice(&rhs, dim, 1);
//! 	let mut sol = faer::MatMut::from_column_major_slice_mut(&mut sol, dim, 1);
//!
//! 	// optional: fill reducing permutation
//! 	let (perm, perm_inv) = {
//! 		let mut perm = Vec::new();
//! 		let mut perm_inv = Vec::new();
//! 		perm.try_reserve_exact(dim)?;
//! 		perm_inv.try_reserve_exact(dim)?;
//! 		perm.resize(dim, 0usize);
//! 		perm_inv.resize(dim, 0usize);
//!
//! 		let mut mem = MemBuffer::try_new(amd::order_scratch::<usize>(dim, A_nnz))?;
//! 		amd::order(
//! 			&mut perm,
//! 			&mut perm_inv,
//! 			A_upper.symbolic(),
//! 			amd::Control::default(),
//! 			MemStack::new(&mut mem),
//! 		)?;
//!
//! 		(perm, perm_inv)
//! 	};
//!
//! 	let perm = unsafe { faer::perm::PermRef::new_unchecked(&perm, &perm_inv, dim) };
//!
//! 	let A_perm_upper = {
//! 		let mut A_perm_col_ptrs = Vec::new();
//! 		let mut A_perm_row_indices = Vec::new();
//! 		let mut A_perm_values = Vec::new();
//!
//! 		A_perm_col_ptrs.try_reserve_exact(dim + 1)?;
//! 		A_perm_col_ptrs.resize(dim + 1, 0usize);
//! 		A_perm_row_indices.try_reserve_exact(A_nnz)?;
//! 		A_perm_row_indices.resize(A_nnz, 0usize);
//! 		A_perm_values.try_reserve_exact(A_nnz)?;
//! 		A_perm_values.resize(A_nnz, 0.0f64);
//!
//! 		let mut mem = MemBuffer::try_new(faer::sparse::utils::permute_self_adjoint_scratch::<
//! 			usize,
//! 		>(dim))?;
//! 		faer::sparse::utils::permute_self_adjoint_to_unsorted(
//! 			&mut A_perm_values,
//! 			&mut A_perm_col_ptrs,
//! 			&mut A_perm_row_indices,
//! 			A_upper.rb(),
//! 			perm,
//! 			faer::Side::Upper,
//! 			faer::Side::Upper,
//! 			MemStack::new(&mut mem),
//! 		);
//!
//! 		SparseColMat::<usize, f64>::new(
//! 			unsafe {
//! 				SymbolicSparseColMat::new_unchecked(
//! 					dim,
//! 					dim,
//! 					A_perm_col_ptrs,
//! 					None,
//! 					A_perm_row_indices,
//! 				)
//! 			},
//! 			A_perm_values,
//! 		)
//! 	};
//!
//! 	// symbolic analysis
//! 	let symbolic = {
//! 		let mut mem = MemBuffer::try_new(StackReq::any_of(&[
//! 			simplicial::prefactorize_symbolic_cholesky_scratch::<usize>(dim, A_nnz),
//! 			simplicial::factorize_simplicial_symbolic_cholesky_scratch::<usize>(dim),
//! 		]))?;
//! 		let stack = MemStack::new(&mut mem);
//!
//! 		let mut etree = Vec::new();
//! 		let mut col_counts = Vec::new();
//! 		etree.try_reserve_exact(dim)?;
//! 		etree.resize(dim, 0isize);
//! 		col_counts.try_reserve_exact(dim)?;
//! 		col_counts.resize(dim, 0usize);
//!
//! 		simplicial::prefactorize_symbolic_cholesky(
//! 			&mut etree,
//! 			&mut col_counts,
//! 			A_perm_upper.symbolic(),
//! 			stack,
//! 		);
//! 		simplicial::factorize_simplicial_symbolic_cholesky(
//! 			A_perm_upper.symbolic(),
//! 			// SAFETY: `etree` was filled correctly by
//! 			// `simplicial::prefactorize_symbolic_cholesky`.
//! 			unsafe { simplicial::EliminationTreeRef::from_inner(&etree) },
//! 			&col_counts,
//! 			stack,
//! 		)?
//! 	};
//!
//! 	// numerical factorization
//! 	let mut mem = MemBuffer::try_new(StackReq::all_of(&[
//! 		simplicial::factorize_simplicial_numeric_llt_scratch::<usize, f64>(dim),
//! 		simplicial::factorize_simplicial_numeric_ldlt_scratch::<usize, f64>(dim),
//! 		faer::perm::permute_rows_in_place_scratch::<usize, f64>(dim, 1),
//! 		symbolic.solve_in_place_scratch::<f64>(dim),
//! 	]))?;
//! 	let stack = MemStack::new(&mut mem);
//!
//! 	// numerical llt factorization
//! 	{
//! 		let mut L_values = Vec::new();
//! 		L_values.try_reserve_exact(symbolic.len_val())?;
//! 		L_values.resize(symbolic.len_val(), 0.0f64);
//!
//! 		match simplicial::factorize_simplicial_numeric_llt::<usize, f64>(
//! 			&mut L_values,
//! 			A_perm_upper.rb(),
//! 			LltRegularization::default(),
//! 			&symbolic,
//! 			stack,
//! 		) {
//! 			Ok(_) => {},
//! 			Err(err) => panic!("matrix is not positive definite: {err}"),
//! 		};
//!
//! 		let llt = simplicial::SimplicialLltRef::<'_, usize, f64>::new(&symbolic, &L_values);
//!
//! 		sol.copy_from(rhs);
//! 		faer::perm::permute_rows_in_place(sol.rb_mut(), perm, stack);
//! 		llt.solve_in_place_with_conj(faer::Conj::No, sol.rb_mut(), faer::Par::Seq, stack);
//! 		faer::perm::permute_rows_in_place(sol.rb_mut(), perm.inverse(), stack);
//!
//! 		assert!((&A * &sol - &rhs).norm_max() <= 1e-14);
//! 	}
//!
//! 	// numerical ldlt factorization
//! 	{
//! 		let mut L_values = Vec::new();
//! 		L_values.try_reserve_exact(symbolic.len_val())?;
//! 		L_values.resize(symbolic.len_val(), 0.0f64);
//!
//! 		simplicial::factorize_simplicial_numeric_ldlt::<usize, f64>(
//! 			&mut L_values,
//! 			A_perm_upper.rb(),
//! 			LdltRegularization::default(),
//! 			&symbolic,
//! 			stack,
//! 		);
//!
//! 		let ldlt = simplicial::SimplicialLdltRef::<'_, usize, f64>::new(&symbolic, &L_values);
//!
//! 		sol.copy_from(rhs);
//! 		faer::perm::permute_rows_in_place(sol.rb_mut(), perm, stack);
//! 		ldlt.solve_in_place_with_conj(faer::Conj::No, sol.rb_mut(), faer::Par::Seq, stack);
//! 		faer::perm::permute_rows_in_place(sol.rb_mut(), perm.inverse(), stack);
//!
//! 		assert!((&A * &sol - &rhs).norm_max() <= 1e-14);
//! 	}
//! 	Ok(())
//! }
//! simplicial_cholesky().unwrap()
//! ```
//! supernodal:
//! ```
//! fn supernodal_cholesky() -> Result<(), faer::sparse::FaerError> {
//! 	use faer::Par;
//! 	use faer::dyn_stack::{MemBuffer, MemStack, StackReq};
//! 	use faer::reborrow::*;
//!
//! 	use faer::linalg::cholesky::ldlt::factor::LdltRegularization;
//!
//! 	use faer::sparse::linalg::amd;
//! 	use faer::sparse::linalg::cholesky::{simplicial, supernodal};
//! 	use faer::sparse::{CreationError, SparseColMat, SymbolicSparseColMat, Triplet};
//! 	use rand::prelude::*;
//!
//! 	// the supernodal cholesky api takes a lower triangular matrix as input, to be
//! 	// interpreted as self-adjoint.
//! 	let dim = 8;
//! 	let A_lower = match SparseColMat::<usize, f64>::try_new_from_triplets(
//! 		dim,
//! 		dim,
//! 		&[
//! 			// diagonal entries
//! 			Triplet::new(0, 0, 11.0),
//! 			Triplet::new(1, 1, 11.0),
//! 			Triplet::new(2, 2, 12.0),
//! 			Triplet::new(3, 3, 13.0),
//! 			Triplet::new(4, 4, 14.0),
//! 			Triplet::new(5, 5, 16.0),
//! 			Triplet::new(6, 6, 16.0),
//! 			Triplet::new(7, 7, 16.0),
//! 			// non diagonal entries
//! 			Triplet::new(1, 0, 10.0),
//! 			Triplet::new(3, 0, 10.5),
//! 			Triplet::new(4, 0, 10.0),
//! 			Triplet::new(7, 0, 10.5),
//! 			Triplet::new(3, 1, 10.5),
//! 			Triplet::new(4, 1, 10.0),
//! 			Triplet::new(7, 1, 10.5),
//! 			Triplet::new(3, 2, 10.5),
//! 			Triplet::new(4, 2, 10.0),
//! 			Triplet::new(7, 2, 10.0),
//! 		],
//! 	) {
//! 		Ok(A) => Ok(A),
//! 		Err(CreationError::Generic(err)) => Err(err),
//! 		Err(CreationError::OutOfBounds { .. }) => panic!(),
//! 	}?;
//!
//! 	let mut A = faer::sparse::ops::add(A_lower.rb(), A_lower.to_row_major()?.rb().transpose())?;
//! 	for i in 0..dim {
//! 		A[(i, i)] /= 2.0;
//! 	}
//!
//! 	let A_nnz = A_lower.compute_nnz();
//! 	let mut rhs = Vec::new();
//! 	let mut rng = StdRng::seed_from_u64(0);
//! 	rhs.try_reserve_exact(dim)?;
//! 	rhs.resize_with(dim, || rng.random::<f64>());
//!
//! 	let mut sol = Vec::new();
//! 	sol.try_reserve_exact(dim)?;
//! 	sol.resize(dim, 0.0f64);
//!
//! 	let rhs = faer::MatRef::from_column_major_slice(&rhs, dim, 1);
//! 	let mut sol = faer::MatMut::from_column_major_slice_mut(&mut sol, dim, 1);
//!
//! 	// optional: fill reducing permutation
//! 	let (perm, perm_inv) = {
//! 		let mut perm = Vec::new();
//! 		let mut perm_inv = Vec::new();
//! 		perm.try_reserve_exact(dim)?;
//! 		perm_inv.try_reserve_exact(dim)?;
//! 		perm.resize(dim, 0usize);
//! 		perm_inv.resize(dim, 0usize);
//!
//! 		let mut mem = MemBuffer::try_new(amd::order_scratch::<usize>(dim, A_nnz))?;
//! 		amd::order(
//! 			&mut perm,
//! 			&mut perm_inv,
//! 			A_lower.symbolic(),
//! 			amd::Control::default(),
//! 			MemStack::new(&mut mem),
//! 		)?;
//!
//! 		(perm, perm_inv)
//! 	};
//!
//! 	let perm = unsafe { faer::perm::PermRef::new_unchecked(&perm, &perm_inv, dim) };
//!
//! 	let A_perm_lower = {
//! 		let mut A_perm_col_ptrs = Vec::new();
//! 		let mut A_perm_row_indices = Vec::new();
//! 		let mut A_perm_values = Vec::new();
//!
//! 		A_perm_col_ptrs.try_reserve_exact(dim + 1)?;
//! 		A_perm_col_ptrs.resize(dim + 1, 0usize);
//! 		A_perm_row_indices.try_reserve_exact(A_nnz)?;
//! 		A_perm_row_indices.resize(A_nnz, 0usize);
//! 		A_perm_values.try_reserve_exact(A_nnz)?;
//! 		A_perm_values.resize(A_nnz, 0.0f64);
//!
//! 		let mut mem = MemBuffer::try_new(faer::sparse::utils::permute_self_adjoint_scratch::<
//! 			usize,
//! 		>(dim))?;
//! 		faer::sparse::utils::permute_self_adjoint_to_unsorted(
//! 			&mut A_perm_values,
//! 			&mut A_perm_col_ptrs,
//! 			&mut A_perm_row_indices,
//! 			A_lower.rb(),
//! 			perm,
//! 			faer::Side::Lower,
//! 			faer::Side::Lower,
//! 			MemStack::new(&mut mem),
//! 		);
//!
//! 		SparseColMat::<usize, f64>::new(
//! 			unsafe {
//! 				SymbolicSparseColMat::new_unchecked(
//! 					dim,
//! 					dim,
//! 					A_perm_col_ptrs,
//! 					None,
//! 					A_perm_row_indices,
//! 				)
//! 			},
//! 			A_perm_values,
//! 		)
//! 	};
//!
//! 	let A_perm_upper = A_perm_lower.rb().transpose().symbolic().to_col_major()?;
//!
//! 	// symbolic analysis
//! 	let symbolic = {
//! 		let mut mem = MemBuffer::try_new(StackReq::any_of(&[
//! 			simplicial::prefactorize_symbolic_cholesky_scratch::<usize>(dim, A_nnz),
//! 			supernodal::factorize_supernodal_symbolic_cholesky_scratch::<usize>(dim),
//! 		]))?;
//! 		let stack = MemStack::new(&mut mem);
//!
//! 		let mut etree = Vec::new();
//! 		let mut col_counts = Vec::new();
//! 		etree.try_reserve_exact(dim)?;
//! 		etree.resize(dim, 0isize);
//! 		col_counts.try_reserve_exact(dim)?;
//! 		col_counts.resize(dim, 0usize);
//!
//! 		simplicial::prefactorize_symbolic_cholesky(
//! 			&mut etree,
//! 			&mut col_counts,
//! 			A_perm_upper.rb(),
//! 			stack,
//! 		);
//! 		supernodal::factorize_supernodal_symbolic_cholesky(
//! 			A_perm_upper.rb(),
//! 			// SAFETY: `etree` was filled correctly by
//! 			// `simplicial::prefactorize_symbolic_cholesky`.
//! 			unsafe { simplicial::EliminationTreeRef::from_inner(&etree) },
//! 			&col_counts,
//! 			stack,
//! 			faer::sparse::linalg::SymbolicSupernodalParams {
//! 				relax: Some(&[(usize::MAX, 1.0)]),
//! 			},
//! 		)?
//! 	};
//!
//! 	// numerical factorization
//! 	let mut mem = MemBuffer::try_new(StackReq::any_of(&[
//! 		supernodal::factorize_supernodal_numeric_llt_scratch::<usize, f64>(
//! 			&symbolic,
//! 			faer::Par::Seq,
//! 			Default::default(),
//! 		),
//! 		supernodal::factorize_supernodal_numeric_ldlt_scratch::<usize, f64>(
//! 			&symbolic,
//! 			faer::Par::Seq,
//! 			Default::default(),
//! 		),
//! 		supernodal::factorize_supernodal_numeric_intranode_lblt_scratch::<usize, f64>(
//! 			&symbolic,
//! 			faer::Par::Seq,
//! 			Default::default(),
//! 		),
//! 		faer::perm::permute_rows_in_place_scratch::<usize, f64>(dim, 1),
//! 		symbolic.solve_in_place_scratch::<f64>(dim, Par::Seq),
//! 	]))?;
//! 	let stack = MemStack::new(&mut mem);
//!
//! 	// llt skipped since a is not positive-definite
//!
//! 	// numerical ldlt factorization
//! 	{
//! 		let mut L_values = Vec::new();
//! 		L_values.try_reserve_exact(symbolic.len_val())?;
//! 		L_values.resize(symbolic.len_val(), 0.0f64);
//!
//! 		supernodal::factorize_supernodal_numeric_ldlt::<usize, f64>(
//! 			&mut L_values,
//! 			A_perm_lower.rb(),
//! 			LdltRegularization::default(),
//! 			&symbolic,
//! 			faer::Par::Seq,
//! 			stack,
//! 			Default::default(),
//! 		);
//!
//! 		let ldlt = supernodal::SupernodalLdltRef::<'_, usize, f64>::new(&symbolic, &L_values);
//!
//! 		sol.copy_from(rhs);
//! 		faer::perm::permute_rows_in_place(sol.rb_mut(), perm, stack);
//! 		ldlt.solve_in_place_with_conj(faer::Conj::No, sol.rb_mut(), faer::Par::Seq, stack);
//! 		faer::perm::permute_rows_in_place(sol.rb_mut(), perm.inverse(), stack);
//!
//! 		assert!((&A * &sol - &rhs).norm_max() <= 1e-14);
//! 	}
//!
//! 	// numerical intranodal LBLT factorization
//! 	{
//! 		let mut L_values = Vec::new();
//! 		let mut subdiag = Vec::new();
//! 		let mut pivot_perm = Vec::new();
//! 		let mut pivot_perm_inv = Vec::new();
//!
//! 		L_values.try_reserve_exact(symbolic.len_val())?;
//! 		L_values.resize(symbolic.len_val(), 0.0f64);
//! 		subdiag.try_reserve_exact(dim)?;
//! 		subdiag.resize(dim, 0.0f64);
//! 		pivot_perm.try_reserve(dim)?;
//! 		pivot_perm.resize(dim, 0usize);
//! 		pivot_perm_inv.try_reserve(dim)?;
//! 		pivot_perm_inv.resize(dim, 0usize);
//!
//! 		supernodal::factorize_supernodal_numeric_intranode_lblt::<usize, f64>(
//! 			&mut L_values,
//! 			&mut subdiag,
//! 			&mut pivot_perm,
//! 			&mut pivot_perm_inv,
//! 			A_perm_lower.rb(),
//! 			&symbolic,
//! 			faer::Par::Seq,
//! 			stack,
//! 			Default::default(),
//! 		);
//!
//! 		let piv_perm =
//! 			unsafe { faer::perm::PermRef::new_unchecked(&pivot_perm, &pivot_perm_inv, dim) };
//! 		let lblt = supernodal::SupernodalIntranodeLbltRef::<'_, usize, f64>::new(
//! 			&symbolic, &L_values, &subdiag, piv_perm,
//! 		);
//!
//! 		sol.copy_from(rhs);
//! 		// we can merge these two permutations if we want to be optimal
//! 		faer::perm::permute_rows_in_place(sol.rb_mut(), perm, stack);
//! 		faer::perm::permute_rows_in_place(sol.rb_mut(), piv_perm, stack);
//!
//! 		lblt.solve_in_place_no_numeric_permute_with_conj(
//! 			faer::Conj::No,
//! 			sol.rb_mut(),
//! 			faer::Par::Seq,
//! 			stack,
//! 		);
//!
//! 		// we can also merge these two permutations if we want to be optimal
//! 		faer::perm::permute_rows_in_place(sol.rb_mut(), piv_perm.inverse(), stack);
//! 		faer::perm::permute_rows_in_place(sol.rb_mut(), perm.inverse(), stack);
//!
//! 		assert!((&A * &sol - &rhs).norm_max() <= 1e-14);
//! 	}
//! 	Ok(())
//! }
//!
//! supernodal_cholesky().unwrap()
//! ```
// implementation inspired by https://gitlab.com/hodge_star/catamari
/// fill reducing ordering to use for the cholesky factorization
/// approximate minimum degree ordering. default option
/// no reordering
/// custom reordering
/// simplicial factorization module
///
/// a simplicial factorization is one that processes the elements of the cholesky factor of the
/// input matrix single elements, rather than by blocks. this is more efficient if the cholesky
/// factor is very sparse
/// reference to a slice containing the cholesky factor's elimination tree
///
/// the elimination tree (or elimination forest, in the general case) is a structure
/// representing the relationship between the columns of the cholesky factor, and the way
/// how earlier columns contribute their sparsity pattern to later columns of the factor
/// dimension of the original matrix
		pub fn len(&self) -> usize {
/// returns the raw elimination tree
///
/// a value can be either nonnegative to represent the index of the parent of a given node,
/// or `-1` to signify that it has no parent
		pub fn into_inner(self) -> &'a [I::Signed] {
/// creates an elimination tree reference from the underlying array
///
/// # safety
/// the elimination tree must come from an array that was previously filled with
/// [`prefactorize_symbolic_cholesky`]
		pub unsafe fn from_inner(inner: &'a [I::Signed]) -> Self {
		pub(crate) fn as_bound<'n>(self, N: ghost::Dim<'n>) -> &'a Array<'n, MaybeIdx<'n, I>> {
/// computes the layout of the workspace required to compute the elimination tree
/// and column counts of a matrix of size `n` with `nnz` non-zero entries
	pub fn prefactorize_symbolic_cholesky_scratch<I: Index>(n: usize, nnz: usize) -> StackReq {
/// computes the elimination tree and column counts of the cholesky factorization of the matrix
/// $A$
///
/// # note
/// only the upper triangular part of $A$ is analyzed
	pub fn prefactorize_symbolic_cholesky<'out, I: Index>(
		etree: &'out mut [I::Signed],
		col_counts: &mut [I],
		A: SymbolicSparseColMatRef<'_, I>,
		stack: &mut MemStack,
	) -> EliminationTreeRef<'out, I> {
// workspace: I×(n)
	fn ghost_prefactorize_symbolic_cholesky<'n, 'out, I: Index>(
		etree: &'out mut Array<'n, I::Signed>,
		col_counts: &mut Array<'n, I>,
		A: SymbolicSparseColMatRef<'_, I, Dim<'n>, Dim<'n>>,
		stack: &mut MemStack,
	) -> &'out mut Array<'n, MaybeIdx<'n, I>> {
	fn ereach<'n, 'a, I: Index>(
		stack: &'a mut Array<'n, I>,
		A: SymbolicSparseColMatRef<'_, I, Dim<'n>, Dim<'n>>,
		etree: &Array<'n, MaybeIdx<'n, I>>,
		k: Idx<'n, usize>,
		visited: &mut Array<'n, I::Signed>,
	) -> &'a [Idx<'n, I>] {
// invariant: stack[top..] elements are less than or equal to k
// (1): after this, we know i < k
// invariant: stack[..len] elements are less than or equal to k
// inserted element is i < k, see (1)
// len is incremented, maintaining the invariant
// because stack[..len] elements are less than or equal to k
// stack[top - len..] elements are now less than or equal to k
// top is decremented by len, maintaining the invariant
// SAFETY: stack[top..] elements are < k < N
/// computes the layout of the workspace required to compute the symbolic
/// cholesky factorization of a square matrix with size `n`
	pub fn factorize_simplicial_symbolic_cholesky_scratch<I: Index>(n: usize) -> StackReq {
/// computes the symbolic structure of the cholesky factor of the matrix $A$
///
/// # note
/// only the upper triangular part of $A$ is analyzed
///
/// # panics
/// the elimination tree and column counts must be computed by calling
/// [`prefactorize_symbolic_cholesky`] with the same matrix. otherwise, the behavior is
/// unspecified and panics may occur
	pub fn factorize_simplicial_symbolic_cholesky<I: Index>(
		A: SymbolicSparseColMatRef<'_, I>,
		etree: EliminationTreeRef<'_, I>,
		col_counts: &[I],
		stack: &mut MemStack,
	) -> Result<SymbolicSimplicialCholesky<I>, FaerError> {
	pub(crate) fn ghost_factorize_simplicial_symbolic_cholesky<'n, I: Index>(
		A: SymbolicSparseColMatRef<'_, I, Dim<'n>, Dim<'n>>,
		etree: &Array<'n, MaybeIdx<'n, I>>,
		col_counts: &Array<'n, I>,
		stack: &mut MemStack,
	) -> Result<SymbolicSimplicialCholesky<I>, FaerError> {
	fn factorize_simplicial_numeric_with_row_idx<I: Index, T: ComplexField>(
		L_values: &mut [T],
		L_row_idx: &mut [I],
		L_col_ptr: &[I],
		kind: FactorizationKind,

		etree: EliminationTreeRef<'_, I>,
		A: SparseColMatRef<'_, I, T>,
		regularization: LdltRegularization<'_, T::Real>,

		stack: &mut MemStack,
	) -> Result<LltInfo, LltError> {
	fn factorize_simplicial_numeric_cholesky<I: Index, T: ComplexField>(
		L_values: &mut [T],
		kind: FactorizationKind,
		A: SparseColMatRef<'_, I, T>,
		regularization: LdltRegularization<'_, T::Real>,
		symbolic: &SymbolicSimplicialCholesky<I>,
		stack: &mut MemStack,
	) -> Result<LltInfo, LltError> {
/// computes the numeric values of the cholesky $LL^H$ factor of the matrix $A$, and stores them
/// in `l_values`
///
/// # note
/// only the upper triangular part of $A$ is accessed
///
/// # panics
/// the symbolic structure must be computed by calling
/// [`factorize_simplicial_symbolic_cholesky`] on a matrix with the same symbolic structure
/// otherwise, the behavior is unspecified and panics may occur
	pub fn factorize_simplicial_numeric_llt<I: Index, T: ComplexField>(
		L_values: &mut [T],
		A: SparseColMatRef<'_, I, T>,
		regularization: LltRegularization<T::Real>,
		symbolic: &SymbolicSimplicialCholesky<I>,
		stack: &mut MemStack,
	) -> Result<LltInfo, LltError> {
/// computes the row indices and  numeric values of the cholesky $LL^H$ factor of the matrix
/// $A$, and stores them in `l_row_idx` and `l_values`
///
/// # note
/// only the upper triangular part of $A$ is accessed
///
/// # panics
/// the elimination tree and column counts must be computed by calling
/// [`prefactorize_symbolic_cholesky`] with the same matrix, then the column pointers are
/// computed from a prefix sum of the column counts. otherwise, the behavior is unspecified
/// and panics may occur
	pub fn factorize_simplicial_numeric_llt_with_row_idx<I: Index, T: ComplexField>(
		L_values: &mut [T],
		L_row_idx: &mut [I],
		L_col_ptr: &[I],

		etree: EliminationTreeRef<'_, I>,
		A: SparseColMatRef<'_, I, T>,
		regularization: LltRegularization<T::Real>,

		stack: &mut MemStack,
	) -> Result<LltInfo, LltError> {
/// computes the numeric values of the cholesky $LDL^H$ factors of the matrix $A$, and stores
/// them in `l_values`
///
/// # note
/// only the upper triangular part of $A$ is accessed
///
/// # panics
/// the symbolic structure must be computed by calling
/// [`factorize_simplicial_symbolic_cholesky`] on a matrix with the same symbolic structure
/// otherwise, the behavior is unspecified and panics may occur
	pub fn factorize_simplicial_numeric_ldlt<I: Index, T: ComplexField>(
		L_values: &mut [T],
		A: SparseColMatRef<'_, I, T>,
		regularization: LdltRegularization<'_, T::Real>,
		symbolic: &SymbolicSimplicialCholesky<I>,
		stack: &mut MemStack,
	) -> Result<LdltInfo, LdltError> {
/// computes the row indices and  numeric values of the cholesky $LDL^H$ factor of the matrix
/// $A$, and stores them in `l_row_idx` and `l_values`
///
/// # note
/// only the upper triangular part of $A$ is accessed
///
/// # panics
/// the elimination tree and column counts must be computed by calling
/// [`prefactorize_symbolic_cholesky`] with the same matrix, then the column pointers are
/// computed from a prefix sum of the column counts. otherwise, the behavior is unspecified
/// and panics may occur
	pub fn factorize_simplicial_numeric_ldlt_with_row_idx<I: Index, T: ComplexField>(
		L_values: &mut [T],
		L_row_idx: &mut [I],
		L_col_ptr: &[I],

		etree: EliminationTreeRef<'_, I>,
		A: SparseColMatRef<'_, I, T>,
		regularization: LdltRegularization<'_, T::Real>,

		stack: &mut MemStack,
	) -> Result<LdltInfo, LdltError> {
/// creates a new cholesky $LL^H$ factor from the symbolic part and numerical values
///
/// # panics
/// panics if `values.len() != symbolic.len_val()`>
		pub fn new(symbolic: &'a SymbolicSimplicialCholesky<I>, values: &'a [T]) -> Self {
/// returns the symbolic part of the cholesky factor
		pub fn symbolic(self) -> &'a SymbolicSimplicialCholesky<I> {
/// returns the numerical values of the cholesky $LL^H$ factor
		pub fn values(self) -> &'a [T] {
/// solves the equation $A x = \text{rhs}$ and stores the result in `rhs`, implicitly
/// conjugating $A$ if needed
///
/// # panics
/// panics if `rhs.nrows() != self.symbolic().nrows()`
		pub fn solve_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>, par: Par, stack: &mut MemStack)
		where
			T: ComplexField,
		{
/// creates a new cholesky $LDL^H$ factor from the symbolic part and numerical values
///
/// # panics
/// panics if `values.len() != symbolic.len_val()`>
		pub fn new(symbolic: &'a SymbolicSimplicialCholesky<I>, values: &'a [T]) -> Self {
/// returns the symbolic part of the cholesky factor
		pub fn symbolic(self) -> &'a SymbolicSimplicialCholesky<I> {
/// returns the numerical values of the cholesky $LDL^H$ factor
		pub fn values(self) -> &'a [T] {
/// solves the equation $A x = \text{rhs}$ and stores the result in `rhs`, implicitly
/// conjugating $A$ if needed
///
/// # panics
/// panics if `rhs.nrows() != self.symbolic().nrows()`
		pub fn solve_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>, par: Par, stack: &mut MemStack)
		where
			T: ComplexField,
		{
/// returns the number of rows of the cholesky factor
		pub fn nrows(&self) -> usize {
/// returns the number of columns of the cholesky factor
		pub fn ncols(&self) -> usize {
/// returns the length of the slice that can be used to contain the numerical values of the
/// cholesky factor
		pub fn len_val(&self) -> usize {
/// returns the column pointers of the cholesky factor
		pub fn col_ptr(&self) -> &[I] {
/// returns the row indices of the cholesky factor
		pub fn row_idx(&self) -> &[I] {
/// returns the cholesky factor's symbolic structure
		pub fn factor(&self) -> SymbolicSparseColMatRef<'_, I> {
/// returns the layout of the workspace required to solve the system
/// $A x = rhs$
		pub fn solve_in_place_scratch<T>(&self, rhs_ncols: usize) -> StackReq {
/// returns the layout of the workspace required to compute the numeric
/// cholesky $LDL^H$ factorization of a matrix $A$ with dimension `n`
	pub fn factorize_simplicial_numeric_ldlt_scratch<I: Index, T: ComplexField>(n: usize) -> StackReq {
/// returns the layout of the workspace required to compute the numeric
/// cholesky $LL^H$ factorization of a matrix $A$ with dimension `n`
	pub fn factorize_simplicial_numeric_llt_scratch<I: Index, T: ComplexField>(n: usize) -> StackReq {
/// cholesky $LL^H$ factor containing both its symbolic and numeric representations
/// cholesky $LDL^H$ factors containing both the symbolic and numeric representations
/// cholesky factor structure containing its symbolic structure
		fn clone(&self) -> Self {
		fn clone(&self) -> Self {
/// supernodal factorization module
///
/// a supernodal factorization is one that processes the elements of the cholesky factor of the
/// input matrix by blocks, rather than single elements. this is more efficient if the cholesky
/// factor is somewhat dense
	pub fn ereach_super<'n, 'nsuper, I: Index>(
		A: SymbolicSparseColMatRef<'_, I, Dim<'n>, Dim<'n>>,
		super_etree: &Array<'nsuper, MaybeIdx<'nsuper, I>>,
		index_to_super: &Array<'n, Idx<'nsuper, I>>,
		current_row_positions: &mut Array<'nsuper, I>,
		row_idx: &mut [Idx<'n, I>],
		k: Idx<'n, usize>,
		visited: &mut Array<'nsuper, I::Signed>,
	) {
	fn ereach_super_ata<'m, 'n, 'nsuper, I: Index>(
		A: SymbolicSparseColMatRef<'_, I, Dim<'m>, Dim<'n>>,
		perm: Option<PermRef<'_, I, Dim<'n>>>,
		min_col: &Array<'m, MaybeIdx<'n, I>>,
		super_etree: &Array<'nsuper, MaybeIdx<'nsuper, I>>,
		index_to_super: &Array<'n, Idx<'nsuper, I>>,
		current_row_positions: &mut Array<'nsuper, I>,
		row_idx: &mut [Idx<'n, I>],
		k: Idx<'n, usize>,
		visited: &mut Array<'nsuper, I::Signed>,
	) {
/// symbolic structure of a single supernode from the cholesky factor
/// a single supernode from the cholesky factor
		fn clone(&self) -> Self {
		fn clone(&self) -> Self {
/// returns the starting index of the supernode
		pub fn start(self) -> usize {
/// returns the pattern of the row indices in the supernode, excluding those on the block
/// diagonal
		pub fn pattern(self) -> &'a [I] {
/// returns the starting index of the supernode
		pub fn start(self) -> usize {
/// returns the pattern of the row indices in the supernode, excluding those on the block
/// diagonal
		pub fn pattern(self) -> &'a [I] {
/// returns a view over the numerical values of the supernode
		pub fn val(self) -> MatRef<'a, T> {
/// cholesky $LL^H$ factor containing both its symbolic and numeric representations
/// cholesky $LDL^H$ factors containing both the symbolic and numeric representations
/// cholesky $LBL^\top$ factors containing both the symbolic and numeric representations
/// cholesky factor structure containing its symbolic structure
/// returns the number of supernodes in the cholesky factor
		pub fn n_supernodes(&self) -> usize {
/// returns the number of rows of the cholesky factor
		pub fn nrows(&self) -> usize {
/// returns the number of columns of the cholesky factor
		pub fn ncols(&self) -> usize {
/// returns the length of the slice that can be used to contain the numerical values of the
/// cholesky factor
		pub fn len_val(&self) -> usize {
/// returns a slice of length `self.n_supernodes()` containing the beginning index of each
/// supernode
		pub fn supernode_begin(&self) -> &[I] {
/// returns a slice of length `self.n_supernodes()` containing the past-the-end index of
/// each
		pub fn supernode_end(&self) -> &[I] {
/// returns the column pointers for row indices of each supernode
		pub fn col_ptr_for_row_idx(&self) -> &[I] {
/// returns the column pointers for numerical values of each supernode
		pub fn col_ptr_for_val(&self) -> &[I] {
/// returns the row indices of the cholesky factor
///
/// # note
/// note that the row indices of each supernode do not contain those of the block diagonal
/// part
		pub fn row_idx(&self) -> &[I] {
/// returns the symbolic structure of the `s`'th supernode
		pub fn supernode(&self, s: usize) -> supernodal::SymbolicSupernodeRef<'_, I> {
/// returns the layout of the workspace required to solve the system
/// $A x = rhs$
		pub fn solve_in_place_scratch<T: ComplexField>(&self, rhs_ncols: usize, par: Par) -> StackReq {
		pub fn __prepare_for_refactorize(&mut self) -> Result<(), FaerError> {
		pub fn __nnz_per_super(&self) -> &[I] {
		pub fn __refactorize(&mut self, A: SymbolicSparseColMatRef<'_, I>, etree: &[I::Signed], stack: &mut MemStack) {
		fn clone(&self) -> Self {
		fn clone(&self) -> Self {
		fn clone(&self) -> Self {
/// creates new cholesky $LDL^H$ factors from the symbolic part and
/// numerical values
///
/// # panics
/// - panics if `values.len() != symbolic.len_val()`
		pub fn new(symbolic: &'a SymbolicSupernodalCholesky<I>, values: &'a [T]) -> Self {
/// returns the symbolic part of the cholesky factor
		pub fn symbolic(self) -> &'a SymbolicSupernodalCholesky<I> {
/// returns the numerical values of the l factor
		pub fn values(self) -> &'a [T] {
/// returns the `s`'th supernode
		pub fn supernode(self, s: usize) -> SupernodeRef<'a, I, T> {
/// solves the equation $A x = \text{rhs}$ and stores the result in `rhs`, implicitly
/// conjugating $A$ if needed
///
/// # panics
/// panics if `rhs.nrows() != self.symbolic().nrows()`
		pub fn solve_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>, par: Par, stack: &mut MemStack)
		where
			T: ComplexField,
		{
/// creates a new cholesky $LL^H$ factor from the symbolic part and
/// numerical values
///
/// # panics
/// - panics if `values.len() != symbolic.len_val()`
		pub fn new(symbolic: &'a SymbolicSupernodalCholesky<I>, values: &'a [T]) -> Self {
/// returns the symbolic part of the cholesky factor
		pub fn symbolic(self) -> &'a SymbolicSupernodalCholesky<I> {
/// returns the numerical values of the l factor
		pub fn values(self) -> &'a [T] {
/// returns the `s`'th supernode
		pub fn supernode(self, s: usize) -> SupernodeRef<'a, I, T> {
/// solves the equation $L x = \text{rhs}$ and stores the result in `rhs`,
/// implicitly conjugating $L$ if needed
///
/// # panics
/// panics if `rhs.nrows() != self.symbolic().nrows()`
		pub fn l_solve_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>, par: Par, stack: &mut MemStack)
		where
			T: ComplexField,
		{
/// solves the equation $L^\top x = \text{rhs}$ and stores the result in `rhs`,
/// implicitly conjugating $L$ if needed
///
/// # panics
/// panics if `rhs.nrows() != self.symbolic().nrows()`
		pub fn l_transpose_solve_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>, par: Par, stack: &mut MemStack)
		where
			T: ComplexField,
		{
/// solves the equation $A x = \text{rhs}$ and stores the result in `rhs`, implicitly
/// conjugating $A$ if needed
///
/// # panics
/// panics if `rhs.nrows() != self.symbolic().nrows()`
		pub fn solve_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>, par: Par, stack: &mut MemStack)
		where
			T: ComplexField,
		{
/// creates a new cholesky intranodal $LBL^\top$ factor from the symbolic part and
/// numerical values, as well as the pivoting permutation
///
/// # panics
/// - panics if `values.len() != symbolic.len_val()`
/// - panics if `subdiag.len() != symbolic.nrows()`
/// - panics if `perm.len() != symbolic.nrows()`
		pub fn new(symbolic: &'a SymbolicSupernodalCholesky<I>, values: &'a [T], subdiag: &'a [T], perm: PermRef<'a, I>) -> Self {
/// returns the symbolic part of the cholesky factor
		pub fn symbolic(self) -> &'a SymbolicSupernodalCholesky<I> {
/// returns the numerical values of the l factor
		pub fn val(self) -> &'a [T] {
/// returns the `s`'th supernode
		pub fn supernode(self, s: usize) -> SupernodeRef<'a, I, T> {
/// returns the pivoting permutation
		pub fn perm(&self) -> PermRef<'a, I> {
/// solves the system $L B L^H x = \text{rhs}$, implicitly conjugating $L$ and
/// $B$ if needed
///
/// # note
/// note that this function doesn't apply the pivoting permutation. users are expected to
/// apply it manually to `rhs` before and after calling this function
///
/// # panics
/// panics if `rhs.nrows() != self.symbolic().nrows()`
		pub fn solve_in_place_no_numeric_permute_with_conj(self, conj_lb: Conj, rhs: MatMut<'_, T>, par: Par, stack: &mut MemStack)
		where
			T: ComplexField,
		{
/// returns the layout of the workspace required to compute the symbolic supernodal
/// factorization of a matrix of size `n`
	pub fn factorize_supernodal_symbolic_cholesky_scratch<I: Index>(n: usize) -> StackReq {
/// computes the supernodal symbolic structure of the cholesky factor of the matrix $A$
///
/// # note
/// only the upper triangular part of $A$ is analyzed
///
/// # panics
/// the elimination tree and column counts must be computed by calling
/// [`simplicial::prefactorize_symbolic_cholesky`] with the same matrix. otherwise, the behavior
/// is unspecified and panics may occur
	pub fn factorize_supernodal_symbolic_cholesky<I: Index>(
		A: SymbolicSparseColMatRef<'_, I>,
		etree: simplicial::EliminationTreeRef<'_, I>,
		col_counts: &[I],
		stack: &mut MemStack,
		params: SymbolicSupernodalParams<'_>,
	) -> Result<SymbolicSupernodalCholesky<I>, FaerError> {
	pub(crate) fn ghost_factorize_supernodal_symbolic<'m, 'n, I: Index>(
		A: SymbolicSparseColMatRef<'_, I, Dim<'m>, Dim<'n>>,
		col_perm: Option<PermRef<'_, I, Dim<'n>>>,
		min_col: Option<&Array<'m, MaybeIdx<'n, I>>>,
		input: CholeskyInput,
		etree: &Array<'n, MaybeIdx<'n, I>>,
		col_counts: &Array<'n, I>,
		stack: &mut MemStack,
		params: SymbolicSupernodalParams<'_>,
	) -> Result<SymbolicSupernodalCholesky<I>, FaerError> {
// would be funny if this allocation failed
// last n elements contain supernode degrees
	pub(crate) fn partition_fn<I: Index>(idx: usize) -> impl Fn(&I) -> bool {
/// returns the layout of the workspace required to compute the numeric
/// cholesky $LL^H$ factorization of a matrix $A$ with dimension `n`
	pub fn factorize_supernodal_numeric_llt_scratch<I: Index, T: ComplexField>(
		symbolic: &SymbolicSupernodalCholesky<I>,
		par: Par,
		params: Spec<LltParams, T>,
	) -> StackReq {
/// returns the layout of the workspace required to compute the numeric
/// cholesky $LDL^H$ factorization of a matrix $A$ with dimension `n`
	pub fn factorize_supernodal_numeric_ldlt_scratch<I: Index, T: ComplexField>(
		symbolic: &SymbolicSupernodalCholesky<I>,
		par: Par,
		params: Spec<LdltParams, T>,
	) -> StackReq {
/// returns the layout of the workspace required to compute the numeric
/// cholesky $LBL^\top$ factorization with intranodal pivoting of a matrix $A$ with dimension
/// `n`
	pub fn factorize_supernodal_numeric_intranode_lblt_scratch<I: Index, T: ComplexField>(
		symbolic: &SymbolicSupernodalCholesky<I>,
		par: Par,
		params: Spec<LbltParams, T>,
	) -> StackReq {
/// computes the numeric values of the cholesky $LL^H$ factor of the matrix $A$, and stores them
/// in `l_values`
///
/// # warning
/// only the *lower* (not upper, unlike the other functions) triangular part of $A$ is
/// accessed
///
/// # panics
/// the symbolic structure must be computed by calling
/// [`factorize_supernodal_symbolic_cholesky`] on a matrix with the same symbolic structure
/// otherwise, the behavior is unspecified and panics may occur
	pub fn factorize_supernodal_numeric_llt<I: Index, T: ComplexField>(
		L_values: &mut [T],
		A_lower: SparseColMatRef<'_, I, T>,
		regularization: LltRegularization<T::Real>,
		symbolic: &SymbolicSupernodalCholesky<I>,
		par: Par,
		stack: &mut MemStack,
		params: Spec<LltParams, T>,
	) -> Result<LltInfo, LltError> {
// mapping from global indices to local
/// computes the numeric values of the cholesky $LDL^H$ factors of the matrix $A$, and stores
/// them in `l_values`
///
/// # note
/// only the *lower* (not upper, unlike the other functions) triangular part of $A$ is
/// accessed
///
/// # panics
/// the symbolic structure must be computed by calling
/// [`factorize_supernodal_symbolic_cholesky`] on a matrix with the same symbolic structure
/// otherwise, the behavior is unspecified and panics may occur
	pub fn factorize_supernodal_numeric_ldlt<I: Index, T: ComplexField>(
		L_values: &mut [T],
		A_lower: SparseColMatRef<'_, I, T>,
		regularization: LdltRegularization<'_, T::Real>,
		symbolic: &SymbolicSupernodalCholesky<I>,
		par: Par,
		stack: &mut MemStack,
		params: Spec<LdltParams, T>,
	) -> Result<LdltInfo, LdltError> {
// mapping from global indices to local
/// computes the numeric values of the cholesky $LBL^\top$ factors of the matrix $A$ with
/// intranodal pivoting, and stores them in `l_values`
///
/// # note
/// only the *lower* (not upper, unlike the other functions) triangular part of $A$ is
/// accessed
///
/// # panics
/// the symbolic structure must be computed by calling
/// [`factorize_supernodal_symbolic_cholesky`] on a matrix with the same symbolic structure
/// otherwise, the behavior is unspecified and panics may occur
	pub fn factorize_supernodal_numeric_intranode_lblt<I: Index, T: ComplexField>(
		L_values: &mut [T],
		subdiag: &mut [T],
		perm_forward: &mut [I],
		perm_inverse: &mut [I],
		A_lower: SparseColMatRef<'_, I, T>,
		symbolic: &SymbolicSupernodalCholesky<I>,
		par: Par,
		stack: &mut MemStack,
		params: Spec<LbltParams, T>,
	) -> LbltInfo {
// mapping from global indices to local
fn postorder_depth_first_search<'n, I: Index>(
	post: &mut Array<'n, I>,
	root: usize,
	mut start_index: usize,
	stack: &mut Array<'n, I>,
	first_child: &mut Array<'n, MaybeIdx<'n, I>>,
	next_child: &Array<'n, I::Signed>,
) -> usize {
pub(crate) fn ghost_postorder<'n, I: Index>(post: &mut Array<'n, I>, etree: &Array<'n, MaybeIdx<'n, I>>, stack: &mut MemStack) {
/// tuning parameters for the symbolic cholesky factorization
/// parameters for computing the fill-reducing permutation
/// threshold for selecting the supernodal factorization
/// supernodal factorization parameters
/// the inner factorization used for the symbolic cholesky, either simplicial or symbolic
/// simplicial structure
/// supernodal structure
/// the symbolic structure of a sparse cholesky decomposition
/// returns the number of rows of the matrix
	pub fn nrows(&self) -> usize {
/// returns the number of columns of the matrix
	pub fn ncols(&self) -> usize {
/// returns the inner type of the factorization, either simplicial or symbolic
	pub fn raw(&self) -> &SymbolicCholeskyRaw<I> {
/// returns the permutation that was computed during symbolic analysis
	pub fn perm(&self) -> Option<PermRef<'_, I>> {
/// returns the length of the slice needed to store the numerical values of the cholesky
/// decomposition
	pub fn len_val(&self) -> usize {
/// computes the required workspace layout for a numerical $LL^H$ factorization
	pub fn factorize_numeric_llt_scratch<T: ComplexField>(&self, par: Par, params: Spec<LltParams, T>) -> StackReq {
/// computes the required workspace layout for a numerical $LDL^H$ factorization
	pub fn factorize_numeric_ldlt_scratch<T: ComplexField>(&self, par: Par, params: Spec<LdltParams, T>) -> StackReq {
/// computes the required workspace layout for a numerical intranodal $LBL^\top$
/// factorization
	pub fn factorize_numeric_intranode_lblt_scratch<T: ComplexField>(&self, par: Par, params: Spec<LbltParams, T>) -> StackReq {
/// computes a numerical llt factorization of a, or returns a [`LltError`] if the matrix
/// is not numerically positive definite
	pub fn factorize_numeric_llt<'out, T: ComplexField>(
		&'out self,
		L_values: &'out mut [T],
		A: SparseColMatRef<'_, I, T>,
		side: Side,
		regularization: LltRegularization<T::Real>,
		par: Par,
		stack: &mut MemStack,
		params: Spec<LltParams, T>,
	) -> Result<LltRef<'out, I, T>, LltError> {
/// computes a numerical $LDL^H$ factorization of a
	pub fn factorize_numeric_ldlt<'out, T: ComplexField>(
		&'out self,
		L_values: &'out mut [T],
		A: SparseColMatRef<'_, I, T>,
		side: Side,
		regularization: LdltRegularization<'_, T::Real>,
		par: Par,
		stack: &mut MemStack,
		params: Spec<LdltParams, T>,
	) -> Result<LdltRef<'out, I, T>, LdltError> {
/// computes a numerical intranodal $LBL^\top$ factorization of a
	pub fn factorize_numeric_intranode_lblt<'out, T: ComplexField>(
		&'out self,
		L_values: &'out mut [T],
		subdiag: &'out mut [T],
		perm_forward: &'out mut [I],
		perm_inverse: &'out mut [I],
		A: SparseColMatRef<'_, I, T>,
		side: Side,
		par: Par,
		stack: &mut MemStack,
		params: Spec<LbltParams, T>,
	) -> IntranodeLbltRef<'out, I, T> {
/// computes the required workspace layout for a dense solve in place using an
/// $LL^H$, $LDL^H$ or intranodal $LBL^\top$ factorization
	pub fn solve_in_place_scratch<T: ComplexField>(&self, rhs_ncols: usize, par: Par) -> StackReq {
/// sparse $LL^H$ factorization wrapper
/// sparse $LDL^H$ factorization wrapper
/// sparse intranodal $LBL^\top$ factorization wrapper
	fn deref(&self) -> &Self::Target {
	fn deref(&self) -> &Self::Target {
	fn deref(&self) -> &Self::Target {
	fn clone(&self) -> Self {
	fn clone(&self) -> Self {
	fn clone(&self) -> Self {
/// creates a new cholesky intranodal $LBL^\top$ factor from the symbolic part and
/// numerical values, as well as the pivoting permutation
///
/// # panics
/// - panics if `values.len() != symbolic.len_val()`
/// - panics if `subdiag.len() != symbolic.nrows()`
/// - panics if `perm.len() != symbolic.nrows()`
	pub fn new(symbolic: &'a SymbolicCholesky<I>, values: &'a [T], subdiag: &'a [T], perm: PermRef<'a, I>) -> Self {
/// returns the symbolic part of the cholesky factor
	pub fn symbolic(self) -> &'a SymbolicCholesky<I> {
/// solves the equation $A x = \text{rhs}$ and stores the result in `rhs`, implicitly
/// conjugating $A$ if needed
///
/// # panics
/// panics if `rhs.nrows() != self.symbolic().nrows()`
	pub fn solve_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>, par: Par, stack: &mut MemStack)
	where
		T: ComplexField,
	{
/// creates a new cholesky $LL^H$ factor from the symbolic part and
/// numerical values
///
/// # panics
/// - panics if `values.len() != symbolic.len_val()`
	pub fn new(symbolic: &'a SymbolicCholesky<I>, values: &'a [T]) -> Self {
/// returns the symbolic part of the cholesky factor
	pub fn symbolic(self) -> &'a SymbolicCholesky<I> {
/// solves the equation $A x = \text{rhs}$ and stores the result in `rhs`, implicitly
/// conjugating $A$ if needed
///
/// # panics
/// panics if `rhs.nrows() != self.symbolic().nrows()`
	pub fn solve_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>, par: Par, stack: &mut MemStack)
	where
		T: ComplexField,
	{
/// creates new cholesky $LDL^H$ factors from the symbolic part and
/// numerical values
///
/// # panics
/// - panics if `values.len() != symbolic.len_val()`
	pub fn new(symbolic: &'a SymbolicCholesky<I>, values: &'a [T]) -> Self {
/// returns the symbolic part of the cholesky factor
	pub fn symbolic(self) -> &'a SymbolicCholesky<I> {
/// solves the equation $A x = \text{rhs}$ and stores the result in `rhs`, implicitly
/// conjugating $A$ if needed
///
/// # panics
/// panics if `rhs.nrows() != self.symbolic().nrows()`
	pub fn solve_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>, par: Par, stack: &mut MemStack)
	where
		T: ComplexField,
	{
/// computes the symbolic cholesky factorization of the matrix $A$, or returns an error if the
/// operation could not be completed
pub fn factorize_symbolic_cholesky<I: Index>(
	A: SymbolicSparseColMatRef<'_, I>,
	side: Side,
	ord: SymmetricOrdering<'_, I>,
	params: CholeskySymbolicParams<'_>,
) -> Result<SymbolicCholesky<I>, FaerError> {
// new_col_ptr
// new_row_idx
// permute_symmetric | etree
// col_counts
// ghost_prefactorize_symbolic
// ghost_factorize_*_symbolic
	pub(crate) fn load_mtx<I: Index>(data: MtxData<f64>) -> (usize, usize, Vec<I>, Vec<I>, Vec<f64>) {
	pub(crate) fn parse_vec<F: FromStr>(text: &str) -> (Vec<F>, &str) {
	pub(crate) fn parse_csc_symbolic(text: &str) -> (SymbolicSparseColMat<usize>, &str) {
	pub(crate) fn parse_csc<T: FromStr>(text: &str) -> (SparseColMat<usize, T>, &str) {
	fn test_counts() {
// 0
// 1
// 2
// 3
// 4
// 5
// 6
// 7
// 8
// 9
// 10
	fn test_amd() -> Result {
	fn reconstruct_from_supernodal_ldlt<I: Index, T: ComplexField>(symbolic: &supernodal::SymbolicSupernodalCholesky<I>, L_values: &[T]) -> Mat<T> {
	pub(crate) fn reconstruct_from_supernodal_llt<I: Index, T: ComplexField>(
		symbolic: &supernodal::SymbolicSupernodalCholesky<I>,
		L_values: &[T],
	) -> Mat<T> {
	fn reconstruct_from_simplicial_ldlt<I: Index, T: ComplexField>(symbolic: &simplicial::SymbolicSimplicialCholesky<I>, L_values: &[T]) -> Mat<T> {
	fn reconstruct_from_simplicial_llt<I: Index, T: ComplexField>(symbolic: &simplicial::SymbolicSimplicialCholesky<I>, L_values: &[T]) -> Mat<T> {
	fn test_supernodal() -> Result {
	fn test_simplicial() -> Result {
	fn test_solver_llt() -> Result {
	fn test_solver_ldlt() -> Result {
	fn test_solver_bk() -> Result {
//! approximate minimum degree column ordering.
// COLAMD, Copyright (c) 1998-2022, Timothy A. Davis and Stefan Larimore,
// All Rights Reserved.
// SPDX-License-Identifier: BSD-3-clause
//
//     Redistribution and use in source and binary forms, with or without
//     modification, are permitted provided that the following conditions are met:
//         * Redistributions of source code must retain the above copyright notice, this list of
//           conditions and the following disclaimer.
//         * Redistributions in binary form must reproduce the above copyright notice, this list of
//           conditions and the following disclaimer in the documentation and/or other materials
//           provided with the distribution.
//         * Neither the name of the organizations to which the authors are affiliated, nor the
//           names of its contributors may be used to endorse or promote products derived from this
//           software without specific prior written permission.
//
//     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
//     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
//     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
//     ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
//     DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
//     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
//     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
//     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
//     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
//     OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
//     DAMAGE.
	fn is_dead_principal(&self) -> bool {
	fn is_dead(&self) -> bool {
	fn is_alive(&self) -> bool {
	fn kill_principal(&mut self) {
	fn kill_non_principal(&mut self) {
	fn is_dead(&self) -> bool {
	fn is_alive(&self) -> bool {
	fn kill(&mut self) {
fn clear_mark<I: Index>(tag_mark: I, max_mark: I, row: &mut [ColamdRow<I>]) -> I {
/// computes the layout of required workspace for computing the colamd ordering of a
/// matrix
pub fn order_scratch<I: Index>(nrows: usize, ncols: usize, A_nnz: usize) -> StackReq {
/// computes the approximate minimum degree ordering for reducing the fill-in during the sparse
/// qr factorization of a matrix with the sparsity pattern of $A$
///
/// # note
/// allows unsorted matrices
pub fn order<I: Index>(
	perm: &mut [I],
	perm_inv: &mut [I],
	A: SymbolicSparseColMatRef<'_, I>,
	control: Control,
	stack: &mut MemStack,
) -> Result<(), FaerError> {
fn detect_super_cols<I: Index>(col: &mut [ColamdCol<I>], A: &mut [I], head: &mut [I], row_start: usize, row_length: usize) {
fn garbage_collection<I: Index>(row: &mut [ColamdRow<I>], col: &mut [ColamdCol<I>], A: &mut [I], pfree: usize) -> usize {
/// tuning parameters for the amd implementation
/// "dense" if degree > dense_row * sqrt(ncols)
/// "dense" if degree > dense_col * sqrt(min(nrows, ncols))
/// do aggressive absorption
	fn default() -> Self {
//! computes the $LU$ decomposition of a given sparse matrix. see
//! [`faer::linalg::lu`](crate::linalg::lu) for more info
//!
//! the entry point in this module is [`SymbolicLu`] and [`factorize_symbolic_lu`]
//!
//! # note
//! the functions in this module accept unsorted inputs, and may produce unsorted decomposition
//! factors.
fn resize_vec<T: Clone>(v: &mut alloc::vec::Vec<T>, n: usize, exact: bool, reserve_only: bool, value: T) -> Result<(), FaerError> {
/// supernodal factorization module
///
/// a supernodal factorization is one that processes the elements of the $LU$ factors of the
/// input matrix by blocks, rather than by single elements. this is more efficient if the lu
/// factors are somewhat dense
/// $LU$ factor structure containing the symbolic structure
/// $LU$ factor structure containing the symbolic and numerical representations
		fn default() -> Self {
/// creates a new supernodal $LU$ of a $0 \times 0$ matrix
		pub fn new() -> Self {
/// returns the number of rows of $A$
		pub fn nrows(&self) -> usize {
/// returns the number of columns of $A$
		pub fn ncols(&self) -> usize {
/// returns the number of supernodes
		pub fn n_supernodes(&self) -> usize {
/// solves the equation $A x = \text{rhs}$ and stores the result in `rhs`, implicitly
/// conjugating $A$ if needed
///
/// # panics
/// - panics if `self.nrows() != self.ncols()`
/// - panics if `rhs.nrows() != self.nrows()`
		pub fn solve_in_place_with_conj(
			&self,
			row_perm: PermRef<'_, I>,
			col_perm: PermRef<'_, I>,
			conj_lhs: Conj,
			rhs: MatMut<'_, T>,
			par: Par,
			work: MatMut<'_, T>,
		) where
			T: ComplexField,
		{
/// solves the equation $A^\top x = \text{rhs}$ and stores the result in `rhs`, implicitly
/// conjugating $A$ if needed
///
/// # panics
/// - panics if `self.nrows() != self.ncols()`
/// - panics if `rhs.nrows() != self.nrows()`
		pub fn solve_transpose_in_place_with_conj(
			&self,
			row_perm: PermRef<'_, I>,
			col_perm: PermRef<'_, I>,
			conj_lhs: Conj,
			rhs: MatMut<'_, T>,
			par: Par,
			work: MatMut<'_, T>,
		) where
			T: ComplexField,
		{
		pub(crate) fn l_solve_in_place_with_conj(&self, conj_lhs: Conj, rhs: MatMut<'_, T>, mut work: MatMut<'_, T>, par: Par)
		where
			T: ComplexField,
		{
		pub(crate) fn l_solve_transpose_in_place_with_conj(&self, conj_lhs: Conj, rhs: MatMut<'_, T>, mut work: MatMut<'_, T>, par: Par)
		where
			T: ComplexField,
		{
		pub(crate) fn u_solve_in_place_with_conj(&self, conj_lhs: Conj, rhs: MatMut<'_, T>, mut work: MatMut<'_, T>, par: Par)
		where
			T: ComplexField,
		{
		pub(crate) fn u_solve_transpose_in_place_with_conj(&self, conj_lhs: Conj, rhs: MatMut<'_, T>, mut work: MatMut<'_, T>, par: Par)
		where
			T: ComplexField,
		{
/// computes the layout of the workspace required to compute the symbolic
/// $LU$ factorization of a square matrix with size `n`.
	pub fn factorize_supernodal_symbolic_lu_scratch<I: Index>(nrows: usize, ncols: usize) -> StackReq {
/// computes the symbolic structure of the $LU$ factors of the matrix $A$
	pub fn factorize_supernodal_symbolic_lu<I: Index>(
		A: SymbolicSparseColMatRef<'_, I>,
		col_perm: Option<PermRef<'_, I>>,
		min_col: &[I],
		etree: EliminationTreeRef<'_, I>,
		col_counts: &[I],
		stack: &mut MemStack,
		params: SymbolicSupernodalParams<'_>,
	) -> Result<SymbolicSupernodalLu<I>, FaerError> {
		fn new() -> Self {
		fn with_dims(nrows: usize, ncols: usize) -> Result<Self, FaerError> {
		fn index(&self, (row, col): (usize, usize)) -> &Self::Output {
		fn index_mut(&mut self, (row, col): (usize, usize)) -> &mut Self::Output {
	fn noinline<T, R>(_: T, f: impl FnOnce() -> R) -> R {
/// computes the layout of the workspace required to perform a numeric $LU$
/// factorization
	pub fn factorize_supernodal_numeric_lu_scratch<I: Index, T: ComplexField>(
		symbolic: &SymbolicSupernodalLu<I>,
		params: Spec<PartialPivLuParams, T>,
	) -> StackReq {
/// computes the numeric values of the $LU$ factors of the matrix $A$ as well as the row
/// pivoting permutation, and stores them in `lu` and `row_perm`/`row_perm_inv`
	pub fn factorize_supernodal_numeric_lu<I: Index, T: ComplexField>(
		row_perm: &mut [I],
		row_perm_inv: &mut [I],
		lu: &mut SupernodalLu<I, T>,

		A: SparseColMatRef<'_, I, T>,
		AT: SparseColMatRef<'_, I, T>,
		col_perm: PermRef<'_, I>,
		symbolic: &SymbolicSupernodalLu<I>,

		par: Par,
		stack: &mut MemStack,
		params: Spec<PartialPivLuParams, T>,
	) -> Result<(), LuError> {
// add the rows from A[s_end:, s_begin:s_end]
// add the rows from child[s_begin:]
/// simplicial factorization module
///
/// a supernodal factorization is one that processes the elements of the $LU$ factors of the
/// input matrix by single elements, rather than by blocks. this is more efficient if the lu
/// factors are very sparse
/// $LU$ factor structure containing the symbolic and numerical representations
		fn default() -> Self {
/// creates a new simplicial $LU$ of a $0 \times 0$ matrix
		pub fn new() -> Self {
/// returns the number of rows of $A$
		pub fn nrows(&self) -> usize {
/// returns the number of columns of $A$
		pub fn ncols(&self) -> usize {
/// returns the $L$ factor of the $LU$ factorization. the row indices may be unsorted
		pub fn l_factor_unsorted(&self) -> SparseColMatRef<'_, I, T> {
/// returns the $U$ factor of the $LU$ factorization. the row indices may be unsorted
		pub fn u_factor_unsorted(&self) -> SparseColMatRef<'_, I, T> {
/// solves the equation $A x = \text{rhs}$ and stores the result in `rhs`, implicitly
/// conjugating $A$ if needed
///
/// # panics
/// - panics if `self.nrows() != self.ncols()`
/// - panics if `rhs.nrows() != self.nrows()`
		pub fn solve_in_place_with_conj(
			&self,
			row_perm: PermRef<'_, I>,
			col_perm: PermRef<'_, I>,
			conj_lhs: Conj,
			rhs: MatMut<'_, T>,
			par: Par,
			work: MatMut<'_, T>,
		) where
			T: ComplexField,
		{
/// solves the equation $A^\top x = \text{rhs}$ and stores the result in `rhs`,
/// implicitly conjugating $A$ if needed
///
/// # panics
/// - panics if `self.nrows() != self.ncols()`
/// - panics if `rhs.nrows() != self.nrows()`
		pub fn solve_transpose_in_place_with_conj(
			&self,
			row_perm: PermRef<'_, I>,
			col_perm: PermRef<'_, I>,
			conj_lhs: Conj,
			rhs: MatMut<'_, T>,
			par: Par,
			work: MatMut<'_, T>,
		) where
			T: ComplexField,
		{
	fn depth_first_search<I: Index>(
		marked: &mut [I],
		mark: I,

		xi: &mut [I],
		l: SymbolicSparseColMatRef<'_, I>,
		row_perm_inv: &[I],
		b: usize,
		stack: &mut [I],
	) -> usize {
	fn reach<I: Index>(
		marked: &mut [I],
		mark: I,

		xi: &mut [I],
		l: SymbolicSparseColMatRef<'_, I>,
		row_perm_inv: &[I],
		bi: &[I],
		stack: &mut [I],
	) -> usize {
	fn l_incomplete_solve_sparse<I: Index, T: ComplexField>(
		marked: &mut [I],
		mark: I,

		xi: &mut [I],
		x: &mut [T],
		l: SparseColMatRef<'_, I, T>,
		row_perm_inv: &[I],
		bi: &[I],
		bx: &[T],
		stack: &mut [I],
	) -> usize {
/// computes the layout of the workspace required to perform a numeric $LU$
/// factorization
	pub fn factorize_simplicial_numeric_lu_scratch<I: Index, T: ComplexField>(nrows: usize, ncols: usize) -> StackReq {
/// computes the numeric values of the $LU$ factors of the matrix $A$ as well as the row
/// pivoting permutation, and stores them in `lu` and `row_perm`/`row_perm_inv`
	pub fn factorize_simplicial_numeric_lu<I: Index, T: ComplexField>(
		row_perm: &mut [I],
		row_perm_inv: &mut [I],
		lu: &mut SimplicialLu<I, T>,

		A: SparseColMatRef<'_, I, T>,
		col_perm: PermRef<'_, I>,
		stack: &mut MemStack,
	) -> Result<(), LuError> {
/// tuning parameters for the $LU$ symbolic factorization
/// parameters for the fill reducing column permutation
/// threshold for selecting the supernodal factorization
/// supernodal factorization parameters
/// the inner factorization used for the symbolic $LU$, either simplicial or symbolic
/// simplicial structure
/// number of rows of $A$
/// number of columns of $A$
/// supernodal structure
/// the symbolic structure of a sparse $LU$ decomposition
/// structure that contains the numerical values and row pivoting permutation of the lu
/// decomposition
	fn default() -> Self {
/// creates a new $LU$ of a $0\times 0$ matrix
	pub fn new() -> Self {
/// sparse $LU$ factorization wrapper
	fn clone(&self) -> Self {
/// creates $LU$ factors from their components
///
/// # safety
/// the numeric part must be the output of [`SymbolicLu::factorize_numeric_lu`], called with a
/// matrix having the same symbolic structure as the one used to create `symbolic`
	pub unsafe fn new_unchecked(symbolic: &'a SymbolicLu<I>, numeric: &'a NumericLu<I, T>) -> Self {
/// returns the symbolic structure of the $LU$ factorization
	pub fn symbolic(self) -> &'a SymbolicLu<I> {
/// returns the row pivoting permutation
	pub fn row_perm(self) -> PermRef<'a, I> {
/// returns the fill reducing column permutation
	pub fn col_perm(self) -> PermRef<'a, I> {
/// solves the equation $A x = \text{rhs}$ and stores the result in `rhs`, implicitly
/// conjugating $A$ if needed
///
/// # panics
/// - panics if `self.nrows() != self.ncols()`
/// - panics if `rhs.nrows() != self.nrows()`
	pub fn solve_in_place_with_conj(self, conj: Conj, rhs: MatMut<'_, T>, par: Par, stack: &mut MemStack)
	where
		T: ComplexField,
	{
/// solves the equation $A^\top x = \text{rhs}$ and stores the result in `rhs`,
/// implicitly conjugating $A$ if needed
///
/// # panics
/// - panics if `self.nrows() != self.ncols()`
/// - panics if `rhs.nrows() != self.nrows()`
	pub fn solve_transpose_in_place_with_conj(self, conj: Conj, rhs: MatMut<'_, T>, par: Par, stack: &mut MemStack)
	where
		T: ComplexField,
	{
/// returns the number of rows of $A$
	pub fn nrows(&self) -> usize {
/// returns the number of columns of $A$
	pub fn ncols(&self) -> usize {
/// returns the fill-reducing column permutation that was computed during symbolic analysis
	pub fn col_perm(&self) -> PermRef<'_, I> {
/// computes the layout of the workspace required to compute the numerical $LU$
/// factorization
	pub fn factorize_numeric_lu_scratch<T>(&self, par: Par, params: Spec<PartialPivLuParams, T>) -> StackReq
	where
		T: ComplexField,
	{
/// computes the layout of the workspace required to solve the equation $A x = b$
	pub fn solve_in_place_scratch<T>(&self, rhs_ncols: usize, par: Par) -> StackReq
	where
		T: ComplexField,
	{
/// computes the layout of the workspace required to solve the equation
/// $A^\top x = b$
	pub fn solve_transpose_in_place_scratch<T>(&self, rhs_ncols: usize, par: Par) -> StackReq
	where
		T: ComplexField,
	{
/// computes a numerical $LU$ factorization of $A$
	pub fn factorize_numeric_lu<'out, T: ComplexField>(
		&'out self,
		numeric: &'out mut NumericLu<I, T>,
		A: SparseColMatRef<'_, I, T>,
		par: Par,
		stack: &mut MemStack,
		params: Spec<PartialPivLuParams, T>,
	) -> Result<LuRef<'out, I, T>, LuError> {
/// computes the symbolic $LU$ factorization of the matrix $A$, or returns an error if the
/// operation could not be completed
pub fn factorize_symbolic_lu<I: Index>(A: SymbolicSparseColMatRef<'_, I>, params: LuSymbolicParams<'_>) -> Result<SymbolicLu<I>, FaerError> {
// new_col_ptr
// new_row_idx
	fn test_numeric_lu_multifrontal() {
	fn test_numeric_lu_simplicial() {
	fn test_solver_lu_simplicial() {
/// info about the matrix multiplication operation to help split the workload between multiple
/// threads
/// performs a symbolic matrix multiplication of a sparse matrix `lhs` by a sparse matrix `rhs`,
/// and returns the result.
///
/// # note
/// allows unsorted matrices, and produces a sorted output.
pub fn sparse_sparse_matmul_symbolic<I: Index>(
	lhs: SymbolicSparseColMatRef<'_, I>,
	rhs: SymbolicSparseColMatRef<'_, I>,
) -> Result<(SymbolicSparseColMat<I>, SparseMatMulInfo), FaerError> {
/// computes the layout of the workspace required to perform the numeric matrix
/// multiplication into `dst`.
pub fn sparse_sparse_matmul_numeric_scratch<I: Index, T: ComplexField>(dst: SymbolicSparseColMatRef<'_, I>, par: Par) -> StackReq {
/// performs a numeric matrix multiplication of a sparse matrix `lhs` by a sparse matrix `rhs`
/// multiplied by `alpha`, and stores or adds the result to `dst`.
///
/// # note
/// `lhs` and `rhs` are allowed to be unsorted matrices.
pub fn sparse_sparse_matmul_numeric<I: Index, T: ComplexField, LhsT: Conjugate<Canonical = T>, RhsT: Conjugate<Canonical = T>>(
	dst: SparseColMatMut<'_, I, T>,
	beta: Accum,
	lhs: SparseColMatRef<'_, I, LhsT>,
	rhs: SparseColMatRef<'_, I, RhsT>,
	alpha: T,
	info: &SparseMatMulInfo,
	par: Par,
	stack: &mut MemStack,
) {
		fn partition_fn(total_flop_count: f64, nthreads: usize, tid: usize) -> impl FnMut(&f64) -> bool {
// SAFETY: UnsafeCell<[T]> ~ [T] ~ [UnsafeCell<T>]
// SAFETY: UnsafeCell<[T]> ~ [T] ~ [UnsafeCell<T>]
// and only thread `tid` has access to the range of column `j`
// since `col_start..col_end` denote disjoint ranges for each `tid`
/// performs a numeric matrix multiplication of a sparse matrix `lhs` by a sparse matrix `rhs`
/// multiplied by `alpha`, and returns the result.
///
/// # note
/// `lhs` and `rhs` are allowed to be unsorted matrices.
pub fn sparse_sparse_matmul<I: Index, T: ComplexField, LhsT: Conjugate<Canonical = T>, RhsT: Conjugate<Canonical = T>>(
	lhs: SparseColMatRef<'_, I, LhsT>,
	rhs: SparseColMatRef<'_, I, RhsT>,
	alpha: T,
	par: Par,
) -> Result<SparseColMat<I, T>, FaerError> {
/// multiplies a sparse matrix `lhs` by a dense matrix `rhs`, and stores or adds the result to
/// `dst`. see [`faer::linalg::matmul::matmul`](crate::linalg::matmul::matmul) for more details.
///
/// # note
/// allows unsorted matrices.
pub fn sparse_dense_matmul<I: Index, T: ComplexField, LhsT: Conjugate<Canonical = T>, RhsT: Conjugate<Canonical = T>>(
	dst: MatMut<'_, T>,
	beta: Accum,
	lhs: SparseColMatRef<'_, I, LhsT>,
	rhs: MatRef<'_, RhsT>,
	alpha: T,
	par: Par,
) {
// TODO: parallelize this
/// multiplies a dense matrix `lhs` by a sparse matrix `rhs`, and stores or adds the result to
/// `dst`. see [`faer::linalg::matmul::matmul`](crate::linalg::matmul::matmul) for more details.
///
/// # note
/// allows unsorted matrices.
pub fn dense_sparse_matmul<I: Index, T: ComplexField, LhsT: Conjugate<Canonical = T>, RhsT: Conjugate<Canonical = T>>(
	dst: MatMut<'_, T>,
	beta: Accum,
	lhs: MatRef<'_, LhsT>,
	rhs: SparseColMatRef<'_, I, RhsT>,
	alpha: T,
	par: Par,
) {
// TODO: parallelize this
	fn test_sp_matmul() {
//
//
//
//
//
//
//
//
/// tuning parameters for the supernodal factorizations
/// supernode relaxation thresholds
///
/// let `n` be the total number of columns in two adjacent supernodes.
/// let `z` be the fraction of zero entries in the two supernodes if they
/// are merged (z includes zero entries from prior amalgamations). the
/// two supernodes are merged if:
///
/// `(n <= relax[0].0 && z < relax[0].1) || (n <= relax[1].0 && z < relax[1].1) || ...`
	fn default() -> Self {
/// nonnegative threshold controlling when the supernodal factorization is used
///
/// increasing it makes it more likely for the simplicial factorization to be used,
/// while decreasing it makes it more likely for the supernodal factorization to be used
///
/// `1.0` is the default value
	fn default() -> Self {
/// determine automatically which variant to select
/// simplicial factorization is always selected
/// supernodal factorization is always selected
/// sparse $ll^\top$ error
/// numerical error
/// non algorithmic error
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
	fn from(value: linalg::cholesky::llt::factor::LltError) -> Self {
/// sparse $lu$ error.
/// rank deficient symbolic structure
/// iteration at which a pivot could not be found
/// non algorithmic error
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
	fn from(value: T) -> Self {
	fn from(value: T) -> Self {
/// sparse matrix multiplication
/// sparse matrix triangular solve
/// high-level sparse matrix solvers
	pub fn fill_zero<'n, 'a, I: Index>(slice: &'a mut [I], size: Dim<'n>) -> &'a mut [Idx<'n, I>] {
	pub fn fill_none<'n, 'a, I: Index>(slice: &'a mut [I::Signed], size: Dim<'n>) -> &'a mut [MaybeIdx<'n, I>] {
	pub fn copy_slice<'n, 'a, I: Index>(dst: &'a mut [I], src: &[Idx<'n, I>]) -> &'a mut [Idx<'n, I>] {
//! computes the $QR$ decomposition of a given sparse matrix. see [`crate::linalg::qr`] for more
//! info
//!
//! the entry point in this module is [`SymbolicQr`] and [`factorize_symbolic_qr`]
//!
//! # note
//! the functions in this module accept unsorted inputs, and may produce unsorted decomposition
//! factors.
pub(crate) fn ghost_col_etree<'n, I: Index>(
	A: SymbolicSparseColMatRef<'_, I, Dim<'_>, Dim<'n>>,
	col_perm: Option<PermRef<'_, I, Dim<'n>>>,
	etree: &mut Array<'n, I::Signed>,
	stack: &mut MemStack,
) {
/// computes the layout of the workspace required to compute the column elimination tree
/// of a matrix $A$ with dimensions `(nrows, ncols)`
pub fn col_etree_scratch<I: Index>(nrows: usize, ncols: usize) -> StackReq {
/// computes the column elimination tree of $A$, which is the same as the elimination tree of
/// $A^\top A$
///
/// `etree` has length `A.ncols()`
pub fn col_etree<'out, I: Index>(
	A: SymbolicSparseColMatRef<'_, I>,
	col_perm: Option<PermRef<'_, I>>,
	etree: &'out mut [I],
	stack: &mut MemStack,
) -> EliminationTreeRef<'out, I> {
pub(crate) fn ghost_least_common_ancestor<'n, I: Index>(
	i: Idx<'n, usize>,
	j: Idx<'n, usize>,
	first: &Array<'n, MaybeIdx<'n, I>>,
	max_first: &mut Array<'n, MaybeIdx<'n, I>>,
	prev_leaf: &mut Array<'n, MaybeIdx<'n, I>>,
	ancestor: &mut Array<'n, Idx<'n, I>>,
) -> isize {
pub(crate) fn ghost_column_counts_aat<'m, 'n, I: Index>(
	col_counts: &mut Array<'m, I>,
	min_row: &mut Array<'n, I::Signed>,
	A: SymbolicSparseColMatRef<'_, I, Dim<'m>, Dim<'n>>,
	row_perm: Option<PermRef<'_, I, Dim<'m>>>,
	etree: &Array<'m, MaybeIdx<'m, I>>,
	post: &Array<'m, Idx<'m, I>>,
	stack: &mut MemStack,
) {
/// computes the layout of the workspace required to compute the column counts
/// of the cholesky factor of the matrix $A A^\top$, where $A$ has dimensions `(nrows, ncols)`
pub fn column_counts_aat_scratch<I: Index>(nrows: usize, ncols: usize) -> StackReq {
/// computes the column counts of the cholesky factor of $A^\top A$
///
/// - `col_counts` has length `A.ncols()`
/// - `min_col` has length `A.nrows()`
/// - `col_perm` has length `A.ncols()`: fill reducing permutation
/// - `etree` has length `A.ncols()`: column elimination tree of $A A^\top$
/// - `post` has length `A.ncols()`: postordering of `etree`
///
/// # warning
/// the function takes as input `A.transpose()`, not `A`
pub fn column_counts_ata<'m, 'n, I: Index>(
	col_counts: &mut [I],
	min_col: &mut [I],
	AT: SymbolicSparseColMatRef<'_, I>,
	col_perm: Option<PermRef<'_, I>>,
	etree: EliminationTreeRef<'_, I>,
	post: &[I],
	stack: &mut MemStack,
) {
/// computes the layout of the workspace required to compute the postordering of an
/// elimination tree of size `n`
pub fn postorder_scratch<I: Index>(n: usize) -> StackReq {
/// computes a postordering of the elimination tree of size `n`
pub fn postorder<I: Index>(post: &mut [I], etree: EliminationTreeRef<'_, I>, stack: &mut MemStack) {
/// supernodal factorization module
///
/// a supernodal factorization is one that processes the elements of the $QR$ factors of the
/// input matrix by blocks, rather than by single elements. this is more efficient if the $QR$
/// factors are somewhat dense
/// symbolic structure of the householder reflections that compose $Q$
///
/// such that:
/// $$ Q = (i - H_1 t_1^{-1} H_1^H) \cdot (i - H_2 t_2^{-1} H_2^H) \dots (i - H_k t_k^{-1}
/// H_k^H)$$
/// returns the number of rows of the householder factors
		pub fn nrows(&self) -> usize {
/// returns the number of supernodes in the symbolic $QR$
		pub fn n_supernodes(&self) -> usize {
/// returns the column pointers for the numerical values of the householder factors
		pub fn col_ptr_for_householder_val(&self) -> &[I] {
/// returns the column pointers for the numerical values of the $t$ factors
		pub fn col_ptr_for_tau_val(&self) -> &[I] {
/// returns the column pointers for the row indices of the householder factors
		pub fn col_ptr_for_householder_row_idx(&self) -> &[I] {
/// returns the length of the slice that can be used to contain the numerical values of the
/// householder factors
		pub fn len_householder_val(&self) -> usize {
/// returns the length of the slice that can be used to contain the row indices of the
/// householder factors
		pub fn len_householder_row_idx(&self) -> usize {
/// returns the length of the slice that can be used to contain the numerical values of the
/// $t$ factors
		pub fn len_tau_val(&self) -> usize {
/// symbolic structure of the $QR$ decomposition,
/// returns the symbolic structure of $R^H$
		pub fn R_adjoint(&self) -> &SymbolicSupernodalCholesky<I> {
/// returns the symbolic structure of the householder and $t$ factors
		pub fn householder(&self) -> &SymbolicSupernodalHouseholder<I> {
/// computes the layout of the workspace required to solve the linear system
/// $A x = \text{rhs}$ in the sense of least squares
		pub fn solve_in_place_scratch<T: ComplexField>(&self, rhs_ncols: usize, par: Par) -> StackReq {
/// computes the layout of the workspace required to compute the symbolic $QR$
/// factorization of a matrix with dimensions `(nrows, ncols)`
	pub fn factorize_supernodal_symbolic_qr_scratch<I: Index>(nrows: usize, ncols: usize) -> StackReq {
/// computes the symbolic $QR$ factorization of a matrix $A$, given a fill-reducing column
/// permutation, and the outputs of the pre-factorization steps
	pub fn factorize_supernodal_symbolic_qr<I: Index>(
		A: SymbolicSparseColMatRef<'_, I>,
		col_perm: Option<PermRef<'_, I>>,
		min_col: alloc::vec::Vec<I>,
		etree: EliminationTreeRef<'_, I>,
		col_counts: &[I],
		stack: &mut MemStack,
		params: SymbolicSupernodalParams<'_>,
	) -> Result<SymbolicSupernodalQr<I>, FaerError> {
	fn ghost_factorize_supernodal_householder_symbolic<'m, 'n, I: Index>(
		L_symbolic: &SymbolicSupernodalCholesky<I>,
		M: Dim<'m>,
		N: Dim<'n>,
		min_col: &Array<'m, MaybeIdx<'n, I>>,
		etree: &Array<'n, MaybeIdx<'n, I>>,
		stack: &mut MemStack,
	) -> Result<SymbolicSupernodalHouseholder<I>, FaerError> {
/// $QR$ factors containing both the symbolic and numeric representations
		fn clone(&self) -> Self {
/// creates $QR$ factors from their components
///
/// # safety
/// the inputs must be the outputs of [`factorize_supernodal_numeric_qr`]
		pub unsafe fn new_unchecked(
			symbolic: &'a SymbolicSupernodalQr<I>,
			householder_row_idx: &'a [I],
			tau_block_size: &'a [I],
			householder_nrows: &'a [I],
			householder_ncols: &'a [I],
			r_val: &'a [T],
			householder_val: &'a [T],
			tau_val: &'a [T],
		) -> Self {
/// returns the symbolic structure of the $QR$ factorization
		pub fn symbolic(self) -> &'a SymbolicSupernodalQr<I> {
/// returns the numerical values of the factor $R$ of the $QR$ factorization
		pub fn R_val(self) -> &'a [T] {
/// returns the numerical values of the householder factors of the $QR$ factorization
		pub fn householder_val(self) -> &'a [T] {
/// returns the numerical values of the $t$ factors of the $QR$ factorization
		pub fn tau_val(self) -> &'a [T] {
/// Applies $Q^{\top}$ to the rhs in place, implicitly conjugating $Q$ if needed
///
/// `work` is a temporary workspace with the same dimensions as `rhs`
		pub fn apply_Q_transpose_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>, par: Par, work: MatMut<'_, T>, stack: &mut MemStack)
		where
			T: ComplexField,
		{
// x <- Q^T x
/// solves the equation $A x = \text{rhs}$ in the sense of least squares, implicitly
/// conjugating $A$ if needed
///
/// `work` is a temporary workspace with the same dimensions as `rhs`
		pub fn solve_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>, par: Par, work: MatMut<'_, T>, stack: &mut MemStack)
		where
			T: ComplexField,
		{
// x <- R^-1 x = L^-T x
/// computes the layout of the workspace required to compute the numerical $QR$
/// factorization of the matrix whose structure was used to produce the symbolic structure
	pub fn factorize_supernodal_numeric_qr_scratch<I: Index, T: ComplexField>(
		symbolic: &SymbolicSupernodalQr<I>,
		par: Par,
		params: Spec<QrParams, T>,
	) -> StackReq {
/// computes the numerical $QR$ factorization of $A$
///
/// - `householder_row_idx` must have length `symbolic.householder().len_householder_row_idx()`
/// - `tau_block_size` must have length `symbolic.householder().len_householder_row_idx() +
///   symbolic.householder().n_supernodes()`
/// - `householder_nrows` must have length `symbolic.householder().len_householder_row_idx()
///   + symbolic.householder().n_supernodes()`
/// - `householder_ncols` must have length `symbolic.householder().len_householder_row_idx()
///   + symbolic.householder().n_supernodes()`
/// - `r_val` must have length `symbolic.R_adjoint().len_val()`
/// - `householder_val` must have length `symbolic.householder().length_householder_val()`.
/// - `tau_val` must have length `symbolic.householder().len_tau_val()`
///
/// # warning
/// - note that the matrix takes as input `A.transpose()`, not `A`
	pub fn factorize_supernodal_numeric_qr<'a, I: Index, T: ComplexField>(
		householder_row_idx: &'a mut [I],
		tau_block_size: &'a mut [I],
		householder_nrows: &'a mut [I],
		householder_ncols: &'a mut [I],

		r_val: &'a mut [T],
		householder_val: &'a mut [T],
		tau_val: &'a mut [T],

		AT: SparseColMatRef<'_, I, T>,
		col_perm: Option<PermRef<'_, I>>,
		symbolic: &'a SymbolicSupernodalQr<I>,
		par: Par,
		stack: &mut MemStack,
		params: Spec<QrParams, T>,
	) -> SupernodalQrRef<'a, I, T> {
	pub(crate) fn factorize_supernodal_numeric_qr_impl<I: Index, T: ComplexField>(
		// len: col_ptr_for_row_idx[n_supernodes]
		householder_row_idx: &mut [I],

		tau_block_size: &mut [I],
		householder_nrows: &mut [I],
		householder_ncols: &mut [I],

		L_val: &mut [T],
		householder_val: &mut [T],
		tau_val: &mut [T],

		AT: SparseColMatRef<'_, I, T>,
		col_perm: Option<PermRef<'_, I>>,
		L_symbolic: &SymbolicSupernodalCholesky<I>,
		H_symbolic: &SymbolicSupernodalHouseholder<I>,
		min_col: &[I],
		min_col_perm: &[I],
		index_to_super: &[I],
		child_head: &[I::Signed],
		child_next: &[I::Signed],

		par: Par,
		stack: &mut MemStack,
		params: Spec<QrParams, T>,
	) -> usize {
// assemble the parts from child supernodes
// all child nodes should be fully assembled
/// simplicial factorization module
///
/// a simplicial factorization is one that processes the elements of the $QR$ factors of the
/// input matrix by single elements, rather than by blocks. this is more efficient if the $QR$
/// factors are very sparse
/// symbolic structure of the $QR$ decomposition
/// returns the number of rows of the matrix $A$
		pub fn nrows(&self) -> usize {
/// returns the number of columns of the matrix $A$
		pub fn ncols(&self) -> usize {
/// returns the length of the slice that can be used to contain the householder factors
		pub fn len_householder(&self) -> usize {
/// returns the length of the slice that can be used to contain the $R$ factor
		pub fn len_r(&self) -> usize {
/// $QR$ factors containing both the symbolic and numeric representations
		fn clone(&self) -> Self {
/// creates $QR$ factors from their components
		pub fn new(
			symbolic: &'a SymbolicSimplicialQr<I>,
			r: SparseColMatRef<'a, I, T>,
			householder: SparseColMatRef<'a, I, T>,
			tau_val: &'a [T],
		) -> Self {
/// returns the symbolic structure of the $QR$ factorization.
		pub fn symbolic(&self) -> &SymbolicSimplicialQr<I> {
/// returns the numerical values of the factor $R$ of the $QR$ factorization
		pub fn R_val(self) -> &'a [T] {
/// returns the factor $R$
		pub fn R(self) -> SparseColMatRef<'a, I, T> {
/// returns the householder coefficients $H$ in the columns of a sparse matrix
		pub fn householder(self) -> SparseColMatRef<'a, I, T> {
/// returns the numerical values of the householder factors of the $QR$ factorization.
		pub fn householder_val(self) -> &'a [T] {
/// returns the numerical values of the $t$ factors of the $QR$ factorization.
		pub fn tau_val(self) -> &'a [T] {
/// Applies $Q^{\top}$ to the input matrix `rhs`, implicitly conjugating the $Q$
/// matrix if needed
///
/// `work` is a temporary workspace with the same dimensions as `rhs`.
		pub fn apply_qt_in_place_with_conj(&self, conj_qr: Conj, rhs: MatMut<'_, T>, par: Par, work: MatMut<'_, T>)
		where
			T: ComplexField,
		{
// x <- Q^T x
/// solves the equation $A x = \text{rhs}$ in the sense of least squares, implicitly
/// conjugating $A$ if needed
///
/// `work` is a temporary workspace with the same dimensions as `rhs`.
		pub fn solve_in_place_with_conj(&self, conj_qr: Conj, rhs: MatMut<'_, T>, par: Par, work: MatMut<'_, T>)
		where
			T: ComplexField,
		{
/// computes the layout of the workspace required to compute the symbolic $QR$
/// factorization of a matrix with dimensions `(nrows, ncols)`
	pub fn factorize_simplicial_symbolic_qr_scratch<I: Index>(nrows: usize, ncols: usize) -> StackReq {
/// computes the symbolic $QR$ factorization of a matrix $A$, given the outputs of the
/// pre-factorization steps
	pub fn factorize_simplicial_symbolic_qr<I: Index>(
		min_col: &[I],
		etree: EliminationTreeRef<'_, I>,
		col_counts: &[I],
		stack: &mut MemStack,
	) -> Result<SymbolicSimplicialQr<I>, FaerError> {
/// computes the layout of the workspace required to compute the numerical $QR$
/// factorization of the matrix whose structure was used to produce the symbolic structure
	pub fn factorize_simplicial_numeric_qr_scratch<I: Index, T: ComplexField>(symbolic: &SymbolicSimplicialQr<I>) -> StackReq {
/// computes the numerical $QR$ factorization of $A$.
///
/// - `r_col_ptr` has length `a.ncols() + 1`
/// - `r_row_idx` has length `symbolic.len_r()`
/// - `r_val` has length `symbolic.len_r()`
/// - `householder_col_ptr` has length `a.ncols() + 1`
/// - `householder_row_idx` has length `symbolic.len_householder()`
/// - `householder_val` has length `symbolic.len_householder()`
/// - `tau_val` has length `a.ncols()`
	pub fn factorize_simplicial_numeric_qr_unsorted<'a, I: Index, T: ComplexField>(
		r_col_ptr: &'a mut [I],
		r_row_idx: &'a mut [I],
		r_val: &'a mut [T],
		householder_col_ptr: &'a mut [I],
		householder_row_idx: &'a mut [I],
		householder_val: &'a mut [T],
		tau_val: &'a mut [T],

		A: SparseColMatRef<'_, I, T>,
		col_perm: Option<PermRef<'_, I>>,
		symbolic: &'a SymbolicSimplicialQr<I>,
		stack: &mut MemStack,
	) -> SimplicialQrRef<'a, I, T> {
/// tuning parameters for the $QR$ symbolic factorization
/// parameters for the fill reducing column permutation
/// threshold for selecting the supernodal factorization
/// supernodal factorization parameters
/// the inner factorization used for the symbolic $QR$, either simplicial or symbolic
/// simplicial structure
/// supernodal structure
/// the symbolic structure of a sparse $QR$ decomposition
/// sparse $QR$ factorization wrapper
	fn clone(&self) -> Self {
/// creates a $QR$ decomposition reference from its symbolic and numerical components
///
/// # safety
/// the indices must be filled by a previous call to [`SymbolicQr::factorize_numeric_qr`] with
/// the right parameters
	pub unsafe fn new_unchecked(symbolic: &'a SymbolicQr<I>, indices: &'a [I], val: &'a [T]) -> Self {
/// returns the symbolic structure of the $QR$ factorization.
	pub fn symbolic(self) -> &'a SymbolicQr<I> {
/// solves the equation $A x = \text{rhs}$ in the sense of least squares, implicitly conjugating
/// $A$ if needed
///
/// `work` is a temporary workspace with the same dimensions as `rhs`
	pub fn solve_in_place_with_conj(self, conj: Conj, rhs: MatMut<'_, T>, par: Par, stack: &mut MemStack)
	where
		T: ComplexField,
	{
/// number of rows of $A$
	pub fn nrows(&self) -> usize {
/// number of columns of $A$
	pub fn ncols(&self) -> usize {
/// returns the fill-reducing column permutation that was computed during symbolic analysis
	pub fn col_perm(&self) -> PermRef<'_, I> {
/// returns the length of the slice needed to store the symbolic indices of the $QR$
/// decomposition
	pub fn len_idx(&self) -> usize {
/// returns the length of the slice needed to store the numerical values of the $QR$
/// decomposition
	pub fn len_val(&self) -> usize {
/// returns the layout of the workspace required to solve the system $A x =
/// \text{rhs}$ in the sense of least squares
	pub fn solve_in_place_scratch<T>(&self, rhs_ncols: usize, par: Par) -> StackReq
	where
		T: ComplexField,
	{
/// computes the required workspace layout for a numerical $QR$ factorization
	pub fn factorize_numeric_qr_scratch<T>(&self, par: Par, params: Spec<QrParams, T>) -> StackReq
	where
		T: ComplexField,
	{
/// computes a numerical $QR$ factorization of $A$
	pub fn factorize_numeric_qr<'out, T: ComplexField>(
		&'out self,
		indices: &'out mut [I],
		val: &'out mut [T],
		A: SparseColMatRef<'_, I, T>,
		par: Par,
		stack: &mut MemStack,
		params: Spec<QrParams, T>,
	) -> QrRef<'out, I, T> {
/// computes the symbolic $QR$ factorization of the matrix $A$, or returns an error if the
/// operation could not be completed
pub fn factorize_symbolic_qr<I: Index>(A: SymbolicSparseColMatRef<'_, I>, params: QrSymbolicParams<'_>) -> Result<SymbolicQr<I>, FaerError> {
// new_col_ptr
// new_row_idx
	fn test_symbolic_qr() {
// 0
// 1
// 2
// 3
// 4
// 5
// 6
// 7
// 8
// 9
// 10
	fn test_numeric_qr_1_no_transpose() {
	fn test_numeric_qr_1_transpose() {
	fn test_numeric_simplicial_qr_1_transpose() {
	fn test_solver_qr_1_transpose() {
	fn test_solver_qr_edge_case() {
/// assuming `tril` is a lower triangular matrix, solves the equation `tril * x = rhs`, and
/// stores the result in `rhs`, implicitly conjugating `tril` if needed
///
/// # note
/// the matrix indices need not be sorted, but
/// the diagonal element is assumed to be the first stored element in each column.
pub fn solve_lower_triangular_in_place<I: Index, T: ComplexField>(tril: SparseColMatRef<'_, I, T>, conj_tril: Conj, rhs: MatMut<'_, T>, par: Par) {
/// assuming `tril` is a lower triangular matrix, solves the equation `tril * x = rhs`, and
/// stores the result in `rhs`, implicitly conjugating `tril` if needed
///
/// # note
/// the matrix indices need not be sorted, but
/// the diagonal element is assumed to be the first stored element in each column.
pub fn solve_unit_lower_triangular_in_place<I: Index, T: ComplexField>(
	tril: SparseColMatRef<'_, I, T>,
	conj_tril: Conj,
	rhs: MatMut<'_, T>,
	par: Par,
) {
/// assuming `tril` is a lower triangular matrix, solves the equation `tril.transpose() * x =
/// rhs`, and stores the result in `rhs`, implicitly conjugating `tril` if needed
///
/// # note
/// the matrix indices need not be sorted, but
/// the diagonal element is assumed to be the first stored element in each column.
pub fn solve_lower_triangular_transpose_in_place<I: Index, T: ComplexField>(
	tril: SparseColMatRef<'_, I, T>,
	conj_tril: Conj,
	rhs: MatMut<'_, T>,
	par: Par,
) {
/// assuming `tril` is a lower triangular matrix, solves the equation `tril.transpose() * x =
/// rhs`, and stores the result in `rhs`, implicitly conjugating `tril` if needed
///
/// # note
/// the matrix indices need not be sorted, but
/// the diagonal element is assumed to be the first stored element in each column.
pub fn solve_unit_lower_triangular_transpose_in_place<I: Index, T: ComplexField>(
	tril: SparseColMatRef<'_, I, T>,
	conj_tril: Conj,
	rhs: MatMut<'_, T>,
	par: Par,
) {
/// assuming `triu` is an upper triangular matrix, solves the equation `triu * x = rhs`, and
/// stores the result in `rhs`, implicitly conjugating `triu` if needed
///
/// # note
/// the matrix indices need not be sorted, but
/// the diagonal element is assumed to be the last stored element in each column.
pub fn solve_upper_triangular_in_place<I: Index, T: ComplexField>(triu: SparseColMatRef<'_, I, T>, conj_triu: Conj, rhs: MatMut<'_, T>, par: Par) {
/// assuming `triu` is an upper triangular matrix, solves the equation `triu * x = rhs`, and
/// stores the result in `rhs`, implicitly conjugating `triu` if needed
///
/// # note
/// the matrix indices need not be sorted, but
/// the diagonal element is assumed to be the last stored element in each column.
pub fn solve_unit_upper_triangular_in_place<I: Index, T: ComplexField>(
	triu: SparseColMatRef<'_, I, T>,
	conj_triu: Conj,
	rhs: MatMut<'_, T>,
	par: Par,
) {
/// assuming `triu` is an upper triangular matrix, solves the equation `triu.transpose() * x =
/// rhs`, and stores the result in `rhs`, implicitly conjugating `triu` if needed
///
/// # note
/// the matrix indices need not be sorted, but
/// the diagonal element is assumed to be the first stored element in each column.
pub fn solve_upper_triangular_transpose_in_place<I: Index, T: ComplexField>(
	triu: SparseColMatRef<'_, I, T>,
	conj_triu: Conj,
	rhs: MatMut<'_, T>,
	par: Par,
) {
/// assuming `triu` is an upper triangular matrix, solves the equation `triu.transpose() * x =
/// rhs`, and stores the result in `rhs`, implicitly conjugating `triu` if needed
///
/// # note
/// the matrix indices need not be sorted, but
/// the diagonal element is assumed to be the first stored element in each column.
pub fn solve_unit_upper_triangular_transpose_in_place<I: Index, T: ComplexField>(
	triu: SparseColMatRef<'_, I, T>,
	conj_triu: Conj,
	rhs: MatMut<'_, T>,
	par: Par,
) {
fn solve_lower_triangular_in_place_impl<I: Index, T: ComplexField>(
	tril: SparseColMatRef<'_, I, T>,
	conj_tril: Conj,
	diag_tril: DiagStatus,
	rhs: MatMut<'_, T>,
	par: Par,
) {
pub(crate) fn ldlt_scale_solve_unit_lower_triangular_transpose_in_place_impl<I: Index, T: ComplexField>(
	tril: SparseColMatRef<'_, I, T>,
	conj_tril: Conj,
	rhs: MatMut<'_, T>,
	par: Par,
) {
fn solve_lower_triangular_transpose_in_place_impl<I: Index, T: ComplexField>(
	tril: SparseColMatRef<'_, I, T>,
	conj_tril: Conj,
	diag_tril: DiagStatus,
	rhs: MatMut<'_, T>,
	par: Par,
) {
fn solve_upper_triangular_in_place_impl<I: Index, T: ComplexField>(
	triu: SparseColMatRef<'_, I, T>,
	conj_triu: Conj,
	diag_triu: DiagStatus,
	rhs: MatMut<'_, T>,
	par: Par,
) {
fn solve_upper_triangular_transpose_in_place_impl<I: Index, T: ComplexField>(
	triu: SparseColMatRef<'_, I, T>,
	conj_triu: Conj,
	diag_triu: DiagStatus,
	rhs: MatMut<'_, T>,
	par: Par,
) {
//! sparse matrix data structures
//!
//! most sparse matrix algorithms accept matrices in sparse column-oriented format.
//! this format represents each column of the matrix by storing the row indices of its non-zero
//! elements, as well as their values
//!
//! the indices and the values are each stored in a contiguous slice (or group of slices for
//! arbitrary values). in order to specify where each column starts and ends, a slice of size
//! `ncols + 1` stores the start of each column, with the last element being equal to the total
//! number of non-zeros (or the capacity in uncompressed mode)
//!
//! # example
//!
//! consider the 4-by-5 matrix:
//! ```notcode
//! [[10.0, 0.0, 12.0, -1.0, 13.0]
//!  [ 0.0, 0.0, 25.0, -2.0,  0.0]
//!  [ 1.0, 0.0,  0.0,  0.0,  0.0]
//!  [ 4.0, 0.0,  0.0,  0.0,  5.0]]
//! ```
//!
//! the matrix is stored as follows:
//! ```notcode
//! column pointers: | 0                  | 3,3         | 5           | 7           | 9
//!
//! row indices    : |    0 |    2 |    3 |    0 |    1 |    0 |    1 |    0 |    3 |
//! values         : | 10.0 |  1.0 |  4.0 | 12.0 | 25.0 | -1.0 | -2.0 | 13.0 |  5.0 |
//! ```
/// sparse linear algebra module.
/// contains low level routines and the implementation of their corresponding high level wrappers
/// sparse matrix binary and ternary operation implementations
/// pair of indices with `C`-compatible layout
/// row index
/// column index
/// triplet of indices and value with `C`-compatible layout
/// row index
/// column index
/// value
/// creates a new pair of indices
	pub const fn new(row: Row, col: Col) -> Self {
/// creates a new pair of indices and value
	pub const fn new(row: Row, col: Col, val: T) -> Self {
/// errors that can occur in sparse algorithms
/// an index exceeding the maximum value (`I::Signed::MAX` for a given index type `I`)
/// memory allocation failed
	fn from(value: dyn_stack::mem::AllocError) -> Self {
	fn from(value: alloc::collections::TryReserveError) -> Self {
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
/// errors that can occur during the creation of sparse matrices from user input
/// generic error (allocation or index overflow)
/// matrix index out-of-bounds error
/// row of the out-of-bounds index
/// column of the out-of-bounds index
	fn from(value: FaerError) -> Self {
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
pub(crate) fn windows2<I>(slice: &[I]) -> impl DoubleEndedIterator<Item = &[I;
pub(crate) fn try_zeroed<I: bytemuck::Pod>(n: usize) -> Result<alloc::vec::Vec<I>, FaerError> {
pub(crate) fn try_collect<I: IntoIterator>(iter: I) -> Result<alloc::vec::Vec<I::Item>, FaerError> {
/// the order values should be read in, when constructing/filling from indices and values
///
/// allows separately creating the symbolic structure and filling the numerical values
/// algorithmic primitives for sparse matrices
	fn index(&self, (row, col): (usize, usize)) -> &Self::Output {
	fn index(&self, (row, col): (usize, usize)) -> &Self::Output {
	fn index(&self, (row, col): (usize, usize)) -> &Self::Output {
	fn index(&self, (row, col): (usize, usize)) -> &Self::Output {
	fn index_mut(&mut self, (row, col): (usize, usize)) -> &mut Self::Output {
	fn index_mut(&mut self, (row, col): (usize, usize)) -> &mut Self::Output {
	fn index(&self, (row, col): (usize, usize)) -> &Self::Output {
	fn index(&self, (row, col): (usize, usize)) -> &Self::Output {
	fn index_mut(&mut self, (row, col): (usize, usize)) -> &mut Self::Output {
	fn index_mut(&mut self, (row, col): (usize, usize)) -> &mut Self::Output {
	fn test_from_indices() {
	fn test_from_nonnegative_indices() {
	fn test_from_indices_oob_row() {
	fn test_from_indices_oob_col() {
/// returns the resulting matrix obtained by applying `f` to the elements from `lhs` and `rhs`,
/// skipping entries that are unavailable in both of `lhs` and `rhs`.
///
/// # panics
/// panics if `lhs` and `rhs` don't have matching dimensions.  
pub fn binary_op<I: Index, T, LhsT, RhsT>(
	lhs: SparseColMatRef<'_, I, LhsT>,
	rhs: SparseColMatRef<'_, I, RhsT>,
	f: impl FnMut(Option<&LhsT>, Option<&RhsT>) -> T,
) -> Result<SparseColMat<I, T>, FaerError> {
/// returns the resulting matrix obtained by applying `f` to the elements from `dst` and `src`
/// skipping entries that are unavailable in both of them.  
/// the sparsity patter of `dst` is unchanged.
///
/// # panics
/// panics if `src` and `dst` don't have matching dimensions.  
/// panics if `src` contains an index that's unavailable in `dst`.  
pub fn binary_op_assign_into<I: Index, T, SrcT>(
	dst: SparseColMatMut<'_, I, T>,
	src: SparseColMatRef<'_, I, SrcT>,
	f: impl FnMut(&mut T, Option<&SrcT>),
) {
/// returns the resulting matrix obtained by applying `f` to the elements from `dst`, `lhs` and
/// `rhs`, skipping entries that are unavailable in all of `dst`, `lhs` and `rhs`.  
/// the sparsity patter of `dst` is unchanged.
///
/// # panics
/// panics if `lhs`, `rhs` and `dst` don't have matching dimensions.  
/// panics if `lhs` or `rhs` contains an index that's unavailable in `dst`.  
pub fn ternary_op_assign_into<I: Index, T, LhsT, RhsT>(
	dst: SparseColMatMut<'_, I, T>,
	lhs: SparseColMatRef<'_, I, LhsT>,
	rhs: SparseColMatRef<'_, I, RhsT>,
	f: impl FnMut(&mut T, Option<&LhsT>, Option<&RhsT>),
) {
/// returns the sparsity pattern containing the union of those of `lhs` and `rhs`.
///
/// # panics
/// panics if `lhs` and `rhs` don't have matching dimensions.  
pub fn union_symbolic<I: Index>(
	lhs: SymbolicSparseColMatRef<'_, I>,
	rhs: SymbolicSparseColMatRef<'_, I>,
) -> Result<SymbolicSparseColMat<I>, FaerError> {
/// returns the sum of `lhs` and `rhs`.
///
/// # panics
/// panics if `lhs` and `rhs` don't have matching dimensions.  
pub fn add<I: Index, T: ComplexField, LhsT: Conjugate<Canonical = T>, RhsT: Conjugate<Canonical = T>>(
	lhs: SparseColMatRef<'_, I, LhsT>,
	rhs: SparseColMatRef<'_, I, RhsT>,
) -> Result<SparseColMat<I, T>, FaerError> {
/// returns the difference of `lhs` and `rhs`.
///
/// # panics
/// panics if `lhs` and `rhs` don't have matching dimensions.  
pub fn sub<I: Index, T: ComplexField, LhsT: Conjugate<Canonical = T>, RhsT: Conjugate<Canonical = T>>(
	lhs: SparseColMatRef<'_, I, LhsT>,
	rhs: SparseColMatRef<'_, I, RhsT>,
) -> Result<SparseColMat<I, T>, FaerError> {
/// computes the sum of `dst` and `src` and stores the result in `dst` without changing its
/// symbolic structure.
///
/// # panics
/// panics if `dst` and `rhs` don't have matching dimensions.  
/// panics if `rhs` contains an index that's unavailable in `dst`.  
pub fn add_assign<I: Index, T: ComplexField, RhsT: Conjugate<Canonical = T>>(dst: SparseColMatMut<'_, I, T>, rhs: SparseColMatRef<'_, I, RhsT>) {
/// computes the difference of `dst` and `src` and stores the result in `dst` without changing its
/// symbolic structure.
///
/// # panics
/// panics if `dst` and `rhs` don't have matching dimensions.  
/// panics if `rhs` contains an index that's unavailable in `dst`.  
pub fn sub_assign<I: Index, T: ComplexField, RhsT: Conjugate<Canonical = T>>(dst: SparseColMatMut<'_, I, T>, rhs: SparseColMatRef<'_, I, RhsT>) {
/// computes the sum of `lhs` and `rhs`, storing the result in `dst` without changing its
/// symbolic structure.
///
/// # panics
/// panics if `dst`, `lhs` and `rhs` don't have matching dimensions.  
/// panics if `lhs` or `rhs` contains an index that's unavailable in `dst`.  
pub fn add_into<I: Index, T: ComplexField, LhsT: Conjugate<Canonical = T>, RhsT: Conjugate<Canonical = T>>(
	dst: SparseColMatMut<'_, I, T>,
	lhs: SparseColMatRef<'_, I, LhsT>,
	rhs: SparseColMatRef<'_, I, RhsT>,
) {
/// computes the difference of `lhs` and `rhs`, storing the result in `dst` without changing its
/// symbolic structure.
///
/// # panics
/// panics if `dst`, `lhs` and `rhs` don't have matching dimensions.  
/// panics if `lhs` or `rhs` contains an index that's unavailable in `dst`.  
pub fn sub_into<I: Index, T: ComplexField, LhsT: Conjugate<Canonical = T>, RhsT: Conjugate<Canonical = T>>(
	dst: SparseColMatMut<'_, I, T>,
	lhs: SparseColMatRef<'_, I, LhsT>,
	rhs: SparseColMatRef<'_, I, RhsT>,
) {
/// reference-counted sparse symbolic $LL^\top$ factorization
/// sparse $LL^\top$ factorization
/// reference-counted sparse symbolic $QR$ factorization
/// sparse $QR$ factorization
/// reference-counted sparse symbolic $LU$ factorization
/// sparse $QR$ factorization
/// returns the symbolic $LL^\top$ factorization of the input matrix
///
/// only the provided side is accessed
	pub fn try_new(mat: SymbolicSparseColMatRef<'_, I>, side: Side) -> Result<Self, FaerError> {
/// returns the symbolic $QR$ factorization of the input matrix
	pub fn try_new(mat: SymbolicSparseColMatRef<'_, I>) -> Result<Self, FaerError> {
/// returns the symbolic $LU$ factorization of the input matrix
	pub fn try_new(mat: SymbolicSparseColMatRef<'_, I>) -> Result<Self, FaerError> {
/// returns the $LL^\top$ factorization of the input matrix with the same sparsity pattern as
/// the original one used to construct the symbolic factorization
///
/// only the provided side is accessed
	pub fn try_new_with_symbolic(symbolic: SymbolicLlt<I>, mat: SparseColMatRef<'_, I, T>, side: Side) -> Result<Self, LltError> {
/// returns the $LU$ factorization of the input matrix with the same sparsity pattern as the
/// original one used to construct the symbolic factorization
	pub fn try_new_with_symbolic(symbolic: SymbolicLu<I>, mat: SparseColMatRef<'_, I, T>) -> Result<Self, LuError> {
/// returns the $QR$ factorization of the input matrix with the same sparsity pattern as the
/// original one used to construct the symbolic factorization
	pub fn try_new_with_symbolic(symbolic: SymbolicQr<I>, mat: SparseColMatRef<'_, I, T>) -> Result<Self, FaerError> {
	fn nrows(&self) -> usize {
	fn ncols(&self) -> usize {
	fn nrows(&self) -> usize {
	fn ncols(&self) -> usize {
	fn nrows(&self) -> usize {
	fn ncols(&self) -> usize {
	fn solve_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
	fn solve_transpose_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
	fn solve_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
	fn solve_transpose_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
	fn solve_lstsq_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
	fn solve_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
	fn solve_transpose_in_place_with_conj(&self, conj: Conj, rhs: MatMut<'_, T>) {
/// assuming `self` is a lower triangular matrix, solves the equation `self * x = rhs`, and
/// stores the result in `rhs`
///
/// # note
/// the matrix indices need not be sorted, but
/// the diagonal element is assumed to be the first stored element in each column
	pub fn sp_solve_lower_triangular_in_place(&self, mut rhs: impl AsMatMut<T = T, Rows = usize>) {
/// assuming `self` is an upper triangular matrix, solves the equation `self * x = rhs`, and
/// stores the result in `rhs`
///
/// # note
/// the matrix indices need not be sorted, but
/// the diagonal element is assumed to be the last stored element in each column
	pub fn sp_solve_upper_triangular_in_place(&self, mut rhs: impl AsMatMut<T = T, Rows = usize>) {
/// assuming `self` is a unit lower triangular matrix, solves the equation `self * x = rhs`,
/// and stores the result in `rhs`
///
/// # note
/// the matrix indices need not be sorted, but
/// the diagonal element is assumed to be the first stored element in each column
	pub fn sp_solve_unit_lower_triangular_in_place(&self, mut rhs: impl AsMatMut<T = T, Rows = usize>) {
/// assuming `self` is a unit upper triangular matrix, solves the equation `self * x = rhs`,
/// and stores the result in `rhs`
///
/// # note
/// the matrix indices need not be sorted, but
/// the diagonal element is assumed to be the last stored element in each column
	pub fn sp_solve_unit_upper_triangular_in_place(&self, mut rhs: impl AsMatMut<T = T, Rows = usize>) {
/// returns the $LL^\top$ decomposition of `self`. only the provided side is accessed
	pub fn sp_cholesky(&self, side: Side) -> Result<Llt<I, T>, LltError> {
/// returns the $LU$ decomposition of `self` with partial (row) pivoting
	pub fn sp_lu(&self) -> Result<Lu<I, T>, LuError> {
/// returns the $QR$ decomposition of `self`
	pub fn sp_qr(&self) -> Result<Qr<I, T>, FaerError> {
/// assuming `self` is an upper triangular matrix, solves the equation `self * x = rhs`, and
/// stores the result in `rhs`
///
/// # note
/// the matrix indices need not be sorted, but
/// the diagonal element is assumed to be the last stored element in each row
	pub fn sp_solve_lower_triangular_in_place(&self, mut rhs: impl AsMatMut<T = T, Rows = usize>) {
/// assuming `self` is an upper triangular matrix, solves the equation `self * x = rhs`, and
/// stores the result in `rhs`
///
/// # note
/// the matrix indices need not be sorted, but
/// the diagonal element is assumed to be the first stored element in each row
	pub fn sp_solve_upper_triangular_in_place(&self, mut rhs: impl AsMatMut<T = T, Rows = usize>) {
/// assuming `self` is a unit lower triangular matrix, solves the equation `self * x = rhs`,
/// and stores the result in `rhs`
///
/// # note
/// the matrix indices need not be sorted, but
/// the diagonal element is assumed to be the last stored element in each row
	pub fn sp_solve_unit_lower_triangular_in_place(&self, mut rhs: impl AsMatMut<T = T, Rows = usize>) {
/// assuming `self` is a unit upper triangular matrix, solves the equation `self * x = rhs`,
/// and stores the result in `rhs`
///
/// # note
/// the matrix indices need not be sorted, but
/// the diagonal element is assumed to be the first stored element in each row
	pub fn sp_solve_unit_upper_triangular_in_place(&self, mut rhs: impl AsMatMut<T = T, Rows = usize>) {
/// returns the $LL^\top$ decomposition of `self`. only the provided side is accessed
	pub fn sp_cholesky(&self, side: Side) -> Result<Llt<I, T>, LltError> {
/// returns the $LU$ decomposition of `self` with partial (row) pivoting
	pub fn sp_lu(&self) -> Result<Lu<I, T>, LuError> {
/// returns the $QR$ decomposition of `self`
	pub fn sp_qr(&self) -> Result<Qr<I, T>, FaerError> {
/// sorts `row_indices` and `values` simultaneously so that `row_indices` is nonincreasing.
pub fn sort_indices<I: Index, T>(col_ptr: &[I], col_nnz: Option<&[I]>, row_idx: &mut [I], val: &mut [T]) {
/// sorts and deduplicates `row_indices` and `values` simultaneously so that `row_indices` is
/// nonincreasing and contains no duplicate indices.
pub fn sort_dedup_indices<I: Index, T: ComplexField>(col_ptr: &[I], col_nnz: &mut [I], row_idx: &mut [I], val: &mut [T]) {
/// computes the workspace layout required to apply a two sided permutation to a
/// self-adjoint sparse matrix
pub fn permute_self_adjoint_scratch<I: Index>(dim: usize) -> StackReq {
/// computes the workspace layout required to apply a two sided permutation to a
/// self-adjoint sparse matrix and deduplicate its elements
pub fn permute_dedup_self_adjoint_scratch<I: Index>(dim: usize) -> StackReq {
/// computes the self-adjoint permutation $P A P^\top$ of the matrix $A$
///
/// the result is stored in `new_col_ptrs`, `new_row_indices`
///
/// # note
/// allows unsorted matrices, producing a sorted output. duplicate entries are kept, however
pub fn permute_self_adjoint<'out, N: Shape, I: Index, T: ComplexField, C: Conjugate<Canonical = T>>(
	new_val: &'out mut [T],
	new_col_ptr: &'out mut [I],
	new_row_idx: &'out mut [I],
	A: SparseColMatRef<'_, I, C, N, N>,
	perm: PermRef<'_, I, N>,
	in_side: Side,
	out_side: Side,
	stack: &mut MemStack,
) -> SparseColMatMut<'out, I, T, N, N> {
/// computes the self-adjoint permutation $P A P^\top$ of the matrix $A$ without sorting the row
/// indices, and returns a view over it
///
/// the result is stored in `new_col_ptrs`, `new_row_indices`
///
/// # note
/// allows unsorted matrices, producing an sorted output
pub fn permute_self_adjoint_to_unsorted<'out, N: Shape, I: Index, T: ComplexField, C: Conjugate<Canonical = T>>(
	new_val: &'out mut [T],
	new_col_ptr: &'out mut [I],
	new_row_idx: &'out mut [I],
	A: SparseColMatRef<'_, I, C, N, N>,
	perm: PermRef<'_, I, N>,
	in_side: Side,
	out_side: Side,
	stack: &mut MemStack,
) -> SparseColMatMut<'out, I, T, N, N> {
/// computes the self-adjoint permutation $P A P^\top$ of the matrix $A$ and deduplicate the
/// elements of the output matrix
///
/// the result is stored in `new_col_ptrs`, `new_row_indices`
///
/// # note
/// allows unsorted matrices, producing a sorted output. duplicate entries are merged
pub fn permute_dedup_self_adjoint<'out, N: Shape, I: Index, T: ComplexField, C: Conjugate<Canonical = T>>(
	new_val: &'out mut [T],
	new_col_ptr: &'out mut [I],
	new_row_idx: &'out mut [I],
	A: SparseColMatRef<'_, I, C, N, N>,
	perm: PermRef<'_, I, N>,
	in_side: Side,
	out_side: Side,
	stack: &mut MemStack,
) -> SparseColMatMut<'out, I, T, N, N> {
fn permute_self_adjoint_imp<'N, 'out, I: Index, T: ComplexField>(
	new_val: &'out mut [T],
	new_col_ptr: &'out mut [I],
	new_row_idx: &'out mut [I],
	A: SparseColMatRef<'_, I, T, Dim<'N>, Dim<'N>>,
	conj_A: Conj,
	perm: PermRef<'_, I, Dim<'N>>,
	in_side: Side,
	out_side: Side,
	sort: bool,
	stack: &mut MemStack,
) -> SparseColMatMut<'out, I, T, Dim<'N>, Dim<'N>> {
// old_i <= old_j => -old_i >= -old_j
// reverse the order with bitwise not
// x + !x == MAX
// x + !x + 1 == 0
// !x = -1 - x
// if we flipped the side of A, then we need to check old_i <= old_j instead
// in_side/out_side are assumed Side::Lower
// cannot overflow because A.compute_nnz() <= I::Signed::MAX
// col_counts[new_j] always >= 0
// col_counts[_] >= 0
// cumulative sum cannot overflow because it's <= A.compute_nnz()
// new_col_ptr is non-decreasing
// SAFETY: cur_row_pos < NNZ
// SAFETY:
// 0. new_col_ptr is non-decreasing
// 1. all written row indices are less than n
fn permute_dedup_self_adjoint_imp<'N, 'out, I: Index, T: ComplexField>(
	new_val: &'out mut [T],
	new_col_ptr: &'out mut [I],
	new_row_idx: &'out mut [I],
	A: SparseColMatRef<'_, I, T, Dim<'N>, Dim<'N>>,
	conj_A: Conj,
	perm: PermRef<'_, I, Dim<'N>>,
	in_side: Side,
	out_side: Side,
	stack: &mut MemStack,
) -> SparseColMatMut<'out, I, T, Dim<'N>, Dim<'N>> {
// same element, add
// new element, copy
/// computes the workspace layout required to transpose a matrix
pub fn transpose_scratch<I: Index>(nrows: usize, ncols: usize) -> StackReq {
/// computes the workspace layout required to transpose a matrix and deduplicate the
/// output elements
pub fn transpose_dedup_scratch<I: Index>(nrows: usize, ncols: usize) -> StackReq {
/// computes the transpose of the matrix $A$ and returns a view over it.
///
/// the result is stored in `new_col_ptrs`, `new_row_indices` and `new_values`.
///
/// # note
/// allows unsorted matrices, producing a sorted output. duplicate entries are kept, however
pub fn transpose<'out, Rows: Shape, Cols: Shape, I: Index, T: Clone>(
	new_val: &'out mut [T],
	new_col_ptr: &'out mut [I],
	new_row_idx: &'out mut [I],
	A: SparseColMatRef<'_, I, T, Rows, Cols>,
	stack: &mut MemStack,
) -> SparseColMatMut<'out, I, T, Cols, Rows> {
/// computes the adjoint of the matrix $A$ and returns a view over it.
///
/// the result is stored in `new_col_ptrs`, `new_row_indices` and `new_values`.
///
/// # note
/// allows unsorted matrices, producing a sorted output. duplicate entries are kept, however
pub fn adjoint<'out, Rows: Shape, Cols: Shape, I: Index, T: ComplexField>(
	new_val: &'out mut [T],
	new_col_ptr: &'out mut [I],
	new_row_idx: &'out mut [I],
	A: SparseColMatRef<'_, I, T, Rows, Cols>,
	stack: &mut MemStack,
) -> SparseColMatMut<'out, I, T, Cols, Rows> {
/// computes the transpose of the matrix $A$ and returns a view over it.
///
/// the result is stored in `new_col_ptrs`, `new_row_indices` and `new_values`.
///
/// # note
/// allows unsorted matrices, producing a sorted output. duplicate entries are merged
pub fn transpose_dedup<'out, Rows: Shape, Cols: Shape, I: Index, T: ComplexField, C: Conjugate<Canonical = T>>(
	new_val: &'out mut [T],
	new_col_ptr: &'out mut [I],
	new_row_idx: &'out mut [I],
	A: SparseColMatRef<'_, I, C, Rows, Cols>,
	stack: &mut MemStack,
) -> SparseColMatMut<'out, I, T, Cols, Rows> {
fn transpose_imp<'ROWS, 'COLS, 'out, I: Index, T>(
	clone: impl Fn(&T) -> T,
	new_val: &'out mut [T],
	new_col_ptr: &'out mut [I],
	new_row_idx: &'out mut [I],
	A: SparseColMatRef<'_, I, T, Dim<'ROWS>, Dim<'COLS>>,
	stack: &mut MemStack,
) -> SparseColMatMut<'out, I, T, Dim<'COLS>, Dim<'ROWS>> {
// can't overflow because the total count is A.compute_nnz() <= I::Signed::MAX
// col_count elements are >= 0
// new_col_ptr is non-decreasing
// *cj = cur_row_pos
// SAFETY: see below
// cur_row_pos[i] == col_ptr[i] + col_count[i] == col_ptr[i + 1] <= col_ptr[m]
// so all the unchecked accesses were valid and non-overlapping, which means the entire array is
// filled.
// SAFETY:
// 0. new_col_ptr is non-decreasing
// 1. all written row indices are less than n
fn transpose_dedup_imp<'ROWS, 'COLS, 'out, I: Index, T: ComplexField, C: Conjugate<Canonical = T>>(
	new_val: &'out mut [T],
	new_col_ptr: &'out mut [I],
	new_row_idx: &'out mut [I],
	A: SparseColMatRef<'_, I, C, Dim<'ROWS>, Dim<'COLS>>,
	stack: &mut MemStack,
) -> SparseColMatMut<'out, I, T, Dim<'COLS>, Dim<'ROWS>> {
// can't overflow because the total count is A.compute_nnz() <= I::Signed::MAX
// col_count elements are >= 0
// new_col_ptr is non-decreasing
// *cj = cur_row_pos
// SAFETY: see below
// cur_row_pos[i] == col_ptr[i] + col_count[i] == col_ptr[i + 1] <= col_ptr[m]
// so all the unchecked accesses were valid and non-overlapping, which means the entire array is
// filled.
// SAFETY:
// 0. new_col_ptr is non-decreasing
// 1. all written row indices are less than n
	fn test_transpose() {
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
	fn test_permute_self_adjoint() {
//
//
//
//
//
//
//
//
//
/// Specifies how missing values should be handled in mean and variance computations.
/// NaNs are passed as-is to arithmetic operators.
/// NaNs are skipped, and they're not included in the total count of entries.
fn from_usize<T: RealField>(n: usize) -> T {
fn reduce<T: ComplexField, S: pulp::Simd>(non_nan_count: T::SimdIndex<S>) -> usize {
fn col_mean_row_major_ignore_nan<T: ComplexField>(out: ColMut<'_, T>, mat: MatRef<'_, T, usize, usize, isize, ContiguousFwd>) {
		fn with_simd<S: pulp::Simd>(self, simd: S) -> Self::Output {
				fn process<'M, T: ComplexField, S: pulp::Simd>(
					simd: SimdCtx<'M, T, S>,
					acc: T::SimdVec<S>,
					non_nan_count: T::SimdIndex<S>,
					val: T::SimdVec<S>,
				) -> (T::SimdVec<S>, T::SimdIndex<S>) {
fn col_varm_row_major_ignore_nan<T: ComplexField>(
	out: ColMut<'_, T::Real>,
	mat: MatRef<'_, T, usize, usize, isize, ContiguousFwd>,
	col_mean: ColRef<'_, T>,
) {
		fn with_simd<S: pulp::Simd>(self, simd: S) -> Self::Output {
				fn process<'M, T: ComplexField, S: pulp::Simd>(
					simd: SimdCtx<'M, T, S>,
					mean: T::SimdVec<S>,
					acc: RealReg<T::SimdVec<S>>,
					non_nan_count: T::SimdIndex<S>,
					val: T::SimdVec<S>,
				) -> (RealReg<T::SimdVec<S>>, T::SimdIndex<S>) {
fn col_mean_row_major_propagate_nan<T: ComplexField>(out: ColMut<'_, T>, mat: MatRef<'_, T, usize, usize, isize, ContiguousFwd>) {
		fn with_simd<S: pulp::Simd>(self, simd: S) -> Self::Output {
fn col_varm_row_major_propagate_nan<T: ComplexField>(
	out: ColMut<'_, T::Real>,
	mat: MatRef<'_, T, usize, usize, isize, ContiguousFwd>,
	col_mean: ColRef<'_, T>,
) {
		fn with_simd<S: pulp::Simd>(self, simd: S) -> Self::Output {
fn col_mean_ignore_nan_fallback<T: ComplexField>(out: ColMut<'_, T>, mat: MatRef<'_, T>) {
fn col_varm_ignore_nan_fallback<T: ComplexField>(out: ColMut<'_, T::Real>, mat: MatRef<'_, T>, col_mean: ColRef<'_, T>) {
fn col_mean_propagate_nan_fallback<T: ComplexField>(out: ColMut<'_, T>, mat: MatRef<'_, T>) {
fn col_varm_propagate_nan_fallback<T: ComplexField>(out: ColMut<'_, T::Real>, mat: MatRef<'_, T>, col_mean: ColRef<'_, T>) {
fn col_mean_ignore<T: ComplexField>(out: ColMut<'_, T>, mat: MatRef<'_, T>) {
fn col_varm_ignore<T: ComplexField>(out: ColMut<'_, T::Real>, mat: MatRef<'_, T>, col_mean: ColRef<'_, T>) {
fn col_mean_propagate<T: ComplexField>(out: ColMut<'_, T>, mat: MatRef<'_, T>) {
fn col_varm_propagate<T: ComplexField>(out: ColMut<'_, T::Real>, mat: MatRef<'_, T>, col_mean: ColRef<'_, T>) {
/// computes the mean of the columns of `mat` and stores the result in `out`
pub fn col_mean<T: ComplexField>(out: ColMut<'_, T>, mat: MatRef<'_, T>, nan: NanHandling) {
/// computes the mean of the rows of `mat` and stores the result in `out`
pub fn row_mean<T: ComplexField>(out: RowMut<'_, T>, mat: MatRef<'_, T>, nan: NanHandling) {
/// computes the variance of the columns of `mat` and stores the result in `out`
pub fn col_varm<T: ComplexField>(out: ColMut<'_, T::Real>, mat: MatRef<'_, T>, col_mean: ColRef<'_, T>, nan: NanHandling) {
/// computes the variance of the rows of `mat` and stores the result in `out`
pub fn row_varm<T: ComplexField>(out: RowMut<'_, T::Real>, mat: MatRef<'_, T>, row_mean: RowRef<'_, T>, nan: NanHandling) {
	fn test_meanvar_propagate() {
	fn test_meanvar_ignore_nan_nonan_c32() {
	fn test_meanvar_ignore_nan_yesnan_c32() {
	fn test_meanvar_ignore_nan_nonan_c64() {
	fn test_meanvar_ignore_nan_yesnan_c64() {
/// A generic random value distribution for complex numbers.
/// Creates a complex distribution from independent
/// distributions of the real and imaginary parts.
	pub fn new(re: Re, im: Im) -> Self {
		fn rand<T>(&self, rng: &mut (impl ?Sized + rand::Rng)) -> T
		where
			Self: Distribution<T>,
		{
		fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> Mat<T, Rows, Cols> {
		fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> Col<T, Rows> {
		fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> Row<T, Cols> {
		fn sample<R: rand::prelude::Rng + ?Sized>(&self, rng: &mut R) -> Mat<T> {
		fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Complex<T> {
	pub fn eps() -> Self {
	fn mul(self, rhs: Real<T>) -> Self::Output {
	fn fmt(
		&self,
		cmp: &ApproxEq<R>,
		lhs: &T,
		mut lhs_source: &str,
		lhs_debug: &dyn core::fmt::Debug,
		rhs: &T,
		rhs_source: &str,
		rhs_debug: &dyn core::fmt::Debug,
		f: &mut core::fmt::Formatter,
	) -> core::fmt::Result {
	fn test(&self, lhs: &T, rhs: &T) -> Result<(), Self::Error> {
	fn fmt(
		&self,
		cmp: &CwiseMat<Cmp>,
		lhs: &L,
		lhs_source: &str,
		_: &dyn core::fmt::Debug,
		rhs: &R,
		rhs_source: &str,
		_: &dyn core::fmt::Debug,
		f: &mut core::fmt::Formatter,
	) -> core::fmt::Result {
	fn test(&self, lhs: &L, rhs: &R) -> Result<(), Self::Error> {
/// splits a range into two segments.
/// size of the first half.
/// size of the second half.
/// returns the midpoint of the partition.
	pub const fn midpoint(&self) -> IdxInc<'n> {
/// returns the midpoint of the partition.
	pub const fn flip(&self) -> Partition<'tail, 'head, 'n> {
/// lifetime branded length
/// # safety
/// the type's safety invariant is that all instances of this type with the same lifetime
/// correspond to the same length.
	fn eq(&self, other: &Self) -> bool {
	fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
	fn cmp(&self, other: &Self) -> core::cmp::Ordering {
/// lifetime branded index.
/// # safety
/// the type's safety invariant is that all instances of this type are valid indices for
/// [`Dim<'n>`] and less than or equal to `i::signed::max`.
/// lifetime branded partition index.
/// # safety
/// the type's safety invariant is that all instances of this type are valid partition places
/// for [`Dim<'n>`] and less than or equal to `i::signed::max`.
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
	fn eq(&self, other: &Dim<'n>) -> bool {
	fn partial_cmp(&self, other: &Dim<'n>) -> Option<core::cmp::Ordering> {
	fn eq(&self, other: &Dim<'n>) -> bool {
	fn partial_cmp(&self, other: &Dim<'n>) -> Option<core::cmp::Ordering> {
/// create new branded value with the value `dim`.
	pub fn with<R>(dim: usize, f: impl for<'dim> FnOnce(Dim<'dim>) -> R) -> R {
/// create new branded value with an arbitrary brand.
/// # safety
/// see struct safety invariant.
	pub const unsafe fn new_unbound(dim: usize) -> Self {
/// create new branded value with a unique brand.
	pub fn new(dim: usize, guard: Guard<'n>) -> Self {
/// returns the unconstrained value.
	pub const fn unbound(self) -> usize {
/// partitions `self` into two segments as specifiedd by the midpoint.
	pub const fn partition<'head, 'tail>(self, midpoint: IdxInc<'n>, head: Guard<'head>, tail: Guard<'tail>) -> Partition<'head, 'tail, 'n> {
/// partitions `self` into two segments.
	pub fn head_partition<'head, 'tail>(self, head: Dim<'head>, tail: Guard<'tail>) -> Partition<'head, 'tail, 'n> {
/// returns `start` advanced by `len` units, saturated to `self`
	pub fn advance(self, start: Idx<'n>, len: usize) -> IdxInc<'n> {
/// returns an iterator over the indices between `0` and `self`.
	pub fn indices(self) -> impl Clone + ExactSizeIterator + DoubleEndedIterator<Item = Idx<'n>> {
/// returns an iterator over the indices between `0` and `self`.
	pub fn par_indices(self) -> impl rayon::iter::IndexedParallelIterator<Item = Idx<'n>> {
/// create new branded value with an arbitrary brand.
/// # safety
/// see struct safety invariant.
	pub const unsafe fn new_unbound(idx: I) -> Self {
/// create new branded value with the same brand as `Dim`.
/// # safety
/// the behavior is undefined unless `idx < dim` and `idx <= i::signed::max`.
	pub unsafe fn new_unchecked(idx: I, dim: Dim<'n>) -> Self {
/// create new branded value with the same brand as `Dim`.
/// # panics
/// panics unless `idx < dim` and `idx <= i::signed::max`.
	pub fn new_checked(idx: I, dim: Dim<'n>) -> Self {
/// returns the unconstrained value.
	pub const fn unbound(self) -> I {
/// zero-extends the internal value into a `usize`.
	pub fn zx(self) -> Idx<'n> {
/// zero index
/// create new branded value with an arbitrary brand.
/// # safety
/// see struct safety invariant.
	pub const unsafe fn new_unbound(idx: I) -> Self {
/// create new branded value with the same brand as `Dim`.
/// # safety
/// the behavior is undefined unless `idx <= dim`.
	pub unsafe fn new_unchecked(idx: I, dim: Dim<'n>) -> Self {
/// create new branded value with the same brand as `Dim`.
/// # panics
/// panics unless `idx <= dim`.
	pub fn new_checked(idx: I, dim: Dim<'n>) -> Self {
/// returns the unconstrained value.
	pub const fn unbound(self) -> I {
/// zero-extends the internal value into a `usize`.
	pub fn zx(self) -> IdxInc<'n> {
/// returns an iterator over the indices between `self` and `to`.
	pub fn to(self, upper: IdxInc<'n>) -> impl Clone + ExactSizeIterator + DoubleEndedIterator<Item = Idx<'n>> {
/// returns an iterator over the indices between `self` and `to`.
	pub fn range_to(self, upper: IdxInc<'n>) -> impl Clone + ExactSizeIterator + DoubleEndedIterator<Item = Idx<'n>> {
	unsafe fn new_unbound(idx: usize) -> Self {
	fn unbound(self) -> usize {
	unsafe fn new_unbound(idx: I) -> Self {
	fn unbound(self) -> I {
	unsafe fn new_unbound(idx: I) -> Self {
	fn unbound(self) -> I {
	unsafe fn new_unbound(idx: I::Signed) -> Self {
	fn unbound(self) -> I::Signed {
	fn from(value: Idx<'n, I>) -> Self {
	fn from(value: Dim<'n>) -> Self {
	fn from(value: Idx<'n, I>) -> Self {
/// check that the index is bounded by `self`, or panic otherwise.
	pub fn check<I: Index>(self, idx: I) -> Idx<'size, I> {
/// check that the index is bounded by `self`, or panic otherwise.
	pub fn idx<I: Index>(self, idx: I) -> Idx<'size, I> {
/// check that the index is bounded by `self`, or panic otherwise.
	pub fn idx_inc<I: Index>(self, idx: I) -> IdxInc<'size, I> {
/// check that the index is bounded by `self`, or return `none` otherwise.
	pub fn try_check<I: Index>(self, idx: I) -> Option<Idx<'size, I>> {
/// truncate `self` to a smaller type `i`.
	pub fn truncate<I: Index>(self) -> Idx<'n, I> {
/// returns the index, bounded inclusively by the value tied to `'n`.
	pub const fn to_incl(self) -> IdxInc<'n, I> {
/// returns the next index, bounded inclusively by the value tied to `'n`.
	pub fn next(self) -> IdxInc<'n, I> {
/// returns the index, bounded inclusively by the value tied to `'n`.
	pub fn excl(self) -> IdxInc<'n, I> {
/// assert that the values of `slice` are all bounded by `size`.
	pub fn from_slice_mut_checked<'a>(slice: &'a mut [I], size: Dim<'n>) -> &'a mut [Idx<'n, I>] {
/// assume that the values of `slice` are all bounded by the value tied to `'n`.
	pub unsafe fn from_slice_mut_unchecked<'a>(slice: &'a mut [I]) -> &'a mut [Idx<'n, I>] {
/// assert that the values of `slice` are all bounded by `size`.
	pub fn from_slice_ref_checked<'a>(slice: &'a [I], size: Dim<'n>) -> &'a [Idx<'n, I>] {
/// assume that the values of `slice` are all bounded by the value tied to `'n`.
	pub unsafe fn from_slice_ref_unchecked<'a>(slice: &'a [I]) -> &'a [Idx<'n, I>] {
/// `i` value smaller than the size corresponding to the lifetime `'n`, or `none`.
/// returns an index value.
	pub fn from_index(idx: Idx<'n, I>) -> Self {
/// returns a `none` value.
	pub fn none() -> Self {
/// returns a constrained index value if `idx` is nonnegative, `none` otherwise.
	pub fn new_checked(idx: I::Signed, size: Dim<'n>) -> Self {
/// returns a constrained index value if `idx` is nonnegative, `none` otherwise.
	pub unsafe fn new_unchecked(idx: I::Signed, size: Dim<'n>) -> Self {
/// returns a constrained index value if `idx` is nonnegative, `none` otherwise.
	pub unsafe fn new_unbound(idx: I) -> Self {
/// returns the inner value.
	pub fn unbound(self) -> I {
/// returns the index if available, or `none` otherwise.
	pub fn idx(self) -> Option<Idx<'n, I>> {
/// sign extend the value.
	pub fn sx(self) -> MaybeIdx<'n> {
/// assert that the values of `slice` are all bounded by `size`.
	pub fn from_slice_mut_checked<'a>(slice: &'a mut [I::Signed], size: Dim<'n>) -> &'a mut [MaybeIdx<'n, I>] {
/// assume that the values of `slice` are all bounded by the value tied to `'n`.
	pub unsafe fn from_slice_mut_unchecked<'a>(slice: &'a mut [I::Signed]) -> &'a mut [MaybeIdx<'n, I>] {
/// assert that the values of `slice` are all bounded by `size`.
	pub fn from_slice_ref_checked<'a>(slice: &'a [I::Signed], size: Dim<'n>) -> &'a [MaybeIdx<'n, I>] {
/// convert a constrained slice to an unconstrained one.
	pub fn as_slice_ref<'a>(slice: &'a [MaybeIdx<'n, I>]) -> &'a [I::Signed] {
/// assume that the values of `slice` are all bounded by the value tied to `'n`.
	pub unsafe fn from_slice_ref_unchecked<'a>(slice: &'a [I::Signed]) -> &'a [MaybeIdx<'n, I>] {
	fn deref(&self) -> &Self::Target {
	fn deref(&self) -> &Self::Target {
	fn deref(&self) -> &Self::Target {
	fn deref(&self) -> &Self::Target {
/// array of length equal to the value tied to `'n`.
/// returns a constrained array after checking that its length matches `size`.
	pub fn from_ref<'a>(slice: &'a [T], size: Dim<'n>) -> &'a Self {
/// returns a constrained array after checking that its length matches `size`.
	pub fn from_mut<'a>(slice: &'a mut [T], size: Dim<'n>) -> &'a mut Self {
/// returns the unconstrained slice.
	pub fn as_ref(&self) -> &[T] {
/// returns the unconstrained slice.
	pub fn as_mut<'a>(&mut self) -> &'a mut [T] {
/// returns the length of `self`.
	pub fn len(&self) -> Dim<'n> {
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
	fn index(&self, idx: Range<IdxInc<'n>>) -> &Self::Output {
	fn index_mut(&mut self, idx: Range<IdxInc<'n>>) -> &mut Self::Output {
	fn index(&self, idx: Idx<'n>) -> &Self::Output {
	fn index_mut(&mut self, idx: Idx<'n>) -> &mut Self::Output {
/// dimension equal to one
/// index equal to zero
/// index equal to zero ro one
/// index equal to zero ro one, or a sentinel value
	unsafe fn new_unbound(idx: I) -> Self {
	fn unbound(self) -> I {
	unsafe fn new_unbound(idx: I::Signed) -> Self {
	fn unbound(self) -> I::Signed {
	unsafe fn new_unbound(idx: I) -> Self {
	fn unbound(self) -> I {
	unsafe fn new_unbound(idx: usize) -> Self {
	fn unbound(self) -> usize {
	fn from(_: Zero) -> Self {
	fn eq(&self, _: &One) -> bool {
	fn partial_cmp(&self, _: &One) -> Option<core::cmp::Ordering> {
	fn eq(&self, _: &One) -> bool {
	fn partial_cmp(&self, _: &One) -> Option<core::cmp::Ordering> {
/// compile-time bound-checked indexing types
/// executes the two operations, possibly in parallel, while splitting the amount of parallelism
/// between the two
	pub fn join_raw(op_a: impl Send + FnOnce(Par), op_b: impl Send + FnOnce(Par), parallelism: Par) {
		fn implementation<'a>(op_a: &'a mut (dyn Send + FnMut(Par)), op_b: &'a mut (dyn Send + FnMut(Par)), parallelism: Par) {
/// unsafe [`Send`] and [`Sync`] pointer type
		fn clone(&self) -> Self {
/// the amount of threads that should ideally execute an operation with the given parallelism
	pub fn parallelism_degree(parallelism: Par) -> usize {
/// returns the start and length of a subsegment of `0..n`, split between `chunk_count`
/// consumers, for the consumer at index `idx`
///
/// for the same `n` and `chunk_count`, different values of `idx` between in `0..chunk_count`
/// will represent distinct subsegments
	pub fn par_split_indices(n: usize, idx: usize, chunk_count: usize) -> (usize, usize) {
/// simd helper utilities based on lifetime-bound indices
/// approximate comparators for testing purposes
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
	fn clone(&self) -> Self {
	fn deref(&self) -> &Self::Target {
	fn read(simd: &SimdCtx<'N, T, S>, slice: ColRef<'_, T, Dim<'N>, ContiguousFwd>, index: Self) -> T::SimdVec<S>;
	fn write(simd: &SimdCtx<'N, T, S>, slice: ColMut<'_, T, Dim<'N>, ContiguousFwd>, index: Self, value: T::SimdVec<S>);
	fn read(simd: &SimdCtx<'N, T, S>, slice: ColRef<'_, T, Dim<'N>, ContiguousFwd>, index: Self) -> T::SimdVec<S> {
	fn write(simd: &SimdCtx<'N, T, S>, slice: ColMut<'_, T, Dim<'N>, ContiguousFwd>, index: Self, value: T::SimdVec<S>) {
	fn read(simd: &SimdCtx<'N, T, S>, slice: ColRef<'_, T, Dim<'N>, ContiguousFwd>, index: Self) -> T::SimdVec<S> {
	fn write(simd: &SimdCtx<'N, T, S>, slice: ColMut<'_, T, Dim<'N>, ContiguousFwd>, index: Self, value: T::SimdVec<S>) {
	fn read(simd: &SimdCtx<'N, T, S>, slice: ColRef<'_, T, Dim<'N>, ContiguousFwd>, index: Self) -> T::SimdVec<S> {
	fn write(simd: &SimdCtx<'N, T, S>, slice: ColMut<'_, T, Dim<'N>, ContiguousFwd>, index: Self, value: T::SimdVec<S>) {
	pub fn new(simd: T::SimdCtx<S>, len: Dim<'N>) -> Self {
	pub fn new_align(simd: T::SimdCtx<S>, len: Dim<'N>, align_offset: usize) -> Self {
	pub fn offset(&self) -> usize {
	pub fn new_force_mask(simd: T::SimdCtx<S>, len: Dim<'N>) -> Self {
	pub fn read<I: SimdIndex<'N, T, S>>(&self, slice: ColRef<'_, T, Dim<'N>, ContiguousFwd>, index: I) -> T::SimdVec<S> {
	pub fn write<I: SimdIndex<'N, T, S>>(&self, slice: ColMut<'_, T, Dim<'N>, ContiguousFwd>, index: I, value: T::SimdVec<S>) {
	pub fn head_mask(&self) -> T::SimdMask<S> {
	pub fn tail_mask(&self) -> T::SimdMask<S> {
	pub fn indices(
		&self,
	) -> (
		Option<SimdHead<'N, T, S>>,
		impl Clone + ExactSizeIterator + DoubleEndedIterator<Item = SimdBody<'N, T, S>>,
		Option<SimdTail<'N, T, S>>,
	) {
	pub fn batch_indices<const BATCH: usize>(
		&self,
	) -> (
		Option<SimdHead<'N, T, S>>,
		impl Clone + ExactSizeIterator + DoubleEndedIterator<Item = [SimdBody<'N, T, S>;
	pub fn offset(&self) -> isize {
	fn clone(&self) -> Self {
	fn clone(&self) -> Self {
	fn clone(&self) -> Self {
