LMMC
Lamina Mathematic core
载入中...
搜索中...
未找到
optimize.c
浏览该文件的文档.
1#include "optimize_internal.h"
2
4 const lmmc_optimize_config_t* cfg,
5 const char* operation,
6 size_t iteration,
7 const lmmc_real_t* values,
8 size_t value_count
9) {
10 const lmmc_diagnostic_t diagnostic = {
11 LMMC_DIAGNOSTIC_TRACE, operation, "iteration", iteration,
12 values, value_count
13 };
14 lmmc_diagnostic_emit(&cfg->diagnostics, &diagnostic);
15}
16
18 const lmmc_optimize_config_t* cfg)
19{
20 if (cfg == NULL) {
21 return 0;
22 }
23 if (!isfinite(cfg->abs_tol) || cfg->abs_tol < 0.0) {
24 return 0;
25 }
26 if (!isfinite(cfg->rel_tol) || cfg->rel_tol < 0.0 || cfg->rel_tol >= 1.0) {
27 return 0;
28 }
29 if (cfg->max_iter == 0 || cfg->lbfgs_memory == 0) {
30 return 0;
31 }
32 return isfinite(cfg->lm_damping) && cfg->lm_damping > 0.0;
33}
34
36 lmmc_real_t residual,
37 lmmc_real_t initial_residual,
38 const lmmc_optimize_config_t* cfg)
39{
40 return residual <= cfg->abs_tol ||
41 (initial_residual > 0.0 &&
42 residual <= cfg->rel_tol * initial_residual);
43}
44
50 size_t i;
51 lmmc_scaled_sumsq_init(&acc);
52 for (i = 0; i < v->size; ++i) {
53 const lmmc_real_t value_abs = fabs(v->data[i]);
54 if (!isfinite(value_abs)) {
55 return value_abs;
56 }
57 lmmc_scaled_sumsq_add(&acc, value_abs);
58 }
59 return lmmc_scaled_sumsq_norm(&acc);
60}
61
63 if (cfg == NULL) {
65 }
66 cfg->abs_tol = 1e-12;
67 cfg->rel_tol = 1e-10;
68 cfg->max_iter = 1000;
69 cfg->lbfgs_memory = 10;
70 cfg->lm_damping = 1e-3;
72 return LMMC_STATUS_OK;
73}
74
77{
78 return x != NULL && out != NULL && x->data != NULL &&
79 lmmc_optimize_config_is_valid(cfg) && x->size != 0;
80}
81
83{
84 out->converged = 0;
85 out->num_iter = 0;
86 out->final_residual = NAN;
88}
89
91 size_t iteration, const lmmc_optimize_config_t* cfg,
93{
94 out->final_residual = norm;
95 if (!isfinite(norm)) {
97 return 1;
98 }
99 if (iteration == 0) {
100 *initial = norm;
101 }
102 if (lmmc_optimize_has_converged(norm, *initial, cfg)) {
103 out->converged = 1;
104 return 1;
105 }
106 if (iteration == cfg->max_iter) {
108 return 1;
109 }
110 return 0;
111}
112
113static int optimize_workspace_count(
114 size_t n, size_t vectors, size_t matrices, size_t extra, size_t* count)
115{
116 size_t vector_count, matrix_count = 0;
117 if (!lmmc_safe_mul_size(n, vectors, &vector_count)) {
118 return 0;
119 }
120 if (matrices != 0) {
121 if (!lmmc_safe_mul_size(n, n, &matrix_count) ||
122 !lmmc_safe_mul_size(matrix_count, matrices, &matrix_count)) {
123 return 0;
124 }
125 }
126 return lmmc_safe_add_size(vector_count, matrix_count, count) &&
127 lmmc_safe_add_size(*count, extra, count);
128}
129
131 size_t n, size_t vectors, size_t matrices, size_t extra,
132 int need_pivots, lmmc_opt_workspace_t* work)
133{
134 size_t count, scalar_bytes, pivot_bytes = 0, bytes;
135 const size_t alignment = _Alignof(lmmc_real_t);
136 if (!optimize_workspace_count(n, vectors, matrices, extra, &count) ||
137 !lmmc_safe_mul_size(count, sizeof(lmmc_real_t), &scalar_bytes)) {
139 }
140 if (need_pivots) {
141 if (!lmmc_safe_mul_size(n, sizeof(size_t), &pivot_bytes) ||
142 !lmmc_safe_add_size(pivot_bytes, alignment - 1, &pivot_bytes)) {
144 }
145 pivot_bytes -= pivot_bytes % alignment;
146 }
147 if (!lmmc_safe_add_size(pivot_bytes, scalar_bytes, &bytes)) {
149 }
150 work->allocation = lmmc_memory_alloc(bytes);
151 if (work->allocation == NULL) {
153 }
154 memset(work->allocation, 0, bytes);
155 work->pivots = need_pivots ? (size_t*)work->allocation : NULL;
156 work->next = (lmmc_real_t*)((unsigned char*)work->allocation + pivot_bytes);
157 return LMMC_STATUS_OK;
158}
159
161{
162 const lmmc_vec_t result = {n, work->next, 0};
163 work->next += n;
164 return result;
165}
166
168{
169 const lmmc_mat_t result = {n, n, n, work->next, 0};
170 work->next += n * n;
171 return result;
172}
173
174static lmmc_status_t optimize_perturb(
175 const lmmc_vec_t* x, size_t j, lmmc_vec_t* x_pert, lmmc_real_t* step)
176{
177 lmmc_real_t h = sqrt(LMMC_REAL_EPSILON) * fmax(fabs(x->data[j]), 1.0);
178 lmmc_real_t perturbed_x = x->data[j] + h;
179 memcpy(x_pert->data, x->data, x->size * sizeof(lmmc_real_t));
180 if (!isfinite(perturbed_x) || perturbed_x == x->data[j]) {
181 perturbed_x = x->data[j] - h;
182 }
183 if (!isfinite(perturbed_x) || perturbed_x == x->data[j]) {
184 perturbed_x = nextafter(x->data[j], 0.0);
185 }
186 h = perturbed_x - x->data[j];
187 if (!isfinite(perturbed_x) || !isfinite(h) || h == 0.0) {
189 }
190 x_pert->data[j] = perturbed_x;
191 *step = h;
192 return LMMC_STATUS_OK;
193}
194
195static lmmc_status_t optimize_difference_column(
196 const lmmc_vec_t* Fx, const lmmc_vec_t* F_pert,
197 lmmc_real_t h, size_t j, lmmc_mat_t* matrix)
198{
199 size_t i;
200 for (i = 0; i < Fx->size; ++i) {
201 lmmc_real_t derivative;
202 if (!isfinite(F_pert->data[i]) || !isfinite(Fx->data[i])) {
204 }
205 derivative = (F_pert->data[i] - Fx->data[i]) / h;
206 if (!isfinite(derivative)) {
208 }
209 matrix->data[i * matrix->stride + j] = derivative;
210 }
211 return LMMC_STATUS_OK;
212}
213
215 lmmc_opt_func_t F, lmmc_opt_jac_t J, void* user_data,
216 const lmmc_vec_t* x, const lmmc_vec_t* Fx, lmmc_mat_t* matrix,
217 lmmc_vec_t* x_pert, lmmc_vec_t* F_pert)
218{
219 size_t j;
220 if (J != NULL) {
221 return J(x, matrix, user_data);
222 }
223 for (j = 0; j < x->size; ++j) {
224 lmmc_real_t h;
225 lmmc_status_t status = optimize_perturb(x, j, x_pert, &h);
226 if (status != LMMC_STATUS_OK) {
227 return status;
228 }
229 status = F(x_pert, F_pert, user_data);
230 if (status != LMMC_STATUS_OK) {
231 return status;
232 }
233 status = optimize_difference_column(Fx, F_pert, h, j, matrix);
234 if (status != LMMC_STATUS_OK) {
235 return status;
236 }
237 }
238 return LMMC_STATUS_OK;
239}
240
242 lmmc_opt_obj_t obj, void* user_data, const lmmc_vec_t* x,
243 const lmmc_vec_t* direction, lmmc_vec_t* trial,
244 lmmc_real_t* value, lmmc_real_t derivative, int attempts, int subtract)
245{
246 lmmc_real_t step = 1.0;
247 const lmmc_real_t c1 = 1e-4;
248 int attempt;
249 size_t i;
250 for (attempt = 0; attempt < attempts; ++attempt) {
251 for (i = 0; i < x->size; ++i) {
252 if (subtract) {
253 trial->data[i] = x->data[i] - step * direction->data[i];
254 } else {
255 trial->data[i] = x->data[i] + step * direction->data[i];
256 }
257 }
258 const lmmc_real_t next = obj(trial, user_data);
259 if (next <= *value + c1 * step * derivative) {
260 *value = next;
261 return 1;
262 }
263 step *= 0.5;
264 }
265 return 0;
266}
double lmmc_real_t
Public and internal LMMC real type.
#define LMMC_REAL_EPSILON
既有算法的经验近似阈值,非机器 epsilon。
lmmc_real_t * data
lmmc_real_t * data
行优先存储的稠密矩阵。
一维稠密向量。
void lmmc_diagnostic_emit(const lmmc_diagnostic_sink_t *sink, const lmmc_diagnostic_t *diagnostic)
通过调用方持有的接收器发送一个诊断事件;空接收器直接完成.
@ LMMC_DIAGNOSTIC_TRACE
void * lmmc_memory_alloc(size_t size)
int lmmc_optimize_armijo(lmmc_opt_obj_t obj, void *user_data, const lmmc_vec_t *x, const lmmc_vec_t *direction, lmmc_vec_t *trial, lmmc_real_t *value, lmmc_real_t derivative, int attempts, int subtract)
lmmc_real_t lmmc_optimize_norm(const lmmc_vec_t *v)
计算向量的 L2 范数。
int lmmc_optimize_config_is_valid(const lmmc_optimize_config_t *cfg)
lmmc_mat_t lmmc_opt_workspace_matrix(lmmc_opt_workspace_t *work, size_t n)
lmmc_status_t lmmc_optimize_jacobian(lmmc_opt_func_t F, lmmc_opt_jac_t J, void *user_data, const lmmc_vec_t *x, const lmmc_vec_t *Fx, lmmc_mat_t *matrix, lmmc_vec_t *x_pert, lmmc_vec_t *F_pert)
临时向量由外层求解器一次性分配。
void lmmc_optimize_emit(const lmmc_optimize_config_t *cfg, const char *operation, size_t iteration, const lmmc_real_t *values, size_t value_count)
lmmc_vec_t lmmc_opt_workspace_vector(lmmc_opt_workspace_t *work, size_t n)
int lmmc_optimize_stop(lmmc_real_t norm, lmmc_real_t *initial, size_t iteration, const lmmc_optimize_config_t *cfg, lmmc_optimize_result_t *out)
int lmmc_optimize_has_converged(lmmc_real_t residual, lmmc_real_t initial_residual, const lmmc_optimize_config_t *cfg)
lmmc_status_t lmmc_opt_workspace_create(size_t n, size_t vectors, size_t matrices, size_t extra, int need_pivots, lmmc_opt_workspace_t *work)
void lmmc_optimize_result_init(lmmc_optimize_result_t *out)
int lmmc_optimize_arguments_valid(const lmmc_vec_t *x, const lmmc_optimize_config_t *cfg, const lmmc_optimize_result_t *out)
@ LMMC_OPT_FAILURE_MAX_ITER
@ LMMC_OPT_FAILURE_NONE
@ LMMC_OPT_FAILURE_NUMERICAL_ISSUE
lmmc_status_t(*) lmmc_opt_func_t(const lmmc_vec_t *x, lmmc_vec_t *F, void *user_data)
非线性函数回调:计算 F(x)。
lmmc_optimize_failure_t failure_reason
lmmc_status_t(*) lmmc_opt_jac_t(const lmmc_vec_t *x, lmmc_mat_t *J, void *user_data)
Jacobian 回调:计算 J(x)。
lmmc_diagnostic_sink_t diagnostics
lmmc_status_t lmmc_optimize_default_config(lmmc_optimize_config_t *cfg)
初始化默认优化配置。
lmmc_real_t(*) lmmc_opt_obj_t(const lmmc_vec_t *x, void *user_data)
目标函数回调:计算标量 f(x)。
优化算法配置参数。
工作区由本次调用拥有,视图仅借用存储,释放由调用方负责。
lmmc_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_OK
@ LMMC_STATUS_NUMERICAL_FAILURE
@ LMMC_STATUS_ALLOCATION_FAILED
@ LMMC_STATUS_INVALID_ARGUMENT