Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
89.80% |
44 / 49 |
|
80.00% |
4 / 5 |
CRAP | |
0.00% |
0 / 1 |
Beta | |
89.80% |
44 / 49 |
|
80.00% |
4 / 5 |
21.47 | |
0.00% |
0 / 1 |
__construct | n/a |
0 / 0 |
n/a |
0 / 0 |
1 | |||||
incompleteBeta | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
regularizedBeta | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
7 | |||
betaFraction | |
85.29% |
29 / 34 |
|
0.00% |
0 / 1 |
7.16 | |||
logBeta | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
4 | |||
beta | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | /** |
3 | * Jingga |
4 | * |
5 | * PHP Version 8.1 |
6 | * |
7 | * @package phpOMS\Math\Functions |
8 | * @copyright Dennis Eichhorn |
9 | * @license OMS License 2.0 |
10 | * @version 1.0.0 |
11 | * @link https://jingga.app |
12 | */ |
13 | declare(strict_types=1); |
14 | |
15 | namespace phpOMS\Math\Functions; |
16 | |
17 | /** |
18 | * Beta function |
19 | * |
20 | * @package phpOMS\Math\Functions |
21 | * @license OMS License 2.0 |
22 | * @link https://jingga.app |
23 | * @since 1.0.0 |
24 | */ |
25 | final class Beta |
26 | { |
27 | /** |
28 | * Constructor. |
29 | * |
30 | * @since 1.0.0 |
31 | * @codeCoverageIgnore |
32 | */ |
33 | private function __construct() |
34 | { |
35 | } |
36 | |
37 | /** |
38 | * Incomplete beta function |
39 | * |
40 | * @param float $x Value |
41 | * @param float $p p |
42 | * @param float $q q |
43 | * |
44 | * @return float |
45 | * |
46 | * @since 1.0.0 |
47 | */ |
48 | public static function incompleteBeta(float $x, float $p, float $q) : float |
49 | { |
50 | return self::regularizedBeta($x, $p, $q) * self::beta($p, $q); |
51 | } |
52 | |
53 | /** |
54 | * Incomplete beta function |
55 | * |
56 | * @param float $x Value |
57 | * @param float $p p |
58 | * @param float $q q |
59 | * |
60 | * @return float |
61 | * |
62 | * @since 1.0.0 |
63 | */ |
64 | public static function regularizedBeta(float $x, float $p, float $q) : float |
65 | { |
66 | if ($x <= 0.0) { |
67 | return 0.0; |
68 | } elseif ($x >= 1.0) { |
69 | return 1.0; |
70 | } elseif ($p <= 0.0 || $q <= 0.0 || $p + $q > 10000000000.0) { |
71 | return 0.0; |
72 | } |
73 | |
74 | $bGamma = \exp(-self::logBeta($p, $q) + $p * \log($x) + $q * \log(1.0 - $x)); |
75 | |
76 | // this uses the symmetry of the beta function |
77 | return ($x < ($p + 1.0) / ($p + $q + 2.0) |
78 | ? $bGamma * self::betaFraction($x, $p, $q) / $p |
79 | : 1.0 - $bGamma * self::betaFraction(1.0 - $x, $q, $p) / $q); |
80 | } |
81 | |
82 | /** |
83 | * Fraction of the beta function |
84 | * |
85 | * @param float $x Value |
86 | * @param float $p p |
87 | * @param float $q q |
88 | * |
89 | * @see JSci |
90 | * @author Jaco van Kooten |
91 | * @license LGPL 2.1 |
92 | * @since 1.0.0 |
93 | */ |
94 | private static function betaFraction(float $x, float $p, float $q) : float |
95 | { |
96 | $c = 1.0; |
97 | $pqSum = $p + $q; |
98 | $pPlus = $p + 1.0; |
99 | $pMinus = $p - 1.0; |
100 | $h = 1.0 - $pqSum * $x / $pPlus; |
101 | |
102 | if (\abs($h) < 1.18e-37) { |
103 | $h = 1.18e-37; |
104 | } |
105 | |
106 | $h = 1.0 / $h; |
107 | $frac = $h; |
108 | $m = 1; |
109 | $delta = 0.0; |
110 | |
111 | do { |
112 | $m2 = 2 * $m; |
113 | $d = $m * ($q - $m) * $x / (($pMinus + $m2) * ($p + $m2)); |
114 | $h = 1.0 + $d * $h; |
115 | if (\abs($h) < 1.18e-37) { |
116 | $h = 1.18e-37; |
117 | } |
118 | |
119 | $h = 1.0 / $h; |
120 | $c = 1.0 + $d / $c; |
121 | if (\abs($c) < 1.18e-37) { |
122 | $c = 1.18e-37; |
123 | } |
124 | |
125 | $frac *= $h * $c; |
126 | $d = -($p + $m) * ($pqSum + $m) * $x / (($p + $m2) * ($pPlus + $m2)); |
127 | $h = 1.0 + $d * $h; |
128 | if (\abs($h) < 1.18e-37) { |
129 | $h = 1.18e-37; |
130 | } |
131 | |
132 | $h = 1.0 / $h; |
133 | $c = 1.0 + $d / $c; |
134 | if (\abs($c) < 1.18e-37) { |
135 | $c = 1.18e-37; |
136 | } |
137 | |
138 | $delta = $h * $c; |
139 | $frac *= $delta; |
140 | ++$m; |
141 | } while ($m < 1000000 && \abs($delta - 1.0) > 8.88e-16); |
142 | |
143 | return $frac; |
144 | } |
145 | |
146 | /** |
147 | * Log of Beta |
148 | * |
149 | * @param float $p p |
150 | * @param float $q q |
151 | * |
152 | * @return float |
153 | * |
154 | * @since 1.0.0 |
155 | */ |
156 | public static function logBeta(float $p, float $q) : float |
157 | { |
158 | return $p <= 0.0 || $q <= 0.0 || $p + $q > 10000000000.0 |
159 | ? 0.0 |
160 | : Gamma::logGamma($p) + Gamma::logGamma($q) - Gamma::logGamma($p + $q); |
161 | } |
162 | |
163 | /** |
164 | * Beta |
165 | * |
166 | * @param float $p p |
167 | * @param float $q q |
168 | * |
169 | * @return float |
170 | * |
171 | * @since 1.0.0 |
172 | */ |
173 | public static function beta(float $p, float $q) : float |
174 | { |
175 | return \exp(self::logBeta($p, $q)); |
176 | } |
177 | } |