TooN 2.1
gauss_jordan.h
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