func testDerivParam(t *testing.T, d derivParamTester) { // Tests that the derivative matches for a number of different quantiles // along the distribution. nTest := 10 quantiles := make([]float64, nTest) floats.Span(quantiles, 0.1, 0.9) deriv := make([]float64, d.NumParameters()) fdDeriv := make([]float64, d.NumParameters()) initParams := d.parameters(nil) init := make([]float64, d.NumParameters()) for i, v := range initParams { init[i] = v.Value } for _, v := range quantiles { d.setParameters(initParams) x := d.Quantile(v) d.DLogProbDParam(x, deriv) f := func(p []float64) float64 { params := d.parameters(nil) for i, v := range p { params[i].Value = v } d.setParameters(params) return d.LogProb(x) } fd.Gradient(fdDeriv, f, init, nil) if !floats.EqualApprox(deriv, fdDeriv, 1e-6) { t.Fatal("Derivative mismatch. Want", fdDeriv, ", got", deriv, ".") } } }
func ExampleHistogram() { x := make([]float64, 101) for i := range x { x[i] = 1.1 * float64(i) // x data ranges from 0 to 110 } dividers := []float64{7, 20, 100, 1000} fmt.Println(`Histogram counts the amount of data in the bins specified by the dividers. In this data set, there are 7 data points less than 7 (dividers[0]), 12 data points between 7 and 20 (dividers[2] and dividers[1]), and 0 data points above 1000. Since dividers has length 4, there will be 5 bins.`) hist := Histogram(nil, dividers, x, nil) fmt.Printf("Hist = %v\n", hist) fmt.Println() fmt.Println("For ease, the floats Span function can be used to set the dividers") nBins := 10 // Create one fewer divider than bins, but add two to work with Span (see // note below) dividers = make([]float64, nBins+1) min, _ := floats.Min(x) max, _ := floats.Max(x) floats.Span(dividers, min, max) // Span includes the min and the max. Trim the dividers to create 10 buckets dividers = dividers[1 : len(dividers)-1] fmt.Println("len dividers = ", len(dividers)) hist = Histogram(nil, dividers, x, nil) fmt.Printf("Hist = %v\n", hist) fmt.Println() fmt.Println(`Histogram also works with weighted data, and allows reusing of the count field in order to avoid extra garbage`) weights := make([]float64, len(x)) for i := range weights { weights[i] = float64(i + 1) } Histogram(hist, dividers, x, weights) fmt.Printf("Weighted Hist = %v\n", hist) // Output: // Histogram counts the amount of data in the bins specified by // the dividers. In this data set, there are 7 data points less than 7 (dividers[0]), // 12 data points between 7 and 20 (dividers[2] and dividers[1]), and 0 data points // above 1000. Since dividers has length 4, there will be 5 bins. // Hist = [7 12 72 10 0] // // For ease, the floats Span function can be used to set the dividers // len dividers = 9 // Hist = [11 10 10 10 9 11 10 10 9 11] // // Histogram also works with weighted data, and allows reusing of // the count field in order to avoid extra garbage // Weighted Hist = [77 175 275 375 423 627 675 775 783 1067] }
func ExampleHistogram() { x := make([]float64, 101) for i := range x { x[i] = 1.1 * float64(i) // x data ranges from 0 to 110 } dividers := []float64{0, 7, 20, 100, 1000} fmt.Println(`Histogram counts the amount of data in the bins specified by the dividers. In this data set, there are 7 data points less than 7 (between dividers[0] and dividers[1]), 12 data points between 7 and 20 (dividers[1] and dividers[2]), and 0 data points above 1000. Since dividers has length 5, there will be 4 bins.`) hist := Histogram(nil, dividers, x, nil) fmt.Printf("Hist = %v\n", hist) fmt.Println() fmt.Println("For ease, the floats Span function can be used to set the dividers") nBins := 10 dividers = make([]float64, nBins+1) min := floats.Min(x) max := floats.Max(x) // Increase the maximum divider so that the maximum value of x is contained // within the last bucket. max += 1 floats.Span(dividers, min, max) // Span includes the min and the max. Trim the dividers to create 10 buckets hist = Histogram(nil, dividers, x, nil) fmt.Printf("Hist = %v\n", hist) fmt.Println() fmt.Println(`Histogram also works with weighted data, and allows reusing of the count field in order to avoid extra garbage`) weights := make([]float64, len(x)) for i := range weights { weights[i] = float64(i + 1) } Histogram(hist, dividers, x, weights) fmt.Printf("Weighted Hist = %v\n", hist) // Output: // Histogram counts the amount of data in the bins specified by // the dividers. In this data set, there are 7 data points less than 7 (between dividers[0] // and dividers[1]), 12 data points between 7 and 20 (dividers[1] and dividers[2]), // and 0 data points above 1000. Since dividers has length 5, there will be 4 bins. // Hist = [7 12 72 10] // // For ease, the floats Span function can be used to set the dividers // Hist = [11 10 10 10 10 10 10 10 10 10] // // Histogram also works with weighted data, and allows reusing of // the count field in order to avoid extra garbage // Weighted Hist = [66 165 265 365 465 565 665 765 865 965] }
func ExampleSingle() { fmt.Println("Create a grid using Span") grid := make([]float64, 3) floats.Span(grid, 0, 1) fmt.Println("grid =", grid) pts := meshgrid.Single(3, grid) fmt.Println("Generated points:") for _, v := range pts { fmt.Println(v) } // Output: // Create a grid using Span // grid = [0 0.5 1] // Generated points: // [0 0 0] // [0 0 0.5] // [0 0 1] // [0 0.5 0] // [0 0.5 0.5] // [0 0.5 1] // [0 1 0] // [0 1 0.5] // [0 1 1] // [0.5 0 0] // [0.5 0 0.5] // [0.5 0 1] // [0.5 0.5 0] // [0.5 0.5 0.5] // [0.5 0.5 1] // [0.5 1 0] // [0.5 1 0.5] // [0.5 1 1] // [1 0 0] // [1 0 0.5] // [1 0 1] // [1 0.5 0] // [1 0.5 0.5] // [1 0.5 1] // [1 1 0] // [1 1 0.5] // [1 1 1] }
// checkProbQuantContinuous checks that the Prob, Rand, and Quantile are all consistent. // checkProbContinuous only checks that Prob is a valid distribution (integrates // to 1 and greater than 0). However, this is also true if the PDF of a different // distribution is used. This checks that PDF is also consistent with the // CDF implementation and the random samples. func checkProbQuantContinuous(t *testing.T, i int, xs []float64, c cumulantProber, tol float64) { ps := make([]float64, 101) floats.Span(ps, 0, 1) var xp, x float64 for i, p := range ps { x = c.Quantile(p) if p == 0 { xp = x if floats.Min(xs) < x { t.Errorf("Sample of x less than Quantile(0). Case %v.", i) break } continue } if p == 1 { if floats.Max(xs) > x { t.Errorf("Sample of x greater than Quantile(1). Case %v.", i) break } } // The integral of the PDF between xp and x should be the difference in // the quantiles. q := quad.Fixed(c.Prob, xp, x, 1000, nil, 0) if math.Abs(q-(p-ps[i-1])) > 1e-10 { t.Errorf("Integral of PDF doesn't match quantile. Case %v. Want %v, got %v.", i, p-ps[i-1], q) break } pEst := stat.CDF(x, stat.Empirical, xs, nil) if math.Abs(pEst-p) > tol { t.Errorf("Empirical CDF doesn't match quantile. Case %v.", i) } xp = x } }
// testFullDist tests all of the functions of a fullDist. func testFullDist(t *testing.T, f fullDist, i int) { tol := 1e-1 const n = 1e6 xs := make([]float64, n) for i := range xs { xs[i] = f.Rand() } sortedXs := make([]float64, n) copy(sortedXs, xs) sort.Float64s(sortedXs) tmp := make([]float64, n) // Mean check. mean := stat.Mean(xs, nil) if !floats.EqualWithinAbsOrRel(mean, f.Mean(), tol, tol) { t.Errorf("Mean mismatch case %v: want: %v, got: %v", i, mean, f.Mean()) } else { mean = f.Mean() } // Median check. median := stat.Quantile(0.5, stat.Empirical, sortedXs, nil) if !floats.EqualWithinAbsOrRel(median, f.Median(), tol, tol) { t.Errorf("Median mismatch case %v: want: %v, got: %v", i, median, f.Median()) } // Variance check. variance := stat.Variance(xs, nil) if !floats.EqualWithinAbsOrRel(variance, f.Variance(), tol, tol) { t.Errorf("Variance mismatch case %v: want: %v, got: %v", i, mean, f.Variance()) } else { variance = f.Variance() } std := math.Sqrt(variance) if !floats.EqualWithinAbsOrRel(std, f.StdDev(), tol, tol) { t.Errorf("StdDev mismatch case %v: want: %v, got: %v", i, mean, f.StdDev()) } else { std = f.StdDev() } // Entropy check. for i, x := range xs { tmp[i] = -f.LogProb(x) } entropy := stat.Mean(tmp, nil) if !floats.EqualWithinAbsOrRel(entropy, f.Entropy(), tol, tol) { t.Errorf("Entropy mismatch case %v: want: %v, got: %v", i, entropy, f.Entropy()) } // Excess Kurtosis check. for i, x := range xs { tmp[i] = math.Pow(x-mean, 4) } mu4 := stat.Mean(tmp, nil) kurtosis := mu4/(variance*variance) - 3 if !floats.EqualWithinAbsOrRel(kurtosis, f.ExKurtosis(), tol, tol) { t.Errorf("ExKurtosis mismatch case %v: want: %v, got: %v", i, kurtosis, f.ExKurtosis()) } // Skewness check. for i, x := range xs { tmp[i] = math.Pow(x-mean, 3) } mu3 := stat.Mean(tmp, nil) skewness := mu3 / math.Pow(std, 3) if !floats.EqualWithinAbsOrRel(skewness, f.Skewness(), tol, tol) { t.Errorf("ExKurtosis mismatch case %v: want: %v, got: %v", i, skewness, f.Skewness()) } // Quantile, CDF, and survival check. for i, p := range []float64{0.1, 0.25, 0.5, 0.75, 0.9} { x := f.Quantile(p) cdf := f.CDF(x) estCDF := stat.CDF(x, stat.Empirical, sortedXs, nil) if !floats.EqualWithinAbsOrRel(cdf, estCDF, tol, tol) { t.Errorf("CDF mismatch case %v: want: %v, got: %v", i, estCDF, cdf) } if !floats.EqualWithinAbsOrRel(cdf, p, tol, tol) { t.Errorf("Quantile/CDF mismatch case %v: want: %v, got: %v", i, p, cdf) } if math.Abs(1-cdf-f.Survival(x)) > 1e-14 { t.Errorf("Survival/CDF mismatch case %v: want: %v, got: %v", i, 1-cdf, f.Survival(x)) } } // Prob and LogProb check. m := 1001 bins := make([]float64, m) dividers := make([]float64, m) floats.Span(bins, 0, 1) for i, v := range bins { dividers[i] = f.Quantile(v) } counts := stat.Histogram(nil, dividers, sortedXs, nil) // Test PDf against normalized count for i, v := range counts { v /= float64(n) at := f.Quantile((bins[i] + bins[i+1]) / 2) prob := f.Prob(at) if !floats.EqualWithinAbsOrRel(skewness, f.Skewness(), tol, tol) { t.Errorf("Prob mismatch case %v at %v: want: %v, got: %v", i, at, v, prob) break } if math.Abs(math.Log(prob)-f.LogProb(at)) > 1e-14 { t.Errorf("Prob and LogProb mismatch case %v at %v: want %v, got %v", i, at, math.Log(prob), f.LogProb(at)) break } } }
func TestTrapezoidal(t *testing.T) { const N = 1e6 x := floats.Span(make([]float64, N), 0, 1) for i, test := range []struct { x []float64 f func(x float64) float64 want float64 }{ { x: x, f: func(x float64) float64 { return x }, want: 0.5, }, { x: floats.Span(make([]float64, N), -1, 1), f: func(x float64) float64 { return x }, want: 0, }, { x: x, f: func(x float64) float64 { return x + 10 }, want: 10.5, }, { x: x, f: func(x float64) float64 { return 3*x*x + 10 }, want: 11, }, { x: x, f: func(x float64) float64 { return math.Exp(x) }, want: 1.7182818284591876, }, { x: floats.Span(make([]float64, N), 0, math.Pi), f: func(x float64) float64 { return math.Cos(x) }, want: 0, }, { x: floats.Span(make([]float64, N), 0, 2*math.Pi), f: func(x float64) float64 { return math.Cos(x) }, want: 0, }, { x: floats.Span(make([]float64, N*10), 0, math.Pi), f: func(x float64) float64 { return math.Sin(x) }, want: 2, }, { x: floats.Span(make([]float64, N*10), 0, 0.5*math.Pi), f: func(x float64) float64 { return math.Sin(x) }, want: 1, }, { x: floats.Span(make([]float64, N), 0, 2*math.Pi), f: func(x float64) float64 { return math.Sin(x) }, want: 0, }, } { y := make([]float64, len(test.x)) for i, v := range test.x { y[i] = test.f(v) } v := Trapezoidal(test.x, y) if !floats.EqualWithinAbs(v, test.want, 1e-12) { t.Errorf("test #%d: got=%v want=%v\n", i, v, test.want) } } }