00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
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"
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
00076 namespace gsl
00077 {
00078 template <class T> class view_of;
00079 class block;
00080 class vector;
00081 class matrix;
00082 }
00083
00084
00085
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
00097 view_of();
00098
00099
00100
00101
00102 view_of& operator=(const view_of&);
00103 };
00104
00105
00106
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
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
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
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
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
00739
00740
00741 const size_t n = v.size;
00742
00743 if (n == 1)
00744 {
00745 return 0.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;
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
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
00798
00799
00800 if (tau == 0)
00801 return 0;
00802
00803
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
00827 const size_t N = v.size;
00828
00829 if (tau == 0)
00830 return 0;
00831
00832 {
00833
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
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
00860
00861
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
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
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
00910
00911
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
01034
01035 create_givens (f0, d1, &c, &s);
01036
01037
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
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
01054
01055 swap_columns (V, 0, 1);
01056
01057 return;
01058 }
01059 else if (d1 == 0.0)
01060 {
01061
01062
01063 create_givens (d0, f0, &c, &s);
01064
01065
01066
01067 d.set(0, d0 * c - f0 * s);
01068 f.set(0, 0.0);
01069
01070
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
01085
01086 create_schur (d0, f0, d1, &c, &s);
01087
01088
01089
01090 a11 = c * d0 - s * f0;
01091 a21 = - s * d1;
01092
01093 a12 = s * d0 + c * f0;
01094 a22 = c * d1;
01095
01096
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
01107
01108
01109 if (hypot(a11, a21) < hypot(a12,a22))
01110 {
01111
01112
01113 const double t1 = a11; a11 = a12; a12 = t1;
01114 const double t2 = a21; a21 = a22; a22 = t2;
01115
01116
01117
01118 swap_columns(V, 0, 1);
01119 }
01120
01121 create_givens (a11, a21, &c, &s);
01122
01123
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
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
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
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
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
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;
01243
01244
01245
01246 if (n == 2)
01247 {
01248 svd2 (d, f, U, V);
01249 return;
01250 }
01251
01252
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
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
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 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
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
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
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
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
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
01408
01409
01410
01411
01412
01413
01414
01415
01416
01417
01418
01419
01420
01421
01422
01423
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433
01434
01435
01436
01437
01438
01439
01440
01441
01442
01443
01444
01445
01446
01447
01448
01449
01450
01451
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
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
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
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
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
01521
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
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
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
01582
01583 set_identity (V);
01584
01585 for (size_t i = N - 1; i > 0 && i--; )
01586 {
01587
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
01601
01602 set_identity (U);
01603
01604 for (size_t j = N; j > 0 && j--; )
01605 {
01606
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
01650
01651 set_identity (V);
01652
01653 for (size_t i = N - 1; i > 0 && i--; )
01654 {
01655
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
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
01677
01678
01679 for (size_t j = N; j > 0 && j--; )
01680 {
01681
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
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
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
01735
01736
01737
01738
01739
01740
01741
01742
01743
01744
01745
01746
01747
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
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
01807
01808 bidiag_decomp (A, S, f.viewee);
01809 bidiag_unpack2 (A, S, f.viewee, V);
01810
01811
01812
01813 chop_small_elements (S, f.viewee);
01814
01815
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
01830
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
01859
01860 chop_small_elements (S_block.viewee, f_block.viewee);
01861 }
01862 }
01863 }
01864
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
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
01903 S.swap_elements(i, i_max);
01904
01905
01906 swap_columns (A, i, i_max);
01907 swap_columns (V, i, i_max);
01908 }
01909 }
01910 }
01911
01912
01913
01914
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
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
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
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
02020
02021 for (size_t j = N; j > 0 && j--; )
02022 {
02023 GVX_TRACE("linalg_SV_decomp_mod-loop3");
02024
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
02031
02032 {
02033 GVX_TRACE("linalg_SV_decomp_mod-loop4");
02034 SV_decomp (X, V, S, work);
02035 }
02036
02037
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 }
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
02142
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
02154
02155
02156
02157
02158 #endif // IMAGE_GSL_C_DEFINED