LagrangePolynomialTest.php 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. <?php
  2. namespace MathPHP\Tests\NumericalAnalysis\Interpolation;
  3. use MathPHP\NumericalAnalysis\Interpolation\LagrangePolynomial;
  4. class LagrangePolynomialTest extends \PHPUnit\Framework\TestCase
  5. {
  6. /**
  7. * @test Interpolated polynomial function computes expected values: p(x) = expected
  8. * @dataProvider dataProviderForPolynomialAgrees
  9. * @param int $x
  10. * @param int $expected
  11. * @throws \Exception
  12. */
  13. public function testPolynomialAgrees(int $x, int $expected)
  14. {
  15. // Given
  16. $points = [[0, 0], [1, 5], [3, 2], [7, 10], [10, -4]];
  17. // And
  18. $p = LagrangePolynomial::interpolate($points);
  19. // When
  20. $evaluated = $p($x);
  21. // Then
  22. $this->assertEqualsWithDelta($expected, $evaluated, 0.00001);
  23. }
  24. /**
  25. * @return array (x, expected)
  26. */
  27. public function dataProviderForPolynomialAgrees(): array
  28. {
  29. return [
  30. [0, 0], // p(0) = 0
  31. [1, 5], // p(1) = 5
  32. [3, 2], // p(3) = 2
  33. [7, 10], // p(7) = 10
  34. [10, -4], // p(10) = -4
  35. ];
  36. }
  37. /**
  38. * @test Solve zero error
  39. * @dataProvider dataProviderForSolve
  40. * @param float $x
  41. * @throws \Exception
  42. *
  43. * f(x) = x⁴ + 8x³ -13x² -92x + 96
  44. *
  45. * Given n points, the error in the Lagrange Polynomials is proportional
  46. * to the max value of the nth derivative. Thus, if we if interpolate n at
  47. * 6 points, the 5th derivative of our original function f(x) = 0, and so
  48. * our resulting polynomial will have no error.
  49. *
  50. * p(x) agrees with f(x) at x = $_
  51. */
  52. public function testSolveZeroError($x)
  53. {
  54. // f(x) = x⁴ + 8x³ -13x² -92x + 96
  55. $f = function ($x) {
  56. return $x ** 4 + 8 * $x ** 3 - 13 * $x ** 2 - 92 * $x + 96;
  57. };
  58. // And
  59. $a = 0;
  60. $b = 10;
  61. $n = 5;
  62. $roundoff = 0.000001; // round off error - Allow a tolerance of 0.0000001
  63. // And
  64. $p = LagrangePolynomial::interpolate($f, $a, $b, $n);
  65. $expected = $f($x);
  66. // When
  67. $evaluated = $p($x);
  68. // Then
  69. $this->assertEqualsWithDelta($expected, $evaluated, $roundoff);
  70. }
  71. /**
  72. * @test Solve non zero error
  73. * @dataProvider dataProviderForSolve
  74. * @param float $x
  75. * @throws \Exception
  76. *
  77. * f(x) = x⁴ + 8x³ -13x² -92x + 96
  78. *
  79. * The error is bounded by:
  80. * |f(x)-p(x)| = tol <= (max f⁽ⁿ⁺¹⁾(x))*(x-x₀)*...*(x-xn)/(n+1)!
  81. *
  82. * f'(x) = 4x³ +24x² -26x - 92
  83. * f''(x) = 12x² - 48x - 26
  84. * f'''(x) = 24x - 48
  85. * f⁽⁴⁾(x) = 24
  86. *
  87. * So, tol <= 24*(x-x₀)*...*(x-xn)/(4!) = (x-x₀)*...*(x-xn) where
  88. *
  89. * Check that p(x) agrees with f(x) at x = $_
  90. */
  91. public function testSolveNonZeroError($x)
  92. {
  93. // f(x) = x⁴ + 8x³ -13x² -92x + 96
  94. $f = function ($x) {
  95. return $x ** 4 + 8 * $x ** 3 - 13 * $x ** 2 - 92 * $x + 96;
  96. };
  97. // And
  98. $a = 0;
  99. $b = 9;
  100. $n = 4;
  101. $roundoff = 0.000001; // round off error - Allow a tolerance of 0.0000001
  102. // And
  103. $x₀ = 0;
  104. $x₁ = 3;
  105. $x₂ = 6;
  106. $x₃ = 9;
  107. $tol = \abs(($x - $x₀) * ($x - $x₁) * ($x - $x₂) * ($x - $x₃));
  108. // And
  109. $p = LagrangePolynomial::interpolate($f, $a, $b, $n);
  110. $expected = $f($x);
  111. // When
  112. $evaluated = $p($x);
  113. // Then
  114. $this->assertEqualsWithDelta($expected, $evaluated, $tol + $roundoff);
  115. }
  116. /**
  117. * @return array p(x) agrees with f(x) at x = $_
  118. */
  119. public function dataProviderForSolve(): array
  120. {
  121. return [
  122. [0],
  123. [2],
  124. [4],
  125. [6],
  126. [8],
  127. [10],
  128. [-99],
  129. ];
  130. }
  131. }