Skip to main content

bixverse_sparse/
errors.rs

1//! Errors raised by `bixverse-sparse`.
2
3use thiserror::Error;
4
5/// Error variants raised by the sparse structures and operations.
6///
7/// `bixverse-core` converts these into the identically named `CoreErrors`
8/// variants, so callers of the core crate keep matching on `CoreErrors`.
9#[derive(Debug, Error)]
10pub enum SparseErrors {
11    /// Error in situations were data_2 in
12    /// [`CompressedSparseData2`](crate::sparse::CompressedSparseData2) is
13    /// asked for but not available
14    #[error("data_2 slot is None but was requested")]
15    Data2NotAvailable,
16
17    /// Error if the slice index is out of bounds
18    #[error("The slice index ({index}) is out of bounds (length: {len})")]
19    SliceIndexOutOfBounds {
20        /// The chosen index
21        index: usize,
22        /// The actual length
23        len: usize,
24    },
25
26    /// Error if the slice index is duplicated
27    #[error("You provided a duplicated slice index {0}")]
28    DuplicateSliceIndex(usize),
29
30    /// Error for sparse multiplication dimension mismatches
31    #[error(
32        "The dimensions of the matrix do not support sparse multiplication (matrix a n_col: {n_col_a}; matrix b n_row: {n_row_b})"
33    )]
34    SparseMatrixMultiplication {
35        /// Number of columns in matrix a
36        n_col_a: usize,
37        /// Number of rows in matrix b
38        n_row_b: usize,
39    },
40
41    /// Dimension mismatch error during construction
42    #[error("The indices (len: {indices_len}) and data (len: {data_len}) need to have same length")]
43    DimensionMisMatchSparse {
44        /// Length indices
45        indices_len: usize,
46        /// Length data
47        data_len: usize,
48    },
49
50    /// Error if the `indptr` is inconsistent with the shape it declares or
51    /// with the stored values.
52    ///
53    /// Raised by
54    /// [`CompressedSparseData2::validate`](crate::sparse::CompressedSparseData2::validate)
55    /// on input that crossed an FFI boundary, where the struct's public fields
56    /// could have been populated with anything.
57    #[error("The sparse indptr is inconsistent ({detail}): expected {expected}, got {got}")]
58    SparseIndptrInvalid {
59        /// Which invariant failed
60        detail: &'static str,
61        /// The value implied by the rest of the structure
62        expected: usize,
63        /// The value actually found
64        got: usize,
65    },
66
67    /// Error if there is a dimension mismatch in terms of the two matrices
68    #[error("The shape of the two sparse matrices must be the same.")]
69    ShapeMismatchSparse,
70
71    /// Error if the sparse matrix is not in CSR.
72    #[error("The SparseCompressedData2 must be in CSR format")]
73    SparseMatrixMustBeCsr,
74
75    /// A row summed to (effectively) zero where a row-stochastic normalisation
76    /// was asked for.
77    ///
78    /// On a kNN-derived affinity matrix every node has `k` out-edges, so a zero
79    /// row means the kernel weights underflowed rather than that the graph is
80    /// legitimately disconnected. Anything built on top of the operator would
81    /// be meaningless, hence an error rather than leaving the row at zero.
82    #[error(
83        "Row {row} of the sparse matrix sums to {row_sum}, which is not positive, so it cannot be normalised to a row-stochastic form (isolated node, or the kernel weights underflowed)"
84    )]
85    SparseMatrixIsolatedRow {
86        /// The offending row index
87        row: usize,
88        /// The row sum that was rejected
89        row_sum: f64,
90    },
91
92    /// A CSR matrix failed one of its structural invariants.
93    ///
94    /// Raised by [`validate_square_csr`](crate::sparse::validate_square_csr).
95    /// The static string names the invariant, because "the graph is malformed"
96    /// alone leaves the caller to bisect their own input.
97    #[error("The CSR matrix is malformed: {0}")]
98    MalformedCsr(&'static str),
99
100    /// Error if the sparse matrix is not in CSC.
101    #[error("The SparseCompressedData2 must be in CSC format")]
102    SparseMatrixMustBeCsc,
103
104    /// Shape mismatch problem for matrices
105    #[error("Expected this shape {expected:?}; got {got:?}.")]
106    ShapeMismatch {
107        /// Expected shape
108        expected: (usize, usize),
109        /// Provided shape
110        got: (usize, usize),
111    },
112}