%PDF- %PDF-
Direktori : /lib/python3/dist-packages/scipy/special/tests/ |
Current File : //lib/python3/dist-packages/scipy/special/tests/test_hyp2f1.py |
"""Tests for hyp2f1 for complex values. Author: Albert Steppi, with credit to Adam Kullberg (FormerPhycisist) for the implementation of mp_hyp2f1 below, which modifies mpmath's hyp2f1 to return the same branch as scipy's on the standard branch cut. """ import sys import pytest import numpy as np from typing import NamedTuple from numpy.testing import assert_allclose from scipy.special import hyp2f1 from scipy.special._testutils import check_version, MissingModule try: import mpmath except ImportError: mpmath = MissingModule("mpmath") def mp_hyp2f1(a, b, c, z): """Return mpmath hyp2f1 calculated on same branch as scipy hyp2f1. For most values of a,b,c mpmath returns the x - 0j branch of hyp2f1 on the branch cut x=(1,inf) whereas scipy's hyp2f1 calculates the x + 0j branch. Thus, to generate the right comparison values on the branch cut, we evaluate mpmath.hyp2f1 at x + 1e-15*j. The exception to this occurs when c-a=-m in which case both mpmath and scipy calculate the x + 0j branch on the branch cut. When this happens mpmath.hyp2f1 will be evaluated at the original z point. """ on_branch_cut = z.real > 1.0 and abs(z.imag) < 1.0e-15 cond1 = abs(c - a - round(c - a)) < 1.0e-15 and round(c - a) <= 0 cond2 = abs(c - b - round(c - b)) < 1.0e-15 and round(c - b) <= 0 # Make sure imaginary part is *exactly* zero if on_branch_cut: z = z.real + 0.0j if on_branch_cut and not (cond1 or cond2): z_mpmath = z.real + 1.0e-15j else: z_mpmath = z return complex(mpmath.hyp2f1(a, b, c, z_mpmath)) class Hyp2f1TestCase(NamedTuple): a: float b: float c: float z: complex expected: complex rtol: float class TestHyp2f1: """Tests for hyp2f1 for complex values. Expected values for test cases were computed using mpmath. See `scipy.special._precompute.hyp2f1_data`. The verbose style of specifying test cases is used for readability and to make it easier to mark individual cases as expected to fail. Expected failures are used to highlight cases where improvements are needed. See `scipy.special._precompute.hyp2f1_data.make_hyp2f1_test_cases` for a function to generate the boilerplate for the test cases. Assertions have been added to each test to ensure that the test cases match the situations that are intended. A final test `test_test_hyp2f1` checks that the expected values in the test cases actually match what is computed by mpmath. This test is marked slow even though it isn't particularly slow so that it won't run by default on continuous integration builds. """ @pytest.mark.parametrize( "hyp2f1_test_case", [ pytest.param( Hyp2f1TestCase( a=0.5, b=0.2, c=-10, z=0.2 + 0.2j, expected=np.inf + 0j, rtol=0 ) ), pytest.param( Hyp2f1TestCase( a=0.5, b=0.2, c=-10, z=0 + 0j, expected=1 + 0j, rtol=0 ), ), pytest.param( Hyp2f1TestCase( a=0.5, b=0, c=-10, z=0.2 + 0.2j, expected=1 + 0j, rtol=0 ), ), pytest.param( Hyp2f1TestCase( a=0.5, b=0, c=0, z=0.2 + 0.2j, expected=1 + 0j, rtol=0, ), ), pytest.param( Hyp2f1TestCase( a=0.5, b=0.2, c=0, z=0.2 + 0.2j, expected=np.inf + 0j, rtol=0, ), ), pytest.param( Hyp2f1TestCase( a=0.5, b=0.2, c=0, z=0 + 0j, expected=np.nan + 0j, rtol=0, ), ), pytest.param( Hyp2f1TestCase( a=0.5, b=-5, c=-10, z=0.2 + 0.2j, expected=(1.0495404166666666+0.05708208333333334j), rtol=1e-15, ), ), pytest.param( Hyp2f1TestCase( a=0.5, b=-10, c=-10, z=0.2 + 0.2j, expected=(1.092966013125+0.13455014673750001j), rtol=1e-15, ), ), pytest.param( Hyp2f1TestCase( a=-10, b=-20, c=-10, z=0.2 + 0.2j, expected=(-0.07712512000000005+0.12752814080000005j), rtol=1e-13, ), ), pytest.param( Hyp2f1TestCase( a=-1, b=3.2, c=-1, z=0.2 + 0.2j, expected=(1.6400000000000001+0.6400000000000001j), rtol=1e-13, ), ), ] ) def test_c_non_positive_int(self, hyp2f1_test_case): a, b, c, z, expected, rtol = hyp2f1_test_case assert_allclose(hyp2f1(a, b, c, z), expected, rtol=rtol) @pytest.mark.parametrize( "hyp2f1_test_case", [ pytest.param( Hyp2f1TestCase( a=0.5, b=0.2, c=1.5, z=1 + 0j, expected=1.1496439092239847 + 0j, rtol=1e-15 ), ), pytest.param( Hyp2f1TestCase( a=12.3, b=8.0, c=20.31, z=1 + 0j, expected=69280986.75273195 + 0j, rtol=1e-15 ), ), pytest.param( Hyp2f1TestCase( a=290.2, b=321.5, c=700.1, z=1 + 0j, expected=1.3396562400934e117 + 0j, rtol=1e-12, ), ), pytest.param( Hyp2f1TestCase( a=-102.1, b=-20.3, c=1.3, z=1 + 0j, expected=2.7899070752746906e22 + 0j, rtol=1e-15 ), ), pytest.param( Hyp2f1TestCase( a=-202.6, b=60.3, c=1.5, z=1 + 0j, expected=-1.3113641413099326e-56 + 0j, rtol=1e-12, ), ), ], ) def test_unital_argument(self, hyp2f1_test_case): """Tests for case z = 1, c - a - b > 0. Expected answers computed using mpmath. """ a, b, c, z, expected, rtol = hyp2f1_test_case assert z == 1 and c - a - b > 0 # Tests the test assert_allclose(hyp2f1(a, b, c, z), expected, rtol=rtol) @pytest.mark.parametrize( "hyp2f1_test_case", [ pytest.param( Hyp2f1TestCase( a=0.5, b=0.2, c=1.3, z=-1 + 0j, expected=0.9428846409614143 + 0j, rtol=1e-15), ), pytest.param( Hyp2f1TestCase( a=12.3, b=8.0, c=5.300000000000001, z=-1 + 0j, expected=-4.845809986595704e-06 + 0j, rtol=1e-15 ), ), pytest.param( Hyp2f1TestCase( a=221.5, b=90.2, c=132.3, z=-1 + 0j, expected=2.0490488728377282e-42 + 0j, rtol=1e-7, ), ), pytest.param( Hyp2f1TestCase( a=-102.1, b=-20.3, c=-80.8, z=-1 + 0j, expected=45143784.46783885 + 0j, rtol=1e-7, ), marks=pytest.mark.xfail( condition=sys.maxsize < 2**32, reason="Fails on 32 bit.", ) ), ], ) def test_special_case_z_near_minus_1(self, hyp2f1_test_case): """Tests for case z ~ -1, c ~ 1 + a - b Expected answers computed using mpmath. """ a, b, c, z, expected, rtol = hyp2f1_test_case assert abs(1 + a - b - c) < 1e-15 and abs(z + 1) < 1e-15 assert_allclose(hyp2f1(a, b, c, z), expected, rtol=rtol) @pytest.mark.parametrize( "hyp2f1_test_case", [ pytest.param( Hyp2f1TestCase( a=-4, b=2.02764642551431, c=1.0561196186065624, z=(0.9473684210526314-0.10526315789473695j), expected=(0.0031961077109535375-0.0011313924606557173j), rtol=1e-12, ), ), pytest.param( Hyp2f1TestCase( a=-8, b=-7.937789122896016, c=-15.964218273004214, z=(2-0.10526315789473695j), expected=(0.005543763196412503-0.0025948879065698306j), rtol=5e-13, ), ), pytest.param( Hyp2f1TestCase( a=-8, b=8.095813935368371, c=4.0013768449590685, z=(0.9473684210526314-0.10526315789473695j), expected=(-0.0003054674127221263-9.261359291755414e-05j), rtol=1e-10, ), ), pytest.param( Hyp2f1TestCase( a=-4, b=-3.956227226099288, c=-3.9316537064827854, z=(1.1578947368421053-0.3157894736842106j), expected=(-0.0020809502580892937-0.0041877333232365095j), rtol=5e-12, ), ), pytest.param( Hyp2f1TestCase( a=2.02764642551431, b=-4, c=2.050308316530781, z=(0.9473684210526314-0.10526315789473695j), expected=(0.0011282435590058734+0.0002027062303465851j), rtol=5e-13, ), ), pytest.param( Hyp2f1TestCase( a=-7.937789122896016, b=-8, c=-15.964218273004214, z=(1.3684210526315788+0.10526315789473673j), expected=(-9.134907719238265e-05-0.00040219233987390723j), rtol=5e-12, ), ), pytest.param( Hyp2f1TestCase( a=4.080187217753502, b=-4, c=4.0013768449590685, z=(0.9473684210526314-0.10526315789473695j), expected=(-0.000519013062087489-0.0005855883076830948j), rtol=5e-12, ), ), pytest.param( Hyp2f1TestCase( a=-10000, b=2.2, c=93459345.3, z=(2+2j), expected=(0.9995292071559088-0.00047047067522659253j), rtol=1e-12, ), ), ] ) def test_a_b_negative_int(self, hyp2f1_test_case): a, b, c, z, expected, rtol = hyp2f1_test_case assert a == int(a) and a < 0 or b == int(b) and b < 0 # Tests the test assert_allclose(hyp2f1(a, b, c, z), expected, rtol=rtol) @pytest.mark.parametrize( "hyp2f1_test_case", [ pytest.param( Hyp2f1TestCase( a=-0.5, b=-0.9629749245209605, c=-15.5, z=(1.1578947368421053-1.1578947368421053j), expected=(0.9778506962676361+0.044083801141231616j), rtol=1e-12, ), ), pytest.param( Hyp2f1TestCase( a=8.5, b=-3.9316537064827854, c=1.5, z=(0.9473684210526314-0.10526315789473695j), expected=(4.0793167523167675-10.11694246310966j), rtol=6e-12, ), ), pytest.param( Hyp2f1TestCase( a=8.5, b=-0.9629749245209605, c=2.5, z=(1.1578947368421053-0.10526315789473695j), expected=(-2.9692999501916915+0.6394599899845594j), rtol=1e-11, ), ), pytest.param( Hyp2f1TestCase( a=-0.5, b=-0.9629749245209605, c=-15.5, z=(1.5789473684210522-1.1578947368421053j), expected=(0.9493076367106102-0.04316852977183447j), rtol=1e-11, ), ), pytest.param( Hyp2f1TestCase( a=-0.9220024191881196, b=-0.5, c=-15.5, z=(0.5263157894736841+0.10526315789473673j), expected=(0.9844377175631795-0.003120587561483841j), rtol=1e-10, ), ), ], ) def test_a_b_neg_int_after_euler_hypergeometric_transformation( self, hyp2f1_test_case ): a, b, c, z, expected, rtol = hyp2f1_test_case assert ( # Tests the test (abs(c - a - int(c - a)) < 1e-15 and c - a < 0) or (abs(c - b - int(c - b)) < 1e-15 and c - b < 0) ) assert_allclose(hyp2f1(a, b, c, z), expected, rtol=rtol) @pytest.mark.parametrize( "hyp2f1_test_case", [ pytest.param( Hyp2f1TestCase( a=-0.9220024191881196, b=-0.9629749245209605, c=-15.963511401609862, z=(0.10526315789473673-0.3157894736842106j), expected=(0.9941449585778349+0.01756335047931358j), rtol=1e-14, ), ), pytest.param( Hyp2f1TestCase( a=1.0272592605282642, b=-0.9629749245209605, c=-15.963511401609862, z=(0.5263157894736841+0.5263157894736841j), expected=(1.0388722293372104-0.09549450380041416j), rtol=5e-11, ), ), pytest.param( Hyp2f1TestCase( a=2.02764642551431, b=1.0561196186065624, c=-7.93846038215665, z=(0.10526315789473673+0.7368421052631575j), expected=(2.1948378809826434+24.934157235172222j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=2.02764642551431, b=16.088264119063613, c=8.031683612216888, z=(0.3157894736842106-0.736842105263158j), expected=(-0.4075277891264672-0.06819344579666956j), rtol=2e-12, ), ), pytest.param( Hyp2f1TestCase( a=4.080187217753502, b=2.050308316530781, c=8.031683612216888, z=(0.7368421052631575-0.10526315789473695j), expected=(2.833535530740603-0.6925373701408158j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=2.02764642551431, b=2.050308316530781, c=4.078873014294075, z=(0.10526315789473673-0.3157894736842106j), expected=(1.005347176329683-0.3580736009337313j), rtol=5e-16, ), ), pytest.param( Hyp2f1TestCase( a=-0.9220024191881196, b=-0.9629749245209605, c=-15.963511401609862, z=(0.3157894736842106-0.5263157894736843j), expected=(0.9824353641135369+0.029271018868990268j), rtol=5e-13, ), ), pytest.param( Hyp2f1TestCase( a=-0.9220024191881196, b=-0.9629749245209605, c=-159.63511401609862, z=(0.3157894736842106-0.5263157894736843j), expected=(0.9982436200365834+0.002927268199671111j), rtol=1e-7, ), marks=pytest.mark.xfail(reason="Poor convergence.") ), pytest.param( Hyp2f1TestCase( a=2.02764642551431, b=16.088264119063613, c=8.031683612216888, z=(0.5263157894736841-0.5263157894736843j), expected=(-0.6906825165778091+0.8176575137504892j), rtol=5e-13, ), ), ] ) def test_region1(self, hyp2f1_test_case): """|z| < 0.9 and real(z) >= 0.""" a, b, c, z, expected, rtol = hyp2f1_test_case assert abs(z) < 0.9 and z.real >= 0 # Tests the test assert_allclose(hyp2f1(a, b, c, z), expected, rtol=rtol) @pytest.mark.parametrize( "hyp2f1_test_case", [ pytest.param( Hyp2f1TestCase( a=2.02764642551431, b=1.0561196186065624, c=4.078873014294075, z=(-0.3157894736842106+0.7368421052631575j), expected=(0.7751915029081136+0.24068493258607315j), rtol=5e-15, ), ), ] ) def test_region2(self, hyp2f1_test_case): """|z| < 1 and real(z) < 0.""" a, b, c, z, expected, rtol = hyp2f1_test_case assert abs(z) < 1 and z.real < 0 # Tests the test assert_allclose(hyp2f1(a, b, c, z), expected, rtol=rtol) @pytest.mark.parametrize( "hyp2f1_test_case", [ pytest.param( Hyp2f1TestCase( a=16.25, b=4.25, c=2.5, z=(0.4931034482758623-0.7965517241379311j), expected=(38.41207903409937-30.510151276075792j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=2.0, b=16.087593263474208, c=16.088264119063613, z=(0.5689655172413794-0.7965517241379311j), expected=(-0.6667857912761286-1.0206224321443573j), rtol=1e-15, ), ), pytest.param( Hyp2f1TestCase( a=8.0, b=1.0272592605282642, c=-7.949900487447654, z=(0.4931034482758623-0.7965517241379311j), expected=(1679024.1647997478-2748129.775857212j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=4.080187217753502, b=16.0, c=-7.949900487447654, z=(0.4931034482758623-0.7965517241379311j), expected=(424747226301.16986-1245539049327.2856j), rtol=1e-14, ), ), pytest.param( Hyp2f1TestCase( a=2.02764642551431, b=-15.964218273004214, c=4.0, z=(0.4931034482758623-0.7965517241379311j), expected=(-0.0057826199201757595+0.026359861999025885j), rtol=5e-06, ), ), pytest.param( Hyp2f1TestCase( a=2.02764642551431, b=-0.9629749245209605, c=2.0397202577726152, z=(0.5689655172413794-0.7965517241379311j), expected=(0.4671901063492606+0.7769632229834897j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=2.0, b=-3.956227226099288, c=-7.949900487447654, z=(0.4931034482758623+0.7965517241379312j), expected=(0.9422283708145973+1.3476905754773343j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=1.0, b=-15.980848054962111, c=-15.964218273004214, z=(0.4931034482758623-0.7965517241379311j), expected=(0.4168719497319604-0.9770953555235625j), rtol=5e-10, ), ), pytest.param( Hyp2f1TestCase( a=-0.5, b=16.088264119063613, c=2.5, z=(0.5689655172413794+0.7965517241379312j), expected=(1.279096377550619-2.173827694297929j), rtol=5e-12, ), ), pytest.param( Hyp2f1TestCase( a=-1.9214641416286231, b=4.0013768449590685, c=2.0397202577726152, z=(0.4931034482758623+0.7965517241379312j), expected=(-2.071520656161738-0.7846098268395909j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=-0.9220024191881196, b=8.0, c=-0.9629749245209605, z=(0.5689655172413794-0.7965517241379311j), expected=(-7.740015495862889+3.386766435696699j), rtol=5e-12, ), ), pytest.param( Hyp2f1TestCase( a=-1.9214641416286231, b=16.088264119063613, c=-7.93846038215665, z=(0.4931034482758623+0.7965517241379312j), expected=(-6318.553685853241-7133.416085202879j), rtol=1e-10, ), ), pytest.param( Hyp2f1TestCase( a=-15.980848054962111, b=-3.9316537064827854, c=16.056809865262608, z=(0.5689655172413794+0.7965517241379312j), expected=(-0.8854577905547399+8.135089099967278j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=-1.9214641416286231, b=-0.9629749245209605, c=4.078873014294075, z=(0.4931034482758623+0.7965517241379312j), expected=(1.224291301521487+0.36014711766402485j), rtol=1e-15, ), ), pytest.param( Hyp2f1TestCase( a=-15.75, b=-0.75, c=-1.5, z=(0.4931034482758623+0.7965517241379312j), expected=(-1.5765685855028473-3.9399766961046323j), rtol=1e-3, ), marks=pytest.mark.xfail( reason="Unhandled parameters." ) ), pytest.param( Hyp2f1TestCase( a=-15.980848054962111, b=-1.92872979730171, c=-7.93846038215665, z=(0.5689655172413794-0.7965517241379311j), expected=(56.794588688231194+4.556286783533971j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=4.5, b=4.5, c=2.050308316530781, z=(0.5689655172413794+0.7965517241379312j), expected=(-4.251456563455306+6.737837111569671j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=4.5, b=8.5, c=-1.92872979730171, z=(0.4931034482758623-0.7965517241379311j), expected=(2177143.9156599627-3313617.2748088865j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=2.5, b=-1.5, c=4.0013768449590685, z=(0.4931034482758623-0.7965517241379311j), expected=(0.45563554481603946+0.6212000158060831j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=8.5, b=-7.5, c=-15.964218273004214, z=(0.4931034482758623+0.7965517241379312j), expected=(61.03201617828073-37.185626416756214j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=-15.5, b=16.5, c=4.0013768449590685, z=(0.4931034482758623+0.7965517241379312j), expected=(-33143.425963520735+20790.608514722644j), rtol=1e-14, ), ), pytest.param( Hyp2f1TestCase( a=-0.5, b=4.5, c=-0.9629749245209605, z=(0.5689655172413794+0.7965517241379312j), expected=(30.778600270824423-26.65160354466787j), rtol=5e-13, ), ), pytest.param( Hyp2f1TestCase( a=-0.5, b=-3.5, c=16.088264119063613, z=(0.5689655172413794-0.7965517241379311j), expected=(1.0629792615560487-0.08308454486044772j), rtol=1e-15, ), ), pytest.param( Hyp2f1TestCase( a=-3.5, b=-7.5, c=-0.9629749245209605, z=(0.4931034482758623-0.7965517241379311j), expected=(17431.571802591767+3553.7129767034507j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=2.25, b=8.25, c=16.5, z=(0.11379310344827598+0.9482758620689657j), expected=(0.4468600750211926+0.7313214934036885j), rtol=1e-3, ), marks=pytest.mark.xfail( reason="Unhandled parameters." ) ), pytest.param( Hyp2f1TestCase( a=8.25, b=16.25, c=4.5, z=(0.3413793103448277+0.8724137931034486j), expected=(-3.905704438293991+3.693347860329299j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=4.25, b=4.25, c=-0.5, z=(0.11379310344827598-0.9482758620689655j), expected=(-40.31777941834244-89.89852492432011j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=1.0272592605282642, b=8.0, c=-15.964218273004214, z=(0.11379310344827598-0.9482758620689655j), expected=(52584.347773055284-109197.86244309516j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=8.095813935368371, b=-15.964218273004214, c=16.056809865262608, z=(0.03793103448275881+0.9482758620689657j), expected=(-1.187733570412592-1.5147865053584582j), rtol=5e-10, ), ), pytest.param( Hyp2f1TestCase( a=4.080187217753502, b=-3.9316537064827854, c=1.0651378143226575, z=(0.26551724137931054+0.9482758620689657j), expected=(13.077494677898947+35.071599628224966j), rtol=5e-13, ), ), pytest.param( Hyp2f1TestCase( a=4.080187217753502, b=-3.5, c=-3.5, z=(0.26551724137931054+0.8724137931034486j), expected=(-0.5359656237994614-0.2344483936591811j), rtol=1e-15, ), ), pytest.param( Hyp2f1TestCase( a=4.25, b=-3.75, c=-1.5, z=(0.26551724137931054+0.9482758620689657j), expected=(1204.8114871663133+64.41022826840198j), rtol=5e-13, ), ), pytest.param( Hyp2f1TestCase( a=-1.9214641416286231, b=16.0, c=4.0013768449590685, z=(0.03793103448275881-0.9482758620689655j), expected=(-9.85268872413994+7.011107558429154j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=-7.937789122896016, b=16.0, c=4.0013768449590685, z=(0.3413793103448277-0.8724137931034484j), expected=(528.5522951158454-1412.21630264791j), rtol=1e-15, ), ), pytest.param( Hyp2f1TestCase( a=-15.5, b=1.0561196186065624, c=-7.5, z=(0.4172413793103451+0.8724137931034486j), expected=(133306.45260685298+256510.7045225382j), rtol=1e-15, ), ), pytest.param( Hyp2f1TestCase( a=-7.937789122896016, b=8.077282662161238, c=-15.963511401609862, z=(0.3413793103448277-0.8724137931034484j), expected=(-0.998555715276967+2.774198742229889j), rtol=5e-11, ), ), pytest.param( Hyp2f1TestCase( a=-7.75, b=-0.75, c=1.5, z=(0.11379310344827598-0.9482758620689655j), expected=(2.072445019723025-2.9793504811373515j), rtol=1e-15, ), ), pytest.param( Hyp2f1TestCase( a=-15.5, b=-1.92872979730171, c=1.5, z=(0.11379310344827598-0.9482758620689655j), expected=(-41.87581944176649-32.52980303527139j), rtol=5e-13, ), ), pytest.param( Hyp2f1TestCase( a=-3.75, b=-15.75, c=-0.5, z=(0.11379310344827598-0.9482758620689655j), expected=(-3729.6214864209774-30627.510509112635j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=-3.956227226099288, b=-15.964218273004214, c=-0.906685989801748, z=(0.03793103448275881+0.9482758620689657j), expected=(-131615.07820609974+145596.13384245415j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=1.5, b=16.5, c=16.088264119063613, z=(0.26551724137931054+0.8724137931034486j), expected=(0.18981844071070744+0.7855036242583742j), rtol=1e-15, ), ), pytest.param( Hyp2f1TestCase( a=16.5, b=8.5, c=-3.9316537064827854, z=(0.11379310344827598-0.9482758620689655j), expected=(110224529.2376068+128287212.04290268j), rtol=5e-13, ), ), pytest.param( Hyp2f1TestCase( a=2.5, b=-7.5, c=4.0013768449590685, z=(0.3413793103448277-0.8724137931034484j), expected=(0.2722302180888523-0.21790187837266162j), rtol=1e-12, ), ), pytest.param( Hyp2f1TestCase( a=8.5, b=-7.5, c=-15.964218273004214, z=(0.11379310344827598-0.9482758620689655j), expected=(-2.8252338010989035+2.430661949756161j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=-3.5, b=16.5, c=4.0013768449590685, z=(0.03793103448275881+0.9482758620689657j), expected=(-20.604894257647945+74.5109432558078j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=-7.5, b=8.5, c=-0.9629749245209605, z=(0.3413793103448277+0.8724137931034486j), expected=(-2764422.521269463-3965966.9965808876j), rtol=1e-15, ), ), pytest.param( Hyp2f1TestCase( a=-1.5, b=-0.5, c=1.0561196186065624, z=(0.26551724137931054+0.9482758620689657j), expected=(1.2262338560994905+0.6545051266925549j), rtol=1e-15, ), ), pytest.param( Hyp2f1TestCase( a=-0.5, b=-15.5, c=-7.949900487447654, z=(0.4172413793103451-0.8724137931034484j), expected=(-2258.1590330318213+8860.193389158803j), rtol=1e-10, ), ), ] ) def test_region4(self, hyp2f1_test_case): """0.9 <= |z| <= 1 and |1 - z| >= 1. This region is unhandled by of the standard transformations and needs special care. """ a, b, c, z, expected, rtol = hyp2f1_test_case assert 0.9 <= abs(z) <= 1 and abs(1 - z) >= 0.9 # Tests the test assert_allclose(hyp2f1(a, b, c, z), expected, rtol=rtol) @pytest.mark.parametrize( "hyp2f1_test_case", [ pytest.param( Hyp2f1TestCase( a=4.5, b=16.088264119063613, c=8.5, z=(0.6448275862068968+0.8724137931034486j), expected=(0.018601324701770394-0.07618420586062377j), rtol=5e-08, ), ), pytest.param( Hyp2f1TestCase( a=8.25, b=4.25, c=4.5, z=(0.6448275862068968-0.8724137931034484j), expected=(-1.391549471425551-0.118036604903893j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=2.02764642551431, b=2.050308316530781, c=-1.9631175993998025, z=(0.6448275862068968+0.8724137931034486j), expected=(-2309.178768155151-1932.7247727595172j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=16.087593263474208, b=1.0, c=-15.964218273004214, z=(0.6448275862068968+0.8724137931034486j), expected=(85592537010.05054-8061416766688.324j), rtol=1e-14, ), ), pytest.param( Hyp2f1TestCase( a=8.095813935368371, b=-0.5, c=1.5, z=(0.6448275862068968+0.8724137931034486j), expected=(1.2334498208515172-2.1639498536219732j), rtol=5e-11, ), ), pytest.param( Hyp2f1TestCase( a=16.087593263474208, b=-15.964218273004214, c=4.0, z=(0.6448275862068968+0.8724137931034486j), expected=(102266.35398605966-44976.97828737755j), rtol=1e-3, ), marks=pytest.mark.xfail( reason="Unhandled parameters." ) ), pytest.param( Hyp2f1TestCase( a=4.0, b=-3.956227226099288, c=-15.964218273004214, z=(0.6448275862068968-0.8724137931034484j), expected=(-2.9590030930007236-4.190770764773225j), rtol=5e-13, ), ), pytest.param( Hyp2f1TestCase( a=4.080187217753502, b=-15.5, c=-7.5, z=(0.5689655172413794-0.8724137931034484j), expected=(-112554838.92074208+174941462.9202412j), rtol=5e-05, ), ), pytest.param( Hyp2f1TestCase( a=-15.980848054962111, b=2.050308316530781, c=1.0, z=(0.6448275862068968-0.8724137931034484j), expected=(3.7519882374080145+7.360753798667486j), rtol=5e-13, ), ), pytest.param( Hyp2f1TestCase( a=-7.937789122896016, b=2.050308316530781, c=4.0, z=(0.6448275862068968-0.8724137931034484j), expected=(0.000181132943964693+0.07742903103815582j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=-7.937789122896016, b=4.0013768449590685, c=-1.9631175993998025, z=(0.5689655172413794+0.8724137931034486j), expected=(386338.760913596-386166.51762171905j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=-15.980848054962111, b=8.0, c=-1.92872979730171, z=(0.6448275862068968+0.8724137931034486j), expected=(1348667126.3444858-2375132427.158893j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=-3.5, b=-0.9629749245209605, c=4.5, z=(0.5689655172413794+0.8724137931034486j), expected=(1.428353429538678+0.6472718120804372j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=-7.937789122896016, b=-0.9629749245209605, c=2.0397202577726152, z=(0.5689655172413794-0.8724137931034484j), expected=(3.1439267526119643-3.145305240375117j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=-1.9214641416286231, b=-15.964218273004214, c=-7.93846038215665, z=(0.6448275862068968-0.8724137931034484j), expected=(75.27467675681773+144.0946946292215j), rtol=1e-07, ), ), pytest.param( Hyp2f1TestCase( a=-3.75, b=-7.75, c=-7.5, z=(0.5689655172413794+0.8724137931034486j), expected=(-0.3699450626264222+0.8732812475910993j), rtol=1e-15, ), ), pytest.param( Hyp2f1TestCase( a=1.5, b=16.5, c=1.0561196186065624, z=(0.5689655172413794-0.8724137931034484j), expected=(5.5361025821300665-2.4709693474656285j), rtol=5e-09, ), ), pytest.param( Hyp2f1TestCase( a=1.5, b=8.5, c=-3.9316537064827854, z=(0.6448275862068968-0.8724137931034484j), expected=(-782805.6699207705-537192.581278909j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=2.5, b=-15.5, c=1.0561196186065624, z=(0.6448275862068968+0.8724137931034486j), expected=(12.345113400639693-14.993248992902007j), rtol=0.0005, ), ), pytest.param( Hyp2f1TestCase( a=1.5, b=-0.5, c=-15.964218273004214, z=(0.6448275862068968+0.8724137931034486j), expected=(23.698109392667842+97.15002033534108j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=-7.5, b=16.5, c=4.0013768449590685, z=(0.6448275862068968-0.8724137931034484j), expected=(1115.2978631811834+915.9212658718577j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=-15.5, b=16.5, c=-0.9629749245209605, z=(0.6448275862068968+0.8724137931034486j), expected=(642077722221.6489+535274495398.21027j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=-7.5, b=-3.5, c=4.0013768449590685, z=(0.5689655172413794+0.8724137931034486j), expected=(-5.689219222945697+16.877463062787143j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=-15.5, b=-1.5, c=-0.9629749245209605, z=(0.5689655172413794-0.8724137931034484j), expected=(-44.32070290703576+1026.9127058617403j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=16.25, b=2.25, c=4.5, z=(0.11379310344827598-1.024137931034483j), expected=(-0.021965227124574663+0.009908300237809064j), rtol=1e-3, ), marks=pytest.mark.xfail( reason="Unhandled parameters." ) ), pytest.param( Hyp2f1TestCase( a=2.02764642551431, b=1.5, c=16.5, z=(0.26551724137931054+1.024137931034483j), expected=(1.0046072901244183+0.19945500134119992j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=16.087593263474208, b=1.0, c=-3.9316537064827854, z=(0.3413793103448277+0.9482758620689657j), expected=(21022.30133421465+49175.98317370489j), rtol=5e-13, ), ), pytest.param( Hyp2f1TestCase( a=4.080187217753502, b=16.088264119063613, c=-1.9631175993998025, z=(0.4172413793103451-0.9482758620689655j), expected=(-7024239.358547302+2481375.02681063j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=16.25, b=-15.75, c=1.5, z=(0.18965517241379315+1.024137931034483j), expected=(92371704.94848-403546832.548352j), rtol=5e-06, ), ), pytest.param( Hyp2f1TestCase( a=8.5, b=-7.949900487447654, c=8.5, z=(0.26551724137931054-1.024137931034483j), expected=(1.9335109845308265+5.986542524829654j), rtol=5e-10, ), ), pytest.param( Hyp2f1TestCase( a=8.095813935368371, b=-1.92872979730171, c=-7.93846038215665, z=(0.4931034482758623+0.8724137931034486j), expected=(-122.52639696039328-59.72428067512221j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=16.25, b=-1.75, c=-1.5, z=(0.4931034482758623+0.9482758620689657j), expected=(-90.40642053579428+50.50649180047921j), rtol=5e-08, ), ), pytest.param( Hyp2f1TestCase( a=-3.5, b=8.077282662161238, c=16.5, z=(0.4931034482758623+0.9482758620689657j), expected=(-0.2155745818150323-0.564628986876639j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=-0.9220024191881196, b=1.0561196186065624, c=8.031683612216888, z=(0.4172413793103451-0.9482758620689655j), expected=(0.9503140488280465+0.11574960074292677j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=-0.75, b=2.25, c=-15.5, z=(0.4172413793103451+0.9482758620689657j), expected=(0.9285862488442175+0.8203699266719692j), rtol=5e-13, ), ), pytest.param( Hyp2f1TestCase( a=-7.75, b=4.25, c=-15.5, z=(0.3413793103448277-0.9482758620689655j), expected=(-1.0509834850116921-1.1145522325486075j), rtol=1e-14, ), ), pytest.param( Hyp2f1TestCase( a=-7.937789122896016, b=-0.9629749245209605, c=2.0397202577726152, z=(0.4931034482758623-0.9482758620689655j), expected=(2.88119116536769-3.4249933450696806j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=-15.5, b=-15.964218273004214, c=16.5, z=(0.18965517241379315+1.024137931034483j), expected=(199.65868451496038+347.79384207302877j), rtol=1e-13, ), ), pytest.param( Hyp2f1TestCase( a=-15.75, b=-15.75, c=-3.5, z=(0.4931034482758623-0.8724137931034484j), expected=(-208138312553.07013+58631611809.026955j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=-7.937789122896016, b=-15.5, c=-7.5, z=(0.3413793103448277+0.9482758620689657j), expected=(-23032.90519856288-18256.94050457296j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=4.5, b=1.5, c=1.0561196186065624, z=(0.4931034482758623-0.8724137931034484j), expected=(1.507342459587056+1.2332023580148403j), rtol=1e-15, ), ), pytest.param( Hyp2f1TestCase( a=2.5, b=4.5, c=-3.9316537064827854, z=(0.4172413793103451+0.9482758620689657j), expected=(7044.766127108853-40210.365567285575j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=1.5, b=-1.5, c=1.0561196186065624, z=(0.03793103448275881+1.024137931034483j), expected=(0.2725347741628333-2.247314875514784j), rtol=1e-15, ), ), pytest.param( Hyp2f1TestCase( a=4.5, b=-1.5, c=-7.949900487447654, z=(0.26551724137931054+1.024137931034483j), expected=(-11.250200011017546+12.597393659160472j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=-7.5, b=8.5, c=16.088264119063613, z=(0.26551724137931054+1.024137931034483j), expected=(-0.18515160890991517+0.7959014164484782j), rtol=1e-15, ), ), pytest.param( Hyp2f1TestCase( a=-7.5, b=16.5, c=-3.9316537064827854, z=(0.3413793103448277-1.024137931034483j), expected=(998246378.8556538+1112032928.103645j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=-1.5, b=-3.5, c=2.050308316530781, z=(0.03793103448275881+1.024137931034483j), expected=(0.5527670397711952+2.697662715303637j), rtol=1e-15, ), ), pytest.param( Hyp2f1TestCase( a=-15.5, b=-1.5, c=-0.9629749245209605, z=(0.4931034482758623-0.8724137931034484j), expected=(55.396931662136886+968.467463806326j), rtol=5e-14, ), ), ] ) def test_region5(self, hyp2f1_test_case): """1 < |z| < 1.1 and |1 - z| >= 0.9 and real(z) >= 0""" a, b, c, z, expected, rtol = hyp2f1_test_case assert 1 < abs(z) < 1.1 and abs(1 - z) >= 0.9 and z.real >= 0 assert_allclose(hyp2f1(a, b, c, z), expected, rtol=rtol) # Marked as slow so it won't run by default. @pytest.mark.slow @check_version(mpmath, "1.0.0") def test_test_hyp2f1(self): """Test that expected values match what is computed by mpmath. This gathers the parameters for the test cases out of the pytest marks. The parameters are a, b, c, z, expected, rtol, where expected should be the value of hyp2f1(a, b, c, z) computed with mpmath. The test recomputes hyp2f1(a, b, c, z) using mpmath and verifies that expected actually is the correct value. This allows the data for the tests to live within the test code instead of an external datafile, while avoiding having to compute the results with mpmath during the test, except for when slow tests are being run. """ test_methods = [ test_method for test_method in dir(self) if test_method.startswith('test') and # Filter properties and attributes (futureproofing). callable(getattr(self, test_method)) and # Filter out this test test_method != 'test_test_hyp2f1' ] for test_method in test_methods: params = self._get_test_parameters(getattr(self, test_method)) for a, b, c, z, expected, _ in params: assert_allclose(mp_hyp2f1(a, b, c, z), expected, rtol=2.25e-16) def _get_test_parameters(self, test_method): """Get pytest.mark parameters for a test in this class.""" return [ case.values[0] for mark in test_method.pytestmark if mark.name == 'parametrize' for case in mark.args[1] ]