Blender V4.3
math_statistics.c
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2015 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "BLI_math_base.h"
10#include "BLI_math_statistics.h"
11#include "BLI_math_vector.h"
12
13#include "BLI_task.h"
14#include "BLI_utildefines.h"
15
16#include "BLI_strict_flags.h" /* Keep last. */
17
18/********************************** Covariance Matrices *********************************/
19
20typedef struct CovarianceData {
21 const float *cos_vn;
22 const float *center;
23 float *r_covmat;
24 float covfac;
25 int n;
28
29static void covariance_m_vn_ex_task_cb(void *__restrict userdata,
30 const int a,
31 const TaskParallelTLS *__restrict UNUSED(tls))
32{
33 CovarianceData *data = userdata;
34 const float *cos_vn = data->cos_vn;
35 const float *center = data->center;
36 float *r_covmat = data->r_covmat;
37 const int n = data->n;
38 const int cos_vn_num = data->cos_vn_num;
39
40 int k;
41
42 /* Covariance matrices are always symmetrical, so we can compute only one half of it,
43 * and mirror it to the other half (at the end of the func).
44 *
45 * This allows using a flat loop of n*n with same results as imbricated one over half the matrix:
46 *
47 * for (i = 0; i < n; i++) {
48 * for (j = i; j < n; j++) {
49 * ...
50 * }
51 * }
52 */
53 const int i = a / n;
54 const int j = a % n;
55 if (j < i) {
56 return;
57 }
58
59 if (center) {
60 for (k = 0; k < cos_vn_num; k++) {
61 r_covmat[a] += (cos_vn[k * n + i] - center[i]) * (cos_vn[k * n + j] - center[j]);
62 }
63 }
64 else {
65 for (k = 0; k < cos_vn_num; k++) {
66 r_covmat[a] += cos_vn[k * n + i] * cos_vn[k * n + j];
67 }
68 }
69 r_covmat[a] *= data->covfac;
70 if (j != i) {
71 /* Mirror result to other half... */
72 r_covmat[j * n + i] = r_covmat[a];
73 }
74}
75
76void BLI_covariance_m_vn_ex(const int n,
77 const float *cos_vn,
78 const int cos_vn_num,
79 const float *center,
80 const bool use_sample_correction,
81 float *r_covmat)
82{
83 /* Note about that division: see https://en.wikipedia.org/wiki/Bessel%27s_correction.
84 * In a nutshell, it must be 1 / (n - 1) for 'sample data', and 1 / n for 'population data'...
85 */
86 const float covfac = 1.0f / (float)(use_sample_correction ? cos_vn_num - 1 : cos_vn_num);
87
88 memset(r_covmat, 0, sizeof(*r_covmat) * (size_t)(n * n));
89
90 CovarianceData data = {
91 .cos_vn = cos_vn,
92 .center = center,
93 .r_covmat = r_covmat,
94 .covfac = covfac,
95 .n = n,
96 .cos_vn_num = cos_vn_num,
97 };
98
99 TaskParallelSettings settings;
101 settings.use_threading = ((cos_vn_num * n * n) >= 10000);
102 BLI_task_parallel_range(0, n * n, &data, covariance_m_vn_ex_task_cb, &settings);
103}
104
105void BLI_covariance_m3_v3n(const float (*cos_v3)[3],
106 const int cos_v3_num,
107 const bool use_sample_correction,
108 float r_covmat[3][3],
109 float r_center[3])
110{
111 float center[3];
112 const float mean_fac = 1.0f / (float)cos_v3_num;
113 int i;
114
115 zero_v3(center);
116 for (i = 0; i < cos_v3_num; i++) {
117 /* Applying mean_fac here rather than once at the end reduce compute errors... */
118 madd_v3_v3fl(center, cos_v3[i], mean_fac);
119 }
120
121 if (r_center) {
122 copy_v3_v3(r_center, center);
123 }
124
126 3, (const float *)cos_v3, cos_v3_num, center, use_sample_correction, (float *)r_covmat);
127}
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void zero_v3(float r[3])
void BLI_task_parallel_range(int start, int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
Definition task_range.cc:99
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition BLI_task.h:230
#define UNUSED(x)
draw_view in_light_buf[] float
static void covariance_m_vn_ex_task_cb(void *__restrict userdata, const int a, const TaskParallelTLS *__restrict UNUSED(tls))
struct CovarianceData CovarianceData
void BLI_covariance_m3_v3n(const float(*cos_v3)[3], const int cos_v3_num, const bool use_sample_correction, float r_covmat[3][3], float r_center[3])
Compute the covariance matrix of given set of 3D coordinates.
void BLI_covariance_m_vn_ex(const int n, const float *cos_vn, const int cos_vn_num, const float *center, const bool use_sample_correction, float *r_covmat)
Compute the covariance matrix of given set of nD coordinates.
const float * cos_vn
const float * center