gsl.C

Go to the documentation of this file.
00001 /*!@file Image/gsl.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 at usc dot edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Image/gsl.C $
00035 // $Id: gsl.C 14376 2011-01-11 02:44:34Z pez $
00036 //
00037 
00038 /* NOTE: Most of the code here in Image/gsl.C is drawn from
00039    the GNU Scientific Library (also under the GPL) with little or no
00040    modification. See http://www.gnu.org/software/gsl/ for information
00041    about the GSL. Original copyright notice:
00042 
00043    Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman, Brian Gough
00044 */
00045 
00046 #ifndef IMAGE_GSL_C_DEFINED
00047 #define IMAGE_GSL_C_DEFINED
00048 
00049 #include "Image/gsl.H"
00050 
00051 #include "Image/Image.H"
00052 #include "Image/LinearAlgebraFlags.H"
00053 #include "Util/log.H"
00054 #include "rutz/compat_cmath.h" // for isnan()
00055 #include "rutz/shared_ptr.h"
00056 #include "rutz/trace.h"
00057 
00058 #include <algorithm>
00059 #include <cstdlib>
00060 
00061 namespace
00062 {
00063   inline int OFFSET(int N, int incX)
00064   {
00065     return
00066       incX > 0
00067       ? 0
00068       : (N - 1) * (-incX);
00069   }
00070 
00071   const double DBL_EPSILON = 2.2204460492503131e-16;
00072 }
00073 
00074 // ############################################################
00075 // declarations of types in gsl namespace
00076 namespace gsl
00077 {
00078   template <class T> class view_of;
00079   class block;
00080   class vector;
00081   class matrix;
00082 }
00083 
00084 // ############################################################
00085 // gsl::view_of
00086 template <class T>
00087 struct gsl::view_of
00088 {
00089   view_of(const T& x) : viewee(x) {}
00090 
00091   view_of(const view_of& that) : viewee(that.viewee) {}
00092 
00093   T viewee;
00094 
00095 private:
00096   // no default constructor allowed
00097   view_of();
00098 
00099   // no assignment operator allowed, because it would be confusing as
00100   // to whether the assignment involves assignment of value or of
00101   // reference
00102   view_of& operator=(const view_of&);
00103 };
00104 
00105 // ############################################################
00106 // gsl::block
00107 struct gsl::block
00108 {
00109   block(const size_t n)
00110     :
00111     size(n),
00112     data(new double[n])
00113   {}
00114 
00115   ~block()
00116   {
00117     delete [] data;
00118   }
00119 
00120   size_t size;
00121   double* data;
00122 
00123 private:
00124   block(const block&);
00125   block& operator=(const block&);
00126 };
00127 
00128 // ############################################################
00129 // gsl::vector
00130 struct gsl::vector
00131 {
00132   vector() : size(0), stride(0), data(0), block(0), owner(0) {}
00133 
00134   vector(size_t n)
00135     :
00136     block()
00137   {
00138     if (n == 0)
00139       {
00140         LFATAL ("vector length n must be positive integer");
00141       }
00142 
00143     block.reset( new gsl::block (n) );
00144     size = n;
00145     stride = 1;
00146     owner = 1;
00147     data = block->data;
00148   }
00149 
00150   void copy_of(const vector& src)
00151   {
00152     const size_t src_size = src.size;
00153     const size_t this_size = this->size;
00154 
00155     if (src_size != this_size)
00156       {
00157         LFATAL("vector lengths are not equal");
00158       }
00159 
00160     const size_t src_stride = src.stride;
00161     const size_t this_stride = this->stride;
00162 
00163     for (size_t j = 0; j < src_size; j++)
00164       {
00165         this->data[this_stride * j] = src.data[src_stride * j];
00166       }
00167   }
00168 
00169   void swap_elements(const size_t i, const size_t j)
00170   {
00171     double* const data = this->data;
00172     const size_t size = this->size;
00173     const size_t stride = this->stride;
00174 
00175     if (i >= size)
00176       {
00177         LFATAL("first index is out of range");
00178       }
00179 
00180     if (j >= size)
00181       {
00182         LFATAL("second index is out of range");
00183       }
00184 
00185     if (i != j)
00186       {
00187         const double tmp = data[j*stride];
00188         data[j*stride] = data[i*stride];
00189         data[i*stride] = tmp;
00190       }
00191   }
00192 
00193   double at(const size_t i) const
00194   {
00195 #if GSL_RANGE_CHECK
00196     if (i >= this->size)
00197       {
00198         LFATAL ("index out of range");
00199       }
00200 #endif
00201     return this->data[i * this->stride];
00202   }
00203 
00204   double& at(const size_t i)
00205   {
00206 #if GSL_RANGE_CHECK
00207     if (i >= this->size)
00208       {
00209         LFATAL ("index out of range");
00210       }
00211 #endif
00212     return this->data[i * this->stride];
00213   }
00214 
00215   double get(const size_t i) const
00216   {
00217     return this->at(i);
00218   }
00219 
00220   void set(const size_t i, const double x)
00221   {
00222     this->at(i) = x;
00223   }
00224 
00225   void set_all (double x)
00226   {
00227     double* const data = this->data;
00228     const size_t n = this->size;
00229     const size_t stride = this->stride;
00230 
00231     for (size_t i = 0; i < n; ++i)
00232       {
00233         data[i * stride] = x;
00234       }
00235   }
00236 
00237   view_of<vector> subvector(const size_t offset, const size_t n)
00238   {
00239     return subvector_impl(offset, n);
00240   }
00241 
00242   view_of<const vector> subvector(const size_t offset,
00243                                   const size_t n) const
00244   {
00245     return subvector_impl(offset, n);
00246   }
00247 
00248   size_t size;
00249   size_t stride;
00250   double* data;
00251   rutz::shared_ptr<gsl::block> block;
00252   int owner;
00253 
00254 private:
00255   vector subvector_impl(const size_t offset, const size_t n) const
00256   {
00257     if (n == 0)
00258       {
00259         LFATAL ("vector length n must be positive integer");
00260       }
00261 
00262     if (offset + (n - 1) >= this->size)
00263       {
00264         LFATAL ("view would extend past end of vector");
00265       }
00266 
00267     vector s;
00268 
00269     s.data = this->data +  this->stride * offset;
00270     s.size = n;
00271     s.stride = this->stride;
00272     s.block = this->block;
00273     s.owner = 0;
00274 
00275     return s;
00276   }
00277 };
00278 
00279 // ############################################################
00280 // gsl::matrix
00281 struct gsl::matrix
00282 {
00283   matrix()
00284     :
00285     mrows(0), ncols(0), tda(0), data(0), block(), owner()
00286   {}
00287 
00288   matrix(const size_t n1, const size_t n2)
00289   {
00290     this->block.reset( new gsl::block (n1 * n2) );
00291 
00292     this->data = block->data;
00293     this->mrows = n1;
00294     this->ncols = n2;
00295     this->tda = n2;
00296     this->owner = 1;
00297   }
00298 
00299   double at(const size_t i, const size_t j) const
00300   {
00301 #if GSL_RANGE_CHECK
00302     if (i >= this->mrows)
00303       {
00304         LFATAL("first index out of range");
00305       }
00306     else if (j >= this->ncols)
00307       {
00308         LFATAL("second index out of range");
00309       }
00310 #endif
00311     return this->data[i * this->tda + j];
00312   }
00313 
00314   double& at(const size_t i, const size_t j)
00315   {
00316 #if GSL_RANGE_CHECK
00317     if (i >= this->mrows)
00318       {
00319         LFATAL("first index out of range");
00320       }
00321     else if (j >= this->ncols)
00322       {
00323         LFATAL("second index out of range");
00324       }
00325 #endif
00326     return this->data[i * this->tda + j];
00327   }
00328 
00329   double get(const size_t i, const size_t j) const
00330   {
00331     return this->at(i,j);
00332   }
00333 
00334   void set(const size_t i, const size_t j, const double x)
00335   {
00336     this->at(i,j) = x;
00337   }
00338 
00339   size_t mrows;
00340   size_t ncols;
00341   size_t tda;
00342   double* data;
00343   rutz::shared_ptr<gsl::block> block;
00344   int owner;
00345 };
00346 
00347 // ############################################################
00348 // helper functions for gsl::matrix, gsl::vector, etc.
00349 namespace
00350 {
00351   // ############################################################
00352   void set_identity (gsl::matrix& m)
00353   {
00354     GVX_TRACE("set_identity");
00355     double* const data = m.data;
00356     const size_t p = m.mrows;
00357     const size_t q = m.ncols;
00358     const size_t tda = m.tda;
00359 
00360     for (size_t i = 0; i < p; ++i)
00361       {
00362         for (size_t j = 0; j < q; ++j)
00363           {
00364             data[i * tda + j] = ((i == j) ? 1.0 : 0.0);
00365           }
00366       }
00367   }
00368 
00369   // ############################################################
00370   void set_all (gsl::matrix& m, const double x)
00371   {
00372     GVX_TRACE("set_all");
00373 
00374     double* const data = m.data;
00375     const size_t p = m.mrows;
00376     const size_t q = m.ncols;
00377     const size_t tda = m.tda;
00378 
00379     for (size_t i = 0; i < p; ++i)
00380       {
00381         for (size_t j = 0; j < q; ++j)
00382           {
00383             data[i * tda + j] = x;
00384           }
00385       }
00386   }
00387 
00388   // ############################################################
00389   gsl::view_of<gsl::matrix>
00390   submatrix_of (gsl::matrix& m,
00391                 const size_t i, const size_t j,
00392                 const size_t n1, const size_t n2)
00393   {
00394     GVX_TRACE("submatrix_of");
00395 
00396     if (i >= m.mrows)
00397       {
00398         LFATAL ("row index is out of range");
00399       }
00400     else if (j >= m.ncols)
00401       {
00402         LFATAL ("column index is out of range");
00403       }
00404     else if (n1 == 0)
00405       {
00406         LFATAL ("first dimension must be non-zero");
00407       }
00408     else if (n2 == 0)
00409       {
00410         LFATAL ("second dimension must be non-zero");
00411       }
00412     else if (i + n1 > m.mrows)
00413       {
00414         LFATAL ("first dimension overflows matrix");
00415       }
00416     else if (j + n2 > m.ncols)
00417       {
00418         LFATAL ("second dimension overflows matrix");
00419       }
00420 
00421     gsl::matrix s;
00422 
00423     s.data = m.data + (i * m.tda + j);
00424     s.mrows = n1;
00425     s.ncols = n2;
00426     s.tda = m.tda;
00427     s.block = m.block;
00428     s.owner = 0;
00429 
00430     return gsl::view_of<gsl::matrix>(s);
00431   }
00432 
00433   // ############################################################
00434   gsl::view_of<gsl::vector>
00435   row_of (gsl::matrix& m, const size_t i)
00436   {
00437     if (i >= m.mrows)
00438       {
00439         LFATAL("row index is out of range");
00440       }
00441 
00442     gsl::vector v;
00443 
00444     v.data = m.data + i * m.tda;
00445     v.size = m.ncols;
00446     v.stride = 1;
00447     v.block = m.block;
00448     v.owner = 0;
00449 
00450     return gsl::view_of<gsl::vector>(v);
00451   }
00452 
00453   // ############################################################
00454   gsl::view_of<gsl::vector>
00455   column_of (gsl::matrix& m, const size_t j)
00456   {
00457     if (j >= m.ncols)
00458       {
00459         LFATAL("column index is out of range");
00460       }
00461 
00462     gsl::vector v;
00463 
00464     v.data = m.data + j;
00465     v.size = m.mrows;
00466     v.stride = m.tda;
00467     v.block = m.block;
00468     v.owner = 0;
00469 
00470     return gsl::view_of<gsl::vector>(v);
00471   }
00472 
00473   // ############################################################
00474   gsl::view_of<const gsl::vector>
00475   const_row (const gsl::matrix& m, const size_t i)
00476   {
00477     GVX_TRACE("const_row");
00478     if (i >= m.mrows)
00479       {
00480         LFATAL("row index is out of range");
00481       }
00482 
00483     gsl::vector v;
00484 
00485     v.data = m.data + i * m.tda;
00486     v.size = m.ncols;
00487     v.stride = 1;
00488     v.block = m.block;
00489     v.owner = 0;
00490 
00491     return gsl::view_of<const gsl::vector>(v);
00492   }
00493 
00494   // ############################################################
00495   gsl::view_of<const gsl::vector>
00496   const_column (const gsl::matrix& m, const size_t j)
00497   {
00498     GVX_TRACE("const_column");
00499 
00500     if (j >= m.ncols)
00501       {
00502         LFATAL("column index is out of range");
00503       }
00504 
00505     gsl::vector v;
00506 
00507     v.data = m.data + j;
00508     v.size = m.mrows;
00509     v.stride = m.tda;
00510     v.block = m.block;
00511     v.owner = 0;
00512 
00513     return gsl::view_of<const gsl::vector>(v);
00514   }
00515 
00516   // ############################################################
00517   void swap_rows (gsl::matrix& m, const size_t i, const size_t j)
00518   {
00519     GVX_TRACE("swap_rows");
00520     const size_t mrows = m.mrows;
00521     const size_t ncols = m.ncols;
00522 
00523     if (i >= mrows)
00524       {
00525         LFATAL("first row index is out of range");
00526       }
00527 
00528     if (j >= mrows)
00529       {
00530         LFATAL("second row index is out of range");
00531       }
00532 
00533     if (i != j)
00534       {
00535         double* row1 = m.data + i * m.tda;
00536         double* row2 = m.data + j * m.tda;
00537 
00538         size_t k;
00539 
00540         for (k = 0; k < ncols; k++)
00541           {
00542             double tmp = row1[k];
00543             row1[k] = row2[k];
00544             row2[k] = tmp;
00545           }
00546       }
00547   }
00548 
00549   // ############################################################
00550   void swap_columns (gsl::matrix& m, const size_t i, const size_t j)
00551   {
00552     GVX_TRACE("swap_columns");
00553     const size_t mrows = m.mrows;
00554     const size_t ncols = m.ncols;
00555 
00556     if (i >= ncols)
00557       {
00558         LFATAL("first column index is out of range");
00559       }
00560 
00561     if (j >= ncols)
00562       {
00563         LFATAL("second column index is out of range");
00564       }
00565 
00566     if (i != j)
00567       {
00568         double* const col1 = m.data + i;
00569         double* const col2 = m.data + j;
00570 
00571         for (size_t p = 0; p < mrows; ++p)
00572           {
00573             size_t n = p * m.tda;
00574 
00575             double tmp = col1[n];
00576             col1[n] = col2[n];
00577             col2[n] = tmp;
00578           }
00579       }
00580   }
00581 
00582   // ############################################################
00583   inline double blas_ddot (const gsl::vector& X, const gsl::vector& Y)
00584   {
00585     if (X.size != Y.size)
00586       LFATAL("invalid length");
00587 
00588     const int N = X.size;
00589     const double* const Xdat = X.data;
00590     const int incX = X.stride;
00591     const double* const Ydat = Y.data;
00592     const int incY = Y.stride;
00593 
00594     double r = 0.0;
00595 
00596     if (incX == 1 && incY == 1)
00597       {
00598         const int m = N % 8;
00599 
00600         for (int i = 0; i < m; ++i)
00601           r += Xdat[i] * Ydat[i];
00602 
00603         for (int i = m; i + 7 < N; i += 8)
00604           {
00605             r += Xdat[i + 0] * Ydat[i + 0];
00606             r += Xdat[i + 1] * Ydat[i + 1];
00607             r += Xdat[i + 2] * Ydat[i + 2];
00608             r += Xdat[i + 3] * Ydat[i + 3];
00609             r += Xdat[i + 4] * Ydat[i + 4];
00610             r += Xdat[i + 5] * Ydat[i + 5];
00611             r += Xdat[i + 6] * Ydat[i + 6];
00612             r += Xdat[i + 7] * Ydat[i + 7];
00613           }
00614       }
00615     else
00616       {
00617         int ix = OFFSET(N, incX);
00618         int iy = OFFSET(N, incY);
00619 
00620         for (int i = 0; i < N; i++)
00621           {
00622             r += Xdat[ix] * Ydat[iy];
00623             ix += incX;
00624             iy += incY;
00625           }
00626       }
00627 
00628     return r;
00629   }
00630 
00631   // ############################################################
00632   double blas_dnrm2 (const gsl::vector& Xv)
00633   {
00634     const int N = Xv.size;
00635     const double* X = Xv.data;
00636     const int incX = Xv.stride;
00637 
00638     if (N <= 0 || incX <= 0)
00639       return 0;
00640 
00641     if (N == 1)
00642       return fabs(X[0]);
00643 
00644     double scale = 0.0;
00645     double ssq = 1.0;
00646     int ix = 0;
00647 
00648     for (int i = 0; i < N; ++i) {
00649       const double x = X[ix];
00650 
00651       if (x != 0.0) {
00652         const double ax = fabs(x);
00653 
00654         if (scale < ax) {
00655           ssq = 1.0 + ssq * (scale / ax) * (scale / ax);
00656           scale = ax;
00657         } else {
00658           ssq += (ax / scale) * (ax / scale);
00659         }
00660       }
00661 
00662       ix += incX;
00663     }
00664 
00665     return scale * sqrt(ssq);
00666   }
00667 
00668   // ############################################################
00669   inline void blas_dscal (const double alpha, gsl::vector& Xv)
00670   {
00671     const int N = Xv.size;
00672     double* X = Xv.data;
00673     const int incX = Xv.stride;
00674 
00675     if (incX <= 0)
00676       return;
00677 
00678     int ix = OFFSET(N, incX);
00679 
00680     for (int i = 0; i < N; ++i)
00681       {
00682         X[ix] *= alpha;
00683         ix += incX;
00684       }
00685   }
00686 
00687   // ############################################################
00688   // Y = Y + alpha x
00689   void blas_daxpy (double alpha, const gsl::vector& X, gsl::vector& Y)
00690   {
00691     if (X.size != Y.size)
00692       LFATAL("invalid length");
00693 
00694     const int N = X.size;
00695     const double* const Xdat = X.data;
00696     const int incX = X.stride;
00697     double* const Ydat = Y.data;
00698     const int incY = Y.stride;
00699 
00700     if (alpha == 0.0)
00701       {
00702         return;
00703       }
00704 
00705     if (incX == 1 && incY == 1)
00706       {
00707         const int m = N % 4;
00708 
00709         for (int i = 0; i < m; i++)
00710           Ydat[i] += alpha * Xdat[i];
00711 
00712         for (int i = m; i + 3 < N; i += 4)
00713           {
00714             Ydat[i + 0] += alpha * Xdat[i + 0];
00715             Ydat[i + 1] += alpha * Xdat[i + 1];
00716             Ydat[i + 2] += alpha * Xdat[i + 2];
00717             Ydat[i + 3] += alpha * Xdat[i + 3];
00718           }
00719       }
00720     else
00721       {
00722         int ix = OFFSET(N, incX);
00723         int iy = OFFSET(N, incY);
00724 
00725         for (int i = 0; i < N; i++)
00726           {
00727             Ydat[iy] += alpha * Xdat[ix];
00728             ix += incX;
00729             iy += incY;
00730           }
00731       }
00732   }
00733 
00734   // ############################################################
00735   double householder_transform (gsl::vector& v)
00736   {
00737     GVX_TRACE("householder_transform");
00738     /* replace v[0:n-1] with a householder vector (v[0:n-1]) and
00739        coefficient tau that annihilate v[1:n-1] */
00740 
00741     const size_t n = v.size;
00742 
00743     if (n == 1)
00744       {
00745         return 0.0; /* tau = 0 */
00746       }
00747     else
00748       {
00749         gsl::view_of<gsl::vector> x = v.subvector(1, n - 1);
00750 
00751         const double xnorm = blas_dnrm2 (x.viewee);
00752 
00753         if (xnorm == 0)
00754           {
00755             return 0.0; /* tau = 0 */
00756           }
00757 
00758         const double alpha = v.get(0);
00759         const double beta = - (alpha >= 0.0 ? +1.0 : -1.0) * hypot(alpha, xnorm);
00760         const double tau = (beta - alpha) / beta;
00761 
00762         blas_dscal (1.0 / (alpha - beta), x.viewee);
00763         v.set(0, beta);
00764 
00765         return tau;
00766       }
00767   }
00768 
00769   // ############################################################
00770   void householder_hm (double tau, const gsl::vector& v, gsl::matrix& A)
00771   {
00772     GVX_TRACE("householder_hm");
00773     /* applies a householder transformation v,tau to matrix m */
00774 
00775     if (tau == 0.0)
00776       return;
00777 
00778     gsl::view_of<const gsl::vector> v1 = v.subvector(1, v.size - 1);
00779     gsl::view_of<gsl::matrix> A1 = submatrix_of (A, 1, 0, A.mrows - 1, A.ncols);
00780 
00781     for (size_t j = 0; j < A.ncols; ++j)
00782       {
00783         gsl::view_of<gsl::vector> A1j = column_of(A1.viewee, j);
00784         double wj = blas_ddot (A1j.viewee, v1.viewee);
00785         wj += A.get(0,j);
00786 
00787         A.at(0, j) -= (tau * wj);
00788 
00789         blas_daxpy (-tau * wj, v1.viewee, A1j.viewee);
00790       }
00791   }
00792 
00793   // ############################################################
00794   int householder_mh (double tau, const gsl::vector& v, gsl::matrix& A)
00795   {
00796     GVX_TRACE("householder_mh");
00797     /* applies a householder transformation v,tau to matrix m from the
00798        right hand side in order to zero out rows */
00799 
00800     if (tau == 0)
00801       return 0;
00802 
00803     /* A = A - tau w v' */
00804 
00805     gsl::view_of<const gsl::vector> v1 = v.subvector(1, v.size - 1);
00806     gsl::view_of<gsl::matrix> A1 = submatrix_of (A, 0, 1, A.mrows, A.ncols-1);
00807 
00808     for (size_t i = 0; i < A.mrows; ++i)
00809       {
00810         gsl::view_of<gsl::vector> A1i = row_of(A1.viewee, i);
00811         double wi = blas_ddot (A1i.viewee, v1.viewee);
00812         wi += A.get(i,0);
00813 
00814         A.at(i,0) -= (tau * wi);
00815 
00816         blas_daxpy(-tau * wi, v1.viewee, A1i.viewee);
00817       }
00818 
00819     return 0;
00820   }
00821 
00822   // ############################################################
00823   int householder_hv (double tau, const gsl::vector& v, gsl::vector& w)
00824   {
00825     GVX_TRACE("householder_hv");
00826     /* applies a householder transformation v to vector w */
00827     const size_t N = v.size;
00828 
00829     if (tau == 0)
00830       return 0;
00831 
00832     {
00833       /* compute d = v'w */
00834 
00835       const double d0 = w.get(0);
00836 
00837       gsl::view_of<const gsl::vector> v1 = v.subvector(1, N-1);
00838       gsl::view_of<gsl::vector> w1 = w.subvector(1, N-1);
00839 
00840       const double d1 = blas_ddot (v1.viewee, w1.viewee);
00841 
00842       const double d = d0 + d1;
00843 
00844       /* compute w = w - tau (v) (v'w) */
00845 
00846       w.at(0) -= (tau * d);
00847 
00848       blas_daxpy (-tau * d, v1.viewee, w1.viewee);
00849     }
00850 
00851     return 0;
00852   }
00853 
00854 
00855   // ############################################################
00856   void householder_hm1 (const double tau, gsl::matrix& A)
00857   {
00858     GVX_TRACE("householder_hm1");
00859     /* applies a householder transformation v,tau to a matrix being
00860        build up from the identity matrix, using the first column of A as
00861        a householder vector */
00862 
00863     if (tau == 0)
00864       {
00865         A.set(0, 0, 1.0);
00866 
00867         for (size_t j = 1; j < A.ncols; ++j)
00868           {
00869             A.set(0, j, 0.0);
00870           }
00871 
00872         for (size_t i = 1; i < A.mrows; ++i)
00873           {
00874             A.set(i, 0, 0.0);
00875           }
00876 
00877         return;
00878       }
00879 
00880     /* w = A' v */
00881 
00882     gsl::view_of<gsl::matrix> A1 = submatrix_of (A, 1, 0, A.mrows - 1, A.ncols);
00883     gsl::view_of<gsl::vector> v1 = column_of (A1.viewee, 0);
00884 
00885     for (size_t j = 1; j < A.ncols; j++)
00886       {
00887         GVX_TRACE("householder_hm1-loop");
00888 
00889         /* A = A - tau v w' */
00890 
00891         gsl::view_of<gsl::vector> A1j = column_of(A1.viewee, j);
00892 
00893         const double wj = blas_ddot (v1.viewee, A1j.viewee);
00894         blas_daxpy(-tau*wj, v1.viewee, A1j.viewee);
00895 
00896         A.set(0, j, - tau *  wj);
00897       }
00898 
00899     blas_dscal(-tau, v1.viewee);
00900 
00901     A.set(0, 0, 1.0 - tau);
00902   }
00903 
00904 
00905   // ############################################################
00906   void create_givens (const double a, const double b,
00907                       double* c, double* s)
00908   {
00909     /* Generate a Givens rotation (cos,sin) which takes v=(x,y) to (|v|,0)
00910 
00911     From Golub and Van Loan, "Matrix Computations", Section 5.1.8 */
00912 
00913     if (b == 0)
00914       {
00915         *c = 1;
00916         *s = 0;
00917       }
00918     else if (fabs (b) > fabs (a))
00919       {
00920         const double t = -a / b;
00921         const double s1 = 1.0 / sqrt (1 + t * t);
00922         *s = s1;
00923         *c = s1 * t;
00924       }
00925     else
00926       {
00927         const double t = -b / a;
00928         const double c1 = 1.0 / sqrt (1 + t * t);
00929         *c = c1;
00930         *s = c1 * t;
00931       }
00932   }
00933 
00934   // ############################################################
00935   void chop_small_elements (gsl::vector& d, gsl::vector& f)
00936   {
00937     const size_t N = d.size;
00938     double d_i = d.get(0);
00939 
00940     for (size_t i = 0; i < N - 1; ++i)
00941       {
00942         double f_i = f.get(i);
00943         double d_ip1 = d.get(i + 1);
00944 
00945         if (fabs (f_i) < DBL_EPSILON * (fabs (d_i) + fabs (d_ip1)))
00946           {
00947             f.set(i, 0.0);
00948           }
00949         d_i = d_ip1;
00950       }
00951 
00952   }
00953 
00954   // ############################################################
00955   double trailing_eigenvalue (const gsl::vector& d, const gsl::vector& f)
00956   {
00957     GVX_TRACE("trailing_eigenvalue");
00958     const size_t n = d.size;
00959 
00960     const double da = d.get(n - 2);
00961     const double db = d.get(n - 1);
00962     const double fa = (n > 2) ? f.get(n - 3) : 0.0;
00963     const double fb = f.get(n - 2);
00964 
00965     const double ta = da * da + fa * fa;
00966     const double tb = db * db + fb * fb;
00967     const double tab = da * fb;
00968 
00969     const double dt = (ta - tb) / 2.0;
00970 
00971     double mu;
00972 
00973     if (dt >= 0)
00974       {
00975         mu = tb - (tab * tab) / (dt + hypot (dt, tab));
00976       }
00977     else
00978       {
00979         mu = tb + (tab * tab) / ((-dt) + hypot (dt, tab));
00980       }
00981 
00982     return mu;
00983   }
00984 
00985   // ############################################################
00986   void create_schur (double d0, double f0, double d1,
00987                      double* c, double* s)
00988   {
00989     GVX_TRACE("create_schur");
00990     const double apq = 2.0 * d0 * f0;
00991 
00992     if (apq != 0.0)
00993       {
00994         double t;
00995         const double tau = (f0*f0 + (d1 + d0)*(d1 - d0)) / apq;
00996 
00997         if (tau >= 0.0)
00998           {
00999             t = 1.0/(tau + hypot(1.0, tau));
01000           }
01001         else
01002           {
01003             t = -1.0/(-tau + hypot(1.0, tau));
01004           }
01005 
01006         *c = 1.0 / hypot(1.0, t);
01007         *s = t * (*c);
01008       }
01009     else
01010       {
01011         *c = 1.0;
01012         *s = 0.0;
01013       }
01014   }
01015 
01016   // ############################################################
01017   void svd2 (gsl::vector& d, gsl::vector& f, gsl::matrix& U, gsl::matrix& V)
01018   {
01019     GVX_TRACE("svd2");
01020 
01021     double c, s, a11, a12, a21, a22;
01022 
01023     const size_t M = U.mrows;
01024     const size_t N = V.mrows;
01025 
01026     const double d0 = d.get(0);
01027     const double f0 = f.get(0);
01028 
01029     const double d1 = d.get(1);
01030 
01031     if (d0 == 0.0)
01032       {
01033         /* Eliminate off-diagonal element in [0,f0;0,d1] to make [d,0;0,0] */
01034 
01035         create_givens (f0, d1, &c, &s);
01036 
01037         /* compute B <= G^T B X,  where X = [0,1;1,0] */
01038 
01039         d.set(0, c * f0 - s * d1);
01040         f.set(0, s * f0 + c * d1);
01041         d.set(1, 0.0);
01042 
01043         /* Compute U <= U G */
01044 
01045         for (size_t i = 0; i < M; ++i)
01046           {
01047             const double Uip = U.get(i, 0);
01048             const double Uiq = U.get(i, 1);
01049             U.set(i, 0, c * Uip - s * Uiq);
01050             U.set(i, 1, s * Uip + c * Uiq);
01051           }
01052 
01053         /* Compute V <= V X */
01054 
01055         swap_columns (V, 0, 1);
01056 
01057         return;
01058       }
01059     else if (d1 == 0.0)
01060       {
01061         /* Eliminate off-diagonal element in [d0,f0;0,0] */
01062 
01063         create_givens (d0, f0, &c, &s);
01064 
01065         /* compute B <= B G */
01066 
01067         d.set(0, d0 * c - f0 * s);
01068         f.set(0, 0.0);
01069 
01070         /* Compute V <= V G */
01071 
01072         for (size_t i = 0; i < N; ++i)
01073           {
01074             const double Vip = V.get(i, 0);
01075             const double Viq = V.get(i, 1);
01076             V.set(i, 0, c * Vip - s * Viq);
01077             V.set(i, 1, s * Vip + c * Viq);
01078           }
01079 
01080         return;
01081       }
01082     else
01083       {
01084         /* Make columns orthogonal, A = [d0, f0; 0, d1] * G */
01085 
01086         create_schur (d0, f0, d1, &c, &s);
01087 
01088         /* compute B <= B G */
01089 
01090         a11 = c * d0 - s * f0;
01091         a21 = - s * d1;
01092 
01093         a12 = s * d0 + c * f0;
01094         a22 = c * d1;
01095 
01096         /* Compute V <= V G */
01097 
01098         for (size_t i = 0; i < N; ++i)
01099           {
01100             double Vip = V.get(i, 0);
01101             double Viq = V.get(i, 1);
01102             V.set(i, 0, c * Vip - s * Viq);
01103             V.set(i, 1, s * Vip + c * Viq);
01104           }
01105 
01106         /* Eliminate off-diagonal elements, bring column with largest
01107            norm to first column */
01108 
01109         if (hypot(a11, a21) < hypot(a12,a22))
01110           {
01111             /* B <= B X */
01112 
01113             const double t1 = a11; a11 = a12; a12 = t1;
01114             const double t2 = a21; a21 = a22; a22 = t2;
01115 
01116             /* V <= V X */
01117 
01118             swap_columns(V, 0, 1);
01119           }
01120 
01121         create_givens (a11, a21, &c, &s);
01122 
01123         /* compute B <= G^T B */
01124 
01125         d.set(0, c * a11 - s * a21);
01126         f.set(0, c * a12 - s * a22);
01127         d.set(1, s * a12 + c * a22);
01128 
01129         /* Compute U <= U G */
01130 
01131         for (size_t i = 0; i < M; ++i)
01132           {
01133             double Uip = U.get(i, 0);
01134             double Uiq = U.get(i, 1);
01135             U.set(i, 0, c * Uip - s * Uiq);
01136             U.set(i, 1, s * Uip + c * Uiq);
01137           }
01138 
01139         return;
01140       }
01141   }
01142 
01143 
01144   // ############################################################
01145   void chase_out_intermediate_zero (gsl::vector& d, gsl::vector& f, gsl::matrix& U, size_t k0)
01146   {
01147     GVX_TRACE("chase_out_intermediate_zero");
01148     const size_t M = U.mrows;
01149     const size_t n = d.size;
01150     double c, s;
01151 
01152     double x = f.get(k0);
01153     double y = d.get(k0+1);
01154 
01155     for (size_t k = k0; k < n - 1; ++k)
01156       {
01157         create_givens (y, -x, &c, &s);
01158 
01159         /* Compute U <= U G */
01160 
01161         for (size_t i = 0; i < M; ++i)
01162           {
01163             double Uip = U.get(i, k0);
01164             double Uiq = U.get(i, k + 1);
01165             U.set(i, k0, c * Uip - s * Uiq);
01166             U.set(i, k + 1, s * Uip + c * Uiq);
01167           }
01168 
01169         /* compute B <= G^T B */
01170 
01171         d.set(k + 1, s * x + c * y);
01172 
01173         if (k == k0)
01174           f.set(k, c * x - s * y );
01175 
01176         if (k < n - 2)
01177           {
01178             double z = f.get(k + 1);
01179             f.set(k + 1, c * z);
01180 
01181             x = -s * z;
01182             y = d.get(k + 2);
01183           }
01184       }
01185   }
01186 
01187   // ############################################################
01188   void chase_out_trailing_zero (gsl::vector& d, gsl::vector& f, gsl::matrix& V)
01189   {
01190     GVX_TRACE("chase_out_trailing_zero");
01191     const size_t N = V.mrows;
01192     const size_t n = d.size;
01193     double c, s;
01194 
01195     double x = d.get(n - 2);
01196     double y = f.get(n - 2);
01197 
01198     for (size_t k = n - 1; k > 0 && k--; /* */)
01199       {
01200         create_givens (x, y, &c, &s);
01201 
01202         /* Compute V <= V G where G = [c, s; -s, c] */
01203 
01204         for (size_t i = 0; i < N; ++i)
01205           {
01206             double Vip = V.get(i, k);
01207             double Viq = V.get(i, n - 1);
01208             V.set(i, k, c * Vip - s * Viq);
01209             V.set(i, n - 1, s * Vip + c * Viq);
01210           }
01211 
01212         /* compute B <= B G */
01213 
01214         d.set(k, c * x - s * y);
01215 
01216         if (k == n - 2)
01217           f.set(k, s * x + c * y );
01218 
01219         if (k > 0)
01220           {
01221             double z = f.get(k - 1);
01222             f.set(k - 1, c * z);
01223 
01224             x = d.get(k - 1);
01225             y = s * z;
01226           }
01227       }
01228   }
01229 
01230   // ############################################################
01231   void qrstep (gsl::vector& d, gsl::vector& f, gsl::matrix& U, gsl::matrix& V)
01232   {
01233     GVX_TRACE("qrstep");
01234     const size_t M = U.mrows;
01235     const size_t N = V.mrows;
01236     const size_t n = d.size;
01237     double y, z;
01238     double ak, bk, zk, ap, bp, aq;
01239     size_t i, k;
01240 
01241     if (n == 1)
01242       return;  /* shouldn't happen */
01243 
01244     /* Compute 2x2 svd directly */
01245 
01246     if (n == 2)
01247       {
01248         svd2 (d, f, U, V);
01249         return;
01250       }
01251 
01252     /* Chase out any zeroes on the diagonal */
01253 
01254     for (i = 0; i < n - 1; i++)
01255       {
01256         const double d_i = d.get(i);
01257 
01258         if (d_i == 0.0)
01259           {
01260             chase_out_intermediate_zero (d, f, U, i);
01261             return;
01262           }
01263       }
01264 
01265     /* Chase out any zero at the end of the diagonal */
01266 
01267     {
01268       const double d_nm1 = d.get(n - 1);
01269 
01270       if (d_nm1 == 0.0)
01271         {
01272           chase_out_trailing_zero (d, f, V);
01273           return;
01274         }
01275     }
01276 
01277 
01278     /* Apply QR reduction steps to the diagonal and offdiagonal */
01279 
01280     {
01281       const double d0 = d.get(0);
01282       const double f0 = f.get(0);
01283 
01284       const double d1 = d.get(1);
01285       /*const double f1 =*/ f.get(1);
01286 
01287       {
01288         const double mu = trailing_eigenvalue (d, f);
01289 
01290         y = d0 * d0 - mu;
01291         z = d0 * f0;
01292       }
01293 
01294       /* Set up the recurrence for Givens rotations on a bidiagonal matrix */
01295 
01296       ak = 0;
01297       bk = 0;
01298 
01299       ap = d0;
01300       bp = f0;
01301 
01302       aq = d1;
01303     }
01304 
01305     for (k = 0; k < n - 1; k++)
01306       {
01307         double c, s;
01308         create_givens (y, z, &c, &s);
01309 
01310         /* Compute V <= V G */
01311 
01312         for (i = 0; i < N; i++)
01313           {
01314             double Vip = V.get(i, k);
01315             double Viq = V.get(i, k + 1);
01316             V.set(i, k, c * Vip - s * Viq);
01317             V.set(i, k + 1, s * Vip + c * Viq);
01318           }
01319 
01320         /* compute B <= B G */
01321 
01322         {
01323           const double bk1 = c * bk - s * z;
01324 
01325           const double ap1 = c * ap - s * bp;
01326           const double bp1 = s * ap + c * bp;
01327           const double zp1 = -s * aq;
01328 
01329           const double aq1 = c * aq;
01330 
01331           if (k > 0)
01332             {
01333               f.set(k - 1, bk1);
01334             }
01335 
01336           ak = ap1;
01337           bk = bp1;
01338           zk = zp1;
01339 
01340           ap = aq1;
01341 
01342           if (k < n - 2)
01343             {
01344               bp = f.get(k + 1);
01345             }
01346           else
01347             {
01348               bp = 0.0;
01349             }
01350 
01351           y = ak;
01352           z = zk;
01353         }
01354 
01355         create_givens (y, z, &c, &s);
01356 
01357         /* Compute U <= U G */
01358 
01359         for (i = 0; i < M; i++)
01360           {
01361             const double Uip = U.get(i, k);
01362             const double Uiq = U.get(i, k + 1);
01363             U.set(i, k, c * Uip - s * Uiq);
01364             U.set(i, k + 1, s * Uip + c * Uiq);
01365           }
01366 
01367         /* compute B <= G^T B */
01368 
01369         {
01370           const double ak1 = c * ak - s * zk;
01371           const double bk1 = c * bk - s * ap;
01372           const double zk1 = -s * bp;
01373 
01374           const double ap1 = s * bk + c * ap;
01375           const double bp1 = c * bp;
01376 
01377           d.set(k, ak1);
01378 
01379           ak = ak1;
01380           bk = bk1;
01381           zk = zk1;
01382 
01383           ap = ap1;
01384           bp = bp1;
01385 
01386           if (k < n - 2)
01387             {
01388               aq = d.get(k + 2);
01389             }
01390           else
01391             {
01392               aq = 0.0;
01393             }
01394 
01395           y = bk;
01396           z = zk;
01397         }
01398       }
01399 
01400     f.set(n - 2, bk);
01401     d.set(n - 1, ap);
01402   }
01403 
01404 
01405 
01406   // ############################################################
01407   // bidiag_decomp
01408 
01409   /* Factorise a matrix A into
01410    *
01411    * A = U B V^T
01412    *
01413    * where U and V are orthogonal and B is upper bidiagonal.
01414    *
01415    * On exit, B is stored in the diagonal and first superdiagonal of A.
01416    *
01417    * U is stored as a packed set of Householder transformations in the
01418    * lower triangular part of the input matrix below the diagonal.
01419    *
01420    * V is stored as a packed set of Householder transformations in the
01421    * upper triangular part of the input matrix above the first
01422    * superdiagonal.
01423    *
01424    * The full matrix for U can be obtained as the product
01425    *
01426    *       U = U_1 U_2 .. U_N
01427    *
01428    * where
01429    *
01430    *       U_i = (I - tau_i * u_i * u_i')
01431    *
01432    * and where u_i is a Householder vector
01433    *
01434    *       u_i = [0, .. , 0, 1, A(i+1,i), A(i+3,i), .. , A(M,i)]
01435    *
01436    * The full matrix for V can be obtained as the product
01437    *
01438    *       V = V_1 V_2 .. V_(N-2)
01439    *
01440    * where
01441    *
01442    *       V_i = (I - tau_i * v_i * v_i')
01443    *
01444    * and where v_i is a Householder vector
01445    *
01446    *       v_i = [0, .. , 0, 1, A(i,i+2), A(i,i+3), .. , A(i,N)]
01447    *
01448    * See Golub & Van Loan, "Matrix Computations" (3rd ed), Algorithm 5.4.2
01449    *
01450    * Note: this description uses 1-based indices. The code below uses
01451    * 0-based indices
01452    */
01453 
01454   void bidiag_decomp (gsl::matrix& A, gsl::vector& tau_U, gsl::vector& tau_V)
01455   {
01456     GVX_TRACE("bidiag_decomp");
01457     if (A.mrows < A.ncols)
01458       {
01459         LFATAL("bidiagonal decomposition requires M>=N");
01460       }
01461     else if (tau_U.size  != A.ncols)
01462       {
01463         LFATAL("size of tau_U must be N");
01464       }
01465     else if (tau_V.size + 1 != A.ncols)
01466       {
01467         LFATAL("size of tau_V must be (N - 1)");
01468       }
01469     else
01470       {
01471         const size_t M = A.mrows;
01472         const size_t N = A.ncols;
01473 
01474         for (size_t i = 0; i < N; ++i)
01475           {
01476             /* Apply Householder transformation to current column */
01477 
01478             {
01479               gsl::view_of<gsl::vector> c = column_of (A, i);
01480               gsl::view_of<gsl::vector> v = c.viewee.subvector(i, M - i);
01481               const double tau_i = householder_transform (v.viewee);
01482 
01483               /* Apply the transformation to the remaining columns */
01484 
01485               if (i + 1 < N)
01486                 {
01487                   gsl::view_of<gsl::matrix> m =
01488                     submatrix_of (A, i, i + 1, M - i, N - (i + 1));
01489                   householder_hm (tau_i, v.viewee, m.viewee);
01490                 }
01491 
01492               tau_U.set(i, tau_i);
01493 
01494             }
01495 
01496             /* Apply Householder transformation to current row */
01497 
01498             if (i + 1 < N)
01499               {
01500                 gsl::view_of<gsl::vector> r = row_of (A, i);
01501                 gsl::view_of<gsl::vector> v = r.viewee.subvector(i + 1, N - (i + 1));
01502                 const double tau_i = householder_transform (v.viewee);
01503 
01504                 /* Apply the transformation to the remaining rows */
01505 
01506                 if (i + 1 < M)
01507                   {
01508                     gsl::view_of<gsl::matrix> m =
01509                       submatrix_of (A, i+1, i+1, M - (i+1), N - (i+1));
01510                     householder_mh (tau_i, v.viewee, m.viewee);
01511                   }
01512 
01513                 tau_V.set(i, tau_i);
01514               }
01515           }
01516       }
01517   }
01518 
01519   // ############################################################
01520   /* Form the orthogonal matrices U, V, diagonal d and superdiagonal sd
01521      from the packed bidiagonal matrix A */
01522   void bidiag_unpack (const gsl::matrix& A,
01523                       const gsl::vector& tau_U,
01524                       gsl::matrix& U,
01525                       const gsl::vector& tau_V,
01526                       gsl::matrix& V,
01527                       gsl::vector& diag,
01528                       gsl::vector& superdiag)
01529   {
01530     GVX_TRACE("bidiag_unpack");
01531     const size_t M = A.mrows;
01532     const size_t N = A.ncols;
01533 
01534     const size_t K = std::min(M, N);
01535 
01536     if (M < N)
01537       {
01538         LFATAL("matrix A must have M >= N");
01539       }
01540     else if (tau_U.size != K)
01541       {
01542         LFATAL("size of tau must be MIN(M,N)");
01543       }
01544     else if (tau_V.size + 1 != K)
01545       {
01546         LFATAL("size of tau must be MIN(M,N) - 1");
01547       }
01548     else if (U.mrows != M || U.ncols != N)
01549       {
01550         LFATAL("size of U must be M x N");
01551       }
01552     else if (V.mrows != N || V.ncols != N)
01553       {
01554         LFATAL("size of V must be N x N");
01555       }
01556     else if (diag.size != K)
01557       {
01558         LFATAL("size of diagonal must match size of A");
01559       }
01560     else if (superdiag.size + 1 != K)
01561       {
01562         LFATAL("size of subdiagonal must be (diagonal size - 1)");
01563       }
01564 
01565     /* Copy diagonal into diag */
01566 
01567     for (size_t i = 0; i < N; ++i)
01568       {
01569         const double Aii = A.get(i, i);
01570         diag.set(i, Aii);
01571       }
01572 
01573     /* Copy superdiagonal into superdiag */
01574 
01575     for (size_t i = 0; i < N - 1; ++i)
01576       {
01577         const double Aij = A.get(i, i+1);
01578         superdiag.set(i, Aij);
01579       }
01580 
01581     /* Initialize V to the identity */
01582 
01583     set_identity (V);
01584 
01585     for (size_t i = N - 1; i > 0 && i--; /* */)
01586       {
01587         /* Householder row transformation to accumulate V */
01588         gsl::view_of<const gsl::vector> r = const_row (A, i);
01589         gsl::view_of<const gsl::vector> h =
01590           r.viewee.subvector(i + 1, N - (i+1));
01591 
01592         const double ti = tau_V.get(i);
01593 
01594         gsl::view_of<gsl::matrix> m =
01595           submatrix_of (V, i + 1, i + 1, N-(i+1), N-(i+1));
01596 
01597         householder_hm (ti, h.viewee, m.viewee);
01598       }
01599 
01600     /* Initialize U to the identity */
01601 
01602     set_identity (U);
01603 
01604     for (size_t j = N; j > 0 && j--; /* */)
01605       {
01606         /* Householder column transformation to accumulate U */
01607         gsl::view_of<const gsl::vector> c = const_column (A, j);
01608         gsl::view_of<const gsl::vector> h = c.viewee.subvector(j, M - j);
01609         const double tj = tau_U.get(j);
01610 
01611         gsl::view_of<gsl::matrix> m =
01612           submatrix_of (U, j, j, M-j, N-j);
01613 
01614         householder_hm (tj, h.viewee, m.viewee);
01615       }
01616 
01617     return;
01618   }
01619 
01620   // ############################################################
01621   void bidiag_unpack2 (gsl::matrix& A,
01622                        gsl::vector& tau_U,
01623                        gsl::vector& tau_V,
01624                        gsl::matrix& V)
01625   {
01626     GVX_TRACE("bidiag_unpack2");
01627     const size_t M = A.mrows;
01628     const size_t N = A.ncols;
01629 
01630     const size_t K = std::min(M, N);
01631 
01632     if (M < N)
01633       {
01634         LFATAL("matrix A must have M >= N");
01635       }
01636     else if (tau_U.size != K)
01637       {
01638         LFATAL("size of tau must be MIN(M,N)");
01639       }
01640     else if (tau_V.size + 1 != K)
01641       {
01642         LFATAL("size of tau must be MIN(M,N) - 1");
01643       }
01644     else if (V.mrows != N || V.ncols != N)
01645       {
01646         LFATAL("size of V must be N x N");
01647       }
01648 
01649     /* Initialize V to the identity */
01650 
01651     set_identity (V);
01652 
01653     for (size_t i = N - 1; i > 0 && i--; /* */)
01654       {
01655         /* Householder row transformation to accumulate V */
01656         gsl::view_of<const gsl::vector> r = const_row (A, i);
01657         gsl::view_of<const gsl::vector> h =
01658           r.viewee.subvector(i + 1, N - (i+1));
01659 
01660         const double ti = tau_V.get(i);
01661 
01662         gsl::view_of<gsl::matrix> m =
01663           submatrix_of (V, i + 1, i + 1, N-(i+1), N-(i+1));
01664 
01665         householder_hm (ti, h.viewee, m.viewee);
01666       }
01667 
01668     /* Copy superdiagonal into tau_v */
01669 
01670     for (size_t i = 0; i < N - 1; ++i)
01671       {
01672         const double Aij = A.get(i, i+1);
01673         tau_V.set(i, Aij);
01674       }
01675 
01676     /* Allow U to be unpacked into the same memory as A, copy
01677        diagonal into tau_U */
01678 
01679     for (size_t j = N; j > 0 && j--; /* */)
01680       {
01681         /* Householder column transformation to accumulate U */
01682         const double tj = tau_U.get(j);
01683         const double Ajj = A.get(j, j);
01684         gsl::view_of<gsl::matrix> m = submatrix_of (A, j, j, M-j, N-j);
01685 
01686         tau_U.set(j, Ajj);
01687         householder_hm1 (tj, m.viewee);
01688       }
01689 
01690   }
01691 
01692 
01693   // ############################################################
01694   void bidiag_unpack_B (const gsl::matrix& A,
01695                         gsl::vector& diag,
01696                         gsl::vector& superdiag)
01697   {
01698     GVX_TRACE("bidiag_unpack_B");
01699     const size_t M = A.mrows;
01700     const size_t N = A.ncols;
01701 
01702     const size_t K = std::min(M, N);
01703 
01704     if (diag.size != K)
01705       {
01706         LFATAL("size of diagonal must match size of A");
01707       }
01708     else if (superdiag.size + 1 != K)
01709       {
01710         LFATAL("size of subdiagonal must be (matrix size - 1)");
01711       }
01712     else
01713       {
01714 
01715         /* Copy diagonal into diag */
01716 
01717         for (size_t i = 0; i < K; ++i)
01718           {
01719             const double Aii = A.get(i, i);
01720             diag.set(i, Aii);
01721           }
01722 
01723         /* Copy superdiagonal into superdiag */
01724 
01725         for (size_t i = 0; i < K - 1; ++i)
01726           {
01727             const double Aij = A.get(i, i+1);
01728             superdiag.set(i, Aij);
01729           }
01730       }
01731   }
01732 
01733   // ############################################################
01734   /* Factorise a general M x N matrix A into,
01735    *
01736    *   A = U D V^T
01737    *
01738    * where U is a column-orthogonal M x N matrix (U^T U = I),
01739    * D is a diagonal N x N matrix,
01740    * and V is an N x N orthogonal matrix (V^T V = V V^T = I)
01741    *
01742    * U is stored in the original matrix A, which has the same size
01743    *
01744    * V is stored as a separate matrix (not V^T). You must take the
01745    * transpose to form the product above.
01746    *
01747    * The diagonal matrix D is stored in the vector S,  D_ii = S_i
01748    */
01749 
01750   void SV_decomp (gsl::matrix& A, gsl::matrix& V, gsl::vector& S,
01751                   gsl::vector& work)
01752   {
01753     GVX_TRACE("SV_decomp");
01754     size_t a, b;
01755 
01756     const size_t M = A.mrows;
01757     const size_t N = A.ncols;
01758     const size_t K = std::min(M, N);
01759 
01760     if (M < N)
01761       {
01762         LFATAL("svd of [M=%"ZU"]x[N=%"ZU"] matrix, M<N, is not implemented",
01763                M, N);
01764       }
01765     else if (V.mrows != V.ncols)
01766       {
01767         LFATAL("matrix V [=%"ZU"x%"ZU"] must be square", V.mrows, V.ncols);
01768       }
01769     else if (V.mrows != N)
01770       {
01771         LFATAL("square matrix V [=%"ZU"x%"ZU"] must match second dimension of matrix A [=%"ZU"]",
01772                V.mrows, V.ncols, N);
01773       }
01774     else if (S.size != N)
01775       {
01776         LFATAL("length of vector S [=%"ZU"] must match second dimension of matrix A [=%"ZU"]",
01777                S.size, N);
01778       }
01779     else if (work.size != N)
01780       {
01781         LFATAL("length of workspace [=%"ZU"] must match second dimension of matrix A [=%"ZU"]",
01782                work.size, N);
01783       }
01784 
01785     /* Handle the case of N = 1 (SVD of a column vector) */
01786 
01787     if (N == 1)
01788       {
01789         gsl::view_of<gsl::vector> column = column_of (A, 0);
01790         const double norm = blas_dnrm2 (column.viewee);
01791 
01792         S.set(0, norm);
01793         V.set(0, 0, 1.0);
01794 
01795         if (norm != 0.0)
01796           {
01797             blas_dscal (1.0/norm, column.viewee);
01798           }
01799 
01800         return;
01801       }
01802 
01803     {
01804       gsl::view_of<gsl::vector> f = work.subvector(0, K - 1);
01805 
01806       /* bidiagonalize matrix A, unpack A into U S V */
01807 
01808       bidiag_decomp (A, S, f.viewee);
01809       bidiag_unpack2 (A, S, f.viewee, V);
01810 
01811       /* apply reduction steps to B=(S,Sd) */
01812 
01813       chop_small_elements (S, f.viewee);
01814 
01815       /* Progressively reduce the matrix until it is diagonal */
01816 
01817       b = N - 1;
01818 
01819       while (b > 0)
01820         {
01821           const double fbm1 = f.viewee.get(b - 1);
01822 
01823           if (fbm1 == 0.0 || isnan (fbm1))
01824             {
01825               b--;
01826               continue;
01827             }
01828 
01829           /* Find the largest unreduced block (a,b) starting from b
01830              and working backwards */
01831 
01832           a = b - 1;
01833 
01834           while (a > 0)
01835             {
01836               const double fam1 = f.viewee.get(a - 1);
01837 
01838               if (fam1 == 0.0 || isnan (fam1))
01839                 {
01840                   break;
01841                 }
01842 
01843               a--;
01844             }
01845 
01846           {
01847             const size_t n_block = b - a + 1;
01848             gsl::view_of<gsl::vector> S_block = S.subvector(a, n_block);
01849             gsl::view_of<gsl::vector> f_block = f.viewee.subvector(a, n_block - 1);
01850 
01851             gsl::view_of<gsl::matrix> U_block =
01852               submatrix_of (A, 0, a, A.mrows, n_block);
01853             gsl::view_of<gsl::matrix> V_block =
01854               submatrix_of (V, 0, a, V.mrows, n_block);
01855 
01856             qrstep (S_block.viewee, f_block.viewee, U_block.viewee, V_block.viewee);
01857 
01858             /* remove any small off-diagonal elements */
01859 
01860             chop_small_elements (S_block.viewee, f_block.viewee);
01861           }
01862         }
01863     }
01864     /* Make singular values positive by reflections if necessary */
01865 
01866     for (size_t j = 0; j < K; ++j)
01867       {
01868         const double Sj = S.get(j);
01869 
01870         if (Sj < 0.0)
01871           {
01872             for (size_t i = 0; i < N; ++i)
01873               {
01874                 const double Vij = V.get(i, j);
01875                 V.set(i, j, -Vij);
01876               }
01877 
01878             S.set(j, -Sj);
01879           }
01880       }
01881 
01882     /* Sort singular values into decreasing order */
01883 
01884     for (size_t i = 0; i < K; ++i)
01885       {
01886         double S_max = S.get(i);
01887         size_t i_max = i;
01888 
01889         for (size_t j = i + 1; j < K; ++j)
01890           {
01891             const double Sj = S.get(j);
01892 
01893             if (Sj > S_max)
01894               {
01895                 S_max = Sj;
01896                 i_max = j;
01897               }
01898           }
01899 
01900         if (i_max != i)
01901           {
01902             /* swap eigenvalues */
01903             S.swap_elements(i, i_max);
01904 
01905             /* swap eigenvectors */
01906             swap_columns (A, i, i_max);
01907             swap_columns (V, i, i_max);
01908           }
01909       }
01910   }
01911 
01912 
01913   // ############################################################
01914   /* Modified algorithm which is better for M>>N */
01915   void linalg_SV_decomp_mod (gsl::matrix& A,
01916                              gsl::matrix& X,
01917                              gsl::matrix& V,
01918                              gsl::vector& S,
01919                              gsl::vector& work)
01920   {
01921     GVX_TRACE("linalg_SV_decomp_mod");
01922 
01923     const size_t M = A.mrows;
01924     const size_t N = A.ncols;
01925 
01926     if (M < N)
01927       {
01928         LFATAL("svd of [M=%"ZU"]x[N=%"ZU"] matrix, M<N, is not implemented",
01929                M, N);
01930       }
01931     else if (V.mrows != V.ncols)
01932       {
01933         LFATAL("matrix V [=%"ZU"x%"ZU"] must be square", V.mrows, V.ncols);
01934       }
01935     else if (V.mrows != N)
01936       {
01937         LFATAL("square matrix V [=%"ZU"x%"ZU"] must match second dimension of matrix A [=%"ZU"]",
01938                V.mrows, V.ncols, N);
01939       }
01940     else if (X.mrows != X.ncols)
01941       {
01942         LFATAL("matrix X [=%"ZU"x%"ZU"] must be square", X.mrows, X.ncols);
01943       }
01944     else if (X.mrows != N)
01945       {
01946         LFATAL("square matrix X [=%"ZU"x%"ZU"] must match second dimension of matrix A [=%"ZU"]",
01947                X.mrows, X.ncols, N);
01948       }
01949     else if (S.size != N)
01950       {
01951         LFATAL("length of vector S [=%"ZU"] must match second dimension of matrix A [=%"ZU"]",
01952                S.size, N);
01953       }
01954     else if (work.size != N)
01955       {
01956         LFATAL("length of workspace [=%"ZU"] must match second dimension of matrix A [=%"ZU"]",
01957                work.size, N);
01958       }
01959 
01960     if (N == 1)
01961       {
01962         gsl::view_of<gsl::vector> column = column_of (A, 0);
01963         const double norm = blas_dnrm2 (column.viewee);
01964 
01965         S.set(0, norm);
01966         V.set(0, 0, 1.0);
01967 
01968         if (norm != 0.0)
01969           {
01970             blas_dscal (1.0/norm, column.viewee);
01971           }
01972 
01973         return;
01974       }
01975 
01976     /* Convert A into an upper triangular matrix R */
01977 
01978     for (size_t i = 0; i < N; ++i)
01979       {
01980         GVX_TRACE("linalg_SV_decomp_mod-loop1");
01981         gsl::view_of<gsl::vector> c = column_of (A, i);
01982         gsl::view_of<gsl::vector> v = c.viewee.subvector(i, M - i);
01983         const double tau_i = householder_transform (v.viewee);
01984 
01985         /* Apply the transformation to the remaining columns */
01986 
01987         if (i + 1 < N)
01988           {
01989             gsl::view_of<gsl::matrix> m =
01990               submatrix_of (A, i, i + 1, M - i, N - (i + 1));
01991             householder_hm (tau_i, v.viewee, m.viewee);
01992           }
01993 
01994         S.set(i, tau_i);
01995       }
01996 
01997     /* Copy the upper triangular part of A into X */
01998 
01999     for (size_t i = 0; i < N; ++i)
02000       {
02001         GVX_TRACE("linalg_SV_decomp_mod-loop2");
02002         for (size_t j = 0; j < i; j++)
02003           {
02004             X.set(i, j, 0.0);
02005           }
02006 
02007         {
02008           const double Aii = A.get(i, i);
02009           X.set(i, i, Aii);
02010         }
02011 
02012         for (size_t j = i + 1; j < N; ++j)
02013           {
02014             const double Aij = A.get(i, j);
02015             X.set(i, j, Aij);
02016           }
02017       }
02018 
02019     /* Convert A into an orthogonal matrix L */
02020 
02021     for (size_t j = N; j > 0 && j--; /* */)
02022       {
02023         GVX_TRACE("linalg_SV_decomp_mod-loop3");
02024         /* Householder column transformation to accumulate L */
02025         const double tj = S.get(j);
02026         gsl::view_of<gsl::matrix> m = submatrix_of (A, j, j, M - j, N - j);
02027         householder_hm1 (tj, m.viewee);
02028       }
02029 
02030     /* unpack R into X V S */
02031 
02032     {
02033       GVX_TRACE("linalg_SV_decomp_mod-loop4");
02034       SV_decomp (X, V, S, work);
02035     }
02036 
02037     /* Multiply L by X, to obtain U = L X, stored in U */
02038 
02039     {
02040       GVX_TRACE("linalg_SV_decomp_mod-loop5");
02041 
02042       gsl::view_of<gsl::vector> sum = work.subvector(0, N);
02043 
02044       for (size_t i = 0; i < M; ++i)
02045         {
02046           gsl::view_of<gsl::vector> L_i = row_of (A, i);
02047           sum.viewee.set_all(0.0);
02048 
02049           for (size_t j = 0; j < N; ++j)
02050             {
02051               const double Lij = L_i.viewee.get(j);
02052               gsl::view_of<gsl::vector> X_j = row_of (X, j);
02053               blas_daxpy (Lij, X_j.viewee, sum.viewee);
02054             }
02055 
02056           L_i.viewee.copy_of(sum.viewee);
02057         }
02058     }
02059   }
02060 
02061   // ############################################################
02062   gsl::matrix image2matrix(const Image<double>& M)
02063   {
02064     const int h = M.getHeight();
02065     const int w = M.getWidth();
02066     gsl::matrix m(h, w);
02067     for (int y = 0; y < h; ++y)
02068       for (int x = 0; x < w; ++x)
02069         m.set(y, x, M.getVal(x, y));
02070     return m;
02071   }
02072 
02073   // ############################################################
02074   Image<double> matrix2image(const gsl::matrix& m)
02075   {
02076     const int h = m.mrows;
02077     const int w = m.ncols;
02078     Image<double> M(w, h, NO_INIT);
02079     for (int y = 0; y < h; ++y)
02080       for (int x = 0; x < w; ++x)
02081         M.setVal(x, y, m.get(y, x));
02082     return M;
02083   }
02084 
02085   // ############################################################
02086   Image<double> vector2image(const gsl::vector& m)
02087   {
02088     const int h = m.size;
02089     Image<double> M(1, h, NO_INIT);
02090     for (int y = 0; y < h; ++y)
02091       M.setVal(y, m.get(y));
02092     return M;
02093   }
02094 
02095   // ############################################################
02096   Image<double> diag2image(const Image<double>& diag)
02097   {
02098     ASSERT(diag.isVector());
02099     const int s = diag.getSize();
02100     Image<double> result(s, s, ZEROS);
02101     for (int i = 0; i < s; ++i)
02102       result.setVal(i, i, diag.getVal(i));
02103     return result;
02104   }
02105 
02106 } // end unnamed namespace
02107 
02108 // ######################################################################
02109 void gsl::svd(const Image<double>& A,
02110               Image<double>& U, Image<double>& S, Image<double>& V,
02111               const SvdFlag flags)
02112 {
02113   gsl::matrix m = image2matrix(A);
02114   gsl::matrix v(m.ncols, m.ncols);
02115   gsl::vector s(m.ncols);
02116   gsl::vector work(m.ncols);
02117 
02118   if (flags & SVD_FULL)
02119     LFATAL("SVD_FULL not supported (try the lapack svd instead)");
02120 
02121   if (flags & SVD_TALL)
02122     {
02123       gsl::matrix x(m.ncols, m.ncols);
02124       linalg_SV_decomp_mod(m, x, v, s, work);
02125     }
02126   else
02127     {
02128       SV_decomp(m, v, s, work);
02129     }
02130 
02131   U = matrix2image(m);
02132   S = diag2image(vector2image(s));
02133   V = matrix2image(v);
02134 }
02135 
02136 // ######################################################################
02137 void gsl::svdf(const Image<float>& A,
02138                Image<float>& U, Image<float>& S, Image<float>& V,
02139                const SvdFlag flags)
02140 {
02141   // we don't have a single-precision gsl version, so we'll just
02142   // have to convert to double and back
02143 
02144   Image<double> Ud, Sd, Vd;
02145 
02146   gsl::svd(Image<double>(A), Ud, Sd, Vd, flags);
02147   U = Ud;
02148   S = Sd;
02149   V = Vd;
02150 }
02151 
02152 // ######################################################################
02153 /* So things look consistent in everyone's emacs... */
02154 /* Local Variables: */
02155 /* indent-tabs-mode: nil */
02156 /* End: */
02157 
02158 #endif // IMAGE_GSL_C_DEFINED
Generated on Sun May 8 08:40:54 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3