123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573 |
- <?php
- namespace MathPHP\Tests\Number;
- use MathPHP\Number\Quaternion;
- use MathPHP\Exception;
- use MathPHP\Number\ObjectArithmetic;
- class QuaternionTest extends \PHPUnit\Framework\TestCase
- {
- /**
- * @test Interfaces
- */
- public function testObjectArithmeticInterface()
- {
- // Given
- $c = new Quaternion(1, 2, 3, 4);
- // Then
- $this->assertInstanceOf(ObjectArithmetic::class, $c);
- }
- public function testZeroValue()
- {
- // Given
- $c = Quaternion::createZeroValue();
- // Then
- $this->assertEquals(0, $c->r);
- $this->assertEquals(0, $c->i);
- $this->assertEquals(0, $c->j);
- $this->assertEquals(0, $c->k);
- }
- /**
- * @test __toString returns the proper string representation of a quaternion
- * @dataProvider dataProviderForToString
- * @param number $r
- * @param number $i
- * @param number $j
- * @param number $k
- * @param string $expected
- */
- public function testToString($r, $i, $j, $k, string $expected)
- {
- // Given
- $c = new Quaternion($r, $i, $j, $k);
- // When
- $string = $c->__toString();
- // Then
- $this->assertEquals($expected, $string);
- $this->assertEquals($expected, (string) $c);
- }
- public function dataProviderForToString(): array
- {
- return [
- [0, 0, 0, 0, '0'],
- [1, 0, 0, 0, '1'],
- [-1, 0, 0, 0, '-1'],
- [0, 1, 0, 0, '1i'],
- [0, -1, 0, 0, '-1i'],
- [1, 0, 1, 0, '1 + 1j'],
- [1, 0, 0, 2, '1 + 2k'],
- [2, 0, -1, 0, '2 - 1j'],
- [2, 0, 0, -2, '2 - 2k'],
- [1, 0, -1, -1, '1 - 1j - 1k'],
- [1, 1, -2, 4, '1 + 1i - 2j + 4k'],
- ];
- }
- /**
- * @test __get returns r, i, j, and k
- */
- public function testGet()
- {
- // Given
- $r = 1;
- $i = 2;
- $j = 3;
- $k = 4;
- $c = new Quaternion($r, $i, $j, $k);
- // Then
- $this->assertEquals($r, $c->r);
- $this->assertEquals($i, $c->i);
- $this->assertEquals($j, $c->j);
- $this->assertEquals($k, $c->k);
- }
- /**
- * @test __get throws an Exception\BadParameterException if a property other than r or i is attempted
- */
- public function testGetException()
- {
- // Given
- $r = 1;
- $i = 2;
- $j = 3;
- $k = 4;
- $c = new Quaternion($r, $i, $j, $k);
- // Then
- $this->expectException(Exception\BadParameterException::class);
- // When
- $z = $c->z;
- }
- /**
- * @test complexConjugate returns the expected Quaternion
- * @dataProvider dataProviderForComplexConjugate
- * @param number $r
- * @param number $i
- * @param number $j
- * @param number $k
- */
- public function testComplexConjugate($r, $i, $j, $k)
- {
- // Given
- $c = new Quaternion($r, $i, $j, $k);
- // When
- $cc = $c->complexConjugate();
- // Then
- $this->assertEquals($c->r, $cc->r);
- $this->assertEquals($c->i, -1 * $cc->i);
- $this->assertEquals($c->j, -1 * $cc->j);
- $this->assertEquals($c->k, -1 * $cc->k);
- }
- public function dataProviderForComplexConjugate(): array
- {
- return [
- [0, 0, 0, 0],
- [1, 0, 0, 0],
- [0, 1, 0, 0],
- [0, 1, 1, 1],
- [1, 1, -1, -1],
- [1, 2, 3, 4],
- [3, 7, 11, -13],
- ];
- }
- /**
- * @test abs returns the expected value
- * @dataProvider dataProviderForAbs
- * @param number $r
- * @param number $i
- * @param number $j
- * @param number $k
- * @param number $expected
- */
- public function testAbs($r, $i, $j, $k, $expected)
- {
- // Given
- $c = new Quaternion($r, $i, $j, $k);
- // When
- $abs = $c->abs();
- // Then
- $this->assertEquals($expected, $abs);
- }
- public function dataProviderForAbs(): array
- {
- return [
- [0, 0, 0, 0, 0],
- [1, 0, 0, 0, 1],
- [0, 1, 0, 0, 1],
- [0, 0, 1, 0, 1],
- [0, 0, 0, 1, 1],
- [1, 2, 3, 4, \sqrt(30)],
- [-1, 0, 0, 0, 1],
- [0, -1, 0, 0, 1],
- [-1, 2, -3, 4, \sqrt(30)],
- ];
- }
- /**
- * @test negate returns the expected quaternion with signs negated
- * @dataProvider dataProviderForNegate
- * @param number $r₁
- * @param number $i₁
- * @param number $r₂
- * @param number $i₂
- */
- public function testNegate($r₁, $i₁, $j₁, $k₁, $r₂, $i₂, $j₂, $k₂)
- {
- // Given
- $c = new Quaternion($r₁, $i₁, $j₁, $k₁);
- $expected = new Quaternion($r₂, $i₂, $j₂, $k₂);
- // When
- $negated = $c->negate();
- // Then
- $this->assertTrue($negated->equals($expected));
- $this->assertEquals($expected->r, $negated->r);
- $this->assertEquals($expected->i, $negated->i);
- $this->assertEquals($expected->j, $negated->j);
- $this->assertEquals($expected->k, $negated->k);
- }
- public function dataProviderForNegate(): array
- {
- return [
- [0, 0, 0, 0, 0, 0, 0, 0],
- [1, 0, 0, 0, -1, 0, 0, 0],
- [0, 1, 1, 1, 0, -1, -1, -1],
- [1, 2, -1, -2, -1, -2, 1, 2],
- [3, 4, 3, 4, -3, -4, -3, -4],
- ];
- }
- /**
- * @test Constructor throws an exception when given non-numeric
- * @dataProvider dataProviderForConstructorException
- * @throws \Exception
- */
- public function testConstructorException($r, $i, $j, $k)
- {
- // Then
- $this->expectException(Exception\BadDataException::class);
- // When
- $c = new Quaternion($r, $i, $j, $k);
- }
- public function dataProviderForConstructorException(): array
- {
- return [
- ['a', 1, 1, 1],
- [1, true, 1, 1],
- [1, 1, new \stdClass(), 1],
- [1, 1, 1, [1]],
- ];
- }
- /**
- * @testCase inverse returns the expected quaternion
- * @dataProvider dataProviderForInverse
- * @param number $r
- * @param number $i
- * @param number $j
- * @param number $k
- * @param number $expected_r
- * @param number $expected_i
- * @param number $expected_j
- * @param number $expected_k
- */
- public function testInverse($r, $i, $j, $k, $expected_r, $expected_i, $expected_j, $expected_k)
- {
- $q = new Quaternion($r, $i, $j, $k);
- $inverse = $q->inverse();
- $this->assertEquals($expected_r, $inverse->r);
- $this->assertEquals($expected_i, $inverse->i);
- $this->assertEquals($expected_j, $inverse->j);
- $this->assertEquals($expected_k, $inverse->k);
- }
- public function dataProviderForInverse(): array
- {
- return [
- [1, 0, 0, 0, 1, 0, 0, 0],
- [0, 1, 0, 0, 0, -1, 0, 0],
- [0, 0, 1, 0, 0, 0, -1, 0],
- [0, 0, 0, 1, 0, 0, 0, -1],
- [1, -1, -1, -1, .25, .25, .25, .25],
- ];
- }
- /**
- * @testCase inverse throws an Exception\BadDataException when value is 0 + 0i + 0j + 0k
- */
- public function testInverseException()
- {
- $q = new Quaternion(0, 0, 0, 0);
- $this->expectException(Exception\BadDataException::class);
- $q->inverse();
- }
- /**
- * @test add of two complex numbers returns the expected complex number
- * @dataProvider dataProviderForAdd
- * @param array $complex1
- * @param array $complex2
- * @param array $expected
- */
- public function testAdd(array $complex1, array $complex2, array $expected)
- {
- // Given
- $q1 = new Quaternion($complex1['r'], $complex1['i'], $complex1['j'], $complex1['k']);
- $q2 = new Quaternion($complex2['r'], $complex2['i'], $complex2['j'], $complex2['k']);
- // When
- $result = $q1->add($q2);
- // Then
- $this->assertEquals($expected['r'], $result->r);
- $this->assertEquals($expected['i'], $result->i);
- $this->assertEquals($expected['j'], $result->j);
- $this->assertEquals($expected['k'], $result->k);
- }
- public function dataProviderForAdd(): array
- {
- return [
- [
- ['r' => 3, 'i' => 2, 'j' => 1, 'k' => -1],
- ['r' => 4, 'i' => -3, 'j' => -2, 'k' => -5],
- ['r' => 7, 'i' => -1, 'j' => -1, 'k' => -6],
- ],
- ];
- }
- /**
- * @test subtract of two quaternions returns the expected quaternion
- * @dataProvider dataProviderForSubtract
- * @param array $complex1
- * @param array $complex2
- * @param array $expected
- */
- public function testSubtract(array $complex1, array $complex2, array $expected)
- {
- // Given
- $q1 = new Quaternion($complex1['r'], $complex1['i'], $complex1['j'], $complex1['k']);
- $q2 = new Quaternion($complex2['r'], $complex2['i'], $complex2['j'], $complex2['k']);
- // When
- $result = $q1->subtract($q2);
- // Then
- $this->assertEquals($expected['r'], $result->r);
- $this->assertEquals($expected['i'], $result->i);
- $this->assertEquals($expected['j'], $result->j);
- $this->assertEquals($expected['k'], $result->k);
- }
- public function dataProviderForSubtract(): array
- {
- return [
- [
- ['r' => 3, 'i' => 2, 'j' => 1, 'k' => -1],
- ['r' => -4, 'i' => 3, 'j' => 2, 'k' => 5],
- ['r' => 7, 'i' => -1, 'j' => -1, 'k' => -6],
- ],
- ];
- }
- /**
- * @test add of real numbers returns the expected quaternion
- * @dataProvider dataProviderForAddReal
- */
- public function testAddReal($complex, $real, $expected)
- {
- // Given
- $q = new Quaternion($complex['r'], $complex['i'], $complex['j'], $complex['k']);
- // When
- $result = $q->add($real);
- // Then
- $this->assertEquals($expected['r'], $result->r);
- $this->assertEquals($expected['i'], $result->i);
- $this->assertEquals($expected['j'], $result->j);
- $this->assertEquals($expected['k'], $result->k);
- }
- public function dataProviderForAddReal()
- {
- return [
- [
- ['r' => 3, 'i' => 2, 'j' => 1, 'k' => -1],
- 5,
- ['r' => 8, 'i' => 2, 'j' => 1, 'k' => -1],
- ],
- [
- ['r' => 0, 'i' => 0, 'j' => 0, 'k' => 0],
- 5,
- ['r' => 5, 'i' => 0, 'j' => 0, 'k' => 0],
- ],
- [
- ['r' => 3, 'i' => 2, 'j' => 1, 'k' => -1],
- -2,
- ['r' => 1, 'i' => 2, 'j' => 1, 'k' => -1],
- ],
- ];
- }
- /**
- * @test subtract of real numbers returns the expected quaternion
- * @dataProvider dataProviderForSubtractReal
- */
- public function testSubtractReal($complex, $real, $expected)
- {
- // Given
- $q = new Quaternion($complex['r'], $complex['i'], $complex['j'], $complex['k']);
- // When
- $result = $q->subtract($real);
- // Then
- $this->assertEquals($expected['r'], $result->r);
- $this->assertEquals($expected['i'], $result->i);
- $this->assertEquals($expected['j'], $result->j);
- $this->assertEquals($expected['k'], $result->k);
- }
- public function dataProviderForSubtractReal()
- {
- return [
- [
- ['r' => 3, 'i' => 2, 'j' => 1, 'k' => -1],
- -5,
- ['r' => 8, 'i' => 2, 'j' => 1, 'k' => -1],
- ],
- [
- ['r' => 0, 'i' => 0, 'j' => 0, 'k' => 0],
- -5,
- ['r' => 5, 'i' => 0, 'j' => 0, 'k' => 0],
- ],
- [
- ['r' => 3, 'i' => 2, 'j' => 1, 'k' => -1],
- 2,
- ['r' => 1, 'i' => 2, 'j' => 1, 'k' => -1],
- ],
- ];
- }
- /**
- * @test multiply of two quaternions returns the expected quaternion
- * @dataProvider dataProviderForMultiply
- * @param array $complex1
- * @param array $complex2
- * @param array $expected
- */
- public function testMultiply(array $complex1, array $complex2, array $expected)
- {
- // Given
- $q1 = new Quaternion($complex1['r'], $complex1['i'], $complex1['j'], $complex1['k']);
- $q2 = new Quaternion($complex2['r'], $complex2['i'], $complex2['j'], $complex2['k']);
- // When
- $result = $q1->multiply($q2);
- // Then
- $this->assertEquals($expected['r'], $result->r);
- $this->assertEquals($expected['i'], $result->i);
- $this->assertEquals($expected['j'], $result->j);
- $this->assertEquals($expected['k'], $result->k);
- }
- public function dataProviderForMultiply(): array
- {
- return [
- [
- ['r' => 3, 'i' => 2, 'j' => 1, 'k' => -1],
- ['r' => 1, 'i' => 4, 'j' => 3, 'k' => 2],
- ['r' => -6, 'i' => 19, 'j' => 2, 'k' => 7],
- ],
- [
- ['r' => 3, 'i' => 13, 'j' => 5, 'k' => 7],
- ['r' => 19, 'i' => 17, 'j' => -11, 'k' => 2],
- ['r' => -123, 'i' => 385, 'j' => 155, 'k' => -89],
- ],
- [
- ['r' => 2, 'i' => 3, 'j' => 4, 'k' => 5],
- ['r' => 6, 'i' => 7, 'j' => 8, 'k' => 9],
- ['r' => -86, 'i' => 28, 'j' => 48, 'k' => 44],
- ],
- ];
- }
- /**
- * @test divide of two cquaternions returns the expected quaternion
- * @dataProvider dataProviderForDivide
- * @param array $complex1
- * @param array $complex2
- * @param array $expected
- */
- public function testDivide(array $complex1, array $complex2, array $expected)
- {
- // Given
- $q1 = new Quaternion($complex1['r'], $complex1['i'], $complex1['j'], $complex1['k']);
- $q2 = new Quaternion($complex2['r'], $complex2['i'], $complex2['j'], $complex2['k']);
- // When
- $result = $q1->divide($q2);
- // Then
- $this->assertEqualsWithDelta($expected['r'], $result->r, 0.00001);
- $this->assertEqualsWithDelta($expected['i'], $result->i, 0.00001);
- $this->assertEqualsWithDelta($expected['j'], $result->j, 0.00001);
- $this->assertEqualsWithDelta($expected['k'], $result->k, 0.00001);
- }
- public function dataProviderForDivide(): array
- {
- return [
- [
- ['r' => 3, 'i' => 2, 'j' => 1, 'k' => -1],
- ['r' => 1, 'i' => 4, 'j' => 3, 'k' => 2],
- ['r' => 2 / 5, 'i' => -1 / 2, 'j' => 0, 'k' => -3 / 10],
- ],
- ];
- }
- /**
- * @test add throws an Exception\IncorrectTypeException when the argument is not a number or quaternion
- */
- public function testQuaternionAddException()
- {
- // Given
- $q = new Quaternion(1, 1, 1, 1);
- // Then
- $this->expectException(Exception\IncorrectTypeException::class);
- // When
- $q->add("string");
- }
- /**
- * @test subtract throws an Exception\IncorrectTypeException when the argument is not a number or quaternion
- */
- public function testQuaternionSubtractException()
- {
- // Given
- $q = new Quaternion(1, 1, 1, 1);
- // Then
- $this->expectException(Exception\IncorrectTypeException::class);
- // When
- $q->subtract("string");
- }
- /**
- * @test multiply throws an Exception\IncorrectTypeException when the argument is not a number or quaternion
- */
- public function tesQuaternionMultiplyException()
- {
- // Given
- $q = new Quaternion(1, 1, 1, 1);
- // Then
- $this->expectException(Exception\IncorrectTypeException::class);
- // When
- $q->multiply("string");
- }
- /**
- * @test divide throws an Exception\IncorrectTypeException when the argument is not a number or quaternion
- */
- public function testQuaternionDivideException()
- {
- // Given
- $q = new Quaternion(1, 1, 1, 1);
- // Then
- $this->expectException(Exception\IncorrectTypeException::class);
- // When
- $q->divide("string");
- }
- }
|