def _eval_evalf(self, prec): # The default code is insufficient for polar arguments. # mpmath provides an optional argument "r", which evaluates # G(z**(1/r)). I am not sure what its intended use is, but we hijack it # here in the following way: to evaluate at a number z of |argument| # less than (say) n*pi, we put r=1/n, compute z' = root(z, n) # (carefully so as not to loose the branch information), and evaluate # G(z'**(1/r)) = G(z'**n) = G(z). from sympy.functions import exp_polar, ceiling from sympy import Expr import mpmath znum = self.argument._eval_evalf(prec) if znum.has(exp_polar): znum, branch = znum.as_coeff_mul(exp_polar) if len(branch) != 1: return branch = branch[0].args[0] / I else: branch = S.Zero n = ceiling(abs(branch / S.Pi)) + 1 znum = znum**(S.One / n) * exp(I * branch / n) # Convert all args to mpf or mpc try: [z, r, ap, bq] = [ arg._to_mpmath(prec) for arg in [znum, 1 / n, self.args[0], self.args[1]] ] except ValueError: return with mpmath.workprec(prec): v = mpmath.meijerg(ap, bq, z, r) return Expr._from_mpmath(v, prec)
def _eval_evalf(self, prec): # The default code is insufficient for polar arguments. # mpmath provides an optional argument "r", which evaluates # G(z**(1/r)). I am not sure what its intended use is, but we hijack it # here in the following way: to evaluate at a number z of |argument| # less than (say) n*pi, we put r=1/n, compute z' = root(z, n) # (carefully so as not to loose the branch information), and evaluate # G(z'**(1/r)) = G(z'**n) = G(z). from sympy.functions import exp_polar, ceiling from sympy import Expr import mpmath z = self.argument znum = self.argument._eval_evalf(prec) if znum.has(exp_polar): znum, branch = znum.as_coeff_mul(exp_polar) if len(branch) != 1: return branch = branch[0].args[0]/I else: branch = S(0) n = ceiling(abs(branch/S.Pi)) + 1 znum = znum**(S(1)/n)*exp(I*branch / n) # Convert all args to mpf or mpc try: [z, r, ap, bq] = [arg._to_mpmath(prec) for arg in [znum, 1/n, self.args[0], self.args[1]]] except ValueError: return with mpmath.workprec(prec): v = mpmath.meijerg(ap, bq, z, r) return Expr._from_mpmath(v, prec)
def analytical_base_partition_function(numer, denom): r"""Accurately approximate the partition function Z(numer / denom). This uses the analytical formulation of the true partition function Z(alpha), as described in the paper (the math after Equation 18), where alpha is a positive rational value numer/denom. This is expensive to compute and not differentiable, so it is only used for unit tests. Args: numer: the numerator of alpha, an integer >= 0. denom: the denominator of alpha, an integer > 0. Returns: Z(numer / denom), a double-precision float, accurate to around 9 digits of precision. Raises: ValueError: If `numer` is not a non-negative integer or if `denom` is not a positive integer. """ if not isinstance(numer, numbers.Integral): raise ValueError( "Expected `numer` of type int, but is of type {}".format( type(numer))) if not isinstance(denom, numbers.Integral): raise ValueError( "Expected `denom` of type int, but is of type {}".format( type(denom))) if not numer >= 0: raise ValueError("Expected `numer` >= 0, but is = {}".format(numer)) if not denom > 0: raise ValueError("Expected `denom` > 0, but is = {}".format(denom)) alpha = numer / denom # The Meijer-G formulation of the partition function has singularities at # alpha = 0 and alpha = 2, but at those special cases the partition function # has simple closed forms which we special-case here. if alpha == 0: return np.pi * np.sqrt(2) if alpha == 2: return np.sqrt(2 * np.pi) # Z(n/d) as described in the paper. a_p = (np.arange(1, numer, dtype=np.float64) / numer).tolist() b_q = ((np.arange(-0.5, numer - 0.5, dtype=np.float64)) / numer).tolist() + (np.arange(1, 2 * denom, dtype=np.float64) / (2 * denom)).tolist() z = (1.0 / numer - 1.0 / (2 * denom))**(2 * denom) mult = (np.exp(np.abs(2 * denom / numer - 1.0)) * np.sqrt(np.abs(2 * denom / numer - 1.0)) * (2 * np.pi)**(1 - denom)) return mult * np.float64(mpmath.meijerg([[], a_p], [b_q, []], z))
def bg_3d_lum_int(rr,pp,qq,i0,bb): # Tested 2011-08-31 """Fully analytic calculation of lum internal to rr""" if not (pp==int(pp) and qq==int(qq)): raise RuntimeError pp, qq = int(pp), int(qq) reff = 1.0 ss = rr/reff avect = [[1-1.0/qq], [xx/(1.0*qq) for xx in range(1,qq)]] bvect = [[xx/(2.0*pp) for xx in range(1,2*pp)] + [xx/(2.0*qq) for xx in range(1,2*qq,2)], [-1.0/qq]] factor = 2*i0*reff**2*np.sqrt(pp)/((2*np.pi)**(pp-1)*np.sqrt(qq)) zz = (bb/(2*pp))**(2*pp) * ss**(2*qq) return factor*ss**2*mpmath.meijerg(avect, bvect, zz)
def bg_3d_lum_int(rr, pp, qq, i0, bb): # Tested 2011-08-31 """Fully analytic calculation of lum internal to rr""" if not (pp == int(pp) and qq == int(qq)): raise RuntimeError pp, qq = int(pp), int(qq) reff = 1.0 ss = rr / reff avect = [[1 - 1.0 / qq], [xx / (1.0 * qq) for xx in range(1, qq)]] bvect = [[xx / (2.0 * pp) for xx in range(1, 2 * pp)] + [xx / (2.0 * qq) for xx in range(1, 2 * qq, 2)], [-1.0 / qq]] factor = 2 * i0 * reff**2 * np.sqrt(pp) / ( (2 * np.pi)**(pp - 1) * np.sqrt(qq)) zz = (bb / (2 * pp))**(2 * pp) * ss**(2 * qq) return factor * ss**2 * mpmath.meijerg(avect, bvect, zz)
def rouse_large_cvv_g(t, delta, deltaN, b, kbT=1, xi=1): """Cvv^delta(t) for infinite polymer. Lampo, BPJ, 2016 Eq. 16.""" k = 3*kbT/b**2 ndmap = lambda G, arr: np.array(list(map(G, arr))) G = lambda x: float(mpmath.meijerg([[],[3/2]], [[0,1/2],[]], x)) gtmd = ndmap(G, np.power(deltaN, 2)*xi/(4*k*np.abs(t-delta))) gtpd = ndmap(G, np.power(deltaN, 2)*xi/(4*k*np.abs(t+delta))) gt = ndmap(G, np.power(deltaN, 2)*xi/(4*k*np.abs(t))) return 3*kbT/(np.power(delta, 2)*np.sqrt(xi*k))* ( np.power(np.abs(t - delta), 1/2)*gtmd + np.power(np.abs(t + delta), 1/2)*gtpd - 2*np.power(np.abs(t), 1/2)*gt )
def _p(self, K): G = lambda k : mpmath.meijerg([[1. / 6., 5. / 12., 11. / 12.], []], [[1. / 6., 1. / 6., 5. / 12., 0.5, 2. / 3., 5. / 6., 11. / 12.], [0, 1. / 3.]], k ** 6 / 46656.0) / (4 * np.sqrt(3) * np.pi ** (5 / 2) * k) if len(K.shape) == 2: K1 = np.reshape(K, -1) K1.sort() else: K1 = K res = np.zeros(len(K[K < 10 ** 3.2])) for i, k in enumerate(K1[K1 < 10 ** 3.2]): res[i] = G(k) fit = spline(np.log(K1[K1 < 10 ** 3.2]), np.log(res), k=1) res = np.reshape(np.exp(fit(np.log(np.reshape(K, -1)))), (len(K[:, 0]), len(K[0, :]))) return res
def _p(self, K): G = lambda k : mpmath.meijerg([[(self.alpha - 2) / 2.0, (self.alpha - 1) / 2.0], []], [[0, 0, 0.5], [-0.5]], k ** 2 / 4) / (np.sqrt(np.pi) * sp.gamma(3 - self.alpha)) if len(K.shape) == 2: K1 = np.reshape(K, -1) K1.sort() else: K1 = K res = np.zeros(len(K[K < 10 ** 3.2])) for i, k in enumerate(K1[K1 < 10 ** 3.2]): res[i] = G(k) fit = spline(np.log(K1[K1 < 10 ** 3.2]), np.log(res), k=1) res = np.reshape(np.exp(fit(np.log(np.reshape(K, -1)))), (len(K[:, 0]), len(K[0, :]))) return res
def _p(self, K): G = lambda k: mpmath.meijerg([[(self.alpha - 2) / 2.0, ( self.alpha - 1) / 2.0], []], [[0, 0, 0.5], [-0.5]], k**2 / 4) / ( np.sqrt(np.pi) * sp.gamma(3 - self.alpha)) if len(K.shape) == 2: K1 = np.reshape(K, -1) K1.sort() else: K1 = K res = np.zeros(len(K[K < 10**3.2])) for i, k in enumerate(K1[K1 < 10**3.2]): res[i] = G(k) fit = spline(np.log(K1[K1 < 10**3.2]), np.log(res), k=1) res = np.reshape(np.exp(fit(np.log(np.reshape(K, -1)))), (len(K[:, 0]), len(K[0, :]))) return res
def _p(self, K): G = lambda k: mpmath.meijerg([[1. / 6., 5. / 12., 11. / 12.], []], [[ 1. / 6., 1. / 6., 5. / 12., 0.5, 2. / 3., 5. / 6., 11. / 12. ], [0, 1. / 3.]], k**6 / 46656.0) / (4 * np.sqrt(3) * np.pi** (5 / 2) * k) if len(K.shape) == 2: K1 = np.reshape(K, -1) K1.sort() else: K1 = K res = np.zeros(len(K[K < 10**3.2])) for i, k in enumerate(K1[K1 < 10**3.2]): res[i] = G(k) fit = spline(np.log(K1[K1 < 10**3.2]), np.log(res), k=1) res = np.reshape(np.exp(fit(np.log(np.reshape(K, -1)))), (len(K[:, 0]), len(K[0, :]))) return res
def totalDerivativeOfIncGamma(x, a, b, da, db): """ Computes the total derivative for the (non-normalized) incomplete gamma function, i.e. d/dx gamma(a(x))*gammainc(a(x),b(x)) :param x: Positions where the function is to be computed. :type x: numpy.ndarray :param a: function handle for a :type a: python function :param b: function handle for b :type b: python function :param da: function handle for da/dx :type da: python function :param db: function handle for db/dx :type db: python function :returns: derivative values :rtype: numpy.ndarray """ return digamma(a(x))*gammafunc(a(x))*da(x) + exp(-b(x))*b(x)**(a(x)-1)*db(x) \ - (meijerg([[],[1,1],],[[0,0,a(x)],[]],b(x)) + log(b(x))*gammaincc(a(x),b(x))*gammafunc(a(x))) * da(x)
def meijerg_func(m, x): return meijerg([[], []], [[0.5, m / 2 - 1, m / 2 - 0.5], [0]], x)
def G(x): return float(mpmath.meijerg([[], [3/2]], [[0, 1/2], []], x))
def produce_subdiff_analytic_soln(params, T, xs): # Use meijer-G function to calculate subdiffusion for alpha = 1/2 D_alpha = params[0] #def integrand(u): # return 1. / math.sqrt(8 * pow(math.pi,3) * math.sqrt(T)) * float(mpmath.meijerg([[],[]], [[0, 0.25, 0.5],[]], pow(u[0],4) / (256. * T))) integrand = lambda u: 1. / math.sqrt(8 * pow(math.pi,3) * D_alpha * math.sqrt(T)) * float(mpmath.meijerg([[],[]], [[0, 0.25, 0.5],[]], pow(u,4) / (256. * D_alpha * D_alpha * T))) return 1.0 - 2.0 * np.vectorize(lambda x: scipy.integrate.quad(integrand, 0., x)[0])(xs)
def lum(rr): if np.iterable(rr): return np.array([lum(r) for r in rr]) ss = rr/reff zz = (bb/(2*mm))**(2*mm) * ss**2 return (factor/ss)*mpmath.meijerg(avect, bvect, zz)
def plane_wave_potential(grid, spinless=False, e_cutoff=None, non_periodic=False, period_cutoff=None, fieldlines=3, R0=1e8, verbose=False): """Return the e-e potential operator in the plane wave basis. Args: grid (Grid): The discretization to use. spinless (bool): Whether to use the spinless model or not. e_cutoff (float): Energy cutoff. non_periodic (bool): If the system is non-periodic, default to False. period_cutoff (float): Period cutoff, default to grid.volume_scale() ** (1. / grid.dimensions). fieldlines (int): Spatial dimension for electric field lines. R0 (float): Reference length scale where the 2D Coulomb potential is zero. verbose (bool): Whether to turn on print statements. Returns: operator (FermionOperator) """ print('MATHEMATICA 11') if grid.dimensions == 1: raise ValueError('System dimension cannot be 1.') # Initialize. prefactor = 0. # 3D case. if grid.dimensions == 3: prefactor = 2. * numpy.pi / grid.volume_scale() # 2D case. elif grid.dimensions == 2: prefactor = 1. / (2. * grid.volume_scale()) operator = FermionOperator((), 0.0) spins = [None] if spinless else [0, 1] if non_periodic and period_cutoff is None: period_cutoff = grid.volume_scale() ** (1. / grid.dimensions) # Pre-Computations. shifted_omega_indices_dict = {} shifted_indices_minus_dict = {} shifted_indices_plus_dict = {} orbital_ids = {} for indices_a in grid.all_points_indices(): shifted_omega_indices = [j - grid.length[i] // 2 for i, j in enumerate(indices_a)] shifted_omega_indices_dict[indices_a] = shifted_omega_indices shifted_indices_minus_dict[indices_a] = {} shifted_indices_plus_dict[indices_a] = {} for indices_b in grid.all_points_indices(): shifted_indices_minus_dict[indices_a][indices_b] = tuple([ (indices_b[i] - shifted_omega_indices[i]) % grid.length[i] for i in range(grid.dimensions)]) shifted_indices_plus_dict[indices_a][indices_b] = tuple([ (indices_b[i] + shifted_omega_indices[i]) % grid.length[i] for i in range(grid.dimensions)]) orbital_ids[indices_a] = {} for spin in spins: orbital_ids[indices_a][spin] = grid.orbital_id(indices_a, spin) # Loop once through all plane waves. for omega_indices in grid.all_points_indices(): shifted_omega_indices = shifted_omega_indices_dict[omega_indices] # Get the momenta vectors. momenta = grid.momentum_vector(omega_indices) momenta_squared = momenta.dot(momenta) # Skip if momentum is zero. if momenta_squared == 0: continue # Energy cutoff. if e_cutoff is not None and momenta_squared / 2. > e_cutoff: continue # Compute coefficient. coefficient = 0. # 3D case. if grid.dimensions == 3: coefficient = prefactor / momenta_squared # If non-periodic. if non_periodic: coefficient *= 1.0 - numpy.cos( period_cutoff * numpy.sqrt(momenta_squared)) # 2D case. elif grid.dimensions == 2: V_nu = 0. # 2D Coulomb potential. if fieldlines == 2: # If non-periodic. if non_periodic: Dkv = period_cutoff * numpy.sqrt(momenta_squared) V_nu = ( 2. * numpy.pi / momenta_squared * ( Dkv * numpy.log(R0 / period_cutoff) * scipy.special.jv(1, Dkv) - scipy.special.jv(0, Dkv))) if verbose: print('non-periodic') print('cutoff: {}\n'.format(period_cutoff)) print('RO = {}'.format(R0)) # If periodic. else: var1 = 4. / momenta_squared var2 = 0.25 * momenta_squared V_nu = 0.5 * numpy.complex128( mpmath.meijerg([[1., 1.5, 2.], []], [[1.5], []], var1) - mpmath.meijerg([[-0.5, 0., 0.], []], [[-0.5, 0.], [-1.]], var2)) # 3D Coulomb potential. elif fieldlines == 3: # If non-periodic. if non_periodic: var = -0.25 * period_cutoff**2 * momenta_squared V_nu = numpy.complex128( 2 * numpy.pi * period_cutoff * mpmath.hyp1f2(0.5, 1., 1.5, var)) if verbose: print('non-periodic') print('cutoff: {}\n'.format(period_cutoff)) # If periodic. else: V_nu = 2 * numpy.pi / numpy.sqrt(momenta_squared) coefficient = prefactor * V_nu if verbose: print('fieldlines = {}'.format(fieldlines)) print('prefactor: {}'.format(prefactor)) print('V_nu: {}'.format(V_nu)) print('coefficient: {}\n'.format(coefficient)) for grid_indices_a in grid.all_points_indices(): shifted_indices_d = ( shifted_indices_minus_dict[omega_indices][grid_indices_a]) for grid_indices_b in grid.all_points_indices(): shifted_indices_c = ( shifted_indices_plus_dict[omega_indices][grid_indices_b]) # Loop over spins. for spin_a in spins: orbital_a = orbital_ids[grid_indices_a][spin_a] orbital_d = orbital_ids[shifted_indices_d][spin_a] for spin_b in spins: orbital_b = orbital_ids[grid_indices_b][spin_b] orbital_c = orbital_ids[shifted_indices_c][spin_b] # Add interaction term. if ((orbital_a != orbital_b) and (orbital_c != orbital_d)): operators = ((orbital_a, 1), (orbital_b, 1), (orbital_c, 0), (orbital_d, 0)) operator += FermionOperator(operators, coefficient) # Return. return operator
def jordan_wigner_dual_basis_jellium(grid, spinless=False, include_constant=False, non_periodic=False, period_cutoff=None, fieldlines=3, R0=1e8, verbose=False): """Return the jellium Hamiltonian as QubitOperator in the dual basis. Args: grid (Grid): The discretization to use. spinless (bool): Whether to use the spinless model or not. include_constant (bool): Whether to include the Madelung constant. Note constant is unsupported for non-uniform, non-cubic cells with ions. non_periodic (bool): If the system is non-periodic, default to False. period_cutoff (float): Period cutoff, default to grid.volume_scale() ** (1. / grid.dimensions). fieldlines (int): Spatial dimension for electric field lines. R0 (float): Reference length scale where the 2D Coulomb potential is zero. verbose (bool): Whether to turn on print statements. Returns: hamiltonian (QubitOperator) """ if grid.dimensions == 1: raise ValueError('System dimension cannot be 1.') # Initialize. n_orbitals = grid.num_points volume = grid.volume_scale() if non_periodic and period_cutoff is None: period_cutoff = volume ** (1.0 / grid.dimensions) if spinless: n_qubits = n_orbitals else: n_qubits = 2 * n_orbitals hamiltonian = QubitOperator() # Compute vectors. momentum_vectors = {} momenta_squared_dict = {} for indices in grid.all_points_indices(): momenta = grid.momentum_vector(indices) momentum_vectors[indices] = momenta momenta_squared_dict[indices] = momenta.dot(momenta) #------------------------------------------------------------------------- # Compute the identity coefficient and the coefficient of local Z terms. #------------------------------------------------------------------------- identity_coefficient = 0. z_coefficient = 0. for k_indices in grid.all_points_indices(): momenta = momentum_vectors[k_indices] momenta_squared = momenta.dot(momenta) if momenta_squared == 0: continue identity_coefficient += momenta_squared / 2. z_coefficient -= momenta_squared / (4. * float(n_orbitals)) # Coefficients for this value of nu. identity_coefficient_nu = 0. z_coefficient_nu = 0. # 3D case. if grid.dimensions == 3: identity_coefficient_nu = (numpy.pi * float(n_orbitals) / (momenta_squared * volume)) z_coefficient_nu = numpy.pi / (momenta_squared * volume) # If non-periodic. if non_periodic: correction = 1.0 - numpy.cos( period_cutoff * numpy.sqrt(momenta_squared)) identity_coefficient_nu *= correction z_coefficient_nu *= correction if verbose: print('non_periodic') print('cutoff: {}'.format(period_cutoff)) print('correction: {}'.format(correction)) # 2D case. elif grid.dimensions == 2: V_nu = 0. # 2D Coulomb potential. if fieldlines == 2: # If non-periodic. if non_periodic: Dkv = period_cutoff * numpy.sqrt(momenta_squared) V_nu = ( 2. * numpy.pi / momenta_squared * ( Dkv * numpy.log(R0 / period_cutoff) * scipy.special.jv(1, Dkv) - scipy.special.jv(0, Dkv))) if verbose: print('non-periodic') print('cutoff: {}'.format(period_cutoff)) print('RO = {}'.format(R0)) # If periodic. else: var1 = 4. / momenta_squared var2 = 0.25 * momenta_squared V_nu = 0.5 * numpy.complex128( mpmath.meijerg([[1., 1.5, 2.], []], [[1.5], []], var1) - mpmath.meijerg([[-0.5, 0., 0.], []], [[-0.5, 0.], [-1.]], var2)) # 3D Coulomb potential. elif fieldlines == 3: # If non-periodic. if non_periodic: var = -0.25 * period_cutoff**2 * momenta_squared V_nu = numpy.complex128( 2 * numpy.pi * period_cutoff * mpmath.hyp1f2(0.5, 1., 1.5, var)) if verbose: print('non-periodic') print('cutoff: {}'.format(period_cutoff)) # If periodic. else: V_nu = 2 * numpy.pi / numpy.sqrt(momenta_squared) identity_coefficient_nu = float(n_orbitals) / (4. * volume) * V_nu z_coefficient_nu = 1. / (4. * volume) * V_nu if verbose: print('V_nu: {}\n'.format(V_nu)) identity_coefficient -= identity_coefficient_nu z_coefficient += z_coefficient_nu if verbose: print('fieldlines = {}'.format(fieldlines)) print('identity coefficient: {}'.format(identity_coefficient)) print('Z coefficient: {}\n'.format(z_coefficient)) if spinless: identity_coefficient /= 2. # Add identity term. identity_term = QubitOperator((), identity_coefficient) hamiltonian += identity_term # Add local Z terms. for qubit in range(n_qubits): qubit_term = QubitOperator(((qubit, 'Z'),), z_coefficient) hamiltonian += qubit_term #------------------------------------------------------------------------- # Add ZZ terms and XZX + YZY terms. #------------------------------------------------------------------------- zz_prefactor = 0. # 3D case. if grid.dimensions == 3: zz_prefactor = numpy.pi / volume # 2D case. elif grid.dimensions == 2: zz_prefactor = 1. / (4. * volume) xzx_yzy_prefactor = .25 / float(n_orbitals) for p in range(n_qubits): index_p = grid.grid_indices(p, spinless) position_p = grid.position_vector(index_p) for q in range(p + 1, n_qubits): index_q = grid.grid_indices(q, spinless) position_q = grid.position_vector(index_q) difference = position_p - position_q skip_xzx_yzy = not spinless and (p + q) % 2 # Loop through momenta. zpzq_coefficient = 0. term_coefficient = 0. for k_indices in grid.all_points_indices(): momenta = momentum_vectors[k_indices] momenta_squared = momenta_squared_dict[k_indices] if momenta_squared == 0: continue cos_difference = numpy.cos(momenta.dot(difference)) zpzq_coefficient_nu = 0. # 3D case. if grid.dimensions == 3: zpzq_coefficient_nu = (zz_prefactor * cos_difference / momenta_squared) # If non-periodic. if non_periodic: correction = 1.0 - numpy.cos( period_cutoff * numpy.sqrt(momenta_squared)) zpzq_coefficient_nu *= correction if verbose: print('non_periodic') print('cutoff: {}'.format(period_cutoff)) print('correction: {}'.format(correction)) # 2D case. elif grid.dimensions == 2: V_nu = 0. # 2D Coulomb potential. if fieldlines == 2: # If non-periodic. if non_periodic: Dkv = period_cutoff * numpy.sqrt(momenta_squared) V_nu = ( 2. * numpy.pi / momenta_squared * ( Dkv * numpy.log(R0 / period_cutoff) * scipy.special.jv(1, Dkv) - scipy.special.jv(0, Dkv))) if verbose: print('non-periodic') print('cutoff: {}'.format(period_cutoff)) print('RO = {}'.format(R0)) # If periodic. else: var1 = 4. / momenta_squared var2 = 0.25 * momenta_squared V_nu = 0.5 * numpy.complex128( mpmath.meijerg([[1., 1.5, 2.], []], [[1.5], []], var1) - mpmath.meijerg([[-0.5, 0., 0.], []], [[-0.5, 0.], [-1.]], var2)) # 3D Coulomb potential. elif fieldlines == 3: # If non-periodic. if non_periodic: var = -0.25 * period_cutoff**2 * momenta_squared V_nu = numpy.complex128( 2 * numpy.pi * period_cutoff * mpmath.hyp1f2(0.5, 1., 1.5, var)) if verbose: print('non-periodic') print('cutoff: {}'.format(period_cutoff)) # If periodic. else: V_nu = 2 * numpy.pi / numpy.sqrt(momenta_squared) zpzq_coefficient_nu = zz_prefactor * cos_difference * V_nu zpzq_coefficient += zpzq_coefficient_nu if skip_xzx_yzy: continue term_coefficient += (xzx_yzy_prefactor * cos_difference * momenta_squared) # Add ZZ term. qubit_term = QubitOperator(((p, 'Z'), (q, 'Z')), zpzq_coefficient) hamiltonian += qubit_term # Add XZX + YZY term. if skip_xzx_yzy: continue z_string = tuple((i, 'Z') for i in range(p + 1, q)) xzx_operators = ((p, 'X'),) + z_string + ((q, 'X'),) yzy_operators = ((p, 'Y'),) + z_string + ((q, 'Y'),) hamiltonian += QubitOperator(xzx_operators, term_coefficient) hamiltonian += QubitOperator(yzy_operators, term_coefficient) # Include the Madelung constant if requested. if include_constant: # TODO Generalize to other cells hamiltonian += (QubitOperator((),) * (2.8372 / grid.volume_scale() ** (1./grid.dimensions))) # Return Hamiltonian. return hamiltonian
def dual_basis_jellium_model(grid, spinless=False, kinetic=True, potential=True, include_constant=False, non_periodic=False, period_cutoff=None, fieldlines=3, R0=1e8, verbose=False): """Return jellium Hamiltonian in the dual basis of arXiv:1706.00023 Args: grid (Grid): The discretization to use. spinless (bool): Whether to use the spinless model or not. kinetic (bool): Whether to include kinetic terms. potential (bool): Whether to include potential terms. include_constant (bool): Whether to include the Madelung constant. Note constant is unsupported for non-uniform, non-cubic cells with ions. non_periodic (bool): If the system is non-periodic, default to False. period_cutoff (float): Period cutoff, default to grid.volume_scale() ** (1. / grid.dimensions). fieldlines (int): Spatial dimension for electric field lines. R0 (float): Reference length scale where the 2D Coulomb potential is zero. verbose (bool): Whether to turn on print statements. Returns: operator (FermionOperator) """ if potential == True and grid.dimensions == 1: raise ValueError('System dimension cannot be 1.') # Initialize. n_points = grid.num_points position_prefactor = 0. # 3D case. if grid.dimensions == 3: position_prefactor = 2.0 * numpy.pi / grid.volume_scale() # 2D case. elif grid.dimensions == 2: position_prefactor = 1. / (2. * grid.volume_scale()) operator = FermionOperator() spins = [None] if spinless else [0, 1] if potential and non_periodic and period_cutoff is None: period_cutoff = grid.volume_scale() ** (1.0 / grid.dimensions) # Pre-Computations. position_vectors = {} momentum_vectors = {} momenta_squared_dict = {} orbital_ids = {} for indices in grid.all_points_indices(): # Store position vectors in dictionary, with corresponding # grid index as key. position_vectors[indices] = grid.position_vector(indices) # Get and store momentum vectors in dictionary, with corresponding # grid index as key. momenta = grid.momentum_vector(indices) momentum_vectors[indices] = momenta # Store momentum squared in dictionary, with corresponding # grid index as key. momenta_squared_dict[indices] = momenta.dot(momenta) # Store spin orbitals at each grid index in dictionary. orbital_ids[indices] = {} for spin in spins: orbital_ids[indices][spin] = grid.orbital_id(indices, spin) # This gives the position vector of the grid point at bottom-left-most # corner. # # x---x---x # | | | # x---x---x # | | | # this point <-- x---x---x # grid_origin = (0, ) * grid.dimensions coordinates_origin = position_vectors[grid_origin] # Loop once through all grid points. for grid_indices_b in grid.all_points_indices(): if verbose: print('Grid point: {}\n'.format(grid_indices_b)) # For all grid points, 'differences' gets the position displacement # from the 'origin' point. This corresponds to evaluating # (r_p - r_q) == r_(p-q). coordinates_b = position_vectors[grid_indices_b] differences = coordinates_b - coordinates_origin # Compute coefficients. kinetic_coefficient = 0. potential_coefficient = 0. # Loop once through all momentum indices, k_nu. for momenta_indices in grid.all_points_indices(): momenta = momentum_vectors[momenta_indices] momenta_squared = momenta_squared_dict[momenta_indices] if momenta_squared == 0: continue cos_difference = numpy.cos(momenta.dot(differences)) # This computes 1/(2N) * sum_nu{ k_nu^2 * cos[k_nu * r_(q-p)] } if kinetic: if verbose: print('Added kinetic term.') kinetic_coefficient += ( cos_difference * momenta_squared / (2. * float(n_points))) if verbose: print('Potential = {}'.format(potential)) # This computes 2pi/Omega * sum_nu{ cos[k_nu * r_(p-q)] / k_nu^2 } if potential: # Potential coefficient for this value of nu. potential_coefficient_nu = 0. # 3D case. if grid.dimensions == 3: potential_coefficient_nu = ( position_prefactor * cos_difference / momenta_squared) # If non-periodic. if non_periodic: correction = 1.0 - numpy.cos( period_cutoff * numpy.sqrt(momenta_squared)) potential_coefficient_nu *= correction if verbose: print('non_periodic') print('cutoff: {}'.format(period_cutoff)) print('correction: {}\n'.format(correction)) # 2D case. elif grid.dimensions == 2: V_nu = 0. # 2D Coulomb potential. if fieldlines == 2: # If non-periodic. if non_periodic: Dkv = period_cutoff * numpy.sqrt(momenta_squared) V_nu = ( 2. * numpy.pi / momenta_squared * ( Dkv * numpy.log(R0 / period_cutoff) * scipy.special.jv(1, Dkv) - scipy.special.jv(0, Dkv))) if verbose: print('non-periodic') print('cutoff: {}\n'.format(period_cutoff)) print('RO = {}'.format(R0)) # If periodic. else: var1 = 4. / momenta_squared var2 = 0.25 * momenta_squared V_nu = 0.5 * numpy.complex128( mpmath.meijerg([[1., 1.5, 2.], []], [[1.5], []], var1) - mpmath.meijerg([[-0.5, 0., 0.], []], [[-0.5, 0.], [-1.]], var2)) # 3D Coulomb potential. elif fieldlines == 3: # If non-periodic. if non_periodic: var = -0.25 * period_cutoff**2 * momenta_squared V_nu = numpy.complex128( 2 * numpy.pi * period_cutoff * mpmath.hyp1f2(0.5, 1., 1.5, var)) if verbose: print('non-periodic') print('cutoff: {}\n'.format(period_cutoff)) # If periodic. else: V_nu = 2. * numpy.pi / numpy.sqrt(momenta_squared) # Potential coefficient for this value of nu. potential_coefficient_nu = ( position_prefactor * V_nu * cos_difference) potential_coefficient += potential_coefficient_nu if verbose: print('fieldlines = {}'.format(fieldlines)) print('potential coefficient nu: {}\n'.format(potential_coefficient_nu)) if verbose: print('kinetic coefficient: {}'.format(kinetic_coefficient)) print('potential coefficient: {}\n'.format(potential_coefficient)) # Loop once through all grid points. # We have r_p - r_q fixed by 'differences' computed above. for grid_indices_shift in grid.all_points_indices(): # Loop over spins and identify interacting orbitals. orbital_a = {} orbital_b = {} # grid_origin = (0, ) * grid.dimensions # 'shifted_index_1' is equivalent to just 'grid_indices_shift'. shifted_index_1 = tuple( [(grid_origin[i] + grid_indices_shift[i]) % grid.length[i] for i in range(grid.dimensions)]) # 'shifted_index_2' shifted_index_2 = tuple( [(grid_indices_b[i] + grid_indices_shift[i]) % grid.length[i] for i in range(grid.dimensions)]) if verbose: print('shifted index 1: {}'.format(shifted_index_1)) print('shifted index 2: {}'.format(shifted_index_2)) for spin in spins: orbital_a[spin] = orbital_ids[shifted_index_1][spin] orbital_b[spin] = orbital_ids[shifted_index_2][spin] if kinetic: for spin in spins: operators = ((orbital_a[spin], 1), (orbital_b[spin], 0)) operator += FermionOperator(operators, kinetic_coefficient) if potential: for sa in spins: for sb in spins: if orbital_a[sa] == orbital_b[sb]: continue operators = ((orbital_a[sa], 1), (orbital_a[sa], 0), (orbital_b[sb], 1), (orbital_b[sb], 0)) operator += FermionOperator(operators, potential_coefficient) # Include the Madelung constant if requested. if include_constant: # TODO: Check for other unit cell shapes # Currently only for cubic cells. operator += (FermionOperator.identity() * (2.8372 / grid.volume_scale()**(1./grid.dimensions))) # Return. return operator
def FourierF(k): return sqrt(2 / pi) * special.kv(0, abs(k)) def FourierIntegral(k): return sqrt(pi / 2) * (1 / k - special.kv(0, k) * special.modstruve(-1, k) - special.kv(0, k) * special.modstruve(0, k)) interpolation_NUM = 1000 interpolation_points_x = np.logspace(-10, 1, interpolation_NUM) interpolation_points_y = map( lambda k: 1 / sqrt(4 * pi) * (5.568327996831708 - float( meijerg([[1], [1]], [[1 / 2, 1 / 2, 1 / 2], [0]], k, 1 / 2))) / k, interpolation_points_x) interpolated_function = interpolate.interp1d(interpolation_points_x, interpolation_points_y, fill_value='extrapolate') def SqFourierIntegral(k): if (k < 10): return interpolated_function(k) else: return 0 #from matplotlib import pyplot as plt #plt.loglog(interpolation_points_x, interpolation_points_y)
def lum(rr): if np.iterable(rr): return np.array([lum(r) for r in rr]) ss = rr / reff zz = (bb / (2 * mm))**(2 * mm) * ss**2 return (factor / ss) * mpmath.meijerg(avect, bvect, zz)
def luminosity(rr): if np.iterable(rr): return np.array([luminosity(r) for r in rr]) ss = rr / reff zz = (bb / (2 * pp))**(2 * pp) * ss**(2 * qq) return lum * ((factor / ss) * mpmath.meijerg(avect, bvect, zz))
def luminosity(rr): if np.iterable(rr): return np.array([luminosity(r) for r in rr]) ss = rr/reff zz = (bb/(2*pp))**(2*pp) * ss**(2*qq) return lum*((factor/ss)*mpmath.meijerg(avect, bvect, zz))
def analytic_solve(params, T, xs): # Use meijer-G function to calculate subdiffusion for alpha = 1/2 import mpmath D_alpha = params[0] integrand = lambda u: 1. / math.sqrt(8 * pow(math.pi,3) * D_alpha * math.sqrt(T)) * float(mpmath.meijerg([[],[]], [[0, 0.25, 0.5],[]], pow(u,4) / (256. * D_alpha * D_alpha * T))) return np.vectorize(lambda x: integrand(x))(xs) #1.0 - 2.0 * np.vectorize(lambda x: scipy.integrate.quad(integrand, 0., x)[0])(xs)