1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486 |
- <?php
- namespace MathPHP\Tests\Functions;
- use MathPHP\Functions\Special;
- use MathPHP\Exception;
- class SpecialTest extends \PHPUnit\Framework\TestCase
- {
- /**
- * @test signum/sgn returns the expected value
- * @dataProvider dataProviderForSignum
- * @param $x
- * @param $sign
- */
- public function testSignum($x, $sign)
- {
- // When
- $signum = Special::signum($x);
- $sgn = Special::sgn($x);
- // Then
- $this->assertEquals($sign, $signum);
- $this->assertEquals($sign, $sgn);
- }
- public function dataProviderForSignum(): array
- {
- return [
- [ 0, 0 ],
- [ 1, 1 ],
- [ 0.5, 1 ],
- [ 1.5, 1 ],
- [ 4, 1 ],
- [ 123241.342, 1 ],
- [ -1, -1 ],
- [ -0.5, -1 ],
- [ -1.5, -1 ],
- [ -4, -1 ],
- [ -123241.342, -1 ],
- ];
- }
- /**
- * @test gamma returns the expected value
- * @dataProvider dataProviderForGamma
- * @param $z
- * @param $Γ
- * @throws \Exception
- */
- public function testGamma($z, $Γ)
- {
- // When
- $gamma = Special::gamma($z);
- // Then
- $this->assertEqualsWithDelta($Γ, $gamma, 0.001);
- }
- /**
- * Test data created with R gamma(z) and online calculator https://keisan.casio.com/exec/system/1180573444
- * @return array (z, Γ)
- */
- public function dataProviderForGamma(): array
- {
- return [
- [0.1, 9.51350769866873183629],
- [0.2, 4.5908437119988030532],
- [0.3, 2.99156898768759062831],
- [0.4, 2.21815954375768822306],
- [0.5, 1.772453850905516027298],
- [0.6, 1.489192248812817102394],
- [0.7, 1.29805533264755778568],
- [0.8, 1.16422971372530337364],
- [0.9, 1.0686287021193193549],
- [1, 1],
- [1.0, 1],
- [1.1, 0.951350769866873183629],
- [1.2, 0.91816874239976061064],
- [1.3, 0.89747069630627718849],
- [1.4, 0.88726381750307528922],
- [1.5, 0.88622692545275801365],
- [1.6, 0.89351534928769026144],
- [1.7, 0.90863873285329044998],
- [1.8, 0.9313837709802426989091],
- [1.9, 0.96176583190738741941],
- [2, 1],
- [2.0, 1],
- [3, 2],
- [3.0, 2],
- [4, 6],
- [4.0, 6],
- [5, 24],
- [5.0, 24],
- [6, 120],
- [6.0, 120],
- [7, 720],
- [8, 5040],
- [9, 40320],
- [10, 362880],
- [11, 3628800],
- [12, 39916800],
- [13, 479001600],
- [14, 6227020800],
- [15, 87178291200],
- [16, 1307674368000],
- [17, 20922789888000],
- [18, 355687428096000],
- [19, 6402373705728000],
- [20, 121645100408832000],
- [2.5, 1.32934038817913702047],
- [5.324, 39.54287866273389258523],
- [10.2, 570499.02784103598123],
- [-0.1, -10.686287021193193549],
- [-0.4, -3.72298062203204275599],
- [-1.1, 9.7148063829029032263],
- [-1.2, 4.8509571405220973902],
- [-1.9, 5.563455],
- [-1.99, 50.47083],
- [-1.999, 500.4623],
- [-1.9999, 5000.461],
- [-1.99999, 50000.4614015337837734],
- [1E-207, 1E207],
- [2E-308, \INF],
- [-2E-309, -\INF],
- [-172.25, 0],
- [-168.0000000000001, -3.482118E-290],
- [-167.9999999999999, 3.482118E-290],
- ];
- }
- /**
- * @test gamma throws an NanException if gamma is undefined.
- * @dataProvider dataProviderUndefinedGamma
- */
- public function testGammaExceptionUndefined($x)
- {
- // Then
- $this->expectException(Exception\NanException::class);
- // When
- Special::gamma($x);
- }
- public function dataProviderUndefinedGamma()
- {
- return [
- [0],
- [0.0],
- [-1],
- [-2],
- [-2.0],
- [-3],
- [-4],
- [-10],
- [-20],
- ];
- }
- /**
- * @test gamma of large values
- * @dataProvider dataProviderForGammaLargeValues
- * @param $z
- * @param $Γ
- * @param float $ε - relative error
- * @throws \Exception
- */
- public function testGammaLargeValues($z, $Γ, float $ε = 1E-10)
- {
- // When
- $gamma = Special::gamma($z);
- // Then
- $this->assertEqualsWithDelta($Γ, $gamma, $Γ * $ε);
- }
- /**
- * Test data created with high-precision online calculator: https://keisan.casio.com/exec/system/1180573444
- * @return array (z, Γ, ε)
- */
- public function dataProviderForGammaLargeValues(): array
- {
- return [
- [15, 87178291200],
- [20, 121645100408832000],
- [50, 6.082818640342675608723E+62],
- [100, 9.33262154439441526817E+155],
- [100.6, 1.477347552911177316693E+157],
- [171, 7.257415615307998967397E+306],
- [200, 3.943289336823952517762E+372],
- ];
- }
- /**
- * @test gammaLanczos returns the expected value
- * @dataProvider dataProviderForGammaLanczos
- * @param $z
- * @param $Γ
- * @throws \Exception
- */
- public function testGammaLanczos($z, $Γ)
- {
- // When
- $gammaLanczos = Special::gammaLanczos($z);
- // Then
- $this->assertEqualsWithDelta($Γ, $gammaLanczos, 0.001);
- }
- public function dataProviderForGammaLanczos(): array
- {
- return [
- [0.1, 9.51350769866873183629],
- [0.2, 4.5908437119988030532],
- [0.3, 2.99156898768759062831],
- [0.4, 2.21815954375768822306],
- [0.5, 1.772453850905516027298],
- [0.6, 1.489192248812817102394],
- [0.7, 1.29805533264755778568],
- [0.8, 1.16422971372530337364],
- [0.9, 1.0686287021193193549],
- [1, 1],
- [1.0, 1],
- [1.1, 0.951350769866873183629],
- [1.2, 0.91816874239976061064],
- [1.3, 0.89747069630627718849],
- [1.4, 0.88726381750307528922],
- [1.5, 0.88622692545275801365],
- [1.6, 0.89351534928769026144],
- [1.7, 0.90863873285329044998],
- [1.8, 0.9313837709802426989091],
- [1.9, 0.96176583190738741941],
- [2, 1],
- [2.0, 1],
- [3, 2],
- [3.0, 2],
- [4, 6],
- [4.0, 6],
- [5, 24],
- [5.0, 24],
- [6, 120],
- [6.0, 120],
- [2.5, 1.32934038817913702047],
- [5.324, 39.54287866273389258523],
- [10.2, 570499.02784103598123],
- [0, \INF],
- [0.0, \INF],
- [-1, -\INF],
- [-2, -\INF],
- [-2.0, -\INF],
- [-0.1, -10.686287021193193549],
- [-0.4, -3.72298062203204275599],
- [-1.1, 9.7148063829029032263],
- [-1.2, 4.8509571405220973902],
- ];
- }
- /**
- * @test gammaStirling returns the expected value
- * @dataProvider dataProviderForGammaStirling
- * @param $n
- * @param $Γ
- * @throws \Exception
- */
- public function testGammaStirling($n, $Γ)
- {
- // When
- $gammaSterling = Special::gammaStirling($n);
- // Then
- $this->assertEqualsWithDelta($Γ, $gammaSterling, 0.01);
- }
- public function dataProviderForGammaStirling(): array
- {
- return [
- [ 1, 1 ],
- [ 1.0, 1 ],
- [ 2, 1 ],
- [ 3, 2 ],
- [ 4, 6 ],
- [ 5, 24 ],
- [ 6, 120 ],
- [ 1.1, 0.951350769866873183629 ],
- [ 1.2, 0.91816874239976061064 ],
- [ 1.5, 0.88622692545275801365 ],
- [ 2.5, 1.32934038817913702047 ],
- [ 5.324, 39.54287866273389258523 ],
- [ 10.2, 570499.02784103598123 ],
- [ 0, \INF ],
- [ -1, -\INF ],
- [ -2, -\INF ],
- [ -2.0, -\INF ],
- ];
- }
- /**
- * @test logGamma returns the expected value
- * @dataProvider dataProviderForLogGamma
- * @param $z
- * @param $Γ
- * @throws \Exception
- */
- public function testLogGamma($z, $Γ)
- {
- // When
- $log_gamma = Special::logGamma($z);
- // Then
- $this->assertEqualsWithDelta($Γ, $log_gamma, abs($Γ) * 0.00001);
- }
- /**
- * Test data produced with R function lgamma(x)
- * @return array
- */
- public function dataProviderForLogGamma(): array
- {
- return [
- [-2, \INF],
- [-1.9, 1.716219],
- [-1.5, 0.860047],
- [-1, \INF],
- [-0.1, 2.368961],
- [0, \INF],
- [0.1, 2.252713],
- [0.5, 0.5723649],
- [1, 0],
- [1.0, 0],
- [2, 0],
- [2.1, 0.04543774],
- [2.5, 0.2846829],
- [3, 0.6931472],
- [10, 12.80183],
- [100, 359.1342],
- [1000, 5905.22],
- [10000, 82099.72],
- [100000, 1051288],
- [5E-307, 705.2842],
- [2.6E305, \INF],
- [2E17, 7.767419e+18],
- [4934770, 71118994],
- [-.9, 2.358073],
- [-11.2, -16.31644474],
- ];
- }
- /**
- * @test logGamma returns NaNException appropriately
- */
- public function testLogGammaNan()
- {
- // Given
- $nan = acos(1.01);
- // Then
- $this->expectException(Exception\NanException::class);
- // When
- $nan = Special::logGamma($nan);
- }
- /**
- * @test gamma returns NaNException appropriately
- */
- public function testGammaNan()
- {
- // Given
- $nan = \NAN;
- // Then
- $this->expectException(Exception\NanException::class);
- // When
- $nan = Special::gamma($nan);
- }
- /**
- * @test beta returns the expected value
- * @dataProvider dataProviderForBeta
- * @param float $x
- * @param float $y
- * @param float $expected
- * @throws \Exception
- */
- public function testBeta(float $x, float $y, float $expected)
- {
- // When
- $beta = Special::beta($x, $y);
- $β = Special::β($y, $x);
- // Then
- $this->assertEqualsWithDelta($expected, $beta, 0.0000001);
- $this->assertEqualsWithDelta($expected, $β, 0.0000001);
- }
- /**
- * Test data created with R beta (x, y) and online calculator https://keisan.casio.com/exec/system/1180573394
- * @return array (x, y, β)
- */
- public function dataProviderForBeta(): array
- {
- return [
- [1.5, 0, \INF],
- [0, 1.5, \INF],
- [0, 0, \INF],
- [1, 1, 1],
- [1, 2, 0.5],
- [1, 3, 0.3333333333],
- [1, 4, 0.25],
- [1, 5, 0.2],
- [1, 6, 0.1666667],
- [1, 7, 0.1428571],
- [1, 8, 0.125],
- [1, 9, 0.1111111],
- [1, 10, 0.1],
- [1, 11, 0.09090909],
- [1, 20, 0.05],
- [2, 0, \INF],
- [2, 1, 0.5],
- [2, 2, 0.1666667],
- [2, 3, 0.08333333],
- [2, 4, 0.05],
- [2, 5, 0.03333333],
- [2, 6, 0.02380952],
- [2, 7, 0.01785714],
- [2, 8, 0.01388889],
- [2, 9, 0.01111111],
- [2, 10, 0.009090909],
- [2, 11, 0.007575758],
- [2, 20, 0.002380952],
- [3, 0, \INF],
- [3, 1, 0.3333333],
- [3, 2, 0.08333333],
- [3, 3, 0.03333333],
- [3, 4, 0.01666667],
- [3, 5, 0.00952381],
- [3, 6, 0.005952381],
- [3, 7, 0.003968254],
- [3, 8, 0.002777778],
- [3, 9, 0.002020202],
- [3, 10, 0.001515152],
- [3, 11, 0.001165501],
- [3, 20, 0.0002164502],
- [1.5, 0.2, 4.4776093743471688104],
- [0.2, 1.5, 4.4776093743471688104],
- [0.1, 0.9, 10.16640738463051963162],
- [0.9, 0.1, 10.16640738463051963162],
- [3, 9, 0.002020202],
- [9, 3, 0.002020202],
- [10, 10, 1.082509e-06],
- [20, 20, 7.254445e-13],
- [\INF, 2, 0],
- [2, \INF, 0],
- [1.5, 170.5, 0.0003971962], // Issue #429
- ];
- }
- /**
- * @testCase logBeta returns the expected value
- * @dataProvider dataProviderForLogBeta
- */
- public function testLogBeta($x, $y, float $log_beta)
- {
- $this->assertEqualsWithDelta($log_beta, Special::logBeta($x, $y), 0.001);
- }
- public function dataProviderForLogBeta(): array
- {
- return [
- [1.5, 0, \INF],
- [0, 1.5, \INF],
- [0, 0, \INF],
- [1, 1, 0],
- [1, 2, -0.6931472],
- [2, 1, -0.6931472],
- [2, 2, -1.791759],
- [.9, .1, 2.319089],
- [20, 20, -27.95199],
- [1, \INF, -\INF],
- [1, 11, -2.397895],
- [5E-307, 5, 705.2842],
- [94907000, 11, -186.9481],
- ];
- }
- /**
- * @test beta returns NaNException appropriately
- */
- public function testBetaNan()
- {
- // Given
- $nan = \NAN;
- // Then
- $this->expectException(Exception\NanException::class);
- // When
- $beta = Special::beta($nan, 2);
- }
- /**
- * @test logBeta returns NaNException appropriately
- */
- public function testLogBetaNan()
- {
- // Given
- $nan = \NAN;
- // Then
- $this->expectException(Exception\NanException::class);
- // When
- $lbeta = Special::logBeta($nan, 2);
- }
- /**
- * @test logBeta parameters must be greater than 0
- */
- public function testLogBetaOutOfBounds()
- {
- // Given
- $p = -1;
- // Then
- $this->expectException(Exception\OutOfBoundsException::class);
- // When
- $lbeta = Special::logBeta($p, 2);
- }
- /**
- * @test beta parameters must be greater than 0
- */
- public function testBetaOutOfBounds()
- {
- // Given
- $p = -1;
- // Then
- $this->expectException(Exception\OutOfBoundsException::class);
- // When
- $beta = Special::beta($p, 2);
- }
- /**
- * @test logGammaCorr parameter must be greater than 10
- */
- public function testLogGammaCorrOutOfBounds()
- {
- // Given
- $x = 1;
- // Then
- $this->expectException(Exception\OutOfBoundsException::class);
- // When
- $correction = Special::logGammaCorr($x);
- }
- /**
- * @test multivariateBeta returns the expected value
- * @dataProvider dataProviderForBeta
- * @param float $x
- * @param float $y
- * @param float $expected
- * @throws \Exception
- */
- public function testMultivariateBeta(float $x, float $y, float $expected)
- {
- // When
- $beta = Special::multivariateBeta([$x, $y]);
- // Then
- $this->assertEqualsWithDelta($expected, $beta, 0.0000001);
- }
- /**
- * @test logistic returns the expected value
- * @dataProvider dataProviderForLogistic
- * @param float $x₀
- * @param float $L
- * @param float $k
- * @param float $x
- * @param float $expected
- */
- public function testLogistic(float $x₀, float $L, float $k, float $x, float $expected)
- {
- // When
- $logistic = Special::logistic($x₀, $L, $k, $x);
- // Then
- $this->assertEqualsWithDelta($expected, $logistic, 0.001);
- }
- public function dataProviderForLogistic(): array
- {
- return [
- [0, 0, 0, 0, 0],
- [1, 1, 1, 1, 0.5],
- [2, 2, 2, 2, 1],
- [3, 2, 2, 2, 0.238405844044],
- [3, 4, 2, 2, 0.476811688088],
- [3, 4, 5, 2, 0.0267714036971],
- [3, 4, 5, 6, 3.99999877639],
- [2.1, 3.2, 1.5, 0.6, 0.305118287677],
- // Test data created with R (sigmoid) logistic(x, k, x₀) where L = 1
- [0, 1, 1, 0, 0.5],
- [0, 1, 1, 1, 0.7310586],
- [1, 1, 1, 0, 0.2689414],
- ];
- }
- /**
- * @test sigmoid
- * @dataProvider dataProviderForSigmoid
- * @param float $x
- * @param float $expected
- */
- public function testSigmoid(float $x, float $expected)
- {
- // When
- $sigmoid = Special::sigmoid($x);
- // Then
- $this->assertEqualsWithDelta($expected, $sigmoid, 0.0000001);
- }
- /**
- * Test data created with R (sigmoid) sigmoid(x)
- * @return array (x, sigmoid)
- */
- public function dataProviderForSigmoid(): array
- {
- return [
- [0, 0.5],
- [1, 0.7310586],
- [2, 0.8807971],
- [3, 0.9525741],
- [4, 0.9820138],
- [5, 0.9933071],
- [6, 0.9975274],
- [10, 0.9999546],
- [13, 0.9999977],
- [15, 0.9999997],
- [16, 0.9999999],
- [17, 1],
- [20, 1],
- [-1, 0.2689414],
- [-2, 0.1192029],
- [-3, 0.04742587],
- [-4, 0.01798621],
- [-5, 0.006692851],
- [-6, 0.002472623],
- [-10, 4.539787e-05],
- [-15, 3.059022e-07],
- [-20, 2.061154e-09],
- [0.5, 0.6224593],
- [5.5, 0.9959299],
- [-0.5, 0.3775407],
- [-5.5, 0.004070138],
- ];
- }
- /**
- * @test sigmoid returns the expected value
- * Sigmoid is just a special case of the logistic function.
- */
- public function testSigmoidSpecialCaseOfLogisitic()
- {
- $this->assertEquals(Special::logistic(1, 1, 1, 2), Special::sigmoid(1));
- $this->assertEquals(Special::logistic(1, 1, 2, 2), Special::sigmoid(2));
- $this->assertEquals(Special::logistic(1, 1, 3, 2), Special::sigmoid(3));
- $this->assertEquals(Special::logistic(1, 1, 4, 2), Special::sigmoid(4));
- $this->assertEquals(Special::logistic(1, 1, 4.6, 2), Special::sigmoid(4.6));
- }
- /**
- * @test errorFunction returns the expected value
- * @dataProvider dataProviderForErrorFunction
- * @param float $x
- * @param float $expected
- */
- public function testErrorFunction(float $x, float $expected)
- {
- // When
- $errorFunction = Special::errorFunction($x);
- $erf = Special::erf($x);
- // Then
- $this->assertEqualsWithDelta($expected, $errorFunction, 0.0001);
- $this->assertEqualsWithDelta($expected, $erf, 0.0001);
- }
- /**
- * Test data created with R (VGAM) erf(x) and online calculator https://keisan.casio.com/exec/system/1180573449
- * @return array (x, erf)
- */
- public function dataProviderForErrorFunction(): array
- {
- return [
- [0, 0],
- [1, 0.8427007929497148693412],
- [-1, -0.8427007929497148693412],
- [2, 0.9953222650189527341621],
- [3.4, 0.9999984780066371377146],
- [0.154, 0.1724063976196591819236],
- [-2.31, -0.9989124231037000500402],
- [-1.034, -0.856340111375020118952],
- [3, 0.9999779],
- [4, 1],
- [5, 1],
- [10, 1],
- [-2, -0.9953223],
- [-3, -0.9999779],
- [-4, -1],
- [-5, -1],
- [-10, -1],
- ];
- }
- /**
- * @test complementaryErrorFunction returns the expected value
- * @dataProvider dataProviderForComplementaryErrorFunction
- * @param float $x
- * @param float $expected
- */
- public function testComplementaryErrorFunction(float $x, float $expected)
- {
- // When
- $complementaryErrorFunction = Special::complementaryErrorFunction($x);
- $efc = Special::erfc($x);
- // Then
- $this->assertEqualsWithDelta($expected, $complementaryErrorFunction, 0.0001);
- $this->assertEqualsWithDelta($expected, $efc, 0.0001);
- }
- /**
- * Test data created with R (VGAM) erfc and online calculator https://keisan.casio.com/exec/system/1180573449
- * @return array (x, erfc)
- */
- public function dataProviderForComplementaryErrorFunction(): array
- {
- return [
- [0, 1],
- [1, 0.1572992070502851306588],
- [-1, 1.842700792949714869341],
- [2, 0.004677734981047265837931],
- [3.4, 1.521993362862285361757E-6],
- [0.154, 0.8275936023803408180764],
- [-2.31, 1.99891242310370005004],
- [-1.034, 1.856340111375020118952],
- [3, 2.20905e-05],
- [4, 1.541726e-08],
- [5, 1.53746e-12],
- [10, 2.088488e-45],
- [-2, 1.995322],
- [-3, 1.999978],
- [-4, 2],
- [-5, 2],
- [-10, 2],
- ];
- }
- /**
- * @test lowerIncompleteGamma returns the expected value
- * @dataProvider dataProviderForLowerIncompleteGamma
- * @param float $s
- * @param float $x
- * @param float $lig
- */
- public function testLowerIncompleteGamma(float $s, float $x, float $lig)
- {
- // When
- $lowerIncompleteGamma = Special::lowerIncompleteGamma($s, $x);
- // Then
- $this->assertEqualsWithDelta($lig, $lowerIncompleteGamma, 0.00001);
- }
- /**
- * Test data created with R (pracma) gammainc(x, a)
- * @return array (s, x, gamma)
- */
- public function dataProviderForLowerIncompleteGamma(): array
- {
- return [
- [0.0001, 1, 9999.2034895],
- [1, 1, 0.6321206],
- [1, 2, 0.8646647],
- [2, 2, 0.5939942],
- [3, 2.5, 0.9123738],
- [3.5, 2, 0.7318770],
- [4.6, 2, 1.07178785],
- [4, 2.6, 1.5839901],
- [2.7, 2.6, 0.8603568],
- [1.5, 2.5, 0.7339757],
- [0.5, 4, 1.764162782],
- [2, 3, 0.8008517],
- [4.5, 2.3, 1.5389745],
- [7, 9.55, 603.9624331],
- [1, 3, 0.95021293],
- [0.5, 0.5, 1.2100356],
- [0.5, 1, 1.4936483],
- [0.5, 4, 1.764162782],
- // Negative x it not officially supported, but sometimes works.
- // Other times it gets NAN.
- [1, -1, -1.718282],
- [1, -2, -6.389056],
- [2, -2, 8.389056],
- [3, -2.5, -37.59311],
- [4, -2.6, 98.84594],
- [2, -3, 41.17107],
- [1, -3, -19.08554],
- ];
- }
- /**
- * @test lowerIncompleteGamma returns 0 for x = 0, and s and x = 0
- * @dataProvider dataProviderForLowerIncompleteGammaZeroBoundary
- * @param float $s
- * @param float $x
- */
- public function testLowerIncompleteGammaZeroBoundary(float $s, float $x)
- {
- // When
- $lowerIncompleteGamma = Special::lowerIncompleteGamma($s, $x);
- // Then
- $this->assertEqualsWithDelta(0, $lowerIncompleteGamma, 0.00001);
- }
- /**
- * @return array (s, x)
- */
- public function dataProviderForLowerIncompleteGammaZeroBoundary(): array
- {
- return [
- [0, 0],
- [1, 0],
- [2, 0],
- [100, 0]
- ];
- }
- /**
- * @test lowerIncompleteGamma returns NAN for x = 0 and x nonzero
- * @dataProvider dataProviderForLowerIncompleteGammaNanBoundary
- * @param float $s
- * @param float $x
- */
- public function testLowerIncompleteGammaNanBoundary(float $s, float $x)
- {
- // When
- $lowerIncompleteGamma = Special::lowerIncompleteGamma($s, $x);
- // Then
- $this->assertNan($lowerIncompleteGamma);
- }
- /**
- * @return array (s, x)
- */
- public function dataProviderForLowerIncompleteGammaNanBoundary(): array
- {
- return [
- [0, 1],
- [0, 2],
- [0, 10],
- [0, 1000]
- ];
- }
- /**
- * @test upperIncompleteGamma returns the expected value
- * @dataProvider dataProviderForUpperIncompleteGamma
- * @param float $s
- * @param float $x
- * @param float $uig
- * @throws \Exception
- */
- public function testUpperIncompleteGamma(float $s, float $x, float $uig)
- {
- // When
- $upperIncompleteGamma = Special::upperIncompleteGamma($s, $x);
- // Then
- $this->assertEqualsWithDelta($uig, $upperIncompleteGamma, 0.00001);
- }
- /**
- * Test data created with R (pracma) gammainc(x, a)
- * @return array (s, x, gamma)
- */
- public function dataProviderForUpperIncompleteGamma(): array
- {
- return [
- [0.0001, 1, 0.21939372],
- [1, 1, 0.3678794],
- [1, 2, 0.1353353],
- [2, 2, 0.40600585],
- [3, 2.5, 1.08762623],
- [3.5, 2, 2.59147401],
- [4.6, 2, 12.30949802],
- [4, 2.6, 4.41600987],
- [2.7, 2.6, 0.68432904],
- [1.5, 2.5, 0.15225125],
- [0.5, 4, 0.008291069],
- [2, 3, 0.1991483],
- [4.5, 2.3, 10.0927539],
- [7, 9.55, 116.0375669],
- [0.5, 0.5, 0.5624182],
- [0.5, 1, 0.2788056],
- [0.5, 4, 0.008291069],
- ];
- }
- /**
- * @test regularizedLowerIncompleteGamma
- * @dataProvider dataProviderForRegularizedLowerIncompleteGamma
- * @param float $s
- * @param float $x
- * @param float $expected
- * @throws \Exception
- */
- public function testRegularizedLowerIncompleteGamma(float $s, float $x, float $expected)
- {
- // When
- $gammainc = Special::regularizedLowerIncompleteGamma($s, $x);
- // Then
- $this->assertEqualsWithDelta($expected, $gammainc, 0.00001);
- }
- public function dataProviderForRegularizedLowerIncompleteGamma(): array
- {
- return [
- [0.0001, 1, 0.9999781],
- [1, 1, 0.6321206],
- [1, 2, 0.8646647],
- [2, 2, 0.5939942],
- [3, 2.5, 0.4561869],
- [3.5, 2, 0.2202226],
- [4.6, 2, 0.08009603],
- [4, 2.6, 0.2639984],
- [2.7, 2.6, 0.5569785],
- [1.5, 2.5, 0.8282029],
- [0.5, 4, 0.995322265],
- [2, 3, 0.8008517],
- [4.5, 2.3, 0.1323083],
- [7, 9.55, 0.8388367],
- [1, 3, 0.95021293],
- [0.5, 0.5, 0.6826895],
- [0.5, 1, 0.8427008],
- [0.5, 4, 0.995322265],
- ];
- }
- /**
- * @test regularizedIncompleteBeta returns the expected value
- * @dataProvider dataProviderForRegularizedIncompleteBeta
- * @param float $x
- * @param float $a
- * @param float $b
- * @param float $rib
- * @throws \Exception
- */
- public function testRegularizedIncompleteBeta(float $x, float $a, float $b, float $rib)
- {
- // When
- $regularizedIncompleteBeta = Special::regularizedIncompleteBeta($x, $a, $b);
- // Then
- $this->assertEqualsWithDelta($rib, $regularizedIncompleteBeta, 0.0000001);
- }
- /**
- * Test data created with Python scipy.special.betainc(a, b, x) and online calculator https://keisan.casio.com/exec/system/1180573396
- * @return array (x, a, b, beta)
- */
- public function dataProviderForRegularizedIncompleteBeta(): array
- {
- return [
- [0.4, 1, 2, 0.64],
- [0.4, 1, 4, 0.87040],
- [0.4, 2, 4, 0.663040],
- [0.4, 4, 4, 0.2897920],
- [0.7, 6, 10, 0.99634748],
- [0.7, 7, 10, 0.99287048],
- [0.44, 3, 8.4, 0.90536083],
- [0.44, 3.5, 8.5, 0.86907356],
- [0.3, 2.5, 4.5, 0.40653902],
- [0.5, 1, 2, 0.750],
- [0.2, 3.4, 2.3, 0.02072722],
- [0.8, 3.4, 2.3, 0.84323132],
- [0.45, 12.45, 3.49, 0.00283809],
- [0.294, 0.23, 2.11, 0.88503883],
- [0.993, 0.23, 2.11, 0.99999612],
- [0.76, 4, 0.3, 0.08350803],
- [0.55, 2, 2.5, 0.67737732],
- [0.55, 2.5, 2, 0.47672251],
- [0.55, 3.5, 2, 0.31772153],
- [0.73, 3.5, 5, 0.97317839],
- [0, 1, 1, 0],
- [0.1, 1, 1, 0.1],
- [0.2, 1, 1, 0.2],
- [0.3, 1, 1, 0.3],
- [0.4, 1, 1, 0.4],
- [0.5, 1, 1, 0.5],
- [0.6, 1, 1, 0.6],
- [0.7, 1, 1, 0.7],
- [0.8, 1, 1, 0.8],
- [0.9, 1, 1, 0.9],
- [1, 1, 1, 1],
- [0, 2, 2, 0],
- [0.1, 2, 2, 0.028],
- [0.2, 2, 2, 0.104],
- [0.3, 2, 2, 0.216],
- [0.4, 2, 2, 0.352],
- [0.5, 2, 2, 0.5],
- [0.6, 2, 2, 0.648],
- [0.7, 2, 2, 0.784],
- [0.8, 2, 2, 0.896],
- [0.9, 2, 2, 0.972],
- [1, 2, 2, 1],
- // SciPy examples - https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.betainc.html#scipy.special.betainc
- [1, 0.2, 3.5, 1],
- [0.5, 1.4, 3.1, 0.8148904036225296],
- [0.4, 2.2, 3.1, 0.4933963880761945],
- // Issue #429
- [0.0041461509490402, 0.5, 170.5, 0.7657225092554762],
- [0.0041461509490402, 1.5, 170.5, 0.29887797299851921],
- // Issue #458
- [0.47241392386467, 0.5, 55.5, 0.99999999999999996],
- [0.47241392386467, 1.5, 55.5, 0.99999999999999773],
- // Reference implementation tests computed using SciPy - https://github.com/codeplea/incbeta/blob/master/test.c
- [0.1, 10, 10, 3.929882327128003e-06],
- [0.3, 10, 10, 0.03255335688130092],
- [0.5, 10, 10, 0.5],
- [0.7, 10, 10, 0.967446643118699],
- [1, 10, 10, 1.0],
- [0.5, 15, 10, 0.1537281274795532],
- [0.6, 15, 10, 0.4890801931489529],
- [0.5, 10, 15, 0.8462718725204468],
- [0.6, 10, 15, 0.978341948670397],
- [0.4, 20, 20, 0.10205863128940816],
- [0.4, 40, 40, 0.03581030716079576],
- [0.7, 40, 40, 0.9999016649962936],
- ];
- }
- /**
- * @test regularizedIncompleteBeta throws an OutOfBoundsException if a is less than 0
- */
- public function testRegularizedIncompleteBetaExceptionALessThanZero()
- {
- // Given
- $a = -1;
- // Then
- $this->expectException(Exception\OutOfBoundsException::class);
- // When
- Special::regularizedIncompleteBeta(0.4, $a, 4);
- }
- /**
- * @test regularizedIncompleteBeta throws an OutOfBoundsException if x is out of bounds
- */
- public function testRegularizedIncompleteBetaExceptionXOutOfBounds()
- {
- // Given
- $x = -1;
- // Then
- $this->expectException(Exception\OutOfBoundsException::class);
- // When
- Special::regularizedIncompleteBeta($x, 4, 4);
- }
- /**
- * @test Github Issue 393 Bug - regularizedIncompleteBeta
- * Reference expected values:
- * Python scipy.special.betainc(a, b, x)
- * >>> scipy.special.betainc(274.40782656165, 0.5, 0.99993441100298)
- * 0.8495884744315958
- * Online calculator https://keisan.casio.com/exec/system/1180573396
- * 0.8495884744316587246283
- */
- public function testIssue393BugInRegularizedIncompleteBeta()
- {
- // Given
- $x = 0.99993441100298;
- $a = 274.40782656165;
- $b = 0.5;
- // And
- $expected = 0.8495884744315958;
- // When
- $betainc = Special::regularizedIncompleteBeta($x, $a, $b);
- // Then
- $this->assertEqualsWithDelta($expected, $betainc, 0.00001);
- }
- /**
- * @test incompleteBeta returns the expected value
- * @dataProvider dataProviderForIncompleteBeta
- * @param float $x
- * @param float $a
- * @param float $b
- * @param float $ib
- * @throws \Exception
- */
- public function testIncompleteBeta(float $x, float $a, float $b, float $ib)
- {
- // When
- $incompleteBeta = Special::incompleteBeta($x, $a, $b);
- // Then
- $this->assertEqualsWithDelta($ib, $incompleteBeta, 0.0001);
- }
- public function dataProviderForIncompleteBeta(): array
- {
- return [
- [0.1, 1, 3, 0.09033333333333333333333],
- [0.4, 1, 3, 0.2613333333333333333333],
- [0.9, 1, 3, 0.333],
- [0.4, 1, 2, 0.32],
- [0.4, 1, 4, 0.2176],
- [0.4, 2, 4, 0.033152],
- [0.4, 4, 4, 0.002069942857142857142857],
- [0.7, 6, 10, 3.31784042288233100233E-5],
- [0.7, 7, 10, 1.23984824870524912587E-5],
- [0.44, 3, 8.4, 0.0022050133154863808046],
- [0.44, 3.5, 8.5, 0.00101547937082370450368],
- [0.3, 2.5, 4.5, 0.00873072257563537808667],
- [0.5, 1, 2, 0.375],
- [0.2, 3.4, 2.3, 9.94015483378346364195E-4],
- [0.8, 3.4, 2.3, 0.040438859297104036187],
- [0.45, 12.45, 3.49, 1.016239733540625974803E-6],
- [0.294, 0.23, 2.11, 3.082589637435583044388],
- [0.993, 0.23, 2.11, 3.48298583651202868119],
- [0.76, 4, 0.3, 0.1692673319857469933301],
- [0.55, 2, 2.5, 0.0774145505281552534703],
- [0.55, 2.5, 2, 0.05448257245698492387678],
- [0.55, 3.5, 2, 0.0201727956188770976315],
- [0.73, 3.5, 5, 0.00553077297647439276549],
- ];
- }
- /**
- * @test upperIncompleteGamma throws an OutOfBoundsException if s is less than 0
- */
- public function testUpperIncompleteGammaExceptionSLessThanZero()
- {
- // Then
- $this->expectException(Exception\OutOfBoundsException::class);
- // When
- Special::upperIncompleteGamma(-1, 1);
- }
- /**
- * @test generalizedHypergeometric throws a BadParameterException if the parameter count is wrong
- */
- public function testGeneralizedHypergeometricExceptionParameterCount()
- {
- // Then
- $this->expectException(Exception\BadParameterException::class);
- // When
- Special::generalizedHypergeometric(2, 1, ...[6.464756838, 0.509199496, 0.241379523]);
- }
- /**
- * @test confluentHypergeometric returns the expected value
- * @dataProvider dataProviderForConfluentHypergeometric
- * @param float $a
- * @param float $b
- * @param float $z
- * @param float $expected
- * @throws \Exception
- */
- public function testConfluentHypergeometric(float $a, float $b, float $z, float $expected)
- {
- // Given
- $tol = .000001 * $expected;
- // When
- $actual = Special::confluentHypergeometric($a, $b, $z);
- // Then
- $this->assertEqualsWithDelta($expected, $actual, $tol);
- }
- public function dataProviderForConfluentHypergeometric(): array
- {
- return [
- [6.464756838, 0.509199496, 0.241379523, 6.48114845060471],
- [5.12297443791641, 5.26188297019653, 0.757399855727661, 2.09281409280936],
- [9.89309990528122, 6.92782493869175, 0.71686043176351, 2.73366255092188],
- [8.59824618495037, 6.66955518297157, 0.0293511981644408, 1.03854226944163],
- ];
- }
- /**
- * @test hypergeometric returns the expected value
- * @dataProvider dataProviderForHypergeometric
- * @param float $a
- * @param float $b
- * @param float $c
- * @param float $z
- * @param float $expected
- * @throws \Exception
- */
- public function testHypergeometric(float $a, float $b, float $c, float $z, float $expected)
- {
- // Given
- $tol = .000001 * $expected;
- // When
- $actual = Special::hypergeometric($a, $b, $c, $z);
- // Then
- $this->assertEqualsWithDelta($expected, $actual, $tol);
- }
- public function dataProviderForHypergeometric(): array
- {
- return [
- [1, 1, 1, .9, 10],
- [1, 1, 1, .8, 5],
- [1, 1, 1, .7, 3.3333333],
- [3, 1.4, 1.5, .926, 1746.206366],
- ];
- }
- /**
- * @test hypergeometric throws an OutOfBoundsException if n is greater than 1
- */
- public function testHypergeometricExceptionNGreaterThanOne()
- {
- // Then
- $this->expectException(Exception\OutOfBoundsException::class);
- // When
- Special::hypergeometric(1, 1, 1, 1);
- }
- /**
- * @test softmax returns the expected value
- * @dataProvider dataProviderForSoftmax
- * @param array $𝐳
- * @param array $expected
- */
- public function testSoftmax(array $𝐳, array $expected)
- {
- // When
- $σ⟮𝐳⟯ⱼ = Special::softmax($𝐳);
- // Then
- $this->assertEqualsWithDelta($expected, $σ⟮𝐳⟯ⱼ, 0.00001);
- $this->assertEqualsWithDelta(1, \array_sum($σ⟮𝐳⟯ⱼ), 0.00001);
- }
- public function dataProviderForSoftmax(): array
- {
- return [
- // Test data: Wikipedia
- [
- [1, 2, 3, 4, 1, 2, 3],
- [0.023640543021591392, 0.064261658510496159, 0.17468129859572226, 0.47483299974438037, 0.023640543021591392, 0.064261658510496159, 0.17468129859572226],
- ],
- // Test data: http://www.kdnuggets.com/2016/07/softmax-regression-related-logistic-regression.html
- [
- [0.07, 0.22, 0.28],
- [0.29450637, 0.34216758, 0.363332605],
- ],
- [
- [0.35, 0.78, 1.12],
- [0.21290077, 0.32728332, 0.45981591],
- ],
- [
- [-0.33, -0.58, -0.92],
- [0.42860913, 0.33380113, 0.23758974],
- ],
- [
- [-0.39, -0.7, -1.1],
- [0.44941979, 0.32962558, 0.22095463],
- ],
- // Test data: https://martin-thoma.com/softmax/
- [
- [0.1, 0.2],
- [0.47502081, 0.52497919],
- ],
- [
- [-0.1, 0.2],
- [0.42555748, 0.57444252],
- ],
- [
- [0.9, -10],
- [0.999981542, 1.84578933e-05],
- ],
- [
- [0, 10],
- [4.53978687e-05, 0.999954602],
- ],
- // Test data: http://stackoverflow.com/questions/34968722/softmax-function-python
- [
- [3.0, 1.0, 0.2],
- [0.8360188, 0.11314284, 0.05083836],
- ],
- [
- [1, 2, 3],
- [0.09003057, 0.24472847, 0.66524096],
- ],
- [
- [2, 4, 8],
- [0.00242826, 0.01794253, 0.97962921],
- ],
- [
- [3, 5, 7],
- [0.01587624, 0.11731043, 0.86681333],
- ],
- [
- [6, 6, 6],
- [0.33333333, 0.33333333, 0.33333333],
- ],
- [
- [1, 2, 3, 6],
- [0.00626879, 0.01704033, 0.04632042, 0.93037047],
- ],
- ];
- }
- /**
- * @test chebyshevEval bounds condition error on n
- * @dataProvider dataProviderForChebyshevEvalNOutOfBounds
- * @param int $n
- */
- public function testChebyshevEvalNOutOfBounds(int $n)
- {
- // Given
- $x = 1;
- $a = [2, 3];
- // And
- $chebyshevEval = new \ReflectionMethod(Special::Class, 'chebyshevEval');
- $chebyshevEval->setAccessible(true);
- // Then
- $this->expectException(Exception\OutOfBoundsException::class);
- // When
- $chebyshevEval->invokeArgs(null, [$x, $a, $n]);
- }
- public function dataProviderForChebyshevEvalNOutOfBounds(): array
- {
- return [
- [-2],
- [1001],
- ];
- }
- /**
- * @test chebyshevEval bounds condition error on x
- * @dataProvider dataProviderForChebyshevEvalXOutOfBounds
- * @param float $x
- */
- public function testChebyshevEvalXOutOfBounds(float $x): void
- {
- // Given
- $n = 5;
- $a = [2, 3];
- // And
- $chebyshevEval = new \ReflectionMethod(Special::Class, 'chebyshevEval');
- $chebyshevEval->setAccessible(true);
- // Then
- $this->expectException(Exception\OutOfBoundsException::class);
- // When
- $chebyshevEval->invokeArgs(null, [$x, $a, $n]);
- }
- public function dataProviderForChebyshevEvalXOutOfBounds(): array
- {
- return [
- [-1.2],
- [1.2],
- ];
- }
- /**
- * @test stirlingError
- * @dataProvider dataProviderForSterlingError
- * @param float $n
- * @param float $expected
- */
- public function testStirlingError(float $n, float $expected): void
- {
- // When
- $stirlingError = Special::stirlingError($n);
- // Then
- $this->assertEqualsWithDelta($expected, $stirlingError, 0.000001);
- }
- /**
- * Test data produces with R library DPQmpfr: stirlerrM(n)
- * @return array
- */
- public function dataProviderForSterlingError(): array
- {
- return [
- [0.5, 0.1534264],
- [1, 0.08106147],
- [1.5, 0.05481412],
- [2, 0.0413407],
- [5, 0.01664469],
- [5.5, 0.01513497],
- [14, 0.00595137],
- [14.5, 0.005746217],
- [15, 0.005554734],
- [0.1, 0.5127401],
- [0.2, 0.3222939],
- [0.9, 0.08958191],
- [1.1, 0.07400292],
- [5.3, 0.0157048],
- [14.7, 0.005668061],
- [15.5, 0.005375599],
- [20, 0.00416632],
- [22.4, 0.003719991],
- ];
- }
- /**
- * @test stirlingError infinity at 0
- */
- public function testStirlingErrorInfinity(): void
- {
- // Given
- $n = 0;
- // When
- $stirlingError = Special::stirlingError($n);
- // Then
- $this->assertInfinite($stirlingError);
- }
- /**
- * @test stirlingError NAN for negative values
- * @dataProvider dataProviderForSterlingErrorNan
- * @param float $n
- */
- public function testStirlingErrorNan(float $n): void
- {
- // Then
- $this->expectException(Exception\NanException::class);
- // When
- $stirlingError = Special::stirlingError($n);
- }
- public function dataProviderForSterlingErrorNan(): array
- {
- return [
- [-0.1],
- [-1],
- [-10],
- ];
- }
- }
|