Skip to main content

hurray_core/layout/
csc.rs

1//! CSC (Compressed Sparse Column) layout descriptor.
2//!
3//! Tag `0x08`. Rank MUST be 2. Buffer count = 3 (values + row_indices + col_ptr).
4//! See `docs/spec/layouts/csc.md`.
5
6/// Descriptor for the CSC (Compressed Sparse Column) sparse layout.
7///
8/// CSC is the column analog of CSR and is defined **only for rank-2 tensors**.
9/// A conforming implementation MUST reject a CSC descriptor whose tensor rank
10/// is not 2 (checked by [`LayoutDescriptor::validate_against_shape`]).
11///
12/// Three buffers are required:
13///
14/// | Buffer | Contents |
15/// |--------|----------|
16/// | 0 — `values` | Non-zero values in column-major order; `nnz` elements. |
17/// | 1 — `row_indices` | Row index of each non-zero; `nnz` `uint64` elements. |
18/// | 2 — `col_ptr` | Column pointer array; `ncols + 1` `uint64` elements where `ncols = shape[1]`. |
19///
20/// The `byte_offset` field MUST be `0` for CSC tensors.
21///
22/// > Also known as **CCS (Compressed Column Storage)**.
23///
24/// # Examples
25///
26/// ```
27/// use hurray_core::layout::{CscLayout, LayoutDescriptor};
28///
29/// let layout = LayoutDescriptor::Csc(CscLayout::new(5));
30/// assert_eq!(layout.tag(), 0x08);
31/// assert_eq!(layout.buffer_count().map(|n| n.get()), Some(3));
32/// ```
33#[derive(Debug, Clone, PartialEq, Eq, Hash)]
34#[non_exhaustive]
35pub struct CscLayout {
36    /// Number of stored (non-zero) elements. MAY be 0 for an empty sparse matrix.
37    pub nnz: u64,
38}
39
40impl CscLayout {
41    /// Creates a new [`CscLayout`].
42    ///
43    /// # Examples
44    ///
45    /// ```
46    /// use hurray_core::layout::CscLayout;
47    ///
48    /// let c = CscLayout::new(5);
49    /// assert_eq!(c.nnz, 5);
50    /// ```
51    pub fn new(nnz: u64) -> Self {
52        Self { nnz }
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59    use crate::layout::LayoutDescriptor;
60
61    #[test]
62    fn csc_tag_is_0x08() {
63        let layout = LayoutDescriptor::Csc(CscLayout::new(0));
64        assert_eq!(layout.tag(), 0x08);
65    }
66
67    #[test]
68    fn csc_buffer_count_is_3() {
69        use std::num::NonZeroU8;
70        let layout = LayoutDescriptor::Csc(CscLayout::new(5));
71        assert_eq!(layout.buffer_count(), Some(NonZeroU8::new(3).unwrap()));
72    }
73}