LMMC
Lamina Mathematic core
载入中...
搜索中...
未找到
sparse_conversion.c
浏览该文件的文档.
1
5#include <stdlib.h>
6#include <string.h>
7
8#include "memory_bridge.h"
9#include "internal.h"
10#include "sparse_internal.h"
11#include "lmmc/sparse.h"
12
14 size_t i = 0, j = 0, nz = 0;
16 if (dense == NULL || out_sparse == NULL || dense->data == NULL) {
18 }
19
20 lmmc_real_t zero; LMMC_REAL_INIT(&zero);
21 lmmc_real_t abs_v; LMMC_REAL_INIT(&abs_v);
22 LMMC_REAL_SET_D(&zero, 0.0);
23
24 if (LMMC_REAL_CMP(&eps, &zero) < 0) {
25 LMMC_REAL_CLEAR(&zero);
26 LMMC_REAL_CLEAR(&abs_v);
28 }
29
30 for (i = 0; i < dense->rows; ++i) {
31 for (j = 0; j < dense->cols; ++j) {
32 LMMC_REAL_ABS(&abs_v, &dense->data[i * dense->stride + j]);
33 if (LMMC_REAL_CMP(&abs_v, &eps) > 0) ++nz;
34 }
35 }
36
37 st = lmmc_sparse_create_csr(dense->rows, dense->cols, nz, out_sparse);
38 if (st != LMMC_STATUS_OK) {
39 LMMC_REAL_CLEAR(&zero);
40 LMMC_REAL_CLEAR(&abs_v);
41 return st;
42 }
43
44 nz = 0;
45 out_sparse->row_ptr[0] = 0;
46 for (i = 0; i < dense->rows; ++i) {
47 for (j = 0; j < dense->cols; ++j) {
48 lmmc_real_t* v_ptr = &dense->data[i * dense->stride + j];
49 LMMC_REAL_ABS(&abs_v, v_ptr);
50 if (LMMC_REAL_CMP(&abs_v, &eps) > 0) {
51 out_sparse->col_idx[nz] = j;
52 LMMC_REAL_SET(&out_sparse->values[nz], v_ptr);
53 ++nz;
54 }
55 }
56 out_sparse->row_ptr[i + 1] = nz;
57 }
58
59 LMMC_REAL_CLEAR(&zero);
60 LMMC_REAL_CLEAR(&abs_v);
61 return LMMC_STATUS_OK;
62}
63
65 size_t i = 0, p = 0;
66 lmmc_status_t st = lmmc_sparse_validate(sparse);
67
68 if (st != LMMC_STATUS_OK || out_dense == NULL || out_dense->data == NULL) {
70 }
71 if (out_dense->rows != sparse->rows || out_dense->cols != sparse->cols) {
73 }
74
75 lmmc_real_t zero; LMMC_REAL_INIT(&zero);
76 LMMC_REAL_SET_D(&zero, 0.0);
77 st = lmmc_mat_fill(out_dense, zero);
78 if (st != LMMC_STATUS_OK) {
79 LMMC_REAL_CLEAR(&zero);
80 return st;
81 }
82
83 if (sparse->format == LMMC_SPARSE_CSR) {
84 for (i = 0; i < sparse->rows; ++i) {
85 for (p = sparse->row_ptr[i]; p < sparse->row_ptr[i + 1]; ++p) {
86 LMMC_REAL_SET(&out_dense->data[i * out_dense->stride + sparse->col_idx[p]], &sparse->values[p]);
87 }
88 }
89 } else {
90 for (i = 0; i < sparse->cols; ++i) {
91 for (p = sparse->row_ptr[i]; p < sparse->row_ptr[i + 1]; ++p) {
92 LMMC_REAL_SET(&out_dense->data[sparse->col_idx[p] * out_dense->stride + i], &sparse->values[p]);
93 }
94 }
95 }
96
97 LMMC_REAL_CLEAR(&zero);
98 return LMMC_STATUS_OK;
99}
101 size_t i = 0, p = 0;
102 size_t* next = NULL;
103 lmmc_status_t st = lmmc_sparse_validate(sparse);
104
105 if (st != LMMC_STATUS_OK || out_transposed == NULL) {
107 }
108
109 st = lmmc_sparse_create(sparse->cols, sparse->rows, sparse->nnz, sparse->format, out_transposed);
110 if (st != LMMC_STATUS_OK) {
111 return st;
112 }
113
114 size_t outer_size_src = (sparse->format == LMMC_SPARSE_CSR) ? sparse->rows : sparse->cols;
115 size_t inner_size_src = (sparse->format == LMMC_SPARSE_CSR) ? sparse->cols : sparse->rows;
116
117 for (p = 0; p < sparse->nnz; ++p) {
118 ++out_transposed->row_ptr[sparse->col_idx[p] + 1];
119 }
120
121 for (i = 0; i < inner_size_src; ++i) {
122 out_transposed->row_ptr[i + 1] += out_transposed->row_ptr[i];
123 }
124
125 if (out_transposed->nnz == 0) {
126 return LMMC_STATUS_OK;
127 }
128
129 next = (size_t*)lmmc_memory_alloc_array(inner_size_src, sizeof(size_t));
130 if (next == NULL) {
131 lmmc_sparse_destroy(out_transposed);
133 }
134 memcpy(next, out_transposed->row_ptr, inner_size_src * sizeof(size_t));
135
136 for (i = 0; i < outer_size_src; ++i) {
137 for (p = sparse->row_ptr[i]; p < sparse->row_ptr[i + 1]; ++p) {
138 size_t inner = sparse->col_idx[p];
139 size_t dst = next[inner]++;
140 out_transposed->col_idx[dst] = i;
141 LMMC_REAL_SET(&out_transposed->values[dst], &sparse->values[p]);
142 }
143 }
144
145 lmmc_memory_free(next);
146 return LMMC_STATUS_OK;
147}
149 if (src == NULL || dst == NULL) {
151 }
152 lmmc_status_t st = lmmc_sparse_validate(src);
153 if (st != LMMC_STATUS_OK) {
154 return st;
155 }
156
157 if (src->format == LMMC_SPARSE_CSC) {
158 st = lmmc_sparse_create_csc(src->rows, src->cols, src->nnz, dst);
159 if (st != LMMC_STATUS_OK) {
160 return st;
161 }
162 memcpy(dst->row_ptr, src->row_ptr, (src->cols + 1) * sizeof(size_t));
163 if (src->nnz > 0) {
164 memcpy(dst->col_idx, src->col_idx, src->nnz * sizeof(size_t));
165 for (size_t k = 0; k < src->nnz; ++k) {
166 LMMC_REAL_SET(&dst->values[k], &src->values[k]);
167 }
168 }
169 return LMMC_STATUS_OK;
170 }
171
172 st = lmmc_sparse_create_csc(src->rows, src->cols, src->nnz, dst);
173 if (st != LMMC_STATUS_OK) {
174 return st;
175 }
176
177 for (size_t p = 0; p < src->nnz; ++p) {
178 ++dst->row_ptr[src->col_idx[p] + 1];
179 }
180 for (size_t i = 0; i < src->cols; ++i) {
181 dst->row_ptr[i + 1] += dst->row_ptr[i];
182 }
183
184 size_t* next = (size_t*)lmmc_memory_alloc_array(src->cols, sizeof(size_t));
185 if (next == NULL) {
188 }
189 memcpy(next, dst->row_ptr, src->cols * sizeof(size_t));
190
191 for (size_t i = 0; i < src->rows; ++i) {
192 for (size_t p = src->row_ptr[i]; p < src->row_ptr[i + 1]; ++p) {
193 size_t col = src->col_idx[p];
194 size_t dest_idx = next[col]++;
195 dst->col_idx[dest_idx] = i;
196 LMMC_REAL_SET(&dst->values[dest_idx], &src->values[p]);
197 }
198 }
199 lmmc_memory_free(next);
200 return LMMC_STATUS_OK;
201}
202
204 if (src == NULL || dst == NULL) {
206 }
207 lmmc_status_t st = lmmc_sparse_validate(src);
208 if (st != LMMC_STATUS_OK) {
209 return st;
210 }
211
212 if (src->format == LMMC_SPARSE_CSR) {
213 st = lmmc_sparse_create_csr(src->rows, src->cols, src->nnz, dst);
214 if (st != LMMC_STATUS_OK) {
215 return st;
216 }
217 memcpy(dst->row_ptr, src->row_ptr, (src->rows + 1) * sizeof(size_t));
218 if (src->nnz > 0) {
219 memcpy(dst->col_idx, src->col_idx, src->nnz * sizeof(size_t));
220 for (size_t k = 0; k < src->nnz; ++k) {
221 LMMC_REAL_SET(&dst->values[k], &src->values[k]);
222 }
223 }
224 return LMMC_STATUS_OK;
225 }
226
227 st = lmmc_sparse_create_csr(src->rows, src->cols, src->nnz, dst);
228 if (st != LMMC_STATUS_OK) {
229 return st;
230 }
231
232 for (size_t p = 0; p < src->nnz; ++p) {
233 ++dst->row_ptr[src->col_idx[p] + 1];
234 }
235 for (size_t i = 0; i < src->rows; ++i) {
236 dst->row_ptr[i + 1] += dst->row_ptr[i];
237 }
238
239 size_t* next = (size_t*)lmmc_memory_alloc_array(src->rows, sizeof(size_t));
240 if (next == NULL) {
243 }
244 memcpy(next, dst->row_ptr, src->rows * sizeof(size_t));
245
246 for (size_t i = 0; i < src->cols; ++i) {
247 for (size_t p = src->row_ptr[i]; p < src->row_ptr[i + 1]; ++p) {
248 size_t row = src->col_idx[p];
249 size_t dest_idx = next[row]++;
250 dst->col_idx[dest_idx] = i;
251 LMMC_REAL_SET(&dst->values[dest_idx], &src->values[p]);
252 }
253 }
254 lmmc_memory_free(next);
255 return LMMC_STATUS_OK;
256}
257typedef struct {
258 size_t row;
259 size_t col;
260 size_t orig_idx;
262
263static int lmmc_coo_cmp_row_col(const void* a, const void* b) {
264 const lmmc_coo_sort_entry_t* ea = (const lmmc_coo_sort_entry_t*)a;
265 const lmmc_coo_sort_entry_t* eb = (const lmmc_coo_sort_entry_t*)b;
266 if (ea->row != eb->row) {
267 return (ea->row < eb->row) ? -1 : 1;
268 }
269 if (ea->col != eb->col) {
270 return (ea->col < eb->col) ? -1 : 1;
271 }
272 return (ea->orig_idx > eb->orig_idx) - (ea->orig_idx < eb->orig_idx);
273}
274
275
276static int lmmc_coo_cmp_col_row(const void* a, const void* b) {
277 const lmmc_coo_sort_entry_t* ea = (const lmmc_coo_sort_entry_t*)a;
278 const lmmc_coo_sort_entry_t* eb = (const lmmc_coo_sort_entry_t*)b;
279 if (ea->col != eb->col) {
280 return (ea->col < eb->col) ? -1 : 1;
281 }
282 if (ea->row != eb->row) {
283 return (ea->row < eb->row) ? -1 : 1;
284 }
285 return (ea->orig_idx > eb->orig_idx) - (ea->orig_idx < eb->orig_idx);
286}
287
288static void lmmc_coo_compressed_offsets(
289 const lmmc_coo_sort_entry_t* entries, size_t nnz, size_t outer_size,
290 int column_major, size_t* row_ptr)
291{
292 size_t prev_row = entries[0].row;
293 size_t prev_col = entries[0].col;
294 memset(row_ptr, 0, (outer_size + 1) * sizeof(size_t));
295 row_ptr[(column_major ? prev_col : prev_row) + 1]++;
296 for (size_t i = 1; i < nnz; ++i) {
297 if (entries[i].row != prev_row || entries[i].col != prev_col) {
298 row_ptr[(column_major ? entries[i].col : entries[i].row) + 1]++;
299 prev_row = entries[i].row;
300 prev_col = entries[i].col;
301 }
302 }
303 for (size_t i = 0; i < outer_size; ++i) {
304 row_ptr[i + 1] += row_ptr[i];
305 }
306}
307
308static void lmmc_coo_compressed_values(
309 const lmmc_sparse_coo_t* coo, const lmmc_coo_sort_entry_t* entries,
310 int column_major, lmmc_sparse_mat_t* out,
311 lmmc_real_t* sum, lmmc_real_t* tmp)
312{
313 size_t index = 0;
314 size_t cur_row = entries[0].row;
315 size_t cur_col = entries[0].col;
316 LMMC_REAL_SET(sum, &coo->values[entries[0].orig_idx]);
317 for (size_t i = 1; i < coo->nnz; ++i) {
318 if (entries[i].row == cur_row && entries[i].col == cur_col) {
319 LMMC_REAL_ADD(tmp, sum, &coo->values[entries[i].orig_idx]);
320 LMMC_REAL_SET(sum, tmp);
321 } else {
322 out->col_idx[index] = column_major ? cur_row : cur_col;
323 LMMC_REAL_SET(&out->values[index], sum);
324 index++;
325 cur_row = entries[i].row;
326 cur_col = entries[i].col;
327 LMMC_REAL_SET(sum, &coo->values[entries[i].orig_idx]);
328 }
329 }
330 out->col_idx[index] = column_major ? cur_row : cur_col;
331 LMMC_REAL_SET(&out->values[index], sum);
332}
333
334
335static lmmc_status_t lmmc_sparse_coo_validate(const lmmc_sparse_coo_t* coo) {
336 if (coo == NULL || coo->rows == 0 || coo->cols == 0 ||
337 coo->nnz > coo->capacity ||
338 (coo->nnz > 0 && (coo->row_idx == NULL || coo->col_idx == NULL || coo->values == NULL))) {
340 }
341 for (size_t i = 0; i < coo->nnz; ++i) {
342 if (coo->row_idx[i] >= coo->rows || coo->col_idx[i] >= coo->cols) {
344 }
345 }
346 return LMMC_STATUS_OK;
347}
348
350 const lmmc_sparse_coo_t* coo,
351 lmmc_sparse_mat_t* out_csr
352) {
353 lmmc_coo_sort_entry_t* entries = NULL;
354 size_t unique_nnz = 0;
355 size_t i;
356 lmmc_status_t st;
357
358 if (out_csr == NULL || lmmc_sparse_coo_validate(coo) != LMMC_STATUS_OK) {
360 }
361
362
363 if (coo->nnz == 0) {
364 return lmmc_sparse_create_csr(coo->rows, coo->cols, 0, out_csr);
365 }
366
367
369 if (entries == NULL) {
371 }
372
373 for (i = 0; i < coo->nnz; ++i) {
374 entries[i].row = coo->row_idx[i];
375 entries[i].col = coo->col_idx[i];
376 entries[i].orig_idx = i;
377 }
378
379
380 qsort(entries, coo->nnz, sizeof(lmmc_coo_sort_entry_t), lmmc_coo_cmp_row_col);
381
382
383 unique_nnz = 1;
384 for (i = 1; i < coo->nnz; ++i) {
385 if (entries[i].row != entries[i - 1].row || entries[i].col != entries[i - 1].col) {
386 unique_nnz++;
387 }
388 }
389
390
391 st = lmmc_sparse_create_csr(coo->rows, coo->cols, unique_nnz, out_csr);
392 if (st != LMMC_STATUS_OK) {
393 lmmc_memory_free(entries);
394 return st;
395 }
396
397
398 {
399 lmmc_real_t sum; LMMC_REAL_INIT(&sum);
400 lmmc_real_t tmp; LMMC_REAL_INIT(&tmp);
401
402
403 lmmc_coo_compressed_offsets(entries, coo->nnz, coo->rows, 0, out_csr->row_ptr);
404 lmmc_coo_compressed_values(coo, entries, 0, out_csr, &sum, &tmp);
405
406 LMMC_REAL_CLEAR(&sum);
407 LMMC_REAL_CLEAR(&tmp);
408 }
409
410 lmmc_memory_free(entries);
411 return LMMC_STATUS_OK;
412}
413
415 const lmmc_sparse_coo_t* coo,
416 lmmc_sparse_mat_t* out_csc
417) {
418 lmmc_coo_sort_entry_t* entries = NULL;
419 size_t unique_nnz = 0;
420 size_t i;
421 lmmc_status_t st;
422
423 if (out_csc == NULL || lmmc_sparse_coo_validate(coo) != LMMC_STATUS_OK) {
425 }
426
427
428 if (coo->nnz == 0) {
429 return lmmc_sparse_create_csc(coo->rows, coo->cols, 0, out_csc);
430 }
431
432
434 if (entries == NULL) {
436 }
437
438 for (i = 0; i < coo->nnz; ++i) {
439 entries[i].row = coo->row_idx[i];
440 entries[i].col = coo->col_idx[i];
441 entries[i].orig_idx = i;
442 }
443
444
445 qsort(entries, coo->nnz, sizeof(lmmc_coo_sort_entry_t), lmmc_coo_cmp_col_row);
446
447
448 unique_nnz = 1;
449 for (i = 1; i < coo->nnz; ++i) {
450 if (entries[i].row != entries[i - 1].row || entries[i].col != entries[i - 1].col) {
451 unique_nnz++;
452 }
453 }
454
455
456 st = lmmc_sparse_create_csc(coo->rows, coo->cols, unique_nnz, out_csc);
457 if (st != LMMC_STATUS_OK) {
458 lmmc_memory_free(entries);
459 return st;
460 }
461
462
463 {
464 lmmc_real_t sum; LMMC_REAL_INIT(&sum);
465 lmmc_real_t tmp; LMMC_REAL_INIT(&tmp);
466
467 lmmc_coo_compressed_values(coo, entries, 1, out_csc, &sum, &tmp);
468 lmmc_coo_compressed_offsets(entries, coo->nnz, coo->cols, 1, out_csc->row_ptr);
469
470 LMMC_REAL_CLEAR(&sum);
471 LMMC_REAL_CLEAR(&tmp);
472 }
473
474 lmmc_memory_free(entries);
475 return LMMC_STATUS_OK;
476}
477
479 if (coo == NULL) {
480 return;
481 }
482 if (coo->values != NULL) {
483 for (size_t k = 0; k < coo->capacity; ++k) {
484 LMMC_REAL_CLEAR(&coo->values[k]);
485 }
487 }
488 if (coo->row_idx != NULL) {
490 }
491 if (coo->col_idx != NULL) {
493 }
494 coo->rows = 0;
495 coo->cols = 0;
496 coo->nnz = 0;
497 coo->capacity = 0;
498 coo->row_idx = NULL;
499 coo->col_idx = NULL;
500 coo->values = NULL;
501}
#define LMMC_REAL_CLEAR(x)
释放一个 lmmc_real_t 变量(POD 类型为空操作)。
#define LMMC_REAL_INIT(x)
初始化一个 lmmc_real_t 变量(POD 类型为空操作)。
#define LMMC_REAL_ADD(res, a, b)
计算 *res = *a + *b 。
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_array(size_t count, size_t element_size)
void lmmc_memory_free(void *pointer)
Private recoverable allocator for persistent LMMC ownership.
稀疏矩阵模块内部共享辅助函数(仅源文件可见)。
lmmc_status_t lmmc_sparse_create_csc(size_t rows, size_t cols, size_t nnz, lmmc_sparse_mat_t *out_sparse)
为指定 nnz 的 CSC 矩阵分配数组。
lmmc_status_t lmmc_sparse_transpose(const lmmc_sparse_mat_t *sparse, lmmc_sparse_mat_t *out_transposed)
计算稀疏矩阵转置,保持原存储格式。
lmmc_status_t lmmc_sparse_coo_to_csr(const lmmc_sparse_coo_t *coo, lmmc_sparse_mat_t *out_csr)
将 COO 排序为 CSR,重复坐标按插入顺序累加,保留显式零。 要求非零维度、nnz<=capacity、有效条目数组和范围内坐标。 输入保持不变;非法描述符返回 INVALID_ARGUMENT,输...
lmmc_status_t lmmc_sparse_to_csc(const lmmc_sparse_mat_t *src, lmmc_sparse_mat_t *dst)
转换为 CSC,src 已为 CSC 时执行深拷贝。
lmmc_status_t lmmc_sparse_to_csr(const lmmc_sparse_mat_t *src, lmmc_sparse_mat_t *dst)
转换为 CSR,src 已为 CSR 时执行深拷贝。
void lmmc_sparse_destroy(lmmc_sparse_mat_t *sparse)
销毁稀疏矩阵,释放其拥有的缓冲区并清零全部字段。
lmmc_status_t lmmc_sparse_create_csr(size_t rows, size_t cols, size_t nnz, lmmc_sparse_mat_t *out_sparse)
为指定 nnz 的 CSR 矩阵分配数组。
lmmc_status_t lmmc_sparse_to_dense(const lmmc_sparse_mat_t *sparse, lmmc_mat_t *out_dense)
将稀疏矩阵展开为稠密矩阵,缺失项填零。
lmmc_status_t lmmc_sparse_coo_to_csc(const lmmc_sparse_coo_t *coo, lmmc_sparse_mat_t *out_csc)
将 COO 转换为 CSC,校验、稳定合并与显式零语义同 COO→CSR。
void lmmc_sparse_coo_destroy(lmmc_sparse_coo_t *coo)
销毁 COO 矩阵并释放缓冲区。
lmmc_status_t lmmc_sparse_from_dense(const lmmc_mat_t *dense, lmmc_real_t eps, lmmc_sparse_mat_t *out_sparse)
由稠密矩阵生成 CSR,丢弃绝对值 <= eps 的元素。
@ LMMC_SPARSE_CSR
@ LMMC_SPARSE_CSC
lmmc_sparse_format_t format
三元组 (COO) 形式的稀疏矩阵临时表示。
通用稀疏矩阵(CSR / CSC 共用同一结构)。
lmmc_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_OK
@ LMMC_STATUS_DIMENSION_MISMATCH
@ LMMC_STATUS_ALLOCATION_FAILED
@ LMMC_STATUS_INVALID_ARGUMENT