Completed
Pull Request — dev (#23)
by Jordan
02:47
created

Exponential::pdf()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 22
Code Lines 10

Duplication

Lines 22
Ratio 100 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 22
loc 22
ccs 0
cts 14
cp 0
rs 9.2
c 0
b 0
f 0
cc 2
eloc 10
nc 2
nop 1
crap 6
1
<?php
2
3
namespace Samsara\Fermat\Provider\Distribution;
4
5
use RandomLib\Factory;
6
use Samsara\Exceptions\UsageError\IntegrityConstraint;
7
use Samsara\Exceptions\UsageError\OptionalExit;
8
use Samsara\Fermat\Numbers;
9
use Samsara\Fermat\Provider\Distribution\Base\Distribution;
10
use Samsara\Fermat\Types\Base\DecimalInterface;
11
use Samsara\Fermat\Values\ImmutableNumber;
12
13
class Exponential extends Distribution
14
{
15
16
    /**
17
     * @var ImmutableNumber
18
     */
19
    private $lambda;
20
21
    /**
22
     * Exponential constructor.
23
     *
24
     * @param int|float|DecimalInterface $lambda This is the *rate parameter* not the *scale parameter*
25
     *
26
     * @throws IntegrityConstraint
27
     */
28 View Code Duplication
    public function __construct($lambda)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
29
    {
30
        $lambda = Numbers::makeOrDont(Numbers::IMMUTABLE, $lambda);
31
32
        if (!$lambda->isPositive()) {
0 ignored issues
show
Bug introduced by
The method isPositive does only exist in Samsara\Fermat\Types\Base\NumberInterface, but not in Samsara\Fermat\Types\Bas...\Base\FractionInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
33
            throw new IntegrityConstraint(
34
                'Lambda must be positive',
35
                'Provide a positive lambda',
36
                'Exponential distributions work on time to occurrence; the mean time to occurrence (lambda) must be positive'
37
            );
38
        }
39
40
        $this->lambda = $lambda;
0 ignored issues
show
Documentation Bug introduced by
It seems like $lambda of type object<Samsara\Fermat\Types\Base\NumberInterface> or object<Samsara\Fermat\Ty...\Base\DecimalInterface> or object<Samsara\Fermat\Ty...Base\FractionInterface> or object<Samsara\Fermat\Ty...se\CoordinateInterface> or array is incompatible with the declared type object<Samsara\Fermat\Values\ImmutableNumber> of property $lambda.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
41
    }
42
43
    /**
44
     * @param int|float|DecimalInterface $x
45
     *
46
     * @return ImmutableNumber
47
     * @throws IntegrityConstraint
48
     */
49 View Code Duplication
    public function cdf($x): ImmutableNumber
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
50
    {
51
52
        $x = Numbers::makeOrDont(Numbers::IMMUTABLE, $x);
53
        /** @var ImmutableNumber $one */
54
        $one = Numbers::makeOne();
55
56
        if (!$x->isPositive()) {
0 ignored issues
show
Bug introduced by
The method isPositive does only exist in Samsara\Fermat\Types\Base\NumberInterface, but not in Samsara\Fermat\Types\Bas...\Base\FractionInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
57
            throw new IntegrityConstraint(
58
                'X must be positive',
59
                'Provide a positive x',
60
                'Exponential distributions work on time to occurrence; the time to occurrence (x) must be positive'
61
            );
62
        }
63
64
        /** @var ImmutableNumber $e */
65
        $e = Numbers::makeE();
66
67
        /** @var ImmutableNumber $cdf */
68
        $cdf = $one->subtract($e->pow($x->multiply($this->lambda)->multiply(-1)));
0 ignored issues
show
Bug introduced by
The method multiply does only exist in Samsara\Fermat\Types\Base\NumberInterface, but not in Samsara\Fermat\Types\Bas...\Base\FractionInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
69
70
        return $cdf;
71
72
    }
73
74
    /**
75
     * @param $x
76
     *
77
     * @return ImmutableNumber
78
     * @throws IntegrityConstraint
79
     */
80 View Code Duplication
    public function pdf($x): ImmutableNumber
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
81
    {
82
83
        $x = Numbers::makeOrDont(Numbers::IMMUTABLE, $x);
84
85
        if (!$x->isPositive()) {
0 ignored issues
show
Bug introduced by
The method isPositive does only exist in Samsara\Fermat\Types\Base\NumberInterface, but not in Samsara\Fermat\Types\Bas...\Base\FractionInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
86
            throw new IntegrityConstraint(
87
                'X must be positive',
88
                'Provide a positive x',
89
                'Exponential distributions work on time to occurrence; the time to occurrence (x) must be positive'
90
            );
91
        }
92
93
        /** @var ImmutableNumber $e */
94
        $e = Numbers::makeE();
95
96
        /** @var ImmutableNumber $pdf */
97
        $pdf = $this->lambda->multiply($e->pow($this->lambda->multiply(-1)->multiply($x)));
0 ignored issues
show
Bug introduced by
The method multiply does only exist in Samsara\Fermat\Types\Base\NumberInterface, but not in Samsara\Fermat\Types\Base\DecimalInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
98
99
        return $pdf;
100
101
    }
102
103
    /**
104
     * @param $x1
105
     * @param $x2
106
     *
107
     * @return ImmutableNumber
108
     * @throws IntegrityConstraint
109
     */
110
    public function rangePdf($x1, $x2): ImmutableNumber
111
    {
112
        $x1 = Numbers::makeOrDont(Numbers::IMMUTABLE, $x1);
113
        $x2 = Numbers::makeOrDont(Numbers::IMMUTABLE, $x2);
114
115
        if (!$x1->isPositive() || !$x2->isPositive()) {
0 ignored issues
show
Bug introduced by
The method isPositive does only exist in Samsara\Fermat\Types\Base\NumberInterface, but not in Samsara\Fermat\Types\Bas...\Base\FractionInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
116
            throw new IntegrityConstraint(
117
                'X must be positive',
118
                'Provide a positive x',
119
                'Exponential distributions work on time to occurrence; the time to occurrence (x) must be positive'
120
            );
121
        }
122
123
        /** @var ImmutableNumber $rangePdf */
124
        $rangePdf = $this->pdf($x2)->subtract($this->pdf($x1))->abs();
125
126
        return $rangePdf;
127
    }
128
129
    /**
130
     * @return ImmutableNumber
131
     */
132
    public function random(): ImmutableNumber
133
    {
134
135
        $randFactory = new Factory();
136
        $generator = $randFactory->getMediumStrengthGenerator();
137
        $one = Numbers::makeOne();
138
        $u = Numbers::make(Numbers::IMMUTABLE, $generator->generateInt(), 20);
139
        $u = $u->divide(PHP_INT_MAX);
0 ignored issues
show
Bug introduced by
The method divide does only exist in Samsara\Fermat\Types\Base\NumberInterface, but not in Samsara\Fermat\Types\Bas...\Base\FractionInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
140
141
        /** @var ImmutableNumber $random */
142
        $random = $one->subtract($u)->ln()->divide($this->lambda->multiply(-1));
143
144
        return $random;
145
146
    }
147
148
    /**
149
     * @param int|float|DecimalInterface $min
150
     * @param int|float|DecimalInterface $max
151
     * @param int $maxIterations
152
     *
153
     * @return ImmutableNumber
154
     * @throws OptionalExit
155
     */
156 View Code Duplication
    public function rangeRandom($min = 0, $max = PHP_INT_MAX, int $maxIterations = 20): ImmutableNumber
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
157
    {
158
159
        $i = 0;
160
161
        do {
162
            $randomNumber = $this->random();
163
            $i++;
164
        } while (($randomNumber->isGreaterThan($max) || $randomNumber->isLessThan($min)) && $i < $maxIterations);
165
166
        if ($randomNumber->isGreaterThan($max) || $randomNumber->isLessThan($min)) {
167
            throw new OptionalExit(
168
                'All random numbers generated were outside of the requested range',
169
                'A suitable random number, restricted by the $max ('.$max.') and $min ('.$min.'), could not be found within '.$maxIterations.' iterations'
170
            );
171
        }
172
173
        return $randomNumber;
174
    }
175
176
}