LMMC
Lamina Mathematic core
载入中...
搜索中...
未找到
statistics_descriptive.c
浏览该文件的文档.
1#include <float.h>
2#include <math.h>
3#include <stdlib.h>
4
5#include "memory_bridge.h"
6#include "lmmc/config.h"
7#include "lmmc/numeric.h"
8#include "lmmc/stats.h"
9
10#include "statistics_internal.h"
11
12static lmmc_status_t lmmc_mean_strided(
13 const lmmc_real_t* data,
14 size_t count,
15 size_t stride,
16 lmmc_real_t* out_mean
17) {
18 lmmc_real_t mean;
19 size_t i;
20
21 if (data == NULL || count == 0 || out_mean == NULL) { return LMMC_STATUS_INVALID_ARGUMENT; }
22 mean = data[0];
23 if (!isfinite(mean)) { return LMMC_STATUS_NUMERICAL_FAILURE; }
24
25 for (i = 1; i < count; ++i) {
26 const lmmc_real_t value = data[i * stride];
27 const lmmc_real_t sample_count = (lmmc_real_t)(i + 1);
28 const lmmc_real_t delta = value - mean;
29 if (!isfinite(value)) { return LMMC_STATUS_NUMERICAL_FAILURE; }
30 if (isfinite(delta)) {
31 mean = fma(delta, 1.0 / sample_count, mean);
32 } else {
33 mean = mean * ((sample_count - 1.0) / sample_count) +
34 value / sample_count;
35 }
36 if (!isfinite(mean)) { return LMMC_STATUS_NUMERICAL_FAILURE; }
37 }
38 *out_mean = mean;
39 return LMMC_STATUS_OK;
40}
41
47
48static lmmc_status_t lmmc_scaled_column(
49 const lmmc_real_t* data,
50 size_t count,
51 size_t stride,
53 lmmc_real_t* out_m2
54) {
55 lmmc_real_t scale = 0.0;
56 lmmc_real_t m2 = 0.0;
57 size_t i;
58
59 for (i = 0; i < count; ++i) {
60 const lmmc_real_t value = data[i * stride];
61 if (!isfinite(value)) { return LMMC_STATUS_NUMERICAL_FAILURE; }
62 scale = fmax(scale, fabs(value));
63 }
64 column->exponent = 0;
65 if (scale != 0.0) {
66 frexp(scale, &column->exponent);
67 }
68 column->origin = scalbn(data[0], -column->exponent);
69 column->mean = 0.0;
70
75 for (i = 1; i < count; ++i) {
76 const lmmc_real_t value =
77 scalbn(data[i * stride], -column->exponent) - column->origin;
78 const lmmc_real_t delta = value - column->mean;
79 const lmmc_real_t sample_count = (lmmc_real_t)(i + 1);
80 column->mean = fma(delta, 1.0 / sample_count, column->mean);
81 if (out_m2 != NULL) {
82 m2 = fma(delta, value - column->mean, m2);
83 }
84 }
85 if (out_m2 != NULL) {
86 *out_m2 = m2;
87 }
88 return LMMC_STATUS_OK;
89}
90
91static lmmc_status_t lmmc_covariance_scaled(
92 const lmmc_real_t* x,
93 size_t x_stride,
94 const lmmc_scaled_column_t* column_x,
95 const lmmc_real_t* y,
96 size_t y_stride,
97 const lmmc_scaled_column_t* column_y,
98 size_t count,
99 lmmc_real_t denominator,
100 lmmc_real_t* out_covariance
101) {
102 lmmc_real_t sum = 0.0;
103 lmmc_real_t covariance;
104 size_t i;
105
106 for (i = 0; i < count; ++i) {
107 const lmmc_real_t delta_x =
108 (scalbn(x[i * x_stride], -column_x->exponent) - column_x->origin) -
109 column_x->mean;
110 const lmmc_real_t delta_y =
111 (scalbn(y[i * y_stride], -column_y->exponent) - column_y->origin) -
112 column_y->mean;
113 sum = fma(delta_x, delta_y, sum);
114 }
116 covariance = scalbn(sum / denominator,
117 column_x->exponent + column_y->exponent);
118 if (!isfinite(covariance)) { return LMMC_STATUS_NUMERICAL_FAILURE; }
119 *out_covariance = covariance;
120 return LMMC_STATUS_OK;
121}
122
123static lmmc_status_t lmmc_vec_variance_common(const lmmc_vec_t* x, int sample, lmmc_real_t* out_variance) {
125 lmmc_real_t m2, variance;
126 lmmc_status_t status;
127
128 if (out_variance == NULL) { return LMMC_STATUS_INVALID_ARGUMENT; }
129 status = lmmc_validate_vec(x);
130 if (status != LMMC_STATUS_OK) { return status; }
131 status = lmmc_scaled_column(x->data, x->size, 1, &column, &m2);
132 if (status != LMMC_STATUS_OK) { return status; }
133 if (sample && x->size < 2) { return LMMC_STATUS_INVALID_ARGUMENT; }
134
135 variance = scalbn(m2 / (lmmc_real_t)(x->size - (sample != 0)),
136 2 * column.exponent);
137 return lmmc_finalize_nonnegative(variance, out_variance);
138}
139
140static lmmc_status_t lmmc_vec_stddev_common(
141 const lmmc_vec_t* x,
142 int sample,
143 lmmc_real_t* out_stddev
144) {
146 lmmc_real_t m2, stddev;
147 lmmc_status_t status;
148
149 if (out_stddev == NULL) { return LMMC_STATUS_INVALID_ARGUMENT; }
150 status = lmmc_validate_vec(x);
151 if (status != LMMC_STATUS_OK) { return status; }
152 status = lmmc_scaled_column(x->data, x->size, 1, &column, &m2);
153 if (status != LMMC_STATUS_OK) { return status; }
154 if (sample && x->size < 2) { return LMMC_STATUS_INVALID_ARGUMENT; }
155
157 stddev = scalbn(sqrt(m2 / (lmmc_real_t)(x->size - (sample != 0))),
158 column.exponent);
159 if (!isfinite(stddev)) { return LMMC_STATUS_NUMERICAL_FAILURE; }
160 *out_stddev = stddev;
161 return LMMC_STATUS_OK;
162}
163
164static lmmc_status_t lmmc_vec_covariance_common(
165 const lmmc_vec_t* x,
166 const lmmc_vec_t* y,
167 int sample,
168 lmmc_real_t* out_covariance
169) {
170 lmmc_scaled_column_t column_x, column_y;
171 lmmc_status_t status;
172
173 if (out_covariance == NULL) { return LMMC_STATUS_INVALID_ARGUMENT; }
174 if (lmmc_validate_vec(x) != LMMC_STATUS_OK ||
175 lmmc_validate_vec(y) != LMMC_STATUS_OK) { return LMMC_STATUS_INVALID_ARGUMENT; }
176 if (x->size != y->size) { return LMMC_STATUS_DIMENSION_MISMATCH; }
177 status = lmmc_scaled_column(x->data, x->size, 1, &column_x, NULL);
178 if (status != LMMC_STATUS_OK) { return status; }
179 status = lmmc_scaled_column(y->data, y->size, 1, &column_y, NULL);
180 if (status != LMMC_STATUS_OK) { return status; }
181 if (sample && x->size < 2) { return LMMC_STATUS_INVALID_ARGUMENT; }
182
183 return lmmc_covariance_scaled(
184 x->data, 1, &column_x, y->data, 1, &column_y, x->size,
185 (lmmc_real_t)(x->size - (sample != 0)), out_covariance);
186}
187
188static lmmc_status_t lmmc_finalize_correlation(
190 size_t count, lmmc_real_t* out_correlation) {
191 lmmc_real_t correlation;
192 const lmmc_real_t rounding_bound =
193 64.0 * DBL_EPSILON + 8.0 * (lmmc_real_t)count * DBL_EPSILON * DBL_EPSILON;
194 if (!(m2x > 0.0) || !(m2y > 0.0) ||
195 !isfinite(c) || !isfinite(m2x) || !isfinite(m2y)) { return LMMC_STATUS_NUMERICAL_FAILURE; }
196
197 correlation = (c / sqrt(m2x)) / sqrt(m2y);
198 if (!isfinite(correlation)) { return LMMC_STATUS_NUMERICAL_FAILURE; }
199 if (correlation > 1.0 && correlation <= 1.0 + rounding_bound) {
200 correlation = 1.0;
201 }
202 if (correlation < -1.0 && correlation >= -1.0 - rounding_bound) {
203 correlation = -1.0;
204 }
205 if (correlation < -1.0 || correlation > 1.0) { return LMMC_STATUS_NUMERICAL_FAILURE; }
206
207 *out_correlation = correlation;
208 return LMMC_STATUS_OK;
209}
210
211static lmmc_status_t lmmc_correlation_scaled(
212 const lmmc_real_t* x,
213 size_t x_stride,
214 const lmmc_real_t* y,
215 size_t y_stride,
216 size_t count,
217 lmmc_real_t* out_correlation
218) {
219 lmmc_scaled_column_t column_x, column_y;
220 lmmc_real_t spread_x = 0.0, spread_y = 0.0;
221 lmmc_real_t sx = 0.0, sy = 0.0, qx = 0.0, qy = 0.0, c = 0.0;
222 lmmc_real_t sx_error = 0.0, sy_error = 0.0;
223 lmmc_real_t qx_error = 0.0, qy_error = 0.0, c_error = 0.0;
224 int exponent_x, exponent_y;
225 size_t i;
226 lmmc_status_t status = lmmc_scaled_column(x, count, x_stride, &column_x, NULL);
227 if (status != LMMC_STATUS_OK) { return status; }
228 status = lmmc_scaled_column(y, count, y_stride, &column_y, NULL);
229 if (status != LMMC_STATUS_OK) { return status; }
230
231 for (i = 0; i < count; ++i) {
232 const lmmc_real_t dx =
233 (scalbn(x[i * x_stride], -column_x.exponent) - column_x.origin) - column_x.mean;
234 const lmmc_real_t dy =
235 (scalbn(y[i * y_stride], -column_y.exponent) - column_y.origin) - column_y.mean;
236 spread_x = fmax(spread_x, fabs(dx));
237 spread_y = fmax(spread_y, fabs(dy));
238 }
239 if (spread_x == 0.0 || spread_y == 0.0) { return LMMC_STATUS_NUMERICAL_FAILURE; }
240 frexp(spread_x, &exponent_x);
241 frexp(spread_y, &exponent_y);
242
247 for (i = 0; i < count; ++i) {
248 const lmmc_real_t dx = scalbn(
249 (scalbn(x[i * x_stride], -column_x.exponent) - column_x.origin) - column_x.mean,
250 -exponent_x);
251 const lmmc_real_t dy = scalbn(
252 (scalbn(y[i * y_stride], -column_y.exponent) - column_y.origin) - column_y.mean,
253 -exponent_y);
254 const lmmc_real_t xx = dx * dx, yy = dy * dy, xy = dx * dy;
255 lmmc_compensated_add(dx, &sx, &sx_error);
256 lmmc_compensated_add(dy, &sy, &sy_error);
257 lmmc_compensated_add(xx, &qx, &qx_error);
258 lmmc_compensated_add(fma(dx, dx, -xx), &qx, &qx_error);
259 lmmc_compensated_add(yy, &qy, &qy_error);
260 lmmc_compensated_add(fma(dy, dy, -yy), &qy, &qy_error);
261 lmmc_compensated_add(xy, &c, &c_error);
262 lmmc_compensated_add(fma(dx, dy, -xy), &c, &c_error);
263 }
264 sx += sx_error;
265 sy += sy_error;
267 qx = fma(-sx, sx / (lmmc_real_t)count, qx + qx_error);
268 qy = fma(-sy, sy / (lmmc_real_t)count, qy + qy_error);
269 c = fma(-sx, sy / (lmmc_real_t)count, c + c_error);
270 return lmmc_finalize_correlation(c, qx, qy, count, out_correlation);
271}
272
273static lmmc_status_t lmmc_vec_correlation_common(
274 const lmmc_vec_t* x,
275 const lmmc_vec_t* y,
276 int sample,
277 lmmc_real_t* out_correlation
278) {
279 lmmc_status_t status_x;
280 lmmc_status_t status_y;
281
282 if (out_correlation == NULL) { return LMMC_STATUS_INVALID_ARGUMENT; }
283 status_x = lmmc_validate_vec(x);
284 status_y = lmmc_validate_vec(y);
285 if (status_x != LMMC_STATUS_OK || status_y != LMMC_STATUS_OK) { return LMMC_STATUS_INVALID_ARGUMENT; }
286 if (x->size != y->size) { return LMMC_STATUS_DIMENSION_MISMATCH; }
287 if (sample && x->size < 2) { return LMMC_STATUS_INVALID_ARGUMENT; }
288
289 return lmmc_correlation_scaled(
290 x->data, 1, y->data, 1, x->size, out_correlation);
291}
292
293static lmmc_status_t lmmc_mat_column_means_to_buffer(
294 const lmmc_mat_t* x, lmmc_real_t* means) {
295 lmmc_status_t status = lmmc_validate_mat(x);
296 size_t column;
297
298 if (status != LMMC_STATUS_OK || means == NULL) { return LMMC_STATUS_INVALID_ARGUMENT; }
299 for (column = 0; column < x->cols; ++column) {
300 status = lmmc_mean_strided(
301 &x->data[column], x->rows, x->stride, &means[column]);
302 if (status != LMMC_STATUS_OK) { return status; }
303 }
304 return LMMC_STATUS_OK;
305}
306
307static lmmc_status_t lmmc_scale_matrix_columns(
308 const lmmc_mat_t* x, lmmc_scaled_column_t* columns) {
309 size_t col_i;
310 lmmc_status_t status;
311 for (col_i = 0; col_i < x->cols; ++col_i) {
312 status = lmmc_scaled_column(
313 &x->data[col_i], x->rows, x->stride, &columns[col_i], NULL);
314 if (status != LMMC_STATUS_OK) {
315 return status;
316 }
317 }
318 return LMMC_STATUS_OK;
319}
320
321static lmmc_status_t lmmc_mat_covariance_common(
322 const lmmc_mat_t* x,
323 int sample,
324 lmmc_mat_t* out_matrix
325) {
326 size_t bytes = 0;
327 lmmc_scaled_column_t* columns = NULL;
328 lmmc_status_t status = lmmc_validate_mat(x);
329 lmmc_real_t denominator;
330 size_t col_i;
331 size_t col_j;
332
333 if (status != LMMC_STATUS_OK ||
334 out_matrix == NULL || out_matrix->data == NULL) { return LMMC_STATUS_INVALID_ARGUMENT; }
335 if (out_matrix->rows != x->cols || out_matrix->cols != x->cols) { return LMMC_STATUS_DIMENSION_MISMATCH; }
336 if (sample && x->rows < 2) { return LMMC_STATUS_INVALID_ARGUMENT; }
337 denominator = sample ? (lmmc_real_t)(x->rows - 1)
338 : (lmmc_real_t)x->rows;
339 if (!lmmc_safe_mul_size(x->cols, sizeof(*columns), &bytes)) { return LMMC_STATUS_INVALID_ARGUMENT; }
340
341 columns = (lmmc_scaled_column_t*)lmmc_memory_alloc(bytes);
342 if (columns == NULL) { return LMMC_STATUS_ALLOCATION_FAILED; }
343 status = lmmc_scale_matrix_columns(x, columns);
344 if (status != LMMC_STATUS_OK) {
345 goto cleanup;
346 }
347
348 for (col_i = 0; col_i < x->cols; ++col_i) {
349 for (col_j = col_i; col_j < x->cols; ++col_j) {
350 lmmc_real_t covariance;
351 status = lmmc_covariance_scaled(
352 &x->data[col_i], x->stride, &columns[col_i],
353 &x->data[col_j], x->stride, &columns[col_j],
354 x->rows, denominator, &covariance);
355 if (status != LMMC_STATUS_OK) {
356 goto cleanup;
357 }
358 out_matrix->data[col_i * out_matrix->stride + col_j] = covariance;
359 out_matrix->data[col_j * out_matrix->stride + col_i] = covariance;
360 }
361 }
362
363cleanup:
364 lmmc_memory_free(columns);
365 return status;
366}
367
368static lmmc_status_t lmmc_mat_correlation_common(
369 const lmmc_mat_t* x,
370 int sample,
371 lmmc_mat_t* out_matrix
372) {
373 lmmc_status_t status = lmmc_validate_mat(x);
374 size_t col_i;
375 size_t col_j;
376
377 if (status != LMMC_STATUS_OK ||
378 out_matrix == NULL || out_matrix->data == NULL) { return LMMC_STATUS_INVALID_ARGUMENT; }
379 if (out_matrix->rows != x->cols || out_matrix->cols != x->cols) { return LMMC_STATUS_DIMENSION_MISMATCH; }
380 if (sample && x->rows < 2) { return LMMC_STATUS_INVALID_ARGUMENT; }
381
382 for (col_i = 0; col_i < x->cols; ++col_i) {
383 for (col_j = col_i; col_j < x->cols; ++col_j) {
384 lmmc_real_t correlation;
385 status = lmmc_correlation_scaled(
386 &x->data[col_i], x->stride,
387 &x->data[col_j], x->stride,
388 x->rows, &correlation);
389 if (status != LMMC_STATUS_OK) { return status; }
390 if (col_i == col_j) {
391 correlation = 1.0;
392 }
393 out_matrix->data[col_i * out_matrix->stride + col_j] =
394 correlation;
395 out_matrix->data[col_j * out_matrix->stride + col_i] =
396 correlation;
397 }
398 }
399 return LMMC_STATUS_OK;
400}
401
403 lmmc_status_t status;
404 if (out_mean == NULL) { return LMMC_STATUS_INVALID_ARGUMENT; }
405 status = lmmc_validate_vec(x);
406 if (status != LMMC_STATUS_OK) { return status; }
407 return lmmc_mean_strided(x->data, x->size, 1, out_mean);
408}
409
411 return lmmc_vec_variance_common(x, 0, out_variance);
412}
413
415 return lmmc_vec_variance_common(x, 1, out_variance);
416}
417
419 return lmmc_vec_stddev_common(x, 0, out_stddev);
420}
421
423 return lmmc_vec_stddev_common(x, 1, out_stddev);
424}
425
427 return lmmc_vec_covariance_common(x, y, 0, out_covariance);
428}
429
431 return lmmc_vec_covariance_common(x, y, 1, out_covariance);
432}
433
435 return lmmc_vec_correlation_common(x, y, 0, out_correlation);
436}
437
439 return lmmc_vec_correlation_common(x, y, 1, out_correlation);
440}
441
443 lmmc_status_t st = lmmc_validate_mat(x);
444
445 if (st != LMMC_STATUS_OK || out_means == NULL || out_means->data == NULL) {
447 }
448 if (out_means->size != x->cols) {
450 }
451
452 return lmmc_mat_column_means_to_buffer(x, out_means->data);
453}
454
456 return lmmc_mat_covariance_common(x, 0, out_covariance);
457}
458
460 return lmmc_mat_covariance_common(x, 1, out_covariance);
461}
462
464 return lmmc_mat_correlation_common(x, 0, out_correlation);
465}
466
468 return lmmc_mat_correlation_common(x, 1, out_correlation);
469}
470
LMMC binary real type and arithmetic spelling.
double lmmc_real_t
Public and internal LMMC real type.
lmmc_real_t * data
lmmc_real_t * data
行优先存储的稠密矩阵。
一维稠密向量。
void * lmmc_memory_alloc(size_t size)
void lmmc_memory_free(void *pointer)
Private recoverable allocator for persistent LMMC ownership.
数值标量、特殊函数和 FFT 公共接口。
基础统计量与组合数学接口。
lmmc_status_t lmmc_vec_variance_sample(const lmmc_vec_t *x, lmmc_real_t *out_variance)
计算样本方差 。
lmmc_status_t lmmc_vec_mean(const lmmc_vec_t *x, lmmc_real_t *out_mean)
计算向量样本均值 。
lmmc_status_t lmmc_vec_correlation_population(const lmmc_vec_t *x, const lmmc_vec_t *y, lmmc_real_t *out_correlation)
总体 Pearson 相关系数。
lmmc_status_t lmmc_mat_column_mean(const lmmc_mat_t *x, lmmc_vec_t *out_means)
计算矩阵各列均值,输出长度为 x->cols 的向量。
lmmc_status_t lmmc_vec_stddev_population(const lmmc_vec_t *x, lmmc_real_t *out_stddev)
总体标准差。 缩放计算支持方差超出 binary64 范围的情况。 输入非有限或标准差结果溢出时返回 LMMC_STATUS_NUMERICAL_FAILURE。
lmmc_status_t lmmc_mat_covariance_population(const lmmc_mat_t *x, lmmc_mat_t *out_covariance)
计算总体协方差矩阵(cols × cols)。
lmmc_status_t lmmc_vec_stddev_sample(const lmmc_vec_t *x, lmmc_real_t *out_stddev)
样本标准差,要求 n>=2 。 缩放计算支持方差超出 binary64 范围的情况。 输入非有限或标准差结果溢出时返回 LMMC_STATUS_NUMERICAL_FAILURE。
lmmc_status_t lmmc_vec_covariance_population(const lmmc_vec_t *x, const lmmc_vec_t *y, lmmc_real_t *out_covariance)
总体协方差 。
lmmc_status_t lmmc_mat_correlation_population(const lmmc_mat_t *x, lmmc_mat_t *out_correlation)
计算总体 Pearson 相关矩阵。
lmmc_status_t lmmc_vec_covariance_sample(const lmmc_vec_t *x, const lmmc_vec_t *y, lmmc_real_t *out_covariance)
样本协方差,要求 n>=2 。
lmmc_status_t lmmc_vec_correlation_sample(const lmmc_vec_t *x, const lmmc_vec_t *y, lmmc_real_t *out_correlation)
样本 Pearson 相关系数;使用同一缩放累计路径,要求 n>=2。
lmmc_status_t lmmc_mat_correlation_sample(const lmmc_mat_t *x, lmmc_mat_t *out_correlation)
使用同一缩放路径计算样本 Pearson 相关矩阵,要求行数 >= 2。
lmmc_status_t lmmc_mat_covariance_sample(const lmmc_mat_t *x, lmmc_mat_t *out_covariance)
计算样本协方差矩阵(cols × cols),要求行数 >= 2 。
lmmc_status_t lmmc_vec_variance_population(const lmmc_vec_t *x, lmmc_real_t *out_variance)
总体方差 。
lmmc_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_OK
@ LMMC_STATUS_NUMERICAL_FAILURE
@ LMMC_STATUS_DIMENSION_MISMATCH
@ LMMC_STATUS_ALLOCATION_FAILED
@ LMMC_STATUS_INVALID_ARGUMENT