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}