github.com/gopherd/gonum@v0.0.4/mathext/beta_test.go (about)

     1  // Copyright ©2016 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 mathext_test
     6  
     7  import (
     8  	"math"
     9  	"testing"
    10  
    11  	"github.com/gopherd/gonum/floats/scalar"
    12  	"github.com/gopherd/gonum/mathext"
    13  )
    14  
    15  var betaTests = []struct {
    16  	p, q float64
    17  	want float64
    18  }{
    19  	{
    20  		p:    1,
    21  		q:    2,
    22  		want: 0.5, // obtained from scipy.special.beta(1,2) (version=0.18.0)
    23  	},
    24  	{
    25  		p:    10,
    26  		q:    20,
    27  		want: 4.9925087406346778e-09, // obtained from scipy.special.beta(10,20) (version=0.18.0)
    28  	},
    29  	{
    30  		p:    +0,
    31  		q:    10,
    32  		want: math.Inf(+1),
    33  	},
    34  	{
    35  		p:    -0,
    36  		q:    10,
    37  		want: math.Inf(+1),
    38  	},
    39  	{
    40  		p:    0,
    41  		q:    0,
    42  		want: math.NaN(),
    43  	},
    44  	{
    45  		p:    0,
    46  		q:    math.Inf(-1),
    47  		want: math.NaN(),
    48  	},
    49  	{
    50  		p:    10,
    51  		q:    math.Inf(-1),
    52  		want: math.NaN(),
    53  	},
    54  	{
    55  		p:    0,
    56  		q:    math.Inf(+1),
    57  		want: math.NaN(),
    58  	},
    59  	{
    60  		p:    10,
    61  		q:    math.Inf(+1),
    62  		want: math.NaN(),
    63  	},
    64  	{
    65  		p:    math.NaN(),
    66  		q:    10,
    67  		want: math.NaN(),
    68  	},
    69  	{
    70  		p:    math.NaN(),
    71  		q:    0,
    72  		want: math.NaN(),
    73  	},
    74  	{
    75  		p:    -1,
    76  		q:    0,
    77  		want: math.NaN(),
    78  	},
    79  	{
    80  		p:    -1,
    81  		q:    +1,
    82  		want: math.NaN(),
    83  	},
    84  }
    85  
    86  func TestBeta(t *testing.T) {
    87  	t.Parallel()
    88  	for i, test := range betaTests {
    89  		v := mathext.Beta(test.p, test.q)
    90  		testOK := func(x float64) bool {
    91  			return scalar.EqualWithinAbsOrRel(x, test.want, 1e-15, 1e-15) || (math.IsNaN(test.want) && math.IsNaN(x))
    92  		}
    93  		if !testOK(v) {
    94  			t.Errorf("test #%d: Beta(%v, %v)=%v. want=%v\n",
    95  				i, test.p, test.q, v, test.want,
    96  			)
    97  		}
    98  
    99  		u := mathext.Beta(test.q, test.p)
   100  		if !testOK(u) {
   101  			t.Errorf("test #%[1]d: Beta(%[2]v, %[3]v)=%[4]v != Beta(%[3]v, %[2]v)=%[5]v)\n",
   102  				i, test.p, test.q, v, u,
   103  			)
   104  		}
   105  
   106  		if math.IsInf(v, +1) || math.IsNaN(v) {
   107  			continue
   108  		}
   109  
   110  		vv := mathext.Beta(test.p, test.q+1)
   111  		uu := mathext.Beta(test.p+1, test.q)
   112  		if !scalar.EqualWithinAbsOrRel(v, vv+uu, 1e-15, 1e-15) {
   113  			t.Errorf(
   114  				"test #%[1]d: Beta(%[2]v, %[3]v)=%[4]v != Beta(%[2]v+1, %[3]v) + Beta(%[2]v, %[3]v+1) (=%[5]v + %[6]v = %[7]v)\n",
   115  				i, test.p, test.q, v, uu, vv, uu+vv,
   116  			)
   117  		}
   118  
   119  		vbeta2 := beta2(test.p, test.q)
   120  		if !scalar.EqualWithinAbsOrRel(v, vbeta2, 1e-15, 1e-15) {
   121  			t.Errorf(
   122  				"test #%[1]d: Beta(%[2]v, %[3]v) != Γ(p)Γ(q) / Γ(p+q) (v=%[4]v u=%[5]v)\n",
   123  				i, test.p, test.q, v, vbeta2,
   124  			)
   125  		}
   126  	}
   127  }
   128  
   129  func beta2(x, y float64) float64 {
   130  	return math.Gamma(x) * math.Gamma(y) / math.Gamma(x+y)
   131  }
   132  
   133  func BenchmarkBeta(b *testing.B) {
   134  	for i := 0; i < b.N; i++ {
   135  		_ = mathext.Beta(10, 20)
   136  	}
   137  }
   138  
   139  func BenchmarkBeta2(b *testing.B) {
   140  	for i := 0; i < b.N; i++ {
   141  		_ = math.Gamma(10) * math.Gamma(20) / math.Gamma(10+20)
   142  	}
   143  }
   144  
   145  func TestLbeta(t *testing.T) {
   146  	t.Parallel()
   147  	for i, test := range betaTests {
   148  		want := math.Log(test.want)
   149  		v := mathext.Lbeta(test.p, test.q)
   150  
   151  		testOK := func(x float64) bool {
   152  			return scalar.EqualWithinAbsOrRel(x, want, 1e-15, 1e-15) || (math.IsNaN(want) && math.IsNaN(x))
   153  		}
   154  		if !testOK(v) {
   155  			t.Errorf("test #%d: Lbeta(%v, %v)=%v. want=%v\n",
   156  				i, test.p, test.q, v, want,
   157  			)
   158  		}
   159  
   160  		u := mathext.Lbeta(test.q, test.p)
   161  		if !testOK(u) {
   162  			t.Errorf("test #%[1]d: Lbeta(%[2]v, %[3]v)=%[4]v != Lbeta(%[3]v, %[2]v)=%[5]v)\n",
   163  				i, test.p, test.q, v, u,
   164  			)
   165  		}
   166  
   167  		if math.IsInf(v, +1) || math.IsNaN(v) {
   168  			continue
   169  		}
   170  
   171  		vbeta2 := math.Log(beta2(test.p, test.q))
   172  		if !scalar.EqualWithinAbsOrRel(v, vbeta2, 1e-15, 1e-15) {
   173  			t.Errorf(
   174  				"test #%[1]d: Lbeta(%[2]v, %[3]v) != Log(Γ(p)Γ(q) / Γ(p+q)) (v=%[4]v u=%[5]v)\n",
   175  				i, test.p, test.q, v, vbeta2,
   176  			)
   177  		}
   178  	}
   179  }