Skip to main content

rusparse/
conversion.rs

1use crate::{
2    CooMatrix, CooMatrixOwned, CscMatrix, CscMatrixOwned, CsrMatrix, CsrMatrixOwned, DenseMatrix,
3    DenseMatrixOwned, DenseOrder, IndexBase, SparseError, dimension,
4};
5
6pub fn dense_to_csr(
7    dense: DenseMatrix<'_>,
8    index_base: IndexBase,
9) -> Result<CsrMatrixOwned, SparseError> {
10    let base = index_base.value();
11    let mut row_offsets = Vec::with_capacity(dense.rows + 1);
12    let mut column_indices = Vec::new();
13    let mut values = Vec::new();
14    row_offsets.push(base);
15    for row in 0..dense.rows {
16        for column in 0..dense.columns {
17            let value = dense.values[dense_index(dense, row, column)];
18            if value != 0.0 {
19                column_indices.push(
20                    dimension(column, "dense to CSR column")?
21                        .checked_add(base)
22                        .ok_or(SparseError::SizeOverflow("dense to CSR column"))?,
23                );
24                values.push(value);
25            }
26        }
27        row_offsets.push(encoded_count(
28            values.len(),
29            base,
30            "dense to CSR row offsets",
31        )?);
32    }
33    CsrMatrixOwned::new(
34        dense.rows,
35        dense.columns,
36        row_offsets,
37        column_indices,
38        values,
39        index_base,
40    )
41}
42
43pub fn dense_to_coo(
44    dense: DenseMatrix<'_>,
45    index_base: IndexBase,
46) -> Result<CooMatrixOwned, SparseError> {
47    let base = index_base.value();
48    let mut row_indices = Vec::new();
49    let mut column_indices = Vec::new();
50    let mut values = Vec::new();
51    for row in 0..dense.rows {
52        for column in 0..dense.columns {
53            let value = dense.values[dense_index(dense, row, column)];
54            if value != 0.0 {
55                row_indices.push(encoded_index(row, base, "dense to COO row")?);
56                column_indices.push(encoded_index(column, base, "dense to COO column")?);
57                values.push(value);
58            }
59        }
60    }
61    CooMatrixOwned::new(
62        dense.rows,
63        dense.columns,
64        row_indices,
65        column_indices,
66        values,
67        index_base,
68    )
69}
70
71pub fn dense_to_csc(
72    dense: DenseMatrix<'_>,
73    index_base: IndexBase,
74) -> Result<CscMatrixOwned, SparseError> {
75    let base = index_base.value();
76    let mut column_offsets = Vec::with_capacity(dense.columns + 1);
77    let mut row_indices = Vec::new();
78    let mut values = Vec::new();
79    column_offsets.push(base);
80    for column in 0..dense.columns {
81        for row in 0..dense.rows {
82            let value = dense.values[dense_index(dense, row, column)];
83            if value != 0.0 {
84                row_indices.push(encoded_index(row, base, "dense to CSC row")?);
85                values.push(value);
86            }
87        }
88        column_offsets.push(encoded_count(
89            values.len(),
90            base,
91            "dense to CSC column offsets",
92        )?);
93    }
94    CscMatrixOwned::new(
95        dense.rows,
96        dense.columns,
97        column_offsets,
98        row_indices,
99        values,
100        index_base,
101    )
102}
103
104pub fn csr_to_dense(
105    matrix: CsrMatrix<'_>,
106    order: DenseOrder,
107) -> Result<DenseMatrixOwned, SparseError> {
108    let mut output = zero_dense(matrix.rows, matrix.columns, order)?;
109    let base = matrix.index_base.value();
110    for row in 0..matrix.rows {
111        let start = (matrix.row_offsets[row] - base) as usize;
112        let end = (matrix.row_offsets[row + 1] - base) as usize;
113        for entry in start..end {
114            let column = (matrix.column_indices[entry] - base) as usize;
115            let index = physical_index(matrix.rows, matrix.columns, order, row, column);
116            output[index] = matrix.values[entry];
117        }
118    }
119    DenseMatrixOwned::new(output, matrix.rows, matrix.columns, order)
120}
121
122pub fn coo_to_dense(
123    matrix: CooMatrix<'_>,
124    order: DenseOrder,
125) -> Result<DenseMatrixOwned, SparseError> {
126    let mut output = zero_dense(matrix.rows(), matrix.columns(), order)?;
127    let base = matrix.index_base().value();
128    for entry in 0..matrix.nnz() {
129        let row = (matrix.row_indices()[entry] - base) as usize;
130        let column = (matrix.column_indices()[entry] - base) as usize;
131        let index = physical_index(matrix.rows(), matrix.columns(), order, row, column);
132        output[index] = matrix.values()[entry];
133    }
134    DenseMatrixOwned::new(output, matrix.rows(), matrix.columns(), order)
135}
136
137pub fn csc_to_dense(
138    matrix: CscMatrix<'_>,
139    order: DenseOrder,
140) -> Result<DenseMatrixOwned, SparseError> {
141    let mut output = zero_dense(matrix.rows(), matrix.columns(), order)?;
142    let base = matrix.index_base().value();
143    for column in 0..matrix.columns() {
144        let start = (matrix.column_offsets()[column] - base) as usize;
145        let end = (matrix.column_offsets()[column + 1] - base) as usize;
146        for entry in start..end {
147            let row = (matrix.row_indices()[entry] - base) as usize;
148            let index = physical_index(matrix.rows(), matrix.columns(), order, row, column);
149            output[index] = matrix.values()[entry];
150        }
151    }
152    DenseMatrixOwned::new(output, matrix.rows(), matrix.columns(), order)
153}
154
155fn dense_index(matrix: DenseMatrix<'_>, row: usize, column: usize) -> usize {
156    physical_index(matrix.rows, matrix.columns, matrix.order, row, column)
157}
158
159fn physical_index(
160    rows: usize,
161    columns: usize,
162    order: DenseOrder,
163    row: usize,
164    column: usize,
165) -> usize {
166    match order {
167        DenseOrder::RowMajor => row * columns + column,
168        DenseOrder::ColumnMajor => column * rows + row,
169    }
170}
171
172fn zero_dense(rows: usize, columns: usize, _order: DenseOrder) -> Result<Vec<f32>, SparseError> {
173    let elements = rows
174        .checked_mul(columns)
175        .ok_or(SparseError::SizeOverflow("sparse to dense output"))?;
176    Ok(vec![0.0; elements])
177}
178
179fn encoded_index(value: usize, base: u32, name: &'static str) -> Result<u32, SparseError> {
180    dimension(value, name)?
181        .checked_add(base)
182        .ok_or(SparseError::SizeOverflow(name))
183}
184
185fn encoded_count(value: usize, base: u32, name: &'static str) -> Result<u32, SparseError> {
186    encoded_index(value, base, name)
187}