#include "Riostream.h"
#include "TMath.h"
#include "TGraphSmooth.h"
#include "TGraphErrors.h"
ClassImp(TGraphSmooth);
TGraphSmooth::TGraphSmooth(): TNamed()
{
   fGin  = 0;
   fGout = 0;
}
TGraphSmooth::TGraphSmooth(const char *name): TNamed(name,"")
{
   fGin  = 0;
   fGout = 0;
}
TGraphSmooth::~TGraphSmooth()
{
   if (fGout) delete fGout;
   fGin  = 0;
   fGout = 0;
}
void TGraphSmooth::Smoothin(TGraph *grin)
{
   if (fGout) {delete fGout; fGout = 0;}
   fGin = grin;
   fNin = fGin->GetN();
   Double_t *xin = new Double_t[fNin];
   Double_t *yin = new Double_t[fNin];
   Int_t i;
   for (i=0;i<fNin;i++) {
      xin[i] = fGin->GetX()[i];
      yin[i] = fGin->GetY()[i];
   }
   Int_t *index = new Int_t[fNin];
   TMath::Sort(fNin, xin, index, kFALSE);
   for (i=0;i<fNin;i++) {
      fGin->SetPoint(i, xin[index[i]], yin[index[i]]);
   }
   fMinX = fGin->GetX()[0];  
   fMaxX = fGin->GetX()[fNin-1];
   delete [] index;
   delete [] xin;
   delete [] yin;
}
TGraph *TGraphSmooth::SmoothKern(TGraph *grin, Option_t *option,
                      Double_t bandwidth, Int_t nout, Double_t *xout)
{
   TString opt = option;
   opt.ToLower();
   Int_t kernel = 1;
   if (opt.Contains("normal")) kernel = 2;
   Smoothin(grin);
   Double_t delta = 0;
   Int_t *index = 0;
   if (xout == 0) {
      fNout = TMath::Max(nout, fNin);
      delta = (fMaxX - fMinX)/(fNout - 1);
   } else {
      fNout = nout;
      index = new Int_t[nout];
      TMath::Sort(nout, xout, index, kFALSE);
   }
   fGout = new TGraph(fNout);
   for (Int_t i=0;i<fNout;i++) {
      if (xout == 0) fGout->SetPoint(i,fMinX + i*delta, 0);
      else           fGout->SetPoint(i,xout[index[i]], 0);
   }
   BDRksmooth(fGin->GetX(), fGin->GetY(), fNin, fGout->GetX(),
                 fGout->GetY(), fNout, kernel, bandwidth);
   if (index) {delete [] index; index = 0;}
   return fGout;
}
void TGraphSmooth::BDRksmooth(Double_t *x, Double_t *y, Int_t n, Double_t *xp,
                   Double_t *yp, Int_t np, Int_t kernel, Double_t bw)
{
   Int_t    imin = 0;
   Double_t cutoff = 0.0;
   if (kernel == 1) {
      bw *= 0.5;
      cutoff = bw;
   }
   if (kernel == 2) {
      bw *= 0.3706506;
      cutoff = 4*bw;
   }
   while ((x[imin] < xp[0] - cutoff) && (imin < n)) imin++;
   for (Int_t j=0;j<np;j++) {
      Double_t xx, w;
      Double_t num = 0.0;
      Double_t den = 0.0;
      Double_t x0 = xp[j];
      for (Int_t i=imin;i<n;i++) {
         if (x[i] < x0 - cutoff) imin = i;
         if (x[i] > x0 + cutoff) break;
         xx = TMath::Abs(x[i] - x0)/bw;
         if (kernel == 1) w = 1;
         else             w = TMath::Exp(-0.5*xx*xx);
         num += w*y[i];
         den += w;
      }
      if (den > 0) {
         yp[j] = num/den;
      } else {
         yp[j] = 0; 
      }
   }
}
TGraph *TGraphSmooth::SmoothLowess(TGraph *grin, Option_t *option ,
                      Double_t span, Int_t iter, Double_t delta)
{
   TString opt = option;
   opt.ToLower();
   Smoothin(grin);
   if (delta == 0) {delta = 0.01*(TMath::Abs(fMaxX - fMinX));}
   fNout = fNin;
   fGout = new TGraphErrors(fNout);
   for (Int_t i=0;i<fNout;i++) {
      fGout->SetPoint(i,fGin->GetX()[i], 0);
   }
   Lowess(fGin->GetX(), fGin->GetY(), fNin, fGout->GetY(), span, iter, delta);
   return fGout;
}
void TGraphSmooth::Lowess(Double_t *x, Double_t *y, Int_t n, Double_t *ys,
                   Double_t span, Int_t iter, Double_t delta)
{
   Int_t    i, iiter, j, last, m1, m2, nleft, nright, ns;
   Double_t alpha, c1, c9, cmad, cut, d1, d2, denom, r;
   Bool_t   ok;
   if (n < 2) {
      ys[0] = y[0];
      return;
   }
   x--;
   y--;
   ys--;
   Double_t *rw  = ((TGraphErrors*)fGout)->GetEX();
   Double_t *res = ((TGraphErrors*)fGout)->GetEY();
   ns = TMath::Max(2, TMath::Min(n, (Int_t)(span*n + 1e-7)));
   iiter = 1;
   while (iiter <= iter+1) {
      nleft = 1;
      nright = ns;
      last = 0;   
      i = 1;      
      for(;;) {
         if (nright < n) {
         
            d1 = x[i] - x[nleft];
            d2 = x[nright+1] - x[i];
         
            if (d1 > d2) {
            
               nleft++;
               nright++;
               continue;
            }
         }
      
         Bool_t iterg1 = iiter>1;
         Lowest(&x[1], &y[1], n, x[i], ys[i], nleft, nright,
                      res, iterg1, rw, ok);
         if (!ok) ys[i] = y[i];
      
         if (last < i-1) {
            denom = x[i]-x[last];
         
            for(j = last+1; j < i; j++) {
               alpha = (x[j]-x[last])/denom;
               ys[j] = alpha*ys[i] + (1.-alpha)*ys[last];
            }
      }
      
         last = i;
      
         cut = x[last] + delta;
         for (i = last+1; i <= n; i++) {
            if (x[i] > cut)
               break;
            if (x[i] == x[last]) {
               ys[i] = ys[last];
               last = i;
            }
         }
         i = TMath::Max(last+1, i-1);
         if (last >= n)
            break;
      }
   
      for(i=0; i < n; i++)
         res[i] = y[i+1] - ys[i+1];
   
      if (iiter > iter)
         break;
      for(i=0 ; i<n ; i++)
         rw[i] = TMath::Abs(res[i]);
   
      m1 = n/2;
   
      Psort(rw, n, m1);
      if(n % 2 == 0) {
         m2 = n-m1-1;
         Psort(rw, n, m2);
         cmad = 3.*(rw[m1]+rw[m2]);
      } else { 
         cmad = 6.*rw[m1];
      }
      c9 = 0.999*cmad;
      c1 = 0.001*cmad;
      for(i=0 ; i<n ; i++) {
         r = TMath::Abs(res[i]);
         if (r <= c1)
            rw[i] = 1.;
         else if (r <= c9)
            rw[i] = (1.-(r/cmad)*(r/cmad))*(1.-(r/cmad)*(r/cmad));
         else
            rw[i] = 0.;
      }
      iiter++;
   }
}
void TGraphSmooth::Lowest(Double_t *x, Double_t *y, Int_t n, Double_t &xs,
                   Double_t &ys, Int_t nleft, Int_t nright, Double_t *w,
                   Bool_t userw, Double_t *rw, Bool_t &ok)
{
   Int_t    nrt, j;
   Double_t a, b, c, d, h, h1, h9, r, range;
   x--;
   y--;
   w--;
   rw--;
   range = x[n]-x[1];
   h = TMath::Max(xs-x[nleft], x[nright]-xs);
   h9 = 0.999*h;
   h1 = 0.001*h;
   a = 0.;
   j = nleft;
   while (j <= n) {
   
      w[j] = 0.;
      r = TMath::Abs(x[j] - xs);
      if (r <= h9) {
         if (r <= h1) {
            w[j] = 1.;
         } else {
            d = (r/h)*(r/h)*(r/h);
            w[j] = (1.- d)*(1.- d)*(1.- d);
         }
         if (userw)
            w[j] *= rw[j];
         a += w[j];
      } else if (x[j] > xs)
         break;
      j = j+1;
   }
   nrt = j-1;
   if (a <= 0.)
      ok = kFALSE;
   else {
      ok = kTRUE;
   
      for(j=nleft ; j<=nrt ; j++)
         w[j] /= a;
      if (h > 0.) {
         a = 0.;
      
         for(j=nleft ; j<=nrt ; j++)
            a += w[j] * x[j];
         b = xs - a;
         c = 0.;
         for(j=nleft ; j<=nrt ; j++)
            c += w[j]*(x[j]-a)*(x[j]-a);
         if (TMath::Sqrt(c) > 0.001*range) {
            b /= c;
         
            for(j=nleft; j <= nrt; j++)
               w[j] *= (b*(x[j]-a) + 1.);
         }
      }
      ys = 0.;
      for(j=nleft; j <= nrt; j++)
         ys += w[j] * y[j];
   }
}
TGraph *TGraphSmooth::SmoothSuper(TGraph *grin, Option_t *,
        Double_t bass, Double_t span, Bool_t isPeriodic, Double_t *w)
{
   if (span < 0 || span > 1) {
      cout << "Error: Span must be between 0 and 1" << endl;
      return 0;
   }
   Smoothin(grin);
   Int_t iper = 1;
   if (isPeriodic) {
      iper = 2;
      if (fMinX < 0 || fMaxX > 1) {
         cout << "Error: x must be between 0 and 1 for periodic smooth" << endl;
         return 0;
      }
   }
   fNout = fNin;
   fGout = new TGraph(fNout);
   Int_t i;
   for (i=0; i<fNout; i++) {
      fGout->SetPoint(i,fGin->GetX()[i], 0);
   }
   Double_t *weight = new Double_t[fNin];
   for (i=0; i<fNin; i++) {
      if (w == 0) weight[i] = 1;
      else        weight[i] = w[i];
   }
   Int_t nTmp = (fNin+1)*8;
   Double_t *tmp = new Double_t[nTmp];
   for (i=0; i<nTmp; i++) {
      tmp[i] = 0;
   }
   BDRsupsmu(fNin, fGin->GetX(), fGin->GetY(), weight, iper, span, bass, fGout->GetY(), tmp);
   delete [] tmp;
   delete [] weight;
   return fGout;
}
void TGraphSmooth::BDRsupsmu(Int_t n, Double_t *x, Double_t *y, Double_t *w,
     Int_t iper, Double_t span, Double_t alpha, Double_t *smo, Double_t *sc)
{
   Int_t sc_offset;
   Int_t i, j, jper;
   Double_t a, f;
   Double_t sw, sy, resmin, vsmlsq;
   Double_t scale;
   Double_t d1, d2;
   Double_t spans[3] = { 0.05, 0.2, 0.5 };
   Double_t big = 1e20;
   Double_t sml = 1e-7;
   Double_t eps = 0.001;
   sc_offset = n + 1;
   sc -= sc_offset;
   --smo;
   --w;
   --y;
   --x;
   if (x[n] <= x[1]) {
      sy = 0.0;
      sw = sy;
      for (j=1;j<=n;++j) {
         sy += w[j] * y[j];
         sw += w[j];
      }
      a = 0.0;
      if (sw > 0.0) a = sy / sw;
      for (j=1;j<=n;++j) smo[j] = a;
      return;
   }
   i = (Int_t)(n / 4);
   j = i * 3;
   scale = x[j] - x[i];
   while (scale <= 0.0) {
      if (j < n) ++j;
      if (i > 1) --i;
      scale = x[j] - x[i];
   }
   d1 = eps * scale;
   vsmlsq = d1 * d1;
   jper = iper;
   if (iper == 2 && (x[1] < 0.0 || x[n] > 1.0)) {
      jper = 1;
   }
   if (jper < 1 || jper > 2) {
      jper = 1;
   }
   if (span > 0.0) {
      BDRsmooth(n, &x[1], &y[1], &w[1], span, jper, vsmlsq,
                      &smo[1], &sc[sc_offset]);
      return;
   }
   Double_t *h = new Double_t[n+1];
   for (i = 1; i <= 3; ++i) {
      BDRsmooth(n, &x[1], &y[1], &w[1], spans[i - 1], jper, vsmlsq,
                      &sc[((i<<1)-1)*n + 1], &sc[n*7 + 1]);
      BDRsmooth(n, &x[1], &sc[n*7 + 1], &w[1], spans[1], -jper, vsmlsq,
                      &sc[(i<<1)*n + 1], &h[1]);
   }
   for (j=1; j<=n; ++j) {
      resmin = big;
      for (i=1; i<=3; ++i) {
         if (sc[j + (i<<1)*n] < resmin) {
            resmin = sc[j + (i<<1)*n];
            sc[j + n*7] = spans[i-1];
         }
      }
      if (alpha>0.0 && alpha<=10.0 && resmin<sc[j + n*6]  && resmin>0.0) {
      
         d1 = TMath::Max(sml,(resmin/sc[j + n*6]));
         d2 = 10. - alpha;
         sc[j + n*7] += (spans[2] - sc[j + n*7]) * TMath::Power(d1, d2);
      }
   }
   BDRsmooth(n, &x[1], &sc[n*7 + 1], &w[1], spans[1], -jper, vsmlsq,
                   &sc[(n<<1) + 1], &h[1]);
   for (j=1; j<=n; ++j) {
      if (sc[j + (n<<1)] <= spans[0]) {
         sc[j + (n<<1)] = spans[0];
      }
      if (sc[j + (n<<1)] >= spans[2]) {
         sc[j + (n<<1)] = spans[2];
      }
      f = sc[j + (n<<1)] - spans[1];
      if (f < 0.0) {
         f = -f / (spans[1] - spans[0]);
         sc[j + (n<<2)] = (1.0 - f) * sc[j + n*3] + f * sc[j + n];
      } else {
         f /= spans[2] - spans[1];
         sc[j + (n<<2)] = (1.0 - f) * sc[j + n*3] + f * sc[j + n*5];
      }
   }
   BDRsmooth(n, &x[1], &sc[(n<<2) + 1], &w[1], spans[0], -jper, vsmlsq,
                   &smo[1], &h[1]);
   delete [] h;
   return;
}
void TGraphSmooth::BDRsmooth(Int_t n, Double_t *x, Double_t *y, Double_t *w,
     Double_t span, Int_t iper, Double_t vsmlsq, Double_t *smo, Double_t *acvr)
{
   Int_t i, j, j0, in, out, it, jper, ibw;
   Double_t a, h1, d1;
   Double_t xm, ym, wt, sy, fbo, fbw;
   Double_t cvar, var, tmp, xti, xto;
   --acvr;
   --smo;
   --w;
   --y;
   --x;
   xm = 0.;
   ym = xm;
   var = ym;
   cvar = var;
   fbw = cvar;
   jper = TMath::Abs(iper);
   ibw = (Int_t)(span * 0.5 * n + 0.5);
   if (ibw < 2) {
      ibw = 2;
   }
   it = 2*ibw + 1;
   for (i=1; i<=it; ++i) {
      j = i;
      if (jper == 2) {
         j = i - ibw - 1;
      }
      xti = x[j];
      if (j < 1) {
         j = n + j;
         xti = x[j] - 1.0;
      }
      wt = w[j];
      fbo = fbw;
      fbw += wt;
      if (fbw > 0.0) {
         xm = (fbo * xm + wt * xti) / fbw;
         ym = (fbo * ym + wt * y[j]) / fbw;
      }
      tmp = 0.0;
      if (fbo > 0.0) {
         tmp = fbw * wt * (xti - xm) / fbo;
      }
      var += tmp * (xti - xm);
      cvar += tmp * (y[j] - ym);
   }
   for (j=1; j<=n; ++j) {
      out = j - ibw - 1;
      in = j + ibw;
      if (!(jper != 2 && (out < 1 || in > n))) {
         if (out < 1) {
            out = n + out;
            xto = x[out] - 1.0;
            xti = x[in];
         } else if (in > n) {
            in -= n;
            xti = x[in] + 1.0;
            xto = x[out];
         } else {
            xto = x[out];
            xti = x[in];
         }
         wt = w[out];
         fbo = fbw;
         fbw -= wt;
         tmp = 0.0;
         if (fbw > 0.0) {
            tmp = fbo * wt * (xto - xm) / fbw;
         }
         var -= tmp * (xto - xm);
         cvar -= tmp * (y[out] - ym);
         if (fbw > 0.0) {
            xm = (fbo * xm - wt * xto) / fbw;
            ym = (fbo * ym - wt * y[out]) / fbw;
         }
         wt = w[in];
         fbo = fbw;
         fbw += wt;
         if (fbw > 0.0) {
            xm = (fbo * xm + wt * xti) / fbw;
            ym = (fbo * ym + wt * y[in]) / fbw;
         }
         tmp = 0.0;
         if (fbo > 0.0) {
            tmp = fbw * wt * (xti - xm) / fbo;
         }
         var += tmp * (xti - xm);
         cvar += tmp * (y[in] - ym);
      }
      a = 0.0;
      if (var > vsmlsq) {
         a = cvar / var;
      }
      smo[j] = a * (x[j] - xm) + ym;
      if (iper <= 0) {
         continue;
      }
      h1 = 0.0;
      if (fbw > 0.0) {
         h1 = 1.0 / fbw;
      }
      if (var > vsmlsq) {
      
         d1 = x[j] - xm;
         h1 += d1 * d1 / var;
      }
      acvr[j] = 0.0;
      a = 1.0 - w[j] * h1;
      if (a > 0.0) {
         acvr[j] = TMath::Abs(y[j] - smo[j]) / a;
         continue;
      }
      if (j > 1) {
         acvr[j] = acvr[j-1];
      }
   }
   j = 1;
   do {
      j0 = j;
      sy = smo[j] * w[j];
      fbw = w[j];
      if (j < n) {
         do {
            if (x[j + 1] > x[j]) {
               break;
            }
            ++j;
            sy += w[j] * smo[j];
            fbw += w[j];
         } while (j < n);
      }
      if (j > j0) {
         a = 0.0;
         if (fbw > 0.0) {
            a = sy / fbw;
         }
         for (i=j0; i<=j; ++i) {
            smo[i] = a;
         }
      }
      ++j;
   } while (j <= n);
   return;
}
void TGraphSmooth::Approxin(TGraph *grin, Int_t , Double_t &ylow,
     Double_t &yhigh, Int_t rule, Int_t iTies)
{
   if (fGout) {delete fGout; fGout = 0;}
   fGin = grin;
   fNin = fGin->GetN();
   Double_t *xin = new Double_t[fNin];
   Double_t *yin = new Double_t[fNin];
   Int_t i;
   for (i=0;i<fNin;i++) {
      xin[i] = fGin->GetX()[i];
      yin[i] = fGin->GetY()[i];
   }
   Int_t *index = new Int_t[fNin];
   Int_t *rank  = new Int_t[fNin];
   Rank(fNin, xin, index, rank, kFALSE);
   Int_t vNDup = 0;
   Int_t k = 0;
   Int_t *dup = new Int_t[fNin];
   Double_t *x = new Double_t[fNin];
   Double_t *y = new Double_t[fNin];
   Double_t vMean, vMin, vMax;
   for (i=1;i<fNin+1;i++) {
      Int_t ndup = 1;
      vMin = vMean = vMax = yin[index[i-1]];
      while ((i < fNin) && (rank[index[i]] == rank[index[i-1]])) {
         vMean += yin[index[i]];
         vMax = (vMax < yin[index[i]]) ? yin[index[i]] : vMax;
         vMin = (vMin > yin[index[i]]) ? yin[index[i]] : vMin;
         dup[vNDup] = i;
         i++;
         ndup++;
         vNDup++;
      }
      x[k] = xin[index[i-1]];
      if (ndup == 1) {y[k++] = yin[index[i-1]];}
      else switch(iTies) {
         case 1:
            y[k++] = vMean/ndup;
            break;
         case 2:
            y[k++] = vMin;
            break;
         case 3:
            y[k++] = vMax;
            break;
         default:
            y[k++] = vMean/ndup;
            break;
      }
   }
   fNin = k;
   fGin->Set(fNin);
   for (i=0;i<fNin;i++) {
      fGin->SetPoint(i, x[i], y[i]);
   }
   fMinX = fGin->GetX()[0];  
   fMaxX = fGin->GetX()[fNin-1];
   switch(rule) {
      case 1:
         ylow  = 0;   
         yhigh = 0;   
         break;
      case 2:
         ylow  = fGin->GetY()[0];
         yhigh = fGin->GetY()[fNin-1];
         break;
      default:
         break;
   }
   delete [] x;
   delete [] y;
   delete [] dup;
   delete [] rank;
   delete [] index;
   delete [] xin;
   delete [] yin;
}
TGraph *TGraphSmooth::Approx(TGraph *grin, Option_t *option, Int_t nout, Double_t *xout,
        Double_t yleft, Double_t yright, Int_t rule, Double_t f, Option_t *ties)
{
   TString opt = option;
   opt.ToLower();
   Int_t iKind = 0;
   if (opt.Contains("linear")) iKind = 1;
   else if (opt.Contains("constant")) iKind = 2;
   if (f < 0 || f > 1) {
      cout << "Error: Invalid f value" << endl;
      return 0;
   }
   opt = ties;
   opt.ToLower();
   Int_t iTies = 0;
   if (opt.Contains("ordered")) {
      iTies = 0;
   } else if (opt.Contains("mean")) {
      iTies = 1;
   } else if (opt.Contains("min")) {
      iTies = 2;
   } else if (opt.Contains("max")) {
      iTies = 3;
   } else {
      cout << "Error: Method not known: " << ties << endl;
      return 0;
   }
   Double_t ylow  = yleft;
   Double_t yhigh = yright;
   Approxin(grin, iKind, ylow, yhigh, rule, iTies);
   Double_t delta = 0;
   fNout = nout;
   if (xout == 0) {
      fNout = TMath::Max(nout, fNin);
      delta = (fMaxX - fMinX)/(fNout - 1);
   }
   fGout = new TGraph(fNout);
   Double_t x;
   for (Int_t i=0;i<fNout;i++) {
      if (xout == 0) x = fMinX + i*delta;
      else           x = xout[i];
      Double_t yout = Approx1(x, f, fGin->GetX(), fGin->GetY(), fNin, iKind, ylow, yhigh);
      fGout->SetPoint(i,x, yout);
   }
   return fGout;
}
Double_t TGraphSmooth::Approx1(Double_t v, Double_t f, Double_t *x, Double_t *y,
         Int_t n, Int_t iKind, Double_t ylow, Double_t yhigh)
{
   Int_t i = 0;
   Int_t j = n - 1;
   if(v < x[i]) return ylow;
   if(v > x[j]) return yhigh;
   while(i < j - 1) {
      Int_t ij = (i + j)/2;
      if(v < x[ij]) j = ij;
      else i = ij;
   }
   if(v == x[j]) return y[j];
   if(v == x[i]) return y[i];
   if(iKind == 1) { 
      return y[i] + (y[j] - y[i]) * ((v - x[i])/(x[j] - x[i]));
   } else { 
      return y[i] * (1-f) + y[j] * f;
   }
}
Int_t TGraphSmooth::Rcmp(Double_t x, Double_t y)
{
   if (x < y)      return -1;
   if (x > y)      return 1;
   return 0;
}
void TGraphSmooth::Psort(Double_t *x, Int_t n, Int_t k)
{
   Double_t v, w;
   Int_t pL, pR, i, j;
   for (pL = 0, pR = n - 1; pL < pR; ) {
      v = x[k];
      for(i = pL, j = pR; i <= j;) {
         while (TGraphSmooth::Rcmp(x[i], v) < 0) i++;
         while (TGraphSmooth::Rcmp(v, x[j]) < 0) j--;
         if (i <= j) { w = x[i]; x[i++] = x[j]; x[j--] = w; }
      }
      if (j < k) pL = i;
      if (k < i) pR = j;
   }
}
void TGraphSmooth::Rank(Int_t n, Double_t *a, Int_t *index, Int_t *rank, Bool_t down)
{
   if (n <= 0) return;
   if (n == 1) {
      index[0] = 0;
      rank[0] = 0;
      return;
   }
   TMath::Sort(n,a,index,down);
   Int_t k = 0;
   for (Int_t i=0;i<n;i++) {
      if ((i > 0) && (a[index[i]] == a[index[i-1]])) {
         rank[index[i]] = i-1;
         k++;
      }
      rank[index[i]] = i-k;
   }
}
Last change: Tue Jul  8 16:57:18 2008
Last generated: 2008-07-08 16:57
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.