Failed Conditions
Pull Request — master (#47)
by Jordan
29:51 queued 14:49
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\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
    public function __construct(array $coefficients)
26 4
    {
27
        parent::__construct(Expression::POLYNOMIAL);
28 4
29
        $sanitizedCoefficients = [];
30 4
31
        foreach ($coefficients as $exponent => $coefficient) {
32 4
            if (!is_int($exponent)) {
33 4
                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 1
                );
38
            }
39
40
            /** @var ImmutableDecimal $fermatCoefficient */
41
            $fermatCoefficient = Numbers::make(Numbers::IMMUTABLE, $coefficient);
42 3
43
            if (!$fermatCoefficient->isEqual(0)) {
44 3
                $sanitizedCoefficients[$exponent] = $fermatCoefficient;
45 3
            }
46
        }
47
48
        $this->coefficients = $sanitizedCoefficients;
49 3
50
        $this->expression = function($x): ImmutableDecimal {
51 3
            /** @var ImmutableDecimal $value */
52
            $value = Numbers::makeZero();
53 3
54
            /** @var ImmutableDecimal $xPart */
55
            $xPart = Numbers::makeOrDont(Numbers::IMMUTABLE, $x);
56 3
57
            foreach ($this->coefficients as $exponent => $coefficient) {
58 3
                if ($exponent == 0) {
59 3
                    $value = $value->add($coefficient);
60 3
                } else {
61
                    $term = $coefficient->multiply($xPart->pow($exponent));
62 3
                    $value = $value->add($term);
63 3
                }
64
            }
65
66
            if ($value->isEqual(0)) {
67 3
                $value = Numbers::makeOne();
68
            }
69 3
70
            return $value;
71
        };
72
    }
73
74
    /**
75
     * @param int|float|string|NumberInterface|DecimalInterface $x
76
     *
77 3
     * @return ImmutableDecimal
78
     */
79
    public function evaluateAt($x): ImmutableDecimal
80 3
    {
81
        /** @var callable $answer */
82 3
        $answer = $this->expression;
83
84
        return $answer($x);
85
    }
86
87
    /**
88
     * @return FunctionInterface
89 1
     * @throws IntegrityConstraint
90
     */
91 1
    public function derivativeExpression(): FunctionInterface
92
    {
93
        $newCoefficients = [];
94
95
        /**
96
         * @var int             $exponent
97 1
         * @var ImmutableDecimal $coefficient
98 1
         */
99 1
        foreach ($this->coefficients as $exponent => $coefficient) {
100
            if ($exponent == 0) {
101
                continue;
102 1
            }
103
104
            $newCoefficients[$exponent-1] = $coefficient->multiply($exponent);
105 1
        }
106
107
        return new PolynomialFunction($newCoefficients);
108
    }
109
110
    /**
111
     * @param int|float|string|NumberInterface|DecimalInterface $C
112
     *
113
     * @return FunctionInterface
114 1
     * @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 1
122
        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...
123
            $newCoefficients[0] = $C;
124
        }
125
126
        /**
127
         * @var int             $exponent
128 1
         * @var ImmutableDecimal $coefficient
129 1
         */
130
        foreach ($this->coefficients as $exponent => $coefficient) {
131 1
            $newExponent = $exponent+1;
132
133
            $newCoefficients[$newExponent] = $coefficient->divide($newExponent);
134 1
        }
135
136
        return new PolynomialFunction($newCoefficients);
137 3
    }
138
139
    public function describeShape(): array
140 3
    {
141
142
        $shape = [];
143
144
        /**
145
         * @var int             $exponent
146 3
         * @var ImmutableDecimal $coefficient
147 3
         */
148
        foreach ($this->coefficients as $exponent => $coefficient) {
149
            $shape[$exponent] = $coefficient->getValue();
150 3
        }
151
152
        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
    public static function createFromFoil(array $group1, array $group2): PolynomialFunction
174
    {
175
        $group1exp = count($group1)-1;
176
        $group2exp = count($group2)-1;
177
178
        /** @var ImmutableDecimal[] $finalCoefs */
179
        $finalCoefs = [];
180
181
        $group1 = Numbers::make(Numbers::IMMUTABLE, $group1);
182
        $group2 = Numbers::make(Numbers::IMMUTABLE, $group2);
183
184
        if ($group1exp <= $group2exp) {
185
            $largerGroup = $group2;
186
            $largerExp = $group2exp;
187
            $smallerGroup = $group1;
188
            $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
        foreach ($largerGroup as $key1 => $value1) {
201
            $largerKey = $largerExp - $key1;
202
203
            /**
204
             * @var int             $key2
205
             * @var ImmutableDecimal $value2
206
             */
207
            foreach ($smallerGroup as $key2 => $value2) {
208
                $smallerKey = $smallerExp - $key2;
209
                $newVal = $value1->multiply($value2);
210
                $newExp = $largerKey + $smallerKey;
211
212
                if (isset($finalCoefs[$newExp])) {
213
                    $finalCoefs[$newExp] = $finalCoefs[$newExp]->add($newVal);
214
                } else {
215
                    $finalCoefs[$newExp] = $newVal;
216
                }
217
            }
218
        }
219
220
        return new PolynomialFunction($finalCoefs);
221
    }
222
223
}