Zephyr Scientific Library (zscilib)
matrices.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/zsl.h>
12 #include <zsl/matrices.h>
13 
14 /*
15  * WARNING: Work in progress!
16  *
17  * The code in this module is very 'naive' in the sense that no attempt
18  * has been made at efficiency. It is written from the perspective
19  * that code should be written to be 'reliable, elegant, efficient' in that
20  * order.
21  *
22  * Clarity and reliability have been absolutely prioritized in this
23  * early stage, with the key goal being good unit test coverage before
24  * moving on to any form of general-purpose or architecture-specific
25  * optimisation.
26  */
27 
28 // TODO: Introduce local macros for bounds/shape checks to avoid duplication!
29 
30 int
31 zsl_mtx_entry_fn_empty(struct zsl_mtx *m, size_t i, size_t j)
32 {
33  return zsl_mtx_set(m, i, j, 0);
34 }
35 
36 int
37 zsl_mtx_entry_fn_identity(struct zsl_mtx *m, size_t i, size_t j)
38 {
39  return zsl_mtx_set(m, i, j, i == j ? 1.0 : 0);
40 }
41 
42 int
43 zsl_mtx_entry_fn_random(struct zsl_mtx *m, size_t i, size_t j)
44 {
45  /* TODO: Determine an appropriate random number generator. */
46  return zsl_mtx_set(m, i, j, 0);
47 }
48 
49 int
51 {
52  int rc;
53 
54  for (size_t i = 0; i < m->sz_rows; i++) {
55  for (size_t j = 0; j < m->sz_cols; j++) {
56  /* If entry_fn is NULL, assign 0.0 values. */
57  if (entry_fn == NULL) {
58  rc = zsl_mtx_entry_fn_empty(m, i, j);
59  } else {
60  rc = entry_fn(m, i, j);
61  }
62  /* Abort if entry_fn returned an error code. */
63  if (rc) {
64  return rc;
65  }
66  }
67  }
68 
69  return 0;
70 }
71 
72 int
74 {
75  memcpy(m->data, a, (m->sz_rows * m->sz_cols) * sizeof(zsl_real_t));
76 
77  return 0;
78 }
79 
80 int
81 zsl_mtx_copy(struct zsl_mtx *mdest, struct zsl_mtx *msrc)
82 {
83 #if CONFIG_ZSL_BOUNDS_CHECKS
84  /* Ensure that msrc and mdest have the same shape. */
85  if ((mdest->sz_rows != msrc->sz_rows) ||
86  (mdest->sz_cols != msrc->sz_cols)) {
87  return -EINVAL;
88  }
89 #endif
90 
91  /* Make a copy of matrix 'msrc'. */
92  memcpy(mdest->data, msrc->data, sizeof(zsl_real_t) *
93  msrc->sz_rows * msrc->sz_cols);
94 
95  return 0;
96 }
97 
98 int
99 zsl_mtx_get(struct zsl_mtx *m, size_t i, size_t j, zsl_real_t *x)
100 {
101 #if CONFIG_ZSL_BOUNDS_CHECKS
102  if ((i >= m->sz_rows) || (j >= m->sz_cols)) {
103  return -EINVAL;
104  }
105 #endif
106 
107  *x = m->data[(i * m->sz_cols) + j];
108 
109  return 0;
110 }
111 
112 int
113 zsl_mtx_set(struct zsl_mtx *m, size_t i, size_t j, zsl_real_t x)
114 {
115 #if CONFIG_ZSL_BOUNDS_CHECKS
116  if ((i >= m->sz_rows) || (j >= m->sz_cols)) {
117  return -EINVAL;
118  }
119 #endif
120 
121  m->data[(i * m->sz_cols) + j] = x;
122 
123  return 0;
124 }
125 
126 int
127 zsl_mtx_get_row(struct zsl_mtx *m, size_t i, zsl_real_t *v)
128 {
129  int rc;
130  zsl_real_t x;
131 
132  for (size_t j = 0; j < m->sz_cols; j++) {
133  rc = zsl_mtx_get(m, i, j, &x);
134  if (rc) {
135  return rc;
136  }
137  v[j] = x;
138  }
139 
140  return 0;
141 }
142 
143 int
144 zsl_mtx_set_row(struct zsl_mtx *m, size_t i, zsl_real_t *v)
145 {
146  int rc;
147 
148  for (size_t j = 0; j < m->sz_cols; j++) {
149  rc = zsl_mtx_set(m, i, j, v[j]);
150  if (rc) {
151  return rc;
152  }
153  }
154 
155  return 0;
156 }
157 
158 int
159 zsl_mtx_get_col(struct zsl_mtx *m, size_t j, zsl_real_t *v)
160 {
161  int rc;
162  zsl_real_t x;
163 
164  for (size_t i = 0; i < m->sz_rows; i++) {
165  rc = zsl_mtx_get(m, i, j, &x);
166  if (rc) {
167  return rc;
168  }
169  v[i] = x;
170  }
171 
172  return 0;
173 }
174 
175 int
176 zsl_mtx_set_col(struct zsl_mtx *m, size_t j, zsl_real_t *v)
177 {
178  int rc;
179 
180  for (size_t i = 0; i < m->sz_rows; i++) {
181  rc = zsl_mtx_set(m, i, j, v[i]);
182  if (rc) {
183  return rc;
184  }
185  }
186 
187  return 0;
188 }
189 
190 int
192 {
193  /* Execute the unary operation component by component. */
194  for (size_t i = 0; i < m->sz_cols * m->sz_rows; i++) {
195  switch (op) {
197  m->data[i] += 1.0;
198  break;
200  m->data[i] -= 1.0;
201  break;
203  m->data[i] = -m->data[i];
204  break;
206  m->data[i] = ZSL_ROUND(m->data[i]);
207  break;
209  m->data[i] = ZSL_ABS(m->data[i]);
210  break;
212  m->data[i] = ZSL_FLOOR(m->data[i]);
213  break;
215  m->data[i] = ZSL_CEIL(m->data[i]);
216  break;
218  m->data[i] = ZSL_EXP(m->data[i]);
219  break;
221  m->data[i] = ZSL_LOG(m->data[i]);
222  break;
224  m->data[i] = ZSL_LOG10(m->data[i]);
225  break;
227  m->data[i] = ZSL_SQRT(m->data[i]);
228  break;
230  m->data[i] = ZSL_SIN(m->data[i]);
231  break;
233  m->data[i] = ZSL_COS(m->data[i]);
234  break;
236  m->data[i] = ZSL_TAN(m->data[i]);
237  break;
239  m->data[i] = ZSL_ASIN(m->data[i]);
240  break;
242  m->data[i] = ZSL_ACOS(m->data[i]);
243  break;
245  m->data[i] = ZSL_ATAN(m->data[i]);
246  break;
248  m->data[i] = ZSL_SINH(m->data[i]);
249  break;
251  m->data[i] = ZSL_COSH(m->data[i]);
252  break;
254  m->data[i] = ZSL_TANH(m->data[i]);
255  break;
256  default:
257  /* Not yet implemented! */
258  return -ENOSYS;
259  }
260  }
261 
262  return 0;
263 }
264 
265 int
267 {
268  int rc;
269 
270  for (size_t i = 0; i < m->sz_rows; i++) {
271  for (size_t j = 0; j < m->sz_cols; j++) {
272  /* If fn is NULL, do nothing. */
273  if (fn != NULL) {
274  rc = fn(m, i, j);
275  if (rc) {
276  return rc;
277  }
278  }
279  }
280  }
281 
282  return 0;
283 }
284 
285 int
286 zsl_mtx_binary_op(struct zsl_mtx *ma, struct zsl_mtx *mb, struct zsl_mtx *mc,
288 {
289 #if CONFIG_ZSL_BOUNDS_CHECKS
290  if ((ma->sz_rows != mb->sz_rows) || (mb->sz_rows != mc->sz_rows) ||
291  (ma->sz_cols != mb->sz_cols) || (mb->sz_cols != mc->sz_cols)) {
292  return -EINVAL;
293  }
294 #endif
295 
296  /* Execute the binary operation component by component. */
297  for (size_t i = 0; i < ma->sz_cols * ma->sz_rows; i++) {
298  switch (op) {
300  mc->data[i] = ma->data[i] + mb->data[i];
301  break;
303  mc->data[i] = ma->data[i] - mb->data[i];
304  break;
306  mc->data[i] = ma->data[i] * mb->data[i];
307  break;
309  if (mb->data[i] == 0.0) {
310  mc->data[i] = 0.0;
311  } else {
312  mc->data[i] = ma->data[i] / mb->data[i];
313  }
314  break;
316  mc->data[i] = (ma->data[i] + mb->data[i]) / 2.0;
318  mc->data[i] = ZSL_POW(ma->data[i], mb->data[i]);
320  mc->data[i] = ma->data[i] < mb->data[i] ?
321  ma->data[i] : mb->data[i];
323  mc->data[i] = ma->data[i] > mb->data[i] ?
324  ma->data[i] : mb->data[i];
326  mc->data[i] = ma->data[i] == mb->data[i] ? 1.0 : 0.0;
328  mc->data[i] = ma->data[i] != mb->data[i] ? 1.0 : 0.0;
330  mc->data[i] = ma->data[i] < mb->data[i] ? 1.0 : 0.0;
332  mc->data[i] = ma->data[i] > mb->data[i] ? 1.0 : 0.0;
334  mc->data[i] = ma->data[i] <= mb->data[i] ? 1.0 : 0.0;
336  mc->data[i] = ma->data[i] >= mb->data[i] ? 1.0 : 0.0;
337  default:
338  /* Not yet implemented! */
339  return -ENOSYS;
340  }
341  }
342 
343  return 0;
344 }
345 
346 int
347 zsl_mtx_binary_func(struct zsl_mtx *ma, struct zsl_mtx *mb,
348  struct zsl_mtx *mc, zsl_mtx_binary_fn_t fn)
349 {
350  int rc;
351 
352 #if CONFIG_ZSL_BOUNDS_CHECKS
353  if ((ma->sz_rows != mb->sz_rows) || (mb->sz_rows != mc->sz_rows) ||
354  (ma->sz_cols != mb->sz_cols) || (mb->sz_cols != mc->sz_cols)) {
355  return -EINVAL;
356  }
357 #endif
358 
359  for (size_t i = 0; i < ma->sz_rows; i++) {
360  for (size_t j = 0; j < ma->sz_cols; j++) {
361  /* If fn is NULL, do nothing. */
362  if (fn != NULL) {
363  rc = fn(ma, mb, mc, i, j);
364  if (rc) {
365  return rc;
366  }
367  }
368  }
369  }
370 
371  return 0;
372 }
373 
374 int
375 zsl_mtx_add(struct zsl_mtx *ma, struct zsl_mtx *mb, struct zsl_mtx *mc)
376 {
377  return zsl_mtx_binary_op(ma, mb, mc, ZSL_MTX_BINARY_OP_ADD);
378 }
379 
380 int
381 zsl_mtx_add_d(struct zsl_mtx *ma, struct zsl_mtx *mb)
382 {
383  return zsl_mtx_binary_op(ma, mb, ma, ZSL_MTX_BINARY_OP_ADD);
384 }
385 
386 int
387 zsl_mtx_sum_rows_d(struct zsl_mtx *m, size_t i, size_t j)
388 {
389 #if CONFIG_ZSL_BOUNDS_CHECKS
390  if ((i >= m->sz_rows) || (j >= m->sz_rows)) {
391  return -EINVAL;
392  }
393 #endif
394 
395  /* Add row j to row i, element by element. */
396  for (size_t x = 0; x < m->sz_cols; x++) {
397  m->data[(i * m->sz_cols) + x] += m->data[(j * m->sz_cols) + x];
398  }
399 
400  return 0;
401 }
402 
404  size_t i, size_t j, zsl_real_t s)
405 {
406 #if CONFIG_ZSL_BOUNDS_CHECKS
407  if ((i >= m->sz_rows) || (j >= m->sz_cols)) {
408  return -EINVAL;
409  }
410 #endif
411 
412  /* Set the values in row 'i' to 'i[n] += j[n] * s' . */
413  for (size_t x = 0; x < m->sz_cols; x++) {
414  m->data[(i * m->sz_cols) + x] +=
415  (m->data[(j * m->sz_cols) + x] * s);
416  }
417 
418  return 0;
419 }
420 
421 int
422 zsl_mtx_sub(struct zsl_mtx *ma, struct zsl_mtx *mb, struct zsl_mtx *mc)
423 {
424  return zsl_mtx_binary_op(ma, mb, mc, ZSL_MTX_BINARY_OP_SUB);
425 }
426 
427 int
428 zsl_mtx_sub_d(struct zsl_mtx *ma, struct zsl_mtx *mb)
429 {
430  return zsl_mtx_binary_op(ma, mb, ma, ZSL_MTX_BINARY_OP_SUB);
431 }
432 
433 int
434 zsl_mtx_mult(struct zsl_mtx *ma, struct zsl_mtx *mb, struct zsl_mtx *mc)
435 {
436 #if CONFIG_ZSL_BOUNDS_CHECKS
437  /* Ensure that ma has the same number as columns as mb has rows. */
438  if (ma->sz_cols != mb->sz_rows) {
439  return -EINVAL;
440  }
441 
442  /* Ensure that mc has ma rows and mb cols */
443  if ((mc->sz_rows != ma->sz_rows) || (mc->sz_cols != mb->sz_cols)) {
444  return -EINVAL;
445  }
446 #endif
447 
448  ZSL_MATRIX_DEF(ma_copy, ma->sz_rows, ma->sz_cols);
449  ZSL_MATRIX_DEF(mb_copy, mb->sz_rows, mb->sz_cols);
450  zsl_mtx_copy(&ma_copy, ma);
451  zsl_mtx_copy(&mb_copy, mb);
452 
453  for (size_t i = 0; i < ma_copy.sz_rows; i++) {
454  for (size_t j = 0; j < mb_copy.sz_cols; j++) {
455  mc->data[j + i * mb_copy.sz_cols] = 0;
456  for (size_t k = 0; k < ma_copy.sz_cols; k++) {
457  mc->data[j + i * mb_copy.sz_cols] +=
458  ma_copy.data[k + i * ma_copy.sz_cols] *
459  mb_copy.data[j + k * mb_copy.sz_cols];
460  }
461  }
462  }
463 
464  return 0;
465 }
466 
467 int
468 zsl_mtx_mult_d(struct zsl_mtx *ma, struct zsl_mtx *mb)
469 {
470 #if CONFIG_ZSL_BOUNDS_CHECKS
471  /* Ensure that ma has the same number as columns as mb has rows. */
472  if (ma->sz_cols != mb->sz_rows) {
473  return -EINVAL;
474  }
475 
476  /* Ensure that mb is a square matrix. */
477  if (mb->sz_rows != mb->sz_cols) {
478  return -EINVAL;
479  }
480 #endif
481 
482  zsl_mtx_mult(ma, mb, ma);
483 
484  return 0;
485 }
486 
487 int
489 {
490  for (size_t i = 0; i < m->sz_rows * m->sz_cols; i++) {
491  m->data[i] *= s;
492  }
493 
494  return 0;
495 }
496 
497 int
499 {
500 #if CONFIG_ZSL_BOUNDS_CHECKS
501  if (i >= m->sz_rows) {
502  return -EINVAL;
503  }
504 #endif
505 
506  for (size_t k = 0; k < m->sz_cols; k++) {
507  m->data[(i * m->sz_cols) + k] *= s;
508  }
509 
510  return 0;
511 }
512 
513 int
514 zsl_mtx_trans(struct zsl_mtx *ma, struct zsl_mtx *mb)
515 {
516 #if CONFIG_ZSL_BOUNDS_CHECKS
517  /* Ensure that ma and mb have the same shape. */
518  if ((ma->sz_rows != mb->sz_cols) || (ma->sz_cols != mb->sz_rows)) {
519  return -EINVAL;
520  }
521 #endif
522 
523  zsl_real_t d[ma->sz_cols];
524 
525  for (size_t i = 0; i < ma->sz_rows; i++) {
526  zsl_mtx_get_row(ma, i, d);
527  zsl_mtx_set_col(mb, i, d);
528  }
529 
530  return 0;
531 }
532 
533 int
534 zsl_mtx_adjoint_3x3(struct zsl_mtx *m, struct zsl_mtx *ma)
535 {
536  /* Make sure this is a square matrix. */
537  if ((m->sz_rows != m->sz_cols) || (ma->sz_rows != ma->sz_cols)) {
538  return -EINVAL;
539  }
540 
541 #if CONFIG_ZSL_BOUNDS_CHECKS
542  /* Make sure this is a 3x3 matrix. */
543  if ((m->sz_rows != 3) || (ma->sz_rows != 3)) {
544  return -EINVAL;
545  }
546 #endif
547 
548  /*
549  * 3x3 matrix element to array table:
550  *
551  * 1,1 = 0 1,2 = 1 1,3 = 2
552  * 2,1 = 3 2,2 = 4 2,3 = 5
553  * 3,1 = 6 3,2 = 7 3,3 = 8
554  */
555 
556  ma->data[0] = m->data[4] * m->data[8] - m->data[7] * m->data[5];
557  ma->data[1] = m->data[7] * m->data[2] - m->data[1] * m->data[8];
558  ma->data[2] = m->data[1] * m->data[5] - m->data[4] * m->data[2];
559 
560  ma->data[3] = m->data[6] * m->data[5] - m->data[3] * m->data[8];
561  ma->data[4] = m->data[0] * m->data[8] - m->data[6] * m->data[2];
562  ma->data[5] = m->data[3] * m->data[2] - m->data[0] * m->data[5];
563 
564  ma->data[6] = m->data[3] * m->data[7] - m->data[6] * m->data[4];
565  ma->data[7] = m->data[6] * m->data[1] - m->data[0] * m->data[7];
566  ma->data[8] = m->data[0] * m->data[4] - m->data[3] * m->data[1];
567 
568  return 0;
569 }
570 
571 int
572 zsl_mtx_adjoint(struct zsl_mtx *m, struct zsl_mtx *ma)
573 {
574  /* Shortcut for 3x3 matrices. */
575  if (m->sz_rows == 3) {
576  return zsl_mtx_adjoint_3x3(m, ma);
577  }
578 
579 #if CONFIG_ZSL_BOUNDS_CHECKS
580  /* Make sure this is a square matrix. */
581  if (m->sz_rows != m->sz_cols) {
582  return -EINVAL;
583  }
584 #endif
585 
586  zsl_real_t sign;
587  zsl_real_t d;
588  ZSL_MATRIX_DEF(mr, (m->sz_cols - 1), (m->sz_cols - 1));
589 
590  for (size_t i = 0; i < m->sz_cols; i++) {
591  for (size_t j = 0; j < m->sz_cols; j++) {
592  sign = 1.0;
593  if ((i + j) % 2 != 0) {
594  sign = -1.0;
595  }
596  zsl_mtx_reduce(m, &mr, i, j);
597  zsl_mtx_deter(&mr, &d);
598  d *= sign;
599  zsl_mtx_set(ma, i, j, d);
600  }
601  }
602 
603  return 0;
604 }
605 
606 #ifndef CONFIG_ZSL_SINGLE_PRECISION
607 int zsl_mtx_vec_wedge(struct zsl_mtx *m, struct zsl_vec *v)
608 {
609 #if CONFIG_ZSL_BOUNDS_CHECKS
610  /* Make sure the dimensions of 'm' and 'v' match. */
611  if (v->sz != m->sz_cols || v->sz < 4 || m->sz_rows != (m->sz_cols - 1)) {
612  return -EINVAL;
613  }
614 #endif
615 
616  zsl_real_t d;
617 
618  ZSL_MATRIX_DEF(A, m->sz_cols, m->sz_cols);
619  ZSL_MATRIX_DEF(Ai, m->sz_cols, m->sz_cols);
620  ZSL_VECTOR_DEF(Av, m->sz_cols);
621  ZSL_MATRIX_DEF(b, m->sz_cols, 1);
622 
623  zsl_mtx_init(&A, NULL);
624  A.data[(m->sz_cols * m->sz_cols - 1)] = 1.0;
625 
626  for (size_t i = 0; i < m->sz_rows; i++) {
627  zsl_mtx_get_row(m, i, Av.data);
628  zsl_mtx_set_row(&A, i, Av.data);
629  }
630 
631  zsl_mtx_deter(&A, &d);
632  zsl_mtx_inv(&A, &Ai);
633  zsl_mtx_init(&b, NULL);
634  b.data[(m->sz_cols - 1)] = d;
635 
636  zsl_mtx_mult(&Ai, &b, &b);
637 
638  zsl_vec_from_arr(v, b.data);
639 
640  return 0;
641 }
642 #endif
643 
644 int
645 zsl_mtx_reduce(struct zsl_mtx *m, struct zsl_mtx *mr, size_t i, size_t j)
646 {
647  size_t u = 0;
648  zsl_real_t x;
649  zsl_real_t v[mr->sz_rows * mr->sz_rows];
650 
651 #if CONFIG_ZSL_BOUNDS_CHECKS
652  /* Make sure mr is 1 less than m. */
653  if (mr->sz_rows != m->sz_rows - 1) {
654  return -EINVAL;
655  }
656  if (mr->sz_cols != m->sz_cols - 1) {
657  return -EINVAL;
658  }
659  if ((i >= m->sz_rows) || (j >= m->sz_cols)) {
660  return -EINVAL;
661  }
662 #endif
663 
664  for (size_t k = 0; k < m->sz_rows; k++) {
665  for (size_t g = 0; g < m->sz_rows; g++) {
666  if (k != i && g != j) {
667  zsl_mtx_get(m, k, g, &x);
668  v[u] = x;
669  u++;
670  }
671  }
672  }
673 
674  zsl_mtx_from_arr(mr, v);
675 
676  return 0;
677 }
678 
679 int
680 zsl_mtx_reduce_iter(struct zsl_mtx *m, struct zsl_mtx *mred)
681 {
682  /* TODO: Properly check if matrix is square. */
683  if (m->sz_rows == mred->sz_rows) {
684  zsl_mtx_copy(mred, m);
685  return 0;
686  }
687 
688  ZSL_MATRIX_DEF(my, (m->sz_rows - 1), (m->sz_cols - 1));
689  zsl_mtx_reduce(m, &my, 0, 0);
690  zsl_mtx_reduce_iter(&my, mred);
691 
692  return 0;
693 }
694 
695 int
696 zsl_mtx_augm_diag(struct zsl_mtx *m, struct zsl_mtx *maug)
697 {
698  zsl_real_t x;
699  /* TODO: Properly check if matrix is square, and diff > 0. */
700  size_t diff = (maug->sz_rows) - (m->sz_rows);
701 
703  for (size_t i = 0; i < m->sz_rows; i++) {
704  for (size_t j = 0; j < m->sz_rows; j++) {
705  zsl_mtx_get(m, i, j, &x);
706  zsl_mtx_set(maug, i + diff, j + diff, x);
707  }
708  }
709 
710  return 0;
711 }
712 
713 int
715 {
716  /* Make sure this is a square matrix. */
717  if (m->sz_rows != m->sz_cols) {
718  return -EINVAL;
719  }
720 
721 #if CONFIG_ZSL_BOUNDS_CHECKS
722  /* Make sure this is a 3x3 matrix. */
723  if (m->sz_rows != 3) {
724  return -EINVAL;
725  }
726 #endif
727 
728  /*
729  * 3x3 matrix element to array table:
730  *
731  * 1,1 = 0 1,2 = 1 1,3 = 2
732  * 2,1 = 3 2,2 = 4 2,3 = 5
733  * 3,1 = 6 3,2 = 7 3,3 = 8
734  */
735 
736  *d = m->data[0] * (m->data[4] * m->data[8] - m->data[7] * m->data[5]);
737  *d -= m->data[3] * (m->data[1] * m->data[8] - m->data[7] * m->data[2]);
738  *d += m->data[6] * (m->data[1] * m->data[5] - m->data[4] * m->data[2]);
739 
740  return 0;
741 }
742 
743 int
745 {
746  /* Shortcut for 1x1 matrices. */
747  if (m->sz_rows == 1) {
748  *d = m->data[0];
749  return 0;
750  }
751 
752  /* Shortcut for 2x2 matrices. */
753  if (m->sz_rows == 2) {
754  *d = m->data[0] * m->data[3] - m->data[2] * m->data[1];
755  return 0;
756  }
757 
758  /* Shortcut for 3x3 matrices. */
759  if (m->sz_rows == 3) {
760  return zsl_mtx_deter_3x3(m, d);
761  }
762 
763 #if CONFIG_ZSL_BOUNDS_CHECKS
764  /* Make sure this is a square matrix. */
765  if (m->sz_rows != m->sz_cols) {
766  return -EINVAL;
767  }
768 #endif
769 
770  /* Full calculation required for non 3x3 matrices. */
771  int rc;
772  zsl_real_t dtmp;
773  zsl_real_t cur;
774  zsl_real_t sign;
775  ZSL_MATRIX_DEF(mr, (m->sz_rows - 1), (m->sz_rows - 1));
776 
777  /* Clear determinant output before starting. */
778  *d = 0.0;
779 
780  /*
781  * Iterate across row 0, removing columns one by one.
782  * Note that these calls are recursive until we reach a 3x3 matrix,
783  * which will be calculated using the shortcut at the top of this
784  * function.
785  */
786  for (size_t g = 0; g < m->sz_cols; g++) {
787  zsl_mtx_get(m, 0, g, &cur); /* Get value at (0, g). */
788  zsl_mtx_init(&mr, NULL); /* Clear mr. */
789  zsl_mtx_reduce(m, &mr, 0, g); /* Remove row 0, column g. */
790  rc = zsl_mtx_deter(&mr, &dtmp); /* Calc. determinant of mr. */
791  sign = 1.0;
792  if (rc) {
793  return -EINVAL;
794  }
795 
796  /* Uneven elements are negative. */
797  if (g % 2 != 0) {
798  sign = -1.0;
799  }
800 
801  /* Add current determinant to final output value. */
802  *d += dtmp * cur * sign;
803  }
804 
805  return 0;
806 }
807 
808 int
809 zsl_mtx_gauss_elim(struct zsl_mtx *m, struct zsl_mtx *mg, struct zsl_mtx *mi,
810  size_t i, size_t j)
811 {
812  int rc;
813  zsl_real_t x, y;
814  zsl_real_t epsilon = 1E-6;
815 
816  /* Make a copy of matrix m. */
817  rc = zsl_mtx_copy(mg, m);
818  if (rc) {
819  return -EINVAL;
820  }
821 
822  /* Get the value of the element at position (i, j). */
823  rc = zsl_mtx_get(mg, i, j, &y);
824  if (rc) {
825  return rc;
826  }
827 
828  /* If this is a zero value, don't do anything. */
829  if ((y >= 0 && y < epsilon) || (y <= 0 && y > -epsilon)) {
830  return 0;
831  }
832 
833  /* Cycle through the matrix row by row. */
834  for (size_t p = 0; p < mg->sz_rows; p++) {
835  /* Skip row 'i'. */
836  if (p == i) {
837  p++;
838  }
839  if (p == mg->sz_rows) {
840  break;
841  }
842  /* Get the value of (p, j), aborting if value is zero. */
843  zsl_mtx_get(mg, p, j, &x);
844  if ((x >= 1E-6) || (x <= -1E-6)) {
845  rc = zsl_mtx_sum_rows_scaled_d(mg, p, i, -(x / y));
846 
847  if (rc) {
848  return -EINVAL;
849  }
850  rc = zsl_mtx_sum_rows_scaled_d(mi, p, i, -(x / y));
851  if (rc) {
852  return -EINVAL;
853  }
854  }
855  }
856 
857  return 0;
858 }
859 
860 int
861 zsl_mtx_gauss_elim_d(struct zsl_mtx *m, struct zsl_mtx *mi, size_t i, size_t j)
862 {
863  return zsl_mtx_gauss_elim(m, m, mi, i, j);
864 }
865 
866 int
867 zsl_mtx_gauss_reduc(struct zsl_mtx *m, struct zsl_mtx *mi,
868  struct zsl_mtx *mg)
869 {
870  zsl_real_t v[m->sz_rows];
871  zsl_real_t epsilon = 1E-6;
872  zsl_real_t x;
873  zsl_real_t y;
874 
875  /* Copy the input matrix into 'mg' so all the changes will be done to
876  * 'mg' and the input matrix will not be destroyed. */
877  zsl_mtx_copy(mg, m);
878 
879  for (size_t k = 0; k < m->sz_rows; k++) {
880 
881  /* Get every element in the diagonal. */
882  zsl_mtx_get(mg, k, k, &x);
883 
884  /* If the diagonal element is zero, find another value in the
885  * same column that isn't zero and add the row containing
886  * the non-zero element to the diagonal element's row. */
887  if ((x >= 0 && x < epsilon) || (x <= 0 && x > -epsilon)) {
888  zsl_mtx_get_col(mg, k, v);
889  for (size_t q = 0; q < m->sz_rows; q++) {
890  zsl_mtx_get(mg, q, q, &y);
891  if ((v[q] >= epsilon) || (v[q] <= -epsilon)) {
892 
893  /* If the non-zero element found is
894  * above the diagonal, only add its row
895  * if the diagonal element in this row
896  * is zero, to avoid undoing previous
897  * steps. */
898  if (q < k && ((y >= epsilon)
899  || (y <= -epsilon))) {
900  } else {
901  zsl_mtx_sum_rows_d(mg, k, q);
902  zsl_mtx_sum_rows_d(mi, k, q);
903  break;
904  }
905  }
906  }
907  }
908 
909  /* Perform the gaussian elimination in the column of the
910  * diagonal element to get rid of all the values in the column
911  * except for the diagonal one. */
912  zsl_mtx_gauss_elim_d(mg, mi, k, k);
913 
914  /* Divide the diagonal element's row by the diagonal element. */
915  zsl_mtx_norm_elem_d(mg, mi, k, k);
916  }
917 
918  return 0;
919 }
920 
921 int
922 zsl_mtx_gram_schmidt(struct zsl_mtx *m, struct zsl_mtx *mort)
923 {
924  ZSL_VECTOR_DEF(v, m->sz_rows);
925  ZSL_VECTOR_DEF(w, m->sz_rows);
926  ZSL_VECTOR_DEF(q, m->sz_rows);
927 
928  for (size_t t = 0; t < m->sz_cols; t++) {
929  zsl_vec_init(&q);
930  zsl_mtx_get_col(m, t, v.data);
931  for (size_t g = 0; g < t; g++) {
932  zsl_mtx_get_col(mort, g, w.data);
933 
934  /* Calculate the projection of every column vector
935  * before 'g' on the 't'th column. */
936  zsl_vec_project(&w, &v, &w);
937  zsl_vec_add(&q, &w, &q);
938  }
939 
940  /* Substract the sum of the projections on the 't'th column from
941  * the 't'th column and set this vector as the 't'th column of
942  * the output matrix. */
943  zsl_vec_sub(&v, &q, &v);
944  zsl_mtx_set_col(mort, t, v.data);
945  }
946 
947  return 0;
948 }
949 
950 int
951 zsl_mtx_cols_norm(struct zsl_mtx *m, struct zsl_mtx *mnorm)
952 {
953  ZSL_VECTOR_DEF(v, m->sz_rows);
954 
955  for (size_t g = 0; g < m->sz_cols; g++) {
956  zsl_mtx_get_col(m, g, v.data);
957  zsl_vec_to_unit(&v);
958  zsl_mtx_set_col(mnorm, g, v.data);
959  }
960 
961  return 0;
962 }
963 
964 int
965 zsl_mtx_norm_elem(struct zsl_mtx *m, struct zsl_mtx *mn, struct zsl_mtx *mi,
966  size_t i, size_t j)
967 {
968  int rc;
969  zsl_real_t x;
970  zsl_real_t epsilon = 1E-6;
971 
972  /* Make a copy of matrix m. */
973  rc = zsl_mtx_copy(mn, m);
974  if (rc) {
975  return -EINVAL;
976  }
977 
978  /* Get the value to normalise. */
979  rc = zsl_mtx_get(mn, i, j, &x);
980  if (rc) {
981  return rc;
982  }
983 
984  /* If the value is 0.0, abort. */
985  if ((x >= 0 && x < epsilon) || (x <= 0 && x > -epsilon)) {
986  return 0;
987  }
988 
989  rc = zsl_mtx_scalar_mult_row_d(mn, i, (1.0 / x));
990  if (rc) {
991  return -EINVAL;
992  }
993 
994  rc = zsl_mtx_scalar_mult_row_d(mi, i, (1.0 / x));
995  if (rc) {
996  return -EINVAL;
997  }
998 
999  return 0;
1000 }
1001 
1002 int
1003 zsl_mtx_norm_elem_d(struct zsl_mtx *m, struct zsl_mtx *mi, size_t i, size_t j)
1004 {
1005  return zsl_mtx_norm_elem(m, m, mi, i, j);
1006 }
1007 
1008 int
1009 zsl_mtx_inv_3x3(struct zsl_mtx *m, struct zsl_mtx *mi)
1010 {
1011  int rc;
1012  zsl_real_t d; /* Determinant. */
1013  zsl_real_t s; /* Scale factor. */
1014 
1015  /* Make sure these are square matrices. */
1016  if ((m->sz_rows != m->sz_cols) || (mi->sz_rows != mi->sz_cols)) {
1017  return -EINVAL;
1018  }
1019 
1020 #if CONFIG_ZSL_BOUNDS_CHECKS
1021  /* Make sure 'm' and 'mi' have the same shape. */
1022  if (m->sz_rows != mi->sz_rows) {
1023  return -EINVAL;
1024  }
1025  if (m->sz_cols != mi->sz_cols) {
1026  return -EINVAL;
1027  }
1028  /* Make sure these are 3x3 matrices. */
1029  if ((m->sz_cols != 3) || (mi->sz_cols != 3)) {
1030  return -EINVAL;
1031  }
1032 #endif
1033 
1034  /* Calculate the determinant. */
1035  rc = zsl_mtx_deter_3x3(m, &d);
1036  if (rc) {
1037  goto err;
1038  }
1039 
1040  /* Calculate the adjoint matrix. */
1041  rc = zsl_mtx_adjoint_3x3(m, mi);
1042  if (rc) {
1043  goto err;
1044  }
1045 
1046  /* Scale the output using the determinant. */
1047  if (d != 0) {
1048  s = 1.0 / d;
1049  rc = zsl_mtx_scalar_mult_d(mi, s);
1050  } else {
1051  /* Provide an identity matrix if the determinant is zero. */
1053  if (rc) {
1054  return -EINVAL;
1055  }
1056  }
1057 
1058  return 0;
1059 err:
1060  return rc;
1061 }
1062 
1063 int
1064 zsl_mtx_inv(struct zsl_mtx *m, struct zsl_mtx *mi)
1065 {
1066  int rc;
1067  zsl_real_t d = 0.0;
1068 
1069  /* Shortcut for 3x3 matrices. */
1070  if (m->sz_rows == 3) {
1071  return zsl_mtx_inv_3x3(m, mi);
1072  }
1073 
1074  /* Make sure we have square matrices. */
1075  if ((m->sz_rows != m->sz_cols) || (mi->sz_rows != mi->sz_cols)) {
1076  return -EINVAL;
1077  }
1078 
1079 #if CONFIG_ZSL_BOUNDS_CHECKS
1080  /* Make sure 'm' and 'mi' have the same shape. */
1081  if (m->sz_rows != mi->sz_rows) {
1082  return -EINVAL;
1083  }
1084  if (m->sz_cols != mi->sz_cols) {
1085  return -EINVAL;
1086  }
1087 #endif
1088 
1089  /* Make a copy of matrix m on the stack to avoid modifying it. */
1090  ZSL_MATRIX_DEF(m_tmp, mi->sz_rows, mi->sz_cols);
1091  rc = zsl_mtx_copy(&m_tmp, m);
1092  if (rc) {
1093  return -EINVAL;
1094  }
1095 
1096  /* Initialise 'mi' as an identity matrix. */
1098  if (rc) {
1099  return -EINVAL;
1100  }
1101 
1102  /* Make sure the determinant of 'm' is not zero. */
1103  zsl_mtx_deter(m, &d);
1104 
1105  if (d == 0) {
1106  return 0;
1107  }
1108 
1109  /* Use Gauss-Jordan elimination for nxn matrices. */
1110  zsl_mtx_gauss_reduc(m, mi, &m_tmp);
1111 
1112  return 0;
1113 }
1114 
1115 int
1116 zsl_mtx_cholesky(struct zsl_mtx *m, struct zsl_mtx *l)
1117 {
1118 #if CONFIG_ZSL_BOUNDS_CHECKS
1119  /* Make sure 'm' is square. */
1120  if (m->sz_rows != m->sz_cols) {
1121  return -EINVAL;
1122  }
1123 
1124  /* Make sure 'm' is symmetric. */
1125  zsl_real_t a, b;
1126  for (size_t i = 0; i < m->sz_rows; i++) {
1127  for (size_t j = 0; j < m->sz_rows; j++) {
1128  zsl_mtx_get(m, i, j, &a);
1129  zsl_mtx_get(m, j, i, &b);
1130  if (a != b) {
1131  return -EINVAL;
1132  }
1133  }
1134  }
1135 
1136  /* Make sure 'm' and 'l' have the same shape. */
1137  if (m->sz_rows != l->sz_rows) {
1138  return -EINVAL;
1139  }
1140  if (m->sz_cols != l->sz_cols) {
1141  return -EINVAL;
1142  }
1143 #endif
1144 
1145  zsl_real_t sum, x, y;
1147  for (size_t j = 0; j < m->sz_cols; j++) {
1148  sum = 0.0;
1149  for (size_t k = 0; k < j; k++) {
1150  zsl_mtx_get(l, j, k, &x);
1151  sum += x * x;
1152  }
1153  zsl_mtx_get(m, j, j, &x);
1154  zsl_mtx_set(l, j, j, ZSL_SQRT(x - sum));
1155 
1156  for (size_t i = j + 1; i < m->sz_cols; i++) {
1157  sum = 0.0;
1158  for (size_t k = 0; k < j; k++) {
1159  zsl_mtx_get(l, j, k, &x);
1160  zsl_mtx_get(l, i, k, &y);
1161  sum += y * x;
1162  }
1163  zsl_mtx_get(l, j, j, &x);
1164  zsl_mtx_get(m, i, j, &y);
1165  zsl_mtx_set(l, i, j, (y - sum) / x);
1166  }
1167  }
1168 
1169  return 0;
1170 }
1171 
1172 int
1173 zsl_mtx_balance(struct zsl_mtx *m, struct zsl_mtx *mout)
1174 {
1175  int rc;
1176  bool done = false;
1177  zsl_real_t sum;
1178  zsl_real_t row, row2;
1179  zsl_real_t col, col2;
1180 
1181  /* Make sure we have square matrices. */
1182  if ((m->sz_rows != m->sz_cols) || (mout->sz_rows != mout->sz_cols)) {
1183  return -EINVAL;
1184  }
1185 
1186 #if CONFIG_ZSL_BOUNDS_CHECKS
1187  /* Make sure 'm' and 'mout' have the same shape. */
1188  if (m->sz_rows != mout->sz_rows) {
1189  return -EINVAL;
1190  }
1191  if (m->sz_cols != mout->sz_cols) {
1192  return -EINVAL;
1193  }
1194 #endif
1195 
1196  rc = zsl_mtx_copy(mout, m);
1197  if (rc) {
1198  goto err;
1199  }
1200 
1201  while (!done) {
1202  done = true;
1203 
1204  for (size_t i = 0; i < m->sz_rows; i++) {
1205  /* Calculate sum of components of each row, column. */
1206  for (size_t j = 0; j < m->sz_cols; j++) {
1207  row += ZSL_ABS(mout->data[(i * m->sz_rows) +
1208  j]);
1209  col += ZSL_ABS(mout->data[(j * m->sz_rows) +
1210  i]);
1211  }
1212 
1213  /* TODO: Extend with a check against epsilon? */
1214  if (col != 0.0 && row != 0.0) {
1215  row2 = row / 2.0;
1216  col2 = 1.0;
1217  sum = col + row;
1218 
1219  while (col < row2) {
1220  col2 *= 2.0;
1221  col *= 4.0;
1222  }
1223 
1224  row2 = row * 2.0;
1225 
1226  while (col > row2) {
1227  col2 /= 2.0;
1228  col /= 4.0;
1229  }
1230 
1231  if ((col + row) / col2 < 0.95 * sum) {
1232  done = false;
1233  row2 = 1.0 / col2;
1234 
1235  for (int k = 0; k < m->sz_rows; k++) {
1236  mout->data[(i * m->sz_rows) + k]
1237  *= row2;
1238  mout->data[(k * m->sz_rows) + i]
1239  *= col2;
1240  }
1241  }
1242  }
1243 
1244  row = 0.0;
1245  col = 0.0;
1246  }
1247  }
1248 
1249 err:
1250  return rc;
1251 }
1252 
1253 int
1254 zsl_mtx_householder(struct zsl_mtx *m, struct zsl_mtx *h, bool hessenberg)
1255 {
1256  size_t size = m->sz_rows;
1257 
1258  if (hessenberg == true) {
1259  size--;
1260  }
1261 
1262  ZSL_VECTOR_DEF(v, size);
1263  ZSL_VECTOR_DEF(v2, m->sz_rows);
1264  ZSL_VECTOR_DEF(e1, size);
1265 
1266  ZSL_MATRIX_DEF(mv, size, 1);
1267  ZSL_MATRIX_DEF(mvt, 1, size);
1268  ZSL_MATRIX_DEF(id, size, size);
1269  ZSL_MATRIX_DEF(vvt, size, size);
1270  ZSL_MATRIX_DEF(h2, size, size);
1271 
1272  /* Create the e1 vector, i.e. the vector (1, 0, 0, ...). */
1273  zsl_vec_init(&e1);
1274  e1.data[0] = 1.0;
1275 
1276  /* Get the first column of the input matrix. */
1277  zsl_mtx_get_col(m, 0, v2.data);
1278  if (hessenberg == true) {
1279  zsl_vec_get_subset(&v2, 1, size, &v);
1280  } else {
1281  zsl_vec_copy(&v, &v2);
1282  }
1283 
1284  /* Change the 'sign' value according to the sign of the first
1285  * coefficient of the matrix. */
1286  zsl_real_t sign = 1.0;
1287 
1288  if (v.data[0] < 0) {
1289  sign = -1.0;
1290  }
1291 
1292  /* Calculate the vector 'v' that will later be used to calculate the
1293  * Householder matrix. */
1294  zsl_vec_scalar_mult(&e1, -sign * zsl_vec_norm(&v));
1295 
1296  zsl_vec_add(&v, &e1, &v);
1297 
1299 
1300  /* Calculate the H householder matrix by doing:
1301  * H = IDENTITY - 2 * v * v^t. */
1302  zsl_mtx_from_arr(&mv, v.data);
1303  zsl_mtx_trans(&mv, &mvt);
1304  zsl_mtx_mult(&mv, &mvt, &vvt);
1306  zsl_mtx_scalar_mult_d(&vvt, -2);
1307  zsl_mtx_add(&id, &vvt, &h2);
1308 
1309  /* If Hessenberg set to true, augment the output to the size of 'm'.
1310  * If Hessenberg set to false, this line of code will do nothing but
1311  * copy the matrix 'h2' into the output matrix 'h', */
1312  zsl_mtx_augm_diag(&h2, h);
1313 
1314  return 0;
1315 }
1316 
1317 int
1318 zsl_mtx_qrd(struct zsl_mtx *m, struct zsl_mtx *q, struct zsl_mtx *r,
1319  bool hessenberg)
1320 {
1321  ZSL_MATRIX_DEF(r2, m->sz_rows, m->sz_cols);
1322  ZSL_MATRIX_DEF(hess, m->sz_rows, m->sz_cols);
1323  ZSL_MATRIX_DEF(h, m->sz_rows, m->sz_rows);
1324  ZSL_MATRIX_DEF(h2, m->sz_rows, m->sz_rows);
1325  ZSL_MATRIX_DEF(qt, m->sz_rows, m->sz_rows);
1326 
1327  zsl_mtx_init(&h, NULL);
1329  zsl_mtx_copy(r, m);
1330 
1331  for (size_t g = 0; g < (m->sz_rows - 1); g++) {
1332 
1333  /* Reduce the matrix by 'g' rows and columns each time. */
1334  ZSL_MATRIX_DEF(mred, (m->sz_rows - g), (m->sz_cols - g));
1335  ZSL_MATRIX_DEF(hred, (m->sz_rows - g), (m->sz_rows - g));
1336  zsl_mtx_reduce_iter(r, &mred);
1337 
1338  /* Calculate the reduced Householder matrix 'hred'. */
1339  if (hessenberg == true) {
1340  zsl_mtx_householder(&mred, &hred, true);
1341  } else {
1342  zsl_mtx_householder(&mred, &hred, false);
1343  }
1344 
1345  /* Augment the Householder matrix to the input matrix size. */
1346  zsl_mtx_augm_diag(&hred, &h);
1347  zsl_mtx_mult(&h, r, &r2);
1348 
1349  /* Multiply this Householder matrix by the previous ones,
1350  * stacked in 'qt'. */
1351  zsl_mtx_mult(&h, &qt, &h2);
1352  zsl_mtx_copy(&qt, &h2);
1353  if (hessenberg == true) {
1354  zsl_mtx_mult(&r2, &h, &hess);
1355  zsl_mtx_copy(r, &hess);
1356  } else {
1357  zsl_mtx_copy(r, &r2);
1358  }
1359  }
1360 
1361  /* Calculate the 'q' matrix by transposing 'qt'. */
1362  zsl_mtx_trans(&qt, q);
1363 
1364  return 0;
1365 }
1366 
1367 #ifndef CONFIG_ZSL_SINGLE_PRECISION
1368 int
1369 zsl_mtx_qrd_iter(struct zsl_mtx *m, struct zsl_mtx *mout, size_t iter)
1370 {
1371  int rc;
1372 
1373  ZSL_MATRIX_DEF(q, m->sz_rows, m->sz_rows);
1374  ZSL_MATRIX_DEF(r, m->sz_rows, m->sz_rows);
1375 
1376 
1377  /* Make a copy of 'm'. */
1378  rc = zsl_mtx_copy(mout, m);
1379  if (rc) {
1380  return -EINVAL;
1381  }
1382 
1383  for (size_t g = 1; g <= iter; g++) {
1384  /* Perform the QR decomposition. */
1385  zsl_mtx_qrd(mout, &q, &r, false);
1386 
1387  /* Multiply the results of the QR decomposition together but
1388  * changing its order. */
1389  zsl_mtx_mult(&r, &q, mout);
1390  }
1391 
1392  return 0;
1393 }
1394 #endif
1395 
1396 #ifndef CONFIG_ZSL_SINGLE_PRECISION
1397 int
1398 zsl_mtx_eigenvalues(struct zsl_mtx *m, struct zsl_vec *v, size_t iter)
1399 {
1400  zsl_real_t diag;
1401  zsl_real_t sdiag;
1402  size_t real = 0;
1403 
1404  /* Epsilon is used to check 0 values in the subdiagonal, to determine
1405  * if any coimplekx values were found. Increasing the number of
1406  * iterations will move these values closer to 0, but when using
1407  * single-precision floats the numbers can still be quite large, so
1408  * we need to set a delta of +/- 0.001 in this case. */
1409 
1410  zsl_real_t epsilon = 1E-6;
1411 
1412  ZSL_MATRIX_DEF(mout, m->sz_rows, m->sz_rows);
1413  ZSL_MATRIX_DEF(mtemp, m->sz_rows, m->sz_rows);
1414  ZSL_MATRIX_DEF(mtemp2, m->sz_rows, m->sz_rows);
1415 
1416  /* Balance the matrix. */
1417  zsl_mtx_balance(m, &mtemp);
1418 
1419  /* Put the balanced matrix into hessenberg form. */
1420  zsl_mtx_qrd(&mtemp, &mout, &mtemp2, true);
1421 
1422  /* Calculate the upper triangular matrix by using the recursive QR
1423  * decomposition method. */
1424  zsl_mtx_qrd_iter(&mtemp2, &mout, iter);
1425 
1426  zsl_vec_init(v);
1427 
1428  /* If the matrix is symmetric, then it will always have real
1429  * eigenvalues, so treat this case appart. */
1430  if (zsl_mtx_is_sym(m) == true) {
1431  for (size_t g = 0; g < m->sz_rows; g++) {
1432  zsl_mtx_get(&mout, g, g, &diag);
1433  v->data[g] = diag;
1434  }
1435 
1436  return 0;
1437  }
1438 
1439  /*
1440  * If any value just below the diagonal is non-zero, it means that the
1441  * numbers above and to the right of the non-zero value are a pair of
1442  * complex values, a complex number and its conjugate.
1443  *
1444  * SVD will always return real numbers so this can be ignored, but if
1445  * you are calculating eigenvalues outside the SVD method, you may
1446  * get complex numbers, which will be indicated with the return error
1447  * code '-ECOMPLEXVAL'.
1448  *
1449  * If the imput matrix has complex eigenvalues, then these will be
1450  * ignored and the output vector will not include them.
1451  *
1452  * NOTE: The real and imaginary parts of the complex numbers are not
1453  * available. This only checks if there are any complex eigenvalues and
1454  * returns an appropriate error code to alert the user that there are
1455  * non-real eigenvalues present.
1456  */
1457 
1458  for (size_t g = 0; g < (m->sz_rows - 1); g++) {
1459  /* Check if any element just below the diagonal isn't zero. */
1460  zsl_mtx_get(&mout, g + 1, g, &sdiag);
1461  if ((sdiag >= epsilon) || (sdiag <= -epsilon)) {
1462  /* Skip two elements if the element below
1463  * is not zero. */
1464  g++;
1465  } else {
1466  /* Get the diagonal element if the element below
1467  * is zero. */
1468  zsl_mtx_get(&mout, g, g, &diag);
1469  v->data[real] = diag;
1470  real++;
1471  }
1472  }
1473 
1474 
1475  /* Since it's not possible to check the coefficient below the last
1476  * diagonal element, then check the element to its left. */
1477  zsl_mtx_get(&mout, (m->sz_rows - 1), (m->sz_rows - 2), &sdiag);
1478  if ((sdiag >= epsilon) || (sdiag <= -epsilon)) {
1479  /* Do nothing if the element to its left is not zero. */
1480  } else {
1481  /* Get the last diagonal element if the element to its left
1482  * is zero. */
1483  zsl_mtx_get(&mout, (m->sz_rows - 1), (m->sz_rows - 1), &diag);
1484  v->data[real] = diag;
1485  real++;
1486  }
1487 
1488  /* If the number of real eigenvalues ('real' coefficient) is less than
1489  * the matrix dimensions, then there must be complex eigenvalues. */
1490  v->sz = real;
1491  if (real != m->sz_rows) {
1492  return -ECOMPLEXVAL;
1493  }
1494 
1495  /* Put the zeros to the end. */
1496  zsl_vec_zte(v);
1497 
1498  return 0;
1499 }
1500 #endif
1501 
1502 #ifndef CONFIG_ZSL_SINGLE_PRECISION
1503 int
1504 zsl_mtx_eigenvectors(struct zsl_mtx *m, struct zsl_mtx *mev, size_t iter,
1505  bool orthonormal)
1506 {
1507  size_t b = 0; /* Total number of eigenvectors. */
1508  size_t e_vals = 0; /* Number of unique eigenvalues. */
1509  size_t count = 0; /* Number of eigenvectors for an eigenvalue. */
1510  size_t ga = 0;
1511 
1512  zsl_real_t epsilon = 1E-6;
1513  zsl_real_t x;
1514 
1515  /* The vector where all eigenvalues will be stored. */
1516  ZSL_VECTOR_DEF(k, m->sz_rows);
1517  /* Temp vector to store column data. */
1518  ZSL_VECTOR_DEF(f, m->sz_rows);
1519  /* The vector where all UNIQUE eigenvalues will be stored. */
1520  ZSL_VECTOR_DEF(o, m->sz_rows);
1521  /* Temporary mxm identity matrix placeholder. */
1522  ZSL_MATRIX_DEF(id, m->sz_rows, m->sz_rows);
1523  /* 'm' minus the eigenvalues * the identity matrix (id). */
1524  ZSL_MATRIX_DEF(mi, m->sz_rows, m->sz_rows);
1525  /* Placeholder for zsl_mtx_gauss_reduc calls (required param). */
1526  ZSL_MATRIX_DEF(mid, m->sz_rows, m->sz_rows);
1527  /* Matrix containing all column eigenvectors for an eigenvalue. */
1528  ZSL_MATRIX_DEF(evec, m->sz_rows, m->sz_rows);
1529  /* Matrix containing all column eigenvectors for an eigenvalue.
1530  * Two matrices are required for the Gramm-Schmidt operation. */
1531  ZSL_MATRIX_DEF(evec2, m->sz_rows, m->sz_rows);
1532  /* Matrix containing all column eigenvectors. */
1533  ZSL_MATRIX_DEF(mev2, m->sz_rows, m->sz_rows);
1534 
1535  /* TODO: Check that we have a SQUARE matrix, etc. */
1536  zsl_mtx_init(&mev2, NULL);
1537  zsl_vec_init(&o);
1538  zsl_mtx_eigenvalues(m, &k, iter);
1539 
1540  /* Copy every non-zero eigenvalue ONCE in the 'o' vector to get rid of
1541  * repeated values. */
1542  for (size_t q = 0; q < m->sz_rows; q++) {
1543  if ((k.data[q] >= epsilon) || (k.data[q] <= -epsilon)) {
1544  if (zsl_vec_contains(&o, k.data[q], epsilon) == 0) {
1545  o.data[e_vals] = k.data[q];
1546  /* Increment the unique eigenvalue counter. */
1547  e_vals++;
1548  }
1549  }
1550  }
1551 
1552  /* If zero is also an eigenvalue, copy it once in 'o'. */
1553  if (zsl_vec_contains(&k, 0.0, epsilon) > 0) {
1554  e_vals++;
1555  }
1556 
1557  /* Calculates the null space of 'm' minus each eigenvalue times
1558  * the identity matrix by performing the gaussian reduction. */
1559  for (size_t g = 0; g < e_vals; g++) {
1560  count = 0;
1561  ga = 0;
1562 
1564  zsl_mtx_scalar_mult_d(&id, -o.data[g]);
1565  zsl_mtx_add_d(&id, m);
1566  zsl_mtx_gauss_reduc(&id, &mid, &mi);
1567 
1568  /* If 'orthonormal' is true, perform the following process. */
1569  if (orthonormal == true) {
1570  /* Count how many eigenvectors ('count' coefficient)
1571  * there are for each eigenvalue. */
1572  for (size_t h = 0; h < m->sz_rows; h++) {
1573  zsl_mtx_get(&mi, h, h, &x);
1574  if ((x >= 0.0 && x < epsilon) ||
1575  (x <= 0.0 && x > -epsilon)) {
1576  count++;
1577  }
1578  }
1579 
1580  /* Resize evec* placeholders to have 'count' cols. */
1581  evec.sz_cols = count;
1582  evec2.sz_cols = count;
1583 
1584  /* Get all the eigenvectors for each eigenvalue and set
1585  * them as the columns of 'evec'. */
1586  for (size_t h = 0; h < m->sz_rows; h++) {
1587  zsl_mtx_get(&mi, h, h, &x);
1588  if ((x >= 0.0 && x < epsilon) ||
1589  (x <= 0.0 && x > -epsilon)) {
1590  zsl_mtx_set(&mi, h, h, -1);
1591  zsl_mtx_get_col(&mi, h, f.data);
1592  zsl_vec_neg(&f);
1593  zsl_mtx_set_col(&evec, ga, f.data);
1594  ga++;
1595  }
1596  }
1597  /* Orthonormalize the set of eigenvectors for each
1598  * eigenvalue using the Gram-Schmidt process. */
1599  zsl_mtx_gram_schmidt(&evec, &evec2);
1600  zsl_mtx_cols_norm(&evec2, &evec);
1601 
1602  /* Place these eigenvectors in the 'mev2' matrix,
1603  * that will hold all the eigenvectors for different
1604  * eigenvalues. */
1605  for (size_t gi = 0; gi < count; gi++) {
1606  zsl_mtx_get_col(&evec, gi, f.data);
1607  zsl_mtx_set_col(&mev2, b, f.data);
1608  b++;
1609  }
1610 
1611  } else {
1612  /* Orthonormal is false. */
1613  /* Get the eigenvectors for every eigenvalue and place
1614  * them in 'mev2'. */
1615  for (size_t h = 0; h < m->sz_rows; h++) {
1616  zsl_mtx_get(&mi, h, h, &x);
1617  if ((x >= 0.0 && x < epsilon) ||
1618  (x <= 0.0 && x > -epsilon)) {
1619  zsl_mtx_set(&mi, h, h, -1);
1620  zsl_mtx_get_col(&mi, h, f.data);
1621  zsl_vec_neg(&f);
1622  zsl_mtx_set_col(&mev2, b, f.data);
1623  b++;
1624  }
1625  }
1626  }
1627  }
1628 
1629  /* Since 'b' is the number of eigenvectors, reduce 'mev' (of size
1630  * m->sz_rows times b) to erase columns of zeros. */
1631  mev->sz_cols = b;
1632 
1633  for (size_t s = 0; s < b; s++) {
1634  zsl_mtx_get_col(&mev2, s, f.data);
1635  zsl_mtx_set_col(mev, s, f.data);
1636  }
1637 
1638  /* Checks if the number of eigenvectors is the same as the shape of
1639  * the input matrix. If the number of eigenvectors is less than
1640  * the number of columns in the input matrix 'm', this will be
1641  * indicated by EEIGENSIZE as a return code. */
1642  if (b != m->sz_cols) {
1643  return -EEIGENSIZE;
1644  }
1645 
1646  return 0;
1647 }
1648 #endif
1649 
1650 #ifndef CONFIG_ZSL_SINGLE_PRECISION
1651 int
1652 zsl_mtx_svd(struct zsl_mtx *m, struct zsl_mtx *u, struct zsl_mtx *e,
1653  struct zsl_mtx *v, size_t iter)
1654 {
1655  ZSL_MATRIX_DEF(aat, m->sz_rows, m->sz_rows);
1656  ZSL_MATRIX_DEF(upri, m->sz_rows, m->sz_rows);
1657  ZSL_MATRIX_DEF(ata, m->sz_cols, m->sz_cols);
1658  ZSL_MATRIX_DEF(at, m->sz_cols, m->sz_rows);
1659  ZSL_VECTOR_DEF(ui, m->sz_rows);
1660  ZSL_MATRIX_DEF(ui2, m->sz_cols, 1);
1661  ZSL_MATRIX_DEF(ui3, m->sz_rows, 1);
1662  ZSL_VECTOR_DEF(hu, m->sz_rows);
1663 
1664  zsl_real_t d;
1665  size_t pu = 0;
1666  size_t min = m->sz_cols;
1667  zsl_real_t epsilon = 1E-6;
1668 
1669  zsl_mtx_trans(m, &at);
1670 
1671  /* Calculate 'm' times 'm' transposed and viceversa. */
1672  zsl_mtx_mult(m, &at, &aat);
1673  zsl_mtx_mult(&at, m, &ata);
1674 
1675  /* Set the value 'min' as the minimum of number of columns and number
1676  * of rows. */
1677  if (m->sz_rows <= m->sz_cols) {
1678  min = m->sz_rows;
1679  }
1680 
1681  /* Calculate the eigenvalues of the square matrix 'm' times 'm'
1682  * transposed or the square matrix 'm' transposed times 'm', whichever
1683  * is smaller in dimensions. */
1684  ZSL_VECTOR_DEF(ev, min);
1685  if (min < m->sz_cols) {
1686  zsl_mtx_eigenvalues(&aat, &ev, iter);
1687  } else {
1688  zsl_mtx_eigenvalues(&ata, &ev, iter);
1689  }
1690 
1691  /* Place the square root of these eigenvalues in the diagonal entries
1692  * of 'e', the sigma matrix. */
1693  zsl_mtx_init(e, NULL);
1694  for (size_t g = 0; g < min; g++) {
1695  zsl_mtx_set(e, g, g, ZSL_SQRT(ev.data[g]));
1696  }
1697 
1698  /* Calculate the eigenvectors of 'm' times 'm' transposed and set them
1699  * as the columns of the 'v' matrix. */
1700  zsl_mtx_eigenvectors(&ata, v, iter, true);
1701  for (size_t i = 0; i < min; i++) {
1702  zsl_mtx_get_col(v, i, ui.data);
1703  zsl_mtx_from_arr(&ui2, ui.data);
1704  zsl_mtx_get(e, i, i, &d);
1705 
1706  /* Calculate the column vectors of 'u' by dividing these
1707  * eniegnvectors by the square root its eigenvalue and
1708  * multiplying them by the input matrix. */
1709  zsl_mtx_mult(m, &ui2, &ui3);
1710  if ((d >= 0.0 && d < epsilon) || (d <= 0.0 && d > -epsilon)) {
1711  pu++;
1712  } else {
1713  zsl_mtx_scalar_mult_d(&ui3, (1 / d));
1714  zsl_vec_from_arr(&ui, ui3.data);
1715  zsl_mtx_set_col(u, i, ui.data);
1716  }
1717  }
1718 
1719  /* Expand the columns of 'u' into an orthonormal basis if there are
1720  * zero eigenvalues or if the number of columns in 'm' is less than the
1721  * number of rows. */
1722  zsl_mtx_eigenvectors(&aat, &upri, iter, true);
1723  for (size_t f = min - pu; f < m->sz_rows; f++) {
1724  zsl_mtx_get_col(&upri, f, hu.data);
1725  zsl_mtx_set_col(u, f, hu.data);
1726  }
1727 
1728  return 0;
1729 }
1730 #endif
1731 
1732 #ifndef CONFIG_ZSL_SINGLE_PRECISION
1733 int
1734 zsl_mtx_pinv(struct zsl_mtx *m, struct zsl_mtx *pinv, size_t iter)
1735 {
1736  zsl_real_t x;
1737  size_t min = m->sz_cols;
1738  zsl_real_t epsilon = 1E-6;
1739 
1740  ZSL_MATRIX_DEF(u, m->sz_rows, m->sz_rows);
1741  ZSL_MATRIX_DEF(e, m->sz_rows, m->sz_cols);
1742  ZSL_MATRIX_DEF(v, m->sz_cols, m->sz_cols);
1743  ZSL_MATRIX_DEF(et, m->sz_cols, m->sz_rows);
1744  ZSL_MATRIX_DEF(ut, m->sz_rows, m->sz_rows);
1745  ZSL_MATRIX_DEF(pas, m->sz_cols, m->sz_rows);
1746 
1747  /* Determine the SVD decomposition of 'm'. */
1748  zsl_mtx_svd(m, &u, &e, &v, iter);
1749 
1750  /* Transpose the 'u' matrix. */
1751  zsl_mtx_trans(&u, &ut);
1752 
1753  /* Set the value 'min' as the minimum of number of columns and number
1754  * of rows. */
1755  if (m->sz_rows <= m->sz_cols) {
1756  min = m->sz_rows;
1757  }
1758 
1759  for (size_t g = 0; g < min; g++) {
1760 
1761  /* Invert the diagonal values in 'e'. If a value is zero, do
1762  * nothing to it. */
1763  zsl_mtx_get(&e, g, g, &x);
1764  if ((x < epsilon) || (x > -epsilon)) {
1765  x = 1 / x;
1766  zsl_mtx_set(&e, g, g, x);
1767  }
1768  }
1769 
1770  /* Transpose the sigma matrix. */
1771  zsl_mtx_trans(&e, &et);
1772 
1773  /* Multiply 'u' (transposed) times sigma (transposed and with inverted
1774  * eigenvalues) times 'v'. */
1775  zsl_mtx_mult(&v, &et, &pas);
1776  zsl_mtx_mult(&pas, &ut, pinv);
1777 
1778  return 0;
1779 }
1780 #endif
1781 
1782 int
1784 {
1785  zsl_real_t min = m->data[0];
1786 
1787  for (size_t i = 0; i < m->sz_cols * m->sz_rows; i++) {
1788  if (m->data[i] < min) {
1789  min = m->data[i];
1790  }
1791  }
1792 
1793  *x = min;
1794 
1795  return 0;
1796 }
1797 
1798 int
1800 {
1801  zsl_real_t max = m->data[0];
1802 
1803  for (size_t i = 0; i < m->sz_cols * m->sz_rows; i++) {
1804  if (m->data[i] > max) {
1805  max = m->data[i];
1806  }
1807  }
1808 
1809  *x = max;
1810 
1811  return 0;
1812 }
1813 
1814 int
1815 zsl_mtx_min_idx(struct zsl_mtx *m, size_t *i, size_t *j)
1816 {
1817  zsl_real_t min = m->data[0];
1818 
1819  *i = 0;
1820  *j = 0;
1821 
1822  for (size_t _i = 0; _i < m->sz_rows; _i++) {
1823  for (size_t _j = 0; _j < m->sz_cols; _j++) {
1824  if (m->data[_i * m->sz_cols + _j] < min) {
1825  min = m->data[_i * m->sz_cols + _j];
1826  *i = _i;
1827  *j = _j;
1828  }
1829  }
1830  }
1831 
1832  return 0;
1833 }
1834 
1835 int
1836 zsl_mtx_max_idx(struct zsl_mtx *m, size_t *i, size_t *j)
1837 {
1838  zsl_real_t max = m->data[0];
1839 
1840  *i = 0;
1841  *j = 0;
1842 
1843  for (size_t _i = 0; _i < m->sz_rows; _i++) {
1844  for (size_t _j = 0; _j < m->sz_cols; _j++) {
1845  if (m->data[_i * m->sz_cols + _j] > max) {
1846  max = m->data[_i * m->sz_cols + _j];
1847  *i = _i;
1848  *j = _j;
1849  }
1850  }
1851  }
1852 
1853  return 0;
1854 }
1855 
1856 bool
1857 zsl_mtx_is_equal(struct zsl_mtx *ma, struct zsl_mtx *mb)
1858 {
1859  int res;
1860 
1861  /* Make sure shape is the same. */
1862  if ((ma->sz_rows != mb->sz_rows) || (ma->sz_cols != mb->sz_cols)) {
1863  return false;
1864  }
1865 
1866  res = memcmp(ma->data, mb->data,
1867  sizeof(zsl_real_t) * (ma->sz_rows + ma->sz_cols));
1868 
1869  return res == 0 ? true : false;
1870 }
1871 
1872 bool
1874 {
1875  for (size_t i = 0; i < m->sz_rows * m->sz_cols; i++) {
1876  if (m->data[i] < 0.0) {
1877  return false;
1878  }
1879  }
1880 
1881  return true;
1882 }
1883 
1884 bool
1886 {
1887  zsl_real_t x;
1888  zsl_real_t y;
1889  zsl_real_t diff;
1890  zsl_real_t epsilon = 1E-6;
1891 
1892  for (size_t i = 0; i < m->sz_rows; i++) {
1893  for (size_t j = 0; j < m->sz_cols; j++) {
1894  zsl_mtx_get(m, i, j, &x);
1895  zsl_mtx_get(m, j, i, &y);
1896  diff = x - y;
1897  if (diff >= epsilon || diff <= -epsilon) {
1898  return false;
1899  }
1900  }
1901  }
1902 
1903  return true;
1904 }
1905 
1906 int
1908 {
1909  int rc;
1910  zsl_real_t x;
1911 
1912  for (size_t i = 0; i < m->sz_rows; i++) {
1913  for (size_t j = 0; j < m->sz_cols; j++) {
1914  rc = zsl_mtx_get(m, i, j, &x);
1915  if (rc) {
1916  printf("Error reading (%zu,%zu)!\n", i, j);
1917  return -EINVAL;
1918  }
1919  /* Print the current floating-point value. */
1920  printf("%f ", x);
1921  }
1922  printf("\n");
1923  }
1924 
1925  printf("\n");
1926 
1927  return 0;
1928 }
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_mtx_augm_diag
int zsl_mtx_augm_diag(struct zsl_mtx *m, struct zsl_mtx *maug)
Augments the input square matrix with additional rows and columns, based on the size 'diff' between m...
Definition: matrices.c:696
zsl_mtx_mult_d
int zsl_mtx_mult_d(struct zsl_mtx *ma, struct zsl_mtx *mb)
Multiplies matrix 'ma' by 'mb', assigning the output to 'ma'. Matrices 'ma' and 'mb' must be compatib...
Definition: matrices.c:468
ZSL_CEIL
#define ZSL_CEIL
Definition: zsl.h:81
zsl_mtx_svd
int zsl_mtx_svd(struct zsl_mtx *m, struct zsl_mtx *u, struct zsl_mtx *e, struct zsl_mtx *v, size_t iter)
Performs singular value decomposition, converting input matrix 'm' into matrices 'u',...
Definition: matrices.c:1652
zsl_mtx_sum_rows_scaled_d
int zsl_mtx_sum_rows_scaled_d(struct zsl_mtx *m, size_t i, size_t j, zsl_real_t s)
This function takes the coefficients of row 'j' and multiplies them by scalar 's',...
Definition: matrices.c:403
zsl_mtx_scalar_mult_row_d
int zsl_mtx_scalar_mult_row_d(struct zsl_mtx *m, size_t i, zsl_real_t s)
Multiplies the elements of row 'i' in matrix 'm' by scalar 's'.
Definition: matrices.c:498
zsl_mtx_set
int zsl_mtx_set(struct zsl_mtx *m, size_t i, size_t j, zsl_real_t x)
Sets a single value at the specified row (i) and column (j).
Definition: matrices.c:113
zsl_mtx_get_row
int zsl_mtx_get_row(struct zsl_mtx *m, size_t i, zsl_real_t *v)
Gets the contents of row 'i' from matrix 'm', assigning the array of data to 'v'.
Definition: matrices.c:127
ZSL_ACOS
#define ZSL_ACOS
Definition: zsl.h:96
ZSL_MTX_UNARY_OP_SINH
@ ZSL_MTX_UNARY_OP_SINH
Definition: matrices.h:99
zsl_mtx_norm_elem_d
int zsl_mtx_norm_elem_d(struct zsl_mtx *m, struct zsl_mtx *mi, size_t i, size_t j)
Normalises elements in matrix m such that the element at position (i, j) is equal to 1....
Definition: matrices.c:1003
zsl_mtx_cholesky
int zsl_mtx_cholesky(struct zsl_mtx *m, struct zsl_mtx *l)
Calculates the Cholesky decomposition of a symmetric square matrix using the Cholesky–Crout algorithm...
Definition: matrices.c:1116
ZSL_MTX_UNARY_OP_FLOOR
@ ZSL_MTX_UNARY_OP_FLOOR
Definition: matrices.h:87
zsl_vec_init
int zsl_vec_init(struct zsl_vec *v)
Definition: vectors.c:19
zsl_mtx::sz_rows
size_t sz_rows
Definition: matrices.h:48
ZSL_FLOOR
#define ZSL_FLOOR
Definition: zsl.h:82
zsl_mtx_get
int zsl_mtx_get(struct zsl_mtx *m, size_t i, size_t j, zsl_real_t *x)
Gets a single value from the specified row (i) and column (j).
Definition: matrices.c:99
ZSL_MTX_UNARY_OP_ATAN
@ ZSL_MTX_UNARY_OP_ATAN
Definition: matrices.h:98
zsl_mtx_unary_fn_t
int(* zsl_mtx_unary_fn_t)(struct zsl_mtx *m, size_t i, size_t j)
Function prototype called when applying a set of component-wise unary operations to a matrix via zsl_...
Definition: matrices.h:142
zsl_mtx
Represents a m x n matrix, with data stored in row-major order.
Definition: matrices.h:46
zsl_mtx_qrd
int zsl_mtx_qrd(struct zsl_mtx *m, struct zsl_mtx *q, struct zsl_mtx *r, bool hessenberg)
If 'hessenberg' is set to false, this function performs the QR decomposition, which is a factorisatio...
Definition: matrices.c:1318
ZSL_COSH
#define ZSL_COSH
Definition: zsl.h:100
zsl_mtx_max
int zsl_mtx_max(struct zsl_mtx *m, zsl_real_t *x)
Traverses the matrix elements to find the maximum element value.
Definition: matrices.c:1799
zsl_mtx_init_entry_fn_t
int(* zsl_mtx_init_entry_fn_t)(struct zsl_mtx *m, size_t i, size_t j)
Function prototype called when populating a matrix via zsl_mtx_init.
Definition: matrices.h:168
ZSL_COS
#define ZSL_COS
Definition: zsl.h:93
ZSL_LOG10
#define ZSL_LOG10
Definition: zsl.h:90
zsl_mtx_reduce_iter
int zsl_mtx_reduce_iter(struct zsl_mtx *m, struct zsl_mtx *mred)
Reduces the number of rows/columns in the input square matrix 'm' to match the shape of 'mred',...
Definition: matrices.c:680
ZSL_MTX_BINARY_OP_GREAT
@ ZSL_MTX_BINARY_OP_GREAT
Definition: matrices.h:117
zsl_mtx_sub_d
int zsl_mtx_sub_d(struct zsl_mtx *ma, struct zsl_mtx *mb)
Subtracts matrix 'mb' from 'ma', assigning the output to 'ma'. Matrices 'ma', and 'mb' must be identi...
Definition: matrices.c:428
zsl_vec::data
zsl_real_t * data
Definition: vectors.h:44
ZSL_MTX_UNARY_OP_ROUND
@ ZSL_MTX_UNARY_OP_ROUND
Definition: matrices.h:85
zsl_mtx_min
int zsl_mtx_min(struct zsl_mtx *m, zsl_real_t *x)
Traverses the matrix elements to find the minimum element value.
Definition: matrices.c:1783
ZSL_MTX_UNARY_OP_ASIN
@ ZSL_MTX_UNARY_OP_ASIN
Definition: matrices.h:96
zsl_mtx_eigenvectors
int zsl_mtx_eigenvectors(struct zsl_mtx *m, struct zsl_mtx *mev, size_t iter, bool orthonormal)
Calcualtes the set of eigenvectors for input matrix 'm', using the specified number of iterations to ...
Definition: matrices.c:1504
ZSL_POW
#define ZSL_POW
Definition: zsl.h:87
zsl_mtx_unary_func
int zsl_mtx_unary_func(struct zsl_mtx *m, zsl_mtx_unary_fn_t fn)
Applies a unary function on every coefficient in matrix 'm', using the specified 'zsl_mtx_apply_unary...
Definition: matrices.c:266
zsl_mtx_binary_op_t
enum zsl_mtx_binary_op zsl_mtx_binary_op_t
Component-wise binary operations.
ZSL_TAN
#define ZSL_TAN
Definition: zsl.h:94
ZSL_MTX_UNARY_OP_TANH
@ ZSL_MTX_UNARY_OP_TANH
Definition: matrices.h:101
zsl_vec::sz
size_t sz
Definition: vectors.h:42
zsl_mtx_mult
int zsl_mtx_mult(struct zsl_mtx *ma, struct zsl_mtx *mb, struct zsl_mtx *mc)
Multiplies matrix 'ma' by 'mb', assigning the output to 'mc'. Matrices 'ma' and 'mb' must be compatib...
Definition: matrices.c:434
ZSL_MTX_UNARY_OP_ACOS
@ ZSL_MTX_UNARY_OP_ACOS
Definition: matrices.h:97
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_MTX_BINARY_OP_MULT
@ ZSL_MTX_BINARY_OP_MULT
Definition: matrices.h:108
ECOMPLEXVAL
#define ECOMPLEXVAL
Definition: matrices.h:43
zsl_mtx_binary_func
int zsl_mtx_binary_func(struct zsl_mtx *ma, struct zsl_mtx *mb, struct zsl_mtx *mc, zsl_mtx_binary_fn_t fn)
Applies a component-wise binary operztion on every coefficient in symmetrical matrices 'ma' and 'mb',...
Definition: matrices.c:347
ZSL_MTX_BINARY_OP_EQUAL
@ ZSL_MTX_BINARY_OP_EQUAL
Definition: matrices.h:114
zsl_mtx_get_col
int zsl_mtx_get_col(struct zsl_mtx *m, size_t j, zsl_real_t *v)
Gets the contents of column 'j' from matrix 'm', assigning the array of data to 'v'.
Definition: matrices.c:159
ZSL_EXP
#define ZSL_EXP
Definition: zsl.h:88
zsl_mtx_deter_3x3
int zsl_mtx_deter_3x3(struct zsl_mtx *m, zsl_real_t *d)
Calculates the determinant of the input 3x3 matrix 'm'.
Definition: matrices.c:714
zsl_mtx_min_idx
int zsl_mtx_min_idx(struct zsl_mtx *m, size_t *i, size_t *j)
Traverses the matrix elements to find the (i,j) index of the minimum element value....
Definition: matrices.c:1815
ZSL_LOG
#define ZSL_LOG
Definition: zsl.h:89
ZSL_SINH
#define ZSL_SINH
Definition: zsl.h:99
zsl_mtx_gauss_reduc
int zsl_mtx_gauss_reduc(struct zsl_mtx *m, struct zsl_mtx *mi, struct zsl_mtx *mg)
Given matrix 'm', puts the matrix into echelon form using Gauss-Jordan reduction.
Definition: matrices.c:867
zsl_mtx_qrd_iter
int zsl_mtx_qrd_iter(struct zsl_mtx *m, struct zsl_mtx *mout, size_t iter)
Computes recursively the QR decompisition method to put the input square matrix into upper triangular...
Definition: matrices.c:1369
zsl_mtx_unary_op_t
enum zsl_mtx_unary_op zsl_mtx_unary_op_t
Component-wise unary operations.
zsl_mtx_balance
int zsl_mtx_balance(struct zsl_mtx *m, struct zsl_mtx *mout)
Balances the square matrix 'm', a process in which the eigenvalues of the output matrix are the same ...
Definition: matrices.c:1173
ZSL_MTX_UNARY_OP_LOG10
@ ZSL_MTX_UNARY_OP_LOG10
Definition: matrices.h:91
zsl_mtx_deter
int zsl_mtx_deter(struct zsl_mtx *m, zsl_real_t *d)
Calculates the determinant of the input square matrix 'm'.
Definition: matrices.c:744
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_mtx_add_d
int zsl_mtx_add_d(struct zsl_mtx *ma, struct zsl_mtx *mb)
Adds matrices 'ma' and 'mb', assigning the output to 'ma'. Matrices 'ma', and 'mb' must be identicall...
Definition: matrices.c:381
zsl_mtx_eigenvalues
int zsl_mtx_eigenvalues(struct zsl_mtx *m, struct zsl_vec *v, size_t iter)
Calculates the eigenvalues for input matrix 'm' using QR decomposition recursively....
Definition: matrices.c:1398
ZSL_SIN
#define ZSL_SIN
Definition: zsl.h:92
zsl_mtx_gauss_elim
int zsl_mtx_gauss_elim(struct zsl_mtx *m, struct zsl_mtx *mg, struct zsl_mtx *mi, size_t i, size_t j)
Given the element (i,j) in matrix 'm', this function performs gaussian elimination by adding row 'i' ...
Definition: matrices.c:809
ZSL_MTX_BINARY_OP_MAX
@ ZSL_MTX_BINARY_OP_MAX
Definition: matrices.h:113
zsl_mtx_entry_fn_empty
int zsl_mtx_entry_fn_empty(struct zsl_mtx *m, size_t i, size_t j)
Assigns a zero-value to all entries in the matrix.
Definition: matrices.c:31
zsl_mtx_vec_wedge
int zsl_mtx_vec_wedge(struct zsl_mtx *m, struct zsl_vec *v)
Calculates the wedge product of n-1 vectors of size n, which are the rows of the matrix 'm'....
Definition: matrices.c:607
zsl_mtx::data
zsl_real_t * data
Definition: matrices.h:52
ZSL_MTX_UNARY_OP_COS
@ ZSL_MTX_UNARY_OP_COS
Definition: matrices.h:94
zsl_mtx_sum_rows_d
int zsl_mtx_sum_rows_d(struct zsl_mtx *m, size_t i, size_t j)
Adds the values of row 'j' to row 'i' in matrix 'm'. This operation is destructive for row 'i'.
Definition: matrices.c:387
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_mtx_init
int zsl_mtx_init(struct zsl_mtx *m, zsl_mtx_init_entry_fn_t entry_fn)
Initialises matrix 'm' using the specified entry function to assign values.
Definition: matrices.c:50
zsl_mtx_pinv
int zsl_mtx_pinv(struct zsl_mtx *m, struct zsl_mtx *pinv, size_t iter)
Performs the pseudo-inverse (aka pinv or Moore-Penrose inverse) on input matrix 'm'.
Definition: matrices.c:1734
ZSL_MTX_UNARY_OP_EXP
@ ZSL_MTX_UNARY_OP_EXP
Definition: matrices.h:89
zsl_mtx_add
int zsl_mtx_add(struct zsl_mtx *ma, struct zsl_mtx *mb, struct zsl_mtx *mc)
Adds matrices 'ma' and 'mb', assigning the output to 'mc'. Matrices 'ma', 'mb' and 'mc' must all be i...
Definition: matrices.c:375
zsl_mtx_max_idx
int zsl_mtx_max_idx(struct zsl_mtx *m, size_t *i, size_t *j)
Traverses the matrix elements to find the (i,j) index of the maximum element value....
Definition: matrices.c:1836
ZSL_ABS
#define ZSL_ABS
Definition: zsl.h:84
ZSL_MTX_BINARY_OP_DIV
@ ZSL_MTX_BINARY_OP_DIV
Definition: matrices.h:109
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_MTX_BINARY_OP_EXPON
@ ZSL_MTX_BINARY_OP_EXPON
Definition: matrices.h:111
zsl_mtx_cols_norm
int zsl_mtx_cols_norm(struct zsl_mtx *m, struct zsl_mtx *mnorm)
Updates the values of every column vector in input matrix 'm' to have unitary values.
Definition: matrices.c:951
zsl_mtx_trans
int zsl_mtx_trans(struct zsl_mtx *ma, struct zsl_mtx *mb)
Transposes the matrix 'ma' into matrix 'mb'. Note that output matrix 'mb' must have 'ma->sz_rows' col...
Definition: matrices.c:514
ZSL_TANH
#define ZSL_TANH
Definition: zsl.h:101
zsl_mtx_entry_fn_identity
int zsl_mtx_entry_fn_identity(struct zsl_mtx *m, size_t i, size_t j)
Sets the value to '1.0' if the entry is on the diagonal (row=col), otherwise '0.0'.
Definition: matrices.c:37
zsl_mtx_entry_fn_random
int zsl_mtx_entry_fn_random(struct zsl_mtx *m, size_t i, size_t j)
Sets the value to a random number between -1.0 and 1.0.
Definition: matrices.c:43
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_mtx_binary_fn_t
int(* zsl_mtx_binary_fn_t)(struct zsl_mtx *ma, struct zsl_mtx *mb, struct zsl_mtx *mc, size_t i, size_t j)
Function prototype called when applying a set of component-wise binary operations using a pair of sym...
Definition: matrices.h:156
ZSL_MTX_BINARY_OP_SUB
@ ZSL_MTX_BINARY_OP_SUB
Definition: matrices.h:107
zsl_mtx_gauss_elim_d
int zsl_mtx_gauss_elim_d(struct zsl_mtx *m, struct zsl_mtx *mi, size_t i, size_t j)
Given the element (i,j) in matrix 'm', this function performs gaussian elimination by adding row 'i' ...
Definition: matrices.c:861
zsl_mtx_copy
int zsl_mtx_copy(struct zsl_mtx *mdest, struct zsl_mtx *msrc)
Copies the contents of matrix 'msrc' into matrix 'mdest'.
Definition: matrices.c:81
EEIGENSIZE
#define EEIGENSIZE
Definition: matrices.h:41
zsl_mtx_norm_elem
int zsl_mtx_norm_elem(struct zsl_mtx *m, struct zsl_mtx *mn, struct zsl_mtx *mi, size_t i, size_t j)
Normalises elements in matrix m such that the element at position (i, j) is equal to 1....
Definition: matrices.c:965
zsl_mtx_is_sym
bool zsl_mtx_is_sym(struct zsl_mtx *m)
Checks if the square input matrix is symmetric.
Definition: matrices.c:1885
zsl_vec_neg
int zsl_vec_neg(struct zsl_vec *v)
Negates the elements in vector 'v'.
Definition: vectors.c:104
ZSL_MTX_UNARY_OP_TAN
@ ZSL_MTX_UNARY_OP_TAN
Definition: matrices.h:95
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_MTX_BINARY_OP_MIN
@ ZSL_MTX_BINARY_OP_MIN
Definition: matrices.h:112
ZSL_MTX_BINARY_OP_GEQ
@ ZSL_MTX_BINARY_OP_GEQ
Definition: matrices.h:119
zsl_mtx_binary_op
int zsl_mtx_binary_op(struct zsl_mtx *ma, struct zsl_mtx *mb, struct zsl_mtx *mc, zsl_mtx_binary_op_t op)
Applies a component-wise binary operation on every coefficient in symmetrical matrices 'ma' and 'mb',...
Definition: matrices.c:286
ZSL_MTX_UNARY_OP_SQRT
@ ZSL_MTX_UNARY_OP_SQRT
Definition: matrices.h:92
zsl_mtx_gram_schmidt
int zsl_mtx_gram_schmidt(struct zsl_mtx *m, struct zsl_mtx *mort)
Performs the Gram-Schmidt algorithm on the set of column vectors in matrix 'm'. This algorithm calcul...
Definition: matrices.c:922
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_MTX_BINARY_OP_LEQ
@ ZSL_MTX_BINARY_OP_LEQ
Definition: matrices.h:118
ZSL_MTX_BINARY_OP_MEAN
@ ZSL_MTX_BINARY_OP_MEAN
Definition: matrices.h:110
ZSL_MTX_UNARY_OP_CEIL
@ ZSL_MTX_UNARY_OP_CEIL
Definition: matrices.h:88
zsl_mtx_set_row
int zsl_mtx_set_row(struct zsl_mtx *m, size_t i, zsl_real_t *v)
Sets the contents of row 'i' in matrix 'm', assigning the values found in array 'v'.
Definition: matrices.c:144
zsl_mtx_inv_3x3
int zsl_mtx_inv_3x3(struct zsl_mtx *m, struct zsl_mtx *mi)
Calculates the inverse of 3x3 matrix 'm'. If the determinant of 'm' is zero, an identity matrix will ...
Definition: matrices.c:1009
zsl_mtx_print
int zsl_mtx_print(struct zsl_mtx *m)
Printf the supplied matrix using printf in a human-readable manner.
Definition: matrices.c:1907
matrices.h
API header file for matrices in zscilib.
zsl_mtx_is_equal
bool zsl_mtx_is_equal(struct zsl_mtx *ma, struct zsl_mtx *mb)
Checks if two matrices are identical in shape and content.
Definition: matrices.c:1857
ZSL_MTX_UNARY_OP_LOG
@ ZSL_MTX_UNARY_OP_LOG
Definition: matrices.h:90
zsl_mtx_unary_op
int zsl_mtx_unary_op(struct zsl_mtx *m, zsl_mtx_unary_op_t op)
Applies a unary operand on every coefficient in matrix 'm'.
Definition: matrices.c:191
ZSL_MATRIX_DEF
#define ZSL_MATRIX_DEF(name, m, n)
Definition: matrices.h:61
zsl_mtx_is_notneg
bool zsl_mtx_is_notneg(struct zsl_mtx *m)
Checks if all elements in matrix m are >= zero.
Definition: matrices.c:1873
ZSL_VECTOR_DEF
#define ZSL_VECTOR_DEF(name, n)
Definition: vectors.h:52
ZSL_MTX_UNARY_OP_ABS
@ ZSL_MTX_UNARY_OP_ABS
Definition: matrices.h:86
zsl.h
API header file for zscilib.
ZSL_ATAN
#define ZSL_ATAN
Definition: zsl.h:97
ZSL_MTX_UNARY_OP_COSH
@ ZSL_MTX_UNARY_OP_COSH
Definition: matrices.h:100
zsl_mtx_scalar_mult_d
int zsl_mtx_scalar_mult_d(struct zsl_mtx *m, zsl_real_t s)
Multiplies all elements in matrix 'm' by scalar value 's'.
Definition: matrices.c:488
ZSL_ASIN
#define ZSL_ASIN
Definition: zsl.h:95
zsl_mtx::sz_cols
size_t sz_cols
Definition: matrices.h:50
zsl_mtx_householder
int zsl_mtx_householder(struct zsl_mtx *m, struct zsl_mtx *h, bool hessenberg)
Calculates the householder reflection of 'm'. Used as part of QR decomposition. When 'hessenberg' is ...
Definition: matrices.c:1254
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_mtx_from_arr
int zsl_mtx_from_arr(struct zsl_mtx *m, zsl_real_t *a)
Converts an array of values into a matrix.
Definition: matrices.c:73
zsl_mtx_set_col
int zsl_mtx_set_col(struct zsl_mtx *m, size_t j, zsl_real_t *v)
Sets the contents of column 'j' in matrix 'm', assigning the values found in array 'v'.
Definition: matrices.c:176
ZSL_MTX_UNARY_OP_NEGATIVE
@ ZSL_MTX_UNARY_OP_NEGATIVE
Definition: matrices.h:84
zsl_mtx_adjoint
int zsl_mtx_adjoint(struct zsl_mtx *m, struct zsl_mtx *ma)
Calculates the ajoint matrix, based on the input square matrix 'm'.
Definition: matrices.c:572
zsl_real_t
double zsl_real_t
Definition: zsl.h:51
ZSL_MTX_BINARY_OP_LESS
@ ZSL_MTX_BINARY_OP_LESS
Definition: matrices.h:116
ZSL_MTX_BINARY_OP_ADD
@ ZSL_MTX_BINARY_OP_ADD
Definition: matrices.h:106
zsl_mtx_inv
int zsl_mtx_inv(struct zsl_mtx *m, struct zsl_mtx *mi)
Calculates the inverse of square matrix 'm'.
Definition: matrices.c:1064
ZSL_MTX_BINARY_OP_NEQUAL
@ ZSL_MTX_BINARY_OP_NEQUAL
Definition: matrices.h:115
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_ROUND
#define ZSL_ROUND
Definition: zsl.h:83
ZSL_MTX_UNARY_OP_INCREMENT
@ ZSL_MTX_UNARY_OP_INCREMENT
Definition: matrices.h:82
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_mtx_adjoint_3x3
int zsl_mtx_adjoint_3x3(struct zsl_mtx *m, struct zsl_mtx *ma)
Calculates the ajoint matrix, based on the input 3x3 matrix 'm'.
Definition: matrices.c:534
ZSL_MTX_UNARY_OP_SIN
@ ZSL_MTX_UNARY_OP_SIN
Definition: matrices.h:93
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_mtx_sub
int zsl_mtx_sub(struct zsl_mtx *ma, struct zsl_mtx *mb, struct zsl_mtx *mc)
Subtracts matrices 'mb' from 'ma', assigning the output to 'mc'. Matrices 'ma', 'mb' and 'mc' must al...
Definition: matrices.c:422
ZSL_MTX_UNARY_OP_DECREMENT
@ ZSL_MTX_UNARY_OP_DECREMENT
Definition: matrices.h:83
ZSL_SQRT
#define ZSL_SQRT
Definition: zsl.h:91
zsl_mtx_reduce
int zsl_mtx_reduce(struct zsl_mtx *m, struct zsl_mtx *mr, size_t i, size_t j)
Removes row 'i' and column 'j' from square matrix 'm', assigning the remaining elements in the matrix...
Definition: matrices.c:645