def dual_eigenspace(self, B=None): """ Return 1-dimensional subspace of the dual of the ambient space with the same system of eigenvalues as self. This is useful when computing a large number of `a_P`. If we can't find such a subspace using Hecke operators of norm less than B, then we raise a RuntimeError. This should only happen if you set B way too small, or self is actually not new. INPUT: - B -- Integer or None; if None, defaults to a heuristic bound. """ N = self.conductor() H = self._S.ambient() V = H.vector_space() if B is None: # TODO: This is a heuristic guess at a "Sturm bound"; it's the same # formula as the one over QQ for Gamma_0(N). I have no idea if this # is correct or not yet. It is probably much too large. -- William Stein from sage.modular.all import Gamma0 B = Gamma0(N.norm()).index()//6 + 1 for P in primes_of_bounded_norm(B+1): P = P.sage_ideal() if V.dimension() == 1: return V if not P.divides(N): T = H.hecke_matrix(P).transpose() V = (T - self.ap(P)).kernel_on(V) raise RuntimeError, "unable to isolate 1-dimensional space"
def dual_eigenspace(self, B=None): """ Return 1-dimensional subspace of the dual of the ambient space with the same system of eigenvalues as self. This is useful when computing a large number of `a_P`. If we can't find such a subspace using Hecke operators of norm less than B, then we raise a RuntimeError. This should only happen if you set B way too small, or self is actually not new. INPUT: - B -- Integer or None; if None, defaults to a heuristic bound. """ N = self.conductor() H = self._S.ambient() V = H.vector_space() if B is None: # TODO: This is a heuristic guess at a "Sturm bound"; it's the same # formula as the one over QQ for Gamma_0(N). I have no idea if this # is correct or not yet. It is probably much too large. -- William Stein from sage.modular.all import Gamma0 B = Gamma0(N.norm()).index() // 6 + 1 for P in primes_of_bounded_norm(B + 1): P = P.sage_ideal() if V.dimension() == 1: return V if not P.divides(N): T = H.hecke_matrix(P).transpose() V = (T - self.ap(P)).kernel_on(V) raise RuntimeError("unable to isolate 1-dimensional space")
def aplist(self, B, dual_bound=None, algorithm='dual'): """ Return list of traces of Frobenius for all primes P of norm less than bound. Use the function psage.number_fields.sqrt5.primes_of_bounded_norm(B) to get the corresponding primes. INPUT: - `B` -- a nonnegative integer - ``dual_bound`` -- default None; passed to dual_eigenvector function - ``algorithm`` -- 'dual' (default) or 'direct' OUTPUT: - a list of Sage integers EXAMPLES:: We compute the aplists up to B=50:: sage: from psage.modform.hilbert.sqrt5.hmf import HilbertModularForms, F sage: H = HilbertModularForms(F.primes_above(71)[1]).elliptic_curve_factors()[0] sage: v = H.aplist(50); v [-1, 0, -2, 0, 0, 2, -4, 6, -6, 8, 2, 6, 12, -4] This agrees with what we get using an elliptic curve of this conductor:: sage: a = F.0; E = EllipticCurve(F, [a,a+1,a,a,0]) sage: from psage.ellcurve.lseries.aplist_sqrt5 import aplist sage: w = aplist(E, 50) sage: v == w True We compare the output from the two algorithms up to norm 75:: sage: H.aplist(75, algorithm='direct') == H.aplist(75, algorithm='dual') True """ primes = [P.sage_ideal() for P in primes_of_bounded_norm(B)] if algorithm == 'direct': return [self.ap(P) for P in primes] elif algorithm == 'dual': v = self.dual_eigenvector(dual_bound) i = v.nonzero_positions()[0] c = v[i] I = self._S.ambient()._icosians_mod_p1 N = self.conductor() aplist = [] for P in primes: if P.divides(N): ap = self.ap(P) else: ap = (I.hecke_operator_on_basis_element( P, i).dot_product(v)) / c aplist.append(ap) return aplist else: raise ValueError("unknown algorithm '{0}'".format(algorithm))
def aplist(self, B, dual_bound=None, algorithm='dual'): """ Return list of traces of Frobenius for all primes P of norm less than bound. Use the function psage.number_fields.sqrt5.primes_of_bounded_norm(B) to get the corresponding primes. INPUT: - `B` -- a nonnegative integer - ``dual_bound`` -- default None; passed to dual_eigenvector function - ``algorithm`` -- 'dual' (default) or 'direct' OUTPUT: - a list of Sage integers EXAMPLES:: We compute the aplists up to B=50:: sage: from psage.modform.hilbert.sqrt5.hmf import HilbertModularForms, F sage: H = HilbertModularForms(F.primes_above(71)[1]).elliptic_curve_factors()[0] sage: v = H.aplist(50); v [-1, 0, -2, 0, 0, 2, -4, 6, -6, 8, 2, 6, 12, -4] This agrees with what we get using an elliptic curve of this conductor:: sage: a = F.0; E = EllipticCurve(F, [a,a+1,a,a,0]) sage: from psage.ellcurve.lseries.aplist_sqrt5 import aplist sage: w = aplist(E, 50) sage: v == w True We compare the output from the two algorithms up to norm 75:: sage: H.aplist(75, algorithm='direct') == H.aplist(75, algorithm='dual') True """ primes = [P.sage_ideal() for P in primes_of_bounded_norm(B)] if algorithm == 'direct': return [self.ap(P) for P in primes] elif algorithm == 'dual': v = self.dual_eigenvector(dual_bound) i = v.nonzero_positions()[0] c = v[i] I = self._S.ambient()._icosians_mod_p1 N = self.conductor() aplist = [] for P in primes: if P.divides(N): ap = self.ap(P) else: ap = (I.hecke_operator_on_basis_element(P,i).dot_product(v))/c aplist.append(ap) return aplist else: raise ValueError, "unknown algorithm '%s'"%algorithm