use std::sync::Arc;
use aligned_vec::{AVec, ConstAlign};
use num_traits::{Float, One, Zero};
use crate::{Sector, Storage, StorageFor};
pub struct BlockSparseStorage<T> {
data: Arc<AVec<T, ConstAlign<64>>>,
}
impl<T> Clone for BlockSparseStorage<T> {
fn clone(&self) -> Self {
Self {
data: Arc::clone(&self.data),
}
}
}
impl<T> BlockSparseStorage<T> {
pub fn new(data: Vec<T>) -> Self
where
T: Clone,
{
let aligned = AVec::from_slice(64, &data);
Self {
data: Arc::new(aligned),
}
}
pub(crate) fn from_aligned(data: AVec<T, ConstAlign<64>>) -> Self {
Self {
data: Arc::new(data),
}
}
pub fn data(&self) -> &[T] {
&self.data[..]
}
pub fn data_mut(&mut self) -> &mut [T]
where
T: Clone,
{
Arc::make_mut(&mut self.data).as_mut_slice()
}
pub(crate) fn arc_mut(&mut self) -> &mut Arc<AVec<T, ConstAlign<64>>> {
&mut self.data
}
}
impl<T> Storage for BlockSparseStorage<T> {
type Element = T;
fn flat_len(&self) -> usize {
self.data.len()
}
}
impl<T, S: Sector> StorageFor<crate::BlockSparseLayout<S>> for BlockSparseStorage<T> {}
impl<T> BlockSparseStorage<T>
where
T: Clone,
{
pub(crate) fn scale<S>(&mut self, factor: S)
where
T: std::ops::Mul<S, Output = T>,
S: Clone,
{
let data = Arc::make_mut(&mut self.data).as_mut_slice();
for elem in data.iter_mut() {
*elem = elem.clone() * factor.clone();
}
}
}
impl<T> BlockSparseStorage<T>
where
T: ariadnetor_core::Scalar,
{
pub(crate) fn stored_len(&self) -> usize {
self.data.len()
}
fn norm_squared(&self) -> T::Real {
self.data
.iter()
.map(|&x| {
let a = x.abs();
a * a
})
.fold(T::Real::zero(), |acc, x| acc + x)
}
pub(crate) fn norm_frobenius(&self) -> T::Real {
self.norm_squared().sqrt()
}
pub(crate) fn norm(&self) -> T::Real {
self.norm_frobenius()
}
pub(crate) fn normalize(&mut self) -> T::Real {
let norm = self.norm_frobenius();
assert!(norm != T::Real::zero(), "Cannot normalize zero tensor");
let inv_norm = T::Real::one() / norm;
let data = Arc::make_mut(&mut self.data);
for elem in data.iter_mut() {
*elem = elem.scale_real(inv_norm);
}
norm
}
}