SpecialTest.php 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486
  1. <?php
  2. namespace MathPHP\Tests\Functions;
  3. use MathPHP\Functions\Special;
  4. use MathPHP\Exception;
  5. class SpecialTest extends \PHPUnit\Framework\TestCase
  6. {
  7. /**
  8. * @test signum/sgn returns the expected value
  9. * @dataProvider dataProviderForSignum
  10. * @param $x
  11. * @param $sign
  12. */
  13. public function testSignum($x, $sign)
  14. {
  15. // When
  16. $signum = Special::signum($x);
  17. $sgn = Special::sgn($x);
  18. // Then
  19. $this->assertEquals($sign, $signum);
  20. $this->assertEquals($sign, $sgn);
  21. }
  22. public function dataProviderForSignum(): array
  23. {
  24. return [
  25. [ 0, 0 ],
  26. [ 1, 1 ],
  27. [ 0.5, 1 ],
  28. [ 1.5, 1 ],
  29. [ 4, 1 ],
  30. [ 123241.342, 1 ],
  31. [ -1, -1 ],
  32. [ -0.5, -1 ],
  33. [ -1.5, -1 ],
  34. [ -4, -1 ],
  35. [ -123241.342, -1 ],
  36. ];
  37. }
  38. /**
  39. * @test gamma returns the expected value
  40. * @dataProvider dataProviderForGamma
  41. * @param $z
  42. * @param $Γ
  43. * @throws \Exception
  44. */
  45. public function testGamma($z, $Γ)
  46. {
  47. // When
  48. $gamma = Special::gamma($z);
  49. // Then
  50. $this->assertEqualsWithDelta($Γ, $gamma, 0.001);
  51. }
  52. /**
  53. * Test data created with R gamma(z) and online calculator https://keisan.casio.com/exec/system/1180573444
  54. * @return array (z, Γ)
  55. */
  56. public function dataProviderForGamma(): array
  57. {
  58. return [
  59. [0.1, 9.51350769866873183629],
  60. [0.2, 4.5908437119988030532],
  61. [0.3, 2.99156898768759062831],
  62. [0.4, 2.21815954375768822306],
  63. [0.5, 1.772453850905516027298],
  64. [0.6, 1.489192248812817102394],
  65. [0.7, 1.29805533264755778568],
  66. [0.8, 1.16422971372530337364],
  67. [0.9, 1.0686287021193193549],
  68. [1, 1],
  69. [1.0, 1],
  70. [1.1, 0.951350769866873183629],
  71. [1.2, 0.91816874239976061064],
  72. [1.3, 0.89747069630627718849],
  73. [1.4, 0.88726381750307528922],
  74. [1.5, 0.88622692545275801365],
  75. [1.6, 0.89351534928769026144],
  76. [1.7, 0.90863873285329044998],
  77. [1.8, 0.9313837709802426989091],
  78. [1.9, 0.96176583190738741941],
  79. [2, 1],
  80. [2.0, 1],
  81. [3, 2],
  82. [3.0, 2],
  83. [4, 6],
  84. [4.0, 6],
  85. [5, 24],
  86. [5.0, 24],
  87. [6, 120],
  88. [6.0, 120],
  89. [7, 720],
  90. [8, 5040],
  91. [9, 40320],
  92. [10, 362880],
  93. [11, 3628800],
  94. [12, 39916800],
  95. [13, 479001600],
  96. [14, 6227020800],
  97. [15, 87178291200],
  98. [16, 1307674368000],
  99. [17, 20922789888000],
  100. [18, 355687428096000],
  101. [19, 6402373705728000],
  102. [20, 121645100408832000],
  103. [2.5, 1.32934038817913702047],
  104. [5.324, 39.54287866273389258523],
  105. [10.2, 570499.02784103598123],
  106. [-0.1, -10.686287021193193549],
  107. [-0.4, -3.72298062203204275599],
  108. [-1.1, 9.7148063829029032263],
  109. [-1.2, 4.8509571405220973902],
  110. [-1.9, 5.563455],
  111. [-1.99, 50.47083],
  112. [-1.999, 500.4623],
  113. [-1.9999, 5000.461],
  114. [-1.99999, 50000.4614015337837734],
  115. [1E-207, 1E207],
  116. [2E-308, \INF],
  117. [-2E-309, -\INF],
  118. [-172.25, 0],
  119. [-168.0000000000001, -3.482118E-290],
  120. [-167.9999999999999, 3.482118E-290],
  121. ];
  122. }
  123. /**
  124. * @test gamma throws an NanException if gamma is undefined.
  125. * @dataProvider dataProviderUndefinedGamma
  126. */
  127. public function testGammaExceptionUndefined($x)
  128. {
  129. // Then
  130. $this->expectException(Exception\NanException::class);
  131. // When
  132. Special::gamma($x);
  133. }
  134. public function dataProviderUndefinedGamma()
  135. {
  136. return [
  137. [0],
  138. [0.0],
  139. [-1],
  140. [-2],
  141. [-2.0],
  142. [-3],
  143. [-4],
  144. [-10],
  145. [-20],
  146. ];
  147. }
  148. /**
  149. * @test gamma of large values
  150. * @dataProvider dataProviderForGammaLargeValues
  151. * @param $z
  152. * @param $Γ
  153. * @param float $ε - relative error
  154. * @throws \Exception
  155. */
  156. public function testGammaLargeValues($z, $Γ, float $ε = 1E-10)
  157. {
  158. // When
  159. $gamma = Special::gamma($z);
  160. // Then
  161. $this->assertEqualsWithDelta($Γ, $gamma, $Γ * $ε);
  162. }
  163. /**
  164. * Test data created with high-precision online calculator: https://keisan.casio.com/exec/system/1180573444
  165. * @return array (z, Γ, ε)
  166. */
  167. public function dataProviderForGammaLargeValues(): array
  168. {
  169. return [
  170. [15, 87178291200],
  171. [20, 121645100408832000],
  172. [50, 6.082818640342675608723E+62],
  173. [100, 9.33262154439441526817E+155],
  174. [100.6, 1.477347552911177316693E+157],
  175. [171, 7.257415615307998967397E+306],
  176. [200, 3.943289336823952517762E+372],
  177. ];
  178. }
  179. /**
  180. * @test gammaLanczos returns the expected value
  181. * @dataProvider dataProviderForGammaLanczos
  182. * @param $z
  183. * @param $Γ
  184. * @throws \Exception
  185. */
  186. public function testGammaLanczos($z, $Γ)
  187. {
  188. // When
  189. $gammaLanczos = Special::gammaLanczos($z);
  190. // Then
  191. $this->assertEqualsWithDelta($Γ, $gammaLanczos, 0.001);
  192. }
  193. public function dataProviderForGammaLanczos(): array
  194. {
  195. return [
  196. [0.1, 9.51350769866873183629],
  197. [0.2, 4.5908437119988030532],
  198. [0.3, 2.99156898768759062831],
  199. [0.4, 2.21815954375768822306],
  200. [0.5, 1.772453850905516027298],
  201. [0.6, 1.489192248812817102394],
  202. [0.7, 1.29805533264755778568],
  203. [0.8, 1.16422971372530337364],
  204. [0.9, 1.0686287021193193549],
  205. [1, 1],
  206. [1.0, 1],
  207. [1.1, 0.951350769866873183629],
  208. [1.2, 0.91816874239976061064],
  209. [1.3, 0.89747069630627718849],
  210. [1.4, 0.88726381750307528922],
  211. [1.5, 0.88622692545275801365],
  212. [1.6, 0.89351534928769026144],
  213. [1.7, 0.90863873285329044998],
  214. [1.8, 0.9313837709802426989091],
  215. [1.9, 0.96176583190738741941],
  216. [2, 1],
  217. [2.0, 1],
  218. [3, 2],
  219. [3.0, 2],
  220. [4, 6],
  221. [4.0, 6],
  222. [5, 24],
  223. [5.0, 24],
  224. [6, 120],
  225. [6.0, 120],
  226. [2.5, 1.32934038817913702047],
  227. [5.324, 39.54287866273389258523],
  228. [10.2, 570499.02784103598123],
  229. [0, \INF],
  230. [0.0, \INF],
  231. [-1, -\INF],
  232. [-2, -\INF],
  233. [-2.0, -\INF],
  234. [-0.1, -10.686287021193193549],
  235. [-0.4, -3.72298062203204275599],
  236. [-1.1, 9.7148063829029032263],
  237. [-1.2, 4.8509571405220973902],
  238. ];
  239. }
  240. /**
  241. * @test gammaStirling returns the expected value
  242. * @dataProvider dataProviderForGammaStirling
  243. * @param $n
  244. * @param $Γ
  245. * @throws \Exception
  246. */
  247. public function testGammaStirling($n, $Γ)
  248. {
  249. // When
  250. $gammaSterling = Special::gammaStirling($n);
  251. // Then
  252. $this->assertEqualsWithDelta($Γ, $gammaSterling, 0.01);
  253. }
  254. public function dataProviderForGammaStirling(): array
  255. {
  256. return [
  257. [ 1, 1 ],
  258. [ 1.0, 1 ],
  259. [ 2, 1 ],
  260. [ 3, 2 ],
  261. [ 4, 6 ],
  262. [ 5, 24 ],
  263. [ 6, 120 ],
  264. [ 1.1, 0.951350769866873183629 ],
  265. [ 1.2, 0.91816874239976061064 ],
  266. [ 1.5, 0.88622692545275801365 ],
  267. [ 2.5, 1.32934038817913702047 ],
  268. [ 5.324, 39.54287866273389258523 ],
  269. [ 10.2, 570499.02784103598123 ],
  270. [ 0, \INF ],
  271. [ -1, -\INF ],
  272. [ -2, -\INF ],
  273. [ -2.0, -\INF ],
  274. ];
  275. }
  276. /**
  277. * @test logGamma returns the expected value
  278. * @dataProvider dataProviderForLogGamma
  279. * @param $z
  280. * @param $Γ
  281. * @throws \Exception
  282. */
  283. public function testLogGamma($z, $Γ)
  284. {
  285. // When
  286. $log_gamma = Special::logGamma($z);
  287. // Then
  288. $this->assertEqualsWithDelta($Γ, $log_gamma, abs($Γ) * 0.00001);
  289. }
  290. /**
  291. * Test data produced with R function lgamma(x)
  292. * @return array
  293. */
  294. public function dataProviderForLogGamma(): array
  295. {
  296. return [
  297. [-2, \INF],
  298. [-1.9, 1.716219],
  299. [-1.5, 0.860047],
  300. [-1, \INF],
  301. [-0.1, 2.368961],
  302. [0, \INF],
  303. [0.1, 2.252713],
  304. [0.5, 0.5723649],
  305. [1, 0],
  306. [1.0, 0],
  307. [2, 0],
  308. [2.1, 0.04543774],
  309. [2.5, 0.2846829],
  310. [3, 0.6931472],
  311. [10, 12.80183],
  312. [100, 359.1342],
  313. [1000, 5905.22],
  314. [10000, 82099.72],
  315. [100000, 1051288],
  316. [5E-307, 705.2842],
  317. [2.6E305, \INF],
  318. [2E17, 7.767419e+18],
  319. [4934770, 71118994],
  320. [-.9, 2.358073],
  321. [-11.2, -16.31644474],
  322. ];
  323. }
  324. /**
  325. * @test logGamma returns NaNException appropriately
  326. */
  327. public function testLogGammaNan()
  328. {
  329. // Given
  330. $nan = acos(1.01);
  331. // Then
  332. $this->expectException(Exception\NanException::class);
  333. // When
  334. $nan = Special::logGamma($nan);
  335. }
  336. /**
  337. * @test gamma returns NaNException appropriately
  338. */
  339. public function testGammaNan()
  340. {
  341. // Given
  342. $nan = \NAN;
  343. // Then
  344. $this->expectException(Exception\NanException::class);
  345. // When
  346. $nan = Special::gamma($nan);
  347. }
  348. /**
  349. * @test beta returns the expected value
  350. * @dataProvider dataProviderForBeta
  351. * @param float $x
  352. * @param float $y
  353. * @param float $expected
  354. * @throws \Exception
  355. */
  356. public function testBeta(float $x, float $y, float $expected)
  357. {
  358. // When
  359. $beta = Special::beta($x, $y);
  360. $β = Special::β($y, $x);
  361. // Then
  362. $this->assertEqualsWithDelta($expected, $beta, 0.0000001);
  363. $this->assertEqualsWithDelta($expected, $β, 0.0000001);
  364. }
  365. /**
  366. * Test data created with R beta (x, y) and online calculator https://keisan.casio.com/exec/system/1180573394
  367. * @return array (x, y, β)
  368. */
  369. public function dataProviderForBeta(): array
  370. {
  371. return [
  372. [1.5, 0, \INF],
  373. [0, 1.5, \INF],
  374. [0, 0, \INF],
  375. [1, 1, 1],
  376. [1, 2, 0.5],
  377. [1, 3, 0.3333333333],
  378. [1, 4, 0.25],
  379. [1, 5, 0.2],
  380. [1, 6, 0.1666667],
  381. [1, 7, 0.1428571],
  382. [1, 8, 0.125],
  383. [1, 9, 0.1111111],
  384. [1, 10, 0.1],
  385. [1, 11, 0.09090909],
  386. [1, 20, 0.05],
  387. [2, 0, \INF],
  388. [2, 1, 0.5],
  389. [2, 2, 0.1666667],
  390. [2, 3, 0.08333333],
  391. [2, 4, 0.05],
  392. [2, 5, 0.03333333],
  393. [2, 6, 0.02380952],
  394. [2, 7, 0.01785714],
  395. [2, 8, 0.01388889],
  396. [2, 9, 0.01111111],
  397. [2, 10, 0.009090909],
  398. [2, 11, 0.007575758],
  399. [2, 20, 0.002380952],
  400. [3, 0, \INF],
  401. [3, 1, 0.3333333],
  402. [3, 2, 0.08333333],
  403. [3, 3, 0.03333333],
  404. [3, 4, 0.01666667],
  405. [3, 5, 0.00952381],
  406. [3, 6, 0.005952381],
  407. [3, 7, 0.003968254],
  408. [3, 8, 0.002777778],
  409. [3, 9, 0.002020202],
  410. [3, 10, 0.001515152],
  411. [3, 11, 0.001165501],
  412. [3, 20, 0.0002164502],
  413. [1.5, 0.2, 4.4776093743471688104],
  414. [0.2, 1.5, 4.4776093743471688104],
  415. [0.1, 0.9, 10.16640738463051963162],
  416. [0.9, 0.1, 10.16640738463051963162],
  417. [3, 9, 0.002020202],
  418. [9, 3, 0.002020202],
  419. [10, 10, 1.082509e-06],
  420. [20, 20, 7.254445e-13],
  421. [\INF, 2, 0],
  422. [2, \INF, 0],
  423. [1.5, 170.5, 0.0003971962], // Issue #429
  424. ];
  425. }
  426. /**
  427. * @testCase logBeta returns the expected value
  428. * @dataProvider dataProviderForLogBeta
  429. */
  430. public function testLogBeta($x, $y, float $log_beta)
  431. {
  432. $this->assertEqualsWithDelta($log_beta, Special::logBeta($x, $y), 0.001);
  433. }
  434. public function dataProviderForLogBeta(): array
  435. {
  436. return [
  437. [1.5, 0, \INF],
  438. [0, 1.5, \INF],
  439. [0, 0, \INF],
  440. [1, 1, 0],
  441. [1, 2, -0.6931472],
  442. [2, 1, -0.6931472],
  443. [2, 2, -1.791759],
  444. [.9, .1, 2.319089],
  445. [20, 20, -27.95199],
  446. [1, \INF, -\INF],
  447. [1, 11, -2.397895],
  448. [5E-307, 5, 705.2842],
  449. [94907000, 11, -186.9481],
  450. ];
  451. }
  452. /**
  453. * @test beta returns NaNException appropriately
  454. */
  455. public function testBetaNan()
  456. {
  457. // Given
  458. $nan = \NAN;
  459. // Then
  460. $this->expectException(Exception\NanException::class);
  461. // When
  462. $beta = Special::beta($nan, 2);
  463. }
  464. /**
  465. * @test logBeta returns NaNException appropriately
  466. */
  467. public function testLogBetaNan()
  468. {
  469. // Given
  470. $nan = \NAN;
  471. // Then
  472. $this->expectException(Exception\NanException::class);
  473. // When
  474. $lbeta = Special::logBeta($nan, 2);
  475. }
  476. /**
  477. * @test logBeta parameters must be greater than 0
  478. */
  479. public function testLogBetaOutOfBounds()
  480. {
  481. // Given
  482. $p = -1;
  483. // Then
  484. $this->expectException(Exception\OutOfBoundsException::class);
  485. // When
  486. $lbeta = Special::logBeta($p, 2);
  487. }
  488. /**
  489. * @test beta parameters must be greater than 0
  490. */
  491. public function testBetaOutOfBounds()
  492. {
  493. // Given
  494. $p = -1;
  495. // Then
  496. $this->expectException(Exception\OutOfBoundsException::class);
  497. // When
  498. $beta = Special::beta($p, 2);
  499. }
  500. /**
  501. * @test logGammaCorr parameter must be greater than 10
  502. */
  503. public function testLogGammaCorrOutOfBounds()
  504. {
  505. // Given
  506. $x = 1;
  507. // Then
  508. $this->expectException(Exception\OutOfBoundsException::class);
  509. // When
  510. $correction = Special::logGammaCorr($x);
  511. }
  512. /**
  513. * @test multivariateBeta returns the expected value
  514. * @dataProvider dataProviderForBeta
  515. * @param float $x
  516. * @param float $y
  517. * @param float $expected
  518. * @throws \Exception
  519. */
  520. public function testMultivariateBeta(float $x, float $y, float $expected)
  521. {
  522. // When
  523. $beta = Special::multivariateBeta([$x, $y]);
  524. // Then
  525. $this->assertEqualsWithDelta($expected, $beta, 0.0000001);
  526. }
  527. /**
  528. * @test logistic returns the expected value
  529. * @dataProvider dataProviderForLogistic
  530. * @param float $x₀
  531. * @param float $L
  532. * @param float $k
  533. * @param float $x
  534. * @param float $expected
  535. */
  536. public function testLogistic(float $x₀, float $L, float $k, float $x, float $expected)
  537. {
  538. // When
  539. $logistic = Special::logistic($x₀, $L, $k, $x);
  540. // Then
  541. $this->assertEqualsWithDelta($expected, $logistic, 0.001);
  542. }
  543. public function dataProviderForLogistic(): array
  544. {
  545. return [
  546. [0, 0, 0, 0, 0],
  547. [1, 1, 1, 1, 0.5],
  548. [2, 2, 2, 2, 1],
  549. [3, 2, 2, 2, 0.238405844044],
  550. [3, 4, 2, 2, 0.476811688088],
  551. [3, 4, 5, 2, 0.0267714036971],
  552. [3, 4, 5, 6, 3.99999877639],
  553. [2.1, 3.2, 1.5, 0.6, 0.305118287677],
  554. // Test data created with R (sigmoid) logistic(x, k, x₀) where L = 1
  555. [0, 1, 1, 0, 0.5],
  556. [0, 1, 1, 1, 0.7310586],
  557. [1, 1, 1, 0, 0.2689414],
  558. ];
  559. }
  560. /**
  561. * @test sigmoid
  562. * @dataProvider dataProviderForSigmoid
  563. * @param float $x
  564. * @param float $expected
  565. */
  566. public function testSigmoid(float $x, float $expected)
  567. {
  568. // When
  569. $sigmoid = Special::sigmoid($x);
  570. // Then
  571. $this->assertEqualsWithDelta($expected, $sigmoid, 0.0000001);
  572. }
  573. /**
  574. * Test data created with R (sigmoid) sigmoid(x)
  575. * @return array (x, sigmoid)
  576. */
  577. public function dataProviderForSigmoid(): array
  578. {
  579. return [
  580. [0, 0.5],
  581. [1, 0.7310586],
  582. [2, 0.8807971],
  583. [3, 0.9525741],
  584. [4, 0.9820138],
  585. [5, 0.9933071],
  586. [6, 0.9975274],
  587. [10, 0.9999546],
  588. [13, 0.9999977],
  589. [15, 0.9999997],
  590. [16, 0.9999999],
  591. [17, 1],
  592. [20, 1],
  593. [-1, 0.2689414],
  594. [-2, 0.1192029],
  595. [-3, 0.04742587],
  596. [-4, 0.01798621],
  597. [-5, 0.006692851],
  598. [-6, 0.002472623],
  599. [-10, 4.539787e-05],
  600. [-15, 3.059022e-07],
  601. [-20, 2.061154e-09],
  602. [0.5, 0.6224593],
  603. [5.5, 0.9959299],
  604. [-0.5, 0.3775407],
  605. [-5.5, 0.004070138],
  606. ];
  607. }
  608. /**
  609. * @test sigmoid returns the expected value
  610. * Sigmoid is just a special case of the logistic function.
  611. */
  612. public function testSigmoidSpecialCaseOfLogisitic()
  613. {
  614. $this->assertEquals(Special::logistic(1, 1, 1, 2), Special::sigmoid(1));
  615. $this->assertEquals(Special::logistic(1, 1, 2, 2), Special::sigmoid(2));
  616. $this->assertEquals(Special::logistic(1, 1, 3, 2), Special::sigmoid(3));
  617. $this->assertEquals(Special::logistic(1, 1, 4, 2), Special::sigmoid(4));
  618. $this->assertEquals(Special::logistic(1, 1, 4.6, 2), Special::sigmoid(4.6));
  619. }
  620. /**
  621. * @test errorFunction returns the expected value
  622. * @dataProvider dataProviderForErrorFunction
  623. * @param float $x
  624. * @param float $expected
  625. */
  626. public function testErrorFunction(float $x, float $expected)
  627. {
  628. // When
  629. $errorFunction = Special::errorFunction($x);
  630. $erf = Special::erf($x);
  631. // Then
  632. $this->assertEqualsWithDelta($expected, $errorFunction, 0.0001);
  633. $this->assertEqualsWithDelta($expected, $erf, 0.0001);
  634. }
  635. /**
  636. * Test data created with R (VGAM) erf(x) and online calculator https://keisan.casio.com/exec/system/1180573449
  637. * @return array (x, erf)
  638. */
  639. public function dataProviderForErrorFunction(): array
  640. {
  641. return [
  642. [0, 0],
  643. [1, 0.8427007929497148693412],
  644. [-1, -0.8427007929497148693412],
  645. [2, 0.9953222650189527341621],
  646. [3.4, 0.9999984780066371377146],
  647. [0.154, 0.1724063976196591819236],
  648. [-2.31, -0.9989124231037000500402],
  649. [-1.034, -0.856340111375020118952],
  650. [3, 0.9999779],
  651. [4, 1],
  652. [5, 1],
  653. [10, 1],
  654. [-2, -0.9953223],
  655. [-3, -0.9999779],
  656. [-4, -1],
  657. [-5, -1],
  658. [-10, -1],
  659. ];
  660. }
  661. /**
  662. * @test complementaryErrorFunction returns the expected value
  663. * @dataProvider dataProviderForComplementaryErrorFunction
  664. * @param float $x
  665. * @param float $expected
  666. */
  667. public function testComplementaryErrorFunction(float $x, float $expected)
  668. {
  669. // When
  670. $complementaryErrorFunction = Special::complementaryErrorFunction($x);
  671. $efc = Special::erfc($x);
  672. // Then
  673. $this->assertEqualsWithDelta($expected, $complementaryErrorFunction, 0.0001);
  674. $this->assertEqualsWithDelta($expected, $efc, 0.0001);
  675. }
  676. /**
  677. * Test data created with R (VGAM) erfc and online calculator https://keisan.casio.com/exec/system/1180573449
  678. * @return array (x, erfc)
  679. */
  680. public function dataProviderForComplementaryErrorFunction(): array
  681. {
  682. return [
  683. [0, 1],
  684. [1, 0.1572992070502851306588],
  685. [-1, 1.842700792949714869341],
  686. [2, 0.004677734981047265837931],
  687. [3.4, 1.521993362862285361757E-6],
  688. [0.154, 0.8275936023803408180764],
  689. [-2.31, 1.99891242310370005004],
  690. [-1.034, 1.856340111375020118952],
  691. [3, 2.20905e-05],
  692. [4, 1.541726e-08],
  693. [5, 1.53746e-12],
  694. [10, 2.088488e-45],
  695. [-2, 1.995322],
  696. [-3, 1.999978],
  697. [-4, 2],
  698. [-5, 2],
  699. [-10, 2],
  700. ];
  701. }
  702. /**
  703. * @test lowerIncompleteGamma returns the expected value
  704. * @dataProvider dataProviderForLowerIncompleteGamma
  705. * @param float $s
  706. * @param float $x
  707. * @param float $lig
  708. */
  709. public function testLowerIncompleteGamma(float $s, float $x, float $lig)
  710. {
  711. // When
  712. $lowerIncompleteGamma = Special::lowerIncompleteGamma($s, $x);
  713. // Then
  714. $this->assertEqualsWithDelta($lig, $lowerIncompleteGamma, 0.00001);
  715. }
  716. /**
  717. * Test data created with R (pracma) gammainc(x, a)
  718. * @return array (s, x, gamma)
  719. */
  720. public function dataProviderForLowerIncompleteGamma(): array
  721. {
  722. return [
  723. [0.0001, 1, 9999.2034895],
  724. [1, 1, 0.6321206],
  725. [1, 2, 0.8646647],
  726. [2, 2, 0.5939942],
  727. [3, 2.5, 0.9123738],
  728. [3.5, 2, 0.7318770],
  729. [4.6, 2, 1.07178785],
  730. [4, 2.6, 1.5839901],
  731. [2.7, 2.6, 0.8603568],
  732. [1.5, 2.5, 0.7339757],
  733. [0.5, 4, 1.764162782],
  734. [2, 3, 0.8008517],
  735. [4.5, 2.3, 1.5389745],
  736. [7, 9.55, 603.9624331],
  737. [1, 3, 0.95021293],
  738. [0.5, 0.5, 1.2100356],
  739. [0.5, 1, 1.4936483],
  740. [0.5, 4, 1.764162782],
  741. // Negative x it not officially supported, but sometimes works.
  742. // Other times it gets NAN.
  743. [1, -1, -1.718282],
  744. [1, -2, -6.389056],
  745. [2, -2, 8.389056],
  746. [3, -2.5, -37.59311],
  747. [4, -2.6, 98.84594],
  748. [2, -3, 41.17107],
  749. [1, -3, -19.08554],
  750. ];
  751. }
  752. /**
  753. * @test lowerIncompleteGamma returns 0 for x = 0, and s and x = 0
  754. * @dataProvider dataProviderForLowerIncompleteGammaZeroBoundary
  755. * @param float $s
  756. * @param float $x
  757. */
  758. public function testLowerIncompleteGammaZeroBoundary(float $s, float $x)
  759. {
  760. // When
  761. $lowerIncompleteGamma = Special::lowerIncompleteGamma($s, $x);
  762. // Then
  763. $this->assertEqualsWithDelta(0, $lowerIncompleteGamma, 0.00001);
  764. }
  765. /**
  766. * @return array (s, x)
  767. */
  768. public function dataProviderForLowerIncompleteGammaZeroBoundary(): array
  769. {
  770. return [
  771. [0, 0],
  772. [1, 0],
  773. [2, 0],
  774. [100, 0]
  775. ];
  776. }
  777. /**
  778. * @test lowerIncompleteGamma returns NAN for x = 0 and x nonzero
  779. * @dataProvider dataProviderForLowerIncompleteGammaNanBoundary
  780. * @param float $s
  781. * @param float $x
  782. */
  783. public function testLowerIncompleteGammaNanBoundary(float $s, float $x)
  784. {
  785. // When
  786. $lowerIncompleteGamma = Special::lowerIncompleteGamma($s, $x);
  787. // Then
  788. $this->assertNan($lowerIncompleteGamma);
  789. }
  790. /**
  791. * @return array (s, x)
  792. */
  793. public function dataProviderForLowerIncompleteGammaNanBoundary(): array
  794. {
  795. return [
  796. [0, 1],
  797. [0, 2],
  798. [0, 10],
  799. [0, 1000]
  800. ];
  801. }
  802. /**
  803. * @test upperIncompleteGamma returns the expected value
  804. * @dataProvider dataProviderForUpperIncompleteGamma
  805. * @param float $s
  806. * @param float $x
  807. * @param float $uig
  808. * @throws \Exception
  809. */
  810. public function testUpperIncompleteGamma(float $s, float $x, float $uig)
  811. {
  812. // When
  813. $upperIncompleteGamma = Special::upperIncompleteGamma($s, $x);
  814. // Then
  815. $this->assertEqualsWithDelta($uig, $upperIncompleteGamma, 0.00001);
  816. }
  817. /**
  818. * Test data created with R (pracma) gammainc(x, a)
  819. * @return array (s, x, gamma)
  820. */
  821. public function dataProviderForUpperIncompleteGamma(): array
  822. {
  823. return [
  824. [0.0001, 1, 0.21939372],
  825. [1, 1, 0.3678794],
  826. [1, 2, 0.1353353],
  827. [2, 2, 0.40600585],
  828. [3, 2.5, 1.08762623],
  829. [3.5, 2, 2.59147401],
  830. [4.6, 2, 12.30949802],
  831. [4, 2.6, 4.41600987],
  832. [2.7, 2.6, 0.68432904],
  833. [1.5, 2.5, 0.15225125],
  834. [0.5, 4, 0.008291069],
  835. [2, 3, 0.1991483],
  836. [4.5, 2.3, 10.0927539],
  837. [7, 9.55, 116.0375669],
  838. [0.5, 0.5, 0.5624182],
  839. [0.5, 1, 0.2788056],
  840. [0.5, 4, 0.008291069],
  841. ];
  842. }
  843. /**
  844. * @test regularizedLowerIncompleteGamma
  845. * @dataProvider dataProviderForRegularizedLowerIncompleteGamma
  846. * @param float $s
  847. * @param float $x
  848. * @param float $expected
  849. * @throws \Exception
  850. */
  851. public function testRegularizedLowerIncompleteGamma(float $s, float $x, float $expected)
  852. {
  853. // When
  854. $gammainc = Special::regularizedLowerIncompleteGamma($s, $x);
  855. // Then
  856. $this->assertEqualsWithDelta($expected, $gammainc, 0.00001);
  857. }
  858. public function dataProviderForRegularizedLowerIncompleteGamma(): array
  859. {
  860. return [
  861. [0.0001, 1, 0.9999781],
  862. [1, 1, 0.6321206],
  863. [1, 2, 0.8646647],
  864. [2, 2, 0.5939942],
  865. [3, 2.5, 0.4561869],
  866. [3.5, 2, 0.2202226],
  867. [4.6, 2, 0.08009603],
  868. [4, 2.6, 0.2639984],
  869. [2.7, 2.6, 0.5569785],
  870. [1.5, 2.5, 0.8282029],
  871. [0.5, 4, 0.995322265],
  872. [2, 3, 0.8008517],
  873. [4.5, 2.3, 0.1323083],
  874. [7, 9.55, 0.8388367],
  875. [1, 3, 0.95021293],
  876. [0.5, 0.5, 0.6826895],
  877. [0.5, 1, 0.8427008],
  878. [0.5, 4, 0.995322265],
  879. ];
  880. }
  881. /**
  882. * @test regularizedIncompleteBeta returns the expected value
  883. * @dataProvider dataProviderForRegularizedIncompleteBeta
  884. * @param float $x
  885. * @param float $a
  886. * @param float $b
  887. * @param float $rib
  888. * @throws \Exception
  889. */
  890. public function testRegularizedIncompleteBeta(float $x, float $a, float $b, float $rib)
  891. {
  892. // When
  893. $regularizedIncompleteBeta = Special::regularizedIncompleteBeta($x, $a, $b);
  894. // Then
  895. $this->assertEqualsWithDelta($rib, $regularizedIncompleteBeta, 0.0000001);
  896. }
  897. /**
  898. * Test data created with Python scipy.special.betainc(a, b, x) and online calculator https://keisan.casio.com/exec/system/1180573396
  899. * @return array (x, a, b, beta)
  900. */
  901. public function dataProviderForRegularizedIncompleteBeta(): array
  902. {
  903. return [
  904. [0.4, 1, 2, 0.64],
  905. [0.4, 1, 4, 0.87040],
  906. [0.4, 2, 4, 0.663040],
  907. [0.4, 4, 4, 0.2897920],
  908. [0.7, 6, 10, 0.99634748],
  909. [0.7, 7, 10, 0.99287048],
  910. [0.44, 3, 8.4, 0.90536083],
  911. [0.44, 3.5, 8.5, 0.86907356],
  912. [0.3, 2.5, 4.5, 0.40653902],
  913. [0.5, 1, 2, 0.750],
  914. [0.2, 3.4, 2.3, 0.02072722],
  915. [0.8, 3.4, 2.3, 0.84323132],
  916. [0.45, 12.45, 3.49, 0.00283809],
  917. [0.294, 0.23, 2.11, 0.88503883],
  918. [0.993, 0.23, 2.11, 0.99999612],
  919. [0.76, 4, 0.3, 0.08350803],
  920. [0.55, 2, 2.5, 0.67737732],
  921. [0.55, 2.5, 2, 0.47672251],
  922. [0.55, 3.5, 2, 0.31772153],
  923. [0.73, 3.5, 5, 0.97317839],
  924. [0, 1, 1, 0],
  925. [0.1, 1, 1, 0.1],
  926. [0.2, 1, 1, 0.2],
  927. [0.3, 1, 1, 0.3],
  928. [0.4, 1, 1, 0.4],
  929. [0.5, 1, 1, 0.5],
  930. [0.6, 1, 1, 0.6],
  931. [0.7, 1, 1, 0.7],
  932. [0.8, 1, 1, 0.8],
  933. [0.9, 1, 1, 0.9],
  934. [1, 1, 1, 1],
  935. [0, 2, 2, 0],
  936. [0.1, 2, 2, 0.028],
  937. [0.2, 2, 2, 0.104],
  938. [0.3, 2, 2, 0.216],
  939. [0.4, 2, 2, 0.352],
  940. [0.5, 2, 2, 0.5],
  941. [0.6, 2, 2, 0.648],
  942. [0.7, 2, 2, 0.784],
  943. [0.8, 2, 2, 0.896],
  944. [0.9, 2, 2, 0.972],
  945. [1, 2, 2, 1],
  946. // SciPy examples - https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.betainc.html#scipy.special.betainc
  947. [1, 0.2, 3.5, 1],
  948. [0.5, 1.4, 3.1, 0.8148904036225296],
  949. [0.4, 2.2, 3.1, 0.4933963880761945],
  950. // Issue #429
  951. [0.0041461509490402, 0.5, 170.5, 0.7657225092554762],
  952. [0.0041461509490402, 1.5, 170.5, 0.29887797299851921],
  953. // Issue #458
  954. [0.47241392386467, 0.5, 55.5, 0.99999999999999996],
  955. [0.47241392386467, 1.5, 55.5, 0.99999999999999773],
  956. // Reference implementation tests computed using SciPy - https://github.com/codeplea/incbeta/blob/master/test.c
  957. [0.1, 10, 10, 3.929882327128003e-06],
  958. [0.3, 10, 10, 0.03255335688130092],
  959. [0.5, 10, 10, 0.5],
  960. [0.7, 10, 10, 0.967446643118699],
  961. [1, 10, 10, 1.0],
  962. [0.5, 15, 10, 0.1537281274795532],
  963. [0.6, 15, 10, 0.4890801931489529],
  964. [0.5, 10, 15, 0.8462718725204468],
  965. [0.6, 10, 15, 0.978341948670397],
  966. [0.4, 20, 20, 0.10205863128940816],
  967. [0.4, 40, 40, 0.03581030716079576],
  968. [0.7, 40, 40, 0.9999016649962936],
  969. ];
  970. }
  971. /**
  972. * @test regularizedIncompleteBeta throws an OutOfBoundsException if a is less than 0
  973. */
  974. public function testRegularizedIncompleteBetaExceptionALessThanZero()
  975. {
  976. // Given
  977. $a = -1;
  978. // Then
  979. $this->expectException(Exception\OutOfBoundsException::class);
  980. // When
  981. Special::regularizedIncompleteBeta(0.4, $a, 4);
  982. }
  983. /**
  984. * @test regularizedIncompleteBeta throws an OutOfBoundsException if x is out of bounds
  985. */
  986. public function testRegularizedIncompleteBetaExceptionXOutOfBounds()
  987. {
  988. // Given
  989. $x = -1;
  990. // Then
  991. $this->expectException(Exception\OutOfBoundsException::class);
  992. // When
  993. Special::regularizedIncompleteBeta($x, 4, 4);
  994. }
  995. /**
  996. * @test Github Issue 393 Bug - regularizedIncompleteBeta
  997. * Reference expected values:
  998. * Python scipy.special.betainc(a, b, x)
  999. * >>> scipy.special.betainc(274.40782656165, 0.5, 0.99993441100298)
  1000. * 0.8495884744315958
  1001. * Online calculator https://keisan.casio.com/exec/system/1180573396
  1002. * 0.8495884744316587246283
  1003. */
  1004. public function testIssue393BugInRegularizedIncompleteBeta()
  1005. {
  1006. // Given
  1007. $x = 0.99993441100298;
  1008. $a = 274.40782656165;
  1009. $b = 0.5;
  1010. // And
  1011. $expected = 0.8495884744315958;
  1012. // When
  1013. $betainc = Special::regularizedIncompleteBeta($x, $a, $b);
  1014. // Then
  1015. $this->assertEqualsWithDelta($expected, $betainc, 0.00001);
  1016. }
  1017. /**
  1018. * @test incompleteBeta returns the expected value
  1019. * @dataProvider dataProviderForIncompleteBeta
  1020. * @param float $x
  1021. * @param float $a
  1022. * @param float $b
  1023. * @param float $ib
  1024. * @throws \Exception
  1025. */
  1026. public function testIncompleteBeta(float $x, float $a, float $b, float $ib)
  1027. {
  1028. // When
  1029. $incompleteBeta = Special::incompleteBeta($x, $a, $b);
  1030. // Then
  1031. $this->assertEqualsWithDelta($ib, $incompleteBeta, 0.0001);
  1032. }
  1033. public function dataProviderForIncompleteBeta(): array
  1034. {
  1035. return [
  1036. [0.1, 1, 3, 0.09033333333333333333333],
  1037. [0.4, 1, 3, 0.2613333333333333333333],
  1038. [0.9, 1, 3, 0.333],
  1039. [0.4, 1, 2, 0.32],
  1040. [0.4, 1, 4, 0.2176],
  1041. [0.4, 2, 4, 0.033152],
  1042. [0.4, 4, 4, 0.002069942857142857142857],
  1043. [0.7, 6, 10, 3.31784042288233100233E-5],
  1044. [0.7, 7, 10, 1.23984824870524912587E-5],
  1045. [0.44, 3, 8.4, 0.0022050133154863808046],
  1046. [0.44, 3.5, 8.5, 0.00101547937082370450368],
  1047. [0.3, 2.5, 4.5, 0.00873072257563537808667],
  1048. [0.5, 1, 2, 0.375],
  1049. [0.2, 3.4, 2.3, 9.94015483378346364195E-4],
  1050. [0.8, 3.4, 2.3, 0.040438859297104036187],
  1051. [0.45, 12.45, 3.49, 1.016239733540625974803E-6],
  1052. [0.294, 0.23, 2.11, 3.082589637435583044388],
  1053. [0.993, 0.23, 2.11, 3.48298583651202868119],
  1054. [0.76, 4, 0.3, 0.1692673319857469933301],
  1055. [0.55, 2, 2.5, 0.0774145505281552534703],
  1056. [0.55, 2.5, 2, 0.05448257245698492387678],
  1057. [0.55, 3.5, 2, 0.0201727956188770976315],
  1058. [0.73, 3.5, 5, 0.00553077297647439276549],
  1059. ];
  1060. }
  1061. /**
  1062. * @test upperIncompleteGamma throws an OutOfBoundsException if s is less than 0
  1063. */
  1064. public function testUpperIncompleteGammaExceptionSLessThanZero()
  1065. {
  1066. // Then
  1067. $this->expectException(Exception\OutOfBoundsException::class);
  1068. // When
  1069. Special::upperIncompleteGamma(-1, 1);
  1070. }
  1071. /**
  1072. * @test generalizedHypergeometric throws a BadParameterException if the parameter count is wrong
  1073. */
  1074. public function testGeneralizedHypergeometricExceptionParameterCount()
  1075. {
  1076. // Then
  1077. $this->expectException(Exception\BadParameterException::class);
  1078. // When
  1079. Special::generalizedHypergeometric(2, 1, ...[6.464756838, 0.509199496, 0.241379523]);
  1080. }
  1081. /**
  1082. * @test confluentHypergeometric returns the expected value
  1083. * @dataProvider dataProviderForConfluentHypergeometric
  1084. * @param float $a
  1085. * @param float $b
  1086. * @param float $z
  1087. * @param float $expected
  1088. * @throws \Exception
  1089. */
  1090. public function testConfluentHypergeometric(float $a, float $b, float $z, float $expected)
  1091. {
  1092. // Given
  1093. $tol = .000001 * $expected;
  1094. // When
  1095. $actual = Special::confluentHypergeometric($a, $b, $z);
  1096. // Then
  1097. $this->assertEqualsWithDelta($expected, $actual, $tol);
  1098. }
  1099. public function dataProviderForConfluentHypergeometric(): array
  1100. {
  1101. return [
  1102. [6.464756838, 0.509199496, 0.241379523, 6.48114845060471],
  1103. [5.12297443791641, 5.26188297019653, 0.757399855727661, 2.09281409280936],
  1104. [9.89309990528122, 6.92782493869175, 0.71686043176351, 2.73366255092188],
  1105. [8.59824618495037, 6.66955518297157, 0.0293511981644408, 1.03854226944163],
  1106. ];
  1107. }
  1108. /**
  1109. * @test hypergeometric returns the expected value
  1110. * @dataProvider dataProviderForHypergeometric
  1111. * @param float $a
  1112. * @param float $b
  1113. * @param float $c
  1114. * @param float $z
  1115. * @param float $expected
  1116. * @throws \Exception
  1117. */
  1118. public function testHypergeometric(float $a, float $b, float $c, float $z, float $expected)
  1119. {
  1120. // Given
  1121. $tol = .000001 * $expected;
  1122. // When
  1123. $actual = Special::hypergeometric($a, $b, $c, $z);
  1124. // Then
  1125. $this->assertEqualsWithDelta($expected, $actual, $tol);
  1126. }
  1127. public function dataProviderForHypergeometric(): array
  1128. {
  1129. return [
  1130. [1, 1, 1, .9, 10],
  1131. [1, 1, 1, .8, 5],
  1132. [1, 1, 1, .7, 3.3333333],
  1133. [3, 1.4, 1.5, .926, 1746.206366],
  1134. ];
  1135. }
  1136. /**
  1137. * @test hypergeometric throws an OutOfBoundsException if n is greater than 1
  1138. */
  1139. public function testHypergeometricExceptionNGreaterThanOne()
  1140. {
  1141. // Then
  1142. $this->expectException(Exception\OutOfBoundsException::class);
  1143. // When
  1144. Special::hypergeometric(1, 1, 1, 1);
  1145. }
  1146. /**
  1147. * @test softmax returns the expected value
  1148. * @dataProvider dataProviderForSoftmax
  1149. * @param array $𝐳
  1150. * @param array $expected
  1151. */
  1152. public function testSoftmax(array $𝐳, array $expected)
  1153. {
  1154. // When
  1155. $σ⟮𝐳⟯ⱼ = Special::softmax($𝐳);
  1156. // Then
  1157. $this->assertEqualsWithDelta($expected, $σ⟮𝐳⟯ⱼ, 0.00001);
  1158. $this->assertEqualsWithDelta(1, \array_sum($σ⟮𝐳⟯ⱼ), 0.00001);
  1159. }
  1160. public function dataProviderForSoftmax(): array
  1161. {
  1162. return [
  1163. // Test data: Wikipedia
  1164. [
  1165. [1, 2, 3, 4, 1, 2, 3],
  1166. [0.023640543021591392, 0.064261658510496159, 0.17468129859572226, 0.47483299974438037, 0.023640543021591392, 0.064261658510496159, 0.17468129859572226],
  1167. ],
  1168. // Test data: http://www.kdnuggets.com/2016/07/softmax-regression-related-logistic-regression.html
  1169. [
  1170. [0.07, 0.22, 0.28],
  1171. [0.29450637, 0.34216758, 0.363332605],
  1172. ],
  1173. [
  1174. [0.35, 0.78, 1.12],
  1175. [0.21290077, 0.32728332, 0.45981591],
  1176. ],
  1177. [
  1178. [-0.33, -0.58, -0.92],
  1179. [0.42860913, 0.33380113, 0.23758974],
  1180. ],
  1181. [
  1182. [-0.39, -0.7, -1.1],
  1183. [0.44941979, 0.32962558, 0.22095463],
  1184. ],
  1185. // Test data: https://martin-thoma.com/softmax/
  1186. [
  1187. [0.1, 0.2],
  1188. [0.47502081, 0.52497919],
  1189. ],
  1190. [
  1191. [-0.1, 0.2],
  1192. [0.42555748, 0.57444252],
  1193. ],
  1194. [
  1195. [0.9, -10],
  1196. [0.999981542, 1.84578933e-05],
  1197. ],
  1198. [
  1199. [0, 10],
  1200. [4.53978687e-05, 0.999954602],
  1201. ],
  1202. // Test data: http://stackoverflow.com/questions/34968722/softmax-function-python
  1203. [
  1204. [3.0, 1.0, 0.2],
  1205. [0.8360188, 0.11314284, 0.05083836],
  1206. ],
  1207. [
  1208. [1, 2, 3],
  1209. [0.09003057, 0.24472847, 0.66524096],
  1210. ],
  1211. [
  1212. [2, 4, 8],
  1213. [0.00242826, 0.01794253, 0.97962921],
  1214. ],
  1215. [
  1216. [3, 5, 7],
  1217. [0.01587624, 0.11731043, 0.86681333],
  1218. ],
  1219. [
  1220. [6, 6, 6],
  1221. [0.33333333, 0.33333333, 0.33333333],
  1222. ],
  1223. [
  1224. [1, 2, 3, 6],
  1225. [0.00626879, 0.01704033, 0.04632042, 0.93037047],
  1226. ],
  1227. ];
  1228. }
  1229. /**
  1230. * @test chebyshevEval bounds condition error on n
  1231. * @dataProvider dataProviderForChebyshevEvalNOutOfBounds
  1232. * @param int $n
  1233. */
  1234. public function testChebyshevEvalNOutOfBounds(int $n)
  1235. {
  1236. // Given
  1237. $x = 1;
  1238. $a = [2, 3];
  1239. // And
  1240. $chebyshevEval = new \ReflectionMethod(Special::Class, 'chebyshevEval');
  1241. $chebyshevEval->setAccessible(true);
  1242. // Then
  1243. $this->expectException(Exception\OutOfBoundsException::class);
  1244. // When
  1245. $chebyshevEval->invokeArgs(null, [$x, $a, $n]);
  1246. }
  1247. public function dataProviderForChebyshevEvalNOutOfBounds(): array
  1248. {
  1249. return [
  1250. [-2],
  1251. [1001],
  1252. ];
  1253. }
  1254. /**
  1255. * @test chebyshevEval bounds condition error on x
  1256. * @dataProvider dataProviderForChebyshevEvalXOutOfBounds
  1257. * @param float $x
  1258. */
  1259. public function testChebyshevEvalXOutOfBounds(float $x): void
  1260. {
  1261. // Given
  1262. $n = 5;
  1263. $a = [2, 3];
  1264. // And
  1265. $chebyshevEval = new \ReflectionMethod(Special::Class, 'chebyshevEval');
  1266. $chebyshevEval->setAccessible(true);
  1267. // Then
  1268. $this->expectException(Exception\OutOfBoundsException::class);
  1269. // When
  1270. $chebyshevEval->invokeArgs(null, [$x, $a, $n]);
  1271. }
  1272. public function dataProviderForChebyshevEvalXOutOfBounds(): array
  1273. {
  1274. return [
  1275. [-1.2],
  1276. [1.2],
  1277. ];
  1278. }
  1279. /**
  1280. * @test stirlingError
  1281. * @dataProvider dataProviderForSterlingError
  1282. * @param float $n
  1283. * @param float $expected
  1284. */
  1285. public function testStirlingError(float $n, float $expected): void
  1286. {
  1287. // When
  1288. $stirlingError = Special::stirlingError($n);
  1289. // Then
  1290. $this->assertEqualsWithDelta($expected, $stirlingError, 0.000001);
  1291. }
  1292. /**
  1293. * Test data produces with R library DPQmpfr: stirlerrM(n)
  1294. * @return array
  1295. */
  1296. public function dataProviderForSterlingError(): array
  1297. {
  1298. return [
  1299. [0.5, 0.1534264],
  1300. [1, 0.08106147],
  1301. [1.5, 0.05481412],
  1302. [2, 0.0413407],
  1303. [5, 0.01664469],
  1304. [5.5, 0.01513497],
  1305. [14, 0.00595137],
  1306. [14.5, 0.005746217],
  1307. [15, 0.005554734],
  1308. [0.1, 0.5127401],
  1309. [0.2, 0.3222939],
  1310. [0.9, 0.08958191],
  1311. [1.1, 0.07400292],
  1312. [5.3, 0.0157048],
  1313. [14.7, 0.005668061],
  1314. [15.5, 0.005375599],
  1315. [20, 0.00416632],
  1316. [22.4, 0.003719991],
  1317. ];
  1318. }
  1319. /**
  1320. * @test stirlingError infinity at 0
  1321. */
  1322. public function testStirlingErrorInfinity(): void
  1323. {
  1324. // Given
  1325. $n = 0;
  1326. // When
  1327. $stirlingError = Special::stirlingError($n);
  1328. // Then
  1329. $this->assertInfinite($stirlingError);
  1330. }
  1331. /**
  1332. * @test stirlingError NAN for negative values
  1333. * @dataProvider dataProviderForSterlingErrorNan
  1334. * @param float $n
  1335. */
  1336. public function testStirlingErrorNan(float $n): void
  1337. {
  1338. // Then
  1339. $this->expectException(Exception\NanException::class);
  1340. // When
  1341. $stirlingError = Special::stirlingError($n);
  1342. }
  1343. public function dataProviderForSterlingErrorNan(): array
  1344. {
  1345. return [
  1346. [-0.1],
  1347. [-1],
  1348. [-10],
  1349. ];
  1350. }
  1351. }