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