NevillesMethod.php 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. <?php
  2. namespace MathPHP\NumericalAnalysis\Interpolation;
  3. use MathPHP\Exception;
  4. use MathPHP\Expression\Polynomial;
  5. /**
  6. * Nevilles Method
  7. *
  8. * In numerical analysis, Nevilles Method is an interpolation technique that
  9. * uses Lagrange polynomials of lower powers recursively in order to compute
  10. * Lagrange polynomials of higher powers.
  11. *
  12. * Nevilles Method belongs to a collection of techniques that interpolate a
  13. * function or a set of values to approximate a function at a target point.
  14. * We can either directly supply a set of inputs and their corresponding outputs
  15. * for said function, or if we explicitly know the function, we can define it as
  16. * a callback function and then generate a set of points by evaluating that
  17. * function at n points between a start and end point. We then use these values
  18. * to interpolate Lagrange polynomials recursively at our target point.
  19. *
  20. * http://www2.math.ou.edu/~npetrov/neville.pdf
  21. */
  22. class NevillesMethod extends Interpolation
  23. {
  24. /**
  25. * Interpolate
  26. *
  27. * @param float $target
  28. * The point at which we are interpolation
  29. * @param callable|array<array{int|float, int|float}> $source
  30. * The source of our approximation. Should be either
  31. * a callback function or a set of arrays. Each array
  32. * (point) contains precisely two numbers, an x and y.
  33. * Example array: [[1,2], [2,3], [3,4]].
  34. * Example callback: function($x) {return $x**2;}
  35. * @param float ...$args
  36. * The arguments of our callback function: start,
  37. * end, and n. Example: approximate($source, 0, 8, 5).
  38. * If $source is a set of points, do not input any
  39. * $args. Example: approximate($source).
  40. *
  41. * @return float The interpolated value at our target
  42. *
  43. * @throws Exception\BadDataException
  44. * @throws Exception\IncorrectTypeException
  45. */
  46. public static function interpolate(float $target, $source, ...$args): float
  47. {
  48. // Get an array of points from our $source argument
  49. $points = self::getPoints($source, $args);
  50. // Validate input and sort points
  51. self::validate($points, $degree = 2);
  52. $sorted = self::sort($points);
  53. // Descriptive constants
  54. $x = self::X;
  55. $y = self::Y;
  56. // Initialize
  57. $n = \count($sorted);
  58. $Q = [];
  59. // Build our 0th-degree Lagrange polynomials: Q₍ᵢ₎₍₀₎ = yᵢ for all i < n
  60. for ($i = 0; $i < $n; $i++) {
  61. $Q[$i][0] = new Polynomial([$sorted[$i][$y]]); // yᵢ
  62. }
  63. // Recursively generate our (n-1)th-degree Lagrange polynomial at $target
  64. for ($i = 1; $i < $n; $i++) {
  65. for ($j = 1; $j <= $i; $j++) {
  66. $xᵢ₋ⱼ = $sorted[$i - $j][$x];
  67. $xᵢ = $sorted[$i][$x];
  68. $Q₍ᵢ₎₍ⱼ₋₁₎ = $Q[$i][$j - 1]($target);
  69. $Q₍ᵢ₋₁₎₍ⱼ₋₁₎ = $Q[$i - 1][$j - 1]($target);
  70. $Q[$i][$j] = LagrangePolynomial::interpolate([[$xᵢ₋ⱼ,$Q₍ᵢ₋₁₎₍ⱼ₋₁₎],[$xᵢ,$Q₍ᵢ₎₍ⱼ₋₁₎]]);
  71. }
  72. }
  73. // Return our (n-1)th-degree Lagrange polynomial evaluated at $target
  74. return $Q[$n - 1][$n - 1]($target);
  75. }
  76. }