rubystats 0.2.3 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/test.yml +21 -0
  3. data/.gitignore +20 -0
  4. data/Gemfile +3 -0
  5. data/History.txt +34 -0
  6. data/{README.txt → README.rdoc} +18 -7
  7. data/Rakefile +11 -44
  8. data/examples/uniform.rb +14 -0
  9. data/lib/rubystats/beta_distribution.rb +4 -0
  10. data/lib/rubystats/binomial_distribution.rb +42 -131
  11. data/lib/rubystats/cauchy_distribution.rb +50 -0
  12. data/lib/rubystats/exponential_distribution.rb +2 -2
  13. data/lib/rubystats/fishers_exact_test.rb +9 -9
  14. data/lib/rubystats/gamma_distribution.rb +70 -0
  15. data/lib/rubystats/lognormal_distribution.rb +59 -0
  16. data/lib/rubystats/modules.rb +57 -48
  17. data/lib/rubystats/multivariate_normal_distribution.rb +73 -0
  18. data/lib/rubystats/normal_distribution.rb +4 -3
  19. data/lib/rubystats/poisson_distribution.rb +78 -0
  20. data/lib/rubystats/probability_distribution.rb +4 -4
  21. data/lib/rubystats/student_t_distribution.rb +62 -0
  22. data/lib/rubystats/uniform_distribution.rb +70 -0
  23. data/lib/rubystats/version.rb +3 -0
  24. data/lib/rubystats/weibull_distribution.rb +56 -0
  25. data/lib/rubystats.rb +39 -5
  26. data/rubystats.gemspec +28 -0
  27. data/test/tc_beta.rb +90 -69
  28. data/test/tc_binomial.rb +30 -16
  29. data/test/tc_cauchy.rb +39 -0
  30. data/test/tc_exponential.rb +13 -3
  31. data/test/tc_fisher.rb +15 -15
  32. data/test/tc_gamma.rb +39 -0
  33. data/test/tc_lnorm.rb +45 -0
  34. data/test/tc_multivariate_normal.rb +53 -0
  35. data/test/tc_norm.rb +35 -6
  36. data/test/tc_poisson.rb +35 -0
  37. data/test/tc_require_all.rb +5 -5
  38. data/test/tc_studentt.rb +43 -0
  39. data/test/tc_unif.rb +48 -0
  40. data/test/tc_weibull.rb +51 -0
  41. data/test/ts_stats.rb +1 -1
  42. metadata +115 -47
@@ -6,6 +6,12 @@ module Rubystats
6
6
  end
7
7
  end
8
8
 
9
+ module MakeDiscrete
10
+ def pmf(x)
11
+ pdf(x)
12
+ end
13
+ end
14
+
9
15
  module NumericalConstants
10
16
  MAX_FLOAT = 3.40282346638528860e292
11
17
  EPS = 2.22e-16
@@ -36,6 +42,9 @@ module Rubystats
36
42
 
37
43
  include Rubystats::NumericalConstants
38
44
 
45
+ attr_reader :log_gamma_cache_res, :log_gamma_cache_x,
46
+ :log_beta_cache_res, :log_beta_cache_p, :log_beta_cache_q
47
+
39
48
  @log_gamma_cache_res = 0.0
40
49
  @log_gamma_cache_x = 0.0
41
50
  @log_beta_cache_res = 0.0
@@ -43,7 +52,7 @@ module Rubystats
43
52
  @log_beta_cache_q = 0.0
44
53
 
45
54
  def log_beta(p,q)
46
- if p != @log_beta_cache_p || q != @log_beta_cache_q
55
+ if p != log_beta_cache_p || q != log_beta_cache_q
47
56
  @log_beta_cache_p = p
48
57
  @log_beta_cache_q = q
49
58
  if (p <= 0.0) || (q <= 0.0) || (p + q) > LOG_GAMMA_X_MAX_VALUE
@@ -52,7 +61,7 @@ module Rubystats
52
61
  @log_beta_cache_res = log_gamma(p) + log_gamma(q) - log_gamma(p + q)
53
62
  end
54
63
  end
55
- return @log_beta_cache_res
64
+ return log_beta_cache_res
56
65
  end
57
66
 
58
67
  # Gamma function.
@@ -84,7 +93,7 @@ module Rubystats
84
93
  # </P>
85
94
  # Author:: Jaco van Kooten
86
95
 
87
- def orig_gamma(x)
96
+ def orig_gamma(x)
88
97
  # Gamma related constants
89
98
  g_p = [ -1.71618513886549492533811, 24.7656508055759199108314,
90
99
  -379.804256470945635097577, 629.331155312818442661052,
@@ -93,7 +102,7 @@ module Rubystats
93
102
  g_q = [-30.8402300119738975254353, 315.350626979604161529144,
94
103
  -1015.15636749021914166146, -3107.77167157231109440444,
95
104
  22538.1184209801510330112, 4755.84627752788110767815,
96
- -134659.959864969306392456, -115132.259675553483497211 ]
105
+ -134659.959864969306392456, -115132.259675553483497211 ]
97
106
  g_c = [-0.001910444077728, 8.4171387781295e-4, -5.952379913043012e-4,
98
107
  7.93650793500350248e-4, -0.002777777777777681622553,
99
108
  0.08333333333333333331554247, 0.0057083835261 ]
@@ -102,14 +111,14 @@ module Rubystats
102
111
  n = 0
103
112
  y = x
104
113
  parity = false
105
- if y <= 0.0
114
+ if y <= 0.0
106
115
  # ----------------------------------------------------------------------
107
116
  # Argument is negative
108
117
  # ----------------------------------------------------------------------
109
118
  y = -(x)
110
119
  y1 = y.to_i
111
120
  res = y - y1
112
- if res != 0.0
121
+ if res != 0.0
113
122
  if y1 != (((y1*0.5).to_i) * 2.0)
114
123
  parity = true
115
124
  fact = -M_pi/sin(M_pi * res)
@@ -141,7 +150,7 @@ module Rubystats
141
150
  # ----------------------------------------------------------------------
142
151
  z = y
143
152
  y += 1
144
- else
153
+ else
145
154
  # ----------------------------------------------------------------------
146
155
  # 1.0 .LT. argument .LT. 12.0, reduce argument if necessary
147
156
  # ----------------------------------------------------------------------
@@ -154,7 +163,7 @@ module Rubystats
154
163
  # ----------------------------------------------------------------------
155
164
  xnum = 0.0
156
165
  xden = 1.0
157
- for i in (0...8)
166
+ for i in (0...8)
158
167
  xnum = (xnum + g_p[i]) * z
159
168
  xden = xden * z + g_q[i]
160
169
  end
@@ -164,7 +173,7 @@ module Rubystats
164
173
  # Adjust result for case 0.0 .LT. argument .LT. 1.0
165
174
  # ----------------------------------------------------------------------
166
175
  res /= y1
167
- elsif y1 > y
176
+ elsif y1 > y
168
177
  # ----------------------------------------------------------------------
169
178
  # Adjust result for case 2.0 .LT. argument .LT. 12.0
170
179
  # ----------------------------------------------------------------------
@@ -173,14 +182,14 @@ module Rubystats
173
182
  y += 1
174
183
  end
175
184
  end
176
- else
185
+ else
177
186
  # ----------------------------------------------------------------------
178
187
  # Evaluate for argument .GE. 12.0
179
188
  # ----------------------------------------------------------------------
180
189
  if y <= GAMMA_X_MAX_VALUE
181
190
  ysq = y * y
182
191
  sum = g_c[6]
183
- for i in(0...6)
192
+ for i in(0...6)
184
193
  sum = sum / ysq + g_c[i]
185
194
  sum = sum / y - y + log(SQRT2PI)
186
195
  sum += (y - 0.5) * log(y)
@@ -276,8 +285,8 @@ module Rubystats
276
285
  lg_frtbig = 2.25e76
277
286
  pnt68 = 0.6796875
278
287
 
279
- if x == @log_gamma_cache_x
280
- return @log_gamma_cache_res
288
+ if x == log_gamma_cache_x
289
+ return log_gamma_cache_res
281
290
  end
282
291
 
283
292
  y = x
@@ -359,14 +368,14 @@ module Rubystats
359
368
 
360
369
 
361
370
  # Incomplete Gamma function.
362
- # The computation is based on approximations presented in
371
+ # The computation is based on approximations presented in
363
372
  # Numerical Recipes, Chapter 6.2 (W.H. Press et al, 1992).
364
373
  # @param a require a>=0
365
374
  # @param x require x>=0
366
375
  # @return 0 if x<0, a<=0 or a>2.55E305 to avoid errors and over/underflow
367
376
  # @author Jaco van Kooten
368
377
 
369
- def incomplete_gamma(a, x)
378
+ def incomplete_gamma(a, x)
370
379
  if x <= 0.0 || a <= 0.0 || a > LOG_GAMMA_X_MAX_VALUE
371
380
  return 0.0
372
381
  elsif x < (a + 1.0)
@@ -381,7 +390,7 @@ module Rubystats
381
390
  ap = a
382
391
  del = 1.0 / a
383
392
  sum = del
384
- for n in (1...MAX_ITERATIONS)
393
+ (1...MAX_ITERATIONS).each do
385
394
  ap += 1
386
395
  del *= x / ap
387
396
  sum += del
@@ -393,14 +402,14 @@ module Rubystats
393
402
  end
394
403
 
395
404
  # Author:: Jaco van Kooten
396
- def gamma_fraction(a, x)
405
+ def gamma_fraction(a, x)
397
406
  b = x + 1.0 - a
398
407
  c = 1.0 / XMININ
399
408
  d = 1.0 / b
400
409
  h = d
401
410
  del= 0.0
402
411
  an = 0.0
403
- for i in (1...MAX_ITERATIONS)
412
+ for i in (1...MAX_ITERATIONS)
404
413
  if (del-1.0).abs > PRECISION
405
414
  an = -i * (i - a)
406
415
  b += 2.0
@@ -424,10 +433,10 @@ module Rubystats
424
433
  #
425
434
  # Author:: Jaco van Kooten
426
435
 
427
- def beta(p, q)
436
+ def beta(p, q)
428
437
  if p <= 0.0 || q <= 0.0 || (p + q) > LOG_GAMMA_X_MAX_VALUE
429
438
  return 0.0
430
- else
439
+ else
431
440
  return Math.exp(log_beta(p, q))
432
441
  end
433
442
  end
@@ -437,17 +446,17 @@ module Rubystats
437
446
  # Author:: Jaco van Kooten
438
447
  # Author:: Paul Meagher
439
448
  #
440
- # The computation is based on formulas from Numerical Recipes,
449
+ # The computation is based on formulas from Numerical Recipes,
441
450
  # Chapter 6.4 (W.H. Press et al, 1992).
442
451
 
443
- def incomplete_beta(x, p, q)
452
+ def incomplete_beta(x, p, q)
444
453
  if x <= 0.0
445
454
  return 0.0
446
455
  elsif x >= 1.0
447
456
  return 1.0
448
457
  elsif (p <= 0.0) || (q <= 0.0) || (p + q) > LOG_GAMMA_X_MAX_VALUE
449
458
  return 0.0
450
- else
459
+ else
451
460
  beta_gam = Math.exp( -log_beta(p, q) + p * Math.log(x) + q * Math.log(1.0 - x) )
452
461
  if x < (p + 1.0) / (p + q + 2.0)
453
462
  return beta_gam * beta_fraction(x, p, q) / p
@@ -462,13 +471,13 @@ module Rubystats
462
471
  # Based on an idea from Numerical Recipes (W.H. Press et al, 1992).
463
472
  # Author:: Jaco van Kooten
464
473
 
465
- def beta_fraction(x, p, q)
474
+ def beta_fraction(x, p, q)
466
475
  c = 1.0
467
476
  sum_pq = p + q
468
477
  p_plus = p + 1.0
469
478
  p_minus = p - 1.0
470
479
  h = 1.0 - sum_pq * x / p_plus
471
- if h.abs < XMININ
480
+ if h.abs < XMININ
472
481
  h = XMININ
473
482
  end
474
483
  h = 1.0 / h
@@ -476,7 +485,7 @@ module Rubystats
476
485
  m = 1
477
486
  delta = 0.0
478
487
 
479
- while (m <= MAX_ITERATIONS) && ((delta - 1.0).abs > PRECISION)
488
+ while (m <= MAX_ITERATIONS) && ((delta - 1.0).abs > PRECISION)
480
489
  m2 = 2 * m
481
490
  # even index for d
482
491
  d = m * (q - m) * x / ( (p_minus + m2) * (p + m2))
@@ -563,14 +572,14 @@ module Rubystats
563
572
  # where
564
573
  # P1(s) = degree 6 poly in s
565
574
  # Q1(s) = degree 6 poly in s
566
- #
575
+ #
567
576
  # 3. For x in [1.25,1/0.35(~2.857143)],
568
577
  # erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1)
569
578
  # erf(x) = 1 - erfc(x)
570
579
  # where
571
580
  # R1(z) = degree 7 poly in z, (z=1/x^2)
572
581
  # S1(z) = degree 8 poly in z
573
- #
582
+ #
574
583
  # 4. For x in [1/0.35,28]
575
584
  # erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0
576
585
  # = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6<x<0
@@ -580,7 +589,7 @@ module Rubystats
580
589
  # where
581
590
  # R2(z) = degree 6 poly in z, (z=1/x^2)
582
591
  # S2(z) = degree 7 poly in z
583
- #
592
+ #
584
593
  # Note1:
585
594
  # To compute exp(-x*x-0.5625+R/S), let s be a single
586
595
  # PRECISION number and s := x then
@@ -602,16 +611,16 @@ module Rubystats
602
611
  # erf(x) = sign(x) *(1 - tiny) (raise inexact)
603
612
  # erfc(x) = tiny*tiny (raise underflow) if x > 0
604
613
  # = 2 - tiny if x<0
605
- #
614
+ #
606
615
  # 7. Special case:
607
616
  # erf(0) = 0, erf(inf) = 1, erf(-inf) = -1,
608
617
  # erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2,
609
618
  # erfc/erf(NaN) is NaN
610
- #
619
+ #
611
620
  # $efx8 = 1.02703333676410069053e00
612
- #
621
+ #
613
622
  # Coefficients for approximation to erf on [0,0.84375]
614
- #
623
+ #
615
624
 
616
625
  # Error function.
617
626
  # Based on C-code for the error function developed at Sun Microsystems.
@@ -654,7 +663,7 @@ module Rubystats
654
663
  # 0 < |x| < 0.84375
655
664
  if abs_x < 0.84375
656
665
  #|x| < 2**-28
657
- if abs_x < 3.7252902984619141e-9
666
+ if abs_x < 3.7252902984619141e-9
658
667
  retval = abs_x + abs_x * e_efx
659
668
  else
660
669
  s = x * x
@@ -666,12 +675,12 @@ module Rubystats
666
675
  end
667
676
  elsif abs_x < 1.25
668
677
  s = abs_x - 1.0
669
- p = ePa[0] + s * (ePa[1] + s *
670
- (ePa[2] + s * (ePa[3] + s *
678
+ p = ePa[0] + s * (ePa[1] + s *
679
+ (ePa[2] + s * (ePa[3] + s *
671
680
  (ePa[4] + s * (ePa[5] + s * ePa[6])))))
672
681
 
673
- q = 1.0 + s * (eQa[0] + s *
674
- (eQa[1] + s * (eQa[2] + s *
682
+ q = 1.0 + s * (eQa[0] + s *
683
+ (eQa[1] + s * (eQa[2] + s *
675
684
  (eQa[3] + s * (eQa[4] + s * eQa[5])))))
676
685
  retval = e_erx + p / q
677
686
 
@@ -736,27 +745,27 @@ module Rubystats
736
745
  else
737
746
  s = 1.0/(abs_x * abs_x)
738
747
  if abs_x < 2.8571428
739
- r = eRa[0] + s * (eRa[1] + s *
740
- (eRa[2] + s * (eRa[3] + s * (eRa[4] + s *
741
- (eRa[5] + s *(eRa[6] + s * eRa[7])
748
+ r = eRa[0] + s * (eRa[1] + s *
749
+ (eRa[2] + s * (eRa[3] + s * (eRa[4] + s *
750
+ (eRa[5] + s * (eRa[6] + s * eRa[7])
742
751
  )))))
743
752
 
744
- s = 1.0 + s * (eSa[0] + s * (eSa[1] + s *
745
- (eSa[2] + s * (eSa[3] + s * (eSa[4] + s *
753
+ s = 1.0 + s * (eSa[0] + s * (eSa[1] + s *
754
+ (eSa[2] + s * (eSa[3] + s * (eSa[4] + s *
746
755
  (eSa[5] + s * (eSa[6] + s * eSa[7])))))))
747
756
 
748
757
  else
749
- r = eRb[0] + s * (eRb[1] + s *
750
- (eRb[2] + s * (eRb[3] + s * (eRb[4] + s *
758
+ r = eRb[0] + s * (eRb[1] + s *
759
+ (eRb[2] + s * (eRb[3] + s * (eRb[4] + s *
751
760
  (eRb[5] + s * eRb[6])))))
752
761
 
753
- s = 1.0 + s * (eSb[0] + s *
754
- (eSb[1] + s * (eSb[2] + s * (eSb[3] + s *
762
+ s = 1.0 + s * (eSb[0] + s *
763
+ (eSb[1] + s * (eSb[2] + s * (eSb[3] + s *
755
764
  (eSb[4] + s * (eSb[5] + s * eSb[6]))))))
756
765
  end
757
766
  retval = Math.exp(-x * x - 0.5625 + r/s) / abs_x
758
767
  end
759
768
  return ( if x >= 0.0 then retval else 2.0 - retval end )
760
- end
769
+ end
761
770
  end
762
771
  end
@@ -0,0 +1,73 @@
1
+ require 'rubystats/probability_distribution'
2
+ require 'rubystats/normal_distribution'
3
+ require 'matrix'
4
+
5
+ module Rubystats
6
+ module MultivariateDistribution
7
+ #override probability_distribution pdf function to work with multivariate input variables
8
+ def pdf(x)
9
+ get_pdf(x)
10
+ end
11
+ end
12
+ class MultivariateNormalDistribution < Rubystats::ProbabilityDistribution
13
+ include Rubystats::NumericalConstants
14
+ include Rubystats::MultivariateDistribution
15
+
16
+ def initialize(mu=[0.0,0.0],sigma=[[1.0,0.0],[0.0,1.0]])
17
+ raise "dimensions of mu vector and sigma matrix doesn't match" if mu.size != sigma.size
18
+ sigma.each{|row| raise "row dim of sigma does not match mu vector" if row.size != mu.size }
19
+
20
+ mu_f = mu.collect{|x| x.to_f }
21
+ sigma_f = sigma.collect{|row| row.collect{|x| x.to_f}}
22
+
23
+ @mu = Vector.elements(mu_f)
24
+ @sigma = Matrix.rows(sigma_f)
25
+ u, d, u_inv = @sigma.eigensystem
26
+ @sigma_inv = u * (1/d) * u_inv
27
+ @a = u * (d)**(0.5)
28
+
29
+ @pdf_factor = 1.0 / Math.sqrt((TWO_PI * @sigma).determinant.to_f)
30
+ @stdnorm = Rubystats::NormalDistribution.new(0.0,1.0)
31
+ end
32
+
33
+ private
34
+
35
+ def get_mean
36
+ @mu.to_a
37
+ end
38
+
39
+ def get_variance
40
+ raise "variance for multivariate normal distribution not implemented"
41
+ end
42
+
43
+ # Private method to obtain single PDF value.
44
+ # x should be greater than 0
45
+ # returns the probability that a stochastic variable x has the value X, i.e. P(x=X).
46
+ def get_pdf(x)
47
+ d = Vector.elements(x) - @mu
48
+ @pdf_factor * Math.exp(-0.5 * d.inner_product(@sigma_inv*d).to_f)
49
+ end
50
+
51
+ # Private method to obtain single CDF value.
52
+ # param x should be greater than 0
53
+ # return the probability that a stochastic variable x is less then X, i.e. P(x<X).
54
+ def get_cdf(x)
55
+ raise "cdf for multivariate normal distribution not implemented"
56
+ end
57
+
58
+ # Private method to obtain single inverse CDF value.
59
+ # return the value X for which P(x<X).
60
+ def get_icdf(p)
61
+ check_range(p)
62
+ raise "inverse cdf for multivariate normal distribution not implemented"
63
+ end
64
+
65
+ # Private method to obtain single RNG value.
66
+ def get_rng
67
+ z = Vector.elements(@mu.collect{ @stdnorm.rng })
68
+ (@mu + @a * z).to_a
69
+ end
70
+
71
+ end
72
+ end
73
+
@@ -11,14 +11,15 @@ module Rubystats
11
11
  # Constructs a normal distribution (defaults to zero mean and
12
12
  # unity variance).
13
13
  def initialize(mu=0.0, sigma=1.0)
14
- @mean = mu
14
+ @mean = mu.to_f
15
15
  if sigma <= 0.0
16
- return "error"
16
+ raise "error, invalid sigma #{sigma}, should be > 0"
17
17
  end
18
- @stdev = sigma
18
+ @stdev = sigma.to_f
19
19
  @variance = sigma**2
20
20
  @pdf_denominator = SQRT2PI * Math.sqrt(@variance)
21
21
  @cdf_denominator = SQRT2 * Math.sqrt(@variance)
22
+ @use_last = nil
22
23
  end
23
24
 
24
25
  # Returns the mean of the distribution
@@ -0,0 +1,78 @@
1
+ require 'rubystats/probability_distribution'
2
+
3
+ module Rubystats
4
+ class PoissonDistribution < Rubystats::ProbabilityDistribution
5
+ include Rubystats::MakeDiscrete
6
+
7
+ # Constructs a Poisson distribution
8
+ def initialize (rate)
9
+ if rate <= 0.0
10
+ raise ArgumentError.new("The rate for the Poisson distribution should be greater than zero.")
11
+ end
12
+ @rate = rate.to_f
13
+ end
14
+
15
+ #returns the mean
16
+ def get_mean
17
+ @rate
18
+ end
19
+
20
+ #returns the variance
21
+ def get_variance
22
+ @rate
23
+ end
24
+
25
+ # Private methods below
26
+
27
+ private
28
+
29
+ # Probability mass function of a Poisson distribution .
30
+ # k should be an integer
31
+ # returns the probability that a stochastic variable x has the value k,
32
+ # i.e. P(x = k)
33
+ def get_pdf(k)
34
+ raise ArgumentError.new("Poisson pdf: k needs to be >= 0") if k < 0
35
+ (@rate**k) * Math.exp(-@rate) / get_factorial(k).to_f
36
+ end
37
+
38
+ # Private shared function for getting cumulant for particular x
39
+ # param k should be integer-valued
40
+ # returns the probability that a stochastic variable x is less than _x
41
+ # i.e P(x < k)
42
+ def get_cdf(k)
43
+ raise ArgumentError.new("Poisson pdf: k needs to be >= 0") if k < 0
44
+ sum = 0.0
45
+ for i in (0 .. k)
46
+ sum = sum + get_pdf(i)
47
+ end
48
+ return sum
49
+ end
50
+
51
+ # Inverse of the cumulative Poisson distribution function
52
+ def get_icdf(prob)
53
+ check_range(prob)
54
+ sum = 0.0
55
+ k = 0
56
+ until prob <= sum
57
+ sum += get_pdf(k)
58
+ k += 1
59
+ end
60
+ return k - 1
61
+ end
62
+
63
+ # Private Poisson RNG function
64
+ # Poisson generator based upon the inversion by sequential search
65
+ def get_rng
66
+ x = 0
67
+ p = Math.exp(-@rate)
68
+ s = p
69
+ u = Kernel.rand
70
+ while u > s
71
+ x += 1
72
+ p *= @rate / x.to_f
73
+ s += p
74
+ end
75
+ x
76
+ end
77
+ end
78
+ end
@@ -122,15 +122,15 @@ module Rubystats
122
122
  def check_range(x, lo=0.0, hi=1.0)
123
123
  raise ArgumentError.new("x cannot be nil") if x.nil?
124
124
  if x < lo or x > hi
125
- raise ArgumentError.new("x must be less than lo (#{lo}) and greater than hi (#{hi})")
125
+ raise ArgumentError.new("x must be greater than lo (#{lo}) and less than hi (#{hi})")
126
126
  end
127
127
  end
128
128
 
129
129
  def get_factorial(n)
130
130
  if n <= 1
131
131
  return 1
132
- else
133
- return n * get_factorial(n-1)
132
+ else
133
+ return n.downto(1).reduce(:*)
134
134
  end
135
135
  end
136
136
 
@@ -154,7 +154,7 @@ module Rubystats
154
154
  _pdf = pdf(x)
155
155
  if _pdf != 0.0
156
156
  dx = error / _pdf
157
- x_new = x -dx
157
+ x_new = x - dx
158
158
  end
159
159
  # If the NR fails to converge (which for example may be the
160
160
  # case if the initial guess is too rough) we apply a bisection
@@ -0,0 +1,62 @@
1
+ require 'rubystats/probability_distribution'
2
+ require 'rubystats/normal_distribution'
3
+ # This class provides an object for encapsulating student t distributions
4
+ module Rubystats
5
+ class StudentTDistribution < Rubystats::ProbabilityDistribution
6
+ include Rubystats::SpecialMath
7
+
8
+ # Constructs a student t distribution.
9
+ def initialize(degree_of_freedom=1.0)
10
+ raise "Argument Error: degrees of freedom for student t distribution must be greater than zero." if degree_of_freedom <= 0.0
11
+ @dof = degree_of_freedom.to_f
12
+ @pdf_factor = Math.gamma((@dof + 1.0) / 2.0) / ( Math.sqrt(@dof * Math::PI) * Math.gamma(@dof / 2.0))
13
+ @stdnorm = Rubystats::NormalDistribution.new(0.0,1.0)
14
+ end
15
+
16
+ # Returns the mean of the distribution
17
+ def get_mean
18
+ (@dof > 1) ? 0.0 : Float::NAN
19
+ end
20
+
21
+ # Returns the standard deviation of the distribution
22
+ def get_standard_deviation
23
+ return Math.sqrt(get_variance)
24
+ end
25
+
26
+ # Returns the variance of the distribution
27
+ def get_variance
28
+ (@dof > 2.0) ? (@dof / (@dof - 2)) : Float::NAN
29
+ end
30
+
31
+ private
32
+
33
+ # Obtain single PDF value
34
+ # Returns the probability that a stochastic variable x has the value X,
35
+ # i.e. P(x=X)
36
+ def get_pdf(x)
37
+ return @pdf_factor * (1.0 + (x**2.0) / @dof)**(-(@dof+1.0)/2.0)
38
+ end
39
+
40
+ # Obtain single CDF value
41
+ # Returns the probability that a stochastic variable x is less than X,
42
+ # i.e. P(x<X)
43
+ def get_cdf(x)
44
+ raise "method 'cdf' not implemented for student t"
45
+ end
46
+
47
+ # Obtain single inverse CDF value.
48
+ # returns the value X for which P(x&lt;X).
49
+ def get_icdf(p)
50
+ raise "method 'icdf' not implemented for student t"
51
+ end
52
+
53
+ # returns single random number from the student t distribution
54
+ def get_rng
55
+ k = @dof.to_i
56
+ samples = []
57
+ k.times {|i| samples << @stdnorm.rng }
58
+ factor = 1.0 / Math.sqrt(samples.inject(0.0) {|sum,x| sum + x**2} / k)
59
+ return (factor * @stdnorm.rng)
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,70 @@
1
+ require 'rubystats/probability_distribution'
2
+ # This class provides an object for encapsulating uniform distributions
3
+ module Rubystats
4
+ class UniformDistribution < Rubystats::ProbabilityDistribution
5
+ include Rubystats::SpecialMath
6
+
7
+ # Constructs a uniform distribution (defaults to zero lower and
8
+ # unity upper bound).
9
+ def initialize(lower=0.0, upper=1.0)
10
+ lower,upper = upper,lower if lower > upper
11
+ @lower = lower.to_f
12
+ @upper = upper.to_f
13
+ @pdf_denominator = 1.0 / (@upper - @lower)
14
+ @use_last = nil
15
+ end
16
+
17
+ # Returns the mean of the distribution
18
+ def get_mean
19
+ return 0.5*(@lower + @upper)
20
+ end
21
+
22
+ # Returns the standard deviation of the distribution
23
+ def get_standard_deviation
24
+ return Math.sqrt(get_variance)
25
+ end
26
+
27
+ # Returns the variance of the distribution
28
+ def get_variance
29
+ return 1.0/12.0 * (@upper-@lower)**2
30
+ end
31
+
32
+ private
33
+
34
+ # Obtain single PDF value
35
+ # Returns the probability that a stochastic variable x has the value X,
36
+ # i.e. P(x=X)
37
+ def get_pdf(x)
38
+ if x >= @lower && x <= @upper
39
+ @pdf_denominator
40
+ else
41
+ 0.0
42
+ end
43
+ end
44
+
45
+ # Obtain single CDF value
46
+ # Returns the probability that a stochastic variable x is less than X,
47
+ # i.e. P(x<X)
48
+ def get_cdf(x)
49
+ if x >= @lower && x < @upper
50
+ (x - @lower).fdiv(@upper - @lower)
51
+ elsif x >= @upper
52
+ 1.0
53
+ else
54
+ 0.0
55
+ end
56
+ end
57
+
58
+ # Obtain single inverse CDF value.
59
+ # returns the value X for which P(x&lt;X).
60
+ def get_icdf(p)
61
+ check_range(p)
62
+ return @lower + p.to_f * (@upper - @lower)
63
+ end
64
+
65
+ # returns single random number
66
+ def get_rng
67
+ return @lower + (@upper - @lower) * Kernel.rand
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,3 @@
1
+ module Rubystats
2
+ VERSION = '0.4.1'
3
+ end