Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members  

min_praxis.cpp

Go to the documentation of this file.
00001 //****************************************************
00002 //  April, 1993, University of Illinois
00003 // Copyright (C) 1993, 1994 Tianlin Wang
00004 /* Copyright (C) 1994-2003 Matvec Development Team. 
00005 
00006   This program is free software; you can redistribute it and/or
00007   modify it under the terms of the GNU Library General Public
00008   License as published by the Free Software Foundation; either
00009   version 2 of the License, or (at your option) any later version.
00010   
00011   This program is distributed in the hope that it will be useful,
00012   but WITHOUT ANY WARRANTY; without even the implied warranty of
00013   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014   Library General Public License for more details.
00015     
00016   You should have received a copy of the GNU Library General Public
00017   License along with this library; if not, write to the Free
00018   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00019   MA 02111-1307, USA 
00020 */
00021 
00022 #include <cmath>
00023 #include <iostream>
00024 #include <iomanip>
00025 #include <cstdlib>
00026 #include "minimizer.h"
00027 #include "matrix.h"
00028 #include "session.h"
00029 
00030 
00031 namespace matvec {
00032 extern double   ranf(void);
00033 
00034 static double qd[2];
00035 static double fx,qf1;      // global variables accessable only with this file
00036   static double macheps, t,m2 ,m4;
00037   static double SmaLL,vsmall,vlarge,large;
00038 static double dmin,ldt,h;
00039 
00040 static int nf,nl;
00041 
00042 static void svd(const int n,double eps,const double tol,double** ab,double* q);
00043 
00044 static void sort(const int n,double* d, double** v) // d,v in descending order
00045 {
00046    int k, i, j;
00047    double s;
00048    for (i=0; i<n-1; i++) {
00049        k = i; s = d[i];
00050        for (j=i+1; j<n; j++) if (d[j] > s) { k = j; s = d[j]; }
00051        if (k > i) {
00052           d[k] = d[i]; d[i] = s;
00053           for (j=0; j<n; j++) { s = v[j][i]; v[j][i] = v[j][k]; v[j][k] = s; }
00054        }
00055    }
00056 }
00057 
00058 static void print(const int n, const Vector<double> &x)
00059 {
00060    int W = 6 + 6;
00061    std::cout << "\n";
00062    std::cout << "-- after " << nf << " function calls\n";
00063    std::cout << "-- including " << nl << " linear searches\n";
00064    std::cout << "-- your function f(x) has been reduced to "
00065         << std::setprecision(W)<< fx <<"\n";
00066    std::cout.precision(6);
00067    std::cout << "-- current values of x:";
00068    x.print();
00069    std::cout << std::endl;
00070 }
00071 
00072 static void flin(const double l, const int j,const Vector<double> &x,const int n,
00073             const Matrix<double> &v,Vector<double> &w, const Matrix<double> &q01)
00074 {
00075    int i;
00076    double qa,qb,qc;
00077    if (j != -1) {               // linear search
00078       for (i=0; i<n; i++) w[i] = x[i] + l *v[i][j];
00079    }
00080    else {                       // search along parabolic space curve
00081       qa = l*(l-qd[1])/(qd[0]*(qd[0]+qd[1]));
00082       qb = (l+qd[0])*(qd[1]-l)/(qd[0]*qd[1]);
00083       qc = l*(l+qd[0])/(qd[1]*(qd[0]+qd[1]));
00084       for (i=0; i<n; i++) w[i] = qa*q01[0][i]+qb*x[i]+qc*q01[1][i];
00085    }
00086 }
00087 
00088 double Minimizer::praxis(Vector<double> &x, const int n,int& maxfun,const double tol,
00089                          const double epsilon, const int pl)
00090 {
00091    ////////////////////////////////////////////////////////////////////
00092    // references:
00093    //  - powell, m.j.d., 1964. an efficient method for finding
00094    //    the minimum of a function in several variables without
00095    //    calculating derivatives, computer journal, 7, 155-162
00096    //  - brent, r.p., 1973. algorithms for minimization without
00097    //    derivatives, prentice hall, englewood cliffs.
00098    //
00099    //  problems, suggestions or improvements are always wellcome
00100    //                    karl gegenfurtner   07/08/87
00101    //                                        c - version
00102    //  On Thu Oct 21 19:56:35 CDT 1993, Tianlin made it into C++ version
00103    //  note that lots of globel variables have been removed.
00104    //
00105    //
00106    // usage: min = praxis(fun, x, n);
00107    //
00108    // fun       the function to be minimized. fun is called from
00109    //           praxis with x and n as arguments
00110    // x         a double array containing the initial guesses for
00111    //           the minimum, which will contain the solution on
00112    //           return
00113    // n         an integer specifying the number of unknown
00114    //           parameters
00115    // min       praxis returns the least calculated value of fun
00116    //
00117    // some additional global variables control some more aspects of
00118    // the inner workings of praxis. setting them is optional, they
00119    // are all set to some reasonable default values given below.
00120    //
00121    //  prin      controls the printed output from the routine.
00122    //            0 -> no output
00123    //            1 -> print only starting and final values
00124    //            2 -> detailed map of the minimization process
00125    //            3 -> print also eigenvalues and vectors of the
00126    //                 search directions
00127    //            the default value is 1
00128    // tol        is the tolerance allowed for the precision of the
00129    //            solution. praxis returns if the criterion
00130    //            2 * ||x[k]-x[k-1]|| <= sqrt(macheps) * ||x[k]|| + tol
00131    //            is fulfilled more than ktm times.
00132    //            the default value 1.0e-16
00133    //            tol is usually equal to  EPISILON*EPISILON
00134    //            where
00135    // ktm        see just above. default is 1, and a value of 4 leads
00136    //            to a very(!) cautious stopping criterion.
00137    // step       is a steplength parameter and should be set equal
00138    //            to the expected distance from the solution.
00139    //            exceptionally small or large values of step lead to
00140    //            slower convergence on the first few iterations
00141    //            the default value for step is 1.0
00142    // scbd       is a scaling parameter. 1.0 is the default and
00143    //            indicates no scaling. if the scales for the different
00144    //            parameters are very different, scbd should be set to
00145    //            a value of about 10.0.
00146    // illc       should be set to true (1) if the problem is known to
00147    //            be ill-conditioned. the default is false (0). this
00148    //            variable is automatically set, when praxis finds
00149    //            the problem to be ill-conditioned during iterations.
00150    // maxfun     is the maximum number of calls to fun allowed. praxis
00151    //            will return after maxfun calls to fun even when the
00152    //            minimum is not yet found. the default value of 0
00153    //            indicates no limit on the number of calls.
00154    //            this return condition is only checked every n
00155    //            iterations.
00156    //
00157    //////////////////////////////////////////////////////////////////////
00158    int i,j,k,k2, W = 6 + 6;
00159 
00160    int  ktm = 1;
00161    int illc = 0;
00162    double scbd = 1.0;
00163    double step = 10.0;         // after the first n*10 loop, step reset to 1
00164    Vector<double> y(n);
00165    Vector<double> z(n);
00166    Vector<double> d(n);
00167 //   d[0] = 0.0;
00168 
00169    Vector<double> w(n);              // working space for flin
00170    Matrix<double> v(n,n);
00171    Matrix<double> q01(2,n);
00172 
00173    qd[0] = 0.0;
00174    prtlevel = pl;
00175    macheps = epsilon;
00176    SmaLL = macheps*macheps;
00177    vsmall = SmaLL*SmaLL;
00178    large = 1.0/SmaLL;
00179    vlarge = 1.0/vsmall;
00180    m2 = std::sqrt(macheps); m4 = std::sqrt(m2);
00181 
00182    nl = 0;
00183    nf = 1;
00184    double t2,sl,dn,df,sf,lds,f1,s;
00185    h = step;
00186 
00187    dmin = SmaLL;
00188    t2 = SmaLL + std::fabs(tol);
00189    t = t2;
00190    double ldfac = (illc ? 0.1 : 0.01);
00191    int kt = 0;
00192    int kl;
00193 
00194    fx = minfun(x, n);
00195    qf1 = fx;
00196 
00197    if (h < 100.0*t) h = 100.0*t;
00198    ldt = h;
00199    for (i=0; i<n; i++) for (j=0; j<n; j++) v[i][j] = (i == j ? 1.0 : 0.0);
00200    for (i=0; i<n; i++) q01[1][i] = x[i];
00201    if (prtlevel > 1) {
00202       std::cout << "\n------------- enter function praxis -----------\n";
00203       std::cout << "-- current parameter settings\n";
00204       std::cout << "-- scaling: " << std::setw(W) << scbd   << "\n";
00205       std::cout << "-- tol    : " << std::setw(W) << t      << "\n";
00206       std::cout << "-- maxstep: " << std::setw(W) << h      << "\n";
00207       std::cout << "-- illc   : " << std::setw(W) << illc   << "\n";
00208       std::cout << "-- ktm    : " << std::setw(W) << ktm    << "\n";
00209       std::cout << "-- maxite : " << std::setw(W) << maxfun << "\n";
00210    }
00211    if (prtlevel) print(n,x);
00212 
00213 mloop:
00214    sf = d[0];
00215    s = d[0] = 0.0;
00216 
00217    /* minimize along first direction */
00218    min_first_dir(0,2,&d[0],&s,fx,0,x,n,v,w,q01);
00219    if (s <= 0.0) for (i=0; i < n; i++) v[i][0] = -v[i][0];
00220    if ((sf <= (0.9 * d[0])) || ((0.9 * sf) >= d[0])) {
00221       for (i=1; i<n; i++) d[i] = 0.0;
00222    }
00223    for (k=1; k<n; k++) {
00224       for (i=0; i<n; i++) y[i] = x[i];
00225       sf = fx;
00226       illc = illc || (kt > 0);
00227 next:
00228       kl = k;
00229       df = 0.0;
00230       if (illc) {        /* random step to get off resolution valley */
00231          for (i=0; i<n; i++) {
00232             z[i] = (0.1*ldt + t2*pow(10.0,(double)kt))*(ranf()-0.5);
00233             s = z[i];
00234             for (j=0; j < n; j++) x[j] += s * v[j][i];
00235          }
00236          fx = minfun(x, n);
00237          nf++;
00238       }
00239        /* minimize along non-conjugate directions */
00240       for (k2=k; k2<n; k2++) {
00241          sl = fx;
00242          s = 0.0;
00243          min_first_dir(k2,2,&d[k2],&s,fx,0,x,n,v,w,q01);
00244          if (illc) {
00245             s = d[k2] * (s + z[k2]) * (s + z[k2]);
00246          }
00247          else
00248             s = sl - fx;
00249          if (df < s) {
00250             df = s;
00251             kl = k2;
00252          }
00253       }
00254 
00255       if (!illc && (df < std::fabs(100.0 * macheps * fx))) {
00256          illc = 1;
00257          goto next;
00258       }
00259       if (k == 1 && prtlevel > 1) {
00260          std::cout << "\n-- New Direction:\n";
00261          d.print();
00262       }
00263        // minimize along conjugate directions
00264       for (k2=0; k2<=k-1; k2++) {
00265          s = 0.0;
00266          min_first_dir(k2,2,&d[k2],&s,fx,0,x,n,v,w,q01);
00267       }
00268       f1 = fx;
00269       fx = sf;
00270       lds = 0.0;
00271       for (i=0; i<n; i++) {
00272          sl = x[i];
00273          x[i] = y[i];
00274          y[i] = sl - y[i];
00275          sl = y[i];
00276          lds = lds + sl*sl;
00277       }
00278       lds = std::sqrt(lds);
00279       if (lds > SmaLL) {
00280          for (i=kl-1; i>=k; i--) {
00281             for (j=0; j < n; j++) v[j][i+1] = v[j][i];
00282             d[i+1] = d[i];
00283          }
00284          d[k] = 0.0;
00285          for (i=0; i < n; i++) v[i][k] = y[i] / lds;
00286          min_first_dir(k,4,&d[k],&lds,f1,1,x,n,v,w,q01);
00287          if (lds <= 0.0) {
00288             lds = -lds;
00289             for (i=0; i<n; i++) v[i][k] = -v[i][k];
00290          }
00291       }
00292       ldt = ldfac * ldt;
00293       if (ldt < lds) ldt = lds;
00294       if (prtlevel > 1) print(n,x);
00295       t2 = 0.0;
00296       for (i=0; i<n; i++) t2 += x[i]*x[i];
00297       t2 = m2 * std::sqrt(t2) + t;
00298       if (ldt > (0.5 * t2))
00299          kt = 0;
00300       else
00301          kt++;
00302       if (kt > ktm) goto fret;
00303    }
00304    /////////////////////////////////////////////
00305    //  try quadratic extrapolation in case    //
00306    //  we are stuck in a curved valley        //
00307    /////////////////////////////////////////////
00308    quadratic(x,n,v,w,q01);
00309    dn = 0.0;
00310    for (i=0; i<n; i++) {
00311       d[i] = 1.0 / std::sqrt(d[i]);
00312       if (dn < d[i]) dn = d[i];
00313    }
00314    if (prtlevel > 2) {
00315       std::cout << "\n-- New Matrix of Directions:\n";
00316       v.print();
00317    }
00318 
00319    for (j=0; j<n; j++) {
00320       s = d[j] / dn;
00321       for (i=0; i < n; i++) v[i][j] *= s;
00322    }
00323    if (scbd > 1.0) {               // scale axis to reduce condition number
00324       s = vlarge;
00325       for (i=0; i<n; i++) {
00326          sl = 0.0;
00327          for (j=0; j < n; j++) sl += v[i][j]*v[i][j];
00328          z[i] = std::sqrt(sl);
00329          if (z[i] < m4) z[i] = m4;
00330          if (s > z[i]) s = z[i];
00331       }
00332       for (i=0; i<n; i++) {
00333          sl = s / z[i];
00334          z[i] = 1.0 / sl;
00335          if (z[i] > scbd) {
00336             sl = 1.0 / scbd;
00337             z[i] = scbd;
00338          }
00339       }
00340    }
00341    for (i=1; i<n; i++) {
00342       for (j=0; j<=i-1; j++) {
00343          s = v[i][j];
00344          v[i][j] = v[j][i];
00345          v[j][i] = s;
00346       }
00347    }
00348    svd(n, macheps, vsmall, v.begin(), d.begin());
00349    if (scbd > 1.0) {
00350       for (i=0; i<n; i++) {
00351          s = z[i];
00352          for (j=0; j<n; j++) v[i][j] *= s;
00353       }
00354       for (i=0; i<n; i++) {
00355          s = 0.0;
00356          for (j=0; j<n; j++) s += v[j][i]*v[j][i];
00357          s = std::sqrt(s);
00358          d[i] *= s;
00359          s = 1.0 / s;
00360          for (j=0; j<n; j++) v[j][i] *= s;
00361       }
00362    }
00363    for (i=0; i<n; i++) {
00364       if ((dn * d[i]) > large)
00365          d[i] = vsmall;
00366       else if ((dn * d[i]) < SmaLL)
00367          d[i] = vlarge;
00368       else
00369          d[i] = pow(dn * d[i],-2.0);
00370    }
00371    sort(n,d.begin(),v.begin());               // the new eigenvalues and eigenvectors
00372    dmin = d[n-1];
00373    if (dmin < SmaLL) dmin = SmaLL;
00374    illc = (m2 * d[0]) > dmin;
00375    if (prtlevel > 2 && scbd > 1.0) {
00376       std::cout << "\n-- Scale Factors:\n";
00377       z.print();
00378    }
00379    if (prtlevel > 2) {
00380       std::cout << "\n-- Eigenvalues of A:\n";
00381       d.print();
00382       std::cout << "\n-- Eigenvectors of A:\n";
00383       v.print();
00384    }
00385 
00386    if (maxfun > 0 && nl > maxfun) {
00387       if (prtlevel) std::cout << "\n-- maxiimum # of function calls reached \n";
00388       goto fret;
00389    }
00390    if (nf > n*10) step = 1.0;
00391    goto mloop;   // back to main loop
00392 
00393 fret:
00394    if (prtlevel > 0) {
00395       std::cout << "\n--after " << nf << " function calls\n";
00396       std::cout << "-- your function f(x) has finally been minimized to "
00397            << std::setprecision(W) << fx << "\n";
00398       std::cout.precision(6);
00399       std::cout << "-- with final x:\n";
00400       x.print();
00401    }
00402    maxfun = nf;
00403    return fx;
00404 }
00405 
00406 void Minimizer::min_first_dir(const int j,const int nits,double *d2,
00407                               double *x1,
00408                               double f1, const int fk,Vector<double> &x,const int n,
00409                               const Matrix<double> &v, Vector<double> &w,Matrix<double> &q01)
00410 {
00411    int k, i, dz;
00412    double x2, xm, f0, f2, fm, d1, t2, s, sf1, sx1;
00413 
00414    sf1 = f1; sx1 = *x1;
00415    k = 0; xm = 0.0; fm = f0 = fx; dz = *d2 < macheps;
00416    ///////////////////////////////////
00417    //        find step size        //
00418    //////////////////////////////////
00419    s = 0;
00420    for (i=0; i<n; i++) s += x[i]*x[i];
00421    s = std::sqrt(s);
00422    if (dz) { t2 = m4*std::sqrt(std::fabs(fx)/dmin + s*ldt) + m2*ldt; }
00423    else    { t2 = m4*std::sqrt(std::fabs(fx)/(*d2) + s*ldt) + m2*ldt; }
00424    s = s*m4 + t;
00425    if (dz && t2 > s) t2 = s;
00426    if (t2 < SmaLL) t2 = SmaLL;
00427    if (t2 > 0.01*h) t2 = 0.01 * h;
00428    if (fk && f1 <= fm) {
00429       xm = *x1;
00430       fm = f1;
00431    }
00432    if (!fk || std::fabs(*x1) < t2) {
00433       *x1 = (*x1 > 0 ? t2 : -t2);
00434       flin(*x1, j,x,n,v,w,q01);
00435       nf++;
00436       f1 = minfun(w,n);
00437    }
00438    if (f1 <= fm) {
00439       xm = *x1;
00440       fm = f1;
00441    }
00442 next:
00443    if (dz) {
00444       x2 = (f0 < f1 ? -(*x1) : 2*(*x1));
00445       flin(x2, j,x,n,v,w,q01);
00446       nf++;
00447       f2 = minfun(w,n);
00448       if (f2 <= fm) {
00449          xm = x2;
00450          fm = f2;
00451       }
00452       *d2 = (x2*(f1-f0) - (*x1)*(f2-f0))/((*x1)*x2*((*x1)-x2));
00453    }
00454    d1 = (f1-f0)/(*x1) - *x1**d2; dz = 1;
00455    if (*d2 <= SmaLL) { x2 = (d1 < 0 ? h : -h); }
00456    else              { x2 = - 0.5*d1/(*d2); }
00457    if (std::fabs(x2) > h) x2 = (x2 > 0 ? h : -h);
00458 tryit:
00459    flin(x2, j,x,n,v,w,q01);
00460    nf++;
00461    f2 = minfun(w,n);
00462    if ((k < nits) && (f2 > f0)) {
00463       k++;
00464       if ((f0 < f1) && (*x1*x2 > 0.0)) goto next;
00465       x2 *= 0.5;
00466       goto tryit;
00467    }
00468    nl++;
00469    if (f2 > fm) x2 = xm; else fm = f2;
00470    if (std::fabs(x2*(x2-*x1)) > SmaLL) {
00471       *d2 = (x2*(f1-f0) - *x1*(fm-f0))/(*x1*x2*(*x1-x2));
00472    }
00473    else {
00474       if (k > 0) *d2 = 0;
00475    }
00476    if (*d2 <= SmaLL) *d2 = SmaLL;
00477    *x1 = x2; fx = fm;
00478    if (sf1 < fx) {
00479       fx = sf1;
00480       *x1 = sx1;
00481    }
00482    if (j != -1) for (i=0; i<n; i++) x[i] += (*x1)*v[i][j];
00483 }
00484 
00485 void Minimizer::quadratic(Vector<double> &x,const int n,const Matrix<double> &v,
00486                           Vector<double> &w,Matrix<double> &q01)
00487 {                               // look for a minimum along the curve q0, q1 //
00488    int i;
00489    double l, s,qa,qb,qc;
00490    s = fx; fx = qf1; qf1 = s;   // swap fx and qf1
00491    qd[1] = 0.0;
00492    for (i=0; i<n; i++) {
00493        s = x[i]; l = q01[1][i]; x[i] = l; q01[1][i] = s;
00494        qd[1] += (s-l)*(s-l);
00495    }
00496    s = 0.0; qd[1] = std::sqrt(qd[1]); l = qd[1];
00497    if ( qd[0]>0.0 && qd[1]>0.0 && nl>=3*n*n ) {
00498       min_first_dir(-1,2, &s,&l,qf1,1,x, n,v,w,q01);
00499       qa = l*(l-qd[1])/(qd[0]*(qd[0]+qd[1]));
00500       qb = (l+qd[0])*(qd[1]-l)/(qd[0]*qd[1]);
00501       qc = l*(l+qd[0])/(qd[1]*(qd[0]+qd[1]));
00502    }
00503    else { qa = qb = 0.0; qc = 1.0; }
00504    qd[0] = qd[1];
00505    for (i=0; i<n; i++) {
00506       s = q01[0][i]; q01[0][i] = x[i];
00507       x[i] = qa*s + qb*x[i] + qc*q01[1][i];
00508    }
00509 }
00510 
00511 /////////////////////////////////////////////
00512 //  singular value decomposition   A = U*S*V'
00513 //  s is returned with values ascendingly
00514 ///////////////////////////////////////////////////
00515 
00516 static void svd(const int n,double eps,const double tol,double** ab,double* q)
00517 {
00518    int l, kt, l2, i, j, k;
00519    double c, f, g, h, s, x, y, z;
00520    Vector<double> e(n);
00521    // householder's reduction to bidiagonal form
00522    l = 0;        // added by  T wang to avoid warning from g++
00523    x = g = 0.0;
00524    for (i=0; i<n; i++) {
00525       e[i] = g; s = 0.0;
00526       l = i+1;
00527       for (j=i; j<n; j++) s += ab[j][i] * ab[j][i];
00528       if (s < tol) {
00529          g = 0.0;
00530       }
00531       else {
00532          f = ab[i][i];
00533          if (f < 0.0) {g = std::sqrt(s); }
00534          else         { g = - std::sqrt(s); }
00535          h = f*g - s; ab[i][i] = f - g;
00536          for (j=l; j<n; j++) {
00537             f = 0.0;
00538             for (k=i; k<n; k++) f += ab[k][i] * ab[k][j];
00539             f /= h;
00540             for (k=i; k<n; k++) ab[k][j] += f * ab[k][i];
00541          }
00542       }
00543       q[i] = g; s = 0.0;
00544       if (i < n) for (j=l; j<n; j++) s += ab[i][j] * ab[i][j];
00545       if (s < tol) {
00546          g = 0.0;
00547       }
00548       else {
00549          f = ab[i][i+1];
00550          if (f < 0.0) { g = std::sqrt(s); }
00551          else         { g = - std::sqrt(s); }
00552          h = f*g - s; ab[i][i+1] = f - g;
00553          for (j=l; j<n; j++) e[j] = ab[i][j]/h;
00554          for (j=l; j<n; j++) {
00555             s = 0;
00556             for (k=l; k<n; k++) s += ab[j][k]*ab[i][k];
00557             for (k=l; k<n; k++) ab[j][k] += s * e[k];
00558          }
00559       }
00560       y = std::fabs(q[i]) + std::fabs(e[i]);
00561       if (y > x) x = y;
00562    }
00563    /* accumulation of right hand transformations */
00564    for (i=n-1; i >= 0; i--) {
00565       if (g != 0.0) {
00566          h = ab[i][i+1]*g;
00567          for (j=l; j<n; j++) ab[j][i] = ab[i][j] / h;
00568          for (j=l; j<n; j++) {
00569             s = 0.0;
00570             for (k=l; k<n; k++) s += ab[i][k] * ab[k][j];
00571             for (k=l; k<n; k++) ab[k][j] += s * ab[k][i];
00572          }
00573       }
00574       for (j=l; j<n; j++) ab[i][j] = ab[j][i] = 0.0;
00575       ab[i][i] = 1.0; g = e[i]; l = i;
00576    }
00577     // diagonalization to bidiagonal form 
00578    eps *= x;
00579    for (k=n-1; k>= 0; k--) {
00580       kt = 0;
00581 TestFsplitting:
00582       if (++kt > 30) {
00583          e[k] = 0.0;
00584          std::cerr << "\n+++ qr failed\n";
00585       }
00586       for (l2=k; l2>=0; l2--) {
00587          l = l2;
00588          if (std::fabs(e[l]) <= eps) goto TestFconvergence;
00589          if (std::fabs(q[l-1]) <= eps) break;
00590       }
00591       c = 0.0; s = 1.0;
00592       for (i=l; i<=k; i++) {
00593          f = s * e[i]; e[i] *= c;
00594          if (std::fabs(f) <= eps) goto TestFconvergence;
00595          g = q[i];
00596          if (std::fabs(f) < std::fabs(g)) {
00597             double fg = f/g;
00598             h = std::fabs(g)*std::sqrt(1.0+fg*fg);
00599          }
00600          else {
00601             double gf = g/f;
00602             h = (f!=0.0 ? std::fabs(f)*std::sqrt(1.0+gf*gf) : 0.0);
00603          }
00604          q[i] = h;
00605          if (h == 0.0) { h = 1.0; g = 1.0; }
00606          c = g/h; s = -f/h;
00607       }
00608 TestFconvergence:
00609       z = q[k];
00610       if (l == k) goto Convergence;
00611        // shift from bottom 2x2 minor 
00612       x = q[l]; y = q[k-l]; g = e[k-1]; h = e[k];
00613       //BRS added to avoid division by y=zero
00614       if (y) {
00615         f = ((y-z)*(y+z) + (g-h)*(g+h)) / (2.0*h*y);
00616       }
00617       else
00618         f = ((y-z)*(y+z) + (g-h)*(g+h)) / (2.0*h);
00619       //BRS
00620       g = std::sqrt(f*f+1.0);
00621       if (f <= 0.0)
00622          f = ((x-z)*(x+z) + h*(y/(f-g)-h))/x;
00623       else
00624          f = ((x-z)*(x+z) + h*(y/(f+g)-h))/x;
00625        // next qr transformation 
00626       s = c = 1.0;
00627       for (i=l+1; i<=k; i++) {
00628          g = e[i]; y = q[i]; h = s*g; g *= c;
00629          if (std::fabs(f) < std::fabs(h)) {
00630             double fh = f/h;
00631             z = std::fabs(h) * std::sqrt(1.0 + fh*fh);
00632          }
00633          else {
00634             double hf = h/f;
00635             z = (f!=0.0 ? std::fabs(f)*std::sqrt(1.0+hf*hf) : 0.0);
00636          }
00637          e[i-1] = z;
00638          if (z == 0.0) f = z = 1.0;
00639          c = f/z; s = h/z;
00640          f = x*c + g*s; g = - x*s + g*c; h = y*s;
00641          y *= c;
00642          for (j=0; j<n; j++) {
00643             x = ab[j][i-1]; z = ab[j][i];
00644             ab[j][i-1] = x*c + z*s;
00645             ab[j][i] = - x*s + z*c;
00646          }
00647          if (std::fabs(f) < std::fabs(h)) {
00648             double fh = f/h;
00649             z = std::fabs(h) * std::sqrt(1.0 + fh*fh);
00650          }
00651          else {
00652             double hf = h/f;
00653             z = (f!=0.0 ? std::fabs(f)*std::sqrt(1.0+hf*hf) : 0.0);
00654          }
00655          q[i-1] = z;
00656          if (z == 0.0) z = f = 1.0;
00657          c = f/z; s = h/z;
00658          f = c*g + s*y; x = - s*g + c*y;
00659       }
00660       e[l] = 0.0; e[k] = f; q[k] = x;
00661       goto TestFsplitting;
00662 Convergence:
00663       if (z < 0.0) {
00664          q[k] = - z;
00665          for (j=0; j<n; j++) ab[j][k] = - ab[j][k];
00666       }
00667    }
00668 }
00669 
00670 } ///// end of namespace matvec
00671 

Generated on Thu Jun 16 17:13:47 2005 for Matvec by doxygen1.2.16