linear_algebra.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2012 Swift Navigation Inc.
00003  * Contact: Matt Peddie <peddie@alum.mit.edu>
00004  *
00005  * This source is subject to the license found in the file 'LICENSE' which must
00006  * be be distributed together with this source. All other rights reserved.
00007  *
00008  * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
00009  * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
00010  * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
00011  */
00012 
00013 #include <math.h>
00014 #include <string.h>
00015 #include <stdio.h>
00016 
00017 #include "common.h"
00018 
00019 #include "linear_algebra.h"
00020 
00021 
00022 /* Todo(MP) -- Implement fast linear solve (all-in-one) with Cholesky
00023  * decomposition: we want to solve $A^{T} W A \hat{x} = A^{T} W y
00024  *
00025  * This should be implemented below the functions that explicitly
00026  * calculate the pseudoinverse: we have a function that computes the
00027  * Cholesky decomposition, a function that performs back-substitution
00028  * for the linear solve and then a whole slew of interface functions
00029  * for least-squares and least-norm solves.  Separate functions are
00030  * required for testing against; a separate "fast" weighted linear
00031  * least-squares operation should perform all operations in one
00032  * function (lazily or orderedly accessing elements from A and W to
00033  * form A W A^T as we go).
00034  */
00035 
00053 #define MATRIX_EPSILON (1e-60)
00054 
00055 
00056 
00057 void dmtx_printf(double *mtx, u32 m, u32 n)
00058 {
00059   for (u32 i = 0; i < m; i++) {
00060     printf(" [% 12lf", mtx[i*n + 0]);
00061     for (u32 j = 1; j < n; j++)
00062       printf(" % 12lf", mtx[i*n + j]);
00063     printf("]\n");
00064   }
00065 }
00066 
00067 
00068 /* \} */
00069 
00097 s32 qrdecomp(const double *a, u32 rows, u32 cols, double *qt, double *r) {
00098   s32 sing = 0;
00099   u32 i, j, k;
00100 
00101   double c[cols], d[cols];
00102   double scale, sigma, sum, tau;
00103   /* r := a */
00104   memcpy(r, a, rows*cols * sizeof(*r));
00105 
00106   for (k = 0; k < cols; k++) {
00107     if (k > cols-1) printf("%d: k (%u) > cols - 1 (%u)\n",
00108                            __LINE__, (unsigned int) k, (unsigned int) cols - 1);
00109     /* This is column k of the input matrix */
00110     scale = 0.0;
00111     /* loop over this column and make sure it's not all zeros*/
00112     for (i = k; i < rows; i++) scale = fmax(scale, fabs(r[i*cols + k]));
00113     /* singularity check */
00114     if (fabs(scale) < MATRIX_EPSILON) {
00115       sing = -1;
00116       c[k] = d[k] = 0.0;
00117       printf("Column %u is singular to machine precision.\n", (unsigned int) k);
00118     } else {
00119       /* scale this column to 1 */
00120       for (i = k; i < rows; i++) r[i*cols + k] /= scale;
00121       /* compute norm-squared of this column */
00122       for (sum = 0.0, i = k; i < rows; i++) sum += r[i*cols + k]*r[i*cols + k];
00123       /* adjust the leading element: σ is the sign of the leading
00124        * (diagonal) element of the column times the norm of the
00125        * head-adjusted column */
00126       sigma = copysign(sqrt(sum), r[k*cols + k]);
00127       r[k*cols + k] += sigma;
00128       /* set c and d for this column */
00129       c[k] = sigma * r[k*cols + k];
00130       d[k] = -scale * sigma;
00131       printf("d[%u] = %lf\n", (unsigned int) k, d[k]);
00132       for (j = k + 1; j < cols; j++) {
00133         if (j > cols-1) printf("%d: j (%u) > cols - 1 (%u)\n",
00134                                __LINE__, (unsigned int) j,
00135                                (unsigned int) cols - 1);
00136         /* some crazy shit to update R in place I think; we never
00137          * explicitly form the householder matrices */
00138         for (sum = 0.0, i = k; i < rows; i++) sum += r[i*cols + k]*r[i*cols + j];
00139         tau = sum / c[k];
00140         for (i = k; i < rows; i++) r[i*cols + j] -= tau*r[i*cols + k];
00141       }
00142     }
00143   }
00144   VEC_PRINTF(d, cols);
00145   VEC_PRINTF(c, cols);
00146   MAT_PRINTF(r, rows, cols);
00147   /* set last element of d to the bottom right corner of the matrix */
00148   /* d[cols - 1] = r[(rows - 1)*cols + cols - 1]; */
00149   printf("bottom corner: r[%u] = d[%u] = %lf\n",
00150          (unsigned int) ((rows - 1)*cols + cols - 1),
00151          (unsigned int) (cols - 1), r[(rows - 1)*cols + cols - 1]);
00152   /* if that's zero too, then the whole bottom row is zero and this
00153    * problem is singular */
00154   if (fabs(d[cols - 1]) < MATRIX_EPSILON) sing = -1;
00155   /* set Q^T to identity */
00156   for (i = 0; i < rows; i++) {
00157     for (j = 0; j < rows; j++) qt[i*rows + j] = 0.0;
00158     qt[i*rows + i] = 1.0;
00159   }
00160   for (k = 0; k < cols; k++) {
00161     if (k > cols-1) printf("%d: k (%u) > cols - 1 (%u)\n",
00162                            __LINE__, (unsigned int) k, (unsigned int) cols - 1);
00163     /* for column k of the matrix */
00164     if (fabs(c[k]) > MATRIX_EPSILON)
00165       /* if there's anything going on in this column */
00166       for (j = 0; j < rows; j++) {
00167         /* matrix multiply in place or something to form qt */
00168         sum = 0.0;
00169         for (i = k; i < rows; i++) sum += r[i*cols + k]*qt[i*rows + j];
00170         sum /= c[k];
00171         for (i = k; i < rows; i++) qt[i*rows + j] -= sum*r[i*cols + k];
00172       }
00173     MAT_PRINTF(qt, rows, rows);
00174   }
00175   for (i = 0; i < cols; i++) {
00176     if (i > cols-1) printf("%d: i (%u) > cols - 1 (%u)\n",
00177                            __LINE__, (unsigned int) i, (unsigned int) cols - 1);
00178     /* set r diagonal to d */
00179     r[i*cols + i] = d[i];
00180     printf("r[%u] = d[%u] = %lf\n", (unsigned int) (i*cols + i),
00181            (unsigned int) i, r[i*cols+i]);
00182   }
00183   for (i = 0; i < rows; i++)
00184     /* set below-diagonal elements to zero */
00185     for (j = 0; j < i && j < cols; j++) {
00186       if (j > cols-1) printf("%d: j (%u) > cols - 1 (%u)\n",
00187                              __LINE__, (unsigned int) j,
00188                              (unsigned int) cols - 1);
00189 
00190       r[i*cols + j] = 0.0;
00191     }
00192   return sing;
00193 }
00194 
00195 
00196 /* static s32 qrdecomp_l(const double *a, u32 rows, */
00197 /*                       u32 cols, double *qt, double *r) { */
00198 /*   s32 sing = 0; */
00199 /*   u32 i, j, k; */
00200 
00201 /*   double scale, anorm, vnorm; */
00202 /*   double u[rows], Hk[rows*rows]; */
00203 
00204 /*   /\* R := A *\/ */
00205 /*   memcpy(r, a, rows*cols*sizeof(*r)); */
00206 /*   /\* Q := I *\/ */
00207 /*   for (i = 0; i < rows; i++) */
00208 /*     for (j = 0; j < rows; j++) { */
00209 /*       qt[i*rows + j] = (i == j); */
00210 /*       Hk[i*rows + j] = 0; */
00211 /*     } */
00212 
00213 /*   for (k = 0; k < rows - 1; k++) { */
00214 /*     /\* Column k of the input matrix *\/ */
00215 /*     scale = 0.0; */
00216 /*     anorm = 0.0; */
00217 /*     /\* compute a^T a *\/ */
00218 /*     for (i = k; i < rows; i++) anorm += a[i*cols + k]*a[i*cols+k]; */
00219 /*     anorm = sqrt(anorm); */
00220 /*     /\* compute u = a + sgn(a[k]) * ||a||_2 * [1 0 0 . . . ]^T *\/ */
00221 /*     u[k] = a[k*cols + k] + copysign(a[k*cols + k], anorm); */
00222 /*     /\* form v = u / u[0] *\/ */
00223 /*     for (i = k+1; i < rows; i++) u[i] = a[i*cols + k] / u[k]; */
00224 /*     u[k] = 1.0; */
00225 /*     vnorm = 0.0; */
00226 /*     /\* compute w = v^T v *\/ */
00227 /*     for (i = k; i < rows; i++) vnorm += u[i]*u[i]; */
00228 /*     for (i = k; i < rows; i++) */
00229 /*       /\* yes, rows is the limit because H is square *\/ */
00230 /*       for (j = k; j < rows; j++) */
00231 /*         /\* Hk = I - 2 / w * v * v^T *\/ */
00232 /*         Hk[i*cols + j] = (i == j) - (2 / vnorm)*u[i]*u[j]; */
00233 /*     /\* Accumulate onto R *\/ */
00234 /*   } */
00235 /*   return sing; */
00236 /* } */
00237 
00251 s32 qrdecomp_square(const double *a, u32 rows, double *qt, double *r) {
00252   s32 sing = 0;
00253   u32 i, j, k;
00254 
00255   double c[rows], d[rows];
00256   double scale, sigma, sum, tau;
00257   memcpy(r, a, rows*rows * sizeof(*r));
00258 
00259   for (k = 0; k < rows - 1; k++) {
00260     scale = 0.0;
00261     for (i = k; i < rows; i++) scale = fmax(scale, fabs(r[i*rows + k]));
00262     if (scale == 0.0) {
00263       sing = -11;
00264       c[k] = d[k] = 0.0;
00265     } else {
00266       for (i = k; i < rows; i++) r[i*rows + k] /= scale;
00267       for (sum = 0.0, i = k; i < rows; i++) sum += r[i*rows + k]*r[i*rows + k];
00268       sigma = copysign(sqrt(sum), r[k*rows+k]);
00269       r[k*rows + k] += sigma;
00270       c[k] = sigma * r[k*rows + k];
00271       d[k] = -scale * sigma;
00272       for (j = k + 1; j < rows; j++) {
00273         for (sum = 0.0, i = k; i < rows; i++) sum += r[i*rows + k]*r[i*rows+j];
00274         tau = sum / c[k];
00275         for (i = k; i < rows; i++) r[i*rows + j] -= tau*r[i*rows + k];
00276       }
00277     }
00278   }
00279   d[rows - 1] = r[(rows - 1)*rows + rows - 1];
00280   if (d[rows - 1] == 0.0) sing = -11;
00281   for (i = 0; i < rows; i++) {
00282     for (j = 0; j < rows; j++) qt[i*rows + j] = 0.0;
00283     qt[i*rows + i] = 1.0;
00284   }
00285   for (k = 0; k < rows - 1; k++) {
00286     if (c[k] != 0.0)
00287       for (j = 0; j < rows; j++) {
00288         sum = 0.0;
00289         for (i = k; i < rows; i++) sum += r[i*rows + k]*qt[i*rows + j];
00290         sum /= c[k];
00291         for (i = k; i < rows; i++) qt[i*rows + j] -= sum*r[i*rows + k];
00292       }
00293   }
00294   for (i = 0; i < rows; i++) {
00295     r[i*rows + i] = d[i];
00296     for (j = 0; j < i; j++) r[i*rows + j] = 0.0;
00297   }
00298   return sing;
00299 }
00300 
00311 void qtmult(const double *qt, u32 n, const double *b, double *x) {
00312   u32 i, j;
00313   double sum;
00314   for (i = 0; i < n; i++) {
00315     sum = 0.0;
00316     for (j = 0; j < n; j++) sum += qt[i*n + j]*b[j];
00317     x[i] = sum;
00318   }
00319 }
00320 
00335 void rsolve(const double *r, u32 rows, u32 cols, const double *b, double *x) {
00336   s32 i, j;
00337   double sum;
00338   for (i = rows - 1; i >= 0; i--) {
00339     sum = b[i];
00340     for (j = i + 1; j < (int) rows; j++) sum -= r[i*cols + j]*x[j];
00341     x[i] = sum / r[i*cols + i];
00342   }
00343 }
00344 
00359 s32 qrsolve(const double *a, u32 rows, u32 cols, const double *b, double *x) {
00360   double qt[rows * rows], r[rows * cols];
00361   s32 sing = qrdecomp_square(a, rows, qt, r);
00362   if (sing != 0) return sing;
00363   qtmult(qt, rows, b, x);
00364   rsolve(r, rows, cols, x, x);
00365   return sing;
00366 }
00367 
00368 
00369 
00378 static inline int inv2(const double *a, double *b) {
00379   double det = a[0]*a[3] - a[1]*a[2];
00380   if (fabs(det) < MATRIX_EPSILON)
00381     return -1;
00382   b[0] = a[3]/det;
00383   b[1] = -a[1]/det;
00384   b[2] = -a[2]/det;
00385   b[3] = a[0]/det;
00386   return 0;
00387 }
00388 
00397 static inline int inv3(const double *a, double *b) {
00398   double det = ((a[3*1 + 0]*-(a[3*0 + 1]*a[3*2 + 2]-a[3*0 + 2]*a[3*2 + 1])
00399                  +a[3*1 + 1]*(a[3*0 + 0]*a[3*2 + 2]-a[3*0 + 2]*a[3*2 + 0]))
00400                 +a[3*1 + 2]*-(a[3*0 + 0]*a[3*2 + 1]-a[3*0 + 1]*a[3*2 + 0]));
00401 
00402   if (fabs(det) < MATRIX_EPSILON)
00403     return -1;
00404 
00405   b[3*0 + 0] = (a[3*1 + 1]*a[3*2 + 2]-a[3*1 + 2]*a[3*2 + 1])/det;
00406   b[3*1 + 0] = -(a[3*1 + 0]*a[3*2 + 2]-a[3*1 + 2]*a[3*2 + 0])/det;
00407   b[3*2 + 0] = (a[3*1 + 0]*a[3*2 + 1]-a[3*1 + 1]*a[3*2 + 0])/det;
00408 
00409   b[3*0 + 1] = -(a[3*0 + 1]*a[3*2 + 2]-a[3*0 + 2]*a[3*2 + 1])/det;
00410   b[3*1 + 1] = (a[3*0 + 0]*a[3*2 + 2]-a[3*0 + 2]*a[3*2 + 0])/det;
00411   b[3*2 + 1] = -(a[3*0 + 0]*a[3*2 + 1]-a[3*0 + 1]*a[3*2 + 0])/det;
00412 
00413   b[3*0 + 2] = (a[3*0 + 1]*a[3*1 + 2]-a[3*0 + 2]*a[3*1 + 1])/det;
00414   b[3*1 + 2] = -(a[3*0 + 0]*a[3*1 + 2]-a[3*0 + 2]*a[3*1 + 0])/det;
00415   b[3*2 + 2] = (a[3*0 + 0]*a[3*1 + 1]-a[3*0 + 1]*a[3*1 + 0])/det;
00416 
00417   return 0;
00418 }
00419 
00428 static inline int inv4(const double *a, double *b) {
00429   double det = (((a[4*1 + 0]*-((a[4*2 + 1]*-(a[4*0 + 2]*a[4*3 + 3]-a[4*0 + 3]*a[4*3 + 2])+a[4*2 + 2]*(a[4*0 + 1]*a[4*3 + 3]-a[4*0 + 3]*a[4*3 + 1]))+a[4*2 + 3]*-(a[4*0 + 1]*a[4*3 + 2]-a[4*0 + 2]*a[4*3 + 1]))+a[4*1 + 1]*((a[4*2 + 0]*-(a[4*0 + 2]*a[4*3 + 3]-a[4*0 + 3]*a[4*3 + 2])+a[4*2 + 2]*(a[4*0 + 0]*a[4*3 + 3]-a[4*0 + 3]*a[4*3 + 0]))+a[4*2 + 3]*-(a[4*0 + 0]*a[4*3 + 2]-a[4*0 + 2]*a[4*3 + 0])))+a[4*1 + 2]*-((a[4*2 + 0]*-(a[4*0 + 1]*a[4*3 + 3]-a[4*0 + 3]*a[4*3 + 1])+a[4*2 + 1]*(a[4*0 + 0]*a[4*3 + 3]-a[4*0 + 3]*a[4*3 + 0]))+a[4*2 + 3]*-(a[4*0 + 0]*a[4*3 + 1]-a[4*0 + 1]*a[4*3 + 0])))+a[4*1 + 3]*((a[4*2 + 0]*-(a[4*0 + 1]*a[4*3 + 2]-a[4*0 + 2]*a[4*3 + 1])+a[4*2 + 1]*(a[4*0 + 0]*a[4*3 + 2]-a[4*0 + 2]*a[4*3 + 0]))+a[4*2 + 2]*-(a[4*0 + 0]*a[4*3 + 1]-a[4*0 + 1]*a[4*3 + 0])));
00430 
00431   if (fabs(det) < MATRIX_EPSILON)
00432     return -1;
00433 
00434   b[4*0 + 0] = ((a[4*2 + 1]*-(a[4*1 + 2]*a[4*3 + 3]-a[4*1 + 3]*a[4*3 + 2])+a[4*2 + 2]*(a[4*1 + 1]*a[4*3 + 3]-a[4*1 + 3]*a[4*3 + 1]))+a[4*2 + 3]*-(a[4*1 + 1]*a[4*3 + 2]-a[4*1 + 2]*a[4*3 + 1]))/det;
00435   b[4*1 + 0] = -((a[4*2 + 0]*-(a[4*1 + 2]*a[4*3 + 3]-a[4*1 + 3]*a[4*3 + 2])+a[4*2 + 2]*(a[4*1 + 0]*a[4*3 + 3]-a[4*1 + 3]*a[4*3 + 0]))+a[4*2 + 3]*-(a[4*1 + 0]*a[4*3 + 2]-a[4*1 + 2]*a[4*3 + 0]))/det;
00436   b[4*2 + 0] = ((a[4*2 + 0]*-(a[4*1 + 1]*a[4*3 + 3]-a[4*1 + 3]*a[4*3 + 1])+a[4*2 + 1]*(a[4*1 + 0]*a[4*3 + 3]-a[4*1 + 3]*a[4*3 + 0]))+a[4*2 + 3]*-(a[4*1 + 0]*a[4*3 + 1]-a[4*1 + 1]*a[4*3 + 0]))/det;
00437   b[4*3 + 0] = -((a[4*2 + 0]*-(a[4*1 + 1]*a[4*3 + 2]-a[4*1 + 2]*a[4*3 + 1])+a[4*2 + 1]*(a[4*1 + 0]*a[4*3 + 2]-a[4*1 + 2]*a[4*3 + 0]))+a[4*2 + 2]*-(a[4*1 + 0]*a[4*3 + 1]-a[4*1 + 1]*a[4*3 + 0]))/det;
00438 
00439   b[4*0 + 1] = -((a[4*2 + 1]*-(a[4*0 + 2]*a[4*3 + 3]-a[4*0 + 3]*a[4*3 + 2])+a[4*2 + 2]*(a[4*0 + 1]*a[4*3 + 3]-a[4*0 + 3]*a[4*3 + 1]))+a[4*2 + 3]*-(a[4*0 + 1]*a[4*3 + 2]-a[4*0 + 2]*a[4*3 + 1]))/det;
00440   b[4*1 + 1] = ((a[4*2 + 0]*-(a[4*0 + 2]*a[4*3 + 3]-a[4*0 + 3]*a[4*3 + 2])+a[4*2 + 2]*(a[4*0 + 0]*a[4*3 + 3]-a[4*0 + 3]*a[4*3 + 0]))+a[4*2 + 3]*-(a[4*0 + 0]*a[4*3 + 2]-a[4*0 + 2]*a[4*3 + 0]))/det;
00441   b[4*2 + 1] = -((a[4*2 + 0]*-(a[4*0 + 1]*a[4*3 + 3]-a[4*0 + 3]*a[4*3 + 1])+a[4*2 + 1]*(a[4*0 + 0]*a[4*3 + 3]-a[4*0 + 3]*a[4*3 + 0]))+a[4*2 + 3]*-(a[4*0 + 0]*a[4*3 + 1]-a[4*0 + 1]*a[4*3 + 0]))/det;
00442   b[4*3 + 1] = ((a[4*2 + 0]*-(a[4*0 + 1]*a[4*3 + 2]-a[4*0 + 2]*a[4*3 + 1])+a[4*2 + 1]*(a[4*0 + 0]*a[4*3 + 2]-a[4*0 + 2]*a[4*3 + 0]))+a[4*2 + 2]*-(a[4*0 + 0]*a[4*3 + 1]-a[4*0 + 1]*a[4*3 + 0]))/det;
00443 
00444   b[4*0 + 2] = ((a[4*1 + 1]*-(a[4*0 + 2]*a[4*3 + 3]-a[4*0 + 3]*a[4*3 + 2])+a[4*1 + 2]*(a[4*0 + 1]*a[4*3 + 3]-a[4*0 + 3]*a[4*3 + 1]))+a[4*1 + 3]*-(a[4*0 + 1]*a[4*3 + 2]-a[4*0 + 2]*a[4*3 + 1]))/det;
00445   b[4*1 + 2] = -((a[4*1 + 0]*-(a[4*0 + 2]*a[4*3 + 3]-a[4*0 + 3]*a[4*3 + 2])+a[4*1 + 2]*(a[4*0 + 0]*a[4*3 + 3]-a[4*0 + 3]*a[4*3 + 0]))+a[4*1 + 3]*-(a[4*0 + 0]*a[4*3 + 2]-a[4*0 + 2]*a[4*3 + 0]))/det;
00446   b[4*2 + 2] = ((a[4*1 + 0]*-(a[4*0 + 1]*a[4*3 + 3]-a[4*0 + 3]*a[4*3 + 1])+a[4*1 + 1]*(a[4*0 + 0]*a[4*3 + 3]-a[4*0 + 3]*a[4*3 + 0]))+a[4*1 + 3]*-(a[4*0 + 0]*a[4*3 + 1]-a[4*0 + 1]*a[4*3 + 0]))/det;
00447   b[4*3 + 2] = -((a[4*1 + 0]*-(a[4*0 + 1]*a[4*3 + 2]-a[4*0 + 2]*a[4*3 + 1])+a[4*1 + 1]*(a[4*0 + 0]*a[4*3 + 2]-a[4*0 + 2]*a[4*3 + 0]))+a[4*1 + 2]*-(a[4*0 + 0]*a[4*3 + 1]-a[4*0 + 1]*a[4*3 + 0]))/det;
00448 
00449   b[4*0 + 3] = -((a[4*1 + 1]*-(a[4*0 + 2]*a[4*2 + 3]-a[4*0 + 3]*a[4*2 + 2])+a[4*1 + 2]*(a[4*0 + 1]*a[4*2 + 3]-a[4*0 + 3]*a[4*2 + 1]))+a[4*1 + 3]*-(a[4*0 + 1]*a[4*2 + 2]-a[4*0 + 2]*a[4*2 + 1]))/det;
00450   b[4*1 + 3] = ((a[4*1 + 0]*-(a[4*0 + 2]*a[4*2 + 3]-a[4*0 + 3]*a[4*2 + 2])+a[4*1 + 2]*(a[4*0 + 0]*a[4*2 + 3]-a[4*0 + 3]*a[4*2 + 0]))+a[4*1 + 3]*-(a[4*0 + 0]*a[4*2 + 2]-a[4*0 + 2]*a[4*2 + 0]))/det;
00451   b[4*2 + 3] = -((a[4*1 + 0]*-(a[4*0 + 1]*a[4*2 + 3]-a[4*0 + 3]*a[4*2 + 1])+a[4*1 + 1]*(a[4*0 + 0]*a[4*2 + 3]-a[4*0 + 3]*a[4*2 + 0]))+a[4*1 + 3]*-(a[4*0 + 0]*a[4*2 + 1]-a[4*0 + 1]*a[4*2 + 0]))/det;
00452   b[4*3 + 3] = ((a[4*1 + 0]*-(a[4*0 + 1]*a[4*2 + 2]-a[4*0 + 2]*a[4*2 + 1])+a[4*1 + 1]*(a[4*0 + 0]*a[4*2 + 2]-a[4*0 + 2]*a[4*2 + 0]))+a[4*1 + 2]*-(a[4*0 + 0]*a[4*2 + 1]-a[4*0 + 1]*a[4*2 + 0]))/det;
00453 
00454   return 0;
00455 }
00456 
00457 /* Apparently there is no C code online that simply inverts a general
00458  * matrix without having to include GSL or something.  Therefore, I
00459  * give you Gaussian Elimination for matrix inversion.  --MP */
00460 
00461 /* Helper function for rref */
00462 static void row_swap(double *a, double *b, u32 size) {
00463   double tmp;
00464   for (u32 i = 0; i < size; i++) {
00465     tmp = a[i];
00466     a[i] = b[i];
00467     b[i] = tmp;
00468   }
00469 }
00470 
00471 /* rref is "reduced row echelon form" -- a helper function for the
00472  * gaussian elimination code. */
00473 static int rref(u32 order, u32 cols, double *m) {
00474   int i, j, k, maxrow;
00475   double tmp;
00476 
00477   for (i = 0; i < (int) order; i++) {
00478     maxrow = i;
00479     for (j = i+1; j < (int) order; j++) {
00480       /* Find the maximum pivot */
00481       if (fabs(m[j*cols+i]) > fabs(m[maxrow*cols+i]))
00482         maxrow = j;
00483     }
00484     row_swap(&m[i*cols], &m[maxrow*cols], cols);
00485     if (fabs(m[i*cols+i]) <= MATRIX_EPSILON) {
00486       /* If we've eliminated our diagonal element, it means our matrix
00487        * isn't full-rank.  Pork chop sandwiches!  */
00488       return -1;
00489     }
00490     for (j = i+1; j < (int) order; j++) {
00491       /* Elimination of column i */
00492       tmp = m[j*cols+i] / m[i*cols+i];
00493       for (k = i; k < (int) cols; k++) {
00494         m[j*cols+k] -= m[i*cols+k] * tmp;
00495       }
00496     }
00497   }
00498   for (i = order-1; i >= 0; i--) {
00499     /* Back-substitution */
00500     tmp = m[i*cols+i];
00501     for (j = 0; j < i; j++) {
00502       for (k = cols-1; k > i-1; k--) {
00503         m[j*cols+k] -= m[i*cols+k] * m[j*cols+i] / tmp;
00504       }
00505     }
00506     m[i*cols+i] /= tmp;
00507     for (j = order; j < (int) cols; j++) {
00508       /* Normalize row */
00509       m[i*cols+j] /= tmp;
00510     }
00511   }
00512   return 0;
00513 }
00514 
00528 inline int matrix_inverse(u32 n, const double *const a, double *b){
00529   /* This function is currently only used to do a linear least-squares
00530    * solve for x, y, z and t in the navigation filter.  Gauss-Jordan
00531    * elimination is not the most efficient way to do this.  In the
00532    * ideal case, we'd use the Cholesky decomposition to compute the
00533    * least-squares fit.  (This may apply also to a least-norm fit if
00534    * we have too few satellites.)  The Cholesky decomposition becomes
00535    * even more important for unscented filters. */
00536   int res;
00537   u32 i, j, k, cols = n*2;
00538   double m[n*cols];
00539 
00540   /* For now, we special-case only small matrices.  If we bring back
00541    * multiple antennas, it won't be hard to auto-generate cases 5 and
00542    * 6 if hard-coded routines prove more efficient. */
00543   switch (n) {
00544     case 2:
00545       return inv2(a, b);
00546       break;
00547     case 3:
00548       return inv3(a, b);
00549       break;
00550     case 4:
00551       return inv4(a, b);
00552       break;
00553     default:
00554       /* Set up an augmented matrix M = [A I] */
00555       for (i = 0; i < n; i++) {
00556         for (j = 0; j < cols; j++) {
00557           if (j >= n) {
00558             if (j-n == i) {
00559               m[i*cols+j] = 1.0;
00560             } else {
00561               m[i*cols+j] = 0;
00562             }
00563           } else {
00564             m[i*cols+j] = a[i*n+j];
00565           }
00566         }
00567       }
00568 
00569       if ((res = rref(n, cols, m)) < 0) {
00570         /* Singular matrix! */
00571         return res;
00572       }
00573 
00574       /* Extract B from the augmented matrix M = [I inv(A)] */
00575       for (i = 0; i < n; i++) {
00576         for (j = n, k = 0; j < cols; j++, k++) {
00577           b[i*n+k] = m[i*cols+j];
00578         }
00579       }
00580 
00581       return 0;
00582       break;
00583   }
00584 }
00585 
00616 int matrix_pseudoinverse(u32 n, u32 m, const double *a, double *b) {
00617   if (n == m)
00618     return matrix_inverse(n, a, b);
00619   if (n > m)
00620     return matrix_ataiat(n, m, a, b);
00621   if (n < m)                                  /* n < m */
00622     return matrix_ataati(n, m, a, b);
00623   return -1;
00624 }
00625 
00641 inline int matrix_atwaiat(u32 n, u32 m, const double *a,
00642                           const double *w, double *b) {
00643   u32 i, j, k;
00644   double c[m*m], inv[m*m];
00645   /* Check to make sure we're doing the right operation */
00646   if (n <= m) return -1;
00647 
00648   /* The resulting matrix is symmetric, so compute both halves at
00649    * once */
00650   for (i = 0; i < m; i++)
00651     for (j = i; j < m; j++) {
00652       c[m*i + j] = 0;
00653       if (i == j) {
00654         /* If this is a diagonal element, just sum the squares of the
00655          * column of A weighted by the weighting vector. */
00656         for (k = 0; k < n; k++)
00657           c[m*i + j] += w[k]*a[m*k + j]*a[m*k + j];
00658       } else {
00659         /* Otherwise, assign both off-diagonal elements at once. */
00660         for (k = 0; k < n; k++)
00661           c[m*i + j] = c[m*j + i] = w[k]*a[m*k + j]*a[m*k + i];
00662         c[m*j + i] = c[m*i + j];
00663       }
00664     }
00665   if (matrix_inverse(m, c, inv) < 0) return -1;
00666   for (i = 0; i < m; i++)
00667     for (j = 0; j < n; j++) {
00668       b[n*i + j] = 0;
00669       for (k = 0; k < m; k++)
00670         b[n*i + j] += inv[n*i+k] * a[m*j + k];
00671     }
00672   return 0;
00673 }
00674 
00690 inline int matrix_atawati(u32 n, u32 m, const double *a,
00691                           const double *w, double *b) {
00692   u32 i, j, k;
00693   double c[m*m], inv[m*m];
00694   /* Check to make sure we're doing the right operation */
00695   if (n <= m) return -1;
00696 
00697   /* TODO(MP) -- implement! */
00698   /* The resulting matrix is symmetric, so compute both halves at
00699    * once */
00700   for (i = 0; i < m; i++)
00701     for (j = i; j < m; j++) {
00702       c[m*i + j] = 0;
00703       if (i == j) {
00704         /* If this is a diagonal element, just sum the squares of the
00705          * column of A weighted by the weighting vector. */
00706         for (k = 0; k < n; k++)
00707           c[m*i + j] += w[k]*a[m*k + j]*a[m*k + j];
00708       } else {
00709         /* Otherwise, assign both off-diagonal elements at once. */
00710         for (k = 0; k < n; k++)
00711           c[m*i + j] = c[m*j + i] = w[k]*a[m*k + j]*a[m*k + i];
00712         c[m*j + i] = c[m*i + j];
00713       }
00714     }
00715   if (matrix_inverse(m, c, inv) < 0) return -1;
00716   for (i = 0; i < m; i++)
00717     for (j = 0; j < n; j++) {
00718       b[n*i + j] = 0;
00719       for (k = 0; k < m; k++)
00720         b[n*i + j] += inv[n*i+k] * a[m*j + k];
00721     }
00722   return 0;
00723 }
00724 
00737 inline int matrix_ataiat(u32 n, u32 m, const double *a, double *b) {
00738   u32 i;
00739   double w[n];
00740   for (i = 0; i < n; i++) w[i] = 1;
00741   return matrix_atwaiat(n, m, a, w, b);
00742 }
00743 
00756 inline int matrix_ataati(u32 n, u32 m, const double *a, double *b) {
00757   u32 i;
00758   double w[n];
00759   for (i = 0; i < n; i++) w[i] = 1;
00760   return matrix_atawati(n, m, a, w, b);
00761 }
00762 
00776 inline void matrix_multiply(u32 n, u32 m, u32 p, const double *a,
00777                             const double *b, double *c) {
00778   u32 i, j, k;
00779   for (i = 0; i < n; i++)
00780     for (j = 0; j < p; j++) {
00781       c[p*i + j] = 0;
00782       for (k = 0; k < m; k++)
00783         c[p*i + j] += a[m*i+k] * b[p*k + j];
00784     }
00785 }
00786 
00797 void matrix_triu(u32 n, double *M)
00798 {
00799   /* NOTE: This function has been bounds checked. Please check again if
00800    * modifying. */
00801   for (u32 i=1; i<n; i++) {
00802     for (u32 j=0; j<i; j++) {
00803       M[i*n + j] = 0;
00804     }
00805   }
00806 }
00807 
00815 void matrix_eye(u32 n, double *M)
00816 {
00817   /* NOTE: This function has been bounds checked. Please check again if
00818    * modifying. */
00819   memset(M, 0, n * n * sizeof(double));
00820   for (u32 i=0; i<n; i++) {
00821     M[i*n + i] = 1;
00822   }
00823 }
00824 
00845 void matrix_udu(u32 n, double *M, double *U, double *D)
00846 {
00847   /* TODO: replace with DSYTRF? */
00848   /* NOTE: This function has been bounds checked. Please check again if
00849    * modifying. */
00850   double alpha, beta;
00851   matrix_triu(n, M);
00852   matrix_eye(n, U);
00853   memset(D, 0, n * sizeof(double));
00854 
00855   for (u32 j=n; j>=2; j--) {
00856     D[j - 1] = M[(j-1)*n + j-1];
00857     if (D[j-1] != 0) {
00858       alpha = 1.0 / D[j-1];
00859     } else {
00860       alpha = 0.0;
00861     }
00862     for (u32 k=1; k<j; k++) {
00863       beta = M[(k-1)*n + j-1];
00864       U[(k-1)*n + j-1] = alpha * beta;
00865       for (u32 kk = 0; kk < k; kk++) {
00866         M[kk*n + k-1] = M[kk*n + k-1] - beta * U[kk*n + j-1];
00867       }
00868     }
00869   }
00870   D[0] = M[0];
00871 }
00872 
00889 void matrix_reconstruct_udu(u32 n, double *U, double *D, double *M)
00890 {
00891   memset(M, 0, n * n * sizeof(double));
00892   /* TODO: M will be symmetric, only need to bother populating part of it */
00893   for (u32 i=0; i<n; i++) {
00894     for (u32 k=i; k<n; k++) {
00895       for (u32 j=k; j<n; j++) {
00896         /* U[i][j] is upper triangular = 0 if j < i
00897          * U[k][j] is upper triangular = 0 if j < k
00898          * U[i][j] * U[k][j] = 0 if j < k or j < i
00899          */
00900         M[i*n + k] += U[i*n +j] * D[j] * U[k*n + j];
00901       }
00902       M[k*n + i] = M[i*n + k];
00903     }
00904   }
00905 }
00906 
00907 
00920 void matrix_add_sc(u32 n, u32 m, const double *a,
00921                    const double *b, double gamma, double *c) {
00922   u32 i, j;
00923   for (i = 0; i < n; i++)
00924     for (j = 0; j < m; j++)
00925       c[m*i + j] = a[m*i + j] + gamma * b[m*i + j];
00926 }
00927 
00938 void matrix_transpose(u32 n, u32 m,
00939                       const double *a, double *b) {
00940   u32 i, j;
00941   for (i = 0; i < n; i++)
00942     for (j = 0; j < m; j++)
00943       b[n*j+i] = a[m*i+j];
00944 }
00945 
00955 void matrix_copy(u32 n, u32 m, const double *a,
00956                  double *b) {
00957   u32 i, j;
00958   for (i = 0; i < n; i++)
00959     for (j = 0; j < m; j++)
00960       b[m*i+j] = a[m*i+j];
00961 }
00962 
00963 /* \} */
00964 
00980 double vector_dot(u32 n, const double *a,
00981                   const double *b) {
00982   u32 i;
00983   double out = 0;
00984   for (i = 0; i < n; i++)
00985     out += a[i]*b[i];
00986   return out;
00987 }
00988 
00998 double vector_norm(u32 n, const double *a) {
00999   u32 i;
01000   double out = 0;
01001   for (i = 0; i < n; i++)
01002     out += a[i]*a[i];
01003   return sqrt(out);
01004 }
01005 
01014 double vector_mean(u32 n, const double *a) {
01015   u32 i;
01016   double out = 0;
01017   for (i = 0; i < n; i++)
01018     out += a[i];
01019   return out / n;
01020 }
01021 
01029 void vector_normalize(u32 n, double *a) {
01030   u32 i;
01031   double norm = vector_norm(n, a);
01032   for (i = 0; i < n; i++)
01033     a[i] /= norm;
01034 }
01035 
01047 void vector_add_sc(u32 n, const double *a,
01048                    const double *b, double gamma,
01049                    double *c) {
01050   u32 i;
01051   for (i = 0; i < n; i++)
01052     c[i] = a[i] + gamma * b[i];
01053 }
01054 
01064 void vector_add(u32 n, const double *a,
01065                 const double *b, double *c) {
01066   vector_add_sc(n, a, b, 1, c);
01067 }
01068 
01078 void vector_subtract(u32 n, const double *a,
01079                      const double *b, double *c) {
01080   vector_add_sc(n, a, b, -1, c);
01081 }
01082 
01092 void vector_cross(const double a[3], const double b[3],
01093                   double c[3]) {
01094   c[0] = a[1]*b[2] - a[2]*b[1];
01095   c[1] = a[2]*b[0] - a[0]*b[2];
01096   c[2] = a[0]*b[1] - a[1]*b[0];
01097 }
01098 
01099 /* \} */
01100 /* \} */
01101 


swiftnav
Author(s):
autogenerated on Sat Jun 8 2019 18:55:56