1 //==============================================================================
2 //
3 //  This file is part of GPSTk, the GPS Toolkit.
4 //
5 //  The GPSTk is free software; you can redistribute it and/or modify
6 //  it under the terms of the GNU Lesser General Public License as published
7 //  by the Free Software Foundation; either version 3.0 of the License, or
8 //  any later version.
9 //
10 //  The GPSTk is distributed in the hope that it will be useful,
11 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //  GNU Lesser General Public License for more details.
14 //
15 //  You should have received a copy of the GNU Lesser General Public
16 //  License along with GPSTk; if not, write to the Free Software Foundation,
17 //  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
18 //
19 //  This software was developed by Applied Research Laboratories at the
20 //  University of Texas at Austin.
21 //  Copyright 2004-2020, The Board of Regents of The University of Texas System
22 //
23 //==============================================================================
24 
25 //==============================================================================
26 //
27 //  This software was developed by Applied Research Laboratories at the
28 //  University of Texas at Austin, under contract to an agency or agencies
29 //  within the U.S. Department of Defense. The U.S. Government retains all
30 //  rights to use, duplicate, distribute, disclose, or release this software.
31 //
32 //  Pursuant to DoD Directive 523024
33 //
34 //  DISTRIBUTION STATEMENT A: This software has been approved for public
35 //                            release, distribution is unlimited.
36 //
37 //==============================================================================
38 
39 /**
40  * @file MatrixOperators.hpp
41  * Matrix operators (arithmetic, transpose(), inverse(), etc)
42  */
43 
44 #ifndef GPSTK_MATRIX_OPERATORS_HPP
45 #define GPSTK_MATRIX_OPERATORS_HPP
46 
47 #include <limits>
48 #include "MiscMath.hpp"
49 #include "MatrixFunctors.hpp"
50 
51 namespace gpstk
52 {
53       /// @ingroup MathGroup
54       //@{
55 
56       /**
57        * Returns the top to bottom concatenation of Matrices l and r
58        * only if they have the same number of columns.
59        * @throw MatrixException
60        */
61    template <class T, class BaseClass1, class BaseClass2>
operator &&(const ConstMatrixBase<T,BaseClass1> & l,const ConstMatrixBase<T,BaseClass2> & r)62    inline Matrix<T> operator&&(const ConstMatrixBase<T, BaseClass1>& l,
63                                const ConstMatrixBase<T, BaseClass2>& r)
64    {
65       if (l.cols() != r.cols())
66       {
67          MatrixException e("Incompatible dimensions for Matrix && Matrix");
68          GPSTK_THROW(e);
69       }
70 
71       size_t rows = l.rows() + r.rows();
72       size_t cols = l.cols();
73       Matrix<T> toReturn(rows, cols);
74 
75       for (rows = 0; rows < l.rows(); rows++)
76          for (cols = 0; cols < l.cols(); cols++)
77             toReturn(rows, cols) = l(rows, cols);
78 
79       for (rows = 0; rows < r.rows(); rows++)
80          for (cols = 0; cols < l.cols(); cols++)
81             toReturn(rows + l.rows(), cols) = r(rows, cols);
82 
83       return toReturn;
84    }
85 
86       /**
87        * Returns the top to bottom concatenation of Matrix t and Vector b
88        * only if they have the same number of columns.
89        * @throw MatrixException
90        */
91    template <class T, class BaseClass1, class BaseClass2>
operator &&(const ConstMatrixBase<T,BaseClass1> & t,const ConstVectorBase<T,BaseClass2> & b)92    inline Matrix<T> operator&&(const ConstMatrixBase<T, BaseClass1>& t,
93                                const ConstVectorBase<T, BaseClass2>& b)
94    {
95       if (t.cols() != b.size())
96       {
97          MatrixException e("Incompatible dimensions for Matrix && Vector");
98          GPSTK_THROW(e);
99       }
100 
101       size_t rows = t.rows() + 1;
102       size_t cols = t.cols();
103       Matrix<T> toReturn(rows, cols);
104 
105       for (rows = 0; rows < t.rows(); rows++)
106          for (cols = 0; cols < t.cols(); cols++)
107             toReturn(rows, cols) = t(rows, cols);
108 
109       for (cols = 0; cols < t.cols(); cols++)
110          toReturn(t.rows(), cols) = b(cols);
111 
112       return toReturn;
113    }
114 
115       /**
116        * Returns the top to bottom concatenation of Vector t and Matrix b
117        * only if they have the same number of columns.
118        * @throw MatrixException
119        */
120    template <class T, class BaseClass1, class BaseClass2>
operator &&(const ConstVectorBase<T,BaseClass1> & t,const ConstMatrixBase<T,BaseClass2> & b)121    inline Matrix<T> operator&&(const ConstVectorBase<T, BaseClass1>& t,
122                                const ConstMatrixBase<T, BaseClass2>& b)
123    {
124       if (t.size() != b.cols())
125       {
126          MatrixException e("Incompatible dimensions for Vector && Matrix");
127          GPSTK_THROW(e);
128       }
129 
130       size_t rows = 1 + b.rows();
131       size_t cols = b.cols();
132       Matrix<T> toReturn(rows, cols);
133 
134       for (cols = 0; cols < b.cols(); cols++)
135          toReturn(0, cols) = t(cols);
136 
137       for (rows = 1; rows < b.rows()+1; rows++)
138          for (cols = 0; cols < b.cols(); cols++)
139             toReturn(rows, cols) = b(rows, cols);
140 
141       return toReturn;
142    }
143 
144       /**
145        * Returns the left to right concatenation of l and r only if
146        * they have the same number of rows.
147        * @throw MatrixException
148        */
149    template <class T, class BaseClass1, class BaseClass2>
operator ||(const ConstMatrixBase<T,BaseClass1> & l,const ConstMatrixBase<T,BaseClass2> & r)150    inline Matrix<T> operator||(const ConstMatrixBase<T, BaseClass1>& l,
151                                const ConstMatrixBase<T, BaseClass2>& r)
152    {
153       if (l.rows() != r.rows())
154       {
155          MatrixException e("Incompatible dimensions for Matrix || Matrix");
156          GPSTK_THROW(e);
157       }
158 
159       size_t rows = l.rows();
160       size_t cols = l.cols() + r.cols();
161       Matrix<T> toReturn(rows, cols);
162 
163       for (cols = 0; cols < l.cols(); cols++)
164          for (rows = 0; rows < l.rows(); rows++)
165             toReturn(rows, cols) = l(rows, cols);
166 
167       for (cols = 0; cols < r.cols(); cols++)
168          for (rows = 0; rows < l.rows(); rows++)
169             toReturn(rows, cols + l.cols()) = r(rows,cols);
170 
171       return toReturn;
172    }
173 
174       /**
175        * Returns the left to right concatenation of Matrix l and Vector r
176        * only if they have the same number of rows.
177        * @throw MatrixException
178        */
179    template <class T, class BaseClass1, class BaseClass2>
operator ||(const ConstMatrixBase<T,BaseClass1> & l,const ConstVectorBase<T,BaseClass2> & r)180    inline Matrix<T> operator||(const ConstMatrixBase<T, BaseClass1>& l,
181                                const ConstVectorBase<T, BaseClass2>& r)
182    {
183       if (l.rows() != r.size())
184       {
185          MatrixException e("Incompatible dimensions for Matrix || Vector");
186          GPSTK_THROW(e);
187       }
188 
189       size_t rows = l.rows();
190       size_t cols = l.cols() + 1;
191       Matrix<T> toReturn(rows, cols);
192 
193       for (cols = 0; cols < l.cols(); cols++)
194          for (rows = 0; rows < l.rows(); rows++)
195             toReturn(rows, cols) = l(rows, cols);
196 
197       for (rows = 0; rows < l.rows(); rows++)
198          toReturn(rows, l.cols()) = r(rows);
199 
200       return toReturn;
201    }
202 
203       /**
204        * Returns the left to right concatenation of Vector l and Matrix r
205        * only if they have the same number of rows.
206        * @throw MatrixException
207        */
208    template <class T, class BaseClass1, class BaseClass2>
operator ||(const ConstVectorBase<T,BaseClass1> & l,const ConstMatrixBase<T,BaseClass2> & r)209    inline Matrix<T> operator||(const ConstVectorBase<T, BaseClass1>& l,
210                                const ConstMatrixBase<T, BaseClass2>& r)
211    {
212       if (l.size() != r.rows())
213       {
214          MatrixException e("Incompatible dimensions for Vector || Matrix");
215          GPSTK_THROW(e);
216       }
217 
218       size_t rows = r.rows();
219       size_t cols = r.cols() + 1;
220       Matrix<T> toReturn(rows, cols);
221 
222       for (rows = 0; rows < r.rows(); rows++)
223          toReturn(rows, 0) = l(rows);
224 
225       for (cols = 1; cols < r.cols()+1; cols++)
226          for (rows = 0; rows < r.rows(); rows++)
227             toReturn(rows, cols) = r(rows, cols);
228 
229       return toReturn;
230    }
231 
232       /**
233        * Returns the left to right concatenation of Vector l and Vector r
234        * only if they have the same number of rows.
235        * @throw MatrixException
236        */
237    template <class T, class BaseClass1, class BaseClass2>
operator ||(const ConstVectorBase<T,BaseClass1> & l,const ConstVectorBase<T,BaseClass2> & r)238    inline Matrix<T> operator||(const ConstVectorBase<T, BaseClass1>& l,
239                                const ConstVectorBase<T, BaseClass2>& r)
240    {
241       if (l.size() != r.size())
242       {
243          MatrixException e("Incompatible dimensions for Vector || Vector");
244          GPSTK_THROW(e);
245       }
246 
247       size_t rows = r.size();
248       Matrix<T> toReturn(rows, 2);
249 
250       for (rows = 0; rows < r.size(); rows++)
251       {
252          toReturn(rows, 0) = l(rows);
253          toReturn(rows, 1) = r(rows);
254       }
255 
256       return toReturn;
257    }
258 
259       /**
260        * Returns the minor matrix of l at element (row, col).  A minor
261        * matrix is the same matrix as \c l but with row \c row and col
262        * \c col removed.
263        * @throw MatrixException
264        */
265    template <class T, class BaseClass>
minorMatrix(const ConstMatrixBase<T,BaseClass> & l,size_t row,size_t col)266    inline Matrix<T> minorMatrix(const ConstMatrixBase<T, BaseClass>& l,
267                                 size_t row, size_t col)
268    {
269       if ((row >= l.rows()) || (col >= l.cols()))
270       {
271          MatrixException e("Invalid row or column for minorMatrix()");
272          GPSTK_THROW(e);
273       }
274          // handle special cases
275       if (row == 0)
276       {
277          if (col == 0)
278          {
279             return Matrix<T>(l,1,1,l.rows()-1,l.cols()-1);
280          }
281          else if (col == (l.cols() - 1))
282          {
283             return Matrix<T>(l,1,0,l.rows()-1,l.cols()-1);
284          }
285          else
286          {
287             return Matrix<T>(l,1,0,l.rows()-1,col) ||
288                Matrix<T>(l,1,col+1,l.rows()-1,l.cols()-col-1);
289          }
290       }
291       else if (row == (l.rows() - 1))
292       {
293          if (col == 0)
294          {
295             return Matrix<T>(l,0,1,l.rows()-1,l.cols()-1);
296          }
297          else if (col == (l.cols() - 1))
298          {
299             return Matrix<T>(l,0,0,l.rows()-1,l.cols()-1);
300          }
301          else
302          {
303             return Matrix<T>(l,0,0,l.rows()-1,col) ||
304                Matrix<T>(l,0,col+1,l.rows()-1,l.cols()-col-1);
305          }
306       }
307       else if (col == 0)
308       {
309          return Matrix<T>(l,0,1,row,l.cols()-1) &&
310             Matrix<T>(l,row+1,1,l.rows()-row-1,l.cols()-1);
311       }
312       else if (col == (l.cols() - 1))
313       {
314          return Matrix<T>(l,0,0,row,l.cols()-1) &&
315             Matrix<T>(l,row+1,0,l.rows()-row-1,l.cols()-1);
316       }
317       else
318       {
319          return (Matrix<T>(l, 0, 0, row, col) ||
320                  Matrix<T>(l, 0, col + 1, row, l.cols()-col-1)) &&
321             (Matrix<T>(l, row + 1, 0, l.rows()-row-1, col) ||
322              Matrix<T>(l, row + 1, col + 1, l.rows()-row-1, l.cols()-col-1));
323       }
324    }
325 
326       /**
327        * Returns a matrix that is \c m transposed.
328        */
329    template <class T, class BaseClass>
transpose(const ConstMatrixBase<T,BaseClass> & m)330    inline Matrix<T> transpose(const ConstMatrixBase<T, BaseClass>& m)
331    {
332       Matrix<T> temp(m.cols(), m.rows());
333       size_t i, j;
334       for (i = 0; i < m.rows(); i++)
335          for (j = 0; j < m.cols(); j++)
336             temp(j,i) = m(i,j);
337       return temp;
338    }
339 
340       /**
341        * Uses an LU Decomposition to calculate the determinate of m.
342        * @throw MatrixException
343        */
344    template <class T, class BaseClass>
det(const ConstMatrixBase<T,BaseClass> & m)345    inline T det(const ConstMatrixBase<T, BaseClass>& m)
346    {
347       try
348       {
349          LUDecomp<T> LU;
350          LU(m);
351          return LU.det();
352       }
353       catch(MatrixException& e)
354       {
355          e.addText("in det()");
356          GPSTK_RETHROW(e);
357       }
358    }
359 
360       /**
361        * returns the condition number of the matrix
362        */
363    template <class T, class BaseClass>
condNum(const ConstMatrixBase<T,BaseClass> & m,T & bigNum,T & smallNum)364    inline T condNum(const ConstMatrixBase<T, BaseClass>& m, T& bigNum, T& smallNum)
365       throw()
366    {
367       SVD<T> svd;
368       svd(m);
369          // SVD will not always sort singular values in descending order
370       svd.sort(true);
371       bigNum = svd.S(0);
372       smallNum = svd.S(svd.S.size()-1);
373       if(smallNum <= std::numeric_limits<T>::epsilon())
374          return T(0);
375       return bigNum/smallNum;
376    }
377 
378       /**
379        * returns the condition number of the matrix, doesnt require
380        * bigNum or smallNum..
381        */
382    template <class T, class BaseClass>
condNum(const ConstMatrixBase<T,BaseClass> & m)383    inline T condNum(const ConstMatrixBase<T, BaseClass>& m)
384       throw()
385    {
386       T bigNum, smallNum;
387       return condNum(m, bigNum, smallNum);
388    }
389 
390       /**
391        * Returns a new \c dim * \c dim matrix that's an identity matrix.
392        * @throw MatrixException
393        */
394    template <class T>
ident(size_t dim)395    inline Matrix<T> ident(size_t dim)
396    {
397       if (dim == 0)
398       {
399          MatrixException e("Invalid (0) dimension for ident()");
400          GPSTK_THROW(e);
401       }
402       Matrix<T> toReturn(dim, dim, T(0));
403       size_t i;
404       for (i = 0; i < toReturn.rows(); i++)
405          toReturn(i,i) = T(1);
406       return toReturn;
407    }
408 
409       /**
410        * Returns the diagonal matrix  of \c m .
411        * @throw MatrixException
412        */
413    template <class T, class BaseClass>
diag(const ConstMatrixBase<T,BaseClass> & m)414    inline Matrix<T> diag(const ConstMatrixBase<T, BaseClass>& m)
415    {
416       if ( (m.rows() != m.cols()) || (m.cols() < 1) )
417       {
418          MatrixException e("invalid matrix dimensions for m");
419          GPSTK_THROW(e);
420       }
421 
422       const size_t dim = m.rows();
423 
424       Matrix<T> temp(dim, dim, T(0));
425       for (size_t i = 0; i < dim; i++)
426          temp(i,i) = m(i,i);
427 
428       return temp;
429    }
430 
431       /**
432        * Block diagonal concatenation of matrix input.
433        * @throw MatrixException
434        */
435    template <class T, class BaseClass>
blkdiag(const ConstMatrixBase<T,BaseClass> & m1,const ConstMatrixBase<T,BaseClass> & m2)436    inline Matrix<T> blkdiag(const ConstMatrixBase<T, BaseClass>& m1,
437                             const ConstMatrixBase<T, BaseClass>& m2)
438    {
439       if ( (m1.rows() != m1.cols()) || (m1.cols() < 1) ||
440            (m2.rows() != m2.cols()) || (m2.cols() < 1) )
441       {
442          MatrixException e("Invalid matrix dimensions of input.");
443          GPSTK_THROW(e);
444       }
445 
446       const size_t dim1 = m1.rows();
447       const size_t dim2 = m2.rows();
448 
449       Matrix<T> temp(dim1+dim2, dim1+dim2, T(0));
450       for (size_t i = 0; i < dim1; i++)
451       {
452          for(size_t j = 0; j < dim1; j++)
453          {
454             temp(i,j) = m1(i,j);
455          }
456       }
457       for (size_t i = 0; i < dim2; i++)
458       {
459          for(size_t j = 0; j < dim2; j++)
460          {
461             temp(i+dim1,j+dim1) = m2(i,j);
462          }
463       }
464 
465       return temp;
466    }
467 
468       /**
469        * @throw MatrixException
470        */
471    template <class T, class BaseClass>
blkdiag(const ConstMatrixBase<T,BaseClass> & m1,const ConstMatrixBase<T,BaseClass> & m2,const ConstMatrixBase<T,BaseClass> & m3)472    inline Matrix<T> blkdiag(const ConstMatrixBase<T, BaseClass>& m1,
473                             const ConstMatrixBase<T, BaseClass>& m2,
474                             const ConstMatrixBase<T, BaseClass>& m3)
475    { return blkdiag( blkdiag(m1,m2), m3 ); }
476 
477       /**
478        * @throw MatrixException
479        */
480    template <class T, class BaseClass>
blkdiag(const ConstMatrixBase<T,BaseClass> & m1,const ConstMatrixBase<T,BaseClass> & m2,const ConstMatrixBase<T,BaseClass> & m3,const ConstMatrixBase<T,BaseClass> & m4)481    inline Matrix<T> blkdiag(const ConstMatrixBase<T, BaseClass>& m1,
482                             const ConstMatrixBase<T, BaseClass>& m2,
483                             const ConstMatrixBase<T, BaseClass>& m3,
484                             const ConstMatrixBase<T, BaseClass>& m4)
485    { return blkdiag( blkdiag(m1,m2,m3), m4 ); }
486 
487 
488       /**
489        * Return a rotation matrix [dimensioned 3x3, inverse() =
490        * transpose()] for the rotation through \c angle radians about
491        * \c axis number (= 1, 2 or 3).
492        * @throw MatrixException
493        */
494    template <class T>
rotation(T angle,int axis)495    inline Matrix<T> rotation(T angle, int axis)
496    {
497       if (axis < 1 || axis > 3)
498       {
499          MatrixException e("Invalid axis (must be 1,2, or 3)");
500          GPSTK_THROW(e);
501       }
502       Matrix<T> toReturn(3,3,T(0));
503       int i1 = axis-1;
504       int i2 = (i1+1) % 3;
505       int i3 = (i2+1) % 3;
506       toReturn(i1,i1) = 1.0;
507       toReturn(i2,i2) = toReturn(i3,i3) = ::cos(angle);
508       toReturn(i3,i2) = -(toReturn(i2,i3) = ::sin(angle));
509 
510       return toReturn;
511    }
512 
513       /**
514        * Inverts the matrix M by Gaussian elimination. Throws on non-square
515        * and singular matricies.
516        * @throw MatrixException
517        */
518    template <class T, class BaseClass>
inverse(const ConstMatrixBase<T,BaseClass> & m)519    inline Matrix<T> inverse(const ConstMatrixBase<T, BaseClass>& m)
520    {
521       if ((m.rows() != m.cols()) || (m.cols() == 0))
522       {
523          MatrixException e("inverse() requires non-trivial square matrix");
524          GPSTK_THROW(e);
525       }
526 
527       Matrix<T> toReturn(m.rows(), m.cols() * 2);
528 
529       size_t r, t, j;
530       T temp;
531 
532          // set the left half to m
533       {
534          MatrixSlice<T> ms(toReturn, 0, 0, m.rows(), m.cols());
535          ms = m;
536       }
537 
538          // set the right half to identity
539       {
540          MatrixSlice<T> ms(toReturn, 0, m.cols(), m.rows(), m.cols());
541          ident(ms);
542       }
543 
544       for (r = 0; r < m.rows(); r++)
545       {
546             // if m(r,r) is zero, find another row
547             // to add to it...
548          if (toReturn(r,r) == 0)
549          {
550             t = r+1;
551             while ( (t < m.rows()) && (toReturn(t,r) == 0) )
552                t++;
553 
554             if (t == m.rows())
555             {
556                SingularMatrixException e("Singular matrix");
557                GPSTK_THROW(e);
558             }
559 
560             for (j = r; j < toReturn.cols(); j++)
561                toReturn(r,j) += (toReturn(t,j) / toReturn(t,r));
562          }
563 
564             // scale this row's (r,r)'th element to 1
565          temp = toReturn(r,r);
566          for (j = r; j < toReturn.cols(); j++)
567             toReturn(r,j) /= temp;
568 
569             // do the elimination
570          for (t = 0; t < m.rows(); t++)
571          {
572             if (t != r)
573             {
574                temp = toReturn(t,r);
575                for (j = r; j < toReturn.cols(); j++)
576                   toReturn(t,j) -= temp/toReturn(r,r) * toReturn(r,j);
577             }
578          }
579       }
580          // return the right hand side square matrix
581       return Matrix<T>(toReturn, 0, m.cols(), m.rows(), m.cols());
582 
583    }  // end inverse
584 
585       /**
586        * Inverts the matrix M by LU decomposition. Throws on non-square
587        * and singular matricies.
588        * @throw MatrixException
589        */
590    template <class T, class BaseClass>
inverseLUD(const ConstMatrixBase<T,BaseClass> & m)591    inline Matrix<T> inverseLUD(const ConstMatrixBase<T, BaseClass>& m)
592    {
593       if ((m.rows() != m.cols()) || (m.cols() == 0)) {
594          MatrixException e("inverseLUD() requires non-trivial square matrix");
595          GPSTK_THROW(e);
596       }
597 
598       size_t i,j,N=m.rows();
599       Matrix<T> inv(m);
600       Vector<T> V(N);
601       LUDecomp<T> LU;
602       LU(m);
603       for(j=0; j<N; j++) {    // loop over columns
604          V = T(0);
605          V(j) = T(1);
606          LU.backSub(V);
607          for(i=0; i<N; i++) inv(i,j)=V(i);
608       }
609       return inv;
610 
611    }  // end inverseLUD
612 
613       /**
614        * Inverts the matrix M by LU decomposition, and returns
615        * determinant as well Throws on non-square and singular
616        * matricies.
617        * @throw MatrixException
618        */
619    template <class T, class BaseClass>
inverseLUD(const ConstMatrixBase<T,BaseClass> & m,T & determ)620    inline Matrix<T> inverseLUD(const ConstMatrixBase<T, BaseClass>& m, T& determ)
621    {
622       if ((m.rows() != m.cols()) || (m.cols() == 0)) {
623          MatrixException e("inverseLUD() requires non-trivial square matrix");
624          GPSTK_THROW(e);
625       }
626 
627       size_t i,j,N=m.rows();
628       Matrix<T> inv(m);
629       Vector<T> V(N);
630       LUDecomp<T> LU;
631       LU(m);
632          // compute determinant
633       determ = T(LU.parity);
634       for(i = 0; i < m.rows(); i++) determ *= LU.LU(i,i);
635          // compute inverse
636       for(j=0; j<N; j++) {    // loop over columns
637          V = T(0);
638          V(j) = T(1);
639          LU.backSub(V);
640          for(i=0; i<N; i++) inv(i,j)=V(i);
641       }
642       return inv;
643 
644    }  // end inverseLUD
645 
646       /**
647        * Inverts the square matrix M by SVD, editing the singular values
648        * using tolerance tol. Throws only on input of the zero matrix.
649        * @throw MatrixException
650        */
651    template <class T, class BaseClass>
inverseSVD(const ConstMatrixBase<T,BaseClass> & m,const T tol=T (1.e-8))652    inline Matrix<T> inverseSVD(const ConstMatrixBase<T, BaseClass>& m,
653                                const T tol=T(1.e-8))
654    {
655       if ((m.rows() != m.cols()) || (m.cols() == 0)) {
656          MatrixException e("inverseSVD() requires non-trivial square matrix");
657          GPSTK_THROW(e);
658       }
659 
660       size_t i,j,N=m.rows();
661       Matrix<T> inv(m);
662       SVD<T> svd;
663       svd(m);
664          // SVD will not always sort singular values in descending order
665       svd.sort(true);
666       if(svd.S(0) == T(0)) {
667          MatrixException e("Input is the zero matrix");
668          GPSTK_THROW(e);
669       }
670          // edit singular values TD input tolerance, output edited SVs
671       for(i=1; i<N; i++) if(svd.S(i) < tol*svd.S(0)) svd.S(i)=T(0);
672          // back substitution
673       Vector<T> V(N);
674       for(j=0; j<N; j++) {    //loop over columns
675          V = T(0);
676          V(j) = T(1);
677          svd.backSub(V);
678          for(i=0; i<N; i++) inv(i,j)=V(i);
679       }
680       return inv;
681 
682    }  // end inverseSVD
683 
684       /**
685        * Invert the square matrix M by SVD, editing the singular values with tolerance tol,
686        * and return the largest and smallest singular values (before any editing).
687        * Throws only on input of the zero matrix.
688        * @throw MatrixException
689        */
690    template <class T, class BaseClass>
inverseSVD(const ConstMatrixBase<T,BaseClass> & m,T & bigNum,T & smallNum,const T tol=T (1.e-8))691    inline Matrix<T> inverseSVD(const ConstMatrixBase<T, BaseClass>& m,
692                                T& bigNum, T& smallNum, const T tol=T(1.e-8))
693    {
694       if ((m.rows() != m.cols()) || (m.cols() == 0)) {
695          MatrixException e("inverseSVD() requires non-trivial square matrix");
696          GPSTK_THROW(e);
697       }
698 
699       size_t i,j,N=m.rows();
700       Matrix<T> inv(m);
701       SVD<T> svd;
702       svd(m);
703          // SVD will not always sort singular values in descending order
704       svd.sort(true);
705       if(svd.S(0) == T(0)) {
706          MatrixException e("Input is the zero matrix");
707          GPSTK_THROW(e);
708       }
709 
710          // compute condition number = bigNum/smallNum
711       bigNum = svd.S(0);
712       smallNum = svd.S(svd.S.size()-1);
713 
714          // edit singular values using input tolerance, output edited SVs
715       for(i=1; i<N; i++) if(svd.S(i) < tol*svd.S(0)) svd.S(i)=T(0);
716 
717          // back substitution
718       Vector<T> V(N);
719       for(j=0; j<N; j++) {    //loop over columns
720          V = T(0);
721          V(j) = T(1);
722          svd.backSub(V);
723          for(i=0; i<N; i++) inv(i,j)=V(i);
724       }
725       return inv;
726 
727    }  // end inverseSVD
728 
729       /**
730        * Invert the square matrix M by SVD, editing the singular values
731        * using tolerance tol, and return the singular values
732        * (before any editing). Throws only on input of the zero matrix.
733        * @throw MatrixException
734        */
735    template <class T, class BaseClass>
inverseSVD(const ConstMatrixBase<T,BaseClass> & m,Vector<T> & sv,const T tol=T (1.e-8))736    inline Matrix<T> inverseSVD(const ConstMatrixBase<T, BaseClass>& m,
737                                Vector<T>& sv, const T tol=T(1.e-8))
738    {
739       if ((m.rows() != m.cols()) || (m.cols() == 0)) {
740          MatrixException e("inverseSVD() requires non-trivial square matrix");
741          GPSTK_THROW(e);
742       }
743 
744       size_t i,j,N=m.rows();
745       Matrix<T> inv(m);
746       SVD<T> svd;
747       svd(m);
748          // SVD will not always sort singular values in descending order
749       svd.sort(true);
750       if(svd.S(0) == T(0)) {
751          MatrixException e("Input is the zero matrix");
752          GPSTK_THROW(e);
753       }
754 
755          // save the singular values
756       sv = Vector<T>(N);
757       for(i=0; i<N; i++) sv(i) = svd.S(i);
758 
759          // edit singular values using input tolerance, output edited SVs
760       for(i=1; i<N; i++) if(svd.S(i) < tol*svd.S(0)) svd.S(i)=T(0);
761 
762          // back substitution
763       Vector<T> V(N);
764       for(j=0; j<N; j++) {    //loop over columns
765          V = T(0);
766          V(j) = T(1);
767          svd.backSub(V);
768          for(i=0; i<N; i++) inv(i,j)=V(i);
769       }
770       return inv;
771 
772    }  // end inverseSVD
773 
774       /**
775        * Inverts the square symmetric positive definite matrix M using
776        * Cholesky-Crout algorithm. Very fast and useful when M comes
777        * from using a Least Mean-Square (LMS) or Weighted Least
778        * Mean-Square (WLMS) method.
779        * @throw MatrixException
780        */
781    template <class T, class BaseClass>
inverseChol(const ConstMatrixBase<T,BaseClass> & m)782    inline Matrix<T> inverseChol(const ConstMatrixBase<T, BaseClass>& m)
783    {
784       int N = m.rows(), i, j, k;
785       double sum;
786       Matrix<T> LI(N,N, 0.0);      // Here we will first store L^-1, and later m^-1
787 
788          // Let's call CholeskyCrout class to decompose matrix "m" in L*LT
789       gpstk::CholeskyCrout<double> CC;
790       CC(m);
791 
792          // Let's find the inverse of L (the LI from above)
793       for(i=0; i<N; i++) {
794          LI(i,i) = 1.0 / CC.L(i,i);
795          for(j=0; j<i; j++) {
796             sum = 0.0;
797             for(k=i; k>=0; k-- ) sum += CC.L(i,k)*LI(k,j);
798             LI(i,j) = -sum*LI(i,i);
799          }
800       }
801 
802          // Now, let's remember that m^-1 = transpose(LI)*LI
803       LI = transpose(LI) * LI;
804       return LI;
805 
806    }  // end inverseChol
807 
808 
809       /**
810        *  Matrix * Matrix : row by column multiplication of two matricies.
811        * @throw MatrixException
812        */
813    template <class T, class BaseClass1, class BaseClass2>
operator *(const ConstMatrixBase<T,BaseClass1> & l,const ConstMatrixBase<T,BaseClass2> & r)814    inline Matrix<T> operator* (const ConstMatrixBase<T, BaseClass1>& l,
815                                const ConstMatrixBase<T, BaseClass2>& r)
816    {
817       if (l.cols() != r.rows())
818       {
819          MatrixException e("Incompatible dimensions for Matrix * Matrix");
820          GPSTK_THROW(e);
821       }
822 
823       Matrix<T> toReturn(l.rows(), r.cols(), T(0));
824       size_t i, j, k;
825       for (i = 0; i < toReturn.rows(); i++)
826          for (j = 0; j < toReturn.cols(); j++)
827             for (k = 0; k < l.cols(); k++)
828                toReturn(i,j) += l(i,k) * r(k,j);
829 
830       return toReturn;
831    }
832 
833       /**
834        * Matrix times vector multiplication, returning a vector.
835        * @throw MatrixException
836        */
837    template <class T, class BaseClass1, class BaseClass2>
operator *(const ConstMatrixBase<T,BaseClass1> & m,const ConstVectorBase<T,BaseClass2> & v)838    inline Vector<T> operator* (const ConstMatrixBase<T, BaseClass1>& m,
839                                const ConstVectorBase<T, BaseClass2>& v)
840    {
841       if (v.size() != m.cols())
842       {
843          gpstk::MatrixException e("Incompatible dimensions for Vector * Matrix");
844          GPSTK_THROW(e);
845       }
846 
847       Vector<T> toReturn(m.rows());
848       size_t i, j;
849       for (i = 0; i < m.rows(); i++)
850       {
851          toReturn[i] = 0;
852          for (j = 0; j < m.cols(); j++)
853             toReturn[i] += m(i, j) * v[j];
854       }
855       return toReturn;
856    }
857       /**
858        * Vector times matrix multiplication, returning a vector.
859        * @throw MatrixException
860        */
861    template <class T, class BaseClass1, class BaseClass2>
operator *(const ConstVectorBase<T,BaseClass1> & v,const ConstMatrixBase<T,BaseClass2> & m)862    inline Vector<T> operator* (const ConstVectorBase<T, BaseClass1>& v,
863                                const ConstMatrixBase<T, BaseClass2>& m)
864    {
865       if (v.size() != m.rows())
866       {
867          gpstk::MatrixException e("Incompatible dimensions for Vector * Matrix");
868          GPSTK_THROW(e);
869       }
870 
871       Vector<T> toReturn(m.cols());
872       size_t i, j;
873       for (i = 0; i < m.cols(); i++)
874       {
875          toReturn[i] = 0;
876          for (j = 0; j < m.rows(); j++)
877             toReturn[i] += m(j,i) * v[j];
878       }
879       return toReturn;
880    }
881 
882       /**
883        * Compute sum of two matricies.
884        * @throw MatrixException
885        */
886    template <class T, class BaseClass1, class BaseClass2>
operator +(const ConstMatrixBase<T,BaseClass1> & l,const ConstMatrixBase<T,BaseClass2> & r)887    inline Matrix<T> operator+ (const ConstMatrixBase<T, BaseClass1>& l,
888                                const ConstMatrixBase<T, BaseClass2>& r)
889    {
890       if (l.cols() != r.cols() || l.rows() != r.rows())
891       {
892          MatrixException e("Incompatible dimensions for Matrix + Matrix");
893          GPSTK_THROW(e);
894       }
895 
896       Matrix<T> toReturn(l.rows(), r.cols(), T(0));
897       size_t i, j;
898       for (i = 0; i < toReturn.rows(); i++)
899          for (j = 0; j < toReturn.cols(); j++)
900             toReturn(i,j) = l(i,j) + r(i,j);
901 
902       return toReturn;
903    }
904 
905       /**
906        * Compute difference of two matricies.
907        * @throw MatrixException
908        */
909    template <class T, class BaseClass1, class BaseClass2>
operator -(const ConstMatrixBase<T,BaseClass1> & l,const ConstMatrixBase<T,BaseClass2> & r)910    inline Matrix<T> operator- (const ConstMatrixBase<T, BaseClass1>& l,
911                                const ConstMatrixBase<T, BaseClass2>& r)
912    {
913       if (l.cols() != r.cols() || l.rows() != r.rows())
914       {
915          MatrixException e("Incompatible dimensions for Matrix - Matrix");
916          GPSTK_THROW(e);
917       }
918 
919       Matrix<T> toReturn(l.rows(), r.cols(), T(0));
920       size_t i, j;
921       for (i = 0; i < toReturn.rows(); i++)
922          for (j = 0; j < toReturn.cols(); j++)
923             toReturn(i,j) = l(i,j) - r(i,j);
924 
925       return toReturn;
926    }
927 
928       /**
929        * Compute the outer product of two vectors.
930        * @throw MatrixException
931        */
932    template <class T, class BaseClass>
outer(const ConstVectorBase<T,BaseClass> & v,const ConstVectorBase<T,BaseClass> & w)933    inline Matrix<T> outer(const ConstVectorBase<T, BaseClass>& v,
934                           const ConstVectorBase<T, BaseClass>& w)
935    {
936       if(v.size()*w.size() == 0) {
937          MatrixException e("Zero length vector(s)");
938          GPSTK_THROW(e);
939       }
940       Matrix<T> M(v.size(),w.size(),T(0));
941       for(size_t i=0; i<v.size(); i++)
942          for(size_t j=0; j<w.size(); j++)
943             M(i,j) = v(i)*w(j);
944       return M;
945    }
946 
947       /**
948        * find the maximum magnitude in a matrix
949        */
950    template <class T, class BaseClass>
maxabs(const ConstMatrixBase<T,BaseClass> & a)951    inline T maxabs(const ConstMatrixBase<T, BaseClass>& a)
952       throw()
953    {
954       T m=0;
955       for(int i = 0; i < a.rows(); i++)
956       {
957          for(int j = 0; j < a.cols(); j++)
958          {
959             T mag = std::abs(a(i,j));
960             if (mag > m)
961                m = mag;
962          }
963       }
964       return m;
965    }
966 
967 
968       /// Multiplies all the elements of m by d.
969    template <class T, class BaseClass>
operator *(const ConstMatrixBase<T,BaseClass> & m,const T d)970    inline Matrix<T> operator* (const ConstMatrixBase<T, BaseClass>& m, const T d)
971    {
972       Matrix<T> temp(m);
973       return temp *= d;
974    }
975 
976       /// Multiplies all the elements of m by d.
977    template <class T, class BaseClass>
operator *(const T d,const ConstMatrixBase<T,BaseClass> & m)978    inline Matrix<T> operator* (const T d, const ConstMatrixBase<T, BaseClass>& m)
979    {
980       Matrix<T> temp(m);
981       return temp *= d;
982    }
983 
984       /// Divides all the elements of m by d.
985    template <class T, class BaseClass>
operator /(const ConstMatrixBase<T,BaseClass> & m,const T d)986    inline Matrix<T> operator/ (const ConstMatrixBase<T, BaseClass>& m, const T d)
987    {
988       Matrix<T> temp(m);
989       return temp /= d;
990    }
991 
992       /// Divides all the elements of m by d.
993    template <class T, class BaseClass>
operator /(const T d,const ConstMatrixBase<T,BaseClass> & m)994    inline Matrix<T> operator/ (const T d, const ConstMatrixBase<T, BaseClass>& m)
995    {
996       Matrix<T> temp(m);
997       return temp /= d;
998    }
999 
1000       /// Adds all the elements of m by d.
1001    template <class T, class BaseClass>
operator +(const ConstMatrixBase<T,BaseClass> & m,const T d)1002    inline Matrix<T> operator+ (const ConstMatrixBase<T, BaseClass>& m, const T d)
1003    {
1004       Matrix<T> temp(m);
1005       return temp += d;
1006    }
1007 
1008       /// Adds all the elements of m by d.
1009    template <class T, class BaseClass>
operator +(const T d,const ConstMatrixBase<T,BaseClass> & m)1010    inline Matrix<T> operator+ (const T d, const ConstMatrixBase<T, BaseClass>& m)
1011    {
1012       Matrix<T> temp(m);
1013       return temp += d;
1014    }
1015 
1016       /// Subtracts all the elements of m by d.
1017    template <class T, class BaseClass>
operator -(const ConstMatrixBase<T,BaseClass> & m,const T d)1018    inline Matrix<T> operator- (const ConstMatrixBase<T, BaseClass>& m, const T d)
1019    {
1020       Matrix<T> temp(m);
1021       return temp -= d;
1022    }
1023 
1024       /// Subtracts all the elements of m by d.
1025    template <class T, class BaseClass>
operator -(const T d,const ConstMatrixBase<T,BaseClass> & m)1026    inline Matrix<T> operator- (const T d, const ConstMatrixBase<T, BaseClass>& m)
1027    {
1028       Matrix<T> temp(m);
1029       return temp -= d;
1030    }
1031 
1032       //@}
1033 
1034 }  // namespace
1035 
1036 #endif
1037