LMMC
Lamina Mathematic core
载入中...
搜索中...
未找到
sparse_arithmetic.c
浏览该文件的文档.
1
5#include "memory_bridge.h"
6#include "internal.h"
7#include "sparse_internal.h"
8#include "lmmc/sparse.h"
9
10static size_t lmmc_sparse_add_row_counts(
11 const lmmc_sparse_mat_t* a, const lmmc_sparse_mat_t* b,
12 size_t* row_ptr)
13{
14 size_t nnz = 0;
15 for (size_t i = 0; i < a->rows; ++i) {
16 size_t ai = a->row_ptr[i], bi = b->row_ptr[i];
17 size_t a_end = a->row_ptr[i + 1], b_end = b->row_ptr[i + 1];
18 size_t row_nnz = 0;
19 while (ai < a_end && bi < b_end) {
20 if (a->col_idx[ai] < b->col_idx[bi]) {
21 ai++;
22 } else if (a->col_idx[ai] > b->col_idx[bi]) {
23 bi++;
24 } else {
25 ai++;
26 bi++;
27 }
28 row_nnz++;
29 }
30 row_nnz += (a_end - ai) + (b_end - bi);
31 nnz += row_nnz;
32 row_ptr[i + 1] = nnz;
33 }
34 return nnz;
35}
36
37static void lmmc_sparse_add_merge(
38 const lmmc_sparse_mat_t* pa, const lmmc_sparse_mat_t* pb,
39 lmmc_real_t alpha, lmmc_real_t beta,
40 size_t* c_col_idx, lmmc_real_t* c_values)
41{
42 lmmc_real_t tmp_a; LMMC_REAL_INIT(&tmp_a);
43 lmmc_real_t tmp_b; LMMC_REAL_INIT(&tmp_b);
44 size_t c_idx = 0;
45 for (size_t i = 0; i < pa->rows; ++i) {
46 size_t ai = pa->row_ptr[i], bi = pb->row_ptr[i];
47 size_t a_end = pa->row_ptr[i + 1], b_end = pb->row_ptr[i + 1];
48 while (ai < a_end && bi < b_end) {
49 if (pa->col_idx[ai] < pb->col_idx[bi]) {
50 c_col_idx[c_idx] = pa->col_idx[ai];
51 LMMC_REAL_MUL(&c_values[c_idx], &alpha, &pa->values[ai]);
52 c_idx++;
53 ai++;
54 } else if (pa->col_idx[ai] > pb->col_idx[bi]) {
55 c_col_idx[c_idx] = pb->col_idx[bi];
56 LMMC_REAL_MUL(&c_values[c_idx], &beta, &pb->values[bi]);
57 c_idx++;
58 bi++;
59 } else {
60 c_col_idx[c_idx] = pa->col_idx[ai];
61 LMMC_REAL_MUL(&tmp_a, &alpha, &pa->values[ai]);
62 LMMC_REAL_MUL(&tmp_b, &beta, &pb->values[bi]);
63 LMMC_REAL_ADD(&c_values[c_idx], &tmp_a, &tmp_b);
64 c_idx++;
65 ai++;
66 bi++;
67 }
68 }
69 while (ai < a_end) {
70 c_col_idx[c_idx] = pa->col_idx[ai];
71 LMMC_REAL_MUL(&c_values[c_idx], &alpha, &pa->values[ai]);
72 c_idx++;
73 ai++;
74 }
75 while (bi < b_end) {
76 c_col_idx[c_idx] = pb->col_idx[bi];
77 LMMC_REAL_MUL(&c_values[c_idx], &beta, &pb->values[bi]);
78 c_idx++;
79 bi++;
80 }
81 }
82 LMMC_REAL_CLEAR(&tmp_a);
83 LMMC_REAL_CLEAR(&tmp_b);
84}
85
86static void lmmc_sparse_diag_copy(
87 const lmmc_sparse_mat_t* pa, lmmc_vec_t* out_diag)
88{
89 for (size_t i = 0; i < pa->rows; ++i) {
90 for (size_t p = pa->row_ptr[i]; p < pa->row_ptr[i + 1]; ++p) {
91 if (pa->col_idx[p] == i) {
92 LMMC_REAL_SET(&out_diag->data[i], &pa->values[p]);
93 break;
94 }
95 }
96 }
97}
98
99static lmmc_status_t lmmc_sparse_add_validate(
100 const lmmc_sparse_mat_t* a, const lmmc_sparse_mat_t* b,
101 const lmmc_sparse_mat_t* out_c)
102{
103 if (a == NULL || b == NULL || out_c == NULL) {
105 }
106 if (lmmc_sparse_validate(a) != LMMC_STATUS_OK) {
108 }
109 if (lmmc_sparse_validate(b) != LMMC_STATUS_OK) {
111 }
112 if (a->rows != b->rows || a->cols != b->cols) {
114 }
115 return LMMC_STATUS_OK;
116}
117
118static lmmc_status_t lmmc_sparse_add_allocate_values(
119 size_t nnz, size_t** indices, lmmc_real_t** values)
120{
121 *indices = (size_t*)lmmc_memory_alloc_array(nnz, sizeof(size_t));
122 *values = (lmmc_real_t*)lmmc_memory_alloc_array(nnz, sizeof(lmmc_real_t));
123 if (*indices == NULL || *values == NULL) {
125 }
126 for (size_t k = 0; k < nnz; ++k) {
127 LMMC_REAL_INIT(&(*values)[k]);
128 }
129 return LMMC_STATUS_OK;
130}
131
133 lmmc_real_t alpha, const lmmc_sparse_mat_t* a,
134 lmmc_real_t beta, const lmmc_sparse_mat_t* b,
135 lmmc_sparse_mat_t* out_c
136) {
137 lmmc_sparse_mat_t a_csr = {0};
138 lmmc_sparse_mat_t b_csr = {0};
139 const lmmc_sparse_mat_t* pa = a;
140 const lmmc_sparse_mat_t* pb = b;
142 size_t nnz_c = 0;
143 size_t* c_row_ptr = NULL;
144 size_t* c_col_idx = NULL;
145 lmmc_real_t* c_values = NULL;
146
147 st = lmmc_sparse_add_validate(a, b, out_c);
148 if (st != LMMC_STATUS_OK) {
149 return st;
150 }
151
152
153 if (a->format == LMMC_SPARSE_CSC) {
154 st = lmmc_sparse_to_csr(a, &a_csr);
155 if (st != LMMC_STATUS_OK) {
156 return st;
157 }
158 pa = &a_csr;
159 }
160 if (b->format == LMMC_SPARSE_CSC) {
161 st = lmmc_sparse_to_csr(b, &b_csr);
162 if (st != LMMC_STATUS_OK) {
163 lmmc_sparse_destroy(&a_csr);
164 return st;
165 }
166 pb = &b_csr;
167 }
168
169
170 c_row_ptr = (size_t*)lmmc_memory_alloc_array_plus(pa->rows, 1, sizeof(size_t));
171 if (c_row_ptr == NULL) {
173 goto cleanup;
174 }
175 c_row_ptr[0] = 0;
176
177 nnz_c = lmmc_sparse_add_row_counts(pa, pb, c_row_ptr);
178
179
180 if (nnz_c > 0) {
181 st = lmmc_sparse_add_allocate_values(nnz_c, &c_col_idx, &c_values);
182 if (st != LMMC_STATUS_OK) {
183 goto cleanup;
184 }
185 }
186
187
188 if (nnz_c > 0) {
189 lmmc_sparse_add_merge(pa, pb, alpha, beta, c_col_idx, c_values);
190 }
191
192
193 out_c->rows = pa->rows;
194 out_c->cols = pa->cols;
195 out_c->nnz = nnz_c;
196 out_c->row_ptr = c_row_ptr;
197 out_c->col_idx = c_col_idx;
198 out_c->values = c_values;
199 out_c->format = LMMC_SPARSE_CSR;
200 out_c->owns_data = 1;
201
202
203 c_row_ptr = NULL;
204 c_col_idx = NULL;
205 c_values = NULL;
206 st = LMMC_STATUS_OK;
207
208cleanup:
209 if (c_row_ptr) {
210 lmmc_memory_free(c_row_ptr);
211 }
212 if (c_col_idx) {
213 lmmc_memory_free(c_col_idx);
214 }
215 if (c_values) {
216 for (size_t k = 0; k < nnz_c; ++k) {
217 LMMC_REAL_CLEAR(&c_values[k]);
218 }
219 lmmc_memory_free(c_values);
220 }
221 lmmc_sparse_destroy(&a_csr);
222 lmmc_sparse_destroy(&b_csr);
223 return st;
224}
225
228 lmmc_real_t alpha
229) {
230 size_t i;
231 lmmc_real_t tmp; LMMC_REAL_INIT(&tmp);
232
233 if (a == NULL) {
235 }
236
237 lmmc_status_t st = lmmc_sparse_validate(a);
238 if (st != LMMC_STATUS_OK) {
240 }
241
242 for (i = 0; i < a->nnz; ++i) {
243 LMMC_REAL_MUL(&tmp, &a->values[i], &alpha);
244 LMMC_REAL_SET(&a->values[i], &tmp);
245 }
246
247 LMMC_REAL_CLEAR(&tmp);
248 return LMMC_STATUS_OK;
249}
250
252 const lmmc_sparse_mat_t* a,
253 lmmc_real_t* out_norm
254) {
256
257 if (a == NULL || out_norm == NULL) {
259 }
260
261 lmmc_status_t st = lmmc_sparse_validate(a);
262 if (st != LMMC_STATUS_OK) {
264 }
265
266 lmmc_scaled_sumsq_init(&acc);
267 for (size_t i = 0; i < a->nnz; ++i) {
268 lmmc_scaled_sumsq_add(&acc, a->values[i]);
269 }
270 *out_norm = lmmc_scaled_sumsq_norm(&acc);
271 return LMMC_STATUS_OK;
272}
273
275 const lmmc_sparse_mat_t* a,
276 lmmc_vec_t* out_diag
277) {
278 lmmc_sparse_mat_t a_csr = {0};
279 const lmmc_sparse_mat_t* pa = a;
280 lmmc_status_t st;
281 size_t n;
282
283 if (a == NULL || out_diag == NULL) {
285 }
286
287 st = lmmc_sparse_validate(a);
288 if (st != LMMC_STATUS_OK) {
290 }
291
292
293 if (a->rows != a->cols) {
295 }
296
297 n = a->rows;
298
299
300 if (a->format == LMMC_SPARSE_CSC) {
301 st = lmmc_sparse_to_csr(a, &a_csr);
302 if (st != LMMC_STATUS_OK) {
303 return st;
304 }
305 pa = &a_csr;
306 }
307
308
309 if (out_diag->data == NULL || out_diag->size != n) {
310 if (out_diag->data != NULL && out_diag->owns_data) {
311 lmmc_vec_destroy(out_diag);
312 }
313 st = lmmc_vec_create(n, out_diag);
314 if (st != LMMC_STATUS_OK) {
315 lmmc_sparse_destroy(&a_csr);
316 return st;
317 }
318 }
319
320
321 {
322 lmmc_real_t zero;
323 LMMC_REAL_INIT(&zero);
324 LMMC_REAL_SET_D(&zero, 0.0);
325 st = lmmc_vec_fill(out_diag, zero);
326 LMMC_REAL_CLEAR(&zero);
327 if (st != LMMC_STATUS_OK) {
328 lmmc_sparse_destroy(&a_csr);
329 return st;
330 }
331 }
332
333
334 lmmc_sparse_diag_copy(pa, out_diag);
335
336 lmmc_sparse_destroy(&a_csr);
337 return LMMC_STATUS_OK;
338}
#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_MUL(res, a, b)
计算 *res = *a * *b 。
#define LMMC_REAL_SET_D(dst, dbl)
将一个 double 字面量赋值到 lmmc_real_t 。
lmmc_status_t lmmc_vec_fill(lmmc_vec_t *vec, lmmc_real_t value)
就地将向量所有元素设为 value。
lmmc_status_t lmmc_vec_create(size_t size, lmmc_vec_t *out_vec)
创建长度为 size 的零向量。
void lmmc_vec_destroy(lmmc_vec_t *vec)
销毁向量,释放其拥有的缓冲区并清零字段。
lmmc_real_t * data
一维稠密向量。
LMMC 内部使用的公共工具(仅源文件可见).
void * lmmc_memory_alloc_array(size_t count, size_t element_size)
void * lmmc_memory_alloc_array_plus(size_t count, size_t extra, size_t element_size)
void lmmc_memory_free(void *pointer)
Private recoverable allocator for persistent LMMC ownership.
lmmc_status_t lmmc_sparse_scale(lmmc_sparse_mat_t *a, lmmc_real_t alpha)
就地标量缩放: 。
lmmc_status_t lmmc_sparse_diag(const lmmc_sparse_mat_t *a, lmmc_vec_t *out_diag)
提取主对角线为稠密向量.要求 a->rows == a->cols 。
lmmc_status_t lmmc_sparse_norm_fro(const lmmc_sparse_mat_t *a, lmmc_real_t *out_norm)
用缩放平方和计算稀疏矩阵的 Frobenius 范数。
lmmc_status_t lmmc_sparse_add(lmmc_real_t alpha, const lmmc_sparse_mat_t *a, lmmc_real_t beta, const lmmc_sparse_mat_t *b, lmmc_sparse_mat_t *out_c)
计算 C = alpha * A + beta * B .要求 a 与 b 同维同格式。
稀疏矩阵模块内部共享辅助函数(仅源文件可见)。
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_SPARSE_CSR
@ LMMC_SPARSE_CSC
lmmc_sparse_format_t format
通用稀疏矩阵(CSR / CSC 共用同一结构)。
lmmc_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_OK
@ LMMC_STATUS_DIMENSION_MISMATCH
@ LMMC_STATUS_ALLOCATION_FAILED
@ LMMC_STATUS_INVALID_ARGUMENT