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

     1  // Copyright ©2014 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  	"math"
     9  	"sort"
    10  	"testing"
    11  
    12  	"golang.org/x/exp/rand"
    13  	"gonum.org/v1/gonum/floats/scalar"
    14  )
    15  
    16  func TestLaplaceProb(t *testing.T) {
    17  	t.Parallel()
    18  	pts := []univariateProbPoint{
    19  		{
    20  			loc:     0,
    21  			prob:    0.5,
    22  			cumProb: 0.5,
    23  			logProb: math.Log(0.5),
    24  		},
    25  		{
    26  			loc:     -1,
    27  			prob:    1 / (2 * math.E),
    28  			cumProb: 0.1839397205857211607977618850807304337229055655158839172539184008487307478724499016785736371729598219,
    29  			logProb: math.Log(1 / (2 * math.E)),
    30  		},
    31  		{
    32  			loc:     1,
    33  			prob:    1 / (2 * math.E),
    34  			cumProb: 0.8160602794142788392022381149192695662770944344841160827460815991512692521275500983214263628270401781,
    35  			logProb: math.Log(1 / (2 * math.E)),
    36  		},
    37  		{
    38  			loc:     -7,
    39  			prob:    1 / (2 * math.Pow(math.E, 7)),
    40  			cumProb: 0.0004559409827772581040015680422046413132368622637180269204080667109447399446551532646631395032324502210,
    41  			logProb: math.Log(1 / (2 * math.Pow(math.E, 7))),
    42  		},
    43  		{
    44  			loc:     7,
    45  			prob:    1 / (2 * math.Pow(math.E, 7)),
    46  			cumProb: 0.9995440590172227418959984319577953586867631377362819730795919332890552600553448467353368604967675498,
    47  			logProb: math.Log(1 / (2 * math.Pow(math.E, 7))),
    48  		},
    49  		{
    50  			loc:     -20,
    51  			prob:    math.Exp(-20.69314718055994530941723212145817656807550013436025525412068000949339362196969471560586332699641869),
    52  			cumProb: 1.030576811219278913982970190077910488187903637799551846486122330814582011892279676639955463952790684 * 1e-9,
    53  			logProb: -20.69314718055994530941723212145817656807550013436025525412068000949339362196969471560586332699641869,
    54  		},
    55  		{
    56  			loc:     20,
    57  			prob:    math.Exp(-20.69314718055994530941723212145817656807550013436025525412068000949339362196969471560586332699641869),
    58  			cumProb: 0.999999998969423188780721086017029809922089511812096362200448153513877669185417988107720323360044536,
    59  			logProb: -20.69314718055994530941723212145817656807550013436025525412068000949339362196969471560586332699641869,
    60  		},
    61  	}
    62  	testDistributionProbs(t, Laplace{Mu: 0, Scale: 1}, "Laplace", pts)
    63  }
    64  
    65  func TestLaplace(t *testing.T) {
    66  	t.Parallel()
    67  	src := rand.New(rand.NewSource(1))
    68  	for i, dist := range []Laplace{
    69  		{Mu: 0, Scale: 3, Src: src},
    70  		{Mu: 1, Scale: 1.5, Src: src},
    71  		{Mu: -1, Scale: 0.9, Src: src},
    72  	} {
    73  		testLaplace(t, dist, i)
    74  	}
    75  }
    76  
    77  func testLaplace(t *testing.T, dist Laplace, i int) {
    78  	const (
    79  		tol  = 1e-2
    80  		n    = 3e6
    81  		bins = 50
    82  	)
    83  	x := make([]float64, n)
    84  	generateSamples(x, dist)
    85  	sort.Float64s(x)
    86  
    87  	checkMean(t, i, x, dist, tol)
    88  	checkVarAndStd(t, i, x, dist, tol)
    89  	checkEntropy(t, i, x, dist, tol)
    90  	checkExKurtosis(t, i, x, dist, tol)
    91  	checkSkewness(t, i, x, dist, tol)
    92  	checkMedian(t, i, x, dist, tol)
    93  	checkQuantileCDFSurvival(t, i, x, dist, tol)
    94  	checkProbContinuous(t, i, x, math.Inf(-1), math.Inf(1), dist, 1e-10)
    95  	checkProbQuantContinuous(t, i, x, dist, tol)
    96  	testDerivParam(t, &dist)
    97  
    98  	if dist.Mu != dist.Mode() {
    99  		t.Errorf("Mismatch in mode value, got: %v, want: %g", dist.Mode(), dist.Mu)
   100  	}
   101  	score := dist.Score(nil, dist.Mu)
   102  	if !math.IsNaN(score[0]) {
   103  		t.Errorf("Expected NaN score over Mu for x == Mu, got %v", score[0])
   104  	}
   105  	if score[1] != -1/dist.Scale {
   106  		t.Errorf("Mismatch in score over Scale value for x == Mu, got: %v, want: %g", score[1], -1/dist.Scale)
   107  	}
   108  	scoreInput := dist.ScoreInput(dist.Mu)
   109  	if !math.IsNaN(scoreInput) {
   110  		t.Errorf("Expected NaN input score for x == Mu, got %v", scoreInput)
   111  	}
   112  }
   113  
   114  func TestLaplaceFit(t *testing.T) {
   115  	t.Parallel()
   116  	cases := []struct {
   117  		samples   []float64
   118  		weights   []float64
   119  		wantMu    float64
   120  		wantScale float64
   121  	}{
   122  		{
   123  			samples:   []float64{10, 1, 1},
   124  			weights:   nil,
   125  			wantMu:    1,
   126  			wantScale: 3,
   127  		},
   128  		{
   129  			samples:   []float64{10, 1, 1},
   130  			weights:   []float64{10, 10, 10},
   131  			wantMu:    1,
   132  			wantScale: 3,
   133  		},
   134  		{
   135  			samples:   []float64{10, 1, 1},
   136  			weights:   []float64{0, 1, 1},
   137  			wantMu:    1,
   138  			wantScale: 0,
   139  		},
   140  		{
   141  			samples:   []float64{1, 1, 10},
   142  			weights:   []float64{1, 1, 0},
   143  			wantMu:    1,
   144  			wantScale: 0,
   145  		},
   146  		{
   147  			samples:   []float64{10},
   148  			weights:   nil,
   149  			wantMu:    10,
   150  			wantScale: 0,
   151  		},
   152  	}
   153  	for i, test := range cases {
   154  		d := Laplace{}
   155  		d.Fit(test.samples, test.weights)
   156  		if !scalar.EqualWithinAbsOrRel(d.Mu, test.wantMu, 1e-10, 1e-10) {
   157  			t.Errorf("unexpected location result for test %d: got:%f, want:%f", i, d.Mu, test.wantMu)
   158  		}
   159  		if !scalar.EqualWithinAbsOrRel(d.Scale, test.wantScale, 1e-10, 1e-10) {
   160  			t.Errorf("unexpected scale result for test %d: got:%f, want:%f", i, d.Scale, test.wantScale)
   161  		}
   162  	}
   163  }
   164  
   165  func TestLaplaceFitRandomSamples(t *testing.T) {
   166  	t.Parallel()
   167  
   168  	nSamples := 100000
   169  	src := rand.New(rand.NewSource(1))
   170  	l := Laplace{
   171  		Mu:    3,
   172  		Scale: 5,
   173  		Src:   src,
   174  	}
   175  	samples := make([]float64, nSamples)
   176  	for i := range samples {
   177  		samples[i] = l.Rand()
   178  	}
   179  	le := Laplace{}
   180  	le.Fit(samples, nil)
   181  	if !scalar.EqualWithinAbsOrRel(le.Mu, l.Mu, 1e-2, 1e-2) {
   182  		t.Errorf("unexpected location result for random test got:%f, want:%f", le.Mu, l.Mu)
   183  	}
   184  	if !scalar.EqualWithinAbsOrRel(le.Scale, l.Scale, 1e-2, 1e-2) {
   185  		t.Errorf("unexpected scale result for random test got:%f, want:%f", le.Scale, l.Scale)
   186  	}
   187  }
   188  
   189  func TestLaplaceFitPanic(t *testing.T) {
   190  	t.Parallel()
   191  	l := Laplace{
   192  		Mu:    3,
   193  		Scale: 5,
   194  		Src:   nil,
   195  	}
   196  	if !panics(func() { l.Fit([]float64{1, 1, 1}, []float64{0.4, 0.4}) }) {
   197  		t.Errorf("Expected panic in Fit for len(sample) != len(weights)")
   198  	}
   199  	if !panics(func() { l.Fit([]float64{}, nil) }) {
   200  		t.Errorf("Expected panic in Fit for len(sample) == 0")
   201  	}
   202  }