ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
ChiSquared.php
Go to the documentation of this file.
1<?php
2
4
7
9{
10 private const MAX_ITERATIONS = 256;
11
12 private const EPS = 2.22e-16;
13
24 public static function distributionRightTail($value, $degrees)
25 {
26 $value = Functions::flattenSingleValue($value);
27 $degrees = Functions::flattenSingleValue($degrees);
28
29 try {
31 $degrees = DistributionValidations::validateInt($degrees);
32 } catch (Exception $e) {
33 return $e->getMessage();
34 }
35
36 if ($degrees < 1) {
37 return Functions::NAN();
38 }
39 if ($value < 0) {
41 return 1;
42 }
43
44 return Functions::NAN();
45 }
46
47 return 1 - (Gamma::incompleteGamma($degrees / 2, $value / 2) / Gamma::gammaValue($degrees / 2));
48 }
49
61 public static function distributionLeftTail($value, $degrees, $cumulative)
62 {
63 $value = Functions::flattenSingleValue($value);
64 $degrees = Functions::flattenSingleValue($degrees);
65 $cumulative = Functions::flattenSingleValue($cumulative);
66
67 try {
69 $degrees = DistributionValidations::validateInt($degrees);
70 $cumulative = DistributionValidations::validateBool($cumulative);
71 } catch (Exception $e) {
72 return $e->getMessage();
73 }
74
75 if ($degrees < 1) {
76 return Functions::NAN();
77 }
78 if ($value < 0) {
80 return 1;
81 }
82
83 return Functions::NAN();
84 }
85
86 if ($cumulative === true) {
87 return 1 - self::distributionRightTail($value, $degrees);
88 }
89
90 return (($value ** (($degrees / 2) - 1) * exp(-$value / 2))) /
91 ((2 ** ($degrees / 2)) * Gamma::gammaValue($degrees / 2));
92 }
93
104 public static function inverseRightTail($probability, $degrees)
105 {
106 $probability = Functions::flattenSingleValue($probability);
107 $degrees = Functions::flattenSingleValue($degrees);
108
109 try {
110 $probability = DistributionValidations::validateProbability($probability);
111 $degrees = DistributionValidations::validateInt($degrees);
112 } catch (Exception $e) {
113 return $e->getMessage();
114 }
115
116 if ($degrees < 1) {
117 return Functions::NAN();
118 }
119
120 $callback = function ($value) use ($degrees) {
121 return 1 - (Gamma::incompleteGamma($degrees / 2, $value / 2)
122 / Gamma::gammaValue($degrees / 2));
123 };
124
125 $newtonRaphson = new NewtonRaphson($callback);
126
127 return $newtonRaphson->execute($probability);
128 }
129
140 public static function inverseLeftTail($probability, $degrees)
141 {
142 $probability = Functions::flattenSingleValue($probability);
143 $degrees = Functions::flattenSingleValue($degrees);
144
145 try {
146 $probability = DistributionValidations::validateProbability($probability);
147 $degrees = DistributionValidations::validateInt($degrees);
148 } catch (Exception $e) {
149 return $e->getMessage();
150 }
151
152 if ($degrees < 1) {
153 return Functions::NAN();
154 }
155
156 return self::inverseLeftTailCalculation($probability, $degrees);
157 }
158
171 public static function test($actual, $expected)
172 {
173 $rows = count($actual);
174 $actual = Functions::flattenArray($actual);
175 $expected = Functions::flattenArray($expected);
176 $columns = count($actual) / $rows;
177
178 $countActuals = count($actual);
179 $countExpected = count($expected);
180 if ($countActuals !== $countExpected || $countActuals === 1) {
181 return Functions::NAN();
182 }
183
184 $result = 0.0;
185 for ($i = 0; $i < $countActuals; ++$i) {
186 if ($expected[$i] == 0.0) {
187 return Functions::DIV0();
188 } elseif ($expected[$i] < 0.0) {
189 return Functions::NAN();
190 }
191 $result += (($actual[$i] - $expected[$i]) ** 2) / $expected[$i];
192 }
193
194 $degrees = self::degrees($rows, $columns);
195
197
198 return $result;
199 }
200
201 protected static function degrees(int $rows, int $columns): int
202 {
203 if ($rows === 1) {
204 return $columns - 1;
205 } elseif ($columns === 1) {
206 return $rows - 1;
207 }
208
209 return ($columns - 1) * ($rows - 1);
210 }
211
212 private static function inverseLeftTailCalculation(float $probability, int $degrees): float
213 {
214 // bracket the root
215 $min = 0;
216 $sd = sqrt(2.0 * $degrees);
217 $max = 2 * $sd;
218 $s = -1;
219
220 while ($s * self::pchisq($max, $degrees) > $probability * $s) {
221 $min = $max;
222 $max += 2 * $sd;
223 }
224
225 // Find root using bisection
226 $chi2 = 0.5 * ($min + $max);
227
228 while (($max - $min) > self::EPS * $chi2) {
229 if ($s * self::pchisq($chi2, $degrees) > $probability * $s) {
230 $min = $chi2;
231 } else {
232 $max = $chi2;
233 }
234 $chi2 = 0.5 * ($min + $max);
235 }
236
237 return $chi2;
238 }
239
240 private static function pchisq($chi2, $degrees)
241 {
242 return self::gammp($degrees, 0.5 * $chi2);
243 }
244
245 private static function gammp($n, $x)
246 {
247 if ($x < 0.5 * $n + 1) {
248 return self::gser($n, $x);
249 }
250
251 return 1 - self::gcf($n, $x);
252 }
253
254 // Return the incomplete gamma function P(n/2,x) evaluated by
255 // series representation. Algorithm from numerical recipe.
256 // Assume that n is a positive integer and x>0, won't check arguments.
257 // Relative error controlled by the eps parameter
258 private static function gser($n, $x)
259 {
260 $gln = Gamma::ln($n / 2);
261 $a = 0.5 * $n;
262 $ap = $a;
263 $sum = 1.0 / $a;
264 $del = $sum;
265 for ($i = 1; $i < 101; ++$i) {
266 ++$ap;
267 $del = $del * $x / $ap;
268 $sum += $del;
269 if ($del < $sum * self::EPS) {
270 break;
271 }
272 }
273
274 return $sum * exp(-$x + $a * log($x) - $gln);
275 }
276
277 // Return the incomplete gamma function Q(n/2,x) evaluated by
278 // its continued fraction representation. Algorithm from numerical recipe.
279 // Assume that n is a postive integer and x>0, won't check arguments.
280 // Relative error controlled by the eps parameter
281 private static function gcf($n, $x)
282 {
283 $gln = Gamma::ln($n / 2);
284 $a = 0.5 * $n;
285 $b = $x + 1 - $a;
286 $fpmin = 1.e-300;
287 $c = 1 / $fpmin;
288 $d = 1 / $b;
289 $h = $d;
290 for ($i = 1; $i < 101; ++$i) {
291 $an = -$i * ($i - $a);
292 $b += 2;
293 $d = $an * $d + $b;
294 if (abs($d) < $fpmin) {
295 $d = $fpmin;
296 }
297 $c = $b + $an / $c;
298 if (abs($c) < $fpmin) {
299 $c = $fpmin;
300 }
301 $d = 1 / $d;
302 $del = $d * $c;
303 $h = $h * $del;
304 if (abs($del - 1) < self::EPS) {
305 break;
306 }
307 }
308
309 return $h * exp(-$x + $a * log($x) - $gln);
310 }
311}
$result
$n
Definition: RandomTest.php:85
if(! $in) $columns
Definition: Utf8Test.php:45
An exception for terminatinating execution or to throw for unit testing.
static flattenArray($array)
Convert a multi-dimensional array to a simple 1-dimensional array.
Definition: Functions.php:583
static flattenSingleValue($value='')
Convert an array to a single scalar value by extracting the first element.
Definition: Functions.php:649
static getCompatibilityMode()
Return the current Compatibility Mode.
Definition: Functions.php:93
static distributionLeftTail($value, $degrees, $cumulative)
CHIDIST.
Definition: ChiSquared.php:61
static inverseLeftTailCalculation(float $probability, int $degrees)
Definition: ChiSquared.php:212
$x
Definition: complexTest.php:9
for( $i=6;$i< 13;$i++) for($i=1; $i< 13; $i++) $d
Definition: date.php:296
$i
Definition: disco.tpl.php:19
$h
$s
Definition: pwgen.php:45
$rows
Definition: xhr_table.php:10