00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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;
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)
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) {
00078 for (i=0; i<n; i++) w[i] = x[i] + l *v[i][j];
00079 }
00080 else {
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
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
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;
00164 Vector<double> y(n);
00165 Vector<double> z(n);
00166 Vector<double> d(n);
00167
00168
00169 Vector<double> w(n);
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
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) {
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
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
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
00306
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) {
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());
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;
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
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 {
00488 int i;
00489 double l, s,qa,qb,qc;
00490 s = fx; fx = qf1; qf1 = s;
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
00513
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
00522 l = 0;
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
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
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
00612 x = q[l]; y = q[k-l]; g = e[k-1]; h = e[k];
00613
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
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
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 }
00671