LMMC
Lamina Mathematic core
载入中...
搜索中...
未找到
sparse_block.c
浏览该文件的文档.
1
5#include <string.h>
6
7#include "memory_bridge.h"
8#include "internal.h"
9#include "sparse_internal.h"
10#include "lmmc/sparse.h"
11
12lmmc_status_t lmmc_sparse_bsr_create(size_t rows, size_t cols, size_t block_size,
13 size_t nnz_blocks, lmmc_sparse_bsr_t* out) {
14 size_t row_ptr_bytes = 0;
15 size_t col_idx_bytes = 0;
16 size_t val_count = 0;
17 size_t val_bytes = 0;
18
19 if (out == NULL || rows == 0 || cols == 0 || block_size == 0) {
21 }
22
23 /* 计算所需内存大小,检查溢出 */
24 if (!lmmc_safe_mul_size(rows + 1, sizeof(size_t), &row_ptr_bytes)) {
26 }
27 if (!lmmc_safe_mul_size(nnz_blocks, sizeof(size_t), &col_idx_bytes)) {
29 }
30 if (!lmmc_safe_mul_size(block_size, block_size, &val_count)) {
32 }
33 if (!lmmc_safe_mul_size(val_count, nnz_blocks, &val_count)) {
35 }
36 if (!lmmc_safe_mul_size(val_count, sizeof(lmmc_real_t), &val_bytes)) {
38 }
39
40 out->row_ptr = (size_t*)lmmc_memory_alloc(row_ptr_bytes);
41 if (out->row_ptr == NULL) {
43 }
44 memset(out->row_ptr, 0, row_ptr_bytes);
45
46 out->col_idx = NULL;
47 out->values = NULL;
48
49 if (nnz_blocks > 0) {
50 out->col_idx = (size_t*)lmmc_memory_alloc(col_idx_bytes);
51 if (out->col_idx == NULL) {
53 out->row_ptr = NULL;
55 }
56 memset(out->col_idx, 0, col_idx_bytes);
57
58 out->values = (lmmc_real_t*)lmmc_memory_alloc(val_bytes);
59 if (out->values == NULL) {
62 out->col_idx = NULL;
63 out->row_ptr = NULL;
65 }
66 memset(out->values, 0, val_bytes);
67 }
68
69 out->rows = rows;
70 out->cols = cols;
71 out->block_size = block_size;
72 out->nnz_blocks = nnz_blocks;
73 out->owns_data = 1;
74 return LMMC_STATUS_OK;
75}
76
77static void lmmc_sparse_bsr_scatter(
78 const lmmc_sparse_bsr_t* bsr, lmmc_mat_t* out)
79{
80 size_t bi, p, li, lj;
81 for (bi = 0; bi < bsr->rows; ++bi) {
82 for (p = bsr->row_ptr[bi]; p < bsr->row_ptr[bi + 1]; ++p) {
83 size_t bj = bsr->col_idx[p];
84 size_t block_offset = p * bsr->block_size * bsr->block_size;
85 size_t row_base = bi * bsr->block_size;
86 size_t col_base = bj * bsr->block_size;
87
88 for (li = 0; li < bsr->block_size; ++li) {
89 for (lj = 0; lj < bsr->block_size; ++lj) {
90 size_t dense_idx = (row_base + li) * out->stride + (col_base + lj);
91 size_t block_idx = block_offset + li * bsr->block_size + lj;
92 LMMC_REAL_SET(&out->data[dense_idx], &bsr->values[block_idx]);
93 }
94 }
95 }
96 }
97}
98
99static int lmmc_sparse_dense_block_nonzero(
100 const lmmc_mat_t* dense, size_t block_size, size_t bi, size_t bj,
101 const lmmc_real_t* eps, lmmc_real_t* abs_v)
102{
103 for (size_t li = 0; li < block_size; ++li) {
104 for (size_t lj = 0; lj < block_size; ++lj) {
105 size_t row = bi * block_size + li;
106 size_t col = bj * block_size + lj;
107 LMMC_REAL_ABS(abs_v, &dense->data[row * dense->stride + col]);
108 if (LMMC_REAL_CMP(abs_v, eps) > 0) {
109 return 1;
110 }
111 }
112 }
113 return 0;
114}
115
116static void lmmc_sparse_dense_block_copy(
117 const lmmc_mat_t* dense, lmmc_sparse_bsr_t* out,
118 size_t bi, size_t bj, size_t nz_idx)
119{
120 size_t block_size = out->block_size;
121 size_t block_offset = nz_idx * block_size * block_size;
122 out->col_idx[nz_idx] = bj;
123 for (size_t li = 0; li < block_size; ++li) {
124 for (size_t lj = 0; lj < block_size; ++lj) {
125 size_t row = bi * block_size + li;
126 size_t col = bj * block_size + lj;
127 size_t blk_idx = block_offset + li * block_size + lj;
128 LMMC_REAL_SET(&out->values[blk_idx],
129 &dense->data[row * dense->stride + col]);
130 }
131 }
132}
133
134static void lmmc_sparse_bsr_gather(
135 const lmmc_mat_t* dense, const lmmc_real_t* eps,
136 lmmc_real_t* abs_v, lmmc_sparse_bsr_t* out)
137{
138 size_t nz_idx = 0;
139 out->row_ptr[0] = 0;
140 for (size_t bi = 0; bi < out->rows; ++bi) {
141 for (size_t bj = 0; bj < out->cols; ++bj) {
142 if (lmmc_sparse_dense_block_nonzero(
143 dense, out->block_size, bi, bj, eps, abs_v)) {
144 lmmc_sparse_dense_block_copy(dense, out, bi, bj, nz_idx);
145 ++nz_idx;
146 }
147 }
148 out->row_ptr[bi + 1] = nz_idx;
149 }
150}
151
152
154 size_t dense_rows, dense_cols;
155 lmmc_real_t zero;
156 lmmc_status_t st;
157
158 if (bsr == NULL || out == NULL || out->data == NULL) {
160 }
161 if (bsr->rows == 0 || bsr->cols == 0 || bsr->block_size == 0) {
163 }
164 if (bsr->row_ptr == NULL) {
166 }
167 if (bsr->nnz_blocks > 0 && (bsr->col_idx == NULL || bsr->values == NULL)) {
169 }
170
171 dense_rows = bsr->rows * bsr->block_size;
172 dense_cols = bsr->cols * bsr->block_size;
173
174 if (out->rows != dense_rows || out->cols != dense_cols) {
176 }
177
178 /* 先清零输出矩阵 */
179 LMMC_REAL_INIT(&zero);
180 LMMC_REAL_SET_D(&zero, 0.0);
181 st = lmmc_mat_fill(out, zero);
182 LMMC_REAL_CLEAR(&zero);
183 if (st != LMMC_STATUS_OK) {
184 return st;
185 }
186
187 lmmc_sparse_bsr_scatter(bsr, out);
188
189 return LMMC_STATUS_OK;
190}
191
192lmmc_status_t lmmc_sparse_dense_to_bsr(const lmmc_mat_t* dense, size_t block_size,
193 lmmc_real_t eps, lmmc_sparse_bsr_t* out) {
194 size_t block_rows, block_cols;
195 size_t bi, bj;
196 size_t nnz_blocks = 0;
197 lmmc_status_t st;
198 lmmc_real_t abs_v;
199 lmmc_real_t zero;
200
201 if (dense == NULL || out == NULL || dense->data == NULL) {
203 }
204 if (block_size == 0) {
206 }
207 if (dense->rows % block_size != 0 || dense->cols % block_size != 0) {
209 }
210
211 LMMC_REAL_INIT(&abs_v);
212 LMMC_REAL_INIT(&zero);
213 LMMC_REAL_SET_D(&zero, 0.0);
214
215 if (LMMC_REAL_CMP(&eps, &zero) < 0) {
216 LMMC_REAL_CLEAR(&abs_v);
217 LMMC_REAL_CLEAR(&zero);
219 }
220
221 block_rows = dense->rows / block_size;
222 block_cols = dense->cols / block_size;
223
224 /* 第一遍:计算非零块数量 */
225 for (bi = 0; bi < block_rows; ++bi) {
226 for (bj = 0; bj < block_cols; ++bj) {
227 if (lmmc_sparse_dense_block_nonzero(
228 dense, block_size, bi, bj, &eps, &abs_v)) {
229 ++nnz_blocks;
230 }
231 }
232 }
233
234 /* 分配 BSR 结构 */
235 st = lmmc_sparse_bsr_create(block_rows, block_cols, block_size, nnz_blocks, out);
236 if (st != LMMC_STATUS_OK) {
237 LMMC_REAL_CLEAR(&abs_v);
238 LMMC_REAL_CLEAR(&zero);
239 return st;
240 }
241 if (nnz_blocks == 0) {
242 LMMC_REAL_CLEAR(&abs_v);
243 LMMC_REAL_CLEAR(&zero);
244 return LMMC_STATUS_OK;
245 }
246
247 /* 第二遍:填充数据 */
248 lmmc_sparse_bsr_gather(dense, &eps, &abs_v, out);
249
250 LMMC_REAL_CLEAR(&abs_v);
251 LMMC_REAL_CLEAR(&zero);
252 return LMMC_STATUS_OK;
253}
254
256 if (bsr == NULL) {
257 return;
258 }
259 if (bsr->owns_data) {
260 if (bsr->row_ptr != NULL) {
262 }
263 if (bsr->col_idx != NULL) {
265 }
266 if (bsr->values != NULL) {
268 }
269 }
270 bsr->row_ptr = NULL;
271 bsr->col_idx = NULL;
272 bsr->values = NULL;
273 bsr->rows = 0;
274 bsr->cols = 0;
275 bsr->block_size = 0;
276 bsr->nnz_blocks = 0;
277 bsr->owns_data = 0;
278}
#define LMMC_REAL_CLEAR(x)
释放一个 lmmc_real_t 变量(POD 类型为空操作)。
#define LMMC_REAL_INIT(x)
初始化一个 lmmc_real_t 变量(POD 类型为空操作)。
double lmmc_real_t
Public and internal LMMC real type.
#define LMMC_REAL_SET(dst, src)
将一个 lmmc_real_t 赋值到另一个:*dst = *src 。
#define LMMC_REAL_ABS(res, a)
计算绝对值,*res = |*a| 。
#define LMMC_REAL_CMP(a, b)
比较 *a 与 *b ,返回 -1/0/1 。
#define LMMC_REAL_SET_D(dst, dbl)
将一个 double 字面量赋值到 lmmc_real_t 。
lmmc_status_t lmmc_mat_fill(lmmc_mat_t *mat, lmmc_real_t value)
就地将矩阵所有元素设为 value。
lmmc_real_t * data
行优先存储的稠密矩阵。
LMMC 内部使用的公共工具(仅源文件可见).
void * lmmc_memory_alloc(size_t size)
void lmmc_memory_free(void *pointer)
Private recoverable allocator for persistent LMMC ownership.
稀疏矩阵模块内部共享辅助函数(仅源文件可见)。
void lmmc_sparse_bsr_destroy(lmmc_sparse_bsr_t *bsr)
销毁 BSR 矩阵,按所有权释放底层缓冲区。
lmmc_status_t lmmc_sparse_bsr_create(size_t rows, size_t cols, size_t block_size, size_t nnz_blocks, lmmc_sparse_bsr_t *out)
创建 BSR 矩阵,数组内容未初始化。
lmmc_status_t lmmc_sparse_bsr_to_dense(const lmmc_sparse_bsr_t *bsr, lmmc_mat_t *out)
将 BSR 矩阵展开为稠密矩阵。
lmmc_status_t lmmc_sparse_dense_to_bsr(const lmmc_mat_t *dense, size_t block_size, lmmc_real_t eps, lmmc_sparse_bsr_t *out)
将稠密矩阵转换为 BSR 格式。
块稀疏行 (BSR) 格式矩阵。
lmmc_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_OK
@ LMMC_STATUS_DIMENSION_MISMATCH
@ LMMC_STATUS_ALLOCATION_FAILED
@ LMMC_STATUS_INVALID_ARGUMENT