BoolesRuleTest.php 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. <?php
  2. namespace MathPHP\Tests\NumericalAnalysis\NumericalIntegration;
  3. use MathPHP\Expression\Polynomial;
  4. use MathPHP\NumericalAnalysis\NumericalIntegration\BoolesRule;
  5. class BoolesRuleTest extends \PHPUnit\Framework\TestCase
  6. {
  7. /**
  8. * @test approximate using sorted points
  9. * @throws \Exception
  10. *
  11. * f(x) = x³ + 2x + 1
  12. * Antiderivative F(x) = (1/4)x⁴ + x² + x
  13. * Indefinite integral over [0, 4] = F(4) - F(0) = 84
  14. *
  15. * h denotes the size of subintervals, or equivalently, the
  16. * distance between two points
  17. * ζ₁, ζ₂, ... denotes the max of the fourth derivative of f(x) on
  18. * interval 1, 2, ...
  19. * f'(x) = 3x² + 2
  20. * f''(x) = 6x
  21. * f'''(x) = 6
  22. * f⁽⁴⁾(x) = 0
  23. * f⁽⁵⁾(x) = 0
  24. * f⁽⁶⁾(x) = 0
  25. * Error = O(h^5 * f⁽⁶⁾(x)) = 0
  26. */
  27. public function testApproximatePolynomialSortedPoints()
  28. {
  29. // Given
  30. $sortedPoints = [[0, 1], [1, 4], [2, 13], [3, 34], [4, 73]];
  31. $expected = 84;
  32. $tol = 0.00001;
  33. // When
  34. $x = BoolesRule::approximate($sortedPoints);
  35. // Then
  36. $this->assertEqualsWithDelta($expected, $x, $tol);
  37. }
  38. /**
  39. * @test approximate using non-sorted points
  40. * @throws \Exception
  41. *
  42. * f(x) = x³ + 2x + 1
  43. * Antiderivative F(x) = (1/4)x⁴ + x² + x
  44. * Indefinite integral over [0, 4] = F(4) - F(0) = 84
  45. *
  46. * h denotes the size of subintervals, or equivalently, the
  47. * distance between two points
  48. * ζ₁, ζ₂, ... denotes the max of the fourth derivative of f(x) on
  49. * interval 1, 2, ...
  50. * f'(x) = 3x² + 2
  51. * f''(x) = 6x
  52. * f'''(x) = 6
  53. * f⁽⁴⁾(x) = 0
  54. * f⁽⁵⁾(x) = 0
  55. * f⁽⁶⁾(x) = 0
  56. * Error = O(h^5 * f⁽⁶⁾(x)) = 0
  57. */
  58. public function testApproximatePolynomialNonSortedPoints()
  59. {
  60. // Given
  61. $nonSortedPoints = [[0, 1], [3, 34], [2, 13], [1, 4], [4, 73]];
  62. $expected = 84;
  63. $tol = 0.00001;
  64. // When
  65. $x = BoolesRule::approximate($nonSortedPoints);
  66. // Then
  67. $this->assertEqualsWithDelta($expected, $x, $tol);
  68. }
  69. /**
  70. * @test approximate using callback function
  71. * @throws \Exception
  72. *
  73. * f(x) = x³ + 2x + 1
  74. * Antiderivative F(x) = (1/4)x⁴ + x² + x
  75. * Indefinite integral over [0, 4] = F(4) - F(0) = 84
  76. *
  77. * h denotes the size of subintervals, or equivalently, the
  78. * distance between two points
  79. * ζ₁, ζ₂, ... denotes the max of the fourth derivative of f(x) on
  80. * interval 1, 2, ...
  81. * f'(x) = 3x² + 2
  82. * f''(x) = 6x
  83. * f'''(x) = 6
  84. * f⁽⁴⁾(x) = 0
  85. * f⁽⁵⁾(x) = 0
  86. * f⁽⁶⁾(x) = 0
  87. * Error = O(h^5 * f⁽⁶⁾(x)) = 0
  88. */
  89. public function testApproximatePolynomialCallback()
  90. {
  91. // Given x³ + 2x + 1
  92. $func = function ($x) {
  93. return $x ** 3 + 2 * $x + 1;
  94. };
  95. $start = 0;
  96. $end = 4;
  97. $n = 5;
  98. $expected = 84;
  99. $tol = 0.00001;
  100. // When
  101. $x = BoolesRule::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/4)x⁴ + x² + x
  111. * Indefinite integral over [0, 4] = F(4) - F(0) = 84
  112. *
  113. * h denotes the size of subintervals, or equivalently, the
  114. * distance between two points
  115. * ζ₁, ζ₂, ... denotes the max of the fourth derivative of f(x) on
  116. * interval 1, 2, ...
  117. * f'(x) = 3x² + 2
  118. * f''(x) = 6x
  119. * f'''(x) = 6
  120. * f⁽⁴⁾(x) = 0
  121. * f⁽⁵⁾(x) = 0
  122. * f⁽⁶⁾(x) = 0
  123. * Error = O(h^5 * f⁽⁶⁾(x)) = 0
  124. */
  125. public function testApproximatePolynomialUsingPolynomial()
  126. {
  127. // Given x³ + 2x + 1
  128. $polynomial = new Polynomial([1, 0, 2, 1]);
  129. $start = 0;
  130. $end = 4;
  131. $n = 5;
  132. $expected = 84;
  133. $tol = 0.00001;
  134. // When
  135. $x = BoolesRule::approximate($polynomial, $start, $end, $n);
  136. // Then
  137. $this->assertEqualsWithDelta($expected, $x, $tol);
  138. }
  139. /**
  140. * @test approximate using callback (http://mathfaculty.fullerton.edu/mathews/n2003/BooleRuleMod.html)
  141. * @throws \Exception
  142. */
  143. public function testApproximatePolynomialCallback2()
  144. {
  145. // Given 2 + \cos(2√x)
  146. $func = function ($x) {
  147. return 2 + \cos(2 * \sqrt($x));
  148. };
  149. $start = 0;
  150. $end = 2;
  151. $n = 5;
  152. $expected = 3.46;
  153. $tol = 0.0001;
  154. // When
  155. $x = BoolesRule::approximate($func, $start, $end, $n);
  156. // Then
  157. $this->assertEqualsWithDelta($expected, $x, $tol);
  158. }
  159. /**
  160. * @test approximate using callback (http://mathfaculty.fullerton.edu/mathews/n2003/BooleRuleMod.html)
  161. * @dataProvider dataProviderForCallback3
  162. * @throws \Exception
  163. */
  164. public function testApproximatePolynomialCallback3(int $n, float $expected)
  165. {
  166. // Given 1 + e^-x sin(8x^2/3)
  167. $func = function ($x) {
  168. return 1 + M_E ** -$x * \sin(8 * $x ** (2 / 3));
  169. };
  170. $start = 0;
  171. $end = 2;
  172. $tol = 0.000001;
  173. // When
  174. $x = BoolesRule::approximate($func, $start, $end, $n);
  175. // Then
  176. $this->assertEqualsWithDelta($expected, $x, $tol);
  177. }
  178. /**
  179. * http://mathfaculty.fullerton.edu/mathews/n2003/boolerule/BooleRuleMod/Links/BooleRuleMod_lnk_12.html
  180. * @return array
  181. */
  182. public function dataProviderForCallback3(): array
  183. {
  184. return [
  185. [5, 1.553155],
  186. [9, 1.963413],
  187. [13, 2.001295],
  188. [17, 2.007328],
  189. [49, 2.014809],
  190. [121, 2.015961],
  191. ];
  192. }
  193. /**
  194. * @test approximate exception when sub intervals are not a factor of four, or
  195. * equivalently, the number of points minus one is not a factor of four
  196. * @throws \Exception
  197. */
  198. public function testSubIntervalsNotFactorFour()
  199. {
  200. // Given
  201. $points = [[0,0], [4,4], [2,2], [6,6], [8,8], [10, 10]];
  202. // Then
  203. $this->expectException(\Exception::class);
  204. // When
  205. BoolesRule::approximate($points);
  206. }
  207. /**
  208. * @test approximate exception when there is not constant spacing between points
  209. * @throws \Exception
  210. */
  211. public function testNonConstantSpacingException()
  212. {
  213. // Given
  214. $points = [[0,0], [3,3], [2,2], [4,4], [5, 5]];
  215. // Then
  216. $this->expectException(\Exception::class);
  217. // When
  218. BoolesRule::approximate($points);
  219. }
  220. }