Passed
Push — dev ( 72f3b6...93ca8f )
by Jordan
15:12
created

PolynomialFunction::createFromFoil()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 48
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 26
c 1
b 0
f 0
nc 8
nop 2
dl 0
loc 48
ccs 0
cts 0
cp 0
crap 30
rs 9.1928
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 FunctionInterface
15
{
16
    /** @var array  */
17
    protected $coefficients = [];
18
19
    /**
20
     * PolynomialFunction constructor.
21
     *
22
     * @param array $coefficients
23
     *
24
     * @throws IntegrityConstraint
25
     */
26 4
    public function __construct(array $coefficients)
27
    {
28 4
        parent::__construct(Expression::POLYNOMIAL);
29
30 4
        $sanitizedCoefficients = [];
31
32 4
        foreach ($coefficients as $exponent => $coefficient) {
33 4
            if (!is_int($exponent)) {
34 1
                throw new IntegrityConstraint(
35 1
                    'Keys in the $coefficients array must be integers',
36 1
                    'Only use integer keys for the $coefficients array',
37 1
                    'The key '.$exponent.' was found in the $coefficients array; an integer was expected'
38
                );
39
            }
40
41
            /** @var ImmutableNumber $fermatCoefficient */
42 3
            $fermatCoefficient = Numbers::make(Numbers::IMMUTABLE, $coefficient);
43
44 3
            if (!$fermatCoefficient->isEqual(0)) {
45 3
                $sanitizedCoefficients[$exponent] = $fermatCoefficient;
46
            }
47
        }
48
49 3
        $this->coefficients = $sanitizedCoefficients;
50
51 3
        $this->expression = function($x) use ($sanitizedCoefficients): ImmutableNumber {
52
            /** @var ImmutableNumber $value */
53 3
            $value = Numbers::makeZero();
54
55
            /** @var ImmutableNumber $xPart */
56 3
            $xPart = Numbers::makeOrDont(Numbers::IMMUTABLE, $x);
57
58 3
            foreach ($sanitizedCoefficients as $exponent => $coefficient) {
59 3
                if ($exponent == 0) {
60 3
                    $value = $value->add($coefficient);
61
                } else {
62 3
                    $term = $coefficient->multiply($xPart->pow($exponent));
63 3
                    $value = $value->add($term);
64
                }
65
            }
66
67 3
            if ($value->isEqual(0)) {
68
                $value = Numbers::makeOne();
69 3
            }
70
71
            return $value;
72
        };
73
    }
74
75
    /**
76
     * @param int|float|string|NumberInterface|DecimalInterface $x
77 3
     *
78
     * @return ImmutableNumber
79
     */
80 3
    public function evaluateAt($x): ImmutableNumber
81
    {
82 3
        /** @var callable $answer */
83
        $answer = $this->expression;
84
85
        return $answer($x);
86
    }
87
88
    /**
89 1
     * @return FunctionInterface
90
     * @throws IntegrityConstraint
91 1
     */
92
    public function derivativeExpression(): FunctionInterface
93
    {
94
        $newCoefficients = [];
95
96
        /**
97 1
         * @var int             $exponent
98 1
         * @var ImmutableNumber $coefficient
99 1
         */
100
        foreach ($this->coefficients as $exponent => $coefficient) {
101
            if ($exponent == 0) {
102 1
                continue;
103
            }
104
105 1
            $newCoefficients[$exponent-1] = $coefficient->multiply($exponent);
106
        }
107
108
        return new PolynomialFunction($newCoefficients);
109
    }
110
111
    /**
112
     * @param int|float|string|NumberInterface|DecimalInterface $C
113
     *
114 1
     * @return FunctionInterface
115
     * @throws IntegrityConstraint
116 1
     */
117
    public function integralExpression($C = 0): FunctionInterface
118 1
    {
119
        $C = Numbers::make(Numbers::IMMUTABLE, $C);
120 1
121 1
        $newCoefficients = [];
122
123
        if (!$C->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

123
        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...
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

123
        if (!$C->/** @scrutinizer ignore-call */ isEqual(0)) {
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

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