use crate::{CsMatrix, Real};
#[non_exhaustive]
#[derive(Clone, Copy)]
pub struct CsVecRef<'a, T> {
indices: &'a [usize],
values: &'a [T],
len: usize,
}
impl<'a, T> CsVecRef<'a, T> {
#[inline]
pub fn from_parts_unchecked(indices: &'a [usize], values: &'a [T], len: usize) -> Self {
Self {
indices,
values,
len,
}
}
#[inline]
pub fn iter(&self) -> impl Iterator<Item = (usize, T)>
where
T: Copy,
{
self.indices
.iter()
.copied()
.zip(self.values.iter().copied())
}
#[inline]
pub fn len(&self) -> usize {
self.len
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
#[inline]
pub fn indices(&self) -> &'a [usize] {
self.indices
}
#[inline]
pub fn values(&self) -> &'a [T] {
self.values
}
}
pub struct CsVecMut<'a, T> {
pub col_indices: &'a [usize],
pub values: &'a mut [T],
}
pub struct CsVecBuilder<'a, T> {
secondary_indices: &'a mut Vec<usize>,
primary_offsets: &'a mut Vec<usize>,
values: &'a mut Vec<T>,
mat_value_start: usize,
num_nonzero_values: usize,
zero_threshold: T,
}
impl<'a, T> CsVecBuilder<'a, T>
where
T: Real,
{
#[inline]
pub fn new(m: &'a mut CsMatrix<T>, zero_threshold: T) -> Self {
Self {
secondary_indices: &mut m.secondary_indices,
primary_offsets: &mut m.primary_offsets,
values: &mut m.values,
mat_value_start: 0,
num_nonzero_values: 0,
zero_threshold,
}
}
pub fn from_parts_unchecked(
secondary_indices: &'a mut Vec<usize>,
primary_offsets: &'a mut Vec<usize>,
values: &'a mut Vec<T>,
mat_value_start: usize,
zero_threshold: T,
) -> Self {
Self {
secondary_indices,
primary_offsets,
values,
mat_value_start,
zero_threshold,
num_nonzero_values: 0,
}
}
#[inline]
pub fn push_unchecked(&mut self, index: usize, value: T) {
#[cfg(debug_assertions)]
{
self.validate(index, value);
}
self.secondary_indices.push(index);
self.values.push(value);
self.num_nonzero_values += 1;
}
#[inline]
pub fn push(&mut self, col: usize, value: T) {
self.validate(col, value);
self.push_unchecked(col, value);
}
pub fn extend(&mut self, idx_values: impl IntoIterator<Item = (usize, T)>) {
for (col, value) in idx_values {
self.push(col, value);
}
}
pub fn extend_unchecked(&mut self, idx_values: impl IntoIterator<Item = (usize, T)>) {
for (col, value) in idx_values {
self.push_unchecked(col, value);
}
}
#[inline]
pub fn extend_with_nonzeros(&mut self, idx_values: impl IntoIterator<Item = (usize, T)>) {
for (idx, value) in idx_values {
if value.abs() > self.zero_threshold {
self.push_unchecked(idx, value);
}
}
}
#[inline]
pub fn finish(self) -> usize {
self.num_nonzero_values
}
#[inline]
fn validate(&self, index: usize, value: T) {
assert!(
value.abs() > self.zero_threshold,
"Cannot push zero value to Sparse Vec"
);
if self.num_nonzero_values > 0 {
if let Some(last) = self.secondary_indices.last() {
assert!(
index > *last,
"sparse element indices must be in ascending order"
);
}
}
}
}
impl<T> Drop for CsVecBuilder<'_, T> {
fn drop(&mut self) {
if self.num_nonzero_values == 0 {
return;
}
self.primary_offsets
.push(self.values.len() - self.mat_value_start);
}
}