gonum.org/v1/gonum@v0.14.0/stat/distuv/poisson_test.go (about)

     1  // Copyright ©2017 The Gonum Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package distuv
     6  
     7  import (
     8  	"fmt"
     9  	"math"
    10  	"sort"
    11  	"testing"
    12  
    13  	"golang.org/x/exp/rand"
    14  
    15  	"gonum.org/v1/gonum/floats/scalar"
    16  )
    17  
    18  func TestPoissonProb(t *testing.T) {
    19  	t.Parallel()
    20  	const tol = 1e-10
    21  	for i, tt := range []struct {
    22  		k      float64
    23  		lambda float64
    24  		want   float64
    25  	}{
    26  		{0, 1, 3.678794411714423e-01},
    27  		{1, 1, 3.678794411714423e-01},
    28  		{2, 1, 1.839397205857211e-01},
    29  		{3, 1, 6.131324019524039e-02},
    30  		{4, 1, 1.532831004881010e-02},
    31  		{5, 1, 3.065662009762020e-03},
    32  		{6, 1, 5.109436682936698e-04},
    33  		{7, 1, 7.299195261338139e-05},
    34  		{8, 1, 9.123994076672672e-06},
    35  		{9, 1, 1.013777119630298e-06},
    36  
    37  		{0, 2.5, 8.208499862389880e-02},
    38  		{1, 2.5, 2.052124965597470e-01},
    39  		{2, 2.5, 2.565156206996838e-01},
    40  		{3, 2.5, 2.137630172497365e-01},
    41  		{4, 2.5, 1.336018857810853e-01},
    42  		{5, 2.5, 6.680094289054267e-02},
    43  		{6, 2.5, 2.783372620439277e-02},
    44  		{7, 2.5, 9.940616501568845e-03},
    45  		{8, 2.5, 3.106442656740263e-03},
    46  		{9, 2.5, 8.629007379834082e-04},
    47  
    48  		{0.5, 2.5, 0},
    49  		{1.5, 2.5, 0},
    50  		{2.5, 2.5, 0},
    51  		{3.5, 2.5, 0},
    52  		{4.5, 2.5, 0},
    53  		{5.5, 2.5, 0},
    54  		{6.5, 2.5, 0},
    55  		{7.5, 2.5, 0},
    56  		{8.5, 2.5, 0},
    57  		{9.5, 2.5, 0},
    58  	} {
    59  		p := Poisson{Lambda: tt.lambda}
    60  		got := p.Prob(tt.k)
    61  		if !scalar.EqualWithinAbs(got, tt.want, tol) {
    62  			t.Errorf("test-%d: got=%e. want=%e\n", i, got, tt.want)
    63  		}
    64  	}
    65  }
    66  
    67  func TestPoissonCDF(t *testing.T) {
    68  	t.Parallel()
    69  	const tol = 1e-10
    70  	for i, tt := range []struct {
    71  		k      float64
    72  		lambda float64
    73  		want   float64
    74  	}{
    75  		{0, 1, 0.367879441171442},
    76  		{1, 1, 0.735758882342885},
    77  		{2, 1, 0.919698602928606},
    78  		{3, 1, 0.981011843123846},
    79  		{4, 1, 0.996340153172656},
    80  		{5, 1, 0.999405815182418},
    81  		{6, 1, 0.999916758850712},
    82  		{7, 1, 0.999989750803325},
    83  		{8, 1, 0.999998874797402},
    84  		{9, 1, 0.999999888574522},
    85  
    86  		{0, 2.5, 0.082084998623899},
    87  		{1, 2.5, 0.287297495183646},
    88  		{2, 2.5, 0.543813115883329},
    89  		{3, 2.5, 0.757576133133066},
    90  		{4, 2.5, 0.891178018914151},
    91  		{5, 2.5, 0.957978961804694},
    92  		{6, 2.5, 0.985812688009087},
    93  		{7, 2.5, 0.995753304510655},
    94  		{8, 2.5, 0.998859747167396},
    95  		{9, 2.5, 0.999722647905379},
    96  	} {
    97  		p := Poisson{Lambda: tt.lambda}
    98  		got := p.CDF(tt.k)
    99  		if !scalar.EqualWithinAbs(got, tt.want, tol) {
   100  			t.Errorf("test-%d: got=%e. want=%e\n", i, got, tt.want)
   101  		}
   102  	}
   103  }
   104  
   105  func TestPoisson(t *testing.T) {
   106  	t.Parallel()
   107  	src := rand.New(rand.NewSource(1))
   108  	for i, b := range []Poisson{
   109  		{100, src},
   110  		{15, src},
   111  		{10, src},
   112  		{9.9, src},
   113  		{3, src},
   114  		{1.5, src},
   115  		{0.9, src},
   116  	} {
   117  		testPoisson(t, b, i)
   118  	}
   119  }
   120  
   121  func testPoisson(t *testing.T, p Poisson, i int) {
   122  	const (
   123  		tol = 1e-2
   124  		n   = 2e6
   125  	)
   126  	x := make([]float64, n)
   127  	generateSamples(x, p)
   128  	sort.Float64s(x)
   129  
   130  	checkProbDiscrete(t, i, x, p, 2e-3)
   131  	checkMean(t, i, x, p, tol)
   132  	checkVarAndStd(t, i, x, p, tol)
   133  	checkExKurtosis(t, i, x, p, 7e-2)
   134  	checkSkewness(t, i, x, p, tol)
   135  
   136  	if p.NumParameters() != 1 {
   137  		t.Errorf("Mismatch in NumParameters: got %v, want 1", p.NumParameters())
   138  	}
   139  	cdf := p.CDF(-0.0001)
   140  	if cdf != 0 {
   141  		t.Errorf("Mismatch in CDF for x < 0: got %v, want 0", cdf)
   142  	}
   143  	surv := p.Survival(-0.0001)
   144  	if surv != 1 {
   145  		t.Errorf("Mismatch in Survival for x < 0: got %v, want 1", surv)
   146  	}
   147  	logProb := p.LogProb(-0.0001)
   148  	if !math.IsInf(logProb, -1) {
   149  		t.Errorf("Mismatch in LogProb for x < 0: got %v, want -Inf", logProb)
   150  	}
   151  	logProb = p.LogProb(1.5)
   152  	if !math.IsInf(logProb, -1) {
   153  		t.Errorf("Mismatch in LogProb for non-integer x: got %v, want -Inf", logProb)
   154  	}
   155  	for _, xx := range x {
   156  		cdf = p.CDF(xx)
   157  		surv = p.Survival(xx)
   158  		if math.Abs(cdf+surv-1) > 1e-10 {
   159  			t.Errorf("Mismatch between CDF and Survival at %g", xx)
   160  		}
   161  	}
   162  }
   163  
   164  func BenchmarkPoissonRand(b *testing.B) {
   165  	src := rand.New(rand.NewSource(1))
   166  	for i, p := range []Poisson{
   167  		{100, src},
   168  		{15, src},
   169  		{10, src},
   170  		{9.9, src},
   171  		{3, src},
   172  		{1.5, src},
   173  		{0.9, src},
   174  	} {
   175  		b.Run(fmt.Sprintf("case %d", i), func(b *testing.B) {
   176  			for i := 0; i < b.N; i++ {
   177  				p.Rand()
   178  			}
   179  		})
   180  	}
   181  }