def __pow__(self, n): """ Returns this species to the power n. This uses a binary exponentiation algorithm to perform the powering. EXAMPLES:: sage: X = species.SingletonSpecies() sage: (X^2).generating_series().coefficients(4) [0, 0, 1, 0] sage: X^1 is X True sage: A = X^32 sage: A.digraph() Multi-digraph on 6 vertices """ from sage.rings.all import Integer import operator n = Integer(n) if n <= 0: raise ValueError, "only positive exponents are currently supported" digits = n.digits(2) squares = [self] for i in range(len(digits)-1): squares.append(squares[-1]*squares[-1]) return reduce(operator.add, (s for i,s in zip(digits, squares) if i != 0))
def _element_constructor_(self, x) : """ TESTS:: sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import * sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import MonoidPowerSeriesRing_generic sage: mps = MonoidPowerSeriesRing_generic(QQ, NNMonoid(False)) sage: h = mps(1) # indirect doctest sage: h = mps(mps.monoid().zero_element()) sage: h = mps.zero_element() sage: K.<rho> = CyclotomicField(6) sage: mps = MonoidPowerSeriesRing_generic(K, NNMonoid(False)) sage: h = mps(rho) sage: h = mps(1) """ if isinstance(x, int) : x = Integer(x) if isinstance(x, Element) : P = x.parent() if P is self.coefficient_domain() : return self._element_class( self, {self.monoid().zero_element(): x}, self.monoid().filter_all() ) elif self.coefficient_domain().has_coerce_map_from(P) : return self._element_class( self, {self.monoid().zero_element(): self.coefficient_domain()(x)}, self.monoid().filter_all() ) elif P is self.monoid() : return self._element_class( self, {x: self.base_ring().one_element}, self.monoid().filter_all() ) return MonoidPowerSeriesAmbient_abstract._element_constructor_(self, x)
def duke_imamoglu_lift(self, f, f_k, precision, half_integral_weight = False) : """ INPUT: - ``half_integral_weight`` -- If ``False`` we assume that `f` is the Fourier expansion of a Jacobi form. Otherwise we assume it is the Fourier expansion of a half integral weight elliptic modular form. """ if half_integral_weight : coeff_index = lambda d : d else : coeff_index = lambda d : ((d + (-d % 4)) // 4, (-d) % 4) coeffs = dict() for t in precision.iter_positive_forms() : dt = (-1)**(precision.genus() // 2) * t.det() d = fundamental_discriminant(dt) eps = Integer(isqrt(dt / d)) coeffs[t] = 0 for a in eps.divisors() : d_a = abs(d * (eps // a)**2) coeffs[t] = coeffs[t] + a**(f_k - 1) * self._kohnen_phi(a, t) \ * f[coeff_index(d_a)] return coeffs
def __pow__(self, n): r""" Returns this species to the power `n`. This uses a binary exponentiation algorithm to perform the powering. EXAMPLES:: sage: One = species.EmptySetSpecies() sage: X = species.SingletonSpecies() sage: X^2 Product of (Singleton species) and (Singleton species) sage: X^5 Product of (Singleton species) and (Product of (Product of (Singleton species) and (Singleton species)) and (Product of (Singleton species) and (Singleton species))) sage: (X^2).generating_series().coefficients(4) [0, 0, 1, 0] sage: (X^3).generating_series().coefficients(4) [0, 0, 0, 1] sage: ((One+X)^3).generating_series().coefficients(4) [1, 3, 3, 1] sage: ((One+X)^7).generating_series().coefficients(8) [1, 7, 21, 35, 35, 21, 7, 1] sage: x = QQ[['x']].gen() sage: coeffs = ((1+x+x+x**2)**25+O(x**10)).padded_list() sage: T = ((One+X+X+X^2)^25) sage: T.generating_series().coefficients(10) == coeffs True sage: X^1 is X True sage: A = X^32 sage: A.digraph() Multi-digraph on 6 vertices TESTS:: sage: X**(-1) Traceback (most recent call last): ... ValueError: only positive exponents are currently supported """ from sage.rings.all import Integer import operator n = Integer(n) if n <= 0: raise ValueError("only positive exponents are currently supported") digits = n.digits(2) squares = [self] for i in range(len(digits) - 1): squares.append(squares[-1] * squares[-1]) return reduce(operator.mul, (s for i, s in zip(digits, squares) if i != 0))
def __init__(self, abvar, p): """ Create a `p`-adic `L`-series. EXAMPLES:: sage: J0(37)[0].padic_lseries(389) 389-adic L-series attached to Simple abelian subvariety 37a(1,37) of dimension 1 of J0(37) """ Lseries.__init__(self, abvar) p = Integer(p) if not p.is_prime(): raise ValueError("p (=%s) must be prime"%p) self.__p = p
def validate_label(label): parts = label.split('.') if len(parts) != 3: raise ValueError("it must be of the form g.q.iso, with g a dimension and q a prime power") g, q, iso = parts try: g = int(g) except ValueError: raise ValueError("it must be of the form g.q.iso, where g is an integer") try: q = Integer(q) if not q.is_prime_power(): raise ValueError except ValueError: raise ValueError("it must be of the form g.q.iso, where g is a prime power") coeffs = iso.split("_") if len(coeffs) != g: raise ValueError("the final part must be of the form c1_c2_..._cg, with g=%s components"%(g)) if not all(c.isalpha() and c==c.lower() for c in coeffs): raise ValueError("the final part must be of the form c1_c2_..._cg, with each ci consisting of lower case letters")
def apply_T(self, j): """ Apply the matrix `T=[0,1,-1,-1]` to the `j`-th Manin symbol. INPUT: - ``j`` - (int) a symbol index OUTPUT: see documentation for apply() EXAMPLE:: sage: from sage.modular.modsym.manin_symbol_list import ManinSymbolList_gamma0 sage: m = ManinSymbolList_gamma0(5,8) sage: m.apply_T(4) [(3, 1), (9, -6), (15, 15), (21, -20), (27, 15), (33, -6), (39, 1)] sage: [m.apply_T(i) for i in xrange(10)] [[(5, 1), (11, -6), (17, 15), (23, -20), (29, 15), (35, -6), (41, 1)], [(0, 1), (6, -6), (12, 15), (18, -20), (24, 15), (30, -6), (36, 1)], [(4, 1), (10, -6), (16, 15), (22, -20), (28, 15), (34, -6), (40, 1)], [(2, 1), (8, -6), (14, 15), (20, -20), (26, 15), (32, -6), (38, 1)], [(3, 1), (9, -6), (15, 15), (21, -20), (27, 15), (33, -6), (39, 1)], [(1, 1), (7, -6), (13, 15), (19, -20), (25, 15), (31, -6), (37, 1)], [(5, 1), (11, -5), (17, 10), (23, -10), (29, 5), (35, -1)], [(0, 1), (6, -5), (12, 10), (18, -10), (24, 5), (30, -1)], [(4, 1), (10, -5), (16, 10), (22, -10), (28, 5), (34, -1)], [(2, 1), (8, -5), (14, 10), (20, -10), (26, 5), (32, -1)]] """ k = self._weight i, u, v = self._symbol_list[j] u, v = self.__syms.normalize(v,-u-v) if (k-2) % 2 == 0: s = 1 else: s = -1 z = [] a = Integer(k-2-i) for j in range(k-2-i+1): m = self.index((j, u, v)) z.append((m, s * a.binomial(j))) s *= -1 return z
def apply_TT(self, j): """ Apply the matrix `TT=[-1,-1,0,1]` to the `j`-th Manin symbol. INPUT: - ``j`` - (int) a symbol index OUTPUT: see documentation for apply() EXAMPLE:: sage: from sage.modular.modsym.manin_symbol_list import ManinSymbolList_gamma0 sage: m = ManinSymbolList_gamma0(5,8) sage: m.apply_TT(4) [(38, 1)] sage: [m.apply_TT(i) for i in xrange(10)] [[(37, 1)], [(41, 1)], [(39, 1)], [(40, 1)], [(38, 1)], [(36, 1)], [(31, -1), (37, 1)], [(35, -1), (41, 1)], [(33, -1), (39, 1)], [(34, -1), (40, 1)]] """ k = self._weight i, u, v = self._symbol_list[j] u, v = self.__syms.normalize(-u-v,u) if (k-2-i) % 2 == 0: s = 1 else: s = -1 z = [] a = Integer(i) for j in range(i+1): m = self.index((k-2-i+j, u, v)) z.append((m, s * a.binomial(j))) s *= -1 return z
def apply_TT(self, j): """ Apply the matrix `TT=[-1,-1,0,1]` to the `j`-th Manin symbol. INPUT: - ``j`` - (integer) a symbol index OUTPUT: A list of pairs `(j, c_i)`, where each `c_i` is an integer, `j` is an integer (the `j`-th Manin symbol), and the sum `c_i*x_i` is the image of self under the right action of the matrix `T^2`. EXAMPLE:: sage: eps = DirichletGroup(4).gen(0) sage: from sage.modular.modsym.manin_symbol_list import ManinSymbolList_character sage: m = ManinSymbolList_character(eps,2); m Manin Symbol List of weight 2 for Gamma1(4) with character [-1] sage: m.apply_TT(4) [(0, 1)] sage: [m.apply_TT(i) for i in xrange(len(m))] [[(1, -1)], [(4, -1)], [(5, 1)], [(2, 1)], [(0, 1)], [(3, 1)]] """ k = self._weight i, u, v = self._symbol_list[j] u, v, r = self.__P1.normalize_with_scalar(-u-v,u) r = self.__character(r) if (k-2-i) % 2 == 0: s = r else: s = -r z = [] a = Integer(i) for j in range(i+1): m, r = self.index((k-2-i+j, u, v)) z.append((m, s * r * a.binomial(j))) s *= -1 return z
def ap(self, p): """ Return a list of the eigenvalues of the Hecke operator `T_p` on all the computed eigenforms. The eigenvalues match up between one prime and the next. INPUT: - ``p`` - integer, a prime number OUTPUT: - ``list`` - a list of double precision complex numbers EXAMPLES:: sage: n = numerical_eigenforms(11,4) sage: n.ap(2) # random order [9.0, 9.0, 2.73205080757, -0.732050807569] sage: n.ap(3) # random order [28.0, 28.0, -7.92820323028, 5.92820323028] sage: m = n.modular_symbols() sage: x = polygen(QQ, 'x') sage: m.T(2).charpoly('x').factor() (x - 9)^2 * (x^2 - 2*x - 2) sage: m.T(3).charpoly('x').factor() (x - 28)^2 * (x^2 + 2*x - 47) """ p = Integer(p) if not p.is_prime(): raise ValueError("p must be a prime") try: return self._ap[p] except AttributeError: self._ap = {} except KeyError: pass a = Sequence(self.eigenvalues([p])[0], immutable=True) self._ap[p] = a return a
def xi_degrees(n,p=2, reverse=True): r""" Decreasing list of degrees of the xi_i's, starting in degree n. INPUT: - `n` - integer - `p` - prime number, optional (default 2) - ``reverse`` - bool, optional (default True) OUTPUT: ``list`` - list of integers When `p=2`: decreasing list of the degrees of the `\xi_i`'s with degree at most n. At odd primes: decreasing list of these degrees, each divided by `2(p-1)`. If ``reverse`` is False, then return an increasing list rather than a decreasing one. EXAMPLES:: sage: sage.algebras.steenrod.steenrod_algebra_bases.xi_degrees(17) [15, 7, 3, 1] sage: sage.algebras.steenrod.steenrod_algebra_bases.xi_degrees(17, reverse=False) [1, 3, 7, 15] sage: sage.algebras.steenrod.steenrod_algebra_bases.xi_degrees(17,p=3) [13, 4, 1] sage: sage.algebras.steenrod.steenrod_algebra_bases.xi_degrees(400,p=17) [307, 18, 1] """ from sage.rings.all import Integer if n <= 0: return [] N = Integer(n*(p-1) + 1) l = [int((p**d-1)/(p-1)) for d in range(1,N.exact_log(p)+1)] if not reverse: return l l.reverse() return l
def _element_constructor_(self, x) : """ TESTS:: sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import * sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import EquivariantMonoidPowerSeriesRing_generic sage: emps = EquivariantMonoidPowerSeriesRing_generic(NNMonoid(True), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ)) sage: h = emps(1) sage: h = emps(emps.monoid().zero_element()) sage: h = emps.zero_element() sage: K.<rho> = CyclotomicField(6) sage: emps = EquivariantMonoidPowerSeriesRing_generic(NNMonoid(True), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", K)) sage: h = emps(rho) sage: h = emps(1) """ if isinstance(x, int) : x = Integer(x) if isinstance(x, Element) : P = x.parent() if P is self.coefficient_domain() : return self._element_class( self, {self.characters().one_element(): {self.monoid().zero_element(): x}}, self.action().filter_all() ) elif self.coefficient_domain().has_coerce_map_from(P) : return self._element_class( self, {self.characters().one_element(): {self.monoid().zero_element(): self.coefficient_domain()(x)}}, self.action().filter_all() ) elif P is self.monoid() : return self._element_class( self, {self.characters().one_element(): {x: self.base_ring().one_element()}}, self.action().filter_all(), symmetrise = True ) return EquivariantMonoidPowerSeriesAmbient_abstract._element_constructor_(self, x)
def cuboctahedron(self): """ An Archimedean solid with 12 vertices and 14 faces. Dual to the rhombic dodecahedron. EXAMPLES:: sage: co = polytopes.cuboctahedron() sage: co.n_vertices() 12 sage: co.n_inequalities() 14 """ one = Integer(1) v = [[0, -one / 2, -one / 2], [0, one / 2, -one / 2], [one / 2, -one / 2, 0], [one / 2, one / 2, 0], [one / 2, 0, one / 2], [one / 2, 0, -one / 2], [0, one / 2, one / 2], [0, -one / 2, one / 2], [-one / 2, 0, one / 2], [-one / 2, one / 2, 0], [-one / 2, 0, -one / 2], [-one / 2, -one / 2, 0]] return Polyhedron(vertices=v)
def num_coeffs(self, T=1): """ Return number of coefficients `a_n` that are needed in order to perform most relevant `L`-function computations to the desired precision. EXAMPLES:: sage: E = EllipticCurve('11a') sage: L = E.lseries().dokchitser() sage: L.num_coeffs() 26 sage: E = EllipticCurve('5077a') sage: L = E.lseries().dokchitser() sage: L.num_coeffs() 568 sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], init='1') sage: L.num_coeffs() 4 """ return Integer(self._gp_call_inst('cflength', T))
def lfsr_autocorrelation(L, p, k): """ INPUT: - ``L`` - is a periodic sequence of elements of ZZ or GF(2). L must have length = p - ``p`` - the period of L - ``k`` - k is an integer (0 k p) OUTPUT: autocorrelation sequence of L EXAMPLES:: sage: F = GF(2) sage: o = F(0) sage: l = F(1) sage: key = [l,o,o,l]; fill = [l,l,o,l]; n = 20 sage: s = lfsr_sequence(key,fill,n) sage: lfsr_autocorrelation(s,15,7) 4/15 sage: lfsr_autocorrelation(s,int(15),7) 4/15 AUTHORS: - Timothy Brock (2006-04-17) """ if not isinstance(L, list): raise TypeError("L (=%s) must be a list" % L) p = Integer(p) _p = int(p) k = int(k) L0 = L[:_p] # slices makes a copy L0 = L0 + L0[:k] L1 = [int(L0[i]) * int(L0[i + k]) / p for i in range(_p)] return sum(L1)
def _induced_flags(self, n, tg, type_edges): flag_counts = {} flags = [] total = 0 for p in Tuples([0, 1], binomial(n, 2) - binomial(tg.n, 2)): edges = list(type_edges) c = 0 for i in range(tg.n + 1, n + 1): for j in range(1, i): if p[c] == 1: edges.append((j, i)) c += 1 ig = ThreeGraphFlag() ig.n = n ig.t = tg.n for s in Combinations(list(range(1, n + 1)), 3): ind_edges = [e for e in edges if e[0] in s and e[1] in s] if len(ind_edges) == 1 or len(ind_edges) == 3: ig.add_edge(s) it = ig.induced_subgraph(list(range(1, tg.n + 1))) if tg.is_labelled_isomorphic(it): ig.make_minimal_isomorph() ghash = hash(ig) if ghash in flag_counts: flag_counts[ghash] += 1 else: flags.append(ig) flag_counts[ghash] = 1 total += 1 return [(f, flag_counts[hash(f)] / Integer(total)) for f in flags]
def _cl_term(n, R = RationalField()): r""" Compute the order-n term of the cycle index series of the virtual species `\Omega`, the compositional inverse of the species `E^{+}` of nonempty sets. EXAMPLES:: sage: from sage.combinat.species.generating_series import _cl_term sage: [_cl_term(i) for i in range(4)] [0, p[1], -1/2*p[1, 1] - 1/2*p[2], 1/3*p[1, 1, 1] - 1/3*p[3]] """ n = Integer(n) # check that n is an integer p = SymmetricFunctions(R).power() res = p.zero() if n == 1: res = p([1]) elif n > 1: res = 1/n * ((-1)**(n-1) * p([1])**n - sum(d * p([n // d]).plethysm(_cl_term(d, R)) for d in divisors(n)[:-1])) return res
def additive_order(self): """ Return the additive order of this element. EXAMPLES:: sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2]) sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (4, 12) sage: Q.0.additive_order() 4 sage: Q.1.additive_order() 12 sage: (Q.0+Q.1).additive_order() 12 sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1]) sage: Q = V/W; Q Finitely generated module V/W over Integer Ring with invariants (12, 0) sage: Q.0.additive_order() 12 sage: type(Q.0.additive_order()) <type 'sage.rings.integer.Integer'> sage: Q.1.additive_order() +Infinity """ Q = self.parent() I = Q.invariants() v = self.vector() from sage.rings.all import infinity, Mod, Integer from sage.arith.all import lcm n = Integer(1) for i, a in enumerate(I): if a == 0: if v[i] != 0: return infinity else: n = lcm(n, Mod(v[i],a).additive_order()) return n
def __init__(self, parent, val=0, quick=False): ModuleElement.__init__(self, parent) self._parent = parent self._n = self._parent._n self._nhalf = Integer(self._n / 2) self._depth = self._parent._depth if quick: self._val = val else: if isinstance(val, self.__class__): d = min([val._parent._depth, parent._depth]) assert (val._parent.weight() == parent.weight()) self._val = Matrix(self._parent._R, self._depth, 1, 0) for ii in range(d): self._val[ii, 0] = val._val[ii, 0] else: try: self._val = MatrixSpace(self._parent._R, self._depth, 1)(val) except: self._val = val * ones_matrix(self._parent._R, self._depth, 1)
class ParamodularFormD2_classical ( ParamodularFormD2_generic, ModularForm_generic ) : def is_gritsenko_form(self) : raise NotImplementedError def atkin_lehner_eigenvalue_numerical(self, (tau1, z, tau2)) : from sage.libs.mpmath import mp from sage.libs.mpmath.mp import exp, pi from sage.libs.mpmath.mp import j as i if not Integer(self.__level()).is_prime() : raise ValueError, "The Atkin Lehner involution is only unique if the level is a prime" precision = ParamodularFormD2Filter_trace(self.precision()) s = Sequence([tau1, z, tau2]) if not is_ComplexField(s) : mp_precision = 30 else : mp_precision = ceil(3.33 * s.universe().precision() ) mp.dps = mp_precision (tau1, z, tau2) = tuple(s) (tau1p, zp, tau2p) = (self.level()*tau1, self.level()*z, self.level()*tau2) (e_tau1, e_z, e_tau2) = (exp(2 * pi * i * tau1), exp(2 * pi * i * z), exp(2 * pi * i * tau2)) (e_tau1p, e_zp, e_tau2p) = (exp(2 * pi * i * tau1p), exp(2 * pi * i * zp), exp(2 * pi * i * tau2p)) self_value = s.universe().zero() trans_value = s.universe().zero() for k in precision : (a,b,c) = apply_GL_to_form(self._P1List()(k[1]), k[0]) self_value = self_value + self[k] * (e_tau1**a * e_z**b * e_tau2**c) trans_value = trans_value + self[k] * (e_tau1p**a * e_zp**b * e_tau2p**c) return trans_value / self_value
def symm_subgraph_densities(self, n): sharp_graph_counts = {} sharp_graphs = [] total, orb_reps = self.tuple_orbit_reps(n) sys.stdout.write("Found %d orbits.\n" % len(orb_reps)) for P, factor in orb_reps.iteritems(): ig = self._graph.degenerate_induced_subgraph(P) ig.make_minimal_isomorph() ghash = hash(ig) if ghash in sharp_graph_counts: sharp_graph_counts[ghash] += factor else: sharp_graphs.append(ig) sharp_graph_counts[ghash] = factor return [(g, sharp_graph_counts[hash(g)] / Integer(total)) for g in sharp_graphs]
def elkies_first_step(E, l, lam): q = E.base_field().order() lam = GF(l)(lam) Phi = ClassicalModularPolynomialDatabase()[l] x = PolynomialRing(E.base_field(), 'x').gen() f = Phi(x, E.j_invariant()) j_1, j_2 = f.roots()[0][0], f.roots()[1][0] E1 = elkies_mod_poly(E, j_1, l) try: I = EllipticCurveIsogeny(E, None, E1, l) except: I = l_isogeny(E, E1, l) r = lam.multiplicative_order() k = GF(q ** r) ext = extend_field(E, r) try: P = ext.lift_x(I.kernel_polynomial().any_root(k)) except: return j_2 if ext(P[0] ** q, P[1] ** q) == Integer(lam) * P: return j_1 else: return j_2
def DihedralPresentation(n): r""" Build the Dihedral group of order `2n` as a finitely presented group. INPUT: - ``n`` -- The size of the set that `D_n` is acting on. OUTPUT: Dihedral group of order `2n`. EXAMPLES:: sage: D = groups.presentation.Dihedral(7); D Finitely presented group < a, b | a^7, b^2, (a*b)^2 > sage: D.as_permutation_group().is_isomorphic(DihedralGroup(7)) True TESTS:: sage: n = 9 sage: D = groups.presentation.Dihedral(n) sage: D.ngens() == 2 True sage: groups.presentation.Dihedral(0) Traceback (most recent call last): ... ValueError: finitely presented group order must be positive """ n = Integer(n) if n < 1: raise ValueError('finitely presented group order must be positive') F = FreeGroup(['a', 'b']) rls = F([1])**n, F([2])**2, (F([1]) * F([2]))**2 return FinitelyPresentedGroup(F, rls)
def hecke_matrix(self, n): """ Return the matrix of the n-th Hecke operator acting on this homology group. EXAMPLES:: sage: t = J1(13).homology(QQ).hecke_matrix(3); t [-2 2 2 -2] [-2 0 2 0] [ 0 0 0 -2] [ 0 0 2 -2] sage: t.base_ring() Rational Field sage: t = J1(13).homology(GF(3)).hecke_matrix(3); t [1 2 2 1] [1 0 2 0] [0 0 0 1] [0 0 2 1] sage: t.base_ring() Finite Field of size 3 """ n = Integer(n) return self.abelian_variety()._rational_hecke_matrix(n)
def r(self): q = Integer(self.q) _, r = q.is_prime_power(get_data=True) return r
def _semistable_reducible_primes(E, verbose=False): r"""Find a list containing all semistable primes l unramified in K/QQ for which the Galois image for E could be reducible. INPUT: - ``E`` - EllipticCurve - over a number field. OUTPUT: A list of primes, which contains all primes `l` unramified in `K/\mathbb{QQ}`, such that `E` is semistable at all primes lying over `l`, and the Galois image at `l` is reducible. If `E` has CM defined over its ground field, a ``ValueError`` is raised. EXAMPLES:: sage: E = EllipticCurve([0, -1, 1, -10, -20]) # X_0(11) sage: 5 in sage.schemes.elliptic_curves.gal_reps_number_field._semistable_reducible_primes(E) True This example, over a quintic field with Galois group `S_5`, took a very long time before :trac:`22343`:: sage: K.<a> = NumberField(x^5 - 6*x^3 + 8*x - 1) sage: E = EllipticCurve(K, [a^3 - 2*a, a^4 - 2*a^3 - 4*a^2 + 6*a + 1, a + 1, -a^3 + a + 1, -a]) sage: from sage.schemes.elliptic_curves.gal_reps_number_field import _semistable_reducible_primes sage: _semistable_reducible_primes(E) [2, 5, 53, 1117] """ if verbose: print("In _semistable_reducible_primes with E={}".format(E.ainvs())) K = E.base_field() d = K.degree() deg_one_primes = deg_one_primes_iter(K, principal_only=True) bad_primes = set([]) # This will store the output. # We find two primes (of distinct residue characteristics) which are # of degree 1, unramified in K/Q, and at which E has good reduction. # Each of these primes will give us a nontrivial divisibility constraint # on the exceptional primes l. For both of these primes P, we precompute # a generator and the characteristic polynomial of Frob_P^12. precomp = [] last_p = 0 # The residue characteristic of the most recent prime. while len(precomp) < 2: P = next(deg_one_primes) p = P.norm() if p != last_p and (d==1 or P.ramification_index() == 1) and E.has_good_reduction(P): precomp.append(P) last_p = p Px, Py = precomp x, y = [P.gens_reduced()[0] for P in precomp] EmodPx = E.reduction(Px) if d>1 else E.reduction(x) EmodPy = E.reduction(Py) if d>1 else E.reduction(y) fxpol = EmodPx.frobenius_polynomial() fypol = EmodPy.frobenius_polynomial() fx12pol = fxpol.adams_operator(12) # roots are 12th powers of those of fxpol fy12pol = fypol.adams_operator(12) px = x.norm() if d>1 else x py = y.norm() if d>1 else x Zx = fxpol.parent() xpol = x.charpoly() if d>1 else Zx([-x,1]) ypol = y.charpoly() if d>1 else Zx([-y,1]) if verbose: print("Finished precomp, x={} (p={}), y={} (p={})".format(x,px,y,py)) for w in range(1+d/2): if verbose: print("w = {}".format(w)) gx = xpol.symmetric_power(w).adams_operator(12).resultant(fx12pol) gy = ypol.symmetric_power(w).adams_operator(12).resultant(fy12pol) if verbose: print("computed gx and gy") gxn = Integer(gx.absolute_norm()) if d>1 else gx gyn = Integer(gy.absolute_norm()) if d>1 else gy gxyn = gxn.gcd(gyn) if gxyn: xprimes = gxyn.prime_factors() if verbose: print("adding prime factors {} of {} to {}".format(xprimes, gxyn, sorted(bad_primes))) bad_primes.update(xprimes) if verbose: print("...done, bad_primes now {}".format(sorted(bad_primes))) continue else: if verbose: print("gx and gy both 0!") ## It is possible that our curve has CM. ## # Our character must be of the form Nm^K_F for an imaginary # quadratic subfield F of K (which is the CM field if E has CM). # Note that this can only happen when d is even, w=d/2, and K # contains (or the Galois closure of K contains?) the # imaginary quadratic field F = Q(sqrt(a)) which is the # splitting field of both fx12pol and fy12pol. We compute a # and relativise K over F: a = fx12pol.discriminant().squarefree_part() # Construct a field isomorphic to K but a relative extension over QQ(sqrt(a)). # See #19229: the names given here, which are not used, should # not be the name of the generator of the base field. rootsa = K(a).sqrt(all=True) # otherwise if a is not a square the # returned result is in the symbolic ring! try: roota = rootsa[0] except IndexError: raise RuntimeError("error in _semistable_reducible_primes: K={} does not contain sqrt({})".format(K,a)) K_rel = K.relativize(roota, ['name1','name2']) iso = K_rel.structure()[1] # an isomorphism from K to K_rel E_rel = E.change_ring(iso) # same as E but over K_rel ## We try again to find a nontrivial divisibility condition. ## div = 0 patience = 5 * K.absolute_degree() # Number of Frobenius elements to check before suspecting that E # has CM and computing the set of CM j-invariants of K to check. # TODO: Is this the best value for this parameter? while div==0 and patience>0: P = next(deg_one_primes) # a prime of K not K_rel while E.has_bad_reduction(P): P = next(deg_one_primes) if verbose: print("trying P = {}...".format(P)) EmodP = E.reduction(P) fpol = EmodP.frobenius_polynomial() if verbose: print("...good reduction, frobenius poly = {}".format(fpol)) x = iso(P.gens_reduced()[0]).relative_norm() xpol = x.charpoly().adams_operator(12) div2 = Integer(xpol.resultant(fpol.adams_operator(12)) // x.norm()**12) if div2: div = div2.isqrt() assert div2==div**2 if verbose: print("...div = {}".format(div)) else: if verbose: print("...div = 0, continuing") patience -= 1 if patience == 0: # We suspect that E has CM, so we check: if E.has_cm(): raise ValueError("In _semistable_reducible_primes, the curve E should not have CM.") assert div != 0 # We found our divisibility constraint. xprimes = div.prime_factors() if verbose: print("...adding prime factors {} of {} to {}...".format(xprimes,div, sorted(bad_primes))) bad_primes.update(xprimes) if verbose: print("...done, bad_primes now {}".format(sorted(bad_primes))) L = sorted(bad_primes) return L
def _tate(self, proof = None, globally = False): r""" Tate's algorithm for an elliptic curve over a number field. Computes both local reduction data at a prime ideal and a local minimal model. The model is not required to be integral on input. If `P` is principal, uses a generator as uniformizer, so it will not affect integrality or minimality at other primes. If `P` is not principal, the minimal model returned will preserve integrality at other primes, but not minimality. The optional argument globally, when set to True, tells the algorithm to use the generator of the prime ideal if it is principal. Otherwise just any uniformizer will be used. .. note:: Called only by ``EllipticCurveLocalData.__init__()``. OUTPUT: (tuple) ``(Emin, p, val_disc, fp, KS, cp)`` where: - ``Emin`` (EllipticCurve) is a model (integral and) minimal at P - ``p`` (int) is the residue characteristic - ``val_disc`` (int) is the valuation of the local minimal discriminant - ``fp`` (int) is the valuation of the conductor - ``KS`` (string) is the Kodaira symbol - ``cp`` (int) is the Tamagawa number EXAMPLES (this raised a type error in sage prior to 4.4.4, see :trac:`7930`) :: sage: E = EllipticCurve('99d1') sage: R.<X> = QQ[] sage: K.<t> = NumberField(X^3 + X^2 - 2*X - 1) sage: L.<s> = NumberField(X^3 + X^2 - 36*X - 4) sage: EK = E.base_extend(K) sage: toK = EK.torsion_order() sage: da = EK.local_data() # indirect doctest sage: EL = E.base_extend(L) sage: da = EL.local_data() # indirect doctest EXAMPLES: The following example shows that the bug at :trac:`9324` is fixed:: sage: K.<a> = NumberField(x^2-x+6) sage: E = EllipticCurve([0,0,0,-53160*a-43995,-5067640*a+19402006]) sage: E.conductor() # indirect doctest Fractional ideal (18, 6*a) The following example shows that the bug at :trac:`9417` is fixed:: sage: K.<a> = NumberField(x^2+18*x+1) sage: E = EllipticCurve(K, [0, -36, 0, 320, 0]) sage: E.tamagawa_number(K.ideal(2)) 4 This is to show that the bug :trac:`11630` is fixed. (The computation of the class group would produce a warning):: sage: K.<t> = NumberField(x^7-2*x+177) sage: E = EllipticCurve([0,1,0,t,t]) sage: P = K.ideal(2,t^3 + t + 1) sage: E.local_data(P).kodaira_symbol() II """ E = self._curve P = self._prime K = E.base_ring() OK = K.maximal_order() t = verbose("Running Tate's algorithm with P = %s"%P, level=1) F = OK.residue_field(P) p = F.characteristic() # In case P is not principal we mostly use a uniformiser which # is globally integral (with positive valuation at some other # primes); for this to work, it is essential that we can # reduce (mod P) elements of K which are not integral (but are # P-integral). However, if the model is non-minimal and we # end up dividing a_i by pi^i then at that point we use a # uniformiser pi which has non-positive valuation at all other # primes, so that we can divide by it without losing # integrality at other primes. if globally: principal_flag = P.is_principal() else: principal_flag = False if (K is QQ) or principal_flag : pi = P.gens_reduced()[0] verbose("P is principal, generator pi = %s"%pi, t, 1) else: pi = K.uniformizer(P, 'positive') verbose("uniformizer pi = %s"%pi, t, 1) pi2 = pi*pi; pi3 = pi*pi2; pi4 = pi*pi3 pi_neg = None prime = pi if K is QQ else P pval = lambda x: x.valuation(prime) pdiv = lambda x: x.is_zero() or pval(x) > 0 # Since ResidueField is cached in a way that # does not care much about embeddings of number # fields, it can happen that F.p.ring() is different # from K. This is a problem: If F.p.ring() has no # embedding but K has, then there is no coercion # from F.p.ring().maximal_order() to K. But it is # no problem to do an explicit conversion in that # case (Simon King, trac ticket #8800). from sage.categories.pushout import pushout, CoercionException try: if hasattr(F.p.ring(), 'maximal_order'): # it is not ZZ _tmp_ = pushout(F.p.ring().maximal_order(),K) pinv = lambda x: F.lift(~F(x)) proot = lambda x,e: F.lift(F(x).nth_root(e, extend = False, all = True)[0]) preduce = lambda x: F.lift(F(x)) except CoercionException: # the pushout does not exist, we need conversion pinv = lambda x: K(F.lift(~F(x))) proot = lambda x,e: K(F.lift(F(x).nth_root(e, extend = False, all = True)[0])) preduce = lambda x: K(F.lift(F(x))) def _pquadroots(a, b, c): r""" Local function returning True iff `ax^2 + bx + c` has roots modulo `P` """ (a, b, c) = (F(a), F(b), F(c)) if a == 0: return (b != 0) or (c == 0) elif p == 2: return len(PolynomialRing(F, "x")([c,b,a]).roots()) > 0 else: return (b**2 - 4*a*c).is_square() def _pcubicroots(b, c, d): r""" Local function returning the number of roots of `x^3 + b*x^2 + c*x + d` modulo `P`, counting multiplicities """ return sum([rr[1] for rr in PolynomialRing(F, 'x')([F(d), F(c), F(b), F(1)]).roots()],0) if p == 2: halfmodp = OK(Integer(0)) else: halfmodp = pinv(Integer(2)) A = E.a_invariants() A = [0, A[0], A[1], A[2], A[3], 0, A[4]] indices = [1,2,3,4,6] if min([pval(a) for a in A if a != 0]) < 0: verbose("Non-integral model at P: valuations are %s; making integral"%([pval(a) for a in A if a != 0]), t, 1) e = 0 for i in range(7): if A[i] != 0: e = max(e, (-pval(A[i])/i).ceil()) pie = pi**e for i in range(7): if A[i] != 0: A[i] *= pie**i verbose("P-integral model is %s, with valuations %s"%([A[i] for i in indices], [pval(A[i]) for i in indices]), t, 1) split = None # only relevant for multiplicative reduction (a1, a2, a3, a4, a6) = (A[1], A[2], A[3], A[4], A[6]) while True: C = EllipticCurve([a1, a2, a3, a4, a6]); (b2, b4, b6, b8) = C.b_invariants() (c4, c6) = C.c_invariants() delta = C.discriminant() val_disc = pval(delta) if val_disc == 0: ## Good reduction already cp = 1 fp = 0 KS = KodairaSymbol("I0") break #return # Otherwise, we change coordinates so that p | a3, a4, a6 if p == 2: if pdiv(b2): r = proot(a4, 2) t = proot(((r + a2)*r + a4)*r + a6, 2) else: temp = pinv(a1) r = temp * a3 t = temp * (a4 + r*r) elif p == 3: if pdiv(b2): r = proot(-b6, 3) else: r = -pinv(b2) * b4 t = a1 * r + a3 else: if pdiv(c4): r = -pinv(12) * b2 else: r = -pinv(12*c4) * (c6 + b2 * c4) t = -halfmodp * (a1 * r + a3) r = preduce(r) t = preduce(t) verbose("Before first transform C = %s"%C) verbose("[a1,a2,a3,a4,a6] = %s"%([a1, a2, a3, a4, a6])) C = C.rst_transform(r, 0, t) (a1, a2, a3, a4, a6) = C.a_invariants() (b2, b4, b6, b8) = C.b_invariants() if min([pval(a) for a in (a1, a2, a3, a4, a6) if a != 0]) < 0: raise RuntimeError("Non-integral model after first transform!") verbose("After first transform %s\n, [a1,a2,a3,a4,a6] = %s\n, valuations = %s"%([r, 0, t], [a1, a2, a3, a4, a6], [pval(a1), pval(a2), pval(a3), pval(a4), pval(a6)]), t, 2) if pval(a3) == 0: raise RuntimeError("p does not divide a3 after first transform!") if pval(a4) == 0: raise RuntimeError("p does not divide a4 after first transform!") if pval(a6) == 0: raise RuntimeError("p does not divide a6 after first transform!") # Now we test for Types In, II, III, IV # NB the c invariants never change. if not pdiv(c4): # Multiplicative reduction: Type In (n = val_disc) split = False if _pquadroots(1, a1, -a2): cp = val_disc split = True elif Integer(2).divides(val_disc): cp = 2 else: cp = 1 KS = KodairaSymbol("I%s"%val_disc) fp = 1 break #return # Additive reduction if pval(a6) < 2: ## Type II KS = KodairaSymbol("II") fp = val_disc cp = 1 break #return if pval(b8) < 3: ## Type III KS = KodairaSymbol("III") fp = val_disc - 1 cp = 2 break #return if pval(b6) < 3: ## Type IV cp = 1 a3t = preduce(a3/pi) a6t = preduce(a6/pi2) if _pquadroots(1, a3t, -a6t): cp = 3 KS = KodairaSymbol("IV") fp = val_disc - 2 break #return # If our curve is none of these types, we change coords so that # p | a1, a2; p^2 | a3, a4; p^3 | a6 if p == 2: s = proot(a2, 2) # so s^2=a2 (mod pi) t = pi*proot(a6/pi2, 2) # so t^2=a6 (mod pi^3) elif p == 3: s = a1 # so a1'=2s+a1=3a1=0 (mod pi) t = a3 # so a3'=2t+a3=3a3=0 (mod pi^2) else: s = -a1*halfmodp # so a1'=2s+a1=0 (mod pi) t = -a3*halfmodp # so a3'=2t+a3=0 (mod pi^2) C = C.rst_transform(0, s, t) (a1, a2, a3, a4, a6) = C.a_invariants() (b2, b4, b6, b8) = C.b_invariants() verbose("After second transform %s\n[a1, a2, a3, a4, a6] = %s\nValuations: %s"%([0, s, t], [a1,a2,a3,a4,a6],[pval(a1),pval(a2),pval(a3),pval(a4),pval(a6)]), t, 2) if pval(a1) == 0: raise RuntimeError("p does not divide a1 after second transform!") if pval(a2) == 0: raise RuntimeError("p does not divide a2 after second transform!") if pval(a3) < 2: raise RuntimeError("p^2 does not divide a3 after second transform!") if pval(a4) < 2: raise RuntimeError("p^2 does not divide a4 after second transform!") if pval(a6) < 3: raise RuntimeError("p^3 does not divide a6 after second transform!") if min(pval(a1), pval(a2), pval(a3), pval(a4), pval(a6)) < 0: raise RuntimeError("Non-integral model after second transform!") # Analyze roots of the cubic T^3 + bT^2 + cT + d = 0 mod P, where # b = a2/p, c = a4/p^2, d = a6/p^3 b = preduce(a2/pi) c = preduce(a4/pi2) d = preduce(a6/pi3) bb = b*b cc = c*c bc = b*c w = 27*d*d - bb*cc + 4*b*bb*d - 18*bc*d + 4*c*cc x = 3*c - bb if pdiv(w): if pdiv(x): sw = 3 else: sw = 2 else: sw = 1 verbose("Analyzing roots of cubic T^3 + %s*T^2 + %s*T + %s, case %s"%(b, c, d, sw), t, 1) if sw == 1: ## Three distinct roots - Type I*0 verbose("Distinct roots", t, 1) KS = KodairaSymbol("I0*") cp = 1 + _pcubicroots(b, c, d) fp = val_disc - 4 break #return elif sw == 2: ## One double root - Type I*m for some m verbose("One double root", t, 1) ## Change coords so that the double root is T = 0 mod p if p == 2: r = proot(c, 2) elif p == 3: r = c * pinv(b) else: r = (bc - 9*d)*pinv(2*x) r = pi * preduce(r) C = C.rst_transform(r, 0, 0) (a1, a2, a3, a4, a6) = C.a_invariants() (b2, b4, b6, b8) = C.b_invariants() # The rest of this branch is just to compute cp, fp, KS. # We use pi to keep transforms integral. ix = 3; iy = 3; mx = pi2; my = mx while True: a2t = preduce(a2 / pi) a3t = preduce(a3 / my) a4t = preduce(a4 / (pi*mx)) a6t = preduce(a6 / (mx*my)) if pdiv(a3t*a3t + 4*a6t): if p == 2: t = my*proot(a6t, 2) else: t = my*preduce(-a3t*halfmodp) C = C.rst_transform(0, 0, t) (a1, a2, a3, a4, a6) = C.a_invariants() (b2, b4, b6, b8) = C.b_invariants() my *= pi iy += 1 a2t = preduce(a2 / pi) a3t = preduce(a3/my) a4t = preduce(a4/(pi*mx)) a6t = preduce(a6/(mx*my)) if pdiv(a4t*a4t - 4*a6t*a2t): if p == 2: r = mx*proot(a6t*pinv(a2t), 2) else: r = mx*preduce(-a4t*pinv(2*a2t)) C = C.rst_transform(r, 0, 0) (a1, a2, a3, a4, a6) = C.a_invariants() (b2, b4, b6, b8) = C.b_invariants() mx *= pi ix += 1 # and stay in loop else: if _pquadroots(a2t, a4t, a6t): cp = 4 else: cp = 2 break # exit loop else: if _pquadroots(1, a3t, -a6t): cp = 4 else: cp = 2 break KS = KodairaSymbol("I%s*"%(ix+iy-5)) fp = val_disc - ix - iy + 1 break #return else: # sw == 3 ## The cubic has a triple root verbose("Triple root", t, 1) ## First we change coordinates so that T = 0 mod p if p == 2: r = b elif p == 3: r = proot(-d, 3) else: r = -b * pinv(3) r = pi*preduce(r) C = C.rst_transform(r, 0, 0) (a1, a2, a3, a4, a6) = C.a_invariants() (b2, b4, b6, b8) = C.b_invariants() verbose("After third transform %s\n[a1,a2,a3,a4,a6] = %s\nValuations: %s"%([r,0,0],[a1,a2,a3,a4,a6],[pval(ai) for ai in [a1,a2,a3,a4,a6]]), t, 2) if min(pval(ai) for ai in [a1,a2,a3,a4,a6]) < 0: raise RuntimeError("Non-integral model after third transform!") if pval(a2) < 2 or pval(a4) < 3 or pval(a6) < 4: raise RuntimeError("Cubic after transform does not have a triple root at 0") a3t = preduce(a3/pi2) a6t = preduce(a6/pi4) # We test for Type IV* if not pdiv(a3t*a3t + 4*a6t): cp = 3 if _pquadroots(1, a3t, -a6t) else 1 KS = KodairaSymbol("IV*") fp = val_disc - 6 break #return # Now change coordinates so that p^3|a3, p^5|a6 if p==2: t = -pi2*proot(a6t, 2) else: t = pi2*preduce(-a3t*halfmodp) C = C.rst_transform(0, 0, t) (a1, a2, a3, a4, a6) = C.a_invariants() (b2, b4, b6, b8) = C.b_invariants() # We test for types III* and II* if pval(a4) < 4: ## Type III* KS = KodairaSymbol("III*") fp = val_disc - 7 cp = 2 break #return if pval(a6) < 6: ## Type II* KS = KodairaSymbol("II*") fp = val_disc - 8 cp = 1 break #return if pi_neg is None: if principal_flag: pi_neg = pi else: pi_neg = K.uniformizer(P, 'negative') pi_neg2 = pi_neg*pi_neg pi_neg3 = pi_neg*pi_neg2 pi_neg4 = pi_neg*pi_neg3 pi_neg6 = pi_neg4*pi_neg2 a1 /= pi_neg a2 /= pi_neg2 a3 /= pi_neg3 a4 /= pi_neg4 a6 /= pi_neg6 verbose("Non-minimal equation, dividing out...\nNew model is %s"%([a1, a2, a3, a4, a6]), t, 1) return (C, p, val_disc, fp, KS, cp, split)
def p(self): q = Integer(self.q) p, _ = q.is_prime_power(get_data=True) return p
def hilbert_class_polynomial(D, algorithm=None): r""" Return the Hilbert class polynomial for discriminant `D`. INPUT: - ``D`` (int) -- a negative integer congruent to 0 or 1 modulo 4. - ``algorithm`` (string, default None). OUTPUT: (integer polynomial) The Hilbert class polynomial for the discriminant `D`. ALGORITHM: - If ``algorithm`` = "arb" (default): Use Arb's implementation which uses complex interval arithmetic. - If ``algorithm`` = "sage": Use complex approximations to the roots. - If ``algorithm`` = "magma": Call the appropriate Magma function (if available). AUTHORS: - Sage implementation originally by Eduardo Ocampo Alvarez and AndreyTimofeev - Sage implementation corrected by John Cremona (using corrected precision bounds from Andreas Enge) - Magma implementation by David Kohel EXAMPLES:: sage: hilbert_class_polynomial(-4) x - 1728 sage: hilbert_class_polynomial(-7) x + 3375 sage: hilbert_class_polynomial(-23) x^3 + 3491750*x^2 - 5151296875*x + 12771880859375 sage: hilbert_class_polynomial(-37*4) x^2 - 39660183801072000*x - 7898242515936467904000000 sage: hilbert_class_polynomial(-37*4, algorithm="magma") # optional - magma x^2 - 39660183801072000*x - 7898242515936467904000000 sage: hilbert_class_polynomial(-163) x + 262537412640768000 sage: hilbert_class_polynomial(-163, algorithm="sage") x + 262537412640768000 sage: hilbert_class_polynomial(-163, algorithm="magma") # optional - magma x + 262537412640768000 TESTS:: sage: all([hilbert_class_polynomial(d, algorithm="arb") == \ ....: hilbert_class_polynomial(d, algorithm="sage") \ ....: for d in range(-1,-100,-1) if d%4 in [0,1]]) True """ if algorithm is None: algorithm = "arb" D = Integer(D) if D >= 0: raise ValueError("D (=%s) must be negative" % D) if not (D % 4 in [0, 1]): raise ValueError("D (=%s) must be a discriminant" % D) if algorithm == "arb": import sage.libs.arb.arith return sage.libs.arb.arith.hilbert_class_polynomial(D) if algorithm == "magma": magma.eval("R<x> := PolynomialRing(IntegerRing())") f = str(magma.eval("HilbertClassPolynomial(%s)" % D)) return IntegerRing()['x'](f) if algorithm != "sage": raise ValueError("%s is not a valid algorithm" % algorithm) from sage.quadratic_forms.binary_qf import BinaryQF_reduced_representatives from sage.rings.all import RR, ComplexField from sage.functions.all import elliptic_j # get all primitive reduced quadratic forms, (necessary to exclude # imprimitive forms when D is not a fundamental discriminant): rqf = BinaryQF_reduced_representatives(D, primitive_only=True) # compute needed precision # # NB: [https://arxiv.org/abs/0802.0979v1], quoting Enge (2006), is # incorrect. Enge writes (2009-04-20 email to John Cremona) "The # source is my paper on class polynomials # [https://hal.inria.fr/inria-00001040] It was pointed out to me by # the referee after ANTS that the constant given there was # wrong. The final version contains a corrected constant on p.7 # which is consistent with your example. It says: # "The logarithm of the absolute value of the coefficient in front # of X^j is bounded above by # # log (2*k_2) * h + pi * sqrt(|D|) * sum (1/A_i) # # independently of j", where k_2 \approx 10.163. h = len(rqf) # class number c1 = 3.05682737291380 # log(2*10.63) c2 = sum([1 / RR(qf[0]) for qf in rqf], RR(0)) prec = c2 * RR(3.142) * RR(D).abs().sqrt() + h * c1 # bound on log prec = prec * 1.45 # bound on log_2 (1/log(2) = 1.44..) prec = 10 + prec.ceil() # allow for rounding error # set appropriate precision for further computing Dsqrt = D.sqrt(prec=prec) R = ComplexField(prec)['t'] t = R.gen() pol = R(1) for qf in rqf: a, b, c = list(qf) tau = (b + Dsqrt) / (a << 1) pol *= (t - elliptic_j(tau)) coeffs = [cof.real().round() for cof in pol.coefficients(sparse=False)] return IntegerRing()['x'](coeffs)
def check_prime(K, P): r""" Function to check that `P` determines a prime of `K`, and return that ideal. INPUT: - ``K`` -- a number field (including `\QQ`). - ``P`` -- an element of ``K`` or a (fractional) ideal of ``K``. OUTPUT: - If ``K`` is `\QQ`: the prime integer equal to or which generates `P`. - If ``K`` is not `\QQ`: the prime ideal equal to or generated by `P`. .. NOTE:: If `P` is not a prime and does not generate a prime, a ``TypeError`` is raised. EXAMPLES:: sage: from sage.schemes.elliptic_curves.ell_local_data import check_prime sage: check_prime(QQ,3) 3 sage: check_prime(QQ,QQ(3)) 3 sage: check_prime(QQ,ZZ.ideal(31)) 31 sage: K.<a> = NumberField(x^2-5) sage: check_prime(K,a) Fractional ideal (a) sage: check_prime(K,a+1) Fractional ideal (a + 1) sage: [check_prime(K,P) for P in K.primes_above(31)] [Fractional ideal (5/2*a + 1/2), Fractional ideal (5/2*a - 1/2)] sage: L.<b> = NumberField(x^2+3) sage: check_prime(K, L.ideal(5)) Traceback (most recent call last): ... TypeError: The ideal Fractional ideal (5) is not a prime ideal of Number Field in a with defining polynomial x^2 - 5 sage: check_prime(K, L.ideal(b)) Traceback (most recent call last): ... TypeError: No compatible natural embeddings found for Number Field in a with defining polynomial x^2 - 5 and Number Field in b with defining polynomial x^2 + 3 """ if K is QQ: if P in ZZ or isinstance(P, integer_types + (Integer,)): P = Integer(P) if P.is_prime(): return P else: raise TypeError("The element %s is not prime" % (P,)) elif P in QQ: raise TypeError("The element %s is not prime" % (P,)) elif is_Ideal(P) and P.base_ring() is ZZ: if P.is_prime(): return P.gen() else: raise TypeError("The ideal %s is not a prime ideal of %s" % (P, ZZ)) else: raise TypeError("%s is neither an element of QQ or an ideal of %s" % (P, ZZ)) if not is_NumberField(K): raise TypeError("%s is not a number field" % (K,)) if is_NumberFieldFractionalIdeal(P) or P in K: # if P is an ideal, making sure it is an fractional ideal of K P = K.fractional_ideal(P) if P.is_prime(): return P else: raise TypeError("The ideal %s is not a prime ideal of %s" % (P, K)) raise TypeError("%s is not a valid prime of %s" % (P, K))
def discriminants_with_bounded_class_number(hmax, B=None, proof=None): """ Return dictionary with keys class numbers `h\le hmax` and values the list of all pairs `(D, f)`, with `D<0` a fundamental discriminant such that `Df^2` has class number `h`. If the optional bound `B` is given, return only those pairs with fundamental `|D| \le B`, though `f` can still be arbitrarily large. INPUT: - ``hmax`` -- integer - `B` -- integer or None; if None returns all pairs - ``proof`` -- this code calls the PARI function ``qfbclassno``, so it could give wrong answers when ``proof``==``False``. The default is whatever ``proof.number_field()`` is. If ``proof==False`` and `B` is ``None``, at least the number of discriminants is correct, since it is double checked with Watkins's table. OUTPUT: - dictionary In case `B` is not given, we use Mark Watkins's: "Class numbers of imaginary quadratic fields" to compute a `B` that captures all `h` up to `hmax` (only available for `hmax\le100`). EXAMPLES:: sage: v = sage.schemes.elliptic_curves.cm.discriminants_with_bounded_class_number(3) sage: list(v) [1, 2, 3] sage: v[1] [(-3, 3), (-3, 2), (-3, 1), (-4, 2), (-4, 1), (-7, 2), (-7, 1), (-8, 1), (-11, 1), (-19, 1), (-43, 1), (-67, 1), (-163, 1)] sage: v[2] [(-3, 7), (-3, 5), (-3, 4), (-4, 5), (-4, 4), (-4, 3), (-7, 4), (-8, 3), (-8, 2), (-11, 3), (-15, 2), (-15, 1), (-20, 1), (-24, 1), (-35, 1), (-40, 1), (-51, 1), (-52, 1), (-88, 1), (-91, 1), (-115, 1), (-123, 1), (-148, 1), (-187, 1), (-232, 1), (-235, 1), (-267, 1), (-403, 1), (-427, 1)] sage: v[3] [(-3, 9), (-3, 6), (-11, 2), (-19, 2), (-23, 2), (-23, 1), (-31, 2), (-31, 1), (-43, 2), (-59, 1), (-67, 2), (-83, 1), (-107, 1), (-139, 1), (-163, 2), (-211, 1), (-283, 1), (-307, 1), (-331, 1), (-379, 1), (-499, 1), (-547, 1), (-643, 1), (-883, 1), (-907, 1)] sage: v = sage.schemes.elliptic_curves.cm.discriminants_with_bounded_class_number(8, proof=False) sage: [len(v[h]) for h in v] [13, 29, 25, 84, 29, 101, 38, 208] Find all class numbers for discriminant up to 50:: sage: sage.schemes.elliptic_curves.cm.discriminants_with_bounded_class_number(hmax=5, B=50) {1: [(-3, 3), (-3, 2), (-3, 1), (-4, 2), (-4, 1), (-7, 2), (-7, 1), (-8, 1), (-11, 1), (-19, 1), (-43, 1)], 2: [(-3, 7), (-3, 5), (-3, 4), (-4, 5), (-4, 4), (-4, 3), (-7, 4), (-8, 3), (-8, 2), (-11, 3), (-15, 2), (-15, 1), (-20, 1), (-24, 1), (-35, 1), (-40, 1)], 3: [(-3, 9), (-3, 6), (-11, 2), (-19, 2), (-23, 2), (-23, 1), (-31, 2), (-31, 1), (-43, 2)], 4: [(-3, 13), (-3, 11), (-3, 8), (-4, 10), (-4, 8), (-4, 7), (-4, 6), (-7, 8), (-7, 6), (-7, 3), (-8, 6), (-8, 4), (-11, 5), (-15, 4), (-19, 5), (-19, 3), (-20, 3), (-20, 2), (-24, 2), (-35, 3), (-39, 2), (-39, 1), (-40, 2), (-43, 3)], 5: [(-47, 2), (-47, 1)]} """ # imports that are needed only for this function from sage.structure.proof.proof import get_flag import math from sage.misc.functional import round # deal with input defaults and type checking proof = get_flag(proof, 'number_field') hmax = Integer(hmax) # T stores the output T = {} # Easy case -- instead of giving error, give meaningful output if hmax < 1: return T if B is None: # Determine how far we have to go by applying Watkins's theorem. v = [largest_fundamental_disc_with_class_number(h) for h in range(1, hmax+1)] B = max([b for b,_ in v]) fund_count = [0] + [cnt for _,cnt in v] else: # Nothing to do -- set to None so we can use this later to know not # to do a double check about how many we find. fund_count = None B = Integer(B) if B <= 2: # This is an easy special case, since there are no fundamental discriminants # this small. return T # This lower bound gets used in an inner loop below. from math import log def lb(f): """Lower bound on euler_phi.""" # 1.79 > e^gamma = 1.7810724... if f <= 1: return 0 # don't do log(log(1)) = log(0) return f/(1.79*log(log(f)) + 3.0/log(log(f))) for D in range(-B, -2): D = Integer(D) if is_fundamental_discriminant(D): h_D = D.class_number(proof) # For each fundamental discriminant D, loop through the f's such # that h(D*f^2) could possibly be <= hmax. As explained to me by Cremona, # we have h(D*f^2) >= (1/c)*h(D)*phi_D(f) >= (1/c)*h(D)*euler_phi(f), where # phi_D(f) is like euler_phi(f) but the factor (1-1/p) is replaced # by a factor of (1-kr(D,p)*p), where kr(D/p) is the Kronecker symbol. # The factor c is 1 unless D=-4 and f>1 (when c=2) or D=-3 and f>1 (when c=3). # Since (1-1/p) <= 1 and (1-1/p) <= (1+1/p), we see that # euler_phi(f) <= phi_D(f). # # We have the following analytic lower bound on euler_phi: # # euler_phi(f) >= lb(f) = f / (exp(euler_gamma)*log(log(n)) + 3/log(log(n))). # # See Theorem 8 of Peter Clark's # http://math.uga.edu/~pete/4400arithmeticorders.pdf # which is a consequence of Theorem 15 of # [Rosser and Schoenfeld, 1962]. # # By Calculus, we see that the lb(f) is an increasing function of f >= 2. # # NOTE: You can visibly "see" that it is a lower bound in Sage with # lb(n) = n/(exp(euler_gamma)*log(log(n)) + 3/log(log(n))) # plot(lb, (n, 1, 10^4), color='red') + plot(lambda x: euler_phi(int(x)), 1, 10^4).show() # # So we consider f=1,2,..., until the first f with lb(f)*h_D > c*h_max. # (Note that lb(f) is <= 0 for f=1,2, so nothing special is needed there.) # # TODO: Maybe we could do better using a bound for for phi_D(f). # f = Integer(1) chmax=hmax if D==-3: chmax*=3 else: if D==-4: chmax*=2 while lb(f)*h_D <= chmax: if f == 1: h = h_D else: h = (D*f*f).class_number(proof) # If the class number of this order is within the range, then # use it. (NOTE: In some cases there is a simple relation between # the class number for D and D*f^2, and this could be used to # optimize this inner loop a little.) if h <= hmax: z = (D, f) if h in T: T[h].append(z) else: T[h] = [z] f += 1 for h in T: T[h] = list(reversed(T[h])) if fund_count is not None: # Double check that we found the right number of fundamental # discriminants; we might as well, since Watkins provides this # data. for h in T: if len([D for D,f in T[h] if f==1]) != fund_count[h]: raise RuntimeError("number of discriminants inconsistent with Watkins's table") return T
def multinomial_odd(list, p): r""" Multinomial coefficient of list, mod p. INPUT: - list - list of integers - p - a prime number OUTPUT: Associated multinomial coefficient, mod p Given the input $[n_1, n_2, n_3, ...]$, this computes the multinomial coefficient $(n_1 + n_2 + n_3 + ...)! / (n_1! n_2! n_3! ...)$, mod $p$. The method is this: expand each $n_i$ in base $p$: $n_i = \sum_j p^j n_{ij}$. Do the same for the sum of the $n_i$'s, which we call $m$: $m = \sum_j p^j m_j$. Then the multinomial coefficient is congruent, mod $p$, to the product of the multinomial coefficients $m_j! / (n_{1j}! n_{2j}! ...)$. Furthermore, any multinomial coefficient $m! / (n_1! n_2! ...)$ can be computed as a product of binomial coefficients: it equals .. math:: \binom{n_1}{n_1} \binom{n_1 + n_2}{n_2} \binom{n_1 + n_2 + n_3}{n_3} ... This is convenient because Sage's binomial function returns integers, not rational numbers (as would be produced just by dividing factorials). EXAMPLES:: sage: from sage.algebras.steenrod.steenrod_algebra_mult import multinomial_odd sage: multinomial_odd([1,2,4], 2) 1 sage: multinomial_odd([1,2,4], 7) 0 sage: multinomial_odd([1,2,4], 11) 6 sage: multinomial_odd([1,2,4], 101) 4 sage: multinomial_odd([1,2,4], 107) 105 """ from sage.rings.all import GF, Integer from sage.rings.arith import binomial n = sum(list) answer = 1 F = GF(p) n_expansion = Integer(n).digits(p) list_expansion = [Integer(k).digits(p) for k in list] index = 0 while answer != 0 and index < len(n_expansion): multi = F(1) partial_sum = 0 for exp in list_expansion: if index < len(exp): partial_sum = partial_sum + exp[index] multi = F(multi * binomial(partial_sum, exp[index])) answer = F(answer * multi) index += 1 return answer
def check_prime(K,P): r""" Function to check that `P` determines a prime of `K`, and return that ideal. INPUT: - ``K`` -- a number field (including `\QQ`). - ``P`` -- an element of ``K`` or a (fractional) ideal of ``K``. OUTPUT: - If ``K`` is `\QQ`: the prime integer equal to or which generates `P`. - If ``K`` is not `\QQ`: the prime ideal equal to or generated by `P`. .. note:: If `P` is not a prime and does not generate a prime, a TypeError is raised. EXAMPLES:: sage: from sage.schemes.elliptic_curves.ell_local_data import check_prime sage: check_prime(QQ,3) 3 sage: check_prime(QQ,ZZ.ideal(31)) 31 sage: K.<a>=NumberField(x^2-5) sage: check_prime(K,a) Fractional ideal (a) sage: check_prime(K,a+1) Fractional ideal (a + 1) sage: [check_prime(K,P) for P in K.primes_above(31)] [Fractional ideal (5/2*a + 1/2), Fractional ideal (5/2*a - 1/2)] """ if K is QQ: if isinstance(P, (int,long,Integer)): P = Integer(P) if P.is_prime(): return P else: raise TypeError("%s is not prime"%P) else: if is_Ideal(P) and P.base_ring() is ZZ and P.is_prime(): return P.gen() raise TypeError("%s is not a prime ideal of %s"%(P,ZZ)) if not is_NumberField(K): raise TypeError("%s is not a number field"%K) if is_NumberFieldFractionalIdeal(P): if P.is_prime(): return P else: raise TypeError("%s is not a prime ideal of %s"%(P,K)) if is_NumberFieldElement(P): if P in K: P = K.ideal(P) else: raise TypeError("%s is not an element of %s"%(P,K)) if P.is_prime(): return P else: raise TypeError("%s is not a prime ideal of %s"%(P,K)) raise TypeError("%s is not a valid prime of %s"%(P,K))
def p_primary_bound(self, p): r""" Returns a provable upper bound for the order of `Sha(E)(p)`. In particular, if this algorithm does not fail, then it proves that the `p`-primary part of `Sha` is finite. INPUT: ``p`` -- a prime > 2 OUTPUT: integer -- power of `p` that bounds the order of `Sha(E)(p)` from above The result is a proven upper bound on the order of `Sha(E)(p)`. So in particular it proves it finiteness even if the rank of the curve is larger than 1. Note also that this bound is sharp if one assumes the main conjecture of Iwasawa theory of elliptic curves (and this is known in certain cases). Currently the algorithm is only implemented when certain conditions are verified. - The mod `p` Galois representation must be surjective. - The reduction at `p` is not allowed to be additive. - If the reduction at `p` is non-split multiplicative, then the rank has to be 0. - If `p=3` then the reduction at 3 must be good ordinary or split multiplicative and the rank must be 0. EXAMPLES:: sage: e = EllipticCurve('11a3') sage: e.sha().p_primary_bound(3) 0 sage: e.sha().p_primary_bound(7) 0 sage: e.sha().p_primary_bound(11) 0 sage: e.sha().p_primary_bound(13) 0 sage: e = EllipticCurve('389a1') sage: e.sha().p_primary_bound(5) 0 sage: e.sha().p_primary_bound(7) 0 sage: e.sha().p_primary_bound(11) 0 sage: e.sha().p_primary_bound(13) 0 sage: e = EllipticCurve('858k2') sage: e.sha().p_primary_bound(3) # long time (10s on sage.math, 2011) Traceback (most recent call last): # 32-bit (see :trac: `11211`) ... # 32-bit OverflowError: Python int too large to convert to C long # 32-bit 0 # 64-bit Some checks for :trac:`6406`:: sage: e.sha().p_primary_bound(7) Traceback (most recent call last): ... ValueError: The mod-p Galois representation is not surjective. Current knowledge about Euler systems does not provide an upper bound in this case. Try an_padic for a conjectural bound. sage: e.sha().an_padic(7) # long time (depends on "e.sha().p_primary_bound(3)" above) Traceback (most recent call last): # 32-bit ... # 32-bit OverflowError: Python int too large to convert to C long # 32-bit 7^2 + O(7^6) # 64-bit sage: e = EllipticCurve('11a3') sage: e.sha().p_primary_bound(5) Traceback (most recent call last): ... ValueError: The mod-p Galois representation is not surjective. Current knowledge about Euler systems does not provide an upper bound in this case. Try an_padic for a conjectural bound. sage: e.sha().an_padic(5) 1 + O(5^2) """ p = Integer(p) E = self.Emin if E.is_ordinary(p) or E.is_good(p): su = E.galois_representation().is_surjective(p) if not su : raise ValueError("The mod-p Galois representation is not surjective. Current knowledge about Euler systems does not provide an upper bound in this case. Try an_padic for a conjectural bound.") shan = self.an_padic(p,prec = 0,use_twists=True) if shan == 0: raise RuntimeError("There is a bug in an_padic.") S = shan.valuation() else: raise ValueError("The curve has to have semi-stable reduction at p.") return S
def galois_action(self, t, N): r""" Suppose this cusp is `\alpha`, `G` is the congruence subgroup `\Gamma_0(N)` of level `N`, and `\sigma` is the automorphism in the Galois group of `\QQ(\zeta_N)/\QQ` that sends `\zeta_N` to `\zeta_N^t`. Then this function computes a cusp `\beta` such that `\sigma([\alpha]) = [\beta]`, where `[\alpha]` is the equivalence class of `\alpha` modulo `G`. BIG WARNING: Despite its general name, this function only computes something that defines an action on `\Gamma_0(N)` equivalence classes; it does not compute the action on `\Gamma_1(N)` classes (see trac 8998). INPUT: - `t` -- integer that is coprime to N - `N` -- positive integer (level) OUTPUT: - a cusp EXAMPLES:: sage: Cusp(1/10).galois_action(3, 50) 1/170 sage: Cusp(oo).galois_action(3, 50) Infinity sage: Cusp(0).galois_action(3, 50) 0 Here we compute explicitly the permutations of the action for t=3 on cusps for Gamma0(50):: sage: N = 50; t=3; G = Gamma0(N); C = G.cusps() sage: cl = lambda z: exists(C, lambda y:y.is_gamma0_equiv(z, N))[1] sage: for i in range(5): print i, t^i, [cl(alpha.galois_action(t^i,N)) for alpha in C] 0 1 [0, 1/25, 1/10, 1/5, 3/10, 2/5, 1/2, 3/5, 7/10, 4/5, 9/10, Infinity] 1 3 [0, 1/25, 7/10, 2/5, 1/10, 4/5, 1/2, 1/5, 9/10, 3/5, 3/10, Infinity] 2 9 [0, 1/25, 9/10, 4/5, 7/10, 3/5, 1/2, 2/5, 3/10, 1/5, 1/10, Infinity] 3 27 [0, 1/25, 3/10, 3/5, 9/10, 1/5, 1/2, 4/5, 1/10, 2/5, 7/10, Infinity] 4 81 [0, 1/25, 1/10, 1/5, 3/10, 2/5, 1/2, 3/5, 7/10, 4/5, 9/10, Infinity] REFERENCES: - Section 1.3 of Glenn Stevens, "Arithmetic on Modular Curves" - There is a long comment about our algorithm in the source code for this function. WARNING: In some cases `N` must fit in a long long, i.e., there are cases where this algorithm isn't fully implemented. AUTHORS: - William Stein, 2009-04-18 """ if self.is_infinity() or not self.__a: return self if not isinstance(t, Integer): t = Integer(t) # Our algorithm for computing the Galois action works as # follows (see Section 1.3 of Glenn Stevens "Arithmetic on # Modular Curves" for a proof that the action given below is # correct). We alternatively view the set of cusps as the # Gamma-equivalence classes of column vectors [a;b] with # gcd(a,b,N)=1, and the left action of Gamma by matrix # multiplication. The action of t is induced by [a;b] |--> # [a;t'*b], where t' is an inverse mod N of t. For [a;t'*b] # with gcd(a,t'*b)==1, the cusp corresponding to [a;t'*b] is # just the rational number a/(t'*b). Thus in this case, to # compute the action of t we just do a/b <--> [a;b] |---> # [a;t'*b] <--> a/(t'*b). IN the other case when we get # [a;t'*b] with gcd(a,t'*b) != 1, which can and does happen, # we have to work a bit harder. We need to find [c;d] such # that [c;d] is congruent to [a;t'*b] modulo N, and # gcd(c,d)=1. There is a standard lifting algorithm that is # implemented for working with P^1(Z/NZ) [it is needed for # modular symbols algorithms], so we just apply it to lift # [a,t'*b] to a matrix [A,B;c,d] in SL_2(Z) with lower two # entries congruent to [a,t'*b] modulo N. This exactly solves # our problem, since gcd(c,d)=1. a = self.__a b = self.__b * t.inverse_mod(N) if b.gcd(a) != 1: _,_,a,b = lift_to_sl2z_llong(a,b,N) a = Integer(a); b = Integer(b) # Now that we've computed the Galois action, we efficiently # construct the corresponding cusp as a Cusp object. return Cusp(a,b,check=False)
def solve_mod(eqns, modulus, solution_dict=False): r""" Return all solutions to an equation or list of equations modulo the given integer modulus. Each equation must involve only polynomials in 1 or many variables. By default the solutions are returned as `n`-tuples, where `n` is the number of variables appearing anywhere in the given equations. The variables are in alphabetical order. INPUT: - ``eqns`` - equation or list of equations - ``modulus`` - an integer - ``solution_dict`` - bool (default: False); if True or non-zero, return a list of dictionaries containing the solutions. If there are no solutions, return an empty list (rather than a list containing an empty dictionary). Likewise, if there's only a single solution, return a list containing one dictionary with that solution. EXAMPLES:: sage: var('x,y') (x, y) sage: solve_mod([x^2 + 2 == x, x^2 + y == y^2], 14) [(4, 2), (4, 6), (4, 9), (4, 13)] sage: solve_mod([x^2 == 1, 4*x == 11], 15) [(14,)] Fermat's equation modulo 3 with exponent 5:: sage: var('x,y,z') (x, y, z) sage: solve_mod([x^5 + y^5 == z^5], 3) [(0, 0, 0), (0, 1, 1), (0, 2, 2), (1, 0, 1), (1, 1, 2), (1, 2, 0), (2, 0, 2), (2, 1, 0), (2, 2, 1)] We can solve with respect to a bigger modulus if it consists only of small prime factors:: sage: [d] = solve_mod([5*x + y == 3, 2*x - 3*y == 9], 3*5*7*11*19*23*29, solution_dict = True) sage: d[x] 12915279 sage: d[y] 8610183 For cases where there are relatively few solutions and the prime factors are small, this can be efficient even if the modulus itself is large:: sage: sorted(solve_mod([x^2 == 41], 10^20)) [(4538602480526452429,), (11445932736758703821,), (38554067263241296179,), (45461397519473547571,), (54538602480526452429,), (61445932736758703821,), (88554067263241296179,), (95461397519473547571,)] We solve a simple equation modulo 2:: sage: x,y = var('x,y') sage: solve_mod([x == y], 2) [(0, 0), (1, 1)] .. warning:: The current implementation splits the modulus into prime powers, then naively enumerates all possible solutions (starting modulo primes and then working up through prime powers), and finally combines the solution using the Chinese Remainder Theorem. The interface is good, but the algorithm is very inefficient if the modulus has some larger prime factors! Sage *does* have the ability to do something much faster in certain cases at least by using Groebner basis, linear algebra techniques, etc. But for a lot of toy problems this function as is might be useful. At least it establishes an interface. TESTS: Make sure that we short-circuit in at least some cases:: sage: solve_mod([2*x==1], 2*next_prime(10^50)) [] Try multi-equation cases:: sage: x, y, z = var("x y z") sage: solve_mod([2*x^2 + x*y, -x*y+2*y^2+x-2*y, -2*x^2+2*x*y-y^2-x-y], 12) [(0, 0), (4, 4), (0, 3), (4, 7)] sage: eqs = [-y^2+z^2, -x^2+y^2-3*z^2-z-1, -y*z-z^2-x-y+2, -x^2-12*z^2-y+z] sage: solve_mod(eqs, 11) [(8, 5, 6)] Confirm that modulus 1 now behaves as it should:: sage: x, y = var("x y") sage: solve_mod([x==1], 1) [(0,)] sage: solve_mod([2*x^2+x*y, -x*y+2*y^2+x-2*y, -2*x^2+2*x*y-y^2-x-y], 1) [(0, 0)] """ from sage.rings.all import Integer, Integers, crt_basis from sage.symbolic.expression import is_Expression from sage.misc.all import cartesian_product_iterator from sage.modules.all import vector from sage.matrix.all import matrix if not isinstance(eqns, (list, tuple)): eqns = [eqns] eqns = [eq if is_Expression(eq) else (eq.lhs() - eq.rhs()) for eq in eqns] modulus = Integer(modulus) if modulus < 1: raise ValueError("the modulus must be a positive integer") vars = list(set(sum([list(e.variables()) for e in eqns], []))) vars.sort(key=repr) if modulus == 1: # degenerate case ans = [tuple(Integers(1)(0) for v in vars)] return ans factors = modulus.factor() crt_basis = vector(Integers(modulus), crt_basis([p**i for p, i in factors])) solutions = [] has_solution = True for p, i in factors: solution = _solve_mod_prime_power(eqns, p, i, vars) if len(solution) > 0: solutions.append(solution) else: has_solution = False break ans = [] if has_solution: for solution in cartesian_product_iterator(solutions): solution_mat = matrix(Integers(modulus), solution) ans.append( tuple( c.dot_product(crt_basis) for c in solution_mat.columns())) # if solution_dict == True: # Relaxed form suggested by Mike Hansen (#8553): if solution_dict: sol_dict = [dict(zip(vars, solution)) for solution in ans] return sol_dict else: return ans
def hecke_operator_on_qexp(f, n, k, eps = None, prec=None, check=True, _return_list=False): r""" Given the `q`-expansion `f` of a modular form with character `\varepsilon`, this function computes the image of `f` under the Hecke operator `T_{n,k}` of weight `k`. EXAMPLES:: sage: M = ModularForms(1,12) sage: hecke_operator_on_qexp(M.basis()[0], 3, 12) 252*q - 6048*q^2 + 63504*q^3 - 370944*q^4 + O(q^5) sage: hecke_operator_on_qexp(M.basis()[0], 1, 12, prec=7) q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 - 6048*q^6 + O(q^7) sage: hecke_operator_on_qexp(M.basis()[0], 1, 12) q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 - 6048*q^6 - 16744*q^7 + 84480*q^8 - 113643*q^9 - 115920*q^10 + 534612*q^11 - 370944*q^12 - 577738*q^13 + O(q^14) sage: M.prec(20) 20 sage: hecke_operator_on_qexp(M.basis()[0], 3, 12) 252*q - 6048*q^2 + 63504*q^3 - 370944*q^4 + 1217160*q^5 - 1524096*q^6 + O(q^7) sage: hecke_operator_on_qexp(M.basis()[0], 1, 12) q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 - 6048*q^6 - 16744*q^7 + 84480*q^8 - 113643*q^9 - 115920*q^10 + 534612*q^11 - 370944*q^12 - 577738*q^13 + 401856*q^14 + 1217160*q^15 + 987136*q^16 - 6905934*q^17 + 2727432*q^18 + 10661420*q^19 - 7109760*q^20 + O(q^21) sage: (hecke_operator_on_qexp(M.basis()[0], 1, 12)*252).add_bigoh(7) 252*q - 6048*q^2 + 63504*q^3 - 370944*q^4 + 1217160*q^5 - 1524096*q^6 + O(q^7) sage: hecke_operator_on_qexp(M.basis()[0], 6, 12) -6048*q + 145152*q^2 - 1524096*q^3 + O(q^4) An example on a formal power series:: sage: R.<q> = QQ[[]] sage: f = q + q^2 + q^3 + q^7 + O(q^8) sage: hecke_operator_on_qexp(f, 3, 12) q + O(q^3) sage: hecke_operator_on_qexp(delta_qexp(24), 3, 12).prec() 8 sage: hecke_operator_on_qexp(delta_qexp(25), 3, 12).prec() 9 An example of computing `T_{p,k}` in characteristic `p`:: sage: p = 199 sage: fp = delta_qexp(prec=p^2+1, K=GF(p)) sage: tfp = hecke_operator_on_qexp(fp, p, 12) sage: tfp == fp[p] * fp True sage: tf = hecke_operator_on_qexp(delta_qexp(prec=p^2+1), p, 12).change_ring(GF(p)) sage: tfp == tf True """ if eps is None: # Need to have base_ring=ZZ to work over finite fields, since # ZZ can coerce to GF(p), but QQ can't. eps = DirichletGroup(1, base_ring=ZZ)[0] if check: if not (is_PowerSeries(f) or is_ModularFormElement(f)): raise TypeError("f (=%s) must be a power series or modular form"%f) if not is_DirichletCharacter(eps): raise TypeError("eps (=%s) must be a Dirichlet character"%eps) k = Integer(k) n = Integer(n) v = [] if prec is None: if is_ModularFormElement(f): # always want at least three coefficients, but not too many, unless # requested pr = max(f.prec(), f.parent().prec(), (n+1)*3) pr = min(pr, 100*(n+1)) prec = pr // n + 1 else: prec = (f.prec() / ZZ(n)).ceil() if prec == Infinity: prec = f.parent().default_prec() // n + 1 if f.prec() < prec: f._compute_q_expansion(prec) p = Integer(f.base_ring().characteristic()) if k != 1 and p.is_prime() and n.is_power_of(p): # if computing T_{p^a} in characteristic p, use the simpler (and faster) # formula v = [f[m*n] for m in range(prec)] else: l = k-1 for m in range(prec): am = sum([eps(d) * d**l * f[m*n//(d*d)] for \ d in divisors(gcd(n, m)) if (m*n) % (d*d) == 0]) v.append(am) if _return_list: return v if is_ModularFormElement(f): R = f.parent()._q_expansion_ring() else: R = f.parent() return R(v, prec)
def victor_miller_basis(k, prec=10, cusp_only=False, var='q'): r""" Compute and return the Victor Miller basis for modular forms of weight `k` and level 1 to precision `O(q^{prec})`. If ``cusp_only`` is True, return only a basis for the cuspidal subspace. INPUT: - ``k`` -- an integer - ``prec`` -- (default: 10) a positive integer - ``cusp_only`` -- bool (default: False) - ``var`` -- string (default: 'q') OUTPUT: A sequence whose entries are power series in ``ZZ[[var]]``. EXAMPLES:: sage: victor_miller_basis(1, 6) [] sage: victor_miller_basis(0, 6) [ 1 + O(q^6) ] sage: victor_miller_basis(2, 6) [] sage: victor_miller_basis(4, 6) [ 1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6) ] sage: victor_miller_basis(6, 6, var='w') [ 1 - 504*w - 16632*w^2 - 122976*w^3 - 532728*w^4 - 1575504*w^5 + O(w^6) ] sage: victor_miller_basis(6, 6) [ 1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6) ] sage: victor_miller_basis(12, 6) [ 1 + 196560*q^2 + 16773120*q^3 + 398034000*q^4 + 4629381120*q^5 + O(q^6), q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6) ] sage: victor_miller_basis(12, 6, cusp_only=True) [ q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6) ] sage: victor_miller_basis(24, 6, cusp_only=True) [ q + 195660*q^3 + 12080128*q^4 + 44656110*q^5 + O(q^6), q^2 - 48*q^3 + 1080*q^4 - 15040*q^5 + O(q^6) ] sage: victor_miller_basis(24, 6) [ 1 + 52416000*q^3 + 39007332000*q^4 + 6609020221440*q^5 + O(q^6), q + 195660*q^3 + 12080128*q^4 + 44656110*q^5 + O(q^6), q^2 - 48*q^3 + 1080*q^4 - 15040*q^5 + O(q^6) ] sage: victor_miller_basis(32, 6) [ 1 + 2611200*q^3 + 19524758400*q^4 + 19715347537920*q^5 + O(q^6), q + 50220*q^3 + 87866368*q^4 + 18647219790*q^5 + O(q^6), q^2 + 432*q^3 + 39960*q^4 - 1418560*q^5 + O(q^6) ] sage: victor_miller_basis(40,200)[1:] == victor_miller_basis(40,200,cusp_only=True) True sage: victor_miller_basis(200,40)[1:] == victor_miller_basis(200,40,cusp_only=True) True AUTHORS: - William Stein, Craig Citro: original code - Martin Raum (2009-08-02): use FLINT for polynomial arithmetic (instead of NTL) """ k = Integer(k) if k%2 == 1 or k==2: return Sequence([]) elif k < 0: raise ValueError("k must be non-negative") elif k == 0: return Sequence([PowerSeriesRing(ZZ,var)(1).add_bigoh(prec)], cr=True) e = k.mod(12) if e == 2: e += 12 n = (k-e) // 12 if n == 0 and cusp_only: return Sequence([]) # If prec is less than or equal to the dimension of the space of # cusp forms, which is just n, then we know the answer, and we # simply return it. if prec <= n: q = PowerSeriesRing(ZZ,var).gen(0) err = bigO(q**prec) ls = [0] * (n+1) if not cusp_only: ls[0] = 1 + err for i in range(1,prec): ls[i] = q**i + err for i in range(prec,n+1): ls[i] = err return Sequence(ls, cr=True) F6 = eisenstein_series_poly(6,prec) if e == 0: A = Fmpz_poly(1) elif e == 4: A = eisenstein_series_poly(4,prec) elif e == 6: A = F6 elif e == 8: A = eisenstein_series_poly(8,prec) elif e == 10: A = eisenstein_series_poly(10,prec) else: # e == 14 A = eisenstein_series_poly(14,prec) if A[0] == -1 : A = -A if n == 0: return Sequence([PowerSeriesRing(ZZ,var)(A.list()).add_bigoh(prec)],cr=True) F6_squared = F6**2 F6_squared._unsafe_mutate_truncate(prec) D = _delta_poly(prec) Fprod = F6_squared Dprod = D if cusp_only: ls = [Fmpz_poly(0)] + [A] * n else: ls = [A] * (n+1) for i in xrange(1,n+1): ls[n-i] *= Fprod ls[i] *= Dprod ls[n-i]._unsafe_mutate_truncate(prec) ls[i]._unsafe_mutate_truncate(prec) Fprod *= F6_squared Dprod *= D Fprod._unsafe_mutate_truncate(prec) Dprod._unsafe_mutate_truncate(prec) P = PowerSeriesRing(ZZ,var) if cusp_only : for i in xrange(1,n+1) : for j in xrange(1, i) : ls[j] = ls[j] - ls[j][i]*ls[i] return Sequence(map(lambda l: P(l.list()).add_bigoh(prec), ls[1:]),cr=True) else : for i in xrange(1,n+1) : for j in xrange(i) : ls[j] = ls[j] - ls[j][i]*ls[i] return Sequence(map(lambda l: P(l.list()).add_bigoh(prec), ls), cr=True)
def coproduct_iterated(self, n=1): r""" Apply ``n`` coproducts to ``self``. .. TODO:: Remove dependency on ``modules_with_basis`` methods. EXAMPLES:: sage: Psi = NonCommutativeSymmetricFunctions(QQ).Psi() sage: Psi[2,2].coproduct_iterated(0) Psi[2, 2] sage: Psi[2,2].coproduct_iterated(2) Psi[] # Psi[] # Psi[2, 2] + 2*Psi[] # Psi[2] # Psi[2] + Psi[] # Psi[2, 2] # Psi[] + 2*Psi[2] # Psi[] # Psi[2] + 2*Psi[2] # Psi[2] # Psi[] + Psi[2, 2] # Psi[] # Psi[] TESTS:: sage: p = SymmetricFunctions(QQ).p() sage: p[5,2,2].coproduct_iterated() p[] # p[5, 2, 2] + 2*p[2] # p[5, 2] + p[2, 2] # p[5] + p[5] # p[2, 2] + 2*p[5, 2] # p[2] + p[5, 2, 2] # p[] sage: p([]).coproduct_iterated(3) p[] # p[] # p[] # p[] :: sage: Psi = NonCommutativeSymmetricFunctions(QQ).Psi() sage: Psi[2,2].coproduct_iterated(0) Psi[2, 2] sage: Psi[2,2].coproduct_iterated(3) Psi[] # Psi[] # Psi[] # Psi[2, 2] + 2*Psi[] # Psi[] # Psi[2] # Psi[2] + Psi[] # Psi[] # Psi[2, 2] # Psi[] + 2*Psi[] # Psi[2] # Psi[] # Psi[2] + 2*Psi[] # Psi[2] # Psi[2] # Psi[] + Psi[] # Psi[2, 2] # Psi[] # Psi[] + 2*Psi[2] # Psi[] # Psi[] # Psi[2] + 2*Psi[2] # Psi[] # Psi[2] # Psi[] + 2*Psi[2] # Psi[2] # Psi[] # Psi[] + Psi[2, 2] # Psi[] # Psi[] # Psi[] :: sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m() sage: m[[1,3],[2]].coproduct_iterated(2) m{} # m{} # m{{1, 3}, {2}} + m{} # m{{1}} # m{{1, 2}} + m{} # m{{1, 2}} # m{{1}} + m{} # m{{1, 3}, {2}} # m{} + m{{1}} # m{} # m{{1, 2}} + m{{1}} # m{{1, 2}} # m{} + m{{1, 2}} # m{} # m{{1}} + m{{1, 2}} # m{{1}} # m{} + m{{1, 3}, {2}} # m{} # m{} sage: m[[]].coproduct_iterated(3), m[[1,3],[2]].coproduct_iterated(0) (m{} # m{} # m{} # m{}, m{{1, 3}, {2}}) """ if n < 0: raise ValueError( "cannot take fewer than 0 coproduct iterations: %s < 0" % str(n)) if n == 0: return self if n == 1: return self.coproduct() from sage.functions.all import floor, ceil from sage.rings.all import Integer # Use coassociativity of `\Delta` to perform many coproducts simultaneously. fn = floor(Integer(n - 1) / 2) cn = ceil(Integer(n - 1) / 2) split = lambda a, b: tensor( [a.coproduct_iterated(fn), b.coproduct_iterated(cn)]) return self.coproduct().apply_multilinear_morphism(split)
def an_numerical(self, prec = None, use_database=True, proof=None): r""" Return the numerical analytic order of `Sha`, which is a floating point number in all cases. INPUT: - ``prec`` - integer (default: 53) bits precision -- used for the L-series computation, period, regulator, etc. - ``use_database`` - whether the rank and generators should be looked up in the database if possible. Default is ``True`` - ``proof`` - bool or ``None`` (default: ``None``, see proof.[tab] or sage.structure.proof) proof option passed onto regulator and rank computation. .. note:: See also the :meth:`an` command, which will return a provably correct integer when the rank is 0 or 1. .. WARNING:: If the curve's generators are not known, computing them may be very time-consuming. Also, computation of the L-series derivative will be time-consuming for large rank and large conductor, and the computation time for this may increase substantially at greater precision. However, use of very low precision less than about 10 can cause the underlying PARI library functions to fail. EXAMPLES:: sage: EllipticCurve('11a').sha().an_numerical() 1.00000000000000 sage: EllipticCurve('37a').sha().an_numerical() 1.00000000000000 sage: EllipticCurve('389a').sha().an_numerical() 1.00000000000000 sage: EllipticCurve('66b3').sha().an_numerical() 4.00000000000000 sage: EllipticCurve('5077a').sha().an_numerical() 1.00000000000000 A rank 4 curve:: sage: EllipticCurve([1, -1, 0, -79, 289]).sha().an_numerical() # long time (3s on sage.math, 2011) 1.00000000000000 A rank 5 curve:: sage: EllipticCurve([0, 0, 1, -79, 342]).sha().an_numerical(prec=10, proof=False) # long time (22s on sage.math, 2011) 1.0 See :trac:`1115`:: sage: sha=EllipticCurve('37a1').sha() sage: [sha.an_numerical(prec) for prec in xrange(40,100,10)] # long time (3s on sage.math, 2013) [1.0000000000, 1.0000000000000, 1.0000000000000000, 1.0000000000000000000, 1.0000000000000000000000, 1.0000000000000000000000000] """ if prec is None: prec = RealField().precision() RR = RealField(prec) prec2 = prec+2 RR2 = RealField(prec2) try: an = self.__an_numerical if an.parent().precision() >= prec: return RR(an) else: # cached precision too low pass except AttributeError: pass # it's critical to switch to the minimal model. E = self.Emin r = Integer(E.rank(use_database=use_database, proof=proof)) L = E.lseries().dokchitser(prec=prec2) Lr= RR2(L.derivative(1,r)) # L.derivative() returns a Complex Om = RR2(E.period_lattice().omega(prec2)) Reg = E.regulator(use_database=use_database, proof=proof, precision=prec2) T = E.torsion_order() cp = E.tamagawa_product() Sha = RR((Lr*T*T)/(r.factorial()*Om*cp*Reg)) self.__an_numerical = Sha return Sha
def hilbert_class_polynomial(D, algorithm=None): r""" Returns the Hilbert class polynomial for discriminant `D`. INPUT: - ``D`` (int) -- a negative integer congruent to 0 or 1 modulo 4. - ``algorithm`` (string, default None). OUTPUT: (integer polynomial) The Hilbert class polynomial for the discriminant `D`. ALGORITHM: - If ``algorithm`` = "arb" (default): Use Arb's implementation which uses complex interval arithmetic. - If ``algorithm`` = "sage": Use complex approximations to the roots. - If ``algorithm`` = "magma": Call the appropriate Magma function (if available). AUTHORS: - Sage implementation originally by Eduardo Ocampo Alvarez and AndreyTimofeev - Sage implementation corrected by John Cremona (using corrected precision bounds from Andreas Enge) - Magma implementation by David Kohel EXAMPLES:: sage: hilbert_class_polynomial(-4) x - 1728 sage: hilbert_class_polynomial(-7) x + 3375 sage: hilbert_class_polynomial(-23) x^3 + 3491750*x^2 - 5151296875*x + 12771880859375 sage: hilbert_class_polynomial(-37*4) x^2 - 39660183801072000*x - 7898242515936467904000000 sage: hilbert_class_polynomial(-37*4, algorithm="magma") # optional - magma x^2 - 39660183801072000*x - 7898242515936467904000000 sage: hilbert_class_polynomial(-163) x + 262537412640768000 sage: hilbert_class_polynomial(-163, algorithm="sage") x + 262537412640768000 sage: hilbert_class_polynomial(-163, algorithm="magma") # optional - magma x + 262537412640768000 TESTS:: sage: all([hilbert_class_polynomial(d, algorithm="arb") == \ ....: hilbert_class_polynomial(d, algorithm="sage") \ ....: for d in range(-1,-100,-1) if d%4 in [0,1]]) True """ if algorithm is None: algorithm = "arb" D = Integer(D) if D >= 0: raise ValueError("D (=%s) must be negative"%D) if not (D%4 in [0,1]): raise ValueError("D (=%s) must be a discriminant"%D) if algorithm == "arb": import sage.libs.arb.arith return sage.libs.arb.arith.hilbert_class_polynomial(D) if algorithm == "magma": magma.eval("R<x> := PolynomialRing(IntegerRing())") f = str(magma.eval("HilbertClassPolynomial(%s)"%D)) return IntegerRing()['x'](f) if algorithm != "sage": raise ValueError("%s is not a valid algorithm"%algorithm) from sage.quadratic_forms.binary_qf import BinaryQF_reduced_representatives from sage.rings.all import RR, ZZ, ComplexField from sage.functions.all import elliptic_j # get all primitive reduced quadratic forms, (necessary to exclude # imprimitive forms when D is not a fundamental discriminant): rqf = BinaryQF_reduced_representatives(D, primitive_only=True) # compute needed precision # # NB: [http://arxiv.org/abs/0802.0979v1], quoting Enge (2006), is # incorrect. Enge writes (2009-04-20 email to John Cremona) "The # source is my paper on class polynomials # [http://hal.inria.fr/inria-00001040] It was pointed out to me by # the referee after ANTS that the constant given there was # wrong. The final version contains a corrected constant on p.7 # which is consistent with your example. It says: # "The logarithm of the absolute value of the coefficient in front # of X^j is bounded above by # # log (2*k_2) * h + pi * sqrt(|D|) * sum (1/A_i) # # independently of j", where k_2 \approx 10.163. h = len(rqf) # class number c1 = 3.05682737291380 # log(2*10.63) c2 = sum([1/RR(qf[0]) for qf in rqf], RR(0)) prec = c2*RR(3.142)*RR(D).abs().sqrt() + h*c1 # bound on log prec = prec * 1.45 # bound on log_2 (1/log(2) = 1.44..) prec = 10 + prec.ceil() # allow for rounding error # set appropriate precision for further computing Dsqrt = D.sqrt(prec=prec) R = ComplexField(prec)['t'] t = R.gen() pol = R(1) for qf in rqf: a, b, c = list(qf) tau = (b+Dsqrt)/(a<<1) pol *= (t - elliptic_j(tau)) coeffs = [cof.real().round() for cof in pol.coefficients(sparse=False)] return IntegerRing()['x'](coeffs)
def FinitelyGeneratedAbelianPresentation(int_list): r""" Return canonical presentation of finitely generated abelian group. INPUT: - ``int_list`` -- List of integers defining the group to be returned, the defining list is reduced to the invariants of the input list before generating the corresponding group. OUTPUT: Finitely generated abelian group, `\ZZ_{n_1} \times \ZZ_{n_2} \times \cdots \times \ZZ_{n_k}` as a finite presentation, where `n_i` forms the invariants of the input list. EXAMPLES:: sage: groups.presentation.FGAbelian([2,2]) Finitely presented group < a, b | a^2, b^2, a^-1*b^-1*a*b > sage: groups.presentation.FGAbelian([2,3]) Finitely presented group < a | a^6 > sage: groups.presentation.FGAbelian([2,4]) Finitely presented group < a, b | a^2, b^4, a^-1*b^-1*a*b > You can create free abelian groups:: sage: groups.presentation.FGAbelian([0]) Finitely presented group < a | > sage: groups.presentation.FGAbelian([0,0]) Finitely presented group < a, b | a^-1*b^-1*a*b > sage: groups.presentation.FGAbelian([0,0,0]) Finitely presented group < a, b, c | a^-1*b^-1*a*b, a^-1*c^-1*a*c, b^-1*c^-1*b*c > And various infinite abelian groups:: sage: groups.presentation.FGAbelian([0,2]) Finitely presented group < a, b | a^2, a^-1*b^-1*a*b > sage: groups.presentation.FGAbelian([0,2,2]) Finitely presented group < a, b, c | a^2, b^2, a^-1*b^-1*a*b, a^-1*c^-1*a*c, b^-1*c^-1*b*c > Outputs are reduced to minimal generators and relations:: sage: groups.presentation.FGAbelian([3,5,2,7,3]) Finitely presented group < a, b | a^3, b^210, a^-1*b^-1*a*b > sage: groups.presentation.FGAbelian([3,210]) Finitely presented group < a, b | a^3, b^210, a^-1*b^-1*a*b > The trivial group is an acceptable output:: sage: groups.presentation.FGAbelian([]) Finitely presented group < | > sage: groups.presentation.FGAbelian([1]) Finitely presented group < | > sage: groups.presentation.FGAbelian([1,1,1,1,1,1,1,1,1,1]) Finitely presented group < | > Input list must consist of positive integers:: sage: groups.presentation.FGAbelian([2,6,3,9,-4]) Traceback (most recent call last): ... ValueError: input list must contain nonnegative entries sage: groups.presentation.FGAbelian([2,'a',4]) Traceback (most recent call last): ... TypeError: unable to convert 'a' to an integer TESTS:: sage: ag = groups.presentation.FGAbelian([2,2]) sage: ag.as_permutation_group().is_isomorphic(groups.permutation.KleinFour()) True sage: G = groups.presentation.FGAbelian([2,4,8]) sage: C2 = CyclicPermutationGroup(2) sage: C4 = CyclicPermutationGroup(4) sage: C8 = CyclicPermutationGroup(8) sage: gg = (C2.direct_product(C4)[0]).direct_product(C8)[0] sage: gg.is_isomorphic(G.as_permutation_group()) True sage: all(groups.presentation.FGAbelian([i]).as_permutation_group().is_isomorphic(groups.presentation.Cyclic(i).as_permutation_group()) for i in [2..35]) True """ from sage.groups.free_group import _lexi_gen check_ls = [Integer(x) for x in int_list if Integer(x) >= 0] if len(check_ls) != len(int_list): raise ValueError('input list must contain nonnegative entries') col_sp = diagonal_matrix(int_list).column_space() invariants = FGP_Module(ZZ**(len(int_list)), col_sp).invariants() name_gen = _lexi_gen() F = FreeGroup([next(name_gen) for i in invariants]) ret_rls = [ F([i + 1])**invariants[i] for i in range(len(invariants)) if invariants[i] != 0 ] # Build commutator relations gen_pairs = [[F.gen(i), F.gen(j)] for i in range(F.ngens() - 1) for j in range(i + 1, F.ngens())] ret_rls = ret_rls + [ x[0]**(-1) * x[1]**(-1) * x[0] * x[1] for x in gen_pairs ] return FinitelyPresentedGroup(F, tuple(ret_rls))
def discriminants_with_bounded_class_number(hmax, B=None, proof=None): r""" Return dictionary with keys class numbers `h\le hmax` and values the list of all pairs `(D, f)`, with `D<0` a fundamental discriminant such that `Df^2` has class number `h`. If the optional bound `B` is given, return only those pairs with fundamental `|D| \le B`, though `f` can still be arbitrarily large. INPUT: - ``hmax`` -- integer - `B` -- integer or None; if None returns all pairs - ``proof`` -- this code calls the PARI function ``qfbclassno``, so it could give wrong answers when ``proof``==``False``. The default is whatever ``proof.number_field()`` is. If ``proof==False`` and `B` is ``None``, at least the number of discriminants is correct, since it is double checked with Watkins's table. OUTPUT: - dictionary In case `B` is not given, we use Mark Watkins's: "Class numbers of imaginary quadratic fields" to compute a `B` that captures all `h` up to `hmax` (only available for `hmax\le100`). EXAMPLES:: sage: v = sage.schemes.elliptic_curves.cm.discriminants_with_bounded_class_number(3) sage: sorted(v) [1, 2, 3] sage: v[1] [(-3, 3), (-3, 2), (-3, 1), (-4, 2), (-4, 1), (-7, 2), (-7, 1), (-8, 1), (-11, 1), (-19, 1), (-43, 1), (-67, 1), (-163, 1)] sage: v[2] [(-3, 7), (-3, 5), (-3, 4), (-4, 5), (-4, 4), (-4, 3), (-7, 4), (-8, 3), (-8, 2), (-11, 3), (-15, 2), (-15, 1), (-20, 1), (-24, 1), (-35, 1), (-40, 1), (-51, 1), (-52, 1), (-88, 1), (-91, 1), (-115, 1), (-123, 1), (-148, 1), (-187, 1), (-232, 1), (-235, 1), (-267, 1), (-403, 1), (-427, 1)] sage: v[3] [(-3, 9), (-3, 6), (-11, 2), (-19, 2), (-23, 2), (-23, 1), (-31, 2), (-31, 1), (-43, 2), (-59, 1), (-67, 2), (-83, 1), (-107, 1), (-139, 1), (-163, 2), (-211, 1), (-283, 1), (-307, 1), (-331, 1), (-379, 1), (-499, 1), (-547, 1), (-643, 1), (-883, 1), (-907, 1)] sage: v = sage.schemes.elliptic_curves.cm.discriminants_with_bounded_class_number(8, proof=False) sage: sorted(len(v[h]) for h in v) [13, 25, 29, 29, 38, 84, 101, 208] Find all class numbers for discriminant up to 50:: sage: sage.schemes.elliptic_curves.cm.discriminants_with_bounded_class_number(hmax=5, B=50) {1: [(-3, 3), (-3, 2), (-3, 1), (-4, 2), (-4, 1), (-7, 2), (-7, 1), (-8, 1), (-11, 1), (-19, 1), (-43, 1)], 2: [(-3, 7), (-3, 5), (-3, 4), (-4, 5), (-4, 4), (-4, 3), (-7, 4), (-8, 3), (-8, 2), (-11, 3), (-15, 2), (-15, 1), (-20, 1), (-24, 1), (-35, 1), (-40, 1)], 3: [(-3, 9), (-3, 6), (-11, 2), (-19, 2), (-23, 2), (-23, 1), (-31, 2), (-31, 1), (-43, 2)], 4: [(-3, 13), (-3, 11), (-3, 8), (-4, 10), (-4, 8), (-4, 7), (-4, 6), (-7, 8), (-7, 6), (-7, 3), (-8, 6), (-8, 4), (-11, 5), (-15, 4), (-19, 5), (-19, 3), (-20, 3), (-20, 2), (-24, 2), (-35, 3), (-39, 2), (-39, 1), (-40, 2), (-43, 3)], 5: [(-47, 2), (-47, 1)]} """ # imports that are needed only for this function from sage.structure.proof.proof import get_flag # deal with input defaults and type checking proof = get_flag(proof, 'number_field') hmax = Integer(hmax) # T stores the output T = {} # Easy case -- instead of giving error, give meaningful output if hmax < 1: return T if B is None: # Determine how far we have to go by applying Watkins's theorem. v = [ largest_fundamental_disc_with_class_number(h) for h in range(1, hmax + 1) ] B = max([b for b, _ in v]) fund_count = [0] + [cnt for _, cnt in v] else: # Nothing to do -- set to None so we can use this later to know not # to do a double check about how many we find. fund_count = None B = Integer(B) if B <= 2: # This is an easy special case, since there are no fundamental discriminants # this small. return T # This lower bound gets used in an inner loop below. from math import log def lb(f): """Lower bound on euler_phi.""" # 1.79 > e^gamma = 1.7810724... if f <= 1: return 0 # don't do log(log(1)) = log(0) return f / (1.79 * log(log(f)) + 3.0 / log(log(f))) for D in range(-B, -2): D = Integer(D) if is_fundamental_discriminant(D): h_D = D.class_number(proof) # For each fundamental discriminant D, loop through the f's such # that h(D*f^2) could possibly be <= hmax. As explained to me by Cremona, # we have h(D*f^2) >= (1/c)*h(D)*phi_D(f) >= (1/c)*h(D)*euler_phi(f), where # phi_D(f) is like euler_phi(f) but the factor (1-1/p) is replaced # by a factor of (1-kr(D,p)*p), where kr(D/p) is the Kronecker symbol. # The factor c is 1 unless D=-4 and f>1 (when c=2) or D=-3 and f>1 (when c=3). # Since (1-1/p) <= 1 and (1-1/p) <= (1+1/p), we see that # euler_phi(f) <= phi_D(f). # # We have the following analytic lower bound on euler_phi: # # euler_phi(f) >= lb(f) = f / (exp(euler_gamma)*log(log(n)) + 3/log(log(n))). # # See Theorem 8 of Peter Clark's # http://math.uga.edu/~pete/4400arithmeticorders.pdf # which is a consequence of Theorem 15 of # [Rosser and Schoenfeld, 1962]. # # By Calculus, we see that the lb(f) is an increasing function of f >= 2. # # NOTE: You can visibly "see" that it is a lower bound in Sage with # lb(n) = n/(exp(euler_gamma)*log(log(n)) + 3/log(log(n))) # plot(lb, (n, 1, 10^4), color='red') + plot(lambda x: euler_phi(int(x)), 1, 10^4).show() # # So we consider f=1,2,..., until the first f with lb(f)*h_D > c*h_max. # (Note that lb(f) is <= 0 for f=1,2, so nothing special is needed there.) # # TODO: Maybe we could do better using a bound for phi_D(f). # f = Integer(1) chmax = hmax if D == -3: chmax *= 3 else: if D == -4: chmax *= 2 while lb(f) * h_D <= chmax: if f == 1: h = h_D else: h = (D * f * f).class_number(proof) # If the class number of this order is within the range, then # use it. (NOTE: In some cases there is a simple relation between # the class number for D and D*f^2, and this could be used to # optimize this inner loop a little.) if h <= hmax: z = (D, f) if h in T: T[h].append(z) else: T[h] = [z] f += 1 for h in T: T[h] = list(reversed(T[h])) if fund_count is not None: # Double check that we found the right number of fundamental # discriminants; we might as well, since Watkins provides this # data. for h in T: if len([DD for DD, ff in T[h] if ff == 1]) != fund_count[h]: raise RuntimeError( "number of discriminants inconsistent with Watkins's table" ) return T
def FinitelyGeneratedHeisenbergPresentation(n=1, p=0): r""" Return a finite presentation of the Heisenberg group. The Heisenberg group is the group of `(n+2) \times (n+2)` matrices over a ring `R` with diagonal elements equal to 1, first row and last column possibly nonzero, and all the other entries equal to zero. INPUT: - ``n`` -- the degree of the Heisenberg group - ``p`` -- (optional) a prime number, where we construct the Heisenberg group over the finite field `\ZZ/p\ZZ` OUTPUT: Finitely generated Heisenberg group over the finite field of order ``p`` or over the integers. .. SEEALSO:: :class:`~sage.groups.matrix_gps.heisenberg.HeisenbergGroup` EXAMPLES:: sage: H = groups.presentation.Heisenberg(); H Finitely presented group < x1, y1, z | x1*y1*x1^-1*y1^-1*z^-1, z*x1*z^-1*x1^-1, z*y1*z^-1*y1^-1 > sage: H.order() +Infinity sage: r1, r2, r3 = H.relations() sage: A = matrix([[1, 1, 0], [0, 1, 0], [0, 0, 1]]) sage: B = matrix([[1, 0, 0], [0, 1, 1], [0, 0, 1]]) sage: C = matrix([[1, 0, 1], [0, 1, 0], [0, 0, 1]]) sage: r1(A, B, C) [1 0 0] [0 1 0] [0 0 1] sage: r2(A, B, C) [1 0 0] [0 1 0] [0 0 1] sage: r3(A, B, C) [1 0 0] [0 1 0] [0 0 1] sage: p = 3 sage: Hp = groups.presentation.Heisenberg(p=3) sage: Hp.order() == p**3 True sage: Hnp = groups.presentation.Heisenberg(n=2, p=3) sage: len(Hnp.relations()) 13 REFERENCES: - :wikipedia:`Heisenberg_group` """ n = Integer(n) if n < 1: raise ValueError('n must be a positive integer') # generators' names are x1, .., xn, y1, .., yn, z vx = ['x' + str(i) for i in range(1, n + 1)] vy = ['y' + str(i) for i in range(1, n + 1)] str_generators = ', '.join(vx + vy + ['z']) F = FreeGroup(str_generators) x = F.gens()[0:n] # list of generators x1, x2, ..., xn y = F.gens()[n:2 * n] # list of generators x1, x2, ..., xn z = F.gen(n * 2) def commutator(a, b): return a * b * a**-1 * b**-1 # First set of relations: [xi, yi] = z r1 = [commutator(x[i], y[i]) * z**-1 for i in range(n)] # Second set of relations: [z, xi] = 1 r2 = [commutator(z, x[i]) for i in range(n)] # Third set of relations: [z, yi] = 1 r3 = [commutator(z, y[i]) for i in range(n)] # Fourth set of relations: [xi, yi] = 1 for i != j r4 = [commutator(x[i], y[j]) for i in range(n) for j in range(n) if i != j] rls = r1 + r2 + r3 + r4 from sage.sets.primes import Primes if p not in Primes() and p != 0: raise ValueError("p must be 0 or a prime number") if p > 0: rls += [w**p for w in F.gens()] return FinitelyPresentedGroup(F, tuple(rls))
def galois_action(self, t, N): r""" Suppose this cusp is `\alpha`, `G` a congruence subgroup of level `N` and `\sigma` is the automorphism in the Galois group of `\QQ(\zeta_N)/\QQ` that sends `\zeta_N` to `\zeta_N^t`. Then this function computes a cusp `\beta` such that `\sigma([\alpha]) = [\beta]`, where `[\alpha]` is the equivalence class of `\alpha` modulo `G`. This code only needs as input the level and not the group since the action of galois for a congruence group `G` of level `N` is compatible with the action of the full congruence group `\Gamma(N)`. INPUT: - `t` -- integer that is coprime to N - `N` -- positive integer (level) OUTPUT: - a cusp .. WARNING:: In some cases `N` must fit in a long long, i.e., there are cases where this algorithm isn't fully implemented. .. NOTE:: Modular curves can have multiple non-isomorphic models over `\QQ`. The action of galois depends on such a model. The model over `\QQ` of `X(G)` used here is the model where the function field `\QQ(X(G))` is given by the functions whose fourier expansion at `\infty` have their coefficients in `\QQ`. For `X(N):=X(\Gamma(N))` the corresponding moduli interpretation over `\ZZ[1/N]` is that `X(N)` parametrizes pairs `(E,a)` where `E` is a (generalized) elliptic curve and `a: \ZZ / N\ZZ \times \mu_N \to E` is a closed immersion such that the weil pairing of `a(1,1)` and `a(0,\zeta_N)` is `\zeta_N`. In this parameterisation the point `z \in H` corresponds to the pair `(E_z,a_z)` with `E_z=\CC/(z \ZZ+\ZZ)` and `a_z: \ZZ / N\ZZ \times \mu_N \to E` given by `a_z(1,1) = z/N` and `a_z(0,\zeta_N) = 1/N`. Similarly `X_1(N):=X(\Gamma_1(N))` parametrizes pairs `(E,a)` where `a: \mu_N \to E` is a closed immersion. EXAMPLES:: sage: Cusp(1/10).galois_action(3, 50) 1/170 sage: Cusp(oo).galois_action(3, 50) Infinity sage: c=Cusp(0).galois_action(3, 50); c 50/67 sage: Gamma0(50).reduce_cusp(c) 0 Here we compute the permutations of the action for t=3 on cusps for Gamma0(50). :: sage: N = 50; t=3; G = Gamma0(N); C = G.cusps() sage: cl = lambda z: exists(C, lambda y:y.is_gamma0_equiv(z, N))[1] sage: for i in range(5): print i, t^i, [cl(alpha.galois_action(t^i,N)) for alpha in C] 0 1 [0, 1/25, 1/10, 1/5, 3/10, 2/5, 1/2, 3/5, 7/10, 4/5, 9/10, Infinity] 1 3 [0, 1/25, 7/10, 2/5, 1/10, 4/5, 1/2, 1/5, 9/10, 3/5, 3/10, Infinity] 2 9 [0, 1/25, 9/10, 4/5, 7/10, 3/5, 1/2, 2/5, 3/10, 1/5, 1/10, Infinity] 3 27 [0, 1/25, 3/10, 3/5, 9/10, 1/5, 1/2, 4/5, 1/10, 2/5, 7/10, Infinity] 4 81 [0, 1/25, 1/10, 1/5, 3/10, 2/5, 1/2, 3/5, 7/10, 4/5, 9/10, Infinity] TESTS: Here we check that the galois action is indeed a permutation on the cusps of Gamma1(48) and check that :trac:`13253` is fixed. :: sage: G=Gamma1(48) sage: C=G.cusps() sage: for i in Integers(48).unit_gens(): ... C_permuted = [G.reduce_cusp(c.galois_action(i,48)) for c in C] ... assert len(set(C_permuted))==len(C) We test that Gamma1(19) has 9 rational cusps and check that :trac:`8998` is fixed. :: sage: G = Gamma1(19) sage: [c for c in G.cusps() if c.galois_action(2,19).is_gamma1_equiv(c,19)[0]] [2/19, 3/19, 4/19, 5/19, 6/19, 7/19, 8/19, 9/19, Infinity] REFERENCES: - Section 1.3 of Glenn Stevens, "Arithmetic on Modular Curves" - There is a long comment about our algorithm in the source code for this function. AUTHORS: - William Stein, 2009-04-18 """ if self.is_infinity(): return self if not isinstance(t, Integer): t = Integer(t) # Our algorithm for computing the Galois action works as # follows (see Section 1.3 of Glenn Stevens "Arithmetic on # Modular Curves" for a proof that the action given below is # correct). We alternatively view the set of cusps as the # Gamma-equivalence classes of column vectors [a;b] with # gcd(a,b,N)=1, and the left action of Gamma by matrix # multiplication. The action of t is induced by [a;b] |--> # [a;t'*b], where t' is an inverse mod N of t. For [a;t'*b] # with gcd(a,t'*b)==1, the cusp corresponding to [a;t'*b] is # just the rational number a/(t'*b). Thus in this case, to # compute the action of t we just do a/b <--> [a;b] |---> # [a;t'*b] <--> a/(t'*b). IN the other case when we get # [a;t'*b] with gcd(a,t'*b) != 1, which can and does happen, # we have to work a bit harder. We need to find [c;d] such # that [c;d] is congruent to [a;t'*b] modulo N, and # gcd(c,d)=1. There is a standard lifting algorithm that is # implemented for working with P^1(Z/NZ) [it is needed for # modular symbols algorithms], so we just apply it to lift # [a,t'*b] to a matrix [A,B;c,d] in SL_2(Z) with lower two # entries congruent to [a,t'*b] modulo N. This exactly solves # our problem, since gcd(c,d)=1. a = self.__a b = self.__b * t.inverse_mod(N) if b.gcd(a) != 1: _,_,a,b = lift_to_sl2z_llong(a,b,N) a = Integer(a); b = Integer(b) # Now that we've computed the Galois action, we efficiently # construct the corresponding cusp as a Cusp object. return Cusp(a,b,check=False)
def intersection(self, other): """ Return the intersection of the finite subgroups self and other. INPUT: - ``other`` - a finite group OUTPUT: a finite group EXAMPLES:: sage: E11a0, E11a1, B = J0(33) sage: G = E11a0.torsion_subgroup(6); H = E11a0.torsion_subgroup(9) sage: G.intersection(H) Finite subgroup with invariants [3, 3] over QQ of Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33) sage: W = E11a1.torsion_subgroup(15) sage: G.intersection(W) Finite subgroup with invariants [] over QQ of Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33) sage: E11a0.intersection(E11a1)[0] Finite subgroup with invariants [5] over QQ of Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33) We intersect subgroups of different abelian varieties. :: sage: E11a0, E11a1, B = J0(33) sage: G = E11a0.torsion_subgroup(5); H = E11a1.torsion_subgroup(5) sage: G.intersection(H) Finite subgroup with invariants [5] over QQ of Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33) sage: E11a0.intersection(E11a1)[0] Finite subgroup with invariants [5] over QQ of Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33) We intersect abelian varieties with subgroups:: sage: t = J0(33).hecke_operator(7) sage: G = t.kernel()[0]; G Finite subgroup with invariants [2, 2, 2, 2, 4, 4] over QQ of Abelian variety J0(33) of dimension 3 sage: A = J0(33).old_subvariety() sage: A.intersection(G) Finite subgroup with invariants [2, 2, 2, 2] over QQ of Abelian subvariety of dimension 2 of J0(33) sage: A.hecke_operator(7).kernel()[0] Finite subgroup with invariants [2, 2, 2, 2] over QQ of Abelian subvariety of dimension 2 of J0(33) sage: B = J0(33).new_subvariety() sage: B.intersection(G) Finite subgroup with invariants [4, 4] over QQ of Abelian subvariety of dimension 1 of J0(33) sage: B.hecke_operator(7).kernel()[0] Finite subgroup with invariants [4, 4] over QQ of Abelian subvariety of dimension 1 of J0(33) sage: A.intersection(B)[0] Finite subgroup with invariants [3, 3] over QQ of Abelian subvariety of dimension 2 of J0(33) """ A = self.abelian_variety() if abelian_variety.is_ModularAbelianVariety(other): amb = other B = other M = B.lattice().scale(Integer(1) / self.exponent()) K = composite_field(self.field_of_definition(), other.base_field()) else: amb = A if not isinstance(other, FiniteSubgroup): raise TypeError, "only addition of two finite subgroups is defined" B = other.abelian_variety() if A.ambient_variety() != B.ambient_variety(): raise TypeError, "finite subgroups must be in the same ambient product Jacobian" M = other.lattice() K = composite_field(self.field_of_definition(), other.field_of_definition()) L = self.lattice() if A != B: # TODO: This might be way slower than what we could do if # we think more carefully. C = A + B L = L + C.lattice() M = M + C.lattice() W = L.intersection(M).intersection(amb.vector_space()) return FiniteSubgroup_lattice(amb, W, field_of_definition=K)
def solve_mod(eqns, modulus, solution_dict = False): r""" Return all solutions to an equation or list of equations modulo the given integer modulus. Each equation must involve only polynomials in 1 or many variables. By default the solutions are returned as `n`-tuples, where `n` is the number of variables appearing anywhere in the given equations. The variables are in alphabetical order. INPUT: - ``eqns`` - equation or list of equations - ``modulus`` - an integer - ``solution_dict`` - bool (default: False); if True or non-zero, return a list of dictionaries containing the solutions. If there are no solutions, return an empty list (rather than a list containing an empty dictionary). Likewise, if there's only a single solution, return a list containing one dictionary with that solution. EXAMPLES:: sage: var('x,y') (x, y) sage: solve_mod([x^2 + 2 == x, x^2 + y == y^2], 14) [(4, 2), (4, 6), (4, 9), (4, 13)] sage: solve_mod([x^2 == 1, 4*x == 11], 15) [(14,)] Fermat's equation modulo 3 with exponent 5:: sage: var('x,y,z') (x, y, z) sage: solve_mod([x^5 + y^5 == z^5], 3) [(0, 0, 0), (0, 1, 1), (0, 2, 2), (1, 0, 1), (1, 1, 2), (1, 2, 0), (2, 0, 2), (2, 1, 0), (2, 2, 1)] We can solve with respect to a bigger modulus if it consists only of small prime factors:: sage: [d] = solve_mod([5*x + y == 3, 2*x - 3*y == 9], 3*5*7*11*19*23*29, solution_dict = True) sage: d[x] 12915279 sage: d[y] 8610183 For cases where there are relatively few solutions and the prime factors are small, this can be efficient even if the modulus itself is large:: sage: sorted(solve_mod([x^2 == 41], 10^20)) [(4538602480526452429,), (11445932736758703821,), (38554067263241296179,), (45461397519473547571,), (54538602480526452429,), (61445932736758703821,), (88554067263241296179,), (95461397519473547571,)] We solve a simple equation modulo 2:: sage: x,y = var('x,y') sage: solve_mod([x == y], 2) [(0, 0), (1, 1)] .. warning:: The current implementation splits the modulus into prime powers, then naively enumerates all possible solutions (starting modulo primes and then working up through prime powers), and finally combines the solution using the Chinese Remainder Theorem. The interface is good, but the algorithm is very inefficient if the modulus has some larger prime factors! Sage *does* have the ability to do something much faster in certain cases at least by using Groebner basis, linear algebra techniques, etc. But for a lot of toy problems this function as is might be useful. At least it establishes an interface. TESTS: Make sure that we short-circuit in at least some cases:: sage: solve_mod([2*x==1], 2*next_prime(10^50)) [] Try multi-equation cases:: sage: x, y, z = var("x y z") sage: solve_mod([2*x^2 + x*y, -x*y+2*y^2+x-2*y, -2*x^2+2*x*y-y^2-x-y], 12) [(0, 0), (4, 4), (0, 3), (4, 7)] sage: eqs = [-y^2+z^2, -x^2+y^2-3*z^2-z-1, -y*z-z^2-x-y+2, -x^2-12*z^2-y+z] sage: solve_mod(eqs, 11) [(8, 5, 6)] Confirm that modulus 1 now behaves as it should:: sage: x, y = var("x y") sage: solve_mod([x==1], 1) [(0,)] sage: solve_mod([2*x^2+x*y, -x*y+2*y^2+x-2*y, -2*x^2+2*x*y-y^2-x-y], 1) [(0, 0)] """ from sage.rings.all import Integer, Integers, crt_basis from sage.symbolic.expression import is_Expression from sage.misc.all import cartesian_product_iterator from sage.modules.all import vector from sage.matrix.all import matrix if not isinstance(eqns, (list, tuple)): eqns = [eqns] eqns = [eq if is_Expression(eq) else (eq.lhs()-eq.rhs()) for eq in eqns] modulus = Integer(modulus) if modulus < 1: raise ValueError("the modulus must be a positive integer") vars = list(set(sum([list(e.variables()) for e in eqns], []))) vars.sort(key=repr) if modulus == 1: # degenerate case ans = [tuple(Integers(1)(0) for v in vars)] return ans factors = modulus.factor() crt_basis = vector(Integers(modulus), crt_basis([p**i for p,i in factors])) solutions = [] has_solution = True for p,i in factors: solution =_solve_mod_prime_power(eqns, p, i, vars) if len(solution) > 0: solutions.append(solution) else: has_solution = False break ans = [] if has_solution: for solution in cartesian_product_iterator(solutions): solution_mat = matrix(Integers(modulus), solution) ans.append(tuple(c.dot_product(crt_basis) for c in solution_mat.columns())) # if solution_dict == True: # Relaxed form suggested by Mike Hansen (#8553): if solution_dict: sol_dict = [dict(zip(vars, solution)) for solution in ans] return sol_dict else: return ans
def nth_iterate_map(self, n): r""" This function returns the ``n``-th iterate of the map. ALGORITHM: Uses a form of successive squaring to reducing computations. .. TODO:: This could be improved. INPUT: - ``n`` - a positive integer. OUTPUT: - A map between Affine spaces. EXAMPLES:: sage: A.<x,y> = AffineSpace(ZZ, 2) sage: H = Hom(A, A) sage: f = H([(x^2-2)/(2*y), y^2-3*x]) sage: f.nth_iterate_map(2) Scheme endomorphism of Affine Space of dimension 2 over Integer Ring Defn: Defined on coordinates by sending (x, y) to ((x^4 - 4*x^2 - 8*y^2 + 4)/(8*y^4 - 24*x*y^2), (2*y^5 - 12*x*y^3 + 18*x^2*y - 3*x^2 + 6)/(2*y)) :: sage: A.<x> = AffineSpace(QQ, 1) sage: H = Hom(A, A) sage: f = H([(3*x^2-2)/(x)]) sage: f.nth_iterate_map(3) Scheme endomorphism of Affine Space of dimension 1 over Rational Field Defn: Defined on coordinates by sending (x) to ((2187*x^8 - 6174*x^6 + 6300*x^4 - 2744*x^2 + 432)/(81*x^7 - 168*x^5 + 112*x^3 - 24*x)) :: sage: A.<x,y> = AffineSpace(ZZ, 2) sage: X = A.subscheme([x-y^2]) sage: H = Hom(X, X) sage: f = H([9*x^2, 3*y]) sage: f.nth_iterate_map(2) Scheme endomorphism of Closed subscheme of Affine Space of dimension 2 over Integer Ring defined by: -y^2 + x Defn: Defined on coordinates by sending (x, y) to (729*x^4, 9*y) """ if self.domain() != self.codomain(): raise TypeError("domain and codomain of function not equal") N = self.codomain().ambient_space().dimension_relative() F = list(self._polys) R = F[0].parent() Coord_ring = self.codomain().ambient_space().coordinate_ring() D = Integer(n).digits(2) PHI = [Coord_ring.gen(i) for i in range(N)] for i in range(len(D)): T = [F[j] for j in range(N)] for k in range(D[i]): PHI = [PHI[j](T) for j in range(N)] if i != len(D) - 1: #avoid extra iterate F = [R(F[j](T)) for j in range(N)] #'square' H = Hom(self.domain(), self.codomain()) return (H(PHI))
def relevant_degs(self): return Integer(self.geometric_extension_degree).divisors()[1:-1]
def check_prime(K,P): r""" Function to check that `P` determines a prime of `K`, and return that ideal. INPUT: - ``K`` -- a number field (including `\QQ`). - ``P`` -- an element of ``K`` or a (fractional) ideal of ``K``. OUTPUT: - If ``K`` is `\QQ`: the prime integer equal to or which generates `P`. - If ``K`` is not `\QQ`: the prime ideal equal to or generated by `P`. .. note:: If `P` is not a prime and does not generate a prime, a TypeError is raised. EXAMPLES:: sage: from sage.schemes.elliptic_curves.ell_local_data import check_prime sage: check_prime(QQ,3) 3 sage: check_prime(QQ,QQ(3)) 3 sage: check_prime(QQ,ZZ.ideal(31)) 31 sage: K.<a>=NumberField(x^2-5) sage: check_prime(K,a) Fractional ideal (a) sage: check_prime(K,a+1) Fractional ideal (a + 1) sage: [check_prime(K,P) for P in K.primes_above(31)] [Fractional ideal (5/2*a + 1/2), Fractional ideal (5/2*a - 1/2)] sage: L.<b> = NumberField(x^2+3) sage: check_prime(K, L.ideal(5)) Traceback (most recent call last): .. TypeError: The ideal Fractional ideal (5) is not a prime ideal of Number Field in a with defining polynomial x^2 - 5 sage: check_prime(K, L.ideal(b)) Traceback (most recent call last): TypeError: No compatible natural embeddings found for Number Field in a with defining polynomial x^2 - 5 and Number Field in b with defining polynomial x^2 + 3 """ if K is QQ: if P in ZZ or isinstance(P, integer_types + (Integer,)): P = Integer(P) if P.is_prime(): return P else: raise TypeError("The element %s is not prime" % (P,) ) elif P in QQ: raise TypeError("The element %s is not prime" % (P,) ) elif is_Ideal(P) and P.base_ring() is ZZ: if P.is_prime(): return P.gen() else: raise TypeError("The ideal %s is not a prime ideal of %s" % (P, ZZ)) else: raise TypeError("%s is neither an element of QQ or an ideal of %s" % (P, ZZ)) if not is_NumberField(K): raise TypeError("%s is not a number field" % (K,) ) if is_NumberFieldFractionalIdeal(P) or P in K: # if P is an ideal, making sure it is an fractional ideal of K P = K.fractional_ideal(P) if P.is_prime(): return P else: raise TypeError("The ideal %s is not a prime ideal of %s" % (P, K)) raise TypeError("%s is not a valid prime of %s" % (P, K))
def atomic_basis_odd(n, basis, p, **kwds): r""" `P^s_t`-bases and commutator basis in dimension `n` at odd primes. This function is called ``atomic_basis_odd`` in analogy with :func:`atomic_basis`. INPUT: - ``n`` - non-negative integer - ``basis`` - string, the name of the basis - ``p`` - positive prime number - ``profile`` - profile function (optional, default None). Together with ``truncation_type``, specify the profile function to be used; None means the profile function for the entire Steenrod algebra. See :mod:`sage.algebras.steenrod.steenrod_algebra` and :func:`SteenrodAlgebra` for information on profile functions. - ``truncation_type`` - truncation type, either 0 or Infinity (optional, default Infinity if no profile function is specified, 0 otherwise). OUTPUT: tuple of basis elements in dimension n The only possible difference in the implementations for `P^s_t` bases and commutator bases is that the former make sense, and require filtering, if there is a nontrivial profile function. This function is called by :func:`steenrod_algebra_basis`, and it will not be called for commutator bases if there is a profile function, so we treat the two bases exactly the same. EXAMPLES:: sage: from sage.algebras.steenrod.steenrod_algebra_bases import atomic_basis_odd sage: atomic_basis_odd(8, 'pst_rlex', 3) (((), (((0, 1), 2),)),) sage: atomic_basis_odd(18, 'pst_rlex', 3) (((0, 2), ()), ((0, 1), (((1, 1), 1),))) sage: atomic_basis_odd(18, 'pst_rlex', 3, profile=((), (2,2,2))) (((0, 2), ()),) """ def sorting_pair(s, t, basis): # pair used for sorting the basis if basis.find('rlex') >= 0: return (t, s) elif basis.find('llex') >= 0: return (s, t) elif basis.find('deg') >= 0: return (s + t, t) elif basis.find('revz') >= 0: return (s + t, s) generic = kwds.get('generic', False if p == 2 else True) if n == 0: if not generic: return ((), ) else: return (((), ()), ) from sage.rings.all import Integer from sage.rings.infinity import Infinity from sage.combinat.integer_vector_weighted import WeightedIntegerVectors profile = kwds.get("profile", None) trunc = kwds.get("truncation_type", 0) result = [] for dim in range(n // (2 * p - 2) + 1): P_result = [] for v in WeightedIntegerVectors(dim, xi_degrees(dim, p=p, reverse=False)): mono = [] for t, a in enumerate(v): for s, pow in enumerate(Integer(a).digits(p)): if pow > 0: mono.append(((s, t + 1), pow)) P_result.append(mono) for p_mono in P_result: p_mono.sort(key=lambda x: sorting_pair(x[0][0], x[0][1], basis)) deg = n - 2 * dim * (p - 1) q_degrees = [ 1 + 2 * (p - 1) * d for d in xi_degrees((deg - 1) // (2 * (p - 1)), p) ] + [1] q_degrees_decrease = q_degrees q_degrees.reverse() if deg % (2 * (p - 1)) <= len(q_degrees): # if this inequality fails, no way to have a partition # with distinct parts. for sigma in restricted_partitions(deg, q_degrees_decrease, no_repeats=True): index = 0 q_mono = [] for q in q_degrees: if q in sigma: q_mono.append(index) index += 1 # check profile: okay = True if profile is not None and profile != ((), ()): # check profile function for q_mono for i in q_mono: if ((len(profile[1]) > i and profile[1][i] == 1) or (len(profile[1]) <= i and trunc == 0)): okay = False break for ((s, t), exp) in p_mono: if ((len(profile[0]) > t - 1 and profile[0][t - 1] <= s) or (len(profile[0]) <= t - 1 and trunc < Infinity)): okay = False break if okay: if list(p_mono) == [0]: p_mono = [] result.append((tuple(q_mono), tuple(p_mono))) return tuple(result)
def an(self, use_database=False, descent_second_limit=12): r""" Returns the Birch and Swinnerton-Dyer conjectural order of `Sha` as a provably correct integer, unless the analytic rank is > 1, in which case this function returns a numerical value. INPUT: - ``use_database`` -- bool (default: ``False``); if ``True``, try to use any databases installed to lookup the analytic order of `Sha`, if possible. The order of `Sha` is computed if it cannot be looked up. - ``descent_second_limit`` -- int (default: 12); limit to use on point searching for the quartic twist in the hard case This result is proved correct if the order of vanishing is 0 and the Manin constant is <= 2. If the optional parameter ``use_database`` is ``True`` (default: ``False``), this function returns the analytic order of `Sha` as listed in Cremona's tables, if this curve appears in Cremona's tables. NOTE: If you come across the following error:: sage: E = EllipticCurve([0, 0, 1, -34874, -2506691]) sage: E.sha().an() Traceback (most recent call last): ... RuntimeError: Unable to compute the rank, hence generators, with certainty (lower bound=0, generators found=[]). This could be because Sha(E/Q)[2] is nontrivial. Try increasing descent_second_limit then trying this command again. You can increase the ``descent_second_limit`` (in the above example, set to the default, 12) option to try again:: sage: E.sha().an(descent_second_limit=16) # long time (2s on sage.math, 2011) 1 EXAMPLES:: sage: E = EllipticCurve([0, -1, 1, -10, -20]) # 11A = X_0(11) sage: E.sha().an() 1 sage: E = EllipticCurve([0, -1, 1, 0, 0]) # X_1(11) sage: E.sha().an() 1 sage: EllipticCurve('14a4').sha().an() 1 sage: EllipticCurve('14a4').sha().an(use_database=True) # will be faster if you have large Cremona database installed 1 The smallest conductor curve with nontrivial `Sha`:: sage: E = EllipticCurve([1,1,1,-352,-2689]) # 66b3 sage: E.sha().an() 4 The four optimal quotients with nontrivial `Sha` and conductor <= 1000:: sage: E = EllipticCurve([0, -1, 1, -929, -10595]) # 571A sage: E.sha().an() 4 sage: E = EllipticCurve([1, 1, 0, -1154, -15345]) # 681B sage: E.sha().an() 9 sage: E = EllipticCurve([0, -1, 0, -900, -10098]) # 960D sage: E.sha().an() 4 sage: E = EllipticCurve([0, 1, 0, -20, -42]) # 960N sage: E.sha().an() 4 The smallest conductor curve of rank > 1:: sage: E = EllipticCurve([0, 1, 1, -2, 0]) # 389A (rank 2) sage: E.sha().an() 1.00000000000000 The following are examples that require computation of the Mordell-Weil group and regulator:: sage: E = EllipticCurve([0, 0, 1, -1, 0]) # 37A (rank 1) sage: E.sha().an() 1 sage: E = EllipticCurve("1610f3") sage: E.sha().an() 4 In this case the input curve is not minimal, and if this function did not transform it to be minimal, it would give nonsense:: sage: E = EllipticCurve([0,-432*6^2]) sage: E.sha().an() 1 See :trac:`10096`: this used to give the wrong result 6.0000 before since the minimal model was not used:: sage: E = EllipticCurve([1215*1216,0]) # non-minimal model sage: E.sha().an() # long time (2s on sage.math, 2011) 1.00000000000000 sage: E.minimal_model().sha().an() # long time (1s on sage.math, 2011) 1.00000000000000 """ if hasattr(self, '__an'): return self.__an if use_database: d = self.Emin.database_curve() if hasattr(d, 'db_extra'): self.__an = Integer(round(float(d.db_extra[4]))) return self.__an # it's critical to switch to the minimal model. E = self.Emin eps = E.root_number() if eps == 1: L1_over_omega = E.lseries().L_ratio() if L1_over_omega == 0: # order of vanishing is at least 2 return self.an_numerical(use_database=use_database) T = E.torsion_subgroup().order() Sha = (L1_over_omega * T * T) / Q(E.tamagawa_product()) try: Sha = Integer(Sha) except ValueError: raise RuntimeError("There is a bug in an, since the computed conjectural order of Sha is %s, which is not an integer."%Sha) if not arith.is_square(Sha): raise RuntimeError("There is a bug in an, since the computed conjectural order of Sha is %s, which is not a square."%Sha) E.__an = Sha self.__an = Sha return Sha else: # rank > 0 (Not provably correct) L1, error_bound = E.lseries().deriv_at1(10*sqrt(E.conductor()) + 10) if abs(L1) < error_bound: s = self.an_numerical() E.__an = s self.__an = s return s regulator = E.regulator(use_database=use_database, descent_second_limit=descent_second_limit) T = E.torsion_subgroup().order() omega = E.period_lattice().omega() Sha = Integer(round ( (L1 * T * T) / (E.tamagawa_product() * regulator * omega) )) try: Sha = Integer(Sha) except ValueError: raise RuntimeError("There is a bug in an, since the computed conjectural order of Sha is %s, which is not an integer."%Sha) if not arith.is_square(Sha): raise RuntimeError("There is a bug in an, since the computed conjectural order of Sha is %s, which is not a square."%Sha) E.__an = Sha self.__an = Sha return Sha