use super::*;
use crate::assert;
pub struct SparseColMatRef<'a, I: Index, E: Entity> {
pub(crate) symbolic: SymbolicSparseColMatRef<'a, I>,
pub(crate) values: SliceGroup<'a, E>,
}
impl<I: Index, E: Entity> Copy for SparseColMatRef<'_, I, E> {}
impl<I: Index, E: Entity> Clone for SparseColMatRef<'_, I, E> {
#[inline]
fn clone(&self) -> Self {
*self
}
}
impl<'short, I: Index, E: Entity> Reborrow<'short> for SparseColMatRef<'_, I, E> {
type Target = SparseColMatRef<'short, I, E>;
#[inline]
fn rb(&'short self) -> Self::Target {
*self
}
}
impl<'short, I: Index, E: Entity> ReborrowMut<'short> for SparseColMatRef<'_, I, E> {
type Target = SparseColMatRef<'short, I, E>;
#[inline]
fn rb_mut(&'short mut self) -> Self::Target {
*self
}
}
impl<'a, I: Index, E: Entity> IntoConst for SparseColMatRef<'a, I, E> {
type Target = SparseColMatRef<'a, I, E>;
#[inline]
fn into_const(self) -> Self::Target {
self
}
}
impl<'a, I: Index, E: Entity> SparseColMatRef<'a, I, E> {
#[inline]
#[track_caller]
pub fn new(
symbolic: SymbolicSparseColMatRef<'a, I>,
values: GroupFor<E, &'a [E::Unit]>,
) -> Self {
let values = SliceGroup::new(values);
assert!(symbolic.row_indices().len() == values.len());
Self { symbolic, values }
}
#[inline]
pub fn nrows(&self) -> usize {
self.symbolic.nrows
}
#[inline]
pub fn ncols(&self) -> usize {
self.symbolic.ncols
}
#[inline]
pub fn shape(&self) -> (usize, usize) {
(self.nrows(), self.ncols())
}
#[inline]
pub fn as_ref(&self) -> SparseColMatRef<'_, I, E> {
*self
}
#[inline]
pub fn to_owned(&self) -> Result<SparseColMat<I, E::Canonical>, FaerError>
where
E: Conjugate,
E::Canonical: ComplexField,
{
let symbolic = self.symbolic().to_owned()?;
let mut values = VecGroup::<E::Canonical>::new();
values
.try_reserve_exact(self.values.len())
.map_err(|_| FaerError::OutOfMemory)?;
values.resize(
self.values.len(),
E::Canonical::faer_zero().faer_into_units(),
);
let src = self.values;
let dst = values.as_slice_mut();
for (mut dst, src) in core::iter::zip(dst.into_mut_iter(), src.into_ref_iter()) {
dst.write(src.read().canonicalize());
}
Ok(SparseColMat { symbolic, values })
}
#[inline]
pub fn to_sorted(&self) -> Result<SparseColMat<I, E::Canonical>, FaerError>
where
E: Conjugate,
E::Canonical: ComplexField,
{
let mut mat = (*self).to_owned()?;
mat.sort_indices();
Ok(mat)
}
#[inline]
pub fn to_dense(&self) -> Mat<E::Canonical>
where
E: Conjugate,
E::Canonical: ComplexField,
{
let mut mat = Mat::<E::Canonical>::zeros(self.nrows(), self.ncols());
for j in 0..self.ncols() {
for (i, val) in self.row_indices_of_col(j).zip(
crate::utils::slice::SliceGroup::<'_, E>::new(self.values_of_col(j))
.into_ref_iter(),
) {
mat.write(i, j, mat.read(i, j).faer_add(val.read().canonicalize()));
}
}
mat
}
#[inline]
pub fn to_row_major(&self) -> Result<SparseRowMat<I, E::Canonical>, FaerError>
where
E: Conjugate,
E::Canonical: ComplexField,
{
let mut col_ptr = try_zeroed::<I>(self.nrows() + 1)?;
let nnz = self.compute_nnz();
let mut row_ind = try_zeroed::<I>(nnz)?;
let mut values = VecGroup::<E::Canonical>::new();
values
.try_reserve_exact(nnz)
.map_err(|_| FaerError::OutOfMemory)?;
values.resize(nnz, E::Canonical::faer_zero().faer_into_units());
let mut mem = GlobalPodBuffer::try_new(StackReq::new::<I>(self.nrows()))
.map_err(|_| FaerError::OutOfMemory)?;
let (this, conj) = self.canonicalize();
if conj == Conj::No {
utils::transpose::<I, E::Canonical>(
&mut col_ptr,
&mut row_ind,
values.as_slice_mut().into_inner(),
this,
PodStack::new(&mut mem),
);
} else {
utils::adjoint::<I, E::Canonical>(
&mut col_ptr,
&mut row_ind,
values.as_slice_mut().into_inner(),
this,
PodStack::new(&mut mem),
);
}
let transpose = unsafe {
SparseColMat::new(
SymbolicSparseColMat::new_unchecked(
self.ncols(),
self.nrows(),
col_ptr,
None,
row_ind,
),
values.into_inner(),
)
};
Ok(transpose.into_transpose())
}
#[inline]
pub fn transpose(self) -> SparseRowMatRef<'a, I, E> {
SparseRowMatRef {
symbolic: SymbolicSparseRowMatRef {
nrows: self.symbolic.ncols,
ncols: self.symbolic.nrows,
row_ptr: self.symbolic.col_ptr,
row_nnz: self.symbolic.col_nnz,
col_ind: self.symbolic.row_ind,
},
values: self.values,
}
}
#[inline]
pub fn conjugate(self) -> SparseColMatRef<'a, I, E::Conj>
where
E: Conjugate,
{
SparseColMatRef {
symbolic: self.symbolic,
values: unsafe {
SliceGroup::<'a, E::Conj>::new(transmute_unchecked::<
GroupFor<E, &[UnitFor<E::Conj>]>,
GroupFor<E::Conj, &[UnitFor<E::Conj>]>,
>(E::faer_map(
self.values.into_inner(),
|slice| {
let len = slice.len();
core::slice::from_raw_parts(
slice.as_ptr() as *const UnitFor<E> as *const UnitFor<E::Conj>,
len,
)
},
)))
},
}
}
#[inline]
pub fn canonicalize(self) -> (SparseColMatRef<'a, I, E::Canonical>, Conj)
where
E: Conjugate,
{
(
SparseColMatRef {
symbolic: self.symbolic,
values: unsafe {
SliceGroup::<'a, E::Canonical>::new(transmute_unchecked::<
GroupFor<E, &[UnitFor<E::Canonical>]>,
GroupFor<E::Canonical, &[UnitFor<E::Canonical>]>,
>(E::faer_map(
self.values.into_inner(),
|slice| {
let len = slice.len();
core::slice::from_raw_parts(
slice.as_ptr() as *const UnitFor<E> as *const UnitFor<E::Canonical>,
len,
)
},
)))
},
},
if coe::is_same::<E, E::Canonical>() {
Conj::No
} else {
Conj::Yes
},
)
}
#[inline]
pub fn adjoint(self) -> SparseRowMatRef<'a, I, E::Conj>
where
E: Conjugate,
{
self.transpose().conjugate()
}
#[inline]
pub fn values(self) -> GroupFor<E, &'a [E::Unit]> {
self.values.into_inner()
}
#[inline]
#[track_caller]
pub fn values_of_col(self, j: usize) -> GroupFor<E, &'a [E::Unit]> {
self.values.subslice(self.col_range(j)).into_inner()
}
#[inline]
pub fn symbolic(&self) -> SymbolicSparseColMatRef<'a, I> {
self.symbolic
}
#[inline]
pub fn parts(self) -> (SymbolicSparseColMatRef<'a, I>, GroupFor<E, &'a [E::Unit]>) {
(self.symbolic, self.values.into_inner())
}
#[inline]
pub fn compute_nnz(&self) -> usize {
self.symbolic.compute_nnz()
}
#[inline]
pub fn col_ptrs(&self) -> &'a [I] {
self.symbolic.col_ptrs()
}
#[inline]
pub fn nnz_per_col(&self) -> Option<&'a [I]> {
self.symbolic.col_nnz
}
#[inline]
pub fn row_indices(&self) -> &'a [I] {
self.symbolic.row_ind
}
#[inline]
#[track_caller]
pub fn row_indices_of_col_raw(&self, j: usize) -> &'a [I] {
self.symbolic.row_indices_of_col_raw(j)
}
#[inline]
#[track_caller]
pub fn row_indices_of_col(
&self,
j: usize,
) -> impl 'a + ExactSizeIterator + DoubleEndedIterator<Item = usize> {
self.symbolic.row_indices_of_col(j)
}
#[inline]
#[track_caller]
pub fn col_range(&self, j: usize) -> Range<usize> {
self.symbolic.col_range(j)
}
#[inline]
#[track_caller]
pub unsafe fn col_range_unchecked(&self, j: usize) -> Range<usize> {
self.symbolic.col_range_unchecked(j)
}
#[track_caller]
pub fn get(self, row: usize, col: usize) -> Option<GroupFor<E, &'a E::Unit>> {
let values = self.get_all(row, col);
if E::faer_first(E::faer_as_ref(&values)).len() == 1 {
Some(E::faer_map(values, |slice| &slice[0]))
} else {
None
}
}
#[track_caller]
pub fn get_all(self, row: usize, col: usize) -> GroupFor<E, &'a [E::Unit]> {
assert!(row < self.nrows());
assert!(col < self.ncols());
let row = I::truncate(row);
let start = self
.row_indices_of_col_raw(col)
.partition_point(|&p| p < row);
let end = start + self.row_indices_of_col_raw(col)[start..].partition_point(|&p| p <= row);
E::faer_map(self.values_of_col(col), |slice| &slice[start..end])
}
}
impl<I: Index, E: Entity> core::fmt::Debug for SparseColMatRef<'_, I, E> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let mat = *self;
let mut iter = (0..mat.ncols()).flat_map(move |j| {
struct Wrapper<E: Entity>(usize, usize, E);
impl<E: Entity> core::fmt::Debug for Wrapper<E> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let row = self.0;
let col = self.1;
let val = self.2;
write!(f, "({row}, {col}, {val:?})")
}
}
mat.row_indices_of_col(j)
.zip(SliceGroup::<'_, E>::new(mat.values_of_col(j)).into_ref_iter())
.map(move |(i, val)| Wrapper(i, j, val.read()))
});
f.debug_list().entries(&mut iter).finish()
}
}