| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485 |
- <?php
- namespace MathPHP\NumericalAnalysis\Interpolation;
- use MathPHP\Exception;
- use MathPHP\Expression\Polynomial;
- /**
- * Nevilles Method
- *
- * In numerical analysis, Nevilles Method is an interpolation technique that
- * uses Lagrange polynomials of lower powers recursively in order to compute
- * Lagrange polynomials of higher powers.
- *
- * Nevilles Method belongs to a collection of techniques that interpolate a
- * function or a set of values to approximate a function at a target point.
- * We can either directly supply a set of inputs and their corresponding outputs
- * for said function, or if we explicitly know the function, we can define it as
- * a callback function and then generate a set of points by evaluating that
- * function at n points between a start and end point. We then use these values
- * to interpolate Lagrange polynomials recursively at our target point.
- *
- * http://www2.math.ou.edu/~npetrov/neville.pdf
- */
- class NevillesMethod extends Interpolation
- {
- /**
- * Interpolate
- *
- * @param float $target
- * The point at which we are interpolation
- * @param callable|array<array{int|float, int|float}> $source
- * The source of our approximation. Should be either
- * a callback function or a set of arrays. Each array
- * (point) contains precisely two numbers, an x and y.
- * Example array: [[1,2], [2,3], [3,4]].
- * Example callback: function($x) {return $x**2;}
- * @param float ...$args
- * The arguments of our callback function: start,
- * end, and n. Example: approximate($source, 0, 8, 5).
- * If $source is a set of points, do not input any
- * $args. Example: approximate($source).
- *
- * @return float The interpolated value at our target
- *
- * @throws Exception\BadDataException
- * @throws Exception\IncorrectTypeException
- */
- public static function interpolate(float $target, $source, ...$args): float
- {
- // Get an array of points from our $source argument
- $points = self::getPoints($source, $args);
- // Validate input and sort points
- self::validate($points, $degree = 2);
- $sorted = self::sort($points);
- // Descriptive constants
- $x = self::X;
- $y = self::Y;
- // Initialize
- $n = \count($sorted);
- $Q = [];
- // Build our 0th-degree Lagrange polynomials: Q₍ᵢ₎₍₀₎ = yᵢ for all i < n
- for ($i = 0; $i < $n; $i++) {
- $Q[$i][0] = new Polynomial([$sorted[$i][$y]]); // yᵢ
- }
- // Recursively generate our (n-1)th-degree Lagrange polynomial at $target
- for ($i = 1; $i < $n; $i++) {
- for ($j = 1; $j <= $i; $j++) {
- $xᵢ₋ⱼ = $sorted[$i - $j][$x];
- $xᵢ = $sorted[$i][$x];
- $Q₍ᵢ₎₍ⱼ₋₁₎ = $Q[$i][$j - 1]($target);
- $Q₍ᵢ₋₁₎₍ⱼ₋₁₎ = $Q[$i - 1][$j - 1]($target);
- $Q[$i][$j] = LagrangePolynomial::interpolate([[$xᵢ₋ⱼ,$Q₍ᵢ₋₁₎₍ⱼ₋₁₎],[$xᵢ,$Q₍ᵢ₎₍ⱼ₋₁₎]]);
- }
- }
- // Return our (n-1)th-degree Lagrange polynomial evaluated at $target
- return $Q[$n - 1][$n - 1]($target);
- }
- }
|