Zephyr Scientific Library (zscilib)
vectors.c
Go to the documentation of this file.
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 
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 
27 {
28  memcpy(v->data, a, v->sz * sizeof(zsl_real_t));
29 
30  return 0;
31 }
32 
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 
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
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 
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 
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 
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
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
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
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 
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 
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 
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 
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 
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 
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 
304 {
305  zsl_real_t dot = 0.0;
306 
307  zsl_vec_dot(v, v, &dot);
308 
309  return dot;
310 }
311 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 }
zsl_vec_get_subset
int zsl_vec_get_subset(struct zsl_vec *v, size_t offset, size_t len, struct zsl_vec *vsub)
Returns a subset of source vector 'v' in 'vsub'..
Definition: vectors.c:42
zsl_vec_mean
int zsl_vec_mean(struct zsl_vec **v, size_t n, struct zsl_vec *m)
Computes the component-wise mean of a set of identically-sized vectors.
Definition: vectors.c:312
zsl_vec_ar_mean
int zsl_vec_ar_mean(struct zsl_vec *v, zsl_real_t *m)
Computes the arithmetic mean of a vector.
Definition: vectors.c:334
zsl_vec_init
int zsl_vec_init(struct zsl_vec *v)
Definition: vectors.c:19
zsl_vec::data
zsl_real_t * data
Definition: vectors.h:44
zsl_vec::sz
size_t sz
Definition: vectors.h:42
zsl_vec_sum_of_sqrs
zsl_real_t zsl_vec_sum_of_sqrs(struct zsl_vec *v)
Computes the vector's sum of squares.
Definition: vectors.c:303
zsl_vec_norm
zsl_real_t zsl_vec_norm(struct zsl_vec *v)
Calculates the norm or absolute value of vector 'v' (the square root of the vector's dot product).
Definition: vectors.c:219
zsl_vec_dot
int zsl_vec_dot(struct zsl_vec *v, struct zsl_vec *w, zsl_real_t *d)
Computes the dot (aka scalar) product of two equal-length vectors (the sum of their component-wise pr...
Definition: vectors.c:199
zsl_vec_project
int zsl_vec_project(struct zsl_vec *u, struct zsl_vec *v, struct zsl_vec *w)
Calculates the projection of vector 'u' over vector 'v', placing the results in vector 'w'.
Definition: vectors.c:230
zsl_vec_print
int zsl_vec_print(struct zsl_vec *v)
Print the supplied vector using printf in a human-readable manner.
Definition: vectors.c:515
zsl_vec_sub
int zsl_vec_sub(struct zsl_vec *v, struct zsl_vec *w, struct zsl_vec *x)
Subtracts corresponding vector elements in 'v' and 'w', saving to 'x'.
Definition: vectors.c:88
zsl_vec_contains
int zsl_vec_contains(struct zsl_vec *v, zsl_real_t val, zsl_real_t eps)
Checks if vector v contains val, returning the number of occurences.
Definition: vectors.c:416
zsl_vec_sort
int zsl_vec_sort(struct zsl_vec *v, struct zsl_vec *w)
Sorts the values in vector v from smallest to largest using quicksort, and assigns the sorted output ...
Definition: vectors.c:475
zsl_vec_from_arr
int zsl_vec_from_arr(struct zsl_vec *v, zsl_real_t *a)
Converts an array of values into a vector. The number of elements in array 'a' must match the number ...
Definition: vectors.c:26
zsl_vec_rev
int zsl_vec_rev(struct zsl_vec *v)
Reverses the order of the entries in vector 'v'.
Definition: vectors.c:351
zsl_vec_sum
int zsl_vec_sum(struct zsl_vec **v, size_t n, struct zsl_vec *w)
Component-wise sum of a set of equal-length vectors.
Definition: vectors.c:113
vectors.h
API header file for vectors in zscilib.
zsl_vec_neg
int zsl_vec_neg(struct zsl_vec *v)
Negates the elements in vector 'v'.
Definition: vectors.c:104
zsl_vec_copy
int zsl_vec_copy(struct zsl_vec *vdest, struct zsl_vec *vsrc)
Copies the contents of vector 'vsrc' into vector 'vdest'.
Definition: vectors.c:33
zsl_vec_cross
int zsl_vec_cross(struct zsl_vec *v, struct zsl_vec *w, struct zsl_vec *c)
Computes the cross (or vector) product of two 3-vectors.
Definition: vectors.c:273
zsl_vec_dist
zsl_real_t zsl_vec_dist(struct zsl_vec *v, struct zsl_vec *w)
Calculates the distance between two vectors, which is equal to the norm of vector v - vector w.
Definition: vectors.c:181
zsl_vec_to_unit
int zsl_vec_to_unit(struct zsl_vec *v)
Converts (normalises) vector 'v' to a unit vector (a vector of magnitude or length 1)....
Definition: vectors.c:250
ZSL_VECTOR_DEF
#define ZSL_VECTOR_DEF(name, n)
Definition: vectors.h:52
zsl.h
API header file for zscilib.
zsl_vec_zte
int zsl_vec_zte(struct zsl_vec *v)
Rearranges the input vector to place any zero-values at the end.
Definition: vectors.c:368
zsl_vec
Represents a vector.
Definition: vectors.h:40
zsl_real_t
double zsl_real_t
Definition: zsl.h:51
zsl_vec_add
int zsl_vec_add(struct zsl_vec *v, struct zsl_vec *w, struct zsl_vec *x)
Adds corresponding vector elements in 'v' and 'w', saving to 'x'.
Definition: vectors.c:71
zsl_vec_scalar_div
int zsl_vec_scalar_div(struct zsl_vec *v, zsl_real_t s)
Divide a vector by a scalar.
Definition: vectors.c:166
zsl_vec_is_equal
bool zsl_vec_is_equal(struct zsl_vec *v, struct zsl_vec *w, zsl_real_t eps)
Checks if two vectors are identical in size and content.
Definition: vectors.c:387
zsl_vec_scalar_mult
int zsl_vec_scalar_mult(struct zsl_vec *v, zsl_real_t s)
Multiply a vector by a scalar.
Definition: vectors.c:155
zsl_vec_scalar_add
int zsl_vec_scalar_add(struct zsl_vec *v, zsl_real_t s)
Adds a scalar to each element in a vector.
Definition: vectors.c:144
ZSL_SQRT
#define ZSL_SQRT
Definition: zsl.h:91
zsl_vec_is_nonneg
bool zsl_vec_is_nonneg(struct zsl_vec *v)
Checks if all elements in vector v are >= zero.
Definition: vectors.c:405