LMMC
Lamina Mathematic core
载入中...
搜索中...
未找到
optimize_broyden.c
浏览该文件的文档.
1#include "optimize_internal.h"
2
8
9static lmmc_status_t broyden_workspace_create(
10 size_t n, lmmc_broyden_workspace_t* work)
11{
12 lmmc_status_t status = lmmc_opt_workspace_create(n, 6, 2, 0, 1, &work->arena);
13 if (status != LMMC_STATUS_OK) { return status; }
14 work->value = lmmc_opt_workspace_vector(&work->arena, n);
16 work->delta_x = lmmc_opt_workspace_vector(&work->arena, n);
17 work->delta_F = lmmc_opt_workspace_vector(&work->arena, n);
18 work->Bdx = lmmc_opt_workspace_vector(&work->arena, n);
19 work->rhs = lmmc_opt_workspace_vector(&work->arena, n);
20 work->B = lmmc_opt_workspace_matrix(&work->arena, n);
21 work->lu = lmmc_opt_workspace_matrix(&work->arena, n);
22 return LMMC_STATUS_OK;
23}
24
25static lmmc_optimize_failure_t broyden_step(
27{
28 const size_t n = x->size;
29 lmmc_status_t status;
30 size_t i;
31 memcpy(work->lu.data, work->B.data, n * n * sizeof(lmmc_real_t));
32 status = lmmc_lu_decompose_inplace(&work->lu, work->arena.pivots, NULL);
33 if (status == LMMC_STATUS_SINGULAR_MATRIX) {
35 }
36 if (status != LMMC_STATUS_OK) { return LMMC_OPT_FAILURE_NUMERICAL_ISSUE; }
37 for (i = 0; i < n; ++i) {
38 work->rhs.data[i] = -work->value.data[i];
39 }
40 status = lmmc_lu_solve(&work->lu, work->arena.pivots,
41 &work->rhs, &work->delta_x);
42 if (status != LMMC_STATUS_OK) { return LMMC_OPT_FAILURE_SINGULAR_JACOBIAN; }
43 for (i = 0; i < n; ++i) {
44 x->data[i] += work->delta_x.data[i];
45 }
47}
48
49static void broyden_rank_one_update(lmmc_broyden_workspace_t* work)
50{
51 const size_t n = work->value.size;
52 lmmc_real_t dxTdx = 0.0;
53 size_t i, j;
54 for (i = 0; i < n; ++i) {
55 work->delta_F.data[i] = work->next_value.data[i] - work->value.data[i];
56 }
57 for (i = 0; i < n; ++i) {
58 work->Bdx.data[i] = 0.0;
59 for (j = 0; j < n; ++j) {
60 work->Bdx.data[i] += work->B.data[i * work->B.stride + j] *
61 work->delta_x.data[j];
62 }
63 }
64 for (i = 0; i < n; ++i) {
65 dxTdx += work->delta_x.data[i] * work->delta_x.data[i];
66 }
67 if (dxTdx > 1e-300) {
68 for (i = 0; i < n; ++i) {
69 const lmmc_real_t num_i = work->delta_F.data[i] - work->Bdx.data[i];
70 for (j = 0; j < n; ++j) {
71 work->B.data[i * work->B.stride + j] +=
72 num_i * work->delta_x.data[j] / dxTdx;
73 }
74 }
75 }
76 memcpy(work->value.data, work->next_value.data, n * sizeof(lmmc_real_t));
77}
78
80 lmmc_opt_func_t F, void* user_data, lmmc_vec_t* x,
82{
84 lmmc_status_t status;
85 lmmc_real_t initial_residual = 0.0;
86 size_t iter;
87 if (F == NULL || !lmmc_optimize_arguments_valid(x, cfg, out)) {
89 }
91 status = broyden_workspace_create(x->size, &work);
92 if (status != LMMC_STATUS_OK) { return status; }
93 status = F(x, &work.value, user_data);
94 if (status != LMMC_STATUS_OK) {
96 goto cleanup;
97 }
98 for (iter = 0; ; ++iter) {
99 const lmmc_real_t norm = lmmc_optimize_norm(&work.value);
100 if (lmmc_optimize_stop(norm, &initial_residual, iter, cfg, out)) { break; }
101 if (iter == 0) {
103 status = lmmc_optimize_jacobian(F, NULL, user_data, x, &work.value,
104 &work.B, &work.delta_x, &work.next_value);
105 if (status != LMMC_STATUS_OK) {
107 break;
108 }
109 }
110 out->failure_reason = broyden_step(&work, x);
111 if (out->failure_reason != LMMC_OPT_FAILURE_NONE) { break; }
112 out->num_iter = iter + 1;
113 status = F(x, &work.next_value, user_data);
114 if (status != LMMC_STATUS_OK) {
115 out->final_residual = NAN;
117 break;
118 }
119 broyden_rank_one_update(&work);
120 lmmc_optimize_emit(cfg, "broyden", iter + 1, &norm, 1);
121 }
122cleanup:
124 return LMMC_STATUS_OK;
125}
double lmmc_real_t
Public and internal LMMC real type.
lmmc_real_t * data
lmmc_real_t * data
行优先存储的稠密矩阵。
一维稠密向量。
lmmc_status_t lmmc_lu_solve(const lmmc_mat_t *lu, const size_t *pivots, const lmmc_vec_t *b, lmmc_vec_t *x)
利用 LU 分解结果求解线性系统 A*x = b。
lmmc_status_t lmmc_lu_decompose_inplace(lmmc_mat_t *a, size_t *pivots, size_t *out_swap_count)
就地 LU 分解(带部分主元选取):P*A = L*U。
void lmmc_memory_free(void *pointer)
lmmc_real_t lmmc_optimize_norm(const lmmc_vec_t *v)
计算向量的 L2 范数。
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)
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_optimize_failure_t
优化失败原因枚举。
@ LMMC_OPT_FAILURE_NONE
@ LMMC_OPT_FAILURE_SINGULAR_JACOBIAN
@ 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_status_t lmmc_nleq_broyden(lmmc_opt_func_t F, void *user_data, lmmc_vec_t *x, const lmmc_optimize_config_t *cfg, lmmc_optimize_result_t *out)
Broyden 法求解非线性方程组 F(x) = 0。
lmmc_optimize_failure_t failure_reason
优化算法配置参数。
工作区由本次调用拥有,视图仅借用存储,释放由调用方负责。
lmmc_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_OK
@ LMMC_STATUS_SINGULAR_MATRIX
@ LMMC_STATUS_INVALID_ARGUMENT