mod coo_utils;
use crate::Dims;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use cl_traits::{ArrayWrapper, Storage};
use coo_utils::*;
pub type CooArray<DA, DTA> = Coo<DA, ArrayWrapper<DTA>>;
#[cfg(feature = "with_arrayvec")]
pub type CooArrayVec<DA, DTA> = Coo<DA, cl_traits::ArrayVecArrayWrapper<DTA>>;
pub type CooMut<'a, DA, DATA> = Coo<DA, &'a mut [(ArrayWrapper<DA>, DATA)]>;
pub type CooRef<'a, DA, DATA> = Coo<DA, &'a [(ArrayWrapper<DA>, DATA)]>;
#[cfg(feature = "with_smallvec")]
pub type CooSmallVec<DA, DTA> = Coo<DA, cl_traits::SmallVecArrayWrapper<DTA>>;
#[cfg(feature = "with_staticvec")]
pub type CooStaticVec<DATA, const DIMS: usize, const NNZ: usize> =
Coo<[usize; DIMS], staticvec::StaticVec<(ArrayWrapper<[usize; DIMS]>, DATA), NNZ>>;
#[cfg(feature = "alloc")]
pub type CooVec<DA, DATA> = Coo<DA, Vec<(ArrayWrapper<DA>, DATA)>>;
#[cfg_attr(feature = "with_serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Clone, Debug, Default, PartialEq)]
pub struct Coo<DA, DS>
where
DA: Dims,
{
pub(crate) data: DS,
pub(crate) dims: ArrayWrapper<DA>,
}
impl<DA, DS> Coo<DA, DS>
where
DA: Dims,
{
#[inline]
pub fn dims(&self) -> &DA {
&*self.dims
}
}
impl<DA, DATA, DS> Coo<DA, DS>
where
DA: Dims,
DS: AsRef<[<DS as Storage>::Item]> + Storage<Item = (ArrayWrapper<DA>, DATA)>,
{
pub fn new<ID, IDS>(into_dims: ID, into_data: IDS) -> Self
where
ID: Into<ArrayWrapper<DA>>,
IDS: Into<DS>,
{
let data = into_data.into();
let dims = into_dims.into();
assert!(
crate::utils::are_in_ascending_order(data.as_ref(), |a, b| [&a.0, &b.0]),
"Data indices must be in asceding order"
);
assert!(
data.as_ref().iter().all(|(indcs, _)| {
indcs.slice().iter().zip(dims.slice().iter()).all(|(data_idx, dim)| data_idx < dim)
}),
"All indices must be lesser than the defined dimensions"
);
assert!(
does_not_have_duplicates_sorted(data.as_ref(), |a, b| a.0[..] != b.0[..]),
"Must not have duplicated indices"
);
Self { data, dims }
}
pub fn data(&self) -> &[(ArrayWrapper<DA>, DATA)] {
self.data.as_ref()
}
pub fn value(&self, indcs: DA) -> Option<&DATA> {
value(indcs.into(), &self.data.as_ref())
}
}
impl<DA, DATA, DS> Coo<DA, DS>
where
DA: Dims,
DS: AsMut<[<DS as Storage>::Item]> + Storage<Item = (ArrayWrapper<DA>, DATA)>,
{
pub unsafe fn data_mut(&mut self) -> &[(ArrayWrapper<DA>, DATA)] {
self.data.as_mut()
}
pub fn value_mut(&mut self, indcs: DA) -> Option<&mut DATA> {
value_mut(indcs.into(), self.data.as_mut())
}
}
#[cfg(feature = "with_rand")]
impl<DA, DATA, DS> Coo<DA, DS>
where
DA: Dims,
DS: AsMut<[<DS as Storage>::Item]>
+ AsRef<[<DS as Storage>::Item]>
+ Default
+ Storage<Item = (ArrayWrapper<DA>, DATA)>
+ cl_traits::Push<Input = <DS as Storage>::Item>,
{
pub fn new_random_with_rand<F, ID, R>(into_dims: ID, nnz: usize, rng: &mut R, mut cb: F) -> Self
where
F: FnMut(&mut R, &DA) -> DATA,
ID: Into<ArrayWrapper<DA>>,
R: rand::Rng,
{
use rand::distributions::Distribution;
let dims = into_dims.into();
let mut data: DS = Default::default();
for _ in 0..nnz {
data.push({
let indcs: DA = cl_traits::create_array(|idx| {
rand::distributions::Uniform::from(0..dims[idx]).sample(rng)
});
let element = cb(rng, &indcs);
(indcs.into(), element)
});
}
data.as_mut().sort_unstable_by(|a, b| a.0.cmp(&b.0));
Coo::new(dims, data)
}
}
#[cfg(all(test, feature = "with_rand"))]
impl<DA, DATA, DS> quickcheck::Arbitrary for Coo<DA, DS>
where
DA: Dims + Clone + Send + 'static,
DATA: Default + quickcheck::Arbitrary,
DS: AsRef<[<DS as Storage>::Item]>
+ AsMut<[<DS as Storage>::Item]>
+ Clone
+ Default
+ Send
+ Storage<Item = (ArrayWrapper<DA>, DATA)>
+ cl_traits::Push<Input = <DS as Storage>::Item>
+ 'static,
rand::distributions::Standard: rand::distributions::Distribution<DATA>,
{
#[inline]
fn arbitrary<G>(g: &mut G) -> Self
where
G: quickcheck::Gen,
{
use rand::Rng;
let dims: DA = cl_traits::create_array(|_| g.gen_range(0, g.size()));
let nnz = g.gen_range(0, dims.slice().iter().product::<usize>());
Self::new_random_with_rand(dims, nnz, g, |g, _| g.gen())
}
}