bpmnr/gsl_linalg.c

Go to the documentation of this file.
00001 
00005 #include <bpm/bpm_messages.h>
00006 #include <bpm/bpm_nr.h>
00007 
00008 int gsl_linalg_householder_hm (double tau, const gsl_vector * v, gsl_matrix * A)
00009 {
00032   if (tau == 0.0)
00033     {
00034       return BPM_SUCCESS;
00035     }
00036 
00037 #ifdef USE_BLAS
00038   {
00039     gsl_vector_const_view v1 = gsl_vector_const_subvector (v, 1, v->size - 1);
00040     gsl_matrix_view A1 = gsl_matrix_submatrix (A, 1, 0, A->size1 - 1, A->size2);
00041     size_t j;
00042 
00043     for (j = 0; j < A->size2; j++)
00044       {
00045         double wj = 0.0;
00046         gsl_vector_view A1j = gsl_matrix_column(&A1.matrix, j);
00047         gsl_blas_ddot (&A1j.vector, &v1.vector, &wj);
00048         wj += gsl_matrix_get(A,0,j);
00049 
00050         {
00051           double A0j = gsl_matrix_get (A, 0, j);
00052           gsl_matrix_set (A, 0, j, A0j - tau *  wj);
00053         }
00054 
00055         gsl_blas_daxpy (-tau * wj, &v1.vector, &A1j.vector);
00056       }
00057   }
00058 #else
00059   {
00060     size_t i, j;
00061     
00062     for (j = 0; j < A->size2; j++)
00063       {
00064         /* Compute wj = Akj vk */
00065         
00066         double wj = gsl_matrix_get(A,0,j);  
00067         
00068         for (i = 1; i < A->size1; i++)  /* note, computed for v(0) = 1 above */
00069           {
00070             wj += gsl_matrix_get(A,i,j) * gsl_vector_get(v,i);
00071           }
00072         
00073         /* Aij = Aij - tau vi wj */
00074         
00075         /* i = 0 */
00076         {
00077           double A0j = gsl_matrix_get (A, 0, j);
00078           gsl_matrix_set (A, 0, j, A0j - tau *  wj);
00079         }
00080         
00081         /* i = 1 .. M-1 */
00082         
00083         for (i = 1; i < A->size1; i++)
00084           {
00085             double Aij = gsl_matrix_get (A, i, j);
00086             double vi = gsl_vector_get (v, i);
00087             gsl_matrix_set (A, i, j, Aij - tau * vi * wj);
00088           }
00089       }
00090   }
00091 #endif
00092     
00093   return BPM_SUCCESS;
00094 }
00095 
00096 int gsl_linalg_householder_hm1 (double tau, gsl_matrix * A)
00097 {
00104   if (tau == 0)
00105     {
00106       size_t i,j;
00107 
00108       gsl_matrix_set (A, 0, 0, 1.0);
00109       
00110       for (j = 1; j < A->size2; j++)
00111         {
00112           gsl_matrix_set (A, 0, j, 0.0);
00113         }
00114 
00115       for (i = 1; i < A->size1; i++)
00116         {
00117           gsl_matrix_set (A, i, 0, 0.0);
00118         }
00119 
00120       return BPM_SUCCESS;
00121     }
00122 
00123   /* w = A' v */
00124 
00125 #ifdef USE_BLAS
00126   {
00127     gsl_matrix_view A1 = gsl_matrix_submatrix (A, 1, 0, A->size1 - 1, A->size2);
00128     gsl_vector_view v1 = gsl_matrix_column (&A1.matrix, 0);
00129     size_t j;
00130 
00131     for (j = 1; j < A->size2; j++)
00132       {
00133         double wj = 0.0;   /* A0j * v0 */
00134         
00135         gsl_vector_view A1j = gsl_matrix_column(&A1.matrix, j);
00136         gsl_blas_ddot (&A1j.vector, &v1.vector, &wj);
00137 
00138         /* A = A - tau v w' */
00139         
00140         gsl_matrix_set (A, 0, j, - tau *  wj);
00141         
00142         gsl_blas_daxpy(-tau*wj, &v1.vector, &A1j.vector);
00143       }
00144 
00145     gsl_blas_dscal(-tau, &v1.vector);
00146     
00147     gsl_matrix_set (A, 0, 0, 1.0 - tau);
00148   }
00149 #else
00150   {
00151     size_t i, j;
00152     
00153     for (j = 1; j < A->size2; j++)
00154       {
00155         double wj = 0.0;   /* A0j * v0 */
00156         
00157         for (i = 1; i < A->size1; i++)
00158           {
00159             double vi = gsl_matrix_get(A, i, 0);
00160             wj += gsl_matrix_get(A,i,j) * vi;
00161           }
00162         
00163         /* A = A - tau v w' */
00164         
00165         gsl_matrix_set (A, 0, j, - tau *  wj);
00166         
00167         for (i = 1; i < A->size1; i++)
00168           {
00169             double vi = gsl_matrix_get (A, i, 0);
00170             double Aij = gsl_matrix_get (A, i, j);
00171             gsl_matrix_set (A, i, j, Aij - tau * vi * wj);
00172           }
00173       }
00174     
00175     for (i = 1; i < A->size1; i++)
00176       {
00177         double vi = gsl_matrix_get(A, i, 0);
00178         gsl_matrix_set(A, i, 0, -tau * vi);
00179       }
00180     
00181     gsl_matrix_set (A, 0, 0, 1.0 - tau);
00182   }
00183 #endif
00184 
00185   return BPM_SUCCESS;
00186 }
00187 
00188 void create_givens (const double a, const double b, double *c, double *s)
00189 {
00190   if (b == 0)
00191     {
00192       *c = 1;
00193       *s = 0;
00194     }
00195   else if (fabs (b) > fabs (a))
00196     {
00197       double t = -a / b;
00198       double s1 = 1.0 / sqrt (1 + t * t);
00199       *s = s1;
00200       *c = s1 * t;
00201     }
00202   else
00203     {
00204       double t = -b / a;
00205       double c1 = 1.0 / sqrt (1 + t * t);
00206       *c = c1;
00207       *s = c1 * t;
00208     }
00209 }
00210 
00211 
00212 int gsl_linalg_bidiag_decomp (gsl_matrix * A, gsl_vector * tau_U, gsl_vector * tau_V)  
00213 {
00214   if (A->size1 < A->size2)
00215     {
00216       bpm_error("bidiagonal decomposition requires M>=N in gsl_linalg_bidag_decomp(...)",
00217                 __FILE__, __LINE__);
00218       return BPM_SUCCESS;
00219     }
00220   else if (tau_U->size  != A->size2)
00221     {
00222       bpm_error("size of tau_U must be N in gsl_linalg_bidag_decomp(...)",
00223                 __FILE__, __LINE__);
00224       return BPM_SUCCESS;
00225     }
00226   else if (tau_V->size + 1 != A->size2)
00227     {
00228       bpm_error("size of tau_V must be (N - 1) in gsl_linalg_bidag_decomp(...)",
00229                 __FILE__, __LINE__);
00230       return BPM_SUCCESS;
00231     }
00232   else
00233     {
00234       const size_t M = A->size1;
00235       const size_t N = A->size2;
00236       size_t i;
00237   
00238       for (i = 0 ; i < N; i++)
00239         {
00240           /* Apply Householder transformation to current column */
00241           
00242           {
00243             gsl_vector_view c = gsl_matrix_column (A, i);
00244             gsl_vector_view v = gsl_vector_subvector (&c.vector, i, M - i);
00245             double tau_i = gsl_linalg_householder_transform (&v.vector);
00246             
00247             /* Apply the transformation to the remaining columns */
00248             
00249             if (i + 1 < N)
00250               {
00251                 gsl_matrix_view m = 
00252                   gsl_matrix_submatrix (A, i, i + 1, M - i, N - (i + 1));
00253                 gsl_linalg_householder_hm (tau_i, &v.vector, &m.matrix);
00254               }
00255 
00256             gsl_vector_set (tau_U, i, tau_i);            
00257 
00258           }
00259 
00260           /* Apply Householder transformation to current row */
00261           
00262           if (i + 1 < N)
00263             {
00264               gsl_vector_view r = gsl_matrix_row (A, i);
00265               gsl_vector_view v = gsl_vector_subvector (&r.vector, i + 1, N - (i + 1));
00266               double tau_i = gsl_linalg_householder_transform (&v.vector);
00267               
00268               /* Apply the transformation to the remaining rows */
00269               
00270               if (i + 1 < M)
00271                 {
00272                   gsl_matrix_view m = 
00273                     gsl_matrix_submatrix (A, i+1, i+1, M - (i+1), N - (i+1));
00274                   gsl_linalg_householder_mh (tau_i, &v.vector, &m.matrix);
00275                 }
00276 
00277               gsl_vector_set (tau_V, i, tau_i);
00278             }
00279         }
00280     }
00281         
00282   return BPM_SUCCESS;
00283 }
00284 
00285 double gsl_linalg_householder_transform (gsl_vector * v)
00286 {
00292   const size_t n = v->size ;
00293 
00294   if (n == 1)
00295     {
00296       return 0.0; /* tau = 0 */
00297     }
00298   else
00299     { 
00300       double alpha, beta, tau ;
00301       
00302       gsl_vector_view x = gsl_vector_subvector (v, 1, n - 1) ; 
00303       
00304       double xnorm = gsl_blas_dnrm2 (&x.vector);
00305       
00306       if (xnorm == 0) 
00307         {
00308           return 0.0; /* tau = 0 */
00309         }
00310       
00311       alpha = gsl_vector_get (v, 0) ;
00312       beta = - (alpha >= 0.0 ? +1.0 : -1.0) * hypot(alpha, xnorm) ;
00313       tau = (beta - alpha) / beta ;
00314       
00315       gsl_blas_dscal (1.0 / (alpha - beta), &x.vector);
00316       gsl_vector_set (v, 0, beta) ;
00317       
00318       return tau;
00319     }
00320 }
00321 
00322 int gsl_linalg_householder_mh (double tau, const gsl_vector * v, gsl_matrix * A)
00323 {
00329   if (tau == 0)
00330     return BPM_SUCCESS;
00331 
00332   /* A = A - tau w v' */
00333 
00334 #ifdef USE_BLAS
00335   {
00336     gsl_vector_const_view v1 = gsl_vector_const_subvector (v, 1, v->size - 1);
00337     gsl_matrix_view A1 = gsl_matrix_submatrix (A, 0, 1, A->size1, A->size2-1);
00338     size_t i;
00339 
00340     for (i = 0; i < A->size1; i++)
00341       {
00342         double wi = 0.0;
00343         gsl_vector_view A1i = gsl_matrix_row(&A1.matrix, i);
00344         gsl_blas_ddot (&A1i.vector, &v1.vector, &wi);
00345         wi += gsl_matrix_get(A,i,0);  
00346         
00347         {
00348           double Ai0 = gsl_matrix_get (A, i, 0);
00349           gsl_matrix_set (A, i, 0, Ai0 - tau *  wi);
00350         }
00351         
00352         gsl_blas_daxpy(-tau * wi, &v1.vector, &A1i.vector);
00353       }
00354   }
00355 #else
00356   {
00357     size_t i, j;
00358     
00359     for (i = 0; i < A->size1; i++)
00360       {
00361         double wi = gsl_matrix_get(A,i,0);  
00362         
00363         for (j = 1; j < A->size2; j++)  /* note, computed for v(0) = 1 above */
00364           {
00365             wi += gsl_matrix_get(A,i,j) * gsl_vector_get(v,j);
00366           }
00367         
00368         /* j = 0 */
00369         
00370         {
00371           double Ai0 = gsl_matrix_get (A, i, 0);
00372           gsl_matrix_set (A, i, 0, Ai0 - tau *  wi);
00373         }
00374         
00375         /* j = 1 .. N-1 */
00376         
00377         for (j = 1; j < A->size2; j++) 
00378           {
00379             double vj = gsl_vector_get (v, j);
00380             double Aij = gsl_matrix_get (A, i, j);
00381             gsl_matrix_set (A, i, j, Aij - tau * wi * vj);
00382           }
00383       }
00384   }
00385 #endif
00386     
00387   return BPM_SUCCESS;
00388 }
00389 
00390 int gsl_linalg_SV_solve (const gsl_matrix * U,
00391                          const gsl_matrix * V,
00392                          const gsl_vector * S,
00393                          const gsl_vector * b, gsl_vector * x)
00394 {
00395   if (U->size1 != b->size)
00396     {
00397       bpm_error("first dimension of matrix U must size of vector b in gsl_linalg_SV_solve(..)",
00398                 __FILE__, __LINE__);
00399       return BPM_SUCCESS;
00400     }
00401   else if (U->size2 != S->size)
00402     {
00403       bpm_error("length of vector S must match second dimension of matrix U in gsl_linalg_SV_solve(..)",
00404                 __FILE__, __LINE__);
00405       return BPM_SUCCESS;
00406     }
00407   else if (V->size1 != V->size2)
00408     {
00409       bpm_error("matrix V must be square in gsl_linalg_SV_solve(..)",
00410                 __FILE__, __LINE__);
00411       return BPM_SUCCESS;
00412     }
00413   else if (S->size != V->size1)
00414     {
00415       bpm_error("length of vector S must match size of matrix V in gsl_linalg_SV_solve(..)",
00416                 __FILE__, __LINE__);
00417       return BPM_SUCCESS;
00418     }
00419   else if (V->size2 != x->size)
00420     {
00421       bpm_error("size of matrix V must match size of vector x in gsl_linalg_SV_solve(..)",
00422                 __FILE__, __LINE__);
00423       return BPM_SUCCESS;
00424     }
00425   else
00426     {
00427       const size_t N = U->size2;
00428       size_t i;
00429 
00430       gsl_vector *w = gsl_vector_calloc (N);
00431 
00432       gsl_blas_dgemv (CblasTrans, 1.0, U, b, 0.0, w);
00433 
00434       for (i = 0; i < N; i++)
00435         {
00436           double wi = gsl_vector_get (w, i);
00437           double alpha = gsl_vector_get (S, i);
00438           if (alpha != 0)
00439             alpha = 1.0 / alpha;
00440           gsl_vector_set (w, i, alpha * wi);
00441         }
00442 
00443       gsl_blas_dgemv (CblasNoTrans, 1.0, V, w, 0.0, x);
00444 
00445       gsl_vector_free (w);
00446 
00447       return BPM_SUCCESS;
00448     }
00449 }
00450 
00451 int gsl_isnan (const double x)
00452 {
00453   int status = (x != x);
00454   return status;
00455 }
00456 
00457 void chop_small_elements (gsl_vector * d, gsl_vector * f)
00458 {
00459   const size_t N = d->size;
00460   double d_i = gsl_vector_get (d, 0);
00461 
00462   size_t i;
00463 
00464   for (i = 0; i < N - 1; i++)
00465     {
00466       double f_i = gsl_vector_get (f, i);
00467       double d_ip1 = gsl_vector_get (d, i + 1);
00468 
00469       if (fabs (f_i) < GSL_DBL_EPSILON * (fabs (d_i) + fabs (d_ip1)))
00470         {
00471           gsl_vector_set (f, i, 0.0);
00472         }
00473       d_i = d_ip1;
00474     }
00475 
00476 }
00477 
00478 void qrstep (gsl_vector * d, gsl_vector * f, gsl_matrix * U, gsl_matrix * V)
00479 { 
00480 #if !USE_BLAS
00481   const size_t M = U->size1;
00482   const size_t N = V->size1;
00483 #endif
00484   const size_t n = d->size;
00485   double y, z;
00486   double ak, bk, zk, ap, bp, aq, bq;
00487   size_t i, k;
00488 
00489   if (n == 1)
00490     return;  /* shouldn't happen */
00491 
00492   /* Compute 2x2 svd directly */
00493 
00494   if (n == 2)
00495     {
00496       svd2 (d, f, U, V);
00497       return;
00498     }
00499 
00500   /* Chase out any zeroes on the diagonal */
00501 
00502   for (i = 0; i < n - 1; i++)
00503     {
00504       double d_i = gsl_vector_get (d, i);
00505       
00506       if (d_i == 0.0)
00507         {
00508           chase_out_intermediate_zero (d, f, U, i);
00509           return;
00510         }
00511     }
00512 
00513   /* Chase out any zero at the end of the diagonal */
00514 
00515   {
00516     double d_nm1 = gsl_vector_get (d, n - 1);
00517 
00518     if (d_nm1 == 0.0) 
00519       {
00520         chase_out_trailing_zero (d, f, V);
00521         return;
00522       }
00523   }
00524 
00525 
00526   /* Apply QR reduction steps to the diagonal and offdiagonal */
00527 
00528   {
00529     double d0 = gsl_vector_get (d, 0);
00530     double f0 = gsl_vector_get (f, 0);
00531     
00532     double d1 = gsl_vector_get (d, 1);
00533     double f1 = gsl_vector_get (f, 1);
00534     
00535     {
00536       double mu = trailing_eigenvalue (d, f);
00537     
00538       y = d0 * d0 - mu;
00539       z = d0 * f0;
00540     }
00541     
00542     /* Set up the recurrence for Givens rotations on a bidiagonal matrix */
00543     
00544     ak = 0;
00545     bk = 0;
00546     
00547     ap = d0;
00548     bp = f0;
00549     
00550     aq = d1;
00551     bq = f1;
00552   }
00553 
00554   for (k = 0; k < n - 1; k++)
00555     {
00556       double c, s;
00557       create_givens (y, z, &c, &s);
00558 
00559       /* Compute V <= V G */
00560 
00561 #ifdef USE_BLAS
00562       {
00563         gsl_vector_view Vk = gsl_matrix_column(V,k);
00564         gsl_vector_view Vkp1 = gsl_matrix_column(V,k+1);
00565         gsl_blas_drot(&Vk.vector, &Vkp1.vector, c, -s);
00566       }
00567 #else
00568       for (i = 0; i < N; i++)
00569         {
00570           double Vip = gsl_matrix_get (V, i, k);
00571           double Viq = gsl_matrix_get (V, i, k + 1);
00572           gsl_matrix_set (V, i, k, c * Vip - s * Viq);
00573           gsl_matrix_set (V, i, k + 1, s * Vip + c * Viq);
00574         }
00575 #endif
00576 
00577       /* compute B <= B G */
00578 
00579       {
00580         double bk1 = c * bk - s * z;
00581 
00582         double ap1 = c * ap - s * bp;
00583         double bp1 = s * ap + c * bp;
00584         double zp1 = -s * aq;
00585 
00586         double aq1 = c * aq;
00587 
00588         if (k > 0)
00589           {
00590             gsl_vector_set (f, k - 1, bk1);
00591           }
00592 
00593         ak = ap1;
00594         bk = bp1;
00595         zk = zp1;
00596 
00597         ap = aq1;
00598 
00599         if (k < n - 2)
00600           {
00601             bp = gsl_vector_get (f, k + 1);
00602           }
00603         else
00604           {
00605             bp = 0.0;
00606           }
00607 
00608         y = ak;
00609         z = zk;
00610       }
00611 
00612       create_givens (y, z, &c, &s);
00613 
00614       /* Compute U <= U G */
00615 
00616 #ifdef USE_BLAS
00617       {
00618         gsl_vector_view Uk = gsl_matrix_column(U,k);
00619         gsl_vector_view Ukp1 = gsl_matrix_column(U,k+1);
00620         gsl_blas_drot(&Uk.vector, &Ukp1.vector, c, -s);
00621       }
00622 #else
00623       for (i = 0; i < M; i++)
00624         {
00625           double Uip = gsl_matrix_get (U, i, k);
00626           double Uiq = gsl_matrix_get (U, i, k + 1);
00627           gsl_matrix_set (U, i, k, c * Uip - s * Uiq);
00628           gsl_matrix_set (U, i, k + 1, s * Uip + c * Uiq);
00629         }
00630 #endif
00631 
00632       /* compute B <= G^T B */
00633 
00634       {
00635         double ak1 = c * ak - s * zk;
00636         double bk1 = c * bk - s * ap;
00637         double zk1 = -s * bp;
00638 
00639         double ap1 = s * bk + c * ap;
00640         double bp1 = c * bp;
00641 
00642         gsl_vector_set (d, k, ak1);
00643 
00644         ak = ak1;
00645         bk = bk1;
00646         zk = zk1;
00647 
00648         ap = ap1;
00649         bp = bp1;
00650 
00651         if (k < n - 2)
00652           {
00653             aq = gsl_vector_get (d, k + 2);
00654           }
00655         else
00656           {
00657             aq = 0.0;
00658           }
00659 
00660         y = bk;
00661         z = zk;
00662       }
00663     }
00664 
00665   gsl_vector_set (f, n - 2, bk);
00666   gsl_vector_set (d, n - 1, ap);
00667 }
00668 
00669 double trailing_eigenvalue (const gsl_vector * d, const gsl_vector * f)
00670 {
00671 
00672   const size_t n = d->size;
00673 
00674   double da = gsl_vector_get (d, n - 2);
00675   double db = gsl_vector_get (d, n - 1);
00676   double fa = (n > 2) ? gsl_vector_get (f, n - 3) : 0.0;
00677   double fb = gsl_vector_get (f, n - 2);
00678 
00679   double ta = da * da + fa * fa;
00680   double tb = db * db + fb * fb;
00681   double tab = da * fb;
00682 
00683   double dt = (ta - tb) / 2.0;
00684 
00685   double mu;
00686 
00687   if (dt >= 0)
00688     {
00689       mu = tb - (tab * tab) / (dt + hypot (dt, tab));
00690     }
00691   else 
00692     {
00693       mu = tb + (tab * tab) / ((-dt) + hypot (dt, tab));
00694     }
00695 
00696   return mu;
00697 }
00698 
00699 void create_schur (double d0, double f0, double d1, double * c, double * s)
00700 {
00701 
00702   double apq = 2.0 * d0 * f0;
00703   
00704   if (apq != 0.0)
00705     {
00706       double t;
00707       double tau = (f0*f0 + (d1 + d0)*(d1 - d0)) / apq;
00708       
00709       if (tau >= 0.0)
00710         {
00711           t = 1.0/(tau + hypot(1.0, tau));
00712         }
00713       else
00714         {
00715           t = -1.0/(-tau + hypot(1.0, tau));
00716         }
00717 
00718       *c = 1.0 / hypot(1.0, t);
00719       *s = t * (*c);
00720     }
00721   else
00722     {
00723       *c = 1.0;
00724       *s = 0.0;
00725     }
00726 }
00727 
00728 void svd2 (gsl_vector * d, gsl_vector * f, gsl_matrix * U, gsl_matrix * V)
00729 {
00730 
00731   size_t i;
00732   double c, s, a11, a12, a21, a22;
00733 
00734   const size_t M = U->size1;
00735   const size_t N = V->size1;
00736 
00737   double d0 = gsl_vector_get (d, 0);
00738   double f0 = gsl_vector_get (f, 0);
00739   
00740   double d1 = gsl_vector_get (d, 1);
00741 
00742   if (d0 == 0.0)
00743     {
00744       /* Eliminate off-diagonal element in [0,f0;0,d1] to make [d,0;0,0] */
00745 
00746       create_givens (f0, d1, &c, &s);
00747 
00748       /* compute B <= G^T B X,  where X = [0,1;1,0] */
00749 
00750       gsl_vector_set (d, 0, c * f0 - s * d1);
00751       gsl_vector_set (f, 0, s * f0 + c * d1);
00752       gsl_vector_set (d, 1, 0.0);
00753       
00754       /* Compute U <= U G */
00755 
00756       for (i = 0; i < M; i++)
00757         {
00758           double Uip = gsl_matrix_get (U, i, 0);
00759           double Uiq = gsl_matrix_get (U, i, 1);
00760           gsl_matrix_set (U, i, 0, c * Uip - s * Uiq);
00761           gsl_matrix_set (U, i, 1, s * Uip + c * Uiq);
00762         }
00763 
00764       /* Compute V <= V X */
00765 
00766       gsl_matrix_swap_columns (V, 0, 1);
00767 
00768       return;
00769     }
00770   else if (d1 == 0.0)
00771     {
00772       /* Eliminate off-diagonal element in [d0,f0;0,0] */
00773 
00774       create_givens (d0, f0, &c, &s);
00775 
00776       /* compute B <= B G */
00777 
00778       gsl_vector_set (d, 0, d0 * c - f0 * s);
00779       gsl_vector_set (f, 0, 0.0);
00780 
00781       /* Compute V <= V G */
00782 
00783       for (i = 0; i < N; i++)
00784         {
00785           double Vip = gsl_matrix_get (V, i, 0);
00786           double Viq = gsl_matrix_get (V, i, 1);
00787           gsl_matrix_set (V, i, 0, c * Vip - s * Viq);
00788           gsl_matrix_set (V, i, 1, s * Vip + c * Viq);
00789         }
00790 
00791       return;
00792     }
00793   else
00794     {
00795       /* Make columns orthogonal, A = [d0, f0; 0, d1] * G */
00796       
00797       create_schur (d0, f0, d1, &c, &s);
00798       
00799       /* compute B <= B G */
00800       
00801       a11 = c * d0 - s * f0;
00802       a21 = - s * d1;
00803       
00804       a12 = s * d0 + c * f0;
00805       a22 = c * d1;
00806       
00807       /* Compute V <= V G */
00808       
00809       for (i = 0; i < N; i++)
00810         {
00811           double Vip = gsl_matrix_get (V, i, 0);
00812           double Viq = gsl_matrix_get (V, i, 1);
00813           gsl_matrix_set (V, i, 0, c * Vip - s * Viq);
00814           gsl_matrix_set (V, i, 1, s * Vip + c * Viq);
00815         }
00816       
00817       /* Eliminate off-diagonal elements, bring column with largest
00818          norm to first column */
00819       
00820       if (hypot(a11, a21) < hypot(a12,a22))
00821         {
00822           double t1, t2;
00823 
00824           /* B <= B X */
00825 
00826           t1 = a11; a11 = a12; a12 = t1;
00827           t2 = a21; a21 = a22; a22 = t2;
00828 
00829           /* V <= V X */
00830 
00831           gsl_matrix_swap_columns(V, 0, 1);
00832         } 
00833 
00834       create_givens (a11, a21, &c, &s);
00835       
00836       /* compute B <= G^T B */
00837       
00838       gsl_vector_set (d, 0, c * a11 - s * a21);
00839       gsl_vector_set (f, 0, c * a12 - s * a22);
00840       gsl_vector_set (d, 1, s * a12 + c * a22);
00841       
00842       /* Compute U <= U G */
00843       
00844       for (i = 0; i < M; i++)
00845         {
00846           double Uip = gsl_matrix_get (U, i, 0);
00847           double Uiq = gsl_matrix_get (U, i, 1);
00848           gsl_matrix_set (U, i, 0, c * Uip - s * Uiq);
00849           gsl_matrix_set (U, i, 1, s * Uip + c * Uiq);
00850         }
00851 
00852       return;
00853     }
00854 }
00855 
00856 
00857 void chase_out_intermediate_zero (gsl_vector * d, gsl_vector * f, gsl_matrix * U, size_t k0)
00858 {
00859   
00860 #if !USE_BLAS
00861   const size_t M = U->size1;
00862 #endif
00863   const size_t n = d->size;
00864   double c, s;
00865   double x, y;
00866   size_t k;
00867 
00868   x = gsl_vector_get (f, k0);
00869   y = gsl_vector_get (d, k0+1);
00870 
00871   for (k = k0; k < n - 1; k++)
00872     {
00873       create_givens (y, -x, &c, &s);
00874       
00875       /* Compute U <= U G */
00876 
00877 #ifdef USE_BLAS
00878       {
00879         gsl_vector_view Uk0 = gsl_matrix_column(U,k0);
00880         gsl_vector_view Ukp1 = gsl_matrix_column(U,k+1);
00881         gsl_blas_drot(&Uk0.vector, &Ukp1.vector, c, -s);
00882       }
00883 #else
00884       {
00885         size_t i;
00886 
00887         for (i = 0; i < M; i++)
00888           {
00889             double Uip = gsl_matrix_get (U, i, k0);
00890             double Uiq = gsl_matrix_get (U, i, k + 1);
00891             gsl_matrix_set (U, i, k0, c * Uip - s * Uiq);
00892             gsl_matrix_set (U, i, k + 1, s * Uip + c * Uiq);
00893           }
00894       }
00895 #endif
00896       
00897       /* compute B <= G^T B */
00898       
00899       gsl_vector_set (d, k + 1, s * x + c * y);
00900 
00901       if (k == k0)
00902         gsl_vector_set (f, k, c * x - s * y );
00903 
00904       if (k < n - 2) 
00905         {
00906           double z = gsl_vector_get (f, k + 1);
00907           gsl_vector_set (f, k + 1, c * z); 
00908 
00909           x = -s * z ;
00910           y = gsl_vector_get (d, k + 2); 
00911         }
00912     }
00913 }
00914 
00915 void chase_out_trailing_zero (gsl_vector * d, gsl_vector * f, gsl_matrix * V)
00916 {
00917 #if !USE_BLAS
00918   const size_t N = V->size1;
00919 #endif
00920   const size_t n = d->size;
00921   double c, s;
00922   double x, y;
00923   size_t k;
00924 
00925   x = gsl_vector_get (d, n - 2);
00926   y = gsl_vector_get (f, n - 2);
00927 
00928   for (k = n - 1; k > 0 && k--;)
00929     {
00930       create_givens (x, y, &c, &s);
00931 
00932       /* Compute V <= V G where G = [c, s ; -s, c] */
00933 
00934 #ifdef USE_BLAS
00935       {
00936         gsl_vector_view Vp = gsl_matrix_column(V,k);
00937         gsl_vector_view Vq = gsl_matrix_column(V,n-1);
00938         gsl_blas_drot(&Vp.vector, &Vq.vector, c, -s);
00939       }
00940 #else
00941       {
00942         size_t i;
00943    
00944         for (i = 0; i < N; i++)
00945           {
00946             double Vip = gsl_matrix_get (V, i, k);
00947             double Viq = gsl_matrix_get (V, i, n - 1);
00948             gsl_matrix_set (V, i, k, c * Vip - s * Viq);
00949             gsl_matrix_set (V, i, n - 1, s * Vip + c * Viq);
00950           }
00951       }
00952 #endif
00953 
00954       /* compute B <= B G */
00955       
00956       gsl_vector_set (d, k, c * x - s * y);
00957 
00958       if (k == n - 2)
00959         gsl_vector_set (f, k, s * x + c * y );
00960 
00961       if (k > 0) 
00962         {
00963           double z = gsl_vector_get (f, k - 1);
00964           gsl_vector_set (f, k - 1, c * z); 
00965 
00966           x = gsl_vector_get (d, k - 1); 
00967           y = s * z ;
00968         }
00969     }
00970 }
00971 
00972 int gsl_linalg_bidiag_unpack (const gsl_matrix * A, const gsl_vector * tau_U, 
00973                               gsl_matrix * U, const gsl_vector * tau_V,
00974                               gsl_matrix * V, gsl_vector * diag, 
00975                               gsl_vector * superdiag) {
00976   const size_t M = A->size1;
00977   const size_t N = A->size2;
00978 
00979   const size_t K = GSL_MIN(M, N);
00980 
00981   if (M < N)
00982     {
00983       bpm_error("matrix A must have M >= N in gsl_linalg_bidiag_unpack(...)",
00984                 __FILE__, __LINE__);
00985       return BPM_FAILURE;
00986     }
00987   else if (tau_U->size != K)
00988     {
00989       bpm_error("size of tau must be MIN(M,N) in gsl_linalg_bidiag_unpack(...)",
00990                 __FILE__, __LINE__);
00991       return BPM_FAILURE;
00992     }
00993   else if (tau_V->size + 1 != K)
00994     {
00995       bpm_error("size of tau must be MIN(M,N) - 1 in gsl_linalg_bidiag_unpack(...)",
00996                 __FILE__, __LINE__);
00997       return BPM_FAILURE;
00998     }
00999   else if (U->size1 != M || U->size2 != N)
01000     {
01001       bpm_error("size of U must be M x N in gsl_linalg_bidiag_unpack(...)",
01002                 __FILE__, __LINE__);
01003       return BPM_FAILURE;
01004     }
01005   else if (V->size1 != N || V->size2 != N)
01006     {
01007       bpm_error("size of V must be N x N in gsl_linalg_bidiag_unpack(...)",
01008                 __FILE__, __LINE__);
01009       return BPM_FAILURE;
01010     }
01011   else if (diag->size != K)
01012     {
01013       bpm_error("size of diagonal must match size of A in gsl_linalg_bidiag_unpack(...)",
01014                 __FILE__, __LINE__);
01015       return BPM_FAILURE;
01016     }
01017   else if (superdiag->size + 1 != K)
01018     {
01019       bpm_error("size of subdiagonal must be (diagonal size - 1) in gsl_linalg_bidiag_unpack(...)",
01020                 __FILE__, __LINE__);
01021       return BPM_FAILURE;
01022     }
01023   else
01024     {
01025       size_t i, j;
01026 
01027       /* Copy diagonal into diag */
01028 
01029       for (i = 0; i < N; i++)
01030         {
01031           double Aii = gsl_matrix_get (A, i, i);
01032           gsl_vector_set (diag, i, Aii);
01033         }
01034 
01035       /* Copy superdiagonal into superdiag */
01036 
01037       for (i = 0; i < N - 1; i++)
01038         {
01039           double Aij = gsl_matrix_get (A, i, i+1);
01040           gsl_vector_set (superdiag, i, Aij);
01041         }
01042 
01043       /* Initialize V to the identity */
01044 
01045       gsl_matrix_set_identity (V);
01046 
01047       for (i = N - 1; i > 0 && i--;)
01048         {
01049           /* Householder row transformation to accumulate V */
01050           gsl_vector_const_view r = gsl_matrix_const_row (A, i);
01051           gsl_vector_const_view h = 
01052             gsl_vector_const_subvector (&r.vector, i + 1, N - (i+1));
01053           
01054           double ti = gsl_vector_get (tau_V, i);
01055           
01056           gsl_matrix_view m = 
01057             gsl_matrix_submatrix (V, i + 1, i + 1, N-(i+1), N-(i+1));
01058           
01059           gsl_linalg_householder_hm (ti, &h.vector, &m.matrix);
01060         }
01061 
01062       /* Initialize U to the identity */
01063 
01064       gsl_matrix_set_identity (U);
01065 
01066       for (j = N; j > 0 && j--;)
01067         {
01068           /* Householder column transformation to accumulate U */
01069           gsl_vector_const_view c = gsl_matrix_const_column (A, j);
01070           gsl_vector_const_view h = gsl_vector_const_subvector (&c.vector, j, M - j);
01071           double tj = gsl_vector_get (tau_U, j);
01072           
01073           gsl_matrix_view m = 
01074             gsl_matrix_submatrix (U, j, j, M-j, N-j);
01075           
01076           gsl_linalg_householder_hm (tj, &h.vector, &m.matrix);
01077         }
01078 
01079       return BPM_SUCCESS;
01080     }
01081 }
01082 
01083 int gsl_linalg_bidiag_unpack2 (gsl_matrix * A, gsl_vector * tau_U, gsl_vector * tau_V, gsl_matrix * V)
01084 {
01085 
01086   const size_t M = A->size1;
01087   const size_t N = A->size2;
01088 
01089   const size_t K = GSL_MIN(M, N);
01090 
01091   if (M < N)
01092     {
01093       bpm_error("matrix A must have M >= N in gsl_linalg_bidiag_unpack2(...)",
01094                 __FILE__, __LINE__);
01095       return BPM_FAILURE;
01096     }
01097   else if (tau_U->size != K)
01098     {
01099       bpm_error("size of tau must be MIN(M,N) in gsl_linalg_bidiag_unpack2(...)",
01100                 __FILE__, __LINE__);
01101       return BPM_FAILURE;
01102     }
01103   else if (tau_V->size + 1 != K)
01104     {
01105       bpm_error("size of tau must be MIN(M,N) - 1 in gsl_linalg_bidiag_unpack2(...)",
01106                 __FILE__, __LINE__);
01107       return BPM_FAILURE;
01108     }
01109   else if (V->size1 != N || V->size2 != N)
01110     {
01111       bpm_error("size of V must be N x N in gsl_linalg_bidiag_unpack2(...)",
01112                 __FILE__, __LINE__);
01113       return BPM_FAILURE;
01114     }
01115   else
01116     {
01117       size_t i, j;
01118 
01119       /* Initialize V to the identity */
01120 
01121       gsl_matrix_set_identity (V);
01122 
01123       for (i = N - 1; i > 0 && i--;)
01124         {
01125           /* Householder row transformation to accumulate V */
01126           gsl_vector_const_view r = gsl_matrix_const_row (A, i);
01127           gsl_vector_const_view h = 
01128             gsl_vector_const_subvector (&r.vector, i + 1, N - (i+1));
01129           
01130           double ti = gsl_vector_get (tau_V, i);
01131           
01132           gsl_matrix_view m = 
01133             gsl_matrix_submatrix (V, i + 1, i + 1, N-(i+1), N-(i+1));
01134           
01135           gsl_linalg_householder_hm (ti, &h.vector, &m.matrix);
01136         }
01137 
01138       /* Copy superdiagonal into tau_v */
01139 
01140       for (i = 0; i < N - 1; i++)
01141         {
01142           double Aij = gsl_matrix_get (A, i, i+1);
01143           gsl_vector_set (tau_V, i, Aij);
01144         }
01145 
01146       /* Allow U to be unpacked into the same memory as A, copy
01147          diagonal into tau_U */
01148 
01149       for (j = N; j > 0 && j--;)
01150         {
01151           /* Householder column transformation to accumulate U */
01152           double tj = gsl_vector_get (tau_U, j);
01153           double Ajj = gsl_matrix_get (A, j, j);
01154           gsl_matrix_view m = gsl_matrix_submatrix (A, j, j, M-j, N-j);
01155 
01156           gsl_vector_set (tau_U, j, Ajj);
01157           gsl_linalg_householder_hm1 (tj, &m.matrix);
01158         }
01159 
01160       return BPM_SUCCESS;
01161     }
01162 }
01163 
01164 int gsl_linalg_SV_decomp (gsl_matrix * A, gsl_matrix * V, gsl_vector * S, 
01165                           gsl_vector * work) {
01166 
01167   size_t a, b, i, j;
01168 
01169   const size_t M = A->size1;
01170   const size_t N = A->size2;
01171   const size_t K = GSL_MIN (M, N);
01172 
01173   if (M < N)
01174     {
01175       bpm_error( "svd of MxN matrix, M<N, is not implemented in gsl_linalg_SV_solve(...)",
01176                  __FILE__, __LINE__);
01177     }
01178   else if (V->size1 != N)
01179     {
01180       bpm_error( "square matrix V must match second dimension of matrix A in gsl_linalg_SV_solve(...)",
01181                  __FILE__, __LINE__);
01182     }
01183   else if (V->size1 != V->size2)
01184     {
01185       bpm_error( "matrix V must be square in gsl_linalg_SV_solve(...)",
01186                  __FILE__, __LINE__);
01187     }
01188   else if (S->size != N)
01189     {
01190       bpm_error( "length of vector S must match second dimension of matrix A in gsl_linalg_SV_solve(...)",
01191                  __FILE__, __LINE__);
01192     }
01193   else if (work->size != N)
01194     {
01195       bpm_error( "length of workspace must match second dimension of matrix A in gsl_linalg_SV_solve(...)",
01196                  __FILE__, __LINE__);
01197     }
01198 
01199   /* Handle the case of N = 1 (SVD of a column vector) */
01200 
01201   if (N == 1)
01202     {
01203       gsl_vector_view column = gsl_matrix_column (A, 0);
01204       double norm = gsl_blas_dnrm2 (&column.vector);
01205 
01206       gsl_vector_set (S, 0, norm); 
01207       gsl_matrix_set (V, 0, 0, 1.0);
01208       
01209       if (norm != 0.0)
01210         {
01211           gsl_blas_dscal (1.0/norm, &column.vector);
01212         }
01213 
01214       return BPM_SUCCESS;
01215     }
01216   
01217   {
01218     gsl_vector_view f = gsl_vector_subvector (work, 0, K - 1);
01219     
01220     /* bidiagonalize matrix A, unpack A into U S V */
01221 
01222     gsl_linalg_bidiag_decomp (A, S, &f.vector);
01223     gsl_linalg_bidiag_unpack2 (A, S, &f.vector, V);
01224 
01225     /* apply reduction steps to B=(S,Sd) */
01226     chop_small_elements (S, &f.vector);
01227 
01228     /* Progressively reduce the matrix until it is diagonal */
01229     
01230     b = N - 1;
01231     
01232     while (b > 0)
01233       {
01234         double fbm1 = gsl_vector_get (&f.vector, b - 1);
01235 
01236         if (fbm1 == 0.0 || gsl_isnan (fbm1))
01237           {
01238             b--;
01239             continue;
01240           }
01241 
01242         /* Find the largest unreduced block (a,b) starting from b
01243            and working backwards */
01244         
01245         a = b - 1;
01246         
01247         while (a > 0)
01248           {
01249             double fam1 = gsl_vector_get (&f.vector, a - 1);
01250 
01251             if (fam1 == 0.0 || gsl_isnan (fam1))
01252               {
01253                 break;
01254               }
01255             
01256             a--;
01257 
01258           }
01259 
01260         {
01261           const size_t n_block = b - a + 1;
01262 
01263           gsl_vector_view S_block = gsl_vector_subvector (S, a, n_block);
01264           gsl_vector_view f_block = gsl_vector_subvector (&f.vector, a, n_block - 1);
01265           
01266           gsl_matrix_view U_block =
01267             gsl_matrix_submatrix (A, 0, a, A->size1, n_block);
01268           gsl_matrix_view V_block =
01269             gsl_matrix_submatrix (V, 0, a, V->size1, n_block);
01270           
01271           qrstep (&S_block.vector, &f_block.vector, &U_block.matrix, &V_block.matrix);
01272           /* remove any small off-diagonal elements */
01273           
01274           chop_small_elements (&S_block.vector, &f_block.vector);
01275         }
01276       }
01277   }
01278   /* Make singular values positive by reflections if necessary */
01279   
01280   for (j = 0; j < K; j++)
01281     {
01282       double Sj = gsl_vector_get (S, j);
01283       
01284       if (Sj < 0.0)
01285         {
01286           for (i = 0; i < N; i++)
01287             {
01288               double Vij = gsl_matrix_get (V, i, j);
01289 
01290               gsl_matrix_set (V, i, j, -Vij);
01291             }
01292           
01293           gsl_vector_set (S, j, -Sj);
01294         }
01295     }
01296   
01297   /* Sort singular values into decreasing order */
01298   
01299   for (i = 0; i < K; i++)
01300     {
01301       double S_max = gsl_vector_get (S, i);
01302       size_t i_max = i;
01303       
01304       for (j = i + 1; j < K; j++)
01305         {
01306           double Sj = gsl_vector_get (S, j);
01307           
01308           if (Sj > S_max)
01309             {
01310               S_max = Sj;
01311               i_max = j;
01312             }
01313         }
01314       
01315       if (i_max != i)
01316         {
01317           /* swap eigenvalues */
01318           gsl_vector_swap_elements (S, i, i_max);
01319           
01320           /* swap eigenvectors */
01321           gsl_matrix_swap_columns (A, i, i_max);
01322           gsl_matrix_swap_columns (V, i, i_max);
01323         }
01324     }
01325   
01326   return BPM_SUCCESS;
01327 }
01328 

Generated on Thu Jan 10 10:18:04 2008 for libbpm by  doxygen 1.5.1