1 /*
2 * Copyright (c) 2019 Kevin Townsend (KTOWN)
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/vectors.h>
12 #include <zsl/zsl.h>
13
14 /* Enable optimised ARM Thumb/Thumb2 functions if available. */
15 #if (CONFIG_ZSL_PLATFORM_OPT == 1 || CONFIG_ZSL_PLATFORM_OPT == 2)
16 #include <zsl/asm/arm/asm_arm_vectors.h>
17 #endif
18
zsl_vec_init(struct zsl_vec * v)19 int zsl_vec_init(struct zsl_vec *v)
20 {
21 memset(v->data, 0, v->sz * sizeof(zsl_real_t));
22
23 return 0;
24 }
25
zsl_vec_from_arr(struct zsl_vec * v,zsl_real_t * a)26 int zsl_vec_from_arr(struct zsl_vec *v, zsl_real_t *a)
27 {
28 memcpy(v->data, a, v->sz * sizeof(zsl_real_t));
29
30 return 0;
31 }
32
zsl_vec_copy(struct zsl_vec * vdest,struct zsl_vec * vsrc)33 int zsl_vec_copy(struct zsl_vec *vdest, struct zsl_vec *vsrc)
34 {
35 vdest->sz = vsrc->sz;
36 memcpy(vdest->data, vsrc->data, sizeof(zsl_real_t) *
37 vdest->sz);
38
39 return 0;
40 }
41
zsl_vec_get_subset(struct zsl_vec * v,size_t offset,size_t len,struct zsl_vec * vsub)42 int zsl_vec_get_subset(struct zsl_vec *v, size_t offset, size_t len,
43 struct zsl_vec *vsub)
44 {
45 #if CONFIG_ZSL_BOUNDS_CHECKS
46 /* Make sure offset doesn't exceed v->sz. */
47 if (offset >= v->sz) {
48 return -EINVAL;
49 }
50 /* If offset+len exceeds v->sz, truncate len. */
51 if (offset + len >= v->sz) {
52 len = v->sz - offset;
53 }
54 /* Make sure vsub->sz is at least len, otherwise buffer overrun. */
55 if (vsub->sz < len) {
56 return -EINVAL;
57 }
58 #endif
59
60 /* Truncate vsub->sz if there is an underrun. */
61 if (vsub->sz > len) {
62 vsub->sz = len;
63 }
64
65 memcpy(vsub->data, &v->data[offset], len * sizeof(zsl_real_t));
66
67 return 0;
68 }
69
70 #if !asm_vec_add
zsl_vec_add(struct zsl_vec * v,struct zsl_vec * w,struct zsl_vec * x)71 int zsl_vec_add(struct zsl_vec *v, struct zsl_vec *w, struct zsl_vec *x)
72 {
73 #if CONFIG_ZSL_BOUNDS_CHECKS
74 /* Make sure v and w are equal length. */
75 if ((v->sz != w->sz) || (v->sz != x->sz)) {
76 return -EINVAL;
77 }
78 #endif
79
80 for (size_t i = 0; i < v->sz; i++) {
81 x->data[i] = v->data[i] + w->data[i];
82 }
83
84 return 0;
85 }
86 #endif
87
zsl_vec_sub(struct zsl_vec * v,struct zsl_vec * w,struct zsl_vec * x)88 int zsl_vec_sub(struct zsl_vec *v, struct zsl_vec *w, struct zsl_vec *x)
89 {
90 #if CONFIG_ZSL_BOUNDS_CHECKS
91 /* Make sure v and w are equal length. */
92 if ((v->sz != w->sz) || (v->sz != x->sz)) {
93 return -EINVAL;
94 }
95 #endif
96
97 for (size_t i = 0; i < v->sz; i++) {
98 x->data[i] = v->data[i] - w->data[i];
99 }
100
101 return 0;
102 }
103
zsl_vec_neg(struct zsl_vec * v)104 int zsl_vec_neg(struct zsl_vec *v)
105 {
106 for (size_t i = 0; i < v->sz; i++) {
107 v->data[i] = -v->data[i];
108 }
109
110 return 0;
111 }
112
zsl_vec_sum(struct zsl_vec ** v,size_t n,struct zsl_vec * w)113 int zsl_vec_sum(struct zsl_vec **v, size_t n, struct zsl_vec *w)
114 {
115 size_t sz_last;
116
117 if (!n) {
118 return -EINVAL;
119 }
120
121 sz_last = v[0]->sz;
122
123 #if CONFIG_ZSL_BOUNDS_CHECKS
124 /* Make sure all vectors have the same size. */
125 for (size_t i = 0; i < n; i++) {
126 if (sz_last != v[i]->sz) {
127 return -EINVAL;
128 }
129 }
130 #endif
131
132 /* Sum all vectors. */
133 w->sz = sz_last;
134 for (size_t i = 0; i < n; i++) {
135 for (size_t j = 0; j < w->sz; j++) {
136 w->data[j] += v[i]->data[j];
137 }
138 }
139
140 return 0;
141 }
142
143 #if !asm_vec_scalar_add
zsl_vec_scalar_add(struct zsl_vec * v,zsl_real_t s)144 int zsl_vec_scalar_add(struct zsl_vec *v, zsl_real_t s)
145 {
146 for (size_t i = 0; i < v->sz; i++) {
147 v->data[i] += s;
148 }
149
150 return 0;
151 }
152 #endif
153
154 #if !asm_vec_scalar_mult
zsl_vec_scalar_mult(struct zsl_vec * v,zsl_real_t s)155 int zsl_vec_scalar_mult(struct zsl_vec *v, zsl_real_t s)
156 {
157 for (size_t i = 0; i < v->sz; i++) {
158 v->data[i] *= s;
159 }
160
161 return 0;
162 }
163 #endif
164
165 #if !asm_vec_scalar_div
zsl_vec_scalar_div(struct zsl_vec * v,zsl_real_t s)166 int zsl_vec_scalar_div(struct zsl_vec *v, zsl_real_t s)
167 {
168 /* Avoid divide by zero errors. */
169 if (s == 0) {
170 return -EINVAL;
171 }
172
173 for (size_t i = 0; i < v->sz; i++) {
174 v->data[i] /= s;
175 }
176
177 return 0;
178 }
179 #endif
180
zsl_vec_dist(struct zsl_vec * v,struct zsl_vec * w)181 zsl_real_t zsl_vec_dist(struct zsl_vec *v, struct zsl_vec *w)
182 {
183 int rc = 0;
184
185 zsl_real_t xdat[v->sz];
186
187 struct zsl_vec x = { .sz = v->sz, .data = xdat };
188
189 memset(xdat, 0, x.sz * sizeof(zsl_real_t));
190
191 rc = zsl_vec_sub(v, w, &x);
192 if (rc) {
193 return NAN;
194 }
195
196 return zsl_vec_norm(&x);
197 }
198
zsl_vec_dot(struct zsl_vec * v,struct zsl_vec * w,zsl_real_t * d)199 int zsl_vec_dot(struct zsl_vec *v, struct zsl_vec *w, zsl_real_t *d)
200 {
201 zsl_real_t res = 0.0;
202
203 #if CONFIG_ZSL_BOUNDS_CHECKS
204 /* Make sure v and w are equal length. */
205 if (v->sz != w->sz) {
206 return -EINVAL;
207 }
208 #endif
209
210 for (size_t i = 0; i < v->sz; i++) {
211 res += v->data[i] * w->data[i];
212 }
213
214 *d = res;
215
216 return 0;
217 }
218
zsl_vec_norm(struct zsl_vec * v)219 zsl_real_t zsl_vec_norm(struct zsl_vec *v)
220 {
221 /*
222 * |v| = sqrt( v[0]^2 + v[1]^2 + V[...]^2 )
223 */
224 if (v == NULL) {
225 return 0;
226 }
227 return ZSL_SQRT(zsl_vec_sum_of_sqrs(v));
228 }
229
zsl_vec_project(struct zsl_vec * u,struct zsl_vec * v,struct zsl_vec * w)230 int zsl_vec_project(struct zsl_vec *u, struct zsl_vec *v, struct zsl_vec *w)
231 {
232 zsl_real_t p;
233 zsl_real_t t;
234
235 #if CONFIG_ZSL_BOUNDS_CHECKS
236 /* Make sure v, w and u are equal length. */
237 if ((v->sz != w->sz) || (v->sz != u->sz)) {
238 return -EINVAL;
239 }
240 #endif
241
242 zsl_vec_copy(w, u);
243 zsl_vec_dot(v, u, &p);
244 zsl_vec_dot(u, u, &t);
245 zsl_vec_scalar_mult(w, p / t);
246
247 return 0;
248 }
249
zsl_vec_to_unit(struct zsl_vec * v)250 int zsl_vec_to_unit(struct zsl_vec *v)
251 {
252 zsl_real_t norm = zsl_vec_norm(v);
253
254 /*
255 * v
256 * unit(v) = ---
257 * |v|
258 */
259
260 /* Avoid divide by zero errors. */
261 if (norm != 0.0) {
262 zsl_vec_scalar_mult(v, 1.0 / norm);
263 } else {
264 /* TODO: What is the best approach here? */
265 /* On div by zero clear vector and return v[0] = 1.0. */
266 zsl_vec_init(v);
267 v->data[0] = 1.0;
268 }
269
270 return 0;
271 }
272
zsl_vec_cross(struct zsl_vec * v,struct zsl_vec * w,struct zsl_vec * c)273 int zsl_vec_cross(struct zsl_vec *v, struct zsl_vec *w, struct zsl_vec *c)
274 {
275 #if CONFIG_ZSL_BOUNDS_CHECKS
276 /* Make sure this is a 3-vector. */
277 if ((v->sz != 3) || (w->sz != 3) || (c->sz != 3)) {
278 return -EINVAL;
279 }
280 #endif
281
282 /*
283 * Given:
284 *
285 * |Cx| |Vx| |Wx|
286 * C = |Cy|, V = |Vy|, W = |Wy|
287 * |Cz| |Vz| |Wz|
288 *
289 * The cross product can be represented as:
290 *
291 * Cx = VyWz - VzWy
292 * Cy = VzWx - VxWz
293 * Cz = VxWy - VyWx
294 */
295
296 c->data[0] = v->data[1] * w->data[2] - v->data[2] * w->data[1];
297 c->data[1] = v->data[2] * w->data[0] - v->data[0] * w->data[2];
298 c->data[2] = v->data[0] * w->data[1] - v->data[1] * w->data[0];
299
300 return 0;
301 }
302
zsl_vec_sum_of_sqrs(struct zsl_vec * v)303 zsl_real_t zsl_vec_sum_of_sqrs(struct zsl_vec *v)
304 {
305 zsl_real_t dot = 0.0;
306
307 zsl_vec_dot(v, v, &dot);
308
309 return dot;
310 }
311
zsl_vec_mean(struct zsl_vec ** v,size_t n,struct zsl_vec * m)312 int zsl_vec_mean(struct zsl_vec **v, size_t n, struct zsl_vec *m)
313 {
314 int rc;
315
316 #if CONFIG_ZSL_BOUNDS_CHECKS
317 /* Make sure the mean vector has an approproate size. */
318 if (m->sz != v[0]->sz) {
319 return -EINVAL;
320 }
321 #endif
322
323 /* sum also checks that all vectors have the same length. */
324 rc = zsl_vec_sum(v, n, m);
325 if (rc) {
326 return rc;
327 }
328
329 rc = zsl_vec_scalar_mult(m, 1.0 / (zsl_real_t) n);
330
331 return 0;
332 }
333
zsl_vec_ar_mean(struct zsl_vec * v,zsl_real_t * m)334 int zsl_vec_ar_mean(struct zsl_vec *v, zsl_real_t *m)
335 {
336 /* Avoid divide by zero errors. */
337 if (v->sz < 1) {
338 return -EINVAL;
339 }
340
341 *m = 0.0;
342 for (size_t i = 0; i < v->sz; i++) {
343 *m += v->data[i];
344 }
345
346 *m /= v->sz;
347
348 return 0;
349 }
350
zsl_vec_rev(struct zsl_vec * v)351 int zsl_vec_rev(struct zsl_vec *v)
352 {
353 zsl_real_t t;
354 size_t start = 0;
355 size_t end = v->sz - 1;
356
357 while (start < end) {
358 t = v->data[start];
359 v->data[start] = v->data[end];
360 v->data[end] = t;
361 start++;
362 end--;
363 }
364
365 return 0;
366 }
367
zsl_vec_zte(struct zsl_vec * v)368 int zsl_vec_zte(struct zsl_vec *v)
369 {
370 size_t x = 0;
371 zsl_real_t epsilon = 1E-6;
372
373 for (size_t g = 0; g < v->sz; g++) {
374 if ((v->data[g - x] >= 0.0 && v->data[g - x] < epsilon) ||
375 (v->data[g - x] <= 0.0 && v->data[g - x] > epsilon)) {
376 for (size_t p = g - x; p < (v->sz - 1); p++) {
377 v->data[p] = v->data[p + 1];
378 }
379 v->data[v->sz - 1] = 0.0;
380 x++;
381 }
382 }
383
384 return 0;
385 }
386
zsl_vec_is_equal(struct zsl_vec * v,struct zsl_vec * w,zsl_real_t eps)387 bool zsl_vec_is_equal(struct zsl_vec *v, struct zsl_vec *w, zsl_real_t eps)
388 {
389 zsl_real_t c;
390
391 if (v->sz != w->sz) {
392 return false;
393 }
394
395 for (size_t i = 0; i < v->sz; i++) {
396 c = v->data[i] - w->data[i];
397 if (c >= eps || -c >= eps) {
398 return false;
399 }
400 }
401
402 return true;
403 }
404
zsl_vec_is_nonneg(struct zsl_vec * v)405 bool zsl_vec_is_nonneg(struct zsl_vec *v)
406 {
407 for (size_t i = 0; i < v->sz; i++) {
408 if (v->data[i] < 0.0) {
409 return false;
410 }
411 }
412
413 return true;
414 }
415
zsl_vec_contains(struct zsl_vec * v,zsl_real_t val,zsl_real_t eps)416 int zsl_vec_contains(struct zsl_vec *v, zsl_real_t val, zsl_real_t eps)
417 {
418 zsl_real_t c;
419 int count = 0;
420
421 for (size_t i = 0; i < v->sz; i++) {
422 c = v->data[i] - val;
423 if (c < eps && -c < eps) {
424 count++;
425 }
426 }
427
428 return count;
429 }
430
431 /**
432 * @brief Quicksort implementation used by zsl_vec_sort.
433 *
434 * @param v Unsorted input vector.
435 * @param low Low index value.
436 * @param high High index value.
437 *
438 * @return 0 if everything executed properly, otherwise a negative error code.
439 */
zsl_vec_quicksort(struct zsl_vec * v,size_t low,size_t high)440 static int zsl_vec_quicksort(struct zsl_vec *v, size_t low, size_t high)
441 {
442 size_t i, j, p;
443 zsl_real_t t;
444
445 if (low < high) {
446 p = low;
447 i = low;
448 j = high;
449
450 while (i < j) {
451 while (v->data[i] <= v->data[p] && i <= high) {
452 i++;
453 }
454 while (v->data[j] > v->data[p] && j >= low) {
455 j--;
456 }
457 if (i < j) {
458 t = v->data[i];
459 v->data[i] = v->data[j];
460 v->data[j] = t;
461 }
462 }
463
464 t = v->data[j];
465 v->data[j] = v->data[p];
466 v->data[p] = t;
467
468 zsl_vec_quicksort(v, low, i - 1);
469 zsl_vec_quicksort(v, j + 1, high);
470 }
471
472 return 0;
473 }
474
zsl_vec_sort(struct zsl_vec * v,struct zsl_vec * w)475 int zsl_vec_sort(struct zsl_vec *v, struct zsl_vec *w)
476 {
477 /* Set counters to zero. */
478 size_t count = 0;
479 size_t count2 = 0;
480 size_t i, j, k;
481
482 ZSL_VECTOR_DEF(u, v->sz);
483 zsl_vec_init(&u);
484
485 /* Copy the vector 'v' into the vector 'u' with no repeated values. */
486 for (j = 0; j < v->sz; j++) {
487 if (v->data[j] >= 1E-5 || v->data[j] <= 1E-5) {
488 if (zsl_vec_contains(&u, v->data[j], 1E-5) == 0) {
489 u.data[count] = v->data[j];
490 count++;
491 }
492 }
493 }
494
495 if (zsl_vec_contains(v, 0.0, 1E-5) > 0) {
496 count++;
497 }
498
499 u.sz = count;
500
501 /* Sort the vector with no repeated values 'u'. */
502 zsl_vec_quicksort(&u, 0, count - 1);
503
504 /* Add back the repeated values in the correct order into the vector 'w'. */
505 for (i = 0; i < count; i++) {
506 for (k = 0; k < zsl_vec_contains(v, u.data[i], 1E-5); k++) {
507 w->data[count2] = u.data[i];
508 count2++;
509 }
510 }
511
512 return 0;
513 }
514
zsl_vec_print(struct zsl_vec * v)515 int zsl_vec_print(struct zsl_vec *v)
516 {
517 for (size_t g = 0; g < v->sz; g++) {
518 printf("%f ", v->data[g]);
519 }
520 printf("\n\n");
521
522 return 0;
523 }
524