File Coverage

blib/lib/Statistics/GammaDistribution.pm
Criterion Covered Total %
statement 71 75 94.6
branch 10 14 71.4
condition 3 9 33.3
subroutine 13 14 92.8
pod 4 6 66.6
total 101 118 85.5


line stmt bran cond sub pod time code
1             package Statistics::GammaDistribution;
2 2     2   60400 use strict;
  2         5  
  2         71  
3 2     2   10 use warnings;
  2         4  
  2         60  
4 2     2   13 use vars qw ( $VERSION );
  2         7  
  2         1713  
5             $VERSION = 0.02;
6              
7             sub PI(){ 3.14159265358979323846264338328; }
8             sub E() { 2.71828182845904523536028747135; }
9              
10             sub new
11             {
12 1     1 1 12 my ($caller,%args) = @_;
13 1   33     8 my $class = ref($caller) || $caller;
14 1         3 my $self = bless {}, $class;
15 1         5 $self->_init(%args);
16 1         3 return $self;
17             }
18              
19             sub _init
20             {
21 1     1   1 my ($self,%args) = @_;
22 1         2 return $self;
23             }
24              
25             sub get_order
26             {
27 0     0 0 0 my ($self) = @_;
28 0         0 return $self->{_a};
29             }
30              
31             sub set_order
32             {
33 12     12 1 22 my ($self,$order) = @_;
34 12         21 $self->{_a} = $order;
35 12         16 $self->{_na} = int($order);
36 12         18 return $self->{_a};
37             }
38              
39             sub rand
40             {
41 12     12 1 24 my ($self,$scale) = shift;
42 12 50       23 $scale = 1 unless defined $scale;
43 12         14 my $order = $self->{_a};
44 12         12 my $n_order = $self->{_na};
45              
46 12 50 33     49 die('Statistics::GammaDistribution::rand() - order of distribution must be set greater than zero using set_order()')
47             unless ((defined $order) && ($order>0));
48            
49 12 100       25 if ($order == $n_order){
    100          
50 3         5 return $scale * _gamma_int($n_order);
51             } elsif ($n_order == 0) {
52 4         28 return $scale * _gamma_frac($order);
53             } else {
54 5         9 return $scale * (_gamma_int($n_order) + _gamma_frac($order-$n_order));
55             }
56             }
57              
58             # random number between zero and one,
59             # NOT including zero
60             sub _rand_nonzero
61             {
62 23     23   13 my $rand;
63 23         83 while(!($rand = CORE::rand()))
64             {
65             # loop
66             }
67 23         42 return $rand;
68             }
69              
70             sub _gamma_int
71             {
72 8     8   10 my $order = shift;
73 8 100       12 if ($order < 12){
74 4         5 my $prod = 1;
75 4         11 for (my $i=0; $i<$order; $i++){
76 12         16 $prod *= _rand_nonzero();
77             }
78 4         24 return -log($prod);
79             } else {
80 4         7 return _gamma_large_int($order);
81             }
82             }
83              
84 6     6 0 33 sub tan($){ sin($_[0])/cos($_[0]); }
85              
86             sub _gamma_large_int
87             {
88 4     4   5 my $order = shift;
89 4         8 my $sqrt = sqrt(2 * $order - 1);
90 4         6 my ($x,$y,$v);
91 4         3 do {
92 6         5 do {
93 6         13 $y = tan(PI * CORE::rand());
94 6         46 $x = $sqrt * $y + $order - 1;
95             } while ($x <= 0);
96 6         26 $v = CORE::rand();
97             } while ($v > (1+$y*$y) * exp(($order-1) * log($x/($order-1)) - $sqrt*$y));
98 4         12 return $x;
99             }
100              
101             sub _gamma_frac
102             {
103 9     9   11 my $order = shift;
104 9         10 my $p = E / ($order + E);
105 9         10 my ($q, $x, $u, $v);
106            
107 9         9 do {
108 11         8 $u = CORE::rand();
109 11         18 $v = _rand_nonzero();
110 11 50       20 if ($u < $p){
111 11         30 $x = exp((1/$order) * log($v));
112 11         36 $q = exp(-$x);
113             } else {
114 0         0 $x = 1 - log($v);
115 0         0 $q = exp(($order - 1) * log($x));
116             }
117             } while (CORE::rand() >= $q);
118 9         26 return $x;
119             }
120              
121             sub dirichlet_dist
122             {
123 1     1 1 349 my ($self,@alpha) = @_;
124 1         2 my @theta;
125 1         2 my $norm = 0.0;
126              
127 1         4 for(my $i=0; $i<=$#alpha; $i++){
128 8         9 my $order = $alpha[$i];
129 8 50 33     32 die('Statistics::GammaDistribution::dirichlet_dist() - every parameter must be greater than zero')
130             unless ((defined $order) && ($order>0));
131 8         17 $self->set_order($order);
132 8         11 $theta[$i] = $self->rand(1);
133 8         23 $norm += $theta[$i];
134             }
135              
136 1         4 for(my $i=0; $i<=$#theta; $i++){
137 8         17 $theta[$i] /= $norm;
138             }
139              
140 1         5 return @theta;
141             }
142              
143             1;
144              
145             __END__