1mod csl_error;
11mod csl_line_constructor;
12mod csl_line_iter;
13#[cfg(feature = "rayon")]
14mod csl_rayon;
15#[cfg(feature = "rand")]
16mod csl_rnd;
17pub(crate) mod csl_utils;
18
19use crate::utils::{are_in_ascending_order, are_in_upper_bound, has_duplicates, max_nnz, windows2};
20#[cfg(feature = "alloc")]
21use alloc::vec::Vec;
22use cl_aux::{ArrayWrapper, Clear, Push, SingleTypeStorage, Truncate, WithCapacity};
23use core::ops::Range;
24pub use csl_error::*;
25pub use csl_line_constructor::*;
26pub use csl_line_iter::*;
27
28pub type CslArray<DATA, const D: usize, const N: usize, const O: usize> =
30 Csl<[DATA; N], [usize; N], [usize; O], D>;
31pub type CslMut<'data, DATA, const D: usize> =
33 Csl<&'data mut [DATA], &'data [usize], &'data [usize], D>;
34pub type CslRef<'data, DATA, const D: usize> =
36 Csl<&'data [DATA], &'data [usize], &'data [usize], D>;
37#[cfg(feature = "alloc")]
39pub type CslVec<DATA, const D: usize> = Csl<Vec<DATA>, Vec<usize>, Vec<usize>, D>;
40
41#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
57#[derive(Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
58pub struct Csl<DS, IS, OS, const D: usize> {
59 pub(crate) data: DS,
60 pub(crate) dims: ArrayWrapper<usize, D>,
61 pub(crate) indcs: IS,
62 pub(crate) offs: OS,
63}
64
65impl<DS, IS, OS, const D: usize> Csl<DS, IS, OS, D>
66where
67 DS: WithCapacity<Error = cl_aux::Error, Input = usize>,
68 IS: WithCapacity<Error = cl_aux::Error, Input = usize>,
69 OS: WithCapacity<Error = cl_aux::Error, Input = usize>,
70{
71 #[cfg_attr(feature = "alloc", doc = "```rust")]
83 #[cfg_attr(not(feature = "alloc"), doc = "```ignore")]
84 #[inline]
91 pub fn with_capacity(nnz: usize, nolp1: usize) -> Self {
92 Self {
93 data: DS::with_capacity(nnz),
94 dims: <_>::default(),
95 indcs: IS::with_capacity(nnz),
96 offs: OS::with_capacity(nolp1),
97 }
98 }
99}
100
101impl<DS, IS, OS, const D: usize> Csl<DS, IS, OS, D> {
102 #[inline]
111 pub fn dims(&self) -> &[usize; D] {
112 &self.dims
113 }
114}
115
116impl<DATA, DS, IS, OS, const D: usize> Csl<DS, IS, OS, D>
117where
118 DS: AsRef<[DATA]> + SingleTypeStorage<Item = DATA>,
119 IS: AsRef<[usize]>,
120 OS: AsRef<[usize]>,
121{
122 #[cfg_attr(feature = "alloc", doc = "```rust")]
137 #[cfg_attr(not(feature = "alloc"), doc = "```ignore")]
138 #[inline]
146 pub fn new(dims: [usize; D], data: DS, indcs: IS, offs: OS) -> crate::Result<Self> {
147 let data_ref = data.as_ref();
148 let indcs_ref = indcs.as_ref();
149 let offs_ref = offs.as_ref();
150
151 let innermost_dim_is_zero = {
152 let mut iter = dims.iter().copied();
153 for dim in &mut iter {
154 if dim != 0 {
155 break;
156 }
157 }
158 iter.any(|v| v == 0)
159 };
160 if innermost_dim_is_zero {
161 return Err(CslError::InnermostDimsZero.into());
162 }
163
164 if data_ref.len() != indcs_ref.len() {
165 return Err(CslError::DiffDataIndcsLength.into());
166 }
167
168 if !are_in_ascending_order(offs_ref, |a, b| [a, b]) {
169 return Err(CslError::InvalidOffsetsOrder.into());
170 }
171
172 let data_indcs_length_greater_than_dims_length = {
173 let max_nnz = max_nnz(&dims);
174 data_ref.len() > max_nnz || indcs_ref.len() > max_nnz
175 };
176 if data_indcs_length_greater_than_dims_length {
177 return Err(CslError::DataIndcsLengthGreaterThanDimsLength.into());
178 }
179
180 if let Some(last) = dims.last() {
181 let are_in_upper_bound = are_in_upper_bound(indcs_ref, last);
182 if !are_in_upper_bound {
183 return Err(CslError::IndcsGreaterThanEqualDimLength.into());
184 }
185 if offs_ref.len() != csl_utils::correct_offs_len(&dims)? {
186 return Err(CslError::InvalidOffsetsLength.into());
187 }
188 }
189
190 let Some(first_off) = offs_ref.first().copied() else {
191 return Ok(Self { data, dims: dims.into(), indcs, offs });
192 };
193
194 if let Some(last_ref) = offs_ref.last() {
195 if let Some(last) = last_ref.checked_sub(first_off) {
196 if last != data_ref.len() || last != indcs_ref.len() {
197 return Err(CslError::LastOffsetDifferentNnz.into());
198 }
199 }
200 }
201
202 let has_duplicated_indices = windows2(offs_ref).any(|[a, b]| {
203 let fun = || {
204 let first = a.checked_sub(first_off)?;
205 let last = b.checked_sub(first_off)?;
206 indcs_ref.get(first..last)
207 };
208 if let Some(indcs_slice) = fun() {
209 has_duplicates(indcs_slice)
210 } else {
211 false
212 }
213 });
214 if has_duplicated_indices {
215 return Err(CslError::DuplicatedIndices.into());
216 }
217
218 Ok(Self { data, dims: dims.into(), indcs, offs })
219 }
220
221 #[inline]
230 pub fn data(&self) -> &[DATA] {
231 self.data.as_ref()
232 }
233
234 #[inline]
243 pub fn indcs(&self) -> &[usize] {
244 self.indcs.as_ref()
245 }
246
247 #[inline]
258 pub fn line(&self, indcs: [usize; D]) -> Option<CslRef<'_, DATA, 1>> {
259 csl_utils::line(self, indcs)
260 }
261
262 #[inline]
271 pub fn nnz(&self) -> usize {
272 self.data.as_ref().len()
273 }
274
275 #[inline]
288 pub fn offs(&self) -> &[usize] {
289 self.offs.as_ref()
290 }
291
292 #[inline]
314 pub fn outermost_line_iter(&self) -> crate::Result<CslLineIterRef<'_, DATA, D>> {
315 CslLineIterRef::new(self.dims.0, self.data.as_ref(), self.indcs.as_ref(), self.offs.as_ref())
316 }
317
318 #[cfg_attr(all(feature = "alloc", feature = "rayon"), doc = "```rust")]
323 #[cfg_attr(not(all(feature = "alloc", feature = "rayon")), doc = "```ignore")]
324 #[cfg(feature = "rayon")]
335 #[inline]
336 pub fn outermost_line_rayon_iter(
337 &self,
338 ) -> crate::Result<crate::ParallelIteratorWrapper<CslLineIterRef<'_, DATA, D>>> {
339 Ok(crate::ParallelIteratorWrapper(self.outermost_line_iter()?))
340 }
341
342 #[inline]
366 pub fn sub_dim<const TD: usize>(&self, range: Range<usize>) -> Option<CslRef<'_, DATA, TD>> {
367 csl_utils::sub_dim(self, range)
368 }
369
370 #[inline]
386 pub fn value(&self, indcs: [usize; D]) -> Option<&DATA> {
387 let idx = csl_utils::data_idx(self, indcs)?;
388 self.data.as_ref().get(idx)
389 }
390}
391
392impl<DATA, DS, IS, OS, const D: usize> Csl<DS, IS, OS, D>
393where
394 DS: AsMut<[DATA]> + AsRef<[DATA]> + SingleTypeStorage<Item = DATA>,
395 IS: AsRef<[usize]>,
396 OS: AsRef<[usize]>,
397{
398 #[cfg_attr(feature = "alloc", doc = "```rust")]
402 #[cfg_attr(not(feature = "alloc"), doc = "```ignore")]
403 #[inline]
409 pub fn clear(&mut self)
410 where
411 DS: Clear,
412 IS: Clear,
413 OS: Clear,
414 {
415 self.dims = <_>::default();
416 self.data.clear();
417 self.indcs.clear();
418 self.offs.clear();
419 }
420
421 #[inline]
423 pub fn constructor(&mut self) -> crate::Result<CslLineConstructor<'_, DS, IS, OS, D>>
424 where
425 DS: Push<DATA>,
426 IS: Push<usize>,
427 OS: Push<usize>,
428 {
429 CslLineConstructor::new(self)
430 }
431
432 #[inline]
434 pub fn data_mut(&mut self) -> &mut [DATA] {
435 self.data.as_mut()
436 }
437
438 #[inline]
440 pub fn line_mut(&mut self, indcs: [usize; D]) -> Option<CslMut<'_, DATA, 1>> {
441 csl_utils::line_mut(self, indcs)
442 }
443
444 #[inline]
446 pub fn outermost_line_iter_mut(&mut self) -> crate::Result<CslLineIterMut<'_, DATA, D>> {
447 CslLineIterMut::new(self.dims.0, self.data.as_mut(), self.indcs.as_ref(), self.offs.as_ref())
448 }
449
450 #[cfg(feature = "rayon")]
452 #[inline]
453 pub fn outermost_line_rayon_iter_mut(
454 &mut self,
455 ) -> crate::Result<crate::ParallelIteratorWrapper<CslLineIterMut<'_, DATA, D>>> {
456 Ok(crate::ParallelIteratorWrapper(self.outermost_line_iter_mut()?))
457 }
458
459 #[inline]
461 pub fn sub_dim_mut<const TD: usize>(
462 &mut self,
463 range: Range<usize>,
464 ) -> Option<CslMut<'_, DATA, TD>> {
465 csl_utils::sub_dim_mut(self, range)
466 }
467
468 #[cfg_attr(feature = "alloc", doc = "```rust")]
477 #[cfg_attr(not(feature = "alloc"), doc = "```ignore")]
478 #[inline]
484 pub fn swap_value(&mut self, a: [usize; D], b: [usize; D]) -> bool {
485 if let Some(a_idx) = csl_utils::data_idx(self, a) {
486 if let Some(b_idx) = csl_utils::data_idx(self, b) {
487 self.data.as_mut().swap(a_idx, b_idx);
488 return true;
489 }
490 }
491 false
492 }
493
494 #[cfg_attr(feature = "alloc", doc = "```rust")]
498 #[cfg_attr(not(feature = "alloc"), doc = "```ignore")]
499 #[inline]
508 pub fn truncate(&mut self, indcs: [usize; D])
509 where
510 DS: Truncate<Input = usize>,
511 IS: Truncate<Input = usize>,
512 OS: AsMut<[usize]> + Truncate<Input = usize>,
513 {
514 let Some([offs_indcs, values]) = csl_utils::line_offs(&self.dims, &indcs, self.offs.as_ref())
515 else {
516 return;
517 };
518 let cut_point = values.start;
519 self.data.truncate(cut_point);
520 self.indcs.truncate(cut_point);
521 self.offs.truncate(offs_indcs.end);
522 let iter = indcs.iter().zip(self.dims.iter_mut()).rev().skip(1).rev();
523 iter.filter(|&(a, _)| *a == 0).for_each(|(_, b)| *b = 0);
524 let before_last = if let Some(rslt) = self.offs.as_ref().get(offs_indcs.end.saturating_sub(2)) {
525 *rslt
526 } else {
527 return;
528 };
529 if let Some(rslt) = self.offs.as_mut().get_mut(offs_indcs.end.saturating_sub(1)) {
530 *rslt = before_last;
531 }
532 }
533
534 #[inline]
536 pub fn value_mut(&mut self, indcs: [usize; D]) -> Option<&mut DATA> {
537 let idx = csl_utils::data_idx(self, indcs)?;
538 self.data.as_mut().get_mut(idx)
539 }
540}
541
542#[cfg(feature = "rand")]
543impl<DATA, DS, IS, OS, const D: usize> Csl<DS, IS, OS, D>
544where
545 DS: AsMut<[DATA]> + AsRef<[DATA]> + Default + Push<DATA> + SingleTypeStorage<Item = DATA>,
546 IS: AsMut<[usize]> + AsRef<[usize]> + Default + Push<usize>,
547 OS: AsMut<[usize]> + AsRef<[usize]> + Default + Push<usize>,
548{
549 #[cfg_attr(feature = "alloc", doc = "```rust")]
560 #[cfg_attr(not(feature = "alloc"), doc = "```ignore")]
561 #[inline]
569 pub fn new_controlled_random_rand<R>(
570 dims: [usize; D],
571 nnz: usize,
572 rng: &mut R,
573 cb: impl FnMut(&mut R, [usize; D]) -> DATA,
574 ) -> crate::Result<Self>
575 where
576 R: rand::Rng,
577 {
578 let mut csl = Csl { dims: dims.into(), ..Default::default() };
579 csl_rnd::CslRnd::new(&mut csl, nnz, rng)?.fill(cb).ok_or(crate::Error::UnknownError)?;
580 Self::new(csl.dims.0, csl.data, csl.indcs, csl.offs)
581 }
582
583 #[cfg_attr(feature = "alloc", doc = "```rust")]
594 #[cfg_attr(not(feature = "alloc"), doc = "```ignore")]
595 #[inline]
605 pub fn new_random_rand<R>(rng: &mut R, upper_bound: usize) -> crate::Result<Self>
606 where
607 R: rand::Rng,
608 rand::distributions::Standard: rand::distributions::Distribution<DATA>,
609 {
610 let dims = crate::utils::valid_random_dims(rng, upper_bound);
611 let max_nnz = max_nnz(&dims);
612 let nnz = if max_nnz == 0 { 0 } else { rng.gen_range(0..max_nnz) };
613 Self::new_controlled_random_rand(dims, nnz, rng, |r, _| r.gen())
614 }
615}