mod coo_error;
mod coo_utils;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use cl_aux::{ArrayWrapper, SingleTypeStorage};
pub use coo_error::*;
use coo_utils::{does_not_have_duplicates_sorted, value, value_mut};
pub type CooArray<DATA, const D: usize, const DN: usize> = Coo<[([usize; D], DATA); DN], D>;
pub type CooMut<'data, DATA, const D: usize> = Coo<&'data mut [([usize; D], DATA)], D>;
pub type CooRef<'data, DATA, const D: usize> = Coo<&'data [([usize; D], DATA)], D>;
#[cfg(feature = "alloc")]
pub type CooVec<DATA, const D: usize> = Coo<Vec<([usize; D], DATA)>, D>;
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
pub struct Coo<DS, const D: usize> {
pub(crate) data: DS,
pub(crate) dims: ArrayWrapper<usize, D>,
}
impl<DS, const D: usize> Coo<DS, D> {
#[inline]
pub fn dims(&self) -> &[usize; D] {
&self.dims
}
}
impl<DATA, DS, const D: usize> Coo<DS, D>
where
DS: AsRef<[<DS as SingleTypeStorage>::Item]> + SingleTypeStorage<Item = ([usize; D], DATA)>,
{
#[cfg_attr(feature = "alloc", doc = "```rust")]
#[cfg_attr(not(feature = "alloc"), doc = "```ignore")]
#[inline]
pub fn new(dims: [usize; D], data: DS) -> crate::Result<Self> {
if !crate::utils::are_in_ascending_order(data.as_ref(), |a, b| [&a.0, &b.0]) {
return Err(CooError::InvalidIndcsOrder.into());
}
let has_invalid_indcs = !data.as_ref().iter().all(|&(indcs, _)| {
indcs.iter().zip(dims.iter()).all(
|(data_idx, dim)| {
if dim == &0 {
true
} else {
data_idx < dim
}
},
)
});
if has_invalid_indcs {
return Err(CooError::InvalidIndcs.into());
}
if !does_not_have_duplicates_sorted(data.as_ref(), |a, b| a.0[..] != b.0[..]) {
return Err(CooError::DuplicatedIndices.into());
}
Ok(Self { data, dims: dims.into() })
}
#[inline]
pub fn data(&self) -> &[([usize; D], DATA)] {
self.data.as_ref()
}
#[inline]
pub fn value(&self, indcs: [usize; D]) -> Option<&DATA> {
value(indcs, self.data.as_ref())
}
}
impl<DATA, DS, const D: usize> Coo<DS, D>
where
DS: AsMut<[<DS as SingleTypeStorage>::Item]> + SingleTypeStorage<Item = ([usize; D], DATA)>,
{
#[inline]
pub fn value_mut(&mut self, indcs: [usize; D]) -> Option<&mut DATA> {
value_mut(indcs, self.data.as_mut())
}
}
#[cfg(feature = "rand")]
impl<DATA, DS, const D: usize> Coo<DS, D>
where
DS: AsMut<[<DS as SingleTypeStorage>::Item]>
+ AsRef<[<DS as SingleTypeStorage>::Item]>
+ Default
+ SingleTypeStorage<Item = ([usize; D], DATA)>
+ cl_aux::CapacityUpperBound
+ cl_aux::Push<<DS as SingleTypeStorage>::Item>,
{
#[cfg_attr(feature = "alloc", doc = "```rust")]
#[cfg_attr(not(feature = "alloc"), doc = "```ignore")]
#[inline]
pub fn new_controlled_random_rand<R>(
dims: [usize; D],
nnz: usize,
rng: &mut R,
mut cb: impl FnMut(&mut R, &[usize; D]) -> DATA,
) -> crate::Result<Self>
where
R: rand::Rng,
{
use rand::distr::Distribution as _;
if nnz > crate::utils::max_nnz(&dims) {
return Err(CooError::NnzGreaterThanMaximumNnz.into());
}
let mut data: DS = Default::default();
if nnz > data.as_ref().len() {
return Err(crate::Error::InsufficientCapacity);
}
for _ in 0..nnz {
let indcs: [usize; D] = ArrayWrapper::from_fn(|idx| {
let dim = *dims.get(idx).unwrap_or(&0);
if dim == 0 {
0
} else {
rand::distr::Uniform::new(0, dim).ok().map(|el| el.sample(rng)).unwrap_or_default()
}
})
.0;
if data.as_ref().iter().all(|value| value.0 != indcs) {
data
.push({
let element = cb(rng, &indcs);
(indcs, element)
})
.map_err(|_err| crate::Error::InsufficientCapacity)?;
}
}
data.as_mut().sort_unstable_by(|a, b| a.0.cmp(&b.0));
Coo::new(dims, data)
}
#[inline]
pub fn new_random_rand<R>(rng: &mut R, upper_bound: usize) -> crate::Result<Self>
where
R: rand::Rng,
rand::distr::StandardUniform: rand::distr::Distribution<DATA>,
{
let dims = crate::utils::valid_random_dims(rng, upper_bound);
let max_nnz = crate::utils::max_nnz(&dims);
let nnz = if max_nnz == 0 { 0 } else { rng.random_range(0..max_nnz) };
Self::new_controlled_random_rand(dims, nnz, rng, |r, _| r.random())
}
}