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

     1  // Copyright ©2020 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/stat"
    14  )
    15  
    16  func TestAlphaStable(t *testing.T) {
    17  	t.Parallel()
    18  	src := rand.New(rand.NewSource(1))
    19  	for i, dist := range []AlphaStable{
    20  		{Alpha: 0.5, Beta: 0, C: 1, Mu: 0, Src: src},
    21  		{Alpha: 1, Beta: 0, C: 1, Mu: 0, Src: src},
    22  		{Alpha: 2, Beta: 0, C: 1, Mu: 0, Src: src},
    23  		{Alpha: 0.5, Beta: 1, C: 1, Mu: 0, Src: src},
    24  		{Alpha: 1, Beta: 1, C: 1, Mu: 0, Src: src},
    25  		{Alpha: 2, Beta: 1, C: 1, Mu: 0, Src: src},
    26  		{Alpha: 0.5, Beta: 0, C: 1, Mu: 1, Src: src},
    27  		{Alpha: 1, Beta: 0, C: 1, Mu: 1, Src: src},
    28  		{Alpha: 2, Beta: 0, C: 1, Mu: 1, Src: src},
    29  		{Alpha: 0.5, Beta: 0.5, C: 1, Mu: 1, Src: src},
    30  		{Alpha: 1, Beta: 0.5, C: 1, Mu: 1, Src: src},
    31  		{Alpha: 1.1, Beta: 0.5, C: 1, Mu: 1, Src: src},
    32  		{Alpha: 2, Beta: 0.5, C: 1, Mu: 1, Src: src},
    33  	} {
    34  		testAlphaStableAnalytic(t, i, dist)
    35  	}
    36  }
    37  
    38  func TestAlphaStability(t *testing.T) {
    39  	t.Parallel()
    40  	const (
    41  		n     = 10000
    42  		ksTol = 2e-2
    43  	)
    44  	for i, test := range []struct {
    45  		alpha, beta1, beta2, c1, c2, mu1, mu2 float64
    46  	}{
    47  		{2, 0, 0, 1, 2, 0.5, 0.25},
    48  		{2, 0.9, -0.4, 1, 2, 0.5, 0.25},
    49  		{1.9, 0, 0, 1, 2, 0.5, 0.25},
    50  		{1, 0, 0, 1, 2, 0.5, 0.25},
    51  		{1, -0.5, 0.5, 1, 2, 0.5, 0.25},
    52  		{0.5, 0, 0, 1, 2, 0.5, 0.25},
    53  		{0.5, -0.5, 0.5, 1, 2, 0.5, 0.25},
    54  	} {
    55  		testStability(t, i, n, test.alpha, test.beta1, test.beta2, test.c1, test.c2, test.mu1, test.mu2, ksTol)
    56  	}
    57  }
    58  
    59  func TestAlphaStableGaussian(t *testing.T) {
    60  	t.Parallel()
    61  	src := rand.New(rand.NewSource(1))
    62  	d := AlphaStable{Alpha: 2, Beta: 0, C: 1.5, Mu: -0.4, Src: src}
    63  	n := 100000
    64  	x := make([]float64, n)
    65  	for i := 0; i < n; i++ {
    66  		x[i] = d.Rand()
    67  	}
    68  	checkSkewness(t, 0, x, d, 1e-2)
    69  	checkExKurtosis(t, 0, x, d, 1e-2)
    70  	checkMean(t, 0, x, d, 1e-2)
    71  	checkVarAndStd(t, 0, x, d, 1e-2)
    72  	checkMode(t, 0, x, d, 5e-2, 1e-1)
    73  }
    74  
    75  func TestAlphaStableMean(t *testing.T) {
    76  	t.Parallel()
    77  	src := rand.New(rand.NewSource(1))
    78  	d := AlphaStable{Alpha: 1.75, Beta: 0.2, C: 1.2, Mu: 0.3, Src: src}
    79  	n := 100000
    80  	x := make([]float64, n)
    81  	for i := 0; i < n; i++ {
    82  		x[i] = d.Rand()
    83  	}
    84  	checkMean(t, 0, x, d, 1e-2)
    85  }
    86  
    87  func TestAlphaStableCauchy(t *testing.T) {
    88  	t.Parallel()
    89  	src := rand.New(rand.NewSource(1))
    90  	d := AlphaStable{Alpha: 1, Beta: 0, C: 1, Mu: 0, Src: src}
    91  	n := 1000000
    92  	x := make([]float64, n)
    93  	for i := 0; i < n; i++ {
    94  		x[i] = d.Rand()
    95  	}
    96  	checkMode(t, 0, x, d, 1e-2, 5e-2)
    97  }
    98  
    99  func testAlphaStableAnalytic(t *testing.T, i int, dist AlphaStable) {
   100  	if dist.NumParameters() != 4 {
   101  		t.Errorf("%d: expected NumParameters == 4, got %v", i, dist.NumParameters())
   102  	}
   103  	if dist.Beta == 0 {
   104  		if dist.Mode() != dist.Mu {
   105  			t.Errorf("%d: expected Mode == Mu for Beta == 0, got %v", i, dist.Mode())
   106  		}
   107  		if dist.Median() != dist.Mu {
   108  			t.Errorf("%d: expected Median == Mu for Beta == 0, got %v", i, dist.Median())
   109  		}
   110  	} else {
   111  		if !panics(func() { dist.Mode() }) {
   112  			t.Errorf("%d: expected Mode to panic for Beta != 0", i)
   113  		}
   114  		if !panics(func() { dist.Median() }) {
   115  			t.Errorf("%d: expected Median to panic for Beta != 0", i)
   116  		}
   117  	}
   118  	if dist.Alpha > 1 {
   119  		if dist.Mean() != dist.Mu {
   120  			t.Errorf("%d: expected Mean == Mu for Alpha > 1, got %v", i, dist.Mean())
   121  		}
   122  	} else {
   123  		if !math.IsNaN(dist.Mean()) {
   124  			t.Errorf("%d: expected NaN Mean for Alpha <= 1, got %v", i, dist.Mean())
   125  		}
   126  	}
   127  	if dist.Alpha == 2 {
   128  		got := dist.Variance()
   129  		want := 2 * dist.C * dist.C
   130  		if got != want {
   131  			t.Errorf("%d: mismatch in Variance for Alpha == 2: got %v, want %g", i, got, want)
   132  		}
   133  		got = dist.StdDev()
   134  		want = math.Sqrt(2) * dist.C
   135  		if got != want {
   136  			t.Errorf("%d: mismatch in StdDev for Alpha == 2: got %v, want %g", i, got, want)
   137  		}
   138  		got = dist.Skewness()
   139  		want = 0
   140  		if got != want {
   141  			t.Errorf("%d: mismatch in Skewness for Alpha == 2: got %v, want %g", i, got, want)
   142  		}
   143  		got = dist.ExKurtosis()
   144  		want = 0
   145  		if got != want {
   146  			t.Errorf("%d: mismatch in ExKurtosis for Alpha == 2: got %v, want %g", i, got, want)
   147  		}
   148  	} else {
   149  		got := dist.Variance()
   150  		if !math.IsInf(got, 1) {
   151  			t.Errorf("%d: Variance is not +Inf for Alpha != 2: got %v", i, got)
   152  		}
   153  		got = dist.StdDev()
   154  		if !math.IsInf(got, 1) {
   155  			t.Errorf("%d: StdDev is not +Inf for Alpha != 2: got %v", i, got)
   156  		}
   157  		got = dist.Skewness()
   158  		if !math.IsNaN(got) {
   159  			t.Errorf("%d: Skewness is not NaN for Alpha != 2: got %v", i, got)
   160  		}
   161  		got = dist.ExKurtosis()
   162  		if !math.IsNaN(got) {
   163  			t.Errorf("%d: ExKurtosis is not NaN for Alpha != 2: got %v", i, got)
   164  		}
   165  	}
   166  }
   167  
   168  func testStability(t *testing.T, i, n int, alpha, beta1, beta2, c1, c2, mu1, mu2, ksTol float64) {
   169  	src := rand.New(rand.NewSource(1))
   170  	d1 := AlphaStable{alpha, beta1, c1, mu1, src}
   171  	d2 := AlphaStable{alpha, beta2, c2, mu2, src}
   172  	c := math.Pow(math.Pow(c1, alpha)+math.Pow(c2, alpha), 1/alpha)
   173  	beta := (beta1*math.Pow(c1, alpha) + beta2*math.Pow(c2, alpha)) / math.Pow(c, alpha)
   174  	// Sum of d1 and d2.
   175  	d := AlphaStable{alpha, beta, c, mu1 + mu2, src}
   176  	sample1 := make([]float64, n)
   177  	sample2 := make([]float64, n)
   178  	for i := 0; i < n; i++ {
   179  		sample1[i] = d1.Rand() + d2.Rand()
   180  		sample2[i] = d.Rand()
   181  	}
   182  	sort.Float64s(sample1)
   183  	sort.Float64s(sample2)
   184  	ks := stat.KolmogorovSmirnov(sample1, nil, sample2, nil)
   185  	if ks > ksTol {
   186  		t.Errorf("%d: Kolmogorov-Smirnov distance %g exceeding tolerance %g", i, ks, ksTol)
   187  	}
   188  }