"""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, ), ), pytest.param( Hyp2f1TestCase( a=-2, b=1.2, c=-4, z=1 + 0j, expected=1.8200000000000001 + 0j, rtol=1e-15, ), ), ] ) 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, ), ), # Note that here even mpmath produces different results for # results that should be equivalent. pytest.param( Hyp2f1TestCase( a=9.2, b=621.5, c=700.1, z=(1+0j), expected=(952726652.4158565+0j), rtol=5e-13, ), ), pytest.param( Hyp2f1TestCase( a=621.5, b=9.2, c=700.1, z=(1+0j), expected=(952726652.4160284+0j), rtol=5e-12, ), ), pytest.param( Hyp2f1TestCase( a=-101.2, b=-400.4, c=-172.1, z=(1+0j), expected=(2.2253618341394838e+37+0j), rtol=1e-13, ), ), pytest.param( Hyp2f1TestCase( a=-400.4, b=-101.2, c=-172.1, z=(1+0j), expected=(2.2253618341394838e+37+0j), rtol=5e-13, ), ), pytest.param( Hyp2f1TestCase( a=172.5, b=-201.3, c=151.2, z=(1+0j), expected=(7.072266653650905e-135+0j), rtol=5e-13, ), ), pytest.param( Hyp2f1TestCase( a=-201.3, b=172.5, c=151.2, z=(1+0j), expected=(7.072266653650905e-135+0j), rtol=5e-13, ), ), pytest.param( Hyp2f1TestCase( a=-102.1, b=-20.3, c=1.3, z=1 + 0j, expected=2.7899070752746906e22 + 0j, rtol=3e-14, ), ), 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=3e-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, ), ), pytest.param( Hyp2f1TestCase( a=16.087593263474208, b=16.088264119063613, c=2.0397202577726152, z=(-0.9473684210526316-0.3157894736842106j), expected=(6.564549348474962e-07+1.6761570598334562e-06j), rtol=5e-09, ), ), pytest.param( Hyp2f1TestCase( a=1.0272592605282642, b=2.050308316530781, c=16.056809865262608, z=(-0.10526315789473695-0.10526315789473695j), expected=(0.9862043298997204-0.013293151372712681j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=4.080187217753502, b=8.077282662161238, c=16.056809865262608, z=(-0.3157894736842106-0.736842105263158j), expected=(0.16163826638754716-0.41378530376373734j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=2.02764642551431, b=2.050308316530781, c=-0.906685989801748, z=(-0.5263157894736843+0.3157894736842106j), expected=(-6.256871535165936+0.13824973858225484j), rtol=1e-15, ), ), pytest.param( Hyp2f1TestCase( a=2.02764642551431, b=8.077282662161238, c=-3.9924618758357022, z=(-0.9473684210526316-0.3157894736842106j), expected=(75.54672526086316+50.56157041797548j), rtol=5e-12, ), ), pytest.param( Hyp2f1TestCase( a=16.087593263474208, b=8.077282662161238, c=-1.9631175993998025, z=(-0.5263157894736843+0.5263157894736841j), expected=(282.0602536306534-82.31597306936214j), rtol=5e-13, ), ), pytest.param( Hyp2f1TestCase( a=8.095813935368371, b=-3.9316537064827854, c=8.031683612216888, z=(-0.5263157894736843-0.10526315789473695j), expected=(5.179603735575851+1.4445374002099813j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=4.080187217753502, b=-7.949900487447654, c=1.0651378143226575, z=(-0.3157894736842106-0.9473684210526316j), expected=(2317.623517606141-269.51476321010324j), rtol=5e-13, ), ), pytest.param( Hyp2f1TestCase( a=16.087593263474208, b=-1.92872979730171, c=2.0397202577726152, z=(-0.736842105263158-0.3157894736842106j), expected=(29.179154096175836+22.126690357535043j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=8.095813935368371, b=-3.9316537064827854, c=-15.963511401609862, z=(-0.736842105263158-0.10526315789473695j), expected=(0.20820247892032057-0.04763956711248794j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=1.0272592605282642, b=-15.964218273004214, c=-1.9631175993998025, z=(-0.3157894736842106-0.5263157894736843j), expected=(-157471.63920142158+991294.0587828817j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=8.095813935368371, b=-7.949900487447654, c=-7.93846038215665, z=(-0.10526315789473695-0.10526315789473695j), expected=(0.30765349653210194-0.2979706363594157j), rtol=1e-15, ), ), pytest.param( Hyp2f1TestCase( a=-3.956227226099288, b=1.0561196186065624, c=8.031683612216888, z=(-0.9473684210526316-0.10526315789473695j), expected=(1.6787607400597109+0.10056620134616838j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=-7.937789122896016, b=16.088264119063613, c=4.078873014294075, z=(-0.5263157894736843-0.736842105263158j), expected=(7062.07842506049-12768.77955655703j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=-7.937789122896016, b=16.088264119063613, c=2.0397202577726152, z=(-0.3157894736842106+0.7368421052631575j), expected=(54749.216391029935-23078.144720887536j), rtol=2e-15, ), ), pytest.param( Hyp2f1TestCase( a=-3.956227226099288, b=1.0561196186065624, c=-0.906685989801748, z=(-0.10526315789473695-0.10526315789473695j), expected=(1.21521766411428-4.449385173946672j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=-15.980848054962111, b=4.0013768449590685, c=-1.9631175993998025, z=(-0.736842105263158+0.5263157894736841j), expected=(19234693144.196907+1617913967.7294445j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=-1.9214641416286231, b=1.0561196186065624, c=-15.963511401609862, z=(-0.5263157894736843+0.3157894736842106j), expected=(0.9345201094534371+0.03745712558992195j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=-7.937789122896016, b=-0.9629749245209605, c=2.0397202577726152, z=(-0.10526315789473695+0.10526315789473673j), expected=(0.605732446296829+0.398171533680972j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=-1.9214641416286231, b=-15.964218273004214, c=2.0397202577726152, z=(-0.10526315789473695-0.5263157894736843j), expected=(-9.753761888305416-4.590126012666959j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=-3.956227226099288, b=-1.92872979730171, c=2.0397202577726152, z=(-0.10526315789473695+0.3157894736842106j), expected=(0.45587226291120714+1.0694545265819797j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=-0.9220024191881196, b=-7.949900487447654, c=-0.906685989801748, z=(-0.736842105263158+0.3157894736842106j), expected=(12.334808243233418-76.26089051819054j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=-0.9220024191881196, b=-7.949900487447654, c=-15.963511401609862, z=(-0.5263157894736843+0.10526315789473673j), expected=(1.2396019687632678-0.047507973161146286j), rtol=1e-14, ), ), pytest.param( Hyp2f1TestCase( a=-15.980848054962111, b=-0.9629749245209605, c=-0.906685989801748, z=(-0.3157894736842106-0.5263157894736843j), expected=(97.7889554372208-18.999754543400016j), rtol=5e-13, ), ), ] ) 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=-3.75, c=-3.5, z=(0.5263157894736841+0.7368421052631575j), expected=(-1279.4894322256655-2302.914821389276j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=-15.75, b=8.25, c=-1.5, z=(0.9473684210526314+0.3157894736842106j), expected=(-8889.452798586273-11961.162305065242j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=2.25, b=2.25, c=-1.5, z=(0.5263157894736841-0.736842105263158j), expected=(-236.58971357952055-238.5228224781136j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=-0.75, b=-7.75, c=-15.5, z=(0.5263157894736841+0.7368421052631575j), expected=(0.8116076584352279-0.29360565398246036j), rtol=5e-16, ), ), pytest.param( Hyp2f1TestCase( a=1.25, b=4.25, c=-0.5, z=(0.5263157894736841-0.736842105263158j), expected=(-28.119407485189985+98.89858821348005j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=-0.75, b=2.25, c=1.5, z=(0.5263157894736841+0.7368421052631575j), expected=(0.5311049067450484-0.9434347326448517j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=8.25, b=-15.75, c=-7.5, z=(0.9473684210526314+0.10526315789473673j), expected=(1262084.378141873+1775569.6338380123j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=-15.75, b=-7.75, c=-15.5, z=(0.5263157894736841-0.736842105263158j), expected=(-0.009810480794804165+0.3648997569257999j), rtol=1e-15, ), ), pytest.param( Hyp2f1TestCase( a=8.25, b=2.25, c=-3.5, z=(0.5263157894736841-0.736842105263158j), expected=(585660.8815535795-33646.68398590896j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=4.080187217753502, b=-3.9316537064827854, c=-15.963511401609862, z=(0.9473684210526314-0.10526315789473695j), expected=(181899621848365.2-173207123998705.7j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=-15.75, b=8.25, c=-0.5, z=(0.9473684210526314-0.10526315789473695j), expected=(0.04271686244952705-0.14087902824639406j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=-7.937789122896016, b=-1.92872979730171, c=-0.906685989801748, z=(0.9473684210526314-0.3157894736842106j), expected=(-449.5119088817207+320.1423128036188j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=-3.956227226099288, b=1.0561196186065624, c=8.031683612216888, z=(0.9473684210526314-0.10526315789473695j), expected=(0.6361479738012501+0.028575620091205088j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=4.25, b=16.25, c=16.5, z=(0.5263157894736841+0.7368421052631575j), expected=(-0.9038811840552261-1.5356250756164884j), rtol=1e-8, ), marks=pytest.mark.xfail( reason="Unhandled parameters." ) ), pytest.param( Hyp2f1TestCase( a=8.25, b=-1.75, c=-1.5, z=(0.9473684210526314+0.3157894736842106j), expected=(653.0109150415394-4554.162605155542j), rtol=1e-15, ), ), pytest.param( Hyp2f1TestCase( a=-15.75, b=-3.75, c=4.5, z=(0.9473684210526314-0.10526315789473695j), expected=(118.7009859241035-34.18713648654642j), rtol=1e-15, ), ), pytest.param( Hyp2f1TestCase( a=4.25, b=-15.75, c=-3.5, z=(0.5263157894736841+0.7368421052631575j), expected=(-540204.4774526551+4970059.109251281j), rtol=1e-14, ), ), pytest.param( Hyp2f1TestCase( a=8.25, b=-15.75, c=-0.5, z=(0.5263157894736841-0.736842105263158j), expected=(2253490.972258385+3318620.683390017j), rtol=5e-13, ), ), pytest.param( Hyp2f1TestCase( a=16.25, b=-7.75, c=-7.5, z=(0.9473684210526314+0.3157894736842106j), expected=(-46159826.46716958-17880663.82218242j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=-0.9220024191881196, b=-7.949900487447654, c=-7.93846038215665, z=(0.9473684210526314-0.10526315789473695j), expected=(0.07116833581404514+0.11823358038036977j), rtol=5e-13, ), ), pytest.param( Hyp2f1TestCase( a=16.087593263474208, b=4.0013768449590685, c=-7.93846038215665, z=(0.7368421052631575+0.5263157894736841j), expected=(4.7724909620664006e+17-6.039064078946702e+16j), rtol=5e-13, ), ), pytest.param( Hyp2f1TestCase( a=1.25, b=-7.75, c=1.5, z=(0.9473684210526314-0.10526315789473695j), expected=(0.0188022179759303+0.002921737281641378j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=1.0272592605282642, b=1.0561196186065624, c=-7.93846038215665, z=(0.7368421052631575-0.5263157894736843j), expected=(-9203.462928334846+12390.110518017136j), rtol=5e-13, ), ), pytest.param( Hyp2f1TestCase( a=-3.75, b=-15.75, c=8.5, z=(0.7368421052631575+0.5263157894736841j), expected=(6.468457061368628+24.190040684917374j), rtol=5e-16, ), ), pytest.param( Hyp2f1TestCase( a=2.02764642551431, b=16.088264119063613, c=2.0397202577726152, z=(0.7368421052631575+0.5263157894736841j), expected=(2408.3451340186543-4275.257316636014j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=-3.75, b=-7.75, c=8.5, z=(0.7368421052631575-0.5263157894736843j), expected=(4.1379984626381345-5.183654781039423j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=8.25, b=-7.75, c=-0.5, z=(0.5263157894736841+0.7368421052631575j), expected=(-81177.775295738+56079.73286548954j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=4.080187217753502, b=2.050308316530781, c=-0.906685989801748, z=(0.9473684210526314+0.3157894736842106j), expected=(1192868.5068926765+3624210.8182139914j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=-7.937789122896016, b=-1.92872979730171, c=8.031683612216888, z=(0.5263157894736841+0.7368421052631575j), expected=(1.8286341846195202+1.9295255682312178j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=1.0272592605282642, b=1.0561196186065624, c=16.056809865262608, z=(0.7368421052631575-0.5263157894736843j), expected=(1.0514645669696452-0.0430834059440128j), rtol=5e-10, ), ), pytest.param( Hyp2f1TestCase( a=16.087593263474208, b=-15.964218273004214, c=2.0397202577726152, z=(0.5263157894736841+0.7368421052631575j), expected=(541983.236432269+288200.2043029435j), rtol=5e-13, ), ), pytest.param( Hyp2f1TestCase( a=2.25, b=8.25, c=1.5, z=(0.5263157894736841-0.736842105263158j), expected=(-10.931988086039945+1.9136272843579096j), rtol=1e-15, ), ), ] ) def test_region3(self, hyp2f1_test_case): """0.9 <= |z| <= 1 and |1 - z| < 0.9.""" 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=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=5e-9, ), ), 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=5e-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=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=-15.5, b=1.0561196186065624, c=-7.5, z=(0.4172413793103451+0.8724137931034486j), expected=(133306.45260685298+256510.7045225382j), rtol=5e-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=5e-14, ), ), 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=5e-14, ), ), 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=1.4e-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=2e-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=5e-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=5e-12, ), ), 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=2e-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=1.2e-15, # rtol bumped from 1e-15 in gh18414 ), ), 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) @pytest.mark.parametrize( "hyp2f1_test_case", [ pytest.param( Hyp2f1TestCase( a=8.095813935368371, b=4.0013768449590685, c=4.078873014294075, z=(-0.9473684210526316+0.5263157894736841j), expected=(-0.0018093573941378783+0.003481887377423739j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=16.087593263474208, b=2.050308316530781, c=1.0651378143226575, z=(-0.736842105263158-0.736842105263158j), expected=(-0.00023401243818780545-1.7983496305603562e-05j), rtol=1e-15, ), ), pytest.param( Hyp2f1TestCase( a=1.0272592605282642, b=8.077282662161238, c=4.078873014294075, z=(-0.5263157894736843-0.9473684210526316j), expected=(0.22359773002226846-0.24092487123993353j), rtol=1e-15, ), ), pytest.param( Hyp2f1TestCase( a=1.0272592605282642, b=2.050308316530781, c=-15.963511401609862, z=(-0.9473684210526316-0.5263157894736843j), expected=(1.191573745740011+0.14347394589721466j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=4.080187217753502, b=4.0013768449590685, c=-15.963511401609862, z=(-0.9473684210526316-0.5263157894736843j), expected=(31.822620756901784-66.09094396747611j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=4.080187217753502, b=8.077282662161238, c=-7.93846038215665, z=(-0.9473684210526316+0.5263157894736841j), expected=(207.16750179245952+34.80478274924269j), rtol=5e-12, ), ), pytest.param( Hyp2f1TestCase( a=8.095813935368371, b=-7.949900487447654, c=8.031683612216888, z=(-0.736842105263158+0.7368421052631575j), expected=(-159.62429364277145+9.154224290644898j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=1.0272592605282642, b=-1.92872979730171, c=16.056809865262608, z=(-0.9473684210526316+0.5263157894736841j), expected=(1.121122351247184-0.07170260470126685j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=16.087593263474208, b=-0.9629749245209605, c=16.056809865262608, z=(-0.9473684210526316+0.5263157894736841j), expected=(1.9040596681316053-0.4951799449960107j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=1.0272592605282642, b=-1.92872979730171, c=-0.906685989801748, z=(-0.9473684210526316-0.5263157894736843j), expected=(-14.496623497780739-21.897524523299875j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=4.080187217753502, b=-3.9316537064827854, c=-3.9924618758357022, z=(-0.5263157894736843-0.9473684210526316j), expected=(36.33473466026878+253.88728442029577j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=1.0272592605282642, b=-15.964218273004214, c=-0.906685989801748, z=(-0.9473684210526316+0.5263157894736841j), expected=(1505052.5653144997-50820766.81043443j), rtol=1e-14, ), ), pytest.param( Hyp2f1TestCase( a=-3.956227226099288, b=4.0013768449590685, c=1.0651378143226575, z=(-0.5263157894736843+0.9473684210526314j), expected=(-127.79407519260877-28.69899444941112j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=-1.9214641416286231, b=8.077282662161238, c=16.056809865262608, z=(-0.9473684210526316-0.5263157894736843j), expected=(2.0623331933754976+0.741234463565458j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=-3.956227226099288, b=8.077282662161238, c=2.0397202577726152, z=(-0.9473684210526316+0.5263157894736841j), expected=(30.729193458862525-292.5700835046965j), rtol=1e-15, ), ), pytest.param( Hyp2f1TestCase( a=-1.9214641416286231, b=1.0561196186065624, c=-1.9631175993998025, z=(-0.5263157894736843-0.9473684210526316j), expected=(1.1285917906203495-0.735264575450189j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=-0.9220024191881196, b=1.0561196186065624, c=-3.9924618758357022, z=(-0.736842105263158+0.7368421052631575j), expected=(0.6356474446678052-0.02429663008952248j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=-1.9214641416286231, b=16.088264119063613, c=-7.93846038215665, z=(-0.736842105263158+0.7368421052631575j), expected=(0.4718880510273174+0.655083067736377j), rtol=1e-11, ), ), pytest.param( Hyp2f1TestCase( a=-7.937789122896016, b=-3.9316537064827854, c=16.056809865262608, z=(-0.9473684210526316+0.5263157894736841j), expected=(-0.14681550942352714+0.16092206364265146j), rtol=5e-11, ), ), pytest.param( Hyp2f1TestCase( a=-0.9220024191881196, b=-15.964218273004214, c=1.0651378143226575, z=(-0.5263157894736843+0.9473684210526314j), expected=(-6.436835190526225+22.883156700606182j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=-0.9220024191881196, b=-7.949900487447654, c=4.078873014294075, z=(-0.9473684210526316-0.5263157894736843j), expected=(-0.7505682955068583-1.1026583264249945j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=-3.956227226099288, b=-3.9316537064827854, c=-7.93846038215665, z=(-0.9473684210526316-0.5263157894736843j), expected=(3.6247814989198166+2.596041360148318j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=-3.956227226099288, b=-15.964218273004214, c=-1.9631175993998025, z=(-0.5263157894736843-0.9473684210526316j), expected=(-59537.65287927933-669074.4342539902j), rtol=5e-15, ), ), pytest.param( Hyp2f1TestCase( a=-3.956227226099288, b=-15.964218273004214, c=-1.9631175993998025, z=(-0.9473684210526316-0.5263157894736843j), expected=(-433084.9970266166+431088.393918521j), rtol=5e-14, ), ), pytest.param( Hyp2f1TestCase( a=1, b=1, c=4, z=(3 + 4j), expected=(0.49234384000963544+0.6051340616612397j), rtol=5e-14, ), ), ] ) def test_region6(self, hyp2f1_test_case): """|z| > 1 but not in region 5.""" a, b, c, z, expected, rtol = hyp2f1_test_case assert ( abs(z) > 1 and not (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) @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] ]