Failed Conditions
Pull Request — master (#47)
by Jordan
06:42 queued 03:44
created

StatsProvider::normalCDF()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 30
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 19
nc 1
nop 1
dl 0
loc 30
ccs 0
cts 20
cp 0
crap 2
rs 9.6333
c 0
b 0
f 0
1
<?php
2
3
namespace Samsara\Fermat\Provider;
4
5
use Samsara\Exceptions\UsageError\IntegrityConstraint;
6
use Samsara\Exceptions\SystemError\LogicalError\IncompatibleObjectState;
7
use Samsara\Exceptions\UsageError\OptionalExit;
8
use Samsara\Fermat\Numbers;
9
use Samsara\Fermat\Types\Base\Interfaces\Numbers\NumberInterface;
10
use Samsara\Fermat\Types\Base\Interfaces\Numbers\DecimalInterface;
11
use Samsara\Fermat\Types\Base\Interfaces\Numbers\FractionInterface;
12
use Samsara\Fermat\Values\ImmutableDecimal;
13
14
class StatsProvider
15
{
16
17
    /**
18
     * @param $x
19
     *
20
     * @return NumberInterface
21
     * @throws IntegrityConstraint
22
     * @throws OptionalExit
23
     */
24
    public static function normalCDF($x)
25
    {
26
        $x = Numbers::makeOrDont(Numbers::IMMUTABLE, $x);
27
28
        $pi = Numbers::makePi();
29
        $e = Numbers::makeE();
30
        $one = Numbers::makeOne();
31
32
        $eExponent = Numbers::make(Numbers::IMMUTABLE, $x->getValue());
0 ignored issues
show
Bug introduced by
The method getValue() does not exist on Samsara\Fermat\Types\Bas...Numbers\NumberInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Samsara\Fermat\Types\Bas...Numbers\NumberInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

32
        $eExponent = Numbers::make(Numbers::IMMUTABLE, $x->/** @scrutinizer ignore-call */ getValue());
Loading history...
33
        $eExponent = $eExponent->pow(2)->divide(2)->multiply(-1);
34
35
        $answer = Numbers::make(Numbers::IMMUTABLE, 0.5);
36
        $answer = $answer->add(
37
            $one->divide($pi->multiply(2)->sqrt())
38
                ->multiply($e->pow($eExponent))
39
                ->multiply(SeriesProvider::maclaurinSeries(
40
                    $x,
41
                    function ($n) {
0 ignored issues
show
Unused Code introduced by
The parameter $n is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

41
                    function (/** @scrutinizer ignore-unused */ $n) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
42
                        return Numbers::makeOne();
43
                    },
44
                    function ($n) {
45
                        return SequenceProvider::nthOddNumber($n);
46
                    },
47
                    function ($n) {
48
                        return SequenceProvider::nthOddNumber($n)->doubleFactorial();
0 ignored issues
show
Bug introduced by
The method doubleFactorial() does not exist on Samsara\Fermat\Types\Bas...Numbers\NumberInterface. It seems like you code against a sub-type of Samsara\Fermat\Types\Bas...Numbers\NumberInterface such as Samsara\Fermat\Types\Bas...umbers\DecimalInterface or Samsara\Fermat\Types\Decimal. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

48
                        return SequenceProvider::nthOddNumber($n)->/** @scrutinizer ignore-call */ doubleFactorial();
Loading history...
49
                    }
50
                ))
51
        );
52
53
        return $answer;
54
55
    }
56
57
    /**
58
     * @param $x
59
     *
60
     * @return DecimalInterface|NumberInterface
61
     * @throws IntegrityConstraint
62
     * @throws OptionalExit
63
     */
64
    public static function complementNormalCDF($x)
65
    {
66
        $p = self::normalCDF($x);
67
        $one = Numbers::makeOne();
68
69
        return $one->subtract($p);
70
    }
71
72
    /**
73
     * @param $x
74
     *
75
     * @return DecimalInterface|FractionInterface|NumberInterface|ImmutableDecimal
76
     * @throws IntegrityConstraint
77
     * @throws OptionalExit
78
     */
79 1
    public static function gaussErrorFunction($x)
80
    {
81
82 1
        $x = Numbers::makeOrDont(Numbers::IMMUTABLE, $x);
83 1
        $answer = Numbers::makeOne();
84 1
        $pi = Numbers::makePi();
85
86 1
        $answer = $answer->multiply(2)->divide($pi->sqrt());
87
88 1
        $answer = $answer->multiply(
89 1
            SeriesProvider::maclaurinSeries(
90 1
                $x,
91
                function ($n) {
92 1
                    $negOne = Numbers::make(Numbers::IMMUTABLE, -1);
93
94 1
                    return $negOne->pow($n);
0 ignored issues
show
Bug introduced by
The method pow() does not exist on Samsara\Fermat\Types\Bas...tes\CoordinateInterface. It seems like you code against a sub-type of Samsara\Fermat\Types\Bas...tes\CoordinateInterface such as Samsara\Fermat\Types\ComplexNumber or Samsara\Fermat\Types\ComplexNumber. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

94
                    return $negOne->/** @scrutinizer ignore-call */ pow($n);
Loading history...
Bug introduced by
The method pow() does not exist on Samsara\Fermat\Values\Ge...ems\CartesianCoordinate. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

94
                    return $negOne->/** @scrutinizer ignore-call */ pow($n);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
95 1
                },
96
                function ($n) {
97 1
                    return SequenceProvider::nthOddNumber($n);
98 1
                },
99
                function ($n) {
100 1
                    $n = Numbers::makeOrDont(Numbers::IMMUTABLE, $n);
101
102 1
                    return $n->factorial()->multiply(SequenceProvider::nthOddNumber($n));
0 ignored issues
show
Bug introduced by
The method factorial() does not exist on Samsara\Fermat\Types\Bas...Numbers\NumberInterface. It seems like you code against a sub-type of Samsara\Fermat\Types\Bas...Numbers\NumberInterface such as Samsara\Fermat\Types\Bas...umbers\DecimalInterface or Samsara\Fermat\Types\Decimal. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

102
                    return $n->/** @scrutinizer ignore-call */ factorial()->multiply(SequenceProvider::nthOddNumber($n));
Loading history...
103 1
                }
104
            )
105
        );
106
107 1
        return $answer;
108
109
    }
110
111
    /**
112
     * @param     $p
113
     * @param int $precision
114
     *
115
     * @return DecimalInterface|NumberInterface|ImmutableDecimal
116
     * @throws IntegrityConstraint
117
     * @throws OptionalExit
118
     */
119
    public static function inverseNormalCDF($p, int $precision = 10)
120
    {
121
        $pi = Numbers::makePi();
122
        $r2pi = $pi->multiply(2)->sqrt();
123
        $e = Numbers::makeE();
124
        $p = Numbers::makeOrDont(Numbers::IMMUTABLE, $p);
125
126
        $continue = true;
127
128
        $xCur = Numbers::make(Numbers::IMMUTABLE, $p);
129
130
        while ($continue) {
131
132
            $cumulative = self::normalCDF($xCur);
133
            $dx = $cumulative->subtract($p)->divide(
134
                $r2pi->multiply(
135
                    $e->pow(
136
                        $xCur->pow(2)
137
                    )->divide(-2)
138
                )
139
            );
140
            $xCur = $xCur->subtract($dx);
0 ignored issues
show
Bug introduced by
The method subtract() does not exist on Samsara\Fermat\Types\Bas...tes\CoordinateInterface. It seems like you code against a sub-type of Samsara\Fermat\Types\Bas...tes\CoordinateInterface such as Samsara\Fermat\Types\ComplexNumber or Samsara\Fermat\Types\ComplexNumber. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

140
            /** @scrutinizer ignore-call */ 
141
            $xCur = $xCur->subtract($dx);
Loading history...
Bug introduced by
The method subtract() does not exist on Samsara\Fermat\Values\Ge...ems\CartesianCoordinate. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

140
            /** @scrutinizer ignore-call */ 
141
            $xCur = $xCur->subtract($dx);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
141
142
            if ($dx->numberOfLeadingZeros() > $precision) {
0 ignored issues
show
Bug introduced by
The method numberOfLeadingZeros() does not exist on Samsara\Fermat\Types\Bas...Numbers\NumberInterface. It seems like you code against a sub-type of Samsara\Fermat\Types\Bas...Numbers\NumberInterface such as Samsara\Fermat\Types\Bas...umbers\DecimalInterface or Samsara\Fermat\Types\Decimal. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

142
            if ($dx->/** @scrutinizer ignore-call */ numberOfLeadingZeros() > $precision) {
Loading history...
Bug introduced by
The method numberOfLeadingZeros() does not exist on Samsara\Fermat\Types\Bas...mbers\FractionInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

142
            if ($dx->/** @scrutinizer ignore-call */ numberOfLeadingZeros() > $precision) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
143
                $continue = false;
144
            }
145
146
        }
147
148
        if ($p->isLessThan(0.5)) {
0 ignored issues
show
Bug introduced by
The method isLessThan() does not exist on Samsara\Fermat\Types\Bas...Numbers\NumberInterface. It seems like you code against a sub-type of Samsara\Fermat\Types\Bas...Numbers\NumberInterface such as Samsara\Fermat\Types\Bas...s\SimpleNumberInterface or Samsara\Fermat\Types\Fraction or Samsara\Fermat\Types\Decimal. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

148
        if ($p->/** @scrutinizer ignore-call */ isLessThan(0.5)) {
Loading history...
149
            return $xCur->multiply(-1);
150
        } else {
151
            return $xCur;
152
        }
153
    }
154
155
    /**
156
     * @param $n
157
     * @param $k
158
     *
159
     * @return DecimalInterface|NumberInterface|ImmutableDecimal
160
     * @throws IntegrityConstraint
161
     * @throws IncompatibleObjectState
162
     */
163
    public static function binomialCoefficient($n, $k)
164
    {
165
166
        $n = Numbers::makeOrDont(Numbers::IMMUTABLE, $n);
167
        $k = Numbers::makeOrDont(Numbers::IMMUTABLE, $k);
168
169
        if ($k->isLessThan(0) || $n->isLessThan($k)) {
170
            throw new IntegrityConstraint(
171
                '$k must be larger or equal to 0 and less than or equal to $n',
172
                'Provide valid $n and $k values such that 0 <= $k <= $n',
173
                'For $n choose $k, the values of $n and $k must satisfy the inequality 0 <= $k <= $n'
174
            );
175
        }
176
177
        if (!$n->isInt() || !$k->isInt()) {
0 ignored issues
show
Bug introduced by
The method isInt() does not exist on Samsara\Fermat\Types\Bas...Numbers\NumberInterface. It seems like you code against a sub-type of Samsara\Fermat\Types\Bas...Numbers\NumberInterface such as Samsara\Fermat\Types\Bas...umbers\DecimalInterface or Samsara\Fermat\Types\Fraction or Samsara\Fermat\Types\Fraction or Samsara\Fermat\Types\Decimal. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

177
        if (!$n->/** @scrutinizer ignore-call */ isInt() || !$k->isInt()) {
Loading history...
178
            throw new IntegrityConstraint(
179
                '$k and $n must be whole numbers',
180
                'Provide whole numbers for $n and $k',
181
                'For $n choose $k, the values $n and $k must be whole numbers'
182
            );
183
        }
184
185
        return $n->factorial()->divide($k->factorial()->multiply($n->subtract($k)->factorial()));
0 ignored issues
show
Bug introduced by
The method factorial() does not exist on Samsara\Fermat\Types\Bas...mbers\FractionInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

185
        return $n->factorial()->divide($k->factorial()->multiply($n->subtract($k)->/** @scrutinizer ignore-call */ factorial()));

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Bug introduced by
The method factorial() does not exist on Samsara\Fermat\Values\ImmutableComplexNumber. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

185
        return $n->factorial()->divide($k->factorial()->multiply($n->subtract($k)->/** @scrutinizer ignore-call */ factorial()));

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
186
187
    }
188
189
    /**
190
     * @param     $z
191
     * @param int $precision
192
     *
193
     * @return DecimalInterface|NumberInterface|ImmutableDecimal
194
     * @throws IntegrityConstraint
195
     */
196
    public static function gammaFunction($z, int $precision = 10)
197
    {
198
        $z = Numbers::makeOrDont(Numbers::IMMUTABLE, $z);
199
200
        if ($z->isInt()) {
201
            if ($z->isNegative() || $z->isEqual(0)) {
0 ignored issues
show
Bug introduced by
The method isNegative() does not exist on Samsara\Fermat\Types\Bas...Numbers\NumberInterface. It seems like you code against a sub-type of Samsara\Fermat\Types\Bas...Numbers\NumberInterface such as Samsara\Fermat\Types\Bas...s\SimpleNumberInterface or Samsara\Fermat\Types\Fraction or Samsara\Fermat\Types\Decimal. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

201
            if ($z->/** @scrutinizer ignore-call */ isNegative() || $z->isEqual(0)) {
Loading history...
202
                throw new IntegrityConstraint(
203
                    'Non-positive integers are not valid gamma function arguments',
204
                    'Do not provide non-positive integers to this function',
205
                    'The gamma function is not defined for zero or negative integers, but is continuous for all other values'
206
                );
207
            }
208
            return $z->subtract(1)->factorial();
209
        }
210
211
        $x = Numbers::makeZero();
212
        $e = Numbers::makeE();
213
        $gamma = Numbers::makeZero();
214
215
        $continue = true;
216
217
        while ($continue) {
218
219
            $adjustment = $x->pow(
220
                $z->subtract(1)
221
            )->multiply(
222
                $e->pow(
223
                    $x->multiply(-1)
224
                )
225
            );
226
227
            $gamma = $gamma->add($adjustment);
228
229
            if ($adjustment->numberOfLeadingZeros() > $precision) {
0 ignored issues
show
Bug introduced by
The method numberOfLeadingZeros() does not exist on Samsara\Fermat\Values\ImmutableComplexNumber. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

229
            if ($adjustment->/** @scrutinizer ignore-call */ numberOfLeadingZeros() > $precision) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
230
                $continue = false;
231
            }
232
233
        }
234
235
        return $gamma;
236
    }
237
238
}