00001
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005
00006
00007 #include "vnl_powell.h"
00008
00009 #include <vcl_cassert.h>
00010 #include <vnl/vnl_math.h>
00011 #include <vnl/algo/vnl_brent.h>
00012 #ifdef DEBUG
00013 #include <vnl/vnl_matlab_print.h>
00014 #include <vcl_iostream.h>
00015 #endif
00016
00017 class vnl_powell_1dfun : public vnl_cost_function
00018 {
00019 public:
00020 vnl_powell* powell_;
00021 vnl_cost_function* f_;
00022 unsigned int n_;
00023 vnl_vector<double> x0_;
00024 vnl_vector<double> dx_;
00025 vnl_vector<double> tmpx_;
00026 vnl_powell_1dfun(int n, vnl_cost_function* f, vnl_powell* p)
00027 : vnl_cost_function(1), powell_(p), f_(f), n_(n), x0_(n), dx_(n), tmpx_(n) {}
00028
00029 void init(vnl_vector<double> const& x0, vnl_vector<double> const& dx)
00030 {
00031 x0_ = x0;
00032 dx_ = dx;
00033 assert(x0.size() == n_);
00034 assert(dx.size() == n_);
00035 }
00036
00037 double f(const vnl_vector<double>& x)
00038 {
00039 uninit(x[0], tmpx_);
00040 double e = f_->f(tmpx_);
00041 powell_->pub_report_eval(e);
00042 return e;
00043 }
00044
00045 void uninit(double lambda, vnl_vector<double>& out)
00046 {
00047 for (unsigned int i = 0; i < n_; ++i)
00048 out[i] = x0_[i] + lambda * dx_[i];
00049 }
00050 };
00051
00052 vnl_nonlinear_minimizer::ReturnCodes
00053 vnl_powell::minimize(vnl_vector<double>& p)
00054
00055 {
00056
00057 int n = p.size();
00058 vnl_powell_1dfun f1d(n, functor_, this);
00059
00060 vnl_matrix<double> xi(n,n, vnl_matrix_identity);
00061 vnl_vector<double> ptt(n);
00062 vnl_vector<double> xit(n);
00063 double fret = functor_->f(p);
00064 report_eval(fret);
00065 vnl_vector<double> pt = p;
00066 while (num_iterations_ < unsigned(maxfev))
00067 {
00068 double fp = fret;
00069 int ibig=0;
00070 double del=0.0;
00071
00072 for (int i=0;i<n;i++)
00073 {
00074
00075 for (int j = 0; j < n; ++j)
00076 xit[j] = xi[j][i];
00077 double fptt = fret;
00078
00079
00080 f1d.init(p, xit);
00081 vnl_brent brent(&f1d);
00082 double ax = 0.0;
00083 double xx = initial_step_;
00084 double bx;
00085 brent.bracket_minimum(&ax, &xx, &bx);
00086 fret = brent.minimize_given_bounds(bx, xx, ax, linmin_xtol_, &xx);
00087 f1d.uninit(xx, p);
00088
00089
00090 if (vcl_fabs(fptt-fret) > del) {
00091 del = vcl_fabs(fptt-fret);
00092 ibig = i;
00093 }
00094 }
00095
00096 if (2.0*vcl_fabs(fp-fret) <= ftol*(vcl_fabs(fp)+vcl_fabs(fret)))
00097 {
00098 #ifdef DEBUG
00099 vnl_matlab_print(vcl_cerr, xi, "xi");
00100 #endif
00101 return CONVERGED_FTOL;
00102 }
00103
00104 if (num_iterations_ == unsigned(maxfev))
00105 return TOO_MANY_ITERATIONS;
00106
00107 for (int j=0;j<n;++j)
00108 {
00109 ptt[j]=2.0*p[j]-pt[j];
00110 xit[j]=p[j]-pt[j];
00111 pt[j]=p[j];
00112 }
00113
00114 double fptt = functor_->f(ptt);
00115 report_eval(fret);
00116 if (fptt < fp)
00117 {
00118 double t=2.0*(fp-2.0*fret+fptt)*vnl_math_sqr(fp-fret-del)-del*vnl_math_sqr(fp-fptt);
00119 if (t < 0.0)
00120 {
00121 f1d.init(p, xit);
00122 vnl_brent brent(&f1d);
00123 double ax = 0.0;
00124 double xx = 1.0;
00125 double bx;
00126 brent.bracket_minimum(&ax, &xx, &bx);
00127 fret = brent.minimize_given_bounds(bx, xx, ax, linmin_xtol_, &xx);
00128 f1d.uninit(xx, p);
00129
00130 for (int j=0;j<n;j++) {
00131 xi[j][ibig]=xi[j][n-1];
00132 xi[j][n-1]=xit[j];
00133 }
00134 }
00135 }
00136 if (this->report_iter())
00137 return FAILED_USER_REQUEST;
00138 }
00139 return TOO_MANY_ITERATIONS;
00140 }