matd.c
Go to the documentation of this file.
1 /* Copyright (C) 2013-2016, The Regents of The University of Michigan.
2 All rights reserved.
3 
4 This software was developed in the APRIL Robotics Lab under the
5 direction of Edwin Olson, ebolson@umich.edu. This software may be
6 available under alternative licensing terms; contact the address above.
7 
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions are met:
10 
11 1. Redistributions of source code must retain the above copyright notice, this
12  list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright notice,
14  this list of conditions and the following disclaimer in the documentation
15  and/or other materials provided with the distribution.
16 
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
21 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 The views and conclusions contained in the software and documentation are those
29 of the authors and should not be interpreted as representing official policies,
30 either expressed or implied, of the Regents of The University of Michigan.
31 */
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <stdarg.h>
37 #include <assert.h>
38 #include <math.h>
39 #include <float.h>
40 
41 #include "common/math_util.h"
42 #include "common/svd22.h"
43 #include "common/matd.h"
44 
45 // a matd_t with rows=0 cols=0 is a SCALAR.
46 
47 // to ease creating mati, matf, etc. in the future.
48 #define TYPE double
49 
50 matd_t *matd_create(int rows, int cols)
51 {
52  assert(rows >= 0);
53  assert(cols >= 0);
54 
55  if (rows == 0 || cols == 0)
56  return matd_create_scalar(0);
57 
58  matd_t *m = calloc(1, sizeof(matd_t) + (rows*cols*sizeof(double)));
59  m->nrows = rows;
60  m->ncols = cols;
61 
62  return m;
63 }
64 
66 {
67  matd_t *m = calloc(1, sizeof(matd_t) + sizeof(double));
68  m->nrows = 0;
69  m->ncols = 0;
70  m->data[0] = v;
71 
72  return m;
73 }
74 
75 matd_t *matd_create_data(int rows, int cols, const TYPE *data)
76 {
77  if (rows == 0 || cols == 0)
78  return matd_create_scalar(data[0]);
79 
80  matd_t *m = matd_create(rows, cols);
81  for (int i = 0; i < rows * cols; i++)
82  m->data[i] = data[i];
83 
84  return m;
85 }
86 
87 matd_t *matd_create_dataf(int rows, int cols, const float *data)
88 {
89  if (rows == 0 || cols == 0)
90  return matd_create_scalar(data[0]);
91 
92  matd_t *m = matd_create(rows, cols);
93  for (int i = 0; i < rows * cols; i++)
94  m->data[i] = (double)data[i];
95 
96  return m;
97 }
98 
100 {
101  if (dim == 0)
102  return matd_create_scalar(1);
103 
104  matd_t *m = matd_create(dim, dim);
105  for (int i = 0; i < dim; i++)
106  MATD_EL(m, i, i) = 1;
107 
108  return m;
109 }
110 
111 // row and col are zero-based
112 TYPE matd_get(const matd_t *m, int row, int col)
113 {
114  assert(m != NULL);
115  assert(!matd_is_scalar(m));
116  assert(row >= 0);
117  assert(row < m->nrows);
118  assert(col >= 0);
119  assert(col < m->ncols);
120 
121  return MATD_EL(m, row, col);
122 }
123 
124 // row and col are zero-based
125 void matd_put(matd_t *m, int row, int col, TYPE value)
126 {
127  assert(m != NULL);
128 
129  if (matd_is_scalar(m)) {
130  matd_put_scalar(m, value);
131  return;
132  }
133 
134  assert(row >= 0);
135  assert(row < m->nrows);
136  assert(col >= 0);
137  assert(col < m->ncols);
138 
139  MATD_EL(m, row, col) = value;
140 }
141 
143 {
144  assert(m != NULL);
145  assert(matd_is_scalar(m));
146 
147  return (m->data[0]);
148 }
149 
150 void matd_put_scalar(matd_t *m, TYPE value)
151 {
152  assert(m != NULL);
153  assert(matd_is_scalar(m));
154 
155  m->data[0] = value;
156 }
157 
159 {
160  assert(m != NULL);
161 
162  matd_t *x = matd_create(m->nrows, m->ncols);
163  if (matd_is_scalar(m))
164  x->data[0] = m->data[0];
165  else
166  memcpy(x->data, m->data, sizeof(TYPE)*m->ncols*m->nrows);
167 
168  return x;
169 }
170 
171 matd_t *matd_select(const matd_t * a, int r0, int r1, int c0, int c1)
172 {
173  assert(a != NULL);
174 
175  assert(r0 >= 0 && r0 < a->nrows);
176  assert(c0 >= 0 && c0 < a->ncols);
177 
178  int nrows = r1 - r0 + 1;
179  int ncols = c1 - c0 + 1;
180 
181  matd_t * r = matd_create(nrows, ncols);
182 
183  for (int row = r0; row <= r1; row++)
184  for (int col = c0; col <= c1; col++)
185  MATD_EL(r,row-r0,col-c0) = MATD_EL(a,row,col);
186 
187  return r;
188 }
189 
190 void matd_print(const matd_t *m, const char *fmt)
191 {
192  assert(m != NULL);
193  assert(fmt != NULL);
194 
195  if (matd_is_scalar(m)) {
196  printf(fmt, MATD_EL(m, 0, 0));
197  printf("\n");
198  } else {
199  for (int i = 0; i < m->nrows; i++) {
200  for (int j = 0; j < m->ncols; j++) {
201  printf(fmt, MATD_EL(m, i, j));
202  }
203  printf("\n");
204  }
205  }
206 }
207 
208 void matd_print_transpose(const matd_t *m, const char *fmt)
209 {
210  assert(m != NULL);
211  assert(fmt != NULL);
212 
213  if (matd_is_scalar(m)) {
214  printf(fmt, MATD_EL(m, 0, 0));
215  printf("\n");
216  } else {
217  for (int j = 0; j < m->ncols; j++) {
218  for (int i = 0; i < m->nrows; i++) {
219  printf(fmt, MATD_EL(m, i, j));
220  }
221  printf("\n");
222  }
223  }
224 }
225 
227 {
228  if (!m)
229  return;
230 
231  assert(m != NULL);
232  free(m);
233 }
234 
235 matd_t *matd_multiply(const matd_t *a, const matd_t *b)
236 {
237  assert(a != NULL);
238  assert(b != NULL);
239 
240  if (matd_is_scalar(a))
241  return matd_scale(b, a->data[0]);
242  if (matd_is_scalar(b))
243  return matd_scale(a, b->data[0]);
244 
245  assert(a->ncols == b->nrows);
246  matd_t *m = matd_create(a->nrows, b->ncols);
247 
248  for (int i = 0; i < m->nrows; i++) {
249  for (int j = 0; j < m->ncols; j++) {
250  TYPE acc = 0;
251  for (int k = 0; k < a->ncols; k++) {
252  acc += MATD_EL(a, i, k) * MATD_EL(b, k, j);
253  }
254  MATD_EL(m, i, j) = acc;
255  }
256  }
257 
258  return m;
259 }
260 
261 matd_t *matd_scale(const matd_t *a, double s)
262 {
263  assert(a != NULL);
264 
265  if (matd_is_scalar(a))
266  return matd_create_scalar(a->data[0] * s);
267 
268  matd_t *m = matd_create(a->nrows, a->ncols);
269 
270  for (int i = 0; i < m->nrows; i++) {
271  for (int j = 0; j < m->ncols; j++) {
272  MATD_EL(m, i, j) = s * MATD_EL(a, i, j);
273  }
274  }
275 
276  return m;
277 }
278 
279 void matd_scale_inplace(matd_t *a, double s)
280 {
281  assert(a != NULL);
282 
283  if (matd_is_scalar(a)) {
284  a->data[0] *= s;
285  return;
286  }
287 
288  for (int i = 0; i < a->nrows; i++) {
289  for (int j = 0; j < a->ncols; j++) {
290  MATD_EL(a, i, j) *= s;
291  }
292  }
293 }
294 
295 matd_t *matd_add(const matd_t *a, const matd_t *b)
296 {
297  assert(a != NULL);
298  assert(b != NULL);
299  assert(a->nrows == b->nrows);
300  assert(a->ncols == b->ncols);
301 
302  if (matd_is_scalar(a))
303  return matd_create_scalar(a->data[0] + b->data[0]);
304 
305  matd_t *m = matd_create(a->nrows, a->ncols);
306 
307  for (int i = 0; i < m->nrows; i++) {
308  for (int j = 0; j < m->ncols; j++) {
309  MATD_EL(m, i, j) = MATD_EL(a, i, j) + MATD_EL(b, i, j);
310  }
311  }
312 
313  return m;
314 }
315 
316 void matd_add_inplace(matd_t *a, const matd_t *b)
317 {
318  assert(a != NULL);
319  assert(b != NULL);
320  assert(a->nrows == b->nrows);
321  assert(a->ncols == b->ncols);
322 
323  if (matd_is_scalar(a)) {
324  a->data[0] += b->data[0];
325  return;
326  }
327 
328  for (int i = 0; i < a->nrows; i++) {
329  for (int j = 0; j < a->ncols; j++) {
330  MATD_EL(a, i, j) += MATD_EL(b, i, j);
331  }
332  }
333 }
334 
335 
336 matd_t *matd_subtract(const matd_t *a, const matd_t *b)
337 {
338  assert(a != NULL);
339  assert(b != NULL);
340  assert(a->nrows == b->nrows);
341  assert(a->ncols == b->ncols);
342 
343  if (matd_is_scalar(a))
344  return matd_create_scalar(a->data[0] - b->data[0]);
345 
346  matd_t *m = matd_create(a->nrows, a->ncols);
347 
348  for (int i = 0; i < m->nrows; i++) {
349  for (int j = 0; j < m->ncols; j++) {
350  MATD_EL(m, i, j) = MATD_EL(a, i, j) - MATD_EL(b, i, j);
351  }
352  }
353 
354  return m;
355 }
356 
358 {
359  assert(a != NULL);
360  assert(b != NULL);
361  assert(a->nrows == b->nrows);
362  assert(a->ncols == b->ncols);
363 
364  if (matd_is_scalar(a)) {
365  a->data[0] -= b->data[0];
366  return;
367  }
368 
369  for (int i = 0; i < a->nrows; i++) {
370  for (int j = 0; j < a->ncols; j++) {
371  MATD_EL(a, i, j) -= MATD_EL(b, i, j);
372  }
373  }
374 }
375 
376 
378 {
379  assert(a != NULL);
380 
381  if (matd_is_scalar(a))
382  return matd_create_scalar(a->data[0]);
383 
384  matd_t *m = matd_create(a->ncols, a->nrows);
385 
386  for (int i = 0; i < a->nrows; i++) {
387  for (int j = 0; j < a->ncols; j++) {
388  MATD_EL(m, j, i) = MATD_EL(a, i, j);
389  }
390  }
391  return m;
392 }
393 
394 static
395 double matd_det_general(const matd_t *a)
396 {
397  // Use LU decompositon to calculate the determinant
398  matd_plu_t *mlu = matd_plu(a);
399  matd_t *L = matd_plu_l(mlu);
400  matd_t *U = matd_plu_u(mlu);
401 
402  // The determinants of the L and U matrices are the products of
403  // their respective diagonal elements
404  double detL = 1; double detU = 1;
405  for (int i = 0; i < a->nrows; i++) {
406  detL *= matd_get(L, i, i);
407  detU *= matd_get(U, i, i);
408  }
409 
410  // The determinant of a can be calculated as
411  // epsilon*det(L)*det(U),
412  // where epsilon is just the sign of the corresponding permutation
413  // (which is +1 for an even number of permutations and is −1
414  // for an uneven number of permutations).
415  double det = mlu->pivsign * detL * detU;
416 
417  // Cleanup
418  matd_plu_destroy(mlu);
419  matd_destroy(L);
420  matd_destroy(U);
421 
422  return det;
423 }
424 
425 double matd_det(const matd_t *a)
426 {
427  assert(a != NULL);
428  assert(a->nrows == a->ncols);
429 
430  switch(a->nrows) {
431  case 0:
432  // scalar: invalid
433  assert(a->nrows > 0);
434  break;
435 
436  case 1:
437  // 1x1 matrix
438  return a->data[0];
439 
440  case 2:
441  // 2x2 matrix
442  return a->data[0] * a->data[3] - a->data[1] * a->data[2];
443 
444  case 3:
445  // 3x3 matrix
446  return a->data[0]*a->data[4]*a->data[8]
447  - a->data[0]*a->data[5]*a->data[7]
448  + a->data[1]*a->data[5]*a->data[6]
449  - a->data[1]*a->data[3]*a->data[8]
450  + a->data[2]*a->data[3]*a->data[7]
451  - a->data[2]*a->data[4]*a->data[6];
452 
453  case 4: {
454  // 4x4 matrix
455  double m00 = MATD_EL(a,0,0), m01 = MATD_EL(a,0,1), m02 = MATD_EL(a,0,2), m03 = MATD_EL(a,0,3);
456  double m10 = MATD_EL(a,1,0), m11 = MATD_EL(a,1,1), m12 = MATD_EL(a,1,2), m13 = MATD_EL(a,1,3);
457  double m20 = MATD_EL(a,2,0), m21 = MATD_EL(a,2,1), m22 = MATD_EL(a,2,2), m23 = MATD_EL(a,2,3);
458  double m30 = MATD_EL(a,3,0), m31 = MATD_EL(a,3,1), m32 = MATD_EL(a,3,2), m33 = MATD_EL(a,3,3);
459 
460  return m00 * m11 * m22 * m33 - m00 * m11 * m23 * m32 -
461  m00 * m21 * m12 * m33 + m00 * m21 * m13 * m32 + m00 * m31 * m12 * m23 -
462  m00 * m31 * m13 * m22 - m10 * m01 * m22 * m33 +
463  m10 * m01 * m23 * m32 + m10 * m21 * m02 * m33 -
464  m10 * m21 * m03 * m32 - m10 * m31 * m02 * m23 +
465  m10 * m31 * m03 * m22 + m20 * m01 * m12 * m33 -
466  m20 * m01 * m13 * m32 - m20 * m11 * m02 * m33 +
467  m20 * m11 * m03 * m32 + m20 * m31 * m02 * m13 -
468  m20 * m31 * m03 * m12 - m30 * m01 * m12 * m23 +
469  m30 * m01 * m13 * m22 + m30 * m11 * m02 * m23 -
470  m30 * m11 * m03 * m22 - m30 * m21 * m02 * m13 +
471  m30 * m21 * m03 * m12;
472  }
473 
474  default:
475  return matd_det_general(a);
476  }
477 
478  assert(0);
479  return 0;
480 }
481 
482 // returns NULL if the matrix is (exactly) singular. Caller is
483 // otherwise responsible for knowing how to cope with badly
484 // conditioned matrices.
486 {
487  matd_t *m = NULL;
488 
489  assert(x != NULL);
490  assert(x->nrows == x->ncols);
491 
492  if (matd_is_scalar(x)) {
493  if (x->data[0] == 0)
494  return NULL;
495 
496  return matd_create_scalar(1.0 / x->data[0]);
497  }
498 
499  switch(x->nrows) {
500  case 1: {
501  double det = x->data[0];
502  if (det == 0)
503  return NULL;
504 
505  double invdet = 1.0 / det;
506 
507  m = matd_create(x->nrows, x->nrows);
508  MATD_EL(m, 0, 0) = 1.0 * invdet;
509  return m;
510  }
511 
512  case 2: {
513  double det = x->data[0] * x->data[3] - x->data[1] * x->data[2];
514  if (det == 0)
515  return NULL;
516 
517  double invdet = 1.0 / det;
518 
519  m = matd_create(x->nrows, x->nrows);
520  MATD_EL(m, 0, 0) = MATD_EL(x, 1, 1) * invdet;
521  MATD_EL(m, 0, 1) = - MATD_EL(x, 0, 1) * invdet;
522  MATD_EL(m, 1, 0) = - MATD_EL(x, 1, 0) * invdet;
523  MATD_EL(m, 1, 1) = MATD_EL(x, 0, 0) * invdet;
524  return m;
525  }
526 
527  default: {
528  matd_plu_t *plu = matd_plu(x);
529 
530  matd_t *inv = NULL;
531  if (!plu->singular) {
532  matd_t *ident = matd_identity(x->nrows);
533  inv = matd_plu_solve(plu, ident);
534  matd_destroy(ident);
535  }
536 
537  matd_plu_destroy(plu);
538 
539  return inv;
540  }
541  }
542 
543  return NULL; // unreachable
544 }
545 
546 
547 
548 // TODO Optimization: Some operations we could perform in-place,
549 // saving some memory allocation work. E.g., ADD, SUBTRACT. Just need
550 // to make sure that we don't do an in-place modification on a matrix
551 // that was an input argument!
552 
553 // handle right-associative operators, greedily consuming them. These
554 // include transpose and inverse. This is called by the main recursion
555 // method.
556 static inline matd_t *matd_op_gobble_right(const char *expr, int *pos, matd_t *acc, matd_t **garb, int *garbpos)
557 {
558  while (expr[*pos] != 0) {
559 
560  switch (expr[*pos]) {
561 
562  case '\'': {
563  assert(acc != NULL); // either a syntax error or a math op failed, producing null
564  matd_t *res = matd_transpose(acc);
565  garb[*garbpos] = res;
566  (*garbpos)++;
567  acc = res;
568 
569  (*pos)++;
570  break;
571  }
572 
573  // handle inverse ^-1. No other exponents are allowed.
574  case '^': {
575  assert(acc != NULL);
576  assert(expr[*pos+1] == '-');
577  assert(expr[*pos+2] == '1');
578 
579  matd_t *res = matd_inverse(acc);
580  garb[*garbpos] = res;
581  (*garbpos)++;
582  acc = res;
583 
584  (*pos)+=3;
585  break;
586  }
587 
588  default:
589  return acc;
590  }
591  }
592 
593  return acc;
594 }
595 
596 // @garb, garbpos A list of every matrix allocated during evaluation... used to assist cleanup.
597 // @oneterm: we should return at the end of this term (i.e., stop at a PLUS, MINUS, LPAREN).
598 static matd_t *matd_op_recurse(const char *expr, int *pos, matd_t *acc, matd_t **args, int *argpos,
599  matd_t **garb, int *garbpos, int oneterm)
600 {
601  while (expr[*pos] != 0) {
602 
603  switch (expr[*pos]) {
604 
605  case '(': {
606  if (oneterm && acc != NULL)
607  return acc;
608  (*pos)++;
609  matd_t *rhs = matd_op_recurse(expr, pos, NULL, args, argpos, garb, garbpos, 0);
610  rhs = matd_op_gobble_right(expr, pos, rhs, garb, garbpos);
611 
612  if (acc == NULL) {
613  acc = rhs;
614  } else {
615  matd_t *res = matd_multiply(acc, rhs);
616  garb[*garbpos] = res;
617  (*garbpos)++;
618  acc = res;
619  }
620 
621  break;
622  }
623 
624  case ')': {
625  if (oneterm)
626  return acc;
627 
628  (*pos)++;
629  return acc;
630  }
631 
632  case '*': {
633  (*pos)++;
634 
635  matd_t *rhs = matd_op_recurse(expr, pos, NULL, args, argpos, garb, garbpos, 1);
636  rhs = matd_op_gobble_right(expr, pos, rhs, garb, garbpos);
637 
638  if (acc == NULL) {
639  acc = rhs;
640  } else {
641  matd_t *res = matd_multiply(acc, rhs);
642  garb[*garbpos] = res;
643  (*garbpos)++;
644  acc = res;
645  }
646 
647  break;
648  }
649 
650  case 'F': {
651  matd_t *rhs = args[*argpos];
652  garb[*garbpos] = rhs;
653  (*garbpos)++;
654 
655  (*pos)++;
656  (*argpos)++;
657 
658  rhs = matd_op_gobble_right(expr, pos, rhs, garb, garbpos);
659 
660  if (acc == NULL) {
661  acc = rhs;
662  } else {
663  matd_t *res = matd_multiply(acc, rhs);
664  garb[*garbpos] = res;
665  (*garbpos)++;
666  acc = res;
667  }
668 
669  break;
670  }
671 
672  case 'M': {
673  matd_t *rhs = args[*argpos];
674 
675  (*pos)++;
676  (*argpos)++;
677 
678  rhs = matd_op_gobble_right(expr, pos, rhs, garb, garbpos);
679 
680  if (acc == NULL) {
681  acc = rhs;
682  } else {
683  matd_t *res = matd_multiply(acc, rhs);
684  garb[*garbpos] = res;
685  (*garbpos)++;
686  acc = res;
687  }
688 
689  break;
690  }
691 
692 /*
693  case 'D': {
694  int rows = expr[*pos+1]-'0';
695  int cols = expr[*pos+2]-'0';
696 
697  matd_t *rhs = matd_create(rows, cols);
698 
699  break;
700  }
701 */
702  // a constant (SCALAR) defined inline. Treat just like M, creating a matd_t on the fly.
703  case '0':
704  case '1':
705  case '2':
706  case '3':
707  case '4':
708  case '5':
709  case '6':
710  case '7':
711  case '8':
712  case '9':
713  case '.': {
714  const char *start = &expr[*pos];
715  char *end;
716  double s = strtod(start, &end);
717  (*pos) += (end - start);
718  matd_t *rhs = matd_create_scalar(s);
719  garb[*garbpos] = rhs;
720  (*garbpos)++;
721 
722  rhs = matd_op_gobble_right(expr, pos, rhs, garb, garbpos);
723 
724  if (acc == NULL) {
725  acc = rhs;
726  } else {
727  matd_t *res = matd_multiply(acc, rhs);
728  garb[*garbpos] = res;
729  (*garbpos)++;
730  acc = res;
731  }
732 
733  break;
734  }
735 
736  case '+': {
737  if (oneterm && acc != NULL)
738  return acc;
739 
740  // don't support unary plus
741  assert(acc != NULL);
742  (*pos)++;
743  matd_t *rhs = matd_op_recurse(expr, pos, NULL, args, argpos, garb, garbpos, 1);
744  rhs = matd_op_gobble_right(expr, pos, rhs, garb, garbpos);
745 
746  matd_t *res = matd_add(acc, rhs);
747 
748  garb[*garbpos] = res;
749  (*garbpos)++;
750  acc = res;
751  break;
752  }
753 
754  case '-': {
755  if (oneterm && acc != NULL)
756  return acc;
757 
758  if (acc == NULL) {
759  // unary minus
760  (*pos)++;
761  matd_t *rhs = matd_op_recurse(expr, pos, NULL, args, argpos, garb, garbpos, 1);
762  rhs = matd_op_gobble_right(expr, pos, rhs, garb, garbpos);
763 
764  matd_t *res = matd_scale(rhs, -1);
765  garb[*garbpos] = res;
766  (*garbpos)++;
767  acc = res;
768  } else {
769  // subtract
770  (*pos)++;
771  matd_t *rhs = matd_op_recurse(expr, pos, NULL, args, argpos, garb, garbpos, 1);
772  rhs = matd_op_gobble_right(expr, pos, rhs, garb, garbpos);
773 
774  matd_t *res = matd_subtract(acc, rhs);
775  garb[*garbpos] = res;
776  (*garbpos)++;
777  acc = res;
778  }
779  break;
780  }
781 
782  case ' ': {
783  // nothing to do. spaces are meaningless.
784  (*pos)++;
785  break;
786  }
787 
788  default: {
789  fprintf(stderr, "matd_op(): Unknown character: '%c'\n", expr[*pos]);
790  assert(expr[*pos] != expr[*pos]);
791  }
792  }
793  }
794  return acc;
795 }
796 
797 // always returns a new matrix.
798 matd_t *matd_op(const char *expr, ...)
799 {
800  int nargs = 0;
801  int exprlen = 0;
802 
803  assert(expr != NULL);
804 
805  for (const char *p = expr; *p != 0; p++) {
806  if (*p == 'M' || *p == 'F')
807  nargs++;
808  exprlen++;
809  }
810 
811  assert(nargs > 0);
812 
813  if (!exprlen) // expr = ""
814  return NULL;
815 
816  va_list ap;
817  va_start(ap, expr);
818 
819  matd_t *args[nargs];
820  for (int i = 0; i < nargs; i++) {
821  args[i] = va_arg(ap, matd_t*);
822  // XXX: sanity check argument; emit warning/error if args[i]
823  // doesn't look like a matd_t*.
824  }
825 
826  va_end(ap);
827 
828  int pos = 0;
829  int argpos = 0;
830  int garbpos = 0;
831 
832  matd_t *garb[2*exprlen]; // can't create more than 2 new result per character
833  // one result, and possibly one argument to free
834 
835  matd_t *res = matd_op_recurse(expr, &pos, NULL, args, &argpos, garb, &garbpos, 0);
836 
837  // 'res' may need to be freed as part of garbage collection (i.e. expr = "F")
838  matd_t *res_copy = (res ? matd_copy(res) : NULL);
839 
840  for (int i = 0; i < garbpos; i++) {
841  matd_destroy(garb[i]);
842  }
843 
844  return res_copy;
845 }
846 
847 double matd_vec_mag(const matd_t *a)
848 {
849  assert(a != NULL);
850  assert(matd_is_vector(a));
851 
852  double mag = 0.0;
853  int len = a->nrows*a->ncols;
854  for (int i = 0; i < len; i++)
855  mag += sq(a->data[i]);
856  return sqrt(mag);
857 }
858 
859 double matd_vec_dist(const matd_t *a, const matd_t *b)
860 {
861  assert(a != NULL);
862  assert(b != NULL);
863  assert(matd_is_vector(a) && matd_is_vector(b));
864  assert(a->nrows*a->ncols == b->nrows*b->ncols);
865 
866  int lena = a->nrows*a->ncols;
867  return matd_vec_dist_n(a, b, lena);
868 }
869 
870 double matd_vec_dist_n(const matd_t *a, const matd_t *b, int n)
871 {
872  assert(a != NULL);
873  assert(b != NULL);
874  assert(matd_is_vector(a) && matd_is_vector(b));
875 
876  int lena = a->nrows*a->ncols;
877  int lenb = b->nrows*b->ncols;
878 
879  assert(n <= lena && n <= lenb);
880 
881  double mag = 0.0;
882  for (int i = 0; i < n; i++)
883  mag += sq(a->data[i] - b->data[i]);
884  return sqrt(mag);
885 }
886 
887 // find the index of the off-diagonal element with the largest mag
888 static inline int max_idx(const matd_t *A, int row, int maxcol)
889 {
890  int maxi = 0;
891  double maxv = -1;
892 
893  for (int i = 0; i < maxcol; i++) {
894  if (i == row)
895  continue;
896  double v = fabs(MATD_EL(A, row, i));
897  if (v > maxv) {
898  maxi = i;
899  maxv = v;
900  }
901  }
902 
903  return maxi;
904 }
905 
906 double matd_vec_dot_product(const matd_t *a, const matd_t *b)
907 {
908  assert(a != NULL);
909  assert(b != NULL);
910  assert(matd_is_vector(a) && matd_is_vector(b));
911  int adim = a->ncols*a->nrows;
912  int bdim = b->ncols*b->nrows;
913  assert(adim == bdim);
914 
915  double acc = 0;
916  for (int i = 0; i < adim; i++) {
917  acc += a->data[i] * b->data[i];
918  }
919  return acc;
920 }
921 
922 
924 {
925  assert(a != NULL);
926  assert(matd_is_vector(a));
927 
928  double mag = matd_vec_mag(a);
929  assert(mag > 0);
930 
931  matd_t *b = matd_create(a->nrows, a->ncols);
932 
933  int len = a->nrows*a->ncols;
934  for(int i = 0; i < len; i++)
935  b->data[i] = a->data[i] / mag;
936 
937  return b;
938 }
939 
940 matd_t *matd_crossproduct(const matd_t *a, const matd_t *b)
941 { // only defined for vecs (col or row) of length 3
942  assert(a != NULL);
943  assert(b != NULL);
944  assert(matd_is_vector_len(a, 3) && matd_is_vector_len(b, 3));
945 
946  matd_t * r = matd_create(a->nrows, a->ncols);
947 
948  r->data[0] = a->data[1] * b->data[2] - a->data[2] * b->data[1];
949  r->data[1] = a->data[2] * b->data[0] - a->data[0] * b->data[2];
950  r->data[2] = a->data[0] * b->data[1] - a->data[1] * b->data[0];
951 
952  return r;
953 }
954 
955 TYPE matd_err_inf(const matd_t *a, const matd_t *b)
956 {
957  assert(a->nrows == b->nrows);
958  assert(a->ncols == b->ncols);
959 
960  TYPE maxf = 0;
961 
962  for (int i = 0; i < a->nrows; i++) {
963  for (int j = 0; j < a->ncols; j++) {
964  TYPE av = MATD_EL(a, i, j);
965  TYPE bv = MATD_EL(b, i, j);
966 
967  TYPE err = fabs(av - bv);
968  maxf = fmax(maxf, err);
969  }
970  }
971 
972  return maxf;
973 }
974 
975 // Computes an SVD for square or tall matrices. This code doesn't work
976 // for wide matrices, because the bidiagonalization results in one
977 // non-zero element too far to the right for us to rotate away.
978 //
979 // Caller is responsible for destroying U, S, and V.
980 static matd_svd_t matd_svd_tall(matd_t *A, int flags)
981 {
982  matd_t *B = matd_copy(A);
983 
984  // Apply householder reflections on each side to reduce A to
985  // bidiagonal form. Specifically:
986  //
987  // A = LS*B*RS'
988  //
989  // Where B is bidiagonal, and LS/RS are unitary.
990  //
991  // Why are we doing this? Some sort of transformation is necessary
992  // to reduce the matrix's nz elements to a square region. QR could
993  // work too. We need nzs confined to a square region so that the
994  // subsequent iterative process, which is based on rotations, can
995  // work. (To zero out a term at (i,j), our rotations will also
996  // affect (j,i).
997  //
998  // We prefer bidiagonalization over QR because it gets us "closer"
999  // to the SVD, which should mean fewer iterations.
1000 
1001  // LS: cumulative left-handed transformations
1002  matd_t *LS = matd_identity(A->nrows);
1003 
1004  // RS: cumulative right-handed transformations.
1005  matd_t *RS = matd_identity(A->ncols);
1006 
1007  for (int hhidx = 0; hhidx < A->nrows; hhidx++) {
1008 
1009  if (hhidx < A->ncols) {
1010  // We construct the normal of the reflection plane: let u
1011  // be the vector to reflect, x =[ M 0 0 0 ] the target
1012  // location for u (u') after reflection (with M = ||u||).
1013  //
1014  // The normal vector is then n = (u - x), but since we
1015  // could equally have the target location be x = [-M 0 0 0
1016  // ], we could use n = (u + x).
1017  //
1018  // We then normalize n. To ensure a reasonable magnitude,
1019  // we select the sign of M so as to maximize the magnitude
1020  // of the first element of (x +/- M). (Otherwise, we could
1021  // end up with a divide-by-zero if u[0] and M cancel.)
1022  //
1023  // The householder reflection matrix is then H=(I - nn'), and
1024  // u' = Hu.
1025  //
1026  //
1027  int vlen = A->nrows - hhidx;
1028 
1029  double v[vlen];
1030 
1031  double mag2 = 0;
1032  for (int i = 0; i < vlen; i++) {
1033  v[i] = MATD_EL(B, hhidx+i, hhidx);
1034  mag2 += v[i]*v[i];
1035  }
1036 
1037  double oldv0 = v[0];
1038  if (oldv0 < 0)
1039  v[0] -= sqrt(mag2);
1040  else
1041  v[0] += sqrt(mag2);
1042 
1043  mag2 += -oldv0*oldv0 + v[0]*v[0];
1044 
1045  // normalize v
1046  double mag = sqrt(mag2);
1047 
1048  // this case arises with matrices of all zeros, for example.
1049  if (mag == 0)
1050  continue;
1051 
1052  for (int i = 0; i < vlen; i++)
1053  v[i] /= mag;
1054 
1055  // Q = I - 2vv'
1056  //matd_t *Q = matd_identity(A->nrows);
1057  //for (int i = 0; i < vlen; i++)
1058  // for (int j = 0; j < vlen; j++)
1059  // MATD_EL(Q, i+hhidx, j+hhidx) -= 2*v[i]*v[j];
1060 
1061 
1062  // LS = matd_op("F*M", LS, Q);
1063  // Implementation: take each row of LS, compute dot product with n,
1064  // subtract n (scaled by dot product) from it.
1065  for (int i = 0; i < LS->nrows; i++) {
1066  double dot = 0;
1067  for (int j = 0; j < vlen; j++)
1068  dot += MATD_EL(LS, i, hhidx+j) * v[j];
1069  for (int j = 0; j < vlen; j++)
1070  MATD_EL(LS, i, hhidx+j) -= 2*dot*v[j];
1071  }
1072 
1073  // B = matd_op("M*F", Q, B); // should be Q', but Q is symmetric.
1074  for (int i = 0; i < B->ncols; i++) {
1075  double dot = 0;
1076  for (int j = 0; j < vlen; j++)
1077  dot += MATD_EL(B, hhidx+j, i) * v[j];
1078  for (int j = 0; j < vlen; j++)
1079  MATD_EL(B, hhidx+j, i) -= 2*dot*v[j];
1080  }
1081  }
1082 
1083  if (hhidx+2 < A->ncols) {
1084  int vlen = A->ncols - hhidx - 1;
1085 
1086  double v[vlen];
1087 
1088  double mag2 = 0;
1089  for (int i = 0; i < vlen; i++) {
1090  v[i] = MATD_EL(B, hhidx, hhidx+i+1);
1091  mag2 += v[i]*v[i];
1092  }
1093 
1094  double oldv0 = v[0];
1095  if (oldv0 < 0)
1096  v[0] -= sqrt(mag2);
1097  else
1098  v[0] += sqrt(mag2);
1099 
1100  mag2 += -oldv0*oldv0 + v[0]*v[0];
1101 
1102  // compute magnitude of ([1 0 0..]+v)
1103  double mag = sqrt(mag2);
1104 
1105  // this case can occur when the vectors are already perpendicular
1106  if (mag == 0)
1107  continue;
1108 
1109  for (int i = 0; i < vlen; i++)
1110  v[i] /= mag;
1111 
1112  // TODO: optimize these multiplications
1113  // matd_t *Q = matd_identity(A->ncols);
1114  // for (int i = 0; i < vlen; i++)
1115  // for (int j = 0; j < vlen; j++)
1116  // MATD_EL(Q, i+1+hhidx, j+1+hhidx) -= 2*v[i]*v[j];
1117 
1118  // RS = matd_op("F*M", RS, Q);
1119  for (int i = 0; i < RS->nrows; i++) {
1120  double dot = 0;
1121  for (int j = 0; j < vlen; j++)
1122  dot += MATD_EL(RS, i, hhidx+1+j) * v[j];
1123  for (int j = 0; j < vlen; j++)
1124  MATD_EL(RS, i, hhidx+1+j) -= 2*dot*v[j];
1125  }
1126 
1127  // B = matd_op("F*M", B, Q); // should be Q', but Q is symmetric.
1128  for (int i = 0; i < B->nrows; i++) {
1129  double dot = 0;
1130  for (int j = 0; j < vlen; j++)
1131  dot += MATD_EL(B, i, hhidx+1+j) * v[j];
1132  for (int j = 0; j < vlen; j++)
1133  MATD_EL(B, i, hhidx+1+j) -= 2*dot*v[j];
1134  }
1135  }
1136  }
1137 
1138  // maxiters used to be smaller to prevent us from looping forever,
1139  // but this doesn't seem to happen any more with our more stable
1140  // svd22 implementation.
1141  int maxiters = 1UL << 30;
1142  assert(maxiters > 0); // reassure clang
1143  int iter;
1144 
1145  double maxv; // maximum non-zero value being reduced this iteration
1146 
1147  double tol = 1E-10;
1148 
1149  // which method will we use to find the largest off-diagonal
1150  // element of B?
1151  const int find_max_method = 1; //(B->ncols < 6) ? 2 : 1;
1152 
1153  // for each of the first B->ncols rows, which index has the
1154  // maximum absolute value? (used by method 1)
1155  int maxrowidx[B->ncols];
1156  int lastmaxi, lastmaxj;
1157 
1158  if (find_max_method == 1) {
1159  for (int i = 2; i < B->ncols; i++)
1160  maxrowidx[i] = max_idx(B, i, B->ncols);
1161 
1162  // note that we started the array at 2. That's because by setting
1163  // these values below, we'll recompute first two entries on the
1164  // first iteration!
1165  lastmaxi = 0, lastmaxj = 1;
1166  }
1167 
1168  for (iter = 0; iter < maxiters; iter++) {
1169 
1170  // No diagonalization required for 0x0 and 1x1 matrices.
1171  if (B->ncols < 2)
1172  break;
1173 
1174  // find the largest off-diagonal element of B, and put its
1175  // coordinates in maxi, maxj.
1176  int maxi, maxj;
1177 
1178  if (find_max_method == 1) {
1179  // method 1 is the "smarter" method which does at least
1180  // 4*ncols work. More work might be needed (up to
1181  // ncols*ncols), depending on data. Thus, this might be a
1182  // bit slower than the default method for very small
1183  // matrices.
1184  maxi = -1;
1185  maxv = -1;
1186 
1187  // every iteration, we must deal with the fact that rows
1188  // and columns lastmaxi and lastmaxj have been
1189  // modified. Update maxrowidx accordingly.
1190 
1191  // now, EVERY row also had columns lastmaxi and lastmaxj modified.
1192  for (int rowi = 0; rowi < B->ncols; rowi++) {
1193 
1194  // the magnitude of the largest off-diagonal element
1195  // in this row.
1196  double thismaxv;
1197 
1198  // row 'lastmaxi' and 'lastmaxj' have been completely
1199  // changed. compute from scratch.
1200  if (rowi == lastmaxi || rowi == lastmaxj) {
1201  maxrowidx[rowi] = max_idx(B, rowi, B->ncols);
1202  thismaxv = fabs(MATD_EL(B, rowi, maxrowidx[rowi]));
1203  goto endrowi;
1204  }
1205 
1206  // our maximum entry was just modified. We don't know
1207  // if it went up or down, and so we don't know if it
1208  // is still the maximum. We have to update from
1209  // scratch.
1210  if (maxrowidx[rowi] == lastmaxi || maxrowidx[rowi] == lastmaxj) {
1211  maxrowidx[rowi] = max_idx(B, rowi, B->ncols);
1212  thismaxv = fabs(MATD_EL(B, rowi, maxrowidx[rowi]));
1213  goto endrowi;
1214  }
1215 
1216  // This row is unchanged, except for columns
1217  // 'lastmaxi' and 'lastmaxj', and those columns were
1218  // not previously the largest entry... just check to
1219  // see if they are now the maximum entry in their
1220  // row. (Remembering to consider off-diagonal entries
1221  // only!)
1222  thismaxv = fabs(MATD_EL(B, rowi, maxrowidx[rowi]));
1223 
1224  // check column lastmaxi. Is it now the maximum?
1225  if (lastmaxi != rowi) {
1226  double v = fabs(MATD_EL(B, rowi, lastmaxi));
1227  if (v > thismaxv) {
1228  thismaxv = v;
1229  maxrowidx[rowi] = lastmaxi;
1230  }
1231  }
1232 
1233  // check column lastmaxj
1234  if (lastmaxj != rowi) {
1235  double v = fabs(MATD_EL(B, rowi, lastmaxj));
1236  if (v > thismaxv) {
1237  thismaxv = v;
1238  maxrowidx[rowi] = lastmaxj;
1239  }
1240  }
1241 
1242  // does this row have the largest value we've seen so far?
1243  endrowi:
1244  if (thismaxv > maxv) {
1245  maxv = thismaxv;
1246  maxi = rowi;
1247  }
1248  }
1249 
1250  assert(maxi >= 0);
1251  maxj = maxrowidx[maxi];
1252 
1253  // save these for the next iteration.
1254  lastmaxi = maxi;
1255  lastmaxj = maxj;
1256 
1257  if (maxv < tol)
1258  break;
1259 
1260  } else if (find_max_method == 2) {
1261  // brute-force (reference) version.
1262  maxv = -1;
1263 
1264  // only search top "square" portion
1265  for (int i = 0; i < B->ncols; i++) {
1266  for (int j = 0; j < B->ncols; j++) {
1267  if (i == j)
1268  continue;
1269 
1270  double v = fabs(MATD_EL(B, i, j));
1271 
1272  if (v > maxv) {
1273  maxi = i;
1274  maxj = j;
1275  maxv = v;
1276  }
1277  }
1278  }
1279 
1280  // termination condition.
1281  if (maxv < tol)
1282  break;
1283  } else {
1284  assert(0);
1285  }
1286 
1287 // printf(">>> %5d %3d, %3d %15g\n", maxi, maxj, iter, maxv);
1288 
1289  // Now, solve the 2x2 SVD problem for the matrix
1290  // [ A0 A1 ]
1291  // [ A2 A3 ]
1292  double A0 = MATD_EL(B, maxi, maxi);
1293  double A1 = MATD_EL(B, maxi, maxj);
1294  double A2 = MATD_EL(B, maxj, maxi);
1295  double A3 = MATD_EL(B, maxj, maxj);
1296 
1297  if (1) {
1298  double AQ[4];
1299  AQ[0] = A0;
1300  AQ[1] = A1;
1301  AQ[2] = A2;
1302  AQ[3] = A3;
1303 
1304  double U[4], S[2], V[4];
1305  svd22(AQ, U, S, V);
1306 
1307 /* Reference (slow) implementation...
1308 
1309  // LS = LS * ROT(theta) = LS * QL
1310  matd_t *QL = matd_identity(A->nrows);
1311  MATD_EL(QL, maxi, maxi) = U[0];
1312  MATD_EL(QL, maxi, maxj) = U[1];
1313  MATD_EL(QL, maxj, maxi) = U[2];
1314  MATD_EL(QL, maxj, maxj) = U[3];
1315 
1316  matd_t *QR = matd_identity(A->ncols);
1317  MATD_EL(QR, maxi, maxi) = V[0];
1318  MATD_EL(QR, maxi, maxj) = V[1];
1319  MATD_EL(QR, maxj, maxi) = V[2];
1320  MATD_EL(QR, maxj, maxj) = V[3];
1321 
1322  LS = matd_op("F*M", LS, QL);
1323  RS = matd_op("F*M", RS, QR); // remember we'll transpose RS.
1324  B = matd_op("M'*F*M", QL, B, QR);
1325 
1326  matd_destroy(QL);
1327  matd_destroy(QR);
1328 */
1329 
1330  // LS = matd_op("F*M", LS, QL);
1331  for (int i = 0; i < LS->nrows; i++) {
1332  double vi = MATD_EL(LS, i, maxi);
1333  double vj = MATD_EL(LS, i, maxj);
1334 
1335  MATD_EL(LS, i, maxi) = U[0]*vi + U[2]*vj;
1336  MATD_EL(LS, i, maxj) = U[1]*vi + U[3]*vj;
1337  }
1338 
1339  // RS = matd_op("F*M", RS, QR); // remember we'll transpose RS.
1340  for (int i = 0; i < RS->nrows; i++) {
1341  double vi = MATD_EL(RS, i, maxi);
1342  double vj = MATD_EL(RS, i, maxj);
1343 
1344  MATD_EL(RS, i, maxi) = V[0]*vi + V[2]*vj;
1345  MATD_EL(RS, i, maxj) = V[1]*vi + V[3]*vj;
1346  }
1347 
1348  // B = matd_op("M'*F*M", QL, B, QR);
1349  // The QL matrix mixes rows of B.
1350  for (int i = 0; i < B->ncols; i++) {
1351  double vi = MATD_EL(B, maxi, i);
1352  double vj = MATD_EL(B, maxj, i);
1353 
1354  MATD_EL(B, maxi, i) = U[0]*vi + U[2]*vj;
1355  MATD_EL(B, maxj, i) = U[1]*vi + U[3]*vj;
1356  }
1357 
1358  // The QR matrix mixes columns of B.
1359  for (int i = 0; i < B->nrows; i++) {
1360  double vi = MATD_EL(B, i, maxi);
1361  double vj = MATD_EL(B, i, maxj);
1362 
1363  MATD_EL(B, i, maxi) = V[0]*vi + V[2]*vj;
1364  MATD_EL(B, i, maxj) = V[1]*vi + V[3]*vj;
1365  }
1366  }
1367  }
1368 
1369  if (!(flags & MATD_SVD_NO_WARNINGS) && iter == maxiters) {
1370  printf("WARNING: maximum iters (maximum = %d, matrix %d x %d, max=%.15f)\n",
1371  iter, A->nrows, A->ncols, maxv);
1372 
1373 // matd_print(A, "%15f");
1374  }
1375 
1376  // them all positive by flipping the corresponding columns of
1377  // U/LS.
1378  int idxs[A->ncols];
1379  double vals[A->ncols];
1380  for (int i = 0; i < A->ncols; i++) {
1381  idxs[i] = i;
1382  vals[i] = MATD_EL(B, i, i);
1383  }
1384 
1385  // A bubble sort. Seriously.
1386  int changed;
1387  do {
1388  changed = 0;
1389 
1390  for (int i = 0; i + 1 < A->ncols; i++) {
1391  if (fabs(vals[i+1]) > fabs(vals[i])) {
1392  int tmpi = idxs[i];
1393  idxs[i] = idxs[i+1];
1394  idxs[i+1] = tmpi;
1395 
1396  double tmpv = vals[i];
1397  vals[i] = vals[i+1];
1398  vals[i+1] = tmpv;
1399 
1400  changed = 1;
1401  }
1402  }
1403  } while (changed);
1404 
1405  matd_t *LP = matd_identity(A->nrows);
1406  matd_t *RP = matd_identity(A->ncols);
1407 
1408  for (int i = 0; i < A->ncols; i++) {
1409  MATD_EL(LP, idxs[i], idxs[i]) = 0; // undo the identity above
1410  MATD_EL(RP, idxs[i], idxs[i]) = 0;
1411 
1412  MATD_EL(LP, idxs[i], i) = vals[i] < 0 ? -1 : 1;
1413  MATD_EL(RP, idxs[i], i) = 1; //vals[i] < 0 ? -1 : 1;
1414  }
1415 
1416  // we've factored:
1417  // LP*(something)*RP'
1418 
1419  // solve for (something)
1420  B = matd_op("M'*F*M", LP, B, RP);
1421 
1422  // update LS and RS, remembering that RS will be transposed.
1423  LS = matd_op("F*M", LS, LP);
1424  RS = matd_op("F*M", RS, RP);
1425 
1426  matd_destroy(LP);
1427  matd_destroy(RP);
1428 
1429  matd_svd_t res;
1430  memset(&res, 0, sizeof(res));
1431 
1432  // make B exactly diagonal
1433 
1434  for (int i = 0; i < B->nrows; i++) {
1435  for (int j = 0; j < B->ncols; j++) {
1436  if (i != j)
1437  MATD_EL(B, i, j) = 0;
1438  }
1439  }
1440 
1441  res.U = LS;
1442  res.S = B;
1443  res.V = RS;
1444 
1445  return res;
1446 }
1447 
1449 {
1450  return matd_svd_flags(A, 0);
1451 }
1452 
1454 {
1455  matd_svd_t res;
1456 
1457  if (A->ncols <= A->nrows) {
1458  res = matd_svd_tall(A, flags);
1459  } else {
1460  matd_t *At = matd_transpose(A);
1461 
1462  // A =U S V'
1463  // A'=V S' U'
1464 
1465  matd_svd_t tmp = matd_svd_tall(At, flags);
1466 
1467  memset(&res, 0, sizeof(res));
1468  res.U = tmp.V; //matd_transpose(tmp.V);
1469  res.S = matd_transpose(tmp.S);
1470  res.V = tmp.U; //matd_transpose(tmp.U);
1471 
1472  matd_destroy(tmp.S);
1473  matd_destroy(At);
1474  }
1475 
1476 /*
1477  matd_t *check = matd_op("M*M*M'-M", res.U, res.S, res.V, A);
1478  double maxerr = 0;
1479 
1480  for (int i = 0; i < check->nrows; i++)
1481  for (int j = 0; j < check->ncols; j++)
1482  maxerr = fmax(maxerr, fabs(MATD_EL(check, i, j)));
1483 
1484  matd_destroy(check);
1485 
1486  if (maxerr > 1e-7) {
1487  printf("bad maxerr: %15f\n", maxerr);
1488  }
1489 
1490  if (maxerr > 1e-5) {
1491  printf("bad maxerr: %15f\n", maxerr);
1492  matd_print(A, "%15f");
1493  assert(0);
1494  }
1495 
1496 */
1497  return res;
1498 }
1499 
1500 
1502 {
1503  unsigned int *piv = calloc(a->nrows, sizeof(unsigned int));
1504  int pivsign = 1;
1505  matd_t *lu = matd_copy(a);
1506 
1507  // only for square matrices.
1508  assert(a->nrows == a->ncols);
1509 
1510  matd_plu_t *mlu = calloc(1, sizeof(matd_plu_t));
1511 
1512  for (int i = 0; i < a->nrows; i++)
1513  piv[i] = i;
1514 
1515  for (int j = 0; j < a->ncols; j++) {
1516  for (int i = 0; i < a->nrows; i++) {
1517  int kmax = i < j ? i : j; // min(i,j)
1518 
1519  // compute dot product of row i with column j (up through element kmax)
1520  double acc = 0;
1521  for (int k = 0; k < kmax; k++)
1522  acc += MATD_EL(lu, i, k) * MATD_EL(lu, k, j);
1523 
1524  MATD_EL(lu, i, j) -= acc;
1525  }
1526 
1527  // find pivot and exchange if necessary.
1528  int p = j;
1529  if (1) {
1530  for (int i = j+1; i < lu->nrows; i++) {
1531  if (fabs(MATD_EL(lu,i,j)) > fabs(MATD_EL(lu, p, j))) {
1532  p = i;
1533  }
1534  }
1535  }
1536 
1537  // swap rows p and j?
1538  if (p != j) {
1539  TYPE tmp[lu->ncols];
1540  memcpy(tmp, &MATD_EL(lu, p, 0), sizeof(TYPE) * lu->ncols);
1541  memcpy(&MATD_EL(lu, p, 0), &MATD_EL(lu, j, 0), sizeof(TYPE) * lu->ncols);
1542  memcpy(&MATD_EL(lu, j, 0), tmp, sizeof(TYPE) * lu->ncols);
1543  int k = piv[p];
1544  piv[p] = piv[j];
1545  piv[j] = k;
1546  pivsign = -pivsign;
1547  }
1548 
1549  double LUjj = MATD_EL(lu, j, j);
1550 
1551  // If our pivot is very small (which means the matrix is
1552  // singular or nearly singular), replace with a new pivot of the
1553  // right sign.
1554  if (fabs(LUjj) < MATD_EPS) {
1555 /*
1556  if (LUjj < 0)
1557  LUjj = -MATD_EPS;
1558  else
1559  LUjj = MATD_EPS;
1560 
1561  MATD_EL(lu, j, j) = LUjj;
1562 */
1563  mlu->singular = 1;
1564  }
1565 
1566  if (j < lu->ncols && j < lu->nrows && LUjj != 0) {
1567  LUjj = 1.0 / LUjj;
1568  for (int i = j+1; i < lu->nrows; i++)
1569  MATD_EL(lu, i, j) *= LUjj;
1570  }
1571  }
1572 
1573  mlu->lu = lu;
1574  mlu->piv = piv;
1575  mlu->pivsign = pivsign;
1576 
1577  return mlu;
1578 }
1579 
1581 {
1582  matd_destroy(mlu->lu);
1583  free(mlu->piv);
1584  memset(mlu, 0, sizeof(matd_plu_t));
1585  free(mlu);
1586 }
1587 
1588 double matd_plu_det(const matd_plu_t *mlu)
1589 {
1590  matd_t *lu = mlu->lu;
1591  double det = mlu->pivsign;
1592 
1593  if (lu->nrows == lu->ncols) {
1594  for (int i = 0; i < lu->ncols; i++)
1595  det *= MATD_EL(lu, i, i);
1596  }
1597 
1598  return det;
1599 }
1600 
1602 {
1603  matd_t *lu = mlu->lu;
1604  matd_t *P = matd_create(lu->nrows, lu->nrows);
1605 
1606  for (int i = 0; i < lu->nrows; i++) {
1607  MATD_EL(P, mlu->piv[i], i) = 1;
1608  }
1609 
1610  return P;
1611 }
1612 
1614 {
1615  matd_t *lu = mlu->lu;
1616 
1617  matd_t *L = matd_create(lu->nrows, lu->ncols);
1618  for (int i = 0; i < lu->nrows; i++) {
1619  MATD_EL(L, i, i) = 1;
1620 
1621  for (int j = 0; j < i; j++) {
1622  MATD_EL(L, i, j) = MATD_EL(lu, i, j);
1623  }
1624  }
1625 
1626  return L;
1627 }
1628 
1630 {
1631  matd_t *lu = mlu->lu;
1632 
1633  matd_t *U = matd_create(lu->ncols, lu->ncols);
1634  for (int i = 0; i < lu->ncols; i++) {
1635  for (int j = 0; j < lu->ncols; j++) {
1636  if (i <= j)
1637  MATD_EL(U, i, j) = MATD_EL(lu, i, j);
1638  }
1639  }
1640 
1641  return U;
1642 }
1643 
1644 // PLU = A
1645 // Ax = B
1646 // PLUx = B
1647 // LUx = P'B
1648 matd_t *matd_plu_solve(const matd_plu_t *mlu, const matd_t *b)
1649 {
1650  matd_t *x = matd_copy(b);
1651 
1652  // permute right hand side
1653  for (int i = 0; i < mlu->lu->nrows; i++)
1654  memcpy(&MATD_EL(x, i, 0), &MATD_EL(b, mlu->piv[i], 0), sizeof(TYPE) * b->ncols);
1655 
1656  // solve Ly = b
1657  for (int k = 0; k < mlu->lu->nrows; k++) {
1658  for (int i = k+1; i < mlu->lu->nrows; i++) {
1659  double LUik = -MATD_EL(mlu->lu, i, k);
1660  for (int t = 0; t < b->ncols; t++)
1661  MATD_EL(x, i, t) += MATD_EL(x, k, t) * LUik;
1662  }
1663  }
1664 
1665  // solve Ux = y
1666  for (int k = mlu->lu->ncols-1; k >= 0; k--) {
1667  double LUkk = 1.0 / MATD_EL(mlu->lu, k, k);
1668  for (int t = 0; t < b->ncols; t++)
1669  MATD_EL(x, k, t) *= LUkk;
1670 
1671  for (int i = 0; i < k; i++) {
1672  double LUik = -MATD_EL(mlu->lu, i, k);
1673  for (int t = 0; t < b->ncols; t++)
1674  MATD_EL(x, i, t) += MATD_EL(x, k, t) *LUik;
1675  }
1676  }
1677 
1678  return x;
1679 }
1680 
1682 {
1683  matd_plu_t *mlu = matd_plu(A);
1684  matd_t *x = matd_plu_solve(mlu, b);
1685 
1686  matd_plu_destroy(mlu);
1687  return x;
1688 }
1689 
1690 #if 0
1691 
1692 static int randi()
1693 {
1694  int v = random()&31;
1695  v -= 15;
1696  return v;
1697 }
1698 
1699 static double randf()
1700 {
1701  double v = 1.0 *random() / RAND_MAX;
1702  return 2*v - 1;
1703 }
1704 
1705 int main(int argc, char *argv[])
1706 {
1707  if (1) {
1708  int maxdim = 16;
1709  matd_t *A = matd_create(maxdim, maxdim);
1710 
1711  for (int iter = 0; 1; iter++) {
1712  srand(iter);
1713 
1714  if (iter % 1000 == 0)
1715  printf("%d\n", iter);
1716 
1717  int m = 1 + (random()%(maxdim-1));
1718  int n = 1 + (random()%(maxdim-1));
1719 
1720  for (int i = 0; i < m*n; i++)
1721  A->data[i] = randi();
1722 
1723  A->nrows = m;
1724  A->ncols = n;
1725 
1726 // printf("%d %d ", m, n);
1727  matd_svd_t svd = matd_svd(A);
1728  matd_destroy(svd.U);
1729  matd_destroy(svd.S);
1730  matd_destroy(svd.V);
1731 
1732  }
1733 
1734 /* matd_t *A = matd_create_data(2, 5, (double[]) { 1, 5, 2, 6,
1735  3, 3, 0, 7,
1736  1, 1, 0, -2,
1737  4, 0, 9, 9, 2, 6, 1, 3, 2, 5, 5, 4, -1, 2, 5, 9, 8, 2 });
1738 
1739  matd_svd(A);
1740 */
1741  return 0;
1742  }
1743 
1744 
1745  struct svd22 s;
1746 
1747  srand(0);
1748 
1749  matd_t *A = matd_create(2, 2);
1750  MATD_EL(A,0,0) = 4;
1751  MATD_EL(A,0,1) = 7;
1752  MATD_EL(A,1,0) = 2;
1753  MATD_EL(A,1,1) = 6;
1754 
1755  matd_t *U = matd_create(2, 2);
1756  matd_t *V = matd_create(2, 2);
1757  matd_t *S = matd_create(2, 2);
1758 
1759  for (int iter = 0; 1; iter++) {
1760  if (iter % 100000 == 0)
1761  printf("%d\n", iter);
1762 
1763  MATD_EL(A,0,0) = randf();
1764  MATD_EL(A,0,1) = randf();
1765  MATD_EL(A,1,0) = randf();
1766  MATD_EL(A,1,1) = randf();
1767 
1768  matd_svd22_impl(A->data, &s);
1769 
1770  memcpy(U->data, s.U, 4*sizeof(double));
1771  memcpy(V->data, s.V, 4*sizeof(double));
1772  MATD_EL(S,0,0) = s.S[0];
1773  MATD_EL(S,1,1) = s.S[1];
1774 
1775  assert(s.S[0] >= s.S[1]);
1776  assert(s.S[0] >= 0);
1777  assert(s.S[1] >= 0);
1778  if (s.S[0] == 0) {
1779 // printf("*"); fflush(NULL);
1780 // printf("%15f %15f %15f %15f\n", MATD_EL(A,0,0), MATD_EL(A,0,1), MATD_EL(A,1,0), MATD_EL(A,1,1));
1781  }
1782  if (s.S[1] == 0) {
1783 // printf("#"); fflush(NULL);
1784  }
1785 
1786  matd_t *USV = matd_op("M*M*M'", U, S, V);
1787 
1788  double maxerr = 0;
1789  for (int i = 0; i < 4; i++)
1790  maxerr = fmax(maxerr, fabs(USV->data[i] - A->data[i]));
1791 
1792  if (0) {
1793  printf("------------------------------------\n");
1794  printf("A:\n");
1795  matd_print(A, "%15f");
1796  printf("\nUSV':\n");
1797  matd_print(USV, "%15f");
1798  printf("maxerr: %.15f\n", maxerr);
1799  printf("\n\n");
1800  }
1801 
1802  matd_destroy(USV);
1803 
1804  assert(maxerr < 0.00001);
1805  }
1806 }
1807 
1808 #endif
1809 
1810 // XXX NGV Cholesky
1811 /*static double *matd_cholesky_raw(double *A, int n)
1812  {
1813  double *L = (double*)calloc(n * n, sizeof(double));
1814 
1815  for (int i = 0; i < n; i++) {
1816  for (int j = 0; j < (i+1); j++) {
1817  double s = 0;
1818  for (int k = 0; k < j; k++)
1819  s += L[i * n + k] * L[j * n + k];
1820  L[i * n + j] = (i == j) ?
1821  sqrt(A[i * n + i] - s) :
1822  (1.0 / L[j * n + j] * (A[i * n + j] - s));
1823  }
1824  }
1825 
1826  return L;
1827  }
1828 
1829  matd_t *matd_cholesky(const matd_t *A)
1830  {
1831  assert(A->nrows == A->ncols);
1832  double *L_data = matd_cholesky_raw(A->data, A->nrows);
1833  matd_t *L = matd_create_data(A->nrows, A->ncols, L_data);
1834  free(L_data);
1835  return L;
1836  }*/
1837 
1838 // NOTE: The below implementation of Cholesky is different from the one
1839 // used in NGV.
1841 {
1842  assert(A->nrows == A->ncols);
1843  int N = A->nrows;
1844 
1845  // make upper right
1846  matd_t *U = matd_copy(A);
1847 
1848  // don't actually need to clear lower-left... we won't touch it.
1849 /* for (int i = 0; i < U->nrows; i++) {
1850  for (int j = 0; j < i; j++) {
1851 // assert(MATD_EL(U, i, j) == MATD_EL(U, j, i));
1852 MATD_EL(U, i, j) = 0;
1853 }
1854 }
1855 */
1856  int is_spd = 1; // (A->nrows == A->ncols);
1857 
1858  for (int i = 0; i < N; i++) {
1859  double d = MATD_EL(U, i, i);
1860  is_spd &= (d > 0);
1861 
1862  if (d < MATD_EPS)
1863  d = MATD_EPS;
1864  d = 1.0 / sqrt(d);
1865 
1866  for (int j = i; j < N; j++)
1867  MATD_EL(U, i, j) *= d;
1868 
1869  for (int j = i+1; j < N; j++) {
1870  double s = MATD_EL(U, i, j);
1871 
1872  if (s == 0)
1873  continue;
1874 
1875  for (int k = j; k < N; k++) {
1876  MATD_EL(U, j, k) -= MATD_EL(U, i, k)*s;
1877  }
1878  }
1879  }
1880 
1881  matd_chol_t *chol = calloc(1, sizeof(matd_chol_t));
1882  chol->is_spd = is_spd;
1883  chol->u = U;
1884  return chol;
1885 }
1886 
1888 {
1889  matd_destroy(chol->u);
1890  free(chol);
1891 }
1892 
1893 // Solve: (U')x = b, U is upper triangular
1895 {
1896  int n = u->ncols;
1897  memcpy(x, b, n*sizeof(TYPE));
1898  for (int i = 0; i < n; i++) {
1899  x[i] /= MATD_EL(u, i, i);
1900 
1901  for (int j = i+1; j < u->ncols; j++) {
1902  x[j] -= x[i] * MATD_EL(u, i, j);
1903  }
1904  }
1905 }
1906 
1907 // Solve: Lx = b, L is lower triangular
1908 void matd_ltriangle_solve(matd_t *L, const TYPE *b, TYPE *x)
1909 {
1910  int n = L->ncols;
1911 
1912  for (int i = 0; i < n; i++) {
1913  double acc = b[i];
1914 
1915  for (int j = 0; j < i; j++) {
1916  acc -= MATD_EL(L, i, j)*x[j];
1917  }
1918 
1919  x[i] = acc / MATD_EL(L, i, i);
1920  }
1921 }
1922 
1923 // solve Ux = b, U is upper triangular
1924 void matd_utriangle_solve(matd_t *u, const TYPE *b, TYPE *x)
1925 {
1926  for (int i = u->ncols-1; i >= 0; i--) {
1927  double bi = b[i];
1928 
1929  double diag = MATD_EL(u, i, i);
1930 
1931  for (int j = i+1; j < u->ncols; j++)
1932  bi -= MATD_EL(u, i, j)*x[j];
1933 
1934  x[i] = bi / diag;
1935  }
1936 }
1937 
1938 matd_t *matd_chol_solve(const matd_chol_t *chol, const matd_t *b)
1939 {
1940  matd_t *u = chol->u;
1941 
1942  matd_t *x = matd_copy(b);
1943 
1944  // LUx = b
1945 
1946  // solve Ly = b ==> (U')y = b
1947 
1948  for (int i = 0; i < u->nrows; i++) {
1949  for (int j = 0; j < i; j++) {
1950  // b[i] -= L[i,j]*x[j]... replicated across columns of b
1951  // ==> i.e., ==>
1952  // b[i,k] -= L[i,j]*x[j,k]
1953  for (int k = 0; k < b->ncols; k++) {
1954  MATD_EL(x, i, k) -= MATD_EL(u, j, i)*MATD_EL(x, j, k);
1955  }
1956  }
1957  // x[i] = b[i] / L[i,i]
1958  for (int k = 0; k < b->ncols; k++) {
1959  MATD_EL(x, i, k) /= MATD_EL(u, i, i);
1960  }
1961  }
1962 
1963  // solve Ux = y
1964  for (int k = u->ncols-1; k >= 0; k--) {
1965  double LUkk = 1.0 / MATD_EL(u, k, k);
1966  for (int t = 0; t < b->ncols; t++)
1967  MATD_EL(x, k, t) *= LUkk;
1968 
1969  for (int i = 0; i < k; i++) {
1970  double LUik = -MATD_EL(u, i, k);
1971  for (int t = 0; t < b->ncols; t++)
1972  MATD_EL(x, i, t) += MATD_EL(x, k, t) *LUik;
1973  }
1974  }
1975 
1976  return x;
1977 }
1978 
1979 /*void matd_chol_solve(matd_chol_t *chol, const TYPE *b, TYPE *x)
1980  {
1981  matd_t *u = chol->u;
1982 
1983  TYPE y[u->ncols];
1984  matd_ltransposetriangle_solve(u, b, y);
1985  matd_utriangle_solve(u, y, x);
1986  }
1987 */
1988 // only sensible on PSD matrices. had expected it to be faster than
1989 // inverse via LU... for now, doesn't seem to be.
1991 {
1992  assert(a->nrows == a->ncols);
1993 
1994  matd_chol_t *chol = matd_chol(a);
1995 
1996  matd_t *eye = matd_identity(a->nrows);
1997  matd_t *inv = matd_chol_solve(chol, eye);
1998  matd_destroy(eye);
1999  matd_chol_destroy(chol);
2000 
2001  return inv;
2002 }
2003 
2004 double matd_max(matd_t *m)
2005 {
2006  double d = -DBL_MAX;
2007  for(int x=0; x<m->nrows; x++) {
2008  for(int y=0; y<m->ncols; y++) {
2009  if(MATD_EL(m, x, y) > d)
2010  d = MATD_EL(m, x, y);
2011  }
2012  }
2013 
2014  return d;
2015 }
matd_svd_t matd_svd_flags(matd_t *A, int flags)
Definition: matd.c:1453
matd_t * matd_plu_l(const matd_plu_t *mlu)
Definition: matd.c:1613
matd_plu_t * matd_plu(const matd_t *a)
Definition: matd.c:1501
double matd_det(const matd_t *a)
Definition: matd.c:425
matd_t * matd_select(const matd_t *a, int r0, int r1, int c0, int c1)
Definition: matd.c:171
#define MATD_SVD_NO_WARNINGS
Definition: matd.h:383
int is_spd
Definition: matd.h:433
double matd_vec_dist_n(const matd_t *a, const matd_t *b, int n)
Definition: matd.c:870
double data[]
Definition: matd.h:54
void matd_chol_destroy(matd_chol_t *chol)
Definition: matd.c:1887
void matd_utriangle_solve(matd_t *u, const TYPE *b, TYPE *x)
Definition: matd.c:1924
TYPE matd_get_scalar(const matd_t *m)
Definition: matd.c:142
matd_t * matd_add(const matd_t *a, const matd_t *b)
Definition: matd.c:295
unsigned int nrows
Definition: matd.h:53
void matd_ltriangle_solve(matd_t *L, const TYPE *b, TYPE *x)
Definition: matd.c:1908
matd_t * matd_chol_solve(const matd_chol_t *chol, const matd_t *b)
Definition: matd.c:1938
matd_t * matd_create_scalar(TYPE v)
Definition: matd.c:65
void matd_put_scalar(matd_t *m, TYPE value)
Definition: matd.c:150
int singular
Definition: matd.h:398
unsigned int ncols
Definition: matd.h:53
#define MATD_EL(m, row, col)
Definition: matd.h:71
matd_svd_t matd_svd(matd_t *A)
Definition: matd.c:1448
matd_t * u
Definition: matd.h:434
void matd_add_inplace(matd_t *a, const matd_t *b)
Definition: matd.c:316
matd_chol_t * matd_chol(matd_t *A)
Definition: matd.c:1840
TYPE matd_get(const matd_t *m, int row, int col)
Definition: matd.c:112
matd_t * matd_transpose(const matd_t *a)
Definition: matd.c:377
static int matd_is_scalar(const matd_t *a)
Definition: matd.h:256
matd_t * S
Definition: matd.h:366
#define TYPE
Definition: matd.c:48
matd_t * matd_vec_normalize(const matd_t *a)
Definition: matd.c:923
unsigned int * piv
Definition: matd.h:400
matd_t * matd_solve(matd_t *A, matd_t *b)
Definition: matd.c:1681
static double sq(double v)
Definition: math_util.h:84
double matd_max(matd_t *m)
Definition: matd.c:2004
static int max_idx(const matd_t *A, int row, int maxcol)
Definition: matd.c:888
int pivsign
Definition: matd.h:401
matd_t * matd_create_data(int rows, int cols, const TYPE *data)
Definition: matd.c:75
static int matd_is_vector(const matd_t *a)
Definition: matd.h:267
static matd_t * matd_op_recurse(const char *expr, int *pos, matd_t *acc, matd_t **args, int *argpos, matd_t **garb, int *garbpos, int oneterm)
Definition: matd.c:598
static float randf()
Definition: math_util.h:95
static double matd_det_general(const matd_t *a)
Definition: matd.c:395
static matd_t * matd_op_gobble_right(const char *expr, int *pos, matd_t *acc, matd_t **garb, int *garbpos)
Definition: matd.c:556
matd_t * matd_plu_u(const matd_plu_t *mlu)
Definition: matd.c:1629
void matd_scale_inplace(matd_t *a, double s)
Definition: matd.c:279
matd_t * lu
Definition: matd.h:407
matd_t * U
Definition: matd.h:365
matd_t * matd_scale(const matd_t *a, double s)
Definition: matd.c:261
void matd_print_transpose(const matd_t *m, const char *fmt)
Definition: matd.c:208
matd_t * matd_create_dataf(int rows, int cols, const float *data)
Definition: matd.c:87
Definition: matd.h:51
void matd_destroy(matd_t *m)
Definition: matd.c:226
matd_t * matd_identity(int dim)
Definition: matd.c:99
void matd_subtract_inplace(matd_t *a, const matd_t *b)
Definition: matd.c:357
void matd_print(const matd_t *m, const char *fmt)
Definition: matd.c:190
matd_t * matd_subtract(const matd_t *a, const matd_t *b)
Definition: matd.c:336
matd_t * matd_create(int rows, int cols)
Definition: matd.c:50
matd_t * matd_plu_solve(const matd_plu_t *mlu, const matd_t *b)
Definition: matd.c:1648
matd_t * matd_inverse(const matd_t *x)
Definition: matd.c:485
matd_t * V
Definition: matd.h:367
void matd_put(matd_t *m, int row, int col, TYPE value)
Definition: matd.c:125
matd_t * matd_plu_p(const matd_plu_t *mlu)
Definition: matd.c:1601
double matd_vec_dist(const matd_t *a, const matd_t *b)
Definition: matd.c:859
double matd_vec_dot_product(const matd_t *a, const matd_t *b)
Definition: matd.c:906
#define MATD_EPS
Definition: matd.h:65
matd_t * matd_copy(const matd_t *m)
Definition: matd.c:158
matd_t * matd_op(const char *expr,...)
Definition: matd.c:798
void matd_ltransposetriangle_solve(matd_t *u, const TYPE *b, TYPE *x)
Definition: matd.c:1894
static matd_svd_t matd_svd_tall(matd_t *A, int flags)
Definition: matd.c:980
matd_t * matd_multiply(const matd_t *a, const matd_t *b)
Definition: matd.c:235
void matd_plu_destroy(matd_plu_t *mlu)
Definition: matd.c:1580
double matd_plu_det(const matd_plu_t *mlu)
Definition: matd.c:1588
matd_t * matd_crossproduct(const matd_t *a, const matd_t *b)
Definition: matd.c:940
double matd_vec_mag(const matd_t *a)
Definition: matd.c:847
static int matd_is_vector_len(const matd_t *a, int len)
Definition: matd.h:277
matd_t * matd_chol_inverse(matd_t *a)
Definition: matd.c:1990
void svd22(const double A[4], double U[4], double S[2], double V[4])
Definition: svd22.c:98
TYPE matd_err_inf(const matd_t *a, const matd_t *b)
Definition: matd.c:955


apriltags2
Author(s): Danylo Malyuta
autogenerated on Fri Oct 19 2018 04:02:32