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