LMMC
Lamina Mathematic core
载入中...
搜索中...
未找到
precond_ilut.c
浏览该文件的文档.
1#include "precond_internal.h"
2
3static lmmc_status_t lmmc_ilut_load_row(const lmmc_sparse_mat_t* a,
4 size_t i, lmmc_ilu_row_t* row) {
5 row->count = 0;
6 for (size_t p = a->row_ptr[i]; p < a->row_ptr[i + 1]; ++p) {
7 size_t col = a->col_idx[p];
8 lmmc_real_t value = a->values[p];
9 if (!isfinite(value)) {
11 }
12 if (!row->present[col]) {
13 row->present[col] = 1;
14 row->processed[col] = 0;
15 row->active[row->count++] = col;
16 row->values[col] = value;
17 } else {
18 row->values[col] = row->values[col] + value;
19 if (!isfinite(row->values[col])) {
21 }
22 }
23 }
24 return LMMC_STATUS_OK;
25}
26
27static size_t lmmc_ilut_next_lower(const lmmc_ilu_row_t* row, size_t i) {
28 size_t k = (size_t)-1;
29 for (size_t p = 0; p < row->count; ++p) {
30 size_t col = row->active[p];
31 if (!row->present[col] || row->processed[col] || col >= i) {
32 continue;
33 }
34 if (k == (size_t)-1 || col < k) {
35 k = col;
36 }
37 }
38 return k;
39}
40
41static lmmc_status_t lmmc_ilut_subtract_upper(const lmmc_precond_ilu_impl_t* impl,
42 lmmc_ilu_row_t* row, size_t k, lmmc_real_t multiplier) {
43 for (size_t p = impl->diag_pos[k] + 1; p < impl->row_ptr[k + 1]; ++p) {
44 size_t j = impl->col_idx[p];
45 lmmc_real_t delta = multiplier * impl->lu_values[p];
46 if (j <= k) {
47 continue;
48 }
49 if (!isfinite(delta)) {
51 }
52 if (!row->present[j]) {
53 row->present[j] = 1;
54 row->processed[j] = 0;
55 row->active[row->count++] = j;
56 row->values[j] = -delta;
57 } else {
58 row->values[j] = row->values[j] - delta;
59 }
60 if (!isfinite(row->values[j])) {
62 }
63 }
64 return LMMC_STATUS_OK;
65}
66
67static lmmc_status_t lmmc_ilut_eliminate_entry(const lmmc_precond_ilu_impl_t* impl,
68 lmmc_ilu_row_t* row, size_t k, lmmc_real_t drop_tol) {
69 row->processed[k] = 1;
70 lmmc_real_t aik = row->values[k];
71 if (!isfinite(aik)) {
73 }
74 if (fabs(aik) <= drop_tol) {
75 row->present[k] = 0;
76 row->values[k] = 0.0;
77 return LMMC_STATUS_OK;
78 }
79 if (impl->diag_pos[k] == (size_t)-1 || impl->diag_pos[k] >= impl->nnz) {
81 }
82 lmmc_real_t diag = impl->lu_values[impl->diag_pos[k]];
83 if (!isfinite(diag) || fabs(diag) <= 1e-15) {
85 }
86 lmmc_real_t multiplier = aik / diag;
87 if (!isfinite(multiplier)) {
89 }
90 row->values[k] = multiplier;
91 return lmmc_ilut_subtract_upper(impl, row, k, multiplier);
92}
93
94static lmmc_status_t lmmc_ilut_eliminate_row(const lmmc_precond_ilu_impl_t* impl,
95 lmmc_ilu_row_t* row, size_t i, lmmc_real_t drop_tol) {
96 for (;;) {
97 size_t k = lmmc_ilut_next_lower(row, i);
98 if (k == (size_t)-1) {
99 return LMMC_STATUS_OK;
100 }
101 lmmc_status_t st = lmmc_ilut_eliminate_entry(impl, row, k, drop_tol);
102 if (st != LMMC_STATUS_OK) {
103 return st;
104 }
105 }
106}
107
108static lmmc_status_t lmmc_ilut_append_entries(lmmc_precond_ilu_impl_t* impl,
109 const lmmc_ilu_row_t* row, const size_t* cols, size_t count) {
110 for (size_t p = 0; p < count; ++p) {
111 size_t col = cols[p];
112 lmmc_real_t value = row->values[col];
113 if (!isfinite(value)) {
115 }
116 impl->col_idx[impl->nnz] = col;
117 impl->lu_values[impl->nnz] = value;
118 impl->nnz += 1;
119 }
120 return LMMC_STATUS_OK;
121}
122
123static lmmc_status_t lmmc_ilut_store_row(lmmc_precond_ilu_impl_t* impl,
124 lmmc_ilu_row_t* row, size_t i, lmmc_real_t drop_tol, size_t fill) {
125 if (!row->present[i]) {
126 row->present[i] = 1;
127 row->processed[i] = 0;
128 row->active[row->count++] = i;
129 row->values[i] = 0.0;
130 }
131 lmmc_real_t diag = row->values[i];
132 if (!isfinite(diag) || fabs(diag) <= 1e-15) {
134 }
135 size_t lower_count, upper_count;
136 lmmc_ilu_select(row, i, 1, drop_tol, fill, row->lower, &lower_count);
137 lmmc_ilu_select(row, i, 0, drop_tol, fill, row->upper, &upper_count);
138 size_t needed = lower_count + 1 + upper_count;
139 if (impl->nnz > (size_t)-1 - needed) {
141 }
142 lmmc_status_t st = lmmc_ilu_impl_reserve(impl, impl->nnz + needed);
143 if (st != LMMC_STATUS_OK) {
144 return st;
145 }
146 st = lmmc_ilut_append_entries(impl, row, row->lower, lower_count);
147 if (st != LMMC_STATUS_OK) {
148 return st;
149 }
150 impl->diag_pos[i] = impl->nnz;
151 impl->col_idx[impl->nnz] = i;
152 impl->lu_values[impl->nnz] = diag;
153 impl->nnz += 1;
154 st = lmmc_ilut_append_entries(impl, row, row->upper, upper_count);
155 if (st != LMMC_STATUS_OK) {
156 return st;
157 }
158 impl->row_ptr[i + 1] = impl->nnz;
159 return LMMC_STATUS_OK;
160}
161
162static lmmc_status_t lmmc_ilut_factor(const lmmc_sparse_mat_t* a,
164 lmmc_real_t drop_tol, size_t fill) {
165 size_t capacity = a->nnz;
166 if (capacity < 16) {
167 capacity = 16;
168 }
169 if (capacity < a->rows && a->rows <= (size_t)-1 - capacity) {
170 capacity += a->rows;
171 }
172 lmmc_status_t st = lmmc_ilu_impl_reserve(impl, capacity);
173 if (st != LMMC_STATUS_OK) {
174 return st;
175 }
176 impl->row_ptr[0] = 0;
177 for (size_t i = 0; i < a->rows; ++i) {
178 st = lmmc_ilut_load_row(a, i, row);
179 if (st != LMMC_STATUS_OK) {
180 return st;
181 }
182 st = lmmc_ilut_eliminate_row(impl, row, i, drop_tol);
183 if (st != LMMC_STATUS_OK) {
184 return st;
185 }
186 st = lmmc_ilut_store_row(impl, row, i, drop_tol, fill);
187 if (st != LMMC_STATUS_OK) {
188 return st;
189 }
191 }
192 return LMMC_STATUS_OK;
193}
194
196 lmmc_real_t drop_tol, size_t max_fill_per_row, lmmc_precond_t* out_precond) {
197 lmmc_status_t st = lmmc_sparse_validate(a);
198 if (out_precond == NULL || st != LMMC_STATUS_OK ||
199 a->format != LMMC_SPARSE_CSR || !isfinite(drop_tol) ||
200 drop_tol < 0.0 || max_fill_per_row == 0) {
202 }
203 if (a->rows != a->cols) {
205 }
206 size_t bytes;
207 st = lmmc_ilu_row_bytes(a->rows, max_fill_per_row, &bytes);
208 if (st != LMMC_STATUS_OK) {
209 return st;
210 }
211 lmmc_precond_ilu_impl_t* impl = NULL;
212 lmmc_ilu_row_t row = {0};
213 st = lmmc_ilu_impl_create(a->rows, &impl);
214 if (st != LMMC_STATUS_OK) {
215 return st;
216 }
217 st = lmmc_ilu_row_create(a->rows, max_fill_per_row, bytes, &row);
218 if (st == LMMC_STATUS_OK) {
219 st = lmmc_ilut_factor(a, impl, &row, drop_tol, max_fill_per_row);
220 }
222 if (st != LMMC_STATUS_OK) {
224 return st;
225 }
226 out_precond->type = LMMC_PRECOND_ILUT;
227 out_precond->size = a->rows;
228 out_precond->impl = impl;
229 out_precond->owns_data = 1;
230 return LMMC_STATUS_OK;
231}
double lmmc_real_t
Public and internal LMMC real type.
void lmmc_memory_free(void *pointer)
lmmc_precond_type_t type
@ LMMC_PRECOND_ILUT
lmmc_status_t lmmc_precond_create_ilut(const lmmc_sparse_mat_t *a, lmmc_real_t drop_tol, size_t max_fill_per_row, lmmc_precond_t *out_precond)
创建 ILUT 预处理子。
通用预处理子句柄。
lmmc_status_t lmmc_ilu_impl_reserve(lmmc_precond_ilu_impl_t *impl, size_t required)
lmmc_status_t lmmc_ilu_row_create(size_t n, size_t fill, size_t bytes, lmmc_ilu_row_t *row)
lmmc_status_t lmmc_ilu_impl_create(size_t size, lmmc_precond_ilu_impl_t **out)
unsigned char * processed
void lmmc_ilu_impl_destroy(lmmc_precond_ilu_impl_t *impl)
lmmc_status_t lmmc_ilu_row_bytes(size_t n, size_t fill, size_t *bytes)
void lmmc_ilu_select(const lmmc_ilu_row_t *row, size_t i, int lower, lmmc_real_t drop_tol, size_t max_keep, size_t *cols, size_t *count)
unsigned char * present
void lmmc_ilu_row_reset(lmmc_ilu_row_t *row)
行工作区仅分配一次,以下指针均借用该内存。
@ LMMC_SPARSE_CSR
lmmc_sparse_format_t format
通用稀疏矩阵(CSR / CSC 共用同一结构)。
lmmc_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_OK
@ LMMC_STATUS_NUMERICAL_FAILURE
@ LMMC_STATUS_DIMENSION_MISMATCH
@ LMMC_STATUS_SINGULAR_MATRIX
@ LMMC_STATUS_INVALID_ARGUMENT