def VonMisesFisher_sample(phi0, theta0, sigma0, size=None): """ Draw a sample from the Von-Mises Fisher distribution. Parameters ---------- phi0, theta0 : float or array-like Spherical-polar coordinates of the center of the distribution. sigma0 : float Width of the distribution. size : int, tuple, array-like number of samples to draw. Returns ------- phi, theta : float or array_like Spherical-polar coordinates of sample from distribution. """ n0 = cartesian_from_polar(phi0, theta0) M = rotation_matrix([0, 0, 1], n0) x = numpy.random.uniform(size=size) phi = numpy.random.uniform(size=size) * 2 * numpy.pi theta = numpy.arccos(1 + sigma0**2 * numpy.log(1 + (numpy.exp(-2 / sigma0**2) - 1) * x)) n = cartesian_from_polar(phi, theta) x = M.dot(n) phi, theta = polar_from_cartesian(x) return phi, theta
def VonMisesFisher_distribution(phi, theta, phi0, theta0, sigma0): """ Von-Mises Fisher distribution function. Parameters ---------- phi, theta : float or array_like Spherical-polar coordinates to evaluate function at. phi0, theta0 : float or array-like Spherical-polar coordinates of the center of the distribution. sigma0 : float Width of the distribution. Returns ------- float or array_like log-probability of the vonmises fisher distribution. Notes ----- Wikipedia: https://en.wikipedia.org/wiki/Von_Mises-Fisher_distribution """ x = cartesian_from_polar(phi, theta) x0 = cartesian_from_polar(phi0, theta0) norm = -numpy.log(4 * numpy.pi * sigma0**2) - logsinh(1. / sigma0**2) return norm + numpy.tensordot(x, x0, axes=[[0], [0]]) / sigma0**2
def test_rotation_matrix(): numpy.random.seed(seed=0) theta = numpy.random.rand(10, 2)*numpy.pi phi = numpy.random.rand(10, 2)*2*numpy.pi for (p1, p2), (t1, t2) in zip(phi, theta): n1 = utils.cartesian_from_polar(p1, t1) n2 = utils.cartesian_from_polar(p2, t2) M = utils.rotation_matrix(n1, n2) assert_allclose(M.dot(n1), n2) assert_allclose(M.T.dot(n2), n1) M = utils.rotation_matrix(n1, n1) assert_allclose(M, numpy.identity(3))
def VonMises_std(phi, theta): """ Von-Mises sample standard deviation. Parameters ---------- phi, theta : array-like Spherical-polar coordinate samples to compute mean from. Returns ------- solution for ..math:: 1/tanh(x) - 1/x = R, where ..math:: R = || \sum_i^N x_i || / N Notes ----- Wikipedia: https://en.wikipedia.org/wiki/Von_Mises-Fisher_distribution#Estimation_of_parameters but re-parameterised for sigma rather than kappa. """ x = cartesian_from_polar(phi, theta) S = numpy.sum(x, axis=-1) R = S.dot(S)**0.5 / x.shape[-1] def f(s): return 1 / numpy.tanh(s) - 1. / s - R kappa = scipy.optimize.brentq(f, 1e-8, 1e8) sigma = kappa**-0.5 return sigma
def VonMises_mean(phi, theta): """ Von-Mises sample mean. Parameters ---------- phi, theta : array-like Spherical-polar coordinate samples to compute mean from. Returns ------- float ..math:: \sum_i^N x_i / || \sum_i^N x_i || Notes ----- Wikipedia: https://en.wikipedia.org/wiki/Von_Mises-Fisher_distribution#Estimation_of_parameters """ x = cartesian_from_polar(phi, theta) S = numpy.sum(x, axis=-1) phi, theta = polar_from_cartesian(S) return phi, theta
def test_cartesian_from_polar_array(): cart1 = utils.cartesian_from_polar(*test_polar.T) assert_allclose(test_cartesian.T, cart1)
def test_cartesian_from_polar_scalar(): for ang, cart0 in zip(test_polar, test_cartesian): cart1 = utils.cartesian_from_polar(*ang) assert_allclose(cart0, cart1)
def g(phi, theta): return f(phi, theta) * cartesian_from_polar(phi, theta)[i]