src/linalg.c

Go to the documentation of this file.
00001 /*
00002    libit - Library for basic source and channel coding functions
00003    Copyright (C) 2005-2005 Vivien Chappelier, Herve Jegou
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public
00016    License along with this library; if not, write to the Free
00017    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00018 */
00019 
00020 /*
00021   Linear algebra functions
00022   Copyright (C) 2006 Vivien Chappelier, Herve Jegou, François Cayre
00023 */
00024 
00025 #include <it/linalg.h>
00026 #include <it/mat.h>
00027 #include <it/vec.h>
00028 
00029 /* 
00030   Static helper functions: 
00031   - ccdiv( ... ): I know it is ugly. Should be performed 
00032     with standard libit cdiv. Too lazy to do it right 
00033     now. 
00034   - maxx( double, double ): ugly too. 
00035 
00036 -> Francois, tu seras flagellé sur la place publique pour cette insulte 
00037    au dogme que tu es censé défendre
00038 */
00039 
00040 static void ccdiv (double xr, double xi, double yr, double yi, double *cdivr,
00041        double *cdivi)
00042 {
00043   double r, d;
00044 
00045   if (fabs (yr) > fabs (yi)) {
00046     r = yi / yr;
00047     d = yr + r * yi;
00048     *cdivr = (xr + r * xi) / d;
00049     *cdivi = (xi - r * xr) / d;
00050   }
00051   else {
00052     r = yr / yi;
00053     d = yi + r * yr;
00054     *cdivr = (r * xr + xi) / d;
00055     *cdivi = (r * xi - xr) / d;
00056   }
00057 }
00058 
00059 
00060 static double maxx (double a, double b)
00061 {
00062   if (a > b)
00063     return (a);
00064   else
00065     return (b);
00066 }
00067 
00068 int mat_is_symmetric( mat a ) 
00069 {
00070 
00071   idx_t i, j; 
00072 
00073   if( mat_width(a)!=mat_height(a) ) 
00074     return 0; 
00075 
00076   for ( i= 0; i< mat_width(a); i++ )
00077     for ( j= 0; j< i; j++ ) 
00078       if ( a[i][j]!=a[j][i] ) return 0; 
00079 
00080   return 1; 
00081 }
00082 
00083 /* 
00084    SVD decomposition 
00085 
00086    Set either U or V (or both) to  NULL to  *not* compute 
00087    singular subspaces. 
00088 
00089    If one wants to compute singular subspaces, make  sure 
00090    allocation of U and V matrices has been performed in a 
00091    proper way (check size). 
00092 
00093    In particular: 
00094    - U = mat_new( m, min( m, n ) ); 
00095    - V = mat_new( n, n ); 
00096 
00097    NOTE: This implementation is known to work with m>=n 
00098    matrices and *may* fail with m<n matrices. We chose 
00099    the conservative approach. 
00100    
00101 */
00102 
00103 vec mat_svd (mat M, mat U, mat V)
00104 {
00105   /* Initialize */
00106 
00107   int  i, j, k, kase, ks, m, n, p, pp, iter, nu, nct, nrt, wantu = 0, wantv =
00108     0;
00109   int  mmax;
00110 
00111   double t, f, g, cs, sn, eps, scale, sp, spm1, epm1, sk, ek, b, c, shift;
00112   mat A; 
00113   vec  s, e, work;
00114 
00115   m = mat_height (M);
00116   n = mat_width (M);
00117 
00118   /* Comment this next line if you want a non conservative SVD */
00119   it_assert (m >= n, "This SVD is meant for m > n matrices");
00120 
00121   nu = m > n ? n : m;
00122 
00123   s = vec_new_zeros (m + 1 > n ? n : m + 1);
00124 
00125   if (U) {
00126     it_assert (mat_height (U) == m
00127          && mat_width (U) == nu,
00128          "U matrix should be a m by min(m+1,n) real matrix");
00129     mat_zeros (U);
00130     wantu = 1;
00131   }
00132 
00133   if (V) {
00134     it_assert (mat_height (V) == mat_width (V), "Matrix V must be square");
00135     it_assert (mat_height (V) == n, "Size mismatch for matrix V");
00136     mat_zeros (V);
00137     wantv = 1;
00138   }
00139 
00140   A = mat_clone( M );
00141 
00142   e = vec_new_zeros (n);
00143   work = vec_new_zeros (m);
00144 
00145   /* 
00146      Reduce A to bidiagonal form, storing the diagonal elements
00147      in s and the super-diagonal elements in e.
00148    */
00149 
00150   nct = m - 1 > n ? n : m - 1;
00151   nrt = 0 > (n - 2 > m ? m : n - 2) ? 0 : (n - 2 > m ? m : n - 2);
00152 
00153   mmax = nct > nrt ? nct : nrt;
00154 
00155   for (k = 0; k < mmax; k++) {
00156     if (k < nct) {
00157       /* 
00158          Compute the transformation for the k-th column and
00159          place the k-th diagonal in s[k].
00160          Compute 2-norm of k-th column without under/overflow.
00161        */
00162 
00163       s[k] = 0;
00164       for (i = k; i < m; i++)
00165   s[k] = sqrt (s[k] * s[k] + A[i][k] * A[i][k]);
00166 
00167       if (s[k]) {
00168   if (A[k][k] < 0.0)
00169     s[k] = -s[k];
00170 
00171   for (i = k; i < m; i++)
00172     A[i][k] /= s[k];
00173 
00174   A[k][k] += 1.0;
00175       }
00176       s[k] = -s[k];
00177     }
00178     for (j = k + 1; j < n; j++) {
00179       if ((k < nct) && (s[k] != 0.0)) {
00180   /* Apply the transformation */
00181 
00182   t = 0.;
00183   for (i = k; i < m; i++)
00184     t += A[i][k] * A[i][j];
00185 
00186   t = -t / A[k][k];
00187   for (i = k; i < m; i++)
00188     A[i][j] += t * A[i][k];
00189 
00190       }
00191 
00192       /* 
00193          Place the k-th row of A into e for the
00194          subsequent calculation of the row transformation
00195        */
00196 
00197       e[j] = A[k][j];
00198     }
00199     if (wantu && (k < nct)) {
00200       /* 
00201          Place the transformation in U for subsequent back
00202          multiplication.
00203        */
00204 
00205       for (i = k; i < m; i++)
00206   U[i][k] = A[i][k];
00207 
00208     }
00209     if (k < nrt) {
00210       /* 
00211          Compute the k-th row transformation and place the
00212          k-th super-diagonal in e[k].
00213          Compute 2-norm without under/overflow.
00214        */
00215 
00216       e[k] = 0;
00217       for (i = k + 1; i < n; i++)
00218   e[k] = sqrt (e[k] * e[k] + e[i] * e[i]);
00219 
00220       if (e[k]) {
00221   if (e[k + 1] < 0.0)
00222     e[k] = -e[k];
00223 
00224   for (i = k + 1; i < n; i++)
00225     e[i] /= e[k];
00226 
00227   e[k + 1] += 1.0;
00228       }
00229       e[k] = -e[k];
00230       if ((k + 1 < m) && e[k]) {
00231 
00232   /* Apply the transformation */
00233 
00234   for (i = k + 1; i < m; i++)
00235     work[i] = 0.0;
00236 
00237   for (j = k + 1; j < n; j++)
00238     for (i = k + 1; i < m; i++)
00239       work[i] += e[j] * A[i][j];
00240 
00241   for (j = k + 1; j < n; j++) {
00242     t = -e[j] / e[k + 1];
00243     for (i = k + 1; i < m; i++)
00244       A[i][j] += t * work[i];
00245   }
00246       }
00247       if (wantv) {
00248   /* 
00249      Place the transformation in V for subsequent
00250      back multiplication
00251    */
00252 
00253   for (i = k + 1; i < n; i++)
00254     V[i][k] = e[i];
00255 
00256       }
00257     }
00258   }
00259 
00260   /* Set up the final bidiagonal matrix or order p */
00261 
00262   p = n > m + 1 ? m + 1 : n;
00263 
00264   if (nct < n)
00265     s[nct] = A[nct][nct];
00266   if (m < p)
00267     s[p - 1] = 0.0;
00268   if (nrt + 1 < p)
00269     e[nrt] = A[nrt][p - 1];
00270 
00271   e[p - 1] = 0.0;
00272 
00273   /* If required, generate U */
00274 
00275   if (wantu) {
00276     for (j = nct; j < nu; j++) {
00277       for (i = 0; i < m; i++)
00278   U[i][j] = 0.0;
00279 
00280       U[j][j] = 1.0;
00281     }
00282     for (k = nct - 1; k >= 0; k--) {
00283       if (s[k]) {
00284   for (j = k + 1; j < nu; j++) {
00285     t = 0.;
00286     for (i = k; i < m; i++)
00287       t += U[i][k] * U[i][j];
00288 
00289     t = -t / U[k][k];
00290     for (i = k; i < m; i++)
00291       U[i][j] += t * U[i][k];
00292 
00293   }
00294   for (i = k; i < m; i++)
00295     U[i][k] = -U[i][k];
00296 
00297   U[k][k] = 1.0 + U[k][k];
00298   for (i = 0; i < k - 1; i++)
00299     U[i][k] = 0.0;
00300 
00301       }
00302       else {
00303   for (i = 0; i < m; i++)
00304     U[i][k] = 0.0;
00305 
00306   U[k][k] = 1.0;
00307       }
00308     }
00309   }
00310 
00311   /* If required, generate V */
00312 
00313   if (wantv) {
00314     for (k = n - 1; k >= 0; k--) {
00315       if ((k < nrt) && e[k]) {
00316   for (j = k + 1; j < nu; j++) {
00317     t = 0.;
00318     for (i = k + 1; i < n; i++)
00319       t += V[i][k] * V[i][j];
00320 
00321     t = -t / V[k + 1][k];
00322     for (i = k + 1; i < n; i++)
00323       V[i][j] += t * V[i][k];
00324 
00325   }
00326       }
00327       for (i = 0; i < n; i++)
00328   V[i][k] = 0.0;
00329 
00330       V[k][k] = 1.0;
00331     }
00332   }
00333 
00334 
00335   /* Main iteration loop for the singular values */
00336 
00337   pp = p - 1;
00338   iter = 0;
00339   eps = pow (2.0, -52.0);
00340 
00341   while (p > 0) {
00342     /* Here is where a test for too many iterations would go */
00343 
00344     /* 
00345        This section of the program inspects for
00346        negligible elements in the s and e arrays.  On
00347        completion the variables kase and k are set as follows.
00348 
00349        kase = 1     if s(p) and e[k-1] are negligible and k<p
00350        kase = 2     if s(k) is negligible and k<p
00351        kase = 3     if e[k-1] is negligible, k<p, and
00352        s(k), ..., s(p) are not negligible (qr step).
00353        kase = 4     if e(p-1) is negligible (convergence).
00354      */
00355 
00356     for (k = p - 2; k >= -1; k--) {
00357       if (k == -1)
00358   break;
00359 
00360       if (fabs (e[k]) <= eps * (fabs (s[k]) + fabs (s[k + 1]))) {
00361   e[k] = 0.0;
00362   break;
00363       }
00364     }
00365 
00366     if (k == p - 2)
00367       kase = 4;
00368 
00369     else {
00370       for (ks = p - 1; ks >= k; ks--) {
00371   if (ks == k)
00372     break;
00373 
00374   t =
00375     (ks != p ? fabs (e[ks]) : 0.) + (ks !=
00376              k + 1 ? fabs (e[ks - 1]) : 0.);
00377   if (fabs (s[ks]) <= eps * t) {
00378     s[ks] = 0.0;
00379     break;
00380   }
00381       }
00382       if (ks == k)
00383   kase = 3;
00384       else if (ks == p - 1)
00385   kase = 1;
00386       else {
00387   kase = 2;
00388   k = ks;
00389       }
00390     }
00391     k++;
00392 
00393     /* Perform the task indicated by kase */
00394 
00395     switch (kase) {
00396       /* Deflate negligible s(p) */
00397 
00398     case 1:{
00399   f = e[p - 2];
00400   e[p - 2] = 0.;
00401   for (j = p - 2; j >= k; j--) {
00402     t = sqrt (s[j] * s[j] + f * f);
00403     cs = s[j] / t;
00404     sn = f / t;
00405     s[j] = t;
00406     if (j != k) {
00407       f = -sn * e[j - 1];
00408       e[j - 1] = cs * e[j - 1];
00409     }
00410     if (wantv) {
00411       for (i = 0; i < n; i++) {
00412         t = cs * V[i][j] + sn * V[i][p - 1];
00413         V[i][p - 1] = -sn * V[i][j] + cs * V[i][p - 1];
00414         V[i][j] = t;
00415       }
00416     }
00417   }
00418       }
00419       break;
00420 
00421       /* Split at negligible s(k) */
00422 
00423     case 2:{
00424   f = e[k - 1];
00425   e[k - 1] = 0.0;
00426   for (j = k; j < p; j++) {
00427     t = sqrt (s[j] * s[j] + f * f);
00428     cs = s[j] / t;
00429     sn = f / t;
00430     s[j] = t;
00431     f = -sn * e[j];
00432     e[j] = cs * e[j];
00433     if (wantu) {
00434       for (i = 0; i < m; i++) {
00435         t = cs * U[i][j] + sn * U[i][k - 1];
00436         U[i][k - 1] = -sn * U[i][j] + cs * U[i][k - 1];
00437         U[i][j] = t;
00438       }
00439     }
00440   }
00441       }
00442       break;
00443 
00444       /* Perform one qr step */
00445 
00446     case 3:{
00447 
00448   /* Calculate the shift */
00449   scale =
00450     maxx (maxx
00451     (maxx
00452      (maxx (fabs (s[p - 1]), fabs (s[p - 2])), fabs (e[p - 2])),
00453      fabs (s[k])), fabs (e[k]));
00454 
00455   sp = s[p - 1] / scale;
00456   spm1 = s[p - 2] / scale;
00457   epm1 = e[p - 2] / scale;
00458   sk = s[k] / scale;
00459   ek = e[k] / scale;
00460   b = ((spm1 + sp) * (spm1 - sp) + epm1 * epm1) / 2.0;
00461   c = (sp * epm1) * (sp * epm1);
00462   shift = 0.;
00463   if (b || c) {
00464     shift = sqrt (b * b + c);
00465     if (b < 0.0)
00466       shift = -shift;
00467 
00468     shift = c / (b + shift);
00469   }
00470   f = (sk + sp) * (sk - sp) + shift;
00471   g = sk * ek;
00472 
00473   /* Chase zeros */
00474 
00475   for (j = k; j < p - 1; j++) {
00476     t = sqrt (f * f + g * g);
00477     cs = f / t;
00478     sn = g / t;
00479     if (j != k)
00480       e[j - 1] = t;
00481 
00482     f = cs * s[j] + sn * e[j];
00483     e[j] = cs * e[j] - sn * s[j];
00484     g = sn * s[j + 1];
00485     s[j + 1] = cs * s[j + 1];
00486     if (wantv) {
00487       for (i = 0; i < n; i++) {
00488         t = cs * V[i][j] + sn * V[i][j + 1];
00489         V[i][j + 1] = -sn * V[i][j] + cs * V[i][j + 1];
00490         V[i][j] = t;
00491       }
00492     }
00493     t = sqrt (f * f + g * g);
00494     cs = f / t;
00495     sn = g / t;
00496     s[j] = t;
00497     f = cs * e[j] + sn * s[j + 1];
00498     s[j + 1] = -sn * e[j] + cs * s[j + 1];
00499     g = sn * e[j + 1];
00500     e[j + 1] = cs * e[j + 1];
00501     if (wantu && (j < m - 1)) {
00502       for (i = 0; i < m; i++) {
00503         t = cs * U[i][j] + sn * U[i][j + 1];
00504         U[i][j + 1] = -sn * U[i][j] + cs * U[i][j + 1];
00505         U[i][j] = t;
00506       }
00507     }
00508   }
00509   e[p - 2] = f;
00510   iter = iter + 1;
00511       }
00512 
00513       break;
00514 
00515       /* Convergence */
00516 
00517     case 4:{
00518 
00519   /* Make the singular values positive */
00520 
00521   if (s[k] <= 0.0) {
00522     s[k] = (s[k] < 0.0 ? -s[k] : 0.0);
00523     if (wantv)
00524       for (i = 0; i <= pp; i++)
00525         V[i][k] = -V[i][k];
00526   }
00527 
00528   /* Order the singular values */
00529 
00530   while (k < pp) {
00531     if (s[k] >= s[k + 1])
00532       break;
00533 
00534     t = s[k];
00535     s[k] = s[k + 1];
00536     s[k + 1] = t;
00537 
00538     if (wantv && (k < n - 1)) {
00539       for (i = 0; i < n; i++)
00540         {
00541     t = V[i][k + 1];
00542     V[i][k + 1] = V[i][k];
00543     V[i][k] = t;
00544         }
00545     }
00546 
00547     if (wantu && (k < m - 1)) {
00548       for (i = 0; i < m; i++)
00549         {
00550     t = U[i][k + 1];
00551     U[i][k + 1] = U[i][k];
00552     U[i][k] = t;
00553         }
00554     }
00555 
00556     k++;
00557   }
00558   iter = 0;
00559   p--;
00560       }
00561       break;
00562     }
00563   }
00564 
00565   vec_delete (e);
00566   vec_delete (work);
00567 
00568   return (s);
00569 }
00570 
00571 
00572 /* 
00573    This is the recommended way of computing the rank of a matrix. 
00574  */
00575 
00576 int mat_rank (mat a)
00577 {
00578   int  i, r = 0;
00579   double eps = pow (2., -52.);
00580   double tol;
00581   vec  s = mat_svd (a, NULL, NULL);
00582 
00583   tol = (double) (mat_height (a) >
00584       mat_width (a) ? mat_height (a) : mat_width (a)) * s[0] * eps;
00585 
00586   for (i = 0; i < vec_length (s); i++)
00587     if (s[i] > tol)
00588       r++;
00589 
00590   vec_delete (s);
00591 
00592   return (r);
00593 }
00594 
00595 
00596 /*
00597   Condition number of a matrix is the ratio of the two extremal singular values. 
00598  */
00599 double mat_cond (mat a)
00600 {
00601   double cond;
00602   vec  s = mat_svd (a, NULL, NULL);
00603 
00604   cond =
00605     s[0] / s[mat_height (a) >
00606        mat_width (a) ? mat_width (a) - 1 : mat_height (a) - 1];
00607 
00608   vec_delete (s);
00609 
00610   return (cond);
00611 
00612 }
00613 
00614 /*
00615   2-norm of a matrix is the largest singular value. 
00616  */
00617 
00618 double mat_norm2 (mat a)
00619 {
00620 
00621   double norm2;
00622   vec  s = mat_svd (a, NULL, NULL);
00623 
00624   norm2 = s[0];
00625 
00626   vec_delete (s);
00627 
00628   return (norm2);
00629 
00630 }
00631 
00632 static mat mat_tridiag (vec e, vec d, mat evec)
00633 {
00634 
00635   int  i, j, k, n;
00636   double scale, f, g, h, hh;
00637 
00638   it_assert (mat_width (evec) == mat_height (evec), "Matrix must be square");
00639 
00640   n = mat_height (evec);
00641 
00642   vec_zeros (e);
00643 
00644   for (j = 0; j < n; j++)
00645     d[j] = evec[n - 1][j];
00646 
00647   /* Householder reduction to tridiagonal form */
00648 
00649   for (i = n - 1; i > 0; i--) {
00650     /* Scale to avoid under/overflow */
00651 
00652     scale = 0.0;
00653     h = 0.0;
00654 
00655     for (k = 0; k < i; k++)
00656       scale += fabs (d[k]);
00657 
00658     if (!scale) {
00659       e[i] = d[i - 1];
00660       for (j = 0; j < i; j++) {
00661   d[j] = evec[i - 1][j];
00662   evec[i][j] = 0.0;
00663   evec[j][i] = 0.0;
00664       }
00665     }
00666     else {
00667       /* Generate Householder vector */
00668 
00669       for (k = 0; k < i; k++) {
00670   d[k] /= scale;
00671   h += d[k] * d[k];
00672       }
00673       f = d[i - 1];
00674       g = sqrt (h);
00675       if (f > 0)
00676   g = -g;
00677 
00678       e[i] = scale * g;
00679       h = h - f * g;
00680       d[i - 1] = f - g;
00681       for (j = 0; j < i; j++)
00682   e[j] = 0.0;
00683 
00684       /* Apply similarity transformation to remaining columns */
00685 
00686       for (j = 0; j < i; j++) {
00687   f = d[j];
00688   evec[j][i] = f;
00689   g = e[j] + evec[j][j] * f;
00690   for (k = j + 1; k <= i - 1; k++) {
00691     g += evec[k][j] * d[k];
00692     e[k] += evec[k][j] * f;
00693   }
00694   e[j] = g;
00695       }
00696       f = 0.0;
00697       for (j = 0; j < i; j++) {
00698   e[j] /= h;
00699   f += e[j] * d[j];
00700       }
00701       hh = f / (h + h);
00702       for (j = 0; j < i; j++)
00703   e[j] -= hh * d[j];
00704 
00705       for (j = 0; j < i; j++) {
00706   f = d[j];
00707   g = e[j];
00708   for (k = j; k <= i - 1; k++)
00709     evec[k][j] -= (f * e[k] + g * d[k]);
00710 
00711   d[j] = evec[i - 1][j];
00712   evec[i][j] = 0.0;
00713       }
00714     }
00715     d[i] = h;
00716   }
00717 
00718   /* Accumulate transformations */
00719 
00720   for (i = 0; i < n - 1; i++) {
00721     evec[n - 1][i] = evec[i][i];
00722     evec[i][i] = 1.0;
00723     h = d[i + 1];
00724     if (h != 0.0) {
00725       for (k = 0; k <= i; k++)
00726   d[k] = evec[k][i + 1] / h;
00727 
00728       for (j = 0; j <= i; j++) {
00729   g = 0.0;
00730   for (k = 0; k <= i; k++)
00731     g += evec[k][i + 1] * evec[k][j];
00732 
00733   for (k = 0; k <= i; k++)
00734     evec[k][j] -= g * d[k];
00735 
00736       }
00737     }
00738 
00739     for (k = 0; k <= i; k++)
00740       evec[k][i + 1] = 0.0;
00741 
00742   }
00743   for (j = 0; j < n; j++) {
00744     d[j] = evec[n - 1][j];
00745     evec[n - 1][j] = 0.0;
00746   }
00747   evec[n - 1][n - 1] = 1.0;
00748   e[0] = 0.0;
00749 
00750   return (evec);
00751 
00752 }
00753 
00754 
00755 /* Symmetric tridiagonal QL algorithm */
00756 static vec mat_tridiag_ql (vec e, vec d, mat evec)
00757 {
00758   int  i, j, k, l, m, n, iter;
00759   double f, tst1, eps, p, g, r, el1, dl1, h, c, c2, c3, s, s2;
00760 
00761   n = mat_height (evec);
00762 
00763   for (i = 1; i < n; i++)
00764     e[i - 1] = e[i];
00765 
00766   e[n - 1] = 0.0;
00767 
00768   f = 0.0;
00769   tst1 = 0.0;
00770   eps = pow (2.0, -52.0);
00771 
00772   for (l = 0; l < n; l++) {
00773     /* Find small subdiagonal element */
00774 
00775     tst1 =
00776       tst1 > fabs (d[l]) + fabs (e[l]) ? tst1 : fabs (d[l]) + fabs (e[l]);
00777     m = l;
00778 
00779     while (m < n) {
00780       if (fabs (e[m]) <= eps * tst1)
00781   break;
00782 
00783       m++;
00784     }
00785 
00786     /* 
00787        If m == l, d[l] is an eigenvalue,
00788        otherwise, iterate.
00789      */
00790 
00791     if (m > l) {
00792       iter = 0;
00793 
00794       do {
00795   iter++;     /* (Could check iteration count here.) */
00796 
00797   /* Compute implicit shift */
00798 
00799   g = d[l];
00800   p = (d[l + 1] - g) / (2.0 * e[l]);
00801   r = sqrt (p * p + 1.);
00802   if (p < 0)
00803     r = -r;
00804 
00805   d[l] = e[l] / (p + r);
00806   d[l + 1] = e[l] * (p + r);
00807   dl1 = d[l + 1];
00808   h = g - d[l];
00809   for (i = l + 2; i < n; i++)
00810     d[i] -= h;
00811 
00812   f = f + h;
00813 
00814   /* Implicit QL transformation */
00815 
00816   p = d[m];
00817   c = 1.0;
00818   c2 = c;
00819   c3 = c;
00820   el1 = e[l + 1];
00821   s = 0.0;
00822   s2 = 0.0;
00823 
00824   for (i = m - 1; i >= l; i--) {
00825     c3 = c2;
00826     c2 = c;
00827     s2 = s;
00828     g = c * e[i];
00829     h = c * p;
00830     r = sqrt (p * p + e[i] * e[i]);
00831     e[i + 1] = s * r;
00832     s = e[i] / r;
00833     c = p / r;
00834     p = c * d[i] - s * g;
00835     d[i + 1] = h + s * (c * g + s * d[i]);
00836 
00837     /* Accumulate transformation */
00838 
00839     for (k = 0; k < n; k++) {
00840       h = evec[k][i + 1];
00841       evec[k][i + 1] = s * evec[k][i] + c * h;
00842       evec[k][i] = c * evec[k][i] - s * h;
00843     }
00844   }
00845   p = -s * s2 * c3 * el1 * e[l] / dl1;
00846   e[l] = s * p;
00847   d[l] = c * p;
00848 
00849   /* Check for convergence */
00850 
00851       } while (fabs (e[l]) > eps * tst1);
00852     }
00853     d[l] = d[l] + f;
00854     e[l] = 0.0;
00855   }
00856 
00857   /* Sort eigenvalues and corresponding vectors */
00858 
00859   for (i = 0; i < n - 1; i++) {
00860     k = i;
00861     p = d[i];
00862 
00863     for (j = i + 1; j < n; j++)
00864       if (d[j] < p) {
00865   k = j;
00866   p = d[j];
00867       }
00868 
00869     if (k != i) {
00870       d[k] = d[i];
00871       d[i] = p;
00872       for (j = 0; j < n; j++) {
00873   p = evec[j][i];
00874   evec[j][i] = evec[j][k];
00875   evec[j][k] = p;
00876       }
00877     }
00878   }
00879 
00880   return (d);
00881 }
00882 
00883 
00884 /*  
00885     I doubt there's any use for this function. Could be 
00886     declared static. 
00887 */
00888 
00889 mat mat_hessenberg (mat a, mat V)
00890 {
00891 
00892   int  i, j, m, n;
00893   int  low = 0, high;
00894   double scale, f, g, h;
00895   mat  H;
00896   vec  ort;
00897 
00898   it_assert (mat_height (a) == mat_width (a), "Matrix must be square");
00899 
00900   it_assert (mat_height (V) == mat_width (V),
00901        "Transformation matrix must be square");
00902 
00903   it_assert (mat_width (a) == mat_width (V),
00904        "Matrices must have same dimensions");
00905 
00906   H = mat_clone (a);
00907 
00908   n = mat_height (a);
00909 
00910   mat_zeros (V);
00911   ort = vec_new_zeros (n);
00912 
00913   high = n - 1;
00914 
00915   for (m = low + 1; m <= high - 1; m++) {
00916 
00917     /* Scale column */
00918 
00919     scale = 0.0;
00920     for (i = m; i <= high; i++)
00921       scale = scale + fabs (H[i][m - 1]);
00922 
00923     if (scale) {
00924       /* Compute Householder transformation */
00925 
00926       h = 0.0;
00927       for (i = high; i >= m; i--) {
00928   ort[i] = H[i][m - 1] / scale;
00929   h += ort[i] * ort[i];
00930       }
00931       g = sqrt (h);
00932 
00933       if (ort[m] > 0)
00934   g = -g;
00935 
00936       h = h - ort[m] * g;
00937       ort[m] = ort[m] - g;
00938 
00939       /* 
00940          Apply Householder similarity transformation
00941          H = (I-u*u'/h)*H*(I-u*u')/h)
00942        */
00943 
00944       for (j = m; j < n; j++) {
00945   f = 0.0;
00946   for (i = high; i >= m; i--)
00947     f += ort[i] * H[i][j];
00948 
00949   f /= h;
00950 
00951   for (i = m; i <= high; i++)
00952     H[i][j] -= f * ort[i];
00953       }
00954 
00955       for (i = 0; i <= high; i++) {
00956   f = 0.0;
00957   for (j = high; j >= m; j--)
00958     f += ort[j] * H[i][j];
00959 
00960   f /= h;
00961 
00962   for (j = m; j <= high; j++)
00963     H[i][j] -= f * ort[j];
00964 
00965       }
00966       ort[m] = scale * ort[m];
00967       H[m][m - 1] = scale * g;
00968 
00969     }       /* IF scale */
00970   }
00971 
00972   /* Accumulate transformations (Algol's ortran) */
00973 
00974   for (i = 0; i < n; i++)
00975     for (j = 0; j < n; j++)
00976       V[i][j] = (i == j ? 1.0 : 0.0);
00977 
00978   for (m = high - 1; m >= low + 1; m--) {
00979     if (H[m][m - 1]) {
00980       for (i = m + 1; i <= high; i++)
00981   ort[i] = H[i][m - 1];
00982 
00983       for (j = m; j <= high; j++) {
00984   g = 0.0;
00985   for (i = m; i <= high; i++)
00986     g += ort[i] * V[i][j];
00987 
00988   /* Double division avoids possible underflow */
00989   g = (g / ort[m]) / H[m][m - 1];
00990   for (i = m; i <= high; i++)
00991     V[i][j] += g * ort[i];
00992       }
00993     }
00994   }
00995 
00996   vec_delete (ort);
00997 
00998   return (H);
00999 
01000 }
01001 
01002 static cvec mat_h2rs (mat H, mat evec)
01003 {
01004 
01005   int  nn, n, low, high;
01006   int  i, j, k, l, m, mmax, mmin, iter, notlast;
01007   double eps;
01008   double exshift = 0.0;
01009   double p = 0, q = 0, r = 0, s = 0, z = 0, t, w, x, y;
01010   double norm = 0.0;
01011   double ra, sa, vr, vi;
01012   double cdivr, cdivi;
01013   cvec eval;
01014   vec  e, d;
01015 
01016   it_assert (mat_width (H) == mat_height (H), "Matrix must be square");
01017 
01018   nn = mat_height (H);
01019   n = nn - 1;
01020   low = 0;
01021   high = nn - 1;
01022   eps = pow (2.0, -52.0);
01023 
01024   e = vec_new_zeros (nn);
01025   d = vec_new_zeros (nn);
01026 
01027   eval = cvec_new_zeros (nn);
01028 
01029   /* Store roots isolated by balanc and compute matrix norm */
01030 
01031   /* Initialize */
01032 
01033   for (i = 0; i < nn; i++) {
01034     if (i < low || i > high) {
01035       d[i] = H[i][i];
01036       e[i] = 0.0;
01037     }
01038 
01039     mmax = i - 1 > 0 ? i - 1 : 0;
01040 
01041     for (j = mmax; j < nn; j++)
01042       norm += fabs (H[i][j]);
01043 
01044   }
01045 
01046   /* Outer loop over eigenvalue index */
01047 
01048   iter = 0;
01049 
01050   while (n >= low) {
01051 
01052     /* Look for single small sub-diagonal element */
01053 
01054     l = n;
01055 
01056     while (l > low) {
01057       s = fabs (H[l - 1][l - 1]) + fabs (H[l][l]);
01058 
01059       if (!s)
01060   s = norm;
01061 
01062       if (fabs (H[l][l - 1]) < eps * s)
01063   break;
01064 
01065       l--;
01066     }
01067 
01068     /* Check for convergence */
01069     /* One root found */
01070 
01071     if (l == n) {
01072       H[n][n] += exshift;
01073       d[n] = H[n][n];
01074       e[n] = 0.0;
01075       n--;
01076       iter = 0;
01077 
01078       /* Two roots found */
01079 
01080     }
01081     else if (l == n - 1) {
01082       w = H[n][n - 1] * H[n - 1][n];
01083       p = (H[n - 1][n - 1] - H[n][n]) / 2.;
01084       q = p * p + w;
01085       z = sqrt (fabs (q));
01086       H[n][n] += exshift;
01087       H[n - 1][n - 1] += exshift;
01088       x = H[n][n];
01089 
01090       /* Real pair */
01091 
01092       if (q >= 0) {
01093   if (p >= 0)
01094     z = p + z;
01095   else
01096     z = p - z;
01097 
01098   d[n - 1] = x + z;
01099   d[n] = d[n - 1];
01100   if (z)
01101     d[n] = x - w / z;
01102 
01103   e[n - 1] = 0.0;
01104   e[n] = 0.0;
01105   x = H[n][n - 1];
01106   s = fabs (x) + fabs (z);
01107   p = x / s;
01108   q = z / s;
01109   r = sqrt (p * p + q * q);
01110   p /= r;
01111   q /= r;
01112 
01113   /* Row modification */
01114 
01115   for (j = n - 1; j < nn; j++) {
01116     z = H[n - 1][j];
01117     H[n - 1][j] = q * z + p * H[n][j];
01118     H[n][j] = q * H[n][j] - p * z;
01119   }
01120 
01121   /* Column modification */
01122 
01123   for (i = 0; i <= n; i++) {
01124     z = H[i][n - 1];
01125     H[i][n - 1] = q * z + p * H[i][n];
01126     H[i][n] = q * H[i][n] - p * z;
01127   }
01128 
01129   /* Accumulate transformations */
01130 
01131   for (i = low; i <= high; i++) {
01132     z = evec[i][n - 1];
01133     evec[i][n - 1] = q * z + p * evec[i][n];
01134     evec[i][n] = q * evec[i][n] - p * z;
01135   }
01136 
01137   /* Complex pair */
01138 
01139       }
01140       else {
01141   d[n - 1] = x + p;
01142   d[n] = x + p;
01143   e[n - 1] = z;
01144   e[n] = -z;
01145       }
01146 
01147       n -= 2;
01148       iter = 0;
01149 
01150       /* No convergence yet */
01151 
01152     }
01153     else {
01154       /* Form shift */
01155 
01156       x = H[n][n];
01157       y = 0.0;
01158       w = 0.0;
01159       if (l < n) {
01160   y = H[n - 1][n - 1];
01161   w = H[n][n - 1] * H[n - 1][n];
01162       }
01163 
01164       /* Wilkinson's original ad hoc shift */
01165 
01166       if (iter == 10) {
01167   exshift += x;
01168   for (i = low; i <= n; i++)
01169     H[i][i] -= x;
01170 
01171   s = fabs (H[n][n - 1]) + fabs (H[n - 1][n - 2]);
01172   x = y = 0.75 * s;
01173   w = -0.4375 * s * s;
01174       }
01175 
01176       /* MATLAB's new ad hoc shift */
01177 
01178       if (iter == 30) {
01179   s = (y - x) / 2.0;
01180   s = s * s + w;
01181   if (s > 0) {
01182     s = sqrt (s);
01183     if (y < x)
01184       s = -s;
01185     s = x - w / ((y - x) / 2. + s);
01186     for (i = low; i <= n; i++)
01187       H[i][i] -= s;
01188     exshift += s;
01189     x = y = w = 0.964;
01190   }
01191       }
01192 
01193       iter++;     /* (Could check iteration count here.) */
01194 
01195       /* Look for two consecutive small sub-diagonal elements */
01196 
01197       m = n - 2;
01198       while (m >= l) {
01199   z = H[m][m];
01200   r = x - z;
01201   s = y - z;
01202   p = (r * s - w) / H[m + 1][m] + H[m][m + 1];
01203   q = H[m + 1][m + 1] - z - r - s;
01204   r = H[m + 2][m + 1];
01205   s = fabs (p) + fabs (q) + fabs (r);
01206   p /= s;
01207   q /= s;
01208   r /= s;
01209   if (m == l)
01210     break;
01211 
01212   if (fabs (H[m][m - 1]) * (fabs (q) + fabs (r)) <
01213       eps * (fabs (p) *
01214        (fabs (H[m - 1][m - 1]) + fabs (z) +
01215         fabs (H[m + 1][m + 1]))))
01216     break;
01217 
01218   m--;
01219       }
01220 
01221       for (i = m + 2; i <= n; i++) {
01222   H[i][i - 2] = 0.;
01223   if (i > m + 2)
01224     H[i][i - 3] = 0.;
01225       }
01226 
01227       /* Double QR step involving rows l:n and columns m:n */
01228 
01229       for (k = m; k <= n - 1; k++) {
01230   notlast = (k != n - 1);
01231   if (k != m) {
01232     p = H[k][k - 1];
01233     q = H[k + 1][k - 1];
01234     r = (notlast ? H[k + 2][k - 1] : 0.);
01235     x = fabs (p) + fabs (q) + fabs (r);
01236     if (x) {
01237       p /= x;
01238       q /= x;
01239       r /= x;
01240     }
01241   }
01242 
01243   if (!x)
01244     break;
01245 
01246   s = sqrt (p * p + q * q + r * r);
01247   if (p < 0)
01248     s = -s;
01249 
01250   if (s) {
01251     if (k != m)
01252       H[k][k - 1] = -s * x;
01253     else if (l != m)
01254       H[k][k - 1] = -H[k][k - 1];
01255 
01256     p += s;
01257     x = p / s;
01258     y = q / s;
01259     z = r / s;
01260     q /= p;
01261     r /= p;
01262 
01263     /* Row modification */
01264 
01265     for (j = k; j < nn; j++) {
01266       p = H[k][j] + q * H[k + 1][j];
01267       if (notlast) {
01268         p = p + r * H[k + 2][j];
01269         H[k + 2][j] = H[k + 2][j] - p * z;
01270       }
01271       H[k][j] = H[k][j] - p * x;
01272       H[k + 1][j] = H[k + 1][j] - p * y;
01273     }
01274 
01275     /* Column modification */
01276 
01277     mmin = n < k + 3 ? n : k + 3;
01278 
01279     for (i = 0; i <= mmin; i++) {
01280       p = x * H[i][k] + y * H[i][k + 1];
01281       if (notlast) {
01282         p += z * H[i][k + 2];
01283         H[i][k + 2] -= p * r;
01284       }
01285       H[i][k] -= p;
01286       H[i][k + 1] -= p * q;
01287     }
01288 
01289     /* Accumulate transformations */
01290 
01291     for (i = low; i <= high; i++) {
01292       p = x * evec[i][k] + y * evec[i][k + 1];
01293       if (notlast) {
01294         p += z * evec[i][k + 2];
01295         evec[i][k + 2] -= p * r;
01296       }
01297       evec[i][k] -= p;
01298       evec[i][k + 1] -= p * q;
01299     }
01300 
01301   }     /* (s != 0) */
01302       }       /* k loop */
01303     }       /* check convergence */
01304   }       /* while (n >= low) */
01305 
01306   /* Backsubstitute to find vectors of upper triangular form */
01307 
01308   /* We return null vector if there is a problem */
01309   if (!norm)
01310     return (eval);
01311 
01312   for (n = nn - 1; n >= 0; n--) {
01313     p = d[n];
01314     q = e[n];
01315 
01316     /* Real vector */
01317 
01318     if (!q) {
01319       l = n;
01320       H[n][n] = 1.;
01321       for (i = n - 1; i >= 0; i--) {
01322   w = H[i][i] - p;
01323   r = 0.;
01324   for (j = l; j <= n; j++)
01325     r += H[i][j] * H[j][n];
01326 
01327   if (e[i] < 0.0) {
01328     z = w;
01329     s = r;
01330   }
01331   else {
01332     l = i;
01333     if (!e[i]) {
01334       if (w != 0.0)
01335         H[i][n] = -r / w;
01336       else
01337         H[i][n] = -r / (eps * norm);
01338 
01339       /* Solve real equations */
01340 
01341     }
01342     else {
01343       x = H[i][i + 1];
01344       y = H[i + 1][i];
01345       q = (d[i] - p) * (d[i] - p) + e[i] * e[i];
01346       t = (x * s - z * r) / q;
01347       H[i][n] = t;
01348       if (fabs (x) > fabs (z))
01349         H[i + 1][n] = (-r - w * t) / x;
01350       else
01351         H[i + 1][n] = (-s - y * t) / z;
01352     }
01353 
01354     /* Overflow control */
01355 
01356     t = fabs (H[i][n]);
01357     if ((eps * t) * t > 1)
01358       for (j = i; j <= n; j++)
01359         H[j][n] /= t;
01360   }
01361       }
01362 
01363       /* Complex vector */
01364 
01365     }
01366     else if (q < 0) {
01367       l = n - 1;
01368 
01369       /* Last vector component imaginary so matrix is triangular */
01370 
01371       if (fabs (H[n][n - 1]) > fabs (H[n - 1][n])) {
01372   H[n - 1][n - 1] = q / H[n][n - 1];
01373   H[n - 1][n] = -(H[n][n] - p) / H[n][n - 1];
01374       }
01375       else {
01376   ccdiv (0.0, -H[n - 1][n], H[n - 1][n - 1] - p, q, &cdivr, &cdivi);
01377   H[n - 1][n - 1] = cdivr;
01378   H[n - 1][n] = cdivi;
01379       }
01380       H[n][n - 1] = 0.;
01381       H[n][n] = 1.;
01382       for (i = n - 2; i >= 0; i--) {
01383   ra = 0.0;
01384   sa = 0.0;
01385   for (j = l; j <= n; j++) {
01386     ra += H[i][j] * H[j][n - 1];
01387     sa += H[i][j] * H[j][n];
01388   }
01389   w = H[i][i] - p;
01390 
01391   if (e[i] < 0.0) {
01392     z = w;
01393     r = ra;
01394     s = sa;
01395   }
01396   else {
01397     l = i;
01398     if (e[i]) {
01399       ccdiv (-ra, -sa, w, q, &cdivr, &cdivi);
01400       H[i][n - 1] = cdivr;
01401       H[i][n] = cdivi;
01402     }
01403     else {
01404 
01405       /* Solve complex equations */
01406 
01407       x = H[i][i + 1];
01408       y = H[i + 1][i];
01409       vr = (d[i] - p) * (d[i] - p) + e[i] * e[i] - q * q;
01410       vi = (d[i] - p) * 2.0 * q;
01411       if (!vr && !vi)
01412         vr =
01413     eps * norm * (fabs (w) + fabs (q) + fabs (x) + fabs (y) +
01414             fabs (z));
01415 
01416       ccdiv (x * r - z * ra + q * sa, x * s - z * sa - q * ra, vr, vi,
01417        &cdivr, &cdivi);
01418       H[i][n - 1] = cdivr;
01419       H[i][n] = cdivi;
01420       if (fabs (x) > (fabs (z) + fabs (q))) {
01421         H[i + 1][n - 1] = (-ra - w * H[i][n - 1] + q * H[i][n]) / x;
01422         H[i + 1][n] = (-sa - w * H[i][n] - q * H[i][n - 1]) / x;
01423       }
01424       else {
01425         ccdiv (-r - y * H[i][n - 1], -s - y * H[i][n], z, q, &cdivr,
01426          &cdivi);
01427         H[i + 1][n - 1] = cdivr;
01428         H[i + 1][n] = cdivi;
01429       }
01430     }
01431 
01432     /* Overflow control */
01433 
01434     t =
01435       fabs (H[i][n - 1]) >
01436       fabs (H[i][n]) ? fabs (H[i][n - 1]) : fabs (H[i][n]);
01437 
01438     if ((eps * t) * t > 1.)
01439       for (j = i; j <= n; j++) {
01440         H[j][n - 1] /= t;
01441         H[j][n] /= t;
01442       }
01443   }
01444       }
01445     }
01446   }
01447 
01448   /* Vectors of isolated roots */
01449 
01450   for (i = 0; i < nn; i++)
01451     if (i < low || i > high)
01452       for (j = i; j < nn; j++)
01453   evec[i][j] = H[i][j];
01454 
01455   /* Back transformation to get eigenvectors of original matrix */
01456 
01457   for (j = nn - 1; j >= low; j--) {
01458     for (i = low; i <= high; i++) {
01459       z = 0.;
01460 
01461       mmin = j < high ? j : high;
01462 
01463       for (k = low; k <= mmin; k++)
01464   z += evec[i][k] * H[k][j];
01465       evec[i][j] = z;
01466     }
01467   }
01468 
01469   for (i = 0; i < vec_length (d); i++) {
01470     creal (eval[i]) = d[i];
01471     cimag (eval[i]) = e[i];
01472   }
01473 
01474   vec_delete (e);
01475   vec_delete (d);
01476 
01477   return (eval);
01478 
01479 }
01480 
01481 /*
01482   
01483   Eigenvalues/eigenvectors decomposition of a real symmetric 
01484   matrix. The output is real in every cases (Hermitian). 
01485 
01486  */
01487 
01488 vec mat_eig_sym (mat a, mat evec)
01489 {
01490 
01491   int  i, j;
01492   vec  e, d;
01493 
01494   it_assert (mat_width (a) == mat_height (a), "Matrix must be square");
01495   it_assert (evec != NULL,
01496        "Memory for matrix of eigenvectors must be reserved");
01497   it_assert (mat_width (evec) == mat_height (evec),
01498        "Matrix of eigenvectors must be square");
01499   it_assert (mat_width (evec) == mat_width (a),
01500        "Matrices dimensions must agree");
01501 
01502   e = vec_new_zeros (mat_width (a));
01503   d = vec_new_zeros (mat_width (a));
01504 
01505   for (i = 0; i < mat_height (a); i++)
01506     for (j = 0; j < mat_width (a); j++)
01507       evec[i][j] = a[i][j];
01508 
01509   mat_tridiag (e, d, evec);
01510   mat_tridiag_ql (e, d, evec);
01511 
01512   vec_delete (e);
01513 
01514   return (d);
01515 }
01516 
01517 /*
01518 
01519   Eigenvalues/eigenvectors decomposition of a real *NON* symmetric 
01520   matrix. Well, it works with symmetric matrices too, but it is 
01521   slower. The output is generally complex. 
01522 
01523  */
01524 
01525 cvec mat_eig (mat a, cmat evec)
01526 {
01527 
01528   int  i, j, n;
01529   cvec eval;
01530   mat  h, V;
01531   double z;
01532 
01533   it_assert (mat_width (a) == mat_height (a), "Matrix must be square");
01534   it_assert (evec != NULL,
01535        "Memory for matrix of eigenvectors must be reserved");
01536   it_assert (cmat_width (evec) == cmat_height (evec),
01537        "Matrix of eigenvectors must be square");
01538   it_assert (cmat_width (evec) == mat_width (a),
01539        "Matrices dimensions must agree");
01540 
01541   V = mat_clone (a);
01542 
01543   n = mat_width (a);
01544 
01545   h = mat_hessenberg (a, V);
01546   eval = mat_h2rs (h, V);
01547   mat_delete (h);
01548 
01549   /* Outputs (possibly) complex normalized eigenvectors from real Schur form */
01550 
01551   for (j = 0; j < n; j++) {
01552     if (cimag (eval[j])) {
01553 
01554       z = 0.;
01555 
01556       for (i = 0; i < n; i++) {
01557   creal (evec[i][j]) = creal (evec[i][j + 1]) = V[i][j];
01558   cimag (evec[i][j]) = V[i][j + 1];
01559   cimag (evec[i][j + 1]) = -V[i][j + 1];
01560   z +=
01561     creal (evec[i][j]) * creal (evec[i][j]) +
01562     cimag (evec[i][j]) * cimag (evec[i][j]);
01563       }
01564 
01565       z = 1. / sqrt (z);
01566 
01567       for (i = 0; i < n; i++) {
01568   creal (evec[i][j]) *= z;
01569   cimag (evec[i][j]) *= z;
01570   creal (evec[i][j + 1]) *= z;
01571   cimag (evec[i][j + 1]) *= z;
01572       }
01573 
01574       j++;      /* Skip conj */
01575     }
01576     else {
01577 
01578       z = 0.;
01579 
01580       for (i = 0; i < n; i++) {
01581   cimag (evec[i][j]) = 0.;
01582   creal (evec[i][j]) = V[i][j];
01583   z += V[i][j] * V[i][j];
01584       }
01585 
01586       z = 1. / sqrt (z);
01587 
01588       /* Mimic Octave behaviour */
01589       if (V[0][j] < 0.)
01590   z = -z;
01591 
01592       for (i = 0; i < n; i++)
01593   creal (evec[i][j]) *= z;
01594 
01595     }
01596 
01597   }
01598 
01599   mat_delete (V);
01600 
01601   return (eval);
01602 
01603 }
01604 
01605 
01606 /*
01607   Like the Hessenberg function, it could be declared static. 
01608  */
01609 mat mat_real_schur (mat a)
01610 {
01611   mat  h, e;
01612   cvec eval;
01613 
01614   it_assert (mat_height (a) == mat_width (a), "Matrix must be square");
01615 
01616   e = mat_new_zeros (mat_height (a), mat_width (a));
01617 
01618   h = mat_hessenberg (a, e);
01619   eval = mat_h2rs (h, e);
01620 
01621   cvec_delete (eval);
01622   mat_delete (e);
01623 
01624   return (h);
01625 }
01626 
01627 double  mat_lu( mat a, ivec piv ) 
01628 {
01629 
01630   idx_t i = 0; 
01631   idx_t j = 0; 
01632   idx_t k = 0; 
01633   idx_t pi = 0; 
01634   idx_t xp, yp; 
01635   idx_t t = 0; 
01636 
01637   int pivsign = 1; 
01638 
01639   size_t n, m, p; 
01640 
01641   double max = 0.0; 
01642   double eps = IT_EPSILON*IT_EPSILON; 
01643 
01644   it_assert( a, "Please use an existing matrix" ); 
01645   it_assert( pc, "Please use an existing pc vector" ); 
01646   it_assert( pr, "Please use an existing pr vector" ); 
01647   it_assert( ivec_length( piv ) == mat_height( a ), "Vector piv must have matrix height size" ); 
01648 
01649   m = mat_height( a );
01650   n = mat_width( a );
01651 
01652   for ( i= 0; i< ivec_length( piv ); i++ ) 
01653     piv[i] = i; 
01654 
01655   p = (n<=m)?n:m; 
01656 
01657   /* Iterate on columns */
01658   for ( k= 0; k< p; k++ ) 
01659     {
01660       /* Find pivot */ 
01661       max = a[k][k]; 
01662       xp = yp = k; 
01663 
01664       for ( i= k; i< m; i++ ) 
01665   if ( fabs(max) < fabs( a[i][k] ) ) 
01666     {
01667       max = a[i][k]; 
01668       yp = i; 
01669     }
01670             
01671       if ( fabs(max) > eps ) /* We have found a non-zero pivot */
01672   {
01673     /* Swap rows if necessary */ 
01674     if ( yp!=k ) 
01675       {
01676         mat_swap_rows( a, yp, k );
01677         
01678         /* Update pivot vector */ 
01679         t = piv[yp]; 
01680         piv[yp] = piv[k]; 
01681         piv[k] = t; 
01682 
01683         pivsign = -pivsign; 
01684         
01685       }      
01686 
01687     /* Compute U coeffs */
01688     /* Iterate on rows for U */
01689     for ( j= k; j< n; j++ )
01690       for ( pi= 0; pi< k; pi++ )
01691         a[k][j] -= a[k][pi]*a[pi][j];
01692     
01693     /* Compute L coeffs */
01694     for ( i= k+1; i< m; i++ ) 
01695       {
01696         for ( pi= 0; pi< k; pi++ ) 
01697     a[i][k] -= a[i][pi]*a[pi][k];     
01698         a[i][k] /= a[k][k]; 
01699       } /* L */   
01700 
01701   }
01702       else /* matrix is singular */
01703   {
01704     it_warning( "Matrix is singular" );
01705     return( 0. ); 
01706   }
01707 
01708     }
01709 
01710   /* Computing determinant : priceless... */
01711   max = (double)pivsign; 
01712 
01713   for ( i= 0; i< n; i++ ) 
01714     max *= a[i][i];
01715 
01716   return( max );
01717 
01718 }
01719 
01720 /* Compute determinant of a matrix. Returns zero if the matrix is singular. */
01721 
01722 double mat_det (mat a)
01723 {
01724   double det = 0.;
01725   ivec piv; 
01726   mat  lu = mat_clone (a);
01727 
01728   piv = ivec_new_zeros (mat_height (a));
01729 
01730   /* Use total pivoting strategy, useless? */
01731   det = mat_lu (lu, piv ); 
01732 
01733   ivec_delete (piv);
01734   mat_delete (lu);
01735 
01736   return (det);
01737 }
01738 
01739 
01740 /* Use LU for solving A x = b. */
01741 vec mat_solve_vec (mat A, vec b)
01742 {
01743   size_t m, n; 
01744   idx_t i, k; 
01745   ivec piv; 
01746   mat LU; 
01747   vec X; 
01748 
01749   m  = mat_height( A ); 
01750   n  = mat_width( A ); 
01751 
01752   it_assert( m==vec_length(b), "Matrices size mismatch" );
01753 
01754   piv = ivec_new( m ); 
01755   LU = mat_clone( A ); 
01756 
01757   if ( !mat_lu( LU, piv ) ) 
01758     {
01759       it_warning( "Matrix is singular, aborting" ); 
01760       ivec_delete( piv ); 
01761       mat_delete( LU ); 
01762       return( NULL );
01763     }
01764   
01765   X = vec_new( ivec_length(piv) );
01766 
01767   for ( i= 0; i< ivec_length(piv); i++ ) 
01768     X[i] = b[piv[i]]; 
01769 
01770   for ( k= 0; k< n; k++ ) 
01771     for ( i= k+1; i< n; i++ ) 
01772       X[i] -= X[k]*LU[i][k]; 
01773 
01774   for ( k= n-1; k >= 0; k-- ) 
01775     {
01776       X[k] /= LU[k][k]; 
01777 
01778       for ( i= 0; i< k; i++ )
01779   X[i] -= X[k]*LU[i][k];
01780     }
01781 
01782   ivec_delete( piv ); 
01783   mat_delete( LU );
01784 
01785   return( X ); 
01786 }
01787 
01788 
01789 /*  Use LU for solving several equations A x_i = b_i.
01790     The various b_i are to be stored column-wise in B.
01791     Return column-wise solutions.                          */
01792 
01793 mat mat_solve_mat( mat A, mat B ) 
01794 {
01795   size_t m, n, nx; 
01796   ivec piv; 
01797   idx_t i, j, k; 
01798   mat LU, X; 
01799 
01800   m  = mat_height( A ); 
01801   n  = mat_width( A ); 
01802   nx = mat_width( B ); 
01803 
01804   it_assert( m==mat_height(B), "Matrices size mismatch" );
01805 
01806   piv = ivec_new( m ); 
01807   LU = mat_clone( A ); 
01808 
01809   if ( !mat_lu( LU, piv ) ) 
01810     {
01811       it_warning( "Matrix is singular, aborting" ); 
01812       ivec_delete( piv ); 
01813       mat_delete( LU ); 
01814       return( NULL );
01815     }
01816   
01817   X = mat_new( ivec_length(piv), nx ); 
01818 
01819   for ( i= 0; i< ivec_length(piv); i++ ) 
01820     for ( j= 0; j< nx; j++ ) 
01821       X[i][j] = B[piv[i]][j]; 
01822 
01823   for ( k= 0; k< n; k++ ) 
01824     for ( i= k+1; i< n; i++ ) 
01825       for ( j= 0; j< nx; j++ ) 
01826   X[i][j] -= X[k][j]*LU[i][k]; 
01827 
01828   for ( k= n-1; k >= 0; k-- ) 
01829     {
01830       for ( j= 0; j< nx; j++ ) 
01831   X[k][j] /= LU[k][k]; 
01832 
01833       for ( i= 0; i< k; i++ ) 
01834   for ( j= 0; j< nx; j++ ) 
01835     X[i][j] -= X[k][j]*LU[i][k];
01836     }
01837 
01838   ivec_delete( piv );
01839   mat_delete( LU );
01840 
01841   return( X ); 
01842 }
01843 
01844 static mat mat_inv_direct (mat A)
01845 {
01846   mat  I, Id;
01847 
01848   it_assert (mat_width (A) == mat_height (A), "Matrix must be square");
01849 
01850   Id = mat_new_zeros (mat_height (A), mat_width (A));
01851   mat_eye (Id);
01852 
01853   I = mat_solve_mat (A, Id);
01854 
01855   mat_delete (Id);
01856   return (I);
01857 }
01858 
01859 /* 
01860    QR decomposition
01861 */
01862 vec mat_qr( mat A ) 
01863 {
01864 
01865   size_t m, n; 
01866   idx_t i, j, k; 
01867   vec Rdiag; 
01868   double nrm, s; 
01869 
01870   m = mat_height( A );
01871   n = mat_width( A );
01872 
01873   Rdiag = vec_new( n ); 
01874 
01875   for ( k= 0; k< n; k++ )
01876     {
01877       nrm = 0.; 
01878       for ( i= k; i< m; i++ ) 
01879   nrm = hypot( nrm, A[i][k] ); 
01880 
01881       if ( nrm ) 
01882   {
01883     if ( A[k][k] < 0 ) 
01884       nrm = -nrm; 
01885 
01886     for ( i= k; i< m; i++ ) 
01887       A[i][k] /= nrm; 
01888 
01889     A[k][k] += 1.; 
01890 
01891     for ( j= k+1; j< n; j++ ) 
01892       {
01893         s = 0.; 
01894         for ( i= k; i< m; i++ ) 
01895     s+= A[i][k]*A[i][j]; 
01896 
01897         s = -s / A[k][k]; 
01898 
01899         for ( i= k; i< m; i++ ) 
01900     A[i][j] += s*A[i][k];
01901       }
01902 
01903   }
01904 
01905       Rdiag[k] = -nrm; 
01906     }
01907 
01908   return Rdiag; 
01909 
01910 }
01911 
01912 mat mat_ls( mat A, mat B ) 
01913 {
01914 
01915   size_t m, n, nx; 
01916   idx_t i, j, k; 
01917   double s; 
01918   mat QR, X; 
01919   vec Rdiag; 
01920 
01921   m =  mat_height( A );
01922   n =  mat_width( A );
01923   nx = mat_width( B );
01924 
01925   it_assert( m==mat_height(B), "Matrices size mismatch" ); 
01926 
01927   QR = mat_clone( A ); 
01928 
01929   Rdiag = mat_qr( QR ); 
01930 
01931   for ( j= 0; j< n; j++ ) 
01932     if ( !Rdiag[j] ) 
01933       {
01934   it_warning( "Matrix is rank deficient, aborting" ); 
01935   vec_delete( Rdiag ); 
01936   mat_delete( QR ); 
01937   return NULL; 
01938       }
01939 
01940   X = mat_clone( B ); 
01941 
01942   for ( k= 0; k< n; k++ ) 
01943     for ( j= 0; j< nx; j++ ) 
01944       {
01945   s = 0.; 
01946   for ( i= k; i< m; i++ ) 
01947     s+= QR[i][k]*X[i][j]; 
01948   
01949   s = -s / QR[k][k]; 
01950   
01951   for ( i= k; i< m; i++ ) 
01952     X[i][j] += s*QR[i][k];
01953   
01954       }
01955   
01956   for ( k= n-1; k >= 0; k-- ) 
01957     {
01958       for ( j= 0; j< nx; j++ ) 
01959   X[k][j] /= Rdiag[k]; 
01960 
01961       for ( i= 0; i< k; i++ ) 
01962   for ( j= 0; j< nx; j++ ) 
01963     X[i][j] -= X[k][j]*QR[i][k]; 
01964     }
01965 
01966   vec_delete( Rdiag );
01967   mat_delete( QR );
01968 
01969   return X; 
01970 
01971 }
01972 
01973 /*----------------------------------------------------------------------------*/
01974 /* Orthonormalisation in-place function.                                      */
01975 /* Implement Gram-Schmidt procedure                                           */
01976 void mat_gs (mat A) 
01977 {
01978   int  i, j, k;
01979   vec  v = vec_new (mat_height (A)), proj;
01980   double innerp;    /* for the inner product */
01981 
01982   for (i = 1; i < mat_width (A); i++) {
01983     vec_zeros (v);
01984 
01985     for (j = 0; j < i; j++) {
01986       innerp = 0.;
01987       for (k = 0; k < mat_height (A); k++)
01988   innerp += A[k][i] * A[k][j];
01989 
01990       proj = mat_get_col (A, j);
01991       vec_mul_by (proj, innerp / pow( vec_norm( proj, 2.), 2.));
01992 
01993       vec_add (v, proj);
01994       vec_delete (proj);
01995     }
01996 
01997     /* deduce v from column vector i */
01998     for (j = 0; j < mat_height (A); j++)
01999       A[j][i] -= v[j];
02000   }
02001 
02002   /* Proceed to normalization when possible
02003      Priority is given to orthogonalisation
02004    */
02005   if ( mat_width( A ) < mat_height( A ) )
02006     mat_cols_normalize( A, 2. );
02007 
02008   vec_delete (v);
02009 }
02010 
02011 void mat_cholesky( mat a ) 
02012 {
02013 
02014   idx_t i = 0; 
02015   idx_t j = 0; 
02016   idx_t k = 0; 
02017   size_t n = 0; 
02018 
02019   it_assert( a, "Please use an existing matrix" ); 
02020   it_assert( mat_width( a )==mat_height( a ), "Matrix must be square" );
02021 
02022   n = mat_width( a );
02023 
02024   for ( k= 0; k< n; k++ ) 
02025     {
02026       a[k][k] = sqrt( a[k][k] );
02027       for ( i= k+1; i< n; i++ )
02028   a[i][k] /= a[k][k];
02029       for ( j= k+1; j< n; j++ ) 
02030   for ( i= j; i< n; i++ ) 
02031     a[i][j] -= a[i][k]*a[j][k];
02032     }
02033 
02034   for ( j= 0; j< n; j++ ) 
02035     for ( i= 0; i< j; i++ ) 
02036       a[i][j] = 0.0;
02037 
02038   return;
02039 }
02040 
02041 /*
02042 
02043   Inversion of a matrix using LU. 
02044 
02045  */
02046 
02047 mat mat_inv (mat m)
02048 {
02049 
02050   mat  inv;
02051   idx_t i, j;
02052 
02053   inv = mat_inv_direct (m);
02054 
02055   if (inv) {
02056     for (i = 0; i < mat_height (m); i++)
02057       for (j = 0; j < mat_width (m); j++)
02058   m[i][j] = inv[i][j];
02059 
02060     mat_delete (inv);
02061 
02062     return (m);
02063 
02064   }
02065   else
02066     return (NULL);
02067 
02068 }
02069 
02070 
02071 /*----------------------------------------------------------------------------*/
02072 mat mat_new_inv (mat m)
02073 {
02074   return mat_inv_direct (m);
02075 }
02076 
02077 
02078 /*----------------------------------------------------------------------------*/
02079 cmat cmat_inv (cmat m)
02080 {
02081   idx_t i, j, k;
02082   cplx coef;
02083   cvec f = cvec_new (cmat_height (m));
02084 
02085   it_assert (cmat_height (m) == cmat_width (m), "Matrix must be square");
02086 
02087   /* Gauss method */
02088   for (i = 0; i < cmat_height (m); i++) {
02089     if (cnorm (m[i][i]) < IT_EPSILON * 1e-5) {  /* Singular matrix ? */
02090       cmat_delete (m);
02091       cvec_delete (f);
02092       it_warning
02093   ("Matrix is singular or you are unlucky. Try another method for inversion.\n");
02094       m = cmat_new_void ();
02095       return m;
02096     }
02097 
02098     f[i] = m[i][i];
02099     cvec_div_by (m[i], f[i]);
02100 
02101     for (j = 0; j < cmat_height (m); j++) {
02102       if (i != j) {
02103   coef = m[j][i];
02104   m[j][i] = cplx_0;
02105 
02106   for (k = 0; k < cmat_width (m); k++)
02107     m[j][k] = csub (m[j][k], cmul (coef, m[i][k]));
02108       }
02109     }
02110   }
02111 
02112   /* Normalization  */
02113   for (i = 0; i < cmat_height (m); i++)
02114     cvec_div_by (m[i], f[i]);
02115 
02116   cvec_delete (f);
02117   return m;
02118 }
02119 
02120 
02121 /*----------------------------------------------------------------------------*/
02122 cmat cmat_new_inv (cmat m)
02123 {
02124   cmat r = cmat_clone (m);
02125   return cmat_inv (r);
02126 }

Hosted by
Copyright (C) 2005-2006 Hervé Jégou
Vivien Chappelier
Francois Cayre
libit logo courtesy of Jonathan Delhumeau