00001
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005
00006
00007
00008
00009
00010
00011 #include "vnl_amoeba.h"
00012
00013 #include <vcl_cstdio.h>
00014 #include <vcl_cstdlib.h>
00015 #include <vcl_iostream.h>
00016 #include <vcl_vector.h>
00017 #include <vnl/vnl_math.h>
00018 #include <vnl/vnl_vector.h>
00019 #include <vnl/vnl_cost_function.h>
00020 #include <vnl/vnl_least_squares_function.h>
00021
00022 bool vnl_amoeba::default_verbose = false;
00023
00024 vnl_amoeba::vnl_amoeba(vnl_cost_function& f)
00025 : fptr(&f), num_evaluations_(0)
00026 {
00027 verbose = default_verbose;
00028 maxiter = f.get_number_of_unknowns() * 200;
00029 X_tolerance = 1e-8;
00030 F_tolerance = 1e-4;
00031 relative_diameter = 0.05;
00032 }
00033
00034
00035 struct vnl_amoebaFit : public vnl_amoeba
00036 {
00037 int cnt;
00038
00039 vnl_amoebaFit(vnl_amoeba& a): vnl_amoeba(a) {
00040 cnt = 0;
00041 }
00042
00043
00044 void set_up_simplex_relative(vcl_vector<vnl_amoeba_SimplexCorner>& simplex,
00045 const vnl_vector<double>& x);
00046
00047
00048 void set_up_simplex_absolute(vcl_vector<vnl_amoeba_SimplexCorner>& simplex,
00049 const vnl_vector<double>& x,
00050 const vnl_vector<double>& dx);
00051
00052
00053 void amoeba(vnl_vector<double>& x);
00054
00055
00056 void amoeba(vnl_vector<double>& x, const vnl_vector<double>& dx);
00057
00058
00059 void amoeba(vnl_vector<double>& x, vcl_vector<vnl_amoeba_SimplexCorner>& simplex);
00060
00061 double f(const vnl_vector<double>& x) {
00062 return fptr->f(x);
00063 }
00064
00065 void set_corner(vnl_amoeba_SimplexCorner * s,
00066 const vnl_vector<double>& v)
00067 {
00068 s->v = v;
00069 s->fv = f(v);
00070 cnt++;
00071 }
00072 void set_corner_a_plus_bl(vnl_amoeba_SimplexCorner * s,
00073 const vnl_vector<double>& vbar,
00074 const vnl_vector<double>& v,
00075 double lambda)
00076 {
00077 s->v = (1 - lambda) * vbar + lambda * v;
00078 s->fv = f(s->v);
00079 cnt++;
00080 }
00081 };
00082
00083 int vnl_amoeba_SimplexCorner::compare(vnl_amoeba_SimplexCorner const& s1,
00084 vnl_amoeba_SimplexCorner const& s2)
00085 {
00086 return vnl_math_sgn(s1.fv - s2.fv);
00087 }
00088
00089 #ifdef VCL_SUNPRO_CC
00090 extern "C"
00091 #else
00092 static
00093 #endif
00094 int compare_aux(const void * s1, const void * s2)
00095 {
00096 return vnl_amoeba_SimplexCorner::compare(*(const vnl_amoeba_SimplexCorner*)s1,
00097 *(const vnl_amoeba_SimplexCorner*)s2);
00098 }
00099
00100 static
00101 void sort_simplex(vcl_vector<vnl_amoeba_SimplexCorner>& simplex)
00102 {
00103 vcl_qsort(&simplex[0], simplex.size(), sizeof simplex[0], compare_aux);
00104 }
00105
00106 static
00107 double maxabsdiff(const vnl_vector<double>& a, const vnl_vector<double>& b)
00108 {
00109 double v = 0;
00110 for (unsigned i = 0; i < a.size(); ++i) {
00111 double ad = vnl_math_abs(a[i] - b[i]);
00112 if (ad > v)
00113 v = ad;
00114 }
00115 return v;
00116 }
00117
00118 static
00119 double sorted_simplex_fdiameter(const vcl_vector<vnl_amoeba_SimplexCorner>& simplex)
00120 {
00121 return simplex[simplex.size()-1].fv - simplex[0].fv;
00122 }
00123
00124 #if 0
00125 static
00126 double simplex_fdiameter(const vcl_vector<vnl_amoeba_SimplexCorner>& simplex)
00127 {
00128
00129 double max = 0;
00130 for (unsigned i = 1; i < simplex.size(); i++) {
00131 double thismax = vnl_math_abs(simplex[0].fv - simplex[i].fv);
00132 if (thismax > max)
00133 max = thismax;
00134 }
00135 return max;
00136 }
00137 #endif
00138
00139 static
00140 double simplex_diameter(const vcl_vector<vnl_amoeba_SimplexCorner>& simplex)
00141 {
00142 double max = 0;
00143 for (unsigned i = 0; i < simplex.size() - 1; i++) {
00144 double thismax = maxabsdiff(simplex[i].v, simplex[i+1].v);
00145 if (thismax > max)
00146 max = thismax;
00147 }
00148 return max;
00149 }
00150
00151
00152 vcl_ostream& operator<<(vcl_ostream& s, const vnl_amoeba_SimplexCorner& simplex)
00153 {
00154 s << 'S' << simplex.fv << ' ';
00155 return s;
00156 }
00157
00158 vcl_ostream& operator<<(vcl_ostream& s, const vcl_vector<vnl_amoeba_SimplexCorner>& simplex)
00159 {
00160 for (unsigned i = 0; i < simplex.size(); ++i)
00161 s << simplex[i].fv << ' ';
00162 return s;
00163 }
00164
00165
00166 bool operator==(const vnl_amoeba_SimplexCorner& a, const vnl_amoeba_SimplexCorner& b)
00167 {
00168 return (&a) == (&b);
00169 }
00170
00171
00172 void vnl_amoebaFit::set_up_simplex_relative(vcl_vector<vnl_amoeba_SimplexCorner>& simplex,
00173 const vnl_vector<double>& x)
00174 {
00175 int n = x.size();
00176
00177 simplex[0].v = x;
00178 simplex[0].fv = f(x);
00179
00180
00181 const double usual_delta = relative_diameter;
00182 const double zero_term_delta = 0.00025;
00183
00184 for (int j = 0; j < n; ++j) {
00185 vnl_amoeba_SimplexCorner *s = &simplex[j+1];
00186 s->v = x;
00187
00188
00189 if (vnl_math_abs(s->v[j]) > zero_term_delta)
00190 s->v[j] = (1 + usual_delta)*s->v[j];
00191 else
00192 s->v[j] = zero_term_delta;
00193
00194 s->fv = f(s->v);
00195 }
00196 }
00197
00198
00199 void vnl_amoebaFit::set_up_simplex_absolute(vcl_vector<vnl_amoeba_SimplexCorner>& simplex,
00200 const vnl_vector<double>& x,
00201 const vnl_vector<double>& dx)
00202 {
00203 int n = x.size();
00204
00205 simplex[0].v = x;
00206 simplex[0].fv = f(x);
00207
00208 for (int j = 0; j < n; ++j) {
00209 vnl_amoeba_SimplexCorner *s = &simplex[j+1];
00210 s->v = x;
00211
00212
00213 s->v[j] = s->v[j] + dx[j];
00214
00215 s->fv = f(s->v);
00216 }
00217 }
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245 void vnl_amoebaFit::amoeba(vnl_vector<double>& x)
00246 {
00247
00248 int n = x.size();
00249 vcl_vector<vnl_amoeba_SimplexCorner> simplex(n+1, vnl_amoeba_SimplexCorner(n));
00250
00251 set_up_simplex_relative(simplex,x);
00252 amoeba(x,simplex);
00253 }
00254
00255 void vnl_amoebaFit::amoeba(vnl_vector<double>& x, const vnl_vector<double>& dx)
00256 {
00257
00258 int n = x.size();
00259 vcl_vector<vnl_amoeba_SimplexCorner> simplex(n+1, vnl_amoeba_SimplexCorner(n));
00260
00261 set_up_simplex_absolute(simplex,x,dx);
00262 amoeba(x,simplex);
00263 }
00264
00265
00266 void vnl_amoebaFit::amoeba(vnl_vector<double>& x,
00267 vcl_vector<vnl_amoeba_SimplexCorner>& simplex)
00268 {
00269 int n = x.size();
00270 sort_simplex(simplex);
00271
00272 if (verbose > 1) {
00273 vcl_cerr << "initial\n" << simplex;
00274 } else if (verbose) {
00275 vcl_cerr << "initial: " << simplex << vcl_endl;
00276 }
00277
00278
00279 vnl_amoeba_SimplexCorner reflect(n);
00280 vnl_amoeba_SimplexCorner expand(n);
00281 vnl_amoeba_SimplexCorner contract(n);
00282 vnl_amoeba_SimplexCorner shrink(n);
00283 vnl_amoeba_SimplexCorner *next;
00284
00285 vnl_vector<double> vbar(n);
00286 while (cnt < maxiter) {
00287 if (simplex_diameter(simplex) < X_tolerance &&
00288 sorted_simplex_fdiameter(simplex) < F_tolerance)
00289 break;
00290
00291
00292 for (int k = 0; k < n; ++k) {
00293 vbar[k] = 0;
00294 for (int i = 0; i < n; ++i)
00295 vbar[k] += simplex[i].v[k];
00296 vbar[k] /= n;
00297 }
00298
00299 set_corner_a_plus_bl(&reflect, vbar, simplex[n].v, -1);
00300
00301 next = &reflect;
00302 const char *how = "reflect ";
00303 if (reflect.fv < simplex[n-1].fv) {
00304
00305 if (reflect.fv < simplex[0].fv) {
00306
00307 set_corner_a_plus_bl(&expand, vbar, reflect.v, 2);
00308
00309 if (expand.fv < simplex[0].fv) {
00310 next = &expand;
00311 how = "expand ";
00312 }
00313 }
00314 } else {
00315
00316 {
00317 vnl_amoeba_SimplexCorner *tmp = &simplex[n];
00318 if (reflect.fv < tmp->fv)
00319
00320 tmp = &reflect;
00321 set_corner_a_plus_bl(&contract, vbar, tmp->v, 0.5);
00322 }
00323
00324 if (contract.fv < simplex[0].fv) {
00325
00326 next = &contract;
00327 how = "contract";
00328 }
00329 else {
00330
00331 for (int j = 1; j < n; ++j)
00332
00333 set_corner_a_plus_bl(&simplex[j], simplex[0].v, simplex[j].v, 0.5);
00334 set_corner_a_plus_bl(&shrink, simplex[0].v, simplex[n].v, 0.5);
00335
00336 next = &shrink;
00337 how = "shrink ";
00338 }
00339 }
00340 simplex[n] = *next;
00341
00342 sort_simplex(simplex);
00343
00344
00345 if (verbose) {
00346 char buf[16383];
00347 vcl_sprintf(buf, "iter %5d: %s ", cnt, how);
00348 vcl_cerr << buf;
00349 if (verbose ==2)
00350 vcl_cerr << "\nFirst corner: " << simplex[0].v;
00351 if (verbose > 1)
00352 {
00353 vcl_streamsize a = vcl_cerr.width(10);
00354 vcl_cerr << vcl_endl << simplex << vcl_endl;
00355 vcl_cerr.width(a);
00356 }
00357 else if (verbose)
00358 vcl_cerr << simplex << vcl_endl;
00359 }
00360 }
00361 num_evaluations_ = cnt;
00362 x = simplex[0].v;
00363 }
00364
00365
00366
00367 void vnl_amoeba::minimize(vnl_vector<double>& x)
00368 {
00369 vnl_amoebaFit af(*this);
00370 af.amoeba(x);
00371 num_evaluations_ = af.num_evaluations_;
00372 }
00373
00374
00375 void vnl_amoeba::minimize(vnl_vector<double>& x, const vnl_vector<double>& dx)
00376 {
00377 vnl_amoebaFit af(*this);
00378 af.amoeba(x,dx);
00379 num_evaluations_ = af.num_evaluations_;
00380 }
00381
00382
00383
00384 void vnl_amoeba::minimize(vnl_cost_function& f, vnl_vector<double>& x)
00385 {
00386 minimize(f, x, 0);
00387 }
00388
00389
00390 void vnl_amoeba::minimize(vnl_cost_function& f, vnl_vector<double>& x, double delta)
00391 {
00392 vnl_amoeba a(f);
00393 a.verbose = vnl_amoeba::default_verbose;
00394 if (delta != 0)
00395 a.relative_diameter = delta;
00396 vnl_amoebaFit amoeba(a);
00397 amoeba.amoeba(x);
00398 }
00399
00400
00401 void vnl_amoeba::minimize(vnl_cost_function& f, vnl_vector<double>& x,
00402 const vnl_vector<double>& dx)
00403 {
00404 vnl_amoeba a(f);
00405 a.verbose = vnl_amoeba::default_verbose;
00406 vnl_amoebaFit amoeba(a);
00407 amoeba.amoeba(x,dx);
00408 }
00409
00410
00411 class vnl_amoeba_LSCF : public vnl_cost_function
00412 {
00413 vnl_least_squares_function* ls_;
00414 vnl_vector<double> fx;
00415 public:
00416 vnl_amoeba_LSCF(vnl_least_squares_function& ls)
00417 : vnl_cost_function(ls.get_number_of_unknowns()),
00418 ls_(&ls), fx(ls.get_number_of_residuals()) {}
00419
00420 ~vnl_amoeba_LSCF() {}
00421
00422 double f(vnl_vector<double> const& x) {
00423 ls_->f(x, fx);
00424 return fx.squared_magnitude();
00425 }
00426 };
00427
00428 void vnl_amoeba::minimize(vnl_least_squares_function& f, vnl_vector<double>& x)
00429 {
00430 vnl_amoeba_LSCF lsf(f);
00431 minimize(lsf, x);
00432 }
00433
00434
00435 vnl_amoeba_SimplexCorner::vnl_amoeba_SimplexCorner(int n) : v(n) {}
00436
00437 vnl_amoeba_SimplexCorner& vnl_amoeba_SimplexCorner::operator=(const vnl_amoeba_SimplexCorner& that)
00438 {
00439 v = that.v;
00440 fv = that.fv;
00441 return *this;
00442 }
00443
00444