123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277 |
- <?php
- namespace MathPHP\Tests\NumericalAnalysis\RootFinding;
- use MathPHP\Expression\Polynomial;
- use MathPHP\NumericalAnalysis\RootFinding\NewtonsMethod;
- class NewtonsMethodTest extends \PHPUnit\Framework\TestCase
- {
- /**
- * @test Solve f(x) = x⁴ + 8x³ -13x² -92x + 96
- * Polynomial has 4 roots: 3, 1, -8 and -4
- * Uses \Closure object
- * @dataProvider dataProviderForPolynomial
- * @param float[] $args
- * @param int $expected
- * @throws \Exception
- */
- public function testSolvePolynomialWithFourRootsUsingClosure(array $args, int $expected)
- {
- // Given
- $func = function ($x) {
- return $x ** 4 + 8 * $x ** 3 - 13 * $x ** 2 - 92 * $x + 96;
- };
- // And
- $target = 0;
- $position = 0;
- $tol = 0.00001;
- // When solving for f(x) = 0 where x is $expected
- $x = NewtonsMethod::solve($func, $args, $target, $tol, $position);
- // Then
- $this->assertEqualsWithDelta($expected, $x, $tol);
- }
- /**
- * @test Solve f(x) = x⁴ + 8x³ -13x² -92x + 96
- * Polynomial has 4 roots: 3, 1, -8 and -4
- * Uses Polynomial object
- * @dataProvider dataProviderForPolynomial
- * @param float[] $args
- * @param int $expected
- * @throws \Exception
- */
- public function testSolvePolynomialWithFourRootsUsingPolynomial(array $args, int $expected)
- {
- // Given
- $polynomial = new Polynomial([1, 8, -13, -92, 96]);
- // And
- $target = 0;
- $position = 0;
- $tol = 0.00001;
- // When solving for f(x) = 0 where x is $expected
- $x = NewtonsMethod::solve($polynomial, $args, $target, $tol, $position);
- // Then
- $this->assertEqualsWithDelta($expected, $x, $tol);
- }
- /**
- * @return array (args, expected)
- */
- public function dataProviderForPolynomial(): array
- {
- return [
- 'solving for f(x) = 0 where x is -4' => [[-4.1], -4],
- 'solving for f(x) = 0 where x is -8' => [[-8.4], -8],
- 'solving for f(x) = 0 where x is 3' => [[3.5], 3],
- 'When solving f(x) = 0 where x is 1' => [[-.3], 1],
- ];
- }
- /**
- * @test Solve f(x) = x³ - x + 1
- * Polynomial has a root of approximately -1.324717
- * @throws \Exception
- */
- public function testXCubedSubtractXPlusOne()
- {
- // Given
- $func = function ($x) {
- return $x ** 3 - $x + 1;
- };
- // And
- $expected = -1.324717;
- $args = [-1];
- $target = 0;
- $position = 0;
- $tol = 0.00001;
- // When
- $root = NewtonsMethod::solve($func, $args, $target, $tol, $position);
- // Then
- $this->assertEqualsWithDelta($expected, $root, $tol);
- }
- /**
- * @test Solve f(x) = x² - 5
- * Polynomial has a root of √5
- * @throws \Exception
- */
- public function testXSquaredSubtractFive()
- {
- // Given
- $func = function ($x) {
- return $x ** 2 - 5;
- };
- // And
- $expected = \sqrt(5);
- $args = [2];
- $target = 0;
- $position = 0;
- $tol = 0.00001;
- // When
- $root = NewtonsMethod::solve($func, $args, $target, $tol, $position);
- // Then
- $this->assertEqualsWithDelta($expected, $root, $tol);
- }
- /**
- * @test Solve \cos(x) - 2x
- * Has a root of approximately 0.450183
- * @throws \Exception
- */
- public function testCosXSubtractTwoX()
- {
- // Given
- $func = function ($x) {
- return \cos($x) - 2 * $x;
- };
- // And
- $expected = 0.450183;
- $args = [0];
- $target = 0;
- $position = 0;
- $tol = 0.00001;
- // When
- $root = NewtonsMethod::solve($func, $args, $target, $tol, $position);
- // Then
- $this->assertEqualsWithDelta($expected, $root, $tol);
- }
- /**
- * @test Solve \cos(x) = x
- * Has a root of approximately 0.7390851332
- * @throws \Exception
- */
- public function testCosXEqualsX()
- {
- // Given
- $func = function ($x) {
- return \cos($x);
- };
- // And
- $x = 0.7390851332;
- $args = [0.6];
- $target = $x;
- $position = 0;
- $tol = 0.00001;
- // When
- $root = NewtonsMethod::solve($func, $args, $target, $tol, $position);
- // Then
- $this->assertEqualsWithDelta($x, $root, $tol);
- }
- /**
- * @test Solve with negative tolerance
- * @throws \Exception
- */
- public function testNewtonsMethodExceptionNegativeTolerance()
- {
- // Given
- $func = function ($x) {
- return $x ** 4 + 8 * $x ** 3 - 13 * $x ** 2 - 92 * $x + 96;
- };
- // And
- $args = [-4.1];
- $target = 0;
- $position = 0;
- $tol = -0.00001;
- // Then
- $this->expectException('\Exception');
- // When
- $x = NewtonsMethod::solve($func, $args, $target, $tol, $position);
- }
- /**
- * @test Solve with near zero slope
- * @throws \Exception
- */
- public function testNewtonsMethodNearZeroSlopeNAN()
- {
- // Given
- $func = function ($x) {
- return $x / $x;
- };
- // And
- $args = [0.1];
- $target = 0;
- $position = 0;
- $tol = 0.00001;
- // When
- $x = NewtonsMethod::solve($func, $args, $target, $tol, $position);
- // Then
- $this->assertNan($x);
- }
- /**
- * @test Solve with no real solutions
- * @throws \Exception
- */
- public function testNewtonsMethodNoRealSolutionsNAN()
- {
- // Given
- $func = function ($x) {
- return $x ** 2 + 3 * $x + 3;
- };
- // And
- $args = [0.1];
- $target = 0;
- $position = 0;
- $tol = 0.00001;
- // When
- $x = NewtonsMethod::solve($func, $args, $target, $tol, $position);
- // Then
- $this->assertNan($x);
- }
- /**
- * @test Solve f(x) = ³√x for ³√x = 0
- * Has no solution
- * @throws \Exception
- */
- public function testNoSolutionCubeRootX()
- {
- // Given
- $func = function ($x) {
- return $x ** (1 / 3);
- };
- // And
- $args = [1];
- $target = 0;
- $position = 0;
- $tol = 0.00001;
- // When
- $root = NewtonsMethod::solve($func, $args, $target, $tol, $position);
- // Then
- $this->assertNan($root);
- }
- }
|