def _combine_polyvals(self, coors, polyvals, idx): from scipy.special import eval_jacobi if len(idx) == 1: # 1D return nm.prod(polyvals[..., range(len(idx)), idx], axis=-1) elif len(idx) == 2: # 2D r = coors[..., 0] s = coors[..., 1] a = 2 * (1 + r) / (1 - s) - 1 a[nm.isnan(a)] = -1. b = s return eval_jacobi(idx[0], 0, 0, a) \ * eval_jacobi(idx[1],2 * idx[0] + 1, 0,b) * (1 - b) ** idx[0] elif len(idx) == 3: # 3D r = coors[..., 0] s = coors[..., 1] t = coors[..., 2] a = -2 * (1 + r) / (s + t) - 1 b = 2 * (1 + s) / (1 - t) - t c = t a[nm.isnan(a)] = -1. b[nm.isnan(b)] = -1. return eval_jacobi(idx[0], 0, 0, a) * \ eval_jacobi(idx[1], 2 * idx[0] + 1, 0, 0, b) * \ eval_jacobi(idx[2], 2 * idx[0] + 2 * idx[1] + 2, 0, c) * \ (1 - c) ** (idx[0] + idx[1])
def eval_poly_multiD(self, X, normalize='norm'): """Evaluate (and potentially normalize) multivariate Jacobi polynomials :math:`P_{k}(x) = \\prod_{i=1}^d P_{k_i}^{a_i, b_i}(x_i)` :param X: Array of points :math:`\\in [-1, 1]^d`, with size :math:`n\\times d` where :math:`n` is the number of points :type X: array_like :param normalize: - 'norm' - 'square_norm' :type normalize: str (default 'norm') :return: - ``normalize='norm'`` :math:`P_k(X) / \\left\\| P_k \\right\\|` - ``normalize='square_norm'`` :math:`P_k(X) / \\left\\| P_k \\right\\|^2` :rtype: array_like .. seealso:: - evaluation of the kernel :py:meth:`~dppy.multivariate_jacobi_ope.MultivariateJacobiOPE.K` """ if X.size == self.dim: poly_1D_jacobi = eval_jacobi(self.poly_1D_degrees, self.jacobi_params[:, 0], self.jacobi_params[:, 1], X) if normalize == 'square_norm': poly_1D_jacobi /= self.poly_1D_square_norms elif normalize == 'norm': poly_1D_jacobi /= np.sqrt(self.poly_1D_square_norms) else: pass return np.prod(poly_1D_jacobi[self.ordering, range(self.dim)], axis=1) else: poly_1D_jacobi = eval_jacobi(self.poly_1D_degrees, self.jacobi_params[:, 0], self.jacobi_params[:, 1], X[:, None]) if normalize == 'square_norm': poly_1D_jacobi /= self.poly_1D_square_norms elif normalize == 'norm': poly_1D_jacobi /= np.sqrt(self.poly_1D_square_norms) else: pass return np.prod(poly_1D_jacobi[:, self.ordering, range(self.dim)], axis=2)
def A(i, j, d): return quad( lambda x: (ks(i, d) * ((math.cos(x)) ** d) * eval_jacobi(i, 0.5 * d - 1, 0.5 * d, math.cos(2 * x))) * (ks(j, d) * ((math.cos(x)) ** d) * eval_jacobi(j, 0.5 * d - 1, 0.5 * d, math.cos(2 * x))) * math.sin(x) * math.cos(x), 0, math.pi / 2.0, )[0]
def __integrand(x1, x2, k1, k2, n, c, t, theta, m, weights): x1_eval = eval_jacobi(m, theta - 1, theta - 1, 2 * np.expand_dims(x1, -1) - 1) x2_eval = eval_jacobi(m, theta - 1, theta - 1, 2 * np.expand_dims(x2, -1) - 1) jacobi_total = np.sum(x2_eval * x1_eval * weights, axis=-1) bc1 = binom_cdf(k1, n, (1 - c) * x1 + c * x2) bc2 = binom_cdf(k2, n, c * x1 + (1 - c) * x2) return bc1 * bc2 * jacobi_total
def W10(i, j, k, l, d): return dblquad( lambda x, y: (ep(i, d)(x)) * (ep(j, d)(x)) * math.sin(x) * math.cos(x) * (ks(l, d) * ((math.cos(y)) ** d) * eval_jacobi(l, 0.5 * d - 1, 0.5 * d, math.cos(2 * y))) * (ks(k, d) * ((math.cos(y)) ** d) * eval_jacobi(k, 0.5 * d - 1, 0.5 * d, math.cos(2 * y))) * (math.tan(y)) ** (d - 1.0), 0, math.pi / 2, lambda x: 0, lambda x: x, )[0]
def test_jacobi(self): assert_mpmath_equal(sc.eval_jacobi, _exception_to_nan(lambda a, b, c, x: mpmath.jacobi(a, b, c, x, **HYPERKW)), [Arg(), Arg(), Arg(), Arg()]) assert_mpmath_equal(lambda n, b, c, x: sc.eval_jacobi(int(n), b, c, x), _exception_to_nan(lambda a, b, c, x: mpmath.jacobi(a, b, c, x, **HYPERKW)), [IntArg(), Arg(), Arg(), Arg()])
def calcWignerMatrices(self, rot): a,b,y = rot sinb2 = sin(b/2) cosb2 = cos(b/2) cosb = cos(b) sinb = sin(b) Jmax = self.Jmax Js, m1s, m2s = self.Js, self.m1s, self.m2s Ds = np.zeros((Jmax+1, 2*Jmax+1, 2*Jmax+1), np.complex128) grad = np.zeros((3, Jmax+1, 2*Jmax+1, 2*Jmax+1), np.complex128) mu = abs(m1s-m2s) nu = abs(m1s+m2s) s = Js - (mu + nu)/2 xi = np.ones_like(s) xi[m2s<m1s] = (-1)**(m1s-m2s)[m2s<m1s] factor = sqrt(factorial(s)*factorial(s+mu+nu)/ factorial(s+mu)/factorial(s+nu)) * xi jac = eval_jacobi(s, mu, nu, cosb) d = (factor * jac * sinb2 ** mu * cosb2 ** nu) ## gradjac = eval_grad_jacobi(s, mu, nu, cosb) * - sinb gradd = (factor * gradjac * sinb2 ** mu * cosb2 ** nu + factor * jac * sinb2 ** (mu-1) * cosb2 ** (nu+1) * mu/2 - factor * jac * sinb2 ** (mu+1) * cosb2 ** (nu-1) * nu/2) ## Ds[Js, m1s, m2s] = exp(-1j*m1s*a) * d * exp(-1j*m2s*y) grad[0,Js, m1s, m2s] = -1j*m1s * Ds[Js, m1s, m2s] grad[1,Js, m1s, m2s] = exp(-1j*m1s*a) * gradd * exp(-1j*m2s*y) grad[2,Js, m1s, m2s] = -1j*m2s * Ds[Js, m1s, m2s] return Ds, grad
def evaluate_basis(self, x, i=0, output_array=None): x = np.atleast_1d(x) if output_array is None: output_array = np.zeros(x.shape) output_array[:] = (1 - x**2)**3 * eval_jacobi( i, 3, 3, x, out=output_array) return output_array
def evaluate_basis_derivative(self, x=None, i=0, k=0, output_array=None): if x is None: x = self.mesh(False, False) #x = self.points_and_weights(mode='mpmath')[0] dj = np.prod( np.array([i + self.alpha + self.beta + 1 + j for j in range(k)])) return dj / 2**k * eval_jacobi(i - k, self.alpha + k, self.beta + k, x)
def test_square_norms(self): N = 100 dims = np.arange(2, 5) max_deg = 50 # to avoid quad warning in dimension 1 for d in dims: jacobi_params = 0.5 - np.random.rand(d, 2) jacobi_params[0, :] = -0.5 dpp = MultivariateJacobiOPE(N, jacobi_params) pol_2_eval = dpp.poly_1D_degrees[:max_deg] quad_square_norms =\ [[quad(lambda x: (1-x)**a * (1+x)**b * eval_jacobi(n, a, b, x)**2, -1, 1)[0] for n, a, b in zip(deg, dpp.jacobi_params[:, 0], dpp.jacobi_params[:, 1])] for deg in pol_2_eval] self.assertTrue( np.allclose( dpp.poly_1D_square_norms[pol_2_eval, range(dpp.dim)], quad_square_norms))
def jacobi_poly (si,c,alfa, beta): phi=[0.]*len(si) for i in range(0, len(c)): if c[i] != 0: for j in range(0, len(si)): phi[j] +=c[i]*sps.eval_jacobi(i, alfa, beta, si[j]) return np.array(phi)
def jacobi_value(n, a, b, x): if (isinstance(n, types.int32) and isinstance(a, types.float64) and\ isinstance(b, types.float64) and isinstance(x, types.float64)): outval = eval_jacobi(n, a, b, x) def my_jacobi(n, a, b, x): return outval return my_jacobi
def evaluate_basis(self, x, i=0, output_array=None): x = np.atleast_1d(x) if output_array is None: output_array = np.zeros(x.shape) output_array = eval_jacobi(i, self.alpha, self.beta, x, out=output_array) return output_array
def lagrangeToJacobi(t, a, b, axis=0): n = t.shape[axis] points = chebNodes(n=n) JacobiM = np.zeros([n, n]) for i in range(n): JacobiM[:, i] = special.eval_jacobi(i, a, b, points) if axis == 0: return sp_lin.solve(JacobiM, t) else: return (sp_lin.solve(JacobiM, t.T))
def jacobi(self, x, alpha, beta, N): V = np.zeros((x.shape[0], N)) if mode == 'numpy': for n in range(N): V[:, n] = eval_jacobi(n, alpha, beta, x) else: for n in range(N): V[:, n] = sp.lambdify(xp, sp.jacobi(n, alpha, beta, xp), 'mpmath')(x) return V
def jacobf(z, n, alpha, beta): """ evaluate Jacobi polynomial P_n^{alpha,beta} on a set of points :param z: numpy array, values of the points to evaluate Jacobi polynomial on :param n: order of Jacobi polynomial in P_n^{alpha,beta} :param alpha: parameters, alpha > -1 :param beta: parameters, beta > -1 :return: vector of Jacobi polynomial values on these points """ return eval_jacobi(n, alpha, beta, z)
def evaluate_basis(self, x, i=0, output_array=None): x = np.atleast_1d(x) if output_array is None: output_array = np.zeros(x.shape) if mode == 'numpy': output_array[:] = (1 - x**2)**3 * eval_jacobi( i, 3, 3, x, out=output_array) else: f = self.sympy_basis(i, xp) output_array[:] = sp.lambdify(xp, f, 'mpmath')(x) return output_array
def test_jacobi(self): assert_mpmath_equal( sc.eval_jacobi, _exception_to_nan( lambda a, b, c, x: mpmath.jacobi(a, b, c, x, **HYPERKW)), [Arg(), Arg(), Arg(), Arg()]) assert_mpmath_equal( lambda n, b, c, x: sc.eval_jacobi(int(n), b, c, x), _exception_to_nan( lambda a, b, c, x: mpmath.jacobi(a, b, c, x, **HYPERKW)), [IntArg(), Arg(), Arg(), Arg()])
def radial_polynomial(self, rho, m, n): # See https://mathworld.wolfram.com/ZernikePolynomial.html if (n - m) % 2 == 1: print("ODD") return 0 eff_n = (n - m) // 2 alpha = m beta = 0 x = 1 - 2 * (rho**2.0) return (-1)**(eff_n) * (rho**m) * eval_jacobi(eff_n, alpha, beta, x)
def jacobi(self, x, alpha, beta, N): V = np.zeros((x.shape[0], N)) if mode == 'numpy': for n in range(N): V[:, n] = eval_jacobi(n, alpha, beta, x) else: X = sp.symbols('x', real=True) for n in range(N): V[:, n] = sp.lambdify(X, sp.jacobi(n, alpha, beta, X), 'mpmath')(x) return V
def evaluate_basis(self, x, i=0, output_array=None): x = np.atleast_1d(x) if output_array is None: output_array = np.zeros(x.shape) if mode == 'numpy': output_array[:] = (1 - x**2)**2 * eval_jacobi( i, 2, 2, x, out=output_array) else: X = sp.symbols('x', real=True) f = self.sympy_basis(i, X) output_array[:] = sp.lambdify(X, f, 'mpmath')(x) return output_array
def eval_zernike_R(n, m, rho): """Return the value of the radial Zernike polynomial""" # n>=m # m>=0 k = n - m if k % 2 == 1: return 0.0 n_jacobi = k // 2 comp = 1 - 2 * rho * rho # jacobi form return (-1)**n_jacobi * rho**m * eval_jacobi(n_jacobi, m, 0, comp)
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 evaluate_basis_derivative(self, x=None, i=0, k=0, output_array=None): if x is None: x = self.points_and_weights(mode=mode)[0] #x = np.atleast_1d(x) if output_array is None: output_array = np.zeros(x.shape, dtype=self.dtype) if mode == 'numpy': dj = np.prod( np.array( [i + self.alpha + self.beta + 1 + j for j in range(k)])) output_array[:] = dj / 2**k * eval_jacobi(i - k, self.alpha + k, self.beta + k, x) else: f = sp.jacobi(i, self.alpha, self.beta, xp) output_array[:] = sp.lambdify(xp, f.diff(xp, k), 'mpmath')(x) return output_array
def _radial_zernike(r, n, m): """The radial part of the zernike polynomial Formula from http://mathworld.wolfram.com/ZernikePolynomial.html""" rad_zern = np.zeros_like(r) # zernike polynomials are only valid for r <= 1 valid_points = r <= 1.0 if m == 0 and n == 0: rad_zern[valid_points] = 1 return rad_zern rprime = r[valid_points] # for the radial part m is always positive m = abs(m) # calculate the coefs coef1 = (n + m) // 2 coef2 = (n - m) // 2 jacobi = eval_jacobi(coef2, m, 0, 1 - 2 * rprime**2) rad_zern[valid_points] = (-1)**coef1 * rprime**m * jacobi return rad_zern
def eval_multiD_polynomials(self, X): """Evaluate .. math:: \\mathbf{\\Phi}(X) := \\begin{pmatrix} \\Phi(x_1)^{\\top}\\\\ \\vdots\\\\ \\Phi(x_M)^{\\top} \\end{pmatrix} where :math:`\\Phi(x) = \\left(P_{\\mathfrak{b}^{-1}(0)}(x), \\dots, P_{\\mathfrak{b}^{-1}(N-1)}(x) \\right)^{\\top}` such that :math:`K(x, y) = \\Phi(x)^{\\top} \\Phi(y)`. Recall that :math:`\\mathfrak{b}` denotes the ordering chosen to order multi-indices :math:`k\\in \\mathbb{N}^d`. This is done by evaluating each of the `three-term recurrence relations <https://en.wikipedia.org/wiki/Jacobi_polynomials#Recurrence_relations>`_ satisfied by each univariate orthogonal Jacobi polynomial, using the dedicated `see also SciPy <https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.eval_jacobi.html>`_ :func:`scipy.special.eval_jacobi` satistified by the respective univariate Jacobi polynomials :math:`P_{k_i}^{(a_i, b_i)}(x_i)`. Then we use the slicing feature of the Python language to compute :math:`\\Phi(x)=\\left(P_{k}(x) = \\prod_{i=1}^d P_{k_i}^{(a_i, b_i)}(x_i)\\right)_{k=\\mathfrak{b}^{-1}(0), \\dots, \\mathfrak{b}^{-1}(N-1)}^{\\top}` :param X: :math:`M\\times d` array of :math:`M` points :math:`\\in [-1, 1]^d` :type X: array_like :return: :math:`\\mathbf{\\Phi}(X)` - :math:`M\\times N` array :rtype: array_like .. seealso:: - evaluation of the kernel :py:meth:`~dppy.multivariate_jacobi_ope.MultivariateJacobiOPE.K` """ poly_1D_jacobi = eval_jacobi(self.degrees_1D_polynomials, self.jacobi_params[:, 0], self.jacobi_params[:, 1], np.atleast_2d(X)[:, None])\ / self.norms_1D_polynomials return np.prod(poly_1D_jacobi[:, self.ordering, range(self.dim)], axis=2)
def Wigner_d(j, m1, m2, x): # using definition from A.R. Edmonds, eq 4.1.23 from scipy.special import factorial, eval_jacobi from numpy import sqrt mp, m = m1, m2 p = 1 if mp + m < 0: mp, m = -mp, -m p *= (-1) ** (mp - m) if mp < m: mp, m = m, mp p *= (-1) ** (mp - m) return (p * sqrt( factorial(j + mp) * factorial(j - mp) / (factorial(j + m) * factorial(j - m)) ) * sqrt(.5 + .5 * x) ** (mp + m) * sqrt(.5 - .5 * x) ** (mp - m) * eval_jacobi(j - mp, mp - m, mp + m, x) )
def calcWignerMatrices(self): bw = self.bw bws = self.bws beta = self.b sinb2 = sin(beta / 2) cosb2 = cos(beta / 2) cosb = cos(beta) Js, m1s, m2s = self.Js, self.m1s, self.m2s Dfull = np.zeros((bw, 2 * bw - 1, 2 * bw - 1, 2 * bw)) mu = abs(m1s - m2s) nu = abs(m1s + m2s) s = Js - (mu + nu) / 2 xi = np.ones_like(s) xi[m2s < m1s] = (-1)**(m1s - m2s)[m2s < m1s] factor = sqrt( factorial(s) * factorial(s + mu + nu) / factorial(s + mu) / factorial(s + nu)) * xi jac = eval_jacobi(s[:, None], mu[:, None], nu[:, None], cosb[None, :]) Dfull[Js[:, None], m1s[:, None], m2s[:, None], bws[None, :]] = (((2. * Js[:, None] + 1.) / 2.)**0.5 * factor[:, None] * jac * sinb2[None, :]**mu[:, None] * cosb2[None, :]**nu[:, None]) return Dfull
def test_roots_jacobi(): rf = lambda a, b: lambda n, mu: sc.roots_jacobi(n, a, b, mu) ef = lambda a, b: lambda n, x: sc.eval_jacobi(n, a, b, x) wf = lambda a, b: lambda x: (1 - x)**a * (1 + x)**b vgq = verify_gauss_quad vgq(rf(-0.5, -0.75), ef(-0.5, -0.75), wf(-0.5, -0.75), -1., 1., 5) vgq(rf(-0.5, -0.75), ef(-0.5, -0.75), wf(-0.5, -0.75), -1., 1., 25, atol=1e-12) vgq(rf(-0.5, -0.75), ef(-0.5, -0.75), wf(-0.5, -0.75), -1., 1., 100, atol=1e-11) vgq(rf(0.5, -0.5), ef(0.5, -0.5), wf(0.5, -0.5), -1., 1., 5) vgq(rf(0.5, -0.5), ef(0.5, -0.5), wf(0.5, -0.5), -1., 1., 25, atol=1.5e-13) vgq(rf(0.5, -0.5), ef(0.5, -0.5), wf(0.5, -0.5), -1., 1., 100, atol=2e-12) vgq(rf(1, 0.5), ef(1, 0.5), wf(1, 0.5), -1., 1., 5, atol=2e-13) vgq(rf(1, 0.5), ef(1, 0.5), wf(1, 0.5), -1., 1., 25, atol=2e-13) vgq(rf(1, 0.5), ef(1, 0.5), wf(1, 0.5), -1., 1., 100, atol=1e-12) vgq(rf(0.9, 2), ef(0.9, 2), wf(0.9, 2), -1., 1., 5) vgq(rf(0.9, 2), ef(0.9, 2), wf(0.9, 2), -1., 1., 25, atol=1e-13) vgq(rf(0.9, 2), ef(0.9, 2), wf(0.9, 2), -1., 1., 100, atol=3e-13) vgq(rf(18.24, 27.3), ef(18.24, 27.3), wf(18.24, 27.3), -1., 1., 5) vgq(rf(18.24, 27.3), ef(18.24, 27.3), wf(18.24, 27.3), -1., 1., 25, atol=1.1e-14) vgq(rf(18.24, 27.3), ef(18.24, 27.3), wf(18.24, 27.3), -1., 1., 100, atol=1e-13) vgq(rf(47.1, -0.2), ef(47.1, -0.2), wf(47.1, -0.2), -1., 1., 5, atol=1e-13) vgq(rf(47.1, -0.2), ef(47.1, -0.2), wf(47.1, -0.2), -1., 1., 25, atol=2e-13) vgq(rf(47.1, -0.2), ef(47.1, -0.2), wf(47.1, -0.2), -1., 1., 100, atol=1e-11) vgq(rf(2.25, 68.9), ef(2.25, 68.9), wf(2.25, 68.9), -1., 1., 5) vgq(rf(2.25, 68.9), ef(2.25, 68.9), wf(2.25, 68.9), -1., 1., 25, atol=1e-13) vgq(rf(2.25, 68.9), ef(2.25, 68.9), wf(2.25, 68.9), -1., 1., 100, atol=1e-13) # when alpha == beta == 0, P_n^{a,b}(x) == P_n(x) xj, wj = sc.roots_jacobi(6, 0.0, 0.0) xl, wl = sc.roots_legendre(6) assert_allclose(xj, xl, 1e-14, 1e-14) assert_allclose(wj, wl, 1e-14, 1e-14) # when alpha == beta != 0, P_n^{a,b}(x) == C_n^{alpha+0.5}(x) xj, wj = sc.roots_jacobi(6, 4.0, 4.0) xc, wc = sc.roots_gegenbauer(6, 4.5) assert_allclose(xj, xc, 1e-14, 1e-14) assert_allclose(wj, wc, 1e-14, 1e-14) x, w = sc.roots_jacobi(5, 2, 3, False) y, v, m = sc.roots_jacobi(5, 2, 3, True) assert_allclose(x, y, 1e-14, 1e-14) assert_allclose(w, v, 1e-14, 1e-14) muI, muI_err = integrate.quad(wf(2,3), -1, 1) assert_allclose(m, muI, rtol=muI_err) assert_raises(ValueError, sc.roots_jacobi, 0, 1, 1) assert_raises(ValueError, sc.roots_jacobi, 3.3, 1, 1) assert_raises(ValueError, sc.roots_jacobi, 3, -2, 1) assert_raises(ValueError, sc.roots_jacobi, 3, 1, -2) assert_raises(ValueError, sc.roots_jacobi, 3, -2, -2)
def sample_chain_rule_proposal(self, nb_trials_max=10000, random_state=None): """Use a rejection sampling mechanism to sample .. math:: \\frac{1}{N} K(x, x) w(x) dx = \\frac{1}{N} \\sum_{\\mathfrak{b}(k)=0}^{N-1} \\left( \\frac{P_k(x)}{\\left\\| P_k \\right\\|} \\right)^2 w(x) with proposal distribution .. math:: w_{eq}(x) d x = \\prod_{i=1}^{d} \\frac{1}{\\pi\\sqrt{1-(x_i)^2}} d x_i Since the target density is a mixture, we can sample from it by 1. Select a multi-index :math:`k` uniformly at random in :math:`\\left\\{ \\mathfrak{b}^{-1}(0), \\dots, \\mathfrak{b}^{-1}(N-1) \\right\\}` 2. Sample from :math:`\\left( \\frac{P_k(x)}{\\left\\| P_k \\right\\|} \\right)^2 w(x) dx` with proposal :math:`w_{eq}(x) d x`. The acceptance ratio writes .. math:: \\frac{ \\left( \\frac{P_k(x)}{\\left\\| P_k \\right\\|} \\right)^2 w(x)} {w_{eq}(x)} = \\prod_{i=1}^{d} \\pi \\left( \\frac{P_{k_i}^{(a_i, b_i)}(x)} {\\left\\| P_{k_i}^{(a_i, b_i)} \\right\\|} \\right)^2 (1-x_i)^{a_i+\\frac{1}{2}} (1+x_i)^{b_i+\\frac{1}{2}} \\leq C_{k} which can be bounded using the result of :cite:`Gau09` on Jacobi polynomials. .. note:: Each of the rejection constant :math:`C_{k}` is computed at initialization of the :py:class:`MultivariateJacobiOPE` object using :py:meth:`compute_rejection_bounds` :return: A sample :math:`x\\in[-1,1]^d` with probability distribution :math:`\\frac{1}{N} K(x,x) w(x)` :rtype: array_like .. seealso:: - :py:meth:`compute_rejection_bounds` - :py:meth:`sample` """ rng = check_random_state(random_state) a, b = self.jacobi_params.T a_05, b_05 = a + 0.5, b + 0.5 d = self.dim ind = rng.randint(self.N) k = self.ordering[ind] Pk_square_norm = self.square_norms_multiD_polynomials[ind] # norm_Pk = self.poly_multiD_norm[ind] rejection_bound = self.rejection_bounds[ind] for trial in range(nb_trials_max): # Propose x ~ w_eq(x) = \prod_{i=1}^{d} 1/pi 1/sqrt(1-(x_i)^2) # rng.beta is defined as beta(a, b) = x^(a-1) (1-x)^(b-1) x = 1.0 - 2.0 * rng.beta(0.5, 0.5, size=self.dim) # Compute (P_k(x)/||P_k||)^2 Pk2_x = np.prod(eval_jacobi(k, a, b, x))**2 / Pk_square_norm # Pk2_x = (np.prod(eval_jacobi(k, a, b, x)) / norm_Pk)**2 # Compute w(x) / w_eq(x) w_over_w_eq =\ np.pi**d * np.prod((1.0 - x)**a_05 * (1.0 + x)**b_05) if rng.rand() * rejection_bound < Pk2_x * w_over_w_eq: break else: print( 'marginal distribution 1/N K(x,x), rejection fails after {} proposals' .format(trial)) return x
def e(x, i): return K(i) * (np.cos(x))**Dpl * eval_jacobi(i, d / 2 - 1, Dpl - d / 2, np.cos(2 * x))
def ep(x, j): return -1. * np.tan(x) * (np.cos(x)) ** Dpl * (2 * (Dpl + j) *\ np.cos(x) ** 2 * eval_jacobi(j - 1, d/2, Dpl + 1 - d/2, np.cos(2 * x))\ + Dpl * eval_jacobi(j, d/2 - 1, Dpl - d/2, np.cos(2 * x)))
def eval_grad_jacobi(n, alpha, beta, x, out=None): fact = gamma(alpha + beta + n + 2) / 2 / gamma(alpha + beta + n + 1) return eval_jacobi(n - 1, alpha + 1, beta + 1, x, out) * fact
def sample_proposal_lev_score(self, nb_trials_max=10000, random_state=None): """Use a rejection sampling mechanism to sample .. math:: \\frac{1}{N} K(x, x) w(x) dx = \\frac{1}{N} \\sum_{\\mathfrak{k}=0}^{N-1} P_k(x)^2 w(x) with proposal distribution .. math:: w_{eq}(x) d x = \\frac{1}{\\pi^d} \\prod_{i=1}^{d} \\frac{1}{\\sqrt{1-(x^i)^2}} d x Since the target density is a mixture, we can sample it by 1. Draw a multi-index :math:`k` uniformly at random 2. Sample from :math:`P_k(x)^2 w(x) dx` with proposal :math:`w_{eq}(x) d x`. The acceptance ratio writes .. math:: P_k(x)^2 w(x) \\frac{1}{\\frac{w_{\\text{eq}}(x)}{\\pi^d}} = \\prod_{i=1}^{d} \\pi P_{k^i}(x)^2 (1-x^i)^{a^i+\\frac{1}{2}} (1+x^i)^{b^i+\\frac{1}{2}} which can be bounded using the result of :cite:`Gau09` on Jacobi polynomials. It is computed at initialization of the :py:class:`MultivariateJacobiOPE` object with :py:meth:`compute_Gautschi_bounds` :return: A sample :math:`x\\in[-1,1]^d` with probability distribution :math:`\\frac{1}{N} K(x,x) w(x)` :rtype: array_like .. seealso:: - :py:meth:`compute_Gautschi_bounds` - :py:meth:`sample` """ rng = check_random_state(random_state) ind = rng.randint(self.N) k_multi_ind = self.ordering[ind] square_norm = self.poly_multiD_square_norms[ind] Gautschi_bound = self.Gautschi_bounds[ind] for trial in range(nb_trials_max): # Propose x ~ arcsine = \prod_{i=1}^{d} 1/pi 1/sqrt(1-(x^i)^2) x = 1.0 - 2.0 * rng.beta(0.5, 0.5, size=self.dim) Pk2_x = np.prod( eval_jacobi(k_multi_ind, self.jacobi_params[:, 0], self.jacobi_params[:, 1], x))**2 Pk2_x /= square_norm ratio_w_proposal =\ self._pi_power_dim\ * np.prod((1.0 - x)**(self._jacobi_params_plus_05[:, 0]) * (1.0 + x)**(self._jacobi_params_plus_05[:, 1])) if rng.rand() * Gautschi_bound < Pk2_x * ratio_w_proposal: break else: print('proposal not enough trials') return x, self.K(x, None)
def jacobi_15_4_6(a,b,c,z): n = -a alpha = c-1 beta = b-n-alpha-1 return np.exp(gammaln(n+1)-pochln(alpha+1,n))*eval_jacobi(n,alpha,beta,1-2*z)
def K(self, X, Y=None): '''Evaluate the orthogonal projection kernel :math:`K`. It is based on the `3-terms recurrence relations <https://en.wikipedia.org/wiki/Jacobi_polynomials#Recurrence_relations>`_ satisfied by each univariate orthogonal Jacobi polynomial, `see also SciPy <https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.eval_jacobi.html>`_ :func:`eval_jacobi` .. math:: K(x, y) = \\sum_{\\mathfrak{b}(k)=0}^{N-1} \\frac{P_{k}(x)P_{k}(y)} {\\|P_{k}\\|^2} where - :math:`k \\in \\mathbb{N}^d` is a multi-index ordered according to the ordering :math:`\\mathfrak{b}`, :py:meth:`compute_ordering_BaHa16` - :math:`P_{k}(x) = \\prod_{i=1}^d P_{k_i}^{a_i, b_i}(x^i)` is the product of orthogonal Jacobi polynomials w.r.t. :math:`\\mu(dx) = \\prod_{i=1}^{d} (1-x^i)^{a_i} (1+x^i)^{b_i} d x^i` .. math:: \\int_{-1}^{1} P_{k}^{(a_i,b_i)}(x) P_{\\ell}^{(a_i,b_i)}(x) (1-x)^{a_i} (1+x)^{b_i} d x \\propto \\delta_{k\\ell} :param X: Array of points :math:`\\in [-1, 1]^d`, with size :math:`n\\times d` where :math:`n` is the number of points :type X: array_like :param Y: Array of points :math:`\\in [-1, 1]^d`, with size :math:`n\\times d` where :math:`n` is the number of points :type Y: array_like (default None) :return: Pointwise evaluation of :math:`K` as depicted in the following pseudo code output - if ``Y`` is ``None`` - ``K(X, X)`` if ``X.size`` :math:`=d` - ``[K(x, x) for x in X]`` otherwise - otherwise - ``K(X, Y)`` if ``X.size=Y.size``:math:`=d` - ``[K(X, y) for y in Y]`` if ``X.size`` :math:`=d` - ``[K(x, y) for x, y in zip(X, Y)]`` otherwise :rtype: - float if ``Y`` is ``None`` and ``X.size`` :math:`=d` - array_like otherwise ''' if Y is None: if X.size == self.dim: # X is vector in R^d polys_X_2 = eval_jacobi(self.poly_1D_degrees, self.jacobi_params[:, 0], self.jacobi_params[:, 1], X)**2\ / self.poly_1D_square_norms return np.sum(np.prod(polys_X_2[self.ordering, range(self.dim)], axis=1), axis=0) else: polys_X_2 = eval_jacobi(self.poly_1D_degrees, self.jacobi_params[:, 0], self.jacobi_params[:, 1], X[:, None])**2\ / self.poly_1D_square_norms return np.sum(np.prod(polys_X_2[:, self.ordering, range(self.dim)], axis=2), axis=1) else: lenX = X.size // self.dim # X.shape[0] if X.ndim > 1 else 1 lenY = Y.size // self.dim # Y.shape[0] if Y.ndim > 1 else 1 polys_X_Y = eval_jacobi(self.poly_1D_degrees, self.jacobi_params[:, 0], self.jacobi_params[:, 1], np.vstack((X, Y))[:, None]) if lenX > lenY: polys_X_Y[: lenX] *= polys_X_Y[lenX:] / self.poly_1D_square_norms return np.sum(np.prod(polys_X_Y[:lenX, self.ordering, range(self.dim)], axis=2), axis=1) else: # if lenX < lenY: polys_X_Y[ lenX:] *= polys_X_Y[:lenX] / self.poly_1D_square_norms return np.sum(np.prod(polys_X_Y[lenX:, self.ordering, range(self.dim)], axis=2), axis=1)