SimpsonsThreeEighthsRuleTest.php 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. <?php
  2. namespace MathPHP\Tests\NumericalAnalysis\NumericalIntegration;
  3. use MathPHP\Expression\Polynomial;
  4. use MathPHP\NumericalAnalysis\NumericalIntegration\SimpsonsThreeEighthsRule;
  5. class SimpsonsThreeEighthsRuleTest extends \PHPUnit\Framework\TestCase
  6. {
  7. /**
  8. * @test approximate with points (0, 1), (1, 4), (2, 9) and (3, 16)
  9. * @throws \Exception
  10. *
  11. * f(x) = x² + 2x + 1
  12. * Antiderivative F(x) = (1/3)x³ + x² + x
  13. * Indefinite integral over [0, 3] = F(3) - F(0) = 21
  14. *
  15. * h denotes the size of subintervals, or equivalently, the distance between two points
  16. * ζ₁, ζ₂, ... denotes the max of the fourth derivative of f(x) on interval 1, 2, ...
  17. * f'(x) = 2x + 2
  18. * f''(x) = 2
  19. * f'''(x) = 0
  20. * f''''(x) = 0
  21. * ζ = f''''(x) = 0
  22. * Error = O(h^5 * ζ) = 0
  23. *
  24. * Approximate with points (0, 1), (1, 4), (2, 9) and (3, 16)
  25. * Error = 0
  26. */
  27. public function testApproximateWithPoints()
  28. {
  29. // Given
  30. $points = [[0, 1], [1, 4], [2, 9], [3, 16]];
  31. $tol = 0.00001;
  32. $expected = 21;
  33. // When
  34. $x = SimpsonsThreeEighthsRule::approximate($points);
  35. // Then
  36. $this->assertEqualsWithDelta($expected, $x, $tol);
  37. }
  38. /**
  39. * @test approximate with points not sorted: (0, 1), (1, 4), (2, 9) and (3, 16)
  40. * @throws \Exception
  41. *
  42. * f(x) = x² + 2x + 1
  43. * Antiderivative F(x) = (1/3)x³ + x² + x
  44. * Indefinite integral over [0, 3] = F(3) - F(0) = 21
  45. *
  46. * h denotes the size of subintervals, or equivalently, the distance between two points
  47. * ζ₁, ζ₂, ... denotes the max of the fourth derivative of f(x) on interval 1, 2, ...
  48. * f'(x) = 2x + 2
  49. * f''(x) = 2
  50. * f'''(x) = 0
  51. * f''''(x) = 0
  52. * ζ = f''''(x) = 0
  53. * Error = O(h^5 * ζ) = 0
  54. *
  55. * Approximate with points (0, 1), (1, 4), (2, 9) and (3, 16)
  56. * Error = 0
  57. */
  58. public function testApproximateWitPointsNotSorted()
  59. {
  60. // Given
  61. $points = [[2, 9], [3, 16], [0, 1], [1, 4]];
  62. $tol = 0.00001;
  63. $expected = 21;
  64. // When
  65. $x = SimpsonsThreeEighthsRule::approximate($points);
  66. // Then
  67. $this->assertEqualsWithDelta($expected, $x, $tol);
  68. }
  69. /**
  70. * @test approximate using callback
  71. * @throws \Exception
  72. *
  73. * f(x) = x² + 2x + 1
  74. * Antiderivative F(x) = (1/3)x³ + x² + x
  75. * Indefinite integral over [0, 3] = F(3) - F(0) = 21
  76. *
  77. * h denotes the size of subintervals, or equivalently, the distance between two points
  78. * ζ₁, ζ₂, ... denotes the max of the fourth derivative of f(x) on interval 1, 2, ...
  79. * f'(x) = 2x + 2
  80. * f''(x) = 2
  81. * f'''(x) = 0
  82. * f''''(x) = 0
  83. * ζ = f''''(x) = 0
  84. * Error = O(h^5 * ζ) = 0
  85. *
  86. * Approximate with points (0, 1), (1.5, 6.25) and (3, 16)
  87. * Error = 0
  88. */
  89. public function testApproximateUsingCallback()
  90. {
  91. // Given x² + 2x + 1
  92. $func = $func = function ($x) {
  93. return $x ** 2 + 2 * $x + 1;
  94. };
  95. $start = 0;
  96. $end = 3;
  97. $n = 4;
  98. $tol = 0.00001;
  99. $expected = 21;
  100. // When
  101. $x = SimpsonsThreeEighthsRule::approximate($func, $start, $end, $n);
  102. // Then
  103. $this->assertEqualsWithDelta($expected, $x, $tol);
  104. }
  105. /**
  106. * @test approximate using polynomial
  107. * @throws \Exception
  108. *
  109. * f(x) = x² + 2x + 1
  110. * Antiderivative F(x) = (1/3)x³ + x² + x
  111. * Indefinite integral over [0, 3] = F(3) - F(0) = 21
  112. *
  113. * h denotes the size of subintervals, or equivalently, the distance between two points
  114. * ζ₁, ζ₂, ... denotes the max of the fourth derivative of f(x) on interval 1, 2, ...
  115. * f'(x) = 2x + 2
  116. * f''(x) = 2
  117. * f'''(x) = 0
  118. * f''''(x) = 0
  119. * ζ = f''''(x) = 0
  120. * Error = O(h^5 * ζ) = 0
  121. *
  122. * Approximate with points (0, 1), (1.5, 6.25) and (3, 16)
  123. * Error = 0
  124. */
  125. public function testApproximateUsingPolynomial()
  126. {
  127. // Given x² + 2x + 1
  128. $polynomial = new Polynomial([1, 2, 1]);
  129. $start = 0;
  130. $end = 3;
  131. $n = 4;
  132. $tol = 0.00001;
  133. $expected = 21;
  134. // When
  135. $x = SimpsonsThreeEighthsRule::approximate($polynomial, $start, $end, $n);
  136. // Then
  137. $this->assertEqualsWithDelta($expected, $x, $tol);
  138. }
  139. /**
  140. * @test approximate error when there are not even even number of subintervals, or equivalently, there are not an add number of points
  141. * @throws \Exception
  142. */
  143. public function testApproximateErrorSubintervalsNotEven()
  144. {
  145. // Given
  146. $points = [[0,0], [4,4], [2,2], [6,6], [8,8]];
  147. // Then
  148. $this->expectException(\Exception::class);
  149. // When
  150. SimpsonsThreeEighthsRule::approximate($points);
  151. }
  152. /**
  153. * @test approximate error when there is not constant spacing between points
  154. * @throws \Exception
  155. */
  156. public function testNonConstantSpacingException()
  157. {
  158. // Given
  159. $points = [[0,0], [3,3], [2,2], [4,4]];
  160. // Then
  161. $this->expectException(\Exception::class);
  162. // When
  163. SimpsonsThreeEighthsRule::approximate($points);
  164. }
  165. }