def test_manualintegrate_orthogonal_poly(): n = symbols('n') a, b = 7, Rational(5, 3) polys = [jacobi(n, a, b, x), gegenbauer(n, a, x), chebyshevt(n, x), chebyshevu(n, x), legendre(n, x), hermite(n, x), laguerre(n, x), assoc_laguerre(n, a, x)] for p in polys: integral = manualintegrate(p, x) for deg in [-2, -1, 0, 1, 3, 5, 8]: # some accept negative "degree", some do not try: p_subbed = p.subs(n, deg) except ValueError: continue assert (integral.subs(n, deg).diff(x) - p_subbed).expand() == 0 # can also integrate simple expressions with these polynomials q = x*p.subs(x, 2*x + 1) integral = manualintegrate(q, x) for deg in [2, 4, 7]: assert (integral.subs(n, deg).diff(x) - q.subs(n, deg)).expand() == 0 # cannot integrate with respect to any other parameter t = symbols('t') for i in range(len(p.args) - 1): new_args = list(p.args) new_args[i] = t assert isinstance(manualintegrate(p.func(*new_args), t), Integral)
def wigner_d_naive_v2(l, m, n, beta): """ Wigner d functions as defined in the SOFT 2.0 documentation. When approx_lim is set to a high value, this function appears to give identical results to Johann Goetz' wignerd() function. However, integration fails: does not satisfy orthogonality relations everywhere... """ from scipy.special import jacobi if n >= m: xi = 1 else: xi = (-1)**(n - m) mu = np.abs(m - n) nu = np.abs(n + m) s = l - (mu + nu) * 0.5 sq = np.sqrt((np.math.factorial(s) * np.math.factorial(s + mu + nu)) / (np.math.factorial(s + mu) * np.math.factorial(s + nu))) sinb = np.sin(beta * 0.5)**mu cosb = np.cos(beta * 0.5)**nu P = jacobi(s, mu, nu)(np.cos(beta)) return xi * sq * sinb * cosb * P
def wigner_d_naive(l, m, n, beta): """ Numerically naive implementation of the Wigner-d function. This is useful for checking the correctness of other implementations. :param l: the degree of the Wigner-d function. l >= 0 :param m: the order of the Wigner-d function. -l <= m <= l :param n: the order of the Wigner-d function. -l <= n <= l :param beta: the argument. 0 <= beta <= pi :return: d^l_mn(beta) in the TODO: what basis? complex, quantum(?), centered, cs(?) """ from scipy.special import eval_jacobi try: from scipy.misc import factorial except: from scipy.special import factorial from sympy.functions.special.polynomials import jacobi, jacobi_normalized from sympy.abc import j, a, b, x from sympy import N #jfun = jacobi_normalized(j, a, b, x) jfun = jacobi(j, a, b, x) # eval_jacobi = lambda q, r, p, o: float(jfun.eval(int(q), int(r), int(p), float(o))) # eval_jacobi = lambda q, r, p, o: float(N(jfun, int(q), int(r), int(p), float(o))) eval_jacobi = lambda q, r, p, o: float( jfun.subs({ j: int(q), a: int(r), b: int(p), x: float(o) })) mu = np.abs(m - n) nu = np.abs(m + n) s = l - (mu + nu) / 2 xi = 1 if n >= m else (-1)**(n - m) # print(s, mu, nu, np.cos(beta), type(s), type(mu), type(nu), type(np.cos(beta))) jac = eval_jacobi(s, mu, nu, np.cos(beta)) z = np.sqrt((factorial(s) * factorial(s + mu + nu)) / (factorial(s + mu) * factorial(s + nu))) # print(l, m, n, beta, np.isfinite(mu), np.isfinite(nu), np.isfinite(s), np.isfinite(xi), np.isfinite(jac), np.isfinite(z)) assert np.isfinite(mu) and np.isfinite(nu) and np.isfinite( s) and np.isfinite(xi) and np.isfinite(jac) and np.isfinite(z) assert np.isfinite(xi * z * np.sin(beta / 2)**mu * np.cos(beta / 2)**nu * jac) return xi * z * np.sin(beta / 2)**mu * np.cos(beta / 2)**nu * jac
def test_jacobi(): n = Symbol("n") a = Symbol("a") b = Symbol("b") assert jacobi(0, a, b, x) == 1 assert jacobi(1, a, b, x) == a / 2 - b / 2 + x * (a / 2 + b / 2 + 1) assert jacobi(n, a, a, x) == RisingFactorial(a + 1, n) * gegenbauer( n, a + S.Half, x) / RisingFactorial(2 * a + 1, n) assert jacobi(n, a, -a, x) == ((-1)**a * (-x + 1)**(-a / 2) * (x + 1)**(a / 2) * assoc_legendre(n, a, x) * factorial(-a + n) * gamma(a + n + 1) / (factorial(a + n) * gamma(n + 1))) assert jacobi(n, -b, b, x) == ((-x + 1)**(b / 2) * (x + 1)**(-b / 2) * assoc_legendre(n, b, x) * gamma(-b + n + 1) / gamma(n + 1)) assert jacobi(n, 0, 0, x) == legendre(n, x) assert jacobi(n, S.Half, S.Half, x) == RisingFactorial(Rational( 3, 2), n) * chebyshevu(n, x) / factorial(n + 1) assert jacobi( n, Rational(-1, 2), Rational(-1, 2), x) == RisingFactorial(S.Half, n) * chebyshevt(n, x) / factorial(n) X = jacobi(n, a, b, x) assert isinstance(X, jacobi) assert jacobi(n, a, b, -x) == (-1)**n * jacobi(n, b, a, x) assert jacobi(n, a, b, 0) == 2**(-n) * gamma(a + n + 1) * hyper( (-b - n, -n), (a + 1, ), -1) / (factorial(n) * gamma(a + 1)) assert jacobi(n, a, b, 1) == RisingFactorial(a + 1, n) / factorial(n) m = Symbol("m", positive=True) assert jacobi(m, a, b, oo) == oo * RisingFactorial(a + b + m + 1, m) assert unchanged(jacobi, n, a, b, oo) assert conjugate(jacobi(m, a, b, x)) == \ jacobi(m, conjugate(a), conjugate(b), conjugate(x)) _k = Dummy('k') assert diff(jacobi(n, a, b, x), n) == Derivative(jacobi(n, a, b, x), n) assert diff(jacobi(n, a, b, x), a).dummy_eq( Sum((jacobi(n, a, b, x) + (2 * _k + a + b + 1) * RisingFactorial(_k + b + 1, -_k + n) * jacobi(_k, a, b, x) / ((-_k + n) * RisingFactorial(_k + a + b + 1, -_k + n))) / (_k + a + b + n + 1), (_k, 0, n - 1))) assert diff(jacobi(n, a, b, x), b).dummy_eq( Sum(((-1)**(-_k + n) * (2 * _k + a + b + 1) * RisingFactorial(_k + a + 1, -_k + n) * jacobi(_k, a, b, x) / ((-_k + n) * RisingFactorial(_k + a + b + 1, -_k + n)) + jacobi(n, a, b, x)) / (_k + a + b + n + 1), (_k, 0, n - 1))) assert diff(jacobi(n, a, b, x), x) == \ (a/2 + b/2 + n/2 + S.Half)*jacobi(n - 1, a + 1, b + 1, x) assert jacobi_normalized(n, a, b, x) == \ (jacobi(n, a, b, x)/sqrt(2**(a + b + 1)*gamma(a + n + 1)*gamma(b + n + 1) /((a + b + 2*n + 1)*factorial(n)*gamma(a + b + n + 1)))) raises(ValueError, lambda: jacobi(-2.1, a, b, x)) raises(ValueError, lambda: jacobi(Dummy(positive=True, integer=True), 1, 2, oo)) assert jacobi(n, a, b, x).rewrite("polynomial").dummy_eq( Sum((S.Half - x / 2)**_k * RisingFactorial(-n, _k) * RisingFactorial(_k + a + 1, -_k + n) * RisingFactorial(a + b + n + 1, _k) / factorial(_k), (_k, 0, n)) / factorial(n)) raises(ArgumentIndexError, lambda: jacobi(n, a, b, x).fdiff(5))
def wigner_d_naive_v3(l, m, n, approx_lim=1000000): """ Wigner "small d" matrix. (Euler z-y-z convention) example: l = 2 m = 1 n = 0 beta = linspace(0,pi,100) wd210 = wignerd(l,m,n)(beta) some conditions have to be met: l >= 0 -l <= m <= l -l <= n <= l The approx_lim determines at what point bessel functions are used. Default is when: l > m+10 and l > n+10 for integer l and n=0, we can use the spherical harmonics. If in addition m=0, we can use the ordinary legendre polynomials. """ from scipy.special import jv, legendre, sph_harm, jacobi from scipy.misc import factorial, comb from numpy import floor, sqrt, sin, cos, exp, power from math import pi from scipy.special import jacobi if (l < 0) or (abs(m) > l) or (abs(n) > l): raise ValueError("wignerd(l = {0}, m = {1}, n = {2}) value error.".format(l, m, n) \ + " Valid range for parameters: l>=0, -l<=m,n<=l.") if (l > (m + approx_lim)) and (l > (n + approx_lim)): #print 'bessel (approximation)' return lambda beta: jv(m - n, l * beta) if (floor(l) == l) and (n == 0): if m == 0: #print 'legendre (exact)' return lambda beta: legendre(l)(cos(beta)) elif False: #print 'spherical harmonics (exact)' a = sqrt(4. * pi / (2. * l + 1.)) return lambda beta: a * sph_harm(m, l, beta, 0.).conj() jmn_terms = { l + n: (m - n, m - n), l - n: (n - m, 0.), l + m: (n - m, 0.), l - m: (m - n, m - n), } k = min(jmn_terms) a, lmb = jmn_terms[k] b = 2. * l - 2. * k - a if (a < 0) or (b < 0): raise ValueError("wignerd(l = {0}, m = {1}, n = {2}) value error.".format(l, m, n) \ + " Encountered negative values in (a,b) = ({0},{1})".format(a,b)) coeff = power(-1., lmb) * sqrt(comb(2. * l - k, k + a)) * (1. / sqrt(comb(k + b, b))) #print 'jacobi (exact)' return lambda beta: coeff \ * power(sin(0.5*beta),a) \ * power(cos(0.5*beta),b) \ * jacobi(k,a,b)(cos(beta))