LinearAlgebra.C

Go to the documentation of this file.
00001 /*!@file Image/LinearAlgebra.C */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005   //
00005 // by the University of Southern California (USC) and the iLab at USC.  //
00006 // See http://iLab.usc.edu for information about this project.          //
00007 // //////////////////////////////////////////////////////////////////// //
00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00010 // in Visual Environments, and Applications'' by Christof Koch and      //
00011 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00012 // pending; application number 09/912,225 filed July 23, 2001; see      //
00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00014 // //////////////////////////////////////////////////////////////////// //
00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00016 //                                                                      //
00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00018 // redistribute it and/or modify it under the terms of the GNU General  //
00019 // Public License as published by the Free Software Foundation; either  //
00020 // version 2 of the License, or (at your option) any later version.     //
00021 //                                                                      //
00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00025 // PURPOSE.  See the GNU General Public License for more details.       //
00026 //                                                                      //
00027 // You should have received a copy of the GNU General Public License    //
00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00030 // Boston, MA 02111-1307 USA.                                           //
00031 // //////////////////////////////////////////////////////////////////// //
00032 //
00033 // Primary maintainer for this file: Rob Peters <rjpeters@usc.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Image/LinearAlgebra.C $
00035 // $Id: LinearAlgebra.C 9412 2008-03-10 23:10:15Z farhan $
00036 //
00037 
00038 #ifndef IMAGE_LINEARALGEBRA_C_DEFINED
00039 #define IMAGE_LINEARALGEBRA_C_DEFINED
00040 
00041 #include "Image/LinearAlgebra.H"
00042 
00043 #include "Image/Image.H"
00044 #include "Image/MatrixOps.H"
00045 #include "Image/gsl.H"
00046 #include "Image/lapack.H"
00047 #include "rutz/trace.h"
00048 
00049 namespace
00050 {
00051   // ############################################################
00052   template <class T>
00053   Image<T> invdiag(const Image<T>& x,
00054                    const T tolfactor,
00055                    int* const rank)
00056   {
00057     ASSERT(x.getWidth() == x.getHeight());
00058 
00059     Image<T> result(x.getDims(), ZEROS);
00060     if (rank != NULL) *rank = 0;
00061 
00062     const T thresh = tolfactor*x[0];
00063 
00064     const T eigtot = trace(x);
00065     T eigsum = 0.0;
00066     T eigkept = 0.0;
00067 
00068     for (int i = 0; i < x.getWidth(); ++i)
00069       {
00070         const T xval = x[Point2D<int>(i,i)];
00071 
00072         eigsum += xval;
00073 
00074         // if tolfactor is less than 1.0, then we take it to mean a
00075         // threshold at factor*eigenvalue0; if it is greater than 1.0,
00076         // then we take it to mean a count of the number of
00077         // eigenvectors to keep
00078 
00079         const bool discard =
00080           tolfactor < 1.0
00081           ? (xval < thresh)
00082           : (i >= int(tolfactor));
00083 
00084         LINFO("x[%d]=%g %s %5.2f%% (thresh=%g)",
00085               i, double(xval),
00086               discard ? "discarded" : "kept",
00087               eigtot > 0.0 ? double(100.0 * eigsum) / eigtot : 0.0,
00088               double(thresh));
00089 
00090         if (discard)
00091           result[Point2D<int>(i,i)] = 0.0;
00092         else
00093           {
00094             result[Point2D<int>(i,i)] = 1.0 / xval;
00095             if (rank != NULL) ++*rank;
00096             eigkept = eigsum;
00097           }
00098       }
00099 
00100     LINFO("retained eigenvalues account for %5.2f%% of total",
00101           eigtot > 0.0 ? double(100.0 * eigkept) / eigtot : 0.0);
00102     return result;
00103   }
00104 
00105 } // end unnamed namespace
00106 
00107 // ############################################################
00108 void svd(const Image<double>& A,
00109          Image<double>& U, Image<double>& S, Image<double>& V,
00110          SvdAlgo algo, SvdFlag flags)
00111 {
00112 GVX_TRACE(__PRETTY_FUNCTION__);
00113 
00114 #ifndef HAVE_LAPACK
00115   if (algo == SVD_LAPACK)
00116     {
00117       LINFO("SVD_LAPACK not available, using SVD_GSL instead");
00118       algo = SVD_GSL;
00119       flags |= SVD_TALL;
00120     }
00121 #endif
00122 
00123   switch (algo)
00124     {
00125 #ifdef HAVE_LAPACK
00126     case SVD_LAPACK:
00127       lapack::svd(A, U, S, V, flags);
00128       break;
00129 #endif
00130 
00131     case SVD_GSL:
00132       gsl::svd(A, U, S, V, flags);
00133       break;
00134 
00135     default:
00136       LFATAL("unknown SvdAlgo enumerant '%d'", int(algo));
00137     }
00138 }
00139 
00140 // ############################################################
00141 void svdf(const Image<float>& A,
00142           Image<float>& U, Image<float>& S, Image<float>& V,
00143           SvdAlgo algo, SvdFlag flags)
00144 {
00145 GVX_TRACE(__PRETTY_FUNCTION__);
00146 
00147 #ifndef HAVE_LAPACK
00148   if (algo == SVD_LAPACK)
00149     {
00150       LINFO("SVD_LAPACK not available, using SVD_GSL instead");
00151       algo = SVD_GSL;
00152       flags |= SVD_TALL;
00153     }
00154 #endif
00155 
00156   switch (algo)
00157     {
00158 #ifdef HAVE_LAPACK
00159     case SVD_LAPACK:
00160       lapack::svdf(A, U, S, V, flags);
00161       break;
00162 #endif
00163 
00164     case SVD_GSL:
00165       gsl::svdf(A, U, S, V, flags);
00166       break;
00167 
00168     default:
00169       LFATAL("unknown SvdAlgo enumerant '%d'", int(algo));
00170     }
00171 }
00172 
00173 // ############################################################
00174 Image<double> svdPseudoInv(const Image<double>& x,
00175                            const SvdAlgo algo,
00176                            int* const rank,
00177                            const double tolfactor)
00178 {
00179 GVX_TRACE(__PRETTY_FUNCTION__);
00180 
00181   Image<double> U, S, V;
00182   svd(x, U, S, V, algo);
00183 
00184   LINFO("U is %dx%d", U.getHeight(), U.getWidth());
00185   LINFO("S is %dx%d", S.getHeight(), S.getWidth());
00186   LINFO("V is %dx%d", V.getHeight(), V.getWidth());
00187 
00188   // FIXME this could probably be made significantly more efficient,
00189   // by taking advantage of the fact that S is a diagonal matrix, and
00190   // by rolling transpose(U) directly into the matrix multiplication
00191   return matrixMult(V, matrixMult(invdiag(S, tolfactor, rank),
00192                                   transpose(U)));
00193 }
00194 
00195 // ############################################################
00196 Image<float> svdPseudoInvf(const Image<float>& x,
00197                            const SvdAlgo algo,
00198                            int* const rank,
00199                            const float tolfactor)
00200 {
00201 GVX_TRACE(__PRETTY_FUNCTION__);
00202 
00203   Image<float> U, S, V;
00204   svdf(x, U, S, V, algo);
00205 
00206   LINFO("U is %dx%d", U.getHeight(), U.getWidth());
00207   LINFO("S is %dx%d", S.getHeight(), S.getWidth());
00208   LINFO("V is %dx%d", V.getHeight(), V.getWidth());
00209 
00210   return matrixMult(V, matrixMult(invdiag(S, tolfactor, rank),
00211                                   transpose(U)));
00212 }
00213 
00214 // ############################################################
00215 template <class T>
00216 Image<typename promote_trait<T, float>::TP>
00217 naiveUnstablePseudoInv(const Image<T>& M)
00218 {
00219 GVX_TRACE(__PRETTY_FUNCTION__);
00220 
00221   /*
00222     pseudoinverse(M) = inv(M'*M) * M'
00223 
00224     where M' is the transpose of M, and '*' is matrix
00225     multiplication
00226 
00227     see comments in the header file about why this approach is
00228     numerically unstable, though
00229   */
00230 
00231   typedef typename promote_trait<T, float>::TP TF;
00232 
00233   const Image<TF> m(M);
00234   const Image<TF> mt(transpose(M));
00235   const Image<TF> mtm = matrixMult(mt, m);
00236   const Image<TF> invmtm = matrixInv(mtm);
00237 
00238   return matrixMult(invmtm, mt);
00239 }
00240 
00241 // Include the explicit instantiations
00242 #include "inst/Image/LinearAlgebra.I"
00243 
00244 template Image<promote_trait<double, float>::TP> naiveUnstablePseudoInv(const Image<double>&);
00245 
00246 // ######################################################################
00247 /* So things look consistent in everyone's emacs... */
00248 /* Local Variables: */
00249 /* indent-tabs-mode: nil */
00250 /* End: */
00251 
00252 #endif // IMAGE_LINEARALGEBRA_C_DEFINED
Generated on Sun May 8 08:40:55 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3