00001
00002
00003
00004 #include <algorithm>
00005 #include <cassert>
00006 #include <cmath>
00007 #include <iostream>
00008
00009
00010 #include "Registry/Registry.h"
00011
00012
00013 #include "LocalFit.h"
00014
00015 using namespace std;
00016
00017
00018 Anp::LocalFit::LocalFit()
00019 :fDebug(false),
00020 fValid(false),
00021 fDegree(1),
00022 fIter(3),
00023 fWindow(7)
00024 {
00025 }
00026
00027
00028 Anp::LocalFit::~LocalFit()
00029 {
00030 }
00031
00032
00033 bool Anp::LocalFit::Add(const int index, const double x_, const double y_)
00034 {
00035 if(std::find(fFitVec.begin(), fFitVec.end(), index) != fFitVec.end())
00036 {
00037 cerr << "LocalFit::Add - index already exists: " << index << endl;
00038 return false;
00039 }
00040
00041 fFitVec.push_back(Anp::FitPoint(index, x_, y_));
00042 return false;
00043 }
00044
00045
00046 bool Anp::LocalFit::RunFit()
00047 {
00048
00049
00050
00051
00052 if(fDebug)
00053 {
00054 cout << "LocalFit::RunFit - starting new fit" << endl;
00055 }
00056
00057
00058
00059
00060 if(!SortCleanCheck(fFitVec))
00061 {
00062 cerr << "LocalFit::RunFit - invalid fit vector" << endl;
00063 return false;
00064 }
00065
00066 if(fDebug)
00067 {
00068 cout << "LocalFit::RunFit - fit vector size = " << fFitVec.size() << endl;
00069 }
00070
00071
00072
00073
00074 for(unsigned int ipos = 0; ipos < fFitVec.size(); ++ipos)
00075 {
00076 const List nlist = GetList(ipos);
00077
00078 if(nlist.empty() ||
00079 nlist.size() > fWindow ||
00080 (fFitVec.size() > fWindow && nlist.size() != fWindow))
00081 {
00082 cerr << "LocalFit::RunFit - failed to find " << fWindow << " neighbors" << endl;
00083 return false;
00084 }
00085
00086 FitPoint &point = fFitVec[ipos];
00087
00088 const double width = nlist.back().second;
00089 if(!(width > 0.0))
00090 {
00091 cerr << "LocalFit::RunFit - interval size is zero" << endl;
00092 return false;
00093 }
00094
00095 for(List::const_iterator lit = nlist.begin(); lit != nlist.end(); ++lit)
00096 {
00097 point.SetWeight(lit -> first, WFunction(lit -> second/width));
00098 }
00099 }
00100
00101 if(fDebug)
00102 {
00103 cout << "LocalFit::RunFit - starting " << fIter << " iterations..." << endl;
00104 }
00105
00106 for(unsigned int i = 0; i <= fIter; ++i)
00107 {
00108 std::vector<double> resvec;
00109 for(vector<FitPoint>::iterator fit = fFitVec.begin(); fit != fFitVec.end(); ++fit)
00110 {
00111 if(fDegree == 1)
00112 {
00113 RunLFit(*fit, fFitVec);
00114 }
00115 else if(fDegree == 2)
00116 {
00117 RunQFit(*fit, fFitVec);
00118 }
00119 else
00120 {
00121 cerr << "LocalFit::RunFit - uknown polynomial degree: " << fDegree << endl;
00122 return false;
00123 }
00124
00125 if(fit -> Pass())
00126 {
00127 resvec.push_back(std::fabs(fit -> Residual()));
00128 }
00129 }
00130
00131 if(resvec.size() != fFitVec.size())
00132 {
00133 cerr << "LocalFit::RunFit - # of failed points = " << fFitVec.size() - resvec.size() << endl;
00134 for(vector<FitPoint>::iterator fit = fFitVec.begin(); fit != fFitVec.end(); ++fit)
00135 {
00136 if(!(fit -> Pass()))
00137 {
00138 cout << " ";
00139 fit -> Print();
00140 }
00141 }
00142 return false;
00143 }
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160 const double maxres = *std::max_element(resvec.begin(), resvec.end());
00161
00162 if(!(maxres > 0.0))
00163 {
00164 cerr << "LocalFit::RunFit - maximum residual is zero" << endl;
00165 return false;
00166 }
00167
00168 for(vector<FitPoint>::iterator fit = fFitVec.begin(); fit != fFitVec.end(); ++fit)
00169 {
00170 fit -> SetWeight(BFunction(fit -> Residual()/maxres));
00171 }
00172 }
00173
00174 if(fDebug)
00175 {
00176 cout << "LocalFit::RunFit - finished" << endl;
00177 }
00178
00179 fValid = true;
00180
00181 return true;
00182 }
00183
00184
00185 void Anp::LocalFit::Clear()
00186 {
00187 fFitVec.clear();
00188 fValid = false;
00189 }
00190
00191
00192 void Anp::LocalFit::Config(const Registry ®)
00193 {
00194 const char *value_char = 0;
00195 if(reg.Get("LocalFitDebug", value_char) && value_char)
00196 {
00197 if(strcmp(value_char, "yes") == 0)
00198 {
00199 fDebug = true;
00200 }
00201 else if(strcmp(value_char, "no") == 0)
00202 {
00203 fDebug = false;
00204 }
00205 }
00206
00207 int value_int = 0;
00208 if(reg.Get("LocalFitDegree", value_int))
00209 {
00210 SetDegree(value_int);
00211 }
00212
00213 value_int = 0;
00214 if(reg.Get("LocalFitWindow", value_int))
00215 {
00216 SetWindow(value_int);
00217 }
00218
00219 value_int = 0;
00220 if(reg.Get("LocalFitIter", value_int))
00221 {
00222 SetIter(value_int);
00223 }
00224
00225 value_char = 0;
00226 if(reg.Get("PrintConfig", value_char) && value_char && strcmp(value_char, "yes") == 0)
00227 {
00228 cout << "LocalFit::Config" << endl
00229 << " Debug = " << fDebug << endl
00230 << " Degree = " << fDegree << endl
00231 << " Window = " << fWindow << endl
00232 << " Iter = " << fIter << endl;
00233 }
00234 }
00235
00236
00237 double Anp::LocalFit::FitY(const double x) const
00238 {
00239 if(!fValid || fFitVec.empty())
00240 {
00241 cerr << "LocalFit::FitY - I do not have a valid fit vector" << endl;
00242 return 0.0;
00243 }
00244
00245 vector<FitPoint>::const_iterator fit = std::upper_bound(fFitVec.begin(), fFitVec.end(), x);
00246 if(fit == fFitVec.end())
00247 {
00248 cerr << "LocalFit::FitY - x = " << x << " is greater than upper bound of fit range "
00249 << fFitVec.back().X() << endl;
00250 }
00251 else if(fit == fFitVec.begin())
00252 {
00253 cerr << "LocalFit::FitY - x = " << x << " is less than lower bound of fit range "
00254 << fFitVec.front().X() << endl;
00255 }
00256
00257 if(fit -> Pass())
00258 {
00259 return fit -> FitY(x);
00260 }
00261
00262 cerr << "LocalFit::FitY - closest fit point failed local fit:" << endl << " ";
00263 fit -> Print(std::cerr);
00264
00265 return fit -> Y();
00266 }
00267
00268
00269 void Anp::LocalFit::SetWindow(const int value)
00270 {
00271 if(value < 2)
00272 {
00273 cerr << "LocalFit::SetWindow - invalid window parameter: " << value << endl;
00274 }
00275
00276 fWindow = static_cast<unsigned int>(value);
00277 }
00278
00279
00280 void Anp::LocalFit::SetIter(int value)
00281 {
00282 if(value < 0)
00283 {
00284 value = 0;
00285 }
00286
00287 fIter = static_cast<unsigned int>(value);
00288 }
00289
00290
00291 void Anp::LocalFit::SetDegree(int value)
00292 {
00293 if(value != 1 && value != 2)
00294 {
00295 cerr << "LocalFit::SetDegree - invalid degree parameter: " << value << endl;
00296 }
00297
00298 fDegree = static_cast<unsigned int>(value);
00299 }
00300
00301
00302 void Anp::LocalFit::Print(ostream &os) const
00303 {
00304 os << "LocalFit" << endl
00305 << " Debug = " << fDebug << endl
00306 << " Degree = " << fDegree << endl
00307 << " Iter = " << fIter << endl
00308 << " Window = " << fWindow << endl
00309 << " Valid = " << fValid << endl;
00310
00311 for(vector<FitPoint>::const_iterator fit = fFitVec.begin(); fit != fFitVec.end(); ++fit)
00312 {
00313 os << " ";
00314 fit -> Print(os);
00315 }
00316 }
00317
00318
00319 bool Anp::LocalFit::RunLFit(FitPoint &point, const vector<FitPoint> &fvec) const
00320 {
00324
00325 point.SetL(0.0, point.Y(), false);
00326
00327 const map<unsigned int, double> &wmap = point.GetWeightMap();
00328
00329 double A = 0.0, B = 0.0, C = 0.0, D = 0.0, E = 0.0, F = 0.0;
00330 unsigned int wsize = 0;
00331
00332 for(map<unsigned int, double>::const_iterator wit = wmap.begin(); wit != wmap.end(); ++wit)
00333 {
00334 const unsigned int index = wit -> first;
00335
00336 if(index >= fvec.size())
00337 {
00338 cerr << "LocalFit::RunLFit - index of FitPoint is out of range" << endl;
00339 continue;
00340 }
00341
00342 const FitPoint &fitpoint = fvec[index];
00343
00344 const double x = fitpoint.X();
00345 const double y = fitpoint.Y();
00346 const double w = wit -> second * fitpoint.Weight();
00347
00348 assert(!(fitpoint.Weight() < 0.0) && "Global weight is negative");
00349
00350
00351 if(!(w > 0.0))
00352 {
00353 continue;
00354 }
00355
00356 ++wsize;
00357
00358 A += w * x;
00359 B += w;
00360 C += w * y;
00361 D += w * x * x;
00362 E += w * x * y;
00363 F += w * y * y;
00364 }
00365
00366 if(wsize < 2)
00367 {
00368 cerr << "LocalFit::RunLFit - too few fit points with positive weight" << endl;
00369
00370 for(map<unsigned int, double>::const_iterator wit = wmap.begin(); wit != wmap.end(); ++wit)
00371 {
00372 cout << " (index, weight) = (" << wit -> first << ", " << wit -> second << ")" << endl;
00373 }
00374 return false;
00375 }
00376
00377 const double det = B * D - A * A;
00378 if(!(det > 0.0))
00379 {
00380 cerr << "LocalFit::RunLFit - linear fit failed for " << wsize << " points" << endl;
00381 return false;
00382 }
00383
00384 const double a = (E * B - C * A)/det;
00385 const double b = (D * C - E * A)/det;
00386
00387 point.SetL(a, b, true);
00388
00389 return true;
00390 }
00391
00392 bool Anp::LocalFit::RunQFit(FitPoint &point, const vector<FitPoint> &fvec) const
00393 {
00398
00399 point.SetQ(0.0, 0.0, point.Y(), false);
00400
00401 const map<unsigned int, double> &wmap = point.GetWeightMap();
00402
00403 double S0 = 0.0, S1 = 0.0, S2 = 0.0, S3 = 0.0, S4 = 0.0, M1 = 0.0, M2 = 0.0, M3 = 0.0;
00404 unsigned int wsize = 0;
00405
00406 for(map<unsigned int, double>::const_iterator wit = wmap.begin(); wit != wmap.end(); ++wit)
00407 {
00408 const unsigned int index = wit -> first;
00409 if(!(index < fvec.size()))
00410 {
00411 cerr << "LocalFit::RunQFit - index of FitPoint is out of range" << endl;
00412 continue;
00413 }
00414
00415 const FitPoint &fitpoint = fvec[index];
00416
00417 const double x = fitpoint.X();
00418 const double y = fitpoint.Y();
00419 const double w = wit -> second * fitpoint.Weight();
00420
00421 assert(!(fitpoint.Weight() < 0.0) && "Global weight is negative");
00422
00423
00424 if(!(w > 0.0))
00425 {
00426 continue;
00427 }
00428
00429 ++wsize;
00430
00431 double product_x = x;
00432
00433 S0 += w;
00434
00435 S1 += w * product_x;
00436
00437 product_x *= x;
00438 S2 += w * product_x;
00439
00440 product_x *= x;
00441 S3 += w * product_x;
00442
00443 product_x *= x;
00444 S4 += w * product_x;
00445
00446 double product_xy = y;
00447
00448 M1 += w * product_xy;
00449
00450 product_xy *= x;
00451 M2 += w * product_xy;
00452
00453 product_xy *= x;
00454 M3 += w * product_xy;
00455 }
00456
00457 if(wsize < 3)
00458 {
00459 cerr << "LocalFit::RunQFit - too few fit points with positive weight" << endl;
00460 for(map<unsigned int, double>::const_iterator wit = wmap.begin(); wit != wmap.end(); ++wit)
00461 {
00462 cout << " (index, weight) = (" << wit -> first << ", " << wit -> second << ")" << endl;
00463 }
00464 return false;
00465 }
00466
00467 const double det = S0*(S2*S4 - S3*S3) - S1*(S1*S4 - S2*S3) + S2*(S1*S3 - S2*S2);
00468 if(!(det > 0.0))
00469 {
00470 cerr << "LocalFit::RunQFit - quadratic fit failed for " << wsize << " points" << endl;
00471 return false;
00472 }
00473
00474 const double a = (+M1*(S1*S3 - S2*S2) - M2*(S0*S3 - S1*S2) + M3*(S0*S2 - S1*S1))/det;
00475 const double b = (-M1*(S1*S4 - S2*S3) + M2*(S0*S4 - S2*S2) - M3*(S0*S3 - S1*S2))/det;
00476 const double c = (+M1*(S2*S4 - S3*S3) - M2*(S1*S4 - S2*S3) + M3*(S1*S3 - S2*S2))/det;
00477
00478 point.SetQ(a, b, c, true);
00479
00480 return true;
00481 }
00482
00483
00484 bool Anp::LocalFit::SortCleanCheck(vector<FitPoint> &fvec) const
00485 {
00486 if(fDebug)
00487 {
00488 cout << "LocalFit::SortCleanCheck - begin..." << endl;
00489 }
00490
00491
00492
00493
00494 std::sort(fvec.begin(), fvec.end());
00495
00496
00497
00498
00499 vector<FitPoint>::iterator fit = fvec.begin();
00500 while(fit != fvec.end())
00501 {
00502 vector<FitPoint>::iterator nit = fit + 1;
00503 if(nit == fvec.end())
00504 {
00505 break;
00506 }
00507
00508 if(!(fit -> X() > nit -> X()) && !(fit -> X() < nit -> X()))
00509 {
00510 cerr << "LocalFit::SortCleanCheck - removing duplicate x: " << nit -> X() << endl;
00511 fvec.erase(nit);
00512 fit = fvec.begin();
00513 }
00514 else
00515 {
00516 ++fit;
00517 }
00518 }
00519
00520
00521
00522
00523 if(fvec.size() < fDegree + 2)
00524 {
00525 cerr << "LocalFit::SortCleanCheck - too few points for regression: " << fvec.size() << endl;
00526 return false;
00527 }
00528
00529 if(fDebug)
00530 {
00531 cout << "LocalFit::SortCleanCheck - passed" << endl;
00532 }
00533
00534 return true;
00535 }
00536
00537
00538 const Anp::LocalFit::List Anp::LocalFit::GetList(const unsigned int pos) const
00539 {
00540
00541
00542
00543
00544
00545
00546 List nlist;
00547
00548 if(pos >= fFitVec.size())
00549 {
00550 cerr << "LocalFit::GetList - position is out of range: " << pos << endl;
00551 return nlist;
00552 }
00553
00554 if(fWindow < 1)
00555 {
00556 cerr << "LocalFit::GetList - window is too small " << fWindow << endl;
00557 return nlist;
00558 }
00559
00560 const int ibeg = std::max<int>(int(pos) - int(fWindow + 0), 0);
00561 const int iend = std::min<int>(int(pos) + int(fWindow + 1), int(fFitVec.size()));
00562
00563 assert(ibeg >= 0 && iend <= int(fFitVec.size()) && "invalid range");
00564
00565 if(fDebug)
00566 {
00567 cout << "LocalFit::GetList - range for searching (ibeg, iend) = ("
00568 << ibeg << ", " << iend << ")" << endl;
00569 }
00570
00571 const FitPoint &point = fFitVec[pos];
00572
00573 for(int i = ibeg; i < iend; ++i)
00574 {
00575
00576 if(i == int(pos))
00577 {
00578 continue;
00579 }
00580
00581 const FitPoint &other = fFitVec[i];
00582 const double dist = std::fabs(point.X() - other.X());
00583
00584 if(!(dist > 0.0))
00585 {
00586 cerr << "LocalFit::GetList - ignore zero distance point" << endl;
00587 continue;
00588 }
00589
00590
00591
00592 if(!nlist.empty() && nlist.size() == fWindow && !(dist < nlist.back().second))
00593 {
00594 continue;
00595 }
00596
00597 List::iterator lit = nlist.begin();
00598 for(; lit != nlist.end(); ++lit)
00599 {
00600 if(dist < lit -> second)
00601 {
00602 break;
00603 }
00604 else
00605 {
00606 continue;
00607 }
00608 }
00609
00610 nlist.insert(lit, pair<unsigned int,double>(i, dist));
00611
00612 if(nlist.size() > fWindow)
00613 {
00614 nlist.pop_back();
00615 }
00616 }
00617
00618 if(fDebug)
00619 {
00620 cout << "LocalFit::GetList - list of " << fWindow << " neighbors" << endl;
00621 cout << " Anchor ";
00622 point.Print();
00623
00624 for(List::const_iterator lit = nlist.begin(); lit != nlist.end(); ++lit)
00625 {
00626 cout << " position = " << lit -> first << ", distance = " << lit -> second << endl;
00627 }
00628 }
00629
00630 return nlist;
00631 }
00632
00633
00634 double Anp::LocalFit::BFunction(const double value) const
00635 {
00636 if(!(std::fabs(value) < 1.0))
00637 {
00638 return 0.0;
00639 }
00640
00641 const double prod = 1.0 - value * value;
00642
00643 return (prod * prod);
00644 }
00645
00646
00647 double Anp::LocalFit::WFunction(const double value) const
00648 {
00649 const double avalue = std::fabs(value);
00650
00651 if(!(avalue < 1.0))
00652 {
00653 return 0.0;
00654 }
00655
00656 const double prod = 1.0 - avalue * avalue * avalue;
00657
00658 return (prod * prod * prod);
00659 }