Failed Conditions
Push — dev ( 8ee5b7...b2941f )
by Jordan
18:22
created

PolynomialFunction   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 208
Duplicated Lines 0 %

Test Coverage

Coverage 93.15%

Importance

Changes 4
Bugs 0 Features 0
Metric Value
eloc 72
c 4
b 0
f 0
dl 0
loc 208
ccs 68
cts 73
cp 0.9315
rs 10
wmc 21

6 Methods

Rating   Name   Duplication   Size   Complexity  
A describeShape() 0 14 2
B __construct() 0 46 7
A derivativeExpression() 0 17 3
A evaluateAt() 0 6 1
A integralExpression() 0 21 3
A createFromFoil() 0 48 5
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\Interfaces\Numbers\DecimalInterface;
8
use Samsara\Fermat\Types\Base\Interfaces\Evaluateables\FunctionInterface;
9
use Samsara\Fermat\Types\Base\Interfaces\Numbers\NumberInterface;
10
use Samsara\Fermat\Types\Expression;
11
use Samsara\Fermat\Values\ImmutableDecimal;
12
13
class PolynomialFunction extends Expression implements FunctionInterface
14
{
15
    /** @var array  */
16
    protected $coefficients = [];
17
18
    /**
19
     * PolynomialFunction constructor.
20
     *
21
     * @param array $coefficients
22
     *
23
     * @throws IntegrityConstraint
24
     */
25 5
    public function __construct(array $coefficients)
26
    {
27 5
        parent::__construct(Expression::POLYNOMIAL);
28
29 5
        $sanitizedCoefficients = [];
30
31 5
        foreach ($coefficients as $exponent => $coefficient) {
32 5
            if (!is_int($exponent)) {
33 1
                throw new IntegrityConstraint(
34 1
                    'Keys in the $coefficients array must be integers',
35 1
                    'Only use integer keys for the $coefficients array',
36 1
                    'The key '.$exponent.' was found in the $coefficients array; an integer was expected'
37
                );
38
            }
39
40
            /** @var ImmutableDecimal $fermatCoefficient */
41 4
            $fermatCoefficient = Numbers::make(Numbers::IMMUTABLE, $coefficient);
42
43 4
            if (!$fermatCoefficient->isEqual(0)) {
44 4
                $sanitizedCoefficients[$exponent] = $fermatCoefficient;
45
            }
46
        }
47
48 4
        $this->coefficients = $sanitizedCoefficients;
49
50
        $this->expression = function($x): ImmutableDecimal {
51
            /** @var ImmutableDecimal $value */
52 3
            $value = Numbers::makeZero();
53
54
            /** @var ImmutableDecimal $xPart */
55 3
            $xPart = Numbers::makeOrDont(Numbers::IMMUTABLE, $x);
56
57 3
            foreach ($this->coefficients as $exponent => $coefficient) {
58 3
                if ($exponent == 0) {
59 3
                    $value = $value->add($coefficient);
60
                } else {
61 3
                    $term = $coefficient->multiply($xPart->pow($exponent));
62 3
                    $value = $value->add($term);
63
                }
64
            }
65
66 3
            if ($value->isEqual(0)) {
67
                $value = Numbers::makeOne();
68
            }
69
70 3
            return $value;
71
        };
72 4
    }
73
74
    /**
75
     * @param int|float|string|NumberInterface|DecimalInterface $x
76
     *
77
     * @return ImmutableDecimal
78
     */
79 3
    public function evaluateAt($x): ImmutableDecimal
80
    {
81
        /** @var callable $answer */
82 3
        $answer = $this->expression;
83
84 3
        return $answer($x);
85
    }
86
87
    /**
88
     * @return FunctionInterface
89
     * @throws IntegrityConstraint
90
     */
91 1
    public function derivativeExpression(): FunctionInterface
92
    {
93 1
        $newCoefficients = [];
94
95
        /**
96
         * @var int             $exponent
97
         * @var ImmutableDecimal $coefficient
98
         */
99 1
        foreach ($this->coefficients as $exponent => $coefficient) {
100 1
            if ($exponent == 0) {
101 1
                continue;
102
            }
103
104 1
            $newCoefficients[$exponent-1] = $coefficient->multiply($exponent);
105
        }
106
107 1
        return new PolynomialFunction($newCoefficients);
108
    }
109
110
    /**
111
     * @param int|float|string|NumberInterface|DecimalInterface $C
112
     *
113
     * @return FunctionInterface
114
     * @throws IntegrityConstraint
115
     */
116 1
    public function integralExpression($C = 0): FunctionInterface
117
    {
118 1
        $C = Numbers::make(Numbers::IMMUTABLE, $C);
119
120 1
        $newCoefficients = [];
121
122 1
        if (!$C->isEqual(0)) {
0 ignored issues
show
Bug introduced by
The method isEqual() 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

122
        if (!$C->/** @scrutinizer ignore-call */ isEqual(0)) {
Loading history...
Bug introduced by
The method isEqual() 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

122
        if (!$C->/** @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...
123 1
            $newCoefficients[0] = $C;
124
        }
125
126
        /**
127
         * @var int             $exponent
128
         * @var ImmutableDecimal $coefficient
129
         */
130 1
        foreach ($this->coefficients as $exponent => $coefficient) {
131 1
            $newExponent = $exponent+1;
132
133 1
            $newCoefficients[$newExponent] = $coefficient->divide($newExponent);
134
        }
135
136 1
        return new PolynomialFunction($newCoefficients);
137
    }
138
139 4
    public function describeShape(): array
140
    {
141
142 4
        $shape = [];
143
144
        /**
145
         * @var int             $exponent
146
         * @var ImmutableDecimal $coefficient
147
         */
148 4
        foreach ($this->coefficients as $exponent => $coefficient) {
149 4
            $shape[$exponent] = $coefficient->getValue();
150
        }
151
152 4
        return $shape;
153
154
    }
155
156
    /**
157
     * This function performs a FOIL expansion on a list of parameters.
158
     *
159
     * Assumptions:
160
     *      1. The coefficients are the numbers provided in the arrays
161
     *      2. The coefficients are listed in descending order of their exponent on the function variable. For example,
162
     *         if you were multiplying (2 + 3x)*(5 - 1x^2 + 1x), it would expect these inputs:
163
     *              -  [3, 2], [-1, 1, 5]
164
     *      3. If not all exponents are used continuously, a zero must be provided for the position that is skipped. For
165
     *         example, if one of the provided groups was 4x^2 + 2, it would expect: [4, 0, 2]
166
     *
167
     * @param int[]|float[]|NumberInterface[] $group1
168
     * @param int[]|float[]|NumberInterface[] $group2
169
     *
170
     * @return PolynomialFunction
171
     * @throws IntegrityConstraint
172
     */
173 1
    public static function createFromFoil(array $group1, array $group2): PolynomialFunction
174
    {
175 1
        $group1exp = count($group1)-1;
176 1
        $group2exp = count($group2)-1;
177
178
        /** @var ImmutableDecimal[] $finalCoefs */
179 1
        $finalCoefs = [];
180
181 1
        $group1 = Numbers::makeOrDont(Numbers::IMMUTABLE, $group1);
182 1
        $group2 = Numbers::makeOrDont(Numbers::IMMUTABLE, $group2);
183
184 1
        if ($group1exp <= $group2exp) {
185 1
            $largerGroup = $group2;
186 1
            $largerExp = $group2exp;
187 1
            $smallerGroup = $group1;
188 1
            $smallerExp = $group1exp;
189
        } else {
190
            $largerGroup = $group1;
191
            $largerExp = $group1exp;
192
            $smallerGroup = $group2;
193
            $smallerExp = $group2exp;
194
        }
195
196
        /**
197
         * @var int $key1
198
         * @var ImmutableDecimal $value1
199
         */
200 1
        foreach ($largerGroup as $key1 => $value1) {
201 1
            $largerKey = $largerExp - $key1;
202
203
            /**
204
             * @var int             $key2
205
             * @var ImmutableDecimal $value2
206
             */
207 1
            foreach ($smallerGroup as $key2 => $value2) {
208 1
                $smallerKey = $smallerExp - $key2;
209 1
                $newVal = $value1->multiply($value2);
210 1
                $newExp = $largerKey + $smallerKey;
211
212 1
                if (isset($finalCoefs[$newExp])) {
213 1
                    $finalCoefs[$newExp] = $finalCoefs[$newExp]->add($newVal);
214
                } else {
215 1
                    $finalCoefs[$newExp] = $newVal;
216
                }
217
            }
218
        }
219
220 1
        return new PolynomialFunction($finalCoefs);
221
    }
222
223
}