|
10 | 10 | - nbdtrik
|
11 | 11 | - nbdtrin
|
12 | 12 | - pdtrik
|
13 |
| -- nctdtr |
14 | 13 | - nctdtrit
|
15 | 14 | - nctdtridf
|
16 | 15 | - nctdtrinc
|
@@ -461,40 +460,6 @@ def test_chndtrix_gh2158():
|
461 | 460 | 82.35640899964173, 84.45263768373256]
|
462 | 461 | assert_allclose(res, res_exp)
|
463 | 462 |
|
464 |
| -@pytest.mark.xfail_on_32bit("32bit fails due to algorithm threshold") |
465 |
| -def test_nctdtr_gh19896(): |
466 |
| - # test that gh-19896 is resolved. |
467 |
| - # Compared to SciPy 1.11 results from Fortran code. |
468 |
| - dfarr = [0.98, 9.8, 98, 980] |
469 |
| - pnoncarr = [-3.8, 0.38, 3.8, 38] |
470 |
| - tarr = [0.0015, 0.15, 1.5, 15] |
471 |
| - resarr = [0.9999276519560749, 0.9999276519560749, 0.9999908831755221, |
472 |
| - 0.9999990265452424, 0.3524153312279712, 0.39749697267251416, |
473 |
| - 0.7168629634895805, 0.9656246449259646, 7.234804392512006e-05, |
474 |
| - 7.234804392512006e-05, 0.03538804607509127, 0.795482701508521, |
475 |
| - 0.0, 0.0, 0.0, |
476 |
| - 0.011927908523093889, 0.9999276519560749, 0.9999276519560749, |
477 |
| - 0.9999997441133123, 1.0, 0.3525155979118013, |
478 |
| - 0.4076312014048369, 0.8476794017035086, 0.9999999297116268, |
479 |
| - 7.234804392512006e-05, 7.234804392512006e-05, 0.013477443099785824, |
480 |
| - 0.9998501512331494, 0.0, 0.0, |
481 |
| - 0.0, 6.561112613212572e-07, 0.9999276519560749, |
482 |
| - 0.9999276519560749, 0.9999999313496014, 1.0, |
483 |
| - 0.3525281784865706, 0.40890253001898014, 0.8664672830017024, |
484 |
| - 1.0, 7.234804392512006e-05, 7.234804392512006e-05, |
485 |
| - 0.010990889489704836, 1.0, 0.0, |
486 |
| - 0.0, 0.0, 0.0, |
487 |
| - 0.9999276519560749, 0.9999276519560749, 0.9999999418789304, |
488 |
| - 1.0, 0.35252945487817355, 0.40903153246690993, |
489 |
| - 0.8684247068528264, 1.0, 7.234804392512006e-05, |
490 |
| - 7.234804392512006e-05, 0.01075068918582911, 1.0, |
491 |
| - 0.0, 0.0, 0.0, 0.0] |
492 |
| - actarr = [] |
493 |
| - for df, p, t in itertools.product(dfarr, pnoncarr, tarr): |
494 |
| - actarr += [sp.nctdtr(df, p, t)] |
495 |
| - # The rtol is kept high on purpose to make it pass on 32bit systems |
496 |
| - assert_allclose(actarr, resarr, rtol=1e-6, atol=0.0) |
497 |
| - |
498 | 463 |
|
499 | 464 | def test_nctdtrinc_gh19896():
|
500 | 465 | # test that gh-19896 is resolved.
|
@@ -585,3 +550,139 @@ def test_ncfdtr(dfn, dfd, nc, f, expected):
|
585 | 550 | # sample_idx = rng.choice(len(re), replace=False, size=12)
|
586 | 551 | # cases = np.array(cases)[sample_idx].tolist()
|
587 | 552 | assert_allclose(sp.ncfdtr(dfn, dfd, nc, f), expected, rtol=1e-13, atol=0)
|
| 553 | + |
| 554 | + |
| 555 | +class TestNctdtr: |
| 556 | + |
| 557 | + # Reference values computed with mpmath with the following script |
| 558 | + # Formula from: |
| 559 | + # Lenth, Russell V (1989). "Algorithm AS 243: Cumulative Distribution Function |
| 560 | + # of the Non-central t Distribution". Journal of the Royal Statistical Society, |
| 561 | + # Series C. 38 (1): 185-189 |
| 562 | + # |
| 563 | + # Warning: may take a long time to run |
| 564 | + # |
| 565 | + # from mpmath import mp |
| 566 | + # mp.dps = 400 |
| 567 | + |
| 568 | + # def nct_cdf(df, nc, x): |
| 569 | + # df, nc, x = map(mp.mpf, (df, nc, x)) |
| 570 | + |
| 571 | + # def f(df, nc, x): |
| 572 | + # phi = mp.ncdf(-nc) |
| 573 | + # y = x * x / (x * x + df) |
| 574 | + # constant = mp.exp(-nc * nc / 2.) |
| 575 | + # def term(j): |
| 576 | + # intermediate = constant * (nc *nc / 2.)**j |
| 577 | + # p = intermediate/mp.factorial(j) |
| 578 | + # q = nc / (mp.sqrt(2.) * mp.gamma(j + 1.5)) * intermediate |
| 579 | + # first_beta_term = mp.betainc(j + 0.5, df/2., x2=y, |
| 580 | + # regularized=True) |
| 581 | + # second_beta_term = mp.betainc(j + mp.one, df/2., x2=y, |
| 582 | + # regularized=True) |
| 583 | + # return p * first_beta_term + q * second_beta_term |
| 584 | + |
| 585 | + # sum_term = mp.nsum(term, [0, mp.inf]) |
| 586 | + # f = phi + 0.5 * sum_term |
| 587 | + # return f |
| 588 | + |
| 589 | + # if x >= 0: |
| 590 | + # result = f(df, nc, x) |
| 591 | + # else: |
| 592 | + # result = mp.one - f(df, -nc, x) |
| 593 | + # return float(result) |
| 594 | + |
| 595 | + @pytest.mark.parametrize("df, nc, x, expected", [ |
| 596 | + (0.98, -3.8, 0.0015, 0.9999279987514815), |
| 597 | + (0.98, -3.8, 0.15, 0.9999528361700505), |
| 598 | + (0.98, -3.8, 1.5, 0.9999908823016942), |
| 599 | + (0.98, -3.8, 15, 0.9999990264591945), |
| 600 | + (0.98, 0.38, 0.0015, 0.35241533122693), |
| 601 | + (0.98, 0.38, 0.15, 0.39749697267146983), |
| 602 | + (0.98, 0.38, 1.5, 0.716862963488558), |
| 603 | + (0.98, 0.38, 15, 0.9656246449257494), |
| 604 | + (0.98, 3.8, 0.0015, 7.26973354942293e-05), |
| 605 | + (0.98, 3.8, 0.15, 0.00012416481147589105), |
| 606 | + (0.98, 3.8, 1.5, 0.035388035775454095), |
| 607 | + (0.98, 3.8, 15, 0.7954826975430583), |
| 608 | + (0.98, 38, 0.0015, 3.02106943e-316), |
| 609 | + (0.98, 38, 0.15, 6.069970616996603e-309), |
| 610 | + (0.98, 38, 1.5, 2.591995360483094e-97), |
| 611 | + (0.98, 38, 15, 0.011927265886910935), |
| 612 | + (9.8, -3.8, 0.0015, 0.9999280776192786), |
| 613 | + (9.8, -3.8, 0.15, 0.9999599410685442), |
| 614 | + (9.8, -3.8, 1.5, 0.9999997432394788), |
| 615 | + (9.8, -3.8, 15, 0.9999999999999984), |
| 616 | + (9.8, 0.38, 0.0015, 0.3525155979107491), |
| 617 | + (9.8, 0.38, 0.15, 0.40763120140379194), |
| 618 | + (9.8, 0.38, 1.5, 0.8476794017024651), |
| 619 | + (9.8, 0.38, 15, 0.9999999297116268), |
| 620 | + (9.8, 3.8, 0.0015, 7.277620328149153e-05), |
| 621 | + (9.8, 3.8, 0.15, 0.00013024802220900652), |
| 622 | + (9.8, 3.8, 1.5, 0.013477432800072933), |
| 623 | + (9.8, 3.8, 15, 0.999850151230648), |
| 624 | + (9.8, 38, 0.0015, 3.05066095e-316), |
| 625 | + (9.8, 38, 0.15, 1.79065514676e-313), |
| 626 | + (9.8, 38, 1.5, 2.0935940165900746e-249), |
| 627 | + (9.8, 38, 15, 2.252076291604796e-09), |
| 628 | + (98, -3.8, 0.0015, 0.9999280875149109), |
| 629 | + (98, -3.8, 0.15, 0.9999608250170452), |
| 630 | + (98, -3.8, 1.5, 0.9999999304757682), |
| 631 | + (98, -3.8, 15, 1.0), |
| 632 | + (98, 0.38, 0.0015, 0.35252817848596313), |
| 633 | + (98, 0.38, 0.15, 0.40890253001794846), |
| 634 | + (98, 0.38, 1.5, 0.8664672830006552), |
| 635 | + (98, 0.38, 15, 1.0), |
| 636 | + (98, 3.8, 0.0015, 7.278609891281275e-05), |
| 637 | + (98, 3.8, 0.15, 0.0001310318674827004), |
| 638 | + (98, 3.8, 1.5, 0.010990879189991727), |
| 639 | + (98, 3.8, 15, 0.9999999999999989), |
| 640 | + (98, 38, 0.0015, 3.05437385e-316), |
| 641 | + (98, 38, 0.15, 9.1668336166e-314), |
| 642 | + (98, 38, 1.5, 1.8085884236563926e-288), |
| 643 | + (98, 38, 15, 2.7740532792035907e-50), |
| 644 | + (980, -3.8, 0.0015, 0.9999280885188965), |
| 645 | + (980, -3.8, 0.15, 0.9999609144559273), |
| 646 | + (980, -3.8, 1.5, 0.9999999410050979), |
| 647 | + (980, -3.8, 15, 1.0), |
| 648 | + (980, 0.38, 0.0015, 0.3525294548792812), |
| 649 | + (980, 0.38, 0.15, 0.4090315324657382), |
| 650 | + (980, 0.38, 1.5, 0.8684247068517293), |
| 651 | + (980, 0.38, 15, 1.0), |
| 652 | + (980, 3.8, 0.0015, 7.278710289828983e-05), |
| 653 | + (980, 3.8, 0.15, 0.00013111131667906573), |
| 654 | + (980, 3.8, 1.5, 0.010750678886113882), |
| 655 | + (980, 3.8, 15, 1.0), |
| 656 | + (980, 38, 0.0015, 3.0547506e-316), |
| 657 | + (980, 38, 0.15, 8.6191646313e-314), |
| 658 | + pytest.param(980, 38, 1.5, 1.1824454111413493e-291, |
| 659 | + marks=pytest.mark.xfail( |
| 660 | + reason="Bug in underlying Boost math implementation")), |
| 661 | + (980, 38, 15, 5.407535300713606e-105) |
| 662 | + ]) |
| 663 | + def test_gh19896(self, df, nc, x, expected): |
| 664 | + # test that gh-19896 is resolved. |
| 665 | + # Originally this was a regression test that used the old Fortran results |
| 666 | + # as a reference. The Fortran results were not accurate, so the reference |
| 667 | + # values were recomputed with mpmath. |
| 668 | + result = sp.nctdtr(df, nc, x) |
| 669 | + assert_allclose(result, expected, rtol=1e-13, atol=1e-303) |
| 670 | + |
| 671 | + def test_nctdtr_gh8344(self): |
| 672 | + # test that gh-8344 is resolved. |
| 673 | + df, nc, x = 3000, 3, 0.1 |
| 674 | + expected = 0.0018657780826323328 |
| 675 | + assert_allclose(sp.nctdtr(df, nc, x), expected, rtol=1e-14) |
| 676 | + |
| 677 | + @pytest.mark.parametrize( |
| 678 | + "df, nc, x, expected, rtol", |
| 679 | + [[3., 5., -2., 1.5645373999149622e-09, 5e-9], |
| 680 | + [1000., 10., 1., 1.1493552133826623e-19, 1e-13], |
| 681 | + [1e-5, -6., 2., 0.9999999990135003, 1e-13], |
| 682 | + [10., 20., 0.15, 6.426530505957303e-88, 1e-13], |
| 683 | + [1., 1., np.inf, 1.0, 0.0], |
| 684 | + [1., 1., -np.inf, 0.0, 0.0] |
| 685 | + ] |
| 686 | + ) |
| 687 | + def test_accuracy(self, df, nc, x, expected, rtol): |
| 688 | + assert_allclose(sp.nctdtr(df, nc, x), expected, rtol=rtol) |
0 commit comments