TooN 2.1
|
00001 // -*- c++ -*- 00002 00003 // Copyright (C) 2009 Ed Rosten (er258@cam.ac.uk) 00004 // 00005 // This file is part of the TooN Library. This library is free 00006 // software; you can redistribute it and/or modify it under the 00007 // terms of the GNU General Public License as published by the 00008 // Free Software Foundation; either version 2, or (at your option) 00009 // any later version. 00010 00011 // This library is distributed in the hope that it will be useful, 00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 // GNU General Public License for more details. 00015 00016 // You should have received a copy of the GNU General Public License along 00017 // with this library; see the file COPYING. If not, write to the Free 00018 // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, 00019 // USA. 00020 00021 // As a special exception, you may use this file as part of a free software 00022 // library without restriction. Specifically, if other files instantiate 00023 // templates or use macros or inline functions from this file, or you compile 00024 // this file and link it with other files to produce an executable, this 00025 // file does not by itself cause the resulting executable to be covered by 00026 // the GNU General Public License. This exception does not however 00027 // invalidate any other reasons why the executable file might be covered by 00028 // the GNU General Public License. 00029 00030 00031 #ifndef TOON_INC_GAUSS_JORDAN_H 00032 #define TOON_INC_GAUSS_JORDAN_H 00033 00034 #include <utility> 00035 #include <cmath> 00036 #include <TooN/TooN.h> 00037 00038 namespace TooN 00039 { 00040 /// Perform Gauss-Jordan reduction on m 00041 /// 00042 /// If m is of the form \f$[A | I ]\f$, then after reduction, m 00043 /// will be \f$[ I | A^{-1}]\f$. There is no restriction on the input, 00044 /// in that the matrix augmenting A does not need to be I, or square. 00045 /// The reduction is performed using elementary row operations and 00046 /// partial pivoting. 00047 /// 00048 /// @param m The matrix to be reduced. 00049 /// @ingroup gDecomps 00050 template<int R, int C, class Precision, class Base> void gauss_jordan(Matrix<R, C, Precision, Base>& m) 00051 { 00052 using std::swap; 00053 00054 //Loop over columns to reduce. 00055 for(int col=0; col < m.num_rows(); col++) 00056 { 00057 //Reduce the current column to a single element 00058 00059 00060 //Search down the current column in the lower triangle for the largest 00061 //absolute element (pivot). Then swap the pivot row, so that the pivot 00062 //element is on the diagonal. The benchmarks show that it is actually 00063 //faster to swap whole rows than it is to access the rows via indirection 00064 //and swap the indirection element. This holds for both pointer indirection 00065 //and using a permutation vector over rows. 00066 { 00067 using std::abs; 00068 int pivotpos = col; 00069 double pivotval = abs(m[pivotpos][col]); 00070 for(int p=col+1; p <m.num_rows(); p++) 00071 if(abs(m[p][col]) > pivotval) 00072 { 00073 pivotpos = p; 00074 pivotval = abs(m[pivotpos][col]); 00075 } 00076 00077 if(col != pivotpos) 00078 swap(m[col].ref(), m[pivotpos].ref()); 00079 } 00080 00081 //Reduce the current column in every row to zero, excluding elements on 00082 //the leading diagonal. 00083 for(int row = 0; row < m.num_rows(); row++) 00084 { 00085 if(row != col) 00086 { 00087 double multiple = m[row][col] / m[col][col]; 00088 00089 //We could eliminate some of the computations in the augmented 00090 //matrix, if the augmented half is the identity. In general, it 00091 //is not. 00092 00093 //Subtract the pivot row from all other rows, to make 00094 //column col zero. 00095 m[row][col] = 0; 00096 for(int c=col+1; c < m.num_cols(); c++) 00097 m[row][c] = m[row][c] - m[col][c] * multiple; 00098 } 00099 } 00100 } 00101 00102 //Final pass to make diagonal elements one. Performing this in a final 00103 //pass allows us to avoid any significant computations on the left-hand 00104 //square matrix, since it is diagonal, and ends up as the identity. 00105 for(int row=0;row < m.num_rows(); row++) 00106 { 00107 double mul = 1/m[row][row]; 00108 00109 m[row][row] = 1; 00110 00111 for(int col=m.num_rows(); col < m.num_cols(); col++) 00112 m[row][col] *= mul; 00113 } 00114 } 00115 00116 } 00117 #endif