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