Improve numerical stability of conditional_ppf
Improve the numerical stability of the method
ligo.skymap.distance.conditional_ppf
by reparametrizing the equation
that is being solved. This method, which calculates the inverse of the
distance CDF, works by solving the equation f(x) - p = 0
for x
,
where f(x)
is the distance CDF, and p
is the desired probability.
The reparametrized equation is log(1 - f(x)) - log(1 - p) = 0
if p > 1/2
and log(f(x)) - log(p) = 0
otherwise. This reparametrization is
effective because it improves the dynamic range in the tails of the
distribution. This same reparametrization had already proven effective
in the related method ligo.skymap.distance.marginal_ppf
.
This change also fixes some rare corner cases where marginal_ppf
returned silly values becauses it uses conditional_ppf
internally to
create its own initial guess. One example was the median distance for
the binary neutron star candidate S191205ah. Before this patch, the
result was negative and invalid:
>>> from ligo.skymap.distance import marginal_ppf
>>> from ligo.skymap.moc import uniq2pixarea
>>> from ligo.skymap.io import read_sky_map
>>> url = 'https://gracedb.ligo.org/apiweb/superevents/S191205ah/files/bayestar.multiorder.fits'
>>> s = read_sky_map(url, moc=True)
>>> marginal_ppf(0.5, s['PROBDENSITY'] * uniq2pixarea(s['UNIQ']),
... s['DISTMU'], s['DISTSIGMA'], s['DISTNORM'])
/Users/lpsinger/src/ligo.skymap/ligo/skymap/util/numpy.py:46:
RuntimeWarning: invalid value encountered in marginal_ppf
return func(*args, **kwargs)
-223357.8508233767
After this patch, the result is positive and sensible:
>>> marginal_ppf(0.5, s['PROBDENSITY'] * uniq2pixarea(s['UNIQ']),
... s['DISTMU'], s['DISTSIGMA'], s['DISTNORM'])
362.7485740018039