Completed
Pull Request — dev (#40)
by Jordan
02:33
created

PolynomialFunction   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 140
Duplicated Lines 0 %

Test Coverage

Coverage 87.76%

Importance

Changes 0
Metric Value
eloc 46
dl 0
loc 140
ccs 43
cts 49
cp 0.8776
rs 10
c 0
b 0
f 0
wmc 16

5 Methods

Rating   Name   Duplication   Size   Complexity  
A describeShape() 0 14 2
B __construct() 0 45 7
A derivativeExpression() 0 17 3
A evaluateAt() 0 6 1
A integralExpression() 0 21 3
1
<?php
2
3
namespace Samsara\Fermat\Values\Algebra;
4
5
use Samsara\Exceptions\UsageError\IntegrityConstraint;
6
use Samsara\Fermat\Numbers;
7
use Samsara\Fermat\Types\Base\DecimalInterface;
8
use Samsara\Fermat\Types\Base\ExpressionInterface;
9
use Samsara\Fermat\Types\Base\FunctionInterface;
10
use Samsara\Fermat\Types\Base\NumberInterface;
11
use Samsara\Fermat\Types\Expression;
12
use Samsara\Fermat\Values\ImmutableNumber;
13
14
class PolynomialFunction extends Expression implements ExpressionInterface, FunctionInterface
15
{
16
    /** @var array  */
17
    protected $coefficients = [];
18
19
    /**
20
     * PolynomialFunction constructor.
21
     *
22
     * @param array $coefficients
23
     *
24
     * @throws IntegrityConstraint
25
     */
26 3
    public function __construct(array $coefficients)
27
    {
28 3
        parent::__construct(Expression::POLYNOMIAL);
29
30 3
        $sanitizedCoefficients = [];
31
32 3
        foreach ($coefficients as $exponent => $coefficient) {
33 3
            if (!is_int($exponent)) {
34
                throw new IntegrityConstraint(
35
                    'Keys in the $coefficients array must be integers',
36
                    'Only use integer keys for the $coefficients array',
37
                    'The key '.$exponent.' was found in the $coefficients array; an integer was expected'
38
                );
39
            }
40
41 3
            $fermatCoefficient = Numbers::make(Numbers::IMMUTABLE, $coefficient);
42
43 3
            if (!$fermatCoefficient->isEqual(0)) {
0 ignored issues
show
Bug introduced by
The method isEqual() does not exist on Samsara\Fermat\Types\Base\CoordinateInterface. ( Ignorable by Annotation )

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

43
            if (!$fermatCoefficient->/** @scrutinizer ignore-call */ isEqual(0)) {

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 isEqual() does not exist on Samsara\Fermat\Values\CartesianCoordinate. ( Ignorable by Annotation )

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

43
            if (!$fermatCoefficient->/** @scrutinizer ignore-call */ isEqual(0)) {

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 isEqual() does not exist on Samsara\Fermat\Types\Base\FractionInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Samsara\Fermat\Types\Base\FractionInterface. ( Ignorable by Annotation )

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

43
            if (!$fermatCoefficient->/** @scrutinizer ignore-call */ isEqual(0)) {
Loading history...
44 3
                $sanitizedCoefficients[$exponent] = $fermatCoefficient;
45
            }
46
        }
47
48 3
        $this->coefficients = $sanitizedCoefficients;
49
50 3
        $this->expression = function($x) use ($sanitizedCoefficients): ImmutableNumber {
51
            /** @var ImmutableNumber $value */
52 3
            $value = Numbers::makeZero();
53
54
            /** @var ImmutableNumber $xPart */
55 3
            $xPart = Numbers::makeOrDont(Numbers::IMMUTABLE, $x);
56
57 3
            foreach ($sanitizedCoefficients as $exponent => $coefficient) {
58 3
                if ($coefficient->isEqual(0)) {
59
                    continue;
60
                }
61
62 3
                if ($exponent == 0) {
63 3
                    $value = $value->add($coefficient);
64
                } else {
65 3
                    $term = $coefficient->multiply($xPart->pow($exponent));
66 3
                    $value = $value->add($term);
67
                }
68
            }
69
70 3
            return $value;
71
        };
72 3
    }
73
74
    /**
75
     * @param int|float|string|NumberInterface|DecimalInterface $x
76
     *
77
     * @return ImmutableNumber
78
     * @throws IntegrityConstraint
79
     */
80 3
    public function evaluateAt($x): ImmutableNumber
81
    {
82
        /** @var callable $answer */
83 3
        $answer = $this->expression;
84
85 3
        return $answer($x);
86
    }
87
88
    /**
89
     * @return FunctionInterface
90
     * @throws IntegrityConstraint
91
     */
92 1
    public function derivativeExpression(): FunctionInterface
93
    {
94 1
        $newCoefficients = [];
95
96
        /**
97
         * @var int             $exponent
98
         * @var ImmutableNumber $coefficient
99
         */
100 1
        foreach ($this->coefficients as $exponent => $coefficient) {
101 1
            if ($exponent == 0) {
102 1
                continue;
103
            }
104
105 1
            $newCoefficients[$exponent-1] = $coefficient->multiply($exponent);
106
        }
107
108 1
        return new PolynomialFunction($newCoefficients);
109
    }
110
111
    /**
112
     * @param int|float|string|NumberInterface|DecimalInterface $C
113
     *
114
     * @return FunctionInterface
115
     * @throws IntegrityConstraint
116
     */
117 1
    public function integralExpression($C = 0): FunctionInterface
118
    {
119 1
        $C = Numbers::make(Numbers::IMMUTABLE, $C);
120
121 1
        $newCoefficients = [];
122
123 1
        if (!$C->isEqual(0)) {
124
            $newCoefficients[0] = $C;
125
        }
126
127
        /**
128
         * @var int             $exponent
129
         * @var ImmutableNumber $coefficient
130
         */
131 1
        foreach ($this->coefficients as $exponent => $coefficient) {
132 1
            $newExponent = $exponent+1;
133
134 1
            $newCoefficients[$newExponent] = $coefficient->divide($newExponent);
135
        }
136
137 1
        return new PolynomialFunction($newCoefficients);
138
    }
139
140 3
    public function describeShape()
141
    {
142
143 3
        $shape = [];
144
145
        /**
146
         * @var int             $exponent
147
         * @var ImmutableNumber $coefficient
148
         */
149 3
        foreach ($this->coefficients as $exponent => $coefficient) {
150 3
            $shape[$exponent] = $coefficient->getValue();
151
        }
152
153 3
        return $shape;
154
155
    }
156
157
}