Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

LocalFit.cxx

Go to the documentation of this file.
00001 // $Id: LocalFit.cxx,v 1.2 2009/02/28 21:46:15 gmieg Exp $
00002 
00003 // C++
00004 #include <algorithm>
00005 #include <cassert>
00006 #include <cmath>
00007 #include <iostream>
00008 
00009 // MINOS
00010 #include "Registry/Registry.h"
00011 
00012 // Local
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    // Fit locally data points with 2nd or 3rd degree polynomial
00050    // 
00051 
00052    if(fDebug)
00053    {
00054       cout << "LocalFit::RunFit - starting new fit" << endl;
00055    }
00056 
00057    //
00058    // Check validity of data in fit vector
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    // For each point get list of fWindow nearest points and set local weights
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       std::sort(resvec.begin(), resvec.end());
00146       const double median = resvec[resvec.size()/2];
00147 
00148       if(!(median > 0.0))
00149       {
00150          cerr << "LocalFit::RunFit - median residual is zero" << endl;
00151          return false;
00152       }      
00153       
00154       for(vector<FitPoint>::iterator fit = fFitVec.begin(); fit != fFitVec.end(); ++fit)
00155       {
00156          fit -> SetWeight(BFunction(fit -> Residual()/(6.0*median)));
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 &reg)
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       // ignore points with zero weights
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       // ignore points with zero weights
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    // Sort fit vector by x values
00493    //
00494    std::sort(fvec.begin(), fvec.end());
00495 
00496    //
00497    // Find and remove duplicate x values
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    // Check that fit vector has enough point for regression of degree fDegree
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    // Return pair of position and distance for fWindow nearest points for point at pos.
00542    // Assume that fFitVec is sorted by X values, but no assumption is made
00543    // about relative distances between X values.
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       // ignore this (anchor) point
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       // get current farthest distance from anchor point
00591       // and ignore points outside current minimum range
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 }

Generated on Mon Feb 15 11:06:53 2010 for loon by  doxygen 1.3.9.1