cmtkMathUtil_LinAlg.cxx

Go to the documentation of this file.
00001 /*
00002 //
00003 //  Copyright 1997-2009 Torsten Rohlfing
00004 //
00005 //  Copyright 2004-2011 SRI International
00006 //
00007 //  This file is part of the Computational Morphometry Toolkit.
00008 //
00009 //  http://www.nitrc.org/projects/cmtk/
00010 //
00011 //  The Computational Morphometry Toolkit is free software: you can
00012 //  redistribute it and/or modify it under the terms of the GNU General Public
00013 //  License as published by the Free Software Foundation, either version 3 of
00014 //  the License, or (at your option) any later version.
00015 //
00016 //  The Computational Morphometry Toolkit is distributed in the hope that it
00017 //  will be useful, but WITHOUT ANY WARRANTY; without even the implied
00018 //  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019 //  GNU General Public License for more details.
00020 //
00021 //  You should have received a copy of the GNU General Public License along
00022 //  with the Computational Morphometry Toolkit.  If not, see
00023 //  <http://www.gnu.org/licenses/>.
00024 //
00025 //  $Revision: 2731 $
00026 //
00027 //  $LastChangedDate: 2011-01-13 16:22:47 -0800 (Thu, 13 Jan 2011) $
00028 //
00029 //  $LastChangedBy: torstenrohlfing $
00030 //
00031 */
00032 
00033 #include <Base/cmtkMathUtil.h>
00034 #include <Base/cmtkMatrix.h>
00035 
00036 #include <System/cmtkConsole.h>
00037 
00038 #include "Numerics/sevd.h"
00039 #include "Numerics/spddet.h"
00040 #include "Numerics/svd.h"
00041 
00042 #include <math.h>
00043 #include <algorithm>
00044 #include <vector>
00045 
00046 namespace
00047 cmtk
00048 {
00049 
00052 
00053 template<class T>
00054 void
00055 MathUtil::ComputeEigensystem
00056 ( const Matrix2D<T>& matrix, Matrix2D<T>& eigenvectors,  std::vector<T>& eigenvalues )
00057 {
00058   const size_t n = matrix.GetNumberOfColumns();
00059 
00060   /*  Convert Matrix2D to ap::real_2d_array
00061    *  and Array to ap::real_1d_array
00062    */
00063   ap::real_2d_array apMatrix;
00064   apMatrix.setbounds(0, (int)matrix.GetNumberOfRows(), 0, (int)matrix.GetNumberOfColumns());
00065   for (size_t j = 0; j < n; j++)
00066     for (size_t i = 0; i < n; i++)
00067       apMatrix(i,j) = (double)(1.0 * matrix[i][j]);
00068 
00069   ap::real_1d_array apEigenvalues;
00070   apEigenvalues.setbounds(0, eigenvalues.size());
00071   for (size_t i = 0; i < eigenvalues.size(); i++)
00072         apEigenvalues(i) = (double)(1.0 * eigenvalues[i]);
00073 
00074 
00075   ap::real_2d_array apEigenvectors;
00076   apEigenvectors.setbounds(0, (int)matrix.GetNumberOfRows(), 0, (int)matrix.GetNumberOfColumns());
00077 
00078   /*  Run AlgLib eigensystem computation
00079    */
00080   if ( ! smatrixevd(apMatrix, (int)n, 1, true, apEigenvalues, apEigenvectors) )
00081     {
00082     StdErr << "WARNING: Something went wrong in smatrixevd\n";
00083     }
00084 
00085   /*  Convert ap::real_1d_array and ap::real_2d_array
00086    *  back to our data types.
00087    */
00088 
00089   for (size_t j = 0; j < n; j++)
00090     for (size_t i = 0; i < n; i++)
00091         eigenvectors[i][j] = static_cast<T>( apEigenvectors(i,j) );
00092 
00093   for (size_t i = 0; i < eigenvalues.size(); i++)
00094     eigenvalues[i] = static_cast<T>( apEigenvalues(i) );
00095 }
00096 
00097 template void MathUtil::ComputeEigensystem<float>( const Matrix2D<float>& matrix, Matrix2D<float>& eigensystem, std::vector<float>& eigenvalues );
00098 template void MathUtil::ComputeEigensystem<double>( const Matrix2D<double>& matrix, Matrix2D<double>& eigensystem, std::vector<double>& eigenvalues );
00099 
00100 template<class T>
00101 void
00102 MathUtil::ComputeEigenvalues
00103 ( const Matrix2D<T>& matrix, std::vector<T>& eigenvalues )
00104 {
00105   const size_t n = matrix.GetNumberOfColumns();
00106 
00107   /*  Convert Matrix2D to ap::real_2d_array
00108    *  and Array to ap::real_1d_array
00109    */
00110   ap::real_2d_array apMatrix;
00111   apMatrix.setbounds(0, (int)matrix.GetNumberOfRows(), 0, (int)matrix.GetNumberOfColumns());
00112   for (size_t j = 0; j < n; j++)
00113     for (size_t i = 0; i < n; i++)
00114       apMatrix(i,j) = (double)(1.0 * matrix[i][j]);
00115 
00116   ap::real_1d_array apEigenvalues;
00117   apEigenvalues.setbounds(0, eigenvalues.size());
00118   for (size_t i = 0; i < eigenvalues.size(); i++)
00119         apEigenvalues(i) = (double)(1.0 * eigenvalues[i]);
00120 
00121   ap::real_2d_array nullArray;
00122 
00123   /*  Run AlgLib eigenvalues computation
00124    */
00125   if ( !smatrixevd(apMatrix, (int)n, 0, true, apEigenvalues, nullArray) )
00126     {
00127     StdErr << "WARNING: Something went wrong in smatrixevd\n";
00128     }
00129 
00130   /*  Convert ap::real_1d_array and ap::real_2d_array
00131    *  back to our data types.
00132    */
00133 
00134   for (size_t i = 0; i < n; i++)
00135     for (size_t j = 0; j < n; j++)
00136         matrix[i][j] = static_cast<T>( apMatrix(i,j) );
00137 
00138   for (size_t i = 0; i < eigenvalues.size(); i++)
00139     eigenvalues[i] = static_cast<T>( apEigenvalues(i) );
00140 }
00141 
00142 template void MathUtil::ComputeEigenvalues<float>( const Matrix2D<float>& matrix, std::vector<float>& eigenvalues );
00143 template void MathUtil::ComputeEigenvalues<double>( const Matrix2D<double>& matrix, std::vector<double>& eigenvalues );
00144 
00145 void 
00146 MathUtil::SVD( Matrix2D<double> *U, size_t m, size_t n, std::vector<double> *W, Matrix2D<double> *V )
00147 {
00148   ap::real_2d_array apA;
00149   apA.setbounds(0, m-1, 0, n-1);
00150   for (size_t j = 0; j < n; j++)
00151     for (size_t i = 0; i < m; i++)
00152       apA(i,j) = (double) (*U)[i][j];
00153 
00154   ap::real_1d_array w;
00155   ap::real_2d_array u;
00156   ap::real_2d_array vt;
00157 
00158   rmatrixsvd( apA, m, n, 
00159               true /* U needed */, 
00160               true /* V needed */, 
00161               2 /*max-level memory usage */, 
00162               w, u, vt);
00163 
00164   /* Put u in U */
00165   for (size_t j = 0; j < n; j++)
00166     for (size_t i = 0; i < m; i++)
00167       (*U)[i][j] = u(i,j);
00168   
00169   /* Put w in W */
00170   for (size_t i = 0; i < n; i++)
00171     (*W)[i] = w(i);
00172   
00173   /* Un-transpose vt and put it in V */
00174   for (size_t j = 0; j < n; j++)
00175     for (size_t i = 0; i < n; i++)
00176       (*V)[i][j] = vt(j,i);
00177 
00178 }
00179 
00182 void
00183 MathUtil::SVDLinearRegression( Matrix2D<double> *U, size_t m, size_t n, std::vector<double> *W, Matrix2D<double> *V, double *b, std::vector<double>& lm_params )
00184 {
00185     // From alglib linear regression:
00186     // Take the inverses of the singular values, setting the inverse 
00187     // to 0 if the sv is close to 0 (tolerance controlled by epstol)
00188     double epstol = 1000;
00189     ap::real_1d_array svi;
00190     svi.setbounds( 0, n-1 );
00191     for( size_t i = 0; i < n; i++ )
00192       if( (*W)[i] > epstol*ap::machineepsilon * (*W)[0] )
00193         svi(i) = 1 / (*W)[i];
00194       else
00195         svi(i) = 0;
00196 
00197     // Calculate linear model parameters following Heath, Ch. 3.6
00198     // (Scientific Computing: An Introductory Survey, 2nd Ed., 2002)
00199     for ( size_t i = 0; i < n; i++ )
00200       lm_params[i] = 0.0;
00201     double ut_times_b; 
00202     
00203     for ( size_t i = 0; i < n; i++ )
00204       {
00205       ut_times_b = 0.0;
00206       for ( size_t j = 0; j < m; j++ )
00207         ut_times_b += (*U)[j][i] * b[j];
00208       ut_times_b *= svi(i);
00209       for ( size_t j = 0; j < n; j++ )
00210         lm_params[j] += ut_times_b * (*V)[j][i]; 
00211       }
00212 }
00213 
00215 // HELPERS
00217 
00218 template<class T> 
00219 T
00220 MathUtil::CholeskyDeterminant
00221 (const Matrix2D<T>& matrix, int n)
00222 {    
00223   ap::real_2d_array apMatrix;
00224   apMatrix.setbounds(0, n-1, 0, n-1);
00225   for (int j = 0; j < n; j++)
00226     for (int i = 0; i < n; i++)
00227       apMatrix(i,j) = (double)(1.0 * matrix[i][j]);
00228   spdmatrixcholesky( apMatrix, n, false );
00229   T determinant = (T) spdmatrixcholeskydet( apMatrix, n );
00230   return determinant;
00231 }
00232 
00233 template double MathUtil::CholeskyDeterminant<double>(const Matrix2D<double>& matrix, int n);
00234 template float MathUtil::CholeskyDeterminant<float>(const Matrix2D<float>& matrix, int n);
00235 
00236 } // namespace cmtk
00237 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines