def zeta_function(self, var_name='T'): r""" Return the Zeta function of the curve. For any scheme `X` of finite type over `\mathbb{Z}`, the **arithmetic zeta funtion** of `X` is defined as the product .. MATH:: \zeta(X,s) := \prod_x \frac{1}{1-N(x)^{-s}}, where `x` runs over over all closed points of `X` and `N(x)` denotes the cardinality of the residue field of `x`. If `X` is a smooth projective curve over a field with `q` elements, then `\zeta(X,s) = Z(X,q^{-s})`, where `Z(X,T)` is a rational function in `T` of the form .. MATH:: Z(X,T) = \frac{P(T)}{(1-T)(1-qT)}, for a polynomial `P` of degree `2g`, with some extra properties reflecting the Weil conjectures. See: - Hartshorn, *Algebraic Geometry*, Appendix C, Section 1. Note that that this makes only sense if the constant base field of self is finite, and that `Z(X,T)` depends on the choice of the constant base field (unlike the function `\zeta(X,s)`!). """ if hasattr(self,"_zeta_function"): return self._zeta_function K = self._constant_base_field q = K.order() g = self.genus() S = PowerSeriesRing(ZZ, var_name, g+1) N = self.count_points(g) Z_series = S(1) for k in range(1,g+1): Z_series *= (1-S.gen()**k)**(-N[k]) P = (Z_series*(1-S.gen())*(1-q*S.gen())).polynomial() c = range(2*g+1) for k in range(g+1): c[k] = P[k] for k in range(g+1,2*g+1): c[k] = c[2*g-k]*q**(k-g) R = P.parent() zeta = R(c)/(1-R.gen())/(1-q*R.gen()) self._zeta_function = zeta return zeta
def get_factor_over_nf(curve, prime_ideal, prime_number, conductor, accuracy): """ Returns the inverse of the factor corresponding to the given prime ideal in the Euler product expansion of the L-function at prime_ideal. Unless the accuracy doesn't need this expansion, and then returns 1 in power series ring. """ P = PowerSeriesRing(ZZ, 'T') T = P.gen() q = prime_ideal.norm() inertial_deg = Integer(q).ord(prime_number) if inertial_deg > accuracy: return P(1) if prime_ideal.divides(conductor): a = curve.local_data(prime_ideal).bad_reduction_type() L = 1 - a * (T**inertial_deg) else: discriminant = curve.discriminant() if prime_ideal.divides(discriminant): a = q + 1 - curve.local_minimal_model(prime_ideal).reduction( prime_ideal).count_points() else: a = q + 1 - curve.reduction(prime_ideal).count_points() L = 1 - a * (T**inertial_deg) + q * (T**(2 * inertial_deg)) return L
def set_from_coefficients(self, coeffs): QR = PowerSeriesRing(QQ,name='q',order='neglex') q = QR.gen() res = 0*q**0 for n, c in coeffs.iteritems(): res += c*q**n res = res.add_bigoh(len(coeffs.keys())+1) self.set_value(res)
def set_from_coefficients(self, coeffs): if not len(coeffs) == 0: QR = PowerSeriesRing(coeffs.values()[0].parent(),name='q',order='neglex') q = QR.gen() res = 0*q**0 for n, c in coeffs.iteritems(): res += c*q**n res = res.add_bigoh(len(coeffs.keys())+1) self.set_value(res)
def euler_p_factor(root_list, PREC): ''' computes the coefficients of the pth Euler factor expanded as a geometric series ax^n is the Dirichlet series coefficient p^(-ns) ''' PREC = floor(PREC) # return satake_list R = PowerSeriesRing(CF, 'x') x = R.gen() ep = ~R.prod([1 - a * x for a in root_list]) return ep.O(PREC + 1)
def hilbert_series_using_cand_wts(i, parity, prec=None): wts = load_cand_wts(i, parity) if prec is None: prec = max(wts[0]) ps = PowerSeriesRing(QQ, names='t', default_prec=prec + 1) t = ps.gen() num = sum(t**a for a in wts[0]) if len(wts) > 1: num -= sum(t**a for a in wts[1]) dnm = (1 - t**2) * (1 - t**4) * (1 - t**6) return num / dnm
def hilbert_series_using_dimension_formula(i, prec=10): ''' This assumes dimension formula is true for weight (2, k) where k > 2 and the dimesion for (1, k) k > 2 is zero. If one believes magma, the assumption for (2, k) can be checked for some cases. And the assumption for (1, k) can be checked by the construction. ''' ps = PowerSeriesRing(QQ, names='t', default_prec=prec + 1) t = ps.gen() return (sum(dimension_cuspforms_sqrt5(a, a + 2 * i) * t**a for a in range(2, prec + 1)) + O(t**(prec + 1)))
def hilbert_series_maybe(j, parity=None, prec=30): ''' Returns a hilbert series which is equal to sum_{k > 0} M_{k, j}(Gamma_{2}) t^k modulo a polynomial of degree < 5. ''' R = PowerSeriesRing(QQ, names="t", default_prec=prec) t = R.gen() dnm = R(t_dnm()) nm = hilbert_series_num_maybe(j, parity=parity) return (nm + O(t ** prec)) / dnm
def t_delete_terms_of_small_degrees(f): ''' f is a polynomial of t. Returns a polynomial g which is congruent to f modulo t_dnm so that g/t_dnm does not have terms with degree < 4. ''' R = PowerSeriesRing(QQ, names="t") S = PolynomialRing(QQ, names="t") t = R.gen() dnm = R(t_dnm()) g = R(f / dnm) + O(t ** 4) a = S(sum([t ** i * g[i] for i in range(4)])) return f - t_dnm() * a
def _dimension_Gamma0_4(wt): """ Return the dimensions of subspaces of Siegel modular forms on $Gamma0(4)$. OUTPUT ("Total",) REMARK Not completely implemented """ R = PowerSeriesRing(ZZ, 'x') x = R.gen().O(wt + 1) H_all = (1 + x**4) * (1 + x**11) / (1 - x**2)**3 / (1 - x**6) return (H_all[wt], )
def _dimension_Gamma0_3(wt): """ Return the dimensions of subspaces of Siegel modular forms on $Gamma0(3)$. OUTPUT ("Total") REMARK Only total dimension implemented. """ R = PowerSeriesRing(ZZ, 'x') x = R.gen().O(wt + 1) H_all = (1 + 2 * x**4 + x**6 + x**15 * (1 + 2 * x**2 + x**6)) / (1 - x**2) / (1 - x**4) / (1 - x**6)**2 return (H_all[wt], )
def get_factor_over_nf(curve, prime_ideal, prime_number, conductor, accuracy): """ Returns the inverse of the factor corresponding to the given prime ideal in the Euler product expansion of the L-function at prime_ideal. Unless the accuracy doesn't need this expansion, and then returns 1 in power series ring. """ P = PowerSeriesRing(ZZ, 'T') T = P.gen() q = prime_ideal.norm() inertial_deg = Integer(q).ord(prime_number) if inertial_deg > accuracy: return P(1) if prime_ideal.divides(conductor): a = curve.local_data(prime_ideal).bad_reduction_type() L = 1 - a*(T**inertial_deg) else: discriminant = curve.discriminant() if prime_ideal.divides(discriminant): a = q + 1 - curve.local_minimal_model(prime_ideal).reduction(prime_ideal).count_points() else: a = q + 1 - curve.reduction(prime_ideal).count_points() L = 1 - a*(T**inertial_deg) + q*(T**(2*inertial_deg)) return L
def hilbert_series_using_dimension_formula(i, parity, prec=10): ps = PowerSeriesRing(QQ, names='t', default_prec=prec + 1) t = ps.gen() return (sum( cuspforms_dimension((a, a + 2 * i)) * t**a for a in range(2, prec + 1) if is_even(a + parity)) + O(t**(prec + 1)))
def gen_func_maybe_cusp_num_t_power_srs(parity=None, prec=10): R = PolynomialRing(QQ, names="t") S = PowerSeriesRing(R, names="s", default_prec=prec) s = S.gen() num = gen_func_maybe_cusp_num_t(parity=parity) return S(num) + O(s ** prec)
def anlist_over_sqrt5(E, bound): """ Compute the Dirichlet L-series coefficients, up to and including a_bound. The i-th element of the return list is a[i]. INPUT: - E -- elliptic curve over Q(sqrt(5)), which must have defining polynomial `x^2-x-1`. - ``bound`` -- integer OUTPUT: - list of integers of length bound + 1 EXAMPLES:: sage: from psage.ellcurve.lseries.lseries_nf import anlist_over_sqrt5 sage: K.<a> = NumberField(x^2-x-1); E = EllipticCurve([0,-a,a,0,0]) sage: v = anlist_over_sqrt5(E, 50); v [0, 1, 0, 0, -2, -1, 0, 0, 0, -4, 0, 3, 0, 0, 0, 0, 0, 0, 0, 5, 2, 0, 0, 0, 0, -4, 0, 0, 0, 11, 0, -6, 0, 0, 0, 0, 8, 0, 0, 0, 0, -1, 0, 0, -6, 4, 0, 0, 0, -6, 0] sage: len(v) 51 This function isn't super fast, but at least it will work in a few seconds up to `10^4`:: sage: t = cputime() sage: v = anlist_over_sqrt5(E, 10^4) sage: assert cputime(t) < 5 """ import aplist_sqrt5 from psage.number_fields.sqrt5.prime import primes_of_bounded_norm, Prime # Compute all of the prime ideals of the ring of integers up to the given bound primes = primes_of_bounded_norm(bound+1) # Compute the traces of Frobenius: this is supposed to be the hard part v = aplist_sqrt5.aplist(E, bound+1) # Compute information about the primes of bad reduction, in # particular the integers i such that primes[i] is a prime of bad # reduction. bad_primes = set([Prime(a.prime()) for a in E.local_data()]) # We compute the local factors of the L-series as power series in ZZ[T]. P = PowerSeriesRing(ZZ, 'T') T = P.gen() # Table of powers of T, so we don't have to compute T^4 (say) thousands of times. Tp = [T**i for i in range(5)] # For each prime, we write down the local factor. L_P = [] for i, P in enumerate(primes): inertial_deg = 2 if P.is_inert() else 1 a_p = v[i] if P in bad_primes: # bad reduction f = 1 - a_p*Tp[inertial_deg] else: # good reduction q = P.norm() f = 1 - a_p*Tp[inertial_deg] + q*Tp[2*inertial_deg] L_P.append(f) # Use the local factors of the L-series to compute the Dirichlet # series coefficients of prime-power index. coefficients = [0,1] + [0]*(bound-1) i = 0 while i < len(primes): P = primes[i] if P.is_split(): s = L_P[i] * L_P[i+1] i += 2 else: s = L_P[i] i += 1 p = P.p # We need enough terms t so that p^t > bound accuracy_p = int(math.floor(math.log(bound)/math.log(p))) + 1 series_p = s.add_bigoh(accuracy_p)**(-1) for j in range(1, accuracy_p): coefficients[p**j] = series_p[j] # Using multiplicativity, fill in the non-prime power Dirichlet # series coefficients. extend_multiplicatively_generic(coefficients) return coefficients
def anlist_over_sqrt5(E, bound): """ Compute the Dirichlet L-series coefficients, up to and including a_bound. The i-th element of the return list is a[i]. INPUT: - E -- elliptic curve over Q(sqrt(5)), which must have defining polynomial `x^2-x-1`. - ``bound`` -- integer OUTPUT: - list of integers of length bound + 1 EXAMPLES:: sage: from psage.ellcurve.lseries.lseries_nf import anlist_over_sqrt5 sage: K.<a> = NumberField(x^2-x-1); E = EllipticCurve([0,-a,a,0,0]) sage: v = anlist_over_sqrt5(E, 50); v [0, 1, 0, 0, -2, -1, 0, 0, 0, -4, 0, 3, 0, 0, 0, 0, 0, 0, 0, 5, 2, 0, 0, 0, 0, -4, 0, 0, 0, 11, 0, -6, 0, 0, 0, 0, 8, 0, 0, 0, 0, -1, 0, 0, -6, 4, 0, 0, 0, -6, 0] sage: len(v) 51 This function isn't super fast, but at least it will work in a few seconds up to `10^4`:: sage: t = cputime() sage: v = anlist_over_sqrt5(E, 10^4) sage: assert cputime(t) < 5 """ from . import aplist_sqrt5 from psage.number_fields.sqrt5.prime import primes_of_bounded_norm, Prime # Compute all of the prime ideals of the ring of integers up to the given bound primes = primes_of_bounded_norm(bound + 1) # Compute the traces of Frobenius: this is supposed to be the hard part v = aplist_sqrt5.aplist(E, bound + 1) # Compute information about the primes of bad reduction, in # particular the integers i such that primes[i] is a prime of bad # reduction. bad_primes = set([Prime(a.prime()) for a in E.local_data()]) # We compute the local factors of the L-series as power series in ZZ[T]. P = PowerSeriesRing(ZZ, 'T') T = P.gen() # Table of powers of T, so we don't have to compute T^4 (say) thousands of times. Tp = [T**i for i in range(5)] # For each prime, we write down the local factor. L_P = [] for i, P in enumerate(primes): inertial_deg = 2 if P.is_inert() else 1 a_p = v[i] if P in bad_primes: # bad reduction f = 1 - a_p * Tp[inertial_deg] else: # good reduction q = P.norm() f = 1 - a_p * Tp[inertial_deg] + q * Tp[2 * inertial_deg] L_P.append(f) # Use the local factors of the L-series to compute the Dirichlet # series coefficients of prime-power index. coefficients = [0, 1] + [0] * (bound - 1) i = 0 while i < len(primes): P = primes[i] if P.is_split(): s = L_P[i] * L_P[i + 1] i += 2 else: s = L_P[i] i += 1 p = P.p # We need enough terms t so that p^t > bound accuracy_p = int(math.floor(old_div(math.log(bound), math.log(p)))) + 1 series_p = s.add_bigoh(accuracy_p)**(-1) for j in range(1, accuracy_p): coefficients[p**j] = series_p[j] # Using multiplicativity, fill in the non-prime power Dirichlet # series coefficients. extend_multiplicatively_generic(coefficients) return coefficients
def verify_algebraically_PS(g, P0, alpha, trace_and_norm, verbose=True): # input: # * P0 (only necessary to shift the series) # * [trace_numerator, trace_denominator, norm_numerator, norm_denominator] # output: # a boolean if verbose: print "verify_algebraically()" L = P0.base_ring() assert alpha.base_ring() is L L_poly = PolynomialRing(L, "xL") xL = L_poly.gen() # shifting the series makes our life easier trace_numerator, trace_denominator, norm_numerator, norm_denominator = [ L_poly(coeff)(L_poly.gen() + P0[0]) for coeff in trace_and_norm ] L_fpoly = L_poly.fraction_field() trace = L_fpoly(trace_numerator) / L_fpoly(trace_denominator) norm = L_fpoly(norm_numerator) / L_fpoly(norm_denominator) Xpoly = L_poly([norm(0), -trace(0), 1]) if verbose: print "xpoly = %s" % Xpoly if Xpoly.is_irreducible(): M = Xpoly.root_field("c") else: # this avoids bifurcation later on in the code M = NumberField(xL, "c") if verbose: print M xi_degree = max( [elt.degree() for elt in [trace_denominator, norm_denominator]]) D = 2 * xi_degree hard_bound = D + (4 + 2) soft_bound = hard_bound + 5 M_ps = PowerSeriesRing(M, "T", default_prec=soft_bound) T = M_ps.gen() Tsub = T + P0[0] trace_M = M_ps(trace) norm_M = M_ps(norm) sqrtdisc = sqrt(trace_M**2 - 4 * norm_M) x1 = (trace_M - sqrtdisc) / 2 x2 = (trace_M + sqrtdisc) / 2 y1 = sqrt(g(x1)) y2 = sqrt(g(x2)) iy = 1 / sqrt(g(Tsub)) dx1 = x1.derivative(T) dx2 = x2.derivative(T) dx1_y1 = dx1 / y1 dx2_y2 = dx2 / y2 eq1 = Matrix([[-2 * M_ps(alpha.row(0).list())(Tsub) * iy, dx1_y1, dx2_y2]]) eq2 = Matrix( [[-2 * M_ps(alpha.row(1).list())(Tsub) * iy, x1 * dx1_y1, x2 * dx2_y2]]) branches = Matrix([[1, 1, 1], [1, 1, -1], [1, -1, 1], [1, -1, -1]]).transpose() meq1 = eq1 * branches meq2 = eq2 * branches algzero = False for j in range(4): if meq1[0, j] == 0 and meq2[0, j] == 0: algzero = True break if verbose: print "Done, verify_algebraically() = %s" % algzero return algzero