# go-hep/hep

Switch branches/tags
Nothing to show
Fetching contributors…
Cannot retrieve contributors at this time
311 lines (254 sloc) 6.97 KB
 // Copyright 2016 The go-hep Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package hbook import "math" // Dist0D is a 0-dim distribution. type Dist0D struct { N int64 // number of entries SumW float64 // sum of weights SumW2 float64 // sum of squared weights } // Rank returns the number of dimensions of the distribution. func (*Dist0D) Rank() int { return 1 } // Entries returns the number of entries in the distribution. func (d *Dist0D) Entries() int64 { return d.N } // EffEntries returns the number of weighted entries, such as: // (\sum w)^2 / \sum w^2 func (d *Dist0D) EffEntries() float64 { if d.SumW2 == 0 { return 0 } return d.SumW * d.SumW / d.SumW2 } // errW returns the absolute error on sumW() func (d *Dist0D) errW() float64 { return math.Sqrt(d.SumW2) } // relErrW returns the relative error on sumW() func (d *Dist0D) relErrW() float64 { // FIXME(sbinet) check for low stats ? return d.errW() / d.SumW } func (d *Dist0D) fill(w float64) { d.N++ d.SumW += w d.SumW2 += w * w } func (d *Dist0D) scaleW(f float64) { d.SumW *= f d.SumW2 *= f * f } // Dist1D is a 1-dim distribution. type Dist1D struct { Dist Dist0D // weight moments Stats struct { SumWX float64 // 1st order weighted x moment SumWX2 float64 // 2nd order weighted x moment } } // Rank returns the number of dimensions of the distribution. func (*Dist1D) Rank() int { return 1 } // Entries returns the number of entries in the distribution. func (d *Dist1D) Entries() int64 { return d.Dist.Entries() } // EffEntries returns the effective number of entries in the distribution. func (d *Dist1D) EffEntries() float64 { return d.Dist.EffEntries() } // SumW returns the sum of weights of the distribution. func (d *Dist1D) SumW() float64 { return d.Dist.SumW } // SumW2 returns the sum of squared weights of the distribution. func (d *Dist1D) SumW2() float64 { return d.Dist.SumW2 } // SumWX returns the 1st order weighted x moment. func (d *Dist1D) SumWX() float64 { return d.Stats.SumWX } // SumWX2 returns the 2nd order weighted x moment. func (d *Dist1D) SumWX2() float64 { return d.Stats.SumWX2 } // errW returns the absolute error on sumW() func (d *Dist1D) errW() float64 { return d.Dist.errW() } // relErrW returns the relative error on sumW() func (d *Dist1D) relErrW() float64 { return d.Dist.relErrW() } // mean returns the weighted mean of the distribution func (d *Dist1D) mean() float64 { // FIXME(sbinet): check for low stats? return d.SumWX() / d.SumW() } // variance returns the weighted variance of the distribution, defined as: // sig2 = ( \sum(wx^2) * \sum(w) - \sum(wx)^2 ) / ( \sum(w)^2 - \sum(w^2) ) // see: https://en.wikipedia.org/wiki/Weighted_arithmetic_mean func (d *Dist1D) variance() float64 { // FIXME(sbinet): check for low stats? sumw := d.SumW() num := d.SumWX2()*sumw - d.SumWX()*d.SumWX() den := sumw*sumw - d.SumW2() v := num / den return math.Abs(v) } // stdDev returns the weighted standard deviation of the distribution func (d *Dist1D) stdDev() float64 { return math.Sqrt(d.variance()) } // stdErr returns the weighted standard error of the distribution func (d *Dist1D) stdErr() float64 { // FIXME(sbinet): check for low stats? // TODO(sbinet): unbiased should check that Neff>1 and divide by N-1? return math.Sqrt(d.variance() / d.EffEntries()) } // rms returns the weighted RMS of the distribution, defined as: // rms = \sqrt{\sum{w . x^2} / \sum{w}} func (d *Dist1D) rms() float64 { // FIXME(sbinet): check for low stats? meansq := d.SumWX2() / d.SumW() return math.Sqrt(meansq) } func (d *Dist1D) fill(x, w float64) { d.Dist.fill(w) d.Stats.SumWX += w * x d.Stats.SumWX2 += w * x * x } func (d *Dist1D) scaleW(f float64) { d.Dist.scaleW(f) d.Stats.SumWX *= f d.Stats.SumWX2 *= f } func (d *Dist1D) scaleX(f float64) { d.Stats.SumWX *= f d.Stats.SumWX2 *= f * f } // Dist2D is a 2-dim distribution. type Dist2D struct { X Dist1D // x moments Y Dist1D // y moments Stats struct { SumWXY float64 // 2nd-order cross-term } } // Rank returns the number of dimensions of the distribution. func (*Dist2D) Rank() int { return 2 } // Entries returns the number of entries in the distribution. func (d *Dist2D) Entries() int64 { return d.X.Entries() } // EffEntries returns the effective number of entries in the distribution. func (d *Dist2D) EffEntries() float64 { return d.X.EffEntries() } // SumW returns the sum of weights of the distribution. func (d *Dist2D) SumW() float64 { return d.X.SumW() } // SumW2 returns the sum of squared weights of the distribution. func (d *Dist2D) SumW2() float64 { return d.X.SumW2() } // SumWX returns the 1st order weighted x moment func (d *Dist2D) SumWX() float64 { return d.X.SumWX() } // SumWX2 returns the 2nd order weighted x moment func (d *Dist2D) SumWX2() float64 { return d.X.SumWX2() } // SumWY returns the 1st order weighted y moment func (d *Dist2D) SumWY() float64 { return d.Y.SumWX() } // SumWY2 returns the 2nd order weighted y moment func (d *Dist2D) SumWY2() float64 { return d.Y.SumWX2() } // SumWXY returns the 2nd-order cross-term. func (d *Dist2D) SumWXY() float64 { return d.Stats.SumWXY } // errW returns the absolute error on sumW() func (d *Dist2D) errW() float64 { return d.X.errW() } // relErrW returns the relative error on sumW() func (d *Dist2D) relErrW() float64 { return d.X.relErrW() } // xMean returns the weighted mean of the distribution func (d *Dist2D) xMean() float64 { return d.X.mean() } // yMean returns the weighted mean of the distribution func (d *Dist2D) yMean() float64 { return d.Y.mean() } // xVariance returns the weighted variance of the distribution func (d *Dist2D) xVariance() float64 { return d.X.variance() } // yVariance returns the weighted variance of the distribution func (d *Dist2D) yVariance() float64 { return d.Y.variance() } // xStdDev returns the weighted standard deviation of the distribution func (d *Dist2D) xStdDev() float64 { return d.X.stdDev() } // yStdDev returns the weighted standard deviation of the distribution func (d *Dist2D) yStdDev() float64 { return d.Y.stdDev() } // xStdErr returns the weighted standard error of the distribution func (d *Dist2D) xStdErr() float64 { return d.X.stdErr() } // yStdErr returns the weighted standard error of the distribution func (d *Dist2D) yStdErr() float64 { return d.Y.stdErr() } // xRMS returns the weighted RMS of the distribution func (d *Dist2D) xRMS() float64 { return d.X.rms() } // yRMS returns the weighted RMS of the distribution func (d *Dist2D) yRMS() float64 { return d.Y.rms() } func (d *Dist2D) fill(x, y, w float64) { d.X.fill(x, w) d.Y.fill(y, w) d.Stats.SumWXY += w * x * y } func (d *Dist2D) scaleW(f float64) { d.X.scaleW(f) d.Y.scaleW(f) d.Stats.SumWXY *= f } func (d *Dist2D) scaleX(f float64) { d.X.scaleX(f) d.Stats.SumWXY *= f } func (d *Dist2D) scaleY(f float64) { d.Y.scaleX(f) d.Stats.SumWXY *= f } func (d *Dist2D) scaleXY(fx, fy float64) { d.scaleX(fx) d.scaleY(fy) }