Skip to content

Commit f3fcc90

Browse files
committed
Add a couple tests where 2F1 is singular
1 parent c68c1db commit f3fcc90

File tree

3 files changed

+30
-4
lines changed

3 files changed

+30
-4
lines changed

tests/test_hypergeo.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,3 +240,28 @@ def test_2f1_grad(self, muts, hyp2f1_func, pars):
240240
offset = self._2f1_validate(*pars)
241241
check = self._2f1_grad_validate(*pars, offset=offset)
242242
assert np.allclose(grad, check)
243+
244+
245+
@pytest.mark.parametrize(
246+
"pars",
247+
[
248+
# taken from examples in issues tsdate/286, tsdate/289
249+
[1.104, 0.0001125, 118.1396, 0.009052, 1.0, 0.001404],
250+
[2.7481, 0.001221, 344.94083, 0.02329, 3.0, 0.00026624],
251+
],
252+
)
253+
class TestSingular2F1:
254+
"""
255+
Test detection of cases where 2F1 is close to singular and DLMF 15.8.3
256+
suffers from catastrophic cancellation: in these cases, use DLMF 15.8.1
257+
even though it takes much longer to converge.
258+
"""
259+
260+
def test_dlmf1583_throws_exception(self, pars):
261+
with pytest.raises(Exception, match="is singular"):
262+
hypergeo._hyp2f1_dlmf1583(*pars)
263+
264+
def test_exception_uses_dlmf1581(self, pars):
265+
v1, *_ = hypergeo._hyp2f1(*pars)
266+
v2, *_ = hypergeo._hyp2f1_dlmf1581(*pars)
267+
assert np.isclose(v1, v2)

tsdate/approx.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,6 @@ def sufficient_statistics(a_i, b_i, a_j, b_j, y_ij, mu_ij):
121121
a_i, b_i, a_j, b_j, y_ij, mu_ij
122122
)
123123

124-
if sign_f <= 0:
125-
raise hypergeo.Invalid2F1("Singular hypergeometric function")
126-
127124
logconst = (
128125
log_f + hypergeo._betaln(y_ij + 1, b) + hypergeo._gammaln(a) - a * np.log(t)
129126
)
@@ -139,6 +136,10 @@ def sufficient_statistics(a_i, b_i, a_j, b_j, y_ij, mu_ij):
139136
- hypergeo._digamma(c)
140137
)
141138

139+
# check that Jensen's inequality holds
140+
assert np.log(t_i) > ln_t_i
141+
assert np.log(t_j) > ln_t_j
142+
142143
return logconst, t_i, ln_t_i, t_j, ln_t_j
143144

144145

tsdate/hypergeo.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ def _hyp2f1_dlmf1583(a_i, b_i, a_j, b_j, y, mu):
388388
)
389389
or sign <= 0
390390
):
391-
raise Invalid2F1("Hypergeometric series did not converge")
391+
raise Invalid2F1("Hypergeometric series is singular")
392392

393393
return val, sign, da_i, db_i, da_j, db_j
394394

0 commit comments

Comments
 (0)