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


apriltag
Author(s): Edwin Olson , Max Krogius
autogenerated on Sun Apr 20 2025 02:08:19