1 /*
2 * Copyright (c) 2021 Marti Riba Pons
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <errno.h>
8 #include <stdio.h>
9 #include <stdbool.h>
10 #include <string.h>
11 #include <zsl/zsl.h>
12 #include <zsl/statistics.h>
13
zsl_sta_mean(struct zsl_vec * v,zsl_real_t * m)14 int zsl_sta_mean(struct zsl_vec *v, zsl_real_t *m)
15 {
16 zsl_vec_ar_mean(v, m);
17
18 return 0;
19 }
20
zsl_sta_trim_mean(struct zsl_vec * v,zsl_real_t p,zsl_real_t * m)21 int zsl_sta_trim_mean(struct zsl_vec *v, zsl_real_t p, zsl_real_t *m)
22 {
23 #if CONFIG_ZSL_BOUNDS_CHECKS
24 /* Make sure p is between 0 and 50. */
25 if (p > 50.0 || p < 0.0) {
26 return -EINVAL;
27 }
28 #endif
29
30 ZSL_VECTOR_DEF(w, v->sz);
31 zsl_real_t per_l, per_h;
32 size_t first_val = 0, count = 0;
33
34 *m = 0.0;
35 zsl_sta_percentile(v, p, &per_l);
36 zsl_sta_percentile(v, 100 - p, &per_h);
37
38 zsl_vec_init(&w);
39 zsl_vec_sort(v, &w);
40
41 for (size_t i = 0; i < v->sz; i++) {
42 if (w.data[i] >= per_l && w.data[i] <= per_h) {
43 count++;
44 }
45 if (count == 1) {
46 first_val = i;
47 }
48 }
49
50 ZSL_VECTOR_DEF(sub, count);
51 zsl_vec_get_subset(&w, first_val, count, &sub);
52 zsl_sta_mean(&sub, m);
53
54 return 0;
55 }
56
zsl_sta_weighted_mean(struct zsl_vec * v,struct zsl_vec * w,zsl_real_t * m)57 int zsl_sta_weighted_mean(struct zsl_vec *v, struct zsl_vec *w, zsl_real_t *m)
58 {
59 zsl_real_t sumw = 0.0, sumwx = 0.0;
60
61 for (size_t i = 0; i < v->sz; i++) {
62 sumw += w->data[i];
63 }
64
65 #if CONFIG_ZSL_BOUNDS_CHECKS
66 /* Make sure the vectors dimensions match. */
67 if (v->sz != w->sz) {
68 return -EINVAL;
69 }
70
71 /* Make sure the weights are positive or zero. */
72 for (size_t i = 0; i < v->sz; i++) {
73 if (w->data[i] < 0.0) {
74 return -EINVAL;
75 }
76 }
77
78 /* Make sure that not all of the weights are zero. */
79 if (ZSL_ABS(sumw) < 1E-6) {
80 return -EINVAL;
81 }
82 #endif
83
84 for (size_t i = 0; i < v->sz; i++) {
85 sumwx += w->data[i] * v->data[i];
86 }
87
88 *m = sumwx / sumw;
89
90 return 0;
91 }
92
zsl_sta_time_weighted_mean(struct zsl_vec * v,struct zsl_vec * t,zsl_real_t * m)93 int zsl_sta_time_weighted_mean(struct zsl_vec *v, struct zsl_vec *t,
94 zsl_real_t *m)
95 {
96 #if CONFIG_ZSL_BOUNDS_CHECKS
97 /* Make sure the vectors dimensions match. */
98 if (v->sz != t->sz) {
99 return -EINVAL;
100 }
101 /* Make sure that the values in 'v' are positive. */
102 for (size_t i = 0; i < v->sz; i++) {
103 if (v->data[i] < 0.0) {
104 return -EINVAL;
105 }
106 }
107 /* The vector 'x' can't have any repeated values. */
108 for (size_t i = 0; i < t->sz; i++) {
109 if (zsl_vec_contains(t, t->data[i], 1E-6) > 1) {
110 return -EINVAL;
111 }
112 }
113 #endif
114
115 ZSL_VECTOR_DEF(ts, t->sz);
116 ZSL_VECTOR_DEF(vs, v->sz);
117
118 zsl_real_t sum = 0.0;
119
120 zsl_vec_sort(t, &ts);
121
122 for (size_t i = 0; i < t->sz; i++) {
123 for (size_t g = 0; g < t->sz; g++) {
124 if (ZSL_ABS(ts.data[i] - t->data[g]) < 1E-6) {
125 vs.data[i] = v->data[g];
126 }
127 }
128 }
129
130 for (size_t j = 1; j < t->sz; j++) {
131 sum += (ts.data[j] - ts.data[j - 1]) *
132 (vs.data[j] + vs.data[j - 1]) / 2.0;
133 }
134
135 *m = sum / (ts.data[(t->sz - 1)] - ts.data[0]);
136
137 return 0;
138 }
139
zsl_sta_demean(struct zsl_vec * v,struct zsl_vec * w)140 int zsl_sta_demean(struct zsl_vec *v, struct zsl_vec *w)
141 {
142 #if CONFIG_ZSL_BOUNDS_CHECKS
143 /* Make sure the vectors dimensions match. */
144 if (v->sz != w->sz) {
145 return -EINVAL;
146 }
147 #endif
148
149 zsl_real_t m;
150
151 zsl_vec_copy(w, v);
152 zsl_sta_mean(v, &m);
153 zsl_vec_scalar_add(w, -m);
154
155 return 0;
156 }
157
zsl_sta_percentile(struct zsl_vec * v,zsl_real_t p,zsl_real_t * val)158 int zsl_sta_percentile(struct zsl_vec *v, zsl_real_t p, zsl_real_t *val)
159 {
160 #if CONFIG_ZSL_BOUNDS_CHECKS
161 /* Make sure p is between 0 and 100. */
162 if (p > 100.0 || p < 0.0) {
163 return -EINVAL;
164 }
165 #endif
166
167 ZSL_VECTOR_DEF(w, v->sz);
168
169 zsl_vec_init(&w);
170 zsl_vec_sort(v, &w);
171
172 zsl_real_t x = (p * v->sz) / 100.;
173 zsl_real_t per = ZSL_FLOOR(x);
174
175 if (x == per) {
176 *val = (w.data[(int)per] + w.data[(int)per - 1]) / 2.;
177 } else {
178 *val = w.data[(int)per];
179 }
180
181 return 0;
182 }
183
zsl_sta_median(struct zsl_vec * v,zsl_real_t * m)184 int zsl_sta_median(struct zsl_vec *v, zsl_real_t *m)
185 {
186 zsl_sta_percentile(v, 50, m);
187
188 return 0;
189 }
190
zsl_sta_weighted_median(struct zsl_vec * v,struct zsl_vec * w,zsl_real_t * m)191 int zsl_sta_weighted_median(struct zsl_vec *v, struct zsl_vec *w, zsl_real_t *m)
192 {
193 #if CONFIG_ZSL_BOUNDS_CHECKS
194 /* Make sure the vectors dimensions match. */
195 if (v->sz != w->sz) {
196 return -EINVAL;
197 }
198
199 /* Make sure the weights are positive or zero. */
200 zsl_real_t sum = 0.0;
201 for (size_t i = 0; i < v->sz; i++) {
202 sum += w->data[i];
203 if (w->data[i] < 0.0) {
204 return -EINVAL;
205 }
206 }
207
208 /* Make sure that that the sum of the weights is 1. */
209 if (ZSL_ABS(sum - 1.0) > 1E-6) {
210 return -EINVAL;
211 }
212 #endif
213
214 ZSL_VECTOR_DEF(vsort, v->sz);
215 zsl_real_t lsum = 0.0;
216 size_t i = 0;
217 while (lsum <= 0.5) {
218 lsum += w->data[i];
219 i++;
220 }
221
222 lsum -= w->data[i - 1];
223 zsl_vec_init(&vsort);
224 zsl_vec_sort(v, &vsort);
225
226 if (ZSL_ABS(lsum - 0.5) < 1E-6) {
227 *m = (vsort.data[i - 1] + vsort.data[i - 2]) / 2.0;
228 } else {
229 *m = vsort.data[i - 1];
230 }
231
232 return 0;
233 }
234
zsl_sta_quart(struct zsl_vec * v,zsl_real_t * q1,zsl_real_t * q2,zsl_real_t * q3)235 int zsl_sta_quart(struct zsl_vec *v, zsl_real_t *q1, zsl_real_t *q2,
236 zsl_real_t *q3)
237 {
238 zsl_sta_percentile(v, 25, q1);
239 zsl_sta_percentile(v, 50, q2);
240 zsl_sta_percentile(v, 75, q3);
241
242 return 0;
243 }
244
zsl_sta_quart_range(struct zsl_vec * v,zsl_real_t * r)245 int zsl_sta_quart_range(struct zsl_vec *v, zsl_real_t *r)
246 {
247 zsl_real_t q1, q3;
248
249 zsl_sta_percentile(v, 25, &q1);
250 zsl_sta_percentile(v, 75, &q3);
251
252 *r = q3 - q1;
253
254 return 0;
255 }
256
zsl_sta_mode(struct zsl_vec * v,struct zsl_vec * w)257 int zsl_sta_mode(struct zsl_vec *v, struct zsl_vec *w)
258 {
259 #if CONFIG_ZSL_BOUNDS_CHECKS
260 /* Make sure w and v are the same length. */
261 if (v->sz != w->sz) {
262 return -EINVAL;
263 }
264 #endif
265
266 size_t i, j = 0, count, maxcount = 0;
267
268 ZSL_VECTOR_DEF(u, v->sz);
269 ZSL_VECTOR_DEF(w_temp, v->sz);
270
271 zsl_vec_init(w);
272
273 for (i = 0; i < v->sz; i++) {
274 count = zsl_vec_contains(v, v->data[i], 1E-7);
275 u.data[i] = count;
276 if (count > maxcount) {
277 maxcount = count;
278 }
279 }
280
281 for (i = 0; i < v->sz; i++) {
282 if (u.data[i] == maxcount) {
283 w_temp.data[j] = v->data[i];
284 j++;
285 }
286 }
287
288 w_temp.sz = j;
289 count = 0;
290
291 for (i = 0; i < j; i++) {
292 if (w_temp.data[i] >= 1E-5 || w_temp.data[i] <= 1E-5) {
293 if (zsl_vec_contains(w, w_temp.data[i], 1E-5) == 0) {
294 w->data[count] = w_temp.data[i];
295 count++;
296 }
297 }
298 }
299
300 if (zsl_vec_contains(&w_temp, 0.0, 1E-5) > 0) {
301 count++;
302 }
303
304 w->sz = count;
305
306 return 0;
307 }
308
zsl_sta_data_range(struct zsl_vec * v,zsl_real_t * r)309 int zsl_sta_data_range(struct zsl_vec *v, zsl_real_t *r)
310 {
311 ZSL_VECTOR_DEF(w, v->sz);
312
313 zsl_vec_sort(v, &w);
314
315 *r = w.data[v->sz - 1] - w.data[0];
316
317 return 0;
318 }
319
zsl_sta_mean_abs_dev(struct zsl_vec * v,zsl_real_t * m)320 int zsl_sta_mean_abs_dev(struct zsl_vec *v, zsl_real_t *m)
321 {
322 #if CONFIG_ZSL_BOUNDS_CHECKS
323 /* Make sure v has at least dimension 1. */
324 if (v->sz == 0) {
325 return -EINVAL;
326 }
327 #endif
328 ZSL_VECTOR_DEF(vdm, v->sz);
329 zsl_sta_demean(v, &vdm);
330
331 zsl_real_t sum = 0.0;
332 for (size_t i = 0; i < v->sz; i++) {
333 sum += ZSL_ABS(vdm.data[i]);
334 }
335
336 *m = sum / v->sz;
337
338 return 0;
339 }
340
zsl_sta_median_abs_dev(struct zsl_vec * v,zsl_real_t * m)341 int zsl_sta_median_abs_dev(struct zsl_vec *v, zsl_real_t *m)
342 {
343 ZSL_VECTOR_DEF(med, v->sz);
344 zsl_real_t median;
345
346 zsl_sta_median(v, &median);
347 for (size_t i = 0; i < v->sz; i++) {
348 med.data[i] = ZSL_ABS(v->data[i] - median);
349 }
350
351 zsl_sta_median(&med, m);
352
353 return 0;
354 }
355
zsl_sta_var(struct zsl_vec * v,zsl_real_t * var)356 int zsl_sta_var(struct zsl_vec *v, zsl_real_t *var)
357 {
358 ZSL_VECTOR_DEF(w, v->sz);
359 *var = 0;
360
361 zsl_sta_demean(v, &w);
362
363 for (size_t i = 0; i < v->sz; i++) {
364 *var += w.data[i] * w.data[i];
365 }
366
367 *var /= v->sz - 1;
368
369 return 0;
370 }
371
zsl_sta_std_dev(struct zsl_vec * v,zsl_real_t * s)372 int zsl_sta_std_dev(struct zsl_vec *v, zsl_real_t *s)
373 {
374 zsl_real_t var;
375
376 zsl_sta_var(v, &var);
377
378 *s = ZSL_SQRT(var);
379
380 return 0;
381 }
382
zsl_sta_covar(struct zsl_vec * v,struct zsl_vec * w,zsl_real_t * c)383 int zsl_sta_covar(struct zsl_vec *v, struct zsl_vec *w, zsl_real_t *c)
384 {
385 #if CONFIG_ZSL_BOUNDS_CHECKS
386 /* Make sure v and w are equal length. */
387 if (v->sz != w->sz) {
388 return -EINVAL;
389 }
390 #endif
391
392 ZSL_VECTOR_DEF(v_dm, v->sz);
393 ZSL_VECTOR_DEF(w_dm, w->sz);
394
395 zsl_sta_demean(v, &v_dm);
396 zsl_sta_demean(w, &w_dm);
397
398 *c = 0;
399 for (size_t i = 0; i < v->sz; i++) {
400 *c += v_dm.data[i] * w_dm.data[i];
401 }
402
403 *c /= v->sz - 1;
404
405 return 0;
406 }
407
zsl_sta_covar_mtx(struct zsl_mtx * m,struct zsl_mtx * mc)408 int zsl_sta_covar_mtx(struct zsl_mtx *m, struct zsl_mtx *mc)
409 {
410 #if CONFIG_ZSL_BOUNDS_CHECKS
411 /* Make sure 'mc' is a square matrix with same num. columns as 'm'. */
412 if (mc->sz_rows != mc->sz_cols || mc->sz_cols != m->sz_cols) {
413 return -EINVAL;
414 }
415 #endif
416
417 zsl_real_t c;
418
419 ZSL_VECTOR_DEF(v1, m->sz_rows);
420 ZSL_VECTOR_DEF(v2, m->sz_rows);
421
422 for (size_t i = 0; i < m->sz_cols; i++) {
423 for (size_t j = 0; j < m->sz_cols; j++) {
424 zsl_mtx_get_col(m, i, v1.data);
425 zsl_mtx_get_col(m, j, v2.data);
426 zsl_sta_covar(&v1, &v2, &c);
427 mc->data[(i * m->sz_cols) + j] = c;
428 }
429 }
430
431 return 0;
432 }
433
zsl_sta_linear_reg(struct zsl_vec * x,struct zsl_vec * y,struct zsl_sta_linreg * c)434 int zsl_sta_linear_reg(struct zsl_vec *x, struct zsl_vec *y,
435 struct zsl_sta_linreg *c)
436 {
437 #if CONFIG_ZSL_BOUNDS_CHECKS
438 /* Make sure x and y are equal length. */
439 if (x->sz != y->sz) {
440 return -EINVAL;
441 }
442 #endif
443
444 zsl_real_t sumx, sumy, sumxy, sumxx, sumyy;
445
446 sumx = sumy = sumxy = sumxx = sumyy = 0.0;
447
448 for (size_t i = 0; i < x->sz; i++) {
449 sumx += x->data[i];
450 sumy += y->data[i];
451 sumxy += x->data[i] * y->data[i];
452 sumxx += x->data[i] * x->data[i];
453 sumyy += y->data[i] * y->data[i];
454 }
455
456 c->slope = (x->sz * sumxy - sumx * sumy) / (x->sz * sumxx - sumx * sumx);
457 c->intercept = (sumy - c->slope * sumx) / x->sz;
458 c->correlation = (x->sz * sumxy - sumx * sumy) /
459 ZSL_SQRT((x->sz * sumxx - sumx * sumx) *
460 (x->sz * sumyy - sumy * sumy));
461
462 return 0;
463 }
464
465 #ifndef CONFIG_ZSL_SINGLE_PRECISION
zsl_sta_mult_linear_reg(struct zsl_mtx * x,struct zsl_vec * y,struct zsl_vec * b,zsl_real_t * r)466 int zsl_sta_mult_linear_reg(struct zsl_mtx *x, struct zsl_vec *y,
467 struct zsl_vec *b, zsl_real_t *r)
468 {
469
470 #if CONFIG_ZSL_BOUNDS_CHECKS
471 /* Make sure matrices and vectors' sizes match. */
472 if (x->sz_rows != y->sz || x->sz_cols + 1 != b->sz) {
473 return -EINVAL;
474 }
475 #endif
476
477 ZSL_MATRIX_DEF(x_exp, x->sz_rows, (x->sz_cols + 1));
478 ZSL_MATRIX_DEF(x_trans, (x->sz_cols + 1), x->sz_rows);
479 ZSL_MATRIX_DEF(xx, (x->sz_cols + 1), (x->sz_cols + 1));
480 ZSL_MATRIX_DEF(xinv, (x->sz_cols + 1), (x->sz_cols + 1));
481 ZSL_MATRIX_DEF(ymtx, y->sz, 1);
482 ZSL_MATRIX_DEF(xtemp, (x->sz_cols + 1), x->sz_rows);
483 ZSL_MATRIX_DEF(bmtx, (x->sz_cols + 1), 1);
484 ZSL_MATRIX_DEF(xtemp2, x->sz_rows, 1);
485 ZSL_MATRIX_DEF(emtx, x->sz_rows, 1);
486
487 zsl_real_t v[x->sz_rows];
488 zsl_mtx_init(&x_exp, NULL);
489 for (size_t i = 0; i < x->sz_rows; i++) {
490 v[i] = 1.;
491 }
492
493 zsl_mtx_set_col(&x_exp, 0, v);
494 for (size_t j = 0; j < x->sz_cols; j++) {
495 zsl_mtx_get_col(x, j, v);
496 zsl_mtx_set_col(&x_exp, j + 1, v);
497 }
498
499 zsl_mtx_trans(&x_exp, &x_trans);
500 zsl_mtx_mult(&x_trans, &x_exp, &xx);
501
502 zsl_real_t det;
503 zsl_mtx_deter(&xx, &det);
504 if (ZSL_ABS(det) < 1E-6) {
505 /*
506 * Currently limited to square matrices. pinv could be used,
507 * but is too resource-intensive to add at the momemt.
508 */
509 return -EINVAL;
510 } else {
511 zsl_mtx_inv(&xx, &xinv);
512 }
513
514 zsl_mtx_from_arr(&ymtx, y->data);
515 zsl_mtx_mult(&xinv, &x_trans, &xtemp);
516 zsl_mtx_mult(&xtemp, &ymtx, &bmtx);
517 zsl_vec_from_arr(b, bmtx.data);
518
519 zsl_mtx_mult(&x_exp, &bmtx, &xtemp2);
520 zsl_mtx_sub(&ymtx, &xtemp2, &emtx);
521 zsl_real_t e_norm = 0.0, ymean, ysum = 0.0;
522 zsl_sta_mean(y, &ymean);
523 for (size_t g = 0; g < x->sz_rows; g++) {
524 e_norm += emtx.data[g] * emtx.data[g];
525 ysum += (y->data[g] - ymean) * (y->data[g] - ymean);
526 }
527
528 *r = 1. - e_norm / ysum;
529
530 return 0;
531 }
532 #endif
533
534 #ifndef CONFIG_ZSL_SINGLE_PRECISION
zsl_sta_weighted_mult_linear_reg(struct zsl_mtx * x,struct zsl_vec * y,struct zsl_vec * w,struct zsl_vec * b,zsl_real_t * r)535 int zsl_sta_weighted_mult_linear_reg(struct zsl_mtx *x, struct zsl_vec *y,
536 struct zsl_vec *w, struct zsl_vec *b, zsl_real_t *r)
537 {
538 #if CONFIG_ZSL_BOUNDS_CHECKS
539 /* Make sure matrices and vectors' sizes match. */
540 if (x->sz_rows != y->sz || x->sz_cols + 1 != b->sz || x->sz_rows != w->sz) {
541 return -EINVAL;
542 }
543 /* Make sure no weight is zero. */
544 for (size_t k = 0; k < w->sz; k++) {
545 if (ZSL_ABS(w->data[k]) < 1E-6) {
546 return -EINVAL;
547 }
548 }
549 #endif
550
551 ZSL_MATRIX_DEF(x_exp, x->sz_rows, (x->sz_cols + 1));
552 ZSL_MATRIX_DEF(x_trans, (x->sz_cols + 1), x->sz_rows);
553 ZSL_MATRIX_DEF(xw, (x->sz_cols + 1), x->sz_rows);
554 ZSL_MATRIX_DEF(xx, (x->sz_cols + 1), (x->sz_cols + 1));
555 ZSL_MATRIX_DEF(xinv, (x->sz_cols + 1), (x->sz_cols + 1));
556 ZSL_MATRIX_DEF(ymtx, y->sz, 1);
557 ZSL_MATRIX_DEF(xtemp, (x->sz_cols + 1), x->sz_rows);
558 ZSL_MATRIX_DEF(bmtx, (x->sz_cols + 1), 1);
559 ZSL_MATRIX_DEF(xtemp2, x->sz_rows, 1);
560 ZSL_MATRIX_DEF(emtx, x->sz_rows, 1);
561 ZSL_MATRIX_DEF(idx, w->sz, w->sz);
562
563 zsl_mtx_init(&idx, zsl_mtx_entry_fn_identity);
564 for (size_t k = 0; k < w->sz; k++) {
565 w->data[k] = 1. / w->data[k];
566 zsl_mtx_scalar_mult_row_d(&idx, k, w->data[k]);
567 }
568
569 zsl_real_t v[x->sz_rows];
570 zsl_mtx_init(&x_exp, NULL);
571 for (size_t i = 0; i < x->sz_rows; i++) {
572 v[i] = 1.;
573 }
574
575 zsl_mtx_set_col(&x_exp, 0, v);
576 for (size_t j = 0; j < x->sz_cols; j++) {
577 zsl_mtx_get_col(x, j, v);
578 zsl_mtx_set_col(&x_exp, j + 1, v);
579 }
580
581 zsl_mtx_trans(&x_exp, &x_trans);
582 zsl_mtx_mult(&x_trans, &idx, &xw);
583 zsl_mtx_mult(&xw, &x_exp, &xx);
584
585 zsl_real_t det;
586 zsl_mtx_deter(&xx, &det);
587 if (ZSL_ABS(det) < 1E-6) {
588 /*
589 * Currently limited to square matrices. pinv could be used,
590 * but is too resource-intensive to add at the momemt.
591 */
592 return -EINVAL;
593 } else {
594 zsl_mtx_inv(&xx, &xinv);
595 }
596
597 zsl_mtx_from_arr(&ymtx, y->data);
598 zsl_mtx_mult(&xinv, &xw, &xtemp);
599 zsl_mtx_mult(&xtemp, &ymtx, &bmtx);
600 zsl_vec_from_arr(b, bmtx.data);
601
602 zsl_mtx_mult(&x_exp, &bmtx, &xtemp2);
603 zsl_mtx_sub(&ymtx, &xtemp2, &emtx);
604 zsl_real_t e_norm = 0.0, ymean, ysum = 0.0;
605 zsl_sta_mean(y, &ymean);
606 for (size_t g = 0; g < x->sz_rows; g++) {
607 e_norm += emtx.data[g] * emtx.data[g];
608 ysum += (y->data[g] - ymean) * (y->data[g] - ymean);
609 }
610
611 *r = 1. - e_norm / ysum;
612
613 return 0;
614 }
615 #endif
616
617 #ifndef CONFIG_ZSL_SINGLE_PRECISION
zsl_sta_quad_fit(struct zsl_mtx * m,struct zsl_vec * b)618 int zsl_sta_quad_fit(struct zsl_mtx *m, struct zsl_vec *b)
619 {
620 #if CONFIG_ZSL_BOUNDS_CHECKS
621 /* Make sure matrices and vectors' sizes are adequate. */
622 if (m->sz_cols != 3 || b->sz != 9) {
623 return -EINVAL;
624 }
625 #endif
626
627 ZSL_MATRIX_DEF(x, m->sz_rows, 9);
628 ZSL_VECTOR_DEF(xv, 9);
629 ZSL_VECTOR_DEF(mv, 3);
630 ZSL_MATRIX_DEF(y, m->sz_rows, 1);
631
632 for (size_t i = 0; i < m->sz_rows; i++) {
633 zsl_mtx_get_row(m, i, mv.data);
634 xv.data[0] = mv.data[0] * mv.data[0];
635 xv.data[1] = mv.data[1] * mv.data[1];
636 xv.data[2] = mv.data[2] * mv.data[2];
637 xv.data[3] = 2.0 * mv.data[0] * mv.data[1];
638 xv.data[4] = 2.0 * mv.data[0] * mv.data[2];
639 xv.data[5] = 2.0 * mv.data[1] * mv.data[2];
640 xv.data[6] = 2.0 * mv.data[0];
641 xv.data[7] = 2.0 * mv.data[1];
642 xv.data[8] = 2.0 * mv.data[2];
643 zsl_mtx_set_row(&x, i, xv.data);
644 y.data[i] = 1.0;
645 }
646
647 ZSL_MATRIX_DEF(xt, 9, m->sz_rows);
648 ZSL_MATRIX_DEF(xtx, 9, 9);
649 ZSL_MATRIX_DEF(inv, 9, 9);
650 ZSL_MATRIX_DEF(xtmp, 9, (m->sz_rows));
651 ZSL_MATRIX_DEF(btmp, 9, 1);
652
653 zsl_mtx_trans(&x, &xt);
654 zsl_mtx_mult(&xt, &x, &xtx);
655 zsl_mtx_inv(&xtx, &inv);
656 zsl_mtx_mult(&inv, &xt, &xtmp);
657 zsl_mtx_mult(&xtmp, &y, &btmp);
658
659 zsl_vec_from_arr(b, btmp.data);
660
661 return 0;
662 }
663 #endif
664
zsl_sta_abs_err(zsl_real_t * val,zsl_real_t * exp_val,zsl_real_t * err)665 int zsl_sta_abs_err(zsl_real_t *val, zsl_real_t *exp_val, zsl_real_t *err)
666 {
667 *err = ZSL_ABS(*val - *exp_val);
668
669 return 0;
670 }
671
zsl_sta_rel_err(zsl_real_t * val,zsl_real_t * exp_val,zsl_real_t * err)672 int zsl_sta_rel_err(zsl_real_t *val, zsl_real_t *exp_val, zsl_real_t *err)
673 {
674 *err = ZSL_ABS(100. * *val - 100. * *exp_val) / *exp_val;
675
676 return 0;
677 }
678
zsl_sta_sta_err(struct zsl_vec * v,zsl_real_t * err)679 int zsl_sta_sta_err(struct zsl_vec *v, zsl_real_t *err)
680 {
681 #if CONFIG_ZSL_BOUNDS_CHECKS
682 /* Make sure v has at least dimension 1. */
683 if (v->sz == 0) {
684 return -EINVAL;
685 }
686 #endif
687
688 zsl_real_t var;
689 zsl_sta_var(v, &var);
690 *err = ZSL_SQRT(var / v->sz);
691
692 return 0;
693 }
694